Initial commit

This commit is contained in:
Brian Harris
2012-11-26 12:58:24 -06:00
parent a5214f79ef
commit 5016f605b8
1115 changed files with 587266 additions and 0 deletions

276
neo/d3xp/ai/AAS.cpp Normal file
View File

@@ -0,0 +1,276 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 BFG Edition 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 BFG Edition 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.
===========================================================================
*/
#pragma hdrstop
#include "../../idlib/precompiled.h"
#include "AAS_local.h"
/*
============
idAAS::Alloc
============
*/
idAAS *idAAS::Alloc() {
return new (TAG_AAS) idAASLocal;
}
/*
============
idAAS::idAAS
============
*/
idAAS::~idAAS() {
}
/*
============
idAASLocal::idAASLocal
============
*/
idAASLocal::idAASLocal() {
file = NULL;
}
/*
============
idAASLocal::~idAASLocal
============
*/
idAASLocal::~idAASLocal() {
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() {
if ( file ) {
ShutdownRouting();
RemoveAllObstacles();
AASFileManager->FreeAAS( file );
file = NULL;
}
}
/*
============
idAASLocal::Stats
============
*/
void idAASLocal::Stats() const {
if ( !file ) {
return;
}
common->Printf( "[%s]\n", file->GetName() );
file->PrintInfo();
RoutingStats();
}
/*
============
idAASLocal::GetSettings
============
*/
const idAASSettings *idAASLocal::GetSettings() 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[INT32_SIGNBITSET(edgeNum)];
verts[1] = v[INT32_SIGNBITNOTSET(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[INT32_SIGNBITSET(edgeNum)] );
end = file->GetVertex( v[INT32_SIGNBITNOTSET(edgeNum)] );
}

141
neo/d3xp/ai/AAS.h Normal file
View File

@@ -0,0 +1,141 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 BFG Edition 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 BFG Edition 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();
virtual ~idAAS() = 0;
// Initialize for the given map.
virtual bool Init( const idStr &mapName, unsigned int mapFileCRC ) = 0;
// Print AAS stats.
virtual void Stats() const = 0;
// Test from the given origin.
virtual void Test( const idVec3 &origin ) = 0;
// Get the AAS settings.
virtual const idAASSettings *GetSettings() 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() = 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
View File

@@ -0,0 +1,508 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 BFG Edition 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 BFG Edition 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.
===========================================================================
*/
#pragma hdrstop
#include "../../idlib/precompiled.h"
#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() 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
View File

@@ -0,0 +1,189 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 BFG Edition 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 BFG Edition 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();
int Size() 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() { }
private:
idBounds bounds; // obstacle bounds
idList<int, TAG_AAS> areas; // areas the bounds are in
};
class idAASLocal : public idAAS {
public:
idAASLocal();
virtual ~idAASLocal();
virtual bool Init( const idStr &mapName, unsigned int mapFileCRC );
virtual void Shutdown();
virtual void Stats() const;
virtual void Test( const idVec3 &origin );
virtual const idAASSettings *GetSettings() 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();
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 *, TAG_AAS> obstacleList; // list with obstacles
private: // routing
bool SetupRouting();
void ShutdownRouting();
unsigned short AreaTravelTime( int areaNum, const idVec3 &start, const idVec3 &end ) const;
void CalculateAreaTravelTimes();
void DeleteAreaTravelTimes();
void SetupRoutingCache();
void DeleteClusterCache( int clusterNum );
void DeletePortalCache();
void ShutdownRoutingCache();
void RoutingStats() const;
void LinkCache( idRoutingCache *cache ) const;
void UnlinkCache( idRoutingCache *cache ) const;
void DeleteOldestCache() 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() 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__ */

717
neo/d3xp/ai/AAS_pathing.cpp Normal file
View File

@@ -0,0 +1,717 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 BFG Edition 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 BFG Edition 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.
===========================================================================
*/
#pragma hdrstop
#include "../../idlib/precompiled.h"
#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 ( IEEE_FLT_SIGNBITSET( d1 ) == IEEE_FLT_SIGNBITSET( 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 = NULL;
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 == NULL ) {
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 = NULL;
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 == NULL ) {
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;
}

1350
neo/d3xp/ai/AAS_routing.cpp Normal file

File diff suppressed because it is too large Load Diff

5337
neo/d3xp/ai/AI.cpp Normal file

File diff suppressed because it is too large Load Diff

731
neo/d3xp/ai/AI.h Normal file
View File

@@ -0,0 +1,731 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 BFG Edition 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 BFG Edition 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
typedef struct ballistics_s {
float angle; // angle in degrees in the range [-180, 180]
float time; // time it takes before the projectile arrives
} ballistics_t;
extern int Ballistics( const idVec3 &start, const idVec3 &end, float speed, float gravity, ballistics_t bal[2] );
// 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;
extern const idEventDef AI_LaunchProjectile;
extern const idEventDef AI_TriggerFX;
extern const idEventDef AI_StartEmitter;
extern const idEventDef AI_StopEmitter;
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;
typedef struct funcEmitter_s {
char name[64];
idFuncEmitter* particle;
jointHandle_t joint;
} funcEmitter_t;
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 HeardSound( idEntity *ent, const char *action );
idActor *GetEnemy() const;
void TalkTo( idActor *actor );
talkState_t GetTalkState() 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();
// 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 );
virtual void Gib( const idVec3 &dir, const char *damageDefName );
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, TAG_AI> missileLaunchOffset;
const idDict * projectileDef;
mutable idClipModel *projectileClipModel;
float projectileRadius;
float projectileSpeed;
idVec3 projectileVelocity;
idVec3 projectileGravity;
idEntityPtr<idProjectile> projectile;
idStr attack;
idVec3 homingMissileGoal;
// 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, TAG_AI> lookJoints;
idList<idAngles, TAG_AI> lookJointAngles;
float eyeVerticalOffset;
float eyeHorizontalOffset;
float eyeFocusRate;
float headFocusRate;
int focusAlignTime;
// special fx
bool restartParticles; // should smoke emissions restart
bool useBoneAxis; // use the bone vs the model axis
idList<particleEmitter_t, TAG_AI> 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;
bool spawnClearMoveables;
idHashTable<funcEmitter_t> funcEmitters;
idEntityPtr<idHarvestable> harvestEnt;
// 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();
virtual void DormantBegin(); // called when entity becomes dormant
virtual void DormantEnd(); // called when entity wakes from being dormant
void Think();
void Activate( idEntity *activator );
public:
int ReactionTo( const idEntity *ent );
protected:
bool CheckForEnemy();
void EnemyDead();
virtual bool CanPlayChatterSounds() const;
void SetChatSound();
void PlayChatter();
virtual void Hide();
virtual void Show();
idVec3 FirstVisiblePointOnPath( const idVec3 origin, const idVec3 &target, int travelFlags ) const;
void CalculateAttackOffsets();
void PlayCinematic();
// 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 AnimMove();
void SlideMove();
void AdjustFlyingAngles();
void AddFlyBob( idVec3 &vel );
void AdjustFlyHeight( idVec3 &vel, const idVec3 &goalPos );
void FlySeekGoal( idVec3 &vel, idVec3 &goalPos );
void AdjustFlySpeed( idVec3 &vel );
void FlyTurn();
void FlyMove();
void StaticMove();
// 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() const;
bool GetMovePos( idVec3 &seekPos );
bool MoveDone() const;
bool EntityCanSeePos( idActor *actor, const idVec3 &actorOrigin, const idVec3 &pos );
void BlockedFailSafe();
// movement control
void StopMove( moveStatus_t status );
bool FaceEnemy();
bool FaceEntity( idEntity *ent );
bool DirectMoveToPosition( const idVec3 &pos );
bool MoveToEnemyHeight();
bool MoveOutOfRange( idEntity *entity, float range );
bool MoveToAttackPosition( idEntity *ent, int attack_anim );
bool MoveToEnemy();
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();
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();
// turning
bool FacingIdeal();
void Turn();
bool TurnToward( float yaw );
bool TurnToward( const idVec3 &pos );
// enemy management
void ClearEnemy();
bool EnemyPositionValid() const;
void SetEnemyPosition();
void UpdateEnemyPosition();
void SetEnemy( idActor *newEnemy );
// attacks
void CreateProjectileClipModel() const;
idProjectile *CreateProjectile( const idVec3 &pos, const idVec3 &dir );
void RemoveProjectile();
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() const;
bool AttackMelee( const char *meleeDefName );
void BeginAttack( const char *name );
void EndAttack();
void PushWithAF();
// special effects
void GetMuzzle( const char *jointname, idVec3 &muzzle, idMat3 &axis );
void InitMuzzleFlash();
void TriggerWeaponEffects( const idVec3 &muzzle );
void UpdateMuzzleFlash();
virtual bool UpdateAnimationControllers();
void UpdateParticles();
void TriggerParticles( const char *jointName );
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 );
// AI script state management
void LinkScriptVariables();
void UpdateAIScript();
//
// 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 Event_ClosestReachableEnemyOfEntity( idEntity *team_mate );
void Event_HeardSound( int ignore_team );
void Event_SetEnemy( idEntity *ent );
void Event_ClearEnemy();
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 );
void Event_LaunchHomingMissile();
void Event_SetHomingMissileGoal();
void Event_LaunchProjectile( const char *entityDefName );
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 Event_MeleeAttackToJoint( const char *jointname, const char *meleeDefName );
void Event_RandomPath();
void Event_CanBecomeSolid();
void Event_BecomeSolid();
void Event_BecomeNonSolid();
void Event_BecomeRagdoll();
void Event_StopRagdoll();
void Event_SetHealth( float newHealth );
void Event_GetHealth();
void Event_AllowDamage();
void Event_IgnoreDamage();
void Event_GetCurrentYaw();
void Event_TurnTo( float angle );
void Event_TurnToPos( const idVec3 &pos );
void Event_TurnToEntity( idEntity *ent );
void Event_MoveStatus();
void Event_StopMove();
void Event_MoveToCover();
void Event_MoveToEnemy();
void Event_MoveToEnemyHeight();
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 Event_FacingIdeal();
void Event_FaceEnemy();
void Event_FaceEntity( idEntity *ent );
void Event_WaitAction( const char *waitForState );
void Event_GetCombatNode();
void Event_EnemyInCombatCone( idEntity *ent, int use_current_enemy_location );
void Event_WaitMove();
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 Event_SetTalkState( int state );
void Event_EnemyRange();
void Event_EnemyRange2D();
void Event_GetEnemy();
void Event_GetEnemyPos();
void Event_GetEnemyEyePos();
void Event_PredictEnemyPos( float time );
void Event_CanHitEnemy();
void Event_CanHitEnemyFromAnim( const char *animname );
void Event_CanHitEnemyFromJoint( const char *jointname );
void Event_EnemyPositionValid();
void Event_ChargeAttack( const char *damageDef );
void Event_TestChargeAttack();
void Event_TestAnimMoveTowardEnemy( const char *animname );
void Event_TestAnimMove( const char *animname );
void Event_TestMoveToPosition( const idVec3 &position );
void Event_TestMeleeAttack();
void Event_TestAnimAttack( const char *animname );
void Event_Burn();
void Event_PreBurn();
void Event_ClearBurn();
void Event_SetSmokeVisibility( int num, int on );
void Event_NumSmokeEmitters();
void Event_StopThinking();
void Event_GetTurnDelta();
void Event_GetMoveType();
void Event_SetMoveType( int moveType );
void Event_SaveMove();
void Event_RestoreMove();
void Event_AllowMovement( float flag );
void Event_JumpFrame();
void Event_EnableClip();
void Event_DisableClip();
void Event_EnableGravity();
void Event_DisableGravity();
void Event_EnableAFPush();
void Event_DisableAFPush();
void Event_SetFlySpeed( float speed );
void Event_SetFlyOffset( int offset );
void Event_ClearFlyOffset();
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 Event_ThrowAF();
void Event_SetAngles( idAngles const &ang );
void Event_GetAngles();
void Event_GetTrajectoryToPlayer();
void Event_RealKill();
void Event_Kill();
void Event_WakeOnFlashlight( int enable );
void Event_LocateEnemy();
void Event_KickObstacles( idEntity *kickEnt, float force );
void Event_GetObstacle();
void Event_PushPointIntoAAS( const idVec3 &pos );
void Event_GetTurnRate();
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 Event_GetReachableEntityPosition( idEntity *ent );
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 );
};
class idCombatNode : public idEntity {
public:
CLASS_PROTOTYPE( idCombatNode );
idCombatNode();
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
void Spawn();
bool IsDisabled() const;
bool EntityInView( idActor *actor, const idVec3 &pos );
static void DrawDebugInfo();
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();
};
#endif /* !__AI_H__ */

149
neo/d3xp/ai/AI_Vagary.cpp Normal file
View File

@@ -0,0 +1,149 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 BFG Edition 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 BFG Edition 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
***********************************************************************/
#pragma hdrstop
#include "../../idlib/precompiled.h"
#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 );
return;
}
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 );
}
}

2986
neo/d3xp/ai/AI_events.cpp Normal file

File diff suppressed because it is too large Load Diff

1535
neo/d3xp/ai/AI_pathing.cpp Normal file

File diff suppressed because it is too large Load Diff