jedi-academy/code/RMG/RM_Area.cpp
2013-04-23 15:21:39 +10:00

480 lines
12 KiB
C++

/************************************************************************************************
*
* 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