Raise costs for skills prohibited by wish

This commit is contained in:
Pyrex 2025-02-08 22:00:28 -08:00
parent 1902f6e70b
commit 8c917df618
7 changed files with 142 additions and 14 deletions

View File

@ -34,8 +34,16 @@ export type Skill = {
id: number id: number
} }
export type WishData = {
export type Wish = "celebritySocialite" | "nightswornAlchemist" | "batFreak"; profile: {name: string},
bannedSkills: () => Skill[],
discouragedSkills: () => Skill[],
encouragedSkills: () => Skill[],
requiredSkills: () => Skill[]
}
export type Wish = {
id: number
}
// endings // endings

View File

@ -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 {AlignX, AlignY, Point, Rect, Size} from "./engine/datatypes.ts";
import {DrawPile} from "./drawpile.ts"; import {DrawPile} from "./drawpile.ts";
import {addButton} from "./button.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 {getStateManager} from "./statemanager.ts";
import {getWishes} from "./wishes.ts";
const WIDTH = 384; const WIDTH = 384;
const HEIGHT = 384; const HEIGHT = 384;
@ -240,7 +241,7 @@ export class EndgameModal {
let generalRect = new Rect(at, new Size(w, h)); let generalRect = new Rect(at, new Size(w, h));
let enabled = true; let enabled = true;
let wishLabel = wishLabels[wishOption]; let wishData = getWishes().get(wishOption);
this.#drawpile.addClickable( this.#drawpile.addClickable(
0, 0,
@ -256,7 +257,7 @@ export class EndgameModal {
at.offset(new Point(2, 4)), new Size(w - 4, h - 8), fg, 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, forceWidth: w - 4,
alignX: AlignX.Center, alignX: AlignX.Center,
alignY: AlignY.Middle, alignY: AlignY.Middle,
@ -280,11 +281,6 @@ export class EndgameModal {
} }
} }
const wishLabels: Record<Wish, string> = {
celebritySocialite: "Celebrity Socialite",
nightswornAlchemist: "Nightsworn Alchemist",
batFreak: "Bat Freak"
}
let active = new EndgameModal(); let active = new EndgameModal();
export function getEndgameModal() { export function getEndgameModal() {

View File

@ -1,6 +1,7 @@
import {hostGame} from "./engine/internal/host.ts"; import {hostGame} from "./engine/internal/host.ts";
import {game} from "./game.ts"; import {game} from "./game.ts";
import {getStateManager} from "./statemanager.ts"; import {getStateManager} from "./statemanager.ts";
import {batFreak} from "./wishes.ts";
getStateManager().startGame({ getStateManager().startGame({
name: "Pyrex", name: "Pyrex",
@ -8,5 +9,5 @@ getStateManager().startGame({
note: null, note: null,
stats: {AGI: 10, INT: 10, CHA: 10, PSI: 10}, stats: {AGI: 10, INT: 10, CHA: 10, PSI: 10},
talents: {AGI: 0, INT: 0, CHA: 0, PSI: 0}, talents: {AGI: 0, INT: 0, CHA: 0, PSI: 0},
}, null); }, batFreak);
hostGame(game); hostGame(game);

View File

@ -141,6 +141,10 @@ export class PlayerProgress {
this.#blood -= amt; this.#blood -= amt;
} }
getWish(): Wish | null {
return this.#wish
}
getAvailableSkills(): Skill[] { getAvailableSkills(): Skill[] {
// Sort by cost, then by name, then trim down to first 6 // Sort by cost, then by name, then trim down to first 6
let skillsAvailable = [...this.#untrimmedSkillsAvailable]; let skillsAvailable = [...this.#untrimmedSkillsAvailable];

View File

@ -1,5 +1,6 @@
import {Skill, SkillData, SkillGoverning, SkillScoring, Stat} from "./datatypes.ts"; import {Skill, SkillData, SkillGoverning, SkillScoring, Stat} from "./datatypes.ts";
import {getPlayerProgress} from "./playerprogress.ts"; import {getPlayerProgress} from "./playerprogress.ts";
import {getCostMultiplier} from "./wishes.ts";
class SkillsTable { class SkillsTable {
#skills: SkillData[] #skills: SkillData[]
@ -34,9 +35,14 @@ class SkillsTable {
governingStatValue += getPlayerProgress().getStat(stat) / data.governing.stats.length; 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( return Math.floor(geomInterpolate(
governingStatValue, governingStatValue,
data.governing.underTarget, data.governing.target, underTarget, target,
data.governing.cost, 999 data.governing.cost, 999
)) ))
} }

View File

@ -4,3 +4,15 @@ export function choose<T>(array: Array<T>): T {
} }
return array[Math.floor(Math.random() * array.length)] return array[Math.floor(Math.random() * array.length)]
} }
export function shuffle<T>(array: Array<T>) {
// 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]];
}
}

View File

@ -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[] { 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;
} }