diff --git a/src/Bladeburner/Bladeburner.ts b/src/Bladeburner/Bladeburner.ts index f61d0ca6f..7ddd73f68 100644 --- a/src/Bladeburner/Bladeburner.ts +++ b/src/Bladeburner/Bladeburner.ts @@ -143,17 +143,29 @@ export class Bladeburner { /** Directly sets a skill level, with no validation */ setSkillLevel(skillName: BladeSkillName, value: number) { - this.skills[skillName] = clampInteger(value, 0); + this.skills[skillName] = clampInteger(value, 0, Number.MAX_VALUE); this.updateSkillMultipliers(); } /** Attempts to perform a skill upgrade, gives a message on both success and failure */ upgradeSkill(skillName: BladeSkillName, count = 1): Attempt<{ message: string }> { - const availability = Skills[skillName].canUpgrade(this, count); - if (!availability.available) return { message: `Cannot upgrade ${skillName}: ${availability.error}` }; + const currentSkillLevel = this.skills[skillName] ?? 0; + const actualCount = currentSkillLevel + count - currentSkillLevel; + if (actualCount === 0) { + return { + message: `Cannot upgrade ${skillName}: Due to floating-point inaccuracy and the small value of specified "count", your skill cannot be upgraded.`, + }; + } + const availability = Skills[skillName].canUpgrade(this, actualCount); + if (!availability.available) { + return { message: `Cannot upgrade ${skillName}: ${availability.error}` }; + } this.skillPoints -= availability.cost; - this.setSkillLevel(skillName, (this.skills[skillName] ?? 0) + count); - return { success: true, message: `Upgraded skill ${skillName} by ${count} level${count > 1 ? "s" : ""}` }; + this.setSkillLevel(skillName, currentSkillLevel + actualCount); + return { + success: true, + message: `Upgraded skill ${skillName} by ${actualCount} level${actualCount > 1 ? "s" : ""}`, + }; } executeConsoleCommands(commands: string): void { diff --git a/src/Bladeburner/Skill.ts b/src/Bladeburner/Skill.ts index 2e36e931f..6750ca869 100644 --- a/src/Bladeburner/Skill.ts +++ b/src/Bladeburner/Skill.ts @@ -30,11 +30,12 @@ export class Skill { this.desc = params.desc; this.baseCost = params.baseCost ?? 1; this.costInc = params.costInc ?? 1; - this.maxLvl = params.maxLvl ?? Number.MAX_SAFE_INTEGER; + this.maxLvl = params.maxLvl ?? Number.MAX_VALUE; for (const [multName, mult] of getRecordEntries(params.mults)) this.mults[multName] = mult; } calculateCost(currentLevel: number, count = 1 as PositiveInteger): number { + const actualCount = currentLevel + count - currentLevel; /** * The cost of the next level: (baseCost + currentLevel * costInc) * mult. The cost needs to be an integer, so we * need to use Math.floor or Math.round. @@ -76,16 +77,24 @@ export class Skill { * */ return Math.round( - count * currentNodeMults.BladeburnerSkillCost * (this.baseCost + this.costInc * (currentLevel + (count - 1) / 2)), + actualCount * + currentNodeMults.BladeburnerSkillCost * + (this.baseCost + this.costInc * (currentLevel + (actualCount - 1) / 2)), ); } canUpgrade(bladeburner: Bladeburner, count = 1): Availability<{ cost: number }> { const currentLevel = bladeburner.skills[this.name] ?? 0; - if (!isPositiveInteger(count)) return { error: `Invalid upgrade count ${count}` }; - if (currentLevel + count > this.maxLvl) return { error: `Upgraded level ${currentLevel + count} exceeds max` }; + if (!isPositiveInteger(count)) { + return { error: `Invalid upgrade count ${count}` }; + } + if (currentLevel + count > this.maxLvl) { + return { error: `Upgraded level ${currentLevel + count} exceeds max` }; + } const cost = this.calculateCost(currentLevel, count); - if (cost > bladeburner.skillPoints) return { error: `Insufficient skill points for upgrade` }; + if (cost > bladeburner.skillPoints) { + return { error: `Insufficient skill points for upgrade` }; + } return { available: true, cost }; }