Initial commit.
This commit is contained in:
480
code/RMG/RM_Area.cpp
Normal file
480
code/RMG/RM_Area.cpp
Normal file
@@ -0,0 +1,480 @@
|
||||
/************************************************************************************************
|
||||
*
|
||||
* Copyright (C) 2001-2002 Raven Software
|
||||
*
|
||||
* RM_Area.cpp
|
||||
*
|
||||
************************************************************************************************/
|
||||
|
||||
#include "../server/exe_headers.h"
|
||||
|
||||
#include "rm_headers.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma optimize("p", on)
|
||||
#endif
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMArea::CRMArea
|
||||
* constructor
|
||||
*
|
||||
* inputs:
|
||||
* none
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
CRMArea::CRMArea (
|
||||
float spacingRadius,
|
||||
float paddingSize,
|
||||
float confineRadius,
|
||||
vec3_t confineOrigin,
|
||||
vec3_t lookAtOrigin,
|
||||
bool flatten,
|
||||
int symmetric
|
||||
)
|
||||
{
|
||||
mMoveCount = 0;
|
||||
mAngle = 0;
|
||||
mCollision = true;
|
||||
mConfineRadius = confineRadius;
|
||||
mPaddingSize = paddingSize;
|
||||
mSpacingRadius = spacingRadius;
|
||||
mFlatten = flatten;
|
||||
mLookAt = true;
|
||||
mLockOrigin = false;
|
||||
mSymmetric = symmetric;
|
||||
mRadius = spacingRadius;
|
||||
|
||||
VectorCopy ( confineOrigin, mConfineOrigin );
|
||||
VectorCopy ( lookAtOrigin, mLookAtOrigin );
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMArea::LookAt
|
||||
* Angle the area towards the given point
|
||||
*
|
||||
* inputs:
|
||||
* lookat - the origin to look at
|
||||
*
|
||||
* return:
|
||||
* the angle in radians that was calculated
|
||||
*
|
||||
************************************************************************************************/
|
||||
float CRMArea::LookAt ( vec3_t lookat )
|
||||
{
|
||||
if (mLookAt)
|
||||
{ // this area orients itself towards a point
|
||||
vec3_t a;
|
||||
|
||||
VectorCopy ( lookat, mLookAtOrigin );
|
||||
VectorSubtract ( lookat, mOrigin, a );
|
||||
|
||||
mAngle = atan2 ( a[1], a[0] );
|
||||
}
|
||||
|
||||
return mAngle;
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMArea::Mirror
|
||||
* Mirrors the area to the other side of the map. This includes mirroring the confine origin
|
||||
* and lookat origin
|
||||
*
|
||||
* inputs:
|
||||
* none
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
void CRMArea::Mirror ( void )
|
||||
{
|
||||
mOrigin[0] = -mOrigin[0];
|
||||
mOrigin[1] = -mOrigin[1];
|
||||
|
||||
mConfineOrigin[0] = -mConfineOrigin[0];
|
||||
mConfineOrigin[1] = -mConfineOrigin[1];
|
||||
|
||||
mLookAtOrigin[0] = -mLookAtOrigin[0];
|
||||
mLookAtOrigin[1] = -mLookAtOrigin[1];
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMAreaManager::CRMAreaManager
|
||||
* constructor
|
||||
*
|
||||
* inputs:
|
||||
* none
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
CRMAreaManager::CRMAreaManager ( const vec3_t mins, const vec3_t maxs)
|
||||
{
|
||||
VectorCopy ( mins, mMins );
|
||||
VectorCopy ( maxs, mMaxs );
|
||||
|
||||
mWidth = mMaxs[0] - mMins[0];
|
||||
mHeight = mMaxs[1] - mMins[1];
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMAreaManager::~CRMAreaManager
|
||||
* Removes all managed areas
|
||||
*
|
||||
* inputs:
|
||||
* none
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
CRMAreaManager::~CRMAreaManager ( )
|
||||
{
|
||||
int i;
|
||||
|
||||
for ( i = mAreas.size() - 1; i >=0; i -- )
|
||||
{
|
||||
delete mAreas[i];
|
||||
}
|
||||
|
||||
mAreas.clear();
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMAreaManager::MoveArea
|
||||
* Moves an area within the area manager thus shifting any other areas as needed
|
||||
*
|
||||
* inputs:
|
||||
* area - area to be moved
|
||||
* origin - new origin to attempt to move to
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
void CRMAreaManager::MoveArea ( CRMArea* movedArea, vec3_t origin)
|
||||
{
|
||||
int index;
|
||||
int size;
|
||||
|
||||
// Increment the addcount (this is for infinite protection)
|
||||
movedArea->AddMoveCount ();
|
||||
|
||||
// Infinite recursion prevention
|
||||
if ( movedArea->GetMoveCount() > 250 )
|
||||
{
|
||||
// assert ( 0 );
|
||||
movedArea->EnableCollision ( false );
|
||||
return;
|
||||
}
|
||||
|
||||
// First set the area's origin, This may cause it to be in collision with
|
||||
// another area but that will get fixed later
|
||||
movedArea->SetOrigin ( origin );
|
||||
|
||||
// when symmetric we want to ensure that no instances end up on the "other" side of the imaginary diaganol that cuts the map in two
|
||||
// mSymmetric tells us which side of the map is legal
|
||||
if ( movedArea->GetSymmetric ( ) )
|
||||
{
|
||||
const vec3pair_t& bounds = TheRandomMissionManager->GetLandScape()->GetBounds();
|
||||
|
||||
vec3_t point;
|
||||
vec3_t dir;
|
||||
vec3_t tang;
|
||||
bool push;
|
||||
float len;
|
||||
|
||||
VectorSubtract( movedArea->GetOrigin(), bounds[0], point );
|
||||
VectorSubtract( bounds[1], bounds[0], dir );
|
||||
VectorNormalize(dir);
|
||||
|
||||
dir[2] = 0;
|
||||
point[2] = 0;
|
||||
VectorMA( bounds[0], DotProduct(point, dir), dir, tang );
|
||||
VectorSubtract ( movedArea->GetOrigin(), tang, dir );
|
||||
|
||||
dir[2] = 0;
|
||||
push = false;
|
||||
len = VectorNormalize(dir);
|
||||
|
||||
if ( len < movedArea->GetRadius ( ) )
|
||||
{
|
||||
if ( movedArea->GetLockOrigin ( ) )
|
||||
{
|
||||
movedArea->EnableCollision ( false );
|
||||
return;
|
||||
}
|
||||
|
||||
VectorMA ( point, (movedArea->GetSpacingRadius() - len) + TheRandomMissionManager->GetLandScape()->irand(10,movedArea->GetSpacingRadius()), dir, point );
|
||||
origin[0] = point[0] + bounds[0][0];
|
||||
origin[1] = point[1] + bounds[0][1];
|
||||
movedArea->SetOrigin ( origin );
|
||||
}
|
||||
|
||||
switch ( movedArea->GetSymmetric ( ) )
|
||||
{
|
||||
case SYMMETRY_TOPLEFT:
|
||||
if ( origin[1] > origin[0] )
|
||||
{
|
||||
movedArea->Mirror ( );
|
||||
}
|
||||
break;
|
||||
|
||||
case SYMMETRY_BOTTOMRIGHT:
|
||||
if ( origin[1] < origin[0] )
|
||||
{
|
||||
movedArea->Mirror ( );
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
// unknown symmetry type
|
||||
assert ( 0 );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Confine to area unless we are being pushed back by the same guy who pushed us last time (infinite loop)
|
||||
if ( movedArea->GetConfineRadius() )
|
||||
{
|
||||
if ( movedArea->GetMoveCount() < 25 )
|
||||
{
|
||||
vec3_t cdiff;
|
||||
float cdist;
|
||||
|
||||
VectorSubtract ( movedArea->GetOrigin(), movedArea->GetConfineOrigin(), cdiff );
|
||||
cdiff[2] = 0;
|
||||
cdist = VectorLength ( cdiff );
|
||||
|
||||
if ( cdist + movedArea->GetSpacingRadius() > movedArea->GetConfineRadius() )
|
||||
{
|
||||
cdist = movedArea->GetConfineRadius() - movedArea->GetSpacingRadius();
|
||||
VectorNormalize ( cdiff );
|
||||
|
||||
VectorMA ( movedArea->GetConfineOrigin(), cdist, cdiff, movedArea->GetOrigin());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// See if it fell off the world in the x direction
|
||||
if ( movedArea->GetOrigin()[0] + movedArea->GetSpacingRadius() > mMaxs[0] )
|
||||
movedArea->GetOrigin()[0] = mMaxs[0] - movedArea->GetSpacingRadius() - (TheRandomMissionManager->GetLandScape()->irand(10,200));
|
||||
else if ( movedArea->GetOrigin()[0] - movedArea->GetSpacingRadius() < mMins[0] )
|
||||
movedArea->GetOrigin()[0] = mMins[0] + movedArea->GetSpacingRadius() + (TheRandomMissionManager->GetLandScape()->irand(10,200));
|
||||
|
||||
// See if it fell off the world in the y direction
|
||||
if ( movedArea->GetOrigin()[1] + movedArea->GetSpacingRadius() > mMaxs[1] )
|
||||
movedArea->GetOrigin()[1] = mMaxs[1] - movedArea->GetSpacingRadius() - (TheRandomMissionManager->GetLandScape()->irand(10,200));
|
||||
else if ( movedArea->GetOrigin()[1] - movedArea->GetSpacingRadius() < mMins[1] )
|
||||
movedArea->GetOrigin()[1] = mMins[1] + movedArea->GetSpacingRadius() + (TheRandomMissionManager->GetLandScape()->irand(10,200));
|
||||
|
||||
// Look at what we need to look at
|
||||
movedArea->LookAt ( movedArea->GetLookAtOrigin() );
|
||||
|
||||
// Dont collide against things that have no collision
|
||||
// if ( !movedArea->IsCollisionEnabled ( ) )
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// See if its colliding
|
||||
for(index = 0, size = mAreas.size(); index < size; index ++ )
|
||||
{
|
||||
CRMArea *area = mAreas[index];
|
||||
vec3_t diff;
|
||||
vec3_t newOrigin;
|
||||
float dist;
|
||||
float targetdist;
|
||||
|
||||
// Skip the one that was moved in the first place
|
||||
if ( area == movedArea )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( area->GetLockOrigin ( ) && movedArea->GetLockOrigin( ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Dont collide against things that have no collision
|
||||
if ( !area->IsCollisionEnabled ( ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Grab the distance between the two
|
||||
// only want the horizontal distance -- dmv
|
||||
//dist = Distance ( movedArea->GetOrigin ( ), area->GetOrigin ( ));
|
||||
vec3_t maOrigin;
|
||||
vec3_t aOrigin;
|
||||
VectorCopy(movedArea->GetOrigin(), maOrigin);
|
||||
VectorCopy(area->GetOrigin(), aOrigin);
|
||||
maOrigin[2] = aOrigin[2] = 0;
|
||||
dist = Distance ( maOrigin, aOrigin );
|
||||
targetdist = movedArea->GetSpacingRadius() + area->GetSpacingRadius() + maximum(movedArea->GetPaddingSize(),area->GetPaddingSize());
|
||||
|
||||
if ( dist == 0 )
|
||||
{
|
||||
area->GetOrigin()[0] += (50 * (float)(TheRandomMissionManager->GetLandScape()->irand(0,99))/100.0f);
|
||||
area->GetOrigin()[1] += (50 * (float)(TheRandomMissionManager->GetLandScape()->irand(0,99))/100.0f);
|
||||
|
||||
VectorCopy(area->GetOrigin(), aOrigin);
|
||||
aOrigin[2] = 0;
|
||||
|
||||
dist = Distance ( maOrigin, aOrigin );
|
||||
}
|
||||
|
||||
// Are they are enough apart?
|
||||
if ( dist >= targetdist )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Dont move a step if locked
|
||||
if ( area->GetLockOrigin ( ) )
|
||||
{
|
||||
MoveArea ( area, area->GetOrigin ( ) );
|
||||
continue;
|
||||
}
|
||||
|
||||
// we got a collision, move the guy we hit
|
||||
VectorSubtract ( area->GetOrigin(), movedArea->GetOrigin(), diff );
|
||||
diff[2] = 0;
|
||||
VectorNormalize ( diff );
|
||||
|
||||
// Push by the difference in the distance and no-collide radius
|
||||
VectorMA ( area->GetOrigin(), targetdist - dist + 1 , diff, newOrigin );
|
||||
|
||||
// Move the area now
|
||||
MoveArea ( area, newOrigin );
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMAreaManager::CreateArea
|
||||
* Creates an area and adds it to the list of managed areas
|
||||
*
|
||||
* inputs:
|
||||
* none
|
||||
*
|
||||
* return:
|
||||
* a pointer to the newly added area class
|
||||
*
|
||||
************************************************************************************************/
|
||||
CRMArea* CRMAreaManager::CreateArea (
|
||||
vec3_t origin,
|
||||
float spacingRadius,
|
||||
int spacingLine,
|
||||
float paddingSize,
|
||||
float confineRadius,
|
||||
vec3_t confineOrigin,
|
||||
vec3_t lookAtOrigin,
|
||||
bool flatten,
|
||||
bool collide,
|
||||
bool lockorigin,
|
||||
int symmetric
|
||||
)
|
||||
{
|
||||
CRMArea* area = new CRMArea ( spacingRadius, paddingSize, confineRadius, confineOrigin, lookAtOrigin, flatten, symmetric );
|
||||
|
||||
if ( lockorigin || spacingLine )
|
||||
{
|
||||
area->LockOrigin ( );
|
||||
}
|
||||
|
||||
if (origin[0] != lookAtOrigin[0] || origin[1] != lookAtOrigin[1])
|
||||
area->EnableLookAt(true);
|
||||
|
||||
// First add the area to the list
|
||||
mAreas.push_back ( area );
|
||||
|
||||
area->EnableCollision(collide);
|
||||
|
||||
// Set the real radius which is used for center line detection
|
||||
if ( spacingLine )
|
||||
{
|
||||
area->SetRadius ( spacingRadius + (spacingLine - 1) * spacingRadius );
|
||||
}
|
||||
|
||||
// Now move the area around
|
||||
MoveArea ( area, origin );
|
||||
|
||||
if ( (origin[0] != lookAtOrigin[0] || origin[1] != lookAtOrigin[1]) )
|
||||
{
|
||||
int i;
|
||||
vec3_t linedir;
|
||||
vec3_t dir;
|
||||
vec3_t up = {0,0,1};
|
||||
vec3_t zerodvec;
|
||||
|
||||
VectorClear(zerodvec);
|
||||
|
||||
VectorSubtract ( lookAtOrigin, origin, dir );
|
||||
VectorNormalize ( dir );
|
||||
dir[2] = 0;
|
||||
CrossProduct ( dir, up, linedir );
|
||||
|
||||
for ( i = 0; i < spacingLine - 1; i ++ )
|
||||
{
|
||||
CRMArea* linearea;
|
||||
vec3_t lineorigin;
|
||||
|
||||
linearea = new CRMArea ( spacingRadius, paddingSize, 0, zerodvec, zerodvec, false, symmetric );
|
||||
linearea->LockOrigin ( );
|
||||
linearea->EnableCollision(collide);
|
||||
|
||||
VectorMA ( origin, spacingRadius + (spacingRadius * 2 * i), linedir, lineorigin );
|
||||
mAreas.push_back ( linearea );
|
||||
MoveArea ( linearea, lineorigin );
|
||||
|
||||
linearea = new CRMArea ( spacingRadius, paddingSize, 0, zerodvec, zerodvec, false, symmetric );
|
||||
linearea->LockOrigin ( );
|
||||
linearea->EnableCollision(collide);
|
||||
|
||||
VectorMA ( origin, -spacingRadius - (spacingRadius * 2 * i), linedir, lineorigin );
|
||||
mAreas.push_back ( linearea );
|
||||
MoveArea ( linearea, lineorigin );
|
||||
}
|
||||
}
|
||||
|
||||
// Return it for convienience
|
||||
return area;
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMAreaManager::EnumArea
|
||||
* Allows for enumeration through the area list. If an invalid index is given then NULL will
|
||||
* be returned;
|
||||
*
|
||||
* inputs:
|
||||
* index - current enumeration index
|
||||
*
|
||||
* return:
|
||||
* requested area class pointer or NULL if the index was invalid
|
||||
*
|
||||
************************************************************************************************/
|
||||
CRMArea* CRMAreaManager::EnumArea ( const int index )
|
||||
{
|
||||
// This isnt an assertion case because there is no size method for
|
||||
// the area manager so the areas are enumerated until NULL is returned.
|
||||
if ( index < 0 || index >= mAreas.size ( ) )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return mAreas[index];
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma optimize("p", off)
|
||||
#endif
|
||||
99
code/RMG/RM_Area.h
Normal file
99
code/RMG/RM_Area.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/************************************************************************************************
|
||||
*
|
||||
* Copyright (C) 2001-2002 Raven Software
|
||||
*
|
||||
* RM_Area.h
|
||||
*
|
||||
************************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
#if !defined(RM_AREA_H_INC)
|
||||
#define RM_AREA_H_INC
|
||||
|
||||
#ifdef DEBUG_LINKING
|
||||
#pragma message("...including RM_Area.h")
|
||||
#endif
|
||||
|
||||
class CRMArea
|
||||
{
|
||||
private:
|
||||
|
||||
float mPaddingSize;
|
||||
float mSpacingRadius;
|
||||
float mConfineRadius;
|
||||
float mRadius;
|
||||
float mAngle;
|
||||
int mMoveCount;
|
||||
vec3_t mOrigin;
|
||||
vec3_t mConfineOrigin;
|
||||
vec3_t mLookAtOrigin;
|
||||
bool mCollision;
|
||||
bool mFlatten;
|
||||
bool mLookAt;
|
||||
bool mLockOrigin;
|
||||
int mSymmetric;
|
||||
|
||||
public:
|
||||
|
||||
CRMArea ( float spacing, float padding, float confine, vec3_t confineOrigin, vec3_t lookAtOrigin, bool flatten = true, int symmetric = 0 );
|
||||
|
||||
void Mirror ( void );
|
||||
|
||||
void SetOrigin(vec3_t origin) { VectorCopy ( origin, mOrigin ); }
|
||||
void SetAngle(float angle) { mAngle = angle; }
|
||||
void SetSymmetric(int sym) { mSymmetric = sym; }
|
||||
|
||||
void EnableCollision(bool e) { mCollision = e; }
|
||||
void EnableLookAt(bool la) {mLookAt = la; }
|
||||
|
||||
float LookAt(vec3_t lookat);
|
||||
void LockOrigin( void ) { mLockOrigin = true; }
|
||||
|
||||
void AddMoveCount() { mMoveCount++; }
|
||||
void ClearMoveCount() { mMoveCount=0; }
|
||||
|
||||
float GetPaddingSize() { return mPaddingSize; }
|
||||
float GetSpacingRadius() { return mSpacingRadius; }
|
||||
float GetRadius() { return mRadius; }
|
||||
float GetConfineRadius() { return mConfineRadius; }
|
||||
float GetAngle() { return mAngle; }
|
||||
int GetMoveCount() { return mMoveCount; }
|
||||
vec_t* GetOrigin() { return mOrigin; }
|
||||
vec_t* GetConfineOrigin() { return mConfineOrigin; }
|
||||
vec_t* GetLookAtOrigin() { return mLookAtOrigin; }
|
||||
bool GetLookAt() { return mLookAt;}
|
||||
bool GetLockOrigin() { return mLockOrigin; }
|
||||
int GetSymmetric() { return mSymmetric; }
|
||||
|
||||
void SetRadius(float r) { mRadius = r; }
|
||||
|
||||
bool IsCollisionEnabled(){ return mCollision; }
|
||||
bool IsFlattened (){ return mFlatten; }
|
||||
};
|
||||
|
||||
typedef vector<CRMArea*> rmAreaVector_t;
|
||||
|
||||
class CRMAreaManager
|
||||
{
|
||||
private:
|
||||
|
||||
rmAreaVector_t mAreas;
|
||||
vec3_t mMins;
|
||||
vec3_t mMaxs;
|
||||
float mWidth;
|
||||
float mHeight;
|
||||
|
||||
public:
|
||||
|
||||
CRMAreaManager ( const vec3_t mins, const vec3_t maxs );
|
||||
~CRMAreaManager ( );
|
||||
|
||||
CRMArea* CreateArea ( vec3_t origin, float spacing, int spacingline, float padding, float confine, vec3_t confineOrigin, vec3_t lookAtOrigin, bool flatten=true, bool collide=true, bool lockorigin=false, int symmetric=0);
|
||||
void MoveArea ( CRMArea* area, vec3_t origin);
|
||||
CRMArea* EnumArea ( const int index );
|
||||
|
||||
// void CreateMap ( void );
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
71
code/RMG/RM_Headers.h
Normal file
71
code/RMG/RM_Headers.h
Normal file
@@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
#if !defined(RM_HEADERS_H_INC)
|
||||
#define RM_HEADERS_H_INC
|
||||
|
||||
#ifdef DEBUG_LINKING
|
||||
#pragma message("...including RM_Headers.h")
|
||||
#endif
|
||||
|
||||
#pragma warning (push, 3)
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#pragma warning (pop)
|
||||
|
||||
using namespace std;
|
||||
|
||||
#if !defined(GENERICPARSER2_H_INC)
|
||||
#include "../game/genericparser2.h"
|
||||
#endif
|
||||
|
||||
#if !defined(CM_LOCAL_H_INC)
|
||||
#include "../qcommon/cm_local.h"
|
||||
#endif
|
||||
|
||||
#define MAX_INSTANCE_TRIES 5
|
||||
|
||||
// on a symmetric map which corner is the first node
|
||||
typedef enum
|
||||
{
|
||||
SYMMETRY_NONE,
|
||||
SYMMETRY_TOPLEFT,
|
||||
SYMMETRY_BOTTOMRIGHT
|
||||
|
||||
} symmetry_t;
|
||||
|
||||
#if !defined(CM_TERRAINMAP_H_INC)
|
||||
#include "../qcommon/cm_terrainmap.h"
|
||||
#endif
|
||||
|
||||
#if !defined(RM_AREA_H_INC)
|
||||
#include "RM_Area.h"
|
||||
#endif
|
||||
|
||||
#if !defined(RM_PATH_H_INC)
|
||||
#include "RM_Path.h"
|
||||
#endif
|
||||
|
||||
#if !defined(RM_OBJECTIVE_H_INC)
|
||||
#include "RM_Objective.h"
|
||||
#endif
|
||||
|
||||
#if !defined(RM_INSTANCEFILE_H_INC)
|
||||
#include "RM_InstanceFile.h"
|
||||
#endif
|
||||
|
||||
#if !defined(RM_INSTANCE_H_INC)
|
||||
#include "RM_Instance.h"
|
||||
#endif
|
||||
|
||||
#if !defined(RM_MISSION_H_INC)
|
||||
#include "RM_Mission.h"
|
||||
#endif
|
||||
|
||||
#if !defined(RM_MANAGER_H_INC)
|
||||
#include "RM_Manager.h"
|
||||
#endif
|
||||
|
||||
#if !defined(RM_TERRAIN_H_INC)
|
||||
#include "RM_Terrain.h"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
191
code/RMG/RM_Instance.cpp
Normal file
191
code/RMG/RM_Instance.cpp
Normal file
@@ -0,0 +1,191 @@
|
||||
#include "../server/exe_headers.h"
|
||||
|
||||
#include "rm_headers.h"
|
||||
#include "../qcommon/cm_terrainmap.h"
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMInstance::CRMInstance
|
||||
* constructs a instnace object using the given parser group
|
||||
*
|
||||
* inputs:
|
||||
* instance: parser group containing information about the instance
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
CRMInstance::CRMInstance ( CGPGroup *instGroup, CRMInstanceFile& instFile )
|
||||
{
|
||||
mObjective = NULL;
|
||||
mSpacingRadius = 0;
|
||||
mFlattenRadius = 0;
|
||||
mFilter[0] = mTeamFilter[0] = 0;
|
||||
mArea = NULL;
|
||||
mAutomapSymbol = 0;
|
||||
mEntityID = 0;
|
||||
mSide = 0;
|
||||
mMirror = 0;
|
||||
mFlattenHeight = 66;
|
||||
mSpacingLine = 0;
|
||||
mSurfaceSprites = true;
|
||||
mLockOrigin = false;
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMInstance::PreSpawn
|
||||
* Prepares the instance for spawning by flattening the ground under it
|
||||
*
|
||||
* inputs:
|
||||
* landscape: landscape the instance will be spawned on
|
||||
*
|
||||
* return:
|
||||
* true: spawn preparation successful
|
||||
* false: spawn preparation failed
|
||||
*
|
||||
************************************************************************************************/
|
||||
bool CRMInstance::PreSpawn ( CRandomTerrain* terrain, qboolean IsServer )
|
||||
{
|
||||
vec3_t origin;
|
||||
CArea area;
|
||||
|
||||
VectorCopy(GetOrigin(), origin);
|
||||
|
||||
if (mMirror)
|
||||
{
|
||||
origin[0] = TheRandomMissionManager->GetLandScape()->GetBounds()[0][0] + TheRandomMissionManager->GetLandScape()->GetBounds()[1][0] - origin[0];
|
||||
origin[1] = TheRandomMissionManager->GetLandScape()->GetBounds()[0][1] + TheRandomMissionManager->GetLandScape()->GetBounds()[1][1] - origin[1];
|
||||
}
|
||||
|
||||
const vec3_t& terxelSize = terrain->GetLandScape()->GetTerxelSize ( );
|
||||
const vec3pair_t& bounds = terrain->GetLandScape()->GetBounds();
|
||||
|
||||
// Align the instance to the center of a terxel
|
||||
origin[0] = bounds[0][0] + (int)((origin[0] - bounds[0][0] + terxelSize[0] / 2) / terxelSize[0]) * terxelSize[0];
|
||||
origin[1] = bounds[0][1] + (int)((origin[1] - bounds[0][1] + terxelSize[1] / 2) / terxelSize[1]) * terxelSize[1];
|
||||
|
||||
|
||||
// This is BAD - By copying the mirrored origin back into the instance, you've now mirrored the original instance
|
||||
// so when anything from this point on looks at the instance they'll be looking at a mirrored version but will be expecting the original
|
||||
// so later in the spawn functions the instance will be re-mirrored, because it thinks the mInstances have not been changed
|
||||
// VectorCopy(origin, GetOrigin());
|
||||
|
||||
// Flatten the area below the instance
|
||||
if ( GetFlattenRadius() )
|
||||
{
|
||||
area.Init( origin, GetFlattenRadius(), 0.0f, AT_NONE, 0, 0 );
|
||||
terrain->GetLandScape()->FlattenArea( &area, mFlattenHeight | (mSurfaceSprites?0:0x80), false, true, true );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMInstance::PostSpawn
|
||||
* Finishes the spawn by linking any objectives into the world that are associated with it
|
||||
*
|
||||
* inputs:
|
||||
* landscape: landscape the instance was spawned on
|
||||
*
|
||||
* return:
|
||||
* true: post spawn successfull
|
||||
* false: post spawn failed
|
||||
*
|
||||
************************************************************************************************/
|
||||
bool CRMInstance::PostSpawn ( CRandomTerrain* terrain, qboolean IsServer )
|
||||
{
|
||||
if ( mObjective )
|
||||
{
|
||||
return mObjective->Link ( );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#ifndef DEDICATED
|
||||
void CRMInstance::DrawAutomapSymbol()
|
||||
{
|
||||
// draw proper symbol on map for instance
|
||||
switch (GetAutomapSymbol())
|
||||
{
|
||||
default:
|
||||
case AUTOMAP_NONE:
|
||||
if (HasObjective())
|
||||
CM_TM_AddObjective(GetOrigin()[0], GetOrigin()[1], GetSide());
|
||||
break;
|
||||
case AUTOMAP_BLD:
|
||||
CM_TM_AddBuilding(GetOrigin()[0], GetOrigin()[1], GetSide());
|
||||
if (HasObjective())
|
||||
CM_TM_AddObjective(GetOrigin()[0], GetOrigin()[1], GetSide());
|
||||
break;
|
||||
case AUTOMAP_OBJ:
|
||||
CM_TM_AddObjective(GetOrigin()[0], GetOrigin()[1], GetSide());
|
||||
break;
|
||||
case AUTOMAP_START:
|
||||
CM_TM_AddStart(GetOrigin()[0], GetOrigin()[1], GetSide());
|
||||
break;
|
||||
case AUTOMAP_END:
|
||||
CM_TM_AddEnd(GetOrigin()[0], GetOrigin()[1], GetSide());
|
||||
break;
|
||||
case AUTOMAP_ENEMY:
|
||||
if (HasObjective())
|
||||
CM_TM_AddObjective(GetOrigin()[0], GetOrigin()[1]);
|
||||
if (1 == Cvar_VariableIntegerValue("rmg_automapshowall"))
|
||||
CM_TM_AddNPC(GetOrigin()[0], GetOrigin()[1], false);
|
||||
break;
|
||||
case AUTOMAP_FRIEND:
|
||||
if (HasObjective())
|
||||
CM_TM_AddObjective(GetOrigin()[0], GetOrigin()[1]);
|
||||
if (1 == Cvar_VariableIntegerValue("rmg_automapshowall"))
|
||||
CM_TM_AddNPC(GetOrigin()[0], GetOrigin()[1], true);
|
||||
break;
|
||||
case AUTOMAP_WALL:
|
||||
CM_TM_AddWallRect(GetOrigin()[0], GetOrigin()[1], GetSide());
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif // !DEDICATED
|
||||
/************************************************************************************************
|
||||
* CRMInstance::Preview
|
||||
* Renderings debug information about the instance
|
||||
*
|
||||
* inputs:
|
||||
* none
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
void CRMInstance::Preview ( const vec3_t from )
|
||||
{
|
||||
/* CEntity *tent;
|
||||
|
||||
// Add a cylindar for the whole settlement
|
||||
tent = G_TempEntity( GetOrigin(), EV_DEBUG_CYLINDER );
|
||||
VectorCopy( GetOrigin(), tent->s.origin2 );
|
||||
tent->s.pos.trBase[2] += 40;
|
||||
tent->s.origin2[2] += 50;
|
||||
tent->s.time = 1050 + ((int)(GetSpacingRadius())<<16);
|
||||
tent->s.time2 = GetPreviewColor ( );
|
||||
G_AddTempEntity(tent);
|
||||
|
||||
// Origin line
|
||||
tent = G_TempEntity( GetOrigin ( ), EV_DEBUG_LINE );
|
||||
VectorCopy( GetOrigin(), tent->s.origin2 );
|
||||
tent->s.origin2[2] += 400;
|
||||
tent->s.time = 1050;
|
||||
tent->s.weapon = 10;
|
||||
tent->s.time2 = (255<<24) + (255<<16) + (255<<8) + 255;
|
||||
G_AddTempEntity(tent);
|
||||
|
||||
if ( GetFlattenRadius ( ) )
|
||||
{
|
||||
// Add a cylindar for the whole settlement
|
||||
tent = G_TempEntity( GetOrigin(), EV_DEBUG_CYLINDER );
|
||||
VectorCopy( GetOrigin(), tent->s.origin2 );
|
||||
tent->s.pos.trBase[2] += 40;
|
||||
tent->s.origin2[2] += 50;
|
||||
tent->s.time = 1050 + ((int)(GetFlattenRadius ( ))<<16);
|
||||
tent->s.time2 = (255<<24) + (80<<16) +(80<<8) + 80;
|
||||
G_AddTempEntity(tent);
|
||||
}
|
||||
*/
|
||||
}
|
||||
122
code/RMG/RM_Instance.h
Normal file
122
code/RMG/RM_Instance.h
Normal file
@@ -0,0 +1,122 @@
|
||||
#pragma once
|
||||
#if !defined(RM_INSTANCE_H_INC)
|
||||
#define RM_INSTANCE_H_INC
|
||||
|
||||
#ifdef DEBUG_LINKING
|
||||
#pragma message("...including RM_Instance.h")
|
||||
#endif
|
||||
|
||||
#if !defined(CM_LANDSCAPE_H_INC)
|
||||
#include "../qcommon/cm_landscape.h"
|
||||
#endif
|
||||
|
||||
enum CRMAutomapSymbol
|
||||
{
|
||||
AUTOMAP_NONE = 0,
|
||||
AUTOMAP_BLD = 1,
|
||||
AUTOMAP_OBJ = 2,
|
||||
AUTOMAP_START= 3,
|
||||
AUTOMAP_END = 4,
|
||||
AUTOMAP_ENEMY= 5,
|
||||
AUTOMAP_FRIEND=6,
|
||||
AUTOMAP_WALL=7
|
||||
};
|
||||
|
||||
class CRMInstance
|
||||
{
|
||||
protected:
|
||||
char mFilter[MAX_QPATH]; // filter of entities inside of this
|
||||
char mTeamFilter[MAX_QPATH]; // team specific filter
|
||||
|
||||
vec3pair_t mBounds; // Bounding box for instance itself
|
||||
|
||||
CRMArea* mArea; // Position of the instance
|
||||
|
||||
CRMObjective* mObjective; // Objective associated with this instance
|
||||
|
||||
// optional instance specific strings for objective
|
||||
string mMessage; // message outputed when objective is completed
|
||||
string mDescription; // description of objective
|
||||
string mInfo; // more info for objective
|
||||
|
||||
float mSpacingRadius; // Radius to space instances with
|
||||
float mFlattenRadius; // Radius to flatten under instances
|
||||
|
||||
int mSpacingLine; // Line of spacing radius's, forces locket
|
||||
bool mLockOrigin; // Origin cant move
|
||||
|
||||
bool mSurfaceSprites; // allow surface sprites under instance?
|
||||
|
||||
int mAutomapSymbol; // show which symbol on automap 0=none
|
||||
|
||||
int mEntityID; // id of entity spawned
|
||||
int mSide; // blue or red side
|
||||
int mMirror; // mirror origin, angle
|
||||
|
||||
int mFlattenHeight; // height to flatten land
|
||||
|
||||
public:
|
||||
|
||||
CRMInstance ( CGPGroup* instance, CRMInstanceFile& instFile);
|
||||
|
||||
virtual ~CRMInstance ( ) { }
|
||||
|
||||
virtual bool IsValid ( ) { return true; }
|
||||
|
||||
virtual bool PreSpawn ( CRandomTerrain* terrain, qboolean IsServer );
|
||||
virtual bool Spawn ( CRandomTerrain* terrain, qboolean IsServer ) { return false; }
|
||||
virtual bool PostSpawn ( CRandomTerrain* terrain, qboolean IsServer );
|
||||
|
||||
virtual void Preview ( const vec3_t from );
|
||||
|
||||
virtual void SetArea ( CRMAreaManager* amanager, CRMArea* area ) { mArea = area; }
|
||||
virtual void SetFilter ( const char *filter ) { strcpy(mFilter, filter); }
|
||||
virtual void SetTeamFilter ( const char *teamFilter ) { strcpy(mTeamFilter, teamFilter); }
|
||||
void SetObjective ( CRMObjective* obj ) { mObjective = obj; }
|
||||
CRMObjective* GetObjective (void) {return mObjective;}
|
||||
bool HasObjective () {return mObjective != NULL;}
|
||||
int GetAutomapSymbol () {return mAutomapSymbol;}
|
||||
void DrawAutomapSymbol ();
|
||||
const char* GetMessage(void) { return mMessage.c_str(); }
|
||||
const char* GetDescription(void){ return mDescription.c_str(); }
|
||||
const char* GetInfo(void) { return mInfo.c_str(); }
|
||||
void SetMessage(const char* msg) { mMessage = msg; }
|
||||
void SetDescription(const char* desc) { mDescription = desc; }
|
||||
void SetInfo(const char* info) { mInfo = info; }
|
||||
void SetSide(int side) {mSide = side;}
|
||||
int GetSide ( ) {return mSide;}
|
||||
|
||||
// NOTE: should consider making SetMirror also set all other variables that need flipping
|
||||
// like the origin and Side, etc... Otherwise an Instance may have had it's origin flipped
|
||||
// but then later will have mMirror set to false, but the origin is still flipped. So any functions
|
||||
// that look at the instance later will see mMirror set to false, but not realize the origin has ALREADY been flipped
|
||||
virtual void SetMirror(int mirror) { mMirror = mirror;}
|
||||
int GetMirror ( ) { return mMirror;}
|
||||
|
||||
virtual bool GetSurfaceSprites ( ) { return mSurfaceSprites; }
|
||||
|
||||
virtual bool GetLockOrigin ( ) { return mLockOrigin; }
|
||||
virtual int GetSpacingLine ( ) { return mSpacingLine; }
|
||||
|
||||
virtual int GetPreviewColor ( ) { return 0; }
|
||||
virtual float GetSpacingRadius ( ) { return mSpacingRadius; }
|
||||
virtual float GetFlattenRadius ( ) { return mFlattenRadius; }
|
||||
const char *GetFilter ( ) { return mFilter; }
|
||||
const char *GetTeamFilter ( ) { return mTeamFilter; }
|
||||
|
||||
CRMArea& GetArea ( ) { return *mArea; }
|
||||
vec_t* GetOrigin ( ) {return mArea->GetOrigin(); }
|
||||
float GetAngle ( ) {return mArea->GetAngle();}
|
||||
void SetAngle(float ang ) { mArea->SetAngle(ang);}
|
||||
const vec3pair_t& GetBounds(void) const { return(mBounds); }
|
||||
|
||||
void SetFlattenHeight ( int height ) { mFlattenHeight = height; }
|
||||
int GetFlattenHeight ( void ) { return mFlattenHeight; }
|
||||
|
||||
void SetSpacingRadius (float spacing) { mSpacingRadius = spacing; }
|
||||
};
|
||||
|
||||
typedef list<CRMInstance*>::iterator rmInstanceIter_t;
|
||||
typedef list<CRMInstance*> rmInstanceList_t;
|
||||
|
||||
#endif
|
||||
200
code/RMG/RM_InstanceFile.cpp
Normal file
200
code/RMG/RM_InstanceFile.cpp
Normal file
@@ -0,0 +1,200 @@
|
||||
/************************************************************************************************
|
||||
*
|
||||
* RM_InstanceFile.cpp
|
||||
*
|
||||
* implements the CRMInstanceFile class. This class provides functionality to load
|
||||
* and create instances from an instance file. First call Open to open the instance file and
|
||||
* then use CreateInstance to create new instances. When finished call Close to cleanup.
|
||||
*
|
||||
************************************************************************************************/
|
||||
|
||||
#include "../server/exe_headers.h"
|
||||
|
||||
#include "rm_headers.h"
|
||||
|
||||
//#include "rm_instance_npc.h"
|
||||
#include "rm_instance_bsp.h"
|
||||
#include "rm_instance_random.h"
|
||||
#include "rm_instance_group.h"
|
||||
#include "rm_instance_void.h"
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMInstanceFile::CRMInstanceFile
|
||||
* constructor
|
||||
*
|
||||
* inputs:
|
||||
* none
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
CRMInstanceFile::CRMInstanceFile ( )
|
||||
{
|
||||
mInstances = NULL;
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMInstanceFile::~CRMInstanceFile
|
||||
* Destroys the instance file by freeing the parser
|
||||
*
|
||||
* inputs:
|
||||
* none
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
CRMInstanceFile::~CRMInstanceFile ( )
|
||||
{
|
||||
Close ( );
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMInstanceFile::Open
|
||||
* Opens the given instance file and prepares it for use in instance creation
|
||||
*
|
||||
* inputs:
|
||||
* instance: Name of instance to open. Note that the root path will be automatically
|
||||
* added and shouldnt be included in the given name
|
||||
*
|
||||
* return:
|
||||
* true: instance file successfully loaded
|
||||
* false: instance file could not be loaded for some reason
|
||||
*
|
||||
************************************************************************************************/
|
||||
bool CRMInstanceFile::Open ( const char* instance )
|
||||
{
|
||||
char instanceDef[MAX_QPATH];
|
||||
CGPGroup *basegroup;
|
||||
|
||||
// Build the filename
|
||||
Com_sprintf(instanceDef, MAX_QPATH, "ext_data/rmg/%s.instance", instance );
|
||||
|
||||
#ifndef FINAL_BUILD
|
||||
// Debug message
|
||||
Com_Printf("CM_Terrain: Loading and parsing instanceDef %s.....\n", instance);
|
||||
#endif
|
||||
|
||||
// Parse the text file using the generic parser
|
||||
if(!Com_ParseTextFile(instanceDef, mParser ))
|
||||
{
|
||||
Com_sprintf(instanceDef, MAX_QPATH, "ext_data/arioche/%s.instance", instance );
|
||||
if(!Com_ParseTextFile(instanceDef, mParser ))
|
||||
{
|
||||
Com_Printf(va("CM_Terrain: Could not open instance file '%s'\n", instanceDef));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// The whole file....
|
||||
basegroup = mParser.GetBaseParseGroup();
|
||||
|
||||
// The root { } struct
|
||||
mInstances = basegroup->GetSubGroups();
|
||||
|
||||
// The "instances" { } structure
|
||||
mInstances = mInstances->GetSubGroups ( );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMInstanceFile::Close
|
||||
* Closes an open instance file
|
||||
*
|
||||
* inputs:
|
||||
* none
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
void CRMInstanceFile::Close ( void )
|
||||
{
|
||||
// If not open then dont close it
|
||||
if ( NULL == mInstances )
|
||||
{
|
||||
return;
|
||||
}
|
||||
mParser.Clean();
|
||||
|
||||
mInstances = NULL;
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMInstanceFile::CreateInstance
|
||||
* Creates an instance (to be freed by caller) using the given instance name.
|
||||
*
|
||||
* inputs:
|
||||
* name: Name of the instance to read from the instance file
|
||||
*
|
||||
* return:
|
||||
* NULL: instance could not be read from the instance file
|
||||
* NON-NULL: instance created and returned for further use
|
||||
*
|
||||
************************************************************************************************/
|
||||
CRMInstance* CRMInstanceFile::CreateInstance ( const char* name )
|
||||
{
|
||||
static int instanceID = 0;
|
||||
|
||||
CGPGroup* group;
|
||||
CRMInstance* instance;
|
||||
|
||||
// Make sure we were loaded
|
||||
assert ( mInstances );
|
||||
|
||||
// Search through the instances for the one with the given name
|
||||
for ( group = mInstances; group; group = group->GetNext ( ) )
|
||||
{
|
||||
// Skip it if the name doesnt match
|
||||
if ( stricmp ( name, group->FindPairValue ( "name", "" ) ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle the various forms of instance types
|
||||
if ( !stricmp ( group->GetName ( ), "bsp" ) )
|
||||
{
|
||||
instance = new CRMBSPInstance ( group, *this );
|
||||
}
|
||||
else if ( !stricmp ( group->GetName ( ), "npc" ) )
|
||||
{
|
||||
// instance = new CRMNPCInstance ( group, *this );
|
||||
continue;
|
||||
}
|
||||
else if ( !stricmp ( group->GetName ( ), "group" ) )
|
||||
{
|
||||
instance = new CRMGroupInstance ( group, *this );
|
||||
}
|
||||
else if ( !stricmp ( group->GetName ( ), "random" ) )
|
||||
{
|
||||
instance = new CRMRandomInstance ( group, *this );
|
||||
}
|
||||
else if ( !stricmp ( group->GetName ( ), "void" ) )
|
||||
{
|
||||
instance = new CRMVoidInstance ( group, *this );
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the instance isnt valid after being created then delete it
|
||||
if ( !instance->IsValid ( ) )
|
||||
{
|
||||
delete instance;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// The instance was successfully created so return it
|
||||
return instance;
|
||||
}
|
||||
|
||||
#ifndef FINAL_BUILD
|
||||
// The instance wasnt found in the file so report it
|
||||
Com_Printf(va("WARNING: Instance '%s' was not found in the active instance file\n", name ));
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
28
code/RMG/RM_InstanceFile.h
Normal file
28
code/RMG/RM_InstanceFile.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#if !defined(RM_INSTANCEFILE_H_INC)
|
||||
#define RM_INSTANCEFILE_H_INC
|
||||
|
||||
#ifdef DEBUG_LINKING
|
||||
#pragma message("...including RM_InstanceFile.h")
|
||||
#endif
|
||||
|
||||
class CRMInstance;
|
||||
|
||||
class CRMInstanceFile
|
||||
{
|
||||
public:
|
||||
|
||||
CRMInstanceFile ( );
|
||||
~CRMInstanceFile ( );
|
||||
|
||||
bool Open ( const char* instance );
|
||||
void Close ( void );
|
||||
CRMInstance* CreateInstance ( const char* name );
|
||||
|
||||
protected:
|
||||
|
||||
CGenericParser2 mParser;
|
||||
CGPGroup* mInstances;
|
||||
};
|
||||
|
||||
#endif
|
||||
294
code/RMG/RM_Instance_BSP.cpp
Normal file
294
code/RMG/RM_Instance_BSP.cpp
Normal file
@@ -0,0 +1,294 @@
|
||||
/************************************************************************************************
|
||||
*
|
||||
* RM_Instance_BSP.cpp
|
||||
*
|
||||
* Implements the CRMBSPInstance class. This class is reponsible for parsing a
|
||||
* bsp instance as well as spawning it into a landscape.
|
||||
*
|
||||
************************************************************************************************/
|
||||
|
||||
#include "../server/exe_headers.h"
|
||||
|
||||
#include "../qcommon/cm_local.h"
|
||||
#include "../server/server.h"
|
||||
#include "rm_headers.h"
|
||||
|
||||
#include "rm_instance_bsp.h"
|
||||
|
||||
#include "../client/vmachine.h"
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMBSPInstance::CRMBSPInstance
|
||||
* constructs a building instance object using the given parser group
|
||||
*
|
||||
* inputs:
|
||||
* instance: parser group containing information about the building instance
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
CRMBSPInstance::CRMBSPInstance(CGPGroup *instGroup, CRMInstanceFile& instFile) : CRMInstance ( instGroup, instFile )
|
||||
{
|
||||
strcpy(mBsp, instGroup->FindPairValue("file", ""));
|
||||
|
||||
mAngleVariance = DEG2RAD(atof(instGroup->FindPairValue("anglevariance", "0")));
|
||||
mBaseAngle = DEG2RAD(atof(instGroup->FindPairValue("baseangle", "0")));
|
||||
mAngleDiff = DEG2RAD(atof(instGroup->FindPairValue("anglediff", "0")));
|
||||
mSpacingRadius = atof( instGroup->FindPairValue ( "spacing", "100" ) );
|
||||
mSpacingLine = atoi( instGroup->FindPairValue ( "spacingline", "0" ) );
|
||||
mSurfaceSprites = (!Q_stricmp ( instGroup->FindPairValue ( "surfacesprites", "no" ), "yes")) ? true : false;
|
||||
mLockOrigin = (!Q_stricmp ( instGroup->FindPairValue ( "lockorigin", "no" ), "yes")) ? true : false;
|
||||
mFlattenRadius = atof( instGroup->FindPairValue ( "flatten", "0" ) );
|
||||
mHoleRadius = atof( instGroup->FindPairValue ( "hole", "0" ) );
|
||||
|
||||
const char * automapSymName = instGroup->FindPairValue ( "automap_symbol", "building" );
|
||||
if (0 == strcmpi(automapSymName, "none")) mAutomapSymbol = AUTOMAP_NONE ;
|
||||
else if (0 == strcmpi(automapSymName, "building")) mAutomapSymbol = AUTOMAP_BLD ;
|
||||
else if (0 == strcmpi(automapSymName, "objective")) mAutomapSymbol = AUTOMAP_OBJ ;
|
||||
else if (0 == strcmpi(automapSymName, "start")) mAutomapSymbol = AUTOMAP_START;
|
||||
else if (0 == strcmpi(automapSymName, "end")) mAutomapSymbol = AUTOMAP_END ;
|
||||
else if (0 == strcmpi(automapSymName, "enemy")) mAutomapSymbol = AUTOMAP_ENEMY;
|
||||
else if (0 == strcmpi(automapSymName, "friend")) mAutomapSymbol = AUTOMAP_FRIEND;
|
||||
else if (0 == strcmpi(automapSymName, "wall")) mAutomapSymbol = AUTOMAP_WALL;
|
||||
else mAutomapSymbol = atoi( automapSymName );
|
||||
|
||||
// optional instance objective strings
|
||||
SetMessage(instGroup->FindPairValue("objective_message",""));
|
||||
SetDescription(instGroup->FindPairValue("objective_description",""));
|
||||
SetInfo(instGroup->FindPairValue("objective_info",""));
|
||||
|
||||
mBounds[0][0] = 0;
|
||||
mBounds[0][1] = 0;
|
||||
mBounds[1][0] = 0;
|
||||
mBounds[1][1] = 0;
|
||||
|
||||
mBaseAngle += (TheRandomMissionManager->GetLandScape()->irand(0,mAngleVariance) - mAngleVariance/2);
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMBSPInstance::Spawn
|
||||
* spawns a bsp into the world using the previously aquired origin
|
||||
*
|
||||
* inputs:
|
||||
* none
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
bool CRMBSPInstance::Spawn ( CRandomTerrain* terrain, qboolean IsServer)
|
||||
{
|
||||
#ifndef PRE_RELEASE_DEMO
|
||||
// TEntity* ent;
|
||||
float yaw;
|
||||
char temp[10000];
|
||||
char *savePtr;
|
||||
vec3_t origin;
|
||||
vec3_t notmirrored;
|
||||
float water_level = terrain->GetLandScape()->GetWaterHeight();
|
||||
|
||||
const vec3_t& terxelSize = terrain->GetLandScape()->GetTerxelSize ( );
|
||||
const vec3pair_t& bounds = terrain->GetLandScape()->GetBounds();
|
||||
|
||||
// If this entity somehow lost its collision flag then boot it
|
||||
if ( !GetArea().IsCollisionEnabled ( ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// copy out the unmirrored version
|
||||
VectorCopy(GetOrigin(), notmirrored);
|
||||
|
||||
// we want to mirror it before determining the Z value just in case the landscape isn't perfectly mirrored
|
||||
if (mMirror)
|
||||
{
|
||||
GetOrigin()[0] = TheRandomMissionManager->GetLandScape()->GetBounds()[0][0] + TheRandomMissionManager->GetLandScape()->GetBounds()[1][0] - GetOrigin()[0];
|
||||
GetOrigin()[1] = TheRandomMissionManager->GetLandScape()->GetBounds()[0][1] + TheRandomMissionManager->GetLandScape()->GetBounds()[1][1] - GetOrigin()[1];
|
||||
}
|
||||
|
||||
// Align the instance to the center of a terxel
|
||||
GetOrigin ( )[0] = bounds[0][0] + (int)((GetOrigin ( )[0] - bounds[0][0] + terxelSize[0] / 2) / terxelSize[0]) * terxelSize[0];
|
||||
GetOrigin ( )[1] = bounds[0][1] + (int)((GetOrigin ( )[1] - bounds[0][1] + terxelSize[1] / 2) / terxelSize[1]) * terxelSize[1];
|
||||
|
||||
// Make sure the bsp is resting on the ground, not below or above it
|
||||
// NOTE: This check is basically saying "is this instance not a bridge", because when instances are created they are all
|
||||
// placed above the world's Z boundary, EXCEPT FOR BRIDGES. So this call to GetWorldHeight will move all other instances down to
|
||||
// ground level except bridges
|
||||
if ( GetOrigin()[2] > terrain->GetBounds()[1][2] )
|
||||
{
|
||||
if( GetFlattenRadius() )
|
||||
{
|
||||
terrain->GetLandScape()->GetWorldHeight ( GetOrigin(), GetBounds ( ), false );
|
||||
GetOrigin()[2] += 5;
|
||||
}
|
||||
else if (IsServer)
|
||||
{ // if this instance does not flatten the ground around it, do a trace to more accurately determine its Z value
|
||||
trace_t tr;
|
||||
vec3_t end;
|
||||
vec3_t start;
|
||||
|
||||
VectorCopy(GetOrigin(), end);
|
||||
VectorCopy(GetOrigin(), start);
|
||||
// start the trace below the top height of the landscape
|
||||
start[2] = TheRandomMissionManager->GetLandScape()->GetBounds()[1][2] - 1;
|
||||
// end the trace at the bottom of the world
|
||||
end[2] = MIN_WORLD_COORD;
|
||||
|
||||
memset ( &tr, 0, sizeof ( tr ) );
|
||||
SV_Trace( &tr, start, vec3_origin, vec3_origin, end, ENTITYNUM_NONE, CONTENTS_TERRAIN|CONTENTS_SOLID, G2_NOCOLLIDE, 0); //qfalse, 0, 10 );
|
||||
|
||||
if( !(tr.contents & CONTENTS_TERRAIN) || (tr.fraction == 1.0) )
|
||||
{
|
||||
if ( 0 )
|
||||
assert(0); // this should never happen
|
||||
|
||||
// restore the unmirrored origin
|
||||
VectorCopy( notmirrored, GetOrigin() );
|
||||
// don't spawn
|
||||
return false;
|
||||
}
|
||||
// assign the Z-value to wherever it hit the terrain
|
||||
GetOrigin()[2] = tr.endpos[2];
|
||||
// lower it a little, otherwise the bottom of the instance might be exposed if on some weird sloped terrain
|
||||
GetOrigin()[2] -= 16; // FIXME: would it be better to use a number related to the instance itself like 1/5 it's height or something...
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
terrain->GetLandScape()->GetWorldHeight ( GetOrigin(), GetBounds ( ), true );
|
||||
}
|
||||
|
||||
// save away the origin
|
||||
VectorCopy(GetOrigin(), origin);
|
||||
// make sure not to spawn if in water
|
||||
if (!HasObjective() && GetOrigin()[2] < water_level)
|
||||
return false;
|
||||
// restore the origin
|
||||
VectorCopy(origin, GetOrigin());
|
||||
|
||||
if (mMirror)
|
||||
{ // change blue things to red for symmetric maps
|
||||
if (strlen(mFilter) > 0)
|
||||
{
|
||||
char * blue = strstr(mFilter,"blue");
|
||||
if (blue)
|
||||
{
|
||||
blue[0] = (char) 0;
|
||||
strcat(mFilter, "red");
|
||||
SetSide(SIDE_RED);
|
||||
}
|
||||
}
|
||||
if (strlen(mTeamFilter) > 0)
|
||||
{
|
||||
char * blue = strstr(mTeamFilter,"blue");
|
||||
if (blue)
|
||||
{
|
||||
strcpy(mTeamFilter, "red");
|
||||
SetSide(SIDE_RED);
|
||||
}
|
||||
}
|
||||
yaw = RAD2DEG(mArea->GetAngle() + mBaseAngle) + 180;
|
||||
}
|
||||
else
|
||||
{
|
||||
yaw = RAD2DEG(mArea->GetAngle() + mBaseAngle);
|
||||
}
|
||||
|
||||
/*
|
||||
if( TheRandomMissionManager->GetMission()->GetSymmetric() )
|
||||
{
|
||||
vec3_t diagonal;
|
||||
vec3_t lineToPoint;
|
||||
vec3_t mins;
|
||||
vec3_t maxs;
|
||||
vec3_t point;
|
||||
vec3_t vProj;
|
||||
vec3_t vec;
|
||||
float distance;
|
||||
|
||||
VectorCopy( TheRandomMissionManager->GetLandScape()->GetBounds()[1], maxs );
|
||||
VectorCopy( TheRandomMissionManager->GetLandScape()->GetBounds()[0], mins );
|
||||
VectorCopy( GetOrigin(), point );
|
||||
mins[2] = maxs[2] = point[2] = 0;
|
||||
VectorSubtract( point, mins, lineToPoint );
|
||||
VectorSubtract( maxs, mins, diagonal);
|
||||
|
||||
|
||||
VectorNormalize(diagonal);
|
||||
VectorMA( mins, DotProduct(lineToPoint, diagonal), diagonal, vProj);
|
||||
VectorSubtract(point, vProj, vec );
|
||||
distance = VectorLength(vec);
|
||||
|
||||
// if an instance is too close to the imaginary diagonal that cuts the world in half, don't spawn it
|
||||
// otherwise you can get overlapping instances
|
||||
if( distance < GetSpacingRadius() )
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
mAutomapSymbol = AUTOMAP_END;
|
||||
#endif
|
||||
if( !HasObjective() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// Spawn in the bsp model
|
||||
sprintf(temp,
|
||||
"{\n"
|
||||
"\"classname\" \"misc_bsp\"\n"
|
||||
"\"bspmodel\" \"%s\"\n"
|
||||
"\"origin\" \"%f %f %f\"\n"
|
||||
"\"angles\" \"0 %f 0\"\n"
|
||||
"\"filter\" \"%s\"\n"
|
||||
"\"teamfilter\" \"%s\"\n"
|
||||
"\"spacing\" \"%d\"\n"
|
||||
"\"flatten\" \"%d\"\n"
|
||||
"}\n",
|
||||
mBsp,
|
||||
GetOrigin()[0], GetOrigin()[1], GetOrigin()[2],
|
||||
AngleNormalize360(yaw),
|
||||
mFilter,
|
||||
mTeamFilter,
|
||||
(int)GetSpacingRadius(),
|
||||
(int)GetFlattenRadius()
|
||||
);
|
||||
|
||||
if (IsServer)
|
||||
{ // only allow for true spawning on the server
|
||||
savePtr = sv.entityParsePoint;
|
||||
sv.entityParsePoint = temp;
|
||||
// VM_Call( cgvm, GAME_SPAWN_RMG_ENTITY );
|
||||
// char *s;
|
||||
int bufferSize = 1024;
|
||||
char buffer[1024];
|
||||
|
||||
// s = COM_Parse( (const char **)&sv.entityParsePoint );
|
||||
Q_strncpyz( buffer, sv.entityParsePoint, bufferSize );
|
||||
if ( sv.entityParsePoint && sv.entityParsePoint[0] )
|
||||
{
|
||||
ge->GameSpawnRMGEntity(sv.entityParsePoint);
|
||||
}
|
||||
sv.entityParsePoint = savePtr;
|
||||
}
|
||||
|
||||
|
||||
#ifndef DEDICATED
|
||||
DrawAutomapSymbol();
|
||||
#endif
|
||||
Com_DPrintf( "RMG: Building '%s' spawned at (%f %f %f)\n", mBsp, GetOrigin()[0], GetOrigin()[1], GetOrigin()[2] );
|
||||
// now restore the instances un-mirrored origin
|
||||
// NOTE: all this origin flipping, setting the side etc... should be done when mMirror is set
|
||||
// because right after this function is called, mMirror is set to 0 but all the instance data is STILL MIRRORED -- not good
|
||||
VectorCopy(notmirrored, GetOrigin());
|
||||
|
||||
#endif // PRE_RELEASE_DEMO
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
35
code/RMG/RM_Instance_BSP.h
Normal file
35
code/RMG/RM_Instance_BSP.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
#if !defined(RM_INSTANCE_BSP_H_INC)
|
||||
#define RM_INSTANCE_BSP_H_INC
|
||||
|
||||
#ifdef DEBUG_LINKING
|
||||
#pragma message("...including RM_Instance_BSP.h")
|
||||
#endif
|
||||
|
||||
class CRMBSPInstance : public CRMInstance
|
||||
{
|
||||
private:
|
||||
|
||||
char mBsp[MAX_QPATH];
|
||||
float mAngleVariance;
|
||||
float mBaseAngle;
|
||||
float mAngleDiff;
|
||||
|
||||
float mHoleRadius;
|
||||
|
||||
public:
|
||||
|
||||
CRMBSPInstance ( CGPGroup *instance, CRMInstanceFile& instFile );
|
||||
|
||||
virtual int GetPreviewColor ( ) { return (255<<24)+255; }
|
||||
|
||||
virtual float GetHoleRadius ( ) { return mHoleRadius; }
|
||||
|
||||
virtual bool Spawn ( CRandomTerrain* terrain, qboolean IsServer );
|
||||
|
||||
const char* GetModelName (void) const { return(mBsp); }
|
||||
float GetAngleDiff (void) const { return(mAngleDiff); }
|
||||
bool GetAngularType (void) const { return(mAngleDiff != 0.0f); }
|
||||
};
|
||||
|
||||
#endif
|
||||
343
code/RMG/RM_Instance_Group.cpp
Normal file
343
code/RMG/RM_Instance_Group.cpp
Normal file
@@ -0,0 +1,343 @@
|
||||
/************************************************************************************************
|
||||
*
|
||||
* RM_Instance_Group.cpp
|
||||
*
|
||||
* Implements the CRMGroupInstance class. This class is reponsible for parsing a
|
||||
* group instance as well as spawning it into a landscape.
|
||||
*
|
||||
************************************************************************************************/
|
||||
|
||||
#include "../server/exe_headers.h"
|
||||
|
||||
#include "rm_headers.h"
|
||||
|
||||
#include "rm_instance_group.h"
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMGroupInstance::CRMGroupInstance
|
||||
* constructur
|
||||
*
|
||||
* inputs:
|
||||
* settlementID: ID of the settlement being created
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
CRMGroupInstance::CRMGroupInstance ( CGPGroup *instGroup, CRMInstanceFile& instFile )
|
||||
: CRMInstance ( instGroup, instFile )
|
||||
{
|
||||
// Grab the padding and confine radius
|
||||
mPaddingSize = atof ( instGroup->FindPairValue ( "padding", va("%i", TheRandomMissionManager->GetMission()->GetDefaultPadding() ) ) );
|
||||
mConfineRadius = atof ( instGroup->FindPairValue ( "confine", "0" ) );
|
||||
|
||||
const char * automapSymName = instGroup->FindPairValue ( "automap_symbol", "none" );
|
||||
if (0 == strcmpi(automapSymName, "none")) mAutomapSymbol = AUTOMAP_NONE ;
|
||||
else if (0 == strcmpi(automapSymName, "building")) mAutomapSymbol = AUTOMAP_BLD ;
|
||||
else if (0 == strcmpi(automapSymName, "objective")) mAutomapSymbol = AUTOMAP_OBJ ;
|
||||
else if (0 == strcmpi(automapSymName, "start")) mAutomapSymbol = AUTOMAP_START;
|
||||
else if (0 == strcmpi(automapSymName, "end")) mAutomapSymbol = AUTOMAP_END ;
|
||||
else if (0 == strcmpi(automapSymName, "enemy")) mAutomapSymbol = AUTOMAP_ENEMY;
|
||||
else if (0 == strcmpi(automapSymName, "friend")) mAutomapSymbol = AUTOMAP_FRIEND;
|
||||
else mAutomapSymbol = atoi( automapSymName );
|
||||
|
||||
// optional instance objective strings
|
||||
SetMessage(instGroup->FindPairValue("objective_message",""));
|
||||
SetDescription(instGroup->FindPairValue("objective_description",""));
|
||||
SetInfo(instGroup->FindPairValue("objective_info",""));
|
||||
|
||||
// Iterate through the sub groups to determine the instances which make up the group
|
||||
instGroup = instGroup->GetSubGroups ( );
|
||||
|
||||
while ( instGroup )
|
||||
{
|
||||
CRMInstance* instance;
|
||||
const char* name;
|
||||
int mincount;
|
||||
int maxcount;
|
||||
int count;
|
||||
float minrange;
|
||||
float maxrange;
|
||||
|
||||
// Make sure only instances are specified as sub groups
|
||||
assert ( 0 == stricmp ( instGroup->GetName ( ), "instance" ) );
|
||||
|
||||
// Grab the name
|
||||
name = instGroup->FindPairValue ( "name", "" );
|
||||
|
||||
// Grab the range information
|
||||
minrange = atof(instGroup->FindPairValue ( "minrange", "0" ) );
|
||||
maxrange = atof(instGroup->FindPairValue ( "maxrange", "0" ) );
|
||||
|
||||
// Grab the count information and randomly generate a count value
|
||||
mincount = atoi(instGroup->FindPairValue ( "mincount", "1" ) );
|
||||
maxcount = atoi(instGroup->FindPairValue ( "maxcount", "1" ) );
|
||||
count = mincount;
|
||||
|
||||
if ( maxcount > mincount )
|
||||
{
|
||||
count += (TheRandomMissionManager->GetLandScape()->irand(0, maxcount-mincount));
|
||||
}
|
||||
|
||||
// For each count create and add the instance
|
||||
for ( ; count ; count -- )
|
||||
{
|
||||
// Create the instance
|
||||
instance = instFile.CreateInstance ( name );
|
||||
|
||||
// Skip this instance if it couldnt be created for some reason. The CreateInstance
|
||||
// method will report an error so no need to do so here.
|
||||
if ( NULL == instance )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Set the min and max range for the instance
|
||||
instance->SetFilter(mFilter);
|
||||
instance->SetTeamFilter(mTeamFilter);
|
||||
|
||||
// Add the instance to the list
|
||||
mInstances.push_back ( instance );
|
||||
}
|
||||
|
||||
// Next sub group
|
||||
instGroup = instGroup->GetNext ( );
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMGroupInstance::~CRMGroupInstance
|
||||
* Removes all buildings and inhabitants
|
||||
*
|
||||
* inputs:
|
||||
* none
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
CRMGroupInstance::~CRMGroupInstance(void)
|
||||
{
|
||||
// Cleanup
|
||||
RemoveInstances ( );
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMGroupInstance::SetFilter
|
||||
* Sets a filter used to exclude instances
|
||||
*
|
||||
* inputs:
|
||||
* filter: filter name
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
void CRMGroupInstance::SetFilter( const char *filter )
|
||||
{
|
||||
rmInstanceIter_t it;
|
||||
|
||||
CRMInstance::SetFilter(filter);
|
||||
for(it = mInstances.begin(); it != mInstances.end(); it++)
|
||||
{
|
||||
(*it)->SetFilter(filter);
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMGroupInstance::SetTeamFilter
|
||||
* Sets the filter used to exclude team based instances
|
||||
*
|
||||
* inputs:
|
||||
* teamFilter: filter name
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
void CRMGroupInstance::SetTeamFilter( const char *teamFilter )
|
||||
{
|
||||
rmInstanceIter_t it;
|
||||
|
||||
CRMInstance::SetTeamFilter(teamFilter);
|
||||
for(it = mInstances.begin(); it != mInstances.end(); it++)
|
||||
{
|
||||
(*it)->SetTeamFilter(teamFilter);
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMGroupInstance::SetMirror
|
||||
* Sets the flag to mirror an instance on map
|
||||
*
|
||||
* inputs:
|
||||
* mirror
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
void CRMGroupInstance::SetMirror(int mirror)
|
||||
{
|
||||
rmInstanceIter_t it;
|
||||
|
||||
CRMInstance::SetMirror(mirror);
|
||||
for(it = mInstances.begin(); it != mInstances.end(); it++)
|
||||
{
|
||||
(*it)->SetMirror(mirror);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMGroupInstance::RemoveInstances
|
||||
* Removes all instances associated with the group
|
||||
*
|
||||
* inputs:
|
||||
* none
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
void CRMGroupInstance::RemoveInstances ( )
|
||||
{
|
||||
rmInstanceIter_t it;
|
||||
|
||||
for(it = mInstances.begin(); it != mInstances.end(); it++)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
|
||||
mInstances.clear();
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMGroupInstance::PreSpawn
|
||||
* Prepares the group for spawning by
|
||||
*
|
||||
* inputs:
|
||||
* landscape: landscape to calculate the position within
|
||||
* instance: instance to calculate the position for
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
bool CRMGroupInstance::PreSpawn ( CRandomTerrain* terrain, qboolean IsServer )
|
||||
{
|
||||
rmInstanceIter_t it;
|
||||
|
||||
for(it = mInstances.begin(); it != mInstances.end(); it++ )
|
||||
{
|
||||
CRMInstance* instance = *it;
|
||||
|
||||
instance->SetFlattenHeight ( mFlattenHeight );
|
||||
|
||||
// Add the instance to the landscape now
|
||||
instance->PreSpawn ( terrain, IsServer );
|
||||
}
|
||||
|
||||
return CRMInstance::PreSpawn ( terrain, IsServer );
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMGroupInstance::Spawn
|
||||
* Adds the group instance to the given landscape using the specified origin. All sub instances
|
||||
* will be added to the landscape within their min and max range from the origin.
|
||||
*
|
||||
* inputs:
|
||||
* landscape: landscape to add the instance group to
|
||||
* origin: origin of the instance group
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
bool CRMGroupInstance::Spawn ( CRandomTerrain* terrain, qboolean IsServer )
|
||||
{
|
||||
rmInstanceIter_t it;
|
||||
|
||||
// Spawn all the instances associated with this group
|
||||
for(it = mInstances.begin(); it != mInstances.end(); it++)
|
||||
{
|
||||
CRMInstance* instance = *it;
|
||||
instance->SetSide(GetSide()); // which side owns it?
|
||||
|
||||
// Add the instance to the landscape now
|
||||
instance->Spawn ( terrain, IsServer );
|
||||
}
|
||||
#ifndef DEDICATED
|
||||
DrawAutomapSymbol();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMGroupInstance::Preview
|
||||
* Renders debug information for the instance
|
||||
*
|
||||
* inputs:
|
||||
* from: point to render the preview from
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
void CRMGroupInstance::Preview ( const vec3_t from )
|
||||
{
|
||||
rmInstanceIter_t it;
|
||||
|
||||
CRMInstance::Preview ( from );
|
||||
|
||||
// Render all the instances
|
||||
for(it = mInstances.begin(); it != mInstances.end(); it++)
|
||||
{
|
||||
CRMInstance* instance = *it;
|
||||
|
||||
instance->Preview ( from );
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMGroupInstance::SetArea
|
||||
* Overidden to make sure the groups area doesnt eat up any room. The collision on the
|
||||
* groups area will be turned off
|
||||
*
|
||||
* inputs:
|
||||
* area: area to set
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
void CRMGroupInstance::SetArea ( CRMAreaManager* amanager, CRMArea* area )
|
||||
{
|
||||
rmInstanceIter_t it;
|
||||
|
||||
bool collide = area->IsCollisionEnabled ( );
|
||||
|
||||
// Disable collision
|
||||
area->EnableCollision ( false );
|
||||
|
||||
// Do what really needs to get done
|
||||
CRMInstance::SetArea ( amanager, area );
|
||||
|
||||
// Prepare for spawn by calculating all the positions of the sub instances
|
||||
// and flattening the ground below them.
|
||||
for(it = mInstances.begin(); it != mInstances.end(); it++ )
|
||||
{
|
||||
CRMInstance *instance = *it;
|
||||
CRMArea *newarea;
|
||||
vec3_t origin;
|
||||
|
||||
// Drop it in the center of the group for now
|
||||
origin[0] = GetOrigin()[0];
|
||||
origin[1] = GetOrigin()[1];
|
||||
origin[2] = 2500;
|
||||
|
||||
// Set the area of position
|
||||
newarea = amanager->CreateArea ( origin, instance->GetSpacingRadius(), instance->GetSpacingLine(), mPaddingSize, mConfineRadius, GetOrigin(), GetOrigin(), instance->GetFlattenRadius()?true:false, collide, instance->GetLockOrigin(), area->GetSymmetric ( ) );
|
||||
instance->SetArea ( amanager, newarea );
|
||||
}
|
||||
}
|
||||
41
code/RMG/RM_Instance_Group.h
Normal file
41
code/RMG/RM_Instance_Group.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
#if !defined(RM_INSTANCE_GROUP_H_INC)
|
||||
#define RM_INSTANCE_GROUP_H_INC
|
||||
|
||||
#ifdef DEBUG_LINKING
|
||||
#pragma message("...including RM_Instance_Group.h")
|
||||
#endif
|
||||
|
||||
class CRMGroupInstance : public CRMInstance
|
||||
{
|
||||
protected:
|
||||
|
||||
rmInstanceList_t mInstances;
|
||||
float mConfineRadius;
|
||||
float mPaddingSize;
|
||||
|
||||
public:
|
||||
|
||||
CRMGroupInstance( CGPGroup* instGroup, CRMInstanceFile& instFile);
|
||||
~CRMGroupInstance();
|
||||
|
||||
virtual bool PreSpawn ( CRandomTerrain* terrain, qboolean IsServer );
|
||||
virtual bool Spawn ( CRandomTerrain* terrain, qboolean IsServer );
|
||||
|
||||
virtual void Preview ( const vec3_t from );
|
||||
|
||||
virtual void SetFilter ( const char *filter );
|
||||
virtual void SetTeamFilter ( const char *teamFilter );
|
||||
virtual void SetArea ( CRMAreaManager* amanager, CRMArea* area );
|
||||
|
||||
virtual int GetPreviewColor ( ) { return (255<<24)+(255<<8); }
|
||||
virtual float GetSpacingRadius ( ) { return 0; }
|
||||
virtual float GetFlattenRadius ( ) { return 0; }
|
||||
virtual void SetMirror(int mirror);
|
||||
|
||||
protected:
|
||||
|
||||
void RemoveInstances ( );
|
||||
};
|
||||
|
||||
#endif
|
||||
187
code/RMG/RM_Instance_Random.cpp
Normal file
187
code/RMG/RM_Instance_Random.cpp
Normal file
@@ -0,0 +1,187 @@
|
||||
/************************************************************************************************
|
||||
*
|
||||
* RM_Instance_Random.cpp
|
||||
*
|
||||
* Implements the CRMRandomInstance class. This class is reponsible for parsing a
|
||||
* random instance as well as spawning it into a landscape.
|
||||
*
|
||||
************************************************************************************************/
|
||||
|
||||
#include "../server/exe_headers.h"
|
||||
|
||||
#include "rm_headers.h"
|
||||
|
||||
#include "rm_instance_random.h"
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMRandomInstance::CRMRandomInstance
|
||||
* constructs a random instance by choosing one of the sub instances and creating it
|
||||
*
|
||||
* inputs:
|
||||
* instGroup: parser group containing infromation about this instance
|
||||
* instFile: reference to an open instance file for creating sub instances
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
CRMRandomInstance::CRMRandomInstance ( CGPGroup *instGroup, CRMInstanceFile& instFile )
|
||||
: CRMInstance ( instGroup, instFile )
|
||||
{
|
||||
CGPGroup* group;
|
||||
CGPGroup* groups[MAX_RANDOM_INSTANCES];
|
||||
int numGroups;
|
||||
|
||||
// Build a list of the groups one can be chosen
|
||||
for ( numGroups = 0, group = instGroup->GetSubGroups ( );
|
||||
group;
|
||||
group = group->GetNext ( ) )
|
||||
{
|
||||
// If this isnt an instance group then skip it
|
||||
if ( stricmp ( group->GetName ( ), "instance" ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int multiplier = atoi(group->FindPairValue ( "multiplier", "1" ));
|
||||
for ( ; multiplier > 0 && numGroups < MAX_RANDOM_INSTANCES; multiplier -- )
|
||||
{
|
||||
groups[numGroups++] = group;
|
||||
}
|
||||
}
|
||||
|
||||
// No groups, no instance
|
||||
if ( !numGroups )
|
||||
{
|
||||
// Initialize this now
|
||||
mInstance = NULL;
|
||||
|
||||
Com_Printf ( "WARNING: No sub instances specified for random instance '%s'\n", group->FindPairValue ( "name", "unknown" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
// Now choose a group to parse
|
||||
instGroup = groups[TheRandomMissionManager->GetLandScape()->irand(0,numGroups-1)];
|
||||
|
||||
// Create the child instance now. If the instance create fails then the
|
||||
// IsValid routine will return false and this instance wont be added
|
||||
mInstance = instFile.CreateInstance ( instGroup->FindPairValue ( "name", "" ) );
|
||||
mInstance->SetFilter(mFilter);
|
||||
mInstance->SetTeamFilter(mTeamFilter);
|
||||
|
||||
mAutomapSymbol = mInstance->GetAutomapSymbol();
|
||||
|
||||
SetMessage(mInstance->GetMessage());
|
||||
SetDescription(mInstance->GetDescription());
|
||||
SetInfo(mInstance->GetInfo());
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMRandomInstance::~CRMRandomInstance
|
||||
* Deletes the sub instance
|
||||
*
|
||||
* inputs:
|
||||
* none
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
CRMRandomInstance::~CRMRandomInstance(void)
|
||||
{
|
||||
if ( mInstance )
|
||||
{
|
||||
delete mInstance;
|
||||
}
|
||||
}
|
||||
|
||||
void CRMRandomInstance::SetMirror(int mirror)
|
||||
{
|
||||
CRMInstance::SetMirror(mirror);
|
||||
if (mInstance)
|
||||
{
|
||||
mInstance->SetMirror(mirror);
|
||||
}
|
||||
}
|
||||
|
||||
void CRMRandomInstance::SetFilter( const char *filter )
|
||||
{
|
||||
CRMInstance::SetFilter(filter);
|
||||
if (mInstance)
|
||||
{
|
||||
mInstance->SetFilter(filter);
|
||||
}
|
||||
}
|
||||
|
||||
void CRMRandomInstance::SetTeamFilter( const char *teamFilter )
|
||||
{
|
||||
CRMInstance::SetTeamFilter(teamFilter);
|
||||
if (mInstance)
|
||||
{
|
||||
mInstance->SetTeamFilter(teamFilter);
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMRandomInstance::PreSpawn
|
||||
* Prepares for the spawn of the random instance
|
||||
*
|
||||
* inputs:
|
||||
* landscape: landscape object this instance will be spawned on
|
||||
*
|
||||
* return:
|
||||
* true: preparation successful
|
||||
* false: preparation failed
|
||||
*
|
||||
************************************************************************************************/
|
||||
bool CRMRandomInstance::PreSpawn ( CRandomTerrain* terrain, qboolean IsServer )
|
||||
{
|
||||
assert ( mInstance );
|
||||
|
||||
mInstance->SetFlattenHeight ( GetFlattenHeight( ) );
|
||||
|
||||
return mInstance->PreSpawn ( terrain, IsServer );
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMRandomInstance::Spawn
|
||||
* Spawns the instance onto the landscape
|
||||
*
|
||||
* inputs:
|
||||
* landscape: landscape object this instance will be spawned on
|
||||
*
|
||||
* return:
|
||||
* true: spawn successful
|
||||
* false: spawn failed
|
||||
*
|
||||
************************************************************************************************/
|
||||
bool CRMRandomInstance::Spawn ( CRandomTerrain* terrain, qboolean IsServer )
|
||||
{
|
||||
mInstance->SetObjective(GetObjective());
|
||||
mInstance->SetSide(GetSide());
|
||||
|
||||
if ( !mInstance->Spawn ( terrain, IsServer ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMRandomInstance::SetArea
|
||||
* Forwards the given area off to the internal instance
|
||||
*
|
||||
* inputs:
|
||||
* area: area to be set
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
void CRMRandomInstance::SetArea ( CRMAreaManager* amanager, CRMArea* area )
|
||||
{
|
||||
CRMInstance::SetArea ( amanager, area );
|
||||
|
||||
mInstance->SetArea ( amanager, mArea );
|
||||
}
|
||||
40
code/RMG/RM_Instance_Random.h
Normal file
40
code/RMG/RM_Instance_Random.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
#if !defined(RM_INSTANCE_RANDOM_H_INC)
|
||||
#define RM_INSTANCE_RANDOM_H_INC
|
||||
|
||||
#ifdef DEBUG_LINKING
|
||||
#pragma message("...including RM_Instance_Random.h")
|
||||
#endif
|
||||
|
||||
#define MAX_RANDOM_INSTANCES 64
|
||||
|
||||
class CRMRandomInstance : public CRMInstance
|
||||
{
|
||||
protected:
|
||||
|
||||
CRMInstance* mInstance;
|
||||
|
||||
public:
|
||||
|
||||
CRMRandomInstance ( CGPGroup* instGroup, CRMInstanceFile& instFile );
|
||||
~CRMRandomInstance ( );
|
||||
|
||||
virtual bool IsValid ( ) { return mInstance==NULL?false:true; }
|
||||
|
||||
virtual int GetPreviewColor ( ) { return mInstance->GetPreviewColor ( ); }
|
||||
|
||||
virtual float GetSpacingRadius ( ) { return mInstance->GetSpacingRadius ( ); }
|
||||
virtual int GetSpacingLine ( ) { return mInstance->GetSpacingLine ( ); }
|
||||
virtual float GetFlattenRadius ( ) { return mInstance->GetFlattenRadius ( ); }
|
||||
virtual bool GetLockOrigin ( ) { return mInstance->GetLockOrigin ( ); }
|
||||
|
||||
virtual void SetFilter ( const char *filter );
|
||||
virtual void SetTeamFilter ( const char *teamFilter );
|
||||
virtual void SetArea ( CRMAreaManager* amanager, CRMArea* area );
|
||||
virtual void SetMirror (int mirror);
|
||||
|
||||
virtual bool PreSpawn ( CRandomTerrain* terrain, qboolean IsServer );
|
||||
virtual bool Spawn ( CRandomTerrain* terrain, qboolean IsServer );
|
||||
};
|
||||
|
||||
#endif
|
||||
53
code/RMG/RM_Instance_Void.cpp
Normal file
53
code/RMG/RM_Instance_Void.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
/************************************************************************************************
|
||||
*
|
||||
* RM_Instance_Void.cpp
|
||||
*
|
||||
* Implements the CRMVoidInstance class. This class just adds a void into the
|
||||
* area manager to help space things out.
|
||||
*
|
||||
************************************************************************************************/
|
||||
|
||||
#include "../server/exe_headers.h"
|
||||
|
||||
#include "rm_headers.h"
|
||||
|
||||
#include "rm_instance_void.h"
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMVoidInstance::CRMVoidInstance
|
||||
* constructs a void instance
|
||||
*
|
||||
* inputs:
|
||||
* instGroup: parser group containing infromation about this instance
|
||||
* instFile: reference to an open instance file for creating sub instances
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
CRMVoidInstance::CRMVoidInstance ( CGPGroup *instGroup, CRMInstanceFile& instFile )
|
||||
: CRMInstance ( instGroup, instFile )
|
||||
{
|
||||
mSpacingRadius = atof( instGroup->FindPairValue ( "spacing", "0" ) );
|
||||
mFlattenRadius = atof( instGroup->FindPairValue ( "flatten", "0" ) );
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMVoidInstance::SetArea
|
||||
* Overidden to make sure the void area doesnt continually.
|
||||
*
|
||||
* inputs:
|
||||
* area: area to set
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
void CRMVoidInstance::SetArea ( CRMAreaManager* amanager, CRMArea* area )
|
||||
{
|
||||
// Disable collision
|
||||
area->EnableCollision ( false );
|
||||
|
||||
// Do what really needs to get done
|
||||
CRMInstance::SetArea ( amanager, area );
|
||||
}
|
||||
18
code/RMG/RM_Instance_Void.h
Normal file
18
code/RMG/RM_Instance_Void.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
#if !defined(RM_INSTANCE_VOID_H_INC)
|
||||
#define RM_INSTANCE_VOID_H_INC
|
||||
|
||||
#ifdef DEBUG_LINKING
|
||||
#pragma message("...including RM_Instance_Void.h")
|
||||
#endif
|
||||
|
||||
class CRMVoidInstance : public CRMInstance
|
||||
{
|
||||
public:
|
||||
|
||||
CRMVoidInstance ( CGPGroup* instGroup, CRMInstanceFile& instFile );
|
||||
|
||||
virtual void SetArea ( CRMAreaManager* amanager, CRMArea* area );
|
||||
};
|
||||
|
||||
#endif
|
||||
402
code/RMG/RM_Manager.cpp
Normal file
402
code/RMG/RM_Manager.cpp
Normal file
@@ -0,0 +1,402 @@
|
||||
/************************************************************************************************
|
||||
*
|
||||
* RM_Manager.cpp
|
||||
*
|
||||
* Implements the CRMManager class. The CRMManager class manages the arioche system.
|
||||
*
|
||||
************************************************************************************************/
|
||||
|
||||
#include "../server/exe_headers.h"
|
||||
|
||||
#include "rm_headers.h"
|
||||
#include "../server/server.h"
|
||||
|
||||
CRMObjective *CRMManager::mCurObjective=0;
|
||||
|
||||
/************************************************************************************************
|
||||
* TheRandomMissionManager
|
||||
* Pointer to only active CRMManager class
|
||||
*
|
||||
************************************************************************************************/
|
||||
CRMManager *TheRandomMissionManager;
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMManager::CRMManager
|
||||
* constructor
|
||||
*
|
||||
* inputs:
|
||||
*
|
||||
* return:
|
||||
*
|
||||
************************************************************************************************/
|
||||
CRMManager::CRMManager(void)
|
||||
{
|
||||
mLandScape = NULL;
|
||||
mTerrain = NULL;
|
||||
mMission = NULL;
|
||||
mCurPriority = 1;
|
||||
mUseTimeLimit = false;
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMManager::~CRMManager
|
||||
* destructor
|
||||
*
|
||||
* inputs:
|
||||
*
|
||||
* return:
|
||||
*
|
||||
************************************************************************************************/
|
||||
CRMManager::~CRMManager(void)
|
||||
{
|
||||
#ifndef FINAL_BUILD
|
||||
Com_Printf ("... Shutting down TheRandomMissionManager\n");
|
||||
#endif
|
||||
#ifndef DEDICATED
|
||||
CM_TM_Free();
|
||||
#endif
|
||||
if (mMission)
|
||||
{
|
||||
delete mMission;
|
||||
mMission = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMManager::SetLandscape
|
||||
* Sets the landscape and terrain object used to load a mission
|
||||
*
|
||||
* inputs:
|
||||
* landscape - landscape object
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
void CRMManager::SetLandScape(CCMLandScape *landscape)
|
||||
{
|
||||
mLandScape = landscape;
|
||||
mTerrain = landscape->GetRandomTerrain();
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMManager::LoadMission
|
||||
* Loads the mission using the mission name stored in the ar_mission cvar
|
||||
*
|
||||
* inputs:
|
||||
* none
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
bool CRMManager::LoadMission ( qboolean IsServer )
|
||||
{
|
||||
#ifndef PRE_RELEASE_DEMO
|
||||
char instances[MAX_QPATH];
|
||||
char mission[MAX_QPATH];
|
||||
char course[MAX_QPATH];
|
||||
char map[MAX_QPATH];
|
||||
char temp[MAX_QPATH];
|
||||
|
||||
#ifndef FINAL_BUILD
|
||||
Com_Printf ("--------- Random Mission Manager ---------\n\n");
|
||||
Com_Printf ("RMG version : 0.01\n\n");
|
||||
#endif
|
||||
|
||||
if (!mTerrain)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Grab the arioche variables
|
||||
Cvar_VariableStringBuffer("rmg_usetimelimit", temp, MAX_QPATH);
|
||||
if (strcmpi(temp, "yes") == 0)
|
||||
{
|
||||
mUseTimeLimit = true;
|
||||
}
|
||||
Cvar_VariableStringBuffer("rmg_instances", instances, MAX_QPATH);
|
||||
Cvar_VariableStringBuffer("RMG_mission", temp, MAX_QPATH);
|
||||
Cvar_VariableStringBuffer("rmg_map", map, MAX_QPATH);
|
||||
sprintf(mission, "%s_%s", temp, map);
|
||||
Cvar_VariableStringBuffer("rmg_course", course, MAX_QPATH);
|
||||
|
||||
// dump existing mission, if any
|
||||
if (mMission)
|
||||
{
|
||||
delete mMission;
|
||||
mMission = NULL;
|
||||
}
|
||||
|
||||
// Create a new mission file
|
||||
mMission = new CRMMission ( mTerrain );
|
||||
|
||||
// Load the mission using the arioche variables
|
||||
if ( !mMission->Load ( mission, instances, course ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mUseTimeLimit)
|
||||
{
|
||||
Cvar_Set("rmg_timelimit", va("%d", mMission->GetTimeLimit()));
|
||||
}
|
||||
else
|
||||
{
|
||||
Cvar_Set("rmg_timelimit", "0");
|
||||
}
|
||||
|
||||
if (IsServer)
|
||||
{ // set the names of the teams
|
||||
CGenericParser2 parser;
|
||||
//CGPGroup* root;
|
||||
|
||||
Cvar_VariableStringBuffer("RMG_terrain", temp, MAX_QPATH);
|
||||
|
||||
/*
|
||||
// Create the parser for the mission file
|
||||
if(Com_ParseTextFile(va("ext_data/rmg/%s.teams", temp), parser))
|
||||
{
|
||||
root = parser.GetBaseParseGroup()->GetSubGroups();
|
||||
if (0 == stricmp(root->GetName(), "teams"))
|
||||
{
|
||||
SV_SetConfigstring( CS_GAMETYPE_REDTEAM, root->FindPairValue ( "red", "marine" ));
|
||||
SV_SetConfigstring( CS_GAMETYPE_BLUETEAM, root->FindPairValue ( "blue", "thug" ));
|
||||
}
|
||||
parser.Clean();
|
||||
}
|
||||
*/
|
||||
//rww - This is single player, no such thing.
|
||||
}
|
||||
|
||||
// Must have a valid landscape before we can spawn the mission
|
||||
assert ( mLandScape );
|
||||
|
||||
#ifndef FINAL_BUILD
|
||||
Com_Printf ("------------------------------------------\n");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif // PRE_RELEASE_DEMO
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMManager::IsMissionComplete
|
||||
* Determines whether or not all the arioche objectives have been met
|
||||
*
|
||||
* inputs:
|
||||
* none
|
||||
*
|
||||
* return:
|
||||
* true: all objectives have been completed
|
||||
* false: one or more of the objectives has not been met
|
||||
*
|
||||
************************************************************************************************/
|
||||
bool CRMManager::IsMissionComplete(void)
|
||||
{
|
||||
if ( NULL == mMission->GetCurrentObjective ( ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMManager::HasTimeExpired
|
||||
* Determines whether or not the time limit (if one) has expired
|
||||
*
|
||||
* inputs:
|
||||
* none
|
||||
*
|
||||
* return:
|
||||
* true: time limit has expired
|
||||
* false: time limit has not expired
|
||||
*
|
||||
************************************************************************************************/
|
||||
bool CRMManager::HasTimeExpired(void)
|
||||
{
|
||||
/* if (mMission->GetTimeLimit() == 0 || !mUseTimeLimit)
|
||||
{ // no time limit set
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mMission->GetTimeLimit() * 1000 * 60 > level.time - level.startTime)
|
||||
{ // we are still under our time limit
|
||||
return false;
|
||||
}
|
||||
|
||||
// over our time limit!
|
||||
return true;*/
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMManager::UpdateStatisticCvars
|
||||
* Updates the statistic cvars with data from the game
|
||||
*
|
||||
* inputs:
|
||||
* none
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
void CRMManager::UpdateStatisticCvars ( void )
|
||||
{
|
||||
/* // No player set then nothing more to do
|
||||
if ( mPlayer )
|
||||
{
|
||||
float accuracy;
|
||||
|
||||
// Calculate the accuracy
|
||||
accuracy = (float)mPlayer->client->ps.persistant[PERS_SHOTS_HIT];
|
||||
accuracy /= (float)mPlayer->client->ps.persistant[PERS_SHOTS];
|
||||
accuracy *= 100.0f;
|
||||
|
||||
// set the accuracy cvar
|
||||
gi.Cvar_Set ( "ar_pl_accuracy", va("%d%%",(int)accuracy) );
|
||||
|
||||
// Set the # of kills cvar
|
||||
gi.Cvar_Set ( "ar_kills", va("%d", mPlayer->client->ps.persistant[PERS_SCORE] ) );
|
||||
|
||||
int hours;
|
||||
int mins;
|
||||
int seconds;
|
||||
int tens;
|
||||
int millisec = (level.time - level.startTime);
|
||||
|
||||
seconds = millisec / 1000;
|
||||
hours = seconds / (60 * 60);
|
||||
seconds -= (hours * 60 * 60);
|
||||
mins = seconds / 60;
|
||||
seconds -= mins * 60;
|
||||
tens = seconds / 10;
|
||||
seconds -= tens * 10;
|
||||
|
||||
gi.Cvar_Set ( "ar_duration", va("%dhr %dmin %dsec", hours, mins, seconds ) );
|
||||
|
||||
WpnID wpnID = TheWpnSysMgr().GetFavoriteWeapon ( );
|
||||
gi.Cvar_Set ( "ar_fav_wp", CWeaponSystem::GetWpnName ( wpnID ) );
|
||||
|
||||
// show difficulty
|
||||
char difficulty[MAX_QPATH];
|
||||
gi.Cvar_VariableStringBuffer("g_skill", difficulty, MAX_QPATH);
|
||||
strupr(difficulty);
|
||||
gi.Cvar_Set ( "ar_diff", va("&GENERIC_%s&",difficulty) );
|
||||
|
||||
// compute rank
|
||||
float compositeRank = 1;
|
||||
int rankMax = 3; // max rank less 1
|
||||
float timeRank = mUseTimeLimit ? (1.0f - (mins / (float)mMission->GetTimeLimit())) : 0;
|
||||
float killRank = mPlayer->client->ps.persistant[PERS_SCORE] / (float)GetCharacterManager().GetAllSize();
|
||||
killRank = (killRank > 0) ? killRank : 1.0f;
|
||||
float accuRank = (accuracy > 0) ? accuracy*0.01f : 1.0f;
|
||||
float weapRank = 1.0f - CWeaponSystem::GetRank(wpnID);
|
||||
|
||||
compositeRank = ((timeRank + killRank + accuRank + weapRank) / 3.0f) * rankMax + 1;
|
||||
|
||||
if (compositeRank > 4)
|
||||
compositeRank = 4;
|
||||
|
||||
gi.Cvar_Set ( "ar_rank", va("&RMG_RANK%d&",((int)compositeRank)) );
|
||||
}*/
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMManager::CompleteMission
|
||||
* Does end-of-mission stuff (pause game, end screen, return to menu)
|
||||
* <Description> *
|
||||
* Input *
|
||||
* <Variable>: <Description> *
|
||||
* Output / Return *
|
||||
* <Variable>: <Description> *
|
||||
************************************************************************************************/
|
||||
void CRMManager::CompleteMission(void)
|
||||
{
|
||||
UpdateStatisticCvars ( );
|
||||
|
||||
mMission->CompleteMission();
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMManager::FailedMission
|
||||
* Does end-of-mission stuff (pause game, end screen, return to menu)
|
||||
* <Description> *
|
||||
* Input *
|
||||
* TimeExpired: indicates if the reason failed was because of time
|
||||
* Output / Return *
|
||||
* <Variable>: <Description> *
|
||||
************************************************************************************************/
|
||||
void CRMManager::FailedMission(bool TimeExpired)
|
||||
{
|
||||
UpdateStatisticCvars ( );
|
||||
|
||||
mMission->FailedMission(TimeExpired);
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMManager::CompleteObjective
|
||||
* Marks the given objective as completed
|
||||
*
|
||||
* inputs:
|
||||
* obj: objective to set as completed
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
void CRMManager::CompleteObjective ( CRMObjective *obj )
|
||||
{
|
||||
assert ( obj );
|
||||
|
||||
mMission->CompleteObjective ( obj );
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMManager::Preview
|
||||
* previews the random mission genration information
|
||||
*
|
||||
* inputs:
|
||||
* from: origin being previed from
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
void CRMManager::Preview ( const vec3_t from )
|
||||
{
|
||||
// Dont bother if we havent reached our timer yet
|
||||
/* if ( level.time < mPreviewTimer )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Let the mission do all the previewing
|
||||
mMission->Preview ( from );
|
||||
|
||||
// Another second
|
||||
mPreviewTimer = level.time + 1000;*/
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMManager::Preview
|
||||
* previews the random mission genration information
|
||||
*
|
||||
* inputs:
|
||||
* from: origin being previed from
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
bool CRMManager::SpawnMission ( qboolean IsServer )
|
||||
{
|
||||
// Spawn the mission
|
||||
mMission->Spawn ( mTerrain, IsServer );
|
||||
|
||||
return true;
|
||||
}
|
||||
55
code/RMG/RM_Manager.h
Normal file
55
code/RMG/RM_Manager.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
#if !defined(RM_MANAGER_H_INC)
|
||||
#define RM_MANAGER_H_INC
|
||||
|
||||
#if !defined(CM_LANDSCAPE_H_INC)
|
||||
#include "../qcommon/cm_landscape.h"
|
||||
#endif
|
||||
|
||||
class CRMManager
|
||||
{
|
||||
private:
|
||||
|
||||
CRMMission* mMission;
|
||||
CCMLandScape* mLandScape;
|
||||
CRandomTerrain* mTerrain;
|
||||
int mPreviewTimer;
|
||||
int mCurPriority;
|
||||
bool mUseTimeLimit;
|
||||
|
||||
void UpdateStatisticCvars ( void );
|
||||
|
||||
public:
|
||||
|
||||
// Constructors
|
||||
CRMManager (void);
|
||||
~CRMManager (void);
|
||||
|
||||
bool LoadMission ( qboolean IsServer );
|
||||
bool SpawnMission ( qboolean IsServer );
|
||||
|
||||
// Accessors
|
||||
void SetLandScape (CCMLandScape *landscape);
|
||||
void SetCurPriority (int priority) { mCurPriority = priority; }
|
||||
|
||||
CRandomTerrain* GetTerrain (void) { return mTerrain; }
|
||||
CCMLandScape* GetLandScape (void) { return mLandScape; }
|
||||
CRMMission* GetMission (void) { return mMission; }
|
||||
int GetCurPriority (void) { return mCurPriority; }
|
||||
|
||||
void Preview ( const vec3_t from );
|
||||
|
||||
bool IsMissionComplete (void);
|
||||
bool HasTimeExpired (void);
|
||||
void CompleteObjective ( CRMObjective *obj );
|
||||
void CompleteMission (void);
|
||||
void FailedMission (bool TimeExpired);
|
||||
|
||||
// eek
|
||||
static CRMObjective *mCurObjective;
|
||||
};
|
||||
|
||||
extern CRMManager* TheRandomMissionManager;
|
||||
|
||||
|
||||
#endif // RANDOMMISSION_H_INC
|
||||
1930
code/RMG/RM_Mission.cpp
Normal file
1930
code/RMG/RM_Mission.cpp
Normal file
File diff suppressed because it is too large
Load Diff
129
code/RMG/RM_Mission.h
Normal file
129
code/RMG/RM_Mission.h
Normal file
@@ -0,0 +1,129 @@
|
||||
#pragma once
|
||||
#if !defined(RM_MISSION_H_INC)
|
||||
#define RM_MISSION_H_INC
|
||||
|
||||
#ifdef DEBUG_LINKING
|
||||
#pragma message("...including RM_Mission.h")
|
||||
#endif
|
||||
|
||||
// maximum random choices
|
||||
#define MAX_RANDOM_CHOICES 100
|
||||
|
||||
typedef vector<int> rmIntVector_t;
|
||||
|
||||
|
||||
class CRMMission
|
||||
{
|
||||
private:
|
||||
|
||||
rmObjectiveList_t mObjectives;
|
||||
rmInstanceList_t mInstances;
|
||||
|
||||
CRMInstanceFile mInstanceFile;
|
||||
CRMObjective* mCurrentObjective;
|
||||
|
||||
bool mValidNodes;
|
||||
bool mValidPaths;
|
||||
bool mValidRivers;
|
||||
bool mValidWeapons;
|
||||
bool mValidAmmo;
|
||||
bool mValidObjectives;
|
||||
bool mValidInstances;
|
||||
|
||||
int mTimeLimit;
|
||||
int mMaxInstancePosition;
|
||||
|
||||
// npc multipliers
|
||||
float mAccuracyMultiplier;
|
||||
float mHealthMultiplier;
|
||||
|
||||
// % chance that RMG pickup is actually spawned
|
||||
float mPickupHealth;
|
||||
float mPickupArmor;
|
||||
float mPickupAmmo;
|
||||
float mPickupWeapon;
|
||||
float mPickupEquipment;
|
||||
|
||||
string mDescription;
|
||||
string mExitScreen;
|
||||
string mTimeExpiredScreen;
|
||||
|
||||
// symmetric landscape style
|
||||
symmetry_t mSymmetric;
|
||||
|
||||
// if set to 1 in the mission file, adds an extra connecting path in symmetric maps
|
||||
// to ensure both sides actually do connect
|
||||
int mBackUpPath;
|
||||
|
||||
int mDefaultPadding;
|
||||
|
||||
CRMAreaManager* mAreaManager;
|
||||
|
||||
CRMPathManager* mPathManager;
|
||||
|
||||
CRandomTerrain* mLandScape;
|
||||
|
||||
public:
|
||||
|
||||
CRMMission ( CRandomTerrain* );
|
||||
~CRMMission ( );
|
||||
|
||||
bool Load ( const char* name, const char* instances, const char* difficulty );
|
||||
bool Spawn ( CRandomTerrain* terrain, qboolean IsServer );
|
||||
|
||||
void Preview ( const vec3_t from );
|
||||
|
||||
CRMObjective* FindObjective ( const char* name );
|
||||
CRMObjective* GetCurrentObjective ( ) { return mCurrentObjective; }
|
||||
|
||||
void CompleteMission (void);
|
||||
void FailedMission (bool TimeExpired);
|
||||
void CompleteObjective ( CRMObjective* ojective );
|
||||
|
||||
int GetTimeLimit (void) { return mTimeLimit; }
|
||||
int GetMaxInstancePosition (void) { return mMaxInstancePosition; }
|
||||
const char* GetDescription (void) { return mDescription.c_str(); }
|
||||
const char* GetExitScreen (void) { return mExitScreen.c_str(); }
|
||||
int GetSymmetric (void) { return mSymmetric; }
|
||||
int GetBackUpPath (void) { return mBackUpPath; }
|
||||
int GetDefaultPadding (void) { return mDefaultPadding; }
|
||||
|
||||
// void CreateMap ( void );
|
||||
|
||||
bool DenyPickupHealth () {return mLandScape->flrand(0.0f,1.0f) > mPickupHealth;}
|
||||
bool DenyPickupArmor () {return mLandScape->flrand(0.0f,1.0f) > mPickupArmor;}
|
||||
bool DenyPickupAmmo () {return mLandScape->flrand(0.0f,1.0f) > mPickupAmmo;}
|
||||
bool DenyPickupWeapon () {return mLandScape->flrand(0.0f,1.0f) > mPickupWeapon;}
|
||||
bool DenyPickupEquipment () {return mLandScape->flrand(0.0f,1.0f) > mPickupEquipment;}
|
||||
|
||||
private:
|
||||
|
||||
// void PurgeUnlinkedTriggers ( );
|
||||
// void PurgeTrigger ( CEntity* trigger );
|
||||
|
||||
void MirrorPos (vec3_t pos);
|
||||
CGPGroup* ParseRandom ( CGPGroup* random );
|
||||
bool ParseOrigin ( CGPGroup* originGroup, vec3_t origin, vec3_t lookat, int* flattenHeight );
|
||||
bool ParseNodes ( CGPGroup* group );
|
||||
bool ParsePaths ( CGPGroup *paths);
|
||||
bool ParseRivers ( CGPGroup *rivers);
|
||||
void PlaceBridges ();
|
||||
void PlaceWallInstance(CRMInstance* instance, float xpos, float ypos, float zpos, int x, int y, float angle);
|
||||
|
||||
|
||||
bool ParseDifficulty ( CGPGroup* difficulty, CGPGroup *parent );
|
||||
bool ParseWeapons ( CGPGroup* weapons );
|
||||
bool ParseAmmo ( CGPGroup* ammo );
|
||||
bool ParseOutfit ( CGPGroup* outfit );
|
||||
bool ParseObjectives ( CGPGroup* objectives );
|
||||
bool ParseInstance ( CGPGroup* instance );
|
||||
bool ParseInstances ( CGPGroup* instances );
|
||||
bool ParseInstancesOnPath ( CGPGroup* group );
|
||||
bool ParseWallRect ( CGPGroup* group, int side);
|
||||
|
||||
// void SpawnNPCTriggers ( CCMLandScape* landscape );
|
||||
// void AttachNPCTriggers ( CCMLandScape* landscape );
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
134
code/RMG/RM_Objective.cpp
Normal file
134
code/RMG/RM_Objective.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
/************************************************************************************************
|
||||
*
|
||||
* RM_Objective.cpp
|
||||
*
|
||||
* Implements the CRMObjective class. This class is reponsible for parsing an objective
|
||||
* from the mission file as well as linking the objective into the world.
|
||||
*
|
||||
************************************************************************************************/
|
||||
|
||||
#include "../server/exe_headers.h"
|
||||
|
||||
#include "rm_headers.h"
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMObjective::CRMObjective
|
||||
* Constructs a random mission objective and fills in the default properties
|
||||
*
|
||||
* inputs:
|
||||
* none
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
CRMObjective::CRMObjective ( CGPGroup* group )
|
||||
{
|
||||
SetPriority(atoi(group->FindPairValue("priority", "0")));
|
||||
SetMessage( group->FindPairValue("message",va("Objective %i Completed", GetPriority()) ) );
|
||||
SetDescription(group->FindPairValue("description",va("Objective %i", GetPriority()) ) );
|
||||
SetInfo(group->FindPairValue("info",va("Info %i", GetPriority()) ) );
|
||||
SetTrigger(group->FindPairValue("trigger",""));
|
||||
SetName(group->GetName());
|
||||
|
||||
/* const char * soundPath = group->FindPairValue("completed_sound", "" );
|
||||
if (soundPath)
|
||||
mCompleteSoundID = G_SoundIndex(soundPath);
|
||||
*/
|
||||
|
||||
mCompleted = false;
|
||||
mOrderIndex = -1;
|
||||
|
||||
// If no priority was specified for this objective then its active by default.
|
||||
if ( GetPriority ( ) )
|
||||
{
|
||||
mActive = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
mActive = true;
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMObjective::FindRandomTrigger
|
||||
* 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
|
||||
*
|
||||
************************************************************************************************/
|
||||
/*CTriggerAriocheObjective* CRMObjective::FindRandomTrigger ( )
|
||||
{
|
||||
CEntity* search;
|
||||
CEntity* triggers[20];
|
||||
int numTriggers;
|
||||
|
||||
// Start off the first trigger
|
||||
numTriggers = 0;
|
||||
search = entitySystem->GetEntityFromClassname ( NULL, "trigger_arioche_objective" );
|
||||
|
||||
// Make a list of triggers
|
||||
while ( numTriggers < 20 && search )
|
||||
{
|
||||
CTriggerAriocheObjective* trigger = (CTriggerAriocheObjective*) search;
|
||||
|
||||
// Move on to the next trigger
|
||||
search = entitySystem->GetEntityFromClassname ( search, "trigger_arioche_objective" );
|
||||
|
||||
// See if this trigger is already in use
|
||||
if ( trigger->GetObjective ( ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the objective names dont match then ignore this trigger
|
||||
if ( stricmp ( trigger->GetObjectiveName ( ), GetTrigger() ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add the trigger to the list
|
||||
triggers[numTriggers++] = trigger;
|
||||
}
|
||||
|
||||
// If no matching triggers then just return NULL
|
||||
if ( 0 == numTriggers )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Return a random choice from the trigger list
|
||||
return (CTriggerAriocheObjective*)triggers[TheRandomMissionManager->GetLandScape()->irand(0,numTriggers-1)];
|
||||
}
|
||||
*/
|
||||
/************************************************************************************************
|
||||
* CRMObjective::Link
|
||||
* Links the objective into the world using the current state of the world to determine
|
||||
* where it should link
|
||||
*
|
||||
* inputs:
|
||||
* none
|
||||
*
|
||||
* return:
|
||||
* true: objective successfully linked
|
||||
* false: objective failed to link
|
||||
*
|
||||
************************************************************************************************/
|
||||
bool CRMObjective::Link ( )
|
||||
{
|
||||
/* CTriggerAriocheObjective* trigger;
|
||||
|
||||
// Look for a random trigger to associate this objective to.
|
||||
trigger = FindRandomTrigger ( );
|
||||
if ( NULL != trigger )
|
||||
{
|
||||
trigger->SetObjective ( this );
|
||||
}
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
65
code/RMG/RM_Objective.h
Normal file
65
code/RMG/RM_Objective.h
Normal file
@@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
#if !defined(RM_OBJECTIVE_H_INC)
|
||||
#define RM_OBJECTIVE_H_INC
|
||||
|
||||
#ifdef DEBUG_LINKING
|
||||
#pragma message("...including RM_Objective.h")
|
||||
#endif
|
||||
|
||||
class CRMObjective
|
||||
{
|
||||
protected:
|
||||
|
||||
bool mCompleted; // Is objective completed?
|
||||
bool mActive; // set to false if the objective requires another objective to be met first
|
||||
int mPriority; // sequence in which objectives need to be completed
|
||||
int mOrderIndex; // objective index in ui
|
||||
int mCompleteSoundID; // sound for when objective is finished
|
||||
string mMessage; // message outputed when objective is completed
|
||||
string mDescription; // description of objective
|
||||
string mInfo; // more info for objective
|
||||
string mName; // name of objective
|
||||
string mTrigger; // trigger associated with objective
|
||||
|
||||
public:
|
||||
|
||||
CRMObjective(CGPGroup *group);
|
||||
~CRMObjective(void) {}
|
||||
|
||||
bool Link (void);
|
||||
|
||||
bool IsCompleted (void) const { return mCompleted; }
|
||||
bool IsActive (void) const { return mActive; }
|
||||
|
||||
void Activate (void) { mActive = true; }
|
||||
void Complete (bool comp) { mCompleted = comp;}
|
||||
|
||||
// Get methods
|
||||
int GetPriority(void){return mPriority;}
|
||||
int GetOrderIndex(void) { return mOrderIndex; }
|
||||
const char* GetMessage(void) { return mMessage.c_str(); }
|
||||
const char* GetDescription(void) { return mDescription.c_str(); }
|
||||
const char* GetInfo(void) { return mInfo.c_str(); }
|
||||
const char* GetName(void) { return mName.c_str(); }
|
||||
const char* GetTrigger(void) { return mTrigger.c_str(); }
|
||||
int CompleteSoundID() { return mCompleteSoundID; };
|
||||
|
||||
// Set methods
|
||||
void SetPriority(int priority){mPriority = priority;}
|
||||
void SetOrderIndex(int order) { mOrderIndex = order; }
|
||||
void SetMessage(const char* msg) { mMessage = msg; }
|
||||
void SetDescription(const char* desc) { mDescription = desc; }
|
||||
void SetInfo(const char* info) { mInfo = info; }
|
||||
void SetName(const char* name) { mName = name; }
|
||||
void SetTrigger(const char* name) { mTrigger = name; }
|
||||
|
||||
private:
|
||||
|
||||
// CTriggerAriocheObjective* FindRandomTrigger ( );
|
||||
};
|
||||
|
||||
typedef list<CRMObjective *>::iterator rmObjectiveIter_t;
|
||||
typedef list<CRMObjective *> rmObjectiveList_t;
|
||||
|
||||
|
||||
#endif
|
||||
721
code/RMG/RM_Path.cpp
Normal file
721
code/RMG/RM_Path.cpp
Normal file
@@ -0,0 +1,721 @@
|
||||
/************************************************************************************************
|
||||
*
|
||||
* Copyright (C) 2001-2002 Raven Software
|
||||
*
|
||||
* RM_Path.cpp
|
||||
*
|
||||
************************************************************************************************/
|
||||
#include "../server/exe_headers.h"
|
||||
|
||||
#include "rm_headers.h"
|
||||
|
||||
#define max(a,b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMNode::CRMNode
|
||||
* constructor
|
||||
*
|
||||
* inputs:
|
||||
* none
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
CRMNode::CRMNode ( )
|
||||
{
|
||||
int i;
|
||||
|
||||
mFlattenHeight = -1;
|
||||
|
||||
mPos[0] = 0;
|
||||
mPos[1] = 0;
|
||||
mPos[2] = 0;
|
||||
|
||||
// no paths
|
||||
for (i = 0; i < DIR_MAX; i++)
|
||||
mPathID[i] = -1;
|
||||
|
||||
mAreaPointPlaced = false;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMPathManager::CRMPathManager
|
||||
* constructor
|
||||
*
|
||||
* inputs:
|
||||
* none
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
CRMPathManager::CRMPathManager ( CRandomTerrain* terrain )
|
||||
: mXNodes(0), mYNodes(0), mPathCount(0), mRiverCount(0), mMaxDepth(0), mDepth(0),
|
||||
mPathPoints(10), mPathMinWidth(0.02f), mPathMaxWidth(0.04f), mPathDepth(0.3f), mPathDeviation(0.03f), mPathBreadth(5),
|
||||
mRiverDepth(5), mRiverPoints(10), mRiverMinWidth(0.01f), mRiverMaxWidth(0.02f), mRiverBedDepth(1), mRiverDeviation(0.01f), mRiverBreadth(7),
|
||||
mTerrain(terrain), mCrossed(false)
|
||||
{
|
||||
}
|
||||
|
||||
CRMPathManager::~CRMPathManager ( )
|
||||
{
|
||||
int i,j;
|
||||
|
||||
for ( i = mLocations.size() - 1; i >=0; i-- )
|
||||
{
|
||||
if (mLocations[i])
|
||||
delete mLocations[i];
|
||||
}
|
||||
mLocations.clear();
|
||||
|
||||
for ( j = mNodes.size() - 1; j >=0; j-- )
|
||||
{
|
||||
if (mNodes[j])
|
||||
delete mNodes[j];
|
||||
}
|
||||
mNodes.clear();
|
||||
}
|
||||
|
||||
void CRMPathManager::CreateLocation ( const char* name, const int min_depth, int max_depth, const int min_paths, int max_paths )
|
||||
{
|
||||
int i;
|
||||
|
||||
// sanity checks -- dmv
|
||||
if( max_paths < min_paths )
|
||||
{
|
||||
Com_Printf("[CreateLocation()] ERROR : max_paths < min_paths :: set max_paths = min_paths\n" );
|
||||
max_paths = min_paths;
|
||||
}
|
||||
if( max_depth < min_depth )
|
||||
{
|
||||
Com_Printf("[CreateLocation()] ERROR : max_depth < min_depth :: set max_depth = min_depth\n" );
|
||||
max_depth = min_depth;
|
||||
}
|
||||
|
||||
for (i = mLocations.size()-1; i>=0; --i)
|
||||
if ( !stricmp ( name, mLocations[i]->GetName ( ) ) )
|
||||
{
|
||||
mLocations[i]->SetMinDepth(min_depth);
|
||||
mLocations[i]->SetMaxDepth(max_depth);
|
||||
mLocations[i]->SetMinPaths(min_paths);
|
||||
mLocations[i]->SetMaxPaths(max_paths);
|
||||
return;
|
||||
}
|
||||
|
||||
CRMLoc* pLoc= new CRMLoc(name, min_depth, max_depth, min_paths, max_paths);
|
||||
mLocations.push_back(pLoc);
|
||||
mMaxDepth = max(mMaxDepth, max_depth);
|
||||
}
|
||||
|
||||
void CRMPathManager::ClearCells(int x_nodes, int y_nodes)
|
||||
{
|
||||
int x,y;
|
||||
|
||||
// clear cell array - used for generating paths
|
||||
CRMCell empty;
|
||||
for (x=0; x < x_nodes * y_nodes; x++)
|
||||
{
|
||||
if (x >= mCells.size())
|
||||
mCells.push_back(empty);
|
||||
else
|
||||
mCells[x] = empty;
|
||||
}
|
||||
|
||||
// set borders of world
|
||||
for (y = 0; y < y_nodes; y++)
|
||||
{
|
||||
mCells[y * x_nodes].SetBorder(DIR_W );
|
||||
mCells[y * x_nodes].SetBorder(DIR_SW );
|
||||
mCells[y * x_nodes].SetBorder(DIR_NW );
|
||||
mCells[y * x_nodes + x_nodes-1].SetBorder( DIR_E );
|
||||
mCells[y * x_nodes + x_nodes-1].SetBorder( DIR_NE );
|
||||
mCells[y * x_nodes + x_nodes-1].SetBorder( DIR_SE );
|
||||
}
|
||||
|
||||
for (x = 0; x < x_nodes; x++)
|
||||
{
|
||||
mCells[x].SetBorder( DIR_N );
|
||||
mCells[x].SetBorder( DIR_NE );
|
||||
mCells[x].SetBorder( DIR_NW );
|
||||
mCells[(y_nodes-1) * x_nodes + x].SetBorder( DIR_S );
|
||||
mCells[(y_nodes-1) * x_nodes + x].SetBorder( DIR_SE );
|
||||
mCells[(y_nodes-1) * x_nodes + x].SetBorder( DIR_SW );
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMPathManager::CreateArray
|
||||
* Create array of nodes that are spaced over the landscape.
|
||||
* Create array of cells, which is used to determine how nodes are connected.
|
||||
*
|
||||
* inputs:
|
||||
* x_nodes, y_nodes - how many nodes in each dimension to layout
|
||||
*
|
||||
* return:
|
||||
* true if the node array was created, false if we have a problem
|
||||
*
|
||||
************************************************************************************************/
|
||||
bool CRMPathManager::CreateArray(const int x_nodes, const int y_nodes)
|
||||
{
|
||||
mXNodes = x_nodes;
|
||||
mYNodes = y_nodes;
|
||||
|
||||
// fill node array with positions that are spaced over the landscape
|
||||
int x,y;
|
||||
|
||||
// dump existing nodes
|
||||
for ( x = mNodes.size() - 1; x >=0; x-- )
|
||||
{
|
||||
if (mNodes[x])
|
||||
delete mNodes[x];
|
||||
}
|
||||
mNodes.clear();
|
||||
mNodes.resize(mXNodes * mYNodes, NULL);
|
||||
|
||||
// add a small amount of random jitter to spots chosen
|
||||
float x_rnd = 0.2f / (mXNodes+1);
|
||||
float y_rnd = 0.2f / (mYNodes+1);
|
||||
|
||||
for (x = 0; x < mXNodes; x++)
|
||||
{
|
||||
float cell_x = (x + 1.0f) / (mXNodes+1);
|
||||
// float cell_x = (x + 2.0f) / (mXNodes+3);
|
||||
|
||||
for (y = 0; y < mYNodes; y++)
|
||||
{
|
||||
vec3_t pos;
|
||||
CRMNode * pnode = new CRMNode();
|
||||
mNodes[x + y*mXNodes] = pnode;
|
||||
|
||||
float cell_y = (y + 1.0f) / (mYNodes+1);
|
||||
// float cell_y = (y + 2.0f) / (mYNodes+3);
|
||||
|
||||
pos[0] = TheRandomMissionManager->GetLandScape()->flrand(cell_x - x_rnd, cell_x + x_rnd);
|
||||
pos[1] = TheRandomMissionManager->GetLandScape()->flrand(cell_y - y_rnd, cell_y + y_rnd);
|
||||
pos[2] = 0;
|
||||
|
||||
SetNodePos(x, y, pos);
|
||||
}
|
||||
}
|
||||
|
||||
ClearCells(mXNodes, mYNodes);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// neighbor offsets - easy way to turn a direction into the array position for a neighboring cell or node
|
||||
int CRMPathManager::neighbor_x[DIR_MAX] = { 0, 1, 1, 1, 0,-1,-1,-1};
|
||||
int CRMPathManager::neighbor_y[DIR_MAX] = {-1,-1, 0, 1, 1, 1, 0,-1};
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMPathManager::PlaceLocation
|
||||
* This method is used to determine if a named location should be placed at this node.
|
||||
*
|
||||
* inputs:
|
||||
* c_x, c_y - cell to examine
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
void CRMPathManager::PlaceLocation(const int c_x, const int c_y)
|
||||
{
|
||||
if ( !Node(c_x,c_y)->IsLocation() )
|
||||
{ // not currently a location
|
||||
|
||||
// how many paths lead to this cell?
|
||||
int count_paths = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i<DIR_MAX; i++)
|
||||
if (Node(c_x,c_y)->PathExist(i))
|
||||
count_paths++;
|
||||
|
||||
int deepest_depth = -1;
|
||||
int deepest_loc = -1;
|
||||
for (i = mLocations.size()-1; i>=0; --i)
|
||||
{
|
||||
if (!mLocations[i]->Placed() && // node has not been placed
|
||||
mLocations[i]->MinDepth() <= mDepth && // our current depth is in the proper range
|
||||
mLocations[i]->MaxDepth() >= mDepth &&
|
||||
mLocations[i]->MinPaths() <= count_paths && // our path count is in the proper range
|
||||
mLocations[i]->MaxPaths() >= count_paths &&
|
||||
mLocations[i]->MaxDepth() > deepest_depth) // and this is the deepest location of the ones that match
|
||||
{
|
||||
deepest_loc = i;
|
||||
deepest_depth = mLocations[i]->MaxDepth();
|
||||
}
|
||||
}
|
||||
|
||||
if (deepest_loc >= 0 && deepest_loc < mLocations.size())
|
||||
{ // found a location to place at this node / cell
|
||||
const char * name = mLocations[deepest_loc]->GetName();
|
||||
Node(c_x,c_y)->SetName(name);
|
||||
mLocations[deepest_loc]->SetPlaced(true);
|
||||
|
||||
// need a new max depth
|
||||
int max_depth = -1;
|
||||
for (i = mLocations.size()-1; i>=0; --i)
|
||||
{
|
||||
// figure out new max depth based on the max depth of unplaced locations
|
||||
if (!mLocations[i]->Placed() && // node has not been placed
|
||||
mLocations[i]->MaxDepth() > max_depth) // and this is the deepest
|
||||
{
|
||||
max_depth = mLocations[i]->MaxDepth();
|
||||
}
|
||||
}
|
||||
mMaxDepth = max_depth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMPathManager::PathVisit
|
||||
* This method is called recursively to create a network of nodes connected with paths.
|
||||
*
|
||||
* inputs:
|
||||
* c_x, c_y - cell to visit
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
void CRMPathManager::PathVisit(const int c_x, const int c_y)
|
||||
{
|
||||
// does this cell have any neighbors with all walls intact?
|
||||
int i,off;
|
||||
|
||||
// look at neighbors in random order
|
||||
off = TheRandomMissionManager->GetLandScape()->irand(DIR_FIRST, DIR_MAX-1);
|
||||
|
||||
++mDepth; // track our depth of recursion
|
||||
|
||||
for (i = DIR_FIRST; i<DIR_MAX && mDepth <= mMaxDepth; i++)
|
||||
{
|
||||
int d = (i + off) % DIR_MAX;
|
||||
if ( !Cell(c_x, c_y).Border(d) )
|
||||
{ // we can move this way, since no border
|
||||
int new_c_x = c_x + neighbor_x[d];
|
||||
int new_c_y = c_y + neighbor_y[d];
|
||||
if (Cell(new_c_x,new_c_y).Wall() == DIR_ALL)
|
||||
{ // we have a new cell that has not been visited!
|
||||
int new_dir;
|
||||
// d is the direction relative to the current cell
|
||||
// new_dir is the direction relative to the next cell (N becomes S, NE becomes SW, etc...)
|
||||
if( d < HALF_DIR_MAX )
|
||||
{
|
||||
new_dir = d + HALF_DIR_MAX;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_dir = d - HALF_DIR_MAX;
|
||||
}
|
||||
|
||||
// knock down walls
|
||||
Cell(c_x,c_y).RemoveWall(d);
|
||||
Cell(new_c_x,new_c_y).RemoveWall(new_dir); //DIR_MAX - d);
|
||||
|
||||
// set path id
|
||||
Node(c_x, c_y)->SetPath(d, mPathCount);
|
||||
Node(new_c_x, new_c_y)->SetPath(new_dir, mPathCount); //DIR_MAX - d, mPathCount);
|
||||
|
||||
// create path between cells
|
||||
mTerrain->CreatePath( mPathCount++,
|
||||
-1,
|
||||
0,
|
||||
mPathPoints,
|
||||
GetNodePos(c_x,c_y)[0],
|
||||
GetNodePos(c_x,c_y)[1],
|
||||
GetNodePos(new_c_x,new_c_y)[0],
|
||||
GetNodePos(new_c_x,new_c_y)[1],
|
||||
mPathMinWidth,
|
||||
mPathMaxWidth,
|
||||
mPathDepth,
|
||||
mPathDeviation,
|
||||
mPathBreadth );
|
||||
|
||||
// flatten a small spot
|
||||
CArea area;
|
||||
float flat_radius = mPathMaxWidth *
|
||||
fabs(TheRandomMissionManager->GetLandScape()->GetBounds()[1][0] - TheRandomMissionManager->GetLandScape()->GetBounds()[0][0]);
|
||||
area.Init( GetNodePos(c_x,c_y), flat_radius, 0.0f, AT_NONE, 0, 0 );
|
||||
TheRandomMissionManager->GetLandScape()->FlattenArea(&area, 255 * mPathDepth, false, true, true );
|
||||
|
||||
// recurse
|
||||
PathVisit(new_c_x, new_c_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
--mDepth;
|
||||
|
||||
// NOTE: *whoop* hack alert, the first time this is reached, it should be the very last placed node.
|
||||
if( !mCrossed && TheRandomMissionManager->GetMission()->GetSymmetric() &&
|
||||
TheRandomMissionManager->GetMission()->GetBackUpPath() )
|
||||
{
|
||||
mCrossed = true;
|
||||
|
||||
int directionSet[3][3] = {DIR_NW,DIR_W,DIR_SW,DIR_N,-1,DIR_S,DIR_NE,DIR_E,DIR_SE};
|
||||
int ncx = (mXNodes-1)-c_x;
|
||||
int ncy = (mYNodes-1)-c_y;
|
||||
|
||||
int x_delta = ncx - c_x;
|
||||
int y_delta = ncy - c_y;
|
||||
|
||||
if( x_delta < -1 )
|
||||
{
|
||||
x_delta = -1;
|
||||
}
|
||||
else if( x_delta > 1 )
|
||||
{
|
||||
x_delta = 1;
|
||||
}
|
||||
|
||||
if( y_delta < -1 )
|
||||
{
|
||||
y_delta = -1;
|
||||
}
|
||||
else if( y_delta > 1 )
|
||||
{
|
||||
y_delta = 1;
|
||||
}
|
||||
|
||||
// make sure the mirror is actually in a different position than then un-mirrored node
|
||||
if( x_delta || y_delta )
|
||||
{
|
||||
|
||||
int d = directionSet[x_delta][y_delta];
|
||||
int new_dir;
|
||||
// d is the direction relative to the current cell
|
||||
// new_dir is the direction relative to the next cell (N becomes S, NE becomes SW, etc...)
|
||||
if( d < HALF_DIR_MAX )
|
||||
{
|
||||
new_dir = d + HALF_DIR_MAX;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_dir = d - HALF_DIR_MAX;
|
||||
}
|
||||
|
||||
//NOTE: Knocking down these walls will cause instances to be created on this new artificial path
|
||||
// Since this path could span more than just the normal 1 cell, these walls being knocked down are not exactly correct... but get the job done
|
||||
|
||||
// knock down walls
|
||||
Cell(c_x,c_y).RemoveWall(d);
|
||||
Cell(ncx,ncy).RemoveWall(new_dir); //DIR_MAX - d);
|
||||
|
||||
// set path id
|
||||
Node(c_x, c_y)->SetPath(d, mPathCount);
|
||||
Node(ncx, ncy)->SetPath(new_dir, mPathCount); //DIR_MAX - d, mPathCount);
|
||||
|
||||
// create an artificial path that crosses over to connect the symmetric and non-symmetric map parts
|
||||
mTerrain->CreatePath( mPathCount++,
|
||||
-1,
|
||||
0,
|
||||
mPathPoints,
|
||||
GetNodePos(c_x,c_y)[0],
|
||||
GetNodePos(c_x,c_y)[1],
|
||||
GetNodePos(ncx,ncy)[0],
|
||||
GetNodePos(ncx,ncy)[1],
|
||||
mPathMinWidth,
|
||||
mPathMaxWidth,
|
||||
mPathDepth,
|
||||
mPathDeviation,
|
||||
mPathBreadth );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
PlaceLocation(c_x, c_y);
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMPathManager::FindNodeByName
|
||||
* Finds the managed node with the matching case-insensivity name
|
||||
*
|
||||
* inputs:
|
||||
* name - name of the node to find
|
||||
*
|
||||
* return:
|
||||
* a pointer to the found node or NULL if the node couldn't be found
|
||||
*
|
||||
************************************************************************************************/
|
||||
CRMNode* CRMPathManager::FindNodeByName ( const char* name )
|
||||
{
|
||||
int j;
|
||||
|
||||
for ( j = mNodes.size() - 1; j >=0; j-- )
|
||||
{
|
||||
if ( !stricmp ( name, mNodes[j]->GetName ( ) ) )
|
||||
return mNodes[j];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMPathManager::SetPathStyle
|
||||
* sets style for all paths
|
||||
*
|
||||
* inputs:
|
||||
* settings for paths that are created
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
void CRMPathManager::SetPathStyle (
|
||||
const int points,
|
||||
const float minwidth,
|
||||
const float maxwidth,
|
||||
const float depth,
|
||||
const float deviation,
|
||||
const float breadth
|
||||
)
|
||||
{
|
||||
// save path style
|
||||
mPathPoints = points ;
|
||||
mPathMinWidth = minwidth;
|
||||
mPathMaxWidth = maxwidth;
|
||||
mPathDepth = depth ;
|
||||
mPathDeviation= deviation;
|
||||
mPathBreadth = breadth ;
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMPathManager::SetRiverStyle
|
||||
* sets style for all rivers
|
||||
*
|
||||
* inputs:
|
||||
* settings for river paths that are created
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
void CRMPathManager::SetRiverStyle (const int depth,
|
||||
const int points,
|
||||
const float minwidth,
|
||||
const float maxwidth,
|
||||
const float beddepth,
|
||||
const float deviation,
|
||||
const float breadth,
|
||||
string bridge_name)
|
||||
{
|
||||
// save river style
|
||||
mRiverDepth = depth;
|
||||
mRiverPoints = points ;
|
||||
mRiverMinWidth = minwidth;
|
||||
mRiverMaxWidth = maxwidth;
|
||||
mRiverBedDepth = beddepth ;
|
||||
mRiverDeviation= deviation;
|
||||
mRiverBreadth = breadth ;
|
||||
mRiverBridge = bridge_name;
|
||||
}
|
||||
|
||||
vec3_t& CRMPathManager::GetRiverPos( const int x, const int y )
|
||||
{
|
||||
mRiverPos[0] = (float)(x + 1.0f) / (float)(mXNodes+2);
|
||||
mRiverPos[1] = (float)(y + 1.0f) / (float)(mYNodes+2);
|
||||
return mRiverPos;
|
||||
}
|
||||
|
||||
void CRMPathManager::RiverVisit(const int c_x, const int c_y)
|
||||
{
|
||||
// does this cell have any neighbors with all walls intact?
|
||||
int i,off;
|
||||
|
||||
// look at neighbors in random order
|
||||
off = TheRandomMissionManager->GetLandScape()->irand(DIR_FIRST, DIR_MAX-1);
|
||||
|
||||
++mDepth; // track our depth of recursion
|
||||
|
||||
for (i = DIR_FIRST; i<DIR_MAX && mDepth <= mMaxDepth; i+=2)
|
||||
{
|
||||
int d = (i + off) % DIR_MAX;
|
||||
if ( !Cell(c_x, c_y).Border(d) )
|
||||
{ // we can move this way, since no border
|
||||
int new_c_x = c_x + neighbor_x[d];
|
||||
int new_c_y = c_y + neighbor_y[d];
|
||||
if (RiverCell(new_c_x,new_c_y).Wall() == DIR_ALL)
|
||||
{ // we have a new cell that has not been visited!
|
||||
|
||||
int new_dir;
|
||||
// d is the direction relative to the current cell
|
||||
// new_dir is the direction relative to the next cell (N becomes S, NE becomes SW, etc...)
|
||||
if( d < HALF_DIR_MAX )
|
||||
{
|
||||
new_dir = d + HALF_DIR_MAX;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_dir = d - HALF_DIR_MAX;
|
||||
}
|
||||
// knock down walls
|
||||
RiverCell(c_x,c_y).RemoveWall(d);
|
||||
RiverCell(new_c_x,new_c_y).RemoveWall(new_dir); //DIR_MAX - d);
|
||||
|
||||
// create river between cells
|
||||
mTerrain->CreatePath ( mPathCount++,
|
||||
-1,
|
||||
0,
|
||||
mRiverPoints,
|
||||
GetRiverPos(c_x,c_y)[0],
|
||||
GetRiverPos(c_x,c_y)[1],
|
||||
GetRiverPos(new_c_x,new_c_y)[0],
|
||||
GetRiverPos(new_c_x,new_c_y)[1],
|
||||
mRiverMinWidth,
|
||||
mRiverMaxWidth,
|
||||
mRiverBedDepth,
|
||||
mRiverDeviation,
|
||||
mRiverBreadth );
|
||||
|
||||
// flatten a small spot
|
||||
CArea area;
|
||||
float flat_radius = mRiverMinWidth *
|
||||
fabs(TheRandomMissionManager->GetLandScape()->GetBounds()[1][0] - TheRandomMissionManager->GetLandScape()->GetBounds()[0][0]);
|
||||
area.Init( GetRiverPos(c_x,c_y), flat_radius, 0.0f, AT_NONE, 0, 0 );
|
||||
TheRandomMissionManager->GetLandScape()->FlattenArea (&area, 255 * mRiverBedDepth, false, true, true );
|
||||
|
||||
// recurse
|
||||
RiverVisit(new_c_x, new_c_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --mDepth;
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMPathManager::GenerateRivers
|
||||
* Creates a river which intersects the main path
|
||||
*
|
||||
* inputs:
|
||||
* none
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
void CRMPathManager::GenerateRivers ()
|
||||
{
|
||||
if (mRiverBedDepth == 1)
|
||||
// no rivers
|
||||
return;
|
||||
|
||||
mMaxDepth = mRiverDepth;
|
||||
mDepth = 0;
|
||||
|
||||
int cell_x = 0;
|
||||
int cell_y = 0;
|
||||
|
||||
// choose starting cell along an edge
|
||||
int edge = TheRandomMissionManager->GetLandScape()->irand(0, 7);
|
||||
switch ( edge )
|
||||
{
|
||||
case 0:
|
||||
cell_x = mXNodes / 2; cell_y = 0;
|
||||
break;
|
||||
case 1:
|
||||
cell_x = mXNodes; cell_y = 0;
|
||||
break;
|
||||
case 2:
|
||||
cell_x = mXNodes; cell_y = mYNodes / 2;
|
||||
break;
|
||||
case 3:
|
||||
cell_x = mXNodes; cell_y = mYNodes;
|
||||
break;
|
||||
case 4:
|
||||
cell_x = mXNodes / 2; cell_y = mYNodes;
|
||||
break;
|
||||
case 5:
|
||||
cell_x = 0; cell_y = mYNodes;
|
||||
break;
|
||||
case 6:
|
||||
cell_x = 0; cell_y = mYNodes / 2;
|
||||
break;
|
||||
case 7:
|
||||
cell_x = 0; cell_y = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
ClearCells(mXNodes+1, mYNodes+1);
|
||||
|
||||
mRiverCount = mPathCount;
|
||||
|
||||
// visit the first cell
|
||||
RiverVisit(cell_x,cell_y);
|
||||
|
||||
mRiverCount = mPathCount - mRiverCount;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* CRMPathManager::GeneratePaths
|
||||
* Creates all paths
|
||||
*
|
||||
* inputs:
|
||||
* none
|
||||
*
|
||||
* return:
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
void CRMPathManager::GeneratePaths ( symmetry_t symmetric )
|
||||
{
|
||||
int cell_x = 0;
|
||||
int cell_y = 0;
|
||||
|
||||
switch ( symmetric )
|
||||
{
|
||||
case SYMMETRY_TOPLEFT:
|
||||
cell_x = mXNodes-1;
|
||||
cell_y = 0;
|
||||
break;
|
||||
|
||||
case SYMMETRY_BOTTOMRIGHT:
|
||||
cell_x = 0;
|
||||
cell_y = mYNodes-1;
|
||||
break;
|
||||
|
||||
default:
|
||||
case SYMMETRY_NONE:
|
||||
// choose starting cell along an edge
|
||||
switch ( TheRandomMissionManager->GetLandScape()->irand(0, 7) )
|
||||
{
|
||||
case 0:
|
||||
cell_x = mXNodes / 2;
|
||||
break;
|
||||
case 1:
|
||||
cell_x = mXNodes-1;
|
||||
break;
|
||||
case 2:
|
||||
cell_x = mXNodes-1; cell_y = mYNodes / 2;
|
||||
break;
|
||||
case 3:
|
||||
cell_x = mXNodes-1; cell_y = mYNodes-1;
|
||||
break;
|
||||
case 4:
|
||||
cell_x = mXNodes / 2; cell_y = mYNodes-1;
|
||||
break;
|
||||
case 5:
|
||||
cell_y = mYNodes-1;
|
||||
break;
|
||||
case 6:
|
||||
cell_y = mYNodes / 2;
|
||||
break;
|
||||
default:
|
||||
case 7:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// visit the first cell
|
||||
PathVisit(cell_x,cell_y);
|
||||
}
|
||||
|
||||
223
code/RMG/RM_Path.h
Normal file
223
code/RMG/RM_Path.h
Normal file
@@ -0,0 +1,223 @@
|
||||
/************************************************************************************************
|
||||
*
|
||||
* Copyright (C) 2001-2002 Raven Software
|
||||
*
|
||||
* RM_Path.h
|
||||
*
|
||||
************************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
#if !defined(RM_PATH_H_INC)
|
||||
#define RM_PATH_H_INC
|
||||
|
||||
#ifdef DEBUG_LINKING
|
||||
#pragma message("...including RM_Path.h")
|
||||
#endif
|
||||
|
||||
#if !defined(CM_RANDOMTERRAIN_H_INC)
|
||||
#include "../qcommon/cm_randomterrain.h"
|
||||
#endif
|
||||
|
||||
class CRMPathManager;
|
||||
|
||||
// directions you can proceed from cells
|
||||
enum ERMDir
|
||||
{
|
||||
DIR_FIRST= 0,
|
||||
DIR_N = 0,
|
||||
DIR_NE,
|
||||
DIR_E ,
|
||||
DIR_SE,
|
||||
DIR_S ,
|
||||
DIR_SW,
|
||||
DIR_W ,
|
||||
DIR_NW,
|
||||
DIR_MAX,
|
||||
DIR_ALL = 255
|
||||
};
|
||||
|
||||
#define HALF_DIR_MAX (DIR_MAX/2)
|
||||
|
||||
class CRMNode
|
||||
{
|
||||
private:
|
||||
|
||||
string mName; // name of node - "" if not used yet
|
||||
vec3_t mPos; // where node is
|
||||
int mPathID[DIR_MAX]; // path id's that lead from this node
|
||||
bool mAreaPointPlaced; // false if no area point here yet.
|
||||
|
||||
int mFlattenHeight;
|
||||
|
||||
public:
|
||||
|
||||
CRMNode ( );
|
||||
|
||||
bool IsLocation() {return strlen(mName.c_str())>0;};
|
||||
const char* GetName ( ) { return mName.c_str(); }
|
||||
vec3_t& GetPos ( ) { return mPos; }
|
||||
const float PathExist( const int dir) { return (mPathID[dir % DIR_MAX] != -1); };
|
||||
const float GetPath ( const int dir) { return mPathID[dir % DIR_MAX]; };
|
||||
bool AreaPoint() {return mAreaPointPlaced;};
|
||||
|
||||
void SetName ( const char* name ) { mName = name; }
|
||||
void SetPos ( const vec3_t& v ) { VectorCopy ( v, mPos ); }
|
||||
void SetPath( const int dir, const int id) { mPathID[dir % DIR_MAX] = id; };
|
||||
void SetAreaPoint(bool ap) {mAreaPointPlaced = ap;};
|
||||
|
||||
void SetFlattenHeight(int flattenHeight) {mFlattenHeight = flattenHeight; }
|
||||
int GetFlattenHeight() {return mFlattenHeight; }
|
||||
};
|
||||
|
||||
typedef vector<CRMNode*> rmNodeVector_t;
|
||||
|
||||
// named spots on the map, should be placed into nodes
|
||||
class CRMLoc
|
||||
{
|
||||
private:
|
||||
|
||||
string mName; // name of location
|
||||
int mMinDepth;
|
||||
int mMaxDepth;
|
||||
int mMinPaths;
|
||||
int mMaxPaths;
|
||||
bool mPlaced; // location has been placed at a node
|
||||
|
||||
public:
|
||||
CRMLoc (const char *name, const int min_depth, const int max_depth, const int min_paths =1, const int max_paths=1 )
|
||||
: mMinDepth(min_depth), mMaxDepth(max_depth), mPlaced(false), mMinPaths(min_paths), mMaxPaths(max_paths)
|
||||
{ mName = name; };
|
||||
|
||||
const char* GetName ( ) { return mName.c_str(); }
|
||||
void SetName ( const char* name ) { mName = name; }
|
||||
|
||||
int MinDepth() {return mMinDepth;};
|
||||
void SetMinDepth(const int deep) {mMinDepth = deep;};
|
||||
|
||||
int MaxDepth() {return mMaxDepth;};
|
||||
void SetMaxDepth(const int deep) {mMaxDepth = deep;};
|
||||
|
||||
int MinPaths() {return mMinPaths;};
|
||||
void SetMinPaths(const int paths) {mMinPaths = paths;};
|
||||
|
||||
int MaxPaths() {return mMaxPaths;};
|
||||
void SetMaxPaths(const int paths) {mMaxPaths = paths;};
|
||||
|
||||
bool Placed() { return mPlaced; };
|
||||
void SetPlaced(bool p) { mPlaced = p;};
|
||||
};
|
||||
|
||||
typedef vector<CRMLoc*> rmLocVector_t;
|
||||
|
||||
|
||||
// cells are used for figuring out node connections / paths
|
||||
struct CRMCell
|
||||
{
|
||||
private:
|
||||
int border;
|
||||
int wall;
|
||||
|
||||
public:
|
||||
CRMCell() { border = 0; wall = DIR_ALL; };
|
||||
|
||||
int Border() {return border;};
|
||||
int Wall() {return wall;};
|
||||
bool Border(const int dir) { return (border & (1<<dir))!=0; };
|
||||
bool Wall(const int dir) { return (wall & (1<<dir))!=0; };
|
||||
void SetBorder(const int dir) { border |= (1<<dir); };
|
||||
void SetWall(const int dir) { wall |= (1<<dir); };
|
||||
void RemoveWall(const int dir) { wall &= ~(1<<dir); };
|
||||
};
|
||||
|
||||
typedef vector<CRMCell> rmCellVector_t;
|
||||
|
||||
|
||||
class CRMPathManager
|
||||
{
|
||||
public:
|
||||
int mXNodes; // number of nodes in the x dimension
|
||||
int mYNodes; // number of nodes in the y dimension
|
||||
|
||||
private:
|
||||
rmLocVector_t mLocations; // location, named spots to be placed at nodes
|
||||
rmNodeVector_t mNodes; // nodes, spots on map that *may* be connected by paths
|
||||
rmCellVector_t mCells; // array of cells for doing path generation
|
||||
|
||||
int mPathCount;
|
||||
int mRiverCount;
|
||||
int mMaxDepth; // deepest any location wants to be
|
||||
int mDepth; // current depth
|
||||
|
||||
bool mCrossed; // used to indicate if paths crossed the imaginary diagonal that cuts symmetric maps in half
|
||||
|
||||
// path style
|
||||
int mPathPoints;
|
||||
float mPathMinWidth;
|
||||
float mPathMaxWidth;
|
||||
float mPathDepth;
|
||||
float mPathDeviation;
|
||||
float mPathBreadth;
|
||||
|
||||
// river style
|
||||
int mRiverDepth;
|
||||
int mRiverPoints;
|
||||
float mRiverMinWidth;
|
||||
float mRiverMaxWidth;
|
||||
float mRiverBedDepth;
|
||||
float mRiverDeviation;
|
||||
float mRiverBreadth;
|
||||
string mRiverBridge;
|
||||
vec3_t mRiverPos;
|
||||
|
||||
static int neighbor_x[DIR_MAX];
|
||||
static int neighbor_y[DIR_MAX];
|
||||
|
||||
CRandomTerrain* mTerrain;
|
||||
|
||||
public:
|
||||
CRMPathManager ( CRandomTerrain* terrain );
|
||||
~CRMPathManager ( );
|
||||
|
||||
void ClearCells (int x_nodes, int y_nodes);
|
||||
bool CreateArray ( const int x_nodes, const int y_nodes );
|
||||
|
||||
CRMNode* FindNodeByName ( const char* name );
|
||||
CRMNode* Node ( const int x, const int y ) {return mNodes[x + y*mXNodes];};
|
||||
|
||||
void CreateLocation ( const char* name, const int min_depth, int max_depth, const int min_paths =1, int max_paths =1 );
|
||||
|
||||
vec3_t& GetNodePos ( const int x, const int y ) { return mNodes[x + y*mXNodes]->GetPos(); };
|
||||
void SetNodePos ( const int x, const int y, const vec3_t& pos) { mNodes[x + y*mXNodes]->SetPos(pos); };
|
||||
int GetPathCount () {return mPathCount;};
|
||||
int GetRiverCount () {return mRiverCount;};
|
||||
float GetRiverDepth () {return mRiverBedDepth;};
|
||||
float GetPathDepth () {return mPathDepth;};
|
||||
const char *GetBridgeName () {return mRiverBridge.c_str();};
|
||||
vec3_t& GetRiverPos ( const int x, const int y );
|
||||
|
||||
CRMCell& Cell ( const int x, const int y ) {return mCells[x + y*mXNodes];};
|
||||
CRMCell& RiverCell ( const int x, const int y ) {return mCells[x + y*(mXNodes+1)];};
|
||||
void PlaceLocation ( const int x, const int y );
|
||||
void PathVisit ( const int x, const int y );
|
||||
void RiverVisit ( const int x, const int y );
|
||||
void SetPathStyle ( const int points = 10,
|
||||
const float minwidth = 0.01f,
|
||||
const float maxwidth = 0.05f,
|
||||
const float depth = 0.3f,
|
||||
const float deviation = 0.2f,
|
||||
const float breadth = 5);
|
||||
|
||||
void SetRiverStyle ( const int depth = 5,
|
||||
const int points = 10,
|
||||
const float minwidth = 0.01,
|
||||
const float maxwidth = 0.03,
|
||||
const float beddepth = 0.0f,
|
||||
const float deviation = 0.25f,
|
||||
const float breadth = 7,
|
||||
string bridge_name = "");
|
||||
|
||||
void GeneratePaths ( symmetry_t symmetric = SYMMETRY_NONE );
|
||||
void GenerateRivers ( );
|
||||
};
|
||||
|
||||
#endif
|
||||
533
code/RMG/RM_Terrain.cpp
Normal file
533
code/RMG/RM_Terrain.cpp
Normal file
@@ -0,0 +1,533 @@
|
||||
#include "../server/exe_headers.h"
|
||||
|
||||
#include "../client/client.h"
|
||||
#include "../qcommon/cm_local.h"
|
||||
#include "../renderer/tr_types.h"
|
||||
#include "rm_headers.h"
|
||||
|
||||
//#include "../qcommon/q_imath.h"
|
||||
|
||||
#pragma optimize("", off)
|
||||
|
||||
void R_LoadDataImage ( const char *name, byte **pic, int *width, int *height);
|
||||
void R_InvertImage ( byte *data, int width, int height, int depth);
|
||||
void R_Resample ( byte *source, int swidth, int sheight, byte *dest, int dwidth, int dheight, int components);
|
||||
void RE_GetModelBounds (refEntity_t *refEnt, vec3_t bounds1, vec3_t bounds2);
|
||||
|
||||
static CRMLandScape *rm_landscape;
|
||||
static CCMLandScape *origin_land;
|
||||
|
||||
CRMLandScape::CRMLandScape(void)
|
||||
{
|
||||
common = NULL;
|
||||
mDensityMap = NULL;
|
||||
}
|
||||
|
||||
CRMLandScape::~CRMLandScape(void)
|
||||
{
|
||||
if(mDensityMap)
|
||||
{
|
||||
Z_Free(mDensityMap);
|
||||
mDensityMap = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void CCGHeightDetails::AddModel(const CRandomModel *hd)
|
||||
{
|
||||
if(mNumModels < MAX_RANDOM_MODELS)
|
||||
{
|
||||
mTotalFrequency += hd->GetFrequency();
|
||||
mModels[mNumModels++] = *hd;
|
||||
}
|
||||
}
|
||||
|
||||
void CRMLandScape::AddModel(const int height, int maxheight, const CRandomModel *hd)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(maxheight > HEIGHT_RESOLUTION)
|
||||
{
|
||||
maxheight = HEIGHT_RESOLUTION;
|
||||
}
|
||||
|
||||
for(i = height; hd->GetModel() && (i < maxheight); i++)
|
||||
{
|
||||
mHeightDetails[i].AddModel(hd);
|
||||
}
|
||||
}
|
||||
|
||||
void CRMLandScape::LoadMiscentDef(const char *td)
|
||||
{
|
||||
char miscentDef[MAX_QPATH];
|
||||
CGenericParser2 parse;
|
||||
CGPGroup *basegroup, *classes, *items, *model;
|
||||
CGPValue *pair;
|
||||
|
||||
Com_sprintf(miscentDef, MAX_QPATH, "ext_data/RMG/%s.miscents", Info_ValueForKey(td, "miscentDef"));
|
||||
Com_DPrintf("CG_Terrain: Loading and parsing miscentDef %s.....\n", Info_ValueForKey(td, "miscentDef"));
|
||||
|
||||
if(!Com_ParseTextFile(miscentDef, parse))
|
||||
{
|
||||
Com_sprintf(miscentDef, MAX_QPATH, "ext_data/arioche/%s.miscents", Info_ValueForKey(td, "miscentDef"));
|
||||
if(!Com_ParseTextFile(miscentDef, parse))
|
||||
{
|
||||
Com_Printf("Could not open %s\n", miscentDef);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// The whole file....
|
||||
basegroup = parse.GetBaseParseGroup();
|
||||
|
||||
// The root { } struct
|
||||
classes = basegroup->GetSubGroups();
|
||||
while(classes)
|
||||
{
|
||||
items = classes->GetSubGroups();
|
||||
while(items)
|
||||
{
|
||||
if(!stricmp(items->GetName(), "miscent"))
|
||||
{
|
||||
int height, maxheight;
|
||||
|
||||
// Height must exist - the rest are optional
|
||||
height = atol(items->FindPairValue("height", "0"));
|
||||
maxheight = atol(items->FindPairValue("maxheight", "255"));
|
||||
|
||||
model = items->GetSubGroups();
|
||||
while(model)
|
||||
{
|
||||
if(!stricmp(model->GetName(), "model"))
|
||||
{
|
||||
CRandomModel hd;
|
||||
|
||||
// Set defaults
|
||||
hd.SetModel("");
|
||||
hd.SetFrequency(1.0f);
|
||||
hd.SetMinScale(1.0f);
|
||||
hd.SetMaxScale(1.0f);
|
||||
|
||||
pair = model->GetPairs();
|
||||
while(pair)
|
||||
{
|
||||
if(!stricmp(pair->GetName(), "name"))
|
||||
{
|
||||
hd.SetModel(pair->GetTopValue());
|
||||
}
|
||||
else if(!stricmp(pair->GetName(), "frequency"))
|
||||
{
|
||||
hd.SetFrequency((float)atof(pair->GetTopValue()));
|
||||
}
|
||||
else if(!stricmp(pair->GetName(), "minscale"))
|
||||
{
|
||||
hd.SetMinScale((float)atof(pair->GetTopValue()));
|
||||
}
|
||||
else if(!stricmp(pair->GetName(), "maxscale"))
|
||||
{
|
||||
hd.SetMaxScale((float)atof(pair->GetTopValue()));
|
||||
}
|
||||
pair = (CGPValue *)pair->GetNext();
|
||||
}
|
||||
AddModel(height, maxheight, &hd);
|
||||
}
|
||||
model = (CGPGroup *)model->GetNext();
|
||||
}
|
||||
}
|
||||
items = (CGPGroup *)items->GetNext();
|
||||
}
|
||||
classes = (CGPGroup *)classes->GetNext();
|
||||
}
|
||||
Com_ParseTextFileDestroy(parse);
|
||||
}
|
||||
|
||||
void CG_Decrease(byte *work, float lerp, int *info)
|
||||
{
|
||||
int val;
|
||||
|
||||
val = *work - origin_land->irand(2, 5);
|
||||
*work = (byte)Com_Clamp(1, 255, val);
|
||||
}
|
||||
|
||||
void CRMLandScape::CreateRandomDensityMap(byte *density, int width, int height, int seed)
|
||||
{
|
||||
// int i, border, inc;
|
||||
int x, y, count;
|
||||
// byte *work, *work2;
|
||||
CArea *area;
|
||||
vec3_t derxelSize, pos;
|
||||
ivec3_t dmappos;
|
||||
byte *hm_map = common->GetHeightMap();
|
||||
int hm_width = common->GetRealWidth();
|
||||
int hm_height = common->GetRealHeight();
|
||||
int xpos, ypos, dx, dy;
|
||||
byte *densityPos = density;
|
||||
bool foundUneven;
|
||||
|
||||
// Init to linear spread
|
||||
memset(density, 0, width * height);
|
||||
|
||||
/* // Make more prevalent towards the edges
|
||||
border = Com_Clamp(6, 12, (width + height) >> 4);
|
||||
|
||||
for(i = 0; i < border; i++)
|
||||
{
|
||||
inc = (border - i + 1) * 9;
|
||||
|
||||
// Top line
|
||||
work = density + i + (i * width);
|
||||
for(x = i; x < width - i; x++, work++)
|
||||
{
|
||||
*work += (byte)common->irand(inc >> 1, inc);
|
||||
}
|
||||
|
||||
// Left and right edges
|
||||
work = density + i + ((i + 1) * width);
|
||||
work2 = density + (width - i) + ((i + 1) * width);
|
||||
for(y = i + 1; y < height - i - 2; y++, work += width, work2 += width)
|
||||
{
|
||||
*work += (byte)common->irand(inc >> 1, inc);
|
||||
*work2 += (byte)common->irand(inc >> 1, inc);
|
||||
}
|
||||
|
||||
// Bottom line
|
||||
work = density + i + ((height - i - 1) * width);
|
||||
for(x = i; x < width - i; x++, work++)
|
||||
{
|
||||
*work += (byte)common->irand(inc >> 1, inc);
|
||||
}
|
||||
}
|
||||
*/
|
||||
count = 0;
|
||||
|
||||
for(y=0;y<height;y++)
|
||||
{
|
||||
for(x=0;x<width;x++,densityPos++)
|
||||
{
|
||||
xpos = (x * hm_width / width);
|
||||
ypos = (y * hm_height / height);
|
||||
ypos = hm_height - ypos - 1;
|
||||
|
||||
if (hm_map[ypos*hm_width + xpos] < 150)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foundUneven = false;
|
||||
for(dx=-4;(dx<=4 && !foundUneven);dx++)
|
||||
{
|
||||
for(dy=-4;(dy<=4 && !foundUneven);dy++)
|
||||
{
|
||||
if (dx == 0 && dy == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if ((xpos+dx) >= 0 && (xpos+dx) < hm_width && (ypos+dy) >= 0 && (ypos+dy) < hm_height)
|
||||
{
|
||||
if (hm_map[(ypos+dy)*hm_width + (xpos+dx)] < 190)
|
||||
{
|
||||
*densityPos = 205;
|
||||
count++;
|
||||
foundUneven = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* FILE *FH;
|
||||
|
||||
FH = fopen("c:\o.raw", "wb");
|
||||
fwrite(hm_map, 1, common->GetRealWidth() * common->GetRealHeight(), FH);
|
||||
fclose(FH);
|
||||
|
||||
FH = fopen("c:\d.raw", "wb");
|
||||
fwrite(density, 1, width*height, FH);
|
||||
fclose(FH);
|
||||
*/
|
||||
// Reduce severely for any settlements/buildings/objectives
|
||||
VectorScale(common->GetSize(), 1.0f / width, derxelSize);
|
||||
|
||||
origin_land = common;
|
||||
area = common->GetFirstArea();
|
||||
while(area)
|
||||
{
|
||||
// Skip group types since they encompass to much open area
|
||||
if ( area->GetType ( ) == AT_GROUP )
|
||||
{
|
||||
area = common->GetNextArea();
|
||||
continue;
|
||||
}
|
||||
|
||||
VectorSubtract(area->GetPosition(), common->GetMins(), pos);
|
||||
VectorInverseScaleVector(pos, derxelSize, dmappos);
|
||||
// Damn upside down gensurf
|
||||
dmappos[1] = height - dmappos[1];
|
||||
|
||||
count = ceilf(area->GetRadius() / derxelSize[1]);
|
||||
|
||||
while(count > 0)
|
||||
{
|
||||
CM_CircularIterate(density, width, height, dmappos[0], dmappos[1], 0, count, NULL, CG_Decrease);
|
||||
count--;
|
||||
}
|
||||
area = common->GetNextArea();
|
||||
}
|
||||
}
|
||||
|
||||
void CRMLandScape::LoadDensityMap(const char *td)
|
||||
{
|
||||
char densityMap[MAX_QPATH];
|
||||
byte *imageData;
|
||||
int iWidth, iHeight, seed;
|
||||
char *ptr;
|
||||
|
||||
// Fill in with default values
|
||||
mDensityMap = (byte *)Z_Malloc(common->GetBlockCount(), TAG_R_TERRAIN, qfalse);
|
||||
memset(mDensityMap, 128, common->GetBlockCount());
|
||||
|
||||
// Load in density map (if any)
|
||||
Com_sprintf(densityMap, MAX_QPATH, "%s", Info_ValueForKey(td, "densityMap"));
|
||||
if(strlen(densityMap))
|
||||
{
|
||||
Com_DPrintf("CG_Terrain: Loading density map %s.....\n", densityMap);
|
||||
R_LoadDataImage(densityMap, &imageData, &iWidth, &iHeight);
|
||||
if(imageData)
|
||||
{
|
||||
if(strstr(densityMap, "density_"))
|
||||
{
|
||||
seed = strtoul(Info_ValueForKey(td, "seed"),&ptr,10);
|
||||
CreateRandomDensityMap(imageData, iWidth, iHeight, seed);
|
||||
}
|
||||
R_Resample(imageData, iWidth, iHeight, mDensityMap, common->GetBlockWidth(), common->GetBlockHeight(), 1);
|
||||
R_InvertImage(mDensityMap, common->GetBlockWidth(), common->GetBlockHeight(), 1);
|
||||
Z_Free(imageData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CRandomModel *CCGHeightDetails::GetRandomModel(CCMLandScape *land)
|
||||
{
|
||||
int seek, i;
|
||||
|
||||
seek = land->irand(0, mTotalFrequency);
|
||||
for(i = 0; i < mNumModels; i++)
|
||||
{
|
||||
seek -= mModels[i].GetFrequency();
|
||||
if(seek <= 0)
|
||||
{
|
||||
return(mModels + i);
|
||||
}
|
||||
}
|
||||
assert(0);
|
||||
return(NULL);
|
||||
}
|
||||
#ifndef DEDICATED
|
||||
void CRMLandScape::Sprinkle(CCMPatch *patch, CCGHeightDetails *hd, int level)
|
||||
{
|
||||
int i, count, px, py;
|
||||
float density;
|
||||
vec3_t origin, scale, angles, bounds[2];
|
||||
refEntity_t refEnt;
|
||||
CRandomModel *rm;
|
||||
CArea area;
|
||||
// int areaTypes[] = { AT_BSP, AT_OBJECTIVE };
|
||||
// TCGMiscEnt *data = (TCGMiscEnt *)cl.mSharedMemory;
|
||||
// TCGTrace *td = (TCGTrace *)cl.mSharedMemory;
|
||||
|
||||
// memset(&refEnt, 0, sizeof(refEntity_t));
|
||||
|
||||
px = patch->GetHeightMapX() / common->GetTerxels();
|
||||
py = patch->GetHeightMapY() / common->GetTerxels();
|
||||
// Get a number -5.3f to 5.3f
|
||||
density = (mDensityMap[px + (common->GetBlockWidth() * py)] - 128) / 24.0f;
|
||||
// ..and multiply that into the count
|
||||
count = Round(common->GetPatchScalarSize() * hd->GetAverageFrequency() * powf(2.0f, density) * 0.001);
|
||||
|
||||
for(i = 0; i < count; i++)
|
||||
{
|
||||
if(!common->irand(0, 10))
|
||||
{
|
||||
vec3_t temp;
|
||||
trace_t tr;
|
||||
float average;
|
||||
|
||||
rm = hd->GetRandomModel(common);
|
||||
|
||||
refEnt.hModel = re.RegisterModel(rm->GetModelName());
|
||||
refEnt.frame = 0;
|
||||
RE_GetModelBounds(&refEnt, bounds[0], bounds[1]);
|
||||
|
||||
// Calculate the scale using some magic to help ensure that the
|
||||
// scales are never too different from eachother. Otherwise you
|
||||
// could get an entity that is really small on one axis but huge
|
||||
// on another.
|
||||
temp[0] = common->flrand(rm->GetMinScale(), rm->GetMaxScale());
|
||||
temp[1] = common->flrand(rm->GetMinScale(), rm->GetMaxScale());
|
||||
temp[2] = common->flrand(rm->GetMinScale(), rm->GetMaxScale());
|
||||
|
||||
// Average of the three random numbers and divide that by two
|
||||
average = ( ( temp[0] + temp[1] + temp[2] ) / 3) / 2;
|
||||
|
||||
// Add in half of the other two numbers and then subtract half the average to prevent.
|
||||
// any number from going beyond the range. If all three numbers were the same then
|
||||
// they would remain unchanged after this calculation.
|
||||
scale[0] = temp[0] + (temp[1]+temp[2]) / 2 - average;
|
||||
scale[1] = temp[1] + (temp[0]+temp[2]) / 2 - average;
|
||||
scale[2] = temp[2] + (temp[0]+temp[1]) / 2 - average;
|
||||
|
||||
angles[0] = 0.0f;
|
||||
angles[1] = common->flrand((float)-M_PI, (float)M_PI);
|
||||
angles[2] = 0.0f;
|
||||
|
||||
VectorCopy(patch->GetMins(), origin);
|
||||
origin[0] += common->flrand(0.0f, common->GetPatchWidth());
|
||||
origin[1] += common->flrand(0.0f, common->GetPatchHeight());
|
||||
// Get above world height
|
||||
float slope = common->GetWorldHeight(origin, bounds, true);
|
||||
|
||||
if (slope > 1.33)
|
||||
{ // spot has too steep of a slope
|
||||
continue;
|
||||
}
|
||||
if(origin[2] < common->GetWaterHeight())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// very that we aren't dropped too low
|
||||
if (origin[2] < common->CalcWorldHeight(level))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Hack-ariffic, don't allow them to drop below the big player clip brush.
|
||||
if (origin[2] < 1280 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// FIXME: shouldn't be using a hard-coded 1280 number, only allow to spawn if inside player clip brush?
|
||||
// if( !(CONTENTS_PLAYERCLIP & VM_Call( cgvm, CG_POINT_CONTENTS )) )
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
// Simple radius check for buildings
|
||||
/* area.Init(origin, VectorLength(bounds[0]));
|
||||
if(common->AreaCollision(&area, areaTypes, sizeof(areaTypes) / sizeof(int)))
|
||||
{
|
||||
continue;
|
||||
}*/
|
||||
// Make sure there is no architecture around - doesn't work for ents though =(
|
||||
|
||||
/*
|
||||
memset(td, sizeof(*td), 0);
|
||||
VectorCopy(origin, td->mStart);
|
||||
VectorCopy(bounds[0], td->mMins);
|
||||
VectorCopy(bounds[1], td->mMaxs);
|
||||
VectorCopy(origin, td->mEnd);
|
||||
td->mSkipNumber = -1;
|
||||
td->mMask = MASK_PLAYERSOLID;
|
||||
*/
|
||||
SV_Trace(&tr, origin, bounds[0], bounds[1], origin, -1, (CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_BODY|CONTENTS_TERRAIN));
|
||||
|
||||
/*
|
||||
VM_Call( cgvm, CG_TRACE );
|
||||
if(td->mResult.surfaceFlags & SURF_NOMISCENTS)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if(td->mResult.startsolid)
|
||||
{
|
||||
// continue;
|
||||
}
|
||||
*/
|
||||
if (tr.surfaceFlags & SURF_NOMISCENTS)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (tr.startsolid)
|
||||
{
|
||||
// continue;
|
||||
}
|
||||
|
||||
// Get minimum height of area
|
||||
common->GetWorldHeight(origin, bounds, false);
|
||||
// Account for relative origin
|
||||
origin[2] -= bounds[0][2] * scale[2];
|
||||
origin[2] -= common->flrand(2.0, (bounds[1][2] - bounds[0][2]) / 4);
|
||||
|
||||
//rwwFIXMEFIXME: Do this properly
|
||||
// Spawn the client model
|
||||
/*
|
||||
strcpy(data->mModel, rm->GetModelName());
|
||||
VectorCopy(origin, data->mOrigin);
|
||||
VectorCopy(angles, data->mAngles);
|
||||
VectorCopy(scale, data->mScale);
|
||||
VM_Call( cgvm, CG_MISC_ENT);
|
||||
*/
|
||||
|
||||
mModelCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // !DEDICATED
|
||||
|
||||
void CRMLandScape::SpawnPatchModels(CCMPatch *patch)
|
||||
{
|
||||
int i;
|
||||
CCGHeightDetails *hd;
|
||||
|
||||
// Rand_Init(10);
|
||||
#ifndef DEDICATED
|
||||
for(i = 0; i < 4; i++)
|
||||
{
|
||||
hd = mHeightDetails + patch->GetHeight(i);
|
||||
if(hd->GetNumModels())
|
||||
{
|
||||
Sprinkle(patch, hd, patch->GetHeight(i));
|
||||
}
|
||||
}
|
||||
#endif // !DEDICATED
|
||||
}
|
||||
|
||||
void SpawnPatchModelsWrapper(CCMPatch *patch, void *userdata)
|
||||
{
|
||||
CRMLandScape *landscape = (CRMLandScape *)userdata;
|
||||
landscape->SpawnPatchModels(patch);
|
||||
}
|
||||
|
||||
void RM_CreateRandomModels(int terrainId, const char *terrainInfo)
|
||||
{
|
||||
CRMLandScape *landscape;
|
||||
|
||||
landscape = rm_landscape = new CRMLandScape;
|
||||
landscape->SetCommon(cmg.landScape);
|
||||
|
||||
Com_DPrintf("CG_Terrain: Creating random models.....\n");
|
||||
landscape->LoadMiscentDef(terrainInfo);
|
||||
landscape->LoadDensityMap(terrainInfo);
|
||||
landscape->ClearModelCount();
|
||||
CM_TerrainPatchIterate(landscape->GetCommon(), SpawnPatchModelsWrapper, landscape);
|
||||
|
||||
Com_DPrintf(".....%d random client models spawned\n", landscape->GetModelCount());
|
||||
}
|
||||
|
||||
void RM_InitTerrain(void)
|
||||
{
|
||||
rm_landscape = NULL;
|
||||
}
|
||||
|
||||
void RM_ShutdownTerrain(void)
|
||||
{
|
||||
CRMLandScape *landscape;
|
||||
|
||||
landscape = rm_landscape;
|
||||
if(landscape)
|
||||
{
|
||||
// CM_ShutdownTerrain(i);
|
||||
delete landscape;
|
||||
rm_landscape = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// end
|
||||
|
||||
#pragma optimize("", on)
|
||||
97
code/RMG/RM_Terrain.h
Normal file
97
code/RMG/RM_Terrain.h
Normal file
@@ -0,0 +1,97 @@
|
||||
#pragma once
|
||||
#if !defined(RM_TERRAIN_H_INC)
|
||||
#define RM_TERRAIN_H_INC
|
||||
|
||||
#define MAX_RANDOM_MODELS 8
|
||||
|
||||
class CRandomModel
|
||||
{
|
||||
private:
|
||||
char mModelName[MAX_QPATH];
|
||||
float mFrequency;
|
||||
float mMinScale;
|
||||
float mMaxScale;
|
||||
public:
|
||||
CRandomModel(void) { }
|
||||
~CRandomModel(void) { }
|
||||
|
||||
// Accessors
|
||||
const bool GetModel( void ) const { return(!!strlen(mModelName)); }
|
||||
const char *GetModelName( void ) const { return(mModelName); }
|
||||
void SetModel(const char *name) { Com_sprintf(mModelName, MAX_QPATH, "%s.md3", name); }
|
||||
const float GetFrequency(void) const { return(mFrequency); }
|
||||
void SetFrequency(const float freq) { mFrequency = freq; }
|
||||
const float GetMinScale(void) const { return(mMinScale); }
|
||||
void SetMinScale(const float minscale) { mMinScale = minscale; }
|
||||
const float GetMaxScale(void) const { return(mMaxScale); }
|
||||
void SetMaxScale(const float maxscale) { mMaxScale = maxscale; }
|
||||
};
|
||||
|
||||
class CCGHeightDetails
|
||||
{
|
||||
private:
|
||||
int mNumModels;
|
||||
int mTotalFrequency;
|
||||
CRandomModel mModels[MAX_RANDOM_MODELS];
|
||||
public:
|
||||
// Constructors
|
||||
CCGHeightDetails( void ) { memset(this, 0, sizeof(*this)); }
|
||||
~CCGHeightDetails( void ) { }
|
||||
|
||||
// Accessors
|
||||
const int GetNumModels(void) const { return(mNumModels); }
|
||||
const int GetAverageFrequency(void) const { return(mTotalFrequency / mNumModels); }
|
||||
|
||||
// Prototypes
|
||||
void AddModel(const CRandomModel *hd);
|
||||
CRandomModel *GetRandomModel(CCMLandScape *land);
|
||||
};
|
||||
|
||||
class CCGPatch
|
||||
{
|
||||
private:
|
||||
class CCMLandScape *owner;
|
||||
class CCGLandScape *localowner;
|
||||
CCMPatch *common;
|
||||
public:
|
||||
};
|
||||
|
||||
class CRMLandScape
|
||||
{
|
||||
private:
|
||||
CCMLandScape *common;
|
||||
|
||||
byte *mDensityMap; // Data image of model densities
|
||||
int mModelCount; // Count of spawned client models
|
||||
CCGHeightDetails mHeightDetails[HEIGHT_RESOLUTION]; // Array of info specific to height
|
||||
|
||||
public:
|
||||
CRMLandScape(void);
|
||||
~CRMLandScape(void);
|
||||
|
||||
// Accessors
|
||||
void SetCommon(CCMLandScape *landscape) { common = landscape; }
|
||||
const CCMLandScape *GetCommon( void ) const { return(common); }
|
||||
const thandle_t GetCommonId( void ) const { return(common->GetTerrainId()); }
|
||||
const int GetTerxels(void) const { return(common->GetTerxels()); }
|
||||
const int GetRealWidth(void) const { return(common->GetRealWidth()); }
|
||||
const float GetPatchScalarSize(void) const { return(common->GetPatchScalarSize()); }
|
||||
const CCGHeightDetails *GetHeightDetail(int height) const { return(mHeightDetails + height); }
|
||||
void ClearModelCount(void) { mModelCount = 0; }
|
||||
const int GetModelCount(void) const { return(mModelCount); }
|
||||
|
||||
// Prototypes
|
||||
void SetShaders(const int height, const qhandle_t shader);
|
||||
void AddModel(const int height, int maxheight, const CRandomModel *hd);
|
||||
void LoadMiscentDef(const char *td);
|
||||
void LoadDensityMap(const char *td);
|
||||
void SpawnPatchModels(CCMPatch *patch);
|
||||
void Sprinkle(CCMPatch *patch, CCGHeightDetails *hd, int level);
|
||||
void CreateRandomDensityMap(byte *imageData, int width, int height, int seed);
|
||||
};
|
||||
|
||||
void RM_CreateRandomModels(int terrainId, const char *terrainInfo);
|
||||
void RM_InitTerrain(void);
|
||||
void RM_ShutdownTerrain(void);
|
||||
|
||||
#endif // RM_TERRAIN_H_INC
|
||||
Reference in New Issue
Block a user