// // 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 (){}