Add more stats, crit/block/accuracy/dodge/lifesteal

This commit is contained in:
Peter Stockings
2026-01-05 12:39:43 +11:00
parent 171abb681a
commit 86a6afd1df
14 changed files with 815 additions and 406 deletions

View File

@@ -4,7 +4,8 @@ import {
type Vec2,
type Action,
type RunState,
type World
type World,
type CombatantActor
} from "../core/types";
import { TILE_SIZE } from "../core/constants";
import { inBounds, isBlocked, isPlayerOnExit } from "../engine/world/world-logic";
@@ -148,9 +149,11 @@ export class GameScene extends Phaser.Scene {
if (!this.dungeonRenderer.isSeen(tx, ty)) return;
// Check if clicking on an enemy
const isEnemy = [...this.world.actors.values()].some(a => a.pos.x === tx && a.pos.y === ty && !a.isPlayer);
const isEnemy = [...this.world.actors.values()].some(a =>
a.category === "combatant" && a.pos.x === tx && a.pos.y === ty && !a.isPlayer
);
const player = this.world.actors.get(this.playerId)!;
const player = this.world.actors.get(this.playerId) as CombatantActor;
const path = findPathAStar(
this.world,
this.dungeonRenderer.seenArray,
@@ -170,7 +173,7 @@ export class GameScene extends Phaser.Scene {
// Auto-walk one step per turn
if (this.playerPath.length >= 2) {
const player = this.world.actors.get(this.playerId)!;
const player = this.world.actors.get(this.playerId) as CombatantActor;
const next = this.playerPath[1];
const dx = next.x - player.pos.x;
const dy = next.y - player.pos.y;
@@ -183,7 +186,7 @@ export class GameScene extends Phaser.Scene {
if (isBlocked(this.world, next.x, next.y)) {
// Check if it's an enemy at 'next'
const targetId = [...this.world.actors.values()].find(
a => a.pos.x === next.x && a.pos.y === next.y && !a.isPlayer
a => a.category === "combatant" && a.pos.x === next.x && a.pos.y === next.y && !a.isPlayer
)?.id;
if (targetId !== undefined) {
@@ -213,13 +216,13 @@ export class GameScene extends Phaser.Scene {
else if (Phaser.Input.Keyboard.JustDown(this.cursors.down!)) dy = 1;
if (dx !== 0 || dy !== 0) {
const player = this.world.actors.get(this.playerId)!;
const player = this.world.actors.get(this.playerId) as CombatantActor;
const targetX = player.pos.x + dx;
const targetY = player.pos.y + dy;
// Check for enemy at target position
const targetId = [...this.world.actors.values()].find(
a => a.pos.x === targetX && a.pos.y === targetY && !a.isPlayer
a => a.category === "combatant" && a.pos.x === targetX && a.pos.y === targetY && !a.isPlayer
)?.id;
if (targetId !== undefined) {
@@ -254,11 +257,15 @@ export class GameScene extends Phaser.Scene {
const allEvents = [...playerEvents, ...enemyStep.events];
for (const ev of allEvents) {
if (ev.type === "damaged") {
this.dungeonRenderer.showDamage(ev.x, ev.y, ev.amount);
this.dungeonRenderer.showDamage(ev.x, ev.y, ev.amount, ev.isCrit, ev.isBlock);
} else if (ev.type === "dodged") {
this.dungeonRenderer.showDodge(ev.x, ev.y);
} else if (ev.type === "healed") {
this.dungeonRenderer.showHeal(ev.x, ev.y, ev.amount);
} else if (ev.type === "killed") {
this.dungeonRenderer.spawnCorpse(ev.x, ev.y, ev.victimType || "rat");
} else if (ev.type === "waited" && ev.actorId === this.playerId) {
const player = this.world.actors.get(this.playerId);
const player = this.world.actors.get(this.playerId) as CombatantActor;
if (player) {
this.dungeonRenderer.showWait(player.pos.x, player.pos.y);
}
@@ -328,8 +335,8 @@ export class GameScene extends Phaser.Scene {
}
private syncRunStateFromPlayer() {
const p = this.world.actors.get(this.playerId);
if (!p?.stats || !p.inventory) return;
const p = this.world.actors.get(this.playerId) as CombatantActor;
if (!p || p.category !== "combatant" || !p.stats || !p.inventory) return;
this.runState = {
stats: { ...p.stats },
@@ -348,7 +355,7 @@ export class GameScene extends Phaser.Scene {
private centerCameraOnPlayer() {
const player = this.world.actors.get(this.playerId)!;
const player = this.world.actors.get(this.playerId) as CombatantActor;
this.cameras.main.centerOn(
player.pos.x * TILE_SIZE + TILE_SIZE / 2,
player.pos.y * TILE_SIZE + TILE_SIZE / 2
@@ -356,8 +363,8 @@ export class GameScene extends Phaser.Scene {
}
private allocateStat(statName: string) {
const p = this.world.actors.get(this.playerId);
if (!p || !p.stats || p.stats.statPoints <= 0) return;
const p = this.world.actors.get(this.playerId) as CombatantActor;
if (!p || p.category !== "combatant" || !p.stats || p.stats.statPoints <= 0) return;
p.stats.statPoints--;
if (statName === "strength") {
@@ -380,8 +387,8 @@ export class GameScene extends Phaser.Scene {
}
private allocatePassive(nodeId: string) {
const p = this.world.actors.get(this.playerId);
if (!p || !p.stats || p.stats.skillPoints <= 0) return;
const p = this.world.actors.get(this.playerId) as CombatantActor;
if (!p || p.category !== "combatant" || !p.stats || p.stats.skillPoints <= 0) return;
if (p.stats.passiveNodes.includes(nodeId)) return;