WIP: Party sheet
							parent
							
								
									dcd2aee76e
								
							
						
					
					
						commit
						71f6c9fda3
					
				|  | @ -4,6 +4,7 @@ | |||
|   "OSE.Show": "Show", | ||||
|   "OSE.Add": "Add", | ||||
|   "OSE.Ok": "Ok", | ||||
|   "OSE.Update": "Update", | ||||
|   "OSE.Reset": "Reset", | ||||
|   "OSE.Cancel": "Cancel", | ||||
|   "OSE.Roll": "Roll", | ||||
|  | @ -11,6 +12,9 @@ | |||
|   "OSE.Failure": "Failure", | ||||
| 
 | ||||
|   "OSE.dialog.tweaks": "Tweaks", | ||||
|   "OSE.dialog.partysheet": "Party Overview", | ||||
|   "OSE.dialog.selectActors": "Select PCs", | ||||
|   "OSE.dialog.dealXP": "Deal XP", | ||||
| 
 | ||||
|   "OSE.Formula": "Formula", | ||||
|   "OSE.SitMod": "Situational Modifier", | ||||
|  | @ -137,6 +141,7 @@ | |||
|   "OSE.NPCReaction": "NPC Reaction", | ||||
|   "OSE.RetainersMax": "#Retainers", | ||||
| 
 | ||||
|   "OSE.category.saves": "Saves", | ||||
|   "OSE.category.attributes": "Attributes", | ||||
|   "OSE.category.inventory": "Inventory", | ||||
|   "OSE.category.abilities": "Abilities", | ||||
|  |  | |||
|  | @ -11,6 +11,7 @@ | |||
|   "OSE.Failure": "Fallo", | ||||
| 
 | ||||
|   "OSE.dialog.tweaks": "Ajustes", | ||||
|   "OSE.dialog.partysheet": "Party Sheet", | ||||
| 
 | ||||
|   "OSE.Formula": "Formula", | ||||
|   "OSE.SitMod": "Mod. Situational", | ||||
|  |  | |||
|  | @ -11,6 +11,7 @@ | |||
|   "OSE.Failure": "Échec", | ||||
| 
 | ||||
|   "OSE.dialog.tweaks": "Ajuster", | ||||
|   "OSE.dialog.partysheet": "Fiche de Groupe", | ||||
| 
 | ||||
|   "OSE.Formula": "Formule", | ||||
|   "OSE.SitMod": "Mod. de situation", | ||||
|  | @ -137,6 +138,7 @@ | |||
|   "OSE.NPCReaction": "Réaction", | ||||
|   "OSE.RetainersMax": "#Suivants", | ||||
| 
 | ||||
|   "OSE.category.saves": "Sauvegardes", | ||||
|   "OSE.category.attributes": "Stats", | ||||
|   "OSE.category.inventory": "Inventaire", | ||||
|   "OSE.category.abilities": "Aptitudes", | ||||
|  |  | |||
|  | @ -19,6 +19,9 @@ export class OseCombat { | |||
| 
 | ||||
|     // Set init
 | ||||
|     for (let i = 0; i < data.combatants.length; ++i) { | ||||
|       if (!data.combatants[i].actor) { | ||||
|         return; | ||||
|       } | ||||
|       if (data.combatants[i].actor.data.data.isSlow) { | ||||
|         data.combatants[i].initiative = -789; | ||||
|       } else { | ||||
|  | @ -118,6 +121,9 @@ export class OseCombat { | |||
|     }); | ||||
| 
 | ||||
|     html.find('.combat-control[data-control="reroll"]').click((ev) => { | ||||
|       if (!game.combat) { | ||||
|         return; | ||||
|       } | ||||
|       let data = {}; | ||||
|       OseCombat.rollInitiative(game.combat, data); | ||||
|       game.combat.update({ data: data }); | ||||
|  |  | |||
|  | @ -0,0 +1,119 @@ | |||
| export class OsePartySheet extends FormApplication { | ||||
|   static get defaultOptions() { | ||||
|     const options = super.defaultOptions; | ||||
|     (options.classes = ["ose", "dialog", "party-sheet"]), | ||||
|       (options.id = "party-sheet"); | ||||
|     options.template = "systems/ose/templates/apps/party-sheet.html"; | ||||
|     options.width = 700; | ||||
|     return options; | ||||
|   } | ||||
| 
 | ||||
|   /* -------------------------------------------- */ | ||||
| 
 | ||||
|   /** | ||||
|    * Add the Entity name into the window title | ||||
|    * @type {String} | ||||
|    */ | ||||
|   get title() { | ||||
|     return game.i18n.localize("OSE.dialog.partysheet"); | ||||
|   } | ||||
| 
 | ||||
|   /* -------------------------------------------- */ | ||||
| 
 | ||||
|   /** | ||||
|    * Construct and return the data object used to render the HTML template for this form application. | ||||
|    * @return {Object} | ||||
|    */ | ||||
|   getData() { | ||||
|     let data = { | ||||
|       data: this.object, | ||||
|       config: CONFIG.OSE, | ||||
|       user: game.user | ||||
|     }; | ||||
|     return data; | ||||
|   } | ||||
| 
 | ||||
|   _onDrop(event) { | ||||
|     event.preventDefault(); | ||||
| 
 | ||||
|     console.log("DROPPING"); | ||||
|     let data; | ||||
|     try { | ||||
|       data = JSON.parse(event.dataTransfer.getData("text/plain")); | ||||
|       if (data.type !== "Item") return; | ||||
|     } catch (err) { | ||||
|       return false; | ||||
|     } | ||||
|     console.log(data); | ||||
|   } | ||||
|   /* -------------------------------------------- */ | ||||
| 
 | ||||
|   _dealXP(ev) { | ||||
|     // Grab experience
 | ||||
|     const template = ` | ||||
|           <form> | ||||
|            <div class="form-group"> | ||||
|             <label>How much ?</label>  | ||||
|             <input name="total" placeholder="0" type="text"/> | ||||
|            </div> | ||||
|         </form>`; | ||||
|     let pcs = this.object.entities.filter((e) => { | ||||
|       return e.data.type == "character"; | ||||
|     }); | ||||
|     new Dialog({ | ||||
|       title: "Deal Experience", | ||||
|       content: template, | ||||
|       buttons: { | ||||
|         set: { | ||||
|           icon: '<i class="fas fa-hand"></i>', | ||||
|           label: game.i18n.localize("OSE.dialog.dealXP"), | ||||
|           callback: (html) => { | ||||
|             let toDeal = html.find('input[name="total"]').val(); | ||||
|             const value = parseFloat(toDeal) / pcs.length; | ||||
|             if (value) { | ||||
|               // Give experience
 | ||||
|               pcs.forEach((t) => { | ||||
|                 t.getExperience(Math.floor(value)); | ||||
|               }); | ||||
|             } | ||||
|           }, | ||||
|         }, | ||||
|       }, | ||||
|     }).render(true); | ||||
|   } | ||||
| 
 | ||||
|   async _selectActors(ev) { | ||||
|     const template = "/systems/ose/templates/apps/party-select.html"; | ||||
|     const templateData = { | ||||
|       actors: this.object.entities | ||||
|     } | ||||
|     const content = await renderTemplate(template, templateData); | ||||
|     new Dialog({ | ||||
|       title: "Select Party Characters", | ||||
|       content: content, | ||||
|       buttons: { | ||||
|         set: { | ||||
|           icon: '<i class="fas fa-save"></i>', | ||||
|           label: game.i18n.localize("OSE.Update"), | ||||
|           callback: (html) => { | ||||
|             let checks = html.find("input[data-action='select-actor']"); | ||||
|             checks.each(async (_, c) => { | ||||
|               let key = c.getAttribute('name'); | ||||
|               await this.object.entities[key].setFlag('ose', 'party', c.checked); | ||||
|             }); | ||||
|           }, | ||||
|         }, | ||||
|       }, | ||||
|     }).render(true); | ||||
|   } | ||||
| 
 | ||||
|   /** @override */ | ||||
|   activateListeners(html) { | ||||
|     super.activateListeners(html); | ||||
|     html | ||||
|       .find("button[data-action='select-actors']") | ||||
|       .click(this._selectActors.bind(this)); | ||||
|     html.find("button[data-action='deal-xp']").click(this._dealXP.bind(this)); | ||||
|     html.find("a.resync").click(() => this.render(true)); | ||||
|   } | ||||
| } | ||||
|  | @ -0,0 +1,17 @@ | |||
| import { OsePartySheet } from "./dialog/party-sheet.js"; | ||||
| 
 | ||||
| export const addControl = (object, html) => { | ||||
|     let control = `<a class='ose-party-sheet' title='${game.i18n.localize('OSE.dialog.partysheet')}'><i class='fas fa-users'></i></a>`; | ||||
|     html.find(".fas.fa-search").replaceWith($(control)) | ||||
|     html.find('.ose-party-sheet').click(ev => { | ||||
|         showPartySheet(object); | ||||
|     }) | ||||
| } | ||||
| 
 | ||||
| export const showPartySheet = (object) => { | ||||
|     event.preventDefault(); | ||||
|     new OsePartySheet(object, { | ||||
|       top: window.screen.height / 2, | ||||
|       left:window.screen.width / 2, | ||||
|     }).render(true); | ||||
| } | ||||
|  | @ -11,6 +11,7 @@ import { registerHelpers } from "./module/helpers.js"; | |||
| import * as chat from "./module/chat.js"; | ||||
| import * as treasure from "./module/treasure.js"; | ||||
| import * as macros from "./module/macros.js"; | ||||
| import * as party from "./module/party.js"; | ||||
| import { OseCombat } from "./module/combat.js"; | ||||
| 
 | ||||
| /* -------------------------------------------- */ | ||||
|  | @ -83,6 +84,9 @@ Hooks.once("ready", async () => { | |||
| 
 | ||||
| // License and KOFI infos
 | ||||
| Hooks.on("renderSidebarTab", async (object, html) => { | ||||
|   if (object instanceof ActorDirectory) { | ||||
|     party.addControl(object, html); | ||||
|   } | ||||
|   if (object instanceof Settings) { | ||||
|     const template = "systems/ose/templates/chat/license.html"; | ||||
|     const rendered = await renderTemplate(template); | ||||
|  |  | |||
|  | @ -5,6 +5,67 @@ | |||
|   } | ||||
| } | ||||
| 
 | ||||
| .ose.dialog.party-sheet { | ||||
|   .window-content { | ||||
|     padding: 0; | ||||
|     height: 200px; | ||||
|   } | ||||
|   .header { | ||||
|     color: whitesmoke; | ||||
|     background: $darkBackground; | ||||
|     padding: 4px 0; | ||||
|     text-align: center; | ||||
|   } | ||||
|   .actor-list { | ||||
|     margin: 0; | ||||
|     overflow: auto; | ||||
|     height: 180px; | ||||
|     list-style: none; | ||||
|     padding: 0; | ||||
|     .actor { | ||||
|       &:nth-child(even) { | ||||
|         background-color: rgba(0, 0, 0, 0.1); | ||||
|       } | ||||
|       padding: 2px; | ||||
|       font-size: 12px; | ||||
|       height: 35px; | ||||
|       text-align: center; | ||||
|       line-height: 35px; | ||||
|       .field-img { | ||||
|         flex: 0 0 32px; | ||||
|         img { | ||||
|           border: none; | ||||
|           width: 32px; | ||||
|           height: 32px; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   .field-name { | ||||
|     text-align: left; | ||||
|     text-indent: 10px; | ||||
|   } | ||||
|   .field-short { | ||||
|     flex: 0 0 45px; | ||||
|   } | ||||
|   .field-long { | ||||
|     flex: 0 0 80px; | ||||
|   } | ||||
|   .field-longer { | ||||
|     flex: 0 0 180px; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| #sidebar #actors .directory-header .header-search { | ||||
|   .ose-party-sheet { | ||||
|     width: 30px; | ||||
|     text-align: center;  | ||||
|   } | ||||
|   input { | ||||
|     width: calc(100% - 30px); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| .ose.dialog.modifiers { | ||||
|   .attribute-bonuses { | ||||
|     label { | ||||
|  |  | |||
|  | @ -0,0 +1,12 @@ | |||
| <form autocomplete="off" onsubmit="event.preventDefault();"> | ||||
|     <ol class="actor-list"> | ||||
|     {{#each actors as |actor key|}} | ||||
|         <li class="form-group actor" data-actor-id="{{actor.id}}"> | ||||
|             <label>{{actor.name}}</label> | ||||
|             <div class="form-fields"> | ||||
|                 <input type="checkbox" data-action="select-actor" name="{{key}}" data-dtype="Boolean" {{checked actor.data.flags.ose.party}}/> | ||||
|             </div> | ||||
|         </li> | ||||
|     {{/each}} | ||||
|     </ol> | ||||
| </form> | ||||
|  | @ -0,0 +1,59 @@ | |||
| <form autocomplete="off"> | ||||
|   <header class="flexrow"> | ||||
|     {{#if user.isGM}} | ||||
|     <button data-action="select-actors" type="button">{{localize  "OSE.dialog.selectActors"}}</button> | ||||
|     <button data-action="deal-xp" type="button">{{localize  "OSE.dialog.dealXP"}}</button> | ||||
|     {{/if}} | ||||
|   </header> | ||||
|   <div class="actor header flexrow"> | ||||
|     <div class="field-name"> | ||||
|       <a class="resync"><i class="fas fa-sync"></i></a>   | ||||
|     </div> | ||||
|     <div class="field-long"> | ||||
|       {{localize 'OSE.Health'}} | ||||
|     </div> | ||||
|     <div class="field-short"> | ||||
|       {{localize 'OSE.ArmorClassShort'}} | ||||
|     </div> | ||||
|     <div class="field-short"> | ||||
|       {{localize 'OSE.Thac0'}} | ||||
|     </div> | ||||
|     <div class="field-short"> | ||||
|       {{localize 'OSE.movement.encounter.short'}} | ||||
|     </div> | ||||
|     <div class="field-longer"> | ||||
|       {{localize 'OSE.category.saves'}} | ||||
|     </div> | ||||
|   </div> | ||||
|   <ol class="actor-list"> | ||||
|     {{#each data.entities as |e|}} | ||||
|     {{#if e.data.flags.ose.party}} | ||||
|     <li class="actor flexrow" data-actor-id="{{e.id}}"> | ||||
|       <div class="field-img"> | ||||
|         <img src="{{e.img}}"/> | ||||
|       </div> | ||||
|       <div class="field-name"> | ||||
|         {{e.name}} | ||||
|       </div> | ||||
|       <div class="field-long"> | ||||
|         {{e.data.data.hp.value}}/{{e.data.data.hp.max}} | ||||
|       </div> | ||||
|       <div class="field-short"> | ||||
|         {{e.data.data.ac.value}} | ||||
|       </div> | ||||
|       <div class="field-short"> | ||||
|         {{e.data.data.thac0.value}} | ||||
|       </div> | ||||
|       <div class="field-short"> | ||||
|         {{e.data.data.movement.encounter}} | ||||
|       </div> | ||||
|       <div class="field-longer flexrow"> | ||||
|         {{#each e.data.data.saves as |s i|}} | ||||
|         <span>{{lookup @root.config.saves_short i}} {{s.value}}</span> | ||||
|         {{/each}} | ||||
|       </div> | ||||
|     </li> | ||||
|     {{/if}} | ||||
|     {{/each}} | ||||
|   </ol> | ||||
| </form> | ||||
|  | @ -1,13 +0,0 @@ | |||
| <form autocomplete="off" onsubmit="event.preventDefault();"> | ||||
|     <ol class="trait-list"> | ||||
|         {{#each choices as |choice key|}} | ||||
|         <li> | ||||
|             <label class="checkbox"> | ||||
|                 <input type="checkbox" name="{{key}}" data-dtype="Boolean" {{checked choice.chosen}}> | ||||
|                 {{localize choice.label}} | ||||
|             </label> | ||||
|         </li> | ||||
|         {{/each}} | ||||
|     </ol> | ||||
|     <button type="submit" name="submit" value="1"><i class="far fa-save"></i> Update Actor</button> | ||||
| </form> | ||||
		Loading…
	
		Reference in New Issue