/* Copyright (C) 1997-2001 Id Software, Inc. This program 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 2 of the License, or (at your option) any later version. This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "../g_local.h" #include "ai_local.h" #define MAX_CLIP_PLANES 5 void SV_Impact (edict_t *e1, trace_t *trace); int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce); //========================================== // AI_NPCPhysStepUp // Stepping helper to AI_NPCPhysMove //========================================== qboolean AI_NPCPhysStepUp( edict_t *ent, vec3_t virtual_origin, int mask ) { vec3_t start; vec3_t end; vec3_t movedir; trace_t trace; //check for having groundentity VectorCopy( virtual_origin, end ); end[2] -= 0.25f;//inside floor //trace = gi.trace( virtual_origin, ent->mins, ent->maxs, end, ent, mask ); trap_Trace( &trace, virtual_origin, ent->r.mins, ent->r.maxs, end, ent, mask ); if( trace.fraction == 1.0f || trace.plane.normal[2] < 0.7 ) return qfalse; VectorCopy( virtual_origin, start ); VectorNormalize2( ent->velocity, movedir ); movedir[2] = 0.0f; start[2] += AI_STEPSIZE; VectorMA( start, 0.3f, movedir, end ); end[2] -= AI_STEPSIZE*2; trap_Trace( &trace, start, ent->r.mins, ent->r.maxs, end, ent, mask); //trace = gi.trace (start, ent->r.mins, ent->r.maxs, end, ent, mask); if( trace.startsolid || !trace.fraction ) return qfalse; if( trace.fraction ) VectorCopy( trace.endpos, ent->s.origin ); return qtrue; } //========================================== // AI_NPCPhysMove // Move entity's box based on it's velocity vector. // It does slide on planes, and handles stepping up // if enabled. Doesn't add physics effects, only box movement. // It's a modified copy of SV_FlyMove. //========================================== int AI_NPCPhysMove (edict_t *ent, float time, int mask, qboolean step, float bouncescale ) { edict_t *hit; int bumpcount, numbumps; vec3_t dir; float d; int numplanes; vec3_t planes[MAX_CLIP_PLANES]; vec3_t primal_velocity, original_velocity, new_velocity; int i, j; trace_t trace; vec3_t end; float time_left; int blocked; numbumps = 4; blocked = 0; VectorCopy ( ent->velocity, original_velocity); VectorCopy ( ent->velocity, primal_velocity); numplanes = 0; time_left = time; ent->groundentity = NULL; for (bumpcount=0 ; bumpcounts.origin[i] + time_left * ent->velocity[i]; //trace = gi.trace (ent->s.origin, ent->r.mins, ent->r.maxs, end, ent, mask); trap_Trace( &trace, ent->s.origin, ent->r.mins, ent->r.maxs, end, ent, mask); if (trace.allsolid) { // entity is trapped in another solid VectorCopy (vec3_origin, ent->velocity); return 3; } if (trace.fraction > 0) { // actually covered some distance VectorCopy (trace.endpos, ent->s.origin); VectorCopy (ent->velocity, original_velocity); numplanes = 0; } if (trace.fraction == 1) break; // moved the entire distance hit = &game.edicts[trace.ent]; if (trace.plane.normal[2] > 0.7) { blocked |= 1; // floor if ( hit->r.solid == SOLID_BSP) { ent->groundentity = hit; ent->groundentity_linkcount = hit->r.linkcount; } } if (!trace.plane.normal[2]) { //try to solve the step if( step && AI_NPCPhysStepUp( ent, trace.endpos, mask ) ) { time_left -= time_left * trace.fraction; VectorCopy (ent->velocity, original_velocity); numplanes = 0; goto retry; } blocked |= 2; // step } // // run the impact function // SV_Impact (ent, &trace); if (!ent->r.inuse) break; // removed by the impact function time_left -= time_left * trace.fraction; // cliped to another plane if (numplanes >= MAX_CLIP_PLANES) { // this shouldn't really happen VectorCopy (vec3_origin, ent->velocity); return 3; } VectorCopy (trace.plane.normal, planes[numplanes]); numplanes++; // // modify original_velocity so it parallels all of the clip planes // for (i=0 ; ivelocity); } else { // go along the crease if (numplanes != 2) { // gi.dprintf ("clip velocity, numplanes == %i\n",numplanes); VectorCopy (vec3_origin, ent->velocity); return 7; } CrossProduct (planes[0], planes[1], dir); d = DotProduct (dir, ent->velocity); VectorScale (dir, d, ent->velocity); } // // if original velocity is against the original velocity, stop dead // to avoid tiny occilations in sloping corners // if (DotProduct (ent->velocity, primal_velocity) <= 0) { VectorCopy (vec3_origin, ent->velocity); return blocked; } } return blocked; } //========================================== // M_Phys_Momentum_AddPush // add a force impulse to the acceleration //========================================== void M_Phys_Momentum_AddPush( vec3_t accel, vec3_t pushdir, float push, float mass, float timestep ) { float pushaccel; if( !mass ) mass = 100; pushaccel = ((1000 * push) / mass) * timestep; VectorNormalize( pushdir ); VectorScale( pushdir, pushaccel, pushdir ); VectorAdd( accel, pushdir, accel ); } //========================================== // M_Phys_Momentum_AddFriction //========================================== void M_Phys_Momentum_AddFriction( float classfriction, float class_stopspeed, vec3_t origin, vec3_t vel, float timestep, vec3_t mins, vec3_t maxs, edict_t *passent, int solidmask ) { float speed, newspeed, control; float friction; float drop; int groundentity = -1; int surfflags = 0; trace_t trace; vec3_t v1; //check groundentity VectorCopy( origin, v1 ); v1[2] -= 0.25f;//inside floor trap_Trace( &trace, origin, mins, maxs, v1, passent, solidmask ); //trace = gi.trace( origin, mins, maxs, v1, passent, solidmask ); if( trace.fraction < 1.0f && trace.plane.normal[2] >= 0.7 ) // We have ground entity { groundentity = 1; surfflags = trace.surfFlags; //surfflags = trace.surface->flags; } speed = vel[0]*vel[0] +vel[1]*vel[1] + vel[2]*vel[2]; if (speed < 1) { vel[0] = 0; vel[1] = 0; return; } speed = sqrt(speed); drop = 0; // apply ground friction if (((groundentity != -1) && !(surfflags & SURF_SLICK) ) /*&& (pm->waterlevel < 2) || (pml.ladder)*/ ) { friction = classfriction;//jalfixme control = speed < class_stopspeed ? class_stopspeed : speed; drop += control*friction*timestep; } /* // apply water friction if ((pm->waterlevel >= 2) && !pml.ladder) drop += speed*pm_waterfriction*pm->waterlevel*timestep; */ // scale the velocity newspeed = speed - drop; if (newspeed <= 0) { newspeed = 0; VectorClear ( vel ); } else { newspeed /= speed; VectorScale ( vel, newspeed, vel ); } }