WIP: Attack rolls rework
							parent
							
								
									f31bc3e790
								
							
						
					
					
						commit
						58cbeb95a9
					
				|  | @ -1,5 +1,5 @@ | |||
| { | ||||
|   "dataPath": "C:\\Users\\oreo\\AppData\\Local\\FoundryVTT", | ||||
|   "dataPath": "/home/oreo/.local/share/FoundryVTT", | ||||
|   "manifest": "src", | ||||
|   "repository": "https://gitlab.com/mesfoliesludiques/foundryvtt-ose", | ||||
|   "rawURL": "https://gitlab.com/mesfoliesludiques/foundryvtt-ose/-/raw" | ||||
|  |  | |||
|  | @ -28,7 +28,7 @@ | |||
|   "OSE.RollExample": "e.g. +1d4", | ||||
| 
 | ||||
|   "OSE.roll.formula": "{label} roll", | ||||
|   "OSE.roll.appearing": "Appearing roll", | ||||
|   "OSE.roll.appearing": "Appearing roll ({type})", | ||||
|   "OSE.roll.morale": "Morale check", | ||||
|   "OSE.roll.hd": "Hit Dice roll", | ||||
|   "OSE.roll.attacksWith": "Attacks with {name}", | ||||
|  |  | |||
|  | @ -24,8 +24,8 @@ export class OseActorSheet extends ActorSheet { | |||
| 
 | ||||
|   _createEditor(target, editorOptions, initialContent) { | ||||
|     // remove some controls to the editor as the space is lacking
 | ||||
|     if (target == 'data.details.description') { | ||||
|       editorOptions.toolbar = 'styleselect bullist hr table removeFormat save'; | ||||
|     if (target == "data.details.description") { | ||||
|       editorOptions.toolbar = "styleselect bullist hr table removeFormat save"; | ||||
|     } | ||||
|     super._createEditor(target, editorOptions, initialContent); | ||||
|   } | ||||
|  | @ -83,7 +83,9 @@ export class OseActorSheet extends ActorSheet { | |||
|       summary.slideUp(200, () => summary.remove()); | ||||
|     } else { | ||||
|       // Add item tags
 | ||||
|       let div = $(`<div class="item-summary"><ol class="tag-list">${item.getTags()}</ol><div>${description}</div></div>`); | ||||
|       let div = $( | ||||
|         `<div class="item-summary"><ol class="tag-list">${item.getTags()}</ol><div>${description}</div></div>` | ||||
|       ); | ||||
|       li.parents(".item-entry").append(div.hide()); | ||||
|       div.slideDown(200); | ||||
|     } | ||||
|  | @ -104,7 +106,9 @@ export class OseActorSheet extends ActorSheet { | |||
|   } | ||||
| 
 | ||||
|   async _resetSpells(event) { | ||||
|     let spells = $(event.currentTarget).closest(".inventory.spells").find(".item"); | ||||
|     let spells = $(event.currentTarget) | ||||
|       .closest(".inventory.spells") | ||||
|       .find(".item"); | ||||
|     spells.each((_, el) => { | ||||
|       let itemId = el.dataset.itemId; | ||||
|       const item = this.actor.getOwnedItem(itemId); | ||||
|  | @ -131,7 +135,7 @@ export class OseActorSheet extends ActorSheet { | |||
|     html.find(".item .item-controls .item-show").click(async (ev) => { | ||||
|       const li = $(ev.currentTarget).parents(".item"); | ||||
|       const item = this.actor.getOwnedItem(li.data("itemId")); | ||||
|       item.roll({ skipDialog: event.ctrlKey }); | ||||
|       item.show(); | ||||
|     }); | ||||
| 
 | ||||
|     html.find(".item .item-rollable .item-image").click(async (ev) => { | ||||
|  | @ -143,11 +147,11 @@ export class OseActorSheet extends ActorSheet { | |||
|             data: { counter: { value: item.data.data.counter.value - 1 } }, | ||||
|           }); | ||||
|         } | ||||
|         item.rollWeapon({ event: ev }); | ||||
|         item.rollWeapon({ skipDialog: ev.ctrlKey }); | ||||
|       } else if (item.type == "spell") { | ||||
|         item.spendSpell(); | ||||
|         item.spendSpell({ skipDialog: ev.ctrlKey }); | ||||
|       } else { | ||||
|         item.rollFormula({ event: ev }); | ||||
|         item.rollFormula({ skipDialog: ev.ctrlKey }); | ||||
|       } | ||||
|     }); | ||||
| 
 | ||||
|  | @ -208,12 +212,14 @@ export class OseActorSheet extends ActorSheet { | |||
|     // Resize editors
 | ||||
|     let editors = html.find(".editor"); | ||||
|     editors.each((id, editor) => { | ||||
|       let container = editor.closest('.resizable-editor'); | ||||
|       let container = editor.closest(".resizable-editor"); | ||||
|       if (container) { | ||||
|         let heightDelta = this.position.height - this.options.height; | ||||
|         editor.style.height =  `${heightDelta + parseInt(container.dataset.editorSize)}px`; | ||||
|         editor.style.height = `${ | ||||
|           heightDelta + parseInt(container.dataset.editorSize) | ||||
|         }px`;
 | ||||
|       } | ||||
|     }) | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   _onConfigureActor(event) { | ||||
|  |  | |||
|  | @ -118,14 +118,12 @@ export class OseActor extends Actor { | |||
|     const rollParts = ["1d20"]; | ||||
| 
 | ||||
|     const data = { | ||||
|       ...this.data, | ||||
|       ...{ | ||||
|         rollData: { | ||||
|       actor: this.data, | ||||
|       roll: { | ||||
|         type: "above", | ||||
|         target: this.data.data.saves[save].value, | ||||
|       }, | ||||
|       details: game.i18n.format("OSE.roll.details.save", { save: label }), | ||||
|         }, | ||||
|       }, | ||||
|     }; | ||||
| 
 | ||||
|     let skip = options.event && options.event.ctrlKey; | ||||
|  | @ -146,13 +144,10 @@ export class OseActor extends Actor { | |||
|     const rollParts = ["2d6"]; | ||||
| 
 | ||||
|     const data = { | ||||
|       ...this.data, | ||||
|       ...{ | ||||
|         rollData: { | ||||
|       roll: { | ||||
|         type: "below", | ||||
|         target: this.data.data.details.morale, | ||||
|       }, | ||||
|       }, | ||||
|     }; | ||||
| 
 | ||||
|     // Roll and return
 | ||||
|  | @ -172,13 +167,10 @@ export class OseActor extends Actor { | |||
|     const rollParts = ["2d6"]; | ||||
| 
 | ||||
|     const data = { | ||||
|       ...this.data, | ||||
|       ...{ | ||||
|         rollData: { | ||||
|       roll: { | ||||
|         type: "below", | ||||
|         target: this.data.data.retainer.loyalty, | ||||
|       }, | ||||
|       }, | ||||
|     }; | ||||
| 
 | ||||
|     // Roll and return
 | ||||
|  | @ -197,9 +189,7 @@ export class OseActor extends Actor { | |||
|     const rollParts = ["2d6"]; | ||||
| 
 | ||||
|     const data = { | ||||
|       ...this.data, | ||||
|       ...{ | ||||
|         rollData: { | ||||
|       roll: { | ||||
|         type: "table", | ||||
|         table: { | ||||
|           2: game.i18n.format("OSE.reaction.Hostile", { | ||||
|  | @ -219,7 +209,6 @@ export class OseActor extends Actor { | |||
|           }), | ||||
|         }, | ||||
|       }, | ||||
|       }, | ||||
|     }; | ||||
| 
 | ||||
|     let skip = options.event && options.event.ctrlKey; | ||||
|  | @ -241,16 +230,14 @@ export class OseActor extends Actor { | |||
|     const rollParts = ["1d20"]; | ||||
| 
 | ||||
|     const data = { | ||||
|       ...this.data, | ||||
|       ...{ | ||||
|         rollData: { | ||||
|       roll: { | ||||
|         type: "check", | ||||
|         target: this.data.data.scores[score].value, | ||||
|       }, | ||||
| 
 | ||||
|       details: game.i18n.format("OSE.roll.details.attribute", { | ||||
|         score: label, | ||||
|       }), | ||||
|         }, | ||||
|       }, | ||||
|     }; | ||||
| 
 | ||||
|     let skip = options.event && options.event.ctrlKey; | ||||
|  | @ -275,12 +262,9 @@ export class OseActor extends Actor { | |||
|     } | ||||
| 
 | ||||
|     const data = { | ||||
|       ...this.data, | ||||
|       ...{ | ||||
|         rollData: { | ||||
|       roll: { | ||||
|         type: "hitdice", | ||||
|       }, | ||||
|       }, | ||||
|     }; | ||||
| 
 | ||||
|     // Roll and return
 | ||||
|  | @ -306,9 +290,8 @@ export class OseActor extends Actor { | |||
|       label = "(1)"; | ||||
|     } | ||||
|     const data = { | ||||
|       ...this.data, | ||||
|       ...{ | ||||
|         rollData: { | ||||
|       roll: { | ||||
|         type: { | ||||
|           type: "appearing", | ||||
|         }, | ||||
|       }, | ||||
|  | @ -321,8 +304,8 @@ export class OseActor extends Actor { | |||
|       data: data, | ||||
|       skipDialog: true, | ||||
|       speaker: ChatMessage.getSpeaker({ actor: this }), | ||||
|       flavor: game.i18n.localize("OSE.roll.appearing"), | ||||
|       title: game.i18n.localize("OSE.roll.appearing"), | ||||
|       flavor: game.i18n.format("OSE.roll.appearing", { type: label }), | ||||
|       title: game.i18n.format("OSE.roll.appearing", { type: label }), | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|  | @ -331,16 +314,13 @@ export class OseActor extends Actor { | |||
|     const rollParts = ["1d6"]; | ||||
| 
 | ||||
|     const data = { | ||||
|       ...this.data, | ||||
|       ...{ | ||||
|         rollData: { | ||||
|       roll: { | ||||
|         type: "below", | ||||
|         target: this.data.data.exploration[expl], | ||||
|       }, | ||||
|       details: game.i18n.format("OSE.roll.details.exploration", { | ||||
|         expl: label, | ||||
|       }), | ||||
|         }, | ||||
|       }, | ||||
|     }; | ||||
| 
 | ||||
|     let skip = options.event && options.event.ctrlKey; | ||||
|  | @ -361,25 +341,22 @@ export class OseActor extends Actor { | |||
|     const data = this.data.data; | ||||
| 
 | ||||
|     const rollData = { | ||||
|       ...this.data, | ||||
|       ...{ | ||||
|         rollData: { | ||||
|       actor: this.data, | ||||
|       item: attData.item, | ||||
|       roll: { | ||||
|         type: "damage", | ||||
|           stat: attData.type, | ||||
|           scores: data.scores, | ||||
|         }, | ||||
|       }, | ||||
|     }; | ||||
| 
 | ||||
|     let dmgParts = []; | ||||
|     if (!attData.dmg) { | ||||
|     if (!attData.roll.dmg) { | ||||
|       dmgParts.push("1d6"); | ||||
|     } else { | ||||
|       dmgParts.push(attData.dmg); | ||||
|       dmgParts.push(attData.roll.dmg); | ||||
|     } | ||||
| 
 | ||||
|     // Add Str to damage
 | ||||
|     if (attData.type == "melee") { | ||||
|     if (attData.roll.type == "melee") { | ||||
|       dmgParts.push(data.scores.str.mod); | ||||
|     } | ||||
| 
 | ||||
|  | @ -396,15 +373,20 @@ export class OseActor extends Actor { | |||
|   } | ||||
| 
 | ||||
|   rollAttack(attData, options = {}) { | ||||
|     console.log("ACTOR", attData); | ||||
|     const data = this.data.data; | ||||
|     const rollParts = ["1d20"]; | ||||
|     const dmgParts = []; | ||||
|     let label = game.i18n.format("OSE.roll.attacks", { name: this.data.name }); | ||||
|     if (!attData.dmg) { | ||||
|     let label = game.i18n.format("OSE.roll.attacks", { | ||||
|       name: this.data.name, | ||||
|     }); | ||||
|     if (!attData.item) { | ||||
|       dmgParts.push("1d6"); | ||||
|     } else { | ||||
|       label = game.i18n.format("OSE.roll.attacksWith", { name: attData.label }); | ||||
|       dmgParts.push(attData.dmg); | ||||
|       label = game.i18n.format("OSE.roll.attacksWith", { | ||||
|         name: attData.item.name, | ||||
|       }); | ||||
|       dmgParts.push(attData.item.data.damage); | ||||
|     } | ||||
| 
 | ||||
|     let ascending = game.settings.get("ose", "ascendingAC"); | ||||
|  | @ -422,27 +404,23 @@ export class OseActor extends Actor { | |||
|         data.thac0.mod.melee.toString() | ||||
|       ); | ||||
|     } | ||||
|     if (attData.bonus) { | ||||
|       rollParts.push(attData.bonus); | ||||
|     if (attData.item && attData.item.data.bonus) { | ||||
|       rollParts.push(attData.item.data.bonus); | ||||
|     } | ||||
|     let thac0 = data.thac0.value; | ||||
|     if (attData.type == "melee") { | ||||
|       dmgParts.push(data.scores.str.mod); | ||||
|     } | ||||
| 
 | ||||
|     const rollData = { | ||||
|       ...this.data, | ||||
|       ...{ | ||||
|         rollData: { | ||||
|           type: "attack", | ||||
|       actor: this.data, | ||||
|       item: attData.item, | ||||
|       roll: { | ||||
|         type: attData.type, | ||||
|         thac0: thac0, | ||||
|           save: attData.save, | ||||
|           weapon: { | ||||
|             parts: dmgParts, | ||||
|           }, | ||||
|         }, | ||||
|         dmg: dmgParts, | ||||
|       }, | ||||
|     }; | ||||
| 
 | ||||
|     let skip = options.event && options.event.ctrlKey; | ||||
| 
 | ||||
|     // Roll and return
 | ||||
|  |  | |||
|  | @ -3,35 +3,35 @@ export class OseDice { | |||
|     let result = { | ||||
|       isSuccess: false, | ||||
|       isFailure: false, | ||||
|       target: data.rollData.target, | ||||
|       target: data.roll.target, | ||||
|       total: roll.total, | ||||
|     }; | ||||
| 
 | ||||
|     let die = roll.parts[0].total; | ||||
|     if (data.rollData.type == "above") { | ||||
|     if (data.roll.type == "above") { | ||||
|       // SAVING THROWS
 | ||||
|       if (roll.total >= result.target) { | ||||
|         result.isSuccess = true; | ||||
|       } else { | ||||
|         result.isFailure = true; | ||||
|       } | ||||
|     } else if (data.rollData.type == "below") { | ||||
|     } else if (data.roll.type == "below") { | ||||
|       // MORALE, EXPLORATION
 | ||||
|       if (roll.total <= result.target) { | ||||
|         result.isSuccess = true; | ||||
|       } else { | ||||
|         result.isFailure = true; | ||||
|       } | ||||
|     } else if (data.rollData.type == "check") { | ||||
|     } else if (data.roll.type == "check") { | ||||
|       // SCORE CHECKS (1s and 20s)
 | ||||
|       if (die == 1 || (roll.total <= result.target && die < 20)) { | ||||
|         result.isSuccess = true; | ||||
|       } else { | ||||
|         result.isFailure = true; | ||||
|       } | ||||
|     } else if (data.rollData.type == "table") { | ||||
|     } else if (data.roll.type == "table") { | ||||
|       // Reaction
 | ||||
|       let table = data.rollData.table; | ||||
|       let table = data.roll.table; | ||||
|       let output = ""; | ||||
|       for (let i = 0; i <= roll.total; i++) { | ||||
|         if (table[i]) { | ||||
|  | @ -65,8 +65,8 @@ export class OseDice { | |||
|     }; | ||||
| 
 | ||||
|     // Optionally include a situational bonus
 | ||||
|     if (form !== null) data["bonus"] = form.bonus.value; | ||||
|     if (data["bonus"]) parts.push(data["bonus"]); | ||||
|     // if (form !== null) data["bonus"] = form.bonus.value;
 | ||||
|     if (data.item && data.item.data.bonus) parts.push(data.item.data.bonus); | ||||
| 
 | ||||
|     const roll = new Roll(parts.join("+"), data).roll(); | ||||
| 
 | ||||
|  | @ -75,7 +75,7 @@ export class OseDice { | |||
|     rollMode = form ? form.rollMode.value : rollMode; | ||||
| 
 | ||||
|     // Force blind roll (ability formulas)
 | ||||
|     if (data.rollData.blindroll) { | ||||
|     if (data.blindroll) { | ||||
|       rollMode = "blindroll"; | ||||
|     } | ||||
| 
 | ||||
|  | @ -122,7 +122,7 @@ export class OseDice { | |||
|       target: "", | ||||
|       total: roll.total, | ||||
|     }; | ||||
|     result.target = data.rollData.thac0; | ||||
|     result.target = data.roll.thac0; | ||||
|     if (game.settings.get("ose", "ascendingAC")) { | ||||
|       result.details = game.i18n.format("OSE.messages.AttackAscendingSuccess", { | ||||
|         result: roll.total, | ||||
|  | @ -173,7 +173,7 @@ export class OseDice { | |||
|     if (data["bonus"]) parts.push(data["bonus"]); | ||||
| 
 | ||||
|     const roll = new Roll(parts.join("+"), data).roll(); | ||||
|     const dmgRoll = new Roll(data.rollData.weapon.parts.join("+"), data).roll(); | ||||
|     const dmgRoll = new Roll(data.roll.dmg.join("+"), data).roll(); | ||||
| 
 | ||||
|     // Convert the roll to a chat message and return the roll
 | ||||
|     let rollMode = game.settings.get("core", "rollMode"); | ||||
|  | @ -237,13 +237,10 @@ export class OseDice { | |||
|   static async Roll({ | ||||
|     parts = [], | ||||
|     data = {}, | ||||
|     options = {}, | ||||
|     event = null, | ||||
|     skipDialog = false, | ||||
|     speaker = null, | ||||
|     flavor = null, | ||||
|     title = null, | ||||
|     item = false, | ||||
|   } = {}) { | ||||
|     let rolled = false; | ||||
| 
 | ||||
|  | @ -263,7 +260,7 @@ export class OseDice { | |||
|       speaker: speaker, | ||||
|     }; | ||||
|     if (skipDialog) { | ||||
|       return data.rollData.type === "attack" | ||||
|       return data.roll.type === "attack" | ||||
|         ? OseDice.sendAttackRoll(rollData) | ||||
|         : OseDice.sendRoll(rollData); | ||||
|     } | ||||
|  | @ -275,8 +272,8 @@ export class OseDice { | |||
|         callback: (html) => { | ||||
|           rolled = true; | ||||
|           rollData.form = html[0].children[0]; | ||||
|           roll = | ||||
|             data.rollData.type === "attack" | ||||
|           console.log(data); | ||||
|           roll = ["melee", "missile"].includes(data.roll.type) | ||||
|             ? OseDice.sendAttackRoll(rollData) | ||||
|             : OseDice.sendRoll(rollData); | ||||
|         }, | ||||
|  |  | |||
|  | @ -67,7 +67,7 @@ export class OseItem extends Item { | |||
|   rollWeapon(options = {}) { | ||||
|     let isNPC = this.actor.data.type != "character"; | ||||
|     const data = this.data.data; | ||||
|     let type = "raw"; | ||||
|     let type = "melee"; | ||||
|     if (data.missile && data.melee && !isNPC) { | ||||
|       // Dialog
 | ||||
|       new Dialog({ | ||||
|  | @ -80,11 +80,11 @@ export class OseItem extends Item { | |||
|             callback: () => { | ||||
|               this.actor.rollAttack( | ||||
|                 { | ||||
|                   item: this.data, | ||||
|                   actor: this.actor.data, | ||||
|                   roll: { | ||||
|                     type: "melee", | ||||
|                   save: this.data.data.save, | ||||
|                   label: this.name, | ||||
|                   dmg: this.data.data.damage, | ||||
|                   bonus: data.bonus, | ||||
|                   }, | ||||
|                 }, | ||||
|                 options | ||||
|               ); | ||||
|  | @ -96,10 +96,11 @@ export class OseItem extends Item { | |||
|             callback: () => { | ||||
|               this.actor.rollAttack( | ||||
|                 { | ||||
|                   roll: { | ||||
|                     type: "missile", | ||||
|                   label: this.name, | ||||
|                   save: this.data.data.save, | ||||
|                   dmg: this.data.data.damage, | ||||
|                   }, | ||||
|                   actor: this.actor.data, | ||||
|                   item: this.data, | ||||
|                 }, | ||||
|                 options | ||||
|               ); | ||||
|  | @ -111,16 +112,14 @@ export class OseItem extends Item { | |||
|       return true; | ||||
|     } else if (data.missile && !isNPC) { | ||||
|       type = "missile"; | ||||
|     } else if (data.melee && !isNPC) { | ||||
|       type = "melee"; | ||||
|     } | ||||
|     this.actor.rollAttack( | ||||
|       { | ||||
|         roll: { | ||||
|           type: type, | ||||
|         label: this.name, | ||||
|         save: data.save, | ||||
|         dmg: data.damage, | ||||
|         bonus: data.bonus, | ||||
|         }, | ||||
|         actor: this.actor.data, | ||||
|         item: this.data, | ||||
|       }, | ||||
|       options | ||||
|     ); | ||||
|  | @ -140,14 +139,13 @@ export class OseItem extends Item { | |||
|     let type = data.rollType; | ||||
| 
 | ||||
|     const newData = { | ||||
|       ...this.data, | ||||
|       ...{ | ||||
|         rollData: { | ||||
|       actor: this.actor.data, | ||||
|       item: this.data, | ||||
|       roll: { | ||||
|         type: type, | ||||
|         target: data.rollTarget, | ||||
|         blindroll: data.blindroll, | ||||
|       }, | ||||
|       }, | ||||
|     }; | ||||
| 
 | ||||
|     // Roll and return
 | ||||
|  | @ -168,7 +166,7 @@ export class OseItem extends Item { | |||
|         cast: this.data.data.cast - 1, | ||||
|       }, | ||||
|     }).then(() => { | ||||
|       this.roll({ skipDialog: true }); | ||||
|       this.show({ skipDialog: true }); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|  | @ -270,13 +268,10 @@ export class OseItem extends Item { | |||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Roll the item to Chat, creating a chat card which contains follow up attack or damage roll options | ||||
|    * Show the item to Chat, creating a chat card which contains follow up attack or damage roll options | ||||
|    * @return {Promise} | ||||
|    */ | ||||
|   async roll({ skipDialog = false } = {}) { | ||||
|     if (this.data.type == "weapon") { | ||||
|       if (this.rollWeapon(skipDialog)) return; | ||||
|     } | ||||
|   async show() { | ||||
|     // Basic template rendering data
 | ||||
|     const token = this.actor.token; | ||||
|     const templateData = { | ||||
|  |  | |||
|  | @ -1,5 +1,4 @@ | |||
| {{log data}} | ||||
| <div class="ose chat-card item-card" data-actor-id="{{actor._id}}" data-item-id="{{item._id}}"> | ||||
| <div class="ose chat-card item-card" data-actor-id="{{actor._id}}" data-item-id="{{item._id}}" | ||||
|     {{#if tokenId}}data-token-id="{{tokenId}}"{{/if}}> | ||||
|     <div class="ose chat-block"> | ||||
|         <div class="flexrow chat-header"> | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue