$gameMap.events().forEach(function(ev) {
// Prüfen ob Event existiert und den richtigen Namen hat
if (!ev
!ev.event()
!ev.event().name.includes("Schwarze Ordenswache")) return;
// === INIT ===
if (!ev._moveCounter) ev._moveCounter = 0;
if (ev._state == null) ev._state = "patrol";
if (ev._chaseTarget == null) ev._chaseTarget = null;
if (!ev._lostSightTimer) ev._lostSightTimer = 0;
// NEU: Initialisierung der letzten bekannten Position
if (ev._lastSeenX == null) ev._lastSeenX = ev.x;
if (ev._lastSeenY == null) ev._lastSeenY = ev.y;
ev._moveCounter++;
if (ev._moveCounter < 2) return; // Drosselung (optional, aber gut für Performance)
ev._moveCounter = 0;
const player = $gamePlayer;
const dx = player.x - ev.x;
const dy = player.y - ev.y;
const dist = Math.sqrt(dx * dx + dy * dy);
// === SICHTKONTROLLE (Raycasting) ===
const maxDist = 10;
const fov = 60;
const dirAngles = { 2: 90, 4: 180, 6: 0, 8: 270 };
const guardAngle = dirAngles[ev.direction()];
// Berechnung des Winkels zum Spieler
const angleToPlayer = (Math.atan2(-dy, dx) * 180 / Math.PI + 360) % 360;
let diff = Math.abs(guardAngle - angleToPlayer);
if (diff > 180) diff = 360 - diff;
let seesPlayer = false;
// Einfache Distanz und Winkelprüfung
if (dist <= maxDist && diff <= fov / 2) {
seesPlayer = true; // Erstmal annehmen, wir sehen ihn
const steps = Math.ceil(dist * 2);
// Raycasting: Prüfen ob Wände im Weg sind
for (let i = 1; i < steps; i++) {
const stepX = Math.round(ev.x + (dx * (i / steps)));
const stepY = Math.round(ev.y + (dy * (i / steps)));
// Prüft Passability in alle 4 Richtungen an diesem Punkt
if (
!$gameMap.isPassable(stepX, stepY, 2) &&
!$gameMap.isPassable(stepX, stepY,
&&
!$gameMap.isPassable(stepX, stepY, 4) &&
!$gameMap.isPassable(stepX, stepY, 6)
) {
seesPlayer = false;
break;
}
}
}
// === STATUSWECHSEL & MERKEN ===
if (seesPlayer) {
ev._state = "chase";
ev._chaseTarget = player;
ev._lostSightTimer = 0;
// NEU: Position merken, solange wir ihn sehen!
ev._lastSeenX = player.x;
ev._lastSeenY = player.y;
} else if (ev._state === "chase") {
ev._lostSightTimer++;
// GEÄNDERT: Wenn er an der letzten bekannten Position angekommen ist
// UND den Spieler immer noch nicht sieht -> sofort aufgeben oder suchen.
if (ev.x === ev._lastSeenX && ev.y === ev._lastSeenY) {
ev._state = "alert";
ev._lostSightTimer = 0;
}
// Oder wenn der Timer abläuft (Timeout)
if (ev._lostSightTimer > 180) {
ev._state = "alert";
ev._chaseTarget = null;
ev._lostSightTimer = 0;
}
}
// === BEWEGUNGSVERHALTEN ===
if (ev._state === "chase" && !ev.isMoving()) {
ev.setMoveSpeed(4);
// GEÄNDERT: Zielwahl
// Wenn wir ihn sehen -> Lauf zum Spieler.
// Wenn nicht -> Lauf zur letzten bekannten Position.
let targetX, targetY;
if (seesPlayer) {
targetX = player.x;
targetY = player.y;
} else {
targetX = ev._lastSeenX;
targetY = ev._lastSeenY;
}
const dx2 = targetX - ev.x;
const dy2 = targetY - ev.y;
const dist2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
if (dist2 > 0) { // Größer 0, sonst zittert er auf der Stelle
const dir =
Math.abs(dx2) > Math.abs(dy2)
? (dx2 > 0 ? 6 : 4)
: (dy2 > 0 ? 2 : 8);
// Simples pathfinding (Try & Error)
if (ev.canPass(ev.x, ev.y, dir)) {
ev.moveStraight(dir);
} else {
// NEU: Kleiner Tweak - wenn geradeaus blockiert ist, versuche die andere Achse
// Das verhindert Hängenbleiben an Ecken
const altDir = (dy2 > 0 ? 2 : 8); // Vertikale Alternative, wenn Horizontal blockiert
if (Math.abs(dx2) > Math.abs(dy2) && ev.canPass(ev.x, ev.y, altDir)) {
ev.moveStraight(altDir);
} else if (ev.canPass(ev.x, ev.y, (dx2 > 0 ? 6 : 4))) {
ev.moveStraight((dx2 > 0 ? 6 : 4));
}
}
} else {
// Ziel erreicht (sei es Spieler oder letzte Position)
ev.setDirection(ev.direction());
}
return;
}
if (ev._state === "alert" && !ev.isMoving()) {
ev.setMoveSpeed(3);
// Zufälliges Umherschauen / kleine Schritte
if (Math.random() < 0.1) { // Nicht jeden Frame bewegen, wirkt natürlicher
const dirs = [2, 4, 6, 8];
const rand = dirs[Math.floor(Math.random() * 4)];
if (ev.canPass(ev.x, ev.y, rand)) ev.moveStraight(rand);
}
ev._lostSightTimer++;
if (ev._lostSightTimer > 300) {
ev._state = "patrol";
ev._lostSightTimer = 0;
}
return;
}
if (ev._state === "patrol" && !ev.isMoving()) {
ev.setMoveSpeed(3);
// Behält die Editor-Route bei
}
});