foundry-vtt-system-midgard5/source/index.ts

297 lines
10 KiB
TypeScript

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: '<i class="fas fa-tint"></i>',
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: '<i class="fas fa-shield-alt"></i>',
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: '<i class="fas fa-heart"></i>',
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: '<i class="far fa-heart"></i>',
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;
}