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