mirror of
https://github.com/TTimo/doom3.gpl.git
synced 2026-03-20 00:49:30 +01:00
hello world
This commit is contained in:
275
neo/d3xp/ai/AAS.cpp
Normal file
275
neo/d3xp/ai/AAS.cpp
Normal file
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "../../idlib/precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "AAS_local.h"
|
||||
|
||||
/*
|
||||
============
|
||||
idAAS::Alloc
|
||||
============
|
||||
*/
|
||||
idAAS *idAAS::Alloc( void ) {
|
||||
return new idAASLocal;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAAS::idAAS
|
||||
============
|
||||
*/
|
||||
idAAS::~idAAS( void ) {
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::idAASLocal
|
||||
============
|
||||
*/
|
||||
idAASLocal::idAASLocal( void ) {
|
||||
file = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::~idAASLocal
|
||||
============
|
||||
*/
|
||||
idAASLocal::~idAASLocal( void ) {
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::Init
|
||||
============
|
||||
*/
|
||||
bool idAASLocal::Init( const idStr &mapName, unsigned int mapFileCRC ) {
|
||||
if ( file && mapName.Icmp( file->GetName() ) == 0 && mapFileCRC == file->GetCRC() ) {
|
||||
common->Printf( "Keeping %s\n", file->GetName() );
|
||||
RemoveAllObstacles();
|
||||
}
|
||||
else {
|
||||
Shutdown();
|
||||
|
||||
file = AASFileManager->LoadAAS( mapName, mapFileCRC );
|
||||
if ( !file ) {
|
||||
common->DWarning( "Couldn't load AAS file: '%s'", mapName.c_str() );
|
||||
return false;
|
||||
}
|
||||
SetupRouting();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::Shutdown
|
||||
============
|
||||
*/
|
||||
void idAASLocal::Shutdown( void ) {
|
||||
if ( file ) {
|
||||
ShutdownRouting();
|
||||
RemoveAllObstacles();
|
||||
AASFileManager->FreeAAS( file );
|
||||
file = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::Stats
|
||||
============
|
||||
*/
|
||||
void idAASLocal::Stats( void ) const {
|
||||
if ( !file ) {
|
||||
return;
|
||||
}
|
||||
common->Printf( "[%s]\n", file->GetName() );
|
||||
file->PrintInfo();
|
||||
RoutingStats();
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::GetSettings
|
||||
============
|
||||
*/
|
||||
const idAASSettings *idAASLocal::GetSettings( void ) const {
|
||||
if ( !file ) {
|
||||
return NULL;
|
||||
}
|
||||
return &file->GetSettings();
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::PointAreaNum
|
||||
============
|
||||
*/
|
||||
int idAASLocal::PointAreaNum( const idVec3 &origin ) const {
|
||||
if ( !file ) {
|
||||
return 0;
|
||||
}
|
||||
return file->PointAreaNum( origin );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::PointReachableAreaNum
|
||||
============
|
||||
*/
|
||||
int idAASLocal::PointReachableAreaNum( const idVec3 &origin, const idBounds &searchBounds, const int areaFlags ) const {
|
||||
if ( !file ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return file->PointReachableAreaNum( origin, searchBounds, areaFlags, TFL_INVALID );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::BoundsReachableAreaNum
|
||||
============
|
||||
*/
|
||||
int idAASLocal::BoundsReachableAreaNum( const idBounds &bounds, const int areaFlags ) const {
|
||||
if ( !file ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return file->BoundsReachableAreaNum( bounds, areaFlags, TFL_INVALID );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::PushPointIntoAreaNum
|
||||
============
|
||||
*/
|
||||
void idAASLocal::PushPointIntoAreaNum( int areaNum, idVec3 &origin ) const {
|
||||
if ( !file ) {
|
||||
return;
|
||||
}
|
||||
file->PushPointIntoAreaNum( areaNum, origin );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::AreaCenter
|
||||
============
|
||||
*/
|
||||
idVec3 idAASLocal::AreaCenter( int areaNum ) const {
|
||||
if ( !file ) {
|
||||
return vec3_origin;
|
||||
}
|
||||
return file->GetArea( areaNum ).center;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::AreaFlags
|
||||
============
|
||||
*/
|
||||
int idAASLocal::AreaFlags( int areaNum ) const {
|
||||
if ( !file ) {
|
||||
return 0;
|
||||
}
|
||||
return file->GetArea( areaNum ).flags;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::AreaTravelFlags
|
||||
============
|
||||
*/
|
||||
int idAASLocal::AreaTravelFlags( int areaNum ) const {
|
||||
if ( !file ) {
|
||||
return 0;
|
||||
}
|
||||
return file->GetArea( areaNum ).travelFlags;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::Trace
|
||||
============
|
||||
*/
|
||||
bool idAASLocal::Trace( aasTrace_t &trace, const idVec3 &start, const idVec3 &end ) const {
|
||||
if ( !file ) {
|
||||
trace.fraction = 0.0f;
|
||||
trace.lastAreaNum = 0;
|
||||
trace.numAreas = 0;
|
||||
return true;
|
||||
}
|
||||
return file->Trace( trace, start, end );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::GetPlane
|
||||
============
|
||||
*/
|
||||
const idPlane &idAASLocal::GetPlane( int planeNum ) const {
|
||||
if ( !file ) {
|
||||
static idPlane dummy;
|
||||
return dummy;
|
||||
}
|
||||
return file->GetPlane( planeNum );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::GetEdgeVertexNumbers
|
||||
============
|
||||
*/
|
||||
void idAASLocal::GetEdgeVertexNumbers( int edgeNum, int verts[2] ) const {
|
||||
if ( !file ) {
|
||||
verts[0] = verts[1] = 0;
|
||||
return;
|
||||
}
|
||||
const int *v = file->GetEdge( abs(edgeNum) ).vertexNum;
|
||||
verts[0] = v[INTSIGNBITSET(edgeNum)];
|
||||
verts[1] = v[INTSIGNBITNOTSET(edgeNum)];
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::GetEdge
|
||||
============
|
||||
*/
|
||||
void idAASLocal::GetEdge( int edgeNum, idVec3 &start, idVec3 &end ) const {
|
||||
if ( !file ) {
|
||||
start.Zero();
|
||||
end.Zero();
|
||||
return;
|
||||
}
|
||||
const int *v = file->GetEdge( abs(edgeNum) ).vertexNum;
|
||||
start = file->GetVertex( v[INTSIGNBITSET(edgeNum)] );
|
||||
end = file->GetVertex( v[INTSIGNBITNOTSET(edgeNum)] );
|
||||
}
|
||||
141
neo/d3xp/ai/AAS.h
Normal file
141
neo/d3xp/ai/AAS.h
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __AAS_H__
|
||||
#define __AAS_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Area Awareness System
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
enum {
|
||||
PATHTYPE_WALK,
|
||||
PATHTYPE_WALKOFFLEDGE,
|
||||
PATHTYPE_BARRIERJUMP,
|
||||
PATHTYPE_JUMP
|
||||
};
|
||||
|
||||
typedef struct aasPath_s {
|
||||
int type; // path type
|
||||
idVec3 moveGoal; // point the AI should move towards
|
||||
int moveAreaNum; // number of the area the AI should move towards
|
||||
idVec3 secondaryGoal; // secondary move goal for complex navigation
|
||||
const idReachability * reachability; // reachability used for navigation
|
||||
} aasPath_t;
|
||||
|
||||
|
||||
typedef struct aasGoal_s {
|
||||
int areaNum; // area the goal is in
|
||||
idVec3 origin; // position of goal
|
||||
} aasGoal_t;
|
||||
|
||||
|
||||
typedef struct aasObstacle_s {
|
||||
idBounds absBounds; // absolute bounds of obstacle
|
||||
idBounds expAbsBounds; // expanded absolute bounds of obstacle
|
||||
} aasObstacle_t;
|
||||
|
||||
class idAASCallback {
|
||||
public:
|
||||
virtual ~idAASCallback() {};
|
||||
virtual bool TestArea( const class idAAS *aas, int areaNum ) = 0;
|
||||
};
|
||||
|
||||
typedef int aasHandle_t;
|
||||
|
||||
class idAAS {
|
||||
public:
|
||||
static idAAS * Alloc( void );
|
||||
virtual ~idAAS( void ) = 0;
|
||||
// Initialize for the given map.
|
||||
virtual bool Init( const idStr &mapName, unsigned int mapFileCRC ) = 0;
|
||||
// Print AAS stats.
|
||||
virtual void Stats( void ) const = 0;
|
||||
// Test from the given origin.
|
||||
virtual void Test( const idVec3 &origin ) = 0;
|
||||
// Get the AAS settings.
|
||||
virtual const idAASSettings *GetSettings( void ) const = 0;
|
||||
// Returns the number of the area the origin is in.
|
||||
virtual int PointAreaNum( const idVec3 &origin ) const = 0;
|
||||
// Returns the number of the nearest reachable area for the given point.
|
||||
virtual int PointReachableAreaNum( const idVec3 &origin, const idBounds &bounds, const int areaFlags ) const = 0;
|
||||
// Returns the number of the first reachable area in or touching the bounds.
|
||||
virtual int BoundsReachableAreaNum( const idBounds &bounds, const int areaFlags ) const = 0;
|
||||
// Push the point into the area.
|
||||
virtual void PushPointIntoAreaNum( int areaNum, idVec3 &origin ) const = 0;
|
||||
// Returns a reachable point inside the given area.
|
||||
virtual idVec3 AreaCenter( int areaNum ) const = 0;
|
||||
// Returns the area flags.
|
||||
virtual int AreaFlags( int areaNum ) const = 0;
|
||||
// Returns the travel flags for traveling through the area.
|
||||
virtual int AreaTravelFlags( int areaNum ) const = 0;
|
||||
// Trace through the areas and report the first collision.
|
||||
virtual bool Trace( aasTrace_t &trace, const idVec3 &start, const idVec3 &end ) const = 0;
|
||||
// Get a plane for a trace.
|
||||
virtual const idPlane & GetPlane( int planeNum ) const = 0;
|
||||
// Get wall edges.
|
||||
virtual int GetWallEdges( int areaNum, const idBounds &bounds, int travelFlags, int *edges, int maxEdges ) const = 0;
|
||||
// Sort the wall edges to create continuous sequences of walls.
|
||||
virtual void SortWallEdges( int *edges, int numEdges ) const = 0;
|
||||
// Get the vertex numbers for an edge.
|
||||
virtual void GetEdgeVertexNumbers( int edgeNum, int verts[2] ) const = 0;
|
||||
// Get an edge.
|
||||
virtual void GetEdge( int edgeNum, idVec3 &start, idVec3 &end ) const = 0;
|
||||
// Find all areas within or touching the bounds with the given contents and disable/enable them for routing.
|
||||
virtual bool SetAreaState( const idBounds &bounds, const int areaContents, bool disabled ) = 0;
|
||||
// Add an obstacle to the routing system.
|
||||
virtual aasHandle_t AddObstacle( const idBounds &bounds ) = 0;
|
||||
// Remove an obstacle from the routing system.
|
||||
virtual void RemoveObstacle( const aasHandle_t handle ) = 0;
|
||||
// Remove all obstacles from the routing system.
|
||||
virtual void RemoveAllObstacles( void ) = 0;
|
||||
// Returns the travel time towards the goal area in 100th of a second.
|
||||
virtual int TravelTimeToGoalArea( int areaNum, const idVec3 &origin, int goalAreaNum, int travelFlags ) const = 0;
|
||||
// Get the travel time and first reachability to be used towards the goal, returns true if there is a path.
|
||||
virtual bool RouteToGoalArea( int areaNum, const idVec3 origin, int goalAreaNum, int travelFlags, int &travelTime, idReachability **reach ) const = 0;
|
||||
// Creates a walk path towards the goal.
|
||||
virtual bool WalkPathToGoal( aasPath_t &path, int areaNum, const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin, int travelFlags ) const = 0;
|
||||
// Returns true if one can walk along a straight line from the origin to the goal origin.
|
||||
virtual bool WalkPathValid( int areaNum, const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin, int travelFlags, idVec3 &endPos, int &endAreaNum ) const = 0;
|
||||
// Creates a fly path towards the goal.
|
||||
virtual bool FlyPathToGoal( aasPath_t &path, int areaNum, const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin, int travelFlags ) const = 0;
|
||||
// Returns true if one can fly along a straight line from the origin to the goal origin.
|
||||
virtual bool FlyPathValid( int areaNum, const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin, int travelFlags, idVec3 &endPos, int &endAreaNum ) const = 0;
|
||||
// Show the walk path from the origin towards the area.
|
||||
virtual void ShowWalkPath( const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin ) const = 0;
|
||||
// Show the fly path from the origin towards the area.
|
||||
virtual void ShowFlyPath( const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin ) const = 0;
|
||||
// Find the nearest goal which satisfies the callback.
|
||||
virtual bool FindNearestGoal( aasGoal_t &goal, int areaNum, const idVec3 origin, const idVec3 &target, int travelFlags, aasObstacle_t *obstacles, int numObstacles, idAASCallback &callback ) const = 0;
|
||||
};
|
||||
|
||||
#endif /* !__AAS_H__ */
|
||||
508
neo/d3xp/ai/AAS_debug.cpp
Normal file
508
neo/d3xp/ai/AAS_debug.cpp
Normal file
@@ -0,0 +1,508 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "../../idlib/precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "AAS_local.h"
|
||||
#include "../Game_local.h" // for cvars and debug drawing
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::DrawCone
|
||||
============
|
||||
*/
|
||||
void idAASLocal::DrawCone( const idVec3 &origin, const idVec3 &dir, float radius, const idVec4 &color ) const {
|
||||
int i;
|
||||
idMat3 axis;
|
||||
idVec3 center, top, p, lastp;
|
||||
|
||||
axis[2] = dir;
|
||||
axis[2].NormalVectors( axis[0], axis[1] );
|
||||
axis[1] = -axis[1];
|
||||
|
||||
center = origin + dir;
|
||||
top = center + dir * (3.0f * radius);
|
||||
lastp = center + radius * axis[1];
|
||||
|
||||
for ( i = 20; i <= 360; i += 20 ) {
|
||||
p = center + sin( DEG2RAD(i) ) * radius * axis[0] + cos( DEG2RAD(i) ) * radius * axis[1];
|
||||
gameRenderWorld->DebugLine( color, lastp, p, 0 );
|
||||
gameRenderWorld->DebugLine( color, p, top, 0 );
|
||||
lastp = p;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::DrawReachability
|
||||
============
|
||||
*/
|
||||
void idAASLocal::DrawReachability( const idReachability *reach ) const {
|
||||
gameRenderWorld->DebugArrow( colorCyan, reach->start, reach->end, 2 );
|
||||
|
||||
if ( gameLocal.GetLocalPlayer() ) {
|
||||
gameRenderWorld->DrawText( va( "%d", reach->edgeNum ), ( reach->start + reach->end ) * 0.5f, 0.1f, colorWhite, gameLocal.GetLocalPlayer()->viewAxis );
|
||||
}
|
||||
|
||||
switch( reach->travelType ) {
|
||||
case TFL_WALK: {
|
||||
const idReachability_Walk *walk = static_cast<const idReachability_Walk *>(reach);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::DrawEdge
|
||||
============
|
||||
*/
|
||||
void idAASLocal::DrawEdge( int edgeNum, bool arrow ) const {
|
||||
const aasEdge_t *edge;
|
||||
idVec4 *color;
|
||||
|
||||
if ( !file ) {
|
||||
return;
|
||||
}
|
||||
|
||||
edge = &file->GetEdge( edgeNum );
|
||||
color = &colorRed;
|
||||
if ( arrow ) {
|
||||
gameRenderWorld->DebugArrow( *color, file->GetVertex( edge->vertexNum[0] ), file->GetVertex( edge->vertexNum[1] ), 1 );
|
||||
} else {
|
||||
gameRenderWorld->DebugLine( *color, file->GetVertex( edge->vertexNum[0] ), file->GetVertex( edge->vertexNum[1] ) );
|
||||
}
|
||||
|
||||
if ( gameLocal.GetLocalPlayer() ) {
|
||||
gameRenderWorld->DrawText( va( "%d", edgeNum ), ( file->GetVertex( edge->vertexNum[0] ) + file->GetVertex( edge->vertexNum[1] ) ) * 0.5f + idVec3(0,0,4), 0.1f, colorRed, gameLocal.GetLocalPlayer()->viewAxis );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::DrawFace
|
||||
============
|
||||
*/
|
||||
void idAASLocal::DrawFace( int faceNum, bool side ) const {
|
||||
int i, j, numEdges, firstEdge;
|
||||
const aasFace_t *face;
|
||||
idVec3 mid, end;
|
||||
|
||||
if ( !file ) {
|
||||
return;
|
||||
}
|
||||
|
||||
face = &file->GetFace( faceNum );
|
||||
numEdges = face->numEdges;
|
||||
firstEdge = face->firstEdge;
|
||||
|
||||
mid = vec3_origin;
|
||||
for ( i = 0; i < numEdges; i++ ) {
|
||||
DrawEdge( abs( file->GetEdgeIndex( firstEdge + i ) ), ( face->flags & FACE_FLOOR ) != 0 );
|
||||
j = file->GetEdgeIndex( firstEdge + i );
|
||||
mid += file->GetVertex( file->GetEdge( abs( j ) ).vertexNum[ j < 0 ] );
|
||||
}
|
||||
|
||||
mid /= numEdges;
|
||||
if ( side ) {
|
||||
end = mid - 5.0f * file->GetPlane( file->GetFace( faceNum ).planeNum ).Normal();
|
||||
} else {
|
||||
end = mid + 5.0f * file->GetPlane( file->GetFace( faceNum ).planeNum ).Normal();
|
||||
}
|
||||
gameRenderWorld->DebugArrow( colorGreen, mid, end, 1 );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::DrawArea
|
||||
============
|
||||
*/
|
||||
void idAASLocal::DrawArea( int areaNum ) const {
|
||||
int i, numFaces, firstFace;
|
||||
const aasArea_t *area;
|
||||
idReachability *reach;
|
||||
|
||||
if ( !file ) {
|
||||
return;
|
||||
}
|
||||
|
||||
area = &file->GetArea( areaNum );
|
||||
numFaces = area->numFaces;
|
||||
firstFace = area->firstFace;
|
||||
|
||||
for ( i = 0; i < numFaces; i++ ) {
|
||||
DrawFace( abs( file->GetFaceIndex( firstFace + i ) ), file->GetFaceIndex( firstFace + i ) < 0 );
|
||||
}
|
||||
|
||||
for ( reach = area->reach; reach; reach = reach->next ) {
|
||||
DrawReachability( reach );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::DefaultSearchBounds
|
||||
============
|
||||
*/
|
||||
const idBounds &idAASLocal::DefaultSearchBounds( void ) const {
|
||||
return file->GetSettings().boundingBoxes[0];
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::ShowArea
|
||||
============
|
||||
*/
|
||||
void idAASLocal::ShowArea( const idVec3 &origin ) const {
|
||||
static int lastAreaNum;
|
||||
int areaNum;
|
||||
const aasArea_t *area;
|
||||
idVec3 org;
|
||||
|
||||
areaNum = PointReachableAreaNum( origin, DefaultSearchBounds(), (AREA_REACHABLE_WALK|AREA_REACHABLE_FLY) );
|
||||
org = origin;
|
||||
PushPointIntoAreaNum( areaNum, org );
|
||||
|
||||
if ( aas_goalArea.GetInteger() ) {
|
||||
int travelTime;
|
||||
idReachability *reach;
|
||||
|
||||
RouteToGoalArea( areaNum, org, aas_goalArea.GetInteger(), TFL_WALK|TFL_AIR, travelTime, &reach );
|
||||
gameLocal.Printf( "\rtt = %4d", travelTime );
|
||||
if ( reach ) {
|
||||
gameLocal.Printf( " to area %4d", reach->toAreaNum );
|
||||
DrawArea( reach->toAreaNum );
|
||||
}
|
||||
}
|
||||
|
||||
if ( areaNum != lastAreaNum ) {
|
||||
area = &file->GetArea( areaNum );
|
||||
gameLocal.Printf( "area %d: ", areaNum );
|
||||
if ( area->flags & AREA_LEDGE ) {
|
||||
gameLocal.Printf( "AREA_LEDGE " );
|
||||
}
|
||||
if ( area->flags & AREA_REACHABLE_WALK ) {
|
||||
gameLocal.Printf( "AREA_REACHABLE_WALK " );
|
||||
}
|
||||
if ( area->flags & AREA_REACHABLE_FLY ) {
|
||||
gameLocal.Printf( "AREA_REACHABLE_FLY " );
|
||||
}
|
||||
if ( area->contents & AREACONTENTS_CLUSTERPORTAL ) {
|
||||
gameLocal.Printf( "AREACONTENTS_CLUSTERPORTAL " );
|
||||
}
|
||||
if ( area->contents & AREACONTENTS_OBSTACLE ) {
|
||||
gameLocal.Printf( "AREACONTENTS_OBSTACLE " );
|
||||
}
|
||||
gameLocal.Printf( "\n" );
|
||||
lastAreaNum = areaNum;
|
||||
}
|
||||
|
||||
if ( org != origin ) {
|
||||
idBounds bnds = file->GetSettings().boundingBoxes[ 0 ];
|
||||
bnds[ 1 ].z = bnds[ 0 ].z;
|
||||
gameRenderWorld->DebugBounds( colorYellow, bnds, org );
|
||||
}
|
||||
|
||||
DrawArea( areaNum );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::ShowWalkPath
|
||||
============
|
||||
*/
|
||||
void idAASLocal::ShowWalkPath( const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin ) const {
|
||||
int i, areaNum, curAreaNum, travelTime;
|
||||
idReachability *reach;
|
||||
idVec3 org, areaCenter;
|
||||
aasPath_t path;
|
||||
|
||||
if ( !file ) {
|
||||
return;
|
||||
}
|
||||
|
||||
org = origin;
|
||||
areaNum = PointReachableAreaNum( org, DefaultSearchBounds(), AREA_REACHABLE_WALK );
|
||||
PushPointIntoAreaNum( areaNum, org );
|
||||
curAreaNum = areaNum;
|
||||
|
||||
for ( i = 0; i < 100; i++ ) {
|
||||
|
||||
if ( !RouteToGoalArea( curAreaNum, org, goalAreaNum, TFL_WALK|TFL_AIR, travelTime, &reach ) ) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !reach ) {
|
||||
break;
|
||||
}
|
||||
|
||||
gameRenderWorld->DebugArrow( colorGreen, org, reach->start, 2 );
|
||||
DrawReachability( reach );
|
||||
|
||||
if ( reach->toAreaNum == goalAreaNum ) {
|
||||
break;
|
||||
}
|
||||
|
||||
curAreaNum = reach->toAreaNum;
|
||||
org = reach->end;
|
||||
}
|
||||
|
||||
if ( WalkPathToGoal( path, areaNum, origin, goalAreaNum, goalOrigin, TFL_WALK|TFL_AIR ) ) {
|
||||
gameRenderWorld->DebugArrow( colorBlue, origin, path.moveGoal, 2 );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::ShowFlyPath
|
||||
============
|
||||
*/
|
||||
void idAASLocal::ShowFlyPath( const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin ) const {
|
||||
int i, areaNum, curAreaNum, travelTime;
|
||||
idReachability *reach;
|
||||
idVec3 org, areaCenter;
|
||||
aasPath_t path;
|
||||
|
||||
if ( !file ) {
|
||||
return;
|
||||
}
|
||||
|
||||
org = origin;
|
||||
areaNum = PointReachableAreaNum( org, DefaultSearchBounds(), AREA_REACHABLE_FLY );
|
||||
PushPointIntoAreaNum( areaNum, org );
|
||||
curAreaNum = areaNum;
|
||||
|
||||
for ( i = 0; i < 100; i++ ) {
|
||||
|
||||
if ( !RouteToGoalArea( curAreaNum, org, goalAreaNum, TFL_WALK|TFL_FLY|TFL_AIR, travelTime, &reach ) ) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !reach ) {
|
||||
break;
|
||||
}
|
||||
|
||||
gameRenderWorld->DebugArrow( colorPurple, org, reach->start, 2 );
|
||||
DrawReachability( reach );
|
||||
|
||||
if ( reach->toAreaNum == goalAreaNum ) {
|
||||
break;
|
||||
}
|
||||
|
||||
curAreaNum = reach->toAreaNum;
|
||||
org = reach->end;
|
||||
}
|
||||
|
||||
if ( FlyPathToGoal( path, areaNum, origin, goalAreaNum, goalOrigin, TFL_WALK|TFL_FLY|TFL_AIR ) ) {
|
||||
gameRenderWorld->DebugArrow( colorBlue, origin, path.moveGoal, 2 );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::ShowWallEdges
|
||||
============
|
||||
*/
|
||||
void idAASLocal::ShowWallEdges( const idVec3 &origin ) const {
|
||||
int i, areaNum, numEdges, edges[1024];
|
||||
idVec3 start, end;
|
||||
idPlayer *player;
|
||||
|
||||
player = gameLocal.GetLocalPlayer();
|
||||
if ( !player ) {
|
||||
return;
|
||||
}
|
||||
|
||||
areaNum = PointReachableAreaNum( origin, DefaultSearchBounds(), (AREA_REACHABLE_WALK|AREA_REACHABLE_FLY) );
|
||||
numEdges = GetWallEdges( areaNum, idBounds( origin ).Expand( 256.0f ), TFL_WALK, edges, 1024 );
|
||||
for ( i = 0; i < numEdges; i++ ) {
|
||||
GetEdge( edges[i], start, end );
|
||||
gameRenderWorld->DebugLine( colorRed, start, end );
|
||||
gameRenderWorld->DrawText( va( "%d", edges[i] ), ( start + end ) * 0.5f, 0.1f, colorWhite, player->viewAxis );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::ShowHideArea
|
||||
============
|
||||
*/
|
||||
void idAASLocal::ShowHideArea( const idVec3 &origin, int targetAreaNum ) const {
|
||||
int areaNum, numObstacles;
|
||||
idVec3 target;
|
||||
aasGoal_t goal;
|
||||
aasObstacle_t obstacles[10];
|
||||
|
||||
areaNum = PointReachableAreaNum( origin, DefaultSearchBounds(), (AREA_REACHABLE_WALK|AREA_REACHABLE_FLY) );
|
||||
target = AreaCenter( targetAreaNum );
|
||||
|
||||
// consider the target an obstacle
|
||||
obstacles[0].absBounds = idBounds( target ).Expand( 16 );
|
||||
numObstacles = 1;
|
||||
|
||||
DrawCone( target, idVec3(0,0,1), 16.0f, colorYellow );
|
||||
|
||||
idAASFindCover findCover( target );
|
||||
if ( FindNearestGoal( goal, areaNum, origin, target, TFL_WALK|TFL_AIR, obstacles, numObstacles, findCover ) ) {
|
||||
DrawArea( goal.areaNum );
|
||||
ShowWalkPath( origin, goal.areaNum, goal.origin );
|
||||
DrawCone( goal.origin, idVec3(0,0,1), 16.0f, colorWhite );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::PullPlayer
|
||||
============
|
||||
*/
|
||||
bool idAASLocal::PullPlayer( const idVec3 &origin, int toAreaNum ) const {
|
||||
int areaNum;
|
||||
idVec3 areaCenter, dir, vel;
|
||||
idAngles delta;
|
||||
aasPath_t path;
|
||||
idPlayer *player;
|
||||
|
||||
player = gameLocal.GetLocalPlayer();
|
||||
if ( !player ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
idPhysics *physics = player->GetPhysics();
|
||||
if ( !physics ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( !toAreaNum ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
areaNum = PointReachableAreaNum( origin, DefaultSearchBounds(), (AREA_REACHABLE_WALK|AREA_REACHABLE_FLY) );
|
||||
areaCenter = AreaCenter( toAreaNum );
|
||||
if ( player->GetPhysics()->GetAbsBounds().Expand( 8 ).ContainsPoint( areaCenter ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( WalkPathToGoal( path, areaNum, origin, toAreaNum, areaCenter, TFL_WALK|TFL_AIR ) ) {
|
||||
dir = path.moveGoal - origin;
|
||||
dir[2] *= 0.5f;
|
||||
dir.Normalize();
|
||||
delta = dir.ToAngles() - player->cmdAngles - player->GetDeltaViewAngles();
|
||||
delta.Normalize180();
|
||||
player->SetDeltaViewAngles( player->GetDeltaViewAngles() + delta * 0.1f );
|
||||
dir[2] = 0.0f;
|
||||
dir.Normalize();
|
||||
dir *= 100.0f;
|
||||
vel = physics->GetLinearVelocity();
|
||||
dir[2] = vel[2];
|
||||
physics->SetLinearVelocity( dir );
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::RandomPullPlayer
|
||||
============
|
||||
*/
|
||||
void idAASLocal::RandomPullPlayer( const idVec3 &origin ) const {
|
||||
int rnd, i, n;
|
||||
|
||||
if ( !PullPlayer( origin, aas_pullPlayer.GetInteger() ) ) {
|
||||
|
||||
rnd = gameLocal.random.RandomFloat() * file->GetNumAreas();
|
||||
|
||||
for ( i = 0; i < file->GetNumAreas(); i++ ) {
|
||||
n = (rnd + i) % file->GetNumAreas();
|
||||
if ( file->GetArea( n ).flags & (AREA_REACHABLE_WALK|AREA_REACHABLE_FLY) ) {
|
||||
aas_pullPlayer.SetInteger( n );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ShowWalkPath( origin, aas_pullPlayer.GetInteger(), AreaCenter( aas_pullPlayer.GetInteger() ) );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::ShowPushIntoArea
|
||||
============
|
||||
*/
|
||||
void idAASLocal::ShowPushIntoArea( const idVec3 &origin ) const {
|
||||
int areaNum;
|
||||
idVec3 target;
|
||||
|
||||
target = origin;
|
||||
areaNum = PointReachableAreaNum( target, DefaultSearchBounds(), (AREA_REACHABLE_WALK|AREA_REACHABLE_FLY) );
|
||||
PushPointIntoAreaNum( areaNum, target );
|
||||
gameRenderWorld->DebugArrow( colorGreen, origin, target, 1 );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::Test
|
||||
============
|
||||
*/
|
||||
void idAASLocal::Test( const idVec3 &origin ) {
|
||||
|
||||
if ( !file ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( aas_randomPullPlayer.GetBool() ) {
|
||||
RandomPullPlayer( origin );
|
||||
}
|
||||
if ( ( aas_pullPlayer.GetInteger() > 0 ) && ( aas_pullPlayer.GetInteger() < file->GetNumAreas() ) ) {
|
||||
ShowWalkPath( origin, aas_pullPlayer.GetInteger(), AreaCenter( aas_pullPlayer.GetInteger() ) );
|
||||
PullPlayer( origin, aas_pullPlayer.GetInteger() );
|
||||
}
|
||||
if ( ( aas_showPath.GetInteger() > 0 ) && ( aas_showPath.GetInteger() < file->GetNumAreas() ) ) {
|
||||
ShowWalkPath( origin, aas_showPath.GetInteger(), AreaCenter( aas_showPath.GetInteger() ) );
|
||||
}
|
||||
if ( ( aas_showFlyPath.GetInteger() > 0 ) && ( aas_showFlyPath.GetInteger() < file->GetNumAreas() ) ) {
|
||||
ShowFlyPath( origin, aas_showFlyPath.GetInteger(), AreaCenter( aas_showFlyPath.GetInteger() ) );
|
||||
}
|
||||
if ( ( aas_showHideArea.GetInteger() > 0 ) && ( aas_showHideArea.GetInteger() < file->GetNumAreas() ) ) {
|
||||
ShowHideArea( origin, aas_showHideArea.GetInteger() );
|
||||
}
|
||||
if ( aas_showAreas.GetBool() ) {
|
||||
ShowArea( origin );
|
||||
}
|
||||
if ( aas_showWallEdges.GetBool() ) {
|
||||
ShowWallEdges( origin );
|
||||
}
|
||||
if ( aas_showPushIntoArea.GetBool() ) {
|
||||
ShowPushIntoArea( origin );
|
||||
}
|
||||
}
|
||||
189
neo/d3xp/ai/AAS_local.h
Normal file
189
neo/d3xp/ai/AAS_local.h
Normal file
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __AAS_LOCAL_H__
|
||||
#define __AAS_LOCAL_H__
|
||||
|
||||
#include "AAS.h"
|
||||
#include "../Pvs.h"
|
||||
|
||||
|
||||
class idRoutingCache {
|
||||
friend class idAASLocal;
|
||||
|
||||
public:
|
||||
idRoutingCache( int size );
|
||||
~idRoutingCache( void );
|
||||
|
||||
int Size( void ) const;
|
||||
|
||||
private:
|
||||
int type; // portal or area cache
|
||||
int size; // size of cache
|
||||
int cluster; // cluster of the cache
|
||||
int areaNum; // area of the cache
|
||||
int travelFlags; // combinations of the travel flags
|
||||
idRoutingCache * next; // next in list
|
||||
idRoutingCache * prev; // previous in list
|
||||
idRoutingCache * time_next; // next in time based list
|
||||
idRoutingCache * time_prev; // previous in time based list
|
||||
unsigned short startTravelTime; // travel time to start with
|
||||
unsigned char * reachabilities; // reachabilities used for routing
|
||||
unsigned short * travelTimes; // travel time for every area
|
||||
};
|
||||
|
||||
|
||||
class idRoutingUpdate {
|
||||
friend class idAASLocal;
|
||||
|
||||
private:
|
||||
int cluster; // cluster number of this update
|
||||
int areaNum; // area number of this update
|
||||
unsigned short tmpTravelTime; // temporary travel time
|
||||
unsigned short * areaTravelTimes; // travel times within the area
|
||||
idVec3 start; // start point into area
|
||||
idRoutingUpdate * next; // next in list
|
||||
idRoutingUpdate * prev; // prev in list
|
||||
bool isInList; // true if the update is in the list
|
||||
};
|
||||
|
||||
|
||||
class idRoutingObstacle {
|
||||
friend class idAASLocal;
|
||||
idRoutingObstacle( void ) { }
|
||||
|
||||
private:
|
||||
idBounds bounds; // obstacle bounds
|
||||
idList<int> areas; // areas the bounds are in
|
||||
};
|
||||
|
||||
|
||||
class idAASLocal : public idAAS {
|
||||
public:
|
||||
idAASLocal( void );
|
||||
virtual ~idAASLocal( void );
|
||||
virtual bool Init( const idStr &mapName, unsigned int mapFileCRC );
|
||||
virtual void Shutdown( void );
|
||||
virtual void Stats( void ) const;
|
||||
virtual void Test( const idVec3 &origin );
|
||||
virtual const idAASSettings *GetSettings( void ) const;
|
||||
virtual int PointAreaNum( const idVec3 &origin ) const;
|
||||
virtual int PointReachableAreaNum( const idVec3 &origin, const idBounds &searchBounds, const int areaFlags ) const;
|
||||
virtual int BoundsReachableAreaNum( const idBounds &bounds, const int areaFlags ) const;
|
||||
virtual void PushPointIntoAreaNum( int areaNum, idVec3 &origin ) const;
|
||||
virtual idVec3 AreaCenter( int areaNum ) const;
|
||||
virtual int AreaFlags( int areaNum ) const;
|
||||
virtual int AreaTravelFlags( int areaNum ) const;
|
||||
virtual bool Trace( aasTrace_t &trace, const idVec3 &start, const idVec3 &end ) const;
|
||||
virtual const idPlane & GetPlane( int planeNum ) const;
|
||||
virtual int GetWallEdges( int areaNum, const idBounds &bounds, int travelFlags, int *edges, int maxEdges ) const;
|
||||
virtual void SortWallEdges( int *edges, int numEdges ) const;
|
||||
virtual void GetEdgeVertexNumbers( int edgeNum, int verts[2] ) const;
|
||||
virtual void GetEdge( int edgeNum, idVec3 &start, idVec3 &end ) const;
|
||||
virtual bool SetAreaState( const idBounds &bounds, const int areaContents, bool disabled );
|
||||
virtual aasHandle_t AddObstacle( const idBounds &bounds );
|
||||
virtual void RemoveObstacle( const aasHandle_t handle );
|
||||
virtual void RemoveAllObstacles( void );
|
||||
virtual int TravelTimeToGoalArea( int areaNum, const idVec3 &origin, int goalAreaNum, int travelFlags ) const;
|
||||
virtual bool RouteToGoalArea( int areaNum, const idVec3 origin, int goalAreaNum, int travelFlags, int &travelTime, idReachability **reach ) const;
|
||||
virtual bool WalkPathToGoal( aasPath_t &path, int areaNum, const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin, int travelFlags ) const;
|
||||
virtual bool WalkPathValid( int areaNum, const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin, int travelFlags, idVec3 &endPos, int &endAreaNum ) const;
|
||||
virtual bool FlyPathToGoal( aasPath_t &path, int areaNum, const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin, int travelFlags ) const;
|
||||
virtual bool FlyPathValid( int areaNum, const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin, int travelFlags, idVec3 &endPos, int &endAreaNum ) const;
|
||||
virtual void ShowWalkPath( const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin ) const;
|
||||
virtual void ShowFlyPath( const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin ) const;
|
||||
virtual bool FindNearestGoal( aasGoal_t &goal, int areaNum, const idVec3 origin, const idVec3 &target, int travelFlags, aasObstacle_t *obstacles, int numObstacles, idAASCallback &callback ) const;
|
||||
|
||||
private:
|
||||
idAASFile * file;
|
||||
idStr name;
|
||||
|
||||
private: // routing data
|
||||
idRoutingCache *** areaCacheIndex; // for each area in each cluster the travel times to all other areas in the cluster
|
||||
int areaCacheIndexSize; // number of area cache entries
|
||||
idRoutingCache ** portalCacheIndex; // for each area in the world the travel times from each portal
|
||||
int portalCacheIndexSize; // number of portal cache entries
|
||||
idRoutingUpdate * areaUpdate; // memory used to update the area routing cache
|
||||
idRoutingUpdate * portalUpdate; // memory used to update the portal routing cache
|
||||
unsigned short * goalAreaTravelTimes; // travel times to goal areas
|
||||
unsigned short * areaTravelTimes; // travel times through the areas
|
||||
int numAreaTravelTimes; // number of area travel times
|
||||
mutable idRoutingCache * cacheListStart; // start of list with cache sorted from oldest to newest
|
||||
mutable idRoutingCache * cacheListEnd; // end of list with cache sorted from oldest to newest
|
||||
mutable int totalCacheMemory; // total cache memory used
|
||||
idList<idRoutingObstacle *> obstacleList; // list with obstacles
|
||||
|
||||
private: // routing
|
||||
bool SetupRouting( void );
|
||||
void ShutdownRouting( void );
|
||||
unsigned short AreaTravelTime( int areaNum, const idVec3 &start, const idVec3 &end ) const;
|
||||
void CalculateAreaTravelTimes( void );
|
||||
void DeleteAreaTravelTimes( void );
|
||||
void SetupRoutingCache( void );
|
||||
void DeleteClusterCache( int clusterNum );
|
||||
void DeletePortalCache( void );
|
||||
void ShutdownRoutingCache( void );
|
||||
void RoutingStats( void ) const;
|
||||
void LinkCache( idRoutingCache *cache ) const;
|
||||
void UnlinkCache( idRoutingCache *cache ) const;
|
||||
void DeleteOldestCache( void ) const;
|
||||
idReachability * GetAreaReachability( int areaNum, int reachabilityNum ) const;
|
||||
int ClusterAreaNum( int clusterNum, int areaNum ) const;
|
||||
void UpdateAreaRoutingCache( idRoutingCache *areaCache ) const;
|
||||
idRoutingCache * GetAreaRoutingCache( int clusterNum, int areaNum, int travelFlags ) const;
|
||||
void UpdatePortalRoutingCache( idRoutingCache *portalCache ) const;
|
||||
idRoutingCache * GetPortalRoutingCache( int clusterNum, int areaNum, int travelFlags ) const;
|
||||
void RemoveRoutingCacheUsingArea( int areaNum );
|
||||
void DisableArea( int areaNum );
|
||||
void EnableArea( int areaNum );
|
||||
bool SetAreaState_r( int nodeNum, const idBounds &bounds, const int areaContents, bool disabled );
|
||||
void GetBoundsAreas_r( int nodeNum, const idBounds &bounds, idList<int> &areas ) const;
|
||||
void SetObstacleState( const idRoutingObstacle *obstacle, bool enable );
|
||||
|
||||
private: // pathing
|
||||
bool EdgeSplitPoint( idVec3 &split, int edgeNum, const idPlane &plane ) const;
|
||||
bool FloorEdgeSplitPoint( idVec3 &split, int areaNum, const idPlane &splitPlane, const idPlane &frontPlane, bool closest ) const;
|
||||
idVec3 SubSampleWalkPath( int areaNum, const idVec3 &origin, const idVec3 &start, const idVec3 &end, int travelFlags, int &endAreaNum ) const;
|
||||
idVec3 SubSampleFlyPath( int areaNum, const idVec3 &origin, const idVec3 &start, const idVec3 &end, int travelFlags, int &endAreaNum ) const;
|
||||
|
||||
private: // debug
|
||||
const idBounds & DefaultSearchBounds( void ) const;
|
||||
void DrawCone( const idVec3 &origin, const idVec3 &dir, float radius, const idVec4 &color ) const;
|
||||
void DrawArea( int areaNum ) const;
|
||||
void DrawFace( int faceNum, bool side ) const;
|
||||
void DrawEdge( int edgeNum, bool arrow ) const;
|
||||
void DrawReachability( const idReachability *reach ) const;
|
||||
void ShowArea( const idVec3 &origin ) const;
|
||||
void ShowWallEdges( const idVec3 &origin ) const;
|
||||
void ShowHideArea( const idVec3 &origin, int targerAreaNum ) const;
|
||||
bool PullPlayer( const idVec3 &origin, int toAreaNum ) const;
|
||||
void RandomPullPlayer( const idVec3 &origin ) const;
|
||||
void ShowPushIntoArea( const idVec3 &origin ) const;
|
||||
};
|
||||
|
||||
#endif /* !__AAS_LOCAL_H__ */
|
||||
716
neo/d3xp/ai/AAS_pathing.cpp
Normal file
716
neo/d3xp/ai/AAS_pathing.cpp
Normal file
@@ -0,0 +1,716 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "../../idlib/precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "AAS_local.h"
|
||||
|
||||
#define SUBSAMPLE_WALK_PATH 1
|
||||
#define SUBSAMPLE_FLY_PATH 0
|
||||
|
||||
const int maxWalkPathIterations = 10;
|
||||
const float maxWalkPathDistance = 500.0f;
|
||||
const float walkPathSampleDistance = 8.0f;
|
||||
|
||||
const int maxFlyPathIterations = 10;
|
||||
const float maxFlyPathDistance = 500.0f;
|
||||
const float flyPathSampleDistance = 8.0f;
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::EdgeSplitPoint
|
||||
|
||||
calculates split point of the edge with the plane
|
||||
returns true if the split point is between the edge vertices
|
||||
============
|
||||
*/
|
||||
bool idAASLocal::EdgeSplitPoint( idVec3 &split, int edgeNum, const idPlane &plane ) const {
|
||||
const aasEdge_t *edge;
|
||||
idVec3 v1, v2;
|
||||
float d1, d2;
|
||||
|
||||
edge = &file->GetEdge( edgeNum );
|
||||
v1 = file->GetVertex( edge->vertexNum[0] );
|
||||
v2 = file->GetVertex( edge->vertexNum[1] );
|
||||
d1 = v1 * plane.Normal() - plane.Dist();
|
||||
d2 = v2 * plane.Normal() - plane.Dist();
|
||||
|
||||
//if ( (d1 < CM_CLIP_EPSILON && d2 < CM_CLIP_EPSILON) || (d1 > -CM_CLIP_EPSILON && d2 > -CM_CLIP_EPSILON) ) {
|
||||
if ( FLOATSIGNBITSET( d1 ) == FLOATSIGNBITSET( d2 ) ) {
|
||||
return false;
|
||||
}
|
||||
split = v1 + (d1 / (d1 - d2)) * (v2 - v1);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::FloorEdgeSplitPoint
|
||||
|
||||
calculates either the closest or furthest point on the floor of the area which also lies on the pathPlane
|
||||
the point has to be on the front side of the frontPlane to be valid
|
||||
============
|
||||
*/
|
||||
bool idAASLocal::FloorEdgeSplitPoint( idVec3 &bestSplit, int areaNum, const idPlane &pathPlane, const idPlane &frontPlane, bool closest ) const {
|
||||
int i, j, faceNum, edgeNum;
|
||||
const aasArea_t *area;
|
||||
const aasFace_t *face;
|
||||
idVec3 split;
|
||||
float dist, bestDist;
|
||||
|
||||
if ( closest ) {
|
||||
bestDist = maxWalkPathDistance;
|
||||
} else {
|
||||
bestDist = -0.1f;
|
||||
}
|
||||
|
||||
area = &file->GetArea( areaNum );
|
||||
|
||||
for ( i = 0; i < area->numFaces; i++ ) {
|
||||
faceNum = file->GetFaceIndex( area->firstFace + i );
|
||||
face = &file->GetFace( abs(faceNum) );
|
||||
|
||||
if ( !(face->flags & FACE_FLOOR ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for ( j = 0; j < face->numEdges; j++ ) {
|
||||
edgeNum = file->GetEdgeIndex( face->firstEdge + j );
|
||||
|
||||
if ( !EdgeSplitPoint( split, abs( edgeNum ), pathPlane ) ) {
|
||||
continue;
|
||||
}
|
||||
dist = frontPlane.Distance( split );
|
||||
if ( closest ) {
|
||||
if ( dist >= -0.1f && dist < bestDist ) {
|
||||
bestDist = dist;
|
||||
bestSplit = split;
|
||||
}
|
||||
} else {
|
||||
if ( dist > bestDist ) {
|
||||
bestDist = dist;
|
||||
bestSplit = split;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( closest ) {
|
||||
return ( bestDist < maxWalkPathDistance );
|
||||
} else {
|
||||
return ( bestDist > -0.1f );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::WalkPathValid
|
||||
|
||||
returns true if one can walk in a straight line between origin and goalOrigin
|
||||
============
|
||||
*/
|
||||
bool idAASLocal::WalkPathValid( int areaNum, const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin, int travelFlags, idVec3 &endPos, int &endAreaNum ) const {
|
||||
int curAreaNum, lastAreaNum, lastAreas[4], lastAreaIndex;
|
||||
idPlane pathPlane, frontPlane, farPlane;
|
||||
idReachability *reach;
|
||||
const aasArea_t *area;
|
||||
idVec3 p, dir;
|
||||
|
||||
if ( file == NULL ) {
|
||||
endPos = goalOrigin;
|
||||
endAreaNum = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
lastAreas[0] = lastAreas[1] = lastAreas[2] = lastAreas[3] = areaNum;
|
||||
lastAreaIndex = 0;
|
||||
|
||||
pathPlane.SetNormal( (goalOrigin - origin).Cross( file->GetSettings().gravityDir ) );
|
||||
pathPlane.Normalize();
|
||||
pathPlane.FitThroughPoint( origin );
|
||||
|
||||
frontPlane.SetNormal( goalOrigin - origin );
|
||||
frontPlane.Normalize();
|
||||
frontPlane.FitThroughPoint( origin );
|
||||
|
||||
farPlane.SetNormal( frontPlane.Normal() );
|
||||
farPlane.FitThroughPoint( goalOrigin );
|
||||
|
||||
curAreaNum = areaNum;
|
||||
lastAreaNum = curAreaNum;
|
||||
|
||||
while ( 1 ) {
|
||||
|
||||
// find the furthest floor face split point on the path
|
||||
if ( !FloorEdgeSplitPoint( endPos, curAreaNum, pathPlane, frontPlane, false ) ) {
|
||||
endPos = origin;
|
||||
}
|
||||
|
||||
// if we found a point near or further than the goal we're done
|
||||
if ( farPlane.Distance( endPos ) > -0.5f ) {
|
||||
break;
|
||||
}
|
||||
|
||||
// if we reached the goal area we're done
|
||||
if ( curAreaNum == goalAreaNum ) {
|
||||
break;
|
||||
}
|
||||
|
||||
frontPlane.SetDist( frontPlane.Normal() * endPos );
|
||||
|
||||
area = &file->GetArea( curAreaNum );
|
||||
|
||||
for ( reach = area->reach; reach; reach = reach->next ) {
|
||||
if ( reach->travelType != TFL_WALK ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// if the reachability goes back to a previous area
|
||||
if ( reach->toAreaNum == lastAreas[0] || reach->toAreaNum == lastAreas[1] ||
|
||||
reach->toAreaNum == lastAreas[2] || reach->toAreaNum == lastAreas[3] ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// if undesired travel flags are required to travel through the area
|
||||
if ( file->GetArea( reach->toAreaNum ).travelFlags & ~travelFlags ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// don't optimize through an area near a ledge
|
||||
if ( file->GetArea( reach->toAreaNum ).flags & AREA_LEDGE ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// find the closest floor face split point on the path
|
||||
if ( !FloorEdgeSplitPoint( p, reach->toAreaNum, pathPlane, frontPlane, true ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// direction parallel to gravity
|
||||
dir = ( file->GetSettings().gravityDir * endPos * file->GetSettings().gravityDir ) -
|
||||
( file->GetSettings().gravityDir * p * file->GetSettings().gravityDir );
|
||||
if ( dir.LengthSqr() > Square( file->GetSettings().maxStepHeight ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// direction orthogonal to gravity
|
||||
dir = endPos - p - dir;
|
||||
if ( dir.LengthSqr() > Square( 0.2f ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !reach ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
lastAreas[lastAreaIndex] = curAreaNum;
|
||||
lastAreaIndex = ( lastAreaIndex + 1 ) & 3;
|
||||
|
||||
curAreaNum = reach->toAreaNum;
|
||||
}
|
||||
|
||||
endAreaNum = curAreaNum;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::SubSampleWalkPath
|
||||
============
|
||||
*/
|
||||
idVec3 idAASLocal::SubSampleWalkPath( int areaNum, const idVec3 &origin, const idVec3 &start, const idVec3 &end, int travelFlags, int &endAreaNum ) const {
|
||||
int i, numSamples, curAreaNum;
|
||||
idVec3 dir, point, nextPoint, endPos;
|
||||
|
||||
dir = end - start;
|
||||
numSamples = (int) (dir.Length() / walkPathSampleDistance) + 1;
|
||||
|
||||
point = start;
|
||||
for ( i = 1; i < numSamples; i++ ) {
|
||||
nextPoint = start + dir * ((float) i / numSamples);
|
||||
if ( (point - nextPoint).LengthSqr() > Square( maxWalkPathDistance ) ) {
|
||||
return point;
|
||||
}
|
||||
if ( !idAASLocal::WalkPathValid( areaNum, origin, 0, nextPoint, travelFlags, endPos, curAreaNum ) ) {
|
||||
return point;
|
||||
}
|
||||
point = nextPoint;
|
||||
endAreaNum = curAreaNum;
|
||||
}
|
||||
return point;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::WalkPathToGoal
|
||||
|
||||
FIXME: don't stop optimizing on first failure ?
|
||||
============
|
||||
*/
|
||||
bool idAASLocal::WalkPathToGoal( aasPath_t &path, int areaNum, const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin, int travelFlags ) const {
|
||||
int i, travelTime, curAreaNum, lastAreas[4], lastAreaIndex, endAreaNum;
|
||||
idReachability *reach;
|
||||
idVec3 endPos;
|
||||
|
||||
path.type = PATHTYPE_WALK;
|
||||
path.moveGoal = origin;
|
||||
path.moveAreaNum = areaNum;
|
||||
path.secondaryGoal = origin;
|
||||
path.reachability = NULL;
|
||||
|
||||
if ( file == NULL || areaNum == goalAreaNum ) {
|
||||
path.moveGoal = goalOrigin;
|
||||
return true;
|
||||
}
|
||||
|
||||
lastAreas[0] = lastAreas[1] = lastAreas[2] = lastAreas[3] = areaNum;
|
||||
lastAreaIndex = 0;
|
||||
|
||||
curAreaNum = areaNum;
|
||||
|
||||
for ( i = 0; i < maxWalkPathIterations; i++ ) {
|
||||
|
||||
if ( !idAASLocal::RouteToGoalArea( curAreaNum, path.moveGoal, goalAreaNum, travelFlags, travelTime, &reach ) ) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !reach ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// no need to check through the first area
|
||||
if ( areaNum != curAreaNum ) {
|
||||
// only optimize a limited distance ahead
|
||||
if ( (reach->start - origin).LengthSqr() > Square( maxWalkPathDistance ) ) {
|
||||
#if SUBSAMPLE_WALK_PATH
|
||||
path.moveGoal = SubSampleWalkPath( areaNum, origin, path.moveGoal, reach->start, travelFlags, path.moveAreaNum );
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( !idAASLocal::WalkPathValid( areaNum, origin, 0, reach->start, travelFlags, endPos, endAreaNum ) ) {
|
||||
#if SUBSAMPLE_WALK_PATH
|
||||
path.moveGoal = SubSampleWalkPath( areaNum, origin, path.moveGoal, reach->start, travelFlags, path.moveAreaNum );
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
path.moveGoal = reach->start;
|
||||
path.moveAreaNum = curAreaNum;
|
||||
|
||||
if ( reach->travelType != TFL_WALK ) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !idAASLocal::WalkPathValid( areaNum, origin, 0, reach->end, travelFlags, endPos, endAreaNum ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
path.moveGoal = reach->end;
|
||||
path.moveAreaNum = reach->toAreaNum;
|
||||
|
||||
if ( reach->toAreaNum == goalAreaNum ) {
|
||||
if ( !idAASLocal::WalkPathValid( areaNum, origin, 0, goalOrigin, travelFlags, endPos, endAreaNum ) ) {
|
||||
#if SUBSAMPLE_WALK_PATH
|
||||
path.moveGoal = SubSampleWalkPath( areaNum, origin, path.moveGoal, goalOrigin, travelFlags, path.moveAreaNum );
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
path.moveGoal = goalOrigin;
|
||||
path.moveAreaNum = goalAreaNum;
|
||||
return true;
|
||||
}
|
||||
|
||||
lastAreas[lastAreaIndex] = curAreaNum;
|
||||
lastAreaIndex = ( lastAreaIndex + 1 ) & 3;
|
||||
|
||||
curAreaNum = reach->toAreaNum;
|
||||
|
||||
if ( curAreaNum == lastAreas[0] || curAreaNum == lastAreas[1] ||
|
||||
curAreaNum == lastAreas[2] || curAreaNum == lastAreas[3] ) {
|
||||
common->Warning( "idAASLocal::WalkPathToGoal: local routing minimum going from area %d to area %d", areaNum, goalAreaNum );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !reach ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch( reach->travelType ) {
|
||||
case TFL_WALKOFFLEDGE:
|
||||
path.type = PATHTYPE_WALKOFFLEDGE;
|
||||
path.secondaryGoal = reach->end;
|
||||
path.reachability = reach;
|
||||
break;
|
||||
case TFL_BARRIERJUMP:
|
||||
path.type |= PATHTYPE_BARRIERJUMP;
|
||||
path.secondaryGoal = reach->end;
|
||||
path.reachability = reach;
|
||||
break;
|
||||
case TFL_JUMP:
|
||||
path.type |= PATHTYPE_JUMP;
|
||||
path.secondaryGoal = reach->end;
|
||||
path.reachability = reach;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::FlyPathValid
|
||||
|
||||
returns true if one can fly in a straight line between origin and goalOrigin
|
||||
============
|
||||
*/
|
||||
bool idAASLocal::FlyPathValid( int areaNum, const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin, int travelFlags, idVec3 &endPos, int &endAreaNum ) const {
|
||||
aasTrace_t trace;
|
||||
|
||||
if ( file == NULL ) {
|
||||
endPos = goalOrigin;
|
||||
endAreaNum = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
file->Trace( trace, origin, goalOrigin );
|
||||
|
||||
endPos = trace.endpos;
|
||||
endAreaNum = trace.lastAreaNum;
|
||||
|
||||
if ( trace.fraction >= 1.0f ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::SubSampleFlyPath
|
||||
============
|
||||
*/
|
||||
idVec3 idAASLocal::SubSampleFlyPath( int areaNum, const idVec3 &origin, const idVec3 &start, const idVec3 &end, int travelFlags, int &endAreaNum ) const {
|
||||
int i, numSamples, curAreaNum;
|
||||
idVec3 dir, point, nextPoint, endPos;
|
||||
|
||||
dir = end - start;
|
||||
numSamples = (int) (dir.Length() / flyPathSampleDistance) + 1;
|
||||
|
||||
point = start;
|
||||
for ( i = 1; i < numSamples; i++ ) {
|
||||
nextPoint = start + dir * ((float) i / numSamples);
|
||||
if ( (point - nextPoint).LengthSqr() > Square( maxFlyPathDistance ) ) {
|
||||
return point;
|
||||
}
|
||||
if ( !idAASLocal::FlyPathValid( areaNum, origin, 0, nextPoint, travelFlags, endPos, curAreaNum ) ) {
|
||||
return point;
|
||||
}
|
||||
point = nextPoint;
|
||||
endAreaNum = curAreaNum;
|
||||
}
|
||||
return point;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::FlyPathToGoal
|
||||
|
||||
FIXME: don't stop optimizing on first failure ?
|
||||
============
|
||||
*/
|
||||
bool idAASLocal::FlyPathToGoal( aasPath_t &path, int areaNum, const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin, int travelFlags ) const {
|
||||
int i, travelTime, curAreaNum, lastAreas[4], lastAreaIndex, endAreaNum;
|
||||
idReachability *reach;
|
||||
idVec3 endPos;
|
||||
|
||||
path.type = PATHTYPE_WALK;
|
||||
path.moveGoal = origin;
|
||||
path.moveAreaNum = areaNum;
|
||||
path.secondaryGoal = origin;
|
||||
path.reachability = NULL;
|
||||
|
||||
if ( file == NULL || areaNum == goalAreaNum ) {
|
||||
path.moveGoal = goalOrigin;
|
||||
return true;
|
||||
}
|
||||
|
||||
lastAreas[0] = lastAreas[1] = lastAreas[2] = lastAreas[3] = areaNum;
|
||||
lastAreaIndex = 0;
|
||||
|
||||
curAreaNum = areaNum;
|
||||
|
||||
for ( i = 0; i < maxFlyPathIterations; i++ ) {
|
||||
|
||||
if ( !idAASLocal::RouteToGoalArea( curAreaNum, path.moveGoal, goalAreaNum, travelFlags, travelTime, &reach ) ) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !reach ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// no need to check through the first area
|
||||
if ( areaNum != curAreaNum ) {
|
||||
if ( (reach->start - origin).LengthSqr() > Square( maxFlyPathDistance ) ) {
|
||||
#if SUBSAMPLE_FLY_PATH
|
||||
path.moveGoal = SubSampleFlyPath( areaNum, origin, path.moveGoal, reach->start, travelFlags, path.moveAreaNum );
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( !idAASLocal::FlyPathValid( areaNum, origin, 0, reach->start, travelFlags, endPos, endAreaNum ) ) {
|
||||
#if SUBSAMPLE_FLY_PATH
|
||||
path.moveGoal = SubSampleFlyPath( areaNum, origin, path.moveGoal, reach->start, travelFlags, path.moveAreaNum );
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
path.moveGoal = reach->start;
|
||||
path.moveAreaNum = curAreaNum;
|
||||
|
||||
if ( !idAASLocal::FlyPathValid( areaNum, origin, 0, reach->end, travelFlags, endPos, endAreaNum ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
path.moveGoal = reach->end;
|
||||
path.moveAreaNum = reach->toAreaNum;
|
||||
|
||||
if ( reach->toAreaNum == goalAreaNum ) {
|
||||
if ( !idAASLocal::FlyPathValid( areaNum, origin, 0, goalOrigin, travelFlags, endPos, endAreaNum ) ) {
|
||||
#if SUBSAMPLE_FLY_PATH
|
||||
path.moveGoal = SubSampleFlyPath( areaNum, origin, path.moveGoal, goalOrigin, travelFlags, path.moveAreaNum );
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
path.moveGoal = goalOrigin;
|
||||
path.moveAreaNum = goalAreaNum;
|
||||
return true;
|
||||
}
|
||||
|
||||
lastAreas[lastAreaIndex] = curAreaNum;
|
||||
lastAreaIndex = ( lastAreaIndex + 1 ) & 3;
|
||||
|
||||
curAreaNum = reach->toAreaNum;
|
||||
|
||||
if ( curAreaNum == lastAreas[0] || curAreaNum == lastAreas[1] ||
|
||||
curAreaNum == lastAreas[2] || curAreaNum == lastAreas[3] ) {
|
||||
common->Warning( "idAASLocal::FlyPathToGoal: local routing minimum going from area %d to area %d", areaNum, goalAreaNum );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !reach ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef struct wallEdge_s {
|
||||
int edgeNum;
|
||||
int verts[2];
|
||||
struct wallEdge_s * next;
|
||||
} wallEdge_t;
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::SortWallEdges
|
||||
============
|
||||
*/
|
||||
void idAASLocal::SortWallEdges( int *edges, int numEdges ) const {
|
||||
int i, j, k, numSequences;
|
||||
wallEdge_t **sequenceFirst, **sequenceLast, *wallEdges, *wallEdge;
|
||||
|
||||
wallEdges = (wallEdge_t *) _alloca16( numEdges * sizeof( wallEdge_t ) );
|
||||
sequenceFirst = (wallEdge_t **)_alloca16( numEdges * sizeof( wallEdge_t * ) );
|
||||
sequenceLast = (wallEdge_t **)_alloca16( numEdges * sizeof( wallEdge_t * ) );
|
||||
|
||||
for ( i = 0; i < numEdges; i++ ) {
|
||||
wallEdges[i].edgeNum = edges[i];
|
||||
GetEdgeVertexNumbers( edges[i], wallEdges[i].verts );
|
||||
wallEdges[i].next = NULL;
|
||||
sequenceFirst[i] = &wallEdges[i];
|
||||
sequenceLast[i] = &wallEdges[i];
|
||||
}
|
||||
numSequences = numEdges;
|
||||
|
||||
for ( i = 0; i < numSequences; i++ ) {
|
||||
for ( j = i+1; j < numSequences; j++ ) {
|
||||
if ( sequenceFirst[i]->verts[0] == sequenceLast[j]->verts[1] ) {
|
||||
sequenceLast[j]->next = sequenceFirst[i];
|
||||
sequenceFirst[i] = sequenceFirst[j];
|
||||
break;
|
||||
}
|
||||
if ( sequenceLast[i]->verts[1] == sequenceFirst[j]->verts[0] ) {
|
||||
sequenceLast[i]->next = sequenceFirst[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( j < numSequences ) {
|
||||
numSequences--;
|
||||
for ( k = j; k < numSequences; k++ ) {
|
||||
sequenceFirst[k] = sequenceFirst[k+1];
|
||||
sequenceLast[k] = sequenceLast[k+1];
|
||||
}
|
||||
i = -1;
|
||||
}
|
||||
}
|
||||
|
||||
k = 0;
|
||||
for ( i = 0; i < numSequences; i++ ) {
|
||||
for ( wallEdge = sequenceFirst[i]; wallEdge; wallEdge = wallEdge->next ) {
|
||||
edges[k++] = wallEdge->edgeNum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
idAASLocal::GetWallEdges
|
||||
============
|
||||
*/
|
||||
int idAASLocal::GetWallEdges( int areaNum, const idBounds &bounds, int travelFlags, int *edges, int maxEdges ) const {
|
||||
int i, j, k, l, face1Num, face2Num, edge1Num, edge2Num, numEdges, absEdge1Num;
|
||||
int *areaQueue, curArea, queueStart, queueEnd;
|
||||
byte *areasVisited;
|
||||
const aasArea_t *area;
|
||||
const aasFace_t *face1, *face2;
|
||||
idReachability *reach;
|
||||
|
||||
if ( !file ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
numEdges = 0;
|
||||
|
||||
areasVisited = (byte *) _alloca16( file->GetNumAreas() );
|
||||
memset( areasVisited, 0, file->GetNumAreas() * sizeof( byte ) );
|
||||
areaQueue = (int *) _alloca16( file->GetNumAreas() * sizeof( int ) );
|
||||
|
||||
queueStart = -1;
|
||||
queueEnd = 0;
|
||||
areaQueue[0] = areaNum;
|
||||
areasVisited[areaNum] = true;
|
||||
|
||||
for ( curArea = areaNum; queueStart < queueEnd; curArea = areaQueue[++queueStart] ) {
|
||||
|
||||
area = &file->GetArea( curArea );
|
||||
|
||||
for ( i = 0; i < area->numFaces; i++ ) {
|
||||
face1Num = file->GetFaceIndex( area->firstFace + i );
|
||||
face1 = &file->GetFace( abs(face1Num) );
|
||||
|
||||
if ( !(face1->flags & FACE_FLOOR ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for ( j = 0; j < face1->numEdges; j++ ) {
|
||||
edge1Num = file->GetEdgeIndex( face1->firstEdge + j );
|
||||
absEdge1Num = abs( edge1Num );
|
||||
|
||||
// test if the edge is shared by another floor face of this area
|
||||
for ( k = 0; k < area->numFaces; k++ ) {
|
||||
if ( k == i ) {
|
||||
continue;
|
||||
}
|
||||
face2Num = file->GetFaceIndex( area->firstFace + k );
|
||||
face2 = &file->GetFace( abs(face2Num) );
|
||||
|
||||
if ( !(face2->flags & FACE_FLOOR ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for ( l = 0; l < face2->numEdges; l++ ) {
|
||||
edge2Num = abs( file->GetEdgeIndex( face2->firstEdge + l ) );
|
||||
if ( edge2Num == absEdge1Num ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( l < face2->numEdges ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( k < area->numFaces ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// test if the edge is used by a reachability
|
||||
for ( reach = area->reach; reach; reach = reach->next ) {
|
||||
if ( reach->travelType & travelFlags ) {
|
||||
if ( reach->edgeNum == absEdge1Num ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( reach ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// test if the edge is already in the list
|
||||
for ( k = 0; k < numEdges; k++ ) {
|
||||
if ( edge1Num == edges[k] ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( k < numEdges ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// add the edge to the list
|
||||
edges[numEdges++] = edge1Num;
|
||||
if ( numEdges >= maxEdges ) {
|
||||
return numEdges;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add new areas to the queue
|
||||
for ( reach = area->reach; reach; reach = reach->next ) {
|
||||
if ( reach->travelType & travelFlags ) {
|
||||
// if the area the reachability leads to hasn't been visited yet and the area bounds touch the search bounds
|
||||
if ( !areasVisited[reach->toAreaNum] && bounds.IntersectsBounds( file->GetArea( reach->toAreaNum ).bounds ) ) {
|
||||
areaQueue[queueEnd++] = reach->toAreaNum;
|
||||
areasVisited[reach->toAreaNum] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return numEdges;
|
||||
}
|
||||
1349
neo/d3xp/ai/AAS_routing.cpp
Normal file
1349
neo/d3xp/ai/AAS_routing.cpp
Normal file
File diff suppressed because it is too large
Load Diff
5354
neo/d3xp/ai/AI.cpp
Normal file
5354
neo/d3xp/ai/AI.cpp
Normal file
File diff suppressed because it is too large
Load Diff
736
neo/d3xp/ai/AI.h
Normal file
736
neo/d3xp/ai/AI.h
Normal file
@@ -0,0 +1,736 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __AI_H__
|
||||
#define __AI_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
idAI
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
const float SQUARE_ROOT_OF_2 = 1.414213562f;
|
||||
const float AI_TURN_PREDICTION = 0.2f;
|
||||
const float AI_TURN_SCALE = 60.0f;
|
||||
const float AI_SEEK_PREDICTION = 0.3f;
|
||||
const float AI_FLY_DAMPENING = 0.15f;
|
||||
const float AI_HEARING_RANGE = 2048.0f;
|
||||
const int DEFAULT_FLY_OFFSET = 68;
|
||||
|
||||
#define ATTACK_IGNORE 0
|
||||
#define ATTACK_ON_DAMAGE 1
|
||||
#define ATTACK_ON_ACTIVATE 2
|
||||
#define ATTACK_ON_SIGHT 4
|
||||
|
||||
// defined in script/ai_base.script. please keep them up to date.
|
||||
typedef enum {
|
||||
MOVETYPE_DEAD,
|
||||
MOVETYPE_ANIM,
|
||||
MOVETYPE_SLIDE,
|
||||
MOVETYPE_FLY,
|
||||
MOVETYPE_STATIC,
|
||||
NUM_MOVETYPES
|
||||
} moveType_t;
|
||||
|
||||
typedef enum {
|
||||
MOVE_NONE,
|
||||
MOVE_FACE_ENEMY,
|
||||
MOVE_FACE_ENTITY,
|
||||
|
||||
// commands < NUM_NONMOVING_COMMANDS don't cause a change in position
|
||||
NUM_NONMOVING_COMMANDS,
|
||||
|
||||
MOVE_TO_ENEMY = NUM_NONMOVING_COMMANDS,
|
||||
MOVE_TO_ENEMYHEIGHT,
|
||||
MOVE_TO_ENTITY,
|
||||
MOVE_OUT_OF_RANGE,
|
||||
MOVE_TO_ATTACK_POSITION,
|
||||
MOVE_TO_COVER,
|
||||
MOVE_TO_POSITION,
|
||||
MOVE_TO_POSITION_DIRECT,
|
||||
MOVE_SLIDE_TO_POSITION,
|
||||
MOVE_WANDER,
|
||||
NUM_MOVE_COMMANDS
|
||||
} moveCommand_t;
|
||||
|
||||
typedef enum {
|
||||
TALK_NEVER,
|
||||
TALK_DEAD,
|
||||
TALK_OK,
|
||||
TALK_BUSY,
|
||||
NUM_TALK_STATES
|
||||
} talkState_t;
|
||||
|
||||
//
|
||||
// status results from move commands
|
||||
// make sure to change script/doom_defs.script if you add any, or change their order
|
||||
//
|
||||
typedef enum {
|
||||
MOVE_STATUS_DONE,
|
||||
MOVE_STATUS_MOVING,
|
||||
MOVE_STATUS_WAITING,
|
||||
MOVE_STATUS_DEST_NOT_FOUND,
|
||||
MOVE_STATUS_DEST_UNREACHABLE,
|
||||
MOVE_STATUS_BLOCKED_BY_WALL,
|
||||
MOVE_STATUS_BLOCKED_BY_OBJECT,
|
||||
MOVE_STATUS_BLOCKED_BY_ENEMY,
|
||||
MOVE_STATUS_BLOCKED_BY_MONSTER
|
||||
} moveStatus_t;
|
||||
|
||||
#define DI_NODIR -1
|
||||
|
||||
// obstacle avoidance
|
||||
typedef struct obstaclePath_s {
|
||||
idVec3 seekPos; // seek position avoiding obstacles
|
||||
idEntity * firstObstacle; // if != NULL the first obstacle along the path
|
||||
idVec3 startPosOutsideObstacles; // start position outside obstacles
|
||||
idEntity * startPosObstacle; // if != NULL the obstacle containing the start position
|
||||
idVec3 seekPosOutsideObstacles; // seek position outside obstacles
|
||||
idEntity * seekPosObstacle; // if != NULL the obstacle containing the seek position
|
||||
} obstaclePath_t;
|
||||
|
||||
// path prediction
|
||||
typedef enum {
|
||||
SE_BLOCKED = BIT(0),
|
||||
SE_ENTER_LEDGE_AREA = BIT(1),
|
||||
SE_ENTER_OBSTACLE = BIT(2),
|
||||
SE_FALL = BIT(3),
|
||||
SE_LAND = BIT(4)
|
||||
} stopEvent_t;
|
||||
|
||||
typedef struct predictedPath_s {
|
||||
idVec3 endPos; // final position
|
||||
idVec3 endVelocity; // velocity at end position
|
||||
idVec3 endNormal; // normal of blocking surface
|
||||
int endTime; // time predicted
|
||||
int endEvent; // event that stopped the prediction
|
||||
const idEntity * blockingEntity; // entity that blocks the movement
|
||||
} predictedPath_t;
|
||||
|
||||
//
|
||||
// events
|
||||
//
|
||||
extern const idEventDef AI_BeginAttack;
|
||||
extern const idEventDef AI_EndAttack;
|
||||
extern const idEventDef AI_MuzzleFlash;
|
||||
extern const idEventDef AI_CreateMissile;
|
||||
extern const idEventDef AI_AttackMissile;
|
||||
extern const idEventDef AI_FireMissileAtTarget;
|
||||
#ifdef _D3XP
|
||||
extern const idEventDef AI_LaunchProjectile;
|
||||
extern const idEventDef AI_TriggerFX;
|
||||
extern const idEventDef AI_StartEmitter;
|
||||
extern const idEventDef AI_StopEmitter;
|
||||
#endif
|
||||
extern const idEventDef AI_AttackMelee;
|
||||
extern const idEventDef AI_DirectDamage;
|
||||
extern const idEventDef AI_JumpFrame;
|
||||
extern const idEventDef AI_EnableClip;
|
||||
extern const idEventDef AI_DisableClip;
|
||||
extern const idEventDef AI_EnableGravity;
|
||||
extern const idEventDef AI_DisableGravity;
|
||||
extern const idEventDef AI_TriggerParticles;
|
||||
extern const idEventDef AI_RandomPath;
|
||||
|
||||
class idPathCorner;
|
||||
|
||||
typedef struct particleEmitter_s {
|
||||
particleEmitter_s() {
|
||||
particle = NULL;
|
||||
time = 0;
|
||||
joint = INVALID_JOINT;
|
||||
};
|
||||
const idDeclParticle *particle;
|
||||
int time;
|
||||
jointHandle_t joint;
|
||||
} particleEmitter_t;
|
||||
|
||||
#ifdef _D3XP
|
||||
typedef struct funcEmitter_s {
|
||||
char name[64];
|
||||
idFuncEmitter* particle;
|
||||
jointHandle_t joint;
|
||||
} funcEmitter_t;
|
||||
#endif
|
||||
|
||||
class idMoveState {
|
||||
public:
|
||||
idMoveState();
|
||||
|
||||
void Save( idSaveGame *savefile ) const;
|
||||
void Restore( idRestoreGame *savefile );
|
||||
|
||||
moveType_t moveType;
|
||||
moveCommand_t moveCommand;
|
||||
moveStatus_t moveStatus;
|
||||
idVec3 moveDest;
|
||||
idVec3 moveDir; // used for wandering and slide moves
|
||||
idEntityPtr<idEntity> goalEntity;
|
||||
idVec3 goalEntityOrigin; // move to entity uses this to avoid checking the floor position every frame
|
||||
int toAreaNum;
|
||||
int startTime;
|
||||
int duration;
|
||||
float speed; // only used by flying creatures
|
||||
float range;
|
||||
float wanderYaw;
|
||||
int nextWanderTime;
|
||||
int blockTime;
|
||||
idEntityPtr<idEntity> obstacle;
|
||||
idVec3 lastMoveOrigin;
|
||||
int lastMoveTime;
|
||||
int anim;
|
||||
};
|
||||
|
||||
class idAASFindCover : public idAASCallback {
|
||||
public:
|
||||
idAASFindCover( const idVec3 &hideFromPos );
|
||||
~idAASFindCover();
|
||||
|
||||
virtual bool TestArea( const idAAS *aas, int areaNum );
|
||||
|
||||
private:
|
||||
pvsHandle_t hidePVS;
|
||||
int PVSAreas[ idEntity::MAX_PVS_AREAS ];
|
||||
};
|
||||
|
||||
class idAASFindAreaOutOfRange : public idAASCallback {
|
||||
public:
|
||||
idAASFindAreaOutOfRange( const idVec3 &targetPos, float maxDist );
|
||||
|
||||
virtual bool TestArea( const idAAS *aas, int areaNum );
|
||||
|
||||
private:
|
||||
idVec3 targetPos;
|
||||
float maxDistSqr;
|
||||
};
|
||||
|
||||
class idAASFindAttackPosition : public idAASCallback {
|
||||
public:
|
||||
idAASFindAttackPosition( const idAI *self, const idMat3 &gravityAxis, idEntity *target, const idVec3 &targetPos, const idVec3 &fireOffset );
|
||||
~idAASFindAttackPosition();
|
||||
|
||||
virtual bool TestArea( const idAAS *aas, int areaNum );
|
||||
|
||||
private:
|
||||
const idAI *self;
|
||||
idEntity *target;
|
||||
idBounds excludeBounds;
|
||||
idVec3 targetPos;
|
||||
idVec3 fireOffset;
|
||||
idMat3 gravityAxis;
|
||||
pvsHandle_t targetPVS;
|
||||
int PVSAreas[ idEntity::MAX_PVS_AREAS ];
|
||||
};
|
||||
|
||||
class idAI : public idActor {
|
||||
public:
|
||||
CLASS_PROTOTYPE( idAI );
|
||||
|
||||
idAI();
|
||||
~idAI();
|
||||
|
||||
void Save( idSaveGame *savefile ) const;
|
||||
void Restore( idRestoreGame *savefile );
|
||||
|
||||
void Spawn( void );
|
||||
void HeardSound( idEntity *ent, const char *action );
|
||||
idActor *GetEnemy( void ) const;
|
||||
void TalkTo( idActor *actor );
|
||||
talkState_t GetTalkState( void ) const;
|
||||
|
||||
bool GetAimDir( const idVec3 &firePos, idEntity *aimAtEnt, const idEntity *ignore, idVec3 &aimDir ) const;
|
||||
|
||||
void TouchedByFlashlight( idActor *flashlight_owner );
|
||||
|
||||
// Outputs a list of all monsters to the console.
|
||||
static void List_f( const idCmdArgs &args );
|
||||
|
||||
// Finds a path around dynamic obstacles.
|
||||
static bool FindPathAroundObstacles( const idPhysics *physics, const idAAS *aas, const idEntity *ignore, const idVec3 &startPos, const idVec3 &seekPos, obstaclePath_t &path );
|
||||
// Frees any nodes used for the dynamic obstacle avoidance.
|
||||
static void FreeObstacleAvoidanceNodes( void );
|
||||
// Predicts movement, returns true if a stop event was triggered.
|
||||
static bool PredictPath( const idEntity *ent, const idAAS *aas, const idVec3 &start, const idVec3 &velocity, int totalTime, int frameTime, int stopEvent, predictedPath_t &path );
|
||||
// Return true if the trajectory of the clip model is collision free.
|
||||
static bool TestTrajectory( const idVec3 &start, const idVec3 &end, float zVel, float gravity, float time, float max_height, const idClipModel *clip, int clipmask, const idEntity *ignore, const idEntity *targetEntity, int drawtime );
|
||||
// Finds the best collision free trajectory for a clip model.
|
||||
static bool PredictTrajectory( const idVec3 &firePos, const idVec3 &target, float projectileSpeed, const idVec3 &projGravity, const idClipModel *clip, int clipmask, float max_height, const idEntity *ignore, const idEntity *targetEntity, int drawtime, idVec3 &aimDir );
|
||||
|
||||
#ifdef _D3XP
|
||||
virtual void Gib( const idVec3 &dir, const char *damageDefName );
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// navigation
|
||||
idAAS * aas;
|
||||
int travelFlags;
|
||||
|
||||
idMoveState move;
|
||||
idMoveState savedMove;
|
||||
|
||||
float kickForce;
|
||||
bool ignore_obstacles;
|
||||
float blockedRadius;
|
||||
int blockedMoveTime;
|
||||
int blockedAttackTime;
|
||||
|
||||
// turning
|
||||
float ideal_yaw;
|
||||
float current_yaw;
|
||||
float turnRate;
|
||||
float turnVel;
|
||||
float anim_turn_yaw;
|
||||
float anim_turn_amount;
|
||||
float anim_turn_angles;
|
||||
|
||||
// physics
|
||||
idPhysics_Monster physicsObj;
|
||||
|
||||
// flying
|
||||
jointHandle_t flyTiltJoint;
|
||||
float fly_speed;
|
||||
float fly_bob_strength;
|
||||
float fly_bob_vert;
|
||||
float fly_bob_horz;
|
||||
int fly_offset; // prefered offset from player's view
|
||||
float fly_seek_scale;
|
||||
float fly_roll_scale;
|
||||
float fly_roll_max;
|
||||
float fly_roll;
|
||||
float fly_pitch_scale;
|
||||
float fly_pitch_max;
|
||||
float fly_pitch;
|
||||
|
||||
bool allowMove; // disables any animation movement
|
||||
bool allowHiddenMovement; // allows character to still move around while hidden
|
||||
bool disableGravity; // disables gravity and allows vertical movement by the animation
|
||||
bool af_push_moveables; // allow the articulated figure to push moveable objects
|
||||
|
||||
// weapon/attack vars
|
||||
bool lastHitCheckResult;
|
||||
int lastHitCheckTime;
|
||||
int lastAttackTime;
|
||||
float melee_range;
|
||||
float projectile_height_to_distance_ratio; // calculates the maximum height a projectile can be thrown
|
||||
idList<idVec3> missileLaunchOffset;
|
||||
|
||||
const idDict * projectileDef;
|
||||
mutable idClipModel *projectileClipModel;
|
||||
float projectileRadius;
|
||||
float projectileSpeed;
|
||||
idVec3 projectileVelocity;
|
||||
idVec3 projectileGravity;
|
||||
idEntityPtr<idProjectile> projectile;
|
||||
idStr attack;
|
||||
|
||||
// chatter/talking
|
||||
const idSoundShader *chat_snd;
|
||||
int chat_min;
|
||||
int chat_max;
|
||||
int chat_time;
|
||||
talkState_t talk_state;
|
||||
idEntityPtr<idActor> talkTarget;
|
||||
|
||||
// cinematics
|
||||
int num_cinematics;
|
||||
int current_cinematic;
|
||||
|
||||
bool allowJointMod;
|
||||
idEntityPtr<idEntity> focusEntity;
|
||||
idVec3 currentFocusPos;
|
||||
int focusTime;
|
||||
int alignHeadTime;
|
||||
int forceAlignHeadTime;
|
||||
idAngles eyeAng;
|
||||
idAngles lookAng;
|
||||
idAngles destLookAng;
|
||||
idAngles lookMin;
|
||||
idAngles lookMax;
|
||||
idList<jointHandle_t> lookJoints;
|
||||
idList<idAngles> lookJointAngles;
|
||||
float eyeVerticalOffset;
|
||||
float eyeHorizontalOffset;
|
||||
float eyeFocusRate;
|
||||
float headFocusRate;
|
||||
int focusAlignTime;
|
||||
|
||||
// special fx
|
||||
float shrivel_rate;
|
||||
int shrivel_start;
|
||||
|
||||
bool restartParticles; // should smoke emissions restart
|
||||
bool useBoneAxis; // use the bone vs the model axis
|
||||
idList<particleEmitter_t> particles; // particle data
|
||||
|
||||
renderLight_t worldMuzzleFlash; // positioned on world weapon bone
|
||||
int worldMuzzleFlashHandle;
|
||||
jointHandle_t flashJointWorld;
|
||||
int muzzleFlashEnd;
|
||||
int flashTime;
|
||||
|
||||
// joint controllers
|
||||
idAngles eyeMin;
|
||||
idAngles eyeMax;
|
||||
jointHandle_t focusJoint;
|
||||
jointHandle_t orientationJoint;
|
||||
|
||||
// enemy variables
|
||||
idEntityPtr<idActor> enemy;
|
||||
idVec3 lastVisibleEnemyPos;
|
||||
idVec3 lastVisibleEnemyEyeOffset;
|
||||
idVec3 lastVisibleReachableEnemyPos;
|
||||
idVec3 lastReachableEnemyPos;
|
||||
bool wakeOnFlashlight;
|
||||
|
||||
#ifdef _D3XP
|
||||
bool spawnClearMoveables;
|
||||
|
||||
idHashTable<funcEmitter_t> funcEmitters;
|
||||
|
||||
idEntityPtr<idHarvestable> harvestEnt;
|
||||
#endif
|
||||
|
||||
// script variables
|
||||
idScriptBool AI_TALK;
|
||||
idScriptBool AI_DAMAGE;
|
||||
idScriptBool AI_PAIN;
|
||||
idScriptFloat AI_SPECIAL_DAMAGE;
|
||||
idScriptBool AI_DEAD;
|
||||
idScriptBool AI_ENEMY_VISIBLE;
|
||||
idScriptBool AI_ENEMY_IN_FOV;
|
||||
idScriptBool AI_ENEMY_DEAD;
|
||||
idScriptBool AI_MOVE_DONE;
|
||||
idScriptBool AI_ONGROUND;
|
||||
idScriptBool AI_ACTIVATED;
|
||||
idScriptBool AI_FORWARD;
|
||||
idScriptBool AI_JUMP;
|
||||
idScriptBool AI_ENEMY_REACHABLE;
|
||||
idScriptBool AI_BLOCKED;
|
||||
idScriptBool AI_OBSTACLE_IN_PATH;
|
||||
idScriptBool AI_DEST_UNREACHABLE;
|
||||
idScriptBool AI_HIT_ENEMY;
|
||||
idScriptBool AI_PUSHED;
|
||||
|
||||
//
|
||||
// ai/ai.cpp
|
||||
//
|
||||
void SetAAS( void );
|
||||
virtual void DormantBegin( void ); // called when entity becomes dormant
|
||||
virtual void DormantEnd( void ); // called when entity wakes from being dormant
|
||||
void Think( void );
|
||||
void Activate( idEntity *activator );
|
||||
int ReactionTo( const idEntity *ent );
|
||||
bool CheckForEnemy( void );
|
||||
void EnemyDead( void );
|
||||
virtual bool CanPlayChatterSounds( void ) const;
|
||||
void SetChatSound( void );
|
||||
void PlayChatter( void );
|
||||
virtual void Hide( void );
|
||||
virtual void Show( void );
|
||||
idVec3 FirstVisiblePointOnPath( const idVec3 origin, const idVec3 &target, int travelFlags ) const;
|
||||
void CalculateAttackOffsets( void );
|
||||
void PlayCinematic( void );
|
||||
|
||||
// movement
|
||||
virtual void ApplyImpulse( idEntity *ent, int id, const idVec3 &point, const idVec3 &impulse );
|
||||
void GetMoveDelta( const idMat3 &oldaxis, const idMat3 &axis, idVec3 &delta );
|
||||
void CheckObstacleAvoidance( const idVec3 &goalPos, idVec3 &newPos );
|
||||
void DeadMove( void );
|
||||
void AnimMove( void );
|
||||
void SlideMove( void );
|
||||
void AdjustFlyingAngles( void );
|
||||
void AddFlyBob( idVec3 &vel );
|
||||
void AdjustFlyHeight( idVec3 &vel, const idVec3 &goalPos );
|
||||
void FlySeekGoal( idVec3 &vel, idVec3 &goalPos );
|
||||
void AdjustFlySpeed( idVec3 &vel );
|
||||
void FlyTurn( void );
|
||||
void FlyMove( void );
|
||||
void StaticMove( void );
|
||||
|
||||
// damage
|
||||
virtual bool Pain( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location );
|
||||
virtual void Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location );
|
||||
|
||||
// navigation
|
||||
void KickObstacles( const idVec3 &dir, float force, idEntity *alwaysKick );
|
||||
bool ReachedPos( const idVec3 &pos, const moveCommand_t moveCommand ) const;
|
||||
float TravelDistance( const idVec3 &start, const idVec3 &end ) const;
|
||||
int PointReachableAreaNum( const idVec3 &pos, const float boundsScale = 2.0f ) const;
|
||||
bool PathToGoal( aasPath_t &path, int areaNum, const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin ) const;
|
||||
void DrawRoute( void ) const;
|
||||
bool GetMovePos( idVec3 &seekPos );
|
||||
bool MoveDone( void ) const;
|
||||
bool EntityCanSeePos( idActor *actor, const idVec3 &actorOrigin, const idVec3 &pos );
|
||||
void BlockedFailSafe( void );
|
||||
|
||||
// movement control
|
||||
void StopMove( moveStatus_t status );
|
||||
bool FaceEnemy( void );
|
||||
bool FaceEntity( idEntity *ent );
|
||||
bool DirectMoveToPosition( const idVec3 &pos );
|
||||
bool MoveToEnemyHeight( void );
|
||||
bool MoveOutOfRange( idEntity *entity, float range );
|
||||
bool MoveToAttackPosition( idEntity *ent, int attack_anim );
|
||||
bool MoveToEnemy( void );
|
||||
bool MoveToEntity( idEntity *ent );
|
||||
bool MoveToPosition( const idVec3 &pos );
|
||||
bool MoveToCover( idEntity *entity, const idVec3 &pos );
|
||||
bool SlideToPosition( const idVec3 &pos, float time );
|
||||
bool WanderAround( void );
|
||||
bool StepDirection( float dir );
|
||||
bool NewWanderDir( const idVec3 &dest );
|
||||
|
||||
// effects
|
||||
const idDeclParticle *SpawnParticlesOnJoint( particleEmitter_t &pe, const char *particleName, const char *jointName );
|
||||
void SpawnParticles( const char *keyName );
|
||||
bool ParticlesActive( void );
|
||||
|
||||
// turning
|
||||
bool FacingIdeal( void );
|
||||
void Turn( void );
|
||||
bool TurnToward( float yaw );
|
||||
bool TurnToward( const idVec3 &pos );
|
||||
|
||||
// enemy management
|
||||
void ClearEnemy( void );
|
||||
bool EnemyPositionValid( void ) const;
|
||||
void SetEnemyPosition( void );
|
||||
void UpdateEnemyPosition( void );
|
||||
void SetEnemy( idActor *newEnemy );
|
||||
|
||||
// attacks
|
||||
void CreateProjectileClipModel( void ) const;
|
||||
idProjectile *CreateProjectile( const idVec3 &pos, const idVec3 &dir );
|
||||
void RemoveProjectile( void );
|
||||
idProjectile *LaunchProjectile( const char *jointname, idEntity *target, bool clampToAttackCone );
|
||||
virtual void DamageFeedback( idEntity *victim, idEntity *inflictor, int &damage );
|
||||
void DirectDamage( const char *meleeDefName, idEntity *ent );
|
||||
bool TestMelee( void ) const;
|
||||
bool AttackMelee( const char *meleeDefName );
|
||||
void BeginAttack( const char *name );
|
||||
void EndAttack( void );
|
||||
void PushWithAF( void );
|
||||
|
||||
// special effects
|
||||
void GetMuzzle( const char *jointname, idVec3 &muzzle, idMat3 &axis );
|
||||
void InitMuzzleFlash( void );
|
||||
void TriggerWeaponEffects( const idVec3 &muzzle );
|
||||
void UpdateMuzzleFlash( void );
|
||||
virtual bool UpdateAnimationControllers( void );
|
||||
void UpdateParticles( void );
|
||||
void TriggerParticles( const char *jointName );
|
||||
|
||||
#ifdef _D3XP
|
||||
void TriggerFX( const char* joint, const char* fx );
|
||||
idEntity* StartEmitter( const char* name, const char* joint, const char* particle );
|
||||
idEntity* GetEmitter( const char* name );
|
||||
void StopEmitter( const char* name );
|
||||
#endif
|
||||
|
||||
// AI script state management
|
||||
void LinkScriptVariables( void );
|
||||
void UpdateAIScript( void );
|
||||
|
||||
//
|
||||
// ai/ai_events.cpp
|
||||
//
|
||||
void Event_Activate( idEntity *activator );
|
||||
void Event_Touch( idEntity *other, trace_t *trace );
|
||||
void Event_FindEnemy( int useFOV );
|
||||
void Event_FindEnemyAI( int useFOV );
|
||||
void Event_FindEnemyInCombatNodes( void );
|
||||
void Event_ClosestReachableEnemyOfEntity( idEntity *team_mate );
|
||||
void Event_HeardSound( int ignore_team );
|
||||
void Event_SetEnemy( idEntity *ent );
|
||||
void Event_ClearEnemy( void );
|
||||
void Event_MuzzleFlash( const char *jointname );
|
||||
void Event_CreateMissile( const char *jointname );
|
||||
void Event_AttackMissile( const char *jointname );
|
||||
void Event_FireMissileAtTarget( const char *jointname, const char *targetname );
|
||||
void Event_LaunchMissile( const idVec3 &muzzle, const idAngles &ang );
|
||||
#ifdef _D3XP
|
||||
void Event_LaunchProjectile( const char *entityDefName );
|
||||
#endif
|
||||
void Event_AttackMelee( const char *meleeDefName );
|
||||
void Event_DirectDamage( idEntity *damageTarget, const char *damageDefName );
|
||||
void Event_RadiusDamageFromJoint( const char *jointname, const char *damageDefName );
|
||||
void Event_BeginAttack( const char *name );
|
||||
void Event_EndAttack( void );
|
||||
void Event_MeleeAttackToJoint( const char *jointname, const char *meleeDefName );
|
||||
void Event_RandomPath( void );
|
||||
void Event_CanBecomeSolid( void );
|
||||
void Event_BecomeSolid( void );
|
||||
void Event_BecomeNonSolid( void );
|
||||
void Event_BecomeRagdoll( void );
|
||||
void Event_StopRagdoll( void );
|
||||
void Event_SetHealth( float newHealth );
|
||||
void Event_GetHealth( void );
|
||||
void Event_AllowDamage( void );
|
||||
void Event_IgnoreDamage( void );
|
||||
void Event_GetCurrentYaw( void );
|
||||
void Event_TurnTo( float angle );
|
||||
void Event_TurnToPos( const idVec3 &pos );
|
||||
void Event_TurnToEntity( idEntity *ent );
|
||||
void Event_MoveStatus( void );
|
||||
void Event_StopMove( void );
|
||||
void Event_MoveToCover( void );
|
||||
void Event_MoveToEnemy( void );
|
||||
void Event_MoveToEnemyHeight( void );
|
||||
void Event_MoveOutOfRange( idEntity *entity, float range );
|
||||
void Event_MoveToAttackPosition( idEntity *entity, const char *attack_anim );
|
||||
void Event_MoveToEntity( idEntity *ent );
|
||||
void Event_MoveToPosition( const idVec3 &pos );
|
||||
void Event_SlideTo( const idVec3 &pos, float time );
|
||||
void Event_Wander( void );
|
||||
void Event_FacingIdeal( void );
|
||||
void Event_FaceEnemy( void );
|
||||
void Event_FaceEntity( idEntity *ent );
|
||||
void Event_WaitAction( const char *waitForState );
|
||||
void Event_GetCombatNode( void );
|
||||
void Event_EnemyInCombatCone( idEntity *ent, int use_current_enemy_location );
|
||||
void Event_WaitMove( void );
|
||||
void Event_GetJumpVelocity( const idVec3 &pos, float speed, float max_height );
|
||||
void Event_EntityInAttackCone( idEntity *ent );
|
||||
void Event_CanSeeEntity( idEntity *ent );
|
||||
void Event_SetTalkTarget( idEntity *target );
|
||||
void Event_GetTalkTarget( void );
|
||||
void Event_SetTalkState( int state );
|
||||
void Event_EnemyRange( void );
|
||||
void Event_EnemyRange2D( void );
|
||||
void Event_GetEnemy( void );
|
||||
void Event_GetEnemyPos( void );
|
||||
void Event_GetEnemyEyePos( void );
|
||||
void Event_PredictEnemyPos( float time );
|
||||
void Event_CanHitEnemy( void );
|
||||
void Event_CanHitEnemyFromAnim( const char *animname );
|
||||
void Event_CanHitEnemyFromJoint( const char *jointname );
|
||||
void Event_EnemyPositionValid( void );
|
||||
void Event_ChargeAttack( const char *damageDef );
|
||||
void Event_TestChargeAttack( void );
|
||||
void Event_TestAnimMoveTowardEnemy( const char *animname );
|
||||
void Event_TestAnimMove( const char *animname );
|
||||
void Event_TestMoveToPosition( const idVec3 &position );
|
||||
void Event_TestMeleeAttack( void );
|
||||
void Event_TestAnimAttack( const char *animname );
|
||||
void Event_Shrivel( float shirvel_time );
|
||||
void Event_Burn( void );
|
||||
void Event_PreBurn( void );
|
||||
void Event_ClearBurn( void );
|
||||
void Event_SetSmokeVisibility( int num, int on );
|
||||
void Event_NumSmokeEmitters( void );
|
||||
void Event_StopThinking( void );
|
||||
void Event_GetTurnDelta( void );
|
||||
void Event_GetMoveType( void );
|
||||
void Event_SetMoveType( int moveType );
|
||||
void Event_SaveMove( void );
|
||||
void Event_RestoreMove( void );
|
||||
void Event_AllowMovement( float flag );
|
||||
void Event_JumpFrame( void );
|
||||
void Event_EnableClip( void );
|
||||
void Event_DisableClip( void );
|
||||
void Event_EnableGravity( void );
|
||||
void Event_DisableGravity( void );
|
||||
void Event_EnableAFPush( void );
|
||||
void Event_DisableAFPush( void );
|
||||
void Event_SetFlySpeed( float speed );
|
||||
void Event_SetFlyOffset( int offset );
|
||||
void Event_ClearFlyOffset( void );
|
||||
void Event_GetClosestHiddenTarget( const char *type );
|
||||
void Event_GetRandomTarget( const char *type );
|
||||
void Event_TravelDistanceToPoint( const idVec3 &pos );
|
||||
void Event_TravelDistanceToEntity( idEntity *ent );
|
||||
void Event_TravelDistanceBetweenPoints( const idVec3 &source, const idVec3 &dest );
|
||||
void Event_TravelDistanceBetweenEntities( idEntity *source, idEntity *dest );
|
||||
void Event_LookAtEntity( idEntity *ent, float duration );
|
||||
void Event_LookAtEnemy( float duration );
|
||||
void Event_SetJointMod( int allowJointMod );
|
||||
void Event_ThrowMoveable( void );
|
||||
void Event_ThrowAF( void );
|
||||
void Event_SetAngles( idAngles const &ang );
|
||||
void Event_GetAngles( void );
|
||||
void Event_RealKill( void );
|
||||
void Event_Kill( void );
|
||||
void Event_WakeOnFlashlight( int enable );
|
||||
void Event_LocateEnemy( void );
|
||||
void Event_KickObstacles( idEntity *kickEnt, float force );
|
||||
void Event_GetObstacle( void );
|
||||
void Event_PushPointIntoAAS( const idVec3 &pos );
|
||||
void Event_GetTurnRate( void );
|
||||
void Event_SetTurnRate( float rate );
|
||||
void Event_AnimTurn( float angles );
|
||||
void Event_AllowHiddenMovement( int enable );
|
||||
void Event_TriggerParticles( const char *jointName );
|
||||
void Event_FindActorsInBounds( const idVec3 &mins, const idVec3 &maxs );
|
||||
void Event_CanReachPosition( const idVec3 &pos );
|
||||
void Event_CanReachEntity( idEntity *ent );
|
||||
void Event_CanReachEnemy( void );
|
||||
void Event_GetReachableEntityPosition( idEntity *ent );
|
||||
#ifdef _D3XP
|
||||
void Event_MoveToPositionDirect( const idVec3 &pos );
|
||||
void Event_AvoidObstacles( int ignore);
|
||||
void Event_TriggerFX( const char* joint, const char* fx );
|
||||
|
||||
void Event_StartEmitter( const char* name, const char* joint, const char* particle );
|
||||
void Event_GetEmitter( const char* name );
|
||||
void Event_StopEmitter( const char* name );
|
||||
#endif
|
||||
};
|
||||
|
||||
class idCombatNode : public idEntity {
|
||||
public:
|
||||
CLASS_PROTOTYPE( idCombatNode );
|
||||
|
||||
idCombatNode();
|
||||
|
||||
void Save( idSaveGame *savefile ) const;
|
||||
void Restore( idRestoreGame *savefile );
|
||||
|
||||
void Spawn( void );
|
||||
bool IsDisabled( void ) const;
|
||||
bool EntityInView( idActor *actor, const idVec3 &pos );
|
||||
static void DrawDebugInfo( void );
|
||||
|
||||
private:
|
||||
float min_dist;
|
||||
float max_dist;
|
||||
float cone_dist;
|
||||
float min_height;
|
||||
float max_height;
|
||||
idVec3 cone_left;
|
||||
idVec3 cone_right;
|
||||
idVec3 offset;
|
||||
bool disabled;
|
||||
|
||||
void Event_Activate( idEntity *activator );
|
||||
void Event_MarkUsed( void );
|
||||
};
|
||||
|
||||
#endif /* !__AI_H__ */
|
||||
147
neo/d3xp/ai/AI_Vagary.cpp
Normal file
147
neo/d3xp/ai/AI_Vagary.cpp
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
/***********************************************************************
|
||||
|
||||
game/ai/AI_Vagary.cpp
|
||||
|
||||
Vagary specific AI code
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
#include "../../idlib/precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "../Game_local.h"
|
||||
|
||||
class idAI_Vagary : public idAI {
|
||||
public:
|
||||
CLASS_PROTOTYPE( idAI_Vagary );
|
||||
|
||||
private:
|
||||
void Event_ChooseObjectToThrow( const idVec3 &mins, const idVec3 &maxs, float speed, float minDist, float offset );
|
||||
void Event_ThrowObjectAtEnemy( idEntity *ent, float speed );
|
||||
};
|
||||
|
||||
const idEventDef AI_Vagary_ChooseObjectToThrow( "vagary_ChooseObjectToThrow", "vvfff", 'e' );
|
||||
const idEventDef AI_Vagary_ThrowObjectAtEnemy( "vagary_ThrowObjectAtEnemy", "ef" );
|
||||
|
||||
CLASS_DECLARATION( idAI, idAI_Vagary )
|
||||
EVENT( AI_Vagary_ChooseObjectToThrow, idAI_Vagary::Event_ChooseObjectToThrow )
|
||||
EVENT( AI_Vagary_ThrowObjectAtEnemy, idAI_Vagary::Event_ThrowObjectAtEnemy )
|
||||
END_CLASS
|
||||
|
||||
/*
|
||||
================
|
||||
idAI_Vagary::Event_ChooseObjectToThrow
|
||||
================
|
||||
*/
|
||||
void idAI_Vagary::Event_ChooseObjectToThrow( const idVec3 &mins, const idVec3 &maxs, float speed, float minDist, float offset ) {
|
||||
idEntity * ent;
|
||||
idEntity * entityList[ MAX_GENTITIES ];
|
||||
int numListedEntities;
|
||||
int i, index;
|
||||
float dist;
|
||||
idVec3 vel;
|
||||
idVec3 offsetVec( 0, 0, offset );
|
||||
idEntity *enemyEnt = enemy.GetEntity();
|
||||
|
||||
if ( !enemyEnt ) {
|
||||
idThread::ReturnEntity( NULL );
|
||||
}
|
||||
|
||||
idVec3 enemyEyePos = lastVisibleEnemyPos + lastVisibleEnemyEyeOffset;
|
||||
const idBounds &myBounds = physicsObj.GetAbsBounds();
|
||||
idBounds checkBounds( mins, maxs );
|
||||
checkBounds.TranslateSelf( physicsObj.GetOrigin() );
|
||||
numListedEntities = gameLocal.clip.EntitiesTouchingBounds( checkBounds, -1, entityList, MAX_GENTITIES );
|
||||
|
||||
index = gameLocal.random.RandomInt( numListedEntities );
|
||||
for ( i = 0; i < numListedEntities; i++, index++ ) {
|
||||
if ( index >= numListedEntities ) {
|
||||
index = 0;
|
||||
}
|
||||
ent = entityList[ index ];
|
||||
if ( !ent->IsType( idMoveable::Type ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ent->fl.hidden ) {
|
||||
// don't throw hidden objects
|
||||
continue;
|
||||
}
|
||||
|
||||
idPhysics *entPhys = ent->GetPhysics();
|
||||
const idVec3 &entOrg = entPhys->GetOrigin();
|
||||
dist = ( entOrg - enemyEyePos ).LengthFast();
|
||||
if ( dist < minDist ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
idBounds expandedBounds = myBounds.Expand( entPhys->GetBounds().GetRadius() );
|
||||
if ( expandedBounds.LineIntersection( entOrg, enemyEyePos ) ) {
|
||||
// ignore objects that are behind us
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( PredictTrajectory( entPhys->GetOrigin() + offsetVec, enemyEyePos, speed, entPhys->GetGravity(),
|
||||
entPhys->GetClipModel(), entPhys->GetClipMask(), MAX_WORLD_SIZE, NULL, enemyEnt, ai_debugTrajectory.GetBool() ? 4000 : 0, vel ) ) {
|
||||
idThread::ReturnEntity( ent );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
idThread::ReturnEntity( NULL );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAI_Vagary::Event_ThrowObjectAtEnemy
|
||||
================
|
||||
*/
|
||||
void idAI_Vagary::Event_ThrowObjectAtEnemy( idEntity *ent, float speed ) {
|
||||
idVec3 vel;
|
||||
idEntity *enemyEnt;
|
||||
idPhysics *entPhys;
|
||||
|
||||
entPhys = ent->GetPhysics();
|
||||
enemyEnt = enemy.GetEntity();
|
||||
if ( !enemyEnt ) {
|
||||
vel = ( viewAxis[ 0 ] * physicsObj.GetGravityAxis() ) * speed;
|
||||
} else {
|
||||
PredictTrajectory( entPhys->GetOrigin(), lastVisibleEnemyPos + lastVisibleEnemyEyeOffset, speed, entPhys->GetGravity(),
|
||||
entPhys->GetClipModel(), entPhys->GetClipMask(), MAX_WORLD_SIZE, NULL, enemyEnt, ai_debugTrajectory.GetBool() ? 4000 : 0, vel );
|
||||
vel *= speed;
|
||||
}
|
||||
|
||||
entPhys->SetLinearVelocity( vel );
|
||||
|
||||
if ( ent->IsType( idMoveable::Type ) ) {
|
||||
idMoveable *ment = static_cast<idMoveable*>( ent );
|
||||
ment->EnableDamage( true, 2.5f );
|
||||
}
|
||||
}
|
||||
2906
neo/d3xp/ai/AI_events.cpp
Normal file
2906
neo/d3xp/ai/AI_events.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1525
neo/d3xp/ai/AI_pathing.cpp
Normal file
1525
neo/d3xp/ai/AI_pathing.cpp
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user