Files
Enemy-Territory/src/botlib/be_aas_move.c

1027 lines
36 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
===========================================================================
Wolfenstein: Enemy Territory GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Wolfenstein: Enemy Territory GPL Source Code (“Wolf ET Source Code”).
Wolf ET 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.
Wolf ET 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 Wolf ET Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Wolf: ET 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 Wolf ET 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.
===========================================================================
*/
/*****************************************************************************
* name: be_aas_move.c
*
* desc: AAS
*
*
*****************************************************************************/
#include "../game/q_shared.h"
#include "l_memory.h"
#include "l_script.h"
#include "l_precomp.h"
#include "l_struct.h"
#include "aasfile.h"
#include "../game/botlib.h"
#include "../game/be_aas.h"
#include "be_aas_funcs.h"
#include "be_aas_def.h"
//#define BSPC
extern botlib_import_t botimport;
aas_settings_t aassettings;
//#define AAS_MOVE_DEBUG
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int AAS_DropToFloor( vec3_t origin, vec3_t mins, vec3_t maxs ) {
vec3_t end;
bsp_trace_t trace;
VectorCopy( origin, end );
end[2] -= 100;
trace = AAS_Trace( origin, mins, maxs, end, 0, ( CONTENTS_SOLID | CONTENTS_PLAYERCLIP ) & ~CONTENTS_BODY );
if ( trace.startsolid ) {
return qfalse;
}
VectorCopy( trace.endpos, origin );
return qtrue;
} //end of the function AAS_DropToFloor
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_InitSettings( void ) {
aassettings.sv_friction = 6;
aassettings.sv_stopspeed = 100;
aassettings.sv_gravity = 800;
aassettings.sv_waterfriction = 1;
aassettings.sv_watergravity = 400;
aassettings.sv_maxvelocity = 320;
aassettings.sv_maxwalkvelocity = 300;
aassettings.sv_maxcrouchvelocity = 100;
aassettings.sv_maxswimvelocity = 150;
aassettings.sv_walkaccelerate = 10;
aassettings.sv_airaccelerate = 1;
aassettings.sv_swimaccelerate = 4;
aassettings.sv_maxstep = 18;
aassettings.sv_maxsteepness = 0.7;
aassettings.sv_maxwaterjump = 17;
// Ridah, calculate maxbarrier according to jumpvel and gravity
aassettings.sv_jumpvel = 270;
aassettings.sv_maxbarrier = 49; //-0.8 + (0.5 * aassettings.sv_gravity * (aassettings.sv_jumpvel / aassettings.sv_gravity) * (aassettings.sv_jumpvel / aassettings.sv_gravity));
// done.
} //end of the function AAS_InitSettings
//===========================================================================
// returns qtrue if the bot is against a ladder
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int AAS_AgainstLadder( vec3_t origin, int ms_areanum ) {
int areanum, i, facenum, side;
vec3_t org;
aas_plane_t *plane;
aas_face_t *face;
aas_area_t *area;
VectorCopy( origin, org );
areanum = AAS_PointAreaNum( org );
if ( !areanum ) {
org[0] += 1;
areanum = AAS_PointAreaNum( org );
if ( !areanum ) {
org[1] += 1;
areanum = AAS_PointAreaNum( org );
if ( !areanum ) {
org[0] -= 2;
areanum = AAS_PointAreaNum( org );
if ( !areanum ) {
org[1] -= 2;
areanum = AAS_PointAreaNum( org );
} //end if
} //end if
} //end if
} //end if
//if in solid... wrrr shouldn't happen
//if (!areanum) return qfalse;
// RF, it does if they're in a monsterclip brush
if ( !areanum ) {
areanum = ms_areanum;
}
//if not in a ladder area
if ( !( ( *aasworld ).areasettings[areanum].areaflags & AREA_LADDER ) ) {
return qfalse;
}
//if a crouch only area
if ( !( ( *aasworld ).areasettings[areanum].presencetype & PRESENCE_NORMAL ) ) {
return qfalse;
}
//
area = &( *aasworld ).areas[areanum];
for ( i = 0; i < area->numfaces; i++ )
{
facenum = ( *aasworld ).faceindex[area->firstface + i];
side = facenum < 0;
face = &( *aasworld ).faces[abs( facenum )];
//if the face isn't a ladder face
if ( !( face->faceflags & FACE_LADDER ) ) {
continue;
}
//get the plane the face is in
plane = &( *aasworld ).planes[face->planenum ^ side];
//if the origin is pretty close to the plane
if ( abs( DotProduct( plane->normal, origin ) - plane->dist ) < 7 ) {
// RF, if hanging on to the edge of a ladder, we have to account for bounding box touching
//if (AAS_PointInsideFace(abs(facenum), origin, 0.1)) return qtrue;
if ( AAS_PointInsideFace( abs( facenum ), origin, 2.0 ) ) {
return qtrue;
}
} //end if
} //end for
return qfalse;
} //end of the function AAS_AgainstLadder
//===========================================================================
// returns qtrue if the bot is on the ground
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int AAS_OnGround( vec3_t origin, int presencetype, int passent ) {
//aas_trace_t trace;
bsp_trace_t trace;
vec3_t end, up = {0, 0, 1};
//aas_plane_t *plane;
vec3_t mins, maxs;
VectorCopy( origin, end );
end[2] -= 10;
//trace = AAS_TraceClientBBox(origin, end, presencetype, passent);
AAS_PresenceTypeBoundingBox( presencetype, mins, maxs );
trace = AAS_Trace( origin, mins, maxs, end, passent, CONTENTS_SOLID | CONTENTS_PLAYERCLIP );
//if in solid
if ( trace.startsolid ) {
return qtrue; //qfalse;
}
//if nothing hit at all
if ( trace.fraction >= 1.0 ) {
return qfalse;
}
//if too far from the hit plane
if ( origin[2] - trace.endpos[2] > 10 ) {
return qfalse;
}
//check if the plane isn't too steep
//plane = AAS_PlaneFromNum(trace.planenum);
if ( DotProduct( trace.plane.normal, up ) < aassettings.sv_maxsteepness ) {
return qfalse;
}
//the bot is on the ground
return qtrue;
} //end of the function AAS_OnGround
//===========================================================================
// returns qtrue if a bot at the given position is swimming
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int AAS_Swimming( vec3_t origin ) {
vec3_t testorg;
VectorCopy( origin, testorg );
testorg[2] -= 2;
if ( AAS_PointContents( testorg ) & ( CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER ) ) {
return qtrue;
}
return qfalse;
} //end of the function AAS_Swimming
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
vec3_t VEC_UP = {0, -1, 0};
vec3_t MOVEDIR_UP = {0, 0, 1};
vec3_t VEC_DOWN = {0, -2, 0};
vec3_t MOVEDIR_DOWN = {0, 0, -1};
void AAS_SetMovedir( vec3_t angles, vec3_t movedir ) {
if ( VectorCompare( angles, VEC_UP ) ) {
VectorCopy( MOVEDIR_UP, movedir );
} //end if
else if ( VectorCompare( angles, VEC_DOWN ) ) {
VectorCopy( MOVEDIR_DOWN, movedir );
} //end else if
else
{
AngleVectors( angles, movedir, NULL, NULL );
} //end else
} //end of the function AAS_SetMovedir
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_JumpReachRunStart( aas_reachability_t *reach, vec3_t runstart ) {
vec3_t hordir, start, cmdmove;
aas_clientmove_t move;
//
hordir[0] = reach->start[0] - reach->end[0];
hordir[1] = reach->start[1] - reach->end[1];
hordir[2] = 0;
VectorNormalize( hordir );
//start point
VectorCopy( reach->start, start );
start[2] += 1;
//get command movement
VectorScale( hordir, 400, cmdmove );
//
AAS_PredictClientMovement( &move, -1, start, PRESENCE_NORMAL, qtrue,
vec3_origin, cmdmove, 1, 2, 0.1,
SE_ENTERWATER | SE_ENTERSLIME | SE_ENTERLAVA |
SE_HITGROUNDDAMAGE | SE_GAP, 0, qfalse );
VectorCopy( move.endpos, runstart );
//don't enter slime or lava and don't fall from too high
if ( move.stopevent & ( SE_ENTERLAVA | SE_HITGROUNDDAMAGE ) ) { //----(SA) modified since slime is no longer deadly
// if (move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA|SE_HITGROUNDDAMAGE))
VectorCopy( start, runstart );
} //end if
} //end of the function AAS_JumpReachRunStart
//===========================================================================
// returns the Z velocity when rocket jumping at the origin
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
float AAS_WeaponJumpZVelocity( vec3_t origin, float radiusdamage ) {
vec3_t kvel, v, start, end, forward, right, viewangles, dir;
float mass, knockback, points;
vec3_t rocketoffset = {8, 8, -8};
vec3_t botmins = {-16, -16, -24};
vec3_t botmaxs = {16, 16, 32};
bsp_trace_t bsptrace;
//look down (90 degrees)
viewangles[PITCH] = 90;
viewangles[YAW] = 0;
viewangles[ROLL] = 0;
//get the start point shooting from
VectorCopy( origin, start );
start[2] += 8; //view offset Z
AngleVectors( viewangles, forward, right, NULL );
start[0] += forward[0] * rocketoffset[0] + right[0] * rocketoffset[1];
start[1] += forward[1] * rocketoffset[0] + right[1] * rocketoffset[1];
start[2] += forward[2] * rocketoffset[0] + right[2] * rocketoffset[1] + rocketoffset[2];
//end point of the trace
VectorMA( start, 500, forward, end );
//trace a line to get the impact point
bsptrace = AAS_Trace( start, NULL, NULL, end, 1, CONTENTS_SOLID );
//calculate the damage the bot will get from the rocket impact
VectorAdd( botmins, botmaxs, v );
VectorMA( origin, 0.5, v, v );
VectorSubtract( bsptrace.endpos, v, v );
//
points = radiusdamage - 0.5 * VectorLength( v );
if ( points < 0 ) {
points = 0;
}
//the owner of the rocket gets half the damage
points *= 0.5;
//mass of the bot (p_client.c: PutClientInServer)
mass = 200;
//knockback is the same as the damage points
knockback = points;
//direction of the damage (from trace.endpos to bot origin)
VectorSubtract( origin, bsptrace.endpos, dir );
VectorNormalize( dir );
//damage velocity
VectorScale( dir, 1600.0 * (float)knockback / mass, kvel ); //the rocket jump hack...
//rocket impact velocity + jump velocity
return kvel[2] + aassettings.sv_jumpvel;
} //end of the function AAS_WeaponJumpZVelocity
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
float AAS_RocketJumpZVelocity( vec3_t origin ) {
//rocket radius damage is 120 (p_weapon.c: Weapon_RocketLauncher_Fire)
return AAS_WeaponJumpZVelocity( origin, 120 );
} //end of the function AAS_RocketJumpZVelocity
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
float AAS_BFGJumpZVelocity( vec3_t origin ) {
//bfg radius damage is 1000 (p_weapon.c: weapon_bfg_fire)
return AAS_WeaponJumpZVelocity( origin, 120 );
} //end of the function AAS_BFGJumpZVelocity
//===========================================================================
// applies ground friction to the given velocity
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_Accelerate( vec3_t velocity, float frametime, vec3_t wishdir, float wishspeed, float accel ) {
// q2 style
int i;
float addspeed, accelspeed, currentspeed;
currentspeed = DotProduct( velocity, wishdir );
addspeed = wishspeed - currentspeed;
if ( addspeed <= 0 ) {
return;
}
accelspeed = accel * frametime * wishspeed;
if ( accelspeed > addspeed ) {
accelspeed = addspeed;
}
for ( i = 0 ; i < 3 ; i++ ) {
velocity[i] += accelspeed * wishdir[i];
}
} //end of the function AAS_Accelerate
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_AirControl( vec3_t start, vec3_t end, vec3_t velocity, vec3_t cmdmove ) {
vec3_t dir;
VectorSubtract( end, start, dir );
} //end of the function AAS_AirControl
//===========================================================================
// applies ground friction to the given velocity
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_ApplyFriction( vec3_t vel, float friction, float stopspeed,
float frametime ) {
float speed, control, newspeed;
//horizontal speed
speed = sqrt( vel[0] * vel[0] + vel[1] * vel[1] );
if ( speed ) {
control = speed < stopspeed ? stopspeed : speed;
newspeed = speed - frametime * control * friction;
if ( newspeed < 0 ) {
newspeed = 0;
}
newspeed /= speed;
vel[0] *= newspeed;
vel[1] *= newspeed;
} //end if
} //end of the function AAS_ApplyFriction
//===========================================================================
// predicts the movement
// assumes regular bounding box sizes
// NOTE: out of water jumping is not included
// NOTE: grappling hook is not included
//
// Parameter: origin : origin to start with
// presencetype : presence type to start with
// velocity : velocity to start with
// cmdmove : client command movement
// cmdframes : number of frame cmdmove is valid
// maxframes : maximum number of predicted frames
// frametime : duration of one predicted frame
// stopevent : events that stop the prediction
// stopareanum : stop as soon as entered this area
// Returns: aas_clientmove_t
// Changes Globals: -
//===========================================================================
int AAS_PredictClientMovement( struct aas_clientmove_s *move,
int entnum, vec3_t origin,
int hitent, int onground,
vec3_t velocity, vec3_t cmdmove,
int cmdframes,
int maxframes, float frametime,
int stopevent, int stopareanum, int visualize ) {
float sv_friction, sv_stopspeed, sv_gravity, sv_waterfriction;
float sv_watergravity;
float sv_walkaccelerate, sv_airaccelerate, sv_swimaccelerate;
float sv_maxwalkvelocity, sv_maxcrouchvelocity, sv_maxswimvelocity;
float sv_maxstep, sv_maxsteepness, sv_jumpvel, friction;
float gravity, delta, maxvel, wishspeed, accelerate;
//float velchange, newvel;
int n, i, j, pc, step, swimming, ax, crouch, event, jump_frame, areanum;
int areas[20], numareas;
vec3_t points[20], mins, maxs;
vec3_t org, end, feet, start, stepend, lastorg, wishdir;
vec3_t frame_test_vel, old_frame_test_vel, left_test_vel, savevel;
vec3_t up = {0, 0, 1};
cplane_t *plane, *plane2, *lplane;
//aas_trace_t trace, steptrace;
bsp_trace_t trace, steptrace;
if ( visualize ) {
// These debugging tools are not currently available in bspc. Mad Doctor I, 1/27/2003.
#ifndef BSPC
AAS_ClearShownPolygons();
AAS_ClearShownDebugLines();
#endif
}
// don't let us succeed on interaction with area 0
if ( stopareanum == 0 ) {
stopevent &= ~( SE_ENTERAREA | SE_HITGROUNDAREA );
}
if ( frametime <= 0 ) {
frametime = 0.1;
}
//
sv_friction = aassettings.sv_friction;
sv_stopspeed = aassettings.sv_stopspeed;
sv_gravity = aassettings.sv_gravity;
sv_waterfriction = aassettings.sv_waterfriction;
sv_watergravity = aassettings.sv_watergravity;
sv_maxwalkvelocity = aassettings.sv_maxwalkvelocity; // * frametime;
sv_maxcrouchvelocity = aassettings.sv_maxcrouchvelocity; // * frametime;
sv_maxswimvelocity = aassettings.sv_maxswimvelocity; // * frametime;
sv_walkaccelerate = aassettings.sv_walkaccelerate;
sv_airaccelerate = aassettings.sv_airaccelerate;
sv_swimaccelerate = aassettings.sv_swimaccelerate;
sv_maxstep = aassettings.sv_maxstep;
sv_maxsteepness = aassettings.sv_maxsteepness;
sv_jumpvel = aassettings.sv_jumpvel * frametime;
//
memset( move, 0, sizeof( aas_clientmove_t ) );
memset( &trace, 0, sizeof( bsp_trace_t ) );
AAS_PresenceTypeBoundingBox( PRESENCE_NORMAL, mins, maxs );
//start at the current origin
VectorCopy( origin, org );
org[2] += 0.25;
// test this position, if it's in solid, move it up to adjust for capsules
//trace = AAS_TraceClientBBox(org, org, PRESENCE_NORMAL, entnum);
trace = AAS_Trace( org, mins, maxs, org, entnum, ( CONTENTS_SOLID | CONTENTS_PLAYERCLIP ) & ~CONTENTS_BODY );
while ( trace.startsolid ) {
org[2] += 8;
//trace = AAS_TraceClientBBox(org, org, PRESENCE_NORMAL, entnum);
trace = AAS_Trace( org, mins, maxs, org, entnum, ( CONTENTS_SOLID | CONTENTS_PLAYERCLIP ) & ~CONTENTS_BODY );
if ( trace.startsolid && ( org[2] - origin[2] > 16 ) ) {
move->stopevent = SE_NONE;
return qfalse;
}
}
//velocity to test for the first frame
VectorScale( velocity, frametime, frame_test_vel );
//
jump_frame = -1;
lplane = NULL;
//predict a maximum of 'maxframes' ahead
for ( n = 0; n < maxframes; n++ )
{
swimming = AAS_Swimming( org );
//get gravity depending on swimming or not
gravity = swimming ? sv_watergravity : sv_gravity;
//apply gravity at the START of the frame
frame_test_vel[2] = frame_test_vel[2] - ( gravity * 0.1 * frametime );
//if on the ground or swimming
if ( onground || swimming ) {
friction = swimming ? sv_friction : sv_waterfriction;
//apply friction
VectorScale( frame_test_vel, 1 / frametime, frame_test_vel );
AAS_ApplyFriction( frame_test_vel, friction, sv_stopspeed, frametime );
VectorScale( frame_test_vel, frametime, frame_test_vel );
} //end if
crouch = qfalse;
//apply command movement
if ( cmdframes < 0 ) {
// cmdmove is the destination, we should keep moving towards it
VectorSubtract( cmdmove, org, wishdir );
VectorNormalize( wishdir );
VectorScale( wishdir, sv_maxwalkvelocity, wishdir );
VectorCopy( frame_test_vel, savevel );
VectorScale( wishdir, frametime, frame_test_vel );
if ( !swimming ) {
frame_test_vel[2] = savevel[2];
}
} else if ( n < cmdframes ) {
ax = 0;
maxvel = sv_maxwalkvelocity;
accelerate = sv_airaccelerate;
VectorCopy( cmdmove, wishdir );
if ( onground ) {
if ( cmdmove[2] < -300 ) {
crouch = qtrue;
maxvel = sv_maxcrouchvelocity;
} //end if
//if not swimming and upmove is positive then jump
if ( !swimming && cmdmove[2] > 1 ) {
//jump velocity minus the gravity for one frame + 5 for safety
frame_test_vel[2] = sv_jumpvel - ( gravity * 0.1 * frametime ) + 5;
jump_frame = n;
//jumping so air accelerate
accelerate = sv_airaccelerate;
} //end if
else
{
accelerate = sv_walkaccelerate;
} //end else
ax = 2;
} //end if
if ( swimming ) {
maxvel = sv_maxswimvelocity;
accelerate = sv_swimaccelerate;
ax = 3;
} //end if
else
{
wishdir[2] = 0;
} //end else
//
wishspeed = VectorNormalize( wishdir );
if ( wishspeed > maxvel ) {
wishspeed = maxvel;
}
VectorScale( frame_test_vel, 1 / frametime, frame_test_vel );
AAS_Accelerate( frame_test_vel, frametime, wishdir, wishspeed, accelerate );
VectorScale( frame_test_vel, frametime, frame_test_vel );
/*
for (i = 0; i < ax; i++)
{
velchange = (cmdmove[i] * frametime) - frame_test_vel[i];
if (velchange > sv_maxacceleration) velchange = sv_maxacceleration;
else if (velchange < -sv_maxacceleration) velchange = -sv_maxacceleration;
newvel = frame_test_vel[i] + velchange;
//
if (frame_test_vel[i] <= maxvel && newvel > maxvel) frame_test_vel[i] = maxvel;
else if (frame_test_vel[i] >= -maxvel && newvel < -maxvel) frame_test_vel[i] = -maxvel;
else frame_test_vel[i] = newvel;
} //end for
*/
} //end if
//if (crouch)
//{
// presencetype = PRESENCE_CROUCH;
//} //end if
//else if (presencetype == PRESENCE_CROUCH)
//{
// if (AAS_PointPresenceType(org) & PRESENCE_NORMAL)
// {
// presencetype = PRESENCE_NORMAL;
// } //end if
//} //end else
//save the current origin
VectorCopy( org, lastorg );
//move linear during one frame
VectorCopy( frame_test_vel, left_test_vel );
j = 0;
do
{
VectorAdd( org, left_test_vel, end );
//trace a bounding box
//trace = AAS_TraceClientBBox(org, end, PRESENCE_NORMAL, entnum);
trace = AAS_Trace( org, mins, maxs, end, entnum, ( CONTENTS_SOLID | CONTENTS_PLAYERCLIP ) & ~CONTENTS_BODY );
//
//#ifdef AAS_MOVE_DEBUG
if ( visualize ) {
//if (trace.startsolid)
//botimport.Print(PRT_MESSAGE, "PredictMovement: start solid\n");
AAS_DebugLine( org, trace.endpos, LINECOLOR_RED );
} //end if
//#endif //AAS_MOVE_DEBUG
//
if ( stopevent & SE_HITENT ) {
if ( trace.fraction < 1.0 && trace.ent == hitent ) {
areanum = AAS_PointAreaNum( org );
VectorCopy( org, move->endpos );
VectorScale( frame_test_vel, 1 / frametime, move->velocity );
move->trace = trace;
move->stopevent = SE_HITENT;
move->presencetype = ( *aasworld ).areasettings[areanum].presencetype;
move->endcontents = 0;
move->time = n * frametime;
move->frames = n;
return qtrue;
}
}
if ( stopevent & SE_ENTERAREA ) {
numareas = AAS_TraceAreas( org, trace.endpos, areas, points, 20 );
for ( i = 0; i < numareas; i++ )
{
if ( areas[i] == stopareanum ) {
VectorCopy( points[i], move->endpos );
VectorScale( frame_test_vel, 1 / frametime, move->velocity );
move->trace = trace;
move->stopevent = SE_ENTERAREA;
move->presencetype = ( *aasworld ).areasettings[areas[i]].presencetype;
move->endcontents = 0;
move->time = n * frametime;
move->frames = n;
return qtrue;
} //end if
} //end for
} //end if
if ( stopevent & SE_STUCK ) {
if ( trace.fraction < 1.0 ) {
plane = &trace.plane;
//if (Q_fabs(plane->normal[2]) <= sv_maxsteepness) {
VectorNormalize2( frame_test_vel, wishdir );
if ( DotProduct( plane->normal, wishdir ) < -0.8 ) {
areanum = AAS_PointAreaNum( org );
VectorCopy( org, move->endpos );
VectorScale( frame_test_vel, 1 / frametime, move->velocity );
move->trace = trace;
move->stopevent = SE_STUCK;
move->presencetype = ( *aasworld ).areasettings[areanum].presencetype;
move->endcontents = 0;
move->time = n * frametime;
move->frames = n;
return qtrue;
}
}
}
//move the entity to the trace end point
VectorCopy( trace.endpos, org );
//if there was a collision
if ( trace.fraction < 1.0 ) {
//get the plane the bounding box collided with
plane = &trace.plane;
//
if ( stopevent & SE_HITGROUNDAREA ) {
if ( DotProduct( plane->normal, up ) > sv_maxsteepness ) {
VectorCopy( org, start );
start[2] += 0.5;
if ( ( stopareanum < 0 && AAS_PointAreaNum( start ) ) || ( AAS_PointAreaNum( start ) == stopareanum ) ) {
VectorCopy( start, move->endpos );
VectorScale( frame_test_vel, 1 / frametime, move->velocity );
move->trace = trace;
move->stopevent = SE_HITGROUNDAREA;
move->presencetype = ( *aasworld ).areasettings[stopareanum].presencetype;
move->endcontents = 0;
move->time = n * frametime;
move->frames = n;
return qtrue;
} //end if
} //end if
} //end if
//assume there's no step
step = qfalse;
//if it is a vertical plane and the bot didn't jump recently
if ( plane->normal[2] == 0 && ( jump_frame < 0 || n - jump_frame > 2 ) ) {
//check for a step
VectorMA( org, -0.25, plane->normal, start );
VectorCopy( start, stepend );
start[2] += sv_maxstep;
//steptrace = AAS_TraceClientBBox(start, stepend, PRESENCE_NORMAL, entnum);
steptrace = AAS_Trace( start, mins, maxs, stepend, entnum, ( CONTENTS_SOLID | CONTENTS_PLAYERCLIP ) & ~CONTENTS_BODY );
//
if ( !steptrace.startsolid ) {
plane2 = &steptrace.plane;
if ( DotProduct( plane2->normal, up ) > sv_maxsteepness ) {
VectorSubtract( end, steptrace.endpos, left_test_vel );
left_test_vel[2] = 0;
frame_test_vel[2] = 0;
//#ifdef AAS_MOVE_DEBUG
if ( visualize ) {
if ( steptrace.endpos[2] - org[2] > 0.125 ) {
VectorCopy( org, start );
start[2] = steptrace.endpos[2];
AAS_DebugLine( org, start, LINECOLOR_BLUE );
} //end if
} //end if
//#endif //AAS_MOVE_DEBUG
org[2] = steptrace.endpos[2];
step = qtrue;
} //end if
} //end if
} //end if
//
if ( !step ) {
//velocity left to test for this frame is the projection
//of the current test velocity into the hit plane
VectorMA( left_test_vel, -DotProduct( left_test_vel, plane->normal ),
plane->normal, left_test_vel );
// RF: from PM_SlideMove()
// if this is the same plane we hit before, nudge velocity
// out along it, which fixes some epsilon issues with
// non-axial planes
if ( lplane && DotProduct( lplane->normal, plane->normal ) > 0.99 ) {
VectorAdd( plane->normal, left_test_vel, left_test_vel );
}
lplane = plane;
//store the old velocity for landing check
VectorCopy( frame_test_vel, old_frame_test_vel );
//test velocity for the next frame is the projection
//of the velocity of the current frame into the hit plane
VectorMA( frame_test_vel, -DotProduct( frame_test_vel, plane->normal ),
plane->normal, frame_test_vel );
//check for a landing on an almost horizontal floor
if ( DotProduct( plane->normal, up ) > sv_maxsteepness ) {
onground = qtrue;
} //end if
if ( stopevent & SE_HITGROUNDDAMAGE ) {
delta = 0;
if ( old_frame_test_vel[2] < 0 &&
frame_test_vel[2] > old_frame_test_vel[2] &&
!onground ) {
delta = old_frame_test_vel[2];
} //end if
else if ( onground ) {
delta = frame_test_vel[2] - old_frame_test_vel[2];
} //end else
if ( delta ) {
delta = delta * 10;
delta = delta * delta * 0.0001;
if ( swimming ) {
delta = 0;
}
// never take falling damage if completely underwater
/*
if (ent->waterlevel == 3) return;
if (ent->waterlevel == 2) delta *= 0.25;
if (ent->waterlevel == 1) delta *= 0.5;
*/
if ( delta > 40 ) {
VectorCopy( org, move->endpos );
VectorCopy( frame_test_vel, move->velocity );
move->trace = trace;
move->stopevent = SE_HITGROUNDDAMAGE;
areanum = AAS_PointAreaNum( org );
if ( areanum ) {
move->presencetype = ( *aasworld ).areasettings[areanum].presencetype;
}
move->endcontents = 0;
move->time = n * frametime;
move->frames = n;
return qtrue;
} //end if
} //end if
} //end if
} //end if
} //end if
//extra check to prevent endless loop
if ( ++j > 20 ) {
return qfalse;
}
//while there is a plane hit
} while ( trace.fraction < 1.0 );
//if going down
if ( frame_test_vel[2] <= 10 ) {
//check for a liquid at the feet of the bot
VectorCopy( org, feet );
feet[2] -= 22;
pc = AAS_PointContents( feet );
//get event from pc
event = SE_NONE;
if ( pc & CONTENTS_LAVA ) {
event |= SE_ENTERLAVA;
}
if ( pc & CONTENTS_SLIME ) {
event |= SE_ENTERSLIME;
}
if ( pc & CONTENTS_WATER ) {
event |= SE_ENTERWATER;
}
//
areanum = AAS_PointAreaNum( org );
if ( ( *aasworld ).areasettings[areanum].contents & AREACONTENTS_LAVA ) {
event |= SE_ENTERLAVA;
}
if ( ( *aasworld ).areasettings[areanum].contents & AREACONTENTS_SLIME ) {
event |= SE_ENTERSLIME;
}
if ( ( *aasworld ).areasettings[areanum].contents & AREACONTENTS_WATER ) {
event |= SE_ENTERWATER;
}
//if in lava or slime
if ( event & stopevent ) {
VectorCopy( org, move->endpos );
VectorScale( frame_test_vel, 1 / frametime, move->velocity );
move->stopevent = event & stopevent;
move->presencetype = ( *aasworld ).areasettings[areanum].presencetype;
move->endcontents = pc;
move->time = n * frametime;
move->frames = n;
return qtrue;
} //end if
} //end if
//
onground = AAS_OnGround( org, PRESENCE_NORMAL, entnum );
//if onground and on the ground for at least one whole frame
if ( onground ) {
if ( stopevent & SE_HITGROUND ) {
VectorCopy( org, move->endpos );
VectorScale( frame_test_vel, 1 / frametime, move->velocity );
move->trace = trace;
move->stopevent = SE_HITGROUND;
areanum = AAS_PointAreaNum( org );
if ( areanum ) {
move->presencetype = ( *aasworld ).areasettings[areanum].presencetype;
}
move->endcontents = 0;
move->time = n * frametime;
move->frames = n;
return qtrue;
} //end if
} //end if
else if ( stopevent & SE_LEAVEGROUND ) {
VectorCopy( org, move->endpos );
VectorScale( frame_test_vel, 1 / frametime, move->velocity );
move->trace = trace;
move->stopevent = SE_LEAVEGROUND;
areanum = AAS_PointAreaNum( org );
if ( areanum ) {
move->presencetype = ( *aasworld ).areasettings[areanum].presencetype;
}
move->endcontents = 0;
move->time = n * frametime;
move->frames = n;
return qtrue;
} //end else if
else if ( stopevent & SE_GAP ) {
bsp_trace_t gaptrace;
VectorCopy( org, start );
VectorCopy( start, end );
end[2] -= 48 + aassettings.sv_maxbarrier;
//gaptrace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1);
gaptrace = AAS_Trace( start, mins, maxs, end, -1, ( CONTENTS_SOLID | CONTENTS_PLAYERCLIP ) & ~CONTENTS_BODY );
//if solid is found the bot cannot walk any further and will not fall into a gap
if ( !gaptrace.startsolid ) {
//if it is a gap (lower than one step height)
if ( gaptrace.endpos[2] < org[2] - aassettings.sv_maxstep - 1 ) {
if ( !( AAS_PointContents( end ) & ( CONTENTS_WATER | CONTENTS_SLIME ) ) ) { //----(SA) modified since slime is no longer deadly
// if (!(AAS_PointContents(end) & CONTENTS_WATER))
VectorCopy( lastorg, move->endpos );
VectorScale( frame_test_vel, 1 / frametime, move->velocity );
move->trace = trace;
move->stopevent = SE_GAP;
areanum = AAS_PointAreaNum( org );
if ( areanum ) {
move->presencetype = ( *aasworld ).areasettings[areanum].presencetype;
}
move->endcontents = 0;
move->time = n * frametime;
move->frames = n;
return qtrue;
} //end if
} //end if
} //end if
} //end else if
if ( stopevent & SE_TOUCHJUMPPAD ) {
if ( ( *aasworld ).areasettings[AAS_PointAreaNum( org )].contents & AREACONTENTS_JUMPPAD ) {
VectorCopy( org, move->endpos );
VectorScale( frame_test_vel, 1 / frametime, move->velocity );
move->trace = trace;
move->stopevent = SE_TOUCHJUMPPAD;
areanum = AAS_PointAreaNum( org );
if ( areanum ) {
move->presencetype = ( *aasworld ).areasettings[areanum].presencetype;
}
move->endcontents = 0;
move->time = n * frametime;
move->frames = n;
return qtrue;
} //end if
} //end if
if ( stopevent & SE_TOUCHTELEPORTER ) {
if ( ( *aasworld ).areasettings[AAS_PointAreaNum( org )].contents & AREACONTENTS_TELEPORTER ) {
VectorCopy( org, move->endpos );
VectorScale( frame_test_vel, 1 / frametime, move->velocity );
move->trace = trace;
move->stopevent = SE_TOUCHTELEPORTER;
areanum = AAS_PointAreaNum( org );
if ( areanum ) {
move->presencetype = ( *aasworld ).areasettings[areanum].presencetype;
}
move->endcontents = 0;
move->time = n * frametime;
move->frames = n;
return qtrue;
} //end if
} //end if
} //end for
//
areanum = AAS_PointAreaNum( org );
VectorCopy( org, move->endpos );
VectorScale( frame_test_vel, 1 / frametime, move->velocity );
move->stopevent = SE_NONE;
move->presencetype = aasworld->areasettings ? aasworld->areasettings[areanum].presencetype : 0;
move->endcontents = 0;
move->time = n * frametime;
move->frames = n;
//
return qtrue;
} //end of the function AAS_PredictClientMovement
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_TestMovementPrediction( int entnum, vec3_t origin, vec3_t dir ) {
vec3_t velocity, cmdmove;
aas_clientmove_t move;
VectorClear( velocity );
if ( !AAS_Swimming( origin ) ) {
dir[2] = 0;
}
VectorNormalize( dir );
VectorScale( dir, 400, cmdmove );
cmdmove[2] = 224;
AAS_ClearShownDebugLines();
AAS_PredictClientMovement( &move, entnum, origin, PRESENCE_NORMAL, qtrue,
velocity, cmdmove, 13, 13, 0.1, SE_HITGROUND, 0, qtrue ); //SE_LEAVEGROUND);
if ( move.stopevent & SE_LEAVEGROUND ) {
botimport.Print( PRT_MESSAGE, "leave ground\n" );
} //end if
} //end of the function TestMovementPrediction
//===========================================================================
// calculates the horizontal velocity needed to perform a jump from start
// to end
//
// Parameter: zvel : z velocity for jump
// start : start position of jump
// end : end position of jump
// *speed : returned speed for jump
// Returns: qfalse if too high or too far from start to end
// Changes Globals: -
//===========================================================================
int AAS_HorizontalVelocityForJump( float zvel, vec3_t start, vec3_t end, float *velocity ) {
float sv_gravity, sv_maxvelocity;
float maxjump, height2fall, t, top;
vec3_t dir;
sv_gravity = aassettings.sv_gravity;
sv_maxvelocity = aassettings.sv_maxvelocity;
//maximum height a player can jump with the given initial z velocity
maxjump = 0.5 * sv_gravity * ( zvel / sv_gravity ) * ( zvel / sv_gravity );
//top of the parabolic jump
top = start[2] + maxjump;
//height the bot will fall from the top
height2fall = top - end[2];
//if the goal is to high to jump to
if ( height2fall < 0 ) {
*velocity = sv_maxvelocity;
return 0;
} //end if
//time a player takes to fall the height
t = sqrt( height2fall / ( 0.5 * sv_gravity ) );
//direction from start to end
VectorSubtract( end, start, dir );
//calculate horizontal speed
*velocity = sqrt( dir[0] * dir[0] + dir[1] * dir[1] ) / ( t + zvel / sv_gravity );
//the horizontal speed must be lower than the max speed
if ( *velocity > sv_maxvelocity ) {
*velocity = sv_maxvelocity;
return 0;
} //end if
return 1;
} //end of the function AAS_HorizontalVelocityForJump