WIP: Treasure tables, hp rolls
							parent
							
								
									2acc9992f5
								
							
						
					
					
						commit
						e1319b6215
					
				|  | @ -222,6 +222,7 @@ async function clean() { | |||
|       "lang", | ||||
|       "templates", | ||||
|       "assets", | ||||
|       "packs", | ||||
|       "module", | ||||
|       `${name}.js`, | ||||
|       "module.json", | ||||
|  |  | |||
|  | @ -5,6 +5,8 @@ | |||
|     "OSE.Ok": "Ok", | ||||
|     "OSE.Cancel": "Cancel", | ||||
|     "OSE.Roll": "Roll", | ||||
|     "OSE.Success": "Success", | ||||
|     "OSE.Failure": "Failure", | ||||
| 
 | ||||
|     "OSE.Formula": "Formula", | ||||
|     "OSE.SitMod": "Situational Modifier", | ||||
|  | @ -20,6 +22,8 @@ | |||
|     "OSE.Experience": "Experience", | ||||
|     "OSE.ExperienceBonus": "Bonus Experience", | ||||
|     "OSE.Treasure": "Treasure type", | ||||
|     "OSE.TreasureTable": "Table", | ||||
|     "OSE.TreasureTableHint": "Drop a rollable table here to roll the monster treasure", | ||||
|     "OSE.Size": "Size", | ||||
|     "OSE.Morale": "Morale", | ||||
|     "OSE.Retainer": "Retainer", | ||||
|  |  | |||
|  | @ -125,6 +125,11 @@ export class OseActorSheet extends ActorSheet { | |||
|       actorObject.rollAttack({label: this.actor.name, type: attack}, { event: event }); | ||||
|     }); | ||||
|      | ||||
|     html.find(".hit-dice .attribute-name a").click((ev) => { | ||||
|       let actorObject = this.actor; | ||||
|       actorObject.rollHitDice({ event: event }); | ||||
|     }); | ||||
| 
 | ||||
|     super.activateListeners(html); | ||||
|   } | ||||
| 
 | ||||
|  |  | |||
|  | @ -146,11 +146,6 @@ export class OseActorSheetCharacter extends OseActorSheet { | |||
|       actorObject.rollCheck(score, { event: event }); | ||||
|     }); | ||||
| 
 | ||||
|     html.find(".hit-dice .attribute-name a").click((ev) => { | ||||
|       let actorObject = this.actor; | ||||
|       actorObject.rollHitDice({ event: event }); | ||||
|     }); | ||||
| 
 | ||||
|     html.find(".exploration .attribute-name a").click((ev) => { | ||||
|       let actorObject = this.actor; | ||||
|       let element = event.currentTarget; | ||||
|  |  | |||
|  | @ -26,22 +26,42 @@ export class OseActor extends Actor { | |||
|   /*  Socket Listeners and Handlers | ||||
|     /* -------------------------------------------- */ | ||||
|   getExperience(value, options = {}) { | ||||
|     console.log(this.data); | ||||
|     if (this.data.type != 'character') { | ||||
|     if (this.data.type != "character") { | ||||
|       return; | ||||
|     } | ||||
|     let modified = value + (this.data.data.details.xp.bonus * value) / 100; | ||||
|     console.log(modified); | ||||
|     let modified = Math.floor( | ||||
|       value + (this.data.data.details.xp.bonus * value) / 100 | ||||
|     ); | ||||
|     return this.update({ | ||||
|       "data.details.xp.value": modified + this.data.data.details.xp.value | ||||
|       "data.details.xp.value": modified + this.data.data.details.xp.value, | ||||
|     }).then(() => { | ||||
|       const speaker = ChatMessage.getSpeaker({actor: this}); | ||||
|       ChatMessage.create({content: game.i18n.format("OSE.messages.getExperience", {name: this.name, value: modified}), speaker}); | ||||
|       const speaker = ChatMessage.getSpeaker({ actor: this }); | ||||
|       ChatMessage.create({ | ||||
|         content: game.i18n.format("OSE.messages.getExperience", { | ||||
|           name: this.name, | ||||
|           value: modified, | ||||
|         }), | ||||
|         speaker, | ||||
|       }); | ||||
|     }); | ||||
|   } | ||||
|   /* -------------------------------------------- */ | ||||
|   /*  Rolls                                       */ | ||||
|   /* -------------------------------------------- */ | ||||
| 
 | ||||
|   rollHP(options = {}) { | ||||
|     let roll = new Roll(this.data.data.hp.hd).roll(); | ||||
|     console.log(roll); | ||||
|     return this.update({ | ||||
|       data: { | ||||
|         hp: { | ||||
|           max: roll.total, | ||||
|           value: roll.total, | ||||
|         }, | ||||
|       }, | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   rollSave(save, options = {}) { | ||||
|     const label = game.i18n.localize(`OSE.saves.${save}.long`); | ||||
|     const rollParts = ["1d20"]; | ||||
|  | @ -57,7 +77,7 @@ export class OseActor extends Actor { | |||
|     }; | ||||
| 
 | ||||
|     let skip = options.event && options.event.ctrlKey; | ||||
|    | ||||
| 
 | ||||
|     // Roll and return
 | ||||
|     return OseDice.Roll({ | ||||
|       event: options.event, | ||||
|  | @ -132,7 +152,7 @@ export class OseActor extends Actor { | |||
|       ...this.data, | ||||
|       ...{ | ||||
|         rollData: { | ||||
|           type: "Hit Dice" | ||||
|           type: "Hit Dice", | ||||
|         }, | ||||
|       }, | ||||
|     }; | ||||
|  | @ -186,20 +206,20 @@ export class OseActor extends Actor { | |||
|         rollData: { | ||||
|           type: "Damage", | ||||
|           stat: attData.type, | ||||
|           scores: data.scores | ||||
|           scores: data.scores, | ||||
|         }, | ||||
|       }, | ||||
|     }; | ||||
| 
 | ||||
|     let dmgParts = []; | ||||
|     if (!attData.dmg || !game.settings.get('ose', 'variableWeaponDamage')) { | ||||
|     if (!attData.dmg || !game.settings.get("ose", "variableWeaponDamage")) { | ||||
|       dmgParts.push("1d6"); | ||||
|     } else { | ||||
|       dmgParts.push(attData.dmg); | ||||
|     } | ||||
| 
 | ||||
|     // Add Str to damage
 | ||||
|     if (attData.type == 'melee') { | ||||
|     if (attData.type == "melee") { | ||||
|       dmgParts.push(data.scores.str.mod); | ||||
|     } | ||||
| 
 | ||||
|  | @ -212,7 +232,7 @@ export class OseActor extends Actor { | |||
|       speaker: ChatMessage.getSpeaker({ actor: this }), | ||||
|       flavor: `${attData.label} - ${game.i18n.localize("OSE.Damage")}`, | ||||
|       title: `${attData.label} - ${game.i18n.localize("OSE.Damage")}`, | ||||
|     }) | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   rollAttack(attData, options = {}) { | ||||
|  | @ -240,7 +260,7 @@ export class OseActor extends Actor { | |||
|         rollData: { | ||||
|           type: "Attack", | ||||
|           stat: attData.type, | ||||
|           scores: data.scores | ||||
|           scores: data.scores, | ||||
|         }, | ||||
|       }, | ||||
|     }; | ||||
|  |  | |||
|  | @ -140,6 +140,11 @@ export class OseActorSheetMonster extends OseActorSheet { | |||
|       actorObject.rollMorale({ event: event }); | ||||
|     }); | ||||
| 
 | ||||
|     html.find(".hp-roll").click((ev) => { | ||||
|       let actorObject = this.actor; | ||||
|       actorObject.rollHP({ event: event }); | ||||
|     }); | ||||
| 
 | ||||
|     // Handle default listeners last so system listeners are triggered first
 | ||||
|     super.activateListeners(html); | ||||
|   } | ||||
|  |  | |||
|  | @ -1,6 +1,10 @@ | |||
| export class OseDice { | ||||
|   static digestResult(data, roll) { | ||||
|     let details = ""; | ||||
|     let result = { | ||||
|       isSuccess: false, | ||||
|       isFailure: false, | ||||
|       target: "", | ||||
|     }; | ||||
|     // ATTACKS
 | ||||
|     let die = roll.parts[0].total; | ||||
|     if (data.rollData.type == "Attack") { | ||||
|  | @ -11,12 +15,12 @@ export class OseDice { | |||
|         } else if (data.rollData.stat == "missile") { | ||||
|           bba += data.data.thac0.mod.missile + data.rollData.scores.dex.mod; | ||||
|         } | ||||
| 
 | ||||
|         details = `<div class='roll-result roll-fail'><b>Failure</b> (${bba})</div>`; | ||||
|         result.target = bba; | ||||
|         if (die == 1) { | ||||
|           return details; | ||||
|           result.isFailure = true; | ||||
|           return result; | ||||
|         } | ||||
|         details = `<div class='roll-result'><b>Hits AC ${roll.total}</b> (${bba})</div>`; | ||||
|         result.isSuccess = true; | ||||
|       } else { | ||||
|         // B/X Historic THAC0 Calculation
 | ||||
|         let thac = data.data.thac0.value; | ||||
|  | @ -25,11 +29,12 @@ export class OseDice { | |||
|         } else if (data.rollData.stat == "missile") { | ||||
|           thac -= data.data.thac0.mod.missile + data.rollData.scores.dex.mod; | ||||
|         } | ||||
|         details = `<div class='roll-result roll-fail'><b>Failure</b> (${thac})</div>`; | ||||
|         result.target = thac; | ||||
|         if (thac - roll.total > 9) { | ||||
|           return details; | ||||
|           result.isFailure = true; | ||||
|           return result; | ||||
|         } | ||||
|         details = `<div class='roll-result'><b>Hits AC ${Math.clamped( | ||||
|         result.details = `<div class='roll-result'><b>Hits AC ${Math.clamped( | ||||
|           thac - roll.total, | ||||
|           -3, | ||||
|           9 | ||||
|  | @ -38,37 +43,41 @@ export class OseDice { | |||
|     } else if (data.rollData.type == "Above") { | ||||
|       // SAVING THROWS
 | ||||
|       let sv = data.rollData.target; | ||||
|       result.target = sv; | ||||
|       if (roll.total >= sv) { | ||||
|         details = `<div class='roll-result roll-success'><b>Success!</b> (${sv})</div>`; | ||||
|         result.isSuccess = true; | ||||
|       } else { | ||||
|         details = `<div class='roll-result roll-fail'><b>Failure</b> (${sv})</div>`; | ||||
|         result.isFailure = true; | ||||
|       } | ||||
|     } else if (data.rollData.type == "Below") { | ||||
|       // Morale
 | ||||
|       let m = data.rollData.target; | ||||
|       result.target = m; | ||||
|       if (roll.total <= m) { | ||||
|         details = `<div class='roll-result roll-success'><b>Success!</b> (${m})</div>`; | ||||
|         result.isSuccess = true; | ||||
|       } else { | ||||
|         details = `<div class='roll-result roll-fail'><b>Failure</b> (${m})</div>`; | ||||
|         result.isFailure = true; | ||||
|       } | ||||
|     } else if (data.rollData.type == "Check") { | ||||
|       // SCORE CHECKS
 | ||||
|       let sc = data.rollData.target; | ||||
|       result.target = sc; | ||||
|       if (die == 1 || (roll.total <= sc && die < 20)) { | ||||
|         details = `<div class='roll-result roll-success'><b>Success!</b> (${sc})</div>`; | ||||
|         result.isSuccess = true; | ||||
|       } else { | ||||
|         details = `<div class='roll-result roll-fail'><b>Failure</b> (${sc})</div>`; | ||||
|         result.isFailure = true; | ||||
|       } | ||||
|     } else if (data.rollData.type == "Exploration") { | ||||
|       // EXPLORATION CHECKS
 | ||||
|       let sc = data.data.exploration[data.rollData.stat]; | ||||
|       result.target = sc; | ||||
|       if (roll.total <= sc) { | ||||
|         details = `<div class='roll-result roll-success'><b>Success!</b> (${sc})</div>`; | ||||
|         result.isSuccess = true; | ||||
|       } else { | ||||
|         details = `<div class='roll-result roll-fail'><b>Failure</b> (${sc})</div>`; | ||||
|         result.isFailure = true; | ||||
|       } | ||||
|     } | ||||
|     return details; | ||||
|     return result; | ||||
|   } | ||||
| 
 | ||||
|   static async sendRoll({ | ||||
|  | @ -91,18 +100,18 @@ export class OseDice { | |||
|       flavor: flavor, | ||||
|       data: data, | ||||
|     }; | ||||
|      | ||||
| 
 | ||||
|     // Optionally include a situational bonus
 | ||||
|     if (form !== null) data["bonus"] = form.bonus.value; | ||||
|     if (data["bonus"]) parts.push(data["bonus"]); | ||||
|   | ||||
| 
 | ||||
|     const roll = new Roll(parts.join("+"), data).roll(); | ||||
| 
 | ||||
|     // Convert the roll to a chat message and return the roll
 | ||||
|     let rollMode = game.settings.get("core", "rollMode"); | ||||
|     rollMode = form ? form.rollMode.value : rollMode; | ||||
| 
 | ||||
|     templateData.details = OseDice.digestResult(data, roll); | ||||
|     templateData.result = OseDice.digestResult(data, roll); | ||||
| 
 | ||||
|     return new Promise((resolve) => { | ||||
|       roll.render().then((r) => { | ||||
|  |  | |||
|  | @ -14,14 +14,15 @@ | |||
|   .chat-details { | ||||
|     padding: 4px; | ||||
|     font-size: 13px; | ||||
|     .roll-result { | ||||
|       text-align: center; | ||||
|       &.roll-success { | ||||
|         color: #18520b; | ||||
|       } | ||||
|       &.roll-fail { | ||||
|         color: #aa0200; | ||||
|       } | ||||
|   } | ||||
|   .roll-result { | ||||
|     font-size: 13px; | ||||
|     text-align: center; | ||||
|     &.roll-success { | ||||
|       color: #18520b; | ||||
|     } | ||||
|     &.roll-fail { | ||||
|       color: #aa0200; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -20,6 +20,21 @@ | |||
|       min-width: 75px; | ||||
|     } | ||||
|   } | ||||
|   .attributes { | ||||
|     .attribute.health { | ||||
|       position: relative; | ||||
|       .attribute-name .hp-roll { | ||||
|         font-size: 12px; | ||||
|         position: absolute; | ||||
|         right: 5px; | ||||
|         top: 5px; | ||||
|         color: $colorFaint; | ||||
|         &:hover { | ||||
|           color: white; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   .attribute-group { | ||||
|     .attacks-description { | ||||
|       margin: 2px; | ||||
|  |  | |||
|  | @ -9,7 +9,15 @@ | |||
|   "author": "U~man", | ||||
|   "esmodules": ["ose.js"], | ||||
|   "styles": ["ose.css"], | ||||
|   "packs": [], | ||||
|   "packs": [ | ||||
|     { | ||||
|       "name": "OSEMacros", | ||||
|       "label": "Old School Essentials Macros", | ||||
|       "system": "ose", | ||||
|       "path": "./packs/macros.db", | ||||
|       "entity": "Macro" | ||||
|     } | ||||
|   ], | ||||
|   "languages": [ | ||||
|     { | ||||
|       "lang": "en", | ||||
|  |  | |||
|  | @ -141,7 +141,10 @@ | |||
|         "biography": "", | ||||
|         "alignment": "", | ||||
|         "xp": 0, | ||||
|         "treasure": "", | ||||
|         "treasure": { | ||||
|           "table": "", | ||||
|           "type": "" | ||||
|         }, | ||||
|         "appearing": "", | ||||
|         "morale": 0 | ||||
|       }, | ||||
|  |  | |||
|  | @ -1,15 +1,15 @@ | |||
| <section class="flexrow"> | ||||
|     <ul class="attributes flexrow"> | ||||
|         <li class="attribute health"> | ||||
|             <h4 class="attribute-name box-title" title="{{localize 'OSE.Health'}}">{{ localize "OSE.HealthShort" }}</h4> | ||||
|             <h4 class="attribute-name box-title" title="{{localize 'OSE.Health'}}">{{ localize "OSE.HealthShort" }} <a class="hp-roll"><i class="fas fa-dice"></i></a></h4> | ||||
|             <div class="attribute-value flexrow"> | ||||
|                 <input name="data.hp.value" type="text" value="{{data.hp.value}}" data-dtype="Number" placeholder="0" /> | ||||
|                 <span class="sep"> / </span> | ||||
|                 <input name="data.hp.max" type="text" value="{{data.hp.max}}" data-dtype="Number" placeholder="0" /> | ||||
|             </div> | ||||
|         </li> | ||||
|         <li class="attribute"> | ||||
|             <h4 class="attribute-name box-title" title="{{localize 'OSE.HitDice'}}">{{ localize "OSE.HitDiceShort" }} | ||||
|         <li class="attribute hit-dice"> | ||||
|             <h4 class="attribute-name box-title" title="{{localize 'OSE.HitDice'}}"><a>{{ localize "OSE.HitDiceShort" }}</a> | ||||
|             </h4> | ||||
|             <div class="attribute-value"> | ||||
|                 <input name="data.hp.hd" type="text" value="{{data.hp.hd}}" data-dtype="String" /> | ||||
|  |  | |||
|  | @ -23,13 +23,17 @@ | |||
|     {{/if}} | ||||
|   </ul> | ||||
|   <ul class="summary flexrow"> | ||||
|     <li class="flex2"> | ||||
|     <li class="flex3"> | ||||
|       <input type="text" name="data.details.xp" value="{{data.details.xp}}" /> | ||||
|       <label>{{localize 'OSE.Experience'}}</label> | ||||
|     </li> | ||||
|     <li class="flex2"> | ||||
|       <input type="text" name="data.details.treasure" value="{{data.details.treasure}}" /> | ||||
|     <li class="flex3"> | ||||
|       <input type="text" name="data.details.treasure.type" value="{{data.details.treasure.type}}" /> | ||||
|       <label>{{localize 'OSE.Treasure'}}</label> | ||||
|     </li> | ||||
|     <li title="{{localize 'OSE.TreasureTableHint'}}"> | ||||
|       <div>{{data.details.treasure.table}}</div> | ||||
|       <label>{{localize 'OSE.TreasureTable'}}</label> | ||||
|     </li> | ||||
|   </ul> | ||||
| </section> | ||||
|  | @ -1,7 +1,9 @@ | |||
| <section class="ose chat-message"> | ||||
|     <div class="ose chat-block"> | ||||
|         <h2 class="chat-title">{{title}}</h2> | ||||
|         {{#if details}}<div class="chat-details">{{{details}}}</div>{{/if}} | ||||
|         {{#if result.details}}<div class="chat-details">{{{result.details}}}</div>{{/if}} | ||||
|         {{#if result.isFailure}}<div class='roll-result roll-fail'><b>{{localize 'OSE.Failure'}}</b> ({{result.target}})</div>{{/if}} | ||||
|         {{#if result.isSuccess}}<div class='roll-result roll-success'><b>{{localize 'OSE.Success'}}</b> ({{result.target}})</div>{{/if}} | ||||
|         {{#if rollOSE}}<div>{{{rollOSE}}}</div>{{/if}} | ||||
|     </div> | ||||
| </section> | ||||
		Loading…
	
		Reference in New Issue