Ejemplo n.º 1
0
        private static void ToggleCreatureEvents(NWArea area)
        {
            AreaSpawn areaSpawn   = AreaSpawns[area];
            int       playerCount = NWNXArea.GetNumberOfPlayersInArea(area);

            foreach (var creature in areaSpawn.Creatures)
            {
                if (creature.Spawn.IsValid)
                {
                    bool eventsDisabled = creature.Spawn.GetLocalInt("SPAWN_EVENTS_DISABLED") == TRUE;
                    bool isCreature     = creature.Spawn.IsCreature;

                    if (isCreature)
                    {
                        // Currently disabled, but players are in area. Enable them.
                        if (eventsDisabled && playerCount > 0)
                        {
                            EnableCreatureEvents(creature.SpawnCreature);
                            creature.SpawnCreature.SetLocalInt("SPAWN_EVENTS_DISABLED", FALSE);
                        }
                        // Currently enabled, but players are no longer in area. Disable them.
                        else if (!eventsDisabled && playerCount <= 0)
                        {
                            DisableCreatureEvents(creature.SpawnCreature);
                            creature.SpawnCreature.SetLocalInt("SPAWN_EVENTS_DISABLED", TRUE);
                        }
                    }
                }
            }
        }
Ejemplo n.º 2
0
        private static void ProcessAreaAI()
        {
            using (new Profiler(nameof(AIService) + "." + nameof(ProcessAreaAI)))
            {
                foreach (var area in NWModule.Get().Areas)
                {
                    int lastTickPlayerCount = area.GetLocalInt("AI_PLAYER_COUNT");
                    int thisTickPlayerCount = NWNXArea.GetNumberOfPlayersInArea(area);
                    area.SetLocalInt("AI_PLAYER_COUNT", thisTickPlayerCount);

                    // AI gets processed one more time after an area becomes empty.
                    // We do this so that behaviours can clean up properly.
                    if (thisTickPlayerCount <= 0 && lastTickPlayerCount <= 0)
                    {
                        continue;
                    }

                    // Safety check - If the area isn't in the cache, report it.
                    if (!_areaAICreatures.ContainsKey(area))
                    {
                        Console.WriteLine("Area " + area.Name + " not registered with AI service. Tag: " + area.Tag + ", Resref = " + area.Resref);
                        continue;
                    }

                    var creatures = _areaAICreatures[area];
                    ProcessCreatureAI(area, ref creatures);
                }
            }
        }
Ejemplo n.º 3
0
        private static void ProcessSpawns()
        {
            using (new Profiler(nameof(SpawnService) + "." + nameof(ProcessSpawns)))
            {
                // On module load, we want to populate all areas with NPCs and disable their AI.
                // The reason for this is because we don't want lag when players enter an area.
                // This'll use more memory but the CPU usage will be very limited as none of the
                // creatures will have scripts assigned.
                bool hasRunOnce = NWModule.Get().GetLocalInt("SPAWN_HAS_RUN_ONCE") == TRUE;

                foreach (var spawn in AreaSpawns)
                {
                    // Check for a valid area - otherwise it causes hangs sometimes when the server shuts down.
                    if (!spawn.Key.IsValid)
                    {
                        continue;
                    }

                    // Ignore empty areas.
                    int playerCount = NWNXArea.GetNumberOfPlayersInArea(spawn.Key);
                    if (playerCount <= 0 && hasRunOnce)
                    {
                        continue;
                    }

                    AreaSpawn areaSpawn  = spawn.Value;
                    bool      forceSpawn = !areaSpawn.HasSpawned;

                    foreach (var plc in areaSpawn.Placeables.Where(x => x.Respawns || !x.Respawns && !x.HasSpawnedOnce))
                    {
                        ProcessSpawn(plc, OBJECT_TYPE_PLACEABLE, spawn.Key, forceSpawn);
                    }

                    foreach (var creature in areaSpawn.Creatures.Where(x => x.Respawns || !x.Respawns && !x.HasSpawnedOnce))
                    {
                        ProcessSpawn(creature, OBJECT_TYPE_CREATURE, spawn.Key, forceSpawn);
                    }

                    areaSpawn.SecondsEmpty = 0.0f;
                    areaSpawn.HasSpawned   = true;

                    // Toggle creature AI now, if this is the first time we're running this process.
                    if (!hasRunOnce)
                    {
                        ToggleCreatureEvents(spawn.Key);
                    }
                }

                NWModule.Get().SetLocalInt("SPAWN_HAS_RUN_ONCE", TRUE);
            }
        }
Ejemplo n.º 4
0
        private static void OnAreaExit()
        {
            NWArea area        = NWGameObject.OBJECT_SELF;
            int    playerCount = NWNXArea.GetNumberOfPlayersInArea(area);

            if (playerCount > 0)
            {
                _.SetEventScript(area, _.EVENT_SCRIPT_AREA_ON_HEARTBEAT, "area_on_hb");
            }
            else
            {
                _.SetEventScript(area, _.EVENT_SCRIPT_AREA_ON_HEARTBEAT, string.Empty);
            }
        }
Ejemplo n.º 5
0
        private static void OnAreaExit()
        {
            NWArea area        = _.OBJECT_SELF;
            int    playerCount = NWNXArea.GetNumberOfPlayersInArea(area);

            if (playerCount > 0)
            {
                _.SetEventScript(area, EventScript.Area_OnHeartbeat, "area_on_hb");
            }
            else
            {
                _.SetEventScript(area, EventScript.Area_OnHeartbeat, string.Empty);
            }
        }
Ejemplo n.º 6
0
        public virtual void OnHeartbeat(NWCreature self)
        {
            // No sense processing for empty and invalid (limbo) areas.
            if (!self.Area.IsValid || NWNXArea.GetNumberOfPlayersInArea(self.Area) <= 0)
            {
                return;
            }

            var flags = GetAIFlags(self);

            if ((flags & AIFlags.RandomWalk) != 0)
            {
                RandomWalk(self);
            }
        }
Ejemplo n.º 7
0
        private static void ProcessAreaAI()
        {
            using (new Profiler(nameof(AIService) + "." + nameof(ProcessAreaAI)))
            {
                foreach (var area in NWModule.Get().Areas)
                {
                    // We don't process AI for empty areas.
                    if (NWNXArea.GetNumberOfPlayersInArea(area) <= 0)
                    {
                        continue;
                    }

                    var creatures = _areaAICreatures[area];
                    ProcessCreatureAI(ref creatures);
                }
            }
        }
        private void AttemptCleanup()
        {
            NWPlaceable exit              = NWGameObject.OBJECT_SELF;
            NWArea      mainLevel         = exit.Area.GetLocalObject("MAIN_LEVEL");
            NWArea      restrictedLevel   = exit.Area.GetLocalObject("RESTRICTED_LEVEL");
            NWArea      directorsChambers = exit.Area.GetLocalObject("DIRECTORS_CHAMBERS");

            int playersInAreas = NWNXArea.GetNumberOfPlayersInArea(mainLevel) +
                                 NWNXArea.GetNumberOfPlayersInArea(restrictedLevel) +
                                 NWNXArea.GetNumberOfPlayersInArea(directorsChambers);

            // There are still players in the areas. We can't clean up yet.
            if (playersInAreas > 0)
            {
                return;
            }

            // Otherwise, everyone has left. Do the cleanup now.
            AreaService.DestroyAreaInstance(mainLevel);
            AreaService.DestroyAreaInstance(restrictedLevel);
            AreaService.DestroyAreaInstance(directorsChambers);
        }
Ejemplo n.º 9
0
        private static void ProcessCreatureAI(ref HashSet <NWCreature> creatures)
        {
            // Iterate backwards so we can remove the creature if it's no longer valid.
            for (int x = creatures.Count - 1; x >= 0; x--)
            {
                NWCreature creature = creatures.ElementAt(x);
                NWArea     area     = creature.Area;

                // Limbo check.
                if (!area.IsValid)
                {
                    continue;
                }

                bool areaHasPCs = NWNXArea.GetNumberOfPlayersInArea(area) > 0;

                // Is this creature invalid or dead? If so, remove it and move to the next one.
                if (!creature.IsValid ||
                    creature.IsDead)
                {
                    creatures.Remove(creature);
                    continue;
                }

                // Are there no players in the area? Is the creature being possessed? If so, don't execute AI this frame. Move to the next one.
                if (creature.IsPossessedFamiliar || creature.IsDMPossessed || !areaHasPCs)
                {
                    continue;
                }

                string script = GetBehaviourScript(creature);
                if (string.IsNullOrWhiteSpace(script))
                {
                    continue;
                }
                IAIBehaviour behaviour = GetAIBehaviour(script);
                behaviour.OnProcessObject(creature);
            }
        }
Ejemplo n.º 10
0
        private static void ProcessAreaAI()
        {
            using (new Profiler(nameof(AIService) + "." + nameof(ProcessAreaAI)))
            {
                foreach (var area in NWModule.Get().Areas)
                {
                    // We don't process AI for empty areas.
                    if (NWNXArea.GetNumberOfPlayersInArea(area) <= 0)
                    {
                        continue;
                    }

                    // Safety check - If the area isn't in the cache, report it.
                    if (!_areaAICreatures.ContainsKey(area))
                    {
                        Console.WriteLine("Area " + area.Name + " not registered with AI service. Tag: " + area.Tag + ", Resref = " + area.Resref);
                        return;
                    }

                    var creatures = _areaAICreatures[area];
                    ProcessCreatureAI(ref creatures);
                }
            }
        }