import { VERMINE } from "./config.mjs";
import { getActorSkillScore, updateActorSkillScore } from "./functions.mjs";
export class VermineFight {
async performTest(enemyAchievement, enemyConservation, skillKey, skill, params, actor) {
const dicePool = (params.spleen != undefined || params.purpose != undefined) ? '5' : '4';
const r = new Roll(dicePool + `d6`);
let diceString = '';
let dicePoolHint = '';
let discardedRoll = false;
let bonus = 0;
let bonusText = '/+';
let currentSkillScore = skill;
r.roll(); // dice are rolled
if (params.usure != undefined) {
currentSkillScore += params.usure;
bonus += params.usure;
}
if (params.specialization != undefined) {
currentSkillScore += 2;
}
if (params.trait != undefined) {
currentSkillScore += params.trait;
bonus += params.trait;
}
bonusText += bonus;
let targetText = game.i18n.format('VERMINE.Selected') + ' : ' + game.i18n.format(skillKey) + " " + skill + bonusText;
if (params.specialization != undefined) {
targetText += " (S)";
}
// tri par ordre croissant
r.terms[0].results.sort((a, b) => a.result - b.result);
if (params.purpose != undefined) {
discardedRoll = r.terms[0].results.shift();
dicePoolHint = ' - ' + game.i18n.format('VERMINE.PurposeTrait');
} else if (params.spleen != undefined) {
discardedRoll = r.terms[0].results.pop();
dicePoolHint = ' - ' + game.i18n.format('VERMINE.SpleenTrait');
}
const discardedRollText = (discardedRoll.result != undefined) ? '
' + discardedRoll.result + '
' : "";
for (let i = 0; i < r.terms[0].results.length; i++) {
let result = r.terms[0].results[i].result;
diceString += '' + result + '';
}
let hintText = game.i18n.format('VERMINE.ConfrontationHint');
// Build a dynamic html using the variables from above.
const html = `
` + dicePool + `d6 ` + dicePoolHint + `
` +
`
` + hintText + `
`;
// Check if the dice3d module exists (Dice So Nice). If it does, post a roll in that and then
// send to chat after the roll has finished. If not just send to chat.
if (game.dice3d) {
game.dice3d.showForRoll(r).then((displayed) => {
this.sendToChat(html, r, actor);
});
} else {
this.sendToChat(html, r, actor);
};
// on fait les comptes
}
async sendToChat(content, roll, actor) {
let conf = {
user: game.user._id,
content: content,
roll: roll,
// sound: 'sounds/dice.wav'
};
if (actor)
conf.speaker = ChatMessage.getSpeaker({ actor: actor });
// Send's Chat Message to foundry, if items are missing they will appear as false or undefined and this not be rendered.
ChatMessage.create(conf).then((msg) => {
return msg;
});
}
static instance = null;
static get() {
if (!VermineFight.instance)
VermineFight.instance = new VermineFight();
return VermineFight.instance;
}
// data injected to char data
static previousValues = {
dicePool: 4,
skills: VERMINE.skillsList,
cskills: VERMINE.cskills,
cephalic: false,
achievementReroll: VERMINE.achievementReroll,
conservationReroll: VERMINE.conservationReroll
};
static rollerTemplate = 'systems/vermine2047/templates/fight.html';
static CombatResultTemplate = 'systems/vermine2047/templates/fight-result.html';
static async chatMessageHandler(message, html, data) {
// console.log("accès au fin du fin", message._id);
// sélection du dé actif
html.on("click", '.confrontation .die.d6', event => {
const diceResult = parseInt($(event.target).html(), 10);
html.find('.confrontation .die.d6').removeClass('active');
$(event.target).addClass('active');
});
// sélection des dés d'accomplissement
html.on("click", '.confrontation .add-to-achievement', event => {
const diceResult = parseInt(html.find('.confrontation .die.d6.active').html(), 10);
html.find('.confrontation .die.d6.active').removeClass('min').addClass('max');
});
// sélection des dés de conservation
html.on("click", '.confrontation .add-to-conservation', event => {
const diceResult = parseInt(html.find('.confrontation .die.d6.active').html(), 10);
html.find('.confrontation .die.d6.active').removeClass('max').addClass('min');
});
// reset de la sélection des pools
html.on("click", '.confrontation .reset', event => {
html.find('.confrontation .die.d6')
.removeClass('max')
.removeClass('min');
});
// résolution de la confrontation
html.on("click", '.confrontation .resolve', async event => {
let achievementDice = 0;
let conservationDice = 0;
let achievementBasis = 0;
let conservationBasis = 0;
html.find('.confrontation .die.d6.max').each(function (index) {
achievementDice += parseInt($(this).html(), 10);
});
html.find('.confrontation .die.d6.min').each(function (index) {
conservationDice += parseInt($(this).html(), 10);
});
// saisie des résultats
achievementBasis = html.find('td.achievement-result').data('achievement-basis');
html.find('td.achievement-result').data('achievement-value', achievementDice);
html.find('td.achievement-result').html(achievementBasis + achievementDice);
conservationBasis = html.find('td.conservation-result').data('conservation-basis');
html.find('td.conservation-result').data('conservation-value', conservationDice);
html.find('td.conservation-result').html(conservationBasis + conservationDice);
// calcul des marges
const achievementMargin = achievementBasis + achievementDice - parseInt(html.find('td.adv-achievement-result').html(), 10);
const conservationMargin = conservationBasis + conservationDice - parseInt(html.find('td.adv-conservation-result').html(), 10);
html.find('td.achievement-margin').html(achievementMargin);
html.find('td.conservation-margin').html(conservationMargin);
});
// fin de la résolution de la confrontation
}
static async chatListeners(html) {
// supprime le masquage des résultats du dé
html.off("click", ".dice-roll");
}
/**
* main class function
* @returns
*/
static async ui(externalData = {}) {
let actor = {};
// get the actor
try {
actor = game.user.character;
} catch (e) {
throw ("Aucun personnage défini !");
}
if (actor == null && externalData.speakerId != undefined && externalData.speakerId != null) {
// on récupère le speakerId, et de là l'objet actor
actor = game.actors.get(externalData.speakerId);
VermineFight.previousValues['speakerName'] = actor.name;
VermineFight.previousValues['speakerImg'] = actor.img;
} else {
VermineFight.previousValues['speakerName'] = "Anonyme";
}
// get the data
let charData = (externalData) => {
let o = Object.assign({ _template: VermineFight.rollerTemplate }, { ...VermineFight.previousValues, ...externalData });
return o;
};
let data = charData(externalData);
console.log(data);
// render template
let html = await renderTemplate(data._template, data);
let ui = new Dialog({
title: game.i18n.localize("VERMINE.FightTool"),
content: html,
buttons: {
roll: {
label: game.i18n.localize('VERMINE.Roll4Fight'),
callback: (html) => {
let form = html.find('#dice-pool-form');
if (!form[0].checkValidity()) {
throw "Invalid Data";
}
let enemyAchievement, enemyConservation, skillKey, skill = 5, enemySkill, params = {};
form.serializeArray().forEach(e => {
switch (e.name) {
case "skill":
case "cephalic":
if (e.value !== '') {
skillKey = e.value;
}
break;
case "skill-score":
skill = +e.value;
break;
case "specialization":
params.specialization = true;
break;
case "usure":
params.usure = +e.value;
break;
case "trait":
params.trait = +e.value;
break;
case "purpose":
params.purpose = true;
break;
case "spleen":
params.spleen = true;
break;
case "adv-skill":
enemySkill = +e.value;
break;
case "achievement":
enemyAchievement = +e.value;
break;
case "conservation":
enemyConservation = +e.value;
break;
}
});
// prise en compte de l'usure sur la feuille de perso
if (params.usure != undefined) {
const newSpentScore = getActorSkillScore(actor, skillKey, 'spent') + params.usure;
console.log(newSpentScore);
updateActorSkillScore(actor, skillKey, 'spent', newSpentScore);
}
return VermineFight.get().performTest(enemyAchievement + enemySkill, enemyConservation + enemySkill, skillKey, skill, params, actor);
}
},
cancel: {
label: game.i18n.localize('Close'),
callback: () => { }
}
},
render: function (h) {
h.on("change", 'select[name="skill"]', event => {
const skillLabel = $(event.target).val();
const currentSkillScore = getActorSkillScore(actor, skillLabel) - getActorSkillScore(actor, skillLabel, 'spent');
if (parseInt(currentSkillScore, 10) >= 0) {
h.find('input#skillScore').val(currentSkillScore);
}
});
}
}, { width: 601, height: 'fit-content' });
ui.render(true);
return ui;
}
}
export class VermineCombat extends Combat {
_encounterCheck() {
console.log('encounter combat object', this);
}
async rollInitiative(ids, formula = undefined, messageOptions = {}) {
console.log(`${game.system.title} | Combat.rollInitiative()`, ids, formula, messageOptions);
return super.rollInitiative(ids, formula, messageOptions)
}
nextRound() {
/*let combatants = this.combatants.contents
for (let c of combatants) {
let actor = game.actors.get( c.actorId )
actor.clearRoundModifiers()
}*/
super.nextRound();
}
/************************************************************************************/
startCombat() {
/*let combatants = this.combatants.contents
for (let c of combatants) {
let actor = game.actors.get( c.actorId )
actor.storeVitaliteCombat()
}*/
return super.startCombat();
}
/************************************************************************************/
_onDelete() {
/*let combatants = this.combatants.contents
for (let c of combatants) {
let actor = game.actors.get(c.actorId)
actor.clearInitiative()
actor.displayRecuperation()
}
super._onDelete()*/
}
}
export class VermineCombatTracker extends CombatTracker {
get template() {
return "systems/vermine2047/templates/combat-tracker.hbs";
}
/* -------------------------------------------- */
get template() {
return "systems/vermine2047/templates/combat-tracker.hbs";
}
async getData(options) {
const context = await super.getData(options);
if (!context.hasCombat) {
return context;
}
return context;
}
activateListeners(html) {
super.activateListeners(html);
html.find("[data-attitude]").click(this._setStatut.bind(this));
}
/**
* @description Use to put an attitude to an actor
* @param {*} event
*/
async _setStatut(event) {
event.preventDefault();
event.stopPropagation();
const btn = event.currentTarget;
const attitude = btn.dataset.attitude;
const li = btn.closest(".combatant");
const combat = this.viewed;
const combatant = combat.combatants.get(li.dataset.combatantId);
let flag = combatant.getFlag("world", "attitude");
if (flag == attitude) {
await combatant.setFlag("world", "attitude", null);
} else {
await combatant.setFlag("world", "attitude", attitude);
}
let actor = await game.actors.get(combatant.actorId)
console.log(actor, combatant)
}
}
export class VermineCombatant extends Combatant {
constructor(data, context) {
super(data, context);
this.setDefaultAttitude();
console.log(this)
}
setDefaultAttitude() {
this.attitude = this.token.flags.world?.attitude || "active"
}
_getInitiativeFormula() {
console.log(this);
return String(CONFIG.Combat.initiative.formula || game.system.initiative);
}
}