//MP RULE - ALL PROCESSMOVECOMMANDS FUNCTIONS MUST BE BG-COMPATIBLE!!! //If you really need to violate this rule for SP, then use ifdefs. //By BG-compatible, I mean no use of game-specific data - ONLY use //stuff available in the MP bgEntity (in SP, the bgEntity is #defined //as a gentity, but the MP-compatible access restrictions are based //on the bgEntity structure in the MP codebase) -rww // ProcessMoveCommands the Vehicle. static void ProcessMoveCommands( Vehicle_t *pVeh ) { /************************************************************************************/ /* BEGIN Here is where we move the vehicle (forward or back or whatever). BEGIN */ /************************************************************************************/ //Client sets ucmds and such for speed alterations float speedInc, speedIdleDec, speedIdle, speedIdleAccel, speedMin, speedMax; playerState_t *parentPS; playerState_t *pilotPS = NULL; int curTime; #ifdef _JK2MP parentPS = pVeh->m_pParentEntity->playerState; if (pVeh->m_pPilot) { pilotPS = pVeh->m_pPilot->playerState; } #else parentPS = &pVeh->m_pParentEntity->client->ps; if (pVeh->m_pPilot) { pilotPS = &pVeh->m_pPilot->client->ps; } #endif // If we're flying, make us accelerate at 40% (about half) acceleration rate, and restore the pitch // to origin (straight) position (at 5% increments). if ( pVeh->m_ulFlags & VEH_FLYING ) { speedInc = pVeh->m_pVehicleInfo->acceleration * pVeh->m_fTimeModifier * 0.4f; } #ifdef _JK2MP else if ( !parentPS->m_iVehicleNum ) #else else if ( !pVeh->m_pVehicleInfo->Inhabited( pVeh ) ) #endif {//drifts to a stop speedInc = 0; //pVeh->m_ucmd.forwardmove = 127; } else { speedInc = pVeh->m_pVehicleInfo->acceleration * pVeh->m_fTimeModifier; } speedIdleDec = pVeh->m_pVehicleInfo->decelIdle * pVeh->m_fTimeModifier; #ifndef _JK2MP//SP curTime = level.time; #elif QAGAME//MP GAME curTime = level.time; #elif CGAME//MP CGAME //FIXME: pass in ucmd? Not sure if this is reliable... curTime = pm->cmd.serverTime; #endif if ( (pVeh->m_pPilot /*&& (pilotPS->weapon == WP_NONE || pilotPS->weapon == WP_MELEE )*/ && (pVeh->m_ucmd.buttons & BUTTON_ALT_ATTACK) && pVeh->m_pVehicleInfo->turboSpeed) /*|| (parentPS && parentPS->electrifyTime > curTime && pVeh->m_pVehicleInfo->turboSpeed)*/ //make them go! ) { if ( (parentPS && parentPS->electrifyTime > curTime) || (pVeh->m_pPilot->playerState && (pVeh->m_pPilot->playerState->weapon == WP_MELEE || (pVeh->m_pPilot->playerState->weapon == WP_SABER && BG_SabersOff( pVeh->m_pPilot->playerState ) ))) ) { if ((curTime - pVeh->m_iTurboTime)>pVeh->m_pVehicleInfo->turboRecharge) { pVeh->m_iTurboTime = (curTime + pVeh->m_pVehicleInfo->turboDuration); if (pVeh->m_pVehicleInfo->iTurboStartFX) { int i; for (i=0; (i<MAX_VEHICLE_EXHAUSTS && pVeh->m_iExhaustTag[i]!=-1); i++) { #ifdef QAGAME if (pVeh->m_pParentEntity && pVeh->m_pParentEntity->ghoul2 && pVeh->m_pParentEntity->playerState) { //fine, I'll use a tempent for this, but only because it's played only once at the start of a turbo. vec3_t boltOrg, boltDir; mdxaBone_t boltMatrix; VectorSet(boltDir, 0.0f, pVeh->m_pParentEntity->playerState->viewangles[YAW], 0.0f); trap_G2API_GetBoltMatrix(pVeh->m_pParentEntity->ghoul2, 0, pVeh->m_iExhaustTag[i], &boltMatrix, boltDir, pVeh->m_pParentEntity->playerState->origin, level.time, NULL, pVeh->m_pParentEntity->modelScale); BG_GiveMeVectorFromMatrix(&boltMatrix, ORIGIN, boltOrg); BG_GiveMeVectorFromMatrix(&boltMatrix, ORIGIN, boltDir); G_PlayEffectID(pVeh->m_pVehicleInfo->iTurboStartFX, boltOrg, boltDir); } #endif } } parentPS->speed = pVeh->m_pVehicleInfo->turboSpeed; // Instantly Jump To Turbo Speed } } } // Slide Breaking if (pVeh->m_ulFlags&VEH_SLIDEBREAKING) { if (pVeh->m_ucmd.forwardmove>=0 #ifndef _JK2MP || ((level.time - pVeh->m_pParentEntity->lastMoveTime)>500) #endif ) { pVeh->m_ulFlags &= ~VEH_SLIDEBREAKING; } parentPS->speed = 0; } else if ( (curTime > pVeh->m_iTurboTime) && !(pVeh->m_ulFlags&VEH_FLYING) && pVeh->m_ucmd.forwardmove<0 && fabs(pVeh->m_vOrientation[ROLL])>25.0f) { pVeh->m_ulFlags |= VEH_SLIDEBREAKING; } if ( curTime < pVeh->m_iTurboTime ) { speedMax = pVeh->m_pVehicleInfo->turboSpeed; if (parentPS) { parentPS->eFlags |= EF_JETPACK_ACTIVE; } } else { speedMax = pVeh->m_pVehicleInfo->speedMax; if (parentPS) { parentPS->eFlags &= ~EF_JETPACK_ACTIVE; } } speedIdle = pVeh->m_pVehicleInfo->speedIdle; speedIdleAccel = pVeh->m_pVehicleInfo->accelIdle * pVeh->m_fTimeModifier; speedMin = pVeh->m_pVehicleInfo->speedMin; if ( parentPS->speed || parentPS->groundEntityNum == ENTITYNUM_NONE || pVeh->m_ucmd.forwardmove || pVeh->m_ucmd.upmove > 0 ) { if ( pVeh->m_ucmd.forwardmove > 0 && speedInc ) { parentPS->speed += speedInc; } else if ( pVeh->m_ucmd.forwardmove < 0 ) { if ( parentPS->speed > speedIdle ) { parentPS->speed -= speedInc; } else if ( parentPS->speed > speedMin ) { parentPS->speed -= speedIdleDec; } } // No input, so coast to stop. else if ( parentPS->speed > 0.0f ) { parentPS->speed -= speedIdleDec; if ( parentPS->speed < 0.0f ) { parentPS->speed = 0.0f; } } else if ( parentPS->speed < 0.0f ) { parentPS->speed += speedIdleDec; if ( parentPS->speed > 0.0f ) { parentPS->speed = 0.0f; } } } else { if ( !pVeh->m_pVehicleInfo->strafePerc #ifdef _JK2MP || (0 && pVeh->m_pParentEntity->s.number < MAX_CLIENTS) ) #else || (!g_speederControlScheme->value && !pVeh->m_pParentEntity->s.number) ) #endif {//if in a strafe-capable vehicle, clear strafing unless using alternate control scheme //pVeh->m_ucmd.rightmove = 0; } } if ( parentPS->speed > speedMax ) { parentPS->speed = speedMax; } else if ( parentPS->speed < speedMin ) { parentPS->speed = speedMin; } if (parentPS && parentPS->electrifyTime > curTime) { parentPS->speed *= (pVeh->m_fTimeModifier/60.0f); } /********************************************************************************/ /* END Here is where we move the vehicle (forward or back or whatever). END */ /********************************************************************************/ }
void NPC_BSGrenadier_Attack( void ) { //Don't do anything if we're hurt if ( NPC->painDebounceTime > level.time ) { NPC_UpdateAngles( qtrue, qtrue ); return; } //NPC_CheckEnemy( qtrue, qfalse ); //If we don't have an enemy, just idle if ( NPC_CheckEnemyExt(qfalse) == qfalse )//!NPC->enemy )// { NPC->enemy = NULL; NPC_BSGrenadier_Patrol();//FIXME: or patrol? return; } if ( TIMER_Done( NPC, "flee" ) && NPC_CheckForDanger( NPC_CheckAlertEvents( qtrue, qtrue, -1, qfalse, AEL_DANGER ) ) ) {//going to run NPC_UpdateAngles( qtrue, qtrue ); return; } if ( !NPC->enemy ) {//WTF? somehow we lost our enemy? NPC_BSGrenadier_Patrol();//FIXME: or patrol? return; } enemyLOS3 = enemyCS3 = qfalse; move3 = qtrue; faceEnemy3 = qfalse; shoot3 = qfalse; enemyDist3 = DistanceSquared( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin ); //See if we should switch to melee attack if ( enemyDist3 < 16384 //128 && (!NPC->enemy->client || NPC->enemy->client->ps.weapon != WP_SABER || BG_SabersOff( &NPC->enemy->client->ps ) ) ) {//enemy is close and not using saber if ( NPC->client->ps.weapon == WP_THERMAL ) {//grenadier trace_t trace; trap_Trace ( &trace, NPC->r.currentOrigin, NPC->enemy->r.mins, NPC->enemy->r.maxs, NPC->enemy->r.currentOrigin, NPC->s.number, NPC->enemy->clipmask ); if ( !trace.allsolid && !trace.startsolid && (trace.fraction == 1.0 || trace.entityNum == NPC->enemy->s.number ) ) {//I can get right to him //reset fire-timing variables NPC_ChangeWeapon( WP_STUN_BATON ); if ( !(NPCInfo->scriptFlags&SCF_CHASE_ENEMIES) )//NPCInfo->behaviorState == BS_STAND_AND_SHOOT ) {//FIXME: should we be overriding scriptFlags? NPCInfo->scriptFlags |= SCF_CHASE_ENEMIES;//NPCInfo->behaviorState = BS_HUNT_AND_KILL; } } } } else if ( enemyDist3 > 65536 || (NPC->enemy->client && NPC->enemy->client->ps.weapon == WP_SABER && !NPC->enemy->client->ps.saberHolstered) )//256 {//enemy is far or using saber if ( NPC->client->ps.weapon == WP_STUN_BATON && (NPC->client->ps.stats[STAT_WEAPONS]&(1<<WP_THERMAL)) ) {//fisticuffs, make switch to thermal if have it //reset fire-timing variables NPC_ChangeWeapon( WP_THERMAL ); } } //can we see our target? if ( NPC_ClearLOS4( NPC->enemy ) ) { NPCInfo->enemyLastSeenTime = level.time; enemyLOS3 = qtrue; if ( NPC->client->ps.weapon == WP_STUN_BATON ) { if ( enemyDist3 <= 4096 && InFOV3( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin, NPC->client->ps.viewangles, 90, 45 ) )//within 64 & infront { VectorCopy( NPC->enemy->r.currentOrigin, NPCInfo->enemyLastSeenLocation ); enemyCS3 = qtrue; } } else if ( InFOV3( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin, NPC->client->ps.viewangles, 45, 90 ) ) {//in front of me //can we shoot our target? //FIXME: how accurate/necessary is this check? int hit = NPC_ShotEntity( NPC->enemy, NULL ); gentity_t *hitEnt = &g_entities[hit]; if ( hit == NPC->enemy->s.number || ( hitEnt && hitEnt->client && hitEnt->client->playerTeam == NPC->client->enemyTeam ) ) { float enemyHorzDist; VectorCopy( NPC->enemy->r.currentOrigin, NPCInfo->enemyLastSeenLocation ); enemyHorzDist = DistanceHorizontalSquared( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin ); if ( enemyHorzDist < 1048576 ) {//within 1024 enemyCS3 = qtrue; NPC_AimAdjust( 2 );//adjust aim better longer we have clear shot at enemy } else { NPC_AimAdjust( 1 );//adjust aim better longer we can see enemy } } } } else { NPC_AimAdjust( -1 );//adjust aim worse longer we cannot see enemy } /* else if ( trap_InPVS( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin ) ) { NPCInfo->enemyLastSeenTime = level.time; faceEnemy3 = qtrue; } */ if ( enemyLOS3 ) {//FIXME: no need to face enemy if we're moving to some other goal and he's too far away to shoot? faceEnemy3 = qtrue; } if ( enemyCS3 ) { shoot3 = qtrue; if ( NPC->client->ps.weapon == WP_THERMAL ) {//don't chase and throw move3 = qfalse; } else if ( NPC->client->ps.weapon == WP_STUN_BATON && enemyDist3 < (NPC->r.maxs[0]+NPC->enemy->r.maxs[0]+16)*(NPC->r.maxs[0]+NPC->enemy->r.maxs[0]+16) ) {//close enough move3 = qfalse; } }//this should make him chase enemy when out of range...? //Check for movement to take care of Grenadier_CheckMoveState(); //See if we should override shooting decision with any special considerations Grenadier_CheckFireState(); if ( move3 ) {//move toward goal if ( NPCInfo->goalEntity )//&& ( NPCInfo->goalEntity != NPC->enemy || enemyDist3 > 10000 ) )//100 squared { move3 = Grenadier_Move(); } else { move3 = qfalse; } } if ( !move3 ) { if ( !TIMER_Done( NPC, "duck" ) ) { ucmd.upmove = -127; } //FIXME: what about leaning? } else {//stop ducking! TIMER_Set( NPC, "duck", -1 ); } if ( !faceEnemy3 ) {//we want to face in the dir we're running if ( move3 ) {//don't run away and shoot NPCInfo->desiredYaw = NPCInfo->lastPathAngles[YAW]; NPCInfo->desiredPitch = 0; shoot3 = qfalse; } NPC_UpdateAngles( qtrue, qtrue ); } else// if ( faceEnemy3 ) {//face the enemy NPC_FaceEnemy(qtrue); } if ( NPCInfo->scriptFlags&SCF_DONT_FIRE ) { shoot3 = qfalse; } //FIXME: don't shoot right away! if ( shoot3 ) {//try to shoot if it's time if ( TIMER_Done( NPC, "attackDelay" ) ) { if( !(NPCInfo->scriptFlags & SCF_FIRE_WEAPON) ) // we've already fired, no need to do it again here { WeaponThink( qtrue ); TIMER_Set( NPC, "attackDelay", NPCInfo->shotTime-level.time ); } } } }