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