void ProcessWorldEvent(ZombieAgent zombie, WorldEvent ev) { if (ev == null) { return; } var dist = Vector3.Distance(zombie.pos, ev.Pos); if (dist <= ev.Radius) { Vector3 soundDir = new Vector3(); soundDir.x = _prng.Get(-1.0f, 1.0f); soundDir.z = _prng.Get(-1.0f, 1.0f); // Pick a random position within 75% of the radius. soundDir.Normalize(); soundDir *= (dist * 0.75f); zombie.targetPos = ev.Pos + soundDir; zombie.target = _worldZones.FindByPos2D(zombie.targetPos); zombie.state = ZombieAgent.State.Investigating; } }
void UpdateApproachTarget(ZombieAgent zombie, float dt) { #if false // Test investigation. if (zombie.state != ZombieAgent.State.Investigating) { return; } #endif float speed = _state.ScaledZombieSpeed; speed *= dt; // Calculate direction towards target position. zombie.dir = zombie.targetPos - zombie.pos; zombie.dir.Normalize(); var distance = Vector3.Distance(zombie.pos, zombie.targetPos) * 0.75f; var t = (zombie.simulationTime + zombie.id) * 0.2f; var offset = new Vector3(Mathf.Cos(t), 0.0f, Mathf.Sin(t)); offset *= distance; // Move towards target. zombie.pos = Vector3.MoveTowards(zombie.pos, zombie.targetPos + offset, speed); }
private void UpdateTarget(ZombieAgent zombie) { if (zombie.state != ZombieAgent.State.Idle) { // If we have an active target wait for arrival. if (!zombie.ReachedTarget()) { return; } zombie.AddVisitedZone(zombie.target); } if (_state.IsBloodMoon) { zombie.target = _playerZones.GetRandomClosest(zombie.pos, _prng, 200.0f, null); if (zombie.target == null) { zombie.target = GetNextTarget(zombie); } } else { zombie.target = GetNextTarget(zombie); } zombie.targetPos = GetTargetPos(zombie.target); zombie.state = ZombieAgent.State.Wandering; }
private Zone GetNextTarget(ZombieAgent zombie) { if (_prng.Chance(Config.Instance.POITravellerChance)) { return(GetNextPOI(zombie)); } return(_worldZones.GetRandom(_prng)); }
void UpdateInactiveZombie(ZombieAgent zombie, float dt, WorldEvent ev) { zombie.simulationTime += dt; ProcessWorldEvent(zombie, ev); UpdateTarget(zombie); UpdateApproachTarget(zombie, dt); }
void TurnZombieInactive(ZombieAgent zombie) { zombie.state = ZombieAgent.State.Idle; lock (_inactiveQueue) { _inactiveQueue.Enqueue(zombie); } }
private POIZone GetNextPOI(ZombieAgent zombie) { var closest = _pois.GetRandomClosest(zombie.pos, _prng, 5000, 3); if (closest == null) { return(_pois.GetRandom(_prng)); } return(closest); }
private void RespawnInactiveZombie(ZombieAgent zombie) { lock (_inactiveQueue) { zombie.pos = GetRandomBorderPoint(); zombie.target = GetNextTarget(zombie); zombie.targetPos = GetTargetPos(zombie.target); _inactiveQueue.Enqueue(zombie); } }
private void UpdateInactiveZombie(ZombieAgent zombie, float dt, WorldEvent ev) { UpdateTarget(zombie, ev); zombie.dir = zombie.targetPos - zombie.pos; zombie.dir.Normalize(); float speed = _worldState.GetZombieSpeed() * dt; zombie.pos = Vector3.MoveTowards(zombie.pos, zombie.targetPos, speed); }
private void RequestActiveZombie(ZombieAgent zombie, PlayerZone zone) { ZombieSpawnRequest spawn = new ZombieSpawnRequest(); spawn.zombie = zombie; spawn.zone = zone; lock (_spawnQueue) { _spawnQueue.Enqueue(spawn); } }
void RequestActiveZombie(ZombieAgent zombie, PlayerZone zone) { zombie.state = ZombieAgent.State.Active; ZombieSpawnRequest spawn = new ZombieSpawnRequest(); spawn.zombie = zombie; spawn.zone = zone; lock (_spawnQueue) { _spawnQueue.Enqueue(spawn); } }
private ZombieAgent CreateInactiveZombie(bool initial) { ZombieAgent zombie = new ZombieAgent(); zombie.id = _nextZombieId++; if (initial) { // The initial population is placed nearby pois more frequently. var poiChance = 0.8f; var poi = _prng.Chance(poiChance) ? _pois.GetRandom(_prng) : null; if (poi != null) { // To be not literally inside the POI we add a random radius. var spawnRadius = 256.0f; var randOffset = new Vector3( _prng.Get(-spawnRadius, spawnRadius), 0.0f, _prng.Get(-spawnRadius, spawnRadius)); zombie.pos = poi.GetRandomPos(_prng) + randOffset; zombie.pos = WrapPos(zombie.pos); } else { // Use a random world zone for the rest. var zone = _worldZones.GetRandom(_prng); if (zone != null) { zombie.pos = zone.GetRandomPos(_prng); } else { zombie.pos = GetRandomPos(); } } } else { // New zombies start at the border. zombie.pos = GetRandomBorderPoint(); } zombie.target = GetNextTarget(zombie); zombie.targetPos = GetTargetPos(zombie.target); _inactiveZombies.Add(zombie); return(zombie); }
ZombieAgent CreateInactiveZombie(bool initial) { ZombieAgent zombie = new ZombieAgent(); zombie.id = _nextZombieId++; if (initial) { var poiChance = Config.Instance.POITravellerChance; var poi = _prng.Chance(poiChance) ? _pois.GetRandom(_prng) : null; if (poi != null) { // To be not literally inside the POI we add a random radius. var spawnRadius = 256.0f; var randOffset = new Vector3( _prng.Get(-spawnRadius, spawnRadius), 0.0f, _prng.Get(-spawnRadius, spawnRadius)); zombie.pos = poi.GetRandomPos(_prng) + randOffset; zombie.pos = WrapPos(zombie.pos); } else { // Use a random world zone for the rest. var zone = _worldZones.GetRandom(_prng); if (zone != null) { zombie.pos = zone.GetRandomPos(_prng); } else { zombie.pos = GetRandomPos(); } } } else { // New zombies start at the border. zombie.pos = GetRandomBorderPoint(); } zombie.state = ZombieAgent.State.Idle; _inactiveZombies.Add(zombie); return(zombie); }
public bool Load() { try { using (Stream stream = File.Open(SimulationFile, FileMode.Open)) { BinaryFormatter formatter = new BinaryFormatter(); Config config = formatter.Deserialize(stream) as Config; if (!config.Equals(_config)) { Log.Out("[WalkerSim] Configuration changed, not loading save."); return(false); } lock (_lock) { List <ZombieData> data = formatter.Deserialize(stream) as List <ZombieData>; if (data.Count > 0) { _inactiveZombies.Clear(); foreach (var zombie in data) { var inactiveZombie = new ZombieAgent { health = zombie.health, pos = new Vector3(zombie.x, zombie.y, zombie.z), dir = new Vector3(zombie.dirX, 0.0f, zombie.dirY), target = zombie.target ? _pois.GetRandom(_prng) : null, targetPos = new Vector3(zombie.targetX, zombie.targetY, zombie.targetZ), }; _inactiveZombies.Add(inactiveZombie); } Log.Out("[WalkerSim] Loaded {0} inactive zombies", _inactiveZombies.Count); } } } } catch (Exception) { return(false); } return(true); }
private void UpdateTarget(ZombieAgent zombie, WorldEvent ev) { if (ev != null) { var dist = Vector3.Distance(zombie.pos, ev.Pos); if (dist <= ev.Radius) { Vector3 soundDir = new Vector3(); soundDir.x = _prng.Get(-1.0f, 1.0f); soundDir.z = _prng.Get(-1.0f, 1.0f); soundDir.Normalize(); soundDir *= (dist * 0.75f); zombie.targetPos = ev.Pos + soundDir; #if DEBUG Log.Out("Reacting to sound at {0}", ev.Pos); #endif return; } } // If we have an activate target wait for arrival. if (!zombie.ReachedTarget()) { return; } if (_worldState.IsBloodMoon()) { zombie.target = _playerZones.GetRandomClosest(zombie.pos, _prng, 200.0f); if (zombie.target == null) { zombie.target = GetNextTarget(zombie); } } else { zombie.target = GetNextTarget(zombie); } zombie.targetPos = GetTargetPos(zombie.target); }
public bool Load() { try { using (Stream stream = File.Open(SimulationFile, FileMode.Open)) { BinaryFormatter formatter = new(); var config = (Config)formatter.Deserialize(stream); if (!config.Equals(Config.Instance)) { Logger.Info("Configuration changed, not loading save."); return(false); } lock (_inactiveZombies) { var data = (List <ZombieData>)formatter.Deserialize(stream); if (data.Count > 0) { _inactiveZombies.Clear(); foreach (var zombie in data) { var inactiveZombie = new ZombieAgent { pos = new Vector3(zombie.x, zombie.y, zombie.z), health = zombie.health, }; inactiveZombie.Inactive.target = zombie.target ? _pois.GetRandom(_prng) : null; inactiveZombie.Inactive.targetPos = new Vector3(zombie.targetX, zombie.targetY, zombie.targetZ); _inactiveZombies.Add(inactiveZombie); } Logger.Info("Loaded {0} inactive zombies", _inactiveZombies.Count); } } } } catch (Exception) { return(false); } return(true); }
void RespawnInactiveZombie(ZombieAgent zombie) { zombie.pos = GetRandomBorderPoint(); TurnZombieInactive(zombie); }
void UpdateInactiveZombies(float dt) { // Repopulate lock (_inactiveZombies) { lock (_inactiveQueue) { while (_inactiveQueue.Count > 0) { var zombie = _inactiveQueue.Dequeue(); _inactiveZombies.Add(zombie); } } } // Simulate int activatedZombies = 0; int maxUpdates = _maxZombies; int maxPerZone = MaxZombiesPerZone(); WorldEvent ev = null; lock (_worldEvents) { if (_worldEvents.Count > 0) { ev = _worldEvents.Dequeue(); } } for (int i = 0; ; i++) { lock (_inactiveZombies) { if (i >= _inactiveZombies.Count) { break; } var world = GameManager.Instance.World; if (world == null) { Log.Out("[WalkerSim] World no longer exists, bailing"); break; } bool removeZombie = false; bool activatedZombie = false; ZombieAgent zombie = _inactiveZombies[i]; UpdateInactiveZombie(zombie, dt, ev); //Log.Out("New Zombie Position: {0}, Target: {1}", zombie.pos, zombie.targetPos); if (!CanSpawnActiveZombie()) { continue; } List <PlayerZone> zones = _playerZones.FindAllByPos2D(zombie.pos); if (zones.Count <= 0) { continue; } foreach (var zone in zones) { var player = world.GetEntity(zone.entityId) as EntityPlayer; // Use players spawn border. if (zone.IsInside2D(zombie.pos)) { if (!zone.InsideSpawnArea2D(zombie.pos)) { removeZombie = true; continue; } } else { continue; } if (zone.numZombies >= maxPerZone) { #if DEBUG Log.Out("[WalkerSim] Zone {0} is full: {1} / {2}", zombie.pos, zone.numZombies, maxPerZone); #endif continue; } RequestActiveZombie(zombie, zone); activatedZombie = true; activatedZombies++; break; } // Zombie inside one or more zones will be always removed. if (activatedZombie) { removeZombie = true; } if (removeZombie) { _inactiveZombies.RemoveAt(i); i--; // If the zombie was not activated begin a new cycle. if (!activatedZombie) { RespawnInactiveZombie(zombie); } // NOTE: This should never happen. if (_inactiveZombies.Count == 0) { Log.Error("Population is empty, this should not happen."); break; } } } } #if DEBUG if (activatedZombies > 0) { Log.Out("[WalkerSim] Activated {0} zombies", activatedZombies); } #endif }
bool CreateZombie(ZombieAgent zombie, PlayerZone zone) { if (!CanSpawnActiveZombie()) { return(false); } var world = GameManager.Instance.World; Chunk chunk = (Chunk)world.GetChunkSync(World.toChunkXZ(Mathf.FloorToInt(zombie.pos.x)), 0, World.toChunkXZ(Mathf.FloorToInt(zombie.pos.z))); if (chunk == null) { #if DEBUG Log.Out("[WalkerSim] Chunk not loaded at {0} {1}", zombie.pos, zombie.pos.z); #endif return(false); } int height = world.GetTerrainHeight(Mathf.FloorToInt(zombie.pos.x), Mathf.FloorToInt(zombie.pos.z)); Vector3 spawnPos = new Vector3(zombie.pos.x, height + 1.0f, zombie.pos.z); if (!CanZombieSpawnAt(spawnPos)) { #if DEBUG Log.Out("[WalkerSim] Unable to spawn zombie at {0}, CanMobsSpawnAtPos failed", spawnPos); #endif return(false); } if (zombie.classId == -1) { zombie.classId = _biomeData.GetZombieClass(world, chunk, (int)spawnPos.x, (int)spawnPos.z, _prng); if (zombie.classId == -1) { int lastClassId = -1; zombie.classId = EntityGroups.GetRandomFromGroup("ZombiesAll", ref lastClassId); #if DEBUG Log.Out("Used fallback for zombie class!"); #endif } } EntityZombie zombieEnt = EntityFactory.CreateEntity(zombie.classId, spawnPos) as EntityZombie; if (zombieEnt == null) { #if DEBUG Log.Error("[WalkerSim] Unable to create zombie entity!, Entity Id: {0}, Pos: {1}", zombie.classId, spawnPos); #endif return(false); } zombieEnt.bIsChunkObserver = true; // TODO: Figure out a better way to make them walk towards something. if (true) { // Send zombie towards a random position in the zone. Vector3 targetPos = GetRandomZonePos(zone); if (targetPos == Vector3.zero) { zombieEnt.SetInvestigatePosition(zone.center, 6000, false); } else { zombieEnt.SetInvestigatePosition(targetPos, 6000, false); } } // If the zombie was previously damaged take health to this one. if (zombie.health != -1) { zombieEnt.Health = zombie.health; } else { zombie.health = zombieEnt.Health; } zombieEnt.IsHordeZombie = true; zombieEnt.IsBloodMoon = _state.IsBloodMoon; zombieEnt.SetSpawnerSource(EnumSpawnerSource.StaticSpawner); world.SpawnEntityInWorld(zombieEnt); zombie.entityId = zombieEnt.entityId; zombie.currentZone = zone; zombie.lifeTime = world.GetWorldTime(); zone.numZombies++; #if DEBUG Log.Out("[WalkerSim] Spawned zombie {0} at {1}", zombieEnt, spawnPos); #endif lock (_activeZombies) { _activeZombies.Add(zombie); } return(true); }
bool UpdateActiveZombie(ZombieAgent zombie) { var world = GameManager.Instance.World; int maxPerZone = MaxZombiesPerZone(); bool removeZombie = false; var worldTime = world.GetWorldTime(); var timeAlive = worldTime - zombie.lifeTime; var currentZone = zombie.currentZone as PlayerZone; if (currentZone != null) { currentZone.numZombies--; if (currentZone.numZombies < 0) { currentZone.numZombies = 0; } } zombie.currentZone = null; Vector3 oldPos = new Vector3 { x = zombie.pos.x, y = zombie.pos.y, z = zombie.pos.z }; EntityZombie ent = world.GetEntity(zombie.entityId) as EntityZombie; if (ent == null) { #if DEBUG Log.Out("[WalkerSim] Failed to get zombie with entity id {0}", zombie.entityId); #endif removeZombie = true; RespawnInactiveZombie(zombie); } else { zombie.pos = ent.GetPosition(); zombie.health = ((EntityZombie)ent).Health; zombie.dir = -ent.rotation; if (ent.IsDead()) { removeZombie = true; RespawnInactiveZombie(zombie); } else { List <PlayerZone> zones = _playerZones.FindAllByPos2D(ent.GetPosition()); if (zones.Count == 0 && timeAlive >= MinZombieLifeTime) { #if DEBUG Log.Out("[WalkerSim] Zombie {0} out of range, turning inactive", ent); #endif removeZombie = true; world.RemoveEntity(zombie.entityId, EnumRemoveEntityReason.Despawned); zombie.entityId = -1; zombie.currentZone = null; TurnZombieInactive(zombie); } else { foreach (var zone in zones) { if (zone.numZombies + 1 < maxPerZone) { zone.numZombies++; zombie.currentZone = zone; // If the zombie is inside a player zone make sure we renew the life time. zombie.lifeTime = worldTime; break; } } } } } return(removeZombie); }
public ZombieSpawnRequest(ZombieAgent zombie, PlayerZone zone) { this.zombie = zombie; this.zone = zone; }