type IRunner = { getVariable(key: string): unknown; setVariable(key: string, value: unknown): void; setSmartVariable(name: string, expression: string): void; } export function getTtrpgFunctions(runner: IRunner){ /* time related */ function ensure_time(){ if(!runner.getVariable("time_day")){ runner.setVariable("time_day", 1); runner.setVariable("time_hour", 0); runner.setVariable("time_minute", 0); runner.setSmartVariable("hour_total", "$time_day * 24 + $time_hour"); } } // midnight - 6am is night time function is_night(){ ensure_time(); const hour = runner.getVariable("time_hour") as number; return hour < 6; } function add_minute(delta: number){ ensure_time(); const min = (runner.getVariable("time_minute") as number) + delta; runner.setVariable("time_minute", min % 60); if(min >= 60) add_hour(Math.floor(min / 60)); } function add_hour(delta: number){ ensure_time(); const hour = (runner.getVariable("time_hour") as number) + delta; runner.setVariable("time_hour", hour % 24); if(hour >= 24) add_day(Math.floor(hour / 24)); } function add_day(delta: number){ ensure_time(); const day = (runner.getVariable("time_day") as number) + delta; runner.setVariable("time_day", day); } /* stat related */ function ensure_stat(stat: string){ if(!runner.getVariable(stat)){ const statBase = `${stat}_base`; const statMod = `${stat}_mod`; const statDamage = `${stat}_damage`; const statWound = `${stat}_wound`; runner.setVariable(statBase, 10); runner.setVariable(statMod, 0); runner.setVariable(statDamage, 0); runner.setVariable(statWound, false); runner.setSmartVariable(stat, `$${statBase} - $${statDamage} + $${statMod}`); } } function get_stat(stat: string){ ensure_stat(stat); return runner.getVariable(stat) as number || 0; } function damage(stat: string, amount: number){ const current = get_stat(stat); if(amount * 2 >= current) runner.setVariable(`${stat}_wound`, true); const damage = get_stat(`${stat}_damage`); runner.setVariable(`${stat}_damage`, damage + amount); } function heal(stat: string, amount = 0){ ensure_stat(stat); runner.setVariable(`${stat}_wound`, false); const damage = get_stat(`${stat}_damage`); runner.setVariable(`${stat}_damage`, Math.max(0, damage - amount)); } function check(id: string, stat: string): number { const statVal = get_stat(stat); const pass = Math.ceil(Math.random() * 20) <= statVal; const key = `${id}_${pass ? 'pass' : 'fail'}`; const progress = runner.getVariable(key) as number || 0; const newProgress = progress + Math.ceil(Math.random() * 4); runner.setVariable(key, newProgress); return pass ? newProgress : -newProgress; } function rollStat(){ const index = Math.floor(Math.random() * 6); return ['str', 'dex', 'con', 'int', 'wis', 'cha'][index]; } function fatigue(){ damage(rollStat(), 1); } function regen(){ let stat = rollStat(); if(runner.getVariable(`${stat}_wound`) || get_stat(`${stat}_damage`) <= 0) { stat = rollStat(); } if(runner.getVariable(`${stat}_wound`) || get_stat(`${stat}_damage`) <= 0) { return; } heal(stat, 1); } return { add_minutes: add_minute, add_hours: add_hour, add_days: add_day, damage, heal, check, fatigue, regen, }; }