From 9c0aad2e75f3c3115551939cf99064e80418a29d Mon Sep 17 00:00:00 2001 From: Pabloader Date: Fri, 27 Jun 2025 15:31:49 +0000 Subject: [PATCH] Win checking --- src/games/zombies/player.ts | 12 ++++- src/games/zombies/tile.ts | 5 +- src/games/zombies/tilemap.ts | 98 ++++++++++++++++++++++++++++++++++-- 3 files changed, 106 insertions(+), 9 deletions(-) diff --git a/src/games/zombies/player.ts b/src/games/zombies/player.ts index 92b0ad0..3229fc4 100644 --- a/src/games/zombies/player.ts +++ b/src/games/zombies/player.ts @@ -59,6 +59,14 @@ export default class Player extends Character { return this.inventory.find(i => i.type === ItemType.WEAPON_ROCKET_LAUNCHER); } + get keys() { + return this.inventory.find(i => i.type === ItemType.ITEM_KEYS); + } + + get fuel() { + return this.inventory.find(i => i.type === ItemType.ITEM_FUEL); + } + public heal(player: Player) { player.health += this.healingAmount; } @@ -77,11 +85,11 @@ export default class Player extends Character { return false; } - public hasItem(item: Item | null | undefined): boolean { + public hasItem(item: Item | ItemTypeImage | null | undefined): boolean { if (!item) { return false; } - const itemIndex = this.inventory.findIndex(i => i === item); + const itemIndex = this.inventory.findIndex(i => i === item || i.type === item); return itemIndex >= 0; } diff --git a/src/games/zombies/tile.ts b/src/games/zombies/tile.ts index fcf48f1..7566591 100644 --- a/src/games/zombies/tile.ts +++ b/src/games/zombies/tile.ts @@ -1,7 +1,6 @@ import Entity from "./entity"; import type Item from "./item"; - -import planks from './assets/items/planks.jpg'; +import { ItemType } from "./item"; export enum TileType { NORMAL, @@ -69,7 +68,7 @@ export default class Tile extends Entity { y += (Number(this.top < doorway.top) - Number(doorway.top < this.top)) * 0.5; } - ctx.drawImage(planks, x - 0.2, y - 0.2, 0.4, 0.4); + ctx.drawImage(ItemType.ITEM_PLANKS, x - 0.2, y - 0.2, 0.4, 0.4); } } diff --git a/src/games/zombies/tilemap.ts b/src/games/zombies/tilemap.ts index 4478e9e..c653c32 100644 --- a/src/games/zombies/tilemap.ts +++ b/src/games/zombies/tilemap.ts @@ -20,15 +20,21 @@ export default class TileMap extends Entity { private state = GameState.NORMAL; private availableTiles: Tile[] = []; + public keysFound = false; + public fuelFound = false; + public bossKilled = false; + public readonly foundPlayers: Set; + constructor( - position: [number, number], - private mapSize: number, - private tileSize: number, - private spinner: Spinner, + position: [number, number], + private mapSize: number, + private tileSize: number, + private spinner: Spinner, numPlayers: number = 2, ) { super(position, [mapSize * tileSize, mapSize * tileSize]); this.players = shuffle(Object.values(Players)).slice(0, numPlayers); + this.foundPlayers = new Set(this.players); this.startTile = this.createMap(); this.findAvailableTiles(); } @@ -237,8 +243,10 @@ export default class TileMap extends Entity { } else if (item instanceof Player) { tile.removeItem(item); this.players.push(item); + this.foundPlayers.add(item); } else if (item.isBoss && this.player.removeItem(this.player.rocketLauncher)) { tile.killEnemy(); + this.bossKilled = true; } else if (item.isEnemy) { this.state = GameState.FIGHT; break; @@ -246,6 +254,14 @@ export default class TileMap extends Entity { alert(`Unknown item found: ${item}`); } } + if (tile.type === TileType.END) { + if (this.player.removeItem(this.player.fuel)) { + this.fuelFound = true; + } + if (this.player.removeItem(this.player.keys)) { + this.keysFound = true; + } + } if (this.state === GameState.NORMAL) { this.nextPlayer(); } @@ -325,6 +341,18 @@ export default class TileMap extends Entity { private nextPlayer() { this.spinner.stop(); this.currentPlayerIdx = (this.currentPlayerIdx + 1) % this.players.length; + if (this.win) { + const endTile = this.tiles.findLast(t => t.type === TileType.END); + if (endTile) { + for (const player of this.players) { + const path = Pathfinding.findPath(player.tile, endTile); + player.moveTo(endTile, path); + } + } + setTimeout(alert, 2000, "🎉🎉🎉 ПОБЕДА! 🚗 🎉🎉🎉"); + } else if (this.currentPlayerIdx === 0) { + // TODO zombies turn + } } private killEnemy() { @@ -339,6 +367,28 @@ export default class TileMap extends Entity { this.setNormalState(); } + private get win() { + if (!this.keysFound || !this.fuelFound || !this.bossKilled) { + return false; + } + const endTiles = this.tiles.filter(t => t.type === TileType.END); + for (const tile of endTiles) { + if (tile.items.length !== 0) return false; + } + for (const player of Object.values(Players)) { + if (!this.foundPlayers.has(player)) return false; + if (player.isDead) continue; + + if (endTiles.every((tile) => { + const path = Pathfinding.findPath(player.tile, tile); + return path.length === 0; + })) { + return false; + } + } + return true; + } + protected draw(ctx: CanvasRenderingContext2D): void { ctx.scale(1 / this.width, 1 / this.height); @@ -363,6 +413,46 @@ export default class TileMap extends Entity { ctx.strokeStyle = 'yellow'; ctx.strokeRect(this.player.tile.centerX - w / 2, this.player.tile.centerY - w / 2, w, w); + + let x = this.width + this.tileSize / 2 + 10; + let y = this.height - this.tileSize / 2; + for (const player of Object.values(Players)) { + this.drawItem(ctx, player.type, x, y, w, this.foundPlayers.has(player)); + x += this.tileSize; + } + + x = this.width + this.tileSize / 2 + 10; + y = this.height - 3 * this.tileSize / 2; + for (const [item, found] of zip( + [ItemType.ITEM_KEYS, ItemType.ITEM_FUEL, ItemType.ENEMY_BOSS], + [this.keysFound, this.fuelFound, this.bossKilled], + )) { + this.drawItem(ctx, item, x, y, w, found); + x += this.tileSize; + } + + x = this.width + this.tileSize / 2 + 10; + y = this.height - 5 * this.tileSize / 2; + for (const tile of this.tiles) { + if (tile.type !== TileType.END) continue; + + this.drawItem(ctx, ItemType.ENEMY_ZOMBIE, x, y, w, tile.items.length === 0); + x += this.tileSize; + } + } + + private drawItem( + ctx: CanvasRenderingContext2D, + img: HTMLImageElement, + x: number, y: number, w: number, + found: boolean, + ) { + ctx.drawImage(img, x - w / 2, y - w / 2, w, w); + + if (!found) { + ctx.fillStyle = `rgba(255, 255, 255, 0.6)`; + ctx.fillRect(x - w / 2, y - w / 2, w, w); + } } public update(dt: number) {