Merge branch 'development'
						commit
						7801ae290c
					
				
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 9.6 KiB | 
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 4.2 KiB | 
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 10 KiB | 
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 4.6 KiB | 
|  | @ -2,6 +2,14 @@ | |||
|     "OSE.Edit": "Edit", | ||||
|     "OSE.Delete": "Delete", | ||||
|     "OSE.Add": "Add", | ||||
|     "OSE.Ok": "Ok", | ||||
|     "OSE.Cancel": "Cancel", | ||||
|     "OSE.Roll": "Roll", | ||||
| 
 | ||||
|     "OSE.Formula": "Formula", | ||||
|     "OSE.SitMod": "Situational Modifier", | ||||
|     "OSE.RollMode": "Roll Mode", | ||||
|     "OSE.RollExample": "Roll Example", | ||||
| 
 | ||||
|     "OSE.Name": "Name", | ||||
|     "OSE.Class": "Class", | ||||
|  | @ -9,11 +17,18 @@ | |||
|     "OSE.Alignment": "Alignment", | ||||
|     "OSE.Level": "Level", | ||||
|     "OSE.Experience": "Experience", | ||||
|     "OSE.ExperienceBonus": "Bonus Experience", | ||||
|     "OSE.Treasure": "Treasure type", | ||||
|     "OSE.Size": "Size", | ||||
|     "OSE.Morale": "Morale", | ||||
|     "OSE.Retainer": "Retainer", | ||||
|     "OSE.Appearing": "NA", | ||||
|     "OSE.Attack": "Attack", | ||||
| 
 | ||||
|     "OSE.Loyalty": "Loyalty Rating", | ||||
|     "OSE.LoyaltyShort": "LR", | ||||
|      | ||||
|     "OSE.AbilityCheck": "Ability Check", | ||||
|     "OSE.scores.str.long": "Strength", | ||||
|     "OSE.scores.str.short": "STR", | ||||
|     "OSE.scores.wis.long": "Wisdom", | ||||
|  | @ -27,39 +42,95 @@ | |||
|     "OSE.scores.cha.long": "Charisma", | ||||
|     "OSE.scores.cha.short": "CHA", | ||||
| 
 | ||||
|     "OSE.SavingThrow": "Save", | ||||
|     "OSE.saves.death.short": "D", | ||||
|     "OSE.saves.death.long": "Death", | ||||
|     "OSE.saves.wands.short": "W", | ||||
|     "OSE.saves.wands.long": "Wands", | ||||
|     "OSE.saves.death.long": "Death, Poison", | ||||
|     "OSE.saves.wand.short": "W", | ||||
|     "OSE.saves.wand.long": "Wand", | ||||
|     "OSE.saves.paralysis.short": "P", | ||||
|     "OSE.saves.paralysis.long": "Paralysis", | ||||
|     "OSE.saves.paralysis.long": "Paralysis, Petrify", | ||||
|     "OSE.saves.breath.short": "B", | ||||
|     "OSE.saves.breath.long": "Breath", | ||||
|     "OSE.saves.spells.short": "S", | ||||
|     "OSE.saves.spells.long": "Spells", | ||||
|     "OSE.saves.breath.long": "Dragon Breath", | ||||
|     "OSE.saves.spell.short": "S", | ||||
|     "OSE.saves.spell.long": "Rod, Staff, Spell", | ||||
| 
 | ||||
|     "OSE.Health": "Hit Points", | ||||
|     "OSE.HealthMax": "Maximum Hit Points", | ||||
|     "OSE.HealthShort": "HP", | ||||
|     "OSE.HitDice": "Hit Dice", | ||||
|     "OSE.HitDiceShort": "HD", | ||||
|     "OSE.Movement": "Movement", | ||||
|     "OSE.MovementShort": "MOV", | ||||
|     "OSE.SpecialMovement": "Special Movement", | ||||
|     "OSE.Movement": "Movement Rate", | ||||
|     "OSE.MovementEncounter": "Encounter Movement Rate", | ||||
|     "OSE.MovementEncounterShort": "ENC", | ||||
|     "OSE.MovementOverland": "Overland Movement Rate", | ||||
|     "OSE.MovementOverlandShort": "OVE", | ||||
|     "OSE.MovementShort": "MV", | ||||
|     "OSE.ArmorClass": "Armor Class", | ||||
|     "OSE.ArmorClassShort": "AC", | ||||
|     "OSE.SpellDC": "DC", | ||||
|     "OSE.AscArmorClassShort": "AAC", | ||||
|     "OSE.SpellDC": "Spell DC", | ||||
|     "OSE.SpellDCShort": "DC", | ||||
|     "OSE.Thac0": "THAC0", | ||||
|     "OSE.ABShort": "AB", | ||||
|     "OSE.AB": "Attack Bonus", | ||||
|     "OSE.MeleeShort": "MEL", | ||||
|     "OSE.Melee": "Melee", | ||||
|     "OSE.MeleeBonus": "Melee Bonus", | ||||
|     "OSE.MissileShort": "MIS", | ||||
|     "OSE.Missile": "Missile", | ||||
|     "OSE.MissileBonus": "Missile Bonus", | ||||
|     "OSE.Initiative": "Initiative", | ||||
|     "OSE.InitiativeShort": "INIT", | ||||
|     "OSE.Attacks": "Attacks Usable per Round", | ||||
|     "OSE.AttacksShort": "ATT", | ||||
|     "OSE.Spellcaster": "Spellcaster", | ||||
| 
 | ||||
|      | ||||
|     "OSE.category.attributes": "Attributes", | ||||
|     "OSE.category.inventory": "Inventory", | ||||
|     "OSE.category.abilities": "Abilities", | ||||
|     "OSE.category.spells": "Spells", | ||||
|     "OSE.category.notes": "Notes", | ||||
|      | ||||
|     "OSE.panel.abilities": "Abilities", | ||||
|     "OSE.panel.equipment": "Equipment" | ||||
|     "OSE.panel.equipment": "Equipment", | ||||
| 
 | ||||
|     "OSE.Setting.IndividualInit": "Individual Initiative", | ||||
|     "OSE.Setting.IndividualInitHint": "Initiative is rolled for each actor and modified by its DEX score", | ||||
|     "OSE.Setting.AscendingAC": "Ascending Armor Class", | ||||
|     "OSE.Setting.AscendingACHint": "The more the better", | ||||
|     "OSE.Setting.Morale": "Enable Monster Morale checks", | ||||
|     "OSE.Setting.MoraleHint": "Morale Rating is shown on monster sheets", | ||||
|     "OSE.Setting.THAC0Attacks": "Attacks with THAC0", | ||||
|     "OSE.Setting.THAC0AttacksHint": "Attacks are resolved using the THAC0 value, not compatible with AAC", | ||||
|     "OSE.Setting.VariableWeaponDamage": "Variable Weapon Damage", | ||||
|     "OSE.Setting.VariableWeaponDamageHint": "Weapons have different damage dice", | ||||
| 
 | ||||
|     "OSE.items.Equip": "Equip", | ||||
|     "OSE.items.Unequip": "Unequip", | ||||
|     "OSE.items.Misc": "Misc", | ||||
|     "OSE.items.Weapons": "Weapons", | ||||
|     "OSE.items.Armors": "Armors", | ||||
|     "OSE.items.Weight": "Wgt.", | ||||
|     "OSE.items.Qualities": "Qualities", | ||||
|     "OSE.items.Notes": "Notes", | ||||
|     "OSE.items.Cost": "Cost", | ||||
|     "OSE.items.Quantity": "Qt.", | ||||
|     "OSE.items.Roll": "Roll", | ||||
|     "OSE.items.Damage": "Damage", | ||||
|     "OSE.items.Melee": "Melee", | ||||
|     "OSE.items.Missile": "Missile", | ||||
|     "OSE.items.Slow": "Slow", | ||||
|     "OSE.items.ArmorAC": "AC", | ||||
|     "OSE.items.ArmorAAC": "AAC", | ||||
|      | ||||
|     "OSE.spells.Memorized": "Memorized", | ||||
|     "OSE.spells.Cast": "Cast", | ||||
|     "OSE.spells.Range": "Range", | ||||
|     "OSE.spells.Slots": "Slots", | ||||
|     "OSE.spells.Class": "Class", | ||||
|     "OSE.spells.Duration": "Duration", | ||||
|     "OSE.spells.Level": "Level", | ||||
| 
 | ||||
|     "OSE.abilities.Requirements": "Requirements" | ||||
| } | ||||
|  | @ -44,7 +44,6 @@ | |||
|     "OSE.HitDiceShort": "DV", | ||||
|     "OSE.Movement": "Mouvement", | ||||
|     "OSE.MovementShort": "MOUV", | ||||
|     "OSE.SpecialMovement": "Mouvement Spécial", | ||||
|     "OSE.ArmorClass": "Classe d'Armure", | ||||
|     "OSE.ArmorClassShort": "CA", | ||||
|     "OSE.SpellDC": "DF", | ||||
|  |  | |||
|  | @ -0,0 +1,178 @@ | |||
| import { OseActor } from "./entity.js"; | ||||
| import { OseEntityTweaks } from "../dialog/entity-tweaks.js"; | ||||
| 
 | ||||
| export class OseActorSheet extends ActorSheet { | ||||
|   constructor(...args) { | ||||
|     super(...args); | ||||
|   } | ||||
|   /* -------------------------------------------- */ | ||||
| 
 | ||||
|   getData() { | ||||
|     const data = super.getData(); | ||||
| 
 | ||||
|     data.config = CONFIG.OSE; | ||||
|     // Settings
 | ||||
|     data.config.ascendingAC = game.settings.get("ose", "ascendingAC"); | ||||
| 
 | ||||
|     // Prepare owned items
 | ||||
|     this._prepareItems(data); | ||||
| 
 | ||||
|     return data; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Organize and classify Owned Items for Character sheets | ||||
|    * @private | ||||
|    */ | ||||
|   _prepareItems(data) { | ||||
|     // Partition items by category
 | ||||
|     let [items, weapons, armors, abilities, spells] = data.items.reduce( | ||||
|       (arr, item) => { | ||||
|         // Classify items into types
 | ||||
|         if (item.type === "item") arr[0].push(item); | ||||
|         else if (item.type === "weapon") arr[1].push(item); | ||||
|         else if (item.type === "armor") arr[2].push(item); | ||||
|         else if (item.type === "ability") arr[3].push(item); | ||||
|         else if (item.type === "spell") arr[4].push(item); | ||||
|         return arr; | ||||
|       }, | ||||
|       [[], [], [], [], []] | ||||
|     ); | ||||
| 
 | ||||
|     // Sort spells by level
 | ||||
|     var sortedSpells = {}; | ||||
|     for (var i = 0; i < spells.length; i++) { | ||||
|       let lvl = spells[i].data.lvl; | ||||
|       if (!sortedSpells[lvl]) sortedSpells[lvl] = []; | ||||
|       sortedSpells[lvl].push(spells[i]); | ||||
|     } | ||||
|     // Assign and return
 | ||||
|     data.owned = { | ||||
|       items: items, | ||||
|       weapons: weapons, | ||||
|       armors: armors, | ||||
|     }; | ||||
|     data.abilities = abilities; | ||||
|     data.spells = sortedSpells; | ||||
|   } | ||||
| 
 | ||||
|   _onItemSummary(event) { | ||||
|     event.preventDefault(); | ||||
|     let li = $(event.currentTarget).parents(".item"), | ||||
|       item = this.actor.getOwnedItem(li.data("item-id")), | ||||
|       description = TextEditor.enrichHTML(item.data.data.description); | ||||
|     // Toggle summary
 | ||||
|     if (li.hasClass("expanded")) { | ||||
|       let summary = li.parents(".item-entry").children(".item-summary"); | ||||
|       summary.slideUp(200, () => summary.remove()); | ||||
|     } else { | ||||
|       let div = $(`<div class="item-summary">${description}</div>`); | ||||
|       li.parents(".item-entry").append(div.hide()); | ||||
|       div.slideDown(200); | ||||
|     } | ||||
|     li.toggleClass("expanded"); | ||||
|   } | ||||
| 
 | ||||
|    | ||||
|   activateListeners(html) { | ||||
|     // Item summaries
 | ||||
|     html | ||||
|       .find(".item .item-name h4") | ||||
|       .click((event) => this._onItemSummary(event)); | ||||
| 
 | ||||
|     html.find(".saving-throw .attribute-name a").click((ev) => { | ||||
|       let actorObject = this.actor; | ||||
|       let element = event.currentTarget; | ||||
|       let save = element.parentElement.parentElement.dataset.save; | ||||
|       actorObject.rollSave(save, { event: event }); | ||||
|     }); | ||||
| 
 | ||||
|     //Toggle Spells
 | ||||
|     html.find(".item-cast").click(async (ev) => { | ||||
|       const li = $(ev.currentTarget).parents(".item"); | ||||
|       const item = this.actor.getOwnedItem(li.data("itemId")); | ||||
|       await this.actor.updateOwnedItem({ | ||||
|         _id: li.data("itemId"), | ||||
|         data: { | ||||
|           cast: !item.data.data.cast, | ||||
|         }, | ||||
|       }); | ||||
|     }); | ||||
|     //Toggle Equipment
 | ||||
|     html.find(".item-memorize").click(async (ev) => { | ||||
|       const li = $(ev.currentTarget).parents(".item"); | ||||
|       const item = this.actor.getOwnedItem(li.data("itemId")); | ||||
|       await this.actor.updateOwnedItem({ | ||||
|         _id: li.data("itemId"), | ||||
|         data: { | ||||
|           memorized: !item.data.data.memorized, | ||||
|         }, | ||||
|       }); | ||||
|     }); | ||||
| 
 | ||||
|     html.find(".item-image").click(async (ev) => { | ||||
|       const li = $(ev.currentTarget).parents(".item"); | ||||
|       const item = this.actor.getOwnedItem(li.data("itemId")); | ||||
|       item.roll(); | ||||
|     }); | ||||
| 
 | ||||
|     super.activateListeners(html); | ||||
|   } | ||||
| 
 | ||||
|   // Override to set resizable initial size
 | ||||
|   async _renderInner(...args) { | ||||
|     const html = await super._renderInner(...args); | ||||
|     this.form = html[0]; | ||||
| 
 | ||||
|     // Resize resizable classes
 | ||||
|     let resizable = html.find(".resizable"); | ||||
|     if (resizable.length == 0) { | ||||
|       return; | ||||
|     } | ||||
|     resizable.each((_, el) => { | ||||
|       let heightDelta = this.position.height - this.options.height; | ||||
|       el.style.height = `${heightDelta + parseInt(el.dataset.baseSize)}px`; | ||||
|     }); | ||||
|     return html; | ||||
|   } | ||||
| 
 | ||||
|   async _onResize(event) { | ||||
|     super._onResize(event); | ||||
|     let html = $(event.path); | ||||
|     let resizable = html.find(".resizable"); | ||||
|     resizable.each((_, el) => { | ||||
|       let heightDelta = this.position.height - this.options.height; | ||||
|       el.style.height = `${heightDelta + parseInt(el.dataset.baseSize)}px`; | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   _onConfigureActor(event) { | ||||
|     event.preventDefault(); | ||||
|     new OseEntityTweaks(this.actor, { | ||||
|       top: this.position.top + 40, | ||||
|       left: this.position.left + (this.position.width - 400) / 2, | ||||
|     }).render(true); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Extend and override the sheet header buttons | ||||
|    * @override | ||||
|    */ | ||||
|   _getHeaderButtons() { | ||||
|     let buttons = super._getHeaderButtons(); | ||||
| 
 | ||||
|     // Token Configuration
 | ||||
|     const canConfigure = game.user.isGM || this.actor.owner; | ||||
|     if (this.options.editable && canConfigure) { | ||||
|       buttons = [ | ||||
|         { | ||||
|           label: "Tweaks", | ||||
|           class: "configure-actor", | ||||
|           icon: "fas fa-dice", | ||||
|           onclick: (ev) => this._onConfigureActor(ev), | ||||
|         }, | ||||
|       ].concat(buttons); | ||||
|     } | ||||
|     return buttons; | ||||
|   } | ||||
| } | ||||
|  | @ -1,9 +1,10 @@ | |||
| import { OseActor } from "./entity.js"; | ||||
| import { OseActorSheet } from "./actor-sheet.js"; | ||||
| 
 | ||||
| /** | ||||
|  * Extend the basic ActorSheet with some very simple modifications | ||||
|  */ | ||||
| export class OseActorSheetCharacter extends ActorSheet { | ||||
| export class OseActorSheetCharacter extends OseActorSheet { | ||||
|   constructor(...args) { | ||||
|     super(...args); | ||||
|   } | ||||
|  | @ -19,7 +20,7 @@ export class OseActorSheetCharacter extends ActorSheet { | |||
|       classes: ["ose", "sheet", "actor", "character"], | ||||
|       template: "systems/ose/templates/actors/character-sheet.html", | ||||
|       width: 450, | ||||
|       height: 560, | ||||
|       height: 530, | ||||
|       resizable: true, | ||||
|       tabs: [ | ||||
|         { | ||||
|  | @ -31,81 +32,36 @@ export class OseActorSheetCharacter extends ActorSheet { | |||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   /* -------------------------------------------- */ | ||||
| 
 | ||||
|   // Override to set resizable initial size
 | ||||
|   async _renderInner(...args) { | ||||
|     const html = await super._renderInner(...args); | ||||
|     this.form = html[0]; | ||||
| 
 | ||||
|     // Resize resizable classes
 | ||||
|     let resizable = html.find('.resizable'); | ||||
|     resizable.each((_, el) => { | ||||
|       let heightDelta = this.position.height - (this.options.height); | ||||
|       el.style.height = `${heightDelta + parseInt(el.dataset.baseSize)}px`; | ||||
|     }); | ||||
|     return html; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Prepare data for rendering the Actor sheet | ||||
|    * The prepared data object contains both the actor data as well as additional sheet options | ||||
|    */ | ||||
|   getData() { | ||||
|     const data = super.getData(); | ||||
|      | ||||
|     data.config = CONFIG.OSE; | ||||
| 
 | ||||
|     for (let [a, score] of Object.entries(data.data.scores)) { | ||||
|       data.data.scores[a].label = game.i18n.localize(`OSE.scores.${a}`); | ||||
|     } | ||||
|     // Prepare owned items
 | ||||
|     this._prepareItems(data); | ||||
| 
 | ||||
|     // DEBUG
 | ||||
|     return data; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Organize and classify Owned Items for Character sheets | ||||
|    * @private | ||||
|    */ | ||||
|   _prepareItems(data) { | ||||
|     // Partition items by category
 | ||||
|     let [inventory, abilities, spells] = data.items.reduce( | ||||
|       (arr, item) => { | ||||
|         // Classify items into types
 | ||||
|         if (item.type === "item") arr[0].push(item); | ||||
|         if (item.type === "ability") arr[1].push(item); | ||||
|         else if (item.type === "spell") arr[2].push(item); | ||||
|         return arr; | ||||
|       }, | ||||
|       [[], [], [], []] | ||||
|     // Settings
 | ||||
|     data.config.variableWeaponDamage = game.settings.get( | ||||
|       "ose", | ||||
|       "variableWeaponDamage" | ||||
|     ); | ||||
|     data.config.ascendingAC = game.settings.get("ose", "ascendingAC"); | ||||
|     data.config.individualInit = game.settings.get("ose", "individualInit"); | ||||
| 
 | ||||
|     // Assign and return
 | ||||
|     data.inventory = inventory; | ||||
|     data.spells = spells; | ||||
|     data.abilities = abilities; | ||||
|     data.mods = this.actor.computeModifiers(); | ||||
|     return data; | ||||
|   } | ||||
| 
 | ||||
|   /* -------------------------------------------- */ | ||||
| 
 | ||||
|   _onItemSummary(event) { | ||||
|   async _onQtChange(event) { | ||||
|     event.preventDefault(); | ||||
|     let li = $(event.currentTarget).parents(".item"), | ||||
|         item = this.actor.getOwnedItem(li.data("item-id")), | ||||
|         description = TextEditor.enrichHTML(item.data.data.description); | ||||
|     // Toggle summary
 | ||||
|     if ( li.hasClass("expanded") ) { | ||||
|       let summary = li.parents('.item-entry').children(".item-summary"); | ||||
|       summary.slideUp(200, () => summary.remove()); | ||||
|     } else { | ||||
|       let div = $(`<div class="item-summary">${description}</div>`); | ||||
|       li.parents('.item-entry').append(div.hide()); | ||||
|       div.slideDown(200); | ||||
|     } | ||||
|     li.toggleClass("expanded"); | ||||
|     const itemId = event.currentTarget.closest(".item").dataset.itemId; | ||||
|     const item = this.actor.getOwnedItem(itemId); | ||||
|     return item.update({ "data.quantity.value": parseInt(event.target.value) }); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|  | @ -143,20 +99,38 @@ export class OseActorSheetCharacter extends ActorSheet { | |||
|       return this.actor.createOwnedItem(itemData); | ||||
|     }); | ||||
| 
 | ||||
|     // Item summaries
 | ||||
|     html.find('.item .item-name h4').click(event => this._onItemSummary(event)); | ||||
|     //Toggle Equipment
 | ||||
|     html.find(".item-toggle").click(async (ev) => { | ||||
|       const li = $(ev.currentTarget).parents(".item"); | ||||
|       const item = this.actor.getOwnedItem(li.data("itemId")); | ||||
|       await this.actor.updateOwnedItem({ | ||||
|         _id: li.data("itemId"), | ||||
|         data: { | ||||
|           equipped: !item.data.data.equipped, | ||||
|         }, | ||||
|       }); | ||||
|     }); | ||||
| 
 | ||||
|     html | ||||
|       .find(".quantity input") | ||||
|       .click((ev) => ev.target.select()) | ||||
|       .change(this._onQtChange.bind(this)); | ||||
| 
 | ||||
|     html.find(".ability-score .attribute-name a").click((ev) => { | ||||
|       let actorObject = this.actor; | ||||
|       let element = event.currentTarget; | ||||
|       let score = element.parentElement.parentElement.dataset.score; | ||||
|       actorObject.rollCheck(score, { event: event }); | ||||
|     }); | ||||
| 
 | ||||
|     html.find(".attack a").click(ev => { | ||||
|       let actorObject = this.actor; | ||||
|       let element = event.currentTarget; | ||||
|       let attack = element.parentElement.parentElement.dataset.attack; | ||||
|       actorObject.rollAttack(attack, { event: event }); | ||||
|     }) | ||||
| 
 | ||||
|     // Handle default listeners last so system listeners are triggered first
 | ||||
|     super.activateListeners(html); | ||||
|   } | ||||
| 
 | ||||
|   async _onResize(event) { | ||||
|     super._onResize(event); | ||||
|     let html = $(event.path); | ||||
|     let resizable = html.find('.resizable'); | ||||
|     resizable.each((_, el) => { | ||||
|       let heightDelta = this.position.height - (this.options.height); | ||||
|       el.style.height = `${heightDelta + parseInt(el.dataset.baseSize)}px`; | ||||
|     }); | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -1,20 +1,141 @@ | |||
| import { OseDice } from '../dice.js'; | ||||
| 
 | ||||
| export class OseActor extends Actor { | ||||
|   /** | ||||
|    * Extends data from base Actor class | ||||
|    */ | ||||
|   prepareData() { | ||||
|     super.prepareData(); | ||||
|     return this.data; | ||||
|   } | ||||
|   /* -------------------------------------------- */ | ||||
| 
 | ||||
|    /* -------------------------------------------- */ | ||||
|   /*  Socket Listeners and Handlers | ||||
|     /* -------------------------------------------- */ | ||||
| 
 | ||||
|   /** @override */ | ||||
|   async createOwnedItem(itemData, options) { | ||||
|     return super.createOwnedItem(itemData, options); | ||||
|   } | ||||
|   /* -------------------------------------------- */ | ||||
|   /*  Rolls                                       */ | ||||
|   /* -------------------------------------------- */ | ||||
|   rollSave(save, options = {}) { | ||||
|     const label = game.i18n.localize(`OSE.saves.${save}.long`); | ||||
|     const rollParts = ['1d20']; | ||||
| 
 | ||||
|     const data = {...this.data, ...{ | ||||
|       rollData : { | ||||
|         type: 'Save', | ||||
|         stat: save | ||||
|       } | ||||
|     }}; | ||||
| 
 | ||||
|     // Roll and return
 | ||||
|     return OseDice.Roll({ | ||||
|       event: options.event, | ||||
|       parts: rollParts, | ||||
|       data: data, | ||||
|       speaker: ChatMessage.getSpeaker({ actor: this }), | ||||
|       flavor: `${label} ${game.i18n.localize('OSE.SavingThrow')}`, | ||||
|       title: `${label} ${game.i18n.localize('OSE.SavingThrow')}`, | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   rollCheck(score, options = {}) { | ||||
|     const label = game.i18n.localize(`OSE.scores.${score}.long`); | ||||
|     const rollParts = ['1d20']; | ||||
| 
 | ||||
|     const data = {...this.data, ...{ | ||||
|       rollData : { | ||||
|         type: 'Check', | ||||
|         stat: score | ||||
|       } | ||||
|     }}; | ||||
| 
 | ||||
|     // Roll and return
 | ||||
|     return OseDice.Roll({ | ||||
|       event: options.event, | ||||
|       parts: rollParts, | ||||
|       data: data, | ||||
|       speaker: ChatMessage.getSpeaker({ actor: this }), | ||||
|       flavor: `${label} ${game.i18n.localize('OSE.AbilityCheck')}`, | ||||
|       title: `${label} ${game.i18n.localize('OSE.AbilityCheck')}`, | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   rollAttack(attack, options={}) { | ||||
|     const label = game.i18n.localize(`OSE.${attack}`); | ||||
|     const rollParts = ['1d20',]; | ||||
| 
 | ||||
|     const mods = this.computeModifiers(); | ||||
|     if (attack == 'Missile') { | ||||
|       rollParts.push( | ||||
|         '+', | ||||
|         mods.dex.toString(), | ||||
|         '+', | ||||
|         this.data.data.thac0.mod.missile.toString() | ||||
|       ); | ||||
|     } else if (attack == 'Melee') { | ||||
|       rollParts.push( | ||||
|         '+', | ||||
|         mods.str.toString(), | ||||
|         '+', | ||||
|         this.data.data.thac0.mod.melee.toString() | ||||
|       ); | ||||
|     } | ||||
|     if (game.settings.get('ose', 'ascendingAC')) { | ||||
|       rollParts.push('+', this.data.data.thac0.bba.toString()); | ||||
|     } | ||||
| 
 | ||||
|     const data = {...this.data, ...{ | ||||
|       rollData : { | ||||
|         type: 'Attack', | ||||
|         stat: attack, | ||||
|         mods: mods | ||||
|       } | ||||
|     }}; | ||||
| 
 | ||||
|     // Roll and return
 | ||||
|     return OseDice.Roll({ | ||||
|       event: options.event, | ||||
|       parts: rollParts, | ||||
|       data: data, | ||||
|       speaker: ChatMessage.getSpeaker({ actor: this }), | ||||
|       flavor: `${label} ${game.i18n.localize('OSE.Attack')}`, | ||||
|       title: `${label} ${game.i18n.localize('OSE.Attack')}`, | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   computeModifiers() { | ||||
|     let _valueToMod = (val) => { | ||||
|       switch (val) { | ||||
|         case 3: | ||||
|           return -3; | ||||
|         case 4: | ||||
|         case 5: | ||||
|           return -2; | ||||
|         case 6: | ||||
|         case 7: | ||||
|         case 8: | ||||
|           return -1; | ||||
|         case 9: | ||||
|         case 10: | ||||
|         case 11: | ||||
|         case 12: | ||||
|           return 0; | ||||
|         case 13: | ||||
|         case 14: | ||||
|         case 15: | ||||
|           return 1; | ||||
|         case 16: | ||||
|         case 17: | ||||
|           return 2; | ||||
|         case 18: | ||||
|           return 3; | ||||
|         default: | ||||
|           return 0; | ||||
|       } | ||||
|     }; | ||||
|     return { | ||||
|       str: _valueToMod(this.data.data.scores.str.value), | ||||
|       int: _valueToMod(this.data.data.scores.int.value), | ||||
|       dex: _valueToMod(this.data.data.scores.dex.value), | ||||
|       cha: _valueToMod(this.data.data.scores.cha.value), | ||||
|       wis: _valueToMod(this.data.data.scores.wis.value), | ||||
|       con: _valueToMod(this.data.data.scores.con.value), | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -1,9 +1,10 @@ | |||
| import { OseActor } from "./entity.js"; | ||||
| import { OseActorSheet } from "./actor-sheet.js"; | ||||
| 
 | ||||
| /** | ||||
|  * Extend the basic ActorSheet with some very simple modifications | ||||
|  */ | ||||
| export class OseActorSheetMonster extends ActorSheet { | ||||
| export class OseActorSheetMonster extends OseActorSheet { | ||||
|   constructor(...args) { | ||||
|     super(...args); | ||||
|   } | ||||
|  | @ -31,25 +32,6 @@ export class OseActorSheetMonster extends ActorSheet { | |||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   /* -------------------------------------------- */ | ||||
| 
 | ||||
|   // Override to set resizable initial size
 | ||||
|   async _renderInner(...args) { | ||||
|     const html = await super._renderInner(...args); | ||||
|     this.form = html[0]; | ||||
| 
 | ||||
|     // Resize resizable classes
 | ||||
|     let resizable = html.find('.resizable'); | ||||
|     if (resizable.length == 0) { | ||||
|       return; | ||||
|     } | ||||
|     resizable.each((_, el) => { | ||||
|       let heightDelta = this.position.height - (this.options.height); | ||||
|       el.style.height = `${heightDelta + parseInt(el.dataset.baseSize)}px`; | ||||
|     }); | ||||
|     return html; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Prepare data for rendering the Actor sheet | ||||
|    * The prepared data object contains both the actor data as well as additional sheet options | ||||
|  | @ -57,58 +39,48 @@ export class OseActorSheetMonster extends ActorSheet { | |||
|   getData() { | ||||
|     const data = super.getData(); | ||||
|      | ||||
|     data.config = CONFIG.OSE; | ||||
|     // Settings
 | ||||
|     data.config.morale = game.settings.get('ose', 'morale'); | ||||
| 
 | ||||
|     // Prepare owned items
 | ||||
|     this._prepareItems(data); | ||||
| 
 | ||||
|     // DEBUG
 | ||||
|     return data; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Organize and classify Owned Items for Character sheets | ||||
|    * @private | ||||
|    */ | ||||
|   _prepareItems(data) { | ||||
|     // Partition items by category
 | ||||
|     let [inventory, abilities, spells] = data.items.reduce( | ||||
|       (arr, item) => { | ||||
|         // Classify items into types
 | ||||
|         if (item.type === "item") arr[0].push(item); | ||||
|         if (item.type === "ability") arr[1].push(item); | ||||
|         else if (item.type === "spell") arr[2].push(item); | ||||
|         return arr; | ||||
|       }, | ||||
|       [[], [], [], []] | ||||
|     ); | ||||
| 
 | ||||
|     // Assign and return
 | ||||
|     data.inventory = inventory; | ||||
|     data.spells = spells; | ||||
|     data.abilities = abilities; | ||||
|   } | ||||
|    | ||||
| 
 | ||||
|   _onItemSummary(event) { | ||||
|     event.preventDefault(); | ||||
|     let li = $(event.currentTarget).parents(".item"), | ||||
|         item = this.actor.getOwnedItem(li.data("item-id")), | ||||
|         description = TextEditor.enrichHTML(item.data.data.description); | ||||
|     // Toggle summary
 | ||||
|     if ( li.hasClass("expanded") ) { | ||||
|       let summary = li.parents('.item-entry').children(".item-summary"); | ||||
|       summary.slideUp(200, () => summary.remove()); | ||||
|     } else { | ||||
|       let div = $(`<div class="item-summary">${description}</div>`); | ||||
|       li.parents('.item-entry').append(div.hide()); | ||||
|       div.slideDown(200); | ||||
|     } | ||||
|     li.toggleClass("expanded"); | ||||
|   } | ||||
| 
 | ||||
|   /* -------------------------------------------- */ | ||||
| 
 | ||||
|   async _chooseItemType( | ||||
|     choices = ['weapon', 'armor', 'shield', 'gear'], | ||||
|   ) { | ||||
|     let templateData = { upper: '', lower: '', types: choices }, | ||||
|       dlg = await renderTemplate( | ||||
|         'templates/sidebar/entity-create.html', | ||||
|         templateData, | ||||
|       ); | ||||
|     //Create Dialog window
 | ||||
|     return new Promise((resolve) => { | ||||
|       new Dialog({ | ||||
|         title: '', | ||||
|         content: dlg, | ||||
|         buttons: { | ||||
|           ok: { | ||||
|             label: game.i18n.localize('OSE.Ok'), | ||||
|             icon: '<i class="fas fa-check"></i>', | ||||
|             callback: (html) => { | ||||
|               resolve({ | ||||
|                 type: html.find('select[name="type"]').val(), | ||||
|                 name: html.find('input[name="name"]').val(), | ||||
|               }); | ||||
|             }, | ||||
|           }, | ||||
|           cancel: { | ||||
|             icon: '<i class="fas fa-times"></i>', | ||||
|             label: game.i18n.localize('OSE.Cancel'), | ||||
|           }, | ||||
|         }, | ||||
|         default: 'ok', | ||||
|       }).render(true); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Activate event listeners using the prepared sheet HTML | ||||
|    * @param html {HTML}   The prepared HTML object ready to be rendered into the DOM | ||||
|  | @ -135,30 +107,35 @@ export class OseActorSheetMonster extends ActorSheet { | |||
|       event.preventDefault(); | ||||
|       const header = event.currentTarget; | ||||
|       const type = header.dataset.type; | ||||
|       const itemData = { | ||||
|         name: `New ${type.capitalize()}`, | ||||
|         type: type, | ||||
|         data: duplicate(header.dataset), | ||||
|       }; | ||||
|       delete itemData.data["type"]; | ||||
|       return this.actor.createOwnedItem(itemData); | ||||
|     }); | ||||
| 
 | ||||
|     html.find(".item-name").click((event) => { | ||||
|       this._onItemSummary(event); | ||||
|       // item creation helper func
 | ||||
|       let createItem = function ( | ||||
|         type, | ||||
|         name = `New ${type.capitalize()}`, | ||||
|       ) { | ||||
|         const itemData = { | ||||
|           name: name ? name : `New ${type.capitalize()}`, | ||||
|           type: type, | ||||
|           data: duplicate(header.dataset), | ||||
|         }; | ||||
|         delete itemData.data['type']; | ||||
|         return itemData; | ||||
|       }; | ||||
|        | ||||
|       // Getting back to main logic
 | ||||
|       if (type == 'choice') { | ||||
|         const choices = header.dataset.choices.split(','); | ||||
|         this._chooseItemType(choices).then((dialogInput) => { | ||||
|           const itemData = createItem(dialogInput.type, dialogInput.name); | ||||
|           this.actor.createOwnedItem(itemData, {}); | ||||
|         }); | ||||
|         return; | ||||
|       } | ||||
|       const itemData = createItem(type); | ||||
|       return this.actor.createOwnedItem(itemData, {}); | ||||
|     }); | ||||
| 
 | ||||
|     // Handle default listeners last so system listeners are triggered first
 | ||||
|     super.activateListeners(html); | ||||
|   } | ||||
| 
 | ||||
|   async _onResize(event) { | ||||
|     super._onResize(event); | ||||
|     let html = $(event.path); | ||||
|     let resizable = html.find('.resizable'); | ||||
|     resizable.each((_, el) => { | ||||
|       let heightDelta = this.position.height - (this.options.height); | ||||
|       el.style.height = `${heightDelta + parseInt(el.dataset.baseSize)}px`; | ||||
|     }); | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -0,0 +1,58 @@ | |||
| // eslint-disable-next-line no-unused-vars
 | ||||
| import { OseActor } from '../actor/entity.js'; | ||||
| 
 | ||||
| export class OseEntityTweaks extends FormApplication { | ||||
|   static get defaultOptions() { | ||||
|     const options = super.defaultOptions; | ||||
|     options.id = 'sheet-tweaks'; | ||||
|     options.template = | ||||
|       'systems/ose/templates/actors/dialogs/tweaks-dialog.html'; | ||||
|     options.width = 380; | ||||
|     return options; | ||||
|   } | ||||
| 
 | ||||
|   /* -------------------------------------------- */ | ||||
| 
 | ||||
|   /** | ||||
|    * Add the Entity name into the window title | ||||
|    * @type {String} | ||||
|    */ | ||||
|   get title() { | ||||
|     return `${this.object.name}: OSE Tweaks`; | ||||
|   } | ||||
| 
 | ||||
|   /* -------------------------------------------- */ | ||||
| 
 | ||||
|   /** | ||||
|    * Construct and return the data object used to render the HTML template for this form application. | ||||
|    * @return {Object} | ||||
|    */ | ||||
|   getData() { | ||||
|     let data = this.object.data; | ||||
|     if (this.object.data.type === 'character') { | ||||
|       data.isCharacter = true; | ||||
|     } | ||||
|     return data; | ||||
|   } | ||||
| 
 | ||||
|   /* -------------------------------------------- */ | ||||
| 
 | ||||
|   /** @override */ | ||||
|   activateListeners(html) { | ||||
|     super.activateListeners(html); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * This method is called upon form submission after form data is validated | ||||
|    * @param event {Event}       The initial triggering submission event | ||||
|    * @param formData {Object}   The object of validated form data with which to update the object | ||||
|    * @private | ||||
|    */ | ||||
|   async _updateObject(event, formData) { | ||||
|     event.preventDefault(); | ||||
|     // Update the actor
 | ||||
|     this.object.update(formData); | ||||
|     // Re-draw the updated sheet
 | ||||
|     this.object.sheet.render(true); | ||||
|   } | ||||
| } | ||||
|  | @ -0,0 +1,170 @@ | |||
| export class OseDice { | ||||
|   static digestResult(data, roll) { | ||||
|     let details = ""; | ||||
|      | ||||
|     // ATTACKS
 | ||||
|     let die = roll.parts[0].total; | ||||
|     if (data.rollData.type == "Attack") { | ||||
|       if (game.settings.get("ose", "ascendingAC")) { | ||||
|         let bba = data.data.thac0.bba; | ||||
|         bba += | ||||
|           data.rollData.stat == "Melee" | ||||
|             ? data.data.thac0.mod.melee + data.rollData.mods.str | ||||
|             : data.data.thac0.mod.missile + data.rollData.mods.dex; | ||||
|         details = `<div class='roll-result roll-fail'><b>Failure</b> (${bba})</div>`; | ||||
|         if (die == 1) { | ||||
|           return details; | ||||
|         } | ||||
|         details = `<div class='roll-result'><b>Hits AC ${roll.total}</b> (${bba})</div>`; | ||||
|       } else { | ||||
|         // B/X Historic THAC0 Calculation
 | ||||
|         let thac = data.data.thac0.value; | ||||
|         thac -= | ||||
|           data.rollData.stat == "Melee" | ||||
|             ? data.data.thac0.mod.melee + data.rollData.mods.str | ||||
|             : data.data.thac0.mod.missile + data.rollData.mods.dex; | ||||
| 
 | ||||
|         details = `<div class='roll-result roll-fail'><b>Failure</b> (${thac})</div>`; | ||||
|         if (thac - roll.total > 9) { | ||||
|           return details; | ||||
|         } | ||||
|         details = `<div class='roll-result'><b>Hits AC ${Math.clamped(thac - roll.total,-3,9)}</b> (${thac})</div>`; | ||||
|       } | ||||
|     } else if (data.rollData.type == "Save") { | ||||
|       // SAVING THROWS
 | ||||
|       let sv = data.data.saves[data.rollData.stat].value; | ||||
|       if (roll.total >= sv) { | ||||
|         details = `<div class='roll-result roll-success'><b>Success!</b> (${sv})</div>`; | ||||
|       } else { | ||||
|         details = `<div class='roll-result roll-fail'><b>Failure</b> (${sv})</div>`; | ||||
|       } | ||||
|     } else if (data.rollData.type == "Check") { | ||||
|       // SCORE CHECKS
 | ||||
|       let sc = data.data.scores[data.rollData.stat].value; | ||||
|       if (die == 1 || (roll.total <= sc && die < 20)) { | ||||
|         details = `<div class='roll-result roll-success'><b>Success!</b> (${sc})</div>`; | ||||
|       } else { | ||||
|         details = `<div class='roll-result roll-fail'><b>Failure</b> (${sc})</div>`; | ||||
|       } | ||||
|     } | ||||
|     return details; | ||||
|   } | ||||
| 
 | ||||
|   static async sendRoll( | ||||
|     parts = [], | ||||
|     data = {}, | ||||
|     title = null, | ||||
|     flavor = null, | ||||
|     speaker = null, | ||||
|     form = null | ||||
|   ) { | ||||
|     const template = "systems/ose/templates/chat/roll-attack.html"; | ||||
| 
 | ||||
|     let chatData = { | ||||
|       user: game.user._id, | ||||
|       speaker: speaker, | ||||
|     }; | ||||
| 
 | ||||
|     let templateData = { | ||||
|       title: title, | ||||
|       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); | ||||
|     roll.render().then((r) => { | ||||
|       templateData.rollOSE = r; | ||||
|       renderTemplate(template, templateData).then((content) => { | ||||
|         chatData.content = content; | ||||
|         chatData.sound = CONFIG.sounds.dice; | ||||
|         if (game.dice3d) { | ||||
|           game.dice3d | ||||
|             .showForRoll( | ||||
|               roll, | ||||
|               game.user, | ||||
|               true, | ||||
|               chatData.whisper, | ||||
|               chatData.blind | ||||
|             ) | ||||
|             .then((displayed) => ChatMessage.create(chatData)); | ||||
|         } else { | ||||
|           ChatMessage.create(chatData); | ||||
|         } | ||||
|       }); | ||||
|     }); | ||||
| 
 | ||||
|     return roll; | ||||
|   } | ||||
| 
 | ||||
|   // eslint-disable-next-line no-unused-vars
 | ||||
|   static async Roll({ | ||||
|     parts = [], | ||||
|     data = {}, | ||||
|     options = {}, | ||||
|     event = null, | ||||
|     speaker = null, | ||||
|     flavor = null, | ||||
|     title = null, | ||||
|     item = false, | ||||
|   } = {}) { | ||||
|     let rollMode = game.settings.get("core", "rollMode"); | ||||
|     let rolled = false; | ||||
| 
 | ||||
|     const template = "systems/ose/templates/chat/roll-dialog.html"; | ||||
|     let dialogData = { | ||||
|       formula: parts.join(" "), | ||||
|       data: data, | ||||
|       rollMode: rollMode, | ||||
|       rollModes: CONFIG.Dice.rollModes, | ||||
|     }; | ||||
| 
 | ||||
|     let buttons = { | ||||
|       ok: { | ||||
|         label: game.i18n.localize("OSE.Roll"), | ||||
|         icon: '<i class="fas fa-dice-d20"></i>', | ||||
|         callback: (html) => { | ||||
|           roll = OseDice.sendRoll( | ||||
|             parts, | ||||
|             data, | ||||
|             title, | ||||
|             flavor, | ||||
|             speaker, | ||||
|             html[0].children[0] | ||||
|           ); | ||||
|         }, | ||||
|       }, | ||||
|       cancel: { | ||||
|         icon: '<i class="fas fa-times"></i>', | ||||
|         label: game.i18n.localize("OSE.Cancel"), | ||||
|       }, | ||||
|     }; | ||||
| 
 | ||||
|     if (!item) delete buttons.raise; | ||||
| 
 | ||||
|     const html = await renderTemplate(template, dialogData); | ||||
|     let roll; | ||||
| 
 | ||||
|     //Create Dialog window
 | ||||
|     return new Promise((resolve) => { | ||||
|       new Dialog({ | ||||
|         title: title, | ||||
|         content: html, | ||||
|         buttons: buttons, | ||||
|         default: "ok", | ||||
|         close: () => { | ||||
|           resolve(rolled ? roll : false); | ||||
|         }, | ||||
|       }).render(true); | ||||
|     }); | ||||
|   } | ||||
| } | ||||
|  | @ -0,0 +1,26 @@ | |||
| export const registerHelpers = async function () { | ||||
|   // Handlebars template helpers
 | ||||
|   Handlebars.registerHelper("eq", function (a, b) { | ||||
|     return a == b; | ||||
|   }); | ||||
| 
 | ||||
|   Handlebars.registerHelper("add", function (lh, rh) { | ||||
|     return parseInt(lh) + parseInt(rh); | ||||
|   }); | ||||
| 
 | ||||
|   Handlebars.registerHelper("subtract", function (lh, rh) { | ||||
|     return parseInt(rh) - parseInt(lh); | ||||
|   }); | ||||
| 
 | ||||
|   Handlebars.registerHelper("divide", function (lh, rh) { | ||||
|     return Math.floor(parseFloat(lh) / parseFloat(rh)); | ||||
|   }); | ||||
| 
 | ||||
|   Handlebars.registerHelper("mult", function (lh, rh) { | ||||
|     return parseInt(lh) * parseInt(rh); | ||||
|   }); | ||||
| 
 | ||||
|   Handlebars.registerHelper("counter", function (status, value, max) { | ||||
|     return status ? Math.clamped((100.0 * value) / max, 0, 100) : Math.clamped(100 - (100.0 * value) / max, 0, 100); | ||||
|   }); | ||||
| }; | ||||
|  | @ -12,4 +12,93 @@ export class OseItem extends Item { | |||
|   prepareData() { | ||||
|     super.prepareData(); | ||||
|   } | ||||
| 
 | ||||
|   getChatData(htmlOptions) { | ||||
|     const data = duplicate(this.data.data); | ||||
|      | ||||
|     // Rich text description
 | ||||
|     data.description = TextEditor.enrichHTML(data.description, htmlOptions); | ||||
| 
 | ||||
|     // Item properties
 | ||||
|     const props = []; | ||||
|     const labels = this.labels; | ||||
| 
 | ||||
|     if (this.data.type == "weapon") { | ||||
|       props.push(data.qualities); | ||||
|     } | ||||
|     if (this.data.type == "spell") { | ||||
|       props.push( | ||||
|         `${data.class} ${data.lvl}`, | ||||
|         data.range, | ||||
|         data.duration | ||||
|       ); | ||||
|     } | ||||
|     if (data.hasOwnProperty("equipped")) { | ||||
|       props.push(data.equipped ? "Equipped" : "Not Equipped"); | ||||
|     } | ||||
| 
 | ||||
|     // Filter properties and return
 | ||||
|     data.properties = props.filter((p) => !!p); | ||||
|     return data; | ||||
|   } | ||||
| 
 | ||||
|   rollWeapon() { | ||||
|     if (this.data.data.missile) { | ||||
|       this.actor.rollAttack('Missile'); | ||||
|       return true; | ||||
|     } else if (this.data.data.melee) { | ||||
|       this.actor.rollAttack('Melee'); | ||||
|       return true; | ||||
|     } | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Roll the item to Chat, creating a chat card which contains follow up attack or damage roll options | ||||
|    * @return {Promise} | ||||
|    */ | ||||
|   async roll({ configureDialog = true } = {}) { | ||||
|     console.log(this.data) | ||||
|     if (this.data.type == 'weapon') { | ||||
|       if (this.rollWeapon()) return; | ||||
|     } | ||||
|     // Basic template rendering data
 | ||||
|     const token = this.actor.token; | ||||
|     const templateData = { | ||||
|       actor: this.actor, | ||||
|       tokenId: token ? `${token.scene._id}.${token.id}` : null, | ||||
|       item: this.data, | ||||
|       data: this.getChatData(), | ||||
|       labels: this.labels, | ||||
|       isHealing: this.isHealing, | ||||
|       hasDamage: this.hasDamage, | ||||
|       isSpell: this.data.type === "spell", | ||||
|       hasSave: this.hasSave, | ||||
|     }; | ||||
| 
 | ||||
|     // Render the chat card template
 | ||||
|     const template = `systems/ose/templates/chat/item-card.html`; | ||||
|     const html = await renderTemplate(template, templateData); | ||||
| 
 | ||||
|     // Basic chat message data
 | ||||
|     const chatData = { | ||||
|       user: game.user._id, | ||||
|       type: CONST.CHAT_MESSAGE_TYPES.OTHER, | ||||
|       content: html, | ||||
|       speaker: { | ||||
|         actor: this.actor._id, | ||||
|         token: this.actor.token, | ||||
|         alias: this.actor.name, | ||||
|       }, | ||||
|     }; | ||||
| 
 | ||||
|     // Toggle default roll mode
 | ||||
|     let rollMode = game.settings.get("core", "rollMode"); | ||||
|     if (["gmroll", "blindroll"].includes(rollMode)) | ||||
|       chatData["whisper"] = ChatMessage.getWhisperRecipients("GM"); | ||||
|     if (rollMode === "blindroll") chatData["blind"] = true; | ||||
| 
 | ||||
|     // Create the chat message
 | ||||
|     return ChatMessage.create(chatData); | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ export const preloadHandlebarsTemplates = async function () { | |||
|         //Sheet tabs
 | ||||
|         'systems/ose/templates/actors/partials/character-header.html', | ||||
|         'systems/ose/templates/actors/partials/character-attributes-tab.html', | ||||
|         'systems/ose/templates/actors/partials/character-abilities-tab.html', | ||||
|         'systems/ose/templates/actors/partials/character-spells-tab.html', | ||||
|         'systems/ose/templates/actors/partials/character-inventory-tab.html', | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,47 @@ | |||
| export const registerSettings = function () { | ||||
|     game.settings.register('ose', 'individualInit', { | ||||
|       name: game.i18n.localize('OSE.Setting.IndividualInit'), | ||||
|       hint: game.i18n.localize('OSE.Setting.IndividualInitHint'), | ||||
|       default: false, | ||||
|       scope: 'world', | ||||
|       type: Boolean, | ||||
|       config: true | ||||
|     }); | ||||
| 
 | ||||
|     game.settings.register('ose', 'ascendingAC', { | ||||
|       name: game.i18n.localize('OSE.Setting.AscendingAC'), | ||||
|       hint: game.i18n.localize('OSE.Setting.AscendingACHint'), | ||||
|       default: false, | ||||
|       scope: 'world', | ||||
|       type: Boolean, | ||||
|       config: true | ||||
|     }); | ||||
| 
 | ||||
|     game.settings.register('ose', 'morale', { | ||||
|       name: game.i18n.localize('OSE.Setting.Morale'), | ||||
|       hint: game.i18n.localize('OSE.Setting.MoraleHint'), | ||||
|       default: false, | ||||
|       scope: 'world', | ||||
|       type: Boolean, | ||||
|       config: true | ||||
|     }); | ||||
| 
 | ||||
|     game.settings.register('ose', 'thac0Attacks', { | ||||
|       name: game.i18n.localize('OSE.Setting.THAC0Attacks'), | ||||
|       hint: game.i18n.localize('OSE.Setting.THAC0AttacksHint'), | ||||
|       default: false, | ||||
|       scope: 'world', | ||||
|       type: Boolean, | ||||
|       config: true | ||||
|     }); | ||||
| 
 | ||||
|     game.settings.register('ose', 'variableWeaponDamage', { | ||||
|       name: game.i18n.localize('OSE.Setting.VariableWeaponDamage'), | ||||
|       hint: game.i18n.localize('OSE.Setting.VariableWeaponDamageHint'), | ||||
|       default: false, | ||||
|       scope: 'world', | ||||
|       type: Boolean, | ||||
|       config: true | ||||
|     }); | ||||
| } | ||||
|    | ||||
							
								
								
									
										22
									
								
								src/ose.js
								
								
								
								
							
							
						
						
									
										22
									
								
								src/ose.js
								
								
								
								
							|  | @ -6,19 +6,8 @@ import { preloadHandlebarsTemplates } from "./module/preloadTemplates.js"; | |||
| import { OseActor } from "./module/actor/entity.js"; | ||||
| import { OseItem } from "./module/item/entity.js"; | ||||
| import { OSE } from "./module/config.js"; | ||||
| 
 | ||||
| // Handlebars template helpers
 | ||||
| Handlebars.registerHelper("eq", function (a, b) { | ||||
|   return a == b; | ||||
| }); | ||||
| 
 | ||||
| Handlebars.registerHelper("add", function (lh, rh) { | ||||
|   return parseInt(lh) + parseInt(rh); | ||||
| }); | ||||
| 
 | ||||
| Handlebars.registerHelper("subtract", function (lh, rh) { | ||||
|   return parseInt(rh) - parseInt(lh); | ||||
| }); | ||||
| import { registerSettings } from './module/settings.js'; | ||||
| import { registerHelpers } from './module/helpers.js'; | ||||
| 
 | ||||
| /* -------------------------------------------- */ | ||||
| /*  Foundry VTT Initialization                  */ | ||||
|  | @ -35,6 +24,13 @@ Hooks.once("init", async function () { | |||
|   }; | ||||
| 
 | ||||
|   CONFIG.OSE = OSE; | ||||
| 
 | ||||
|   // Custom Handlebars helpers
 | ||||
|   registerHelpers(); | ||||
|    | ||||
|   // Register custom system settings
 | ||||
|   registerSettings(); | ||||
|    | ||||
|   CONFIG.Actor.entityClass = OseActor; | ||||
|   CONFIG.Item.entityClass = OseItem; | ||||
| 
 | ||||
|  |  | |||
|  | @ -12,7 +12,7 @@ | |||
|     border: 1px solid $colorDark; | ||||
|     .panel-title { | ||||
|       color: whitesmoke; | ||||
|       background: $colorDark; | ||||
|       background: $darkBackground; | ||||
|       line-height: 14px; | ||||
|       height: 20px; | ||||
|       text-align: center; | ||||
|  | @ -32,7 +32,7 @@ | |||
|       padding: 0; | ||||
|     } | ||||
|   } | ||||
|    | ||||
| 
 | ||||
|   /* Header Summary Details */ | ||||
|   .header-details { | ||||
|     h1 { | ||||
|  | @ -74,44 +74,79 @@ | |||
|     } | ||||
|   } | ||||
|   .sheet-tabs { | ||||
|     color: whitesmoke; | ||||
|     background: $colorDark; | ||||
|     margin: 4px 0 0; | ||||
|     border: 1px solid $colorDark; | ||||
|     position: absolute; | ||||
|     transform: rotate(90deg); | ||||
|     top: 365px; | ||||
|     right: -169px; | ||||
|     width: 320px; | ||||
|     z-index: -1; | ||||
|     .item { | ||||
|       padding: 2px; | ||||
|       padding: 2px 10px 0; | ||||
|       margin-left: -5px; | ||||
|       text-indent: 4px; | ||||
|       background: url("/ui/parchment.jpg"); | ||||
|       border-top-right-radius: 4px; | ||||
|       border-top-left-radius: 80px; | ||||
|       box-shadow: 0 0 6px 1px $colorDark; | ||||
|       font-size: 12px; | ||||
|       filter: brightness(0.9); | ||||
|       &.active { | ||||
|         background: $colorTan; | ||||
|         filter: none; | ||||
|         z-index: 1; | ||||
|         font-weight: bold; | ||||
|         text-shadow: none; | ||||
|         margin-bottom: -1px; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   .sheet-body { | ||||
|     padding: 5px 0; | ||||
|     border: 1px solid $colorDark; | ||||
|     border-top: none; | ||||
|     height: calc(100% - 175px); | ||||
|     height: calc(100% - 140px); | ||||
|     .attributes { | ||||
|       margin: 0; | ||||
|       padding: 0; | ||||
|       .attribute { | ||||
|         margin: 10px; | ||||
|         position: relative; | ||||
|         margin: 8px; | ||||
|         border: 1px solid $colorTan; | ||||
|         box-shadow: 0 0 2px $colorTan; | ||||
|         .attribute-name { | ||||
|           color: whitesmoke; | ||||
|           padding: 2px; | ||||
|           margin: 0; | ||||
|           background: $colorDark; | ||||
|           border: 1px solid $colorDark; | ||||
|           background: $darkBackground; | ||||
|           text-align: center; | ||||
|         } | ||||
|         &.attribute-secondaries { | ||||
|           margin: 10px 5px; | ||||
|         } | ||||
|         &.ability-score { | ||||
|           height: 40px; | ||||
|           .attribute-value { | ||||
|             line-height: 36px; | ||||
|           } | ||||
|         } | ||||
|         .attribute-value { | ||||
|           text-align: center; | ||||
|           padding: 4px; | ||||
|           display: flex; | ||||
|           flex-direction: row; | ||||
|           .sep { | ||||
|             flex: 0 0 5px; | ||||
|             line-height: 24px; | ||||
|           } | ||||
|         } | ||||
|         .attribute-mod { | ||||
|           position: absolute; | ||||
|           color: $colorTan; | ||||
|           right: 5px; | ||||
|           top: -5px; | ||||
|           font-size: 13px; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     .attribute-group { | ||||
|       flex: 0 0 105px; | ||||
|       margin: auto 0; | ||||
|       .attributes { | ||||
|         .attribute { | ||||
|           display: flex; | ||||
|  | @ -119,64 +154,151 @@ | |||
|           .attribute-name { | ||||
|             width: 40px; | ||||
|             margin: 0; | ||||
|             line-height: 28px; | ||||
|             line-height: 35px; | ||||
|             a { | ||||
|               margin: auto; | ||||
|             } | ||||
|           } | ||||
|           &.saving-throw .attribute-name { | ||||
|             line-height: 16px; | ||||
|             width: 80px; | ||||
|           } | ||||
|           .attribute-value { | ||||
|             width: 45px; | ||||
|             flex-grow: 0; | ||||
|             input { | ||||
|               padding: 0; | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     .inventory { | ||||
|       overflow: auto; | ||||
|       .header-spells { | ||||
|         line-height: 30px; | ||||
|       } | ||||
|       .item-titles { | ||||
|         text-align: center; | ||||
|         padding: 4px; | ||||
|         border: 1px solid $colorDark; | ||||
|         box-shadow: 0 0 5px $colorDark; | ||||
|         .item-name { | ||||
|           text-align: left; | ||||
|           text-indent: 8px; | ||||
|         } | ||||
|         font-weight: 300; | ||||
|         font-size: 13px; | ||||
|         background: $darkBackground; | ||||
|         color: white; | ||||
|         input { | ||||
|           color: white; | ||||
|           margin: auto; | ||||
|         } | ||||
|       } | ||||
|       .item-list { | ||||
|         list-style: none; | ||||
|         margin: 0; | ||||
|         padding: 0; | ||||
|         & > * { | ||||
|           line-height: 30px; | ||||
|         } | ||||
|         .item-summary { | ||||
|           font-size: 13px; | ||||
|           padding: 0 4px; | ||||
|           line-height: 20px; | ||||
|         } | ||||
|         .item-header { | ||||
|           @extend %header-field !optional; | ||||
|           padding: 0px; | ||||
|           margin-bottom: 0px; | ||||
|         } | ||||
|         .item-entry { | ||||
|           &:nth-child(even) { | ||||
|             .item { | ||||
|               background: rgba(0, 0, 0, 0.1); | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|         .item { | ||||
|           line-height: 30px; | ||||
|           height: 30px; | ||||
|           overflow: hidden; | ||||
|         } | ||||
|         .item-equipped { | ||||
|           grid-area: item-equipped; | ||||
|           justify-self: center; | ||||
|         } | ||||
|         .item-name { | ||||
|           text-indent: 8px; | ||||
|           text-align: left; | ||||
|           overflow: hidden; | ||||
|           height: 30px; | ||||
|           margin: 0; | ||||
|           line-height: 30px; | ||||
|           &:hover .item-image { | ||||
|             background-image: url("/icons/svg/d20-grey.svg") !important; | ||||
|             cursor: pointer; | ||||
|           } | ||||
|           .item-image { | ||||
|             flex-basis: 30px; | ||||
|             flex-grow: 0; | ||||
|             background-size: contain; | ||||
|             background-repeat: no-repeat; | ||||
|             &:hover { | ||||
|               background-image: url("/icons/svg/d20-black.svg") !important; | ||||
|             } | ||||
|           } | ||||
|           h4 { | ||||
|             margin: 0; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|       .field-longer { | ||||
|         text-indent: 8px; | ||||
|         text-align: left; | ||||
|         flex-basis: 150px; | ||||
|         font-size: 12px; | ||||
|         flex-grow: 0; | ||||
|       } | ||||
|       .field-long { | ||||
|         flex-basis: 65px; | ||||
|         flex-grow: 0; | ||||
|         text-align: center; | ||||
|         font-size: 12px; | ||||
|       } | ||||
|       .field-short { | ||||
|         font-size: 12px; | ||||
|         flex-basis: 45px; | ||||
|         flex-grow: 0; | ||||
|         text-align: center; | ||||
|         &.quantity { | ||||
|           display: flex; | ||||
|           input { | ||||
|             margin: 3px 0; | ||||
|             border-bottom: none; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|       .item-controls { | ||||
|         font-size: 12px; | ||||
|         flex-basis: 60px; | ||||
|         flex-grow: 0; | ||||
|         text-align: right; | ||||
|         margin-right: 4px; | ||||
|         .item-unequipped { | ||||
|           color: rgba(0, 0, 0, 0.2); | ||||
|         } | ||||
|       } | ||||
|       &.spells { | ||||
|         .item-controls { | ||||
|           flex-basis: 30px; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     .editor { | ||||
|       height: 300px; | ||||
|     } | ||||
|     .inventory { | ||||
|       .item-entry { | ||||
|         padding: 0; | ||||
|         margin: 0; | ||||
|         list-style: none; | ||||
|         .item { | ||||
|           .item-image { | ||||
|             flex: 0 0 24px; | ||||
|             height: 24px; | ||||
|             background-size: cover; | ||||
|           } | ||||
|           .item-name { | ||||
|             line-height: 24px; | ||||
|             height: 24px; | ||||
|             overflow: hidden; | ||||
|             h4 { | ||||
|               text-indent: 4px; | ||||
|               margin: 0; | ||||
|               cursor: pointer; | ||||
|               &:hover { | ||||
|                 color: whitesmoke; | ||||
|                 background: linear-gradient( | ||||
|                   45deg, | ||||
|                   rgba(0, 0, 0, 0.5), | ||||
|                   transparent | ||||
|                 ); | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|           .item-controls { | ||||
|             line-height: 24px; | ||||
|             flex: 0 0 32px; | ||||
|             margin: 0 3px; | ||||
|             .fas { | ||||
|               color: $colorTan; | ||||
|               font-size: 12px; | ||||
|               &:hover { | ||||
|                 color: $colorDark; | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|         .item-summary { | ||||
|           font-size: 12px; | ||||
|           padding: 0 4px; | ||||
|         } | ||||
|         &:nth-child(odd) { | ||||
|           background: rgba(0, 0, 0, 0.1); | ||||
|         } | ||||
|       } | ||||
|       padding: 4px; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -0,0 +1,124 @@ | |||
| .ose.chat-block { | ||||
|   margin: 0; | ||||
|   .chat-title { | ||||
|     background: $darkBackground; | ||||
|     border: 1px solid black; | ||||
|     border-radius: 3px; | ||||
|     color: white; | ||||
|     padding: 2px; | ||||
|     box-shadow: 0 0 2px #FFF inset; | ||||
|     text-align: center; | ||||
|     margin: 4px 0; | ||||
|     font-size: 16px; | ||||
|   } | ||||
|   .chat-details { | ||||
|     padding: 4px; | ||||
|     font-size: 13px; | ||||
|     .roll-result { | ||||
|       text-align: center; | ||||
|       &.roll-success { | ||||
|         color: #18520b; | ||||
|       } | ||||
|       &.roll-fail { | ||||
|         color: #aa0200; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| .ose.chat-card { | ||||
|   font-style: normal; | ||||
|   font-size: 12px; | ||||
| 
 | ||||
|   .card-header { | ||||
|     padding: 3px 0; | ||||
|     border-top: 2px groove #fff; | ||||
|     border-bottom: 2px groove #fff; | ||||
| 
 | ||||
|     img { | ||||
|       flex: 0 0 36px; | ||||
|       margin-right: 5px; | ||||
|     } | ||||
| 
 | ||||
|     h3 { | ||||
|       flex: 1; | ||||
|       margin: 0; | ||||
|       line-height: 36px; | ||||
|       color: $colorOlive; | ||||
|       &:hover { | ||||
|         color: #111; | ||||
|         text-shadow: 0 0 10px red; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   .card-content { | ||||
|     margin: 5px 0; | ||||
| 
 | ||||
|     h3 { | ||||
|       font-size: 12px; | ||||
|       margin: 0; | ||||
|       font-weight: bold; | ||||
|     } | ||||
| 
 | ||||
|     > * { | ||||
|       -webkit-user-select: text; | ||||
|       -moz-user-select: text; | ||||
|       -ms-user-select: text; | ||||
|       user-select: text; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   .card-buttons { | ||||
|     margin: 5px 0; | ||||
| 
 | ||||
|     span { | ||||
|       display: block; | ||||
|       line-height: 28px; | ||||
|       text-align: center; | ||||
|       border: 1px solid $colorTan; | ||||
|     } | ||||
| 
 | ||||
|     button { | ||||
|       font-size: 12px; | ||||
|       height: 24px; | ||||
|       line-height: 20px; | ||||
|       margin: 2px 0; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   .card-footer { | ||||
|     padding: 3px 0 0; | ||||
|     border-top: 2px groove #fff; | ||||
| 
 | ||||
|     span { | ||||
|       border-right: 2px groove #fff; | ||||
|       padding: 0 5px 0 0; | ||||
|       font-size: 10px; | ||||
| 
 | ||||
|       &:last-child { | ||||
|         border-right: none; | ||||
|         padding-right: 0; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| .dice-roll .dice-total { | ||||
|   &.success { | ||||
|     color: inherit; | ||||
|     background: #c7d0c0; | ||||
|     border: 1px solid #006c00; | ||||
|   } | ||||
|   &.failure { | ||||
|     color: inherit; | ||||
|     background: #ffdddd; | ||||
|     border: 1px solid #6e0000; | ||||
|   } | ||||
|   &.critical { | ||||
|     color: green; | ||||
|   } | ||||
|   &.fumble { | ||||
|     color: red; | ||||
|   } | ||||
| } | ||||
|  | @ -5,35 +5,66 @@ | |||
| /* ----------------------------------------- */ | ||||
| .ose.sheet.actor.character { | ||||
|   min-width: 450px; | ||||
|   min-height: 590px; | ||||
|   min-height: 550px; | ||||
| 
 | ||||
|   /* ----------------------------------------- */ | ||||
|   /*  Sheet Header                             */ | ||||
|   /* ----------------------------------------- */ | ||||
| 
 | ||||
|   .sheet-header { | ||||
|     .xp-bonus { | ||||
|       top: -15px; | ||||
|       right: 3px; | ||||
|       color: $colorTan; | ||||
|       font-size: 10px; | ||||
|       position: absolute; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /* ----------------------------------------- */ | ||||
|   /*  Sheet Body                               */ | ||||
|   /* ----------------------------------------- */ | ||||
|   .sheet-body { | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
|   .abilities { | ||||
|     .panel-content { | ||||
|       height: 250px; | ||||
|       overflow: auto;   | ||||
|     .health { | ||||
|       &.armor-class { | ||||
|         background: url('/systems/ose/assets/shield.png') no-repeat center; | ||||
|         background-size: 70px; | ||||
|       } | ||||
|         margin: 10px 0; | ||||
|         height: 70px; | ||||
|         position: relative; | ||||
|         input { | ||||
|           font-size: 16px; | ||||
|           font-weight: bolder; | ||||
|           text-shadow: 0 0 2px white, 0 1px 2px white, 1px 0 2px white, 1px 1px 2px white;  | ||||
|         } | ||||
|         .health-top { | ||||
|           border-bottom: none; | ||||
|           position: absolute; | ||||
|           font-size: 24px; | ||||
|           top: 10px; | ||||
|           width: 70px; | ||||
|           left: calc(50% - 35px); | ||||
|         } | ||||
|         .health-bottom { | ||||
|           border-bottom: none; | ||||
|           position: absolute; | ||||
|           bottom: 8px; | ||||
|           width: 40px; | ||||
|           right: calc(50% + -20px); | ||||
|         } | ||||
|         .health-empty { | ||||
|           background: url('/systems/ose/assets/heart_empty.png') no-repeat center; | ||||
|           background-size: 70px; | ||||
|           background-position: top; | ||||
|         } | ||||
|         .health-full { | ||||
|           background: url('/systems/ose/assets/heart_full.png') no-repeat center; | ||||
|           background-size: 70px; | ||||
|           background-position: bottom; | ||||
|         } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /* ----------------------------------------- */ | ||||
|   /*  Inventory                                */ | ||||
|   /* ----------------------------------------- */ | ||||
|   .inventory { | ||||
| 
 | ||||
|   } | ||||
|   /* ----------------------------------------- */ | ||||
|   /*  Item Controls                            */ | ||||
|   /* ----------------------------------------- */ | ||||
|  |  | |||
|  | @ -37,4 +37,4 @@ | |||
|   .resizable { | ||||
|     overflow: auto; | ||||
|   } | ||||
| } | ||||
| } | ||||
|  | @ -1,5 +1,37 @@ | |||
| .ose.sheet.item { | ||||
|     .editor { | ||||
|         height: 255px; | ||||
|     .profile-img { | ||||
|         border: none; | ||||
|         flex: 0 0 84px; | ||||
|         height: 84px; | ||||
|     } | ||||
|     .sheet-body { | ||||
|         .stats { | ||||
|             flex: 0 0 90px; | ||||
|             border-right: 1px groove rgba(0, 0, 0, 0.2); | ||||
|             padding-right: 2px; | ||||
|             .form-group { | ||||
|                 margin: 2px; | ||||
|                 border: 1px solid rgba(0, 0, 0, 0.15); | ||||
|                 label { | ||||
|                     background: rgba(0, 0, 0, 0.1); | ||||
|                     padding: 0 4px; | ||||
|                 } | ||||
|                 input { | ||||
|                     border-bottom: none; | ||||
|                     margin: auto 0; | ||||
|                 } | ||||
|             } | ||||
|             .block-input { | ||||
|                 display: flex; | ||||
|                 flex-direction: column; | ||||
|                 text-align: center; | ||||
|             } | ||||
|         } | ||||
|         .editor { | ||||
|             height: 240px; | ||||
|         } | ||||
|         .weapon-editor .editor { | ||||
|             height: 215px; | ||||
|         } | ||||
|      } | ||||
| } | ||||
|  | @ -1,21 +1,23 @@ | |||
| .ose.actor.monster { | ||||
|     min-height: 565px; | ||||
|     min-width: 460px; | ||||
|   min-height: 565px; | ||||
|   min-width: 460px; | ||||
|   .sheet-body { | ||||
|     .editor { | ||||
|       height: 300px; | ||||
|     } | ||||
|   } | ||||
|   .abilities { | ||||
|     .panel-content { | ||||
|       height: 230px; | ||||
|       overflow: auto;   | ||||
|     .attributes .attribute.health { | ||||
|       min-width: 75px; | ||||
|     } | ||||
|   } | ||||
|   .attribute-row { | ||||
|       padding: 2px; | ||||
|       .abilities { | ||||
|           margin: 2px; | ||||
|   .attribute-group { | ||||
|     .attacks-description { | ||||
|       margin: 2px; | ||||
|       padding: 0; | ||||
|       text-align: center; | ||||
|       label { | ||||
|         color: $colorTan; | ||||
|         font-size: 10px; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -3,7 +3,8 @@ | |||
| /*  Sheet Styles                             */ | ||||
| /* ----------------------------------------- */ | ||||
| 
 | ||||
| $colorDark: #191813; | ||||
| $darkBackground: url('/systems/ose/assets/back.png'); | ||||
| $colorDark: rgba(0, 0, 0, 0.9); | ||||
| $colorFaint: #c9c7b8; | ||||
| $colorBeige: #b5b3a4; | ||||
| $colorTan: #7a7971; | ||||
|  |  | |||
|  | @ -1,7 +1,78 @@ | |||
| { | ||||
|   "Actor": { | ||||
|     "types": ["character", "monster"], | ||||
|     "templates": { | ||||
|       "common": { | ||||
|         "retainer": { | ||||
|           "enabled": false, | ||||
|           "loyalty": 0 | ||||
|         }, | ||||
|         "hp": { | ||||
|           "hd": "", | ||||
|           "value": 20, | ||||
|           "max": 20 | ||||
|         }, | ||||
|         "ac": { | ||||
|           "naked": 0, | ||||
|           "value": 0, | ||||
|           "mod": 0 | ||||
|         }, | ||||
|         "aac": { | ||||
|           "naked": 0, | ||||
|           "value": 0, | ||||
|           "mod": 0 | ||||
|         }, | ||||
|         "thac0": { | ||||
|           "value": 19, | ||||
|           "bba": 0, | ||||
|           "mod": { | ||||
|             "missile": 0, | ||||
|             "melee": 0 | ||||
|           } | ||||
|         }, | ||||
|         "saves": { | ||||
|           "death": 10, | ||||
|           "wand": 10, | ||||
|           "paralysis": 10, | ||||
|           "breath": 10, | ||||
|           "spell": 10 | ||||
|         }, | ||||
|         "movement": { | ||||
|           "base": 120 | ||||
|         }  | ||||
|       }, | ||||
|       "spellcaster": { | ||||
|         "spells": { | ||||
|           "enabled": false, | ||||
|           "1": { | ||||
|             "value": 0, | ||||
|             "max": 0 | ||||
|           }, | ||||
|           "2": { | ||||
|             "value": 0, | ||||
|             "max": 0 | ||||
|           }, | ||||
|           "3": { | ||||
|             "value": 0, | ||||
|             "max": 0 | ||||
|           }, | ||||
|           "4": { | ||||
|             "value": 0, | ||||
|             "max": 0 | ||||
|           }, | ||||
|           "5": { | ||||
|             "value": 0, | ||||
|             "max": 0 | ||||
|           }, | ||||
|           "6": { | ||||
|             "value": 0, | ||||
|             "max": 0 | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "character": { | ||||
|       "templates": ["common", "spellcaster"], | ||||
|       "details": { | ||||
|         "biography": "", | ||||
|         "class": "", | ||||
|  | @ -9,7 +80,11 @@ | |||
|         "alignment": "", | ||||
|         "literate": false, | ||||
|         "level": 1, | ||||
|         "xp": 0 | ||||
|         "xp": { | ||||
|           "next": 0, | ||||
|           "value": 0, | ||||
|           "bonus": 0 | ||||
|         } | ||||
|       }, | ||||
|       "scores": { | ||||
|         "str": { | ||||
|  | @ -42,53 +117,6 @@ | |||
|         "silver": 0, | ||||
|         "copper": 0 | ||||
|       }, | ||||
|       "spells": { | ||||
|         "dc": 0, | ||||
|         "lvl1": { | ||||
|           "value": 0, | ||||
|           "max": 0 | ||||
|         }, | ||||
|         "lvl2": { | ||||
|           "value": 0, | ||||
|           "max": 0 | ||||
|         }, | ||||
|         "lvl3": { | ||||
|           "value": 0, | ||||
|           "max": 0 | ||||
|         }, | ||||
|         "lvl4": { | ||||
|           "value": 0, | ||||
|           "max": 0 | ||||
|         }, | ||||
|         "lvl5": { | ||||
|           "value": 0, | ||||
|           "max": 0 | ||||
|         } | ||||
|       }, | ||||
|       "hp": { | ||||
|         "hd": "", | ||||
|         "value": 20, | ||||
|         "max": 20 | ||||
|       }, | ||||
|       "ac": { | ||||
|         "value": 0, | ||||
|         "mod": 0 | ||||
|       }, | ||||
|       "thac0": { | ||||
|         "value": 19, | ||||
|         "mod": 0 | ||||
|       }, | ||||
|       "saves": { | ||||
|         "D": 10, | ||||
|         "W": 10, | ||||
|         "P": 10, | ||||
|         "B": 10, | ||||
|         "S": 10 | ||||
|       }, | ||||
|       "movement": { | ||||
|         "base": 0, | ||||
|         "encounter": 0 | ||||
|       }, | ||||
|       "initative": { | ||||
|         "value": 0, | ||||
|         "mod": 0 | ||||
|  | @ -96,6 +124,7 @@ | |||
|       "languages": [] | ||||
|     }, | ||||
|     "monster": { | ||||
|       "templates": ["common", "spellcaster"], | ||||
|       "details": { | ||||
|         "biography": "", | ||||
|         "alignment": "", | ||||
|  | @ -105,72 +134,52 @@ | |||
|         "appearing": "", | ||||
|         "morale": 0 | ||||
|       }, | ||||
|       "saves": { | ||||
|         "D": 10, | ||||
|         "W": 10, | ||||
|         "P": 10, | ||||
|         "B": 10, | ||||
|         "S": 10 | ||||
|       }, | ||||
|       "thac0": { | ||||
|         "value": 19, | ||||
|         "mod": 0 | ||||
|       }, | ||||
|       "hp": { | ||||
|         "hd": "", | ||||
|         "max": 0, | ||||
|         "value": 0 | ||||
|       }, | ||||
|       "ac": { | ||||
|         "value": 0, | ||||
|         "mod": 0 | ||||
|       }, | ||||
|       "attacks": { | ||||
|         "value": 1 | ||||
|       }, | ||||
|       "movement": { | ||||
|         "base": 0, | ||||
|         "encounter": 0 | ||||
|       }, | ||||
|       "spells": { | ||||
|         "dc": 0, | ||||
|         "lvl1": { | ||||
|           "value": 0, | ||||
|           "max": 0 | ||||
|         }, | ||||
|         "lvl2": { | ||||
|           "value": 0, | ||||
|           "max": 0 | ||||
|         }, | ||||
|         "lvl3": { | ||||
|           "value": 0, | ||||
|           "max": 0 | ||||
|         }, | ||||
|         "lvl4": { | ||||
|           "value": 0, | ||||
|           "max": 0 | ||||
|         }, | ||||
|         "lvl5": { | ||||
|           "value": 0, | ||||
|           "max": 0 | ||||
|         } | ||||
|       } | ||||
|       "attacks": "" | ||||
|     } | ||||
|   }, | ||||
|   "Item": { | ||||
|     "types": ["item", "spell", "ability"], | ||||
|     "types": ["item", "weapon", "armor", "spell", "ability"], | ||||
|     "item": { | ||||
|       "description": "", | ||||
|       "quantity": 1, | ||||
|       "quantity": { | ||||
|         "value": 1, | ||||
|         "max": 0 | ||||
|       }, | ||||
|       "cost": 0, | ||||
|       "weight": 80 | ||||
|     }, | ||||
|     "weapon": { | ||||
|       "description": "", | ||||
|       "damage": "1d6", | ||||
|       "qualities": "", | ||||
|       "slow": false, | ||||
|       "missile": true, | ||||
|       "melee": true, | ||||
|       "cost": 0, | ||||
|       "equipped": false, | ||||
|       "weight": 0 | ||||
|     }, | ||||
|     "armor": { | ||||
|       "description": "", | ||||
|       "ac": 9, | ||||
|       "aac": 10, | ||||
|       "cost": 0, | ||||
|       "equipped": false, | ||||
|       "weight": 0 | ||||
|     }, | ||||
|     "spell": { | ||||
|       "lvl": 1, | ||||
|       "class": "", | ||||
|       "description": "" | ||||
|       "class": "Magic-User", | ||||
|       "duration": "", | ||||
|       "range": "", | ||||
|       "roll": "", | ||||
|       "description": "", | ||||
|       "memorized": false, | ||||
|       "cast": false | ||||
|     }, | ||||
|     "ability": { | ||||
|       "requirements": "", | ||||
|       "roll": "", | ||||
|       "description": "" | ||||
|     } | ||||
|   } | ||||
|  |  | |||
|  | @ -9,12 +9,17 @@ | |||
|     <a class="item" data-tab="attributes"> | ||||
|       {{localize "OSE.category.attributes"}} | ||||
|     </a> | ||||
|     <a class="item" data-tab="inventory"> | ||||
|       {{localize "OSE.category.inventory"}} | ||||
|     <a class="item" data-tab="abilities"> | ||||
|       {{localize "OSE.category.abilities"}} | ||||
|     </a> | ||||
|     {{#if data.spells.enabled}} | ||||
|     <a class="item" data-tab="spells"> | ||||
|       {{localize "OSE.category.spells"}} | ||||
|     </a> | ||||
|     {{/if}} | ||||
|     <a class="item" data-tab="inventory"> | ||||
|       {{localize "OSE.category.inventory"}} | ||||
|     </a> | ||||
|     <a class="item" data-tab="notes"> | ||||
|       {{localize "OSE.category.notes"}} | ||||
|     </a> | ||||
|  | @ -25,12 +30,17 @@ | |||
|     <div class="tab" data-group="primary" data-tab="attributes"> | ||||
|       {{> "systems/ose/templates/actors/partials/character-attributes-tab.html"}} | ||||
|     </div> | ||||
|     <div class="tab" data-group="primary" data-tab="inventory"> | ||||
|       {{> "systems/ose/templates/actors/partials/character-inventory-tab.html"}} | ||||
|     <div class="tab" data-group="primary" data-tab="abilities"> | ||||
|       {{> "systems/ose/templates/actors/partials/character-abilities-tab.html"}} | ||||
|     </div> | ||||
|     {{#if data.spells.enabled}} | ||||
|     <div class="tab" data-group="primary" data-tab="spells"> | ||||
|       {{> "systems/ose/templates/actors/partials/character-spells-tab.html"}} | ||||
|     </div> | ||||
|     {{/if}} | ||||
|     <div class="tab" data-group="primary" data-tab="inventory"> | ||||
|       {{> "systems/ose/templates/actors/partials/character-inventory-tab.html"}} | ||||
|     </div> | ||||
|     <div class="tab" data-group="primary" data-tab="notes"> | ||||
|       {{editor content=data.details.biography target="data.details.biography" | ||||
|       button=true owner=owner editable=editable}} | ||||
|  |  | |||
|  | @ -0,0 +1,69 @@ | |||
| <form autocomplete="off"> | ||||
|     <div class="form-group"> | ||||
|       <label for="spellcaster">{{localize "OSE.Spellcaster"}}</label> | ||||
|       <div class="form-fields"> | ||||
|         <input | ||||
|           type="checkbox" | ||||
|           name="data.spells.enabled" | ||||
|           id="spellcaster" | ||||
|           {{checked | ||||
|           data.spells.enabled}} | ||||
|         /> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="form-group"> | ||||
|       <label for="retainer">{{localize "OSE.Retainer"}}</label> | ||||
|       <div class="form-fields"> | ||||
|         <input | ||||
|           type="checkbox" | ||||
|           name="data.retainer.enabled" | ||||
|           id="retainer" | ||||
|           {{checked | ||||
|           data.retainer.enabled}} | ||||
|         /> | ||||
|       </div> | ||||
|     </div> | ||||
|     {{#if (eq this.type 'character')}} | ||||
|     <div class="form-group"> | ||||
|       <label>{{localize "OSE.ExperienceBonus"}} (%)</label> | ||||
|       <div class="form-fields"> | ||||
|         <input | ||||
|           type="text" | ||||
|           name="data.details.xp.bonus" | ||||
|           id="experience" | ||||
|           value="{{data.details.xp.bonus}}" | ||||
|         /> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="form-group"> | ||||
|       <label>{{localize "OSE.MeleeBonus"}}</label> | ||||
|       <div class="form-fields"> | ||||
|         <input | ||||
|           type="text" | ||||
|           name="data.thac0.mod.melee" | ||||
|           id="melee" | ||||
|           value="{{data.thac0.mod.melee}}" | ||||
|           data-dtype="Number" | ||||
|         /> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="form-group"> | ||||
|       <label>{{localize "OSE.MissileBonus"}}</label> | ||||
|       <div class="form-fields"> | ||||
|         <input | ||||
|           type="text" | ||||
|           name="data.thac0.mod.missile" | ||||
|           id="missile" | ||||
|           value="{{data.thac0.mod.missile}}" | ||||
|           data-dtype="Number" | ||||
|         /> | ||||
|       </div> | ||||
|     </div> | ||||
|     {{/if}} | ||||
|     <footer class="sheet-footer"> | ||||
|       <button type="submit"> | ||||
|         <i class="fas fa-save"></i>{{localize "Save Changes"}} | ||||
|       </button> | ||||
|     </footer> | ||||
|   </form> | ||||
|    | ||||
|  | @ -9,9 +9,11 @@ | |||
|     <a class="item" data-tab="attributes"> | ||||
|       {{localize "OSE.category.attributes"}} | ||||
|     </a> | ||||
|     {{#if data.spells.enabled}} | ||||
|     <a class="item" data-tab="spells"> | ||||
|       {{localize "OSE.category.spells"}} | ||||
|     </a> | ||||
|     {{/if}} | ||||
|     <a class="item" data-tab="notes"> | ||||
|       {{localize "OSE.category.notes"}} | ||||
|     </a> | ||||
|  | @ -22,9 +24,11 @@ | |||
|     <div class="tab" data-group="primary" data-tab="attributes"> | ||||
|       {{> "systems/ose/templates/actors/partials/monster-attributes-tab.html"}} | ||||
|     </div> | ||||
|     {{#if data.spells.enabled}} | ||||
|     <div class="tab" data-group="primary" data-tab="spells"> | ||||
|       {{> "systems/ose/templates/actors/partials/character-spells-tab.html"}} | ||||
|     </div> | ||||
|     {{/if}} | ||||
|     <div class="tab" data-group="primary" data-tab="notes"> | ||||
|       {{editor content=data.details.biography target="data.details.biography" | ||||
|       button=true owner=owner editable=editable}} | ||||
|  |  | |||
|  | @ -0,0 +1,36 @@ | |||
| <div class="inventory abilities"> | ||||
|   <div class="item-titles flexrow"> | ||||
|     <div class="item-name">{{localize 'OSE.panel.abilities'}}</div> | ||||
|     <div class="item-controls"> | ||||
|       {{#if owner}} | ||||
|       <a class="item-control item-create" title='{{localize "OSE.Add"}}' data-type="ability"><i | ||||
|           class="fas fa-plus"></i></a> | ||||
|       {{/if}} | ||||
|     </div> | ||||
|   </div> | ||||
|   <ol class="item-list resizable" data-base-size="300"> | ||||
|     {{#each abilities as |item|}} | ||||
|     <li class="item-entry"> | ||||
|       <div class="item flexrow" data-item-id="{{item._id}}"> | ||||
|         <div class="item-name flexrow"> | ||||
|           <div class="item-image" style="background-image: url({{item.img}})"></div> | ||||
|           <a> | ||||
|             <h4 title="{{item.name}}"> | ||||
|               {{item.name~}} | ||||
|             </h4> | ||||
|           </a> | ||||
|         </div> | ||||
|         <div class="field-long"> | ||||
|           {{item.roll}} | ||||
|         </div> | ||||
|         <div class="item-controls"> | ||||
|           {{#if ../owner}} | ||||
|           <a class="item-control item-edit" title='{{localize "Ose.Edit"}}'><i class="fas fa-edit"></i></a> | ||||
|           <a class="item-control item-delete" title='{{localize "Ose.Delete"}}'><i class="fas fa-trash"></i></a> | ||||
|           {{/if}} | ||||
|         </div> | ||||
|       </div> | ||||
|     </li> | ||||
|     {{/each}} | ||||
|   </ol> | ||||
| </div> | ||||
|  | @ -1,146 +1,237 @@ | |||
| <section class="flexrow"> | ||||
|     <ul class="attributes flexrow"> | ||||
|         <li class="attribute health"> | ||||
|             <h4 class="attribute-name box-title">{{ localize "OSE.HealthShort" }}</h4> | ||||
|             <div class="attribute-value multiple"> | ||||
|                 <input name="data.hp.value" type="text" value="{{data.hp.value}}" data-dtype="Number" | ||||
|                     placeholder="10" /> | ||||
|                 <span class="sep"> / </span> | ||||
|                 <input name="data.hp.max" type="text" value="{{data.hp.max}}" data-dtype="Number" placeholder="10" /> | ||||
|             </div> | ||||
|         </li> | ||||
|         <li class="attribute"> | ||||
|             <h4 class="attribute-name box-title">{{ localize "OSE.ArmorClassShort" }}</h4> | ||||
|             <div class="attribute-value"> | ||||
|                 <input name="data.ac.value" type="text" value="{{data.ac.value}}" data-dtype="Number" | ||||
|                     placeholder="10" data-dtype="Number" /> | ||||
|             </div> | ||||
|         </li> | ||||
|         <li class="attribute"> | ||||
|             <h4 class="attribute-name box-title">{{ localize "OSE.Thac0" }}</h4> | ||||
|             <div class="attribute-value"> | ||||
|                 <input name="data.thac0.value" type="text" value="{{data.thac0.value}}" placeholder="0" | ||||
|                     data-dtype="Number" /> | ||||
|             </div> | ||||
|         </li> | ||||
|         <li class="attribute"> | ||||
|             <h4 class="attribute-name box-title">{{ localize "OSE.InitiativeShort" }}</h4> | ||||
|             <div class="attribute-value"> | ||||
|                 <input name="data.initiative.value" type="text" value="{{data.initiative.value}}" | ||||
|                     placeholder="0" data-dtype="Number" /> | ||||
|             </div> | ||||
|         </li> | ||||
|         <li class="attribute"> | ||||
|             <h4 class="attribute-name box-title">{{ localize "OSE.MovementShort" }}</h4> | ||||
|             <div class="attribute-value"> | ||||
|                 <input name="data.movement.value" type="text" value="{{data.movement.value}}" | ||||
|                     placeholder="0" data-dtype="Number" /> | ||||
|             </div> | ||||
|         </li> | ||||
|     </ul> | ||||
| </section> | ||||
| <section class="flexrow"> | ||||
|     {{!-- Scores --}} | ||||
|     <div class="attribute-group"> | ||||
|         <ul class="attributes"> | ||||
|             <li class="attribute"> | ||||
|                 <h4 class="attribute-name box-title" title="{{ localize 'OSE.scores.str.long' }}">{{ localize "OSE.scores.str.short" }}</h4> | ||||
|             <li class="attribute ability-score" data-score="str"> | ||||
|                 <h4 class="attribute-name box-title" title="{{ localize 'OSE.scores.str.long' }}"> | ||||
|                     <a>{{ localize "OSE.scores.str.short" }}</a></h4> | ||||
|                 <div class="attribute-value"> | ||||
|                     <input name="data.scores.str.value" type="text" value="{{data.scores.str.value}}" placeholder="0"  data-dtype="Number"/> | ||||
|                     <input name="data.scores.str.value" type="text" value="{{data.scores.str.value}}" placeholder="0" | ||||
|                         data-dtype="Number" /> | ||||
|                     <span class="attribute-mod">{{mods.str}}</span> | ||||
|             </li> | ||||
|             <li class="attribute"> | ||||
|                 <h4 class="attribute-name box-title" title="{{ localize 'OSE.scores.int.long' }}">{{ localize "OSE.scores.int.short" }}</h4> | ||||
|             <li class="attribute ability-score" data-score="int"> | ||||
|                 <h4 class="attribute-name box-title" title="{{ localize 'OSE.scores.int.long' }}"> | ||||
|                     <a>{{ localize "OSE.scores.int.short" }}</a></h4> | ||||
|                 <div class="attribute-value"> | ||||
|                     <input name="data.scores.int.value" type="text" value="{{data.scores.int.value}}" placeholder="0"  data-dtype="Number"/> | ||||
|                     <input name="data.scores.int.value" type="text" value="{{data.scores.int.value}}" placeholder="0" | ||||
|                         data-dtype="Number" /> | ||||
|                     <span class="attribute-mod">{{mods.int}}</span> | ||||
|             </li> | ||||
|             <li class="attribute"> | ||||
|                 <h4 class="attribute-name box-title" title="{{ localize 'OSE.scores.wis.long' }}">{{ localize "OSE.scores.wis.short" }}</h4> | ||||
|             <li class="attribute ability-score" data-score="wis"> | ||||
|                 <h4 class="attribute-name box-title" title="{{ localize 'OSE.scores.wis.long' }}"> | ||||
|                     <a>{{ localize "OSE.scores.wis.short" }}</a></h4> | ||||
|                 <div class="attribute-value"> | ||||
|                     <input name="data.scores.wis.value" type="text" value="{{data.scores.wis.value}}" placeholder="0"  data-dtype="Number"/> | ||||
|                     <input name="data.scores.wis.value" type="text" value="{{data.scores.wis.value}}" placeholder="0" | ||||
|                         data-dtype="Number" /> | ||||
|                     <span class="attribute-mod">{{mods.wis}}</span> | ||||
|             </li> | ||||
|             <li class="attribute"> | ||||
|                 <h4 class="attribute-name box-title" title="{{ localize 'OSE.scores.dex.long' }}">{{ localize "OSE.scores.dex.short" }}</h4> | ||||
|             <li class="attribute ability-score" data-score="dex"> | ||||
|                 <h4 class="attribute-name box-title" title="{{ localize 'OSE.scores.dex.long' }}"> | ||||
|                     <a>{{ localize "OSE.scores.dex.short" }}</a></h4> | ||||
|                 <div class="attribute-value"> | ||||
|                     <input name="data.scores.dex.value" type="text" value="{{data.scores.dex.value}}" placeholder="0"  data-dtype="Number"/> | ||||
|                     <input name="data.scores.dex.value" type="text" value="{{data.scores.dex.value}}" placeholder="0" | ||||
|                         data-dtype="Number" /> | ||||
|                     <span class="attribute-mod">{{mods.dex}}</span> | ||||
|             </li> | ||||
|             <li class="attribute"> | ||||
|                 <h4 class="attribute-name box-title" title="{{ localize 'OSE.scores.con.long' }}">{{ localize "OSE.scores.con.short" }}</h4> | ||||
|             <li class="attribute ability-score" data-score="con"> | ||||
|                 <h4 class="attribute-name box-title" title="{{ localize 'OSE.scores.con.long' }}"> | ||||
|                     <a>{{ localize "OSE.scores.con.short" }}</a></h4> | ||||
|                 <div class="attribute-value"> | ||||
|                     <input name="data.scores.con.value" type="text" value="{{data.scores.con.value}}" placeholder="0"  data-dtype="Number"/> | ||||
|                     <input name="data.scores.con.value" type="text" value="{{data.scores.con.value}}" placeholder="0" | ||||
|                         data-dtype="Number" /> | ||||
|                     <span class="attribute-mod">{{mods.con}}</span> | ||||
|             </li> | ||||
|             <li class="attribute"> | ||||
|                 <h4 class="attribute-name box-title" title="{{ localize 'OSE.scores.cha.long' }}">{{ localize "OSE.scores.cha.short" }}</h4> | ||||
|             <li class="attribute ability-score" data-score="cha"> | ||||
|                 <h4 class="attribute-name box-title" title="{{ localize 'OSE.scores.cha.long' }}"> | ||||
|                     <a>{{ localize "OSE.scores.cha.short" }}</a></h4> | ||||
|                 <div class="attribute-value"> | ||||
|                     <input name="data.scores.cha.value" type="text" value="{{data.scores.cha.value}}" placeholder="0"  data-dtype="Number"/> | ||||
|                     <input name="data.scores.cha.value" type="text" value="{{data.scores.cha.value}}" placeholder="0" | ||||
|                         data-dtype="Number" /> | ||||
|                     <span class="attribute-mod">{{mods.cha}}</span> | ||||
|             </li> | ||||
|             {{#if data.retainer.enabled}} | ||||
|             <li class="attribute"> | ||||
|                 <h4 class="attribute-name box-title" title="{{ localize 'OSE.Loyalty' }}"> | ||||
|                     {{ localize "OSE.LoyaltyShort" }} | ||||
|                 </h4> | ||||
|                 <div class="attribute-value"> | ||||
|                     <input name="data.retainer.loyalty" type="text" value="{{data.retainer.loyalty}}" placeholder="0" | ||||
|                         data-dtype="Number" /> | ||||
|                 </div> | ||||
|             </li> | ||||
|             {{/if}} | ||||
|         </ul> | ||||
|     </div> | ||||
|     {{!-- Skills and abilities --}} | ||||
|     <div class="flex3 panel abilities resizable" data-base-size="250"> | ||||
|         <div class="panel-title"> | ||||
|             <h4>{{localize 'OSE.panel.abilities'}}</h4> | ||||
|             <div class="item-controls"> | ||||
|                 {{#if owner}} | ||||
|                 <a class="item-control item-create" title='{{localize "OSE.Add"}}' data-type="ability"><i class="fas fa-plus"></i></a> | ||||
|     {{!-- Resource Tracking --}} | ||||
|     <div class="flex2"> | ||||
|         <div class="flexrow"> | ||||
|             <div class="health"> | ||||
|                 <input class="health-top" name="data.hp.value" type="text" value="{{data.hp.value}}" data-dtype="Number" | ||||
|                     placeholder="0" title="{{localize 'OSE.Health'}}" /> | ||||
|                 <input class="health-bottom" name="data.hp.max" type="text" value="{{data.hp.max}}" data-dtype="Number" | ||||
|                     placeholder="0" title="{{localize 'OSE.HealthMax'}}" /> | ||||
|                 <div class="health-empty" style="height:{{counter false data.hp.value data.hp.max}}%"></div> | ||||
|                 <div class="health-full" style="height:{{counter true data.hp.value data.hp.max}}%"></div> | ||||
|             </div> | ||||
|             <div class="health armor-class"> | ||||
|                 {{#if config.ascendingAC}} | ||||
|                 <input class="health-top" name="data.aac.value" type="text" value="{{data.aac.value}}" | ||||
|                     data-dtype="Number" placeholder="0" title="{{localize 'OSE.ArmorClass'}}" /> | ||||
|                 <input class="health-bottom" type="text" value="{{add 10 mods.dex}}" | ||||
|                     title="{{localize 'OSE.ArmorClass'}}" disabled /> | ||||
|                 {{else}} | ||||
|                 <input class="health-top" name="data.ac.value" type="text" value="{{data.ac.value}}" data-dtype="Number" | ||||
|                     placeholder="0" title="{{localize 'OSE.ArmorClass'}}" /> | ||||
|                 <input class="health-bottom" type="text" value="{{subtract mods.dex 9}}" | ||||
|                     title="{{localize 'OSE.ArmorClass'}}" disabled /> | ||||
|                 {{/if}} | ||||
|             </div> | ||||
|         </div> | ||||
|         <ul class="panel-content inventory resizable" data-base-size="225"> | ||||
|             <div class=""> | ||||
|                 {{#each abilities as |item|}} | ||||
|                 <li class="item-entry"> | ||||
|                     <div class="item flexrow" data-item-id="{{item._id}}"> | ||||
|                         <div class="item-name flexrow"> | ||||
|                             <div class="item-image" style="background-image: url({{item.img}})"></div> | ||||
|                             <h4 title="{{item.name}}"> | ||||
|                                 {{item.name~}} | ||||
|                             </h4> | ||||
|                         </div> | ||||
|                         <div class="item-controls"> | ||||
|                             {{#if ../owner}} | ||||
|                             <a class="item-control item-edit" title='{{localize "Ose.Edit"}}'><i | ||||
|                                     class="fas fa-edit"></i></a> | ||||
|                             <a class="item-control item-delete" title='{{localize "Ose.Delete"}}'><i | ||||
|                                     class="fas fa-trash"></i></a> | ||||
|         <div class="flexrow"> | ||||
|             <ul class="attributes flexrow"> | ||||
|                 <li class="attribute"> | ||||
|                     <h4 class="attribute-name box-title" title="{{ localize 'OSE.HitDice' }}"> | ||||
|                         {{ localize "OSE.HitDiceShort" }} | ||||
|                     </h4> | ||||
|                     <div class="attribute-value"> | ||||
|                         <input name="data.hp.hd" type="text" value="{{data.hp.hd}}" placeholder="0" | ||||
|                             data-dtype="String" /> | ||||
|                     </div> | ||||
|                 </li> | ||||
|                 {{#if config.individualInit}} | ||||
|                 <li class="attribute"> | ||||
|                     <h4 class="attribute-name box-title" title="{{ localize 'OSE.Initiative' }}"> | ||||
|                         {{ localize "OSE.InitiativeShort" }}</h4> | ||||
|                     <div class="attribute-value"> | ||||
|                         <input name="data.initiative.value" type="text" value="{{data.initiative.value}}" | ||||
|                             placeholder="0" data-dtype="Number" /> | ||||
|                     </div> | ||||
|                 </li> | ||||
|                 {{/if}} | ||||
|             </ul> | ||||
|         </div> | ||||
|         <div class="flexrow"> | ||||
|             <ul class="attributes flexrow"> | ||||
|                 <li class="attribute attribute-secondaries attack" data-attack="Melee"> | ||||
|                     <h4 class="attribute-name box-title" title="{{localize 'OSE.Melee'}}"> | ||||
|                         <a>{{localize 'OSE.MeleeShort'}}</a></h4> | ||||
|                     <div class="flexrow"> | ||||
|                         <div class="attribute-value"> | ||||
|                             {{#if config.ascendingAC}} | ||||
|                             {{add data.thac0.mod.melee (add mods.str data.thac0.bba)}} | ||||
|                             {{else}} | ||||
|                             {{subtract data.thac0.mod.melee (subtract mods.str data.thac0.value)}} | ||||
|                             {{/if}} | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </li> | ||||
|                 {{/each}} | ||||
|             </div> | ||||
|         </ul> | ||||
|                 {{#if config.ascendingAC}} | ||||
|                 <li class="attribute"> | ||||
|                     <h4 class="attribute-name box-title" title="{{ localize 'OSE.AB' }}">{{ localize "OSE.ABShort"}} | ||||
|                     </h4> | ||||
|                     <div class="flexrow"> | ||||
|                         <div class="attribute-value"> | ||||
|                             <input name="data.thac0.bba" type="text" value="{{data.thac0.bba}}" placeholder="0" | ||||
|                                 data-dtype="Number" /> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </li> | ||||
|                 {{else}} | ||||
|                 <li class="attribute"> | ||||
|                     <h4 class="attribute-name box-title" title="{{ localize 'OSE.Thac0' }}">{{ localize "OSE.Thac0"}} | ||||
|                     </h4> | ||||
|                     <div class="flexrow"> | ||||
|                         <div class="attribute-value"> | ||||
|                             <input name="data.thac0.value" type="text" value="{{data.thac0.value}}" placeholder="0" | ||||
|                                 data-dtype="Number" /> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </li> | ||||
|                 {{/if}} | ||||
|                 <li class="attribute attribute-secondaries attack" data-attack="Missile"> | ||||
|                     <h4 class="attribute-name box-title" title="{{localize 'OSE.Missile'}}"> | ||||
|                         <a>{{localize 'OSE.MissileShort'}}</a></h4> | ||||
|                     <div class="flexrow"> | ||||
|                         <div class="attribute-value"> | ||||
|                             {{#if config.ascendingAC}} | ||||
|                             {{add data.thac0.mod.missile (add mods.dex data.thac0.bba)}} | ||||
|                             {{else}} | ||||
|                             {{subtract data.thac0.mod.missile (subtract mods.dex data.thac0.value)}} | ||||
|                             {{/if}} | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </li> | ||||
|             </ul> | ||||
|         </div> | ||||
|         <div class="flexrow"> | ||||
|             <ul class="attributes flexrow"> | ||||
|                 <li class="attribute attribute-secondaries"> | ||||
|                     <h4 class="attribute-name box-title" title="{{localize 'OSE.MovementEncounter'}}"> | ||||
|                         {{localize 'OSE.MovementEncounterShort'}}</h4> | ||||
|                     <div class="flexrow"> | ||||
|                         <div class="attribute-value"> | ||||
|                             {{divide data.movement.base 3}} | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </li> | ||||
|                 <li class="attribute"> | ||||
|                     <h4 class="attribute-name box-title" title="{{ localize 'OSE.Movement' }}"> | ||||
|                         {{ localize "OSE.MovementShort" }}</h4> | ||||
|                     <div class="attribute-value flexrow"> | ||||
|                         <input name="data.movement.base" type="text" value="{{data.movement.base}}" placeholder="0" | ||||
|                             data-dtype="Number" /> | ||||
|                     </div> | ||||
|                 </li> | ||||
|                 <li class="attribute attribute-secondaries"> | ||||
|                     <h4 class="attribute-name box-title" title="{{localize 'OSE.MovementOverland'}}"> | ||||
|                         {{localize 'OSE.MovementOverlandShort'}}</h4> | ||||
|                     <div class="flexrow"> | ||||
|                         <div class="attribute-value"> | ||||
|                             {{divide data.movement.base 5}} | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </li> | ||||
|             </ul> | ||||
|         </div> | ||||
|     </div> | ||||
|     {{!-- Saving throws --}} | ||||
|     <div class="attribute-group"> | ||||
|         <ul class="attributes"> | ||||
|             <li class="attribute"> | ||||
|                 <h4 class="attribute-name box-title" title="{{ localize 'OSE.saves.death.long' }}">{{ localize "OSE.saves.death.short" }}</h4> | ||||
|             <li class="attribute saving-throw" data-save="death"> | ||||
|                 <h4 class="attribute-name box-title" title="{{ localize 'OSE.saves.death.long' }}"> | ||||
|                     <a>{{ localize "OSE.saves.death.long" }}</a></h4> | ||||
|                 <div class="attribute-value"> | ||||
|                     <input name="data.saves.d.value" type="text" value="{{data.saves.d.value}}" placeholder="0" | ||||
|                     <input name="data.saves.death.value" type="text" value="{{data.saves.death.value}}" placeholder="0" | ||||
|                         data-dtype="Number" /> | ||||
|             </li> | ||||
|             <li class="attribute"> | ||||
|                 <h4 class="attribute-name box-title" title="{{ localize 'OSE.saves.wands.long' }}">{{ localize "OSE.saves.wands.short" }}</h4> | ||||
|             <li class="attribute saving-throw" data-save="wand"> | ||||
|                 <h4 class="attribute-name box-title" title="{{ localize 'OSE.saves.wand.long' }}"> | ||||
|                     <a>{{ localize "OSE.saves.wand.long" }}</a></h4> | ||||
|                 <div class="attribute-value"> | ||||
|                     <input name="data.saves.w.value" type="text" value="{{data.saves.w.value}}" placeholder="0" | ||||
|                     <input name="data.saves.wand.value" type="text" value="{{data.saves.wand.value}}" placeholder="0" | ||||
|                         data-dtype="Number" /> | ||||
|             </li> | ||||
|             <li class="attribute"> | ||||
|                 <h4 class="attribute-name box-title" title="{{ localize 'OSE.saves.paralysis.long' }}">{{ localize "OSE.saves.paralysis.short" }}</h4> | ||||
|             <li class="attribute saving-throw" data-save="paralysis"> | ||||
|                 <h4 class="attribute-name box-title" title="{{ localize 'OSE.saves.paralysis.long' }}"> | ||||
|                     <a>{{ localize "OSE.saves.paralysis.long" }}</a></h4> | ||||
|                 <div class="attribute-value"> | ||||
|                     <input name="data.saves.p.value" type="text" value="{{data.saves.p.value}}" placeholder="0" | ||||
|                         data-dtype="Number" /> | ||||
|                     <input name="data.saves.paralysis.value" type="text" value="{{data.saves.paralysis.value}}" | ||||
|                         placeholder="0" data-dtype="Number" /> | ||||
|             </li> | ||||
|             <li class="attribute"> | ||||
|                 <h4 class="attribute-name box-title" title="{{ localize 'OSE.saves.breath.long' }}">{{ localize "OSE.saves.breath.short" }}</h4> | ||||
|             <li class="attribute saving-throw" data-save="breath"> | ||||
|                 <h4 class="attribute-name box-title" title="{{ localize 'OSE.saves.breath.long' }}"> | ||||
|                     <a>{{ localize "OSE.saves.breath.long" }}</a></h4> | ||||
|                 <div class="attribute-value"> | ||||
|                     <input name="data.saves.b.value" type="text" value="{{data.saves.b.value}}" placeholder="0" | ||||
|                         data-dtype="Number" /> | ||||
|                     <input name="data.saves.breath.value" type="text" value="{{data.saves.breath.value}}" | ||||
|                         placeholder="0" data-dtype="Number" /> | ||||
|             </li> | ||||
|             <li class="attribute"> | ||||
|                 <h4 class="attribute-name box-title" title="{{ localize 'OSE.saves.spells.long' }}">{{ localize "OSE.saves.spells.short" }}</h4> | ||||
|             <li class="attribute saving-throw" data-save="spell"> | ||||
|                 <h4 class="attribute-name box-title" title="{{ localize 'OSE.saves.spell.long' }}"> | ||||
|                     <a>{{ localize "OSE.saves.spell.long" }}</a></h4> | ||||
|                 <div class="attribute-value"> | ||||
|                     <input name="data.saves.s.value" type="text" value="{{data.saves.s.value}}" placeholder="0" /> | ||||
|                     <input name="data.saves.spell.value" type="text" value="{{data.saves.spell.value}}" | ||||
|                         placeholder="0" /> | ||||
|             </li> | ||||
|         </ul> | ||||
|     </div> | ||||
|  |  | |||
|  | @ -27,9 +27,12 @@ | |||
|       <label>{{localize 'OSE.Level'}}</label> | ||||
|     </li> | ||||
|     <li class="flex2"> | ||||
|       <input type="text" name="data.details.xp" value="{{data.details.xp}}" | ||||
|       <input type="text" name="data.details.xp.value" value="{{data.details.xp.value}}" | ||||
|         placeholder="{{ localize 'OSE.Experience' }}" /> | ||||
|       <label>{{localize 'OSE.Experience'}}</label> | ||||
|       {{#if data.details.xp.bonus}} | ||||
|       <span class="xp-bonus">+{{data.details.xp.bonus}}%</span> | ||||
|       {{/if}} | ||||
|     </li> | ||||
|   </ul> | ||||
| </section> | ||||
|  | @ -1,29 +1,141 @@ | |||
| <section class="inventory resizable" data-base-size="320"> | ||||
|   <div class=""> | ||||
|     {{#each inventory as |item|}} | ||||
|     <li class="item-entry"> | ||||
|       <div class="item flexrow" data-item-id="{{item._id}}"> | ||||
|         <div class="item-name flexrow"> | ||||
|           <div | ||||
|             class="item-image" | ||||
|             style="background-image: url({{item.img}})" | ||||
|           ></div> | ||||
|           <h4 title="{{item.name}}"> | ||||
|             {{item.name~}} | ||||
|           </h4> | ||||
|         </div> | ||||
|         <div class="item-controls"> | ||||
|           {{#if ../owner}} | ||||
|           <a class="item-control item-edit" title='{{localize "Ose.Edit"}}' | ||||
|             ><i class="fas fa-edit"></i | ||||
|           ></a> | ||||
|           <a class="item-control item-delete" title='{{localize "Ose.Delete"}}' | ||||
|             ><i class="fas fa-trash"></i | ||||
|           ></a> | ||||
|           {{/if}} | ||||
|         </div> | ||||
| <section class="inventory resizable" data-base-size="310"> | ||||
|   <div> | ||||
|     <li class="item-titles flexrow"> | ||||
|       <div class="item-name">{{localize "OSE.items.Weapons"}}</div> | ||||
|       {{#if config.variableWeaponDamage}} | ||||
|       <div class="field-short">{{localize "OSE.items.Damage"}}</div> | ||||
|       {{/if}} | ||||
|       <div class="field-longer">{{localize "OSE.items.Qualities"}}</div> | ||||
|       <div class="field-short">{{localize "OSE.items.Weight"}}</div> | ||||
|       <div class="item-controls"> | ||||
|         <a class="item-control item-create" data-type="weapon" title="{{localize 'OSE.Add'}}"><i class="fa fa-plus"></i></a> | ||||
|       </div> | ||||
|     </li> | ||||
|     {{/each}} | ||||
|     <ol class="item-list"> | ||||
|       {{#each owned.weapons as |item|}} | ||||
|       <li class="item-entry"> | ||||
|         <div class="item flexrow" data-item-id="{{item._id}}"> | ||||
|           <div class="item-name flexrow"> | ||||
|             <div class="item-image" style="background-image: url({{item.img}})"></div> | ||||
|             <a> | ||||
|               <h4 title="{{item.name}}"> | ||||
|                 {{item.name~}} | ||||
|               </h4> | ||||
|             </a> | ||||
|           </div> | ||||
|           {{#if config.variableWeaponDamage}} | ||||
|           <div class="field-short"> | ||||
|             {{item.data.damage}} | ||||
|           </div> | ||||
|           {{/if}} | ||||
|           <div class="field-longer" title="{{item.data.qualities}}"> | ||||
|             {{item.data.qualities}} | ||||
|           </div> | ||||
|           <div class="field-short"> | ||||
|             {{item.data.weight}} | ||||
|           </div> | ||||
|           <div class="item-controls"> | ||||
|             {{#if ../owner}} | ||||
|             <a class="item-control item-toggle {{#unless item.data.equipped}}item-unequipped{{/unless}}" | ||||
|               title='{{localize "OSE.items.Equip"}}'> | ||||
|               <i class="fas fa-tshirt"></i> | ||||
|             </a> | ||||
|             <a class="item-control item-edit" title='{{localize "OSE.Edit"}}'><i class="fas fa-edit"></i></a> | ||||
|             <a class="item-control item-delete" title='{{localize "OSE.Delete"}}'><i class="fas fa-trash"></i></a> | ||||
|             {{/if}} | ||||
|           </div> | ||||
|         </div> | ||||
|       </li> | ||||
|       {{/each}} | ||||
|     </ol> | ||||
|   </div> | ||||
| </section> | ||||
|   <div> | ||||
|     <li class="item-titles flexrow"> | ||||
|       <div class="item-name">{{localize "OSE.items.Armors"}}</div> | ||||
|       {{#if config.ascendingAC}} | ||||
|       <div class="field-short">{{localize "OSE.items.ArmorAAC"}}</div> | ||||
|       {{else}} | ||||
|       <div class="field-short">{{localize "OSE.items.ArmorAC"}}</div> | ||||
|       {{/if}} | ||||
|       <div class="field-short">{{localize "OSE.items.Weight"}}</div> | ||||
|       <div class="item-controls"> | ||||
|         <a class="item-control item-create" data-type="armor" title="{{localize 'OSE.Add'}}"><i class="fa fa-plus"></i></a> | ||||
|       </div> | ||||
|     </li> | ||||
|     <ol class="item-list"> | ||||
|       {{#each owned.armors as |item|}} | ||||
|       <li class="item-entry"> | ||||
|         <div class="item flexrow" data-item-id="{{item._id}}"> | ||||
|           <div class="item-name flexrow"> | ||||
|             <div class="item-image" style="background-image: url({{item.img}})"></div> | ||||
|             <a> | ||||
|               <h4 title="{{item.name}}"> | ||||
|                 {{item.name~}} | ||||
|               </h4> | ||||
|             </a> | ||||
|           </div> | ||||
|           <div class="field-short"> | ||||
|             {{#if config.ascendingAC}} | ||||
|             {{item.data.aac}} | ||||
|             {{else}} | ||||
|             {{item.data.ac}} | ||||
|             {{/if}} | ||||
|           </div> | ||||
|           <div class="field-short"> | ||||
|             {{item.data.weight}} | ||||
|           </div> | ||||
|           <div class="item-controls"> | ||||
|             {{#if ../owner}} | ||||
|             <a class="item-control item-toggle {{#unless item.data.equipped}}item-unequipped{{/unless}}" | ||||
|               title='{{localize "OSE.items.Equip"}}'> | ||||
|               <i class="fas fa-tshirt"></i> | ||||
|             </a> | ||||
|             <a class="item-control item-edit" title='{{localize "OSE.Edit"}}'><i class="fas fa-edit"></i></a> | ||||
|             <a class="item-control item-delete" title='{{localize "OSE.Delete"}}'><i class="fas fa-trash"></i></a> | ||||
|             {{/if}} | ||||
|           </div> | ||||
|         </div> | ||||
|       </li> | ||||
|       {{/each}} | ||||
|     </ol> | ||||
|   </div> | ||||
|   <div class=""> | ||||
|     <li class="item-titles flexrow"> | ||||
|       <div class="item-name">{{localize "OSE.items.Misc"}}</div> | ||||
|       <div class="field-short">{{localize "OSE.items.Quantity"}}</div> | ||||
|       <div class="field-short">{{localize "OSE.items.Weight"}}</div> | ||||
|       <div class="item-controls"> | ||||
|         <a class="item-control item-create" data-type="item" title="{{localize 'OSE.Add'}}"><i class="fa fa-plus"></i></a> | ||||
|       </div> | ||||
|     </li> | ||||
|     <ol class="item-list"> | ||||
|       {{#each owned.items as |item|}} | ||||
|       <li class="item-entry"> | ||||
|         <div class="item flexrow" data-item-id="{{item._id}}"> | ||||
|           <div class="item-name flexrow"> | ||||
|             <div class="item-image" style="background-image: url({{item.img}})"></div> | ||||
|             <a> | ||||
|               <h4 title="{{item.name}}"> | ||||
|                 {{item.name~}} | ||||
|               </h4> | ||||
|             </a> | ||||
|           </div> | ||||
|           <div class="field-short quantity"> | ||||
|             <input value="{{item.data.quantity.value}}" type="text" | ||||
|               placeholder="0" />{{#if item.data.quantity.max}}<span>/{{item.data.quantity.max}}</span>{{/if}} | ||||
|           </div> | ||||
|           <div class="field-short"> | ||||
|             {{item.data.weight}} | ||||
|           </div> | ||||
|           <div class="item-controls"> | ||||
|             {{#if ../owner}} | ||||
|             <a class="item-control item-edit" title='{{localize "OSE.Edit"}}'><i class="fas fa-edit"></i></a> | ||||
|             <a class="item-control item-delete" title='{{localize "OSE.Delete"}}'><i class="fas fa-trash"></i></a> | ||||
|             {{/if}} | ||||
|           </div> | ||||
|         </div> | ||||
|       </li> | ||||
|       {{/each}} | ||||
|     </ol> | ||||
|   </div> | ||||
| </section> | ||||
|  | @ -1,93 +1,42 @@ | |||
| <section class="flexrow"> | ||||
|   <ul class="attributes flexrow"> | ||||
|     <li class="attribute"> | ||||
|         <h4 class="attribute-name box-title">{{localize 'OSE.SpellDC'}}</h4> | ||||
|         <div class="attribute-value"> | ||||
|             <input name="data.spells.dc" type="text" value="{{data.spells.dc}}" data-dtype="Number" | ||||
|                 placeholder="0" /> | ||||
|         </div> | ||||
|     </li> | ||||
|       <li class="attribute"> | ||||
|           <h4 class="attribute-name box-title">{{localize 'OSE.Level'}} 1</h4> | ||||
|           <div class="attribute-value"> | ||||
|               <input name="data.spells.lvl1.value" type="text" value="{{data.spells.lvl1.value}}" data-dtype="Number" | ||||
|                   placeholder="0" /> | ||||
|                   <span class="sep"> / </span> | ||||
|                   <input name="data.spells.lvl1.max" type="text" value="{{data.spells.lvl1.max}}" data-dtype="Number" placeholder="0" /> | ||||
|           </div> | ||||
|       </li> | ||||
|       <li class="attribute"> | ||||
|           <h4 class="attribute-name box-title">{{localize 'OSE.Level'}} 2</h4> | ||||
|           <div class="attribute-value"> | ||||
|               <input name="data.spells.lvl2.value" type="text" value="{{data.spells.lvl2.value}}" data-dtype="Number" | ||||
|                   placeholder="0" data-dtype="Number" /> | ||||
|                   <span class="sep"> / </span> | ||||
|                   <input name="data.spells.lvl2.max" type="text" value="{{data.spells.lvl2.max}}" data-dtype="Number" placeholder="0" /> | ||||
|           </div> | ||||
|       </li> | ||||
|       <li class="attribute"> | ||||
|           <h4 class="attribute-name box-title">{{localize 'OSE.Level'}} 3</h4> | ||||
|           <div class="attribute-value"> | ||||
|               <input name="data.spells.lvl3.value" type="text" value="{{data.spells.lvl3.value}}" | ||||
|                   placeholder="0" data-dtype="Number" /> | ||||
|                   <span class="sep"> / </span> | ||||
|                   <input name="data.spells.lvl3.max" type="text" value="{{data.spells.lvl3.max}}" data-dtype="Number" placeholder="0" /> | ||||
|           </div> | ||||
|       </li> | ||||
|       <li class="attribute"> | ||||
|           <h4 class="attribute-name box-title">{{localize 'OSE.Level'}} 4</h4> | ||||
|           <div class="attribute-value"> | ||||
|               <input name="data.spells.lvl4.value" type="text" value="{{data.spells.lvl4.value}}" | ||||
|                   placeholder="0" data-dtype="Number" /> | ||||
|                   <span class="sep"> / </span> | ||||
|                   <input name="data.spells.lvl4.max" type="text" value="{{data.spells.lvl4.max}}" data-dtype="Number" placeholder="0" /> | ||||
|           </div> | ||||
|       </li> | ||||
|       <li class="attribute"> | ||||
|           <h4 class="attribute-name box-title">{{localize 'OSE.Level'}} 5</h4> | ||||
|           <div class="attribute-value multiple"> | ||||
|               <input name="data.spells.lvl5.value" type="text" value="{{data.spells.lvl5.value}}" | ||||
|                   placeholder="0" data-dtype="Number" /> | ||||
|                   <span class="sep"> / </span> | ||||
|                   <input name="data.spells.lvl5.max" type="text" value="{{data.spells.lvl5.max}}" data-dtype="Number" placeholder="0" /> | ||||
|           </div> | ||||
|       </li> | ||||
|   </ul> | ||||
| </section> | ||||
| <section class="panel inventory"> | ||||
|   <div class="panel-title"> | ||||
|     <h4>{{localize 'OSE.category.spells'}}</h4> | ||||
| <section class="inventory spells resizable" data-base-size="320"> | ||||
|   {{#each spells as |spellGroup id|}} | ||||
|   <ol class="item-list"> | ||||
|     <li class="item-titles flexrow"> | ||||
|       <div class="item-name">{{localize "OSE.spells.Level"}} {{id}}</div> | ||||
|       <div class="field-short">{{localize 'OSE.spells.Slots'}}</div> | ||||
|       <div class="field-long flexrow"><input type="text" value="{{lookup (lookup ../actor.data.spells @key) 'value'}}" name="data.spells.{{id}}.value" data-dtype="Number" | ||||
|           placeholder="0">/<input type="text" value="{{lookup (lookup ../actor.data.spells @key) 'max'}}" name="data.spells.{{id}}.max" data-dtype="Number" | ||||
|           placeholder="0"></div> | ||||
|       <div class="item-controls"> | ||||
|           {{#if owner}} | ||||
|           <a class="item-control item-create" title='{{localize "OSE.Add"}}' data-type="spell"><i class="fas fa-plus"></i></a> | ||||
|           {{/if}} | ||||
|         <a class="item-control item-create" data-type="spell" data-lvl="{{id}}" title="{{localize 'OSE.Add'}}"><i | ||||
|             class="fa fa-plus"></i></a> | ||||
|       </div> | ||||
|   </div> | ||||
|   <div class="panel-content resizable" data-base-size="230"> | ||||
|     {{#each spells as |item|}} | ||||
|     </li> | ||||
|     {{#each spellGroup as |item|}} | ||||
|     <li class="item-entry"> | ||||
|       <div class="item flexrow" data-item-id="{{item._id}}"> | ||||
|         <div class="item-controls"> | ||||
|           <a class="item-control item-cast {{#unless item.data.cast}}item-unequipped{{/unless}}" title="{{localize 'OSE.spells.Cast'}}"><i class="{{#if item.data.cast}}fas{{else}}far{{/if}} fa-sun"></i></a> | ||||
|           <a class="item-control item-memorize {{#unless item.data.memorized}}item-unequipped{{/unless}}" title="{{localize 'OSE.spells.Memorized'}}"><i | ||||
|               class="fas fa-book-open"></i></a> | ||||
|         </div> | ||||
|         <div class="item-name flexrow"> | ||||
|           <div | ||||
|             class="item-image" | ||||
|             style="background-image: url({{item.img}})" | ||||
|           ></div> | ||||
|           <h4 title="{{item.name}}"> | ||||
|             {{item.name~}} | ||||
|           </h4> | ||||
|           <div class="item-image" style="background-image: url({{item.img}})"></div> | ||||
|           <a> | ||||
|             <h4 title="{{item.name}}"> | ||||
|               {{item.name~}} | ||||
|             </h4> | ||||
|           </a> | ||||
|         </div> | ||||
|         <div class="item-controls"> | ||||
|           {{#if ../owner}} | ||||
|           <a class="item-control item-edit" title='{{localize "Ose.Edit"}}' | ||||
|             ><i class="fas fa-edit"></i | ||||
|           ></a> | ||||
|           <a class="item-control item-delete" title='{{localize "Ose.Delete"}}' | ||||
|             ><i class="fas fa-trash"></i | ||||
|           ></a> | ||||
|           {{#if ../../owner}} | ||||
|           <a class="item-control item-edit" title='{{localize "OSE.Edit"}}'><i class="fas fa-edit"></i></a> | ||||
|           <a class="item-control item-delete" title='{{localize "OSE.Delete"}}'><i class="fas fa-trash"></i></a> | ||||
|           {{/if}} | ||||
|         </div> | ||||
|       </div> | ||||
|     </li> | ||||
|     {{/each}} | ||||
|   </div> | ||||
| </section> | ||||
|   </ol> | ||||
|   {{/each}} | ||||
| </section> | ||||
|  | @ -2,7 +2,7 @@ | |||
|     <ul class="attributes flexrow"> | ||||
|         <li class="attribute health"> | ||||
|             <h4 class="attribute-name box-title" title="{{localize 'OSE.Health'}}">{{ localize "OSE.HealthShort" }}</h4> | ||||
|             <div class="attribute-value multiple"> | ||||
|             <div class="attribute-value flexrow"> | ||||
|                 <input name="data.hp.value" type="text" value="{{data.hp.value}}" data-dtype="Number" | ||||
|                     placeholder="10" /> | ||||
|                 <span class="sep"> / </span> | ||||
|  | @ -10,11 +10,28 @@ | |||
|             </div> | ||||
|         </li> | ||||
|         <li class="attribute"> | ||||
|             <h4 class="attribute-name box-title" title="{{localize 'OSE.ArmorClass'}}">{{ localize "OSE.ArmorClassShort" }}</h4> | ||||
|             <h4 class="attribute-name box-title" title="{{localize 'OSE.HitDice'}}">{{ localize "OSE.HitDiceShort" }} | ||||
|             </h4> | ||||
|             <div class="attribute-value"> | ||||
|                 <input name="data.ac.value" type="text" value="{{data.ac.value}}" data-dtype="Number" placeholder="10" | ||||
|                 <input name="data.hp.hd" type="text" value="{{data.hp.hd}}" placeholder="0" data-dtype="String" /> | ||||
|             </div> | ||||
|         </li> | ||||
|         <li class="attribute"> | ||||
|             {{#if config.ascendingAC}} | ||||
|             <h4 class="attribute-name box-title" title="{{ localize 'OSE.ArmorClass' }}"> | ||||
|                 {{ localize "OSE.AscArmorClassShort" }}</h4> | ||||
|             <div class="attribute-value"> | ||||
|                 <input name="data.aac.value" type="text" value="{{data.aac.value}}" data-dtype="Number" placeholder="10" | ||||
|                     data-dtype="Number" /> | ||||
|             </div> | ||||
|             {{else}} | ||||
|             <h4 class="attribute-name box-title" title="{{ localize 'OSE.ArmorClass' }}"> | ||||
|                 {{ localize "OSE.ArmorClassShort" }}</h4> | ||||
|             <div class="attribute-value"> | ||||
|                 <input name="data.ac.value" type="text" value="{{data.ac.value}}" data-dtype="Number" placeholder="9" | ||||
|                     data-dtype="Number" /> | ||||
|             </div> | ||||
|             {{/if}} | ||||
|         </li> | ||||
|         <li class="attribute"> | ||||
|             <h4 class="attribute-name box-title" title="{{localize 'OSE.Thac0'}}">{{ localize "OSE.Thac0" }}</h4> | ||||
|  | @ -23,15 +40,19 @@ | |||
|                     data-dtype="Number" /> | ||||
|             </div> | ||||
|         </li> | ||||
|         {{#if data.retainer.enabled}} | ||||
|         <li class="attribute"> | ||||
|             <h4 class="attribute-name box-title" title="{{localize 'OSE.Attacks'}}">{{ localize "OSE.AttacksShort" }}</h4> | ||||
|             <h4 class="attribute-name box-title" title="{{ localize 'OSE.Loyalty' }}">{{ localize "OSE.LoyaltyShort" }} | ||||
|             </h4> | ||||
|             <div class="attribute-value"> | ||||
|                 <input name="data.att.value" type="text" value="{{data.att.value}}" placeholder="0" | ||||
|                 <input name="data.retainer.loyalty" type="text" value="{{data.retainer.loyalty}}" placeholder="0" | ||||
|                     data-dtype="Number" /> | ||||
|             </div> | ||||
|         </li> | ||||
|         {{/if}} | ||||
|         <li class="attribute"> | ||||
|             <h4 class="attribute-name box-title" title="{{localize 'OSE.Movement'}}">{{ localize "OSE.MovementShort" }}</h4> | ||||
|             <h4 class="attribute-name box-title" title="{{localize 'OSE.Movement'}}">{{ localize "OSE.MovementShort" }} | ||||
|             </h4> | ||||
|             <div class="attribute-value"> | ||||
|                 <input name="data.movement.value" type="text" value="{{data.movement.value}}" placeholder="0" | ||||
|                     data-dtype="Number" /> | ||||
|  | @ -40,17 +61,18 @@ | |||
| </section> | ||||
| <section class="flexrow attribute-row"> | ||||
|     {{!-- Skills and abilities --}} | ||||
|     <div class="flex3 panel abilities"> | ||||
|         <div class="panel-title"> | ||||
|             <h4>{{localize 'OSE.panel.abilities'}}</h4> | ||||
|             <div class="item-controls"> | ||||
|                 {{#if owner}} | ||||
|                 <a class="item-control item-create" title='{{localize "OSE.Add"}}' data-type="ability"><i class="fas fa-plus"></i></a> | ||||
|                 {{/if}} | ||||
|             </div> | ||||
|         </div> | ||||
|         <ul class="panel-content inventory resizable" data-base-size="220"> | ||||
|             <div class=""> | ||||
|     <div class="flex3 panel inventory abilities"> | ||||
|         <div> | ||||
|             <li class="item-titles flexrow panel-title"> | ||||
|                 <div class="item-name">{{localize 'OSE.panel.abilities'}} & {{localize 'OSE.panel.equipment'}}</div> | ||||
|                 <div class="item-controls"> | ||||
|                     {{#if owner}} | ||||
|                     <a class="item-control item-create" title='{{localize "OSE.Add"}}' data-type="choice" | ||||
|                         data-choices="weapon,ability,armor,item"><i class="fas fa-plus"></i></a> | ||||
|                     {{/if}} | ||||
|                 </div> | ||||
|             </li> | ||||
|             <ol class="item-list resizable" data-base-size="240"> | ||||
|                 {{#each abilities as |item|}} | ||||
|                 <li class="item-entry"> | ||||
|                     <div class="item flexrow" data-item-id="{{item._id}}"> | ||||
|  | @ -62,31 +84,17 @@ | |||
|                         </div> | ||||
|                         <div class="item-controls"> | ||||
|                             {{#if ../owner}} | ||||
|                             <a class="item-control item-edit" title='{{localize "Ose.Edit"}}'><i | ||||
|                             <a class="item-control item-edit" title='{{localize "OSE.Edit"}}'><i | ||||
|                                     class="fas fa-edit"></i></a> | ||||
|                             <a class="item-control item-delete" title='{{localize "Ose.Delete"}}'><i | ||||
|                             <a class="item-control item-delete" title='{{localize "OSE.Delete"}}'><i | ||||
|                                     class="fas fa-trash"></i></a> | ||||
|                             {{/if}} | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </li> | ||||
|                 {{/each}} | ||||
|             </div> | ||||
|         </ul> | ||||
|     </div> | ||||
|     {{!-- Equipment --}} | ||||
|     <div class="flex3 panel abilities"> | ||||
|         <div class="panel-title"> | ||||
|             <h4>{{localize 'OSE.panel.equipment'}}</h4> | ||||
|             <div class="item-controls"> | ||||
|                 {{#if owner}} | ||||
|                 <a class="item-control item-create" title='{{localize "OSE.Add"}}' data-type="item"><i class="fas fa-plus"></i></a> | ||||
|                 {{/if}} | ||||
|             </div> | ||||
|         </div> | ||||
|         <ul class="panel-content inventory resizable" data-base-size="220"> | ||||
|             <div class=""> | ||||
|                 {{#each inventory as |item|}} | ||||
|                 {{#each owned as |section| }} | ||||
|                 {{#each section as |item|}} | ||||
|                 <li class="item-entry"> | ||||
|                     <div class="item flexrow" data-item-id="{{item._id}}"> | ||||
|                         <div class="item-name flexrow"> | ||||
|  | @ -96,50 +104,61 @@ | |||
|                             </h4> | ||||
|                         </div> | ||||
|                         <div class="item-controls"> | ||||
|                             {{#if ../owner}} | ||||
|                             <a class="item-control item-edit" title='{{localize "Ose.Edit"}}'><i | ||||
|                             {{#if ../../owner}} | ||||
|                             <a class="item-control item-edit" title='{{localize "OSE.Edit"}}'><i | ||||
|                                     class="fas fa-edit"></i></a> | ||||
|                             <a class="item-control item-delete" title='{{localize "Ose.Delete"}}'><i | ||||
|                             <a class="item-control item-delete" title='{{localize "OSE.Delete"}}'><i | ||||
|                                     class="fas fa-trash"></i></a> | ||||
|                             {{/if}} | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </li> | ||||
|                 {{/each}} | ||||
|             </div> | ||||
|         </ul> | ||||
|                 {{/each}} | ||||
|             </ol> | ||||
|         </div> | ||||
|     </div> | ||||
|     {{!-- Saving throws --}} | ||||
|     <div class="attribute-group"> | ||||
|         <div class="attacks-description"> | ||||
|             <label>{{ localize "OSE.Attacks" }}</label> | ||||
|             <input name="data.att" type="text" value="{{data.att}}" placeholder="0" data-dtype="String" /> | ||||
|         </div> | ||||
|         <ul class="attributes"> | ||||
|             <li class="attribute"> | ||||
|                 <h4 class="attribute-name box-title" title="{{ localize 'OSE.saves.death.long' }}">{{ localize "OSE.saves.death.short" }}</h4> | ||||
|             <li class="attribute saving-throw" data-save="death"> | ||||
|                 <h4 class="attribute-name box-title" title="{{ localize 'OSE.saves.death.long' }}"> | ||||
|                     <a>{{ localize "OSE.saves.death.long" }}</a></h4> | ||||
|                 <div class="attribute-value"> | ||||
|                     <input name="data.saves.d.value" type="text" value="{{data.saves.d.value}}" placeholder="0" | ||||
|                     <input name="data.saves.death.value" type="text" value="{{data.saves.death.value}}" placeholder="0" | ||||
|                         data-dtype="Number" /> | ||||
|             </li> | ||||
|             <li class="attribute"> | ||||
|                 <h4 class="attribute-name box-title" title="{{ localize 'OSE.saves.wands.long' }}">{{ localize "OSE.saves.wands.short" }}</h4> | ||||
|             <li class="attribute saving-throw" data-save="wand"> | ||||
|                 <h4 class="attribute-name box-title" title="{{ localize 'OSE.saves.wand.long' }}"> | ||||
|                     <a>{{ localize "OSE.saves.wand.long" }}</a></h4> | ||||
|                 <div class="attribute-value"> | ||||
|                     <input name="data.saves.w.value" type="text" value="{{data.saves.w.value}}" placeholder="0" | ||||
|                     <input name="data.saves.wand.value" type="text" value="{{data.saves.wand.value}}" placeholder="0" | ||||
|                         data-dtype="Number" /> | ||||
|             </li> | ||||
|             <li class="attribute"> | ||||
|                 <h4 class="attribute-name box-title" title="{{ localize 'OSE.saves.paralysis.long' }}">{{ localize "OSE.saves.paralysis.short" }}</h4> | ||||
|             <li class="attribute saving-throw" data-save="paralysis"> | ||||
|                 <h4 class="attribute-name box-title" title="{{ localize 'OSE.saves.paralysis.long' }}"> | ||||
|                     <a>{{ localize "OSE.saves.paralysis.long" }}</a></h4> | ||||
|                 <div class="attribute-value"> | ||||
|                     <input name="data.saves.p.value" type="text" value="{{data.saves.p.value}}" placeholder="0" | ||||
|                         data-dtype="Number" /> | ||||
|                     <input name="data.saves.paralysis.value" type="text" value="{{data.saves.paralysis.value}}" | ||||
|                         placeholder="0" data-dtype="Number" /> | ||||
|             </li> | ||||
|             <li class="attribute"> | ||||
|                 <h4 class="attribute-name box-title" title="{{ localize 'OSE.saves.breath.long' }}">{{ localize "OSE.saves.breath.short" }}</h4> | ||||
|             <li class="attribute saving-throw" data-save="breath"> | ||||
|                 <h4 class="attribute-name box-title" title="{{ localize 'OSE.saves.breath.long' }}"> | ||||
|                     <a>{{ localize "OSE.saves.breath.long" }}</a></h4> | ||||
|                 <div class="attribute-value"> | ||||
|                     <input name="data.saves.b.value" type="text" value="{{data.saves.b.value}}" placeholder="0" | ||||
|                         data-dtype="Number" /> | ||||
|                     <input name="data.saves.breath.value" type="text" value="{{data.saves.breath.value}}" | ||||
|                         placeholder="0" data-dtype="Number" /> | ||||
|             </li> | ||||
|             <li class="attribute"> | ||||
|                 <h4 class="attribute-name box-title" title="{{ localize 'OSE.saves.spells.long' }}">{{ localize "OSE.saves.spells.short" }}</h4> | ||||
|             <li class="attribute saving-throw" data-save="spell"> | ||||
|                 <h4 class="attribute-name box-title" title="{{ localize 'OSE.saves.spell.long' }}"> | ||||
|                     <a>{{ localize "OSE.saves.spell.long" }}</a></h4> | ||||
|                 <div class="attribute-value"> | ||||
|                     <input name="data.saves.s.value" type="text" value="{{data.saves.s.value}}" placeholder="0" /> | ||||
|                     <input name="data.saves.spell.value" type="text" value="{{data.saves.spell.value}}" | ||||
|                         placeholder="0" /> | ||||
|             </li> | ||||
|         </ul> | ||||
|     </div> | ||||
|  |  | |||
|  | @ -31,10 +31,12 @@ | |||
|         placeholder="{{ localize 'OSE.Experience' }}" /> | ||||
|       <label>{{localize 'OSE.Experience'}}</label> | ||||
|     </li> | ||||
|     {{#if config.morale}} | ||||
|     <li> | ||||
|       <input type="text" name="data.details.morale" value="{{data.details.morale}}" | ||||
|         placeholder="{{ localize 'OSE.Morale' }}" /> | ||||
|       <label>{{localize 'OSE.Morale'}}</label> | ||||
|     </li> | ||||
|     {{/if}} | ||||
|   </ul> | ||||
| </section> | ||||
|  | @ -0,0 +1,38 @@ | |||
| <div class="ose chat-card item-card" data-actor-id="{{actor._id}}" data-item-id="{{item._id}}" | ||||
|      {{#if tokenId}}data-token-id="{{tokenId}}"{{/if}}> | ||||
|     <header class="card-header flexrow"> | ||||
|         <img src="{{item.img}}" title="{{item.name}}" width="36" height="36"/> | ||||
|         <h3 class="item-name">{{item.name}}</h3> | ||||
|     </header> | ||||
| 
 | ||||
|     <div class="card-content"> | ||||
|         {{{data.description}}} | ||||
|     </div> | ||||
| 
 | ||||
|     <div class="card-buttons"> | ||||
|         {{#if hasAttack}}<button data-action="attack">{{ localize "OSE.Attack" }}</button>{{/if}} | ||||
| 
 | ||||
|         {{#if hasDamage}} | ||||
|         <button data-action="damage"> | ||||
|             {{#if isHealing}}{{ localize "OSE.Healing" }} | ||||
|             {{else}}{{localize "OSE.Damage" }}{{/if}} | ||||
|         </button> | ||||
|         {{/if}} | ||||
| 
 | ||||
|         {{#if hasSave}} | ||||
|         <button data-action="save" data-ability="{{data.save.ability}}" disabled> | ||||
|             {{ localize "OSE.SavingThrow" }} {{labels.save}} | ||||
|         </button> | ||||
|         {{/if}} | ||||
| 
 | ||||
|         {{#if data.formula}} | ||||
|         <button data-action="formula">{{ localize "OSE.OtherFormula"}}</button> | ||||
|         {{/if}} | ||||
|     </div> | ||||
| 
 | ||||
|     <footer class="card-footer"> | ||||
|         {{#each data.properties}} | ||||
|         <span>{{this}}</span> | ||||
|         {{/each}} | ||||
|     </footer> | ||||
| </div> | ||||
|  | @ -0,0 +1,7 @@ | |||
| <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 rollOSE}}<div>{{{rollOSE}}}</div>{{/if}} | ||||
|     </div> | ||||
| </section> | ||||
|  | @ -0,0 +1,20 @@ | |||
| <form> | ||||
|     <div class="form-group"> | ||||
|         <label>{{localize "OSE.Formula"}}</label> | ||||
|         <input type="text" name="formula" value="{{formula}}" disabled /> | ||||
|     </div> | ||||
|     <div class="form-group"> | ||||
|         <label>{{localize "OSE.SitMod"}}</label> | ||||
|         <input type="text" name="bonus" value="" placeholder="{{localize 'OSE.RollExample'}}" /> | ||||
|     </div> | ||||
|     <div class="form-group"> | ||||
|         <label>{{localize "OSE.RollMode"}}</label> | ||||
|         <select name="rollMode"> | ||||
|             {{#select rollMode}} | ||||
|             {{#each rollModes as |label mode|}} | ||||
|             <option value="{{mode}}">{{localize label}}</option> | ||||
|             {{/each}} | ||||
|             {{/select}} | ||||
|         </select> | ||||
|     </div> | ||||
| </form> | ||||
|  | @ -3,17 +3,30 @@ | |||
|     <img class="profile-img" src="{{item.img}}" data-edit="img" title="{{item.name}}" /> | ||||
|     <div class="header-col"> | ||||
|       <h1 class="charname"> | ||||
|         <input | ||||
|           name="name" | ||||
|           type="text" | ||||
|           value="{{item.name}}" | ||||
|           placeholder="Name" | ||||
|         /> | ||||
|         <input name="name" type="text" value="{{item.name}}" placeholder="Name" /> | ||||
|       </h1> | ||||
|     </div> | ||||
|   </header> | ||||
|   <section class="sheet-body"> | ||||
|     {{editor content=data.description target="data.description" | ||||
|     button=true owner=owner editable=editable}} | ||||
|     <div class="flexrow"> | ||||
|       <div class="stats"> | ||||
|         <div class="form-group block-input"> | ||||
|           <label>{{localize 'OSE.abilities.Requirements'}}</label> | ||||
|           <div class="form-fields"> | ||||
|             <input type="text" name="data.requirements" value="{{data.requirements}}" data-dtype="String" /> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div class="form-group block-input"> | ||||
|           <label>{{localize 'OSE.items.Roll'}}</label> | ||||
|           <div class="form-fields"> | ||||
|             <input type="text" name="data.roll" value="{{data.roll}}" data-dtype="String" /> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="description"> | ||||
|         {{editor content=data.description target="data.description" button=true | ||||
|         owner=owner editable=editable}} | ||||
|       </div> | ||||
|     </div> | ||||
|   </section> | ||||
| </form> | ||||
| </form> | ||||
|  | @ -0,0 +1,44 @@ | |||
| <form class="{{cssClass}}" autocomplete="off"> | ||||
|   <header class="sheet-header"> | ||||
|     <img class="profile-img" src="{{item.img}}" data-edit="img" title="{{item.name}}" /> | ||||
|     <div class="header-col"> | ||||
|       <h1 class="charname"> | ||||
|         <input name="name" type="text" value="{{item.name}}" placeholder="Name" /> | ||||
|       </h1> | ||||
|     </div> | ||||
|   </header> | ||||
|   <section class="sheet-body"> | ||||
|     <div class="flexrow"> | ||||
|       <div class="stats"> | ||||
|         <div class="form-group"> | ||||
|           <label>{{localize 'OSE.items.ArmorAC'}}</label> | ||||
|           <div class="form-fields"> | ||||
|             <input type="text" name="data.level" value="{{data.ac}}" data-dtype="Number" /> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div class="form-group"> | ||||
|           <label>{{localize 'OSE.items.ArmorAAC'}}</label> | ||||
|           <div class="form-fields"> | ||||
|             <input type="text" name="data.class" value="{{data.aac}}" data-dtype="Number" /> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div class="form-group"> | ||||
|           <label>{{localize 'OSE.items.Cost'}}</label> | ||||
|           <div class="form-fields"> | ||||
|             <input type="text" name="data.cost" value="{{data.cost}}" data-dtype="Number" /> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div class="form-group"> | ||||
|           <label>{{localize 'OSE.items.Weight'}}</label> | ||||
|           <div class="form-fields"> | ||||
|             <input type="text" name="data.weight" value="{{data.weight}}" data-dtype="Number" /> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="description"> | ||||
|         {{editor content=data.description target="data.description" button=true | ||||
|         owner=owner editable=editable}} | ||||
|       </div> | ||||
|     </div> | ||||
|   </section> | ||||
| </form> | ||||
|  | @ -3,17 +3,36 @@ | |||
|     <img class="profile-img" src="{{item.img}}" data-edit="img" title="{{item.name}}" /> | ||||
|     <div class="header-col"> | ||||
|       <h1 class="charname"> | ||||
|         <input | ||||
|           name="name" | ||||
|           type="text" | ||||
|           value="{{item.name}}" | ||||
|           placeholder="Name" | ||||
|         /> | ||||
|         <input name="name" type="text" value="{{item.name}}" placeholder="Name" /> | ||||
|       </h1> | ||||
|     </div> | ||||
|   </header> | ||||
|   <section class="sheet-body"> | ||||
|     {{editor content=data.description target="data.description" | ||||
|     button=true owner=owner editable=editable}} | ||||
|     <div class="flexrow"> | ||||
|       <div class="stats"> | ||||
|         <div class="form-group"> | ||||
|           <label>{{localize 'OSE.items.Quantity'}}</label> | ||||
|           <div class="form-fields"> | ||||
|             <input type="text" name="data.quantity.value" value="{{data.quantity.value}}" data-dtype="Number" />/<input type="text" name="data.quantity.max" value="{{data.quantity.max}}" data-dtype="Number" /> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div class="form-group"> | ||||
|           <label>{{localize 'OSE.items.Cost'}}</label> | ||||
|           <div class="form-fields"> | ||||
|             <input type="text" name="data.cost" value="{{data.cost}}" data-dtype="Number" /> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div class="form-group"> | ||||
|           <label>{{localize 'OSE.items.Weight'}}</label> | ||||
|           <div class="form-fields"> | ||||
|             <input type="text" name="data.weight" value="{{data.weight}}" data-dtype="String" /> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="description weapon-editor"> | ||||
|         {{editor content=data.description target="data.description" button=true | ||||
|         owner=owner editable=editable}} | ||||
|       </div> | ||||
|     </div> | ||||
|   </section> | ||||
| </form> | ||||
| </form> | ||||
|  | @ -3,17 +3,48 @@ | |||
|     <img class="profile-img" src="{{item.img}}" data-edit="img" title="{{item.name}}" /> | ||||
|     <div class="header-col"> | ||||
|       <h1 class="charname"> | ||||
|         <input | ||||
|           name="name" | ||||
|           type="text" | ||||
|           value="{{item.name}}" | ||||
|           placeholder="Name" | ||||
|         /> | ||||
|         <input name="name" type="text" value="{{item.name}}" placeholder="Name" /> | ||||
|       </h1> | ||||
|     </div> | ||||
|   </header> | ||||
|   <section class="sheet-body"> | ||||
|     {{editor content=data.description target="data.description" | ||||
|     button=true owner=owner editable=editable}} | ||||
|     <div class="flexrow"> | ||||
|       <div class="stats"> | ||||
|         <div class="form-group"> | ||||
|           <label>{{localize 'OSE.spells.Level'}}</label> | ||||
|           <div class="form-fields"> | ||||
|             <input type="text" name="data.lvl" value="{{data.lvl}}" data-dtype="Number" /> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div class="form-group block-input"> | ||||
|           <label>{{localize 'OSE.spells.Class'}}</label> | ||||
|           <div class="form-fields"> | ||||
|             <input type="text" name="data.class" value="{{data.class}}" data-dtype="String" /> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div class="form-group block-input"> | ||||
|           <label>{{localize 'OSE.spells.Range'}}</label> | ||||
|           <div class="form-fields"> | ||||
|             <input type="text" name="data.range" value="{{data.range}}" data-dtype="String" /> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div class="form-group block-input"> | ||||
|           <label>{{localize 'OSE.spells.Duration'}}</label> | ||||
|           <div class="form-fields"> | ||||
|             <input type="text" name="data.duration" value="{{data.duration}}" data-dtype="String" /> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div class="form-group block-input"> | ||||
|           <label>{{localize 'OSE.items.Roll'}}</label> | ||||
|           <div class="form-fields"> | ||||
|             <input type="text" name="data.roll" value="{{data.roll}}" data-dtype="String" /> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="description"> | ||||
|         {{editor content=data.description target="data.description" button=true | ||||
|         owner=owner editable=editable}} | ||||
|       </div> | ||||
|     </div> | ||||
|   </section> | ||||
| </form> | ||||
| </form> | ||||
|  | @ -0,0 +1,59 @@ | |||
| <form class="{{cssClass}}" autocomplete="off"> | ||||
|   <header class="sheet-header"> | ||||
|     <img class="profile-img" src="{{item.img}}" data-edit="img" title="{{item.name}}" /> | ||||
|     <div class="header-col"> | ||||
|       <h1 class="charname"> | ||||
|         <input name="name" type="text" value="{{item.name}}" placeholder="Name" /> | ||||
|       </h1> | ||||
|     </div> | ||||
|   </header> | ||||
|   <section class="sheet-body"> | ||||
|     <div class="flexrow"> | ||||
|       <input name="data.qualities" type="text" value="{{data.qualities}}" placeholder="Qualities" /> | ||||
|     </div> | ||||
|     <div class="flexrow"> | ||||
|       <div class="stats"> | ||||
|         <div class="form-group block-input"> | ||||
|           <label>{{localize 'OSE.items.Damage'}}</label> | ||||
|           <div class="form-fields"> | ||||
|             <input type="text" name="data.damage" value="{{data.damage}}" data-dtype="String" /> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div class="form-group"> | ||||
|           <label>{{localize 'OSE.items.Slow'}}</label> | ||||
|           <div class="form-fields"> | ||||
|             <input type="checkbox" name="data.slow" value="{{data.level}}" {{checked data.slow}} /> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div class="form-group"> | ||||
|           <label>{{localize 'OSE.items.Missile'}}</label> | ||||
|           <div class="form-fields"> | ||||
|             <input type="checkbox" name="data.missile" {{checked data.missile}} /> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div class="form-group"> | ||||
|           <label>{{localize 'OSE.items.Melee'}}</label> | ||||
|           <div class="form-fields"> | ||||
|             <input type="checkbox" name="data.melee" {{checked data.melee}} /> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div class="form-group"> | ||||
|           <label>{{localize 'OSE.items.Cost'}}</label> | ||||
|           <div class="form-fields"> | ||||
|             <input type="text" name="data.cost" value="{{data.cost}}" data-dtype="Number" /> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div class="form-group"> | ||||
|           <label>{{localize 'OSE.items.Weight'}}</label> | ||||
|           <div class="form-fields"> | ||||
|             <input type="text" name="data.weight" value="{{data.weight}}" data-dtype="Number" /> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="description weapon-editor"> | ||||
|         {{editor content=data.description target="data.description" button=true | ||||
|         owner=owner editable=editable}} | ||||
|       </div> | ||||
|     </div> | ||||
|   </section> | ||||
| </form> | ||||
		Loading…
	
		Reference in New Issue