399 lines
14 KiB
Plaintext
399 lines
14 KiB
Plaintext
#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(){}
|