RATDOG/_module/nss/spawn_cfg_group.nss
Jaysyn904 df709d33fc Horsefly Swamp update
Creatures & encounter tables to support Horsefly swamp expansion.
2023-08-13 17:21:44 -04:00

855 lines
22 KiB
Plaintext

//
// Spawn Groups
//
//
// nChildrenSpawned
// : Number of Total Children ever Spawned
//
// nSpawnCount
// : Number of Children currently Alive
//
// nSpawnNumber
// : Number of Children to Maintain at Spawn
//
// nRandomWalk
// : Walking Randomly? TRUE/FALSE
//
// nPlaceable
// : Spawning Placeables? TRUE/FALSE
//
//
int ParseFlagValue(string sName, string sFlag, int nDigits, int nDefault);
int ParseSubFlagValue(string sName, string sFlag, int nDigits, string sSubFlag, int nSubDigits, int nDefault);
object GetChildByTag(object oSpawn, string sChildTag);
object GetChildByNumber(object oSpawn, int nChildNum);
object GetSpawnByID(int nSpawnID);
void DeactivateSpawn(object oSpawn);
void DeactivateSpawnsByTag(string sSpawnTag);
void DeactivateAllSpawns();
void DespawnChildren(object oSpawn);
void DespawnChildrenByTag(object oSpawn, string sSpawnTag);
//
//
// tinygiant -- set this to FALSE to turn off debug statement
const int IS_DEBUGGING = TRUE;
// tinygiant -- temporary function to send debug messages
void Debug(string sMessage)
{
if (IS_DEBUGGING)
SendMessageToPC(GetFirstPC(), sMessage);
}
string GetTemplateByCR(int nCR, string sGroupType)
{
string sRetTemplate;
if (sGroupType == "outdoor")
{
switch (nCR)
{
case 1:
switch(d6(1))
{
case 1: sRetTemplate = "NW_SKELETON"; break;
case 2: sRetTemplate = "NW_ZOMBIE01"; break;
case 3: sRetTemplate = "NW_NIXIE"; break;
case 4: sRetTemplate = "NW_ORCA"; break;
case 5: sRetTemplate = "NW_ORCB"; break;
case 6: sRetTemplate = "NW_BTLFIRE"; break;
}
break;
case 2:
switch(d4(1))
{
case 1: sRetTemplate = "NW_KOBOLD004"; break;
case 2: sRetTemplate = "NW_KOBOLD005"; break;
case 3: sRetTemplate = "NW_KOBOLD003"; break;
case 4: sRetTemplate = "NW_PIXIE"; break;
}
break;
case 3:
switch(d4(1))
{
case 1: sRetTemplate = "NW_BTLBOMB"; break;
case 2: sRetTemplate = "NW_BTLFIRE002"; break;
case 3: sRetTemplate = "NW_BTLSTINK"; break;
case 4: sRetTemplate = "NW_NYMPH"; break;
}
break;
default:
sRetTemplate = "";
break;
}
}
else if (sGroupType == "crypt")
{
switch (nCR)
{
case 1:
switch(d4(1))
{
case 1:
case 2: sRetTemplate = "NW_SKELETON"; break;
case 3: sRetTemplate = "NW_ZOMBIE01"; break;
case 4: sRetTemplate = "NW_ZOMBIE02"; break;
}
break;
case 2:
sRetTemplate = "NW_GHOUL";
break;
case 3:
sRetTemplate = "NW_SHADOW";
break;
default:
sRetTemplate = "";
break;
}
}
else
{
// unknown group type
sRetTemplate = "";
}
return sRetTemplate;
}
// Convert a given EL equivalent and its encounter level,
// return the corresponding CR
float ConvertELEquivToCR(float fEquiv, float fEncounterLevel)
{
float fCR, fEquivSq, fTemp;
if (fEquiv == 0.0)
{
return 0.0;
}
fEquivSq = fEquiv * fEquiv;
fTemp = log(fEquivSq);
fTemp /= log(2.0);
fCR = fEncounterLevel + fTemp;
return fCR;
}
// Convert a given CR to its encounter level equivalent per DMG page 101.
float ConvertCRToELEquiv(float fCR, float fEncounterLevel)
{
if (fCR > fEncounterLevel || fCR < 1.0)
{
return 1.;
}
float fEquiv, fExponent, fDenom;
fExponent = fEncounterLevel - fCR;
fExponent *= 0.5;
fDenom = pow(2.0, fExponent);
fEquiv = 1.0 / fDenom;
return fEquiv;
}
string SpawnGroup(object oSpawn, string sTemplate)
{
Debug("NESS: Running function SpawnGroup");
Debug(" oSpawn -> " + GetName(oSpawn));
Debug(" sTemplate -> " + sTemplate);
Debug("");
// Initialize
string sRetTemplate;
// Initialize Values
int nSpawnNumber = GetLocalInt(oSpawn, "f_SpawnNumber");
int nRandomWalk = GetLocalInt(oSpawn, "f_RandomWalk");
int nPlaceable = GetLocalInt(oSpawn, "f_Placeable");
int nChildrenSpawned = GetLocalInt(oSpawn, "ChildrenSpawned");
int nSpawnCount = GetLocalInt(oSpawn, "SpawnCount");
//
// Only Make Modifications Between These Lines
// -------------------------------------------
//:: Swamp Mephit Gang
if (sTemplate == "grp_swampmephits")
{
switch(d3(1))
{
case 1:
sRetTemplate = "nw_mepearth";
break;
case 2:
sRetTemplate = "nw_mepooze";
break;
case 3:
sRetTemplate = "nw_mepwater";
break;
}
}
//:: Swamp Mephit Gang
//:: Corrupted Animals
if (sTemplate == "grp_badanimals")
{
switch(d4(1))
{
case 1:
sRetTemplate = "ra_badbadger001";
break;
case 2:
sRetTemplate = "ra_badbear001";
break;
case 3:
sRetTemplate = "ra_baddeer001";
break;
case 4:
sRetTemplate = "ra_badwolf001";
break;
}
}
//:: Corrupted Animals
//:: Undead Animals
if (sTemplate == "grp_banimals")
{
switch(d3(1))
{
case 1:
sRetTemplate = "ra_skelpanther01";
break;
case 2:
sRetTemplate = "ra_skelrat001";
break;
case 3:
sRetTemplate = "ra_zombiewolf001";
break;
}
}
//:: Undead Animals
//:: Wererats
if (sTemplate == "group_wererats")
{
switch(d3(1))
{
case 1:
sRetTemplate = "RA_WERERAT004";
break;
case 2:
sRetTemplate = "RA_WERERAT003";
break;
case 3:
sRetTemplate = "RA_WERERAT003";
break;
}
}
//:: Wererats
//:: Vampire Spawn
if (sTemplate == "group_vampspawn")
{
switch(d3(1))
{
case 1:
sRetTemplate = "RA_VAMPSPAWN01";
break;
case 2:
sRetTemplate = "RA_VAMPSPAWN01";
break;
case 3:
sRetTemplate = "RA_VAMPSPAWN02";
break;
}
}
//:: Vampire Spawn
//:: Brigands
if (sTemplate == "group_brigands")
{
switch(d3(1))
{
case 1:
sRetTemplate = "RA_BRIGAND001";
break;
case 2:
sRetTemplate = "RA_BRIGAND001";
break;
case 3:
sRetTemplate = "RA_F_BRIGAND001";
break;
}
}
//:: Brigands
//:: Aragnak in Lair
if (sTemplate == "grp_aragnak")
{
int iRnd = Random(9)+1;
if (iRnd >= 7) // 30% chance to be awake
{
sRetTemplate = "RA_DRAG_ARAGNAK1";
}
else // 70% chance to be sleeping
{
sRetTemplate = "RA_DRAG_ARAGNAK2";
}
}
//:: Aragnak in Lair
if (GetStringLeft(sTemplate, 7) == "scaled_")
{
float fEncounterLevel;
int nScaledInProgress = GetLocalInt(oSpawn, "ScaledInProgress");
string sGroupType = GetStringRight(sTemplate,
GetStringLength(sTemplate) - 7);
// First Time in for this encounter?
if (! nScaledInProgress)
{
// First time in - find the party level
int nTotalPCs = 0;
int nTotalPCLevel = 0;
object oArea = GetArea(OBJECT_SELF);
object oPC = GetFirstObjectInArea(oArea);
while (oPC != OBJECT_INVALID)
{
if (GetIsPC(oPC) == TRUE)
{
nTotalPCs++;
nTotalPCLevel = nTotalPCLevel + GetHitDice(oPC);
}
oPC = GetNextObjectInArea(oArea);
}
if (nTotalPCs == 0)
{
fEncounterLevel = 0.0;
}
else
{
fEncounterLevel = IntToFloat(nTotalPCLevel) / IntToFloat(nTotalPCs);
}
// Save this for subsequent calls
SetLocalFloat(oSpawn, "ScaledEncounterLevel", fEncounterLevel);
// We're done when the CRs chosen add up to the
// desired encounter level
SetLocalInt(oSpawn, "ScaledCallCount", 0);
SetLocalInt(oSpawn, "ScaledInProgress", TRUE);
}
fEncounterLevel = GetLocalFloat(oSpawn, "ScaledEncounterLevel");
int nScaledCallCount = GetLocalInt(oSpawn, "ScaledCallCount");
// For simplicity, I'm not supporting creatures with CR < 1.0)
if (fEncounterLevel < 1.0)
{
// We're done... No creatures have CR low enough to add to this encounter
sRetTemplate = "";
}
else
{
// randomly choose a CR at or below the remaining (uncovered) encounter
// level
int nCR = Random(FloatToInt(fEncounterLevel)) + 1;
// cap to the largest CR we currently support in GetTemplateByCR
if (nCR > 3)
{
nCR = 3;
}
sRetTemplate = GetTemplateByCR(nCR, sGroupType);
// Convert CR to Encounter Level equivalent so it can be correctly
// subtracted. This does the real scaling work
float fELEquiv = ConvertCRToELEquiv(IntToFloat(nCR), fEncounterLevel);
float fElRemaining = 1.0 - fELEquiv;
fEncounterLevel = ConvertELEquivToCR(fElRemaining, fEncounterLevel);
SetLocalFloat(oSpawn, "ScaledEncounterLevel", fEncounterLevel);
}
nScaledCallCount++;
SetLocalInt(oSpawn, "ScaledCallCount", nScaledCallCount);
nSpawnNumber = GetLocalInt(oSpawn, "f_SpawnNumber");
if (nScaledCallCount >= nSpawnNumber)
{
// reset...
SetLocalInt(oSpawn, "ScaledInProgress", FALSE);
}
}
// cr_militia
if (sTemplate == "cr_militia")
{
switch(d2(1))
{
case 1:
sRetTemplate = "cr_militia_m";
break;
case 2:
sRetTemplate = "cr_militia_f";
break;
}
}
//
// pg_guard
if (sTemplate == "pg_guard")
{
switch(d2(1))
{
case 1:
sRetTemplate = "pg_guard_m";
break;
case 2:
sRetTemplate = "pg_guard_f";
break;
}
}
//
// Goblins
if (sTemplate == "goblins_low")
{
if (d2(1) == 1)
{
sRetTemplate = "NW_GOBLINA";
}
else
{
sRetTemplate = "NW_GOBLINB";
}
}
//
// Wererats
if (sTemplate == "wererats")
{
if (d2(1) == 1)
{
sRetTemplate = "RA_WERERAT001";
}
else
{
sRetTemplate = "RA_WERERAT002";
}
}
//
//:: Kobolds
if (sTemplate == "kobolds")
{
switch(d6(1))
{
case 1:
sRetTemplate = "NW_KOBOLD001";
break;
case 2:
sRetTemplate = "NW_KOBOLD002";
break;
case 3:
sRetTemplate = "NW_KOBOLD003";
break;
case 4:
sRetTemplate = "NW_KOBOLD004";
break;
case 5:
sRetTemplate = "NW_KOBOLD005";
break;
case 6:
sRetTemplate = "NW_KOBOLD006";
break;
}
}
//:: Kobolds
// Giant Ants
if (sTemplate == "giantants")
{
switch(d6(1))
{
case 1:
sRetTemplate = "ra_g_ant_workr01";
break;
case 2:
sRetTemplate = "ra_g_ant_soldr01";
break;
case 3:
sRetTemplate = "ra_g_ant_soldr01";
break;
case 4:
sRetTemplate = "ra_g_ant_workr01";
break;
case 5:
sRetTemplate = "ra_g_ant_workr01";
break;
case 6:
sRetTemplate = "ra_g_ant_workr01";
break;
}
}
//
// Brigands & Leader
if (sTemplate == "brigands01")
{
int nIsBossSpawned = GetLocalInt(oSpawn, "IsBossSpawned");
Debug("NESS: nIsBossSpawned :: oSpawn -> " + GetName(oSpawn));
Debug("NESS: nIsBossSpawned :: Value -> " + IntToString(nIsBossSpawned));
if (nIsBossSpawned == TRUE)
{
// Find the Boss
object oBoss = GetChildByTag(oSpawn, "RA_BRIGAND002");
Debug("NESS: oBoss -> " + (GetIsObjectValid(oBoss) ? GetName(oBoss) : "OBJECT_INVALID"));
// Check if Boss is Alive
if (oBoss != OBJECT_INVALID && GetIsDead(oBoss) == FALSE)
{
Debug("NESS: oBoss is valid and alive, assigning template 'RA_BRIGAND001'");
// He's alive, spawn a Peon to keep him Company
sRetTemplate = "RA_BRIGAND001";
}
else
{
Debug("NESS: oBoss is either invalid or dead, so let's respawn him.");
sRetTemplate = "RA_BRIGAND002";
SetLocalInt(oSpawn, "IsBossSpawned", TRUE);
// He's dead, Deactivate Camp!
//SetLocalInt(oSpawn, "SpawnDeactivated", TRUE);
}
}
else
{
Debug("NESS: Boss does not exist, assiging template 'RA_BRIGAND002'");
// No Boss, so Let's Spawn Him
sRetTemplate = "RA_BRIGAND002";
SetLocalInt(oSpawn, "IsBossSpawned", TRUE);
}
}
//
//:: Vorlak & his Kobolds
if (sTemplate == "vorlaks_kobolds")
{
int nIsBossSpawned = GetLocalInt(oSpawn, "IsBossSpawned");
Debug("NESS: nIsBossSpawned :: oSpawn -> " + GetName(oSpawn));
Debug("NESS: nIsBossSPawned :: Value -> " + IntToString(nIsBossSpawned));
if (nIsBossSpawned == TRUE)
{
// Find the Boss
object oBoss = GetChildByTag(oSpawn, "OGRE_VORLAK");
Debug("NESS: oBoss -> " + (GetIsObjectValid(oBoss) ? GetName(oBoss) : "OBJECT_INVALID"));
// Check if Boss is Alive
if (oBoss != OBJECT_INVALID && GetIsDead(oBoss) == FALSE)
{
Debug("NESS: oBoss is valid and alive, assigning templatle 'ra_koboldwar001'");
// He's alive, spawn a Peon to keep him Company
sRetTemplate = "ra_koboldwar001";
}
else
{
Debug("NESS: oBoss is either invalid or dead, deactivating camp");
// He's dead, Deactivate Camp!
SetLocalInt(oSpawn, "SpawnDeactivated", TRUE);
}
}
else
{
Debug("NESS: Boss does not exist, assiging template 'OGRE_VORLAK'");
// No Boss, so Let's Spawn Him
sRetTemplate = "OGRE_VORLAK";
SetLocalInt(oSpawn, "IsBossSpawned", TRUE);
}
}
//:: Vorlak & his Kobolds
// Goblins and Boss
if (sTemplate == "gobsnboss")
{
int nIsBossSpawned = GetLocalInt(oSpawn, "IsBossSpawned");
Debug("NESS: nIsBossSpawned :: oSpawn -> " + GetName(oSpawn));
Debug("NESS: nIsBossSPawned :: Value -> " + IntToString(nIsBossSpawned));
if (nIsBossSpawned == TRUE)
{
// Find the Boss
object oBoss = GetChildByTag(oSpawn, "NW_GOBCHIEFA");
Debug("NESS: oBoss -> " + (GetIsObjectValid(oBoss) ? GetName(oBoss) : "OBJECT_INVALID"));
// Check if Boss is Alive
if (oBoss != OBJECT_INVALID && GetIsDead(oBoss) == FALSE)
{
Debug("NESS: oBoss is valid and alive, assigning templatle 'NW_GOBLINA'");
// He's alive, spawn a Peon to keep him Company
sRetTemplate = "NW_GOBLINA";
}
else
{
Debug("NESS: oBoss is either invalid or dead, deactivating camp");
// He's dead, Deactivate Camp!
SetLocalInt(oSpawn, "SpawnDeactivated", TRUE);
}
}
else
{
Debug("NESS: Boss does not exist, assiging template 'NW_GOBCHIEFA'");
// No Boss, so Let's Spawn Him
sRetTemplate = "NW_GOBCHIEFA";
SetLocalInt(oSpawn, "IsBossSpawned", TRUE);
}
}
//
// Scaled Encounter
if (sTemplate == "scaledgobs")
{
// Initialize Variables
int nTotalPCs;
int nTotalPCLevel;
int nAveragePCLevel;
object oArea = GetArea(OBJECT_SELF);
// Cycle through PCs in Area
object oPC = GetFirstObjectInArea(oArea);
while (oPC != OBJECT_INVALID)
{
if (GetIsPC(oPC) == TRUE)
{
nTotalPCs++;
nTotalPCLevel = nTotalPCLevel + GetHitDice(oPC);
}
oPC = GetNextObjectInArea(oArea);
}
if (nTotalPCs == 0)
{
nAveragePCLevel = 0;
}
else
{
nAveragePCLevel = nTotalPCLevel / nTotalPCs;
}
// Select a Creature to Spawn
switch (nAveragePCLevel)
{
// Spawn Something with CR 1
case 1:
sRetTemplate = "cr1creature";
break;
//
// Spawn Something with CR 5
case 5:
sRetTemplate = "cr5creature";
break;
//
}
}
//
// Pirates and Boss
if (sTemplate == "pirates")
{
// Delay the Spawn for 45 Minutes
if (GetLocalInt(oSpawn, "DelayEnded") == FALSE)
{
if (GetLocalInt(oSpawn, "DelayStarted") == FALSE)
{
// Start the Delay
SetLocalInt(oSpawn, "DelayStarted", TRUE);
DelayCommand(20.0, SetLocalInt(oSpawn, "DelayEnded", TRUE));
}
sRetTemplate = "";
return sRetTemplate;
}
int nIsBossSpawned = GetLocalInt(oSpawn, "IsBossSpawned");
if (nIsBossSpawned == TRUE)
{
// Find the Boss
object oBoss = GetChildByTag(oSpawn, "NW_GOBCHIEFA");
// Check if Boss is Alive
if (oBoss != OBJECT_INVALID && GetIsDead(oBoss) == FALSE)
{
// He's alive, spawn a Peon to keep him Company
sRetTemplate = "NW_GOBLINA";
}
else
{
// He's dead, Deactivate Camp!
SetLocalInt(oSpawn, "SpawnDeactivated", TRUE);
}
}
else
{
// No Boss, so Let's Spawn Him
sRetTemplate = "NW_GOBCHIEFA";
SetLocalInt(oSpawn, "IsBossSpawned", TRUE);
}
}
//
// Advanced Scaled Encounter
if (sTemplate == "advscaled")
{
//Initalize Variables
int nTotalPCs;
int nTotalPCLevel;
int nAveragePCLevel;
object oArea = GetArea(OBJECT_SELF);
//Cycle through PCs in area
object oPC = GetFirstObjectInArea(oArea);
while (oPC != OBJECT_INVALID)
{
if (GetIsPC(oPC) == TRUE)
{
nTotalPCs++;
nTotalPCLevel = nTotalPCLevel + GetHitDice(oPC);
}
oPC = GetNextObjectInArea(oArea);
}
if (nTotalPCs == 0)
{
nAveragePCLevel = 0;
}
else
{
nAveragePCLevel = nTotalPCLevel / nTotalPCs;
}
//Select a Creature to Spawn
switch (nAveragePCLevel)
{
//Spawn Something with CR 1
case 1:
switch (d6())
{
case 1: sRetTemplate = "cr1example1";
case 2: sRetTemplate = "cr1example2";
case 3: sRetTemplate = "cr1example3";
case 4: sRetTemplate = "cr1example4";
case 5: sRetTemplate = "cr1example5";
case 6: sRetTemplate = "cr1example6";
}
break;
}
}
//
// Encounters
if (sTemplate == "encounter")
{
// Declare Variables
int nCounter, nCounterMax;
string sCurrentTemplate;
// Retreive and Increment Counter
nCounter = GetLocalInt(oSpawn, "GroupCounter");
nCounterMax = GetLocalInt(oSpawn, "CounterMax");
nCounter++;
// Retreive CurrentTemplate
sCurrentTemplate = GetLocalString(oSpawn, "CurrentTemplate");
// Check CounterMax
if (nCounter > nCounterMax)
{
sCurrentTemplate = "";
nCounter = 1;
}
if (sCurrentTemplate != "")
{
// Spawn Another CurrentTemplate
sRetTemplate = sCurrentTemplate;
}
else
{
// Choose New CurrentTemplate and CounterMax
switch (Random(2))
{
// Spawn 1-4 NW_DOGs
case 0:
sRetTemplate = "NW_DOG";
nCounterMax = Random(4) + 1;
break;
}
// Record New CurrentTemplate and CounterMax
SetLocalString(oSpawn, "CurrentTemplate", sRetTemplate);
SetLocalInt(oSpawn, "CounterMax", nCounterMax);
}
// Record Counter
SetLocalInt(oSpawn, "GroupCounter", nCounter);
}
//
//
if (sTemplate == "kobolds")
{
int nKobold = Random(6) + 1;
sRetTemplate = "NW_KOBOLD00" + IntToString(nKobold);
}
//
//Sily's Groups
if (sTemplate == "sily_goblin_scout")
{
switch(d2(1))
{
case 1:
sRetTemplate = "an_goblin";
break;
case 2:
sRetTemplate = "an_goblin2";
break;
}
}
// -------------------------------------------
// Only Make Modifications Between These Lines
//
return sRetTemplate;
}
//void main (){}