TGE spawn points that spawn anything
by Stephen Lujan · 04/10/2007 (9:09 am) · 2 comments
Add this to the bottom of your engine/game/missionmarker.cc file
Add this to the bottom of your engine/game/missionmarker.h file BUT before that last #endif
modify your server/scripts/markers.cs file to include the bolded parts
add this new file: server/scripts/ai/aispawn.cs
Edit this file to quickly add a new spawn group. Then in the mission editor, set each spawn group as needed for each of the AISpawnSpheres you place.
add the bolded parts to server/scripts/game.cs in the startGame() function
also add this line to server/scripts/game.cs in the function onServerCreated()
exec("./ai/aiSpawn.cs");
That's all! Now you can have a place all the AISpawnSpheres you want in the map editor. Just edit the "spawn group name" field to pick out which spawning script you want each one to run when the mission starts. Then add all of your custom scripts to the function AISpawnSphere::spawn in the file server/scripts/ai/aispawn.cs using the template already provided.
Enjoy.
By the way my getterrainlevel algorithm was adapted from this http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=2347
My thanks to the author Emo1313
//------------------------------------------------------------------------------
// Class: AISpawnSphere
//------------------------------------------------------------------------------
IMPLEMENT_CO_NETOBJECT_V1(AISpawnSphere);
Sphere AISpawnSphere::smSphere(Sphere::Octahedron);
AISpawnSphere::AISpawnSphere()
{
mRadius = 100.f;
mSphereWeight = 100.f;
mIndoorWeight = 100.f;
mOutdoorWeight = 100.f;
mSpawnGroupName = StringTable->insert("Default Group");
}
bool AISpawnSphere::onAdd()
{
if(!Parent::onAdd())
return(false);
if(!isClientObject())
setMaskBits(UpdateSphereMask);
return true;
}
void AISpawnSphere::inspectPostApply()
{
Parent::inspectPostApply();
setMaskBits(UpdateSphereMask);
}
U32 AISpawnSphere::packUpdate(NetConnection * con, U32 mask, BitStream * stream)
{
U32 retMask = Parent::packUpdate(con, mask, stream);
//
if(stream->writeFlag(mask & UpdateSphereMask))
{
stream->write(mRadius);
//stream->writeString(mSpawnGroupName); //client doesn't need this, don't pack?
stream->write(mSphereWeight);
stream->write(mIndoorWeight);
stream->write(mOutdoorWeight);
}
return(retMask);
}
void AISpawnSphere::unpackUpdate(NetConnection * con, BitStream * stream)
{
Parent::unpackUpdate(con, stream);
if(stream->readFlag())
{
stream->read(&mRadius);
//mmSpawnGroupName = stream->readSTString(true);
stream->read(&mSphereWeight);
stream->read(&mIndoorWeight);
stream->read(&mOutdoorWeight);
}
}
void AISpawnSphere::initPersistFields()
{
Parent::initPersistFields();
addGroup("Dimensions");
addField("radius", TypeF32, Offset(mRadius, AISpawnSphere));
endGroup("Dimensions");
addGroup("Spawns");
addField("SpawnGroupName", TypeString, Offset(mSpawnGroupName, AISpawnSphere));
endGroup("Spawns");
addGroup("Weight");
addField("sphereWeight", TypeF32, Offset(mSphereWeight, AISpawnSphere));
addField("indoorWeight", TypeF32, Offset(mIndoorWeight, AISpawnSphere));
addField("outdoorWeight", TypeF32, Offset(mOutdoorWeight, AISpawnSphere));
endGroup("Weight");
}Add this to the bottom of your engine/game/missionmarker.h file BUT before that last #endif
//------------------------------------------------------------------------------
// Class: AISpawnSphere
//------------------------------------------------------------------------------
class AISpawnSphere : public MissionMarker
{
private:
typedef MissionMarker Parent;
static Sphere smSphere;
public:
AISpawnSphere();
// SimObject
bool onAdd();
void inspectPostApply();
// NetObject
enum SpawnSphereMasks {
UpdateSphereMask = Parent::NextFreeMask,
NextFreeMask = Parent::NextFreeMask << 1
};
U32 packUpdate (NetConnection *conn, U32 mask, BitStream *stream);
void unpackUpdate(NetConnection *conn, BitStream *stream);
// field data
F32 mRadius;
F32 mSphereWeight;
F32 mIndoorWeight;
F32 mOutdoorWeight;
StringTableEntry mSpawnGroupName;
static void initPersistFields();
DECLARE_CONOBJECT(AISpawnSphere);
};modify your server/scripts/markers.cs file to include the bolded parts
datablock MissionMarkerData(SpawnSphereMarker)
{
category = "Misc";
shapeFile = "~/data/shapes/markers/octahedron.dts";
};
[b]
//new spawn sphere for new spawn code
datablock MissionMarkerData(AISpawnSphere)
{
category = "AI Spawners";
shapeFile = "~/data/shapes/markers/octahedron.dts";
};
//won't render like the old spawn sphere without this
function AISpawnSphere::onEditorRender(%this, %editor, %selected, %expanded)
{
if(%selected $= "true")
{
%editor.consoleFrameColor = "255 0 0";
%editor.consoleFillColor = "0 15 0 15";
%editor.renderSphere(%this.getWorldBoxCenter(), %this.radius, 1);
}
}
[/b]
//------------------------------------------------------------------------------
// - serveral marker types may share MissionMarker datablock type
function MissionMarkerData::create(%block)
{
echo("MissionMarkerData::create(",%block,")");
switch$(%block)
{
case "WayPointMarker":
%obj = new WayPoint() {
dataBlock = %block;
};
return(%obj);
case "SpawnSphereMarker":
%obj = new SpawnSphere() {
datablock = %block;
};
return(%obj);[b]
case "AISpawnSphere":
echo("creating AISpawnSphere");
//new ones should automatically be placed in the appropriate group
//do not put anything but AISpawnSpheres in this new group
%groupName = "MissionGroup/AISpawnPoints";
%group = nameToID(%groupName);
if (%group == -1)
{
%group = new SimGroup(AISpawnPoints);
MissionGroup.add(%group);
}
%obj = new AISpawnSphere() {
datablock = %block; };
%group.add(%obj);
return(%obj);[/b]
}
return(-1);
}add this new file: server/scripts/ai/aispawn.cs
Edit this file to quickly add a new spawn group. Then in the mission editor, set each spawn group as needed for each of the AISpawnSpheres you place.
//checks all AISpawnSpheres and runs their corresponding spawn code
function AIManager::runAISpawners(%this)
{
//for fun lets add two additional bots before we run the AISpawnSpheres' codes
//bots will be added at random AISpawnSpheres
%this.spawnSome(2);
%groupName = "MissionGroup/AISpawnPoints";
%group = nameToID(%groupName);
if (%group != -1) {
%count = %group.getCount();
if (%count != 0) {
for(%i = 0; %i < %count; %i++)
{
%spawner = %group.getObject(%i);
%spawner.spawn(%i+3);
}
}
else
error("No spawn points found in " @ %groupName);
}
else
error("Missing spawn points group " @ %groupName);
return 1;
}
//spawns whatever corresponds to the SpawnGroupName of an AISpawnSphere
function AISpawnSphere::spawn(%this, %number)
{
switch$(%this.SpawnGroupName)
{
//spawn whatever you want, however you want
//just come up with a name for each spawning package
//spawn 2 bots at the spawn point by default
case "Default Group":
//put bot on the ground below this AISpawnSphere
%pos = AIManager::getTerrainLevel(%this.position,%this.radius,4.5);
if (%pos)
//create new object here at %pos
AIGuard::spawn2("Bot "@ %number, %pos);
else
//and create new object here at %this.position
AIGuard::spawn2("Bot "@ %number, %this.position);
%pos = AIManager::getTerrainLevel(%this.position,%this.radius,4.5);
if (%pos)
AIGuard::spawn2("Bot "@ %number+0.5, %pos);
else
AIGuard::spawn2("Bot "@ %number+0.5, %this.position);
return 1; //endcase
//using this example spawn code an AISpawnSphere will spawn only one bot
case "Only One":
%pos = AIManager::getTerrainLevel(%this.position,%this.radius,4.5);
if (%pos)
{
//create new object here at %pos
AIGuard::spawn2("Bot "@ %number, %pos);
}
else
{
//and create new object here at %this.position
AIGuard::spawn2("Bot "@ %number, %this.position);
}
return 1; //endcase
}
error(%this.objId,".SpawnGroupName is not a valid choice");
return (-1);
}
//recursive function adds %number of bots to random AISpawnSpheres
function AIManager::spawnSome(%this, %number)
{
if (%number > 0)
{
AIGuard::spawn2("Bot "@ %number, %this.pickAISpawnPoint());
%number--;
%this.schedule(600, "spawnSome",%number);
}
}
//randomly picks a good spawn location at one of the AISpawnSpheres
//tries to pick a clear space on the ground
function AIManager::pickAISpawnPoint(%this)
{
%groupName = "MissionGroup/AISpawnPoints";
%group = nameToID(%groupName);
if (%group != -1)
{
%count = %group.getCount();
if (%count != 0)
{
%index = getRandom(%count-1);
%spawn = %group.getObject(%index);
%pos = %this.getTerrainLevel(%spawn.position,%spawn.radius,4.5);
if (%pos)
{
return %pos;
}
//else place within 30 horizontal units of origin
else
{
error("Couldn't find clear space at spawn point. Spawning in center of spawn point.");
return %spawn.getTransform();
}
}
else
error("No spawn points found in " @ %groupName);
}
else
error("Missing spawn points group " @ %groupName);
// Could be no spawn points, in which case we'll stick the
// player at the center of the world.
%pos = %this.getTerrainLevel("0 0 600 1 0 0 0",30,4.5);
if (%pos)
{
return %pos;
}
//give up and drop 400 units directly above origin
else return "0 0 400 1 0 0 0";
}
//finds a space on the ground below an AISpawnSphere
//this code is borrowed from someone else resource
function AIManager::getTerrainLevel(%pos,%rad,%height)
{
while(%retries < 150)
{
%x = getWord(%pos, 0) + mFloor(getRandom(%rad * 2) - %rad);
%y = getWord(%pos, 1) + mFloor(getRandom(%rad * 2) - %rad);
%z = getWord(%pos, 2) + mFloor(getRandom(%rad * 2) - %rad);
%start = %x @ " " @ %y @ " 5000";
%end = %x @ " " @ %y @ " -1000";
%ground = containerRayCast(%start, %end, $TypeMasks::TerrainObjectType, 0);
%z = getWord(%ground, 3);
error ("Spawn Position : " @ %x SPC %y);
error ("Ground Level : " @ %z);
%z += %height;
%position = %x @ " " @ %y @ " " @ %z;
%mask = ($TypeMasks::VehicleObjectType |
$TypeMasks::MoveableObjectType |
$TypeMasks::StaticShapeObjectType |
$TypeMasks::ForceFieldObjectType |
$TypeMasks::InteriorObjectType |
$TypeMasks::ItemObjectType);
if (ContainerBoxEmpty(%mask,%position,3.5))
{
error ("Spawn Position Is Good");
return %position;
}
else
%retries++;
}
return false;
}
//original pick spawn point function
// does not try to spawn object at the ground
function pickAISpawnPointOriginal()
{
%groupName = "MissionGroup/AISpawnPoints";
%group = nameToID(%groupName);
if (%group != -1) {
%count = %group.getCount();
if (%count != 0) {
%index = getRandom(%count-1);
%spawn = %group.getObject(%index);
return %spawn.getTransform();
}
else
error("No spawn points found in " @ %groupName);
}
else
error("Missing spawn points group " @ %groupName);
// Could be no spawn points, in which case we'll stick the
// player at the center of the world.
return "0 0 300 1 0 0 0";
}add the bolded parts to server/scripts/game.cs in the startGame() function
// Start the AIManager
new ScriptObject(AIManager) {};
MissionCleanup.add(AIManager);
AIManager.think();
[b]
//Make aiGuards
AIManager.runAISpawners();[/b]
}also add this line to server/scripts/game.cs in the function onServerCreated()
exec("./ai/aiSpawn.cs");
That's all! Now you can have a place all the AISpawnSpheres you want in the map editor. Just edit the "spawn group name" field to pick out which spawning script you want each one to run when the mission starts. Then add all of your custom scripts to the function AISpawnSphere::spawn in the file server/scripts/ai/aispawn.cs using the template already provided.
Enjoy.
By the way my getterrainlevel algorithm was adapted from this http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=2347
My thanks to the author Emo1313
About the author

Torque Owner Kevin Lee