add player death & quotes when win or lose

This commit is contained in:
Evan
2025-01-24 11:19:38 -08:00
parent 87c45853ba
commit ffb0b7c172
5 changed files with 208 additions and 33 deletions
+1 -1
View File
@@ -75,7 +75,7 @@ export async function createClientGame(lobbyConfig: LobbyConfig, gameConfig: Gam
const gameMap = await loadTerrainMap(gameConfig.gameMap);
const worker = new WorkerClient(lobbyConfig.gameID, gameConfig)
await worker.initialize()
const gameView = new GameView(worker, config, gameMap.gameMap)
const gameView = new GameView(worker, config, gameMap.gameMap, lobbyConfig.clientID)
consolex.log('going to init path finder')
-1
View File
@@ -80,7 +80,6 @@ export function createRenderer(canvas: HTMLCanvasElement, game: GameView, eventB
if (!(playerInfo instanceof WinModal)) {
console.error('win modal not found')
}
winModel.clientID = clientID
winModel.game = game
+174 -17
View File
@@ -5,16 +5,160 @@ import { ClientID } from '../../../core/Schemas';
import { GameView, PlayerView } from '../../../core/game/GameView';
import { Layer } from './Layer';
import { GameUpdateType } from '../../../core/game/GameUpdates';
import { PseudoRandom } from '../../../core/PseudoRandom';
import { simpleHash } from '../../../core/Util';
const lowRadiationVictoryQuotes = [
"Victory is mine. The world endures - under new management.",
"They thought they could stop me. Now they serve me.",
"The old order has fallen. My reign begins.",
"Not every victory requires destruction.",
"From this day forward, all will know who rules.",
"The war is over. Long live the victor.",
"A new empire rises - with me at its helm.",
"The throne is claimed. The crown is mine.",
"Today marks the beginning of my dynasty.",
"They feared my wrath. Now they'll know my rule.",
"Victory was inevitable. Surrender was optional.",
"A new era dawns - under my command.",
"The pieces are in place. The victory is complete.",
"Let history remember who conquered all.",
"Their resistance only delayed the inevitable.",
"Power shifts. Empires fall. I remain.",
"The world has a new master now.",
"Their armies fell. Their nations surrendered. I prevailed.",
"All paths led to this victory.",
"The world bows to its new ruler.",
"From the ashes of their defeat, my victory rises.",
"Destiny called. I answered. The world followed.",
"They called me tyrant. Now they call me emperor.",
"The old powers have fallen. Mine endures.",
"Every empire needs a beginning. This is mine.",
"Their defiance crumbled before my ambition.",
"No more rebels. No more resistance. Only order.",
"The final piece falls into place.",
"Let them write of this day in their histories.",
"My vision becomes reality.",
"Their surrender was wise. My victory was certain.",
"The wheels of fate turn in my favor.",
"A new chapter begins - written by the victor.",
"They fought the inevitable. The inevitable won.",
"All that was theirs is now mine.",
"The gods themselves bow before my triumph.",
"Their kingdoms shatter. My empire rises.",
"Victory tastes sweeter than wine.",
"The crown suits me well, don't you think?",
"Behold the dawn of my eternal reign."
];
const highRadiationVictoryQuotes = [
"Let the world burn. I just want to rule the ashes.",
"The old world died screaming. My new one rises from its bones.",
"They could have surrendered. Now they glow.",
"Everything burns. The throne of ashes awaits.",
"A wasteland needs a king. I have answered the call.",
"Their cities turned to glass. My victory endures.",
"Who needs a pristine world when you can rule its ruins?",
"They feared the fire. I embraced it.",
"The radiation clears the way for my reign.",
"A dead world makes for quiet subjects.",
"From atomic fire, my kingdom rises.",
"Nothing left but ashes and victory.",
"They wanted war. I gave them annihilation.",
"The world burns green. My empire glows eternal.",
"All thrones are built on ashes. Mine just glows.",
"Look upon my works and despair - if you can still see.",
"The mushroom clouds herald my coronation.",
"A crown of thorns for a radioactive realm.",
"They chose extinction. I chose supremacy.",
"The wasteland's throne is mine to claim.",
"The Geiger counter clicks. The masses bow.",
"Atoms split. Nations fall. I reign supreme.",
"My kingdom radiates with possibility.",
"The isotopes of victory decay slowly.",
"Critical mass achieved. Dominion secured.",
"Chain reaction complete: world falls, empire rises.",
"In nuclear fire, I forge my legacy."
];
export const defeatQuotes = [
// Last words and final thoughts
"The flame of our nation flickers out...",
"History will remember we fought to the last.",
"Our glory fades into darkness.",
"The end comes for all nations. Today, it comes for us.",
"We fought. We failed. We fade.",
"Our time in the sun is done.",
"The pages of history close on our chapter.",
"So falls the dream of empire.",
"We built in stone, but even stone crumbles.",
"The stars themselves will remember our defiance.",
// Bitter defeats
"Treachery and fate conspired against us.",
"Our enemies dance on the graves of heroes.",
"The vultures circle what remains.",
"Let them celebrate. Dead men need no vengeance.",
"The light dies. The darkness wins.",
"Our walls fall. Our spirit breaks.",
"Victory goes to the ruthless.",
"Time claims another empire.",
"The crown shatters. The throne burns.",
"Our banners fall. Our story ends.",
// Philosophical acceptance
"All great nations must face their sunset.",
"Time is the ultimate conqueror.",
"Today we join the ghosts of fallen empires.",
"What rises must also fall.",
"Our legacy scatters like dust in the wind.",
"The wheel turns. We descend.",
"From glory to ashes, as all things must.",
"The tides of fate show no mercy.",
"Let history judge if we were worthy.",
"We join the eternal silence.",
// Defiant last stands
"Our spirit remains unbroken.",
"They may take our lands, but not our pride.",
"Remember us as we were, not as we fell.",
"We chose death before dishonor.",
"Our courage lives beyond our defeat.",
"Let them write of how we stood fast.",
"We fall, but we fall fighting.",
"Honor guides us to our end.",
"Death before surrender.",
"The echoes of our defiance will ring eternal.",
// Prophetic/Cursed
"Our shadow will haunt their victory.",
"They'll learn the price of empire.",
"Time will prove our cause was just.",
"The seeds of their downfall are sown in our ashes.",
"Our fall heralds their doom.",
"Victory today. Nemesis tomorrow.",
"The wheel turns for all.",
"They'll remember us in their nightmares.",
"Our curse follows them to their graves.",
"What rises in our place will shake the world."
];
@customElement('win-modal')
export class WinModal extends LitElement implements Layer {
public clientID: ClientID
public game: GameView
private winner: PlayerView
private rand: PseudoRandom;
private hasShownDeathModal = false
@state()
isVisible = false
private _title: string
private message: string
static styles = css`
:host {
display: block;
@@ -114,25 +258,19 @@ export class WinModal extends LitElement implements Layer {
`;
render() {
if (!this.winner) return null;
const isWinner = this.winner.clientID() === this.clientID;
const title = isWinner ? 'You Won!!!' : 'You Lost!!!';
const message = `${this.winner.name()} won the game!`;
return html`
<div class="modal ${this.isVisible ? 'visible' : ''}">
<h2>${title}</h2>
<p>${message}</p>
<h2>${this._title}</h2>
<p>${this.message}</p>
<div class="button-container">
<button @click=${this._handleExit}>Exit Game</button>
<button @click=${this._handleContinue}>Keep Playing</button>
<button @click=${this.hide}>Keep Playing</button>
</div>
</div>
`;
}
show(winner: PlayerView) {
this.winner = winner;
show() {
this.isVisible = true;
this.requestUpdate();
}
@@ -147,15 +285,34 @@ export class WinModal extends LitElement implements Layer {
window.location.reload();
}
private _handleContinue() {
this.hide();
init() {
this.rand = new PseudoRandom(simpleHash(this.game.myClientID()))
}
init() { }
tick() {
const myPlayer = this.game.myPlayer()
if (!this.hasShownDeathModal && myPlayer && !myPlayer.isAlive()) {
this.hasShownDeathModal = true
this._title = 'You died'
this.message = this.rand.randElement(defeatQuotes)
this.show()
}
this.game.updatesSinceLastTick()[GameUpdateType.WinUpdate]
.forEach(wu => this.show(this.game.playerBySmallID(wu.winnerID) as PlayerView))
.forEach(wu => {
const winner = this.game.playerBySmallID(wu.winnerID) as PlayerView
if (winner == this.game.myPlayer()) {
this._title = 'You Won!'
if (this.game.numTilesWithFallout() / this.game.numLandTiles() > .6) {
this.message = this.rand.randElement(highRadiationVictoryQuotes)
} else {
this.message = this.rand.randElement(lowRadiationVictoryQuotes)
}
} else {
this._title = `${winner.name()} has won!`
this.message = this.rand.randElement(defeatQuotes)
}
this.show()
})
}
renderLayer(context: CanvasRenderingContext2D) {
+13 -13
View File
@@ -19,7 +19,7 @@ export class DevConfig extends DefaultConfig {
}
numSpawnPhaseTurns(): number {
return this.gameConfig().gameType == GameType.Singleplayer ? 40 : 200
return this.gameConfig().gameType == GameType.Singleplayer ? 40 : 100
// return 100
}
@@ -30,23 +30,23 @@ export class DevConfig extends DefaultConfig {
return info
}
// percentageTilesOwnedToWin(): number {
// return 10
// }
percentageTilesOwnedToWin(): number {
return 1
}
// populationIncreaseRate(player: Player): number {
// return this.maxPopulation(player)
// }
populationIncreaseRate(player: Player): number {
return this.maxPopulation(player)
}
// boatMaxDistance(): number {
// return 5000
// }
// numBots(): number {
// return 0
// }
// spawnNPCs(): boolean {
// return false
// }
numBots(): number {
return 0
}
spawnNPCs(): boolean {
return false
}
}
+20 -1
View File
@@ -162,7 +162,15 @@ export class GameView implements GameMap {
private _units = new Map<number, UnitView>()
private updatedTiles: TileRef[] = []
constructor(public worker: WorkerClient, private _config: Config, private _map: GameMap) {
private _myPlayer: PlayerView | null = null
constructor(
public worker: WorkerClient,
private _config: Config,
private _map: GameMap,
private _myClientID: ClientID
) {
this.lastUpdate = {
tick: 0,
packedTileUpdates: new BigUint64Array([]),
@@ -210,6 +218,17 @@ export class GameView implements GameMap {
return this.updatedTiles
}
myClientID(): ClientID {
return this._myClientID
}
myPlayer(): PlayerView | null {
if (this._myPlayer == null) {
this._myPlayer = this.playerByClientID(this._myClientID)
}
return this._myPlayer
}
player(id: PlayerID): PlayerView {
if (this._players.has(id)) {
return this._players.get(id)