//=================== // AI_CategorizePosition // Categorize waterlevel and groundentity/stepping //=================== void AI_CategorizePosition( edict_t *ent ) { bool stepping = AI_IsStep( ent ); ent->was_swim = ent->is_swim; ent->was_step = ent->is_step; ent->is_ladder = AI_IsLadder( ent->s.origin, ent->s.angles, ent->r.mins, ent->r.maxs, ent ); G_CategorizePosition( ent ); if( ent->waterlevel > 2 || ( ent->waterlevel && !stepping ) ) { ent->is_swim = true; ent->is_step = false; return; } ent->is_swim = false; ent->is_step = stepping; }
//========================================== // BOT_DMclass_FireWeapon // Fire if needed //========================================== static bool BOT_DMclass_FireWeapon( edict_t *self, usercmd_t *ucmd ) { #define WFAC_GENERIC_PROJECTILE 300.0 #define WFAC_GENERIC_INSTANT 150.0 float firedelay; vec3_t target; int weapon, i; float wfac; vec3_t fire_origin; trace_t trace; bool continuous_fire = false; firedef_t *firedef = GS_FiredefForPlayerState( &self->r.client->ps, self->r.client->ps.stats[STAT_WEAPON] ); if( !self->enemy ) return false; weapon = self->s.weapon; if( weapon < 0 || weapon >= WEAP_TOTAL ) weapon = 0; if( !firedef ) return false; // Aim to center of the box for( i = 0; i < 3; i++ ) target[i] = self->enemy->s.origin[i] + ( 0.5f * ( self->enemy->r.maxs[i] + self->enemy->r.mins[i] ) ); fire_origin[0] = self->s.origin[0]; fire_origin[1] = self->s.origin[1]; fire_origin[2] = self->s.origin[2] + self->viewheight; if( self->s.weapon == WEAP_LASERGUN || self->s.weapon == WEAP_PLASMAGUN ) continuous_fire = true; if( !continuous_fire && !BOT_DMclass_CheckShot( self, target ) ) return false; // find out our weapon AIM style if( AIWeapons[weapon].aimType == AI_AIMSTYLE_PREDICTION_EXPLOSIVE ) { // in the lowest skill level, don't predict projectiles if( self->ai->pers.skillLevel >= 0.33f ) BOT_DMclass_PredictProjectileShot( self, fire_origin, firedef->speed, target, self->enemy->velocity ); wfac = WFAC_GENERIC_PROJECTILE * 1.3; // aim to the feet when enemy isn't higher if( fire_origin[2] > ( target[2] + ( self->enemy->r.mins[2] * 0.8 ) ) ) { vec3_t checktarget; VectorSet( checktarget, self->enemy->s.origin[0], self->enemy->s.origin[1], self->enemy->s.origin[2] + self->enemy->r.mins[2] + 4 ); G_Trace( &trace, fire_origin, vec3_origin, vec3_origin, checktarget, self, MASK_SHOT ); if( trace.fraction == 1.0f || ( trace.ent > 0 && game.edicts[trace.ent].takedamage ) ) VectorCopy( checktarget, target ); } else if( !AI_IsStep( self->enemy ) ) wfac *= 2.5; // more imprecise for air rockets } else if( AIWeapons[weapon].aimType == AI_AIMSTYLE_PREDICTION ) { if( self->s.weapon == WEAP_PLASMAGUN ) wfac = WFAC_GENERIC_PROJECTILE * 0.5; else wfac = WFAC_GENERIC_PROJECTILE; // in the lowest skill level, don't predict projectiles if( self->ai->pers.skillLevel >= 0.33f ) BOT_DMclass_PredictProjectileShot( self, fire_origin, firedef->speed, target, self->enemy->velocity ); } else if( AIWeapons[weapon].aimType == AI_AIMSTYLE_DROP ) { //jalToDo wfac = WFAC_GENERIC_PROJECTILE; // in the lowest skill level, don't predict projectiles if( self->ai->pers.skillLevel >= 0.33f ) BOT_DMclass_PredictProjectileShot( self, fire_origin, firedef->speed, target, self->enemy->velocity ); } else // AI_AIMSTYLE_INSTANTHIT { if( self->s.weapon == WEAP_ELECTROBOLT ) wfac = WFAC_GENERIC_INSTANT; else if( self->s.weapon == WEAP_LASERGUN ) wfac = WFAC_GENERIC_INSTANT * 1.5; else wfac = WFAC_GENERIC_INSTANT; } wfac = 25 + wfac * ( 1.0f - self->ai->pers.skillLevel ); // look to target VectorSubtract( target, fire_origin, self->ai->move_vector ); if( self->r.client->ps.weaponState == WEAPON_STATE_READY || self->r.client->ps.weaponState == WEAPON_STATE_REFIRE || self->r.client->ps.weaponState == WEAPON_STATE_REFIRESTRONG ) { // in continuous fire weapons don't add delays if( self->s.weapon == WEAP_LASERGUN || self->s.weapon == WEAP_PLASMAGUN ) firedelay = 1.0f; else firedelay = ( 1.0f - self->ai->pers.skillLevel ) - ( random()-0.25f ); if( firedelay > 0.0f ) { if( G_InFront( self, self->enemy ) ) { ucmd->buttons |= BUTTON_ATTACK; // could fire, but wants to? } // mess up angles only in the attacking frames if( self->r.client->ps.weaponState == WEAPON_STATE_READY || self->r.client->ps.weaponState == WEAPON_STATE_REFIRE || self->r.client->ps.weaponState == WEAPON_STATE_REFIRESTRONG ) { if( (self->s.weapon == WEAP_LASERGUN) || (self->s.weapon == WEAP_PLASMAGUN) ) { target[0] += sinf( (float)level.time/100.0) * wfac; target[1] += cosf( (float)level.time/100.0) * wfac; } else { target[0] += ( random()-0.5f ) * wfac; target[1] += ( random()-0.5f ) * wfac; } } } } //update angles VectorSubtract( target, fire_origin, self->ai->move_vector ); AI_ChangeAngle( self ); if( nav.debugMode && bot_showcombat->integer ) G_PrintChasersf( self, "%s: attacking %s\n", self->ai->pers.netname, self->enemy->r.client ? self->enemy->r.client->netname : self->classname ); return true; }