Created
October 1, 2021 17:12
-
-
Save sean-clayton/bdb9a930b16b07ae32bf8351f9c063c7 to your computer and use it in GitHub Desktop.
Calculate Encounter Severity For Selected Tokens
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function main() { | |
let errors = []; | |
const playerTokens = canvas.tokens.controlled.filter((t) => { | |
return ["character"].includes(t.actor.data.type); | |
}); | |
const enemyTokens = canvas.tokens.controlled.filter((t) => { | |
return ["npc"].includes(t.actor.data.type) && t.data.disposition === -1; | |
}); | |
if (playerTokens.length === 0) { | |
errors.push("You must select at least one player token."); | |
} | |
if (enemyTokens.length === 0) { | |
errors.push("You must select at least one hostile npc token."); | |
} | |
const partyLevels = playerTokens.map( | |
(t) => t.actor.data.data.details.level.value | |
); | |
const partyLevel = Math.min(...partyLevels); | |
const numPlayers = playerTokens.length; | |
const encounterThreats = { | |
TRIVIAL: "Trivial", | |
LOW: "Low", | |
MODERATE: "Moderate", | |
SEVERE: "Severe", | |
EXTREME: "Extreme", | |
}; | |
const threatLevelAdjustments = { | |
[encounterThreats.TRIVIAL]: 10, | |
[encounterThreats.LOW]: 15, | |
[encounterThreats.MODERATE]: 20, | |
[encounterThreats.SEVERE]: 30, | |
[encounterThreats.EXTREME]: 40, | |
}; | |
function getThreatMaxBudgetMap(numPlayers) { | |
const difference = numPlayers - 4; | |
return { | |
[encounterThreats.TRIVIAL]: | |
40 + threatLevelAdjustments[encounterThreats.TRIVIAL] * difference, | |
[encounterThreats.LOW]: | |
60 + threatLevelAdjustments[encounterThreats.LOW] * difference, | |
[encounterThreats.MODERATE]: | |
80 + threatLevelAdjustments[encounterThreats.MODERATE] * difference, | |
[encounterThreats.SEVERE]: | |
120 + threatLevelAdjustments[encounterThreats.SEVERE] * difference, | |
[encounterThreats.EXTREME]: | |
160 + threatLevelAdjustments[encounterThreats.EXTREME] * difference, | |
}; | |
} | |
const creatureLevelToXp = { | |
[-4]: 10, | |
[-3]: 15, | |
[-2]: 20, | |
[-1]: 30, | |
0: 40, | |
1: 60, | |
2: 80, | |
3: 120, | |
4: 160, | |
}; | |
function calculateEnemyLevelDifference(partyLevel, enemyLevel) { | |
return (partyLevel - enemyLevel) * -1; | |
} | |
const enemyXps = enemyTokens.map((t) => { | |
const level = t.actor.data.data.details.level.value; | |
const difference = calculateEnemyLevelDifference(partyLevel, level); | |
if (difference > 4) { | |
errors.push( | |
"Cannot calculate severity because a creature was too high of level" | |
); | |
} | |
if (difference < -4) { | |
errors.push( | |
"Cannot calculate severity because a creature was too low of level" | |
); | |
} | |
return creatureLevelToXp[difference]; | |
}); | |
if (errors.length > 0) { | |
return errors.forEach((error) => ui.notifications.error(error)); | |
} | |
function getThreat(enemyXp) { | |
const threatArr = Object.entries(getThreatMaxBudgetMap(numPlayers)).sort( | |
([_keyA, a], [_keyB, b]) => a - b | |
); | |
return threatArr.find(([_threat, maxExp]) => maxExp >= enemyXp)[0]; | |
} | |
const enemyExpTotal = enemyXps.reduce((acc, curr) => acc + curr, 0); | |
const threat = getThreat(enemyExpTotal); | |
ui.notifications.info( | |
`Encounter threat for a party size of ${numPlayers} at level ${partyLevel}: ${threat}.` | |
); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment