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.
 
 
 
motw-tracker/src/character.ts

125 lines
3.3 KiB

import {parse as parseYaml, stringify as stringifyYaml} from "yaml"
import {readFile, writeFile, readdir} from 'fs/promises'
import {join} from 'path'
export interface GameCharacter {
health: number
armor?: number
unstable?: boolean
luck: number
luckSpecial?: string
experience: number
Charm?: number
Cool?: number
Sharp?: number
Tough?: number
Weird?: number
color: number
defaultFacePath: string
additionalFaces?: GameCharacterFace[]
activeFaceSets?: string[]
moves?: GameCharacterMove[]
improvementsTaken?: string[]
improvementsAvailable?: string[]
improvementsAdvanced?: string[]
}
export enum GameAttribute {
Charm = "Charm",
Cool = "Cool",
Sharp = "Sharp",
Tough = "Tough",
Weird = "Weird",
}
export const GameAttributes = [GameAttribute.Charm, GameAttribute.Cool, GameAttribute.Sharp, GameAttribute.Tough, GameAttribute.Weird] as const
export interface GameCharacterMoveBase {
type?: string
name: string
summary?: string
description?: string
}
export interface GameCharacterPassiveMove extends GameCharacterMoveBase {
type?: "passive"
}
export interface GameCharacterRollableMove extends GameCharacterMoveBase {
type: "rollable"
attribute?: GameAttribute
bonus?: number
advanced?: boolean
onAdvanced?: string
onSuccess?: string
onMixed?: string
onMiss?: string
}
export type GameCharacterMove = GameCharacterPassiveMove|GameCharacterRollableMove
export interface FaceConditionBase {
type: string
negated?: boolean
}
export interface FaceConditionStability extends FaceConditionBase {
type: "stable"|"unstable"|"dead"
}
export interface FaceConditionHealth extends FaceConditionBase {
type: "hpEq"|"hpGt"|"hpLt"|"hpGtEq"|"hpLtEq"
threshold: number
}
export interface FaceConditionHealthDelta extends FaceConditionBase {
type: "beingHealed"|"beingDamaged"|"healthSteady"
}
export interface FaceConditionSet extends FaceConditionBase {
type: "faceSetActive"
set: string
}
export type FaceCondition = FaceConditionStability|FaceConditionHealth|FaceConditionHealthDelta|FaceConditionSet
export interface GameCharacterFace {
path: string
conditions: FaceCondition[]
}
export const FaceSetIdentifier = /^[a-z0-9_]+$/
export async function listCharacters(dataDir: string): Promise<string[]> {
const list = await readdir(join(dataDir, "characters"))
return list.filter(s => s.endsWith(".yaml")).map(s => s.substring(0, s.length - 5))
}
export async function loadCharacter(dataDir: string, name: string): Promise<GameCharacter> {
const contents = await readFile(join(dataDir, "characters", name + ".yaml"), {encoding: "utf-8"})
return parseYaml(contents)
}
export async function saveCharacter(dataDir: string, name: string, character: GameCharacter): Promise<void> {
const contents = stringifyYaml(character)
return writeFile(join(dataDir, "characters", name + ".yaml"), contents)
}
export interface GameParty {
defaultCharacters: Record<string, string>
activeParty: string[]
keeper: string
}
export interface ReadonlyGameParty {
readonly defaultCharacters: Readonly<Record<string, string>>
readonly activeParty: readonly string[]
readonly keeper: string
}
export async function loadParty(dataDir: string): Promise<GameParty> {
const contents = await readFile(join(dataDir, "party.yaml"), {encoding: "utf-8"})
return parseYaml(contents)
}