You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
161 lines
6.2 KiB
161 lines
6.2 KiB
import {assertion} from "../testing/Assertions";
|
|
|
|
/** The interface managing a character's Stamina and Energy. */
|
|
export interface Energy {
|
|
/** The character's maximum Stamina, which they are returned to when they rest. >= 1, <= 99999. */
|
|
readonly maxStamina: number
|
|
/** The character's current Stamina, which their energy returns to when they complete a battle. >= 0, <= maxStamina. */
|
|
readonly currentStamina: number
|
|
/** The character's current Energy, used for special abilities. >= 0, <= currentStamina. */
|
|
readonly currentEnergy: number
|
|
}
|
|
|
|
/** Formats the given Energy object into a string suitable for logging. Should never throw. */
|
|
export function energyToString(energy: Energy): string {
|
|
return `{Energy ${energy.currentEnergy}/${energy.currentStamina}/${energy.maxStamina}}`
|
|
}
|
|
|
|
/**
|
|
* Returns whether the given Energy object is valid, i.e., it has currentEnergy <= currentStamina <= maxStamina, and
|
|
* all three are positive integers or zero.
|
|
*/
|
|
export function isValidEnergy(energy: Energy): boolean {
|
|
return isValidMaxStamina(energy.maxStamina)
|
|
&& isValidCurrentEnergy(energy.currentStamina, energy.maxStamina)
|
|
&& isValidCurrentEnergy(energy.currentEnergy, energy.currentStamina)
|
|
}
|
|
|
|
/** Returns whether the given value is valid for max stamina, i.e., it's an integer between 1 and 99999. */
|
|
export function isValidMaxStamina(maxStamina: number): boolean {
|
|
return Number.isSafeInteger(maxStamina) && maxStamina >= 1 && maxStamina <= 99999
|
|
}
|
|
|
|
/** Returns whether the given value is valid for current energy or stamina, i.e., it's an integer between 0 and max. */
|
|
export function isValidCurrentEnergy(value: number, max: number): boolean {
|
|
return Number.isSafeInteger(value) && value >= 0 && value <= max
|
|
}
|
|
|
|
/** Asserts that the given Energy object is valid (see the documentation for isValidEnergy). */
|
|
export function checkValidEnergy(energy: Energy): Energy {
|
|
return assertion.check(energy, isValidEnergy, (energy) => `Invalid energy: ${energyToString(energy)}`)
|
|
}
|
|
|
|
/** Asserts that the given value is valid for maxStamina. */
|
|
export function checkValidMaxStamina(maxStamina: number): number {
|
|
return assertion.check(maxStamina, isValidMaxStamina, (maxStamina) => `Invalid max stamina: ${maxStamina}`)
|
|
}
|
|
|
|
/** Asserts that the given value is valid for currentStamina or currentEnergy. */
|
|
export function checkValidCurrentEnergy(value: number, max: number): number {
|
|
return assertion.check(value, (value) => isValidCurrentEnergy(value, max), (value) => `Invalid current energy: ${value}`)
|
|
}
|
|
|
|
/**
|
|
* Sets the max stamina value on the given Energy. This may result in the currentStamina (and possibly currentEnergy)
|
|
* values decreasing to fit under the new ceiling.
|
|
*/
|
|
export function setMaxStamina(energy: Energy, maxStamina: number): Energy {
|
|
checkValidEnergy(energy)
|
|
checkValidMaxStamina(maxStamina)
|
|
|
|
const currentStamina = Math.min(energy.currentStamina, maxStamina)
|
|
const currentEnergy = Math.min(energy.currentEnergy, currentStamina)
|
|
|
|
return checkValidEnergy({...energy, maxStamina, currentStamina, currentEnergy})
|
|
}
|
|
|
|
/**
|
|
* Deals damage to the Stamina of the given Energy. currentStamina will be decreased; currentEnergy will also be
|
|
* decreased if damageEnergy is true, or if the new Stamina is lower than the Energy. Neither can drop below 0 this way.
|
|
*/
|
|
export function damageStamina(energy: Energy, damage: number, options: {damageEnergy: boolean}): Energy {
|
|
checkValidEnergy(energy)
|
|
assertion.checkPositiveIntegerOrZero(damage, () => `Invalid damage: ${damage}`)
|
|
|
|
const currentStamina = Math.max(0, energy.currentStamina - damage)
|
|
const currentEnergy = options.damageEnergy ? Math.max(0, energy.currentEnergy - damage) : Math.min(energy.currentEnergy, currentStamina)
|
|
|
|
return checkValidEnergy({
|
|
...energy,
|
|
currentStamina,
|
|
currentEnergy,
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Recovers the Stamina of the given Energy. currentStamina will be increased; currentEnergy will also be increased
|
|
* if recoverEnergy is true. Neither can exceed maxStamina this way.
|
|
*/
|
|
export function recoverStamina(energy: Energy, recovery: number, options: {recoverEnergy: boolean}): Energy {
|
|
checkValidEnergy(energy)
|
|
assertion.checkPositiveIntegerOrZero(recovery, () => `Invalid healing: ${recovery}`)
|
|
|
|
const currentStamina = Math.min(energy.maxStamina, energy.currentStamina + recovery)
|
|
const currentEnergy = options.recoverEnergy ? energy.currentEnergy + (currentStamina - energy.currentStamina) : energy.currentEnergy
|
|
|
|
return checkValidEnergy({
|
|
...energy,
|
|
currentStamina,
|
|
currentEnergy,
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Sets the Stamina of the given Energy. currentEnergy will be decreased if it's lower than the new Stamina.
|
|
*/
|
|
export function setCurrentStamina(energy: Energy, value: number): Energy {
|
|
checkValidEnergy(energy)
|
|
checkValidCurrentEnergy(value, energy.maxStamina)
|
|
|
|
const currentStamina = value
|
|
const currentEnergy = Math.min(currentStamina, energy.currentEnergy)
|
|
|
|
return checkValidEnergy({
|
|
...energy,
|
|
currentStamina,
|
|
currentEnergy
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Deals damage to the Energy of the given Energy. It can't drop below 0 this way.
|
|
*/
|
|
export function damageEnergy(energy: Energy, damage: number): Energy {
|
|
checkValidEnergy(energy)
|
|
assertion.checkPositiveIntegerOrZero(damage, () => `Invalid damage: ${damage}`)
|
|
|
|
const currentEnergy = Math.max(0, energy.currentEnergy - damage)
|
|
|
|
return checkValidEnergy({
|
|
...energy,
|
|
currentEnergy,
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Recovers the Energy of the given Energy. It can't exceed currentStamina this way.
|
|
*/
|
|
export function recoverEnergy(energy: Energy, recovery: number): Energy {
|
|
checkValidEnergy(energy)
|
|
assertion.checkPositiveIntegerOrZero(recovery, () => `Invalid healing: ${recovery}`)
|
|
|
|
const currentEnergy = Math.min(energy.currentStamina, energy.currentEnergy + recovery)
|
|
|
|
return checkValidEnergy({
|
|
...energy,
|
|
currentEnergy
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Sets the current Energy of the given Energy.
|
|
*/
|
|
export function setCurrentEnergy(energy: Energy, value: number): Energy {
|
|
checkValidEnergy(energy)
|
|
checkValidCurrentEnergy(value, energy.currentStamina)
|
|
|
|
return checkValidEnergy({
|
|
...energy,
|
|
currentEnergy: value
|
|
})
|
|
} |