Enemies now react to shots being fired in the same area
Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
@@ -75,6 +75,9 @@ class WolfEngine {
|
||||
|
||||
bool isInitialized = false;
|
||||
|
||||
/// Tracks the last time a sound wave was emitted to prevent BFS spam.
|
||||
int _lastAcousticAlertTime = 0;
|
||||
|
||||
/// Initializes the engine, sets the starting episode, and loads the first level.
|
||||
void init() {
|
||||
_currentEpisodeIndex = startingEpisode;
|
||||
@@ -222,8 +225,15 @@ class WolfEngine {
|
||||
if (input.requestedWeapon != null) {
|
||||
player.requestWeaponSwitch(input.requestedWeapon!);
|
||||
}
|
||||
|
||||
if (input.isFiring) {
|
||||
player.fire(_timeAliveMs);
|
||||
|
||||
// Throttle the acoustic flood-fill to emit a "wave" every 400ms while firing
|
||||
if (_timeAliveMs - _lastAcousticAlertTime > 400) {
|
||||
_propagateGunfire();
|
||||
_lastAcousticAlertTime = _timeAliveMs;
|
||||
}
|
||||
} else {
|
||||
player.releaseTrigger();
|
||||
}
|
||||
@@ -363,6 +373,70 @@ class WolfEngine {
|
||||
if (itemsToAdd.isNotEmpty) entities.addAll(itemsToAdd);
|
||||
}
|
||||
|
||||
/// Propagates weapon noise through corridors and open doors using a Breadth-First Search.
|
||||
void _propagateGunfire() {
|
||||
int maxAcousticRange = 20; // How many tiles the sound wave travels
|
||||
int startX = player.x.toInt();
|
||||
int startY = player.y.toInt();
|
||||
|
||||
// Track visited tiles using a 1D index to prevent infinite loops
|
||||
Set<int> visited = {startY * 64 + startX};
|
||||
|
||||
List<({int x, int y})> queue = [(x: startX, y: startY)];
|
||||
|
||||
int distance = 0;
|
||||
|
||||
while (queue.isNotEmpty && distance < maxAcousticRange) {
|
||||
List<({int x, int y})> nextQueue = [];
|
||||
|
||||
for (var tile in queue) {
|
||||
// 1. Alert any enemies standing on this specific tile
|
||||
for (var entity in entities) {
|
||||
if (entity is Enemy &&
|
||||
!entity.isAlerted &&
|
||||
entity.state != EntityState.dead) {
|
||||
if (entity.position.x.toInt() == tile.x &&
|
||||
entity.position.y.toInt() == tile.y) {
|
||||
entity.isAlerted = true;
|
||||
|
||||
// Wake them up!
|
||||
if (entity.state == EntityState.idle ||
|
||||
entity.state == EntityState.ambush) {
|
||||
entity.state = EntityState.patrolling;
|
||||
entity.lastActionTime = _timeAliveMs;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Expand the sound wave outward to North, East, South, West
|
||||
final neighbors = <({int x, int y})>[
|
||||
(x: tile.x + 1, y: tile.y),
|
||||
(x: tile.x - 1, y: tile.y),
|
||||
(x: tile.x, y: tile.y + 1),
|
||||
(x: tile.x, y: tile.y - 1),
|
||||
];
|
||||
|
||||
for (var n in neighbors) {
|
||||
// Keep it within the 64x64 grid limits
|
||||
if (n.x >= 0 && n.x < 64 && n.y >= 0 && n.y < 64) {
|
||||
int idx = n.y * 64 + n.x;
|
||||
if (!visited.contains(idx)) {
|
||||
visited.add(idx);
|
||||
|
||||
// Sound only travels through walkable tiles (air and OPEN doors).
|
||||
if (isWalkable(n.x, n.y)) {
|
||||
nextQueue.add(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
queue = nextQueue;
|
||||
distance++;
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if a tile is empty or contains a door that is sufficiently open.
|
||||
bool isWalkable(int x, int y) {
|
||||
if (currentLevel[y][x] == 0) return true;
|
||||
|
||||
Reference in New Issue
Block a user