qboolean SandCreature_Move( void ) { qboolean moved = qfalse; //FIXME should ignore doors..? vec3_t dest; VectorCopy( NPCInfo->goalEntity->currentOrigin, dest ); //Sand Creatures look silly using waypoints when they can go straight to the goal if ( SandCreature_CheckAhead( dest ) ) {//use our temp move straight to goal check VectorSubtract( dest, NPC->currentOrigin, NPC->client->ps.moveDir ); NPC->client->ps.speed = VectorNormalize( NPC->client->ps.moveDir ); if ( (ucmd.buttons&BUTTON_WALKING) && NPC->client->ps.speed > NPCInfo->stats.walkSpeed ) { NPC->client->ps.speed = NPCInfo->stats.walkSpeed; } else { if ( NPC->client->ps.speed < NPCInfo->stats.walkSpeed ) { NPC->client->ps.speed = NPCInfo->stats.walkSpeed; } if ( !(ucmd.buttons&BUTTON_WALKING) && NPC->client->ps.speed < NPCInfo->stats.runSpeed ) { NPC->client->ps.speed = NPCInfo->stats.runSpeed; } else if ( NPC->client->ps.speed > NPCInfo->stats.runSpeed ) { NPC->client->ps.speed = NPCInfo->stats.runSpeed; } } moved = qtrue; } else { moved = NPC_MoveToGoal( qtrue ); } if ( moved && NPC->radius ) { vec3_t newPos; float curTurfRange, newTurfRange; curTurfRange = DistanceHorizontal( NPC->currentOrigin, NPC->s.origin ); VectorMA( NPC->currentOrigin, NPC->client->ps.speed/100.0f, NPC->client->ps.moveDir, newPos ); newTurfRange = DistanceHorizontal( newPos, NPC->s.origin ); if ( newTurfRange > NPC->radius && newTurfRange > curTurfRange ) {//would leave our range //stop NPC->client->ps.speed = 0.0f; VectorClear( NPC->client->ps.moveDir ); ucmd.forwardmove = ucmd.rightmove = 0; moved = qfalse; } } return (moved); //often erroneously returns false ??? something wrong with NAV...? }
void RT_Flying_MaintainHeight( void ) { float dif = 0; // Update our angles regardless NPC_UpdateAngles( qtrue, qtrue ); if ( NPC->forcePushTime > level.time ) {//if being pushed, we don't have control over our movement return; } if ( (NPC->client->ps.pm_flags&PMF_TIME_KNOCKBACK) ) {//don't slow down for a bit if ( NPC->client->ps.pm_time > 0 ) { VectorScale( NPC->client->ps.velocity, 0.9f, NPC->client->ps.velocity ); return; } } /* if ( (NPC->client->ps.eFlags&EF_FORCE_GRIPPED) ) { RT_Flying_ApplyFriction( 3.0f ); return; } */ // If we have an enemy, we should try to hover at or a little below enemy eye level if ( NPC->enemy && (!Q3_TaskIDPending( NPC, TID_MOVE_NAV ) || !NPCInfo->goalEntity ) ) { if (TIMER_Done( NPC, "heightChange" )) { TIMER_Set( NPC,"heightChange",Q_irand( 1000, 3000 )); float enemyZHeight = NPC->enemy->currentOrigin[2]; if ( NPC->enemy->client && NPC->enemy->client->ps.groundEntityNum == ENTITYNUM_NONE && (NPC->enemy->client->ps.forcePowersActive&(1<<FP_LEVITATION)) ) {//so we don't go up when they force jump up at us enemyZHeight = NPC->enemy->client->ps.forceJumpZStart; } // Find the height difference dif = (enemyZHeight + Q_flrand( NPC->enemy->maxs[2]/2, NPC->enemy->maxs[2]+8 )) - NPC->currentOrigin[2]; float difFactor = 10.0f; // cap to prevent dramatic height shifts if ( fabs( dif ) > 2*difFactor ) { if ( fabs( dif ) > 20*difFactor ) { dif = ( dif < 0 ? -20*difFactor : 20*difFactor ); } NPC->client->ps.velocity[2] = (NPC->client->ps.velocity[2]+dif)/2; } NPC->client->ps.velocity[2] *= Q_flrand( 0.85f, 1.25f ); } else {//don't get too far away from height of enemy... float enemyZHeight = NPC->enemy->currentOrigin[2]; if ( NPC->enemy->client && NPC->enemy->client->ps.groundEntityNum == ENTITYNUM_NONE && (NPC->enemy->client->ps.forcePowersActive&(1<<FP_LEVITATION)) ) {//so we don't go up when they force jump up at us enemyZHeight = NPC->enemy->client->ps.forceJumpZStart; } dif = NPC->currentOrigin[2] - (enemyZHeight+64); float maxHeight = 200; float hDist = DistanceHorizontal( NPC->enemy->currentOrigin, NPC->currentOrigin ); if ( hDist < 512 ) { maxHeight *= hDist/512; } if ( dif > maxHeight ) { if ( NPC->client->ps.velocity[2] > 0 )//FIXME: or: we can't see him anymore {//slow down if ( NPC->client->ps.velocity[2] ) { NPC->client->ps.velocity[2] *= VELOCITY_DECAY; if ( fabs( NPC->client->ps.velocity[2] ) < 2 ) { NPC->client->ps.velocity[2] = 0; } } } else {//start coming back down NPC->client->ps.velocity[2] -= 4; } } else if ( dif < -200 && NPC->client->ps.velocity[2] < 0 )//we're way below him { if ( NPC->client->ps.velocity[2] < 0 )//FIXME: or: we can't see him anymore {//slow down if ( NPC->client->ps.velocity[2] ) { NPC->client->ps.velocity[2] *= VELOCITY_DECAY; if ( fabs( NPC->client->ps.velocity[2] ) > -2 ) { NPC->client->ps.velocity[2] = 0; } } } else {//start going back up NPC->client->ps.velocity[2] += 4; } } } } else { gentity_t *goal = NULL; if ( NPCInfo->goalEntity ) // Is there a goal? { goal = NPCInfo->goalEntity; } else { goal = NPCInfo->lastGoalEntity; } if ( goal ) { dif = goal->currentOrigin[2] - NPC->currentOrigin[2]; } else if ( VectorCompare( NPC->pos1, vec3_origin ) ) {//have a starting position as a reference point dif = NPC->pos1[2] - NPC->currentOrigin[2]; } if ( fabs( dif ) > 24 ) { ucmd.upmove = ( ucmd.upmove < 0 ? -4 : 4 ); } else { if ( NPC->client->ps.velocity[2] ) { NPC->client->ps.velocity[2] *= VELOCITY_DECAY; if ( fabs( NPC->client->ps.velocity[2] ) < 2 ) { NPC->client->ps.velocity[2] = 0; } } } } // Apply friction RT_Flying_ApplyFriction( 1.0f ); }
//---------------------------------- //replaced with SP version. static void Howler_Combat( void ) { qboolean faced = qfalse; float distance; qboolean advance = qfalse; if ( NPC->client->ps.groundEntityNum == ENTITYNUM_NONE ) {//not on the ground if ( NPC->client->ps.legsAnim == BOTH_JUMP1 || NPC->client->ps.legsAnim == BOTH_INAIR1 ) {//flying through the air with the greatest of ease, etc Howler_TryDamage( 10, qfalse, qfalse ); } } else {//not in air, see if we should attack or advance // If we cannot see our target or we have somewhere to go, then do that if ( !NPC_ClearLOS4( NPC->enemy ) )//|| UpdateGoal( )) { NPCInfo->goalEntity = NPC->enemy; NPCInfo->goalRadius = MAX_DISTANCE; // just get us within combat range if ( NPCInfo->localState == LSTATE_BERZERK ) { NPC_Howler_Move( 3 ); } else { NPC_Howler_Move( 10 ); } NPC_UpdateAngles( qfalse, qtrue ); return; } distance = DistanceHorizontal( NPC->r.currentOrigin, NPC->enemy->r.currentOrigin ); if ( NPC->enemy && NPC->enemy->client && PM_InKnockDown( &NPC->enemy->client->ps ) ) {//get really close to knocked down enemies advance = (qboolean)( distance > MIN_DISTANCE ? qtrue : qfalse ); } else { advance = (qboolean)( distance > MAX_DISTANCE ? qtrue : qfalse );//MIN_DISTANCE } if (( advance || NPCInfo->localState == LSTATE_WAITING ) && TIMER_Done( NPC, "attacking" )) // waiting monsters can't attack { if ( TIMER_Done2( NPC, "takingPain", qtrue )) { NPCInfo->localState = LSTATE_CLEAR; } else if ( TIMER_Done( NPC, "standing" ) ) { faced = Howler_Move( qtrue ); } } else { Howler_Attack( distance, qfalse ); } } if ( !faced ) { if ( //TIMER_Done( NPC, "standing" ) //not just standing there //!advance //not moving TIMER_Done( NPC, "attacking" ) )// not attacking {//not standing around // Sometimes I have problems with facing the enemy I'm attacking, so force the issue so I don't look dumb NPC_FaceEnemy( qtrue ); } else { NPC_UpdateAngles( qfalse, qtrue ); } } }