#include "adv_include" #include "nwnx_tmi" ////////////////////// // SYSTEM CONSTANTS // ////////////////////// // The amount of time between spawns, in seconds // Default: 120.0 (2 minutes) const float ZSS_SPAWN_DELAY = 120.0; // The name of the variable which determines the name of the spawn points in an area // This variable is stored on the area object const string ZSS_WAYPOINT_NAME = "ZSS_WAYPOINT_NAME"; // The name of the variable which determines which group to pull spawn resrefs from. // This variable is stored on the area object const string ZSS_GROUP_ID = "ZSS_GROUP_ID"; // The name of the variable which determines how many spawn points there are in an area // This variable is stored on the area object const string ZSS_SPAWN_WAYPOINT_COUNT = "ZSS_SPAWN"; // The name of the variable which determines how many respawn points there are in an area // This variable is stored on the area object const string ZSS_RESPAWN_WAYPOINT_COUNT = "ZSS_RESPAWN"; // The name of the array which stores spawn waypoint objects const string ZSS_SPAWN_WAYPOINT_OBJECT_ARRAY = "ZSS_SPAWN_WAYPOINT_OBJECT_ARRAY"; // The name of the array which stores respawn waypoint objects const string ZSS_RESPAWN_WAYPOINT_OBJECT_ARRAY = "ZSS_RESPAWN_WAYPOINT_OBJECT_ARRAY"; // The name of the variable which stores the number of zombies to spawn in an area // This variable is stored on the area object const string ZSS_ZOMBIE_COUNT = "ZSS_COUNT"; // The name of the variable which stores the number of special zombies to spawn in an area // This variable is stored on the area object const string ZSS_SPECIAL_ZOMBIE_COUNT = "ZSS_SPECIAL_COUNT"; // The name of the variable which determines whether or not to spawn a mutation // This variable is stored on the area object const string ZSS_MUTATION = "ZSS_MUTATION"; // Name of the variable which tells the system whether or not a zombie was spawned by the system // as opposed to being spawned by a DM. const string ZSS_ZOMBIE_SPAWNED = "ZSS_ZOMBIE_SPAWNED"; // Name of the variable which keeps track of the number of players in an area const string ZSS_PLAYER_COUNT = "ZSS_PLAYER_COUNT"; // Resref of the spawn waypoints. const string ZSS_SPAWN_WAYPOINT_RESREF = "zombie_spawn"; // Resref of the respawn waypoints. const string ZSS_RESPAWN_WAYPOINT_RESREF = "zombie_respawn"; //////////////// // PROTOTYPES // //////////////// // Use with DelayCommand to create a new zombie after a set amount of time. void DelayCreateZombie(string sZombieResref, location lWaypointLocation, object oArea); // Call this on area enter. // Spawns random zombies at random waypoints throughout an area. void ZSS_OnAreaEnter(object oArea = OBJECT_SELF); // Call this on area exit. // Despawns all zombies in an area. void ZSS_OnAreaExit(object oPC = OBJECT_INVALID, object oArea = OBJECT_SELF); // Place this on your module's OnLoad event. // It will cycle through each area and number each spawn and respawn waypoint in the module. // This eliminates the need for area designers to manually number them. // Note that with many areas the instruction limit may be met. For that reason, TMI is disabled // until the completion of this method, after which it's turned back on. void ZSS_OnModuleLoad(); // Call this on zombie death. // Respawns a zombie after a specified amount of time. void ZSS_OnZombieDeath(); // Returns a random resref of a creature to spawn based on the group ID passed in. // If you add more group IDs, be sure to set them up using the same template. // iGroupID = The group ID to pull from // bUnique = If TRUE, attempts will be made to pull from the "unique" section of the group list. // Typically used when you only want to spawn a certain number of powerful enemies (like Hunters or Tyrants) string ZSS_GetZombieToSpawn(int iGroupID, int bUnique = FALSE); /////////////// // FUNCTIONS // /////////////// void ZSS_DelayCreateZombie(string sZombieResref, location lWaypointLocation, object oArea) { // Only respawn if there's PCs in the area if(GetLocalInt(oArea, ZSS_PLAYER_COUNT) > 0) { object oZombie = CreateObject(OBJECT_TYPE_CREATURE, sZombieResref, lWaypointLocation, FALSE); // Just to make sure this zombie was spawned by the spawn system and not by a DM SetLocalInt(oZombie, ZSS_ZOMBIE_SPAWNED, TRUE); // Randomize facing AssignCommand(oZombie, SetFacing(0.01 * Random(3600))); } } void ZSS_OnAreaEnter(object oArea = OBJECT_SELF) { object oPC = GetEnteringObject(); if(!GetIsPC(oPC) || GetIsDM(oPC)) return; //int iPCCount = GetLocalInt(oArea, ZSS_PLAYER_COUNT) + 1; // Safety check //if(iPCCount < 1) iPCCount = 1; int iZombieCount = GetLocalInt(oArea, ZSS_ZOMBIE_COUNT); int iWaypointCount = GetLocalInt(oArea, ZSS_SPAWN_WAYPOINT_COUNT); int iGroupID = GetLocalInt(oArea, ZSS_GROUP_ID); string sSpawnPrefix = GetLocalString(oArea, ZSS_WAYPOINT_NAME) + "_spawn_"; // Safety check if(iGroupID < 1) iGroupID = 1; // Determine if this is the first PC in the area int iPCCount; oPC = GetFirstPC(); while(GetIsObjectValid(oPC)) { if(GetArea(oPC) == oArea) { iPCCount++; } oPC = GetNextPC(); } // Only spawn zombies if this is the first PC in the area if(iPCCount == 1) { int iCurrentZombie; int bUnique = TRUE; for(iCurrentZombie = 1; iCurrentZombie <= iZombieCount; iCurrentZombie++) { int iWaypoint; // Ensure that at least one zombie will be placed at each spawn point if(iCurrentZombie > iWaypointCount) { iWaypoint = Random(iWaypointCount) + 1; } else { iWaypoint = iCurrentZombie; } string sResref = ZSS_GetZombieToSpawn(iGroupID, bUnique); object oWaypoint = GetLocalArrayObject(oArea, ZSS_SPAWN_WAYPOINT_OBJECT_ARRAY, iWaypoint); location lLocation = GetLocation(oWaypoint); object oZombie = CreateObject(OBJECT_TYPE_CREATURE, sResref, lLocation); // Mark zombie as spawned via the system (as opposed from a DM) SetLocalInt(oZombie, ZSS_ZOMBIE_SPAWNED, TRUE); // Randomize facing AssignCommand(oZombie, SetFacing(0.01 * Random(3600))); // No more chances to spawn a unique creature bUnique = FALSE; } } // Update PC counter SetLocalInt(oArea, ZSS_PLAYER_COUNT, iPCCount); } void ZSS_OnAreaExit(object oPC = OBJECT_INVALID, object oArea = OBJECT_SELF) { if(oPC == OBJECT_INVALID) { oPC = GetExitingObject(); } if(!GetIsPC(oPC) || GetIsDM(oPC)) return; //int iPCCount = GetLocalInt(oArea, ZSS_PLAYER_COUNT) - 1; // Safety measure //if(iPCCount < 0) iPCCount = 0; int iPCCount; oPC = GetFirstPC(); while(GetIsObjectValid(oPC)) { if(GetArea(oPC) == oArea) { iPCCount++; } oPC = GetNextPC(); } // Last PC exited the area. Despawn all zombies. if(iPCCount <= 0) { object oZombie = GetFirstObjectInArea(oArea); while(GetIsObjectValid(oZombie)) { if(GetLocalInt(oZombie, ZSS_ZOMBIE_SPAWNED) == TRUE) { DestroyObject(oZombie); } oZombie = GetNextObjectInArea(oArea); } } // Update PC counter SetLocalInt(oArea, ZSS_PLAYER_COUNT, iPCCount); } void ZSS_OnModuleLoad() { if(ADV_USING_LINUX) { int iTMI = GetTMILimit(); SetTMILimit(7000000); object oArea = GetFirstArea(); while(GetIsObjectValid(oArea)) { string sSpawnID = GetResRef(oArea); string sRespawnPrefix = sSpawnID + "_respawn_"; string sSpawnPrefix = sSpawnID + "_spawn_"; int iSpawnCount; int iRespawnCount; object oWaypoint = GetFirstObjectInArea(oArea); while(GetIsObjectValid(oWaypoint)) { string sResref = GetResRef(oWaypoint); // Spawn waypoint if(sResref == ZSS_SPAWN_WAYPOINT_RESREF) { iSpawnCount++; //SetTag(oWaypoint, sSpawnPrefix + IntToString(iSpawnCount)); SetLocalArrayObject(oArea, ZSS_SPAWN_WAYPOINT_OBJECT_ARRAY, iSpawnCount, oWaypoint); } // Respawn waypoint else if(sResref == ZSS_RESPAWN_WAYPOINT_RESREF) { iRespawnCount++; //SetTag(oWaypoint, sRespawnPrefix + IntToString(iRespawnCount)); SetLocalArrayObject(oArea, ZSS_RESPAWN_WAYPOINT_OBJECT_ARRAY, iRespawnCount, oWaypoint); } oWaypoint = GetNextObjectInArea(oArea); } // Mark the number of spawn and respawn waypoints for this area SetLocalInt(oArea, ZSS_SPAWN_WAYPOINT_COUNT, iSpawnCount); SetLocalInt(oArea, ZSS_RESPAWN_WAYPOINT_COUNT, iRespawnCount); // Mark the unique identifier (the resref) SetLocalString(oArea, ZSS_WAYPOINT_NAME, sSpawnID); // Move to the next area oArea = GetNextArea(); } // Set the TMI limit back to normal SetTMILimit(131071); } else { // Windows version: to-do } } void ZSS_OnZombieDeath() { object oZombie = OBJECT_SELF; object oArea = GetArea(oZombie); int iPCCount = GetLocalInt(oArea, ZSS_PLAYER_COUNT); int iWaypointCount = GetLocalInt(oArea, ZSS_RESPAWN_WAYPOINT_COUNT); int iGroupID = GetLocalInt(oArea, ZSS_GROUP_ID); string sRespawnPrefix = GetLocalString(oArea, ZSS_WAYPOINT_NAME) + "_respawn_"; // Safety check if(iGroupID < 1) iGroupID = 1; // Only respawn zombies that were created through this system (as opposed from DMs) if(GetLocalInt(oZombie, ZSS_ZOMBIE_SPAWNED) == TRUE) { // Only spawn when PCs are in the area if(iPCCount > 0) { int iWaypoint = Random(iWaypointCount) + 1; string sRespawn = sRespawnPrefix + IntToString(iWaypoint); string sResref = ZSS_GetZombieToSpawn(iGroupID, FALSE); object oWaypoint = GetLocalArrayObject(oArea, ZSS_RESPAWN_WAYPOINT_OBJECT_ARRAY, iWaypoint); location lLocation = GetLocation(oWaypoint); // Need to create the zombie differently, based on the delay. // For some reason, setting a delay of 0.0 doesn't work correctly. if(ZSS_SPAWN_DELAY == 0.0) { ZSS_DelayCreateZombie(sResref, lLocation, oArea); } else { DelayCommand(ZSS_SPAWN_DELAY, ZSS_DelayCreateZombie(sResref, lLocation, oArea)); } } } } string ZSS_GetZombieToSpawn(int iGroupID, int bUnique = FALSE) { string sResref; switch(iGroupID) { // Group #1 - Basic Zombies (Tier 1) case 1: { int iNumberOfChoices = 15; switch(Random(iNumberOfChoices) + 1) { case 1: sResref = "reo_zombie_1"; break; case 2: sResref = "reo_zombie_2"; break; case 3: sResref = "reo_zombie_3"; break; case 4: sResref = "reo_zombie_4"; break; case 5: sResref = "reo_zombie_5"; break; case 6: sResref = "reo_zombie_6"; break; case 7: sResref = "reo_zombie_7"; break; case 8: sResref = "reo_zombie_8"; break; case 9: sResref = "reo_zombie_9"; break; case 10: sResref = "reo_zombie_10"; break; case 11: sResref = "reo_zombie_11"; break; case 12: sResref = "reo_zombie_12"; break; case 13: sResref = "reo_zombie_13"; break; case 14: sResref = "reo_zombie_14"; break; case 15: sResref = "reo_zombie_15"; break; } break; } // Group #2 - Walkers and MA-121 Hunter Alphas (Tier 2) case 2: { if(bUnique) { int iChance = d100(1); // 15% to spawn a Hunter if(iChance <= 15) { sResref = "reo_hunter_1"; } } if(sResref == "") { int iNumberOfChoices = 15; // In all other cases, spawn normal Walkers switch(Random(iNumberOfChoices) + 1) { case 1: sResref = "reo_walker_1"; break; case 2: sResref = "reo_walker_2"; break; case 3: sResref = "reo_walker_3"; break; case 4: sResref = "reo_walker_4"; break; case 5: sResref = "reo_walker_5"; break; case 6: sResref = "reo_walker_6"; break; case 7: sResref = "reo_walker_7"; break; case 8: sResref = "reo_walker_8"; break; case 9: sResref = "reo_walker_9"; break; case 10: sResref = "reo_walker_10"; break; case 11: sResref = "reo_walker_11"; break; case 12: sResref = "reo_walker_12"; break; case 13: sResref = "reo_walker_13"; break; case 14: sResref = "reo_walker_14"; break; case 15: sResref = "reo_walker_15"; break; } } break; } } return sResref; } // Error checking void main(){}