void mutant_jump_touch(edict_t *self, edict_t *other, cplane_t *plane /* unused */, csurface_t *surf /* unused */) { if (!self || !other) { return; } if (self->health <= 0) { self->touch = NULL; return; } if (other->takedamage) { if (VectorLength(self->velocity) > 400) { vec3_t point; vec3_t normal; int damage; VectorCopy(self->velocity, normal); VectorNormalize(normal); VectorMA(self->s.origin, self->maxs[0], normal, point); damage = 40 + 10 * random(); T_Damage(other, self, self, self->velocity, point, normal, damage, damage, 0, MOD_UNKNOWN); } } if (!M_CheckBottom(self)) { if (self->groundentity) { self->monsterinfo.nextframe = FRAME_attack02; self->touch = NULL; } return; } self->touch = NULL; }
void gekk_jump_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) { if (self->health <= 0) { self->touch = NULL; return; } if (other->takedamage) { if (VectorLength(self->velocity) > 200) { vec3_t point; vec3_t normal; int damage; VectorCopy (self->velocity, normal); VectorNormalize(normal); VectorMA (self->s.origin, self->maxs[0], normal, point); damage = 10 + 10 * random(); T_Damage (other, self, self, self->velocity, point, normal, damage, damage, 0, MOD_GEKK); } } if (!M_CheckBottom (self)) { if (self->groundentity) { self->monsterinfo.nextframe = FRAME_leapatk_11; self->touch = NULL; } return; } self->touch = NULL; }
void SV_Physics_Step (edict_t *ent) { qboolean wasonground; qboolean hitsound = false; float *vel; float speed, newspeed, control; float friction; edict_t *groundentity; int mask; // airborn monsters should always check for ground if (!ent->groundentity) M_CheckGround (ent); groundentity = ent->groundentity; SV_CheckVelocity (ent); if (groundentity) wasonground = true; else wasonground = false; if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2]) SV_AddRotationalFriction (ent); // add gravity except: // flying monsters // swimming monsters who are in the water if (! wasonground) if (!(ent->flags & FL_FLY)) if (!((ent->flags & FL_SWIM) && (ent->waterlevel > 2))) { if (ent->velocity[2] < sv_gravity->value*-0.1) hitsound = true; if (ent->waterlevel == 0) SV_AddGravity (ent); } // friction for flying monsters that have been given vertical velocity if ((ent->flags & FL_FLY) && (ent->velocity[2] != 0)) { speed = fabs(ent->velocity[2]); control = speed < sv_stopspeed->value ? sv_stopspeed->value : speed; friction = sv_friction/3; newspeed = speed - (FRAMETIME * control * friction); if (newspeed < 0) newspeed = 0; newspeed /= speed; ent->velocity[2] *= newspeed; } // friction for flying monsters that have been given vertical velocity if ((ent->flags & FL_SWIM) && (ent->velocity[2] != 0)) { speed = fabs(ent->velocity[2]); control = speed < sv_stopspeed->value ? sv_stopspeed->value : speed; newspeed = speed - (FRAMETIME * control * sv_waterfriction * ent->waterlevel); if (newspeed < 0) newspeed = 0; newspeed /= speed; ent->velocity[2] *= newspeed; } if (ent->velocity[2] || ent->velocity[1] || ent->velocity[0]) { // apply friction // let dead monsters who aren't completely onground slide if ((wasonground) || (ent->flags & (FL_SWIM|FL_FLY))) if (!(ent->health <= 0.0 && !M_CheckBottom(ent))) { vel = ent->velocity; speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]); if (speed) { friction = sv_friction; control = speed < sv_stopspeed->value ? sv_stopspeed->value : speed; newspeed = speed - FRAMETIME*control*friction; if (newspeed < 0) newspeed = 0; newspeed /= speed; vel[0] *= newspeed; vel[1] *= newspeed; } } if (ent->svflags & SVF_MONSTER) mask = MASK_MONSTERSOLID; else mask = MASK_SOLID; SV_FlyMove (ent, FRAMETIME, mask); gi.linkentity (ent); // ======== // PGM - reset this every time they move. // G_touchtriggers will set it back if appropriate ent->gravity = 1.0; // ======== G_TouchTriggers (ent); if (!ent->inuse) return; if (ent->groundentity) if (!wasonground) if (hitsound) gi.sound (ent, 0, gi.soundindex("world/land.wav"), 1, 1, 0); } if(!ent->inuse) // PGM g_touchtrigger free problem return; // regular thinking SV_RunThink (ent); }
void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist) { float deltax,deltay; float d[3]; float tdir, olddir, turnaround; //FIXME: how did we get here with no enemy if (!enemy) return; olddir = anglemod( (int)(actor->ideal_yaw/45)*45 ); turnaround = anglemod(olddir - 180); deltax = enemy->s.origin[0] - actor->s.origin[0]; deltay = enemy->s.origin[1] - actor->s.origin[1]; if (deltax>10) d[1]= 0; else if (deltax<-10) d[1]= 180; else d[1]= DI_NODIR; if (deltay<-10) d[2]= 270; else if (deltay>10) d[2]= 90; else d[2]= DI_NODIR; // try direct route if (d[1] != DI_NODIR && d[2] != DI_NODIR) { if (d[1] == 0) tdir = d[2] == 90 ? 45 : 315; else tdir = d[2] == 90 ? 135 : 215; if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) return; } // try other directions if ( ((rand()&3) & 1) || abs(deltay)>abs(deltax)) { tdir=d[1]; d[1]=d[2]; d[2]=tdir; } if (d[1]!=DI_NODIR && d[1]!=turnaround && SV_StepDirection(actor, d[1], dist)) return; if (d[2]!=DI_NODIR && d[2]!=turnaround && SV_StepDirection(actor, d[2], dist)) return; /* there is no direct path to the player, so pick another direction */ if (olddir!=DI_NODIR && SV_StepDirection(actor, olddir, dist)) return; if (rand()&1) /*randomly determine direction of search*/ { for (tdir=0 ; tdir<=315 ; tdir += 45) if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) ) return; } else { for (tdir=315 ; tdir >=0 ; tdir -= 45) if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) ) return; } if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) ) return; actor->ideal_yaw = olddir; // can't move // if a bridge was pulled out from underneath a monster, it may not have // a valid standing position at all if (!M_CheckBottom (actor)) SV_FixCheckBottom (actor); }
//FIXME since we need to test end position contents here, can we avoid doing //it again later in catagorize position? qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink) { float dz; vec3_t oldorg, neworg, end; trace_t trace; int i; float stepsize; vec3_t test; int contents; // BEGIN: Xatrix/Ridah/Navigator/14-apr-1998 int mask = MASK_MONSTERSOLID; if (ent->cast_info.aiflags & AI_PLAYERCLIP) mask = MASK_PLAYERSOLID; else if (ent->flags & FL_RESPAWN) // used for moveout command mask = MASK_SOLID; // END: Xatrix/Ridah/Navigator/14-apr-1998 // try the move VectorCopy (ent->s.origin, oldorg); VectorAdd (ent->s.origin, move, neworg); // flying monsters don't step up if ( ent->flags & (FL_SWIM | FL_FLY) ) { // try one move with vertical motion, then one without for (i=0 ; i<2 ; i++) { VectorAdd (ent->s.origin, move, neworg); if (i == 0 && ent->enemy) { if (!ent->goalentity) ent->goalentity = ent->enemy; dz = ent->s.origin[2] - ent->goalentity->s.origin[2]; if (ent->goalentity->client) { if (dz > 40) neworg[2] -= 8; if (!((ent->flags & FL_SWIM) && (ent->waterlevel < 2))) if (dz < 30) neworg[2] += 8; } else { if (dz > 8) neworg[2] -= 8; else if (dz > 0) neworg[2] -= dz; else if (dz < -8) neworg[2] += 8; else neworg[2] += dz; } } // BEGIN: Xatrix/Ridah/Navigator/14-apr-1998 (use modified mask for Grunts) trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, neworg, ent, mask); // END: Xatrix/Ridah/Navigator/14-apr-1998 // fly monsters don't enter water voluntarily if (ent->flags & FL_FLY) { if (!ent->waterlevel) { test[0] = trace.endpos[0]; test[1] = trace.endpos[1]; test[2] = trace.endpos[2] + ent->mins[2] + 1; contents = gi.pointcontents(test); if (contents & MASK_WATER) return false; } } // swim monsters don't exit water voluntarily if (ent->flags & FL_SWIM) { if (ent->waterlevel < 2) { test[0] = trace.endpos[0]; test[1] = trace.endpos[1]; test[2] = trace.endpos[2] + ent->mins[2] + 1; contents = gi.pointcontents(test); if (!(contents & MASK_WATER)) return false; } } if (trace.fraction == 1) { VectorCopy (trace.endpos, ent->s.origin); if (relink) { gi.linkentity (ent); G_TouchTriggers (ent); } return true; } if (!ent->enemy) break; } return false; } // push down from a step height above the wished position if (!(ent->cast_info.aiflags & AI_NOSTEP)) stepsize = STEPSIZE; else stepsize = 1; // BEGIN: Xatrix/Ridah/Navigator/03-apr-1998 if (ent->nav_data.goal_index && ((level.node_data->nodes[ent->nav_data.goal_index-1]->origin[2] - ent->s.origin[2]) > 0)) { stepsize += 8; if (ent->waterlevel > 2) stepsize = 1; } // END: Xatrix/Ridah/Navigator/03-apr-1998 neworg[2] += stepsize; VectorCopy (neworg, end); end[2] -= stepsize*2; trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, mask); // Ridah, tell this ent to avoid us if possible if ((trace.ent && trace.ent->svflags & SVF_MONSTER) && (ent->health > 0)) // Ridah, Fixes life after death bug { extern void AI_GetAvoidDirection( edict_t *self, edict_t *other ); AI_GetAvoidDirection( trace.ent, ent ); ent->cast_info.currentmove = ent->cast_info.move_avoid_walk; } if (trace.allsolid) return false; if (trace.startsolid) { neworg[2] -= stepsize; trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, mask); if (trace.allsolid || trace.startsolid || trace.fraction == 0) { return false; } } // BEGIN: Xatrix/Ridah/Navigator/03-apr-1998 // don't let monsters walk onto other monsters if ((trace.fraction < 1) && (trace.ent->svflags & SVF_MONSTER)) { return false; } // END: Xatrix/Ridah/Navigator/03-apr-1998 // don't go in to lava/slime if (ent->waterlevel < 2) { test[0] = trace.endpos[0]; test[1] = trace.endpos[1]; test[2] = trace.endpos[2] + ent->mins[2] + 16; contents = gi.pointcontents(test); if (contents & (CONTENTS_LAVA|CONTENTS_SLIME)) return false; } if (trace.fraction == 1) { // if monster had the ground pulled out, go ahead and fall if ( ent->flags & FL_PARTIALGROUND ) { VectorAdd (ent->s.origin, move, ent->s.origin); if (relink) { gi.linkentity (ent); G_TouchTriggers (ent); } ent->groundentity = NULL; return true; } // BEGIN: Xatrix/Ridah/Navigator/14-apr-1998 else { float fall_dist=0; // never fall into water VectorCopy(trace.endpos, neworg); VectorCopy(neworg, end); end[2] -= 2048; trace = gi.trace( neworg, ent->mins, ent->maxs, end, ent, mask ); test[0] = trace.endpos[0]; test[1] = trace.endpos[1]; test[2] = trace.endpos[2] + ent->mins[2] + 16; contents = gi.pointcontents(test); if (contents & MASK_WATER) return false; /* // let them fall into water if they should be doing so if ( ent->waterlevel || (ent->count && level.node_data->nodes[ent->count-1]->waterlevel) || (ent->goalentity && ent->goalentity->waterlevel)) { VectorAdd (ent->s.origin, move, ent->s.origin); VectorScale(move, 10, ent->velocity); ent->groundentity = NULL; return true; } */ if ( (ent->nav_data.goal_index && ((fall_dist = level.node_data->nodes[ent->nav_data.goal_index-1]->origin[2] - ent->s.origin[2]) < 0)) || (ent->goalentity && (( fall_dist = ent->goalentity->s.origin[2] - ent->s.origin[2]) < 0))) { // VectorCopy(trace.endpos, neworg); VectorCopy(neworg, end); end[2] += (fall_dist - 48); trace = gi.trace( neworg, ent->mins, ent->maxs, end, ent, mask ); if (trace.fraction < 1) { // start to fall VectorAdd (ent->s.origin, move, ent->s.origin); VectorScale(move, 5, ent->velocity); ent->groundentity = NULL; return true; } } } // END: Xatrix/Ridah/Navigator/23-mar-1998 // walked off an edge return false; } // check point traces down for dangling corners VectorCopy (trace.endpos, ent->s.origin); if (!M_CheckBottom (ent)) { if ( ent->flags & FL_PARTIALGROUND ) { // entity had floor mostly pulled out from underneath it // and is trying to correct if (relink) { gi.linkentity (ent); G_TouchTriggers (ent); } return true; } // Joseph if (!ent->fallerflag) { // Ridah, don't bother checking all corners // VectorCopy (oldorg, ent->s.origin); // return false; } else { vec3_t forward, right, up; int speed = 140; // JOSEPH 7-OCT-98 // Stop any drag sound ent->s.sound = 0; // Object is falling ent->fallingflag = 1; // END JOSEPH // JOSEPH 17-MAY-99 if (!ent->pullingflag) { AngleVectors (move, forward, right, up); VectorScale (move, speed, ent->velocity); VectorMA (ent->velocity, 100, up, ent->velocity); ent->movetype = MOVETYPE_TOSS; } // END JOSEPH // JOSEPH 17-MAY-99 //VectorAdd (ent->s.origin, move, ent->s.origin); // END JOSEPH if (relink) { gi.linkentity (ent); G_TouchTriggers (ent); } ent->groundentity = NULL; return true; } } if ( ent->flags & FL_PARTIALGROUND ) { ent->flags &= ~FL_PARTIALGROUND; } ent->groundentity = trace.ent; ent->groundentity_linkcount = trace.ent->linkcount; // the move is ok if (relink) { gi.linkentity (ent); G_TouchTriggers (ent); } return true; }
void SV_Physics_Step (edict_t *ent) { qboolean wasonground; qboolean hitsound = false; float *vel; float speed, newspeed, control; float friction; edict_t *groundentity; int mask; int retval; vec3_t oldpos; // BEGIN: Xatrix/Ridah vec3_t old_vel; // END: Xatrix/Ridah // Joseph if (ent->fallerflag) { // Fix if sitting off center think_checkedges(ent); } // airborn monsters should always check for ground if (!ent->groundentity) M_CheckGround (ent); groundentity = ent->groundentity; SV_CheckVelocity (ent); if (groundentity) wasonground = true; else wasonground = false; if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2]) SV_AddRotationalFriction (ent); // add gravity except: // flying monsters // swimming monsters who are in the water if (! wasonground) if (!(ent->flags & FL_FLY)) if (!((ent->flags & FL_SWIM) && (ent->waterlevel > 2))) { if (ent->velocity[2] < sv_gravity->value*-0.1) hitsound = true; // Ridah, 1-may-99, disabled this to prevent guys getting stuck in water // if (ent->waterlevel == 0) SV_AddGravity (ent); } /* // friction for flying monsters that have been given vertical velocity if ((ent->flags & FL_FLY) && (ent->velocity[2] != 0)) { speed = fabs(ent->velocity[2]); control = speed < sv_stopspeed ? sv_stopspeed : speed; friction = sv_friction/3; newspeed = speed - (FRAMETIME * control * friction); if (newspeed < 0) newspeed = 0; newspeed /= speed; ent->velocity[2] *= newspeed; } */ // friction for flying monsters that have been given vertical velocity if ((ent->flags & FL_SWIM) && (ent->velocity[2] != 0)) { speed = fabs(ent->velocity[2]); control = speed < sv_stopspeed ? sv_stopspeed : speed; newspeed = speed - (FRAMETIME * control * sv_waterfriction * ent->waterlevel); if (newspeed < 0) newspeed = 0; newspeed /= speed; ent->velocity[2] *= newspeed; } if (ent->velocity[2] || ent->velocity[1] || ent->velocity[0]) { // apply friction // let dead monsters who aren't completely onground slide if ((wasonground) || (ent->flags & (FL_SWIM|FL_FLY))) if (!(ent->health <= 0.0 && !M_CheckBottom(ent))) { vel = ent->velocity; speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]); if (speed) { friction = sv_friction; control = speed < sv_stopspeed ? sv_stopspeed : speed; newspeed = speed - FRAMETIME*control*friction; if (newspeed < 0) newspeed = 0; newspeed /= speed; vel[0] *= newspeed; vel[1] *= newspeed; } } // BEGIN: Xatrix/Ridah // JOSEPH 26-APR-99 if ((ent->svflags & SVF_MONSTER) || (ent->monsterprop)) // END JOSEPH { // if (ent->cast_info.aiflags & AI_PLAYERCLIP) mask = MASK_PLAYERSOLID | CONTENTS_MONSTERCLIP; // else // mask = MASK_MONSTERSOLID; } else mask = MASK_SOLID; VectorCopy (ent->velocity, old_vel); // END: Xatrix/Ridah VectorCopy (ent->s.origin, oldpos ); retval = SV_FlyMove (ent, FRAMETIME, mask); #if 0 // leave this here for now. // Ridah, HACK... sometimes they get stuck, we should debug this properly when we get the time if (!ValidBoxAtLoc( ent->s.origin, ent->mins, ent->maxs, ent, MASK_SOLID )) { // move back to old position and clear velocity int iter=0; VectorCopy (oldpos, ent->s.origin); VectorClear (ent->velocity); // find a good position while (!ValidBoxAtLoc( ent->s.origin, ent->mins, ent->maxs, ent, MASK_SOLID )) { VectorAdd( ent->s.origin, tv((random()-0.5) * 64, (random()-0.5) * 64, (random()-0.5) * 64), ent->s.origin ); if (++iter > 10) break; } // if (iter <= 4) // { // make sure they're on the ground // M_droptofloor( ent ); // } goto exit_vel_check; // get out of here? } #endif // BEGIN: Xatrix/Ridah if (!ent->groundentity || (ent->flags & FL_FLY)) { node_t *land_node; // Ridah, prevent guys getting stuck trying to jump if (VectorDistance( ent->s.origin, oldpos ) < 1 && !ent->groundentity && (ent->last_onground < (level.time - 2))) { ent->velocity[0] = crandom() * 300; ent->velocity[1] = crandom() * 300; if (ent->velocity[2] < -200) ent->velocity[2] = -200; ent->velocity[2] += random() * 350; ent->nav_data.goal_index = 0; ent->last_onground = level.time; } if (ent->velocity[2] > 80 && retval != 20) { // while rising, maintain XY velocity ent->velocity[0] = old_vel[0]; ent->velocity[1] = old_vel[1]; } // see if we've gone passed the landing position if ( !(ent->flags & FL_FLY) && (retval == -1) && (ent->nav_data.goal_index) && (land_node = level.node_data->nodes[ent->nav_data.goal_index-1])) // && (land_node->node_type & NODE_LANDING)) { vec3_t unit_vel, goal_dir, goal_vec; float vel_scale, dist; VectorSubtract( land_node->origin, ent->s.origin, goal_vec ); goal_vec[2] = 0; dist = VectorNormalize2( goal_vec, goal_dir ); if (dist > 16) { VectorCopy( ent->velocity, unit_vel ); unit_vel[2] = 0; vel_scale = VectorNormalize( unit_vel ); if (DotProduct( unit_vel, goal_dir ) < 0.8) { // we've either gone passed, or need some correction vec3_t new_pos; float old_z; if (VectorLength( goal_vec ) < 40) { new_pos[0] = land_node->origin[0]; new_pos[1] = land_node->origin[1]; new_pos[2] = ent->s.origin[2]; if (ValidBoxAtLoc( new_pos, ent->mins, ent->maxs, ent, MASK_PLAYERSOLID | MASK_MONSTERSOLID )) { // move there, it's safe, and clear velocity VectorCopy( new_pos, ent->s.origin ); ent->velocity[0] = ent->velocity[1] = 0; goto exit_vel_check; } } // we need to adjust our velocity if (land_node->origin[2] < (ent->s.origin[2] - 64)) { old_z = ent->velocity[2]; VectorScale( goal_dir, vel_scale, ent->velocity ); ent->velocity[2] = old_z; } } } } if ( (ent->flags & FL_FLY) && ((land_node = level.node_data->nodes[ent->nav_data.goal_index-1]) || ((ent->flags &= ~FL_FLY) && false)) /*&& (land_node->node_type & NODE_LANDING)*/) { // if climbing ladder, and we're reached the landing position, stop // Ridah, 8-jun-99, make sure dog's don't climb ladders if (!ent->gender) { goto abort_climb; } if (ent->s.origin[2] > land_node->origin[2]) { //gi.dprintf( "-> end of climb\n" ); // VectorSubtract( land_node->origin, ent->s.origin, ent->velocity ); AngleVectors( ent->s.angles, ent->velocity, NULL, NULL ); ent->velocity[2] = 0; VectorNormalize( ent->velocity ); VectorScale( ent->velocity, 96, ent->velocity ); ent->velocity[2] = 200; ent->flags &= ~FL_FLY; ent->nav_data.goal_index = 0; // look for a new node ent->nav_data.cache_node = -1; if (ent->cast_info.move_end_climb) ent->cast_info.currentmove = ent->cast_info.move_end_climb; } else { trace_t tr; vec3_t end, goal_vec; VectorSubtract( land_node->origin, ent->s.origin, goal_vec ); ent->velocity[0] = goal_vec[0]; ent->velocity[1] = goal_vec[1]; ent->velocity[2] = 120; // if another character is above us, abort VectorCopy( ent->s.origin, end ); end[2] += 128; tr = gi.trace( ent->s.origin, ent->mins, ent->maxs, end, ent, MASK_PLAYERSOLID | MASK_MONSTERSOLID ); if ((tr.fraction < 1) && (tr.ent->svflags & SVF_MONSTER)) { abort_climb: AngleVectors( ent->s.angles, goal_vec, NULL, NULL ); VectorScale( goal_vec, -64, ent->velocity ); ent->flags &= ~FL_FLY; ent->nav_data.goal_index = 0; if (ent->cast_info.move_end_climb) { ent->cast_info.currentmove = ent->cast_info.move_end_climb; } else if (ent->cast_info.move_jump) { ent->cast_info.currentmove = ent->cast_info.move_jump; } } else if (ent->s.origin[2] > (land_node->origin[2] - 48)) { // we're near the top, stopping climbing anim //gi.dprintf( "near end of climb\n" ); if (ent->cast_info.move_end_climb) ent->cast_info.currentmove = ent->cast_info.move_end_climb; // add some forward momentum AngleVectors( ent->s.angles, goal_vec, NULL, NULL ); VectorMA( ent->velocity, 64, goal_vec, ent->velocity ); } } } } exit_vel_check: // END: Xatrix/Ridah gi.linkentity (ent); G_TouchTriggers (ent); // Note to Ryan: we can't use this because we are playing specific sounds elsewhere /* if (ent->groundentity) if (!wasonground) if (hitsound) // BEGIN: Xatrix/Ridah/Navigator/03-apr-1998 if (!(ent->cast_info.move_run)) // END: Xatrix/Ridah/Navigator/03-apr-1998 gi.sound (ent, 0, gi.soundindex("world/land.wav"), 1, 1, 0); */ } // regular thinking SV_RunThink (ent); }
//FIXME since we need to test end position contents here, can we avoid doing //it again later in catagorize position? bool SV_movestep(edict_t *ent, vec3_t move, bool relink) { float dz; vec3_t oldorg, neworg, end; trace_t trace; int i; float stepsize; vec3_t test; int contents; // try the move VectorCopy(ent->s.origin, oldorg); VectorAdd(ent->s.origin, move, neworg); // flying monsters don't step up if (ent->flags & (FL_SWIM | FL_FLY)) { // try one move with vertical motion, then one without for (i = 0 ; i < 2 ; i++) { VectorAdd(ent->s.origin, move, neworg); if (i == 0 && ent->enemy) { if (!ent->goalentity) ent->goalentity = ent->enemy; dz = ent->s.origin[2] - ent->goalentity->s.origin[2]; if (ent->goalentity->client) { if (dz > 40) neworg[2] -= 8; if (!((ent->flags & FL_SWIM) && (ent->waterlevel < 2))) if (dz < 30) neworg[2] += 8; } else { if (dz > 8) neworg[2] -= 8; else if (dz > 0) neworg[2] -= dz; else if (dz < -8) neworg[2] += 8; else neworg[2] += dz; } } trace = gi.trace(ent->s.origin, ent->mins, ent->maxs, neworg, ent, MASK_MONSTERSOLID); // fly monsters don't enter water voluntarily if (ent->flags & FL_FLY) { if (!ent->waterlevel) { test[0] = trace.endpos[0]; test[1] = trace.endpos[1]; test[2] = trace.endpos[2] + ent->mins[2] + 1; contents = gi.pointcontents(test); if (contents & MASK_WATER) return false; } } // swim monsters don't exit water voluntarily if (ent->flags & FL_SWIM) { if (ent->waterlevel < 2) { test[0] = trace.endpos[0]; test[1] = trace.endpos[1]; test[2] = trace.endpos[2] + ent->mins[2] + 1; contents = gi.pointcontents(test); if (!(contents & MASK_WATER)) return false; } } if (trace.fraction == 1) { VectorCopy(trace.endpos, ent->s.origin); if (relink) { gi.linkentity(ent); G_TouchTriggers(ent); } return true; } if (!ent->enemy) break; } return false; } // push down from a step height above the wished position if (!(ent->monsterinfo.aiflags & AI_NOSTEP)) stepsize = STEPSIZE; else stepsize = 1; neworg[2] += stepsize; VectorCopy(neworg, end); end[2] -= stepsize * 2; trace = gi.trace(neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID); if (trace.allsolid) return false; if (trace.startsolid) { neworg[2] -= stepsize; trace = gi.trace(neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID); if (trace.allsolid || trace.startsolid) return false; } // don't go in to water if (ent->waterlevel == 0) { test[0] = trace.endpos[0]; test[1] = trace.endpos[1]; test[2] = trace.endpos[2] + ent->mins[2] + 1; contents = gi.pointcontents(test); if (contents & MASK_WATER) return false; } if (trace.fraction == 1) { // if monster had the ground pulled out, go ahead and fall if (ent->flags & FL_PARTIALGROUND) { VectorAdd(ent->s.origin, move, ent->s.origin); if (relink) { gi.linkentity(ent); G_TouchTriggers(ent); } ent->groundentity = NULL; return true; } return false; // walked off an edge } // check point traces down for dangling corners VectorCopy(trace.endpos, ent->s.origin); if (!M_CheckBottom(ent)) { if (ent->flags & FL_PARTIALGROUND) { // entity had floor mostly pulled out from underneath it // and is trying to correct if (relink) { gi.linkentity(ent); G_TouchTriggers(ent); } return true; } VectorCopy(oldorg, ent->s.origin); return false; } if (ent->flags & FL_PARTIALGROUND) { ent->flags &= ~FL_PARTIALGROUND; } ent->groundentity = trace.ent; ent->groundentity_linkcount = trace.ent->linkcount; // the move is ok if (relink) { gi.linkentity(ent); G_TouchTriggers(ent); } return true; }
void SV_Physics_Step (edict_t *ent) { bool wasonground; bool hitsound = false; float *vel; float speed, newspeed, control; float friction; edict_t *groundentity; int mask; // airborn monsters should always check for ground if (!ent->groundentity) M_CheckGround (ent); groundentity = ent->groundentity; SV_CheckVelocity (ent); if (groundentity) wasonground = true; else wasonground = false; if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2]) SV_AddRotationalFriction (ent); // add gravity except: // flying monsters // swimming monsters who are in the water if (! wasonground) if (!(ent->flags & FL_FLY)) if (!((ent->flags & FL_SWIM) && (ent->waterlevel > 2))) { if (ent->velocity[2] < level.gravity*-0.1) hitsound = true; if (ent->waterlevel == 0) SV_AddGravity (ent); } // friction for flying monsters that have been given vertical velocity if ((ent->flags & FL_FLY) && (ent->velocity[2] != 0)) { speed = fabs(ent->velocity[2]); control = speed < sv_stopspeed ? sv_stopspeed : speed; friction = sv_friction/3; newspeed = speed - (FRAMETIME * control * friction); if (newspeed < 0) newspeed = 0; newspeed /= speed; ent->velocity[2] *= newspeed; } // friction for flying monsters that have been given vertical velocity if ((ent->flags & FL_SWIM) && (ent->velocity[2] != 0)) { speed = fabs(ent->velocity[2]); control = speed < sv_stopspeed ? sv_stopspeed : speed; newspeed = speed - (FRAMETIME * control * sv_waterfriction * ent->waterlevel); if (newspeed < 0) newspeed = 0; newspeed /= speed; ent->velocity[2] *= newspeed; } if (ent->velocity[2] || ent->velocity[1] || ent->velocity[0]) { // apply friction // let dead monsters who aren't completely onground slide if ((wasonground) || (ent->flags & (FL_SWIM|FL_FLY))) if (!(ent->health <= 0.0 && !M_CheckBottom(ent))) { vel = ent->velocity; speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]); if (speed) { friction = sv_friction; control = speed < sv_stopspeed ? sv_stopspeed : speed; newspeed = speed - FRAMETIME*control*friction; if (newspeed < 0) newspeed = 0; newspeed /= speed; vel[0] *= newspeed; vel[1] *= newspeed; } } if (ent->r.svflags & SVF_MONSTER) mask = MASK_MONSTERSOLID; else mask = MASK_SOLID; SV_FlyMove (ent, FRAMETIME, mask); GClip_LinkEntity (ent); GClip_TouchTriggers (ent); if (ent->groundentity) if (!wasonground) if (hitsound) G_Sound (ent, 0, trap_SoundIndex( S_LAND ), ATTN_NORM); } }
//FIXME since we need to test end position contents here, can we avoid doing //it again later in catagorize position? qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink) { float dz; vec3_t oldorg, neworg, end; trace_t trace; int i; float stepsize; vec3_t test; int contents; edict_t *current_bad; // PGM float minheight; // pmm //====== //PGM current_bad = CheckForBadArea(ent); if(current_bad) { // gi.dprintf("in bad area\n"); ent->bad_area = current_bad; if(ent->enemy && !strcmp(ent->enemy->classname, "tesla")) { // gi.dprintf("%s -->> ", vtos(move)); VectorScale(move, -1, move); // gi.dprintf("%s\n", vtos(move)); } } else if(ent->bad_area) { // if we're no longer in a bad area, get back to business. ent->bad_area = NULL; if(ent->oldenemy)// && ent->bad_area->owner == ent->enemy) { // gi.dprintf("resuming being pissed at %s\n", ent->oldenemy->classname); ent->enemy = ent->oldenemy; ent->goalentity = ent->oldenemy; FoundTarget(ent); return true; } } //PGM //====== // try the move VectorCopy (ent->s.origin, oldorg); VectorAdd (ent->s.origin, move, neworg); // flying monsters don't step up if ( ent->flags & (FL_SWIM | FL_FLY) ) { // try one move with vertical motion, then one without for (i=0 ; i<2 ; i++) { VectorAdd (ent->s.origin, move, neworg); if (i == 0 && ent->enemy) { if (!ent->goalentity) ent->goalentity = ent->enemy; dz = ent->s.origin[2] - ent->goalentity->s.origin[2]; if (ent->goalentity->client) { // we want the carrier to stay a certain distance off the ground, to help prevent him // from shooting his fliers, who spawn in below him // if (!strcmp(ent->classname, "monster_carrier")) minheight = 104; else minheight = 40; // if (dz > 40) if (dz > minheight) // pmm neworg[2] -= 8; if (!((ent->flags & FL_SWIM) && (ent->waterlevel < 2))) if (dz < (minheight - 10)) neworg[2] += 8; } else { if (dz > 8) neworg[2] -= 8; else if (dz > 0) neworg[2] -= dz; else if (dz < -8) neworg[2] += 8; else neworg[2] += dz; } } trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, neworg, ent, MASK_MONSTERSOLID); // fly monsters don't enter water voluntarily if (ent->flags & FL_FLY) { if (!ent->waterlevel) { test[0] = trace.endpos[0]; test[1] = trace.endpos[1]; test[2] = trace.endpos[2] + ent->mins[2] + 1; contents = gi.pointcontents(test); if (contents & MASK_WATER) return false; } } // swim monsters don't exit water voluntarily if (ent->flags & FL_SWIM) { if (ent->waterlevel < 2) { test[0] = trace.endpos[0]; test[1] = trace.endpos[1]; test[2] = trace.endpos[2] + ent->mins[2] + 1; contents = gi.pointcontents(test); if (!(contents & MASK_WATER)) return false; } } // if (trace.fraction == 1) // PMM - changed above to this if ((trace.fraction == 1) && (!trace.allsolid) && (!trace.startsolid)) { VectorCopy (trace.endpos, ent->s.origin); //===== //PGM if(!current_bad && CheckForBadArea(ent)) { // gi.dprintf("Oooh! Bad Area!\n"); VectorCopy (oldorg, ent->s.origin); } else { if (relink) { gi.linkentity (ent); G_TouchTriggers (ent); } return true; } //PGM //===== } if (!ent->enemy) break; } return false; } // push down from a step height above the wished position if (!(ent->monsterinfo.aiflags & AI_NOSTEP)) stepsize = STEPSIZE; else stepsize = 1; //PGM #ifdef ROGUE_GRAVITY // trace from 1 stepsize gravityUp to 2 stepsize gravityDown. VectorMA(neworg, -1 * stepsize, ent->gravityVector, neworg); VectorMA(neworg, 2 * stepsize, ent->gravityVector, end); #else neworg[2] += stepsize; VectorCopy (neworg, end); end[2] -= stepsize*2; #endif //PGM trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID); if (trace.allsolid) return false; if (trace.startsolid) { neworg[2] -= stepsize; trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID); if (trace.allsolid || trace.startsolid) return false; } // don't go in to water if (ent->waterlevel == 0) { //PGM #ifdef ROGUE_GRAVITY test[0] = trace.endpos[0]; test[1] = trace.endpos[1]; if(ent->gravityVector[2] > 0) test[2] = trace.endpos[2] + ent->maxs[2] - 1; else test[2] = trace.endpos[2] + ent->mins[2] + 1; #else test[0] = trace.endpos[0]; test[1] = trace.endpos[1]; test[2] = trace.endpos[2] + ent->mins[2] + 1; #endif //PGM contents = gi.pointcontents(test); if (contents & MASK_WATER) return false; } if (trace.fraction == 1) { // if monster had the ground pulled out, go ahead and fall if ( ent->flags & FL_PARTIALGROUND ) { VectorAdd (ent->s.origin, move, ent->s.origin); if (relink) { gi.linkentity (ent); G_TouchTriggers (ent); } ent->groundentity = NULL; return true; } return false; // walked off an edge } // check point traces down for dangling corners VectorCopy (trace.endpos, ent->s.origin); //PGM new_bad = CheckForBadArea(ent); if(!current_bad && new_bad) { if (new_bad->owner) { if ((g_showlogic) && (g_showlogic->value)) gi.dprintf("Blocked -"); if (!strcmp(new_bad->owner->classname, "tesla")) { if ((g_showlogic) && (g_showlogic->value)) gi.dprintf ("it's a tesla -"); if ((!(ent->enemy)) || (!(ent->enemy->inuse))) { if ((g_showlogic) && (g_showlogic->value)) gi.dprintf ("I don't have a valid enemy!\n"); } else if (!strcmp(ent->enemy->classname, "telsa")) { if ((g_showlogic) && (g_showlogic->value)) gi.dprintf ("but we're already mad at a tesla\n"); } else if ((ent->enemy) && (ent->enemy->client)) { if ((g_showlogic) && (g_showlogic->value)) gi.dprintf ("we have a player enemy -"); if (visible(ent, ent->enemy)) { if ((g_showlogic) && (g_showlogic->value)) gi.dprintf ("we can see him -"); } else { if ((g_showlogic) && (g_showlogic->value)) gi.dprintf ("can't see him, kill the tesla! -"); } } else { if ((g_showlogic) && (g_showlogic->value)) gi.dprintf ("the enemy isn't a player -"); } } } gi.dprintf ("\n"); VectorCopy (oldorg, ent->s.origin); return false; } //PGM if (!M_CheckBottom (ent)) { if ( ent->flags & FL_PARTIALGROUND ) { // entity had floor mostly pulled out from underneath it // and is trying to correct if (relink) { gi.linkentity (ent); G_TouchTriggers (ent); } return true; } VectorCopy (oldorg, ent->s.origin); return false; } if ( ent->flags & FL_PARTIALGROUND ) { ent->flags &= ~FL_PARTIALGROUND; } ent->groundentity = trace.ent; ent->groundentity_linkcount = trace.ent->linkcount; // the move is ok if (relink) { gi.linkentity (ent); G_TouchTriggers (ent); } return true; }
//FIXME since we need to test end position contents here, can we avoid doing //it again later in catagorize position? qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink) { float dz; vec3_t oldorg, neworg, end; trace_t trace;//, tr; int i; float stepsize; vec3_t test; int contents; int jump=0; // try the move VectorCopy (ent->s.origin, oldorg); VectorAdd (ent->s.origin, move, neworg); // flying monsters don't step up if ((ent->flags & (FL_SWIM|FL_FLY)) || (ent->waterlevel > 1)) { // gi.dprintf("trying to swim\n"); // try one move with vertical motion, then one without for (i=0 ; i<2 ; i++) { VectorAdd (ent->s.origin, move, neworg); if (i == 0 && ent->enemy) { if (!ent->goalentity) ent->goalentity = ent->enemy; dz = ent->s.origin[2] - ent->goalentity->s.origin[2]; if (ent->goalentity->client) { if (dz > 40) neworg[2] -= 8; if (!((ent->flags & FL_SWIM) && (ent->waterlevel < 2))) if (dz < 30) neworg[2] += 8; } else { if (dz > 8) neworg[2] -= 8; else if (dz > 0) neworg[2] -= dz; else if (dz < -8) neworg[2] += 8; else neworg[2] += dz; } } trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, neworg, ent, MASK_MONSTERSOLID); // fly monsters don't enter water voluntarily if (ent->flags & FL_FLY) { if (!ent->waterlevel) { test[0] = trace.endpos[0]; test[1] = trace.endpos[1]; test[2] = trace.endpos[2] + ent->mins[2] + 1; contents = gi.pointcontents(test); if (contents & MASK_WATER) return false; } } // swim monsters don't exit water voluntarily if (ent->flags & FL_SWIM) { if (ent->waterlevel < 2) { test[0] = trace.endpos[0]; test[1] = trace.endpos[1]; test[2] = trace.endpos[2] + ent->mins[2] + 1; contents = gi.pointcontents(test); if (!(contents & MASK_WATER)) return false; } } if (trace.fraction == 1) { VectorCopy (trace.endpos, ent->s.origin); if (relink) { gi.linkentity (ent); G_TouchTriggers (ent); } return true; } //gi.dprintf("swim move failed\n"); if (!ent->enemy) break; } return false; } // push down from a step height above the wished position if (!(ent->monsterinfo.aiflags & AI_NOSTEP)) stepsize = STEPSIZE; else stepsize = 1; neworg[2] += stepsize; VectorCopy (neworg, end); end[2] -= stepsize*2; // this trace checks from a position one step above the entity (at top of bbox) // to one step below the entity (bottom of bbox) trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID); // there is an obstruction bigger than a step if (trace.allsolid) //GHz START { // az: Regular monsters: don't jump on invasion mode... if (!G_GetClient(ent) && invasion->value) return false; // try to jump over it if (G_EntIsAlive(trace.ent) || !CanJumpUp(ent, neworg, end)) return false; else { jump = 1; } } //GHz END // not enough room at this height--head of bbox intersects something solid // so push down and just try to walk forward at floor height else if (trace.startsolid) { neworg[2] -= stepsize; trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID); if (trace.allsolid || trace.startsolid) return false; } // don't go in to water if (ent->waterlevel == 0) { test[0] = trace.endpos[0]; test[1] = trace.endpos[1]; test[2] = trace.endpos[2] + ent->mins[2] + 1; contents = gi.pointcontents(test); if (contents & (CONTENTS_LAVA|CONTENTS_SLIME)) return false; } //GHz 5/8/2010 - don't get stuck on steep little ramps if (trace.fraction < 1 && trace.plane.normal[2] < 0.7) // too steep return false; //GHz START // if (CanJumpDown(ent, trace.endpos)) // jump = -1; //GHz END // VectorSubtract(trace.endpos, oldorg, forward); // VectorNormalize(forward); // VectorMA(oldorg, 32, forward, end); // VectorAdd(trace.endpos, move, end); // VectorAdd(end, move, end); if ((trace.fraction == 1) && (jump != 1)) { //gi.dprintf("going to fall\n"); // if monster had the ground pulled out, go ahead and fall // VectorSubtract(trace.endpos, oldorg, forward); // VectorMA(oldorg, 64, forward, end); if (!CanJumpDown(ent, trace.endpos)) { if ( ent->flags & FL_PARTIALGROUND ) { VectorAdd (ent->s.origin, move, ent->s.origin); if (relink) { gi.linkentity (ent); G_TouchTriggers (ent); } ent->groundentity = NULL; return true; } return false; // walked off an edge } else jump = -1; } // check point traces down for dangling corners //GHz START /* // fix for monsters walking thru walls tr = gi.trace(trace.endpos, ent->mins, ent->maxs, trace.endpos, ent, MASK_SOLID); if (tr.contents & MASK_SOLID) return false; */ //GHz END if (jump != 1) VectorCopy (trace.endpos, ent->s.origin); if (!M_CheckBottom (ent)) { //gi.dprintf("partial ground\n"); if (ent->flags & FL_PARTIALGROUND) { // entity had floor mostly pulled out from underneath it // and is trying to correct if (relink) { gi.linkentity (ent); G_TouchTriggers (ent); } return true; } if (CanJumpDown(ent, trace.endpos)) jump = -1; if (!jump) { VectorCopy (oldorg, ent->s.origin); return false; } } else if (jump == -1) jump = 0; /* if (jump) { VectorCopy(oldorg, ent->s.origin); CanJumpDown(ent, trace.endpos, true); VectorCopy(trace.endpos, ent->s.origin); } */ if ( ent->flags & FL_PARTIALGROUND ) { ent->flags &= ~FL_PARTIALGROUND; } ent->groundentity = trace.ent; if (trace.ent) ent->groundentity_linkcount = trace.ent->linkcount; if (jump == -1) { /* gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_DEBUGTRAIL); gi.WritePosition (oldorg); gi.WritePosition (end); gi.multicast (end, MULTICAST_ALL); */ //VectorScale(move, 10, ent->velocity); //ent->velocity[2] = 200; } else if (jump == 1) { ent->velocity[2] = 200; //gi.dprintf("jumped at %d\n",level.framenum); } // the move is ok if (relink) { gi.linkentity (ent); G_TouchTriggers (ent); } //gi.dprintf("moved successfully at %d\n", level.framenum); return true; }
// modified SV_movestep for use with player-controlled monsters qboolean M_Move (edict_t *ent, vec3_t move, qboolean relink) { vec3_t oldorg, neworg, end; trace_t trace;//, tr; float stepsize=STEPSIZE; // try the move VectorCopy (ent->s.origin, oldorg); VectorAdd (ent->s.origin, move, neworg); neworg[2] += stepsize; VectorCopy (neworg, end); end[2] -= stepsize*2; trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID); if (trace.allsolid) { // if we would have collided with a live entity, call its touch function // this prevents player-monsters from being invulnerable to obstacles if (G_EntIsAlive(trace.ent) && trace.ent->touch) trace.ent->touch(trace.ent, ent, &trace.plane, trace.surface); return false; } if (trace.startsolid) { neworg[2] -= stepsize; trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID); if (trace.allsolid || trace.startsolid) return false; } if (trace.fraction == 1) { // gi.dprintf("going to fall\n"); // if monster had the ground pulled out, go ahead and fall // VectorSubtract(trace.endpos, oldorg, forward); // VectorMA(oldorg, 64, forward, end); if ( ent->flags & FL_PARTIALGROUND ) { VectorAdd (ent->s.origin, move, ent->s.origin); if (relink) { gi.linkentity (ent); G_TouchTriggers (ent); } ent->groundentity = NULL; return true; } } // check point traces down for dangling corners VectorCopy (trace.endpos, ent->s.origin); if (!M_CheckBottom (ent)) { if (ent->flags & FL_PARTIALGROUND) { // entity had floor mostly pulled out from underneath it // and is trying to correct if (relink) { gi.linkentity (ent); G_TouchTriggers (ent); } return true; } } if (ent->flags & FL_PARTIALGROUND) ent->flags &= ~FL_PARTIALGROUND; ent->groundentity = trace.ent; if (trace.ent) ent->groundentity_linkcount = trace.ent->linkcount; // the move is ok if (relink) { gi.linkentity (ent); G_TouchTriggers (ent); } return true; }
//FIXME since we need to test end position contents here, can we avoid doing //it again later in catagorize position? qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink) { float dz; vec3_t oldorg, neworg, end; trace_t trace; int i; float stepsize; float jumpheight; vec3_t test; int contents; qboolean canjump; float d1, d2; int jump; // 1=jump up, -1=jump down vec3_t forward, up; vec3_t dir; vec_t dist; vec_t g1, g2; edict_t *grenade; edict_t *target; // try the move VectorCopy (ent->s.origin, oldorg); VectorAdd (ent->s.origin, move, neworg); AngleVectors(ent->s.angles,forward,NULL,up); if(ent->enemy) target = ent->enemy; else if(ent->movetarget) target = ent->movetarget; else target = NULL; // flying monsters don't step up if ( ent->flags & (FL_SWIM | FL_FLY) ) { // try one move with vertical motion, then one without for (i=0 ; i<2 ; i++) { VectorAdd (ent->s.origin, move, neworg); if (i == 0 && ent->enemy) { if (!ent->goalentity) ent->goalentity = ent->enemy; dz = ent->s.origin[2] - ent->goalentity->s.origin[2]; if (ent->goalentity->client) { if (dz > 40) neworg[2] -= 8; if (!((ent->flags & FL_SWIM) && (ent->waterlevel < 2))) if (dz < 30) neworg[2] += 8; } else { if (dz > 8) neworg[2] -= 8; else if (dz > 0) neworg[2] -= dz; else if (dz < -8) neworg[2] += 8; else neworg[2] += dz; } } trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, neworg, ent, MASK_MONSTERSOLID); // fly monsters don't enter water voluntarily if (ent->flags & FL_FLY) { if (!ent->waterlevel) { test[0] = trace.endpos[0]; test[1] = trace.endpos[1]; test[2] = trace.endpos[2] + ent->mins[2] + 1; contents = gi.pointcontents(test); if (contents & MASK_WATER) return false; } } // swim monsters don't exit water voluntarily if (ent->flags & FL_SWIM) { if (ent->waterlevel < 2) { test[0] = trace.endpos[0]; test[1] = trace.endpos[1]; test[2] = trace.endpos[2] + ent->mins[2] + 1; contents = gi.pointcontents(test); if (!(contents & MASK_WATER)) return false; } } if (trace.fraction == 1) { VectorCopy (trace.endpos, ent->s.origin); if (relink) { gi.linkentity (ent); G_TouchTriggers (ent); } return true; } if (!ent->enemy) break; } return false; } // push down from a step height above the wished position if (!(ent->monsterinfo.aiflags & AI_NOSTEP)) stepsize = STEPSIZE; else stepsize = 1; neworg[2] += stepsize; VectorCopy (neworg, end); end[2] -= stepsize*2; trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID); // Determine whether monster is capable of and/or should jump jump = 0; if((ent->monsterinfo.jump) && !(ent->monsterinfo.aiflags & AI_DUCKED)) { // Don't jump if path is blocked by monster or player. Otherwise, // monster might attempt to jump OVER the monster/player, which // ends up looking a bit goofy. Also don't jump if the monster's // movement isn't deliberate (target=NULL) if(trace.ent && (trace.ent->client || (trace.ent->svflags & SVF_MONSTER))) canjump = false; else if(target) { // Never jump unless it places monster closer to his goal vec3_t dir; VectorSubtract(target->s.origin, oldorg, dir); d1 = VectorLength(dir); VectorSubtract(target->s.origin, trace.endpos, dir); d2 = VectorLength(dir); if(d2 < d1) canjump = true; else canjump = false; } else canjump = false; } else canjump = false; if (trace.allsolid) { if(canjump && (ent->monsterinfo.jumpup > 0)) { neworg[2] += ent->monsterinfo.jumpup - stepsize; trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID); if (!trace.allsolid && !trace.startsolid && trace.fraction > 0 && (trace.plane.normal[2] > 0.9)) { if(!trace.ent || (!trace.ent->client && !(trace.ent->svflags & SVF_MONSTER) && !(trace.ent->svflags & SVF_DEADMONSTER))) { // Good plane to jump on. Make sure monster is more or less facing // the obstacle to avoid cutting-corners jumps trace_t tr; vec3_t p2; VectorMA(ent->s.origin,1024,forward,p2); tr = gi.trace(ent->s.origin,ent->mins,ent->maxs,p2,ent,MASK_MONSTERSOLID); if(DotProduct(tr.plane.normal,forward) < -0.95) { jump = 1; jumpheight = trace.endpos[2] - ent->s.origin[2]; } else return false; } } else return false; } else return false; } if (trace.startsolid) { neworg[2] -= stepsize; trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID); if (trace.allsolid || trace.startsolid) return false; } // don't go in to water // Lazarus: misc_actors don't go swimming, but wading is fine if (ent->monsterinfo.aiflags & AI_ACTOR) { // First check for lava/slime under feet - but only if we're not already in // a liquid test[0] = trace.endpos[0]; test[1] = trace.endpos[1]; if (ent->waterlevel == 0) { test[2] = trace.endpos[2] + ent->mins[2] + 1; contents = gi.pointcontents(test); if (contents & (CONTENTS_LAVA | CONTENTS_SLIME)) return false; } test[2] = trace.endpos[2] + ent->viewheight - 1; contents = gi.pointcontents(test); if (contents & MASK_WATER) return false; } else if (ent->waterlevel == 0) { test[0] = trace.endpos[0]; test[1] = trace.endpos[1]; test[2] = trace.endpos[2] + ent->mins[2] + 1; contents = gi.pointcontents(test); if (contents & MASK_WATER) return false; } // Lazarus: Don't intentionally move closer to a grenade, // but don't perform this check if we're already evading some // other problem (maybe even this grenade) if(!(ent->monsterinfo.aiflags & AI_CHASE_THING)) { grenade = NULL; while( (grenade=findradius(grenade,neworg,128)) != NULL) { if(!grenade->inuse) continue; if(!grenade->classname) continue; if(!Q_stricmp(grenade->classname,"grenade") || !Q_stricmp(grenade->classname,"hgrenade")) { VectorSubtract(grenade->s.origin,oldorg,dir); g1 = VectorLength(dir); VectorSubtract(grenade->s.origin,neworg,dir); g2 = VectorLength(dir); if(g2 < g1) return false; } } } // Lazarus: Don't intentionally walk into lasers. dist = VectorLength(move); if(dist > 0.) { edict_t *e; trace_t laser_trace; vec_t delta; vec3_t laser_mins, laser_maxs; vec3_t laser_start, laser_end; vec3_t monster_mins, monster_maxs; for(i=game.maxclients+1; i<globals.num_edicts; i++) { e = &g_edicts[i]; if(!e->inuse) continue; if(!e->classname) continue; if(Q_stricmp(e->classname,"target_laser")) continue; if(e->svflags & SVF_NOCLIENT) continue; if( (e->style == 2) || (e->style == 3)) continue; if(!gi.inPVS(ent->s.origin,e->s.origin)) continue; // Check to see if monster is ALREADY in the path of this laser. // If so, allow the move so he can get out. VectorMA(e->s.origin,2048,e->movedir,laser_end); laser_trace = gi.trace(e->s.origin,NULL,NULL,laser_end,NULL,CONTENTS_SOLID|CONTENTS_MONSTER); if(laser_trace.ent == ent) continue; VectorCopy(laser_trace.endpos,laser_end); laser_mins[0] = min(e->s.origin[0],laser_end[0]); laser_mins[1] = min(e->s.origin[1],laser_end[1]); laser_mins[2] = min(e->s.origin[2],laser_end[2]); laser_maxs[0] = max(e->s.origin[0],laser_end[0]); laser_maxs[1] = max(e->s.origin[1],laser_end[1]); laser_maxs[2] = max(e->s.origin[2],laser_end[2]); monster_mins[0] = min(oldorg[0],trace.endpos[0]) + ent->mins[0]; monster_mins[1] = min(oldorg[1],trace.endpos[1]) + ent->mins[1]; monster_mins[2] = min(oldorg[2],trace.endpos[2]) + ent->mins[2]; monster_maxs[0] = max(oldorg[0],trace.endpos[0]) + ent->maxs[0]; monster_maxs[1] = max(oldorg[1],trace.endpos[1]) + ent->maxs[1]; monster_maxs[2] = max(oldorg[2],trace.endpos[2]) + ent->maxs[2]; if( monster_maxs[0] < laser_mins[0] ) continue; if( monster_maxs[1] < laser_mins[1] ) continue; if( monster_maxs[2] < laser_mins[2] ) continue; if( monster_mins[0] > laser_maxs[0] ) continue; if( monster_mins[1] > laser_maxs[1] ) continue; if( monster_mins[2] > laser_maxs[2] ) continue; // If we arrive here, some part of the bounding box surrounding // monster's total movement intersects laser bounding box. // If laser is parallel to x, y, or z, we definitely // know this move will put monster in path of laser if ( (e->movedir[0] == 1.) || (e->movedir[1] == 1.) || (e->movedir[2] == 1.)) return false; // Shift psuedo laser towards monster's current position up to // the total distance he's proposing moving. delta = min(16,dist); VectorNormalize2(move,dir); while(delta < dist+15.875) { if(delta > dist) delta = dist; VectorMA(e->s.origin, -delta,dir,laser_start); VectorMA(e->s.old_origin,-delta,dir,laser_end); laser_trace = gi.trace(laser_start,NULL,NULL,laser_end,world,CONTENTS_SOLID|CONTENTS_MONSTER); if(laser_trace.ent == ent) return false; delta += 16; } } } if ((trace.fraction == 1) && !jump && canjump && (ent->monsterinfo.jumpdn > 0)) { end[2] = oldorg[2] + move[2] - ent->monsterinfo.jumpdn; trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID | MASK_WATER); if(trace.fraction < 1 && (trace.plane.normal[2] > 0.9) && (trace.contents & MASK_SOLID) && (neworg[2] - 16 > trace.endpos[2])) { if(!trace.ent || (!trace.ent->client && !(trace.ent->svflags & SVF_MONSTER) && !(trace.ent->svflags & SVF_DEADMONSTER))) jump = -1; } } if ((trace.fraction == 1) && !jump) { // if monster had the ground pulled out, go ahead and fall if ( ent->flags & FL_PARTIALGROUND ) { VectorAdd (ent->s.origin, move, ent->s.origin); if (relink) { gi.linkentity (ent); G_TouchTriggers (ent); } ent->groundentity = NULL; return true; } return false; // walked off an edge } // check point traces down for dangling corners VectorCopy (trace.endpos, ent->s.origin); if(!jump) { qboolean skip = false; // if monster CAN jump down, and a position just a bit forward would be // a good jump-down spot, allow (briefly) !M_CheckBottom if (canjump && target && (target->s.origin[2] < ent->s.origin[2]) && (ent->monsterinfo.jumpdn > 0)) { vec3_t p1, p2; trace_t tr; VectorMA(oldorg,48,forward,p1); tr = gi.trace(ent->s.origin, ent->mins, ent->maxs, p1, ent, MASK_MONSTERSOLID); if(tr.fraction == 1) { p2[0] = p1[0]; p2[1] = p1[1]; p2[2] = p1[2] - ent->monsterinfo.jumpdn; tr = gi.trace(p1,ent->mins,ent->maxs,p2,ent,MASK_MONSTERSOLID | MASK_WATER); if(tr.fraction < 1 && (tr.plane.normal[2] > 0.9) && (tr.contents & MASK_SOLID) && (p1[2] - 16 > tr.endpos[2])) { if(!tr.ent || (!tr.ent->client && !(tr.ent->svflags & SVF_MONSTER) && !(tr.ent->svflags & SVF_DEADMONSTER))) { VectorSubtract(target->s.origin, tr.endpos, dir); d2 = VectorLength(dir); if(d2 < d1) skip = true; } } } } if (!skip) { if (!M_CheckBottom (ent)) { if ( ent->flags & FL_PARTIALGROUND ) { // entity had floor mostly pulled out from underneath it // and is trying to correct if (relink) { gi.linkentity (ent); G_TouchTriggers (ent); } return true; } VectorCopy (oldorg, ent->s.origin); return false; } } } if ( ent->flags & FL_PARTIALGROUND ) { ent->flags &= ~FL_PARTIALGROUND; } ent->groundentity = trace.ent; if(trace.ent) ent->groundentity_linkcount = trace.ent->linkcount; // the move is ok if(jump) { VectorScale(move, 10, ent->velocity); if(jump > 0) { ent->monsterinfo.jump(ent); ent->velocity[2] = 2.5*jumpheight + 80; } else { ent->velocity[2] = max(ent->velocity[2],100); if(oldorg[2] - ent->s.origin[2] > 48) ent->s.origin[2] = oldorg[2] + ent->velocity[2]*FRAMETIME; } if(relink) { gi.linkentity (ent); G_TouchTriggers (ent); } } else if (relink) { gi.linkentity (ent); G_TouchTriggers (ent); } return true; }
//FIXME since we need to test end position contents here, can we avoid doing //it again later in catagorize position? qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink) { float dz; vec3_t oldorg, neworg, end; trace_t trace; int i; float stepsize; vec3_t test; int contents; edict_t *current_bad = NULL; // PGM float minheight; // pmm //====== //PGM // PMM - who cares about bad areas if you're dead? if (ent->health > 0) { current_bad = CheckForBadArea(ent); if(current_bad) { ent->bad_area = current_bad; if(ent->enemy && !strcmp(ent->enemy->classname, "tesla")) { // if the tesla is in front of us, back up... if (IsBadAhead (ent, current_bad, move)) VectorScale(move, -1, move); } } else if(ent->bad_area) { // if we're no longer in a bad area, get back to business. ent->bad_area = NULL; if(ent->oldenemy)// && ent->bad_area->owner == ent->enemy) { ent->enemy = ent->oldenemy; ent->goalentity = ent->oldenemy; FoundTarget(ent); return true; } } } //PGM //====== // try the move VectorCopy (ent->s.origin, oldorg); VectorAdd (ent->s.origin, move, neworg); // flying monsters don't step up if ( ent->flags & (FL_SWIM | FL_FLY) ) { // try one move with vertical motion, then one without for (i=0 ; i<2 ; i++) { VectorAdd (ent->s.origin, move, neworg); if (i == 0 && ent->enemy) { if (!ent->goalentity) ent->goalentity = ent->enemy; dz = ent->s.origin[2] - ent->goalentity->s.origin[2]; if (ent->goalentity->client) { // we want the carrier to stay a certain distance off the ground, to help prevent him // from shooting his fliers, who spawn in below him // if (!strcmp(ent->classname, "monster_carrier")) minheight = 104; else minheight = 40; if (dz > minheight) // pmm neworg[2] -= 8; if (!((ent->flags & FL_SWIM) && (ent->waterlevel < 2))) if (dz < (minheight - 10)) neworg[2] += 8; } else { if (dz > 8) neworg[2] -= 8; else if (dz > 0) neworg[2] -= dz; else if (dz < -8) neworg[2] += 8; else neworg[2] += dz; } } trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, neworg, ent, MASK_MONSTERSOLID); // fly monsters don't enter water voluntarily if (ent->flags & FL_FLY) { if (!ent->waterlevel) { test[0] = trace.endpos[0]; test[1] = trace.endpos[1]; test[2] = trace.endpos[2] + ent->mins[2] + 1; contents = gi.pointcontents(test); if (contents & MASK_WATER) return false; } } // swim monsters don't exit water voluntarily if (ent->flags & FL_SWIM) { if (ent->waterlevel < 2) { test[0] = trace.endpos[0]; test[1] = trace.endpos[1]; test[2] = trace.endpos[2] + ent->mins[2] + 1; contents = gi.pointcontents(test); if (!(contents & MASK_WATER)) return false; } } // PMM - changed above to this if ((trace.fraction == 1) && (!trace.allsolid) && (!trace.startsolid)) { VectorCopy (trace.endpos, ent->s.origin); //===== //PGM if(!current_bad && CheckForBadArea(ent)) { VectorCopy (oldorg, ent->s.origin); } else { if (relink) { gi.linkentity (ent); G_TouchTriggers (ent); } return true; } //PGM //===== } if (!ent->enemy) break; } return false; } // push down from a step height above the wished position if (!(ent->monsterinfo.aiflags & AI_NOSTEP)) stepsize = STEPSIZE; else stepsize = 1; //PGM // trace from 1 stepsize gravityUp to 2 stepsize gravityDown. VectorMA(neworg, -1 * stepsize, ent->gravityVector, neworg); VectorMA(neworg, 2 * stepsize, ent->gravityVector, end); //PGM trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID); if (trace.allsolid) return false; if (trace.startsolid) { neworg[2] -= stepsize; trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID); if (trace.allsolid || trace.startsolid) return false; } // don't go in to water if (ent->waterlevel == 0) { //PGM test[0] = trace.endpos[0]; test[1] = trace.endpos[1]; if(ent->gravityVector[2] > 0) test[2] = trace.endpos[2] + ent->maxs[2] - 1; else test[2] = trace.endpos[2] + ent->mins[2] + 1; //PGM contents = gi.pointcontents(test); if (contents & MASK_WATER) return false; } if (trace.fraction == 1) { // if monster had the ground pulled out, go ahead and fall if ( ent->flags & FL_PARTIALGROUND ) { VectorAdd (ent->s.origin, move, ent->s.origin); if (relink) { gi.linkentity (ent); G_TouchTriggers (ent); } ent->groundentity = NULL; return true; } return false; // walked off an edge } // check point traces down for dangling corners VectorCopy (trace.endpos, ent->s.origin); //PGM // PMM - don't bother with bad areas if we're dead if (ent->health > 0) { // use AI_BLOCKED to tell the calling layer that we're now mad at a tesla new_bad = CheckForBadArea(ent); if(!current_bad && new_bad) { if (new_bad->owner) { if (!strcmp(new_bad->owner->classname, "tesla")) { if ((!(ent->enemy)) || (!(ent->enemy->inuse))) { TargetTesla (ent, new_bad->owner); ent->monsterinfo.aiflags |= AI_BLOCKED; } else if (!strcmp(ent->enemy->classname, "telsa")) { } else if ((ent->enemy) && (ent->enemy->client)) { if (visible(ent, ent->enemy)) { } else { TargetTesla (ent, new_bad->owner); ent->monsterinfo.aiflags |= AI_BLOCKED; } } else { TargetTesla (ent, new_bad->owner); ent->monsterinfo.aiflags |= AI_BLOCKED; } } } VectorCopy (oldorg, ent->s.origin); return false; } } //PGM if (!M_CheckBottom (ent)) { if ( ent->flags & FL_PARTIALGROUND ) { // entity had floor mostly pulled out from underneath it // and is trying to correct if (relink) { gi.linkentity (ent); G_TouchTriggers (ent); } return true; } VectorCopy (oldorg, ent->s.origin); return false; } if ( ent->flags & FL_PARTIALGROUND ) { ent->flags &= ~FL_PARTIALGROUND; } ent->groundentity = trace.ent; ent->groundentity_linkcount = trace.ent->linkcount; if (relink) { gi.linkentity (ent); G_TouchTriggers (ent); } return true; }
void SV_Physics_Step (edict_t *ent) { qboolean wasonground; qboolean hitsound = false; float *vel; float speed, newspeed, control; float friction; edict_t *groundentity; int mask; // vec3_t dir; // airborn monsters should always check for ground // if (!ent->groundentity) M_CheckGround (ent); groundentity = ent->groundentity; SV_CheckVelocity (ent); if (groundentity) wasonground = true; else wasonground = false; // if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2]) // SV_AddRotationalFriction (ent); // add gravity except: // flying monsters // swimming monsters who are in the water if (! wasonground) if (!(ent->flags & FL_FLY)) if (!((ent->flags & FL_SWIM) && (ent->waterlevel > 2))) { if (ent->velocity[2] < sv_gravity->value*-0.1) hitsound = true; if (ent->waterlevel == 0) SV_AddGravity (ent); } // friction for flying monsters that have been given vertical velocity if ((ent->flags & FL_FLY) && (ent->velocity[2] != 0)) { //gi.bprintf(PRINT_HIGH,"FLY!\n"); speed = fabs(ent->velocity[2]); control = speed < sv_stopspeed ? sv_stopspeed : speed; friction = sv_friction/3; newspeed = speed - (FRAMETIME * control * friction); if (newspeed < 0) newspeed = 0; newspeed /= speed; ent->velocity[2] *= newspeed; } // friction for flying monsters that have been given vertical velocity if ((ent->flags & FL_SWIM) && (ent->velocity[2] != 0)) { //gi.bprintf(PRINT_HIGH,"SWIM!\n"); //K03 Begin float water_friction; //K03 End speed = fabs(ent->velocity[2]); control = speed < sv_stopspeed ? sv_stopspeed : speed; //K03 Begin water_friction=(FRAMETIME * control * sv_waterfriction * ent->waterlevel); //newspeed = speed - (FRAMETIME * control * sv_waterfriction * ent->waterlevel); if ((ent->myskills.abilities[SUPER_SPEED].current_level < 1) || (ent->myskills.abilities[SUPER_SPEED].disable)) newspeed = speed; else newspeed = speed - water_friction; //K03 End if (newspeed < 0) newspeed = 0; newspeed /= speed; ent->velocity[2] *= newspeed; } if (ent->velocity[2] || ent->velocity[1] || ent->velocity[0]) { // apply friction // let dead monsters who aren't completely onground slide if ((wasonground) || (ent->flags & (FL_SWIM|FL_FLY))) if (!(ent->health <= 0.0 && !M_CheckBottom(ent))) { //K03 Begin float water_friction; //K03 End vel = ent->velocity; speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]); if (speed) { friction = sv_friction; control = speed < sv_stopspeed ? sv_stopspeed : speed; newspeed = speed - FRAMETIME*control*friction; //K03 Begin water_friction=FRAMETIME*control*friction; //newspeed = speed - FRAMETIME*control*friction; if ( ((ent->myskills.abilities[SUPER_SPEED].current_level < 1) || (ent->myskills.abilities[SUPER_SPEED].disable)) && !(ent->flags & FL_SWIM)) newspeed = speed; else newspeed = speed - water_friction; //K03 End if (newspeed < 0) newspeed = 0; newspeed /= speed; vel[0] *= newspeed; vel[1] *= newspeed; } } if (ent->svflags & SVF_MONSTER) { if(!deathmatch->value) mask = MASK_MONSTERSOLID; else mask = MASK_BOTSOLIDX;//MASK_PLAYERSOLID; } else mask = MASK_SOLID; //FIXME: warning - SV_FlyMove() can cause an entity to be freed SV_FlyMove (ent, FRAMETIME, mask); gi.linkentity (ent); // G_TouchTriggers (ent); } else V_TouchSolids(ent); // regular thinking SV_RunThink (ent); }
void SV_Physics_Step (edict_t *ent) { qboolean wasonground; qboolean hitsound = false; float *vel; float speed, newspeed, control; float friction; edict_t *groundentity; int mask; if (!ent) { return; } /* airborn monsters should always check for ground */ if (!ent->groundentity) { M_CheckGround(ent); } groundentity = ent->groundentity; SV_CheckVelocity(ent); if (groundentity) { wasonground = true; } else { wasonground = false; } if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2]) { SV_AddRotationalFriction(ent); } /* add gravity except: - flying monsters - swimming monsters who are in the water */ if (!wasonground) { if (!(ent->flags & FL_FLY)) { if (!((ent->flags & FL_SWIM) && (ent->waterlevel > 2))) { if (ent->velocity[2] < sv_gravity->value * -0.1) { hitsound = true; } if (ent->waterlevel == 0) { SV_AddGravity(ent); } } } } /* friction for flying monsters that have been given vertical velocity */ if ((ent->flags & FL_FLY) && (ent->velocity[2] != 0)) { speed = fabs(ent->velocity[2]); control = speed < sv_stopspeed ? sv_stopspeed : speed; friction = sv_friction / 3; newspeed = speed - (FRAMETIME * control * friction); if (newspeed < 0) { newspeed = 0; } newspeed /= speed; ent->velocity[2] *= newspeed; } /* friction for flying monsters that have been given vertical velocity */ if ((ent->flags & FL_SWIM) && (ent->velocity[2] != 0)) { speed = fabs(ent->velocity[2]); control = speed < sv_stopspeed ? sv_stopspeed : speed; newspeed = speed - (FRAMETIME * control * sv_waterfriction * ent->waterlevel); if (newspeed < 0) { newspeed = 0; } newspeed /= speed; ent->velocity[2] *= newspeed; } if (ent->velocity[2] || ent->velocity[1] || ent->velocity[0]) { /* let dead monsters who aren't completely onground slide */ if ((wasonground) || (ent->flags & (FL_SWIM | FL_FLY))) { if (!((ent->health <= 0.0) && !M_CheckBottom(ent))) { vel = ent->velocity; speed = sqrt(vel[0] * vel[0] + vel[1] * vel[1]); if (speed) { friction = sv_friction; control = speed < sv_stopspeed ? sv_stopspeed : speed; newspeed = speed - FRAMETIME * control * friction; if (newspeed < 0) { newspeed = 0; } newspeed /= speed; vel[0] *= newspeed; vel[1] *= newspeed; } } } if (ent->svflags & SVF_MONSTER) { mask = MASK_MONSTERSOLID; } else { mask = MASK_SOLID; } SV_FlyMove(ent, FRAMETIME, mask); gi.linkentity(ent); G_TouchTriggers(ent); if (!ent->inuse) { return; } if (ent->groundentity) { if (!wasonground) { if (hitsound) { gi.sound(ent, 0, gi.soundindex("world/land.wav"), 1, 1, 0); } } } } /* regular thinking */ SV_RunThink(ent); }
/////////////////////////////////////////////////////////////////////// // Wandering code (based on old ACE movement code) /////////////////////////////////////////////////////////////////////// void ACEMV_Wander(edict_t *self, usercmd_t *ucmd) { vec3_t temp; // Do not move if(self->next_move_time > level.time) return; // Special check for elevators, stand still until the ride comes to a complete stop. if(self->groundentity != NULL && self->groundentity->use == Use_Plat) if(self->groundentity->moveinfo.state == STATE_UP || self->groundentity->moveinfo.state == STATE_DOWN) // only move when platform not { self->velocity[0] = 0; self->velocity[1] = 0; self->velocity[2] = 0; self->next_move_time = level.time + 0.5; return; } // Is there a target to move to if (self->movetarget) ACEMV_MoveToGoal(self,ucmd); //////////////////////////////// // Swimming? //////////////////////////////// VectorCopy(self->s.origin,temp); temp[2]+=24; if(gi.pointcontents (temp) & MASK_WATER) { // If drowning and no node, move up if(self->client->next_drown_time > 0) { ucmd->upmove = 1; self->s.angles[PITCH] = -45; } else ucmd->upmove = 15; ucmd->forwardmove = 300; } else self->client->next_drown_time = 0; // probably shound not be messing with this, but //////////////////////////////// // Lava? //////////////////////////////// temp[2]-=48; if(gi.pointcontents(temp) & (CONTENTS_LAVA|CONTENTS_SLIME)) { // safe_bprintf(PRINT_MEDIUM,"lava jump\n"); self->s.angles[YAW] += random() * 360 - 180; ucmd->forwardmove = 400; ucmd->upmove = 400; return; } if(ACEMV_CheckEyes(self,ucmd)) return; // Check for special movement if we have a normal move (have to test) if(VectorLength(self->velocity) < 37) { if(random() > 0.1 && ACEMV_SpecialMove(self,ucmd)) return; self->s.angles[YAW] += random() * 180 - 90; if(!M_CheckBottom(self) || !self->groundentity) // if there is ground continue otherwise wait for next move ucmd->forwardmove = 400; return; } ucmd->forwardmove = 400; }