/* -------------------------------------------- */ import { SoSCombat } from "./sos-combat.js"; import { SoSDialogCombatActions } from "./sos-dialog-combat-actions.js"; /* -------------------------------------------- */ const severity2malus = { "none": 0, "light": -1, "moderate": -2, "severe": -3, "critical": -4}; /* -------------------------------------------- */ export class SoSUtility { /* -------------------------------------------- */ static async preloadHandlebarsTemplates() { const templatePaths = [ 'systems/foundryvtt-shadows-over-sol/templates/actor-sheet.html', 'systems/foundryvtt-shadows-over-sol/templates/editor-notes-gm.html', 'systems/foundryvtt-shadows-over-sol/templates/stat-option-list.html', 'systems/foundryvtt-shadows-over-sol/templates/stat-name-list.html', 'systems/foundryvtt-shadows-over-sol/templates/item-sheet.html', 'systems/foundryvtt-shadows-over-sol/templates/item-geneline-sheet.html', 'systems/foundryvtt-shadows-over-sol/templates/item-subculture-sheet.html', 'systems/foundryvtt-shadows-over-sol/templates/item-weapon-sheet.html', 'systems/foundryvtt-shadows-over-sol/templates/item-commongear-sheet.html', 'systems/foundryvtt-shadows-over-sol/templates/dialog-flip.html' ] return loadTemplates(templatePaths); } /* -------------------------------------------- */ static fillRange (start, end) { return Array(end - start + 1).fill().map((item, index) => start + index); } /* -------------------------------------------- */ onSocketMesssage( msg ) { if (msg.name == 'msg_declare_actions' ) { if (game.user.isGM) { let combat = game.combats.get( msg.data.combatId); // Get the associated combat combat.setupActorActions( msg.data ); } } else if (msg.name == 'msg_close_action') { if (game.user.isGM) { game.combat.closeAction( msg.data.uniqId ); } } } /* -------------------------------------------- */ static async loadCompendiumNames(compendium) { const pack = game.packs.get(compendium); let competences; await pack.getIndex().then(index => competences = index); return competences; } /* -------------------------------------------- */ static async loadCompendium(compendium, filter = item => true) { let compendiumItems = await SoSUtility.loadCompendiumNames(compendium); const pack = game.packs.get(compendium); let list = []; for (let compendiumItem of compendiumItems) { await pack.getEntity(compendiumItem._id).then(it => { const item = it.data; if (filter(item)) { list.push(item); } }); }; return list; } /* -------------------------------------------- */ static updateCombat(combat, round, diff, id) { combat.requestActions(); } /* -------------------------------------------- */ static async openDeclareActions( event) { event.preventDefault(); let round = event.currentTarget.attributes['data-round'].value; let combatantId = event.currentTarget.attributes['data-combatant-id'].value; let combatId = event.currentTarget.attributes['data-combat-id'].value; let uniqId = event.currentTarget.attributes['data-uniq-id'].value; let d = await SoSDialogCombatActions.create( combatId, combatantId, round, uniqId ); d.render(true); } /* -------------------------------------------- */ static getConsequenceMalus(severity) { return severity2malus[severity] ?? 0; } /* -------------------------------------------- */ static computeEncumbrance( items) { let trappings = items.filter( item => item.type == 'gear' || item.type == 'armor' || item.type == 'weapon' ); let sumEnc = 0; for (let object of trappings) { if ( (!object.data.worn) && (!object.data.neg) && (!object.data.containerid || object.data.containerid == "") ) { sumEnc += (object.big > 0) ? object.big : 1; } } return sumEnc; } /* -------------------------------------------- */ static closeAction(event) { let uniqId = event.currentTarget.attributes['data-uniq-id'].value; // Delete message ! const toDelete = game.messages.filter(it => it.data.content.includes( uniqId )); toDelete.forEach(it => it.delete()); if ( game.user.isGM ) { game.combat.closeAction( uniqId ); } else { game.socket.emit("system.foundryvtt-reve-de-dragon", { name: "msg_close_action", data: { uniqId: uniqId} } ); } } /* -------------------------------------------- */ static async registerChatCallbacks(html) { html.on("click", '#button-declare-actions', event => { SoSUtility.openDeclareActions( event ); }); html.on("click", '#button-end-action', event => { SoSUtility.closeAction( event ); }); } /* -------------------------------------------- */ static getTarget() { if (game.user.targets && game.user.targets.size == 1) { for (let target of game.user.targets) { return target; } } return undefined; } /* -------------------------------------------- */ static increaseSeverity( severity ) { if ( severity == 'L') return 'M'; if ( severity == 'M') return 'S'; if ( severity == 'S') return 'C'; if ( severity == 'C') return 'F'; } /* -------------------------------------------- */ static decreaseSeverity( severity ) { if ( severity == 'C') return 'S'; if ( severity == 'S') return 'M'; if ( severity == 'M') return 'L'; if ( severity == 'L') return 'N'; } /* -------------------------------------------- */ static getSeverityLevel( severity) { if ( severity == 'C') return 4; if ( severity == 'S') return 3; if ( severity == 'M') return 2; if ( severity == 'L') return 1; return 0; } /* -------------------------------------------- */ static async applyDamage( flipData ) { let dr = flipData.target.actor.data.data.scores.dr.value; let shock = flipData.target.actor.data.data.scores.shock.value; let defenseCritical = flipData.target.actor.data.data.scores.defense.critical; flipData.damageStatus = 'apply_damage'; flipData.targetShock = shock; flipData.targetDR = dr; flipData.targetCritical = defenseCritical; // DR management if ( flipData.damageValue < dr) { if (flipData.damageValue < dr / 2) { flipData.damageStatus = "no_damage"; // TODO : No damage ! } else { flipData.damageSeverity = this.decreaseSeverity(flipData.damageSeverity ); if ( flipData.damageSeverity == 'N') { flipData.damageStatus = "no_damage"; } } } // Shock management flipData.woundsList = []; if ( flipData.damageValue >= shock) { let incSeverity = Math.floor(flipData.damageValue / shock); for (let i=0; i= defenseCritical); let html = await renderTemplate('systems/foundryvtt-shadows-over-sol/templates/chat-damage-target.html', flipData ); ChatMessage.create( { content: html }); // Is target able to dodge ?? let defender = game.actors.get( flipData.target.actor._id); flipData.coverConsequence = defender.data.items.find( item => item.type == 'consequence' && item.name == 'Cover'); flipData.APavailable = game.combat.getAPFromActor( defender.data._id ); console.log("FLIPDATE : ", flipData); if ( flipData.APavailable > 0) { if ( (flipData.weapon.data.category == 'melee' ) || ( (flipData.weapon.data.category == 'laser' || flipData.weapon.data.category == 'ballistic') && flipData.coverConsequence.data.severity != 'none') ) { flipData.coverSeverityLevel = this.getSeverityLevel( flipData.coverConsequence.data.severity ) * 2; flipData.coverSeverityFlag = (flipData.coverSeverityLevel > 0); flipData.isMelee = (flipData.weapon.data.category == 'melee' ); let melee = defender.data.items.find( item => item.type == 'skill' && item.name == 'Melee'); flipData.defenderMelee = melee.data.value; let html = await renderTemplate('systems/foundryvtt-shadows-over-sol/templates/chat-damage-request-dodge.html', flipData ); ChatMessage.create( { content: html, whisper: [ChatMessage.getWhisperRecipients(flipData.target.actor.name), ChatMessage.getWhisperRecipients("GM") ] } ); } } } }