Beispiel #1
0
/*
* GS_CheckAmmoInWeapon
*/
qboolean GS_CheckAmmoInWeapon( player_state_t *playerState, int checkweapon )
{
	firedef_t *firedef = GS_FiredefForPlayerState( playerState, checkweapon );

	if( checkweapon != WEAP_NONE && !playerState->inventory[checkweapon] )
		return qfalse;

	if( !firedef->usage_count || firedef->ammo_id == AMMO_NONE )
		return qtrue;

	return ( playerState->inventory[firedef->ammo_id] >= firedef->usage_count ) ? qtrue : qfalse;
}
Beispiel #2
0
/*
* G_SetClientEffects
*/
static void G_SetClientEffects( edict_t *ent )
{
	gclient_t *client = ent->r.client;

	if( G_IsDead( ent ) || GS_MatchState() >= MATCH_STATE_POSTMATCH )
		return;

	if( client->ps.inventory[POWERUP_QUAD] > 0 )
	{
		ent->s.effects |= EF_QUAD;
		if( client->ps.inventory[POWERUP_QUAD] < 6 )
			ent->s.effects |= EF_EXPIRING_QUAD;
	}

	if( client->ps.inventory[POWERUP_SHELL] > 0 )
	{
		ent->s.effects |= EF_SHELL;
		if( client->ps.inventory[POWERUP_SHELL] < 6 )
			ent->s.effects |= EF_EXPIRING_SHELL;			
	}

	if( client->ps.inventory[POWERUP_REGEN] > 0 )
	{
		ent->s.effects |= EF_REGEN;
		if( client->ps.inventory[POWERUP_REGEN] < 6 )
			ent->s.effects |= EF_EXPIRING_REGEN;			
	}

	if( ent->s.weapon )
	{
		firedef_t *firedef = GS_FiredefForPlayerState( &client->ps, ent->s.weapon );
		if( firedef && firedef->fire_mode == FIRE_MODE_STRONG )
			ent->s.effects |= EF_STRONG_WEAPON;
	}

	if( client->ps.pmove.stats[PM_STAT_STUN] )
		ent->s.effects |= EF_PLAYER_STUNNED;
	else
		ent->s.effects &= ~EF_PLAYER_STUNNED;

	// show cheaters!!!
	if( ent->flags & FL_GODMODE )
		ent->s.effects |= EF_GODMODE;

	// add chatting icon effect
	if( ent->r.client->resp.snap.buttons & BUTTON_BUSYICON )
		ent->s.effects |= EF_BUSYICON;
}
//==========================================
// 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;
}
Beispiel #4
0
/*
* GS_ThinkPlayerWeapon
*/
int GS_ThinkPlayerWeapon( player_state_t *playerState, int buttons, int msecs, int timeDelta )
{
	firedef_t *firedef;
	qboolean refire = qfalse;

	assert( playerState->stats[STAT_PENDING_WEAPON] >= 0 && playerState->stats[STAT_PENDING_WEAPON] < WEAP_TOTAL );

	if( GS_MatchPaused() )
		return playerState->stats[STAT_WEAPON];

	if( playerState->pmove.pm_type != PM_NORMAL )
	{
		playerState->weaponState = WEAPON_STATE_READY;
		playerState->stats[STAT_PENDING_WEAPON] = playerState->stats[STAT_WEAPON] = WEAP_NONE;
		playerState->stats[STAT_WEAPON_TIME] = 0;
		return playerState->stats[STAT_WEAPON];
	}

	if( playerState->pmove.stats[PM_STAT_NOUSERCONTROL] > 0 )
		buttons = 0;

	if( !msecs )
		goto done;

	if( playerState->stats[STAT_WEAPON_TIME] > 0 )
		playerState->stats[STAT_WEAPON_TIME] -= msecs;
	else
		playerState->stats[STAT_WEAPON_TIME] = 0;

	firedef = GS_FiredefForPlayerState( playerState, playerState->stats[STAT_WEAPON] );

	// during cool-down time it can shoot again or go into reload time
	if( playerState->weaponState == WEAPON_STATE_REFIRE || playerState->weaponState == WEAPON_STATE_REFIRESTRONG )
	{
		int last_firemode;

		if( playerState->stats[STAT_WEAPON_TIME] > 0 )
			goto done;

		last_firemode = ( playerState->weaponState == WEAPON_STATE_REFIRESTRONG ) ? FIRE_MODE_STRONG : FIRE_MODE_WEAK;
		if( last_firemode == firedef->fire_mode )
			refire = qtrue;

		playerState->weaponState = WEAPON_STATE_READY;
	}

	// nothing can be done during reload time
	if( playerState->weaponState == WEAPON_STATE_RELOADING )
	{
		if( playerState->stats[STAT_WEAPON_TIME] > 0 )
			goto done;

		playerState->weaponState = WEAPON_STATE_READY;
	}

	if( playerState->weaponState == WEAPON_STATE_NOAMMOCLICK )
	{
		if( playerState->stats[STAT_WEAPON_TIME] > 0 )
			goto done;

		if( playerState->stats[STAT_WEAPON] != playerState->stats[STAT_PENDING_WEAPON] )
			playerState->weaponState = WEAPON_STATE_READY;
	}

	// there is a weapon to be changed
	if( playerState->stats[STAT_WEAPON] != playerState->stats[STAT_PENDING_WEAPON] )
	{
		if( ( playerState->weaponState == WEAPON_STATE_READY ) ||
			( playerState->weaponState == WEAPON_STATE_DROPPING ) ||
			( playerState->weaponState == WEAPON_STATE_ACTIVATING ) )
		{
			if( playerState->weaponState != WEAPON_STATE_DROPPING )
			{
				playerState->weaponState = WEAPON_STATE_DROPPING;
				playerState->stats[STAT_WEAPON_TIME] += firedef->weapondown_time;

				if( firedef->weapondown_time )
					module_PredictedEvent( playerState->POVnum, EV_WEAPONDROP, 0 );
			}
		}
	}

	// do the change
	if( playerState->weaponState == WEAPON_STATE_DROPPING )
	{
		if( playerState->stats[STAT_WEAPON_TIME] > 0 )
			goto done;

		playerState->stats[STAT_WEAPON] = playerState->stats[STAT_PENDING_WEAPON];

		// update the firedef
		firedef = GS_FiredefForPlayerState( playerState, playerState->stats[STAT_WEAPON] );
		playerState->weaponState = WEAPON_STATE_ACTIVATING;
		playerState->stats[STAT_WEAPON_TIME] += firedef->weaponup_time;
		module_PredictedEvent( playerState->POVnum, EV_WEAPONACTIVATE, playerState->stats[STAT_WEAPON] );
	}

	if( playerState->weaponState == WEAPON_STATE_ACTIVATING )
	{
		if( playerState->stats[STAT_WEAPON_TIME] > 0 )
			goto done;

		playerState->weaponState = WEAPON_STATE_READY;
	}

	if( ( playerState->weaponState == WEAPON_STATE_READY ) || ( playerState->weaponState == WEAPON_STATE_NOAMMOCLICK ) )
	{
		if( playerState->stats[STAT_WEAPON_TIME] > 0 )
			goto done;

		if( !GS_ShootingDisabled() )
		{
			if( buttons & BUTTON_ATTACK )
			{
				if( GS_CheckAmmoInWeapon( playerState, playerState->stats[STAT_WEAPON] ) )
				{
					playerState->weaponState = WEAPON_STATE_FIRING;
				}
				else
				{
					// player has no ammo nor clips
					if( playerState->weaponState == WEAPON_STATE_NOAMMOCLICK )
					{
						playerState->weaponState = WEAPON_STATE_RELOADING;
						playerState->stats[STAT_WEAPON_TIME] += NOAMMOCLICK_AUTOSWITCH;
						if( playerState->stats[STAT_PENDING_WEAPON] == playerState->stats[STAT_WEAPON] )
							playerState->stats[STAT_PENDING_WEAPON] = GS_SelectBestWeapon( playerState );
					}
					else
					{
						playerState->weaponState = WEAPON_STATE_NOAMMOCLICK;
						playerState->stats[STAT_WEAPON_TIME] += NOAMMOCLICK_PENALTY;
						module_PredictedEvent( playerState->POVnum, EV_NOAMMOCLICK, 0 );
						goto done;
					}
				}
			}
			// gunblade auto attack is special
			else if( playerState->stats[STAT_WEAPON] == WEAP_GUNBLADE &&
				playerState->pmove.stats[PM_STAT_NOUSERCONTROL] <= 0 &&
				playerState->pmove.stats[PM_STAT_NOAUTOATTACK] <= 0 &&
				GS_CheckBladeAutoAttack( playerState, timeDelta ) )
			{
				firedef = &GS_GetWeaponDef( WEAP_GUNBLADE )->firedef_weak;
				playerState->weaponState = WEAPON_STATE_FIRING;
			}
		}
	}

	if( playerState->weaponState == WEAPON_STATE_FIRING )
	{
		int parm = playerState->stats[STAT_WEAPON];
		if( firedef->fire_mode == FIRE_MODE_STRONG )
			parm |= EV_INVERSE;

		playerState->stats[STAT_WEAPON_TIME] += firedef->reload_time;
		if( firedef->fire_mode == FIRE_MODE_STRONG )
			playerState->weaponState = WEAPON_STATE_REFIRESTRONG;
		else
			playerState->weaponState = WEAPON_STATE_REFIRE;

		if( refire && firedef->smooth_refire )
			module_PredictedEvent( playerState->POVnum, EV_SMOOTHREFIREWEAPON, parm );
		else
			module_PredictedEvent( playerState->POVnum, EV_FIREWEAPON, parm );

		// waste ammo
		if( !GS_InfiniteAmmo() )
		{
			if( firedef->ammo_id != AMMO_NONE && firedef->usage_count )
				playerState->inventory[firedef->ammo_id] -= firedef->usage_count;
		}
	}
done:
	return playerState->stats[STAT_WEAPON];
}