import Logger from './utils/Logger'; import M5CharacterSheet from './module/sheets/M5CharacterSheet'; import preloadTemplates from './PreloadTemplates'; import { M5Character } from './module/actors/M5Character'; import { M5ItemMod, M5ModOperation, M5Skill, M5TimeUnit } from './module/M5Base'; import { M5ItemSheet } from './module/sheets/M5ItemSheet'; import { M5Item } from './module/items/M5Item'; Hooks.once('init', async () => { Logger.log('M5 | Initialisierung Midgard 5'); Handlebars.registerHelper('times', (n: number, block) => { var accum = ''; for (let i = 0; i < n; ++i) accum += block.fn(i); return accum; }); Handlebars.registerHelper('array', (arr: any[], index: number) => { return arr[index]; }); Handlebars.registerHelper('m5concat', (...values) => { const options = values.pop(); const join = options.hash?.join || ''; //return new Handlebars.SafeString(values.join(join)); return values.map(val => val.toString()).join(join); }); Handlebars.registerHelper('add', (...values) => { const options = values.pop(); return values.reduce((prev, cur) => prev + cur); }); Handlebars.registerHelper('localizeMidgard', (str: string) => { const template = Handlebars.compile('{{localize value}}'); return template({ value: 'midgard5.' + str, }); }); Handlebars.registerHelper('skillBonus', (actorId: string, skill: M5Skill) => { const actor = (game as Game).actors.get(actorId) as M5Character; return actor.skillBonus(skill).toString(); }); Handlebars.registerHelper('skillEw', (actorId: string, skill: M5Skill) => { const actor = (game as Game).actors.get(actorId) as M5Character; return actor.skillEw(skill).toString(); }); Handlebars.registerHelper('skill', (skillId: string) => { return (game as Game).items.get(skillId); }); Handlebars.registerHelper('itemValue', (id: string, path: string) => { let obj = (game as Game).items.get(id); path.split('.').forEach(p => (obj = obj[p])); return `${obj}`; }); Handlebars.registerHelper('actorItemValue', (actorId: any, itemId: string, path: string, token?: boolean) => { //console.log("actorItemValue", actorId, itemId, path) const actor = (game as Game).actors.get(actorId); let obj = actor.items.get(itemId)?.system; path.split('.').forEach(p => { if (obj) obj = obj[p]; }); return `${obj}`; }); Handlebars.registerHelper('icon', (relpath: string) => { return `systems/midgard5/assets/icons/${relpath}`; }); Handlebars.registerHelper('isSkillInList', (skillName: string, list: any) => { for (let key in list) { if (list[key]?.label?.toLowerCase() === skillName?.toLowerCase()) { return true; } } return false; }); Handlebars.registerHelper('stripHtml', function (param) { var regex = /(<([^>]+)>)/gi; return param.replace(regex, ''); }); Handlebars.registerHelper('contains', (label: string, contains: string) => { return label.toLowerCase().includes(contains.toLowerCase()); }); Handlebars.registerHelper('count', (object: any) => { var length = 0; for (var key in object) { if (object.hasOwnProperty(key)) { ++length; } } return length; }); // Default Sheet für Items definieren und das Standardsheet deaktivieren Items.unregisterSheet('core', ItemSheet); Items.registerSheet('midgard5', M5ItemSheet, { makeDefault: true }); // Default Sheet für Actors definieren und das Standardsheet deaktivieren Actors.unregisterSheet('core', ActorSheet); Actors.registerSheet('midgard5', M5CharacterSheet, { makeDefault: true }); CONFIG.Actor.documentClass = M5Character; CONFIG.Item.documentClass = M5Item; //RegisterSettings(); await preloadTemplates(); }); Hooks.once('setup', () => { Logger.log('Template module is being setup.'); }); Hooks.on('getChatLogEntryContext', function (html, options) { options.push( { name: 'LP & AP Schaden', icon: '', condition: li => { const damageRolls = li.find('.damage').length; // All must be true to show the reroll dialogue return (game['user'].character || game['canvas'].tokens.controlled) && damageRolls > 0; }, callback: li => applyDamage(li, 2), }, { name: 'AP Schaden', icon: '', condition: li => { const damageRolls = li.find('.damage').length; // All must be true to show the reroll dialogue return (game['user'].character || game['canvas'].tokens.controlled) && damageRolls > 0; }, callback: li => applyDamage(li, 1), }, { name: 'LP & AP Heilen', icon: '', condition: li => { const damageRolls = li.find('.heal').length; // All must be true to show the reroll dialogue return (game['user'].character || game['canvas'].tokens.controlled) && damageRolls > 0; }, callback: li => applyDamage(li, -1), }, { name: 'AP Heilen', icon: '', condition: li => { const damageRolls = li.find('.heal').length; // All must be true to show the reroll dialogue return (game['user'].character || game['canvas'].tokens.controlled) && damageRolls > 0; }, callback: li => applyDamage(li, -2), } ); }); Hooks.on( 'updateCombat', function ( combat: Combat, updateData: { round: number; turn: number }, updateOptions: { advanceTime: number; direction: number } ) { if (combat.round % 2 === 0 && combat.turn !== null) { const tokenId = combat.current.tokenId; const actorId = combat.combatant['actorId']; let currentToken = game['actors'].tokens[tokenId]; if (!currentToken) { currentToken = game['actors'].get(actorId); } let activeEffects = currentToken.items.filter(x => x.type === 'effect' && x.system.equipped) || []; activeEffects.forEach(effect => { if (effect.system?.duration?.time > 0) { if (effect.system.duration.unit === M5TimeUnit.ROUND) { effect.system.duration.time -= 1; } } if (effect.system?.duration.time === 0 && effect.system.duration.unit !== M5TimeUnit.LIMITLESS) { effect.system.equipped = false; } for (const key in effect.system.mods) { if (effect.system.mods[key].operation === M5ModOperation.SUBTRACT) { switch (effect.system.mods[key].id) { case 'lp': currentToken['system'].lp.value -= effect.system.mods[key].value; break; case 'ap': currentToken['system'].ap.value -= effect.system.mods[key].value; break; } } else if (effect.system.mods[key].operation === M5ModOperation.ADD) { switch (effect.system.mods[key].id) { case 'lp': currentToken['system'].lp.value += limitHeal( effect.system.mods[key].value, currentToken['system'].lp.value, currentToken['system'].lp.max ); break; case 'ap': currentToken['system'].ap.value += limitHeal( effect.system.mods[key].value, currentToken['system'].ap.value, currentToken['system'].ap.max ); break; } } } }); currentToken.render(); } } ); Hooks.on('renderCombatTracker', (combatTracker, html, context) => { if (context.combat === null) { html.find('h3.encounter-title')[0].innerHTML = game['i18n'].localize('midgard5.no-encounter'); } else if (Math.ceil(context.round / 2) === 0) { html.find('h3.encounter-title')[0].innerHTML = game['i18n'].localize('midgard5.encounter-not-started'); } else { html.find('h3.encounter-title')[0].innerHTML = (context.round % 2 == 1 ? game['i18n'].localize('midgard5.phase-movement') : game['i18n'].localize('midgard5.phase-action')) + ' ' + Math.ceil(context.round / 2); } }); Hooks.once('ready', () => { Logger.ok('Template module is now ready.'); }); async function applyDamage(roll, direction) { console.log(roll, direction); const damageValue = Array.from(roll.find('.apply') as HTMLElement[]) .map(x => Math.max(0, Number(x.innerText))) .reduce((prev, curr) => prev + curr, 0); const controlledTokens = game['canvas'].tokens.controlled; const actor = game['user'].character; if (controlledTokens) { controlledTokens.forEach(controlledToken => { let token = controlledToken.document.delta.syntheticActor; switch (direction) { case 2: token['system'].lp.value -= Math.max(0, damageValue - token['system'].calc.stats.lpProtection.value); case 1: token['system'].ap.value -= Math.max(0, damageValue - token['system'].calc.stats.apProtection.value); break; case -1: token['system'].lp.value += limitHeal(damageValue, token['system'].lp.value, token['system'].lp.max); case -2: token['system'].ap.value += limitHeal(damageValue, token['system'].ap.value, token['system'].ap.max); } token.render(); }); } else { switch (direction) { case 2: actor['system'].lp.value -= Math.max(0, damageValue - actor['system'].calc.stats.lpProtection.value); case 1: actor['system'].ap.value -= Math.max(0, damageValue - actor['system'].calc.stats.apProtection.value); break; case -1: actor['system'].lp.value += limitHeal(damageValue, actor['system'].lp.value, actor['system'].lp.max); case -2: actor['system'].ap.value += limitHeal(damageValue, actor['system'].ap.value, actor['system'].ap.max); } actor.render(); } } function limitHeal(heal: number, current: number, max: number): number { if (current === max) { return 0; } else if (heal + current > max) { return max - current; } return heal; }