diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..7a73a41b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/module/actor/entity.js b/module/actor/entity.js index 8ccf8a67..3c1e749d 100644 --- a/module/actor/entity.js +++ b/module/actor/entity.js @@ -368,17 +368,26 @@ export default class Actor5e extends Actor { const forceProgression = { classes: 0, levels: 0, - multi: 0 + multi: 0, + maxClass: "none", + maxClassPriority: 0, + maxClassLevels: 0, + maxClassPowerLevel: 0, + powersKnown: 0, + points: 0 }; const techProgression = { classes: 0, levels: 0, - multi: 0 + multi: 0, + maxClass: "none", + maxClassPriority: 0, + maxClassLevels: 0, + maxClassPowerLevel: 0, + powersKnown: 0, + points: 0 }; - // Keep track of the last seen caster in case we're in a single-caster situation. - let caster = null; - // Tabulate the total power-casting progression const classes = this.data.items.filter(i => i.type === "class"); for ( let cls of classes ) { @@ -387,83 +396,130 @@ export default class Actor5e extends Actor { const levels = d.levels; const prog = d.powercasting; - // Accumulate levels - caster = cls; - switch (prog) { case 'consular': + let priority = 3; forceProgression.levels += levels; forceProgression.multi += (SW5E.powerMaxLevel['consular'][levels-1]/9)*levels; forceProgression.classes++; + // see if class controls high level forcecasting + if ((levels >= forceProgression.maxClassLevels) && (priority > forceProgression.maxClassPriority)){ + forceProgression.maxClass = 'consular'; + forceProgression.maxClassLevels = levels; + forceProgression.maxClassPriority = priority; + forceProgression.maxClassPowerLevel = SW5E.maxPowerLevel['consular'][Math.clamped((levels - 1), 0, 20)]; + } + // calculate points and powers known + forceProgression.powersKnown += SW5E.powersKnown['consular'][Math.clamped((levels - 1), 0, 20)]; + forceProgression.points += SW5E.powerPoints['consular'][Math.clamped((levels - 1), 0, 20)]; break; case 'engineer': + let priority = 2 techProgression.levels += levels; techProgression.multi += (SW5E.powerMaxLevel['engineer'][levels-1]/9)*levels; techProgression.classes++; + // see if class controls high level techcasting + if ((levels >= techProgression.maxClassLevels) && (priority > techProgression.maxClassPriority)){ + techProgression.maxClass = 'engineer'; + techProgression.maxClassLevels = levels; + techProgression.maxClassPriority = priority; + techProgression.maxClassPowerLevel = SW5E.maxPowerLevel['engineer'][Math.clamped((levels - 1), 0, 20)]; + } + techProgression.powersKnown += SW5E.powersKnown['engineer'][Math.clamped((levels - 1), 0, 20)]; + techProgression.points += SW5E.powerPoints['engineer'][Math.clamped((levels - 1), 0, 20)]; break; case 'guardian': + let priority = 1; forceProgression.levels += levels; forceProgression.multi += (SW5E.powerMaxLevel['guardian'][levels-1]/9)*levels; forceProgression.classes++; + // see if class controls high level forcecasting + if ((levels >= forceProgression.maxClassLevels) && (priority > forceProgression.maxClassPriority)){ + forceProgression.maxClass = 'guardian'; + forceProgression.maxClassLevels = levels; + forceProgression.maxClassPriority = priority; + forceProgression.maxClassPowerLevel = SW5E.maxPowerLevel['guardian'][Math.clamped((levels - 1), 0, 20)]; + } + forceProgression.powersKnown += SW5E.powersKnown['guardian'][Math.clamped((levels - 1), 0, 20)]; + forceProgression.points += SW5E.powerPoints['guardian'][Math.clamped((levels - 1), 0, 20)]; break; case 'scout': + let priority = 1; techProgression.levels += levels; techProgression.multi += (SW5E.powerMaxLevel['scout'][levels-1]/9)*levels; techProgression.classes++; + // see if class controls high level techcasting + if ((levels >= techProgression.maxClassLevels) && (priority > techProgression.maxClassPriority)){ + techProgression.maxClass = 'scout'; + techProgression.maxClassLevels = levels; + techProgression.maxClassPriority = priority; + techProgression.maxClassPowerLevel = SW5E.maxPowerLevel['scout'][Math.clamped((levels - 1), 0, 20)]; + } + techProgression.powersKnown += SW5E.powersKnown['scout'][Math.clamped((levels - 1), 0, 20)]; + techProgression.points += SW5E.powerPoints['scout'][Math.clamped((levels - 1), 0, 20)]; break; case 'sentinel': + let priority = 2; forceProgression.levels += levels; forceProgression.multi += (SW5E.powerMaxLevel['sentinel'][levels-1]/9)*levels; forceProgression.classes++; - break; - } + // see if class controls high level forcecasting + if ((levels >= forceProgression.maxClassLevels) && (priority > forceProgression.maxClassPriority)){ + forceProgression.maxClass = 'sentinel'; + forceProgression.maxClassLevels = levels; + forceProgression.maxClassPriority = priority; + forceProgression.maxClassPowerLevel = SW5E.maxPowerLevel['sentinel'][Math.clamped((levels - 1), 0, 20)]; + } + forceProgression.powersKnown += SW5E.powersKnown['sentinel'][Math.clamped((levels - 1), 0, 20)]; + forceProgression.points += SW5E.powerPoints['sentinel'][Math.clamped((levels - 1), 0, 20)]; + break; } } // EXCEPTION: multi-classed progression uses multi rounded down rather than levels if (!isNPC && forceProgression.classes > 1) { forceProgression.levels = Math.floor(forceProgression.multi); + forceProgression.maxClassPowerLevel = SW5E.maxPowerLevel['multi'][levels - 1]; } if (!isNPC && techProgression.classes > 1) { techProgression.levels = Math.floor(techProgression.multi); + techProgression.maxClassPowerLevel = SW5E.maxPowerLevel['multi'][levels - 1]; } // EXCEPTION: NPC with an explicit power-caster level if (isNPC && actorData.data.details.powerForceLevel) { forceProgression.levels = actorData.data.details.powerForceLevel; + forceProgression.maxClass = 'consular'; + forceProgression.maxClassPowerLevel = SW5E.maxPowerLevel['consular'][Math.clamped((forceProgression.levels - 1), 0, 20)]; + forceProgression.powersKnown = SW5E.powersKnown['consular'][Math.clamped((forceProgression.levels - 1), 0, 20)]; + forceProgression.points = SW5E.powerPoints['consular'][Math.clamped((forceProgression.levels - 1), 0, 20)]; } if (isNPC && actorData.data.details.powerTechLevel) { techProgression.levels = actorData.data.details.powerTechLevel; + techProgression.maxClass = 'engineer'; + techProgression.maxClassPowerLevel = SW5E.maxPowerLevel['engineer'][Math.clamped((techProgression.levels - 1), 0, 20)]; + techProgression.powersKnown = SW5E.powersKnown['engineer'][Math.clamped((techProgression.levels - 1), 0, 20)]; + techProgression.points = SW5E.powerPoints['engineer'][Math.clamped((techProgression.levels - 1), 0, 20)]; } - //TODO: STOPPED HERE, PICKUP WHERE YOU LEFT OFF + // Look up the number of slots per level from the powerLimit table + const forcePowerLimit = SW5E.powerLimit['none']; + for (let i = 0; i < (forceProgression.maxPowerLevel - 1); i++) { + forcePowerLimit[i] = SW5E.powerLimit[forceProgression.maxClass][i]; + } + + /** + * ? set max force/tech points? Should probably be done on class level up drop + * ? set max force/tech powers known? Should probably be done on class level up drop + * ? should I tally number of powers known here? + */ - - // Look up the number of slots per level from the progression table - const levels = Math.clamped(progression.slot, 0, 20); - const slots = SW5E.SPELL_SLOT_TABLE[levels - 1] || []; for ( let [n, lvl] of Object.entries(powers) ) { let i = parseInt(n.slice(-1)); if ( Number.isNaN(i) ) continue; if ( Number.isNumeric(lvl.override) ) lvl.max = Math.max(parseInt(lvl.override), 0); - else lvl.max = slots[i-1] || 0; + else lvl.max = forcePowerLimit[i-1] || 0; lvl.value = parseInt(lvl.value); } - - // Determine the Actor's pact magic level (if any) - let pl = Math.clamped(progression.pact, 0, 20); - powers.pact = powers.pact || {}; - if ( (pl === 0) && isNPC && Number.isNumeric(powers.pact.override) ) pl = actorData.data.details.powerLevel; - - // Determine the number of Warlock pact slots per level - if ( pl > 0) { - powers.pact.level = Math.ceil(Math.min(10, pl) / 2); - if ( Number.isNumeric(powers.pact.override) ) powers.pact.max = Math.max(parseInt(powers.pact.override), 1); - else powers.pact.max = Math.max(1, Math.min(pl, 2), Math.min(pl - 8, 3), Math.min(pl - 13, 4)); - powers.pact.value = Math.min(powers.pact.value, powers.pact.max); - } else { - powers.pact.max = parseInt(powers.pact.override) || 0 - powers.pact.level = powers.pact.max > 0 ? 1 : 0; - } } /* -------------------------------------------- */ @@ -1058,11 +1114,6 @@ export default class Actor5e extends Actor { } } - // Recover pact slots. - const pact = this.data.data.powers.pact; - updateData['data.powers.pact.value'] = pact.override || pact.max; - await this.update(updateData); - // Recover item uses const recovery = newDay ? ["sr", "day"] : ["sr"]; const items = this.items.filter(item => item.data.data.uses && recovery.includes(item.data.data.uses.per)); @@ -1149,10 +1200,6 @@ export default class Actor5e extends Actor { updateData[`data.powers.${k}.value`] = Number.isNumeric(v.override) ? v.override : (v.max ?? 0); } - // Recover pact slots. - const pact = data.powers.pact; - updateData['data.powers.pact.value'] = pact.override || pact.max; - // Determine the number of hit dice which may be recovered let recoverHD = Math.max(Math.floor(data.details.level / 2), 1); let dhd = 0; diff --git a/module/config.js b/module/config.js index 797b9b94..54a94c8a 100644 --- a/module/config.js +++ b/module/config.js @@ -537,7 +537,7 @@ SW5E.powerProgression = { * The max number of known powers available to each class per level */ -SW5E.powerKnown = { +SW5E.powersKnown = { "none": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], "consular": [9,11,13,15,17,19,21,23,25,26,28,29,31,32,34,35,37,38,39,40], "engineer": [6,7,9,10,12,13,15,16,18,19,21,22,23,24,25,26,27,28,29,30], @@ -552,11 +552,11 @@ SW5E.powerKnown = { SW5E.powerLimit = { "none": [0,0,0,0,0,0,0,0,0], - "consular": [99,99,99,99,99,1,1,1,1], - "engineer": [99,99,99,99,99,1,1,1,1], - "guardian": [99,99,99,99,1,0,0,0,0], - "scout": [99,99,99,1,1,0,0,0,0], - "sentinel": [99,99,99,99,1,1,1,0,0] + "consular": [1000,1000,1000,1000,1000,1,1,1,1], + "engineer": [1000,1000,1000,1000,1000,1,1,1,1], + "guardian": [1000,1000,1000,1000,1,0,0,0,0], + "scout": [1000,1000,1000,1,1,0,0,0,0], + "sentinel": [1000,1000,1000,1000,1,1,1,0,0] }; /** diff --git a/template.json b/template.json index d08b7927..05530edf 100644 --- a/template.json +++ b/template.json @@ -95,13 +95,29 @@ }, "powercasting": "none", "force": { - "known": 0, - "points": 0, + "known": { + "value": 0, + "min": 0, + "max": 0 + }, + "points": { + "value": 0, + "min": 0, + "max": 0 + }, "level": 0 }, "tech": { - "known": 0, - "points": 0, + "known": { + "value": 0, + "min": 0, + "max": 0 + }, + "points": { + "value": 0, + "min": 0, + "max": 0 + }, "level": 0 } },