188 lines
5.3 KiB
JavaScript
188 lines
5.3 KiB
JavaScript
import { AcksActor } from '../actor/entity.js';
|
|
import { AcksDice } from "../dice.js";
|
|
|
|
export class AcksCharacterCreator extends FormApplication {
|
|
static get defaultOptions() {
|
|
const options = super.defaultOptions;
|
|
options.classes = ["acks", "dialog", "creator"],
|
|
options.id = 'character-creator';
|
|
options.template =
|
|
'systems/acks/templates/actors/dialogs/character-creation.html';
|
|
options.width = 235;
|
|
return options;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
|
|
/**
|
|
* Add the Entity name into the window title
|
|
* @type {String}
|
|
*/
|
|
get title() {
|
|
return `${this.object.name}: ${game.i18n.localize('ACKS.dialog.generator')}`;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
|
|
/**
|
|
* Construct and return the data object used to render the HTML template for this form application.
|
|
* @return {Object}
|
|
*/
|
|
getData() {
|
|
let data = this.object.data;
|
|
data.user = game.user;
|
|
data.config = CONFIG.ACKS;
|
|
data.counters = {
|
|
str: 0,
|
|
wis: 0,
|
|
dex: 0,
|
|
int: 0,
|
|
cha: 0,
|
|
con: 0,
|
|
gold: 0
|
|
}
|
|
data.stats = {
|
|
sum: 0,
|
|
avg: 0,
|
|
std: 0
|
|
}
|
|
return data;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
|
|
doStats(ev) {
|
|
let list = $(ev.currentTarget).closest('.attribute-list');
|
|
let values = [];
|
|
list.find('.score-value').each((i, s) => {
|
|
if (s.value != 0) {
|
|
values.push(parseInt(s.value));
|
|
}
|
|
})
|
|
|
|
let n = values.length;
|
|
let sum = values.reduce((a, b) => a + b);
|
|
let mean = parseFloat(sum) / n;
|
|
let std = Math.sqrt(values.map(x => Math.pow(x - mean, 2)).reduce((a, b) => a + b) / n);
|
|
|
|
let stats = list.siblings('.roll-stats');
|
|
stats.find('.sum').text(sum);
|
|
stats.find('.avg').text(Math.round(10 * sum / n) / 10);
|
|
stats.find('.std').text(Math.round(100 * std) / 100);
|
|
|
|
if (n >= 6) {
|
|
$(ev.currentTarget).closest('form').find('button[type="submit"]').removeAttr('disabled');
|
|
}
|
|
|
|
this.object.data.stats = {
|
|
sum: sum,
|
|
avg: Math.round(10 * sum / n) / 10,
|
|
std: Math.round(100 * std) / 100
|
|
}
|
|
}
|
|
|
|
rollScore(score, options = {}) {
|
|
// Increase counter
|
|
this.object.data.counters[score]++;
|
|
|
|
const label = score != "gold" ? game.i18n.localize(`ACKS.scores.${score}.long`) : "Gold";
|
|
const rollParts = ["3d6"];
|
|
const data = {
|
|
roll: {
|
|
type: "result"
|
|
}
|
|
};
|
|
// Roll and return
|
|
return AcksDice.Roll({
|
|
event: options.event,
|
|
parts: rollParts,
|
|
data: data,
|
|
skipDialog: true,
|
|
speaker: ChatMessage.getSpeaker({ actor: this }),
|
|
flavor: game.i18n.format('ACKS.dialog.generateScore', { score: label, count: this.object.data.counters[score] }),
|
|
title: game.i18n.format('ACKS.dialog.generateScore', { score: label, count: this.object.data.counters[score] }),
|
|
});
|
|
}
|
|
|
|
async close(options) {
|
|
// Gather scores
|
|
let scores = {};
|
|
$(this.form.children).find(".score-roll").each((_, d) => {
|
|
let gr = $(d).closest('.form-group');
|
|
let val = gr.find(".score-value").val();
|
|
scores[gr.data("score")] = val;
|
|
})
|
|
const gold = $(this.form.children).find('.gold-value').val();
|
|
const speaker = ChatMessage.getSpeaker({ actor: this });
|
|
const templateData = {
|
|
config: CONFIG.ACKS,
|
|
scores: scores,
|
|
title: game.i18n.localize("ACKS.dialog.generator"),
|
|
stats: this.object.data.stats,
|
|
gold: gold
|
|
}
|
|
const content = await renderTemplate("/systems/acks/templates/chat/roll-creation.html", templateData)
|
|
ChatMessage.create({
|
|
content: content,
|
|
speaker,
|
|
});
|
|
return super.close(options);
|
|
}
|
|
|
|
/** @override */
|
|
activateListeners(html) {
|
|
super.activateListeners(html);
|
|
html.find('a.score-roll').click((ev) => {
|
|
let el = ev.currentTarget.parentElement.parentElement;
|
|
let score = el.dataset.score;
|
|
this.rollScore(score, { event: ev }).then(r => {
|
|
$(el).find('input').val(r.total).trigger('change');
|
|
});
|
|
});
|
|
|
|
html.find('a.gold-roll').click((ev) => {
|
|
let el = ev.currentTarget.parentElement.parentElement.parentElement;
|
|
this.rollScore("gold", { event: ev }).then(r => {
|
|
$(el).find('.gold-value').val(r.total * 10);
|
|
});
|
|
});
|
|
|
|
html.find('input.score-value').change(ev => {
|
|
this.doStats(ev);
|
|
})
|
|
}
|
|
|
|
async _onSubmit(event, { updateData = null, preventClose = false, preventRender = false } = {}) {
|
|
super._onSubmit(event, { updateData: updateData, preventClose: preventClose, preventRender: preventRender });
|
|
// Generate gold
|
|
let gold = event.target.elements.namedItem('gold').value;
|
|
const itemData = {
|
|
name: "GP",
|
|
type: "item",
|
|
img: "/systems/acks/assets/gold.png",
|
|
data: {
|
|
treasure: true,
|
|
cost: 1,
|
|
weight: 1,
|
|
quantity: {
|
|
value: gold
|
|
}
|
|
}
|
|
};
|
|
this.object.createOwnedItem(itemData);
|
|
}
|
|
/**
|
|
* 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);
|
|
}
|
|
}
|