jedi-academy/code/RMG/RM_Mission.cpp
2013-04-23 21:59:26 +10:00

1930 lines
56 KiB
C++

/************************************************************************************************
*
* RM_Mission.cpp
*
* implements the CRMMission class. The CRMMission class loads and manages an arioche mission
*
************************************************************************************************/
#include "../server/exe_headers.h"
#include "RM_Headers.h"
#define ARIOCHE_CLIPBRUSH_SIZE 300
#define CVAR_OBJECTIVE 0
/************************************************************************************************
* CRMMission::CRMMission
* constructor
*
* inputs:
* none
*
* return:
* none
*
************************************************************************************************/
CRMMission::CRMMission ( CRandomTerrain* landscape )
{
mCurrentObjective = NULL;
mValidPaths = false;
mValidRivers = false;
mValidNodes = false;
mValidWeapons = false;
mValidAmmo = false;
mValidObjectives = false;
mValidInstances = false;
mTimeLimit = 0;
mMaxInstancePosition = 1;
mAccuracyMultiplier = 1.0f;
mHealthMultiplier = 1.0f;
mPickupHealth = 1.0f;
mPickupArmor = 1.0f;
mPickupAmmo = 1.0f;
mPickupWeapon = 1.0f;
mPickupEquipment = 1.0f;
mDefaultPadding = 0;
mSymmetric = SYMMETRY_NONE;
// mCheckedEnts.clear();
mLandScape = landscape;
// cut down the possible area that is 'legal' for area manager to use by 20%
vec3_t land_min, land_max;
land_min[0] = mLandScape->GetBounds ( )[0][0] + (mLandScape->GetBounds ( )[1][0]-mLandScape->GetBounds ( )[0][0]) * 0.1f;
land_min[1] = mLandScape->GetBounds ( )[0][1] + (mLandScape->GetBounds ( )[1][1]-mLandScape->GetBounds ( )[0][1]) * 0.1f;
land_min[2] = mLandScape->GetBounds ( )[0][2] + (mLandScape->GetBounds ( )[1][2]-mLandScape->GetBounds ( )[0][2]) * 0.1f;
land_max[0] = mLandScape->GetBounds ( )[1][0] - (mLandScape->GetBounds ( )[1][0]-mLandScape->GetBounds ( )[0][0]) * 0.1f;
land_max[1] = mLandScape->GetBounds ( )[1][1] - (mLandScape->GetBounds ( )[1][1]-mLandScape->GetBounds ( )[0][1]) * 0.1f;
land_max[2] = mLandScape->GetBounds ( )[1][2] - (mLandScape->GetBounds ( )[1][2]-mLandScape->GetBounds ( )[0][2]) * 0.1f;
// Create a new area manager for the landscape
mAreaManager = new CRMAreaManager ( land_min,
land_max );
// Create a new path manager
mPathManager = new CRMPathManager ( mLandScape );
}
/************************************************************************************************
* CRMMission::~CRMMission
* destructor
*
* inputs:
* none
*
* return:
* none
*
************************************************************************************************/
CRMMission::~CRMMission ( )
{
rmObjectiveIter_t oit;
rmInstanceIter_t iit;
// mCheckedEnts.clear();
// Cleanup the objectives
for (oit = mObjectives.begin(); oit != mObjectives.end(); oit++)
{
delete (*oit);
}
// Cleanup the instances
for (iit = mInstances.begin(); iit != mInstances.end(); iit++)
{
delete (*iit);
}
if (mPathManager)
{
delete mPathManager;
mPathManager = 0;
}
if (mAreaManager)
{
delete mAreaManager;
mAreaManager = 0;
}
}
/************************************************************************************************
* CRMMission::FindObjective
* searches through the missions objectives for the one with the given name
*
* inputs:
* name: name of objective to find
*
* return:
* objective: objective matching the given name or NULL if it couldnt be found
*
************************************************************************************************/
CRMObjective* CRMMission::FindObjective ( const char* name )
{
rmObjectiveIter_t it;
for (it = mObjectives.begin(); it != mObjectives.end(); it++)
{
// Does it match?
if (!Q_stricmp ((*it)->GetName(), name ))
{
return (*it);
}
}
// Not found
return NULL;
}
void CRMMission::MirrorPos(vec3_t pos)
{
pos[0] = 1.0f - pos[0];
pos[1] = 1.0f - pos[1];
}
/************************************************************************************************
* CRMMission::ParseOrigin
* parses an origin block which includes linking to a node and absolute origins
*
* inputs:
* group: parser group containing the node or origin
*
* return:
* true: parsed successfully
* false: failed to parse
*
************************************************************************************************/
bool CRMMission::ParseOrigin ( CGPGroup* originGroup, vec3_t origin, vec3_t lookat, int* flattenHeight )
{
const char* szNodeName;
vec3_t mins;
vec3_t maxs;
if ( flattenHeight )
{
*flattenHeight = 66;
}
// If no group was given then use 0,0,0
if ( NULL == originGroup )
{
VectorCopy ( vec3_origin, origin );
return false;
}
// See if attaching to a named node
szNodeName = originGroup->FindPairValue ( "node", "" );
if ( *szNodeName )
{
CRMNode* node;
// Find the node being attached to
node = mPathManager->FindNodeByName ( szNodeName );
if ( node )
{
if ( flattenHeight )
{
if ( node->GetFlattenHeight ( ) == -1 )
{
node->SetFlattenHeight ( 40 + mLandScape->irand(0,40) );
}
*flattenHeight = node->GetFlattenHeight ( );
}
VectorCopy(node->GetPos(), origin);
VectorCopy ( origin, lookat );
int dir;
int rnd_offset = mLandScape->irand(0, DIR_MAX-1);
for (dir=0; dir<DIR_MAX; dir++)
{
int d = (dir + rnd_offset) % DIR_MAX;
if (node->PathExist(d))
{
vec4_t tmp_pt, tmp_dir;
int pathID = node->GetPath(d);
mLandScape->GetPathInfo(pathID, 0.1f, tmp_pt, tmp_dir );
lookat[0] = tmp_pt[0];
lookat[1] = tmp_pt[1];
lookat[2] = 0;
return true;
}
}
return true;
}
}
mins[0] = atof( originGroup->FindPairValue ( "left", ".1" ) );
mins[1] = atof( originGroup->FindPairValue ( "top", ".1" ) );
maxs[0] = atof( originGroup->FindPairValue ( "right", ".9" ) );
maxs[1] = atof( originGroup->FindPairValue ( "bottom", ".9" ) );
lookat[0] = origin[0] = mLandScape->flrand(mins[0],maxs[0]);
lookat[1] = origin[1] = mLandScape->flrand(mins[1],maxs[1]);
lookat[2] = origin[2] = 0;
return true;
}
/************************************************************************************************
* CRMMission::ParseNodes
* parses all the named nodes in the file
*
* inputs:
* group: parser group containing the named nodes
*
* return:
* true: parsed successfully
* false: failed to parse
*
************************************************************************************************/
bool CRMMission::ParseNodes ( CGPGroup* group )
{
// If NULL that means this particular difficulty level has no named nodes
if ( NULL == group || mValidNodes)
{
return true;
}
// how many nodes spaced over map?
int x_cells;
int y_cells;
x_cells = atoi ( group->FindPairValue ( "x_cells", "3" ) );
y_cells = atoi ( group->FindPairValue ( "y_cells", "3" ) );
mPathManager->CreateArray(x_cells, y_cells);
// Loop through all the nodes and generate each as specified
for ( group = group->GetSubGroups();
group;
group=group->GetNext() )
{
int min_depth = atof( group->FindPairValue ( "min_depth", "0" ) );
int max_depth = atof( group->FindPairValue ( "max_depth", "5" ) );
int min_paths = atoi( group->FindPairValue ( "min_paths", "1" ) );
int max_paths = atoi( group->FindPairValue ( "max_paths", "1" ) );
mPathManager->CreateLocation( group->GetName(), min_depth, max_depth, min_paths, max_paths );
}
mValidNodes = true;
return true;
}
/************************************************************************************************
* CRMMission::ParsePaths
* parses all path styles in the file and then generates paths
*
* inputs:
* group: parser group containing the list of path styles
*
* return:
* true: parsed successfully
* false: failed to parse
*
************************************************************************************************/
bool CRMMission::ParsePaths ( CGPGroup* group )
{
// If NULL that means this particular difficulty level has no paths
if ( NULL == group || mValidPaths)
{
return true;
}
// path style info
float depth;
float deviation;
float breadth;
float minwidth;
float maxwidth;
int points;
points = atoi ( group->FindPairValue ( "points", "10" ) );
depth = atof ( group->FindPairValue ( "depth", ".31" ) );
deviation = atof ( group->FindPairValue ( "deviation", ".025" ) );
breadth = atof ( group->FindPairValue ( "breadth", "5" ) );
minwidth = atof ( group->FindPairValue ( "minwidth", ".03" ) );
maxwidth = atof ( group->FindPairValue ( "maxwidth", ".05" ) );
mPathManager->SetPathStyle( points, minwidth, maxwidth, depth, deviation, breadth);
if (!mValidPaths)
{ // we must create paths
mPathManager->GeneratePaths( mSymmetric );
mValidPaths = true;
}
return true;
}
/************************************************************************************************
* CRMMission::ParseRivers
* parses all river styles in the file and then generates rivers
*
* inputs:
* group: parser group containing the list of path styles
*
* return:
* true: parsed successfully
* false: failed to parse
*
************************************************************************************************/
bool CRMMission::ParseRivers ( CGPGroup* group )
{
// If NULL that means this particular difficulty level has no rivers
if ( NULL == group || mValidRivers)
{
return true;
}
// river style info
int maxdepth;
float beddepth;
float deviation;
float breadth;
float minwidth;
float maxwidth;
int points;
string bridge_name;
maxdepth = atoi ( group->FindPairValue ( "maxpathdepth", "5" ) );
points = atoi ( group->FindPairValue ( "points", "10" ) );
beddepth = atof ( group->FindPairValue ( "depth", "1" ) );
deviation = atof ( group->FindPairValue ( "deviation", ".03" ) );
breadth = atof ( group->FindPairValue ( "breadth", "7" ) );
minwidth = atof ( group->FindPairValue ( "minwidth", ".01" ) );
maxwidth = atof ( group->FindPairValue ( "maxwidth", ".03" ) );
bridge_name= group->FindPairValue ( "bridge", "" ) ;
mPathManager->SetRiverStyle( maxdepth, points, minwidth, maxwidth, beddepth, deviation, breadth, bridge_name);
if (!mValidRivers &&
beddepth < 1) // use a depth of 1 if we don't want any rivers
{ // we must create rivers
mPathManager->GenerateRivers();
mValidRivers = true;
}
return true;
}
void CRMMission::PlaceBridges()
{
if (!mValidRivers || strlen(mPathManager->GetBridgeName()) < 1)
return;
int max_bridges = 0;
int path;
float t;
float river_depth = mLandScape->GetLandScape()->GetWaterHeight();
vec3_t pos, lastpos;
vec3pair_t bounds;
VectorSet(bounds[0], 0,0,0);
VectorSet(bounds[1], 0,0,0);
// walk along paths looking for dips
for (path = 0; path < mPathManager->GetPathCount(); path++)
{
vec4_t tmp_pt, tmp_dir;
bool new_water = true;
mLandScape->GetPathInfo(path, 0, tmp_pt, tmp_dir );
lastpos[0] = mLandScape->GetBounds ( )[0][0] + (mLandScape->GetBounds ( )[1][0]-mLandScape->GetBounds ( )[0][0]) * tmp_pt[0];
lastpos[1] = mLandScape->GetBounds ( )[0][1] + (mLandScape->GetBounds ( )[1][1]-mLandScape->GetBounds ( )[0][1]) * tmp_pt[1];
lastpos[2] = mLandScape->GetBounds ( )[0][2] + (mLandScape->GetBounds ( )[1][2]-mLandScape->GetBounds ( )[0][2]) * tmp_pt[2];
mLandScape->GetLandScape()->GetWorldHeight ( lastpos, bounds, true );
const float delta = 0.05f;
for (t= delta; t < 1.0f; t += delta)
{
mLandScape->GetPathInfo(path, t, tmp_pt, tmp_dir );
pos[0] = mLandScape->GetBounds ( )[0][0] + (mLandScape->GetBounds ( )[1][0]-mLandScape->GetBounds ( )[0][0]) * tmp_pt[0];
pos[1] = mLandScape->GetBounds ( )[0][1] + (mLandScape->GetBounds ( )[1][1]-mLandScape->GetBounds ( )[0][1]) * tmp_pt[1];
pos[2] = mLandScape->GetBounds ( )[0][2] + (mLandScape->GetBounds ( )[1][2]-mLandScape->GetBounds ( )[0][2]) * tmp_pt[2];
mLandScape->GetLandScape()->GetWorldHeight ( pos, bounds, true );
if (new_water &&
lastpos[2] < river_depth &&
pos[2] < river_depth &&
pos[2] > lastpos[2])
{ // add a bridge
if (max_bridges < 3)
{
CRMArea* area;
CRMInstance* instance;
max_bridges++;
// create a single bridge
lastpos[2] = mLandScape->GetBounds ( )[0][2] + (mLandScape->GetBounds ( )[1][2]-mLandScape->GetBounds ( )[0][2]) * mPathManager->GetPathDepth();
instance = mInstanceFile.CreateInstance ( mPathManager->GetBridgeName() );
if ( NULL != instance )
{ // Set the area
vec3_t zerodvec;
VectorClear(zerodvec);
area = mAreaManager->CreateArea ( lastpos, instance->GetSpacingRadius(), instance->GetSpacingLine(), GetDefaultPadding(), 0, zerodvec, pos, instance->GetFlattenRadius()?true:false, false, instance->GetLockOrigin() );
area->EnableLookAt(false);
instance->SetArea ( mAreaManager, area );
mInstances.push_back ( instance );
new_water = false;
}
}
}
else if (pos[2] > river_depth)
{ // hit land again
new_water = true;
}
VectorCopy ( pos, lastpos );
}
}
}
void CRMMission::PlaceWallInstance(CRMInstance* instance, float xpos, float ypos, float zpos, int x, int y, float angle)
{
if (NULL == instance)
return;
float spacing = instance->GetSpacingRadius();
CRMArea* area;
vec3_t origin;
vec3_t zerodvec;
VectorClear(zerodvec);
origin[0] = xpos + spacing * x;
origin[1] = ypos + spacing * y;
origin[2] = zpos;
// Set the area of position
area = mAreaManager->CreateArea ( origin, (spacing / 2.1f), 0, GetDefaultPadding(), 0, zerodvec, origin, instance->GetFlattenRadius()?true:false, false, instance->GetLockOrigin() );
area->EnableLookAt(false);
area->SetAngle(angle);
instance->SetArea ( mAreaManager, area );
mInstances.push_back ( instance );
}
/************************************************************************************************
* CRMMission::ParseWallRect
* creates instances for walled rectangle at this node (fence)
*
* inputs:
* group: parser group containing the wall rect info
*
* return:
* true: parsed successfully
* false: failed to parse
*
************************************************************************************************/
bool CRMMission::ParseWallRect(CGPGroup* group , int side)
{
#ifndef PRE_RELEASE_DEMO
CGPGroup* wallGroup = group->FindSubGroup ( "wallrect" ) ;
// If NULL that means this particular instance has no wall rect
if ( NULL == group || NULL == wallGroup)
{
return true;
}
const char* wallName = wallGroup->FindPairValue ( "wall_instance", "" );
const char* cornerName = wallGroup->FindPairValue ( "corner_instance", "" );
const char* towerName = wallGroup->FindPairValue ( "tower_instance", "" );
const char* gateName = wallGroup->FindPairValue ( "gate_instance", "" );
const char* ripName = wallGroup->FindPairValue ( "rip_instance", "" );
if ( NULL != wallName )
{
int xcount = atoi( wallGroup->FindPairValue ( "xcount", "0" ) );
int ycount = atoi( wallGroup->FindPairValue ( "ycount", "0" ) );
int gateCount = atoi( wallGroup->FindPairValue ( "gate_count", "1" ) );
int gateMin = atoi( wallGroup->FindPairValue ( "gate_min", "0" ) );
int gateMax = atoi( wallGroup->FindPairValue ( "gate_max", "0" ) );
int ripCount = atoi( wallGroup->FindPairValue ( "rip_count", "0" ) );
int ripMin = atoi( wallGroup->FindPairValue ( "rip_min", "0" ) );
int ripMax = atoi( wallGroup->FindPairValue ( "rip_max", "0" ) );
int towerCount = atoi( wallGroup->FindPairValue ( "tower_count", "0" ) );
int towerMin = atoi( wallGroup->FindPairValue ( "tower_min", "0" ) );
int towerMax = atoi( wallGroup->FindPairValue ( "tower_max", "0" ) );
if (gateMin != gateMax)
gateCount = mLandScape->irand(gateMin,gateMax);
if (ripMin != ripMax)
ripCount = mLandScape->irand(ripMin,ripMax);
if (towerMin != towerMax)
towerCount = mLandScape->irand(towerMin,towerMax);
if (NULL == gateName)
gateCount = 0;
if (NULL == towerName)
towerCount = 0;
if (NULL == ripName)
ripCount = 0;
const char* nodename;
CGPGroup* originGroup = group->FindSubGroup ( "origin" );
if (originGroup)
{
nodename = originGroup->FindPairValue ( "node", "" );
if (*nodename)
{
CRMNode* node;
// Find the node being attached to
node = mPathManager->FindNodeByName ( nodename );
if ( node )
{
CRMInstance* instance;
int x,y;
int halfx = xcount/2;
int halfy = ycount/2;
float xpos = mLandScape->GetBounds ( )[0][0] + (mLandScape->GetBounds ( )[1][0]-mLandScape->GetBounds ( )[0][0]) * node->GetPos()[0];
float ypos = mLandScape->GetBounds ( )[0][1] + (mLandScape->GetBounds ( )[1][1]-mLandScape->GetBounds ( )[0][1]) * node->GetPos()[1];
float zpos = mLandScape->GetBounds ( )[1][2] + 100;
float angle = 0;
int lastGate = 0;
int lastRip = 0;
// corners
x = -halfx;
y = -halfy;
if (towerCount > 3 ||
(towerCount > 0 && mLandScape->irand(1,2) == 1) )
{
towerCount--;
instance = mInstanceFile.CreateInstance ( towerName );
}
else
instance = mInstanceFile.CreateInstance ( cornerName );
angle = (float)DEG2RAD(90);
instance->SetSide(side);
PlaceWallInstance(instance, xpos, ypos, zpos, x, y, angle);
x = halfx;
y = -halfy;
if (towerCount > 3 ||
(towerCount > 0 && mLandScape->irand(1,2) == 1) )
{
towerCount--;
instance = mInstanceFile.CreateInstance ( towerName );
}
else
instance = mInstanceFile.CreateInstance ( cornerName );
angle = (float)DEG2RAD(180);
instance->SetSide(side);
PlaceWallInstance(instance, xpos, ypos, zpos, x, y, angle);
x = halfx;
y = halfy;
if (towerCount > 3 ||
(towerCount > 0 && mLandScape->irand(1,2) == 1) )
{
towerCount--;
instance = mInstanceFile.CreateInstance ( towerName );
}
else
instance = mInstanceFile.CreateInstance ( cornerName );
angle = (float)DEG2RAD(270);
instance->SetSide(side);
PlaceWallInstance(instance, xpos, ypos, zpos, x, y, angle);
x = -halfx;
y = halfy;
if (towerCount > 3 ||
(towerCount > 0 && mLandScape->irand(1,2) == 1) )
{
towerCount--;
instance = mInstanceFile.CreateInstance ( towerName );
}
else
instance = mInstanceFile.CreateInstance ( cornerName );
angle = DEG2RAD(0);
instance->SetSide(side);
PlaceWallInstance(instance, xpos, ypos, zpos, x, y, angle);
// walls
angle = DEG2RAD(0);
for (x = -halfx+1; x <= halfx-1; x++)
{
if (lastGate<1 && gateCount > 0 && mLandScape->irand(1,(halfx+halfy)/gateCount) == 1)
{ // gate
gateCount--;
lastGate = 3;
instance = mInstanceFile.CreateInstance ( gateName );
}
else if (lastRip<1 && ripCount > 0 && mLandScape->irand(1,(halfx+halfy)/ripCount) == 1)
{ // damaged fence
ripCount--;
lastRip = 3;
instance = mInstanceFile.CreateInstance ( ripName );
}
else
{ // just a wall
instance = mInstanceFile.CreateInstance ( wallName );
lastRip--;
lastGate--;
}
instance->SetSide(side);
PlaceWallInstance(instance, xpos, ypos, zpos, x, -halfy, angle);
}
for (x = -halfx+1; x <= halfx-1; x++)
{
if (lastGate<1 && gateCount > 0 && mLandScape->irand(1,(halfx+halfy)/gateCount) == 1)
{ // gate
gateCount--;
lastGate = 3;
instance = mInstanceFile.CreateInstance ( gateName );
}
else if (lastRip<1 && ripCount > 0 && mLandScape->irand(1,(halfx+halfy)/ripCount) == 1)
{ // damaged fence
ripCount--;
lastRip = 3;
instance = mInstanceFile.CreateInstance ( ripName );
}
else
{ // just a wall
instance = mInstanceFile.CreateInstance ( wallName );
lastRip--;
lastGate--;
}
instance->SetSide(side);
PlaceWallInstance(instance, xpos, ypos, zpos, x, halfy, angle);
}
angle = (float)DEG2RAD(90);
for (y = -halfy+1; y <= halfy-1; y++)
{
if (lastGate<1 && gateCount > 0 && mLandScape->irand(1,(halfx+halfy)/gateCount) == 1)
{ // gate
gateCount--;
lastGate = 3;
instance = mInstanceFile.CreateInstance ( gateName );
}
else if (lastRip<1 && ripCount > 0 && mLandScape->irand(1,(halfx+halfy)/ripCount) == 1)
{ // damaged fence
ripCount--;
lastRip = 3;
instance = mInstanceFile.CreateInstance ( ripName );
}
else
{ // just a wall
instance = mInstanceFile.CreateInstance ( wallName );
lastRip--;
lastGate--;
}
instance->SetSide(side);
PlaceWallInstance(instance, xpos, ypos, zpos, -halfx, y, angle);
}
for (y = -halfy+1; y <= halfy-1; y++)
{
if (lastGate<1 && gateCount > 0 && mLandScape->irand(1,(halfx+halfy)/gateCount) == 1)
{ // gate
gateCount--;
lastGate = 3;
instance = mInstanceFile.CreateInstance ( gateName );
}
else if (lastRip<1 && ripCount > 0 && mLandScape->irand(1,(halfx+halfy)/ripCount) == 1)
{ // damaged fence
ripCount--;
lastRip = 3;
instance = mInstanceFile.CreateInstance ( ripName );
}
else
{ // just a wall
instance = mInstanceFile.CreateInstance ( wallName );
lastRip--;
lastGate--;
}
instance->SetSide(side);
PlaceWallInstance(instance, xpos, ypos, zpos, halfx, y, angle);
}
}
}
}
}
else
return false;
#endif // #ifndef PRE_RELEASE_DEMO
return true;
}
/************************************************************************************************
* CRMMission::ParseInstancesOnPath
* creates instances on path between nodes
*
* inputs:
* group: parser group containing the defenses, other instances on the path between nodes
*
* return:
* true: parsed successfully
* false: failed to parse
*
************************************************************************************************/
bool CRMMission::ParseInstancesOnPath ( CGPGroup* group )
{
#ifndef PRE_RELEASE_DEMO
CGPGroup* defenseGroup;
for ( defenseGroup = group->GetSubGroups();
defenseGroup;
defenseGroup=defenseGroup->GetNext() )
if (Q_stricmp ( defenseGroup->GetName ( ), "defenses" )==0 ||
Q_stricmp ( defenseGroup->GetName(), "instanceonpath")==0)
{
const char* defName = defenseGroup->FindPairValue ( "instance", "" );
if ( *defName )
{
float minpos;
float maxpos;
int mincount;
int maxcount;
// how far along path does this get placed?
minpos = atof( defenseGroup->FindPairValue ( "minposition", "0.5" ) );
maxpos = atof( defenseGroup->FindPairValue ( "maxposition", "0.5" ) );
mincount = atoi( defenseGroup->FindPairValue ( "mincount", "1" ) );
maxcount = atoi( defenseGroup->FindPairValue ( "maxcount", "1" ) );
const char* nodename;
CGPGroup* originGroup = group->FindSubGroup ( "origin" );
if (originGroup)
{
nodename = originGroup->FindPairValue ( "node", "" );
if (*nodename)
{
CRMNode* node;
// Find the node being attached to
node = mPathManager->FindNodeByName ( nodename );
if ( node )
{
int dir;
// look at each connection from this node to others, if there is a path, create a defense
for (dir=0; dir<DIR_MAX; dir++)
{
if (node->PathExist(dir))
{ // path leads out of this node
CRMArea* area;
CRMInstance* instance;
float spacing;
vec3_t origin;
vec3_t lookat;
vec4_t tmp_pt, tmp_dir;
int n,num_insts = mLandScape->irand(mincount,maxcount);
int pathID = node->GetPath(dir);
if (0 == num_insts)
continue;
float posdelta = (maxpos - minpos) / num_insts;
for (n=0; n<num_insts; n++)
{
instance = mInstanceFile.CreateInstance ( defName );
// Failed to create, not good
if ( NULL == instance )
{
continue;
}
// If a spacing radius was specified then override the one thats
// in the instance
spacing = atof( defenseGroup->FindPairValue ( "spacing", "0" ) );
if ( spacing )
{
instance->SetSpacingRadius ( spacing );
}
instance->SetFilter(group->FindPairValue("filter", ""));
instance->SetTeamFilter(group->FindPairValue("teamfilter", ""));
if (strstr(instance->GetTeamFilter(),"red"))
instance->SetSide(SIDE_RED);
else if (strstr(instance->GetTeamFilter(),"blue"))
instance->SetSide(SIDE_BLUE);
float pos_along_path = mLandScape->flrand(minpos + posdelta*n, minpos + posdelta*(n+1));
float look_along_path = atof( defenseGroup->FindPairValue ( "pathalign", "1" ) ) ;
mLandScape->GetPathInfo (pathID, pos_along_path, tmp_pt, tmp_dir );
origin[0] = tmp_pt[0];
origin[1] = tmp_pt[1];
mLandScape->GetPathInfo (pathID, look_along_path, tmp_dir, tmp_pt );
lookat[0] = tmp_pt[0];
lookat[1] = tmp_pt[1];
origin[0] = mLandScape->GetBounds ( )[0][0] + (mLandScape->GetBounds ( )[1][0]-mLandScape->GetBounds ( )[0][0]) * origin[0];
origin[1] = mLandScape->GetBounds ( )[0][1] + (mLandScape->GetBounds ( )[1][1]-mLandScape->GetBounds ( )[0][1]) * origin[1];
origin[2] = mLandScape->GetBounds ( )[0][2] ;
// look at a point along the path at this location
lookat[0] = mLandScape->GetBounds ( )[0][0] + (mLandScape->GetBounds ( )[1][0]-mLandScape->GetBounds ( )[0][0]) * lookat[0];
lookat[1] = mLandScape->GetBounds ( )[0][1] + (mLandScape->GetBounds ( )[1][1]-mLandScape->GetBounds ( )[0][1]) * lookat[1];
lookat[2] = 0;
// Fixed height? (used for bridges)
if ( !atoi(group->FindPairValue ( "nodrop", "0" )) )
{
origin[2] = mLandScape->GetBounds ( )[1][2] + 100;
}
// Set the area of position
area = mAreaManager->CreateArea ( origin, instance->GetSpacingRadius(), instance->GetSpacingLine(), GetDefaultPadding(), 0, origin, lookat, instance->GetFlattenRadius()?true:false, true, instance->GetLockOrigin(), mSymmetric );
area->EnableLookAt(false);
if ( node->GetFlattenHeight ( ) == -1 )
{
node->SetFlattenHeight ( 66 + mLandScape->irand(0,40) );
}
instance->SetFlattenHeight ( node->GetFlattenHeight ( ) );
instance->SetArea ( mAreaManager, area );
mInstances.push_back ( instance );
}
}
}
}
}
}
else
return false;
}
else
return false;
}
#endif // #ifndef PRE_RELEASE_DEMO
return true;
}
/************************************************************************************************
* CRMMission::ParseInstance
* Parses an individual instance
*
* inputs:
* group: parser group containing the list of instances
*
* return:
* true: instances parsed successfully
* false: instances failed to parse
*
************************************************************************************************/
bool CRMMission::ParseInstance ( CGPGroup* group )
{
CRMArea* area;
CRMInstance* instance;
float spacing;
vec3_t origin;
vec3_t lookat;
int flattenHeight;
vec3_t zerodvec;
VectorClear(zerodvec);
// create fences / walls
// Create the instance using the instance file helper class
instance = mInstanceFile.CreateInstance ( group->GetName ( ) );
// Failed to create, not good
if ( NULL == instance )
{
return false;
}
// If a spacing radius was specified then override the one thats
// in the instance
spacing = atof( group->FindPairValue ( "spacing", "0" ) );
if ( spacing )
{
instance->SetSpacingRadius ( spacing );
}
instance->SetFilter(group->FindPairValue("filter", ""));
instance->SetTeamFilter(group->FindPairValue("teamfilter", ""));
if (strstr(instance->GetTeamFilter(),"red"))
instance->SetSide( SIDE_RED);
else if (strstr(instance->GetTeamFilter(),"blue"))
instance->SetSide( SIDE_BLUE );
// ParseWallRect(group, instance->GetSide());
// Get its origin now
ParseOrigin ( group->FindSubGroup ( "origin" ), origin, lookat, &flattenHeight );
origin[0] = mLandScape->GetBounds ( )[0][0] + (mLandScape->GetBounds ( )[1][0]-mLandScape->GetBounds ( )[0][0]) * origin[0];
origin[1] = mLandScape->GetBounds ( )[0][1] + (mLandScape->GetBounds ( )[1][1]-mLandScape->GetBounds ( )[0][1]) * origin[1];
origin[2] = mLandScape->GetBounds ( )[0][2] + (mLandScape->GetBounds ( )[1][2]-mLandScape->GetBounds ( )[0][2]) * origin[2];
lookat[0] = mLandScape->GetBounds ( )[0][0] + (mLandScape->GetBounds ( )[1][0]-mLandScape->GetBounds ( )[0][0]) * lookat[0];
lookat[1] = mLandScape->GetBounds ( )[0][1] + (mLandScape->GetBounds ( )[1][1]-mLandScape->GetBounds ( )[0][1]) * lookat[1];
lookat[2] = mLandScape->GetBounds ( )[0][2] + (mLandScape->GetBounds ( )[1][2]-mLandScape->GetBounds ( )[0][2]) * lookat[2];
// Fixed height? (used for bridges)
if ( !atoi(group->FindPairValue ( "nodrop", "0" )) )
{
origin[2] = mLandScape->GetBounds ( )[1][2] + 100;
}
// Set the area of position
area = mAreaManager->CreateArea ( origin, instance->GetSpacingRadius(), instance->GetSpacingLine(), GetDefaultPadding(), 0, zerodvec, lookat, instance->GetFlattenRadius()?true:false, true, instance->GetLockOrigin(), mSymmetric );
instance->SetArea ( mAreaManager, area );
instance->SetFlattenHeight ( flattenHeight );
mInstances.push_back ( instance );
// create defenses?
ParseInstancesOnPath(group );
return true;
}
/************************************************************************************************
* CRMMission::ParseInstances
* parses all instances within the mission and populates the instance list
*
* inputs:
* group: parser group containing the list of instances
*
* return:
* true: instances parsed successfully
* false: instances failed to parse
*
************************************************************************************************/
bool CRMMission::ParseInstances ( CGPGroup* group )
{
#ifndef PRE_RELEASE_DEMO
// If NULL that means this particular difficulty level has no instances
if ( NULL == group )
{
return true;
}
// Loop through all the instances in the mission and add each
// to the master list of instances
for ( group = group->GetSubGroups();
group;
group=group->GetNext() )
{
ParseInstance ( group );
}
#endif // #ifndef PRE_RELEASE_DEMO
return true;
}
/************************************************************************************************
* CRMMission::ParseObjectives
* parses all objectives within the mission and populates the objective list
*
* inputs:
* group: parser group containing the list of objectives
*
* return:
* true: objectives parsed successfully
* false: objectives failed to parse
*
************************************************************************************************/
bool CRMMission::ParseObjectives ( CGPGroup* group )
{
// If NULL that means this particular difficulty level has no objectives
if ( NULL == group )
{
return true;
}
// Loop through all the objectives in the mission and add each
// to the master list of objectives
for ( group = group->GetSubGroups();
group;
group=group->GetNext() )
{
CRMObjective* objective;
// Create the new objective
objective = new CRMObjective ( group );
mObjectives.push_back ( objective );
}
mValidObjectives = true;
return true;
}
/************************************************************************************************
* CRMMission::ParseAmmo
* parses the given ammo list and sets the necessary ammo cvars to grant those
* weapons to the players
*
* inputs:
* ammos: parser group containing the ammo list
*
* return:
* true: ammo parsed successfully
* false: ammo failed to parse
*
************************************************************************************************/
bool CRMMission::ParseAmmo ( CGPGroup* ammos )
{
/* CGPValue* ammo;
// No weapons, no success
if ( NULL == ammos )
{
return false;
}
if (0 == gi.Cvar_VariableIntegerValue("ar_wpnselect"))
{
// Make sure the ammo cvars are all reset so ammo from the last map or
// another difficulty level wont carry over
CWeaponSystem::ClearAmmoCvars (TheWpnSysHelper());
ammo = ammos->GetPairs ( );
// Loop through the weapons listed and grant them to the player
while ( ammo )
{
// Grab the weapons ID
AmmoID id = CWeaponSystem::GetAmmoID ( ammo->GetName ( ) );
// Now set the weapon cvar with the given data
TheWpnSysHelper().CvarSet ( CWeaponSystem::GetAmmoCvar ( id ), ammo->GetTopValue ( ), CVAR_AMMO );
// Move on to the next weapon
ammo = (CGPValue*)ammo->GetNext();
}
}
*/
mValidAmmo = true;
return true;
}
/************************************************************************************************
* CRMMission::ParseWeapons
* parses the given weapon list and sets the necessary weapon cvars to grant those
* weapons to the players
*
* inputs:
* weapons: parser group containing the weapons list
*
* return:
* true: weapons parsed successfully
* false: weapons failed to parse
*
************************************************************************************************/
bool CRMMission::ParseWeapons ( CGPGroup* weapons )
{
/* CGPValue* weapon;
WpnID id;
// No weapons, no success
if ( NULL == weapons )
{
return false;
}
if (0 == gi.Cvar_VariableIntegerValue("ar_wpnselect"))
{
// Make sure the weapon cvars are all reset so weapons from the last map or
// another difficulty level wont carry over
CWeaponSystem::ClearWpnCvars (TheWpnSysHelper());
id = NULL_WpnID;
weapon = weapons->GetPairs ( );
// Loop through the weapons listed and grant them to the player
while ( weapon )
{
// Grab the weapons ID
id = CWeaponSystem::GetWpnID ( weapon->GetName ( ) );
// Now set the weapon cvar with the given data
TheWpnSysHelper().CvarSet ( CWeaponSystem::GetWpnCvar ( id ), weapon->GetTopValue ( ) );
// Move on to the next weapon
weapon = (CGPValue*)weapon->GetNext();
}
// If we found at least one weapon then ready the last one in the list
if ( NULL_WpnID != id )
{
TheWpnSysHelper().CvarSet("wp_righthand", va("%i/%i/0/0",id,CWeaponSystem::GetClipSize ( id )), CVAR_MISC );
}
}
*/
mValidWeapons = true;
return true;
}
/************************************************************************************************
* CRMMission::ParseOutfit
* parses the outfit (weapons and ammo)
*
* inputs:
* outfit: parser group containing the outfit
*
* return:
* true: weapons and ammo parsed successfully
* false: failed to parse
*
************************************************************************************************/
bool CRMMission::ParseOutfit ( CGPGroup* outfit )
{
if ( NULL == outfit )
{
return false;
}
/* // Its ok to fail parsing weapons as long as weapons have
// already been parsed at some point
if ( !ParseWeapons ( ParseRandom ( outfit->FindSubGroup ( "weapons" ) ) ) )
{
if ( !mValidWeapons )
{
return false;
}
}
// Its ok to fail parsing ammo as long as ammo have
// already been parsed at some point
if ( !ParseAmmo ( ParseRandom ( outfit->FindSubGroup ( "ammo" ) ) ) )
{
if ( !mValidAmmo)
{
return false;
}
}
*/
return true;
}
/************************************************************************************************
* CRMMission::ParseRandom
* selects a random sub group with from all within this one
*
* inputs:
* random: parser group containing the various subgroups
*
* return:
* true: parsed successfuly
* false: failed to parse
*
************************************************************************************************/
CGPGroup* CRMMission::ParseRandom ( CGPGroup* randomGroup )
{
if (NULL == randomGroup)
return NULL;
CGPGroup* group;
CGPGroup* groups[MAX_RANDOM_CHOICES];
int numGroups;
// Build a list of the groups one can be chosen
for ( numGroups = 0, group = randomGroup->GetSubGroups ( );
group;
group = group->GetNext ( ) )
{
if ( Q_stricmp ( group->GetName ( ), "random_choice" ) )
{
continue;
}
int weight = atoi ( group->FindPairValue ( "random_weight", "1" ) );
while (weight-- > 0)
groups[numGroups++] = group;
assert (numGroups <= MAX_RANDOM_CHOICES);
}
// No groups!
if ( !numGroups )
{
return randomGroup;
}
// Now choose a group to parse
return groups[mLandScape->irand(0,numGroups-1)];
}
/************************************************************************************************
* CRMMission::ParseDifficulty
* parses the given difficulty and populates the mission with its data
*
* inputs:
* difficulty: parser group containing the difficulties info
*
* return:
* true: difficulty parsed successfully
* false: difficulty failed to parse
*
************************************************************************************************/
bool CRMMission::ParseDifficulty ( CGPGroup* difficulty, CGPGroup *parent )
{
// If a null difficulty then stop the recursion. Make sure to
// return true here so the parsing doesnt fail
if ( NULL == difficulty )
{
return true;
}
if (difficulty->GetParent())
{
parent = difficulty->GetParent();
}
// is map supposed to be symmetric?
mSymmetric = (symmetry_t)atoi(parent->FindPairValue ( "symmetric", "0" ));
mBackUpPath = atoi(parent->FindPairValue ( "backuppath", "0" ));
if( mSymmetric )
{// pick between the 2 starting corners -- yes this is a hack
mSymmetric = SYMMETRY_TOPLEFT;
if( TheRandomMissionManager->GetLandScape()->irand(0, 1) )
{
mSymmetric = SYMMETRY_BOTTOMRIGHT;
}
}
mDefaultPadding = atoi(parent->FindPairValue ( "padding", "0" ));
// Parse the nodes
if ( !ParseNodes ( ParseRandom ( difficulty->FindSubGroup ( "nodes" ) ) ) )
{
return false;
}
// Parse the paths
if ( !ParsePaths ( ParseRandom ( difficulty->FindSubGroup ( "paths" ) ) ) )
{
return false;
}
// Parse the rivers
if ( !ParseRivers ( ParseRandom ( difficulty->FindSubGroup ( "rivers" ) ) ) )
{
return false;
}
// Handle inherited properties
if ( !ParseDifficulty ( parent->FindSubGroup ( difficulty->FindPairValue ( "inherit", "" ) ), parent ) )
{
return false;
}
// parse the player's outfit (weapons and ammo)
if ( !ParseOutfit( ParseRandom ( difficulty->FindSubGroup ( "outfit" ) ) ) )
{
// Its ok to fail parsing weapons as long as weapons have
// already been parsed at some point
if ( !ParseWeapons ( ParseRandom ( difficulty->FindSubGroup ( "weapons" ) ) ) )
{
if ( !mValidWeapons )
{
return false;
}
}
// Its ok to fail parsing ammo as long as ammo have
// already been parsed at some point
if ( !ParseAmmo ( ParseRandom ( difficulty->FindSubGroup ( "ammo" ) ) ) )
{
if ( !mValidAmmo)
{
return false;
}
}
}
// Its ok to fail parsing objectives as long as objectives have
// already been parsed at some point
if ( !ParseObjectives ( ParseRandom ( difficulty->FindSubGroup ( "objectives" ) ) ) )
{
if ( !mValidObjectives )
{
return false;
}
}
// Set the cvars with the available values
Cvar_Set ( "mi_health", difficulty->FindPairValue ( "health", "100" ) );
Cvar_Set ( "mi_armor", difficulty->FindPairValue ( "armor", "0" ) );
// Parse out the timelimit
mTimeLimit = atol(difficulty->FindPairValue("timelimit", "0"));
// NPC multipliers
mAccuracyMultiplier = atof(difficulty->FindPairValue("npcaccuracy", "1"));
mHealthMultiplier = atof(difficulty->FindPairValue("npchealth", "1"));
// keep only some of RMG pickups 1 = 100%
mPickupHealth = atof(difficulty->FindPairValue("pickup_health", "1"));
mPickupArmor = atof(difficulty->FindPairValue("pickup_armor", "1"));
mPickupAmmo = atof(difficulty->FindPairValue("pickup_ammo", "1"));
mPickupWeapon = atof(difficulty->FindPairValue("pickup_weapon", "1"));
mPickupEquipment = atof(difficulty->FindPairValue("pickup_equipment", "1"));
// Its ok to fail parsing instances as long as instances have
// already been parsed at some point
if ( !ParseInstances ( ParseRandom ( difficulty->FindSubGroup ( "instances" ) ) ) )
{
if ( !mValidInstances )
{
return false;
}
}
return true;
}
/************************************************************************************************
* CRMMission::Load
* Loads the given mission using the given difficulty level
*
* inputs:
* name: Name of the mission to load (should only be the name rather than the full path)
* difficulty: difficulty level to load
*
* return:
* true: mission successfully loaded
* false: mission failed to load
*
************************************************************************************************/
bool CRMMission::Load ( const char* mission, const char* instances, const char* difficulty )
{
CGenericParser2 parser;
CGPGroup* root;
// Create the parser for the mission file
if(!Com_ParseTextFile(va("ext_data/rmg/%s.mission", mission), parser))
{
if(!Com_ParseTextFile(va("ext_data/arioche/%s.mission", mission), parser))
{
Com_Printf("ERROR: Failed to open mission file '%s'\n", mission);
return false;
}
}
// Grab the root parser groop and make sure its mission, otherwise this
// isnt a valid mission file
root = parser.GetBaseParseGroup()->GetSubGroups();
if(Q_stricmp(root->GetName(), "mission"))
{
Com_Printf("ERROR: '%s' is not a valid mission file\n", mission );
parser.Clean();
return false;
}
// Grab the mission description and set the cvar for it
mDescription = root->FindPairValue ( "description", "<MISSION DESCRIPTION MISSING>" );
// Cvar_Set("ar_obj_main0",mDescription.c_str(), CVAR_OBJECTIVE);
// Cvar_Set("ar_obj_maincom0", "&OBJECTIVES_INPROGRESS&", CVAR_OBJECTIVE);
// Cvar_SetValue ("ar_cur_objective", 0, CVAR_OBJECTIVE);
string mInfo = root->FindPairValue ( "info", "<MISSION ADDITIONAL INFO MISSING>" );
// Cvar_Set("ar_obj_info0",mInfo.c_str(), CVAR_OBJECTIVE);
mExitScreen = root->FindPairValue ( "exitScreen", "<EXIT SCREEN MISSING>" );
mTimeExpiredScreen = root->FindPairValue ( "TimeExpiredScreen", "<TIME EXPIRED SCREEN MISSING>" );
// Open the instance file for the specified instances
if ( !mInstanceFile.Open ( instances) )
{
Com_Printf ( "ERROR: Could not open instance file '%s'\n", instances );
return false;
}
// Start at one and readjust each time we see and instance
// with a higher value
mMaxInstancePosition = 1;
// Now parse the specified difficulty level
CGPGroup* parserdif = root->FindSubGroup ( difficulty );
CGPGroup* parserpar = parserdif->GetParent();
if (!parserpar)
{ //rww - expected to have a parent, but sometime doesn't get set.
//I take it JK2's generic parser is not quite the same as SOF2's. Or is out of date.
parserpar = root;
}
if ( !ParseDifficulty ( parserdif, parserpar ) )
{
return false;
}
// Generate the terrain now
mLandScape->Generate(mSymmetric);
// Cleanup
parser.Clean();
return true;
}
/************************************************************************************************
* CRMMission::Spawn
* Spawns all of the instances for the entire mission onto the given landscape
*
* inputs:
* landscape: landscape to spawn instances on
*
* return:
* true: instances spawned successfully
* false: instances failed to spawn
*
************************************************************************************************/
bool CRMMission::Spawn ( CRandomTerrain* terrain, qboolean IsServer )
{
#ifndef PRE_RELEASE_DEMO
rmInstanceIter_t it;
int areaIndex;
CRMArea* area;
// Prespawn all instances, this is mainly for flattening
for(it = mInstances.begin(); it != mInstances.end(); it++)
{
CRMInstance* instance = *it;
// Pre-Spawn
instance->PreSpawn ( terrain, IsServer );
if (mSymmetric)
{
instance->SetMirror(1);
instance->PreSpawn ( terrain, IsServer );
instance->SetMirror(0);
}
}
mLandScape->Smooth ( );
// place bridges
PlaceBridges();
// create automap
// if (!com_dedicated->integer)
{
#ifndef DEDICATED
CM_TM_Create(mLandScape->GetLandScape());
#endif
}
mLandScape->GetLandScape()->UpdatePatches();
// Spawn all instances
for(it = mInstances.begin(); it != mInstances.end(); it++)
{
CRMInstance* instance = *it;
// Spawn
instance->Spawn ( terrain, IsServer );
instance->PostSpawn ( terrain, IsServer );
if (mSymmetric)
{ // spawn the mirror version
instance->SetMirror(1);
instance->Spawn ( terrain, IsServer );
instance->PostSpawn ( terrain, IsServer );
instance->SetMirror(0);
}
}
#ifndef FINAL_BUILD
// make sure to write out after the mirror happens so red side is displayed on map
if (1 == Cvar_VariableIntegerValue("rmg_saveautomap"))
{ // write out automap for test purposes
char seed[MAX_QPATH];
char terrainName[MAX_QPATH];
char missionName[MAX_QPATH];
Cvar_VariableStringBuffer("RMG_seed", seed, MAX_QPATH);
Cvar_VariableStringBuffer("RMG_terrain", terrainName, MAX_QPATH);
Cvar_VariableStringBuffer("RMG_mission", missionName, MAX_QPATH);
#ifndef DEDICATED
for(it = mInstances.begin(); it != mInstances.end(); it++)
{
(*it)->DrawAutomapSymbol();
}
//gi.CM_TM_SaveImageToDisk(terrainName, missionName, seed);
CM_TM_SaveImageToDisk(terrainName, missionName, seed);
#endif
Com_Error (ERR_DROP, "RMG Automap written.");
return false;
}
#endif
// // draw player start on automap
// CEntity *spot = NULL;
// spot = entitySystem->GetEntityFromClassname( spot, "info_player_start");
// if (spot)
// {
// gi.CM_TM_AddStart(spot->GetOrigin()[0], spot->GetOrigin()[1]);
// }
// Spawn NPC triggers now
// SpawnNPCTriggers ( mLandScape );
// Restory all the NPC's accuracies to the template accuracies times the
// multiplier
// INPCEnt::RestoreTemplate ( mAccuracyMultiplier, mHealthMultiplier );
// Little trick to set the current objective to the first in the list
CompleteObjective ( NULL );
// Iterate through the areas and add each to the landscapes list, this is sorta hacky
// but bridges the game / common gap
for ( areaIndex = 0; NULL != (area = mAreaManager->EnumArea ( areaIndex )); areaIndex ++ )
{
// Dont bother adding it to the list if collision isnt enabled
if ( !area->IsCollisionEnabled() )
{
continue;
}
CArea* newarea = new CArea ( );
newarea->Init ( area->GetOrigin(), area->GetSpacingRadius (), 0, area->IsFlattened()?AT_FLAT:AT_NONE );
mLandScape->GetLandScape()->SaveArea( newarea );
if (mSymmetric)
{
CArea* newarea = new CArea ( );
newarea->Init ( area->GetOrigin(), area->GetSpacingRadius (), 0, area->IsFlattened()?AT_FLAT:AT_NONE );
newarea->GetPosition()[0] = mLandScape->GetBounds ( )[0][0]+mLandScape->GetBounds ( )[1][0]-newarea->GetPosition()[0];
newarea->GetPosition()[1] = mLandScape->GetBounds ( )[0][1]+mLandScape->GetBounds ( )[1][1]-newarea->GetPosition()[1];
mLandScape->GetLandScape()->SaveArea( newarea );
}
}
mInstanceFile.Close ( );
#endif // PRE_RELEASE_DEMO
return true;
}
/************************************************************************************************
* CRMMission::CompleteMission
* Pauses the game, plays an end screen after a brief delay, which then returns the player to
* the RMG menu.
* *
* Input *
* <Variable>: <Description> *
* Output / Return *
* <Variable>: <Description> *
************************************************************************************************/
void CRMMission::CompleteMission(void)
{
Cvar_Set ("cl_paused", "1");
// AddText(va("killserver; menu %s\n", mExitScreen.c_str()));
return;
}
/************************************************************************************************
* CRMMission::FailedMission
* Pauses the game, plays an end screen after a brief delay, which then returns the player to
* the RMG menu.
* *
* Input *
* TimeExpired: indicates if the reason failed was because of time
* Output / Return *
* <Variable>: <Description> *
************************************************************************************************/
void CRMMission::FailedMission(bool TimeExpired)
{
Cvar_Set ("cl_paused", "1");
if (TimeExpired)
{
// AddText(va("killserver; menu %s\n", mTimeExpiredScreen.c_str()));
}
return;
}
/************************************************************************************************
* CRMMission::CompleteObjective
* Completes the given objective and advances the current objective accordingly
*
* inputs:
* objective: the objetive to mark complete
*
* return:
* none
*
************************************************************************************************/
void CRMMission::CompleteObjective ( CRMObjective* objective )
{
rmObjectiveIter_t it;
// Set the object as completed
if ( objective )
{
objective->Complete ( true );
// Set the completed text for the objective
// gi.Cvar_Set( va("ar_obj_subcom0_%i", objective->GetOrderIndex ( )), "&OBJECTIVES_COMPLETE&", CVAR_OBJECTIVE) ;
/* CEntity *tent = G_TempEntity( vec3_origin, EV_SUB_PRINT );
tent->s.time2 = gi.SP_GetStringID ( objective->GetMessage ( ) );
tent->r.svFlags |= SVF_BROADCAST;
G_AddTempEntity(tent);
if (objective->CompleteSoundID())
G_SoundBroadcast( tent, objective->CompleteSoundID());
*/
}
mCurrentObjective = NULL;
// Find the next objective
for (it = mObjectives.begin(); it != mObjectives.end(); it++)
{
objective = (*it);
// Skip completed objectives
if ( objective->IsCompleted ( ) )
{
continue;
}
// Find the objective with the lowest priority
if ( mCurrentObjective && objective->GetPriority ( ) > mCurrentObjective->GetPriority ( ) )
{
continue;
}
// Found one
mCurrentObjective = objective;
}
if ( NULL != mCurrentObjective )
{
// Cvar_SetValue ("ar_cur_objective", mCurrentObjective->GetOrderIndex ( ), CVAR_OBJECTIVE);
mCurrentObjective->Activate ( );
}
else
{
// Set the completed text for the objective
// Cvar_Set( "ar_obj_maincom0", "&OBJECTIVES_COMPLETE&", CVAR_OBJECTIVE) ;
}
}
/************************************************************************************************
* CRMMission::Preview
* Previews the instances within the mission
*
* inputs:
* from: the origin which the mission is being previewed from
*
* return:
* none
*
************************************************************************************************/
void CRMMission::Preview ( const vec3_t from )
{
rmInstanceIter_t it;
// Look for settlements close to the player and put up some debug stuff
for(it = mInstances.begin(); it != mInstances.end(); it++)
{
CRMInstance* instance = *it;
vec3_t a;
vec3_t b;
VectorCopy ( from, a );
VectorCopy ( instance->GetOrigin(), b );
a[2] = 0;
b[2] = 0;
// Skip stuff thats too far away
if ( Distance ( a, b) > 2000 )
{
continue;
}
instance->Preview ( from );
}
}
/************************************************************************************************
* CRMMission::PurgeTrigger
* Purge the trigger and all its targets
*
* inputs:
* trigger: trigger to purge
*
* return:
* none
*
************************************************************************************************/
/*void CRMMission::PurgeTrigger ( CEntity* trigger )
{
CEntity* target;
// Purge all targets
target = entitySystem->GetEntityFromTargetName ( NULL, trigger->GetTarget ( ) );
while ( target )
{
PurgeTrigger ( target );
target = entitySystem->GetEntityFromTargetName ( target, trigger->GetTarget ( ) );
}
// Get rid of the purge trigger
entitySystem->RemoveEntityWithServer ( trigger );
entitySystem->RemoveEntity ( trigger );
}
*/
/************************************************************************************************
* CRMMission::PurgeUnlinkedTriggers
* Searches the entitySystem form a random arioche trigger that matches the objective name
*
* inputs:
* none
*
* return:
* trigger: a random trigger or NULL if one couldnt be found
*
************************************************************************************************/
/*void CRMMission::PurgeUnlinkedTriggers ( )
{
CTriggerAriocheObjective* search;
// Start at the first match of the classname
search = (CTriggerAriocheObjective*) entitySystem->GetEntityFromClassname ( NULL, "trigger_arioche_objective" );
// Continue on as long as there are triggers
while ( search )
{
CTriggerAriocheObjective* purge = search;
// move on to the next trigger before deleting the entity
// just in case there are some state issues with the search
search = (CTriggerAriocheObjective*) entitySystem->GetEntityFromClassname ( search, "trigger_arioche_objective" );
// Dont purge linked triggers
if ( purge->GetObjective ( ) )
{
continue;
}
// Purge the trigger and all its targets
PurgeTrigger ( purge );
}
}
*/
/************************************************************************************************
* CRMMission::SpawnNPCTriggers
* Spawn triggers across the map which will activate sleeping NPCs
*
* inputs:
* landscape: landscape to spawn the triggers relative to
*
* return:
* trigger: a random trigger or NULL if one couldnt be found
*
************************************************************************************************/
/*void CRMMission::SpawnNPCTriggers ( CCMLandScape* landscape )
{
CEntity* ent;
int i;
int count;
float section;
// Determine how many NPC sections there are in the map
count = (landscape->GetBounds()[1][0] - landscape->GetBounds()[0][0]) / 5000.0f;
section = (landscape->GetBounds()[1][0] - landscape->GetBounds()[0][0]) / count;
// Drop a trigger down at each NPC section interval except for the first and last.
for ( i = 1; i < count - 1; i ++ )
{
vec3_t mins;
vec3_t maxs;
vec3_t origin;
VectorCopy ( landscape->GetBounds()[0], mins );
VectorCopy ( landscape->GetBounds()[1], maxs );
// Set up the mins and maxs for the trigger
mins[0] = mins[0] + (section * i) - 100;
maxs[0] = mins[0] + 100;
maxs[2] = maxs[2] + 100;
mins[2] = mins[2] - 100;
origin[0] = (maxs[0]-mins[0])/2 + mins[0];
origin[1] = (maxs[1]-mins[1])/2 + mins[1];
origin[2] = (maxs[2]-mins[2])/2 + mins[2];
spawnSystem->ClearSpawnFields();
spawnSystem->AddSpawnField("classname", "trigger_arioche_npcspawner" );
spawnSystem->AddSpawnField("origin", va("%f %f %f",origin[0],origin[1],origin[2]) );
spawnSystem->AddSpawnField("target", va("rmg_npc_%i", i + 1) );
// Spawn the inhabitant, if it fails then fail
ent = entitySystem->SpawnItem("trigger_arioche_npcspawner");
if ( !ent )
{
continue;
}
// Fail if we cant register the entity
if ( -1 == entitySystem->RegisterEntityWithServer( ent ) )
{
entitySystem->RemoveEntity ( ent );
continue;
}
// Normalize the mins and maxs for the X axis since they arent
// absolute mins and maxs
mins[0] = -100;
maxs[0] = 100;
// Adjust the absmin and absmax for the trigger now
VectorCopy ( mins, ent->r.mins[0] );
VectorCopy ( maxs, ent->r.maxs[0] );
Com_DPrintf( "NPC Trigger spawned at '%f %f %f' for targets 'rmg_npc_%i'\n", origin[0], origin[1], origin[2], i + 1 );
// Set the "ONLY_ONCE" spawn flag
ent->AddSpawnflags ( 2 );
#ifdef _GAME
// initial linking
gi.SV_LinkEntity( ent );
#endif
}
AttachNPCTriggers ( landscape );
}
*/
/************************************************************************************************
* CRMMission::AttachNPCTriggers
* Attaches npc triggers to all unattached npcs
*
* inputs:
* landscape: landscape triggers were spawned on
*
* return:
* trigger: a random trigger or NULL if one couldnt be found
*
************************************************************************************************/
/*void CRMMission::AttachNPCTriggers ( CCMLandScape* landscape )
{
TNPCList npcList;
TNPCFinder npcFinder;
CNPC* theNPC = 0;
int npcsegment;
GetCharacterManager().GetCharacterList(npcList);
// Loop through all npcs and reset their accuracy
for( npcFinder = npcList.begin(); npcFinder != npcList.end(); npcFinder++)
{
theNPC = (CNPC*) INPCEnt::GetEntity(*npcFinder);
if(!theNPC)
{
continue;
}
npcsegment = (theNPC->r.currentOrigin[0] - landscape->GetMins()[0]) / 5000.0f;
// All npcs in segment 0 and 1 are immediately spawned, all others wait for the
// trigger
if ( npcsegment > 1 )
{
entitySystem->RemoveFromTargetNameMap(theNPC);
theNPC->SetTargetName ( va("rmg_npc_%i", npcsegment ) );
entitySystem->AddToTargetNameMap(theNPC);
// Start the NPC in the off position
theNPC->SetSpawnflags(1);
theNPC->r.contents = 0;
theNPC->r.svFlags |= SVF_NOCLIENT;
theNPC->s.eFlags |= EF_NODRAW;
}
}
}
*/