Various minor fixes to successor system and mixing
This commit is contained in:
		
							
								
								
									
										
											BIN
										
									
								
								src/art/sounds/ending.mp3
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/art/sounds/ending.mp3
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								src/art/sounds/silence.mp3
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/art/sounds/silence.mp3
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 648 B After Width: | Height: | Size: 651 B | 
| @@ -7,7 +7,6 @@ import { BG_INSET, FG_BOLD } from "./colors.ts"; | ||||
| import { addButton } from "./button.ts"; | ||||
| import { getSkills } from "./skills.ts"; | ||||
| import { getPlayerProgress } from "./playerprogress.ts"; | ||||
| import { sndRecruit } from "./sounds.ts"; | ||||
|  | ||||
| export class CheckModal { | ||||
|   #drawpile: DrawPile; | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| import { VNScene } from "./vnscene.ts"; | ||||
| import { Thrall } from "./thralls.ts"; | ||||
|  | ||||
| export type Stat = "AGI" | "INT" | "CHA" | "PSI"; | ||||
| export const ALL_STATS: Array<Stat> = ["AGI", "INT", "CHA", "PSI"]; | ||||
| @@ -104,6 +105,7 @@ export type EndingAnalytics = { | ||||
| export type SuccessorOption = { | ||||
|   name: string; | ||||
|   title: string; | ||||
|   template: Thrall; | ||||
|   note: string | null; // ex "already a vampire" | ||||
|   stats: Record<Stat, number>; | ||||
|   talents: Record<Stat, number>; | ||||
|   | ||||
| @@ -7,6 +7,7 @@ import { addButton } from "./button.ts"; | ||||
| import { ALL_STATS, Ending } from "./datatypes.ts"; | ||||
| import { getStateManager } from "./statemanager.ts"; | ||||
| import { getWishes } from "./wishes.ts"; | ||||
| import { sndEnding } from "./sounds.ts"; | ||||
|  | ||||
| const WIDTH = 384; | ||||
| const HEIGHT = 384; | ||||
| @@ -19,6 +20,8 @@ export class EndgameModal { | ||||
|   #selectedWish: number | null; | ||||
|   #ending: Ending | null; | ||||
|  | ||||
|   #playedSound: boolean; | ||||
|  | ||||
|   constructor() { | ||||
|     this.#drawpile = new DrawPile(); | ||||
|     this.#page = 0; | ||||
| @@ -27,6 +30,8 @@ export class EndgameModal { | ||||
|     this.#selectedWish = null; | ||||
|     this.#ending = null; | ||||
|  | ||||
|     this.#playedSound = false; | ||||
|  | ||||
|     // this.show(getScorer().pickEnding()); | ||||
|   } | ||||
|  | ||||
| @@ -66,6 +71,11 @@ export class EndgameModal { | ||||
|   #update() { | ||||
|     this.#fixCompulsory(); | ||||
|  | ||||
|     if (!this.#playedSound) { | ||||
|       sndEnding.play({ bgm: true }); | ||||
|       this.#playedSound = true; | ||||
|     } | ||||
|  | ||||
|     this.#drawpile.clear(); | ||||
|     if (this.#page == 0) { | ||||
|       let analytics = this.#ending?.analytics; | ||||
|   | ||||
| @@ -120,9 +120,8 @@ export class Floater { | ||||
|   } | ||||
|  | ||||
|   get bbox(): Circle { | ||||
|     let w = 0.25; | ||||
|     let h = 0.25; | ||||
|     return new Circle(this.xy, w / 2); | ||||
|     let sz = 0.25; | ||||
|     return new Circle(this.xy, sz / 2); | ||||
|   } | ||||
|   drawParticle(projected: Point, isShadow: boolean): any { | ||||
|     this.#callbacks.drawParticle( | ||||
|   | ||||
| @@ -6,9 +6,6 @@ import { addButton } from "./button.ts"; | ||||
| import { getPlayerProgress } from "./playerprogress.ts"; | ||||
| import { getStateManager } from "./statemanager.ts"; | ||||
| import { getCheckModal } from "./checkmodal.ts"; | ||||
| import { sndRecruit, sndSleep } from "./sounds.ts"; | ||||
| //import { LadderPickup } from "./pickups.ts"; | ||||
| // import { generateMap } from "./mapgen.ts"; | ||||
|  | ||||
| type Button = { | ||||
|   label: string; | ||||
|   | ||||
| @@ -1,7 +1,6 @@ | ||||
| import { Circle, Point, Rect, Size } from "./engine/datatypes.ts"; | ||||
| import { Circle, Point, Size } from "./engine/datatypes.ts"; | ||||
| import { DrawPile } from "./drawpile.ts"; | ||||
| import { D, I } from "./engine/public.ts"; | ||||
| import { sprThrallLore } from "./sprites.ts"; | ||||
| import { | ||||
|   BG_INSET, | ||||
|   FG_TEXT, | ||||
| @@ -14,11 +13,10 @@ import { FLOOR_CELL_SIZE, GridArt } from "./gridart.ts"; | ||||
| import { shadowcast } from "./shadowcast.ts"; | ||||
| import { withCamera } from "./layout.ts"; | ||||
| import { getCheckModal } from "./checkmodal.ts"; | ||||
| import { CARDINAL_DIRECTIONS } from "./mapgen.ts"; | ||||
| import { Block3D, Floor3D, World3D } from "./world3d.ts"; | ||||
| import { Floater } from "./floater.ts"; | ||||
| import { displace } from "./physics.ts"; | ||||
| import { sndRecruit } from "./sounds.ts"; | ||||
| import { getThralls } from "./thralls.ts"; | ||||
|  | ||||
| export class HuntMode { | ||||
|   map: LoadedNewMap; | ||||
| @@ -197,12 +195,11 @@ export class HuntMode { | ||||
|       this.faceLeft = false; | ||||
|     } | ||||
|  | ||||
|     let szX = 0.5; | ||||
|     let szY = 0.5; | ||||
|     let sz = getThralls().get(getPlayerProgress().template).hitboxSize; | ||||
|  | ||||
|     this.velocity = new Point(dx, dy); | ||||
|  | ||||
|     let bbox = new Circle(this.floatingPlayer, szX / 2); | ||||
|     let bbox = new Circle(this.floatingPlayer, sz / 2); | ||||
|     let { displacement, dxy } = displace(bbox, this.velocity, (b: Circle) => | ||||
|       this.getContact(b), | ||||
|     ); | ||||
| @@ -373,8 +370,9 @@ export class HuntMode { | ||||
|       }); | ||||
|     }); | ||||
|      */ | ||||
|     let sprite = getThralls().get(getPlayerProgress().template).sprite; | ||||
|     this.drawpile.add(1024, () => { | ||||
|       D.drawSprite(sprThrallLore, new Point(192, 192), 1, { | ||||
|       D.drawSprite(sprite, new Point(192, 192), 1, { | ||||
|         xScale: this.faceLeft ? -2 : 2, | ||||
|         yScale: 2, | ||||
|       }); | ||||
|   | ||||
| @@ -42,14 +42,14 @@ const names = [ | ||||
|   "Thisby", | ||||
|   "Calloway", | ||||
|   "Fenna", | ||||
|   "Lupin", | ||||
|   // "Lupin", | ||||
|   "Finlo", | ||||
|   "Tycho", | ||||
|   "Talmadge", | ||||
|   // others | ||||
|   "Jeff", | ||||
|   "Jon", | ||||
|   "Garrett", | ||||
|   // "Garrett", | ||||
|   "Russell", | ||||
|   "Tyson", | ||||
|   "Gervase", | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| import { Circle, lerp, Point, Rect } from "./engine/datatypes.ts"; | ||||
| import { Circle, lerp, Point } from "./engine/datatypes.ts"; | ||||
|  | ||||
| export function displace( | ||||
|   bbox: Circle, | ||||
|   | ||||
| @@ -4,6 +4,7 @@ import { getThralls, ItemStage, LifeStage, Thrall } from "./thralls.ts"; | ||||
|  | ||||
| export class PlayerProgress { | ||||
|   #name: string; | ||||
|   #thrallTemplate: number; | ||||
|   #stats: Record<Stat, number>; | ||||
|   #talents: Record<Stat, number>; | ||||
|   #isInPenance: boolean; | ||||
| @@ -20,6 +21,7 @@ export class PlayerProgress { | ||||
|  | ||||
|   constructor(asSuccessor: SuccessorOption, withWish: Wish | null) { | ||||
|     this.#name = asSuccessor.name; | ||||
|     this.#thrallTemplate = asSuccessor.template.id; | ||||
|     this.#stats = { ...asSuccessor.stats }; | ||||
|     this.#talents = { ...asSuccessor.talents }; | ||||
|     this.#isInPenance = asSuccessor.inPenance; | ||||
| @@ -47,6 +49,10 @@ export class PlayerProgress { | ||||
|     return this.#name; | ||||
|   } | ||||
|  | ||||
|   get template(): Thrall { | ||||
|     return { id: this.#thrallTemplate }; | ||||
|   } | ||||
|  | ||||
|   get isInPenance(): boolean { | ||||
|     return this.#isInPenance; | ||||
|   } | ||||
|   | ||||
							
								
								
									
										16
									
								
								src/sound.ts
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								src/sound.ts
									
									
									
									
									
								
							| @@ -1,8 +1,12 @@ | ||||
| class SoundShared { | ||||
|   readonly context: AudioContext; | ||||
|   bgmSource: AudioBufferSourceNode | null; | ||||
|   bgmGain: GainNode | null; | ||||
|  | ||||
|   constructor() { | ||||
|     this.context = new AudioContext(); | ||||
|     this.bgmSource = null; | ||||
|     this.bgmGain = null; | ||||
|   } | ||||
| } | ||||
| const shared = new SoundShared(); | ||||
| @@ -25,7 +29,7 @@ export class Sound { | ||||
|     return await this.#audioBufferPromise; | ||||
|   } | ||||
|  | ||||
|   play(options?: { volume: number }) { | ||||
|   play(options?: { volume?: number; bgm?: boolean }) { | ||||
|     this.#getAudioBuffer().then((adata) => { | ||||
|       let source = shared.context.createBufferSource(); | ||||
|       source.buffer = adata; | ||||
| @@ -34,6 +38,16 @@ export class Sound { | ||||
|       source.connect(gain); | ||||
|       gain.connect(shared.context.destination); | ||||
|       source.start(); | ||||
|  | ||||
|       if (options?.bgm) { | ||||
|         shared.bgmSource?.stop(shared.context.currentTime + 1); | ||||
|         shared.bgmGain?.gain?.linearRampToValueAtTime( | ||||
|           0.0, | ||||
|           shared.context.currentTime + 1, | ||||
|         ); | ||||
|         shared.bgmSource = source; | ||||
|         shared.bgmGain = gain; | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,22 +1,26 @@ | ||||
| import audBite from "./art/sounds/bite.mp3"; | ||||
| import audDeath from "./art/sounds/death.mp3"; | ||||
| import audDig from "./art/sounds/dig.mp3"; | ||||
| import audEnding from "./art/sounds/ending.mp3"; | ||||
| import audRecruit from "./art/sounds/recruit.mp3"; | ||||
| import audRewardBig from "./art/sounds/reward_big.mp3"; | ||||
| import audRewardHuge from "./art/sounds/reward_huge.mp3"; | ||||
| import audRewardMedium from "./art/sounds/reward_medium.mp3"; | ||||
| import audRewardSmall from "./art/sounds/reward_small.mp3"; | ||||
| import audSilence from "./art/sounds/silence.mp3"; | ||||
| import audSleep from "./art/sounds/sleep.mp3"; | ||||
| import { Sound } from "./sound.ts"; | ||||
|  | ||||
| export let sndBite = new Sound(audBite); | ||||
| export let sndDeath = new Sound(audDeath); | ||||
| export let sndDig = new Sound(audDig); | ||||
| export let sndEnding = new Sound(audEnding); | ||||
| export let sndRecruit = new Sound(audRecruit); | ||||
| export let sndRewardBig = new Sound(audRewardBig); | ||||
| export let sndRewardHuge = new Sound(audRewardHuge); | ||||
| export let sndRewardMedium = new Sound(audRewardMedium); | ||||
| export let sndRewardSmall = new Sound(audRewardSmall); | ||||
| export let sndSilence = new Sound(audSilence); | ||||
| export let sndSleep = new Sound(audSleep); | ||||
|  | ||||
| export function sndRewardFor(amount: number) { | ||||
|   | ||||
| @@ -5,8 +5,11 @@ import { getScorer } from "./scorer.ts"; | ||||
| import { getEndgameModal } from "./endgamemodal.ts"; | ||||
| import { SuccessorOption, Wish } from "./datatypes.ts"; | ||||
| import { generateManor } from "./manormap.ts"; | ||||
| import { sndSleep } from "./sounds.ts"; | ||||
| import { sndSilence, sndSleep } from "./sounds.ts"; | ||||
| import { openingScene } from "./openingscene.ts"; | ||||
| import { generateName } from "./namegen.ts"; | ||||
| import { photogenicThralls } from "./thralls.ts"; | ||||
| import { choose } from "./utils.ts"; | ||||
|  | ||||
| const N_TURNS: number = 9; | ||||
|  | ||||
| @@ -29,7 +32,8 @@ export class StateManager { | ||||
|         callback: () => { | ||||
|           this.startGame( | ||||
|             { | ||||
|               name: "Pyrex", | ||||
|               name: generateName(), | ||||
|               template: choose(photogenicThralls), | ||||
|               title: "", | ||||
|               note: null, | ||||
|               stats: { AGI: 10, INT: 10, CHA: 10, PSI: 10 }, | ||||
| @@ -49,7 +53,7 @@ export class StateManager { | ||||
|     this.#turn = 1; | ||||
|     initPlayerProgress(asSuccessor, withWish); | ||||
|     initHuntMode(new HuntMode(1, generateManor())); | ||||
|     sndSleep.play(); | ||||
|     sndSleep.play({ bgm: true }); | ||||
|   } | ||||
|  | ||||
|   advance() { | ||||
| @@ -58,9 +62,9 @@ export class StateManager { | ||||
|       getPlayerProgress().applyEndOfTurn(); | ||||
|       getPlayerProgress().refill(); | ||||
|       initHuntMode(new HuntMode(getHuntMode().depth, generateManor())); | ||||
|       sndSleep.play(); | ||||
|       sndSleep.play({ bgm: true }); | ||||
|     } else { | ||||
|       // TODO: Play a specific scene | ||||
|       sndSilence.play({ bgm: true }); | ||||
|       let ending = getScorer().pickEnding(); | ||||
|       getVNModal().play(ending.scene); | ||||
|       getEndgameModal().show(ending); | ||||
|   | ||||
| @@ -2,6 +2,7 @@ import { ALL_STATS, Skill, Stat, SuccessorOption } from "./datatypes.ts"; | ||||
| import { generateName, generateTitle } from "./namegen.ts"; | ||||
| import { choose } from "./utils.ts"; | ||||
| import { getPlayerProgress } from "./playerprogress.ts"; | ||||
| import { photogenicThralls } from "./thralls.ts"; | ||||
|  | ||||
| export function generateSuccessors( | ||||
|   nImprovements: number, | ||||
| @@ -35,6 +36,7 @@ export function generateSuccessorFromPlayer(): SuccessorOption { | ||||
|   let progress = getPlayerProgress(); | ||||
|   let successor = { | ||||
|     name: progress.name, | ||||
|     template: progress.template, | ||||
|     title: "Penitent", | ||||
|     note: "Failed at Master's bidding", | ||||
|     stats: { ...progress.getStats() }, | ||||
| @@ -52,6 +54,7 @@ export function generateSuccessorFromPlayer(): SuccessorOption { | ||||
|  | ||||
| export function generateSuccessor(nImprovements: number): SuccessorOption { | ||||
|   let name = generateName(); | ||||
|   let template = choose(photogenicThralls); | ||||
|   let title = generateTitle(); | ||||
|   let note = null; | ||||
|   let stats: Record<Stat, number> = { | ||||
| @@ -85,5 +88,15 @@ export function generateSuccessor(nImprovements: number): SuccessorOption { | ||||
|   let skills: Skill[] = []; | ||||
|   let inPenance = false; | ||||
|   let isCompulsory = false; | ||||
|   return { name, title, note, stats, talents, skills, inPenance, isCompulsory }; | ||||
|   return { | ||||
|     name, | ||||
|     template, | ||||
|     title, | ||||
|     note, | ||||
|     stats, | ||||
|     talents, | ||||
|     skills, | ||||
|     inPenance, | ||||
|     isCompulsory, | ||||
|   }; | ||||
| } | ||||
|   | ||||
| @@ -56,6 +56,7 @@ class ThrallsTable { | ||||
| export type ThrallData = { | ||||
|   label: string; | ||||
|   sprite: Sprite; | ||||
|   hitboxSize: number; | ||||
|   posterCheck: CheckData; | ||||
|   initialCheck: CheckData; | ||||
|   itemHint: string; | ||||
| @@ -99,6 +100,7 @@ export function getThralls() { | ||||
| export let thrallParty = table.add({ | ||||
|   label: "Garrett", | ||||
|   sprite: sprThrallParty, | ||||
|   hitboxSize: 0.7, | ||||
|   posterCheck: { | ||||
|     label: | ||||
|       "This room would be perfect for someone with an ostensibly managed gambling addiction.", | ||||
| @@ -172,6 +174,7 @@ export let thrallParty = table.add({ | ||||
| export let thrallLore = table.add({ | ||||
|   label: "Lupin", | ||||
|   sprite: sprThrallLore, | ||||
|   hitboxSize: 0.65, | ||||
|   posterCheck: { | ||||
|     label: | ||||
|       "This room would be perfect for someone with a love of nature and screaming.", | ||||
| @@ -244,6 +247,7 @@ export let thrallLore = table.add({ | ||||
| export let thrallBat = table.add({ | ||||
|   label: "Monica", | ||||
|   sprite: sprThrallBat, | ||||
|   hitboxSize: 0.4, | ||||
|   posterCheck: { | ||||
|     label: "This room would be perfect for some kind of television chef.", | ||||
|     options: [], | ||||
| @@ -318,6 +322,7 @@ export let thrallBat = table.add({ | ||||
| export let thrallCharm = table.add({ | ||||
|   label: "Renfield", | ||||
|   sprite: sprThrallCharm, | ||||
|   hitboxSize: 0.85, | ||||
|   posterCheck: { | ||||
|     label: | ||||
|       "This room would be perfect for someone who likes vampires even more than you enjoy being a vampire.", | ||||
| @@ -389,6 +394,7 @@ export let thrallCharm = table.add({ | ||||
| export let thrallStealth = table.add({ | ||||
|   label: "Narthyss", | ||||
|   sprite: sprThrallStealth, | ||||
|   hitboxSize: 0.85, | ||||
|   posterCheck: { | ||||
|     label: "This room would be perfect for someone who can breathe fire.", | ||||
|     options: [], | ||||
| @@ -461,6 +467,7 @@ export let thrallStealth = table.add({ | ||||
| export let thrallStare = table.add({ | ||||
|   label: "Ridley", | ||||
|   sprite: sprThrallStare, | ||||
|   hitboxSize: 0.85, | ||||
|   posterCheck: { | ||||
|     label: "This room would be perfect for a soulless robot.", | ||||
|     options: [], | ||||
| @@ -525,3 +532,19 @@ export let thrallStare = table.add({ | ||||
|     }, | ||||
|   }, | ||||
| }); | ||||
|  | ||||
| export let photogenicThralls = [ | ||||
|   thrallParty, | ||||
|   thrallParty, | ||||
|   thrallParty, | ||||
|   thrallLore, | ||||
|   thrallLore, | ||||
|   thrallLore, | ||||
|   thrallCharm, | ||||
|   thrallCharm, | ||||
|   thrallCharm, | ||||
|   thrallStealth, | ||||
|   thrallStealth, | ||||
|   thrallStealth, | ||||
|   thrallBat, | ||||
| ]; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user