Tracker made in React for keeping track of HP and MP and so on.
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.
 
 
 

230 lines
8.5 KiB

import {Affinity, AffinityDisplay} from "./Messages";
export enum MeteredResource {
Experience = "EXP",
Health = "HP",
Magic = "MP",
Items = "IP",
Zero = "Zero Charge",
Blood = "BP",
Turns = "Turns",
Segments = "Segments",
}
export function isMeteredResource(r: Resource): r is MeteredResource {
return Object.values<Resource>(MeteredResource).includes(r)
}
export enum UnmeteredResource {
Fabula = "FP",
Ultima = "UP",
Special = "SP",
Level = "Levels",
Materials = "Zenit of Materials",
Zenit = "Zenit",
Order = "Order",
}
export function formatResourceDelta(r: Resource, a: Affinity, n: number): string {
const delta = `${n > 0 ? "+" : n === 0 ? "±" : ""}${n.toFixed(0)}${AffinityDisplay[a]}`
if (Math.abs(n) === 1) {
switch (r) {
case MeteredResource.Turns:
return `${delta} Turn`
case MeteredResource.Segments:
return `${delta} Segment`
case UnmeteredResource.Level:
return `${delta} Level`
}
}
return `${delta} ${r}`
}
export function formatMeteredResource(r: MeteredResource, n: number, mx: number): string {
const value = `${n}/${mx}`
if (n === 1 && mx === 1) {
switch (r) {
case MeteredResource.Turns:
return `${value} Turn`
case MeteredResource.Segments:
return `${value} Segment`
}
}
return `${value} ${r}`
}
export function formatResourceValue(r: Resource, n: number): string {
const value = `${n}`
if (r === UnmeteredResource.Level) {
return `Lv. ${value}`
}
if (n === 1) {
switch (r) {
case MeteredResource.Turns:
return `${value} Turn`
case MeteredResource.Segments:
return `${value} Segment`
}
}
return `${value} ${r}`
}
export function formatResourceMax(r: MeteredResource, n: number): string {
const value = `${n}`
if (n === 1) {
switch (r) {
case MeteredResource.Turns:
return `Max ${value} Turn`
case MeteredResource.Segments:
return `Max ${value} Segment`
}
}
return `Max ${value} ${r}`
}
export function isUnmeteredResource(r: Resource): r is UnmeteredResource {
return Object.values<Resource>(UnmeteredResource).includes(r)
}
export type Resource = MeteredResource|UnmeteredResource
export function getResourceValue<
KeySetT extends string|number|symbol, ObjectT extends {[key in KeySetT]?: number},
ResourceT extends string|number|symbol>
(valueMap: {[key in ResourceT]: KeySetT|undefined}, object: ObjectT, resource: ResourceT): number|undefined {
const field = valueMap[resource]
if (typeof field === "undefined") {
return undefined
}
return object[field]
}
export function setResourceValue<
KeySetT extends string|number|symbol, ObjectT extends {[key in KeySetT]?: number},
ResourceT extends string|number|symbol>
(valueMap: {[key in ResourceT]: KeySetT|undefined}, maxMap: {[key in ResourceT]: KeySetT|undefined}, object: ObjectT, resource: ResourceT, value: number): ObjectT {
const valueField = valueMap[resource]
const maxField = maxMap[resource]
if (typeof valueField === "undefined") {
return object
}
if (typeof maxField !== "undefined") {
const max = getResourceValue(maxMap, object, resource)
if (typeof max === "undefined") {
return object
}
return setMeteredResource(valueMap, maxMap, object, resource, value, max)
}
const effectiveValue = Math.max(0, value)
return {
...object,
[valueField as KeySetT]: effectiveValue,
}
}
export function applyResourceDelta<
KeySetT extends string|number|symbol, ObjectT extends {[key in KeySetT]?: number},
ResourceT extends string|number|symbol>
(valueMap: {[key in ResourceT]: KeySetT|undefined}, maxMap: {[key in ResourceT]: KeySetT|undefined}, object: ObjectT, resource: ResourceT, delta: number): ObjectT {
const value = getResourceValue(valueMap, object, resource)
if (typeof value === "undefined") {
return object
}
return setResourceValue(valueMap, maxMap, object, resource, value + delta)
}
export function setResourceMax<
KeySetT extends string|number|symbol, ObjectT extends {[key in KeySetT]?: number},
ResourceT extends string|number|symbol>
(valueMap: {[key in ResourceT]: KeySetT|undefined}, maxMap: {[key in ResourceT]: KeySetT|undefined}, object: ObjectT, resource: ResourceT, max: number): ObjectT {
const valueField = valueMap[resource]
const maxField = maxMap[resource]
if (typeof valueField === "undefined" || typeof maxField === "undefined") {
return object
}
const value = getResourceValue(valueMap, object, resource)
if (typeof value === "undefined") {
return object
}
return setMeteredResource(valueMap, maxMap, object, resource, value, max)
}
export function setMeteredResource<
KeySetT extends string|number|symbol, ObjectT extends {[key in KeySetT]?: number},
ResourceT extends string|number|symbol>
(valueMap: {[key in ResourceT]: KeySetT|undefined}, maxMap: {[key in ResourceT]: KeySetT|undefined}, object: ObjectT, resource: ResourceT, value: number, max: number): ObjectT {
const valueField = valueMap[resource]
const maxField = maxMap[resource]
if (typeof valueField === "undefined" || typeof maxField === "undefined") {
return object
}
const effectiveMax = Math.max(0, max)
const effectiveValue = Math.max(0, Math.min(value, effectiveMax))
return {
...object,
[valueField as KeySetT]: effectiveValue,
[maxField as KeySetT]: effectiveMax,
}
}
export function clearResource<
KeySetT extends string|number|symbol, ObjectT extends {[key in KeySetT]?: number},
ResourceT extends string|number|symbol>
(valueMap: {[key in ResourceT]: KeySetT|undefined}, maxMap: {[key in ResourceT]: KeySetT|undefined}, object: ObjectT, resource: ResourceT): ObjectT {
const valueField = valueMap[resource]
const maxField = maxMap[resource]
const isValidValue = typeof valueField !== "undefined" && object.hasOwnProperty(valueField)
const isValidMax = typeof maxField !== "undefined" && object.hasOwnProperty(maxField)
const result: { -readonly [key in keyof ObjectT]: ObjectT[key] } = {...object}
if (isValidValue) {
delete result[valueField as KeySetT]
}
if (isValidMax) {
delete result[maxField as KeySetT]
}
return result as ObjectT
}
export interface ResourceManipulator<ObjectT, ResourceT> {
getValue(object: ObjectT, resource: ResourceT): number|undefined
getMax(object: ObjectT, resource: ResourceT): number|undefined
setValue(object: ObjectT, resource: ResourceT, value: number): ObjectT
setMax(object: ObjectT, resource: ResourceT, max: number): ObjectT
setMetered(object: ObjectT, resource: ResourceT, value: number, max: number): ObjectT
applyDelta(object: ObjectT, resource: ResourceT, delta: number): ObjectT
clear(object: ObjectT, resource: ResourceT): ObjectT
}
export function createResourceManipulator<KeySetT extends string|number|symbol, ObjectT extends {[key in KeySetT]?: number},
ResourceT extends string|number|symbol>(valueMap: {[key in ResourceT]: KeySetT|undefined}, maxMap: {[key in ResourceT]: KeySetT|undefined}): ResourceManipulator<ObjectT, ResourceT> {
return {
getValue(object: ObjectT, resource: ResourceT): number | undefined {
return getResourceValue(valueMap, object, resource)
},
applyDelta(object: ObjectT, resource: ResourceT, delta: number): ObjectT {
return applyResourceDelta(valueMap, maxMap, object, resource, delta)
},
getMax(object: ObjectT, resource: ResourceT): number | undefined {
return getResourceValue(maxMap, object, resource)
},
setMax(object: ObjectT, resource: ResourceT, max: number): ObjectT {
return setResourceMax(valueMap, maxMap, object, resource, max)
},
setMetered(object: ObjectT, resource: ResourceT, value: number, max: number): ObjectT {
return setMeteredResource(valueMap, maxMap, object, resource, value, max);
},
setValue(object: ObjectT, resource: ResourceT, value: number): ObjectT {
return setResourceValue(valueMap, maxMap, object, resource, value);
},
clear(object: ObjectT, resource: ResourceT): ObjectT {
return clearResource(valueMap, maxMap, object, resource)
}
}
}