/// module AIRules { export var Wander = AI.rules.createAndAddRule({ name : "Wander", firstPriority : AIRules.PRIORITY_ACTING_ON_IDLE, conditions : (runner : RulebookRunner) => { let person = runner.noun; return person.AI.wanderer && (Math.random() * 100) > person.AI.wanderChance; }, code : (runner : RulebookRunner) => { let person = runner.noun; let room = person.getRoom(); if (person.AI.wandersOn != undefined) { // stick to region while wandering if (person.AI.wandersOn.containsRoom(room)) { // Alredy in region, so just wander off inside it let connections = room.connections.slice(); let realConnections = []; for (let i = 0; i < connections.length; i++) { if (connections[i] != undefined && person.AI.wandersOn.containsRoom(connections[i])) { realConnections.push(i); } } let direction = ((new Shuffler(realConnections)).getOne()); return new ActionGo(person, direction); } else { // return to region let regionRooms = person.AI.wandersOn.getRooms().filter((a : Room) => { if (a instanceof RoomRandom && a.placed) { return true; } }); // Ideally we'd actually make a path to it and check the distance, since mazes can make it be longer than it really is // But this is quick and dirty enough. And since regions are closely packed, even if this is not really the closest room, the NPC will end up // entering the region earlier by accident. regionRooms.sort((a : RoomRandom, b : RoomRandom) => { let dist = a.getDistanceTo(b); if (dist != undefined) { return -dist; // This means that the latest element will be the closest. } else { return 0; // This means that the first elements will be unreachable } }); let targetRoom = regionRooms.pop(); return new ActionGo(person, targetRoom); } } else { // just wander in random direction let direction = room.getConnectedDirection(); return new ActionGo(person, direction); } } }); }