Merge branch 'development'

master
U~man 2020-07-03 23:17:33 +02:00
commit 7801ae290c
43 changed files with 2244 additions and 690 deletions

BIN
src/assets/back.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

BIN
src/assets/heart_empty.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
src/assets/heart_full.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
src/assets/shield.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@ -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"
}

View File

@ -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",

View File

@ -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;
}
}

View File

@ -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`;
});
}
}

View File

@ -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),
}
}
}

View File

@ -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`;
});
}
}

View File

@ -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);
}
}

170
src/module/dice.js Normal file
View File

@ -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);
});
}
}

26
src/module/helpers.js Normal file
View File

@ -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);
});
};

View File

@ -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);
}
}

View File

@ -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',

47
src/module/settings.js Normal file
View File

@ -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
});
}

View File

@ -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;

View File

@ -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;
}
}
}

View File

@ -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;
}
}

View File

@ -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 */
/* ----------------------------------------- */

View File

@ -37,4 +37,4 @@
.resizable {
overflow: auto;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}
}

View File

@ -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;

View File

@ -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": ""
}
}

View File

@ -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}}

View File

@ -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>

View File

@ -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}}

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>