From 8c917df6181d7be1c1ff6f130cb80c285bc73884 Mon Sep 17 00:00:00 2001 From: Nyeogmi Date: Sat, 8 Feb 2025 22:00:28 -0800 Subject: [PATCH] Raise costs for skills prohibited by wish --- src/datatypes.ts | 12 ++++- src/endgamemodal.ts | 12 ++--- src/main.ts | 3 +- src/playerprogress.ts | 4 ++ src/skills.ts | 8 +++- src/utils.ts | 12 +++++ src/wishes.ts | 105 +++++++++++++++++++++++++++++++++++++++++- 7 files changed, 142 insertions(+), 14 deletions(-) diff --git a/src/datatypes.ts b/src/datatypes.ts index 974d703..8576024 100644 --- a/src/datatypes.ts +++ b/src/datatypes.ts @@ -34,8 +34,16 @@ export type Skill = { id: number } - -export type Wish = "celebritySocialite" | "nightswornAlchemist" | "batFreak"; +export type WishData = { + profile: {name: string}, + bannedSkills: () => Skill[], + discouragedSkills: () => Skill[], + encouragedSkills: () => Skill[], + requiredSkills: () => Skill[] +} +export type Wish = { + id: number +} // endings diff --git a/src/endgamemodal.ts b/src/endgamemodal.ts index 22267cb..25cfa86 100644 --- a/src/endgamemodal.ts +++ b/src/endgamemodal.ts @@ -4,8 +4,9 @@ import {BG_INSET, FG_BOLD, FG_TEXT} from "./colors.ts"; import {AlignX, AlignY, Point, Rect, Size} from "./engine/datatypes.ts"; import {DrawPile} from "./drawpile.ts"; import {addButton} from "./button.ts"; -import {ALL_STATS, Ending, Wish} from "./datatypes.ts"; +import {ALL_STATS, Ending} from "./datatypes.ts"; import {getStateManager} from "./statemanager.ts"; +import {getWishes} from "./wishes.ts"; const WIDTH = 384; const HEIGHT = 384; @@ -240,7 +241,7 @@ export class EndgameModal { let generalRect = new Rect(at, new Size(w, h)); let enabled = true; - let wishLabel = wishLabels[wishOption]; + let wishData = getWishes().get(wishOption); this.#drawpile.addClickable( 0, @@ -256,7 +257,7 @@ export class EndgameModal { at.offset(new Point(2, 4)), new Size(w - 4, h - 8), fg, ) - D.drawText(wishLabel, at.offset(new Point(w / 2,h / 2 )), fgBold, { + D.drawText(wishData.profile.name, at.offset(new Point(w / 2,h / 2 )), fgBold, { forceWidth: w - 4, alignX: AlignX.Center, alignY: AlignY.Middle, @@ -280,11 +281,6 @@ export class EndgameModal { } } -const wishLabels: Record = { - celebritySocialite: "Celebrity Socialite", - nightswornAlchemist: "Nightsworn Alchemist", - batFreak: "Bat Freak" -} let active = new EndgameModal(); export function getEndgameModal() { diff --git a/src/main.ts b/src/main.ts index c68d228..2a11c3f 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,6 +1,7 @@ import {hostGame} from "./engine/internal/host.ts"; import {game} from "./game.ts"; import {getStateManager} from "./statemanager.ts"; +import {batFreak} from "./wishes.ts"; getStateManager().startGame({ name: "Pyrex", @@ -8,5 +9,5 @@ getStateManager().startGame({ note: null, stats: {AGI: 10, INT: 10, CHA: 10, PSI: 10}, talents: {AGI: 0, INT: 0, CHA: 0, PSI: 0}, -}, null); +}, batFreak); hostGame(game); \ No newline at end of file diff --git a/src/playerprogress.ts b/src/playerprogress.ts index 3ff8d69..ee10782 100644 --- a/src/playerprogress.ts +++ b/src/playerprogress.ts @@ -141,6 +141,10 @@ export class PlayerProgress { this.#blood -= amt; } + getWish(): Wish | null { + return this.#wish + } + getAvailableSkills(): Skill[] { // Sort by cost, then by name, then trim down to first 6 let skillsAvailable = [...this.#untrimmedSkillsAvailable]; diff --git a/src/skills.ts b/src/skills.ts index b68c684..738eb99 100644 --- a/src/skills.ts +++ b/src/skills.ts @@ -1,5 +1,6 @@ import {Skill, SkillData, SkillGoverning, SkillScoring, Stat} from "./datatypes.ts"; import {getPlayerProgress} from "./playerprogress.ts"; +import {getCostMultiplier} from "./wishes.ts"; class SkillsTable { #skills: SkillData[] @@ -34,9 +35,14 @@ class SkillsTable { governingStatValue += getPlayerProgress().getStat(stat) / data.governing.stats.length; } + let mult = getCostMultiplier(getPlayerProgress().getWish(), skill); + let [underTarget, target] = [data.governing.underTarget, data.governing.target]; + underTarget = mult * underTarget; + target = mult * target; + return Math.floor(geomInterpolate( governingStatValue, - data.governing.underTarget, data.governing.target, + underTarget, target, data.governing.cost, 999 )) } diff --git a/src/utils.ts b/src/utils.ts index 3a77dcd..80ec0cc 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -4,3 +4,15 @@ export function choose(array: Array): T { } return array[Math.floor(Math.random() * array.length)] } + +export function shuffle(array: Array) { + // source: https://stackoverflow.com/posts/2450976/revisions + let currentIndex = array.length; + while (currentIndex != 0) { + let randomIndex = Math.floor(Math.random() * currentIndex); + currentIndex--; + + [array[currentIndex], array[randomIndex]] = [array[randomIndex], array[currentIndex]]; + } + +} \ No newline at end of file diff --git a/src/wishes.ts b/src/wishes.ts index 3500428..1dcb009 100644 --- a/src/wishes.ts +++ b/src/wishes.ts @@ -1,5 +1,106 @@ -import {Wish} from "./datatypes.ts"; +import {Skill, Wish, WishData} from "./datatypes.ts"; +import {shuffle} from "./utils.ts"; +import { + bat0, bat1, bat2, + bat3, + charm0, + charm1, + charm2, + charm3, + lore0, lore1, lore2, + party0, + party1, party2, party3, stare0, stare1, stare2, stare3, + stealth0, + stealth1, + stealth2, + stealth3 +} from "./skills.ts"; + +class WishesTable { + #wishes: WishData[] + + constructor() { + this.#wishes = []; + } + + add(data: WishData): Wish { + let id = this.#wishes.length; + this.#wishes.push(data); + return {id}; + } + + get(wish: Wish): WishData { + return this.#wishes[wish.id]; + } + + getAllPossibleWishes(): Wish[] { + let wishes: Wish[] = []; + for (let i = 0; i < this.#wishes.length; i++) { + wishes.push({id: i}); + } + return wishes; + } +} + +let table = new WishesTable(); +export function getWishes(): WishesTable { + return table; +} + +export const celebritySocialite = table.add({ + profile: {name: "Celebrity Socialite"}, + bannedSkills: () => [lore0], + discouragedSkills: () => [stealth0, stealth1, stealth2, stealth3], + encouragedSkills: () => [party0, party1, party2, party3], + requiredSkills: () => [charm0, charm1, charm2], +}); + +export const nightswornAlchemist = table.add({ + profile: {name: "Nightsworn Alchemist"}, + bannedSkills: () => [party0], + discouragedSkills: () => [charm0, charm1, charm2, charm3], + encouragedSkills: () => [stare0, stare1, stare2, stare3], + requiredSkills: () => [lore0, lore1, lore2] +}); + +export const batFreak = table.add({ + profile: {name: "Bat Freak"}, + bannedSkills: () => [charm0, stare0, party0, lore0], + discouragedSkills: () => [], + encouragedSkills: () => [stealth0, stealth1, stealth2, stealth3], + requiredSkills: () => [bat0, bat1, bat2, bat3] +}); export function generateWishes(): Wish[] { - return ["celebritySocialite", "nightswornAlchemist", "batFreak"]; + let possibleWishes = table.getAllPossibleWishes(); + shuffle(possibleWishes); + + let selectedWishes: Wish[] = []; + for (let i = 0; i < possibleWishes.length; i++) { + selectedWishes.push(possibleWishes[i]); + } + return selectedWishes; +} + +export function getCostMultiplier(wish: Wish | null, skill: Skill): number { + if (wish == null) { return 1.0; } + + let wishData = getWishes().get(wish); + + for (let subj of wishData.requiredSkills()) { + if (subj.id == skill.id) { return 0.75; } + } + for (let subj of wishData.encouragedSkills()) { + if (subj.id == skill.id) { return 0.875; } + } + + for (let subj of wishData.discouragedSkills()) { + if (subj.id == skill.id) { return 1.25; } + } + + for (let subj of wishData.bannedSkills()) { + if (subj.id == skill.id) { return 9999.0; } + } + + return 1.0; } \ No newline at end of file