starting dices implementation

This commit is contained in:
Vlyan
2020-12-07 19:07:41 +01:00
parent 4c900f03bb
commit 7b219b2460
21 changed files with 8853 additions and 6025 deletions

8
.editorconfig Normal file
View File

@@ -0,0 +1,8 @@
root = true
[*]
indent_style = space
indent_size = 4
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = false

5
.eslintignore Normal file
View File

@@ -0,0 +1,5 @@
node_modules
system/lib/
.editorconfig
.idea
.vscode

466
.eslintrc.js Normal file
View File

@@ -0,0 +1,466 @@
module.exports = {
env: {
jquery: true,
browser: true,
es2021: true,
node: true,
},
extends: ["eslint:recommended", "plugin:prettier/recommended"],
parser: "babel-eslint",
parserOptions: {
ecmaVersion: 12,
sourceType: "module",
},
rules: {
// Required for Foundry compatibility
"no-underscore-dangle": "off",
"import/extensions": "off",
"class-methods-use-this": "off",
// Personal Preference
"linebreak-style": "off",
"no-mixed-operators": "off",
"no-param-reassign": "off",
"no-continue": "off",
"no-console": "off",
//"brace-style": ["error"],
"no-unused-vars": "off",
"newline-per-chained-call": "off",
"no-plusplus": "off",
},
globals: {
AudioHelper: "readonly",
Collection: "readonly",
Hooks: "readonly",
KeyboardManager: "readonly",
ClientSettings: "readonly",
WorldSettingsStorage: "readonly",
SetupConfiguration: "readonly",
SocketInterface: "readonly",
SortingHelpers: "readonly",
VideoHelper: "readonly",
Application: "readonly",
FormApplication: "readonly",
BaseEntitySheet: "readonly",
Localization: "readonly",
Game: "readonly",
Die: "readonly",
FateDie: "readonly",
DicePool: "readonly",
Roll: "readonly",
MersenneTwister: "readonly",
EntityCollection: "readonly",
Compendium: "readonly",
Entity: "readonly",
Canvas: "readonly",
CanvasLayer: "readonly",
PlaceableObject: "readonly",
PlaceablesLayer: "readonly",
ContextMenu: "readonly",
Dialog: "readonly",
Draggable: "readonly",
DragDrop: "readonly",
TextEditor: "readonly",
FilePicker: "readonly",
Notifications: "readonly",
Tabs: "readonly",
TabsV2: "readonly",
WebRTC: "readonly",
WebRTCInterface: "readonly",
WebRTCSettings: "readonly",
ActorSheet: "readonly",
AVConfig: "readonly",
CombatTrackerConfig: "readonly",
FolderConfig: "readonly",
GridConfig: "readonly",
ImagePopout: "readonly",
ItemSheet: "readonly",
JournalSheet: "readonly",
MacroConfig: "readonly",
MeasuredTemplateConfig: "readonly",
PermissionControl: "readonly",
PlayerConfig: "readonly",
PlaylistConfig: "readonly",
PlaylistSoundConfig: "readonly",
RollTableConfig: "readonly",
SceneConfig: "readonly",
EntitySheetConfig: "readonly",
CameraPopoutAppWrapper: "readonly",
CameraViews: "readonly",
ChatBubbles: "readonly",
HeadsUpDisplay: "readonly",
SceneControls: "readonly",
Hotbar: "readonly",
BasePlaceableHUD: "readonly",
MainMenu: "readonly",
SceneNavigation: "readonly",
Pause: "readonly",
PlayerList: "readonly",
DrawingConfig: "readonly",
DrawingHUD: "readonly",
LightConfig: "readonly",
NoteConfig: "readonly",
AmbientSoundConfig: "readonly",
TileConfig: "readonly",
TileHUD: "readonly",
TokenConfig: "readonly",
TokenHUD: "readonly",
WallConfig: "readonly",
EULA: "readonly",
InstallPackage: "readonly",
SetupConfigurationForm: "readonly",
UpdateNotes: "readonly",
UserManagement: "readonly",
WorldConfig: "readonly",
Sidebar: "readonly",
SidebarTab: "readonly",
SidebarDirectory: "readonly",
Actors: "readonly",
Actor: "readonly",
ActorTokenHelpers: "readonly",
CombatEncounters: "readonly",
Combat: "readonly",
Folders: "readonly",
Folder: "readonly",
Items: "readonly",
Item: "readonly",
Journal: "readonly",
JournalEntry: "readonly",
Macros: "readonly",
Macro: "readonly",
Messages: "readonly",
ChatMessage: "readonly",
Playlists: "readonly",
Playlist: "readonly",
Scenes: "readonly",
Scene: "readonly",
RollTables: "readonly",
RollTable: "readonly",
Users: "readonly",
User: "readonly",
UserTargets: "readonly",
CanvasAnimation: "readonly",
ControlIcon: "readonly",
TextureLoader: "readonly",
MouseInteractionManager: "readonly",
Ray: "readonly",
NormalizedRectangle: "readonly",
ResizeHandle: "readonly",
SightLayerSource: "readonly",
BackgroundLayer: "readonly",
DrawingsLayer: "readonly",
EffectsLayer: "readonly",
LightingLayer: "readonly",
NotesLayer: "readonly",
SightLayer: "readonly",
SoundsLayer: "readonly",
TemplateLayer: "readonly",
TilesLayer: "readonly",
TokenLayer: "readonly",
WallsLayer: "readonly",
Drawing: "readonly",
AmbientLight: "readonly",
Note: "readonly",
AmbientSound: "readonly",
MeasuredTemplate: "readonly",
Tile: "readonly",
Token: "readonly",
Wall: "readonly",
SettingsConfig: "readonly",
ControlsReference: "readonly",
InvitationLinks: "readonly",
ModuleManagement: "readonly",
PermissionConfig: "readonly",
ActorDirectory: "readonly",
ChatLog: "readonly",
CombatTracker: "readonly",
CompendiumDirectory: "readonly",
ItemDirectory: "readonly",
JournalDirectory: "readonly",
MacroDirectory: "readonly",
PlaylistDirectory: "readonly",
SceneDirectory: "readonly",
Settings: "readonly",
FrameViewer: "readonly",
RollTableDirectory: "readonly",
Cursor: "readonly",
DoorControl: "readonly",
ControlsLayer: "readonly",
Ruler: "readonly",
SpecialEffect: "readonly",
AutumnLeavesWeatherEffect: "readonly",
RainWeatherEffect: "readonly",
SnowWeatherEffect: "readonly",
BaseGrid: "readonly",
HexagonalGrid: "readonly",
GridHighlight: "readonly",
GridLayer: "readonly",
SquareGrid: "readonly",
EasyRTCClient: "readonly",
parent: "readonly",
opener: "readonly",
top: "readonly",
length: "readonly",
frames: "readonly",
closed: "readonly",
location: "readonly",
self: "readonly",
window: "readonly",
document: "readonly",
name: "readonly",
customElements: "readonly",
history: "readonly",
locationbar: "readonly",
menubar: "readonly",
personalbar: "readonly",
scrollbars: "readonly",
statusbar: "readonly",
toolbar: "readonly",
status: "readonly",
frameElement: "readonly",
navigator: "readonly",
origin: "readonly",
external: "readonly",
screen: "readonly",
innerWidth: "readonly",
innerHeight: "readonly",
scrollX: "readonly",
pageXOffset: "readonly",
scrollY: "readonly",
pageYOffset: "readonly",
visualViewport: "readonly",
screenX: "readonly",
screenY: "readonly",
outerWidth: "readonly",
outerHeight: "readonly",
devicePixelRatio: "readonly",
clientInformation: "readonly",
screenLeft: "readonly",
screenTop: "readonly",
defaultStatus: "readonly",
defaultstatus: "readonly",
styleMedia: "readonly",
onsearch: "readonly",
isSecureContext: "readonly",
onabort: "readonly",
onblur: "readonly",
oncancel: "readonly",
oncanplay: "readonly",
oncanplaythrough: "readonly",
onchange: "readonly",
onclick: "readonly",
onclose: "readonly",
oncontextmenu: "readonly",
oncuechange: "readonly",
ondblclick: "readonly",
ondrag: "readonly",
ondragend: "readonly",
ondragenter: "readonly",
ondragleave: "readonly",
ondragover: "readonly",
ondragstart: "readonly",
ondrop: "readonly",
ondurationchange: "readonly",
onemptied: "readonly",
onended: "readonly",
onerror: "readonly",
onfocus: "readonly",
onformdata: "readonly",
oninput: "readonly",
oninvalid: "readonly",
onkeydown: "readonly",
onkeypress: "readonly",
onkeyup: "readonly",
onload: "readonly",
onloadeddata: "readonly",
onloadedmetadata: "readonly",
onloadstart: "readonly",
onmousedown: "readonly",
onmouseenter: "readonly",
onmouseleave: "readonly",
onmousemove: "readonly",
onmouseout: "readonly",
onmouseover: "readonly",
onmouseup: "readonly",
onmousewheel: "readonly",
onpause: "readonly",
onplay: "readonly",
onplaying: "readonly",
onprogress: "readonly",
onratechange: "readonly",
onreset: "readonly",
onresize: "readonly",
onscroll: "readonly",
onseeked: "readonly",
onseeking: "readonly",
onselect: "readonly",
onstalled: "readonly",
onsubmit: "readonly",
onsuspend: "readonly",
ontimeupdate: "readonly",
ontoggle: "readonly",
onvolumechange: "readonly",
onwaiting: "readonly",
onwebkitanimationend: "readonly",
onwebkitanimationiteration: "readonly",
onwebkitanimationstart: "readonly",
onwebkittransitionend: "readonly",
onwheel: "readonly",
onauxclick: "readonly",
ongotpointercapture: "readonly",
onlostpointercapture: "readonly",
onpointerdown: "readonly",
onpointermove: "readonly",
onpointerup: "readonly",
onpointercancel: "readonly",
onpointerover: "readonly",
onpointerout: "readonly",
onpointerenter: "readonly",
onpointerleave: "readonly",
onselectstart: "readonly",
onselectionchange: "readonly",
onanimationend: "readonly",
onanimationiteration: "readonly",
onanimationstart: "readonly",
ontransitionend: "readonly",
onafterprint: "readonly",
onbeforeprint: "readonly",
onbeforeunload: "readonly",
onhashchange: "readonly",
onlanguagechange: "readonly",
onmessage: "readonly",
onmessageerror: "readonly",
onoffline: "readonly",
ononline: "readonly",
onpagehide: "readonly",
onpageshow: "readonly",
onpopstate: "readonly",
onrejectionhandled: "readonly",
onstorage: "readonly",
onunhandledrejection: "readonly",
onunload: "readonly",
performance: "readonly",
stop: "readonly",
open: "readonly",
alert: "readonly",
confirm: "readonly",
prompt: "readonly",
print: "readonly",
queueMicrotask: "readonly",
requestAnimationFrame: "readonly",
cancelAnimationFrame: "readonly",
captureEvents: "readonly",
releaseEvents: "readonly",
requestIdleCallback: "readonly",
cancelIdleCallback: "readonly",
getComputedStyle: "readonly",
matchMedia: "readonly",
moveTo: "readonly",
moveBy: "readonly",
resizeTo: "readonly",
resizeBy: "readonly",
scroll: "readonly",
scrollTo: "readonly",
scrollBy: "readonly",
getSelection: "readonly",
find: "readonly",
webkitRequestAnimationFrame: "readonly",
webkitCancelAnimationFrame: "readonly",
fetch: "readonly",
btoa: "readonly",
atob: "readonly",
setTimeout: "readonly",
clearTimeout: "readonly",
setInterval: "readonly",
clearInterval: "readonly",
createImageBitmap: "readonly",
close: "readonly",
focus: "readonly",
blur: "readonly",
postMessage: "readonly",
onappinstalled: "readonly",
onbeforeinstallprompt: "readonly",
crypto: "readonly",
indexedDB: "readonly",
webkitStorageInfo: "readonly",
sessionStorage: "readonly",
localStorage: "readonly",
chrome: "readonly",
applicationCache: "readonly",
onpointerrawupdate: "readonly",
trustedTypes: "readonly",
speechSynthesis: "readonly",
webkitRequestFileSystem: "readonly",
webkitResolveLocalFileSystemURL: "readonly",
openDatabase: "readonly",
caches: "readonly",
ondevicemotion: "readonly",
ondeviceorientation: "readonly",
ondeviceorientationabsolute: "readonly",
Handlebars: "readonly",
HandlebarsIntl: "readonly",
HowlerGlobal: "readonly",
Howler: "readonly",
Howl: "readonly",
Sound: "readonly",
WebFont: "readonly",
PIXI: "readonly",
io: "readonly",
tinymce: "readonly",
tinyMCE: "readonly",
easyrtc_lang: "readonly",
adapter: "readonly",
easyrtc: "readonly",
duplicate: "readonly",
getType: "readonly",
invertObject: "readonly",
filterObject: "readonly",
flattenObject: "readonly",
expandObject: "readonly",
isObjectEmpty: "readonly",
mergeObject: "readonly",
diffObject: "readonly",
hasProperty: "readonly",
getProperty: "readonly",
setProperty: "readonly",
encodeURL: "readonly",
rgbToHsv: "readonly",
hsvToRgb: "readonly",
rgbToHex: "readonly",
hexToRGB: "readonly",
hexToRGBAString: "readonly",
colorStringToHex: "readonly",
isNewerVersion: "readonly",
randomID: "readonly",
loadFont: "readonly",
saveDataToFile: "readonly",
readTextFromFile: "readonly",
fromUuid: "readonly",
_handleMouseWheelInputChange: "readonly",
getTemplate: "readonly",
loadTemplates: "readonly",
renderTemplate: "readonly",
srcExists: "readonly",
getTexture: "readonly",
loadTexture: "readonly",
CONST: "readonly",
toDegrees: "readonly",
normalizeDegrees: "readonly",
toRadians: "readonly",
normalizeRadians: "readonly",
validateForm: "readonly",
timeSince: "readonly",
_templateCache: "readonly",
CONFIG: "readonly",
socket: "readonly",
ui: "readonly",
canvas: "readonly",
keyboard: "readonly",
JSHINT: "readonly",
game: "readonly",
vtt: "readonly",
ENTITY_PERMISSIONS: "readonly",
DEFAULT_TOKEN: "readonly",
DiceTerm: "readonly",
GRID_TYPES: "readonly",
},
};

10
.gitignore vendored
View File

@@ -1 +1,9 @@
node_modules # Node
node_modules
# IDE
.idea
.vscode
# lint
.eslintcache

6
.prettierignore Normal file
View File

@@ -0,0 +1,6 @@
node_modules/
system/lib/
*.hbs
*.css
.idea
.vscode

4
.prettierrc.json Normal file
View File

@@ -0,0 +1,4 @@
{
"tabWidth": 4,
"printWidth": 120
}

13525
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,27 +1,45 @@
{ {
"name": "l5r5e", "name": "l5r5e",
"version": "1.0.0", "version": "1.0.0",
"description": "This is a game system for Legend of the Five Rings (5th edition) by Edge Studio", "description": "This is a game system for Legend of the Five Rings (5th edition) by Edge Studio",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"compile": "gulp css", "compile": "gulp css",
"watch": "gulp watch", "watch": "gulp watch",
"prettier": "prettier --quote-props=preserve --print-width=5000 --write" "prettier": "prettier --quote-props=preserve --print-width=5000 --write"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://gitlab.com/teaml5r/l5r5e.git" "url": "git+https://gitlab.com/teaml5r/l5r5e.git"
}, },
"author": "Team L5r", "author": "Team L5r",
"license": "ISC", "license": "ISC",
"bugs": { "bugs": {
"url": "https://gitlab.com/teaml5r/l5r5e/issues" "url": "https://gitlab.com/teaml5r/l5r5e/issues"
}, },
"homepage": "https://gitlab.com/teaml5r/l5r5e#readme", "homepage": "https://gitlab.com/teaml5r/l5r5e#readme",
"devDependencies": { "devDependencies": {
"browser-sync": "^2.26.13", "babel-eslint": "^10.1.0",
"gulp": "^4.0.2", "browser-sync": "^2.26.13",
"gulp-autoprefixer": "^7.0.1", "eslint": "^7.15.0",
"gulp-sass": "^4.1.0" "eslint-config-prettier": "^6.15.0",
} "eslint-plugin-prettier": "^3.1.4",
"foundry-pc-types": "gitlab:foundry-projects/foundry-pc/foundry-pc-types",
"gulp": "^4.0.2",
"gulp-autoprefixer": "^7.0.1",
"gulp-sass": "^4.1.0",
"husky": "^4.3.0",
"lint-staged": "^10.5.1",
"prettier": "^2.1.2"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"*.js": "eslint --cache --fix",
"*.json": "prettier --write",
"*.scss": "prettier --write"
}
} }

View File

@@ -3,8 +3,9 @@
* @extends {DiceTerm} * @extends {DiceTerm}
*/ */
export { AbilityDie } from "./dice/dietype/AbilityDie.js"; export { L5rBaseDie } from "./dice/dietype/l5r-base-die.js";
export { RingsDie } from "./dice/dietype/RingsDie.js"; export { AbilityDie } from "./dice/dietype/ability-die.js";
export { RingDie } from "./dice/dietype/ring-die.js";
/** /**
* New extension of the core DicePool class for evaluating rolls with the L5r5e DiceTerms * New extension of the core DicePool class for evaluating rolls with the L5r5e DiceTerms

View File

@@ -1,63 +0,0 @@
export class AbilityDie extends DiceTerm {
constructor(termData) {
super(termData);
this.faces = 8;
}
/* -------------------------------------------- */
/** @override */
static DENOMINATION = "a";
/* -------------------------------------------- */
/** @override */
get formula() {
return `${this.number}${this.constructor.DENOMINATION}${this.modifiers.join("")}`;
}
/* -------------------------------------------- */
/** @override */
evaluate({ minimize = false, maximize = false } = {}) {
if (this._evaluated) {
throw new Error(`This ${this.constructor.name} has already been evaluated and is immutable`);
}
// Roll the initial number of dice
for (let n = 1; n <= this.number; n++) {
this.roll({ minimize, maximize });
}
// Apply modifiers
this._evaluateModifiers();
// Combine all FFG results.
this.ffg = { success: 0, failure: 0, advantage: 0, threat: 0, triumph: 0, despair: 0, light: 0, dark: 0 };
this.results.forEach((result) => {
this.ffg.success += parseInt(result.ffg.success);
this.ffg.failure += parseInt(result.ffg.failure);
this.ffg.advantage += parseInt(result.ffg.advantage);
this.ffg.threat += parseInt(result.ffg.threat);
this.ffg.triumph += parseInt(result.ffg.triumph);
this.ffg.despair += parseInt(result.ffg.despair);
this.ffg.light += parseInt(result.ffg.light);
this.ffg.dark += parseInt(result.ffg.dark);
});
// Return the evaluated term
this._evaluated = true;
this._isFFG = true;
return this;
}
/* -------------------------------------------- */
/** @override */
roll(options) {
const roll = super.roll(options);
roll.ffg = CONFIG.FFG.ABILITY_RESULTS[roll.result];
return roll;
}
/* -------------------------------------------- */
/** @override */
static getResultLabel(result) {
return CONFIG.FFG.ABILITY_RESULTS[result].label;
}
}

View File

@@ -1,63 +0,0 @@
export class RingsDie extends DiceTerm {
constructor(termData) {
super(termData);
this.faces = 12;
}
/* -------------------------------------------- */
/** @override */
static DENOMINATION = "p";
/* -------------------------------------------- */
/** @override */
get formula() {
return `${this.number}${this.constructor.DENOMINATION}${this.modifiers.join("")}`;
}
/* -------------------------------------------- */
/** @override */
evaluate({ minimize = false, maximize = false } = {}) {
if (this._evaluated) {
throw new Error(`This ${this.constructor.name} has already been evaluated and is immutable`);
}
// Roll the initial number of dice
for (let n = 1; n <= this.number; n++) {
this.roll({ minimize, maximize });
}
// Apply modifiers
this._evaluateModifiers();
// Combine all FFG results.
this.ffg = { success: 0, failure: 0, advantage: 0, threat: 0, triumph: 0, despair: 0, light: 0, dark: 0 };
this.results.forEach((result) => {
this.ffg.success += parseInt(result.ffg.success);
this.ffg.failure += parseInt(result.ffg.failure);
this.ffg.advantage += parseInt(result.ffg.advantage);
this.ffg.threat += parseInt(result.ffg.threat);
this.ffg.triumph += parseInt(result.ffg.triumph);
this.ffg.despair += parseInt(result.ffg.despair);
this.ffg.light += parseInt(result.ffg.light);
this.ffg.dark += parseInt(result.ffg.dark);
});
// Return the evaluated term
this._evaluated = true;
this._isFFG = true;
return this;
}
/* -------------------------------------------- */
/** @override */
roll(options) {
const roll = super.roll(options);
roll.ffg = CONFIG.FFG.PROFICIENCY_RESULTS[roll.result];
return roll;
}
/* -------------------------------------------- */
/** @override */
static getResultLabel(result) {
return CONFIG.FFG.PROFICIENCY_RESULTS[result].label;
}
}

View File

@@ -0,0 +1,30 @@
import { L5rBaseDie } from "./l5r-base-die.js";
/**
* L5R5e Skill Die
*/
export class AbilityDie extends L5rBaseDie {
/** @override */
static DENOMINATION = "ds";
static FACES = {
1: { success: 0, explosive: 0, opportunity: 0, strife: 0, image: "skill_blank" },
2: { success: 0, explosive: 0, opportunity: 0, strife: 0, image: "skill_blank" },
3: { success: 0, explosive: 0, opportunity: 1, strife: 0, image: "skill_o" },
4: { success: 0, explosive: 0, opportunity: 1, strife: 0, image: "skill_o" },
5: { success: 0, explosive: 0, opportunity: 1, strife: 0, image: "skill_o" },
6: { success: 1, explosive: 0, opportunity: 0, strife: 1, image: "skill_st" },
7: { success: 1, explosive: 0, opportunity: 0, strife: 1, image: "skill_st" },
8: { success: 1, explosive: 0, opportunity: 0, strife: 0, image: "skill_s" },
9: { success: 1, explosive: 0, opportunity: 0, strife: 0, image: "skill_s" },
10: { success: 1, explosive: 0, opportunity: 1, strife: 0, image: "skill_so" },
11: { success: 1, explosive: 1, opportunity: 0, strife: 1, image: "skill_et" },
12: { success: 1, explosive: 1, opportunity: 0, strife: 0, image: "skill_e" },
};
/** @override */
constructor(termData) {
super(termData);
this.faces = 12;
}
}

View File

@@ -0,0 +1,105 @@
/**
* L5R5e Base Die
*/
export class L5rBaseDie extends DiceTerm {
/** Need to be override */
static DENOMINATION = "";
/** Need to be override */
static FACES = {};
/** @override */
constructor(termData) {
super(termData);
this.l5r5e = { success: 0, explosive: 0, opportunity: 0, strife: 0 };
console.log("L5rBaseDie.constructor", termData, this); // TODO tmp
}
/**
* Return a standardized representation for the displayed formula associated with this DiceTerm
* @override
*/
get formula() {
return `${this.number}${this.constructor.DENOMINATION}${this.modifiers.join("")}`;
}
/**
* Return a string used as the label for each rolled result
* @override
*/
static getResultLabel(result) {
return `<img src="${CONFIG.L5r5e.paths.assets}dices/default/${this.FACES[result].image}.png" alt="${result}" />`;
}
/**
* Evaluate the roll term, populating the results Array
* @override
*/
evaluate({ minimize = false, maximize = false } = {}) {
if (this._evaluated) {
throw new Error(`This ${this.constructor.name} has already been evaluated and is immutable`);
}
// Roll the initial number of dice
for (let n = 1; n <= this.number; n++) {
this.roll({ minimize, maximize });
}
// Apply modifiers
this._evaluateModifiers();
// Combine all results
this.l5r5e = { success: 0, explosive: 0, opportunity: 0, strife: 0 };
this.results.forEach((term) => {
const face = this.constructor.FACES[term.result];
["success", "explosive", "opportunity", "strife"].forEach((props) => {
this.l5r5e[props] += parseInt(face[props]);
});
});
// Return the evaluated term
this._evaluated = true;
this.result = 0;
console.log("L5rBaseDie.evaluate.out", this); // TODO tmp
return this;
}
/**
* Roll the DiceTerm by mapping a random uniform draw against the faces of the dice term
* @override
*/
roll(options) {
const roll = super.roll(options);
//roll.l5r5e = this.l5r5e;
console.log("L5rBaseDie.roll", roll); // TODO tmp
return roll;
}
/** @override */
static fromData(data) {
const roll = super.fromData(data);
roll.l5r5e = data.l5r5e;
console.log("L5rBaseDie.fromData", roll); // TODO tmp
return roll;
}
/**
* Represent the data of the Roll as an object suitable for JSON serialization
* @override
*/
toJSON() {
const json = super.toJSON();
json.l5r5e = this.l5r5e;
console.log("L5rBaseDie.toJSON", json); // TODO tmp
return json;
}
}

View File

@@ -0,0 +1,24 @@
import { L5rBaseDie } from "./l5r-base-die.js";
/**
* L5R5e Ring Die
*/
export class RingDie extends L5rBaseDie {
/** @override */
static DENOMINATION = "dr";
static FACES = {
1: { success: 0, explosive: 0, opportunity: 0, strife: 0, image: "ring_blank" },
2: { success: 0, explosive: 0, opportunity: 1, strife: 1, image: "ring_ot" },
3: { success: 0, explosive: 0, opportunity: 1, strife: 0, image: "ring_o" },
4: { success: 1, explosive: 0, opportunity: 0, strife: 1, image: "ring_st" },
5: { success: 1, explosive: 0, opportunity: 0, strife: 0, image: "ring_s" },
6: { success: 1, explosive: 1, opportunity: 0, strife: 1, image: "ring_et" },
};
/** @override */
constructor(termData) {
super(termData);
this.faces = 6;
}
}

View File

@@ -1,8 +1,4 @@
/** /**
* Dice pool utility specializing in the FFG special dice * Dice pool utility specializing in the FFG special dice
*/ */
export class DicePoolL5r5e { export class DicePoolL5r5e {}
}

View File

@@ -1,8 +1,269 @@
import { L5rBaseDie } from "./dietype/l5r-base-die.js";
/** /**
* New extension of the core DicePool class for evaluating rolls with the FFG DiceTerms * Roll for L5R5e
*/ */
export class RollL5r5e extends Roll { export class RollL5r5e extends Roll {
static CHAT_TEMPLATE = "systems/l5r5e/templates/dice/chat-roll.html";
static TOOLTIP_TEMPLATE = "systems/l5r5e/templates/dice/tooltip.html";
// static CHAT_TEMPLATE = `${CONFIG.L5r5e.pathTemplates}dice/chat-roll.html`;
// static TOOLTIP_TEMPLATE = `${CONFIG.L5r5e.pathTemplates}dice/tooltip.html`;
constructor(...args) {
console.log("RollL5r5e.in.args", args); // TODO tmp
super(...args);
this.l5r5e = {
stance: "",
skillId: "",
actor: null,
dicesTypes: {
std: false,
l5r: false,
},
summary: {
difficulty: 0,
success_total: 0,
success: 0,
explosive: 0,
opportunity: 0,
strife: 0,
},
};
// TODO parse difficulty stance skillId from cmd line ?
console.log("RollL5r5e.out.args", args, this); // TODO tmp
}
/**
* Execute the Roll, replacing dice and evaluating the total result
* @override
**/
evaluate({ minimize = false, maximize = false } = {}) {
if (this._rolled) {
throw new Error("This Roll object has already been rolled.");
}
// console.log('RollL5r5e.evaluate.in', this); return; // TODO tmp
// Split L5R dices / regulars
let l5rDices = this.terms.filter((term) => term instanceof L5rBaseDie);
this.terms = this.terms.filter((t) => !(t instanceof L5rBaseDie));
this.terms = this._identifyTerms(this.constructor.cleanFormula(this.terms));
// Roll regular dices
this._total = 0;
if (this.terms.length > 0) {
this.l5r5e.dicesTypes.std = true;
console.log("this.terms", this.terms);
// clean terms (trim symbols)
this.terms = this._identifyTerms(this.constructor.cleanFormula(this.terms));
// Roll
super.evaluate({ minimize, maximize });
}
// Roll L5R dices
if (l5rDices.length > 0) {
this.l5r5e.dicesTypes.l5r = true;
l5rDices.forEach((term) => {
// Roll
term.evaluate({ minimize, maximize });
// Total
["success", "explosive", "opportunity", "strife"].forEach((props) => {
this.l5r5e.summary[props] += parseInt(term.l5r5e[props]);
});
this.l5r5e.summary.success_total += parseInt(term.l5r5e.success) + parseInt(term.l5r5e.explosive);
this.terms.push("+");
this.terms.push(term);
});
// Clean
if (this.terms[0] === "+") {
this.terms.shift();
}
// TODO Others advantage/disadvantage
// re-inject L5R dices
// this.terms = this.terms.concat(l5rTerms);
}
// Store final outputs
//this._total = total;
this._rolled = true;
console.log("RollL5r5e.evaluate.out", this); // TODO tmp
return this;
}
/**
* Render the tooltip HTML for a Roll instance
* @override
*/
getTooltip() {
console.log("RollL5r5e.getTooltip", this); // TODO tmp
const parts = this.dice
.filter((t) => !(t instanceof L5rBaseDie))
.map((d) => {
const cls = d.constructor;
return {
formula: d.formula,
total: d.total,
faces: d.faces,
flavor: d.options.flavor,
isL5rDices: d.constructor instanceof L5rBaseDie,
rolls: d.results.map((r) => {
return {
result: cls.getResultLabel(r.result),
classes: [
cls.name.toLowerCase(),
"d" + d.faces,
r.rerolled ? "rerolled" : null,
r.exploded ? "exploded" : null,
r.discarded ? "discarded" : null,
r.result === 1 ? "min" : null,
r.result === d.faces ? "max" : null,
]
.filter((c) => !!c)
.join(" "),
};
}),
};
});
parts.addedResults = this.addedResults;
return renderTemplate(this.constructor.TOOLTIP_TEMPLATE, { parts });
}
/**
* Render a Roll instance to HTML
* @override
*/
async render(chatOptions = {}) {
console.log("RollL5r5e.render", chatOptions, this); // TODO tmp
chatOptions = mergeObject(
{
user: game.user._id,
flavor: null,
template: this.constructor.CHAT_TEMPLATE,
blind: false,
},
chatOptions
);
const isPrivate = chatOptions.isPrivate;
// Execute the roll, if needed
if (!this._rolled) {
this.roll();
}
// Define chat data
const chatData = {
formula: isPrivate ? "???" : this._formula,
flavor: isPrivate ? null : chatOptions.flavor,
user: chatOptions.user,
isPublicRoll: !chatOptions.isPrivate,
tooltip: isPrivate ? "" : await this.getTooltip(),
total: isPrivate ? "?" : Math.round(this.total * 100) / 100,
data: this.data,
l5r5e: isPrivate
? {}
: {
dicesTypes: this.l5r5e.dicesTypes,
summary: this.l5r5e.summary,
dices: this.dice.map((d) => {
return {
diceTypeL5r: d instanceof L5rBaseDie,
rolls: d.results.map((r) => {
return {
result: d.constructor.getResultLabel(r.result),
};
}),
};
}),
},
};
console.log("RollL5r5e.render", chatOptions, chatData, this); // TODO tmp
// Render the roll display template
return renderTemplate(chatOptions.template, chatData);
}
/**
* Transform a Roll instance into a ChatMessage, displaying the roll result.
* This function can either create the ChatMessage directly, or return the data object that will be used to create.
* @override
*/
toMessage(messageData = {}, { rollMode = null, create = true } = {}) {
console.log("RollL5r5e.toMessage", this); // TODO tmp
// Perform the roll, if it has not yet been rolled
if (!this._rolled) {
this.evaluate();
}
const rMode = rollMode || messageData.rollMode || game.settings.get("core", "rollMode");
let template = CONST.CHAT_MESSAGE_TYPES.ROLL;
if (["gmroll", "blindroll"].includes(rMode)) {
messageData.whisper = ChatMessage.getWhisperRecipients("GM");
}
if (rMode === "blindroll") messageData.blind = true;
if (rMode === "selfroll") messageData.whisper = [game.user.id];
// Prepare chat data
messageData = mergeObject(
{
user: game.user._id,
type: template,
content: this.total,
sound: CONFIG.sounds.dice,
},
messageData
);
messageData.roll = this;
// Prepare message options
const messageOptions = { rollMode: rMode };
// Either create the message or just return the chat data
return create ? CONFIG.ChatMessage.entityClass.create(messageData, messageOptions) : messageData;
}
/** @override */
static fromData(data) {
const roll = super.fromData(data);
roll.data = data.data;
roll.l5r5e = data.l5r5e;
console.log("RollL5r5e.fromData", roll); // TODO tmp
return roll;
}
/**
* Represent the data of the Roll as an object suitable for JSON serialization
* @override
*/
toJSON() {
const json = super.toJSON();
json.data = this.data;
json.l5r5e = this.l5r5e;
return json;
}
} }

View File

@@ -1,54 +1,73 @@
// Import Modules // Import Modules
import { RegisterSettings } from './settings.js'; import { RegisterSettings } from "./settings.js";
import { PreloadTemplates } from './preloadTemplates.js'; import { PreloadTemplates } from "./preloadTemplates.js";
import { ActorL5r5e } from "./actor-l5r5e.js"; import { ActorL5r5e } from "./actor-l5r5e.js";
import { ActorSheetL5r5e } from './sheets/actor-sheet.js'; import { ActorSheetL5r5e } from "./sheets/actor-sheet.js";
import { RollL5r5e } from "./dice/roll.js";
import { AbilityDie } from "./dice/dietype/ability-die.js";
import { RingDie } from "./dice/dietype/ring-die.js";
// Import Dice Types // Import Dice Types
/* ------------------------------------ */ /* ------------------------------------ */
/* Initialize system */ /* Initialize system */
/* ------------------------------------ */ /* ------------------------------------ */
Hooks.once('init', async function() { Hooks.once("init", async function () {
console.log('l5r5e | Initializing l5r5e'); console.log("l5r5e | Initializing l5r5e");
// Assign custom classes and constants here // Assign custom classes and constants here
CONFIG.Actor.entityClass = ActorL5r5e; CONFIG.Actor.entityClass = ActorL5r5e;
CONFIG.Actor.sheetClasses = ActorSheetL5r5e; CONFIG.Actor.sheetClasses = ActorSheetL5r5e;
// Define custom Roll class
CONFIG.Dice.rolls.push(CONFIG.Dice.rolls[0]);
CONFIG.Dice.rolls[0] = RollL5r5e;
// Define DiceTerms
CONFIG.Dice.terms["s"] = AbilityDie;
CONFIG.Dice.terms["r"] = RingDie;
// Define L5R Paths
CONFIG.L5r5e = {
paths: {
assets: `systems/l5r5e/assets/`,
templates: `systems/l5r5e/templates/`,
},
};
// Register custom system settings // Register custom system settings
RegisterSettings(); RegisterSettings();
// Preload Handlebars templates // Preload Handlebars templates
await PreloadTemplates(); await PreloadTemplates();
// Register custom sheets (if any) // Register custom sheets (if any)
// Actors sheet // Actors sheet
Actors.unregisterSheet("core", ActorSheet); Actors.unregisterSheet("core", ActorSheet);
Actors.registerSheet("l5r5e", ActorSheetL5r5e, { types: ["character"], makeDefault: true }); Actors.registerSheet("l5r5e", ActorSheetL5r5e, { types: ["character"], makeDefault: true });
Handlebars.registerHelper('localizeSkillCategory', function(skillName) { Handlebars.registerHelper("localizeSkillCategory", function (skillName) {
const key = 'L5r5e.Skills.' + skillName + '.Title'; const key = "L5r5e.Skills." + skillName + ".Title";
return game.i18n.localize(key); return game.i18n.localize(key);
}); });
Handlebars.registerHelper('localizeSkill', function(skillCategory, skillName) { Handlebars.registerHelper("localizeSkill", function (skillCategory, skillName) {
const key = 'L5r5e.Skills.' + skillCategory + '.' + skillName; const key = "L5r5e.Skills." + skillCategory + "." + skillName;
return game.i18n.localize(key); return game.i18n.localize(key);
}); });
Handlebars.registerHelper('localizeRing', function(ringName) { Handlebars.registerHelper("localizeRing", function (ringName) {
const key = 'L5r5e.Rings.' + ringName.charAt(0).toUpperCase() + ringName.slice(1); const key = "L5r5e.Rings." + ringName.charAt(0).toUpperCase() + ringName.slice(1);
return game.i18n.localize(key); return game.i18n.localize(key);
}); });
Handlebars.registerHelper('localizeRingTip', function(ringName) { Handlebars.registerHelper("localizeRingTip", function (ringName) {
const key = 'L5r5e.Rings.' + ringName.charAt(0).toUpperCase() + ringName.slice(1) + "Tip"; const key = "L5r5e.Rings." + ringName.charAt(0).toUpperCase() + ringName.slice(1) + "Tip";
return game.i18n.localize(key); return game.i18n.localize(key);
}); });
Handlebars.registerHelper('localizeStanceTip', function(ringName) { Handlebars.registerHelper("localizeStanceTip", function (ringName) {
const key = 'L5r5e.Conflict.Stances.' + ringName.charAt(0).toUpperCase() + ringName.slice(1) + "Tip"; const key = "L5r5e.Conflict.Stances." + ringName.charAt(0).toUpperCase() + ringName.slice(1) + "Tip";
return game.i18n.localize(key); return game.i18n.localize(key);
}); });
}); });
@@ -56,7 +75,7 @@ Hooks.once('init', async function() {
/* ------------------------------------ */ /* ------------------------------------ */
/* Setup system */ /* Setup system */
/* ------------------------------------ */ /* ------------------------------------ */
Hooks.once('setup', function() { Hooks.once("setup", function () {
// Do anything after initialization but before // Do anything after initialization but before
// ready // ready
}); });
@@ -68,8 +87,54 @@ Hooks.once('setup', function() {
/* ------------------------------------ */ /* ------------------------------------ */
/* When ready */ /* When ready */
/* ------------------------------------ */ /* ------------------------------------ */
Hooks.once('ready', function() { Hooks.once("ready", function () {
// Do anything once the system is ready // Do anything once the system is ready
}); });
/* ------------------------------------ */
/* DiceSoNice Hook */
/* ------------------------------------ */
Hooks.once("diceSoNiceReady", (dice3d) => {
const texturePath = `${CONFIG.L5r5e.paths.assets}dices/default/3d/`;
// dice3d.addSystem({
// id: "l5r5e",
// name: "Legend of the Five Rings 5E"
// }, "force");
// Rings
dice3d.addDicePreset(
{
name: "L5R Ring Dice",
type: "ddr", // don't known why the "dd" prefix is required, term is "r"
labels: Object.keys(RingDie.FACES).map(
(e) => `${texturePath}${RingDie.FACES[e].image.replace("ring_", "")}.png`
),
bumpMaps: Object.keys(RingDie.FACES).map(
(e) => `${texturePath}${RingDie.FACES[e].image.replace("ring_", "")}_bm.png`
),
colorset: "black",
system: "standard",
},
"d6"
);
// Skills
dice3d.addDicePreset(
{
name: "L5R Skill Dice",
type: "dds",
labels: Object.keys(AbilityDie.FACES).map(
(e) => `${texturePath}${AbilityDie.FACES[e].image.replace("skill_", "")}.png`
),
bumpMaps: Object.keys(AbilityDie.FACES).map(
(e) => `${texturePath}${AbilityDie.FACES[e].image.replace("skill_", "")}_bm.png`
),
colorset: "white",
system: "standard",
},
"d12"
);
});
// Add any additional hooks if necessary // Add any additional hooks if necessary

View File

@@ -1 +1 @@
.testing{width:14.28571%}.testing{width:28.57143%}.testing{width:14.28571%}.testing{width:28.57143%}.testing{width:14.28571%}.testing{width:28.57143%}.testing{width:14.28571%}.testing{width:28.57143%}.l5r5e .testing{width:14.28571%}.l5r5e .testing{width:28.57143%}.l5r5e .testing{width:14.28571%}.l5r5e .testing{width:28.57143%}.l5r5e .testing{width:14.28571%}.l5r5e .testing{width:28.57143%}.l5r5e .testing{width:14.28571%}.l5r5e .testing{width:28.57143%}.l5r5e .testing{width:14.28571%}.l5r5e .testing{width:28.57143%} .testing{width:14.28571%}.testing{width:28.57143%}.testing{width:14.28571%}.testing{width:28.57143%}.testing{width:14.28571%}.testing{width:28.57143%}.l5r5e.chat-dice>img{border:1px solid transparent;background-repeat:no-repeat;background-position:center;background-size:100%;height:40px;width:40px;outline:none;margin:0;flex:0 0 20px;display:inline-block}.l5r5e .testing{width:14.28571%}.l5r5e .testing{width:28.57143%}.l5r5e .testing{width:14.28571%}.l5r5e .testing{width:28.57143%}.l5r5e .testing{width:14.28571%}.l5r5e .testing{width:28.57143%}.l5r5e .testing{width:14.28571%}.l5r5e .testing{width:28.57143%}.l5r5e .testing{width:14.28571%}.l5r5e .testing{width:28.57143%}

View File

@@ -1,9 +1,19 @@
//SCSS //SCSS
// l5re5.scss // dices.scss
.testing {
width: percentage(1/7); // Dice in chat
.l5r5e.chat-dice > img {
border: 1px solid transparent;
background-repeat: no-repeat;
background-position: center;
background-size: 100%;
height: 40px;
width: 40px;
//cursor: pointer;
//-webkit-appearance: none;
//appearance: none;
outline: none;
margin: 0;
flex: 0 0 20px;
display: inline-block;
} }
// test
.testing {
width: percentage(2/7);
}

View File

@@ -0,0 +1,62 @@
<div class="l5r5e dice-roll">
{{#if isPublicRoll }}
<div class="l5r5e dice-formula">{{formula}}</div>
{{#if l5r5e.stance}}
<div class="l5r5e dice-stance">
{{l5r5e.skillId}} ({{l5r5e.stance}})
</div>
{{/if}}
<div class="l5r5e dice-result">
{{#if l5r5e.dicesTypes.l5r}}
<div class="l5r5e item-display dices-l5r">
{{#each l5r5e.dices}}
{{#if this.diceTypeL5r}}
{{#each this.rolls}}
<span class="l5r5e chat-dice">{{{this.result}}}</span>
{{/each}}
{{/if}}
{{/each}}
{{#l5r5e.summary}}
<ul>
<li>Successes: {{this.success_total}}</li>
{{#if opportunity}}
<li>Opportunities: {{this.opportunity}}</li>
{{/if}}
{{#if strife}}
<li>Strife: {{this.strife}}</li>
{{/if}}
{{#if difficulty}}
<li>Difficulty: {{this.difficulty}}</li>
{{/if}}
</ul>
{{/l5r5e.summary}}
</div>
{{/if}}
{{#if l5r5e.dicesTypes.std}}
<div class="l5r5e dices-std">
{{#each results}}
{{#each this.rolls}}
<span class="l5r5e chat-dice">{{{this.result}}}</span>
{{/each}}
{{/each}}
</div>
{{{tooltip}}}
<h4 class="l5r5e dice-total dice-total-std">{{total}}</h4>
{{/if}}
</div>
{{/if}}
</div>

View File

@@ -0,0 +1,20 @@
<div class="dice-tooltip">
{{#each parts}}
<section class="tooltip-part">
<div class="dice">
<header class="part-header flexrow">
<span class="part-formula">{{this.formula}}</span>
{{#if this.flavor}}<span class="part-flavor">{{this.flavor}}</span>{{/if}} <span class="part-total">{{this.total}}</span>
</header>
<ol class="dice-rolls">
{{#each this.rolls}}
<li class="roll {{this.classes}}">{{{this.result}}}</li>
{{/each}}
</ol>
<ol class="dice-rolls">
<li class="roll">{{{addedResults.success}}}</li>
</ol>
</div>
</section>
{{/each}}
</div>