Merge pull request #3 from thehappyanarchist/OSE-1.0.3

Ose 1.0.3
master
thehappyanarchist 2020-09-03 17:43:32 -10:00 committed by GitHub
commit 8cf10371c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 329 additions and 143 deletions

View File

@ -83,9 +83,33 @@
</div>
</div>
<div id="demo" class="row" style="text-align: center;">
<iframe width="560" height="315" src="https://www.youtube.com/embed/xKFuPXfyMoE" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<iframe width="560" height="315"
src="https://www.youtube.com/embed/xKFuPXfyMoE" frameborder="0"
allow="accelerometer; autoplay; encrypted-media; gyroscope;
picture-in-picture" allowfullscreen></iframe>
</div>
<div id="setup" class="row">
<h4>Installation</h4>
<p>
You'll need a Foundry VTT License or GM access to a Foundry VTT
server.
</p>
<p>
<ul>
<li>
Launch Foundry VTT.
</li>
<li>
Go to Game Systems, Install System.
</li>
<li>
Find 'Old-School Essentials' and click Install.
</li>
<li>
Create a new World using the Old-School Essentials system.
</li>
</ul>
</p>
<h4>Setup</h4>
<p>You can find System settings in the Configure Settings dialog you
open from the sidebar</p>

BIN
package/ose-v0.1.zip Normal file

Binary file not shown.

BIN
package/ose-v0.2.zip Normal file

Binary file not shown.

BIN
package/ose-v0.3.zip Normal file

Binary file not shown.

BIN
package/ose-v0.4.zip Normal file

Binary file not shown.

BIN
package/ose-v0.5.zip Normal file

Binary file not shown.

BIN
package/ose-v0.6.zip Normal file

Binary file not shown.

BIN
package/ose-v0.7.zip Normal file

Binary file not shown.

BIN
package/ose-v0.8.zip Normal file

Binary file not shown.

BIN
package/ose-v0.9.1.zip Normal file

Binary file not shown.

BIN
package/ose-v0.9.2.zip Normal file

Binary file not shown.

BIN
package/ose-v0.9.3.zip Normal file

Binary file not shown.

BIN
package/ose-v0.9.4.zip Normal file

Binary file not shown.

BIN
package/ose-v0.9.5.zip Normal file

Binary file not shown.

BIN
package/ose-v0.9.6.zip Normal file

Binary file not shown.

BIN
package/ose-v0.9.7.zip Normal file

Binary file not shown.

BIN
package/ose-v0.9.8.zip Normal file

Binary file not shown.

BIN
package/ose-v0.9.9.zip Normal file

Binary file not shown.

BIN
package/ose-v0.9.zip Normal file

Binary file not shown.

BIN
package/ose-v1.0.1.zip Normal file

Binary file not shown.

BIN
package/ose-v1.0.2.zip Normal file

Binary file not shown.

BIN
package/ose-v1.0.3.zip Normal file

Binary file not shown.

View File

@ -125,15 +125,22 @@ Hooks.on("renderCombatTracker", (object, html, data) => {
Hooks.on("preUpdateCombat", async (combat, data, diff, id) => {
let init = game.settings.get("acks", "initiative");
let reroll = game.settings.get("acks", "rerollInitiative");
if (!data.round) {
return;
}
if (data.round !== 1) {
if (reroll === "reset") {
OseCombat.resetInitiative(combat, data, diff, id);
return;
} else if (reroll === "keep") {
return;
}
}
if (init === "group") {
AcksCombat.rollInitiative(combat, data, diff, id);
} else if (init === "rerolled") {
} else if (init === "individual") {
AcksCombat.individualInitiative(combat, data, diff, id);
} else if (init === "reset") {
AcksCombat.resetInitiative(combat, data, diff, id);
}
});

View File

@ -95,6 +95,7 @@
"ACKS.saves.spell.short": "S",
"ACKS.saves.spell.long": "Spells",
"ACKS.saves.magic.long": "Bonus vs Magic",
"ACKS.saves.magic.short": "vs Magic",
"ACKS.Health": "Hit Points",
"ACKS.HealthMax": "Maximum Hit Points",
@ -160,11 +161,14 @@
"ACKS.category.equipment": "Equipment",
"ACKS.Setting.Initiative": "Initiative",
"ACKS.Setting.InitiativeHint": "Grouped or individual initiative. Unique individual is only rolled at the start of the combat",
"ACKS.Setting.InitiativeOnce": "Unique individual Initiative",
"ACKS.Setting.InitiativeReroll": "Roll individual Initiative each Round",
"ACKS.Setting.InitiativeReset": "Reset individual Initiative each Round",
"ACKS.Setting.InitiativeHint": "Grouped or individual initiative.",
"ACKS.Setting.InitiativeIndividual": "Individual initiative",
"ACKS.Setting.InitiativeGroup": "Grouped Initiative",
"ACKS.Setting.RerollInitiative": "Initiative persistence",
"ACKS.Setting.RerollInitiativeHint": "Keeps, resets or rerolls initiative each round",
"ACKS.Setting.InitiativeKeep": "Keep for each round",
"ACKS.Setting.InitiativeReroll": "Reroll each round",
"ACKS.Setting.InitiativeReset": "Reset each round",
"ACKS.Setting.AscendingAC": "Ascending Armor Class",
"ACKS.Setting.AscendingACHint": "The more the better",
"ACKS.Setting.Morale": "Enable monsters Morale Rating",

View File

@ -13,8 +13,7 @@ export class AcksActorSheet extends ActorSheet {
data.config = CONFIG.ACKS;
// Settings
data.config.ascendingAC = game.settings.get("acks", "ascendingAC");
data.config.encumbranceBasic =
game.settings.get("acks", "encumbranceOption") == "basic";
data.config.encumbrance = game.settings.get("acks", "encumbranceOption");
// Prepare owned items
this._prepareItems(data);
@ -120,11 +119,20 @@ export class AcksActorSheet extends ActorSheet {
}
activateListeners(html) {
super.activateListeners(html);
// Item summaries
html
.find(".item .item-name h4")
.click((event) => this._onItemSummary(event));
html.find(".item .item-controls .item-show").click(async (ev) => {
const li = $(ev.currentTarget).parents(".item");
const item = this.actor.getOwnedItem(li.data("itemId"));
item.show();
});
html.find(".saving-throw .attribute-name a").click((ev) => {
let actorObject = this.actor;
let element = event.currentTarget;
@ -132,12 +140,6 @@ export class AcksActorSheet extends ActorSheet {
actorObject.rollSave(save, { event: event });
});
html.find(".item .item-controls .item-show").click(async (ev) => {
const li = $(ev.currentTarget).parents(".item");
const item = this.actor.getOwnedItem(li.data("itemId"));
item.show();
});
html.find(".item .item-rollable .item-image").click(async (ev) => {
const li = $(ev.currentTarget).parents(".item");
const item = this.actor.getOwnedItem(li.data("itemId"));
@ -166,21 +168,35 @@ export class AcksActorSheet extends ActorSheet {
let attack = element.parentElement.parentElement.dataset.attack;
const rollData = {
actor: this.data,
roll: {}
}
actorObject.targetAttack(rollData, attack, {type: attack, skipDialog: ev.ctrlKey});
});
roll: {},
};
actorObject.targetAttack(rollData, attack, {
type: attack,
skipDialog: ev.ctrlKey,
});
html.find(".spells .item-reset").click((ev) => {
this._resetSpells(ev);
});
});
html.find(".hit-dice .attribute-name a").click((ev) => {
let actorObject = this.actor;
actorObject.rollHitDice({ event: event });
});
super.activateListeners(html);
// Everything below here is only needed if the sheet is editable
if (!this.options.editable) return;
html
.find(".memorize input")
.click((ev) => ev.target.select())
.change(this._onSpellChange.bind(this));
html.find(".spells .item-reset").click((ev) => {
this._resetSpells(ev);
});
}
// Override to set resizable initial size
@ -221,7 +237,7 @@ export class AcksActorSheet extends ActorSheet {
let heightDelta = this.position.height - this.options.height;
editor.style.height = `${
heightDelta + parseInt(container.dataset.editorSize)
}px`;
}px`;
}
});
}

View File

@ -26,7 +26,7 @@ export class AcksActorSheetCharacter extends AcksActorSheet {
resizable: true,
tabs: [
{
navSelector: ".tabs",
navSelector: ".sheet-tabs",
contentSelector: ".sheet-body",
initial: "attributes",
},
@ -136,6 +136,50 @@ export class AcksActorSheetCharacter extends AcksActorSheet {
* @param html {HTML} The prepared HTML object ready to be rendered into the DOM
*/
activateListeners(html) {
super.activateListeners(html);
html.find(".ability-score .attribute-name a").click((ev) => {
let actorObject = this.actor;
let element = event.currentTarget;
let score = element.parentElement.parentElement.dataset.score;
let stat = element.parentElement.parentElement.dataset.stat;
if (!score) {
if (stat == "lr") {
actorObject.rollLoyalty(score, { event: event });
}
} else {
actorObject.rollCheck(score, { event: event });
}
});
html.find(".exploration .attribute-name a").click((ev) => {
let actorObject = this.actor;
let element = event.currentTarget;
let expl = element.parentElement.parentElement.dataset.exploration;
actorObject.rollExploration(expl, { event: event });
});
html.find(".inventory .item-titles .item-caret").click((ev) => {
let items = $(event.currentTarget.parentElement.parentElement).children(
".item-list"
);
if (items.css("display") == "none") {
let el = $(event.currentTarget).find(".fas.fa-caret-right");
el.removeClass("fa-caret-right");
el.addClass("fa-caret-down");
items.slideDown(200);
} else {
let el = $(event.currentTarget).find(".fas.fa-caret-down");
el.removeClass("fa-caret-down");
el.addClass("fa-caret-right");
items.slideUp(200);
}
});
html.find("a[data-action='modifiers']").click((ev) => {
this._onShowModifiers(ev);
});
// Everything below here is only needed if the sheet is editable
if (!this.options.editable) return;
@ -200,53 +244,8 @@ export class AcksActorSheetCharacter extends AcksActorSheet {
.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;
let stat = element.parentElement.parentElement.dataset.stat;
if (!score) {
if (stat == "lr") {
actorObject.rollLoyalty(score, { event: event });
}
} else {
actorObject.rollCheck(score, { event: event });
}
});
html.find(".exploration .attribute-name a").click((ev) => {
let actorObject = this.actor;
let element = event.currentTarget;
let expl = element.parentElement.parentElement.dataset.exploration;
actorObject.rollExploration(expl, { event: event });
});
html.find(".inventory .item-titles .item-caret").click((ev) => {
let items = $(event.currentTarget.parentElement.parentElement).children(
".item-list"
);
if (items.css("display") == "none") {
let el = $(event.currentTarget).find(".fas.fa-caret-right");
el.removeClass("fa-caret-right");
el.addClass("fa-caret-down");
items.slideDown(200);
} else {
let el = $(event.currentTarget).find(".fas.fa-caret-down");
el.removeClass("fa-caret-down");
el.addClass("fa-caret-right");
items.slideUp(200);
}
});
html.find("a[data-action='modifiers']").click((ev) => {
this._onShowModifiers(ev);
});
html.find("a[data-action='generate-scores']").click((ev) => {
this.generateScores(ev);
});
// Handle default listeners last so system listeners are triggered first
super.activateListeners(html);
}
}

View File

@ -123,12 +123,15 @@ export class AcksActor extends Actor {
roll: {
type: "above",
target: this.data.data.saves[save].value,
magic: this.data.data.scores.wis.mod
},
details: game.i18n.format("ACKS.roll.details.save", { save: label }),
};
let skip = options.event && options.event.ctrlKey;
const rollMethod = this.data.type == "character" ? OseDice.RollSave : OseDice.Roll;
// Roll and return
return AcksDice.Roll({
event: options.event,
@ -384,7 +387,10 @@ export class AcksActor extends Actor {
if (game.user.targets.size > 0) {
for (let t of game.user.targets.values()) {
data.roll.target = t;
await this.rollAttack(data, { type: type, skipDialog: options.skipDialog });
await this.rollAttack(data, {
type: type,
skipDialog: options.skipDialog,
});
}
} else {
this.rollAttack(data, { type: type, skipDialog: options.skipDialog });
@ -437,7 +443,7 @@ export class AcksActor extends Actor {
thac0: thac0,
dmg: dmgParts,
save: attData.roll.save,
target: attData.roll.target
target: attData.roll.target,
},
};
@ -500,14 +506,20 @@ export class AcksActor extends Actor {
let totalWeight = 0;
let hasItems = false;
Object.values(this.data.items).forEach((item) => {
if (item.type == "item" && (['complete', 'disabled'].includes(option) || item.data.treasure)) {
totalWeight += item.data.quantity.value * item.data.weight;
if (item.type == "item" && !item.data.treasure) {
hasItems = true;
} else if (option != 'basic' && ['weapon', 'armor'].includes(item.type)) {
}
if (
item.type == "item" &&
(["complete", "disabled"].includes(option) || item.data.treasure)
) {
totalWeight += item.data.quantity.value * item.data.weight;
} else if (option != "basic" && ["weapon", "armor"].includes(item.type)) {
totalWeight += item.data.weight;
}
});
if (option === 'detailed' && hasItems) totalWeight += 80;
if (option === "detailed" && hasItems) totalWeight += 80;
data.encumbrance = {
pct: Math.clamped(

View File

@ -170,6 +170,24 @@ export class AcksActorSheetMonster extends AcksActorSheet {
* @param html {HTML} The prepared HTML object ready to be rendered into the DOM
*/
activateListeners(html) {
super.activateListeners(html);
html.find(".morale-check a").click((ev) => {
let actorObject = this.actor;
actorObject.rollMorale({ event: event });
});
html.find(".reaction-check a").click((ev) => {
let actorObject = this.actor;
actorObject.rollReaction({ event: event });
});
html.find(".appearing-check a").click((ev) => {
let actorObject = this.actor;
let check = $(ev.currentTarget).closest('.check-field').data('check');
actorObject.rollAppearing({ event: event, check: check });
});
// Everything below here is only needed if the sheet is editable
if (!this.options.editable) return;
@ -220,22 +238,6 @@ export class AcksActorSheetMonster extends AcksActorSheet {
this._resetCounters(ev);
});
html.find(".morale-check a").click((ev) => {
let actorObject = this.actor;
actorObject.rollMorale({ event: event });
});
html.find(".reaction-check a").click((ev) => {
let actorObject = this.actor;
actorObject.rollReaction({ event: event });
});
html.find(".appearing-check a").click((ev) => {
let actorObject = this.actor;
let check = $(ev.currentTarget).closest('.check-field').data('check');
actorObject.rollAppearing({ event: event, check: check });
});
html
.find(".counter input")
.click((ev) => ev.target.select())
@ -263,7 +265,5 @@ export class AcksActorSheetMonster extends AcksActorSheet {
});
html.find('button[data-action="generate-saves"]').click(() => this.generateSave());
// Handle default listeners last so system listeners are triggered first
super.activateListeners(html);
}
}

View File

@ -29,14 +29,15 @@ export class AcksCombat {
groups[data.combatants[i].flags.acks.group].initiative;
}
}
combat.setupTurns();
}
static async resetInitiative(combat, data) {
let updates = [];
combat.data.combatants.forEach((c, i) => {
updates.push({_id: c._id, initiative: ""});
});
await combat.updateEmbeddedEntity("Combatant", updates);
let reroll = game.settings.get("acks", "rerollInitiative");
if (!["reset", "reroll"].includes(reroll)) {
return;
}
combat.resetAll();
}
static async individualInitiative(combat, data) {
@ -171,7 +172,9 @@ export class AcksCombat {
}
let data = {};
AcksCombat.rollInitiative(game.combat, data);
game.combat.update({ data: data });
game.combat.update({ data: data }).then(() => {
game.combat.setupTurns();
});
});
}

View File

@ -128,16 +128,23 @@ export class AcksDice {
};
result.target = data.roll.thac0;
const targetAc = data.roll.target ? data.roll.target.actor.data.data.ac.value : 9;
const targetAac = data.roll.target ? data.roll.target.actor.data.data.aac.value : 0;
result.victim = data.roll.target ? data.roll.target.actor.name : null;
const targetAc = data.roll.target
? data.roll.target.actor.data.data.ac.value
: 9;
const targetAac = data.roll.target
? data.roll.target.actor.data.data.aac.value
: 0;
result.victim = data.roll.target ? data.roll.target.data.name : null;
if (game.settings.get("acks", "ascendingAC")) {
if (roll.total < targetAac + 10) {
result.details = game.i18n.format("ACKS.messages.AttackAscendingFailure", {
result: roll.total - 10,
bonus: result.target,
});
result.details = game.i18n.format(
"ACKS.messages.AttackAscendingFailure",
{
result: roll.total - 10,
bonus: result.target,
}
);
return result;
}
result.details = game.i18n.format("ACKS.messages.AttackAscendingSuccess", {
@ -257,6 +264,77 @@ export class AcksDice {
});
}
static async RollSave({
parts = [],
data = {},
skipDialog = false,
speaker = null,
flavor = null,
title = null,
} = {}) {
let rolled = false;
const template = "systems/acks/templates/chat/roll-dialog.html";
let dialogData = {
formula: parts.join(" "),
data: data,
rollMode: game.settings.get("core", "rollMode"),
rollModes: CONFIG.Dice.rollModes,
};
let rollData = {
parts: parts,
data: data,
title: title,
flavor: flavor,
speaker: speaker,
};
if (skipDialog) { AcksDice.sendRoll(rollData); }
let buttons = {
ok: {
label: game.i18n.localize("ACKS.Roll"),
icon: '<i class="fas fa-dice-d20"></i>',
callback: (html) => {
rolled = true;
rollData.form = html[0].children[0];
roll = AcksDice.sendRoll(rollData);
},
},
magic: {
label: game.i18n.localize("ACKS.saves.magic.short"),
icon: '<i class="fas fa-magic"></i>',
callback: (html) => {
rolled = true;
rollData.form = html[0].children[0];
rollData.data.roll.target = parseInt(rollData.data.roll.target) + parseInt(rollData.data.roll.magic);
rollData.title += ` ${game.i18n.localize("ACKS.saves.magic.short")} (${rollData.data.roll.magic})`;
roll = AcksDice.sendRoll(rollData);
},
},
cancel: {
icon: '<i class="fas fa-times"></i>',
label: game.i18n.localize("ACKS.Cancel"),
callback: (html) => { },
},
};
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);
});
}
static async Roll({
parts = [],
data = {},
@ -302,7 +380,7 @@ export class AcksDice {
cancel: {
icon: '<i class="fas fa-times"></i>',
label: game.i18n.localize("ACKS.Cancel"),
callback: (html) => {},
callback: (html) => { },
},
};

View File

@ -16,6 +16,20 @@ export const registerSettings = function () {
onChange: _ => window.location.reload()
});
game.settings.register("acks", "ascendingAC", {
name: game.i18n.localize("ACKS.Setting.RerollInitiative"),
hint: game.i18n.localize("ACKS.Setting.RerollInitiativeHint"),
default: "reset",
scope: "world",
type: String,
config: true,
choices: {
keep: "ACKS.Setting.InitiativeKeep",
reset: "ACKS.Setting.InitiativeReset",
reroll: "ACKS.Setting.InitiativeReroll",
}
});
game.settings.register("acks", "ascendingAC", {
name: game.i18n.localize("ACKS.Setting.AscendingAC"),
hint: game.i18n.localize("ACKS.Setting.AscendingACHint"),

View File

@ -30,38 +30,44 @@ export const augmentTable = (table, html, data) => {
});
};
async function rollTreasure(table, options = {}) {
let percent = (chance) => {
let roll = new Roll("1d100").roll();
function drawTreasure(table, data) {
const percent = (chance) => {
const roll = new Roll("1d100").roll();
return roll.total <= chance;
};
data.treasure = {};
if (table.getFlag('ose', 'treasure')) {
table.results.forEach((r) => {
if (percent(r.weight)) {
const text = table._getResultChatText(r);
data.treasure[r._id] = ({
img: r.img,
text: TextEditor.enrichHTML(text),
});
if ((r.type === CONST.TABLE_RESULT_TYPES.ENTITY) && (r.collection === "RollTable")) {
const embeddedTable = game.tables.get(r.resultId);
drawTreasure(embeddedTable, data.treasure[r._id]);
}
}
});
} else {
const results = table.roll().results;
results.forEach((s) => {
const text = TextEditor.enrichHTML(table._getResultChatText(s));
data.treasure[s._id] = {img: s.img, text: text};
});
}
return data;
}
async function rollTreasure(table, options = {}) {
// Draw treasure
const data = drawTreasure(table, {});
let templateData = {
treasure: [],
treasure: data.treasure,
table: table,
};
let ids = [];
table.results.forEach((r) => {
if (percent(r.weight)) {
let text = "";
switch (r.type) {
case 0:
text = r.text;
break;
case 1:
text = `@${r.collection}[${r.resultId}]{${r.text}}`;
break;
case 2:
text = `@Compendium[${r.collection}.${r.resultId}]{${r.text}}`;
}
templateData.treasure.push({
id: r._id,
img: r.img,
text: TextEditor.enrichHTML(text),
});
ids.push(r._id);
}
});
// Animation
if (options.event) {
let results = $(event.currentTarget.parentElement)
@ -69,7 +75,7 @@ async function rollTreasure(table, options = {}) {
.find(".table-result");
results.each((_, item) => {
item.classList.remove("active");
if (ids.includes(item.dataset.resultId)) {
if (data.treasure[item.dataset.resultId]) {
item.classList.add("active");
}
});
@ -82,7 +88,7 @@ async function rollTreasure(table, options = {}) {
let chatData = {
content: html,
sound: "/systems/acks/assets/coins.mp3"
// sound: "/systems/acks/assets/coins.mp3"
}
let rollMode = game.settings.get("core", "rollMode");

View File

@ -306,6 +306,18 @@
}
line-height: 36px;
}
.sub {
padding-left: 25px;
line-height: 28px;
img {
flex: 0 0 28px;
border: none;
}
div {
text-indent: 10px;
font-size: 14px;
}
}
}
h3 {
font-size: 12px;

View File

@ -4,7 +4,7 @@
"description": "Play B/X OSR modules with ACKS on Foundry VTT",
"version": "0.1.0",
"minimumCoreVersion": "0.6.2",
"compatibleCoreVersion": "0.6.5",
"compatibleCoreVersion": "0.6.6",
"templateVersion": 2,
"author": "The Happy Anarchist",
"esmodules": ["acks.js"],

View File

@ -5,7 +5,7 @@
</header>
{{! Sheet Tab Navigation }}
<nav class="sheet-tabs tabs flexrow" data-group="primary">
<nav class="sheet-tabs tabs" data-group="primary">
<a class="item" data-tab="attributes">
{{localize "ACKS.category.attributes"}}
</a>

View File

@ -31,12 +31,13 @@
{{#each item.data.tags as |tag|}}
{{#unless (getTagIcon tag.value)}}
<span title="{{tag.title}}">{{tag.value}}{{#unless @last}},{{/unless}}</span>
{{/unless}}
{{/each}}
</div>
<div class="field-short">
{{#if @root.config.encumbranceBasic}}_{{else}}{{item.data.weight}}{{/if}}
{{#if (eq @root.config.encumbrance "basic")}}_{{else}}{{item.data.weight}}{{/if}}
</div>
<div class="item-controls">
{{#if ../owner}}
@ -88,7 +89,7 @@
{{/if}}
</div>
<div class="field-short">
{{#if @root.config.encumbranceBasic}}_{{else}}{{item.data.weight}}{{/if}}
{{#if (eq @root.config.encumbrance "basic")}}_{{else}}{{item.data.weight}}{{/if}}
</div>
<div class="item-controls">
{{#if ../owner}}
@ -135,7 +136,7 @@
placeholder="0" />{{#if item.data.quantity.max}}<span>/{{item.data.quantity.max}}</span>{{/if}}
</div>
<div class="field-short">
{{#if @root.config.encumbranceBasic}}_{{else}}{{mult item.data.quantity.value item.data.weight}}{{/if}}
{{#if (eq @root.config.encumbrance "basic")}}_{{else if (eq @root.config.encumbrance "detailed")}}_{{else}}{{item.data.weight}}{{/if}}
</div>
<div class="item-controls">
{{#if ../owner}}
@ -158,7 +159,7 @@
<div class="field-short"><i class="fas fa-hashtag"></i></div>
<div class="field-short"><i class="fas fa-weight-hanging"></i></div>
<div class="item-controls">
<a class="item-control item-create" data-type="item" title="{{localize 'ACKS.Add'}}"><i
<a class="item-control item-create" data-type="item" data-treasure="true" title="{{localize 'ACKS.Add'}}"><i
class="fa fa-plus"></i></a>
</div>
</li>

View File

@ -7,8 +7,18 @@
<ol class="treasure-list">
{{#each treasure as |t|}}
<li class="treasure flexrow">
<img src="{{t.img}}" width="36" height="36" />
<div>{{{t.text}}}</div>
{{#if t.img}}<img src="{{t.img}}" width="36" height="36" />{{/if}}
<div>
<div>{{{t.text}}}</div>
{{#each t.treasure}}
<li class="sub flexrow">
{{#if img}}<img src="{{img}}" width="28" height="28">{{/if}}
<div>
{{{text}}}
</div>
</li>
{{/each}}
</div>
</li>
{{/each}}
</ol>