Пример #1
0
        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;
            }
        }
Пример #2
0
        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);
        }
Пример #3
0
        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;
        }
Пример #4
0
 private Zone GetNextTarget(ZombieAgent zombie)
 {
     if (_prng.Chance(Config.Instance.POITravellerChance))
     {
         return(GetNextPOI(zombie));
     }
     return(_worldZones.GetRandom(_prng));
 }
Пример #5
0
        void UpdateInactiveZombie(ZombieAgent zombie, float dt, WorldEvent ev)
        {
            zombie.simulationTime += dt;

            ProcessWorldEvent(zombie, ev);
            UpdateTarget(zombie);
            UpdateApproachTarget(zombie, dt);
        }
Пример #6
0
 void TurnZombieInactive(ZombieAgent zombie)
 {
     zombie.state = ZombieAgent.State.Idle;
     lock (_inactiveQueue)
     {
         _inactiveQueue.Enqueue(zombie);
     }
 }
Пример #7
0
        private POIZone GetNextPOI(ZombieAgent zombie)
        {
            var closest = _pois.GetRandomClosest(zombie.pos, _prng, 5000, 3);

            if (closest == null)
            {
                return(_pois.GetRandom(_prng));
            }
            return(closest);
        }
Пример #8
0
 private void RespawnInactiveZombie(ZombieAgent zombie)
 {
     lock (_inactiveQueue)
     {
         zombie.pos       = GetRandomBorderPoint();
         zombie.target    = GetNextTarget(zombie);
         zombie.targetPos = GetTargetPos(zombie.target);
         _inactiveQueue.Enqueue(zombie);
     }
 }
Пример #9
0
        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);
        }
Пример #10
0
        private void RequestActiveZombie(ZombieAgent zombie, PlayerZone zone)
        {
            ZombieSpawnRequest spawn = new ZombieSpawnRequest();

            spawn.zombie = zombie;
            spawn.zone   = zone;
            lock (_spawnQueue)
            {
                _spawnQueue.Enqueue(spawn);
            }
        }
Пример #11
0
        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);
            }
        }
Пример #12
0
        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);
        }
Пример #13
0
        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);
        }
Пример #14
0
        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);
        }
Пример #15
0
        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);
        }
Пример #16
0
        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);
        }
Пример #17
0
 void RespawnInactiveZombie(ZombieAgent zombie)
 {
     zombie.pos = GetRandomBorderPoint();
     TurnZombieInactive(zombie);
 }
Пример #18
0
        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
        }
Пример #19
0
        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);
        }
Пример #20
0
        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);
        }
Пример #21
0
 public ZombieSpawnRequest(ZombieAgent zombie, PlayerZone zone)
 {
     this.zombie = zombie;
     this.zone   = zone;
 }