Can now open secret walls and pick up machine gun

Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
2026-03-14 15:34:27 +01:00
parent 9f5f29100b
commit 001c7c3131
13 changed files with 545 additions and 120 deletions

View File

@@ -58,18 +58,26 @@ class BrownGuard extends Enemy {
required Coordinate2D playerPosition,
required bool Function(int x, int y) isWalkable,
required void Function(int damage) onDamagePlayer,
required void Function(int x, int y) tryOpenDoor,
}) {
Coordinate2D movement = const Coordinate2D(0, 0);
double newAngle = angle;
// 1. Wake up logic
// 1. Wake up logic (Matches SightPlayer & FirstSighting)
if (state == EntityState.idle &&
hasLineOfSight(playerPosition, isWalkable)) {
state = EntityState.patrolling;
lastActionTime = elapsedMs;
if (reactionTimeMs == 0) {
// Init reaction delay: ~1 to 4 tics in C (1 tic = ~14ms, but plays out longer in engine ticks).
// Let's approximate human-feeling reaction time: 200ms - 800ms
reactionTimeMs = elapsedMs + 200 + math.Random().nextInt(600);
} else if (elapsedMs >= reactionTimeMs) {
state =
EntityState.patrolling; // Equivalent to FirstSighting chase frame
lastActionTime = elapsedMs;
reactionTimeMs = 0; // Reset
}
}
// 2. Pre-calculate spatial relations
double distance = position.distanceTo(playerPosition);
double angleToPlayer = position.angleTo(playerPosition);
@@ -77,7 +85,7 @@ class BrownGuard extends Enemy {
newAngle = angleToPlayer;
}
// Calculate Octant for sprite direction
// Octant logic remains the same
double diff = newAngle - angleToPlayer;
while (diff <= -math.pi) {
diff += 2 * math.pi;
@@ -85,6 +93,7 @@ class BrownGuard extends Enemy {
while (diff > math.pi) {
diff -= 2 * math.pi;
}
int octant = ((diff + (math.pi / 8)) / (math.pi / 4)).floor() % 8;
if (octant < 0) octant += 8;
@@ -96,22 +105,34 @@ class BrownGuard extends Enemy {
case EntityState.patrolling:
if (distance > 0.8) {
// Calculate movement intent
movement =
Coordinate2D(math.cos(newAngle), math.sin(newAngle)) * speed;
// Jitter fix: Use continuous vector movement instead of single-axis snapping
double moveX = math.cos(angleToPlayer) * speed;
double moveY = math.sin(angleToPlayer) * speed;
Coordinate2D intendedMovement = Coordinate2D(moveX, moveY);
// Pass tryOpenDoor down!
movement = getValidMovement(
intendedMovement,
isWalkable,
tryOpenDoor,
);
}
// Animation fix: Update the sprite so he actually turns and walks!
int walkFrame = (elapsedMs ~/ 150) % 4;
spriteIndex = 58 + (walkFrame * 8) + octant;
if (distance < 5.0 && elapsedMs - lastActionTime > 2000) {
// Shooting fix: Give him permission to stop and shoot you
// (1500ms delay between shots)
if (distance < 6.0 && elapsedMs - lastActionTime > 1500) {
if (hasLineOfSight(playerPosition, isWalkable)) {
state = EntityState.shooting;
lastActionTime = elapsedMs;
_hasFiredThisCycle = false;
}
}
break;
break; // Fallthrough fix: Don't forget the break!
case EntityState.shooting:
int timeShooting = elapsedMs - lastActionTime;
@@ -152,6 +173,7 @@ class BrownGuard extends Enemy {
spriteIndex = 95;
}
break;
default:
break;
}