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.
125 lines
3.3 KiB
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)
|
|
}
|
|
|