Sounds interesting. Are you up for sharing the code here?
Sure, see below, though I'm no longer sure what is mine and what is original, other than specific comment code. I've also gone through the code and commented out unnecessary variable declarations through NESS. There are quite a bit of declarations that are never called in many of the most frequently-used functions.
Essentially, my camps are set up as random encounters. I set area variables that set the type and % chance that a camp will spawn. If one does spawn, the type of camp is determined from a list (e.g. an underwater camp could be kuo-toa or suahagin, or sea hags, etc...). It then creates a camp with placeables and banners. A boss creature is created and upgraded appropriately to be challenging to the party who spawned it. The flag I added was the SS flag, which calls custom spawn script flags (the SS flag is a regular NESS flag, but wasn't being checked for in the camp code). Much of this information is set dynamically on the spawnpoint as the camp is being constructed by the code.
from Spawn_main:
Object CampSpawn
object CampSpawn(object oSpawn, string sCamp, location lCamp)
{
// Spawn in Camp Placeholder
object oCamp = CreateObject(OBJECT_TYPE_PLACEABLE, "plc_invisobj", lCamp, FALSE);
SetPlotFlag(oCamp, TRUE);
SetLocalObject(oCamp, "ParentSpawn", oSpawn);
SetCampSpawn(oCamp, sCamp, lCamp);
// Initialize
int nCampNumP = GetLocalInt(oCamp, "CampNumP");
int nCampNumC = GetLocalInt(oCamp, "CampNumC");
float fSpawnRadius = GetLocalFloat(oCamp, "CampRadius");
vector vCamp = GetPositionFromLocation(lCamp);
object oSpawned;
int iCount;
//int nRandomWalk, nSpawnFacing;
int nSpawnGroup; //nLootTable, nTrapDisabled,, nDeathScript
//float fCorpseDecay;
int nCampCenter; //nCorpseDecayType,
string sObject, sTemplate, sFlags, sCampCenter;
// Get Camp Center
sCampCenter = GetLocalString(oCamp, "CampCenter");
// Spawn Placeables
for (iCount = 1; iCount <= nCampNumP; iCount++)
{
// Initialize Values
sObject = "CampP" + IntToString(iCount - 1);
sTemplate = GetLocalString(oCamp, sObject);
nCampCenter = FALSE;
// Check Flags
sFlags = GetLocalString(oCamp, sObject + "_Flags");
nSpawnGroup = IsFlagPresent(sFlags, "SG");
// Spawn Group
if (nSpawnGroup ) //== TRUE
{
sTemplate = SpawnGroup(oSpawn, sTemplate);
}
// Check Camp Center
if (sCampCenter != "")
{
if (sCampCenter == "P" + IntToString(iCount - 1))
{
nCampCenter = TRUE;
}
}
// If no CampCenter set, Use first Placeable
else if (iCount == 1)
{
nCampCenter = TRUE;
}
oSpawned = DoCampSpawn(oCamp, lCamp, fSpawnRadius, sTemplate, TRUE, iCount, nCampCenter);
// Run the Spawn Script
SetLocalObject(oCamp, sObject, oSpawned);
SetupCampSpawned(oSpawn, oSpawned, vCamp, GetLocation(oSpawned), sFlags);
}
// Spawn Creatures
for (iCount = 1; iCount <= nCampNumC; iCount++)
{
// Initialize Values
sObject = "CampC" + IntToString(iCount - 1);
sTemplate = GetLocalString(oCamp, sObject);
// Check Flags
sFlags = GetLocalString(oCamp, sObject + "_Flags");
nSpawnGroup = IsFlagPresent(sFlags, "SG");
// Spawn Group
if (nSpawnGroup ) //== TRUE
{
sTemplate = SpawnGroup(oSpawn, sTemplate);
}
// Check Camp Center
if (sCampCenter != "")
{
if (sCampCenter == "C" + IntToString(iCount - 1))
{
nCampCenter = TRUE;
}
}
oSpawned = DoCampSpawn(oCamp, lCamp, fSpawnRadius, sTemplate, FALSE, iCount, nCampCenter);
//Added for Arenthyor - to be able to run spawn scripts on camp spawned creatures, primarily for level-up of camp mobs
if (IsFlagPresent(sFlags, "SS") ) //==TRUE
{
//int iSpawnScriptValue = GetFlagValue(sFlags, "SS",4);
//SendMessageToPC(GetFirstPC(), "DEBUG: spawn_main: iSpawnScriptFlag found. Spawnscript :" +IntToString(iSpawnScriptValue));
SetLocalInt(oSpawned, "SpawnScript", GetFlagValue(sFlags, "SS",4));
ExecuteScript("spawn_sc_spawn", oSpawned);
}
SetLocalObject(oCamp, sObject, oSpawned);
SetupCampSpawned(oSpawn, oSpawned, vCamp, GetLocation(oSpawned), sFlags);
}
// Return Placeholder
return oCamp;
}
Spawn_main
// This Function Spawns the Camp Members
object DoCampSpawn(object oCamp, location lCamp, float fSpawnRadius,
string sTemplate, int nPlaceable, int nSpawnNumber, int nCampCenter)
{
object oCampSpawned;
vector vCamp, vRadius;
float fRadius, fAngle; //fRadiusX, fRadiusY,
// Set up Location
if (!nCampCenter ) //== FALSE
{
//vCamp = GetPositionFromLocation(lCamp);
fAngle = IntToFloat(Random(361));
fRadius = IntToFloat(Random(FloatToInt(fSpawnRadius)) + 1);
//fRadiusX = fRadius * cos(fAngle);
//fRadiusY = fRadius * sin(fAngle);
vRadius = Vector(fRadius * cos(fAngle), fRadius * sin(fAngle));
lCamp = Location(OBJECT_SELF, GetPositionFromLocation(lCamp) + vRadius, 0.0);
}
// Spawn Camp Object
if (nPlaceable ) //== TRUE
{
oCampSpawned = CreateObject(OBJECT_TYPE_PLACEABLE, sTemplate, lCamp, FALSE);
//debug("created placeable at " + LocationToString(lCamp));
}
else
{
oCampSpawned = CreateObject(OBJECT_TYPE_CREATURE, sTemplate, lCamp, FALSE);
}
// Return Camp Object
return oCampSpawned;
}
then this one:
// This Function Spawns the Camp Members
object DoCampSpawn(object oCamp, location lCamp, float fSpawnRadius,
string sTemplate, int nPlaceable, int nSpawnNumber, int nCampCenter)
{
object oCampSpawned;
vector vCamp, vRadius;
float fRadius, fAngle; //fRadiusX, fRadiusY,
// Set up Location
if (!nCampCenter ) //== FALSE
{
//vCamp = GetPositionFromLocation(lCamp);
fAngle = IntToFloat(Random(361));
fRadius = IntToFloat(Random(FloatToInt(fSpawnRadius)) + 1);
//fRadiusX = fRadius * cos(fAngle);
//fRadiusY = fRadius * sin(fAngle);
vRadius = Vector(fRadius * cos(fAngle), fRadius * sin(fAngle));
lCamp = Location(OBJECT_SELF, GetPositionFromLocation(lCamp) + vRadius, 0.0);
}
// Spawn Camp Object
if (nPlaceable ) //== TRUE
{
oCampSpawned = CreateObject(OBJECT_TYPE_PLACEABLE, sTemplate, lCamp, FALSE);
//debug("created placeable at " + LocationToString(lCamp));
}
else
{
oCampSpawned = CreateObject(OBJECT_TYPE_CREATURE, sTemplate, lCamp, FALSE);
}
// Return Camp Object
return oCampSpawned;
}
from Spawn_cfg_camp
void SetCampSpawn(object oCamp, string sCamp, location lCamp)
{
//
// Place Custom Camps Here
// -------------------------------------------
//SendMessageToPC (GetFirstPC(), "DEBUG: spawn_cfg_camp: Success!! camp script firing");
int iNoStructures = d3(); //determine how many structure
int iStructuresLoopCount; //for looping through and setting the structures
int iAltarYN = d2(1); //determine if to use an altar/throne
int iNoPlaceables = d4(); //determine how many placeables to use
int iPlaceableTotal; //total number of placeables we're going to be putting down across banner, altar, structure, and placeables
int iTotalPlaceableLoopCount; //for keeping track of the total number of placeables we've set
//int iPlaceableLoopCount; //for looping through the placeables we've set
int iCreatures = 4+ d4(); //number of creatures
int iTotalCreatureLoopCount;
int iPCHD;
int iCreatureHD;
int iCreatureNewHD;
float fRadius = IntToFloat(10+d4(3));
object oCampBoss;
object oArea = GetArea (oCamp);
object oPC;
string sBanner;
string sStructure;
string sAltar;
string sPlaceable;
string sCampType = GetLocalString (oArea, "CampType");
string sCampGroup;
string sCampCreature;
string sLT;
if (iAltarYN == 1)//1 = yes, let's have an altar
{
iPlaceableTotal = 2 + iNoStructures + iNoPlaceables; //1 banner + 1 altar + number of structures + number of placeables
//SendMessageToPC (GetFirstPC(), "DEBUG: spawn_cfg_camp: Altar check successful - should place an altar");
}
else //2 = no, let's not have an altar
{
iPlaceableTotal = 1 +iNoStructures + iNoPlaceables; //1 banner + number of structures + number of placeables
//SendMessageToPC (GetFirstPC(), "DEBUG: spawn_cfg_camp: Altar check failed - will not place an altar");
}
// Set Number of Placeables
SetLocalInt(oCamp, "CampNumP", iPlaceableTotal);
// Set Number of Creatures
SetLocalInt(oCamp, "CampNumC", iCreatures);
// Set Radius of Camp
SetLocalFloat(oCamp, "CampRadius", fRadius);
//SendMessageToPC (GetFirstPC(), "DEBUG: spawn_cfg_camp: Total number of placeables should be "+IntToString(iPlaceableTotal));
//SendMessageToPC (GetFirstPC(), "DEBUG: spawn_cfg_camp: Total number of creatures should be "+IntToString(iCreatures));
//SendMessageToPC (GetFirstPC(), "DEBUG: spawn_cfg_camp: Float radius of the camp should be "+FloatToString(fRadius));
//Start with the placeables
iTotalPlaceableLoopCount = 1;
iStructuresLoopCount = 1;
//iPlaceableLoopCount =1;
while (iTotalPlaceableLoopCount <= iPlaceableTotal)
{
//SendMessageToPC (GetFirstPC(), "DEBUG: spawn_cfg_camp: Looping for all placeables. Loop # "+IntToString(iTotalPlaceableLoopCount));
//first placeable should be for banner, which will be the center of the camp;
if (iTotalPlaceableLoopCount ==1)
{
//SendMessageToPC (GetFirstPC(), "DEBUG: spawn_cfg_camp: Placeable Loop Count =1. Initializing GetCampPlaceableBanner ");
sBanner = GetCampPlaceableBanner();
// Set Placeable 0 to be Camp Center
SetLocalString(oCamp, "CampCenter", "P0");
// Set Placeable 0 and Spawn Flags
// First Placeable always Spawns at Center of Camp
// If CampCenter Is Not Set
SetLocalString(oCamp, "CampP0", sBanner);
SetLocalString(oCamp, "CampP0_Flags", "SP_SF");
}
// on the second loop, if we're to use the altar, then let's get it
else if (iTotalPlaceableLoopCount ==2 && iAltarYN == 1)
{
//SendMessageToPC (GetFirstPC(), "DEBUG: spawn_cfg_camp: iPlaceableLoopCount ==2 && iAltarYN == 1 Initializing GetCampPlaceableAltar ");
sAltar = GetCampPlaceableAltar();
// Set Placeable 1 and Spawn Flags
SetLocalString(oCamp, "CampP1", sAltar); //altar will alway be P1, since it will always immediately follow the banner when it is used
SetLocalString(oCamp, "CampP1_Flags", "SP_SF");
}
else
{
//now we need to do a couple of subloops to set the structures
if (iStructuresLoopCount <= iNoStructures)
{
//SendMessageToPC (GetFirstPC(), "DEBUG: spawn_cfg_camp: iStructuresLoopCount = "+IntToString(iStructuresLoopCount));
//SendMessageToPC (GetFirstPC(), "DEBUG: spawn_cfg_camp: Initializing GetCampStructures ");
sStructure = GetCampStructures(sCampType);
// Set structures and Spawn Flags
SetLocalString(oCamp, "CampP"+IntToString(iTotalPlaceableLoopCount-1), sStructure); //i.e, the 3rd loop will put in placeable, 0, 1, and 2, so need to subtract one
SetLocalString(oCamp, "CampP"+IntToString(iTotalPlaceableLoopCount-1)+"_Flags", "SP_SF");
iStructuresLoopCount = iStructuresLoopCount +1;
}
//now that the structures are done, we can get the placeables
else
{
//if (iPlaceableLoopCount <= iNoPlaceables)
{
//SendMessageToPC (GetFirstPC(), "DEBUG: spawn_cfg_camp: iPlaceableLoopCount = "+IntToString(iPlaceableLoopCount));
//SendMessageToPC (GetFirstPC(), "DEBUG: spawn_cfg_camp: Initializing GetCampPlaceables ");
sPlaceable = GetCampPlaceables(sCampType);
// Set structures and Spawn Flags
SetLocalString(oCamp, "CampP"+IntToString(iTotalPlaceableLoopCount-1), sPlaceable); //i.e, the 3rd loop will put in placeable, 0, 1, and 2, so need to subtract one
SetLocalString(oCamp, "CampP"+IntToString(iTotalPlaceableLoopCount-1)+"_Flags", "SP_SF");
//iPlaceableLoopCount = iPlaceableLoopCount +1;
}
}
}
iTotalPlaceableLoopCount = iTotalPlaceableLoopCount+1;
}
//now let's figure out the HD that the creatures should be, based on the PCs in the area and only have to do loop once
oPC = GetFirstObjectInArea (oArea);
while( GetIsObjectValid(oPC))// now begin counting faction members and their hitdice
{
if (GetIsPC(oPC) && !GetIsDM(oPC) && !GetIsDMPossessed(oPC))
{
iPCHD = GetHitDice(oPC);
if (iCreatureHD < iPCHD)
{
iCreatureNewHD = iPCHD ;
//SendMessageToPC (GetFirstPC(), "DEBUG: spawn_cfg_camp: Creature Target HD should be "+IntToString(iCreatureNewHD));
}
}
oPC = GetNextObjectInArea(oArea);
}
SetLocalInt (oArea, "PCHD", iCreatureNewHD); //ar_boss_scale will look at this and levelup with it
//now let's do the creatures
iTotalCreatureLoopCount=1;
//SendMessageToPC (GetFirstPC(), "DEBUG: spawn_cfg_camp: Initializing sCampGroup ");
sCampGroup = GetCampGroup(sCampType);
//SendMessageToPC (GetFirstPC(), "DEBUG: spawn_cfg_camp: Recognizing sCampGroup as "+sCampGroup);
while (iTotalCreatureLoopCount <=iCreatures)
{
//first creature should be the boss, so no loot table set, though does use a death tag, which will spawn treasure & xp
//SendMessageToPC (GetFirstPC(), "DEBUG: spawn_cfg_camp: iTotalCreatureLoopCount = "+IntToString(iTotalCreatureLoopCount));
if (iTotalCreatureLoopCount ==1)
{
//SendMessageToPC (GetFirstPC(), "DEBUG: spawn_cfg_camp: iTotalCreatureLoopCount = "+IntToString(iTotalCreatureLoopCount));
//SendMessageToPC (GetFirstPC(), "DEBUG: spawn_cfg_camp: Setting Boss Creature");
// Set Creature 0 to be Trigger
// Script 00 : Kill him and the Camp Despawns - commented out because the whole camp disappears if he's killed
SetLocalString(oCamp, "CampTrigger", "C0");
SetLocalInt(oCamp, "CampTriggerScript", 2); //- spawns the chests when the boss dies and destroys the "PCHD" int and the camp waypoint, so camp checks will begin again
// Set Creature 0 and Spawn Flags
SetLocalString(oCamp, "CampC0", sCampGroup+"boss");
SetLocalString(oCamp, "CampC0_Flags", "SP_SS3_CD060"); //SR10M05_SS3_DT1"); // level up the creature
//SendMessageToPC (GetFirstPC(), "DEBUG: spawn_cfg_camp: Setting Boss Creature string set as "+sCampGroup+"boss");
}
//remainder creatures
else
{
sLT= GetLootTable (iPCHD);
//SendMessageToPC (GetFirstPC(), "DEBUG: spawn_cfg_camp: iTotalCreatureLoopCount = "+IntToString(iTotalCreatureLoopCount));
//SendMessageToPC (GetFirstPC(), "DEBUG: spawn_cfg_camp: Setting minion Creatures");
sCampCreature = GetCampCreature (sCampGroup);
// Set Placeable 1+ and Spawn Flags
SetLocalString(oCamp, "CampC"+IntToString(iTotalCreatureLoopCount-1), sCampCreature);
SetLocalString(oCamp, "CampC"+IntToString(iTotalCreatureLoopCount-1)+"_Flags", "SP_SS4_LT"+sLT+"_CD060"); //SR10M05_SS4");//
//SendMessageToPC (GetFirstPC(), "DEBUG: spawn_cfg_camp: Setting minion creature string set as "+sCampCreature+" with flag: CampC"+IntToString(iTotalCreatureLoopCount-1)+"_Flags");
}
iTotalCreatureLoopCount = iTotalCreatureLoopCount+1;
}
}
In the above script, there are separate functions that are essentially switch-case statements that select the resrefs for random placeables:
GetCampPlaceableBanner() - returns a resref for a banner for the the creatures to rally aournd.
GetCampPlaceableAltar() - returns the resref for an altar (every camp needs an altar, right?)
GetCampStructures(string sCampType) - returns a "building'/structure resref appropriate to a specific camp type
GetCampPlaceables(string sCampType) - returns a placeable resref appropriate to a specific camp type
GetCampGroup(string sCampType) - determines the type of group given it's general type (if it's an underwater camp, is it sahuagin, kuotoa, or sea hags)
GetCampCreature(string sCampGroup) - determines the resref of creatures that can be spawned given a specific type of camp
GetLootTable(int iHD) - tells NESS what loot table creatures should pull from, based upon the HD of the party that spawned it.
Hope that helps, or at least provides some inspiration!