import { VNScene } from "./vnscene.ts"; import { getPlayerProgress } from "./playerprogress.ts"; import { getSkills } from "./skills.ts"; import { Ending, SCORING_CATEGORIES, ScoringCategory } from "./datatypes.ts"; import { sceneBat, sceneCharm, sceneLore, sceneParty, sceneStare, sceneStealth, } from "./endings.ts"; import { generateWishes, getWishes, isWishCompleted } from "./wishes.ts"; import { generateSuccessors } from "./successors.ts"; class Scorer { constructor() {} pickEnding(): Ending { let learnedSkills = getPlayerProgress().getLearnedSkills(); let scores: Record = {}; let itemsPurloined = getPlayerProgress().getItemsPurloined(); let vampiricSkills = 0; let mortalServants = itemsPurloined / 10; for (const skill of learnedSkills.values()) { let data = getSkills().get(skill); for (let [category, number] of Object.entries(data.governing.scoring)) { scores[category] = (scores[category] ?? 0) + number; } mortalServants += data.governing.mortalServantValue; vampiricSkills += 1; } mortalServants = Math.max(Math.floor(mortalServants), 0); // NOTE: This approach isn't efficient but it's easy to understand // and it allows me to arbitrate ties however I want let runningScores: Record = { ...scores }; const isMax = (cat: ScoringCategory, min: number) => { let score = runningScores[cat] ?? 0; runningScores[cat] = 0; // each category, once checked, can't disqualify any other category if (score < min) { return false; } for (let cat of SCORING_CATEGORIES.values()) { if (runningScores[cat] > score) { return false; } } return true; }; let scene: VNScene; let rank: string; let domicile: string; let reignSentence: string; let penance: boolean = false; let successorVerb: string = "Appoint a Successor"; // Let the player let wish = getPlayerProgress().getWish(); if (wish != null) { let data = getWishes().get(wish); if (isWishCompleted(wish)) { scene = data.onVictory; rank = data.profile.name; domicile = data.profile.domicile; reignSentence = data.profile.reignSentence; } else { scene = data.onFailure; rank = data.profile.failureName; domicile = data.profile.failureDomicile; reignSentence = data.profile.failureReignSentence; penance = true; successorVerb = data.profile.failureSuccessorVerb; } } // TODO: Award different ranks depending on second-to-top skill // TODO: Award different domiciles based on overall score // TODO: Force the rank to match the wish if one existed else if (isMax("stare", 3)) { scene = sceneStare; rank = "Hypno-Chiropteran"; domicile = "Village of Brainwashed Mortals"; reignSentence = "You rule with a fair but unflinching gaze."; } else if (isMax("lore", 3)) { scene = sceneLore; rank = "Loremaster"; domicile = "Vineyard"; reignSentence = "You're well on the path to ultimate knowledge."; } else if (isMax("charm", 2)) { scene = sceneCharm; rank = "Seducer"; domicile = "Guest House"; reignSentence = "You get to sink your fangs into anyone you want."; } else if (isMax("party", 1)) { scene = sceneParty; rank = "Party Animal"; domicile = "Nightclub"; reignSentence = "Everyone thinks you're too cool to disobey."; } else if (isMax("stealth", 0)) { scene = sceneStealth; rank = "Invisible"; domicile = "Townhouse"; reignSentence = "People don't see you but they do most of what you want."; } // if (isMax("bat")) { else { scene = sceneBat; rank = "Bat"; domicile = "Cave"; reignSentence = "Your skreeking verdicts are irresistible to your subjects."; } // TODO: Analytics tracker let analytics = { itemsPurloined, vampiricSkills, mortalServants, }; let successorOptions = generateSuccessors(0, penance); // TODO: generate nImprovements from mortalServants and the player's bsae improvements let wishOptions = generateWishes(penance); let progenerateVerb = penance ? "Repent" : "Progenerate"; return { scene, personal: { rank, domicile, reignSentence, successorVerb, progenerateVerb, }, analytics, successorOptions, wishOptions, }; } } let active = new Scorer(); export function getScorer(): Scorer { return active; }