Ejemplo n.º 1
0
/*
=================
G_GiveClientMaxAmmo
=================
*/
void G_GiveClientMaxAmmo( gentity_t *ent, qboolean buyingEnergyAmmo )
{
	int      i, maxAmmo, maxClips;
	qboolean restoredAmmo = qfalse, restoredEnergy = qfalse;
	//TODO find a solution to move dependency of ent->s.number and &ent->eventTime outside this function
	playerState_t *ps=&ent->client->ps;

	for ( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ )
	{
		qboolean energyWeapon;

		energyWeapon = BG_Weapon( i )->usesEnergy;

		if ( !BG_InventoryContainsWeapon( i, ps->stats ) ||
		     BG_Weapon( i )->infiniteAmmo ||
		     BG_WeaponIsFull( i, ps->stats,
		                      ps->ammo, ps->clips ) ||
		     ( buyingEnergyAmmo && !energyWeapon ) )
		{
			continue;
		}

		maxAmmo = BG_Weapon( i )->maxAmmo;
		maxClips = BG_Weapon( i )->maxClips;

		// Apply battery pack modifier
		if ( energyWeapon &&
		     BG_InventoryContainsUpgrade( UP_BATTPACK, ps->stats ) )
		{
			maxAmmo *= BATTPACK_MODIFIER;
			restoredEnergy = qtrue;
		}

		ps->ammo = maxAmmo;
		ps->clips = maxClips;

		restoredAmmo = qtrue;
	}

	if ( restoredAmmo )
	{
		G_ForceWeaponChange( ps, ps->weapon );
	}

	if ( restoredEnergy )
	{
		G_AddPlayerEvent( ps, EV_RPTUSE_SOUND, 0, ent->s.number, &ent->eventTime );
	}
}
Ejemplo n.º 2
0
/**
 * @brief Checks the condition for G_RefillAmmo.
 */
static qboolean CanUseAmmoRefill( gentity_t *self )
{
	const weaponAttributes_t *wa;
	playerState_t *ps;

	if ( !self || !self->client )
	{
		return qfalse;
	}

	ps = &self->client->ps;
	wa = BG_Weapon( ps->stats[ STAT_WEAPON ] );

	if ( wa->infiniteAmmo )
	{
		return qfalse;
	}

	if ( wa->maxClips == 0 )
	{
		// clipless weapons can be refilled whenever they lack ammo
		return ( ps->ammo != wa->maxAmmo );
	}
	else if ( ps->clips != wa->maxClips )
	{
		// clip weapons have to miss a clip to be refillable
		return qtrue;
	}
	else
	{
		return qfalse;
	}
}
Ejemplo n.º 3
0
static void CG_CompleteItem( void )
{
	int i = 0;

	if( cgs.clientinfo[ cg.clientNum ].team == TEAM_ALIENS )
	{
		return;
	}

	trap_CompleteCallback( "weapon" );

	for( i = 0; i < UP_NUM_UPGRADES; i++ )
	{
		const upgradeAttributes_t *item = BG_Upgrade( i );
		if ( item->usable )
		{
			trap_CompleteCallback( item->name );
		}
	}

	for( i = 0; i < WP_NUM_WEAPONS; i++ )
	{
		const weaponAttributes_t *item = BG_Weapon( i );
		if( item->team == TEAM_HUMANS )
		{
			trap_CompleteCallback( item->name );
		}
	}
}
Ejemplo n.º 4
0
/**
 * @brief Refills clips on clip based weapons, refills charge on other weapons.
 * @param self
 * @param triggerEvent Trigger an event when relvant resource was modified.
 * @return Whether relevant resource was modified.
 */
qboolean G_RefillAmmo( gentity_t *self, qboolean triggerEvent )
{
	if ( !CanUseAmmoRefill( self ) )
	{
		return qfalse;
	}

	self->client->lastAmmoRefillTime = level.time;

	if ( BG_Weapon( self->client->ps.stats[ STAT_WEAPON ] )->maxClips > 0 )
	{
		GiveMaxClips( self );

		if ( triggerEvent )
		{
			G_AddEvent( self, EV_CLIPS_REFILL, 0 );
		}
	}
	else
	{
		GiveFullClip( self );

		if ( triggerEvent )
		{
			G_AddEvent( self, EV_AMMO_REFILL, 0 );
		}
	}

	return qtrue;
}
Ejemplo n.º 5
0
static void CG_CompleteBuy( void )
{
	int i;

	if( cgs.clientinfo[ cg.clientNum ].team != TEAM_HUMANS )
	{
		return;
	}

	for( i = 0; i < UP_NUM_UPGRADES; i++ )
	{
		const upgradeAttributes_t *item = BG_Upgrade( i );
		if ( item->purchasable && item->team == TEAM_HUMANS )
		{
			trap_CompleteCallback( item->name );
		}
	}

	trap_CompleteCallback( "grenade" ); // called "gren" elsewhere, so special-case it

	for( i = 0; i < WP_NUM_WEAPONS; i++ )
	{
		const weaponAttributes_t *item = BG_Weapon( i );
		if ( item->purchasable && item->team == TEAM_HUMANS )
		{
			trap_CompleteCallback( item->name );
		}
	}
}
Ejemplo n.º 6
0
/*
=================
G_GiveClientMaxAmmo
=================
*/
void G_GiveClientMaxAmmo( gentity_t *ent, qboolean buyingEnergyAmmo )
{
	int      i, maxAmmo, maxClips;
	qboolean restoredAmmo = qfalse, restoredEnergy = qfalse;

	for ( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ )
	{
		qboolean energyWeapon;

		energyWeapon = BG_Weapon( i )->usesEnergy;

		if ( !BG_InventoryContainsWeapon( i, ent->client->ps.stats ) ||
		     BG_Weapon( i )->infiniteAmmo ||
		     BG_WeaponIsFull( i, ent->client->ps.stats,
		                      ent->client->ps.Ammo, ent->client->ps.clips ) ||
		     ( buyingEnergyAmmo && !energyWeapon ) )
		{
			continue;
		}

		maxAmmo = BG_Weapon( i )->maxAmmo;
		maxClips = BG_Weapon( i )->maxClips;

		// Apply battery pack modifier
		if ( energyWeapon &&
		     BG_InventoryContainsUpgrade( UP_BATTPACK, ent->client->ps.stats ) )
		{
			maxAmmo *= BATTPACK_MODIFIER;
			restoredEnergy = qtrue;
		}

		ent->client->ps.Ammo = maxAmmo;
		ent->client->ps.clips = maxClips;

		restoredAmmo = qtrue;
	}

	if ( restoredAmmo )
	{
		G_ForceWeaponChange( ent, ent->client->ps.weapon );
	}

	if ( restoredEnergy )
	{
		G_AddEvent( ent, EV_RPTUSE_SOUND, 0 );
	}
}
Ejemplo n.º 7
0
static void CG_CompleteClass( void )
{
	int i = 0;

	if ( cgs.clientinfo[ cg.clientNum ].team == TEAM_ALIENS )
	{
		for ( i = PCL_ALIEN_BUILDER0; i < PCL_HUMAN; i++ )
		{
			trap_CompleteCallback( BG_Class( i )->name );
		}
	}
	else if ( cgs.clientinfo[ cg.clientNum ].team == TEAM_HUMANS )
	{
		trap_CompleteCallback( BG_Weapon( WP_HBUILD )->name );
		trap_CompleteCallback( BG_Weapon( WP_MACHINEGUN )->name );
	}
}
Ejemplo n.º 8
0
/*
===============
trigger_ammo_touch
===============
*/
void trigger_ammo_touch( gentity_t *self, gentity_t *other, trace_t *trace )
{
    int maxClips, maxAmmo;
    weapon_t weapon;

    if( !other->client )
        return;

    if( other->client->ps.stats[ STAT_TEAM ] != TEAM_HUMANS )
        return;

    if( self->timestamp > level.time )
        return;

    if( other->client->ps.weaponstate != WEAPON_READY )
        return;

    weapon = BG_PrimaryWeapon( other->client->ps.stats );
    if( BG_Weapon( weapon )->usesEnergy && self->spawnflags & 2 )
        return;

    if( !BG_Weapon( weapon )->usesEnergy && self->spawnflags & 4 )
        return;

    if( self->spawnflags & 1 )
        self->timestamp = level.time + 1000;
    else
        self->timestamp = level.time + FRAMETIME;

    maxAmmo = BG_Weapon( weapon )->maxAmmo;
    maxClips = BG_Weapon( weapon )->maxClips;

    if( ( other->client->ps.ammo + self->damage ) > maxAmmo )
    {
        if( other->client->ps.clips < maxClips )
        {
            other->client->ps.clips++;
            other->client->ps.ammo = 1;
        }
        else
            other->client->ps.ammo = maxAmmo;
    }
    else
        other->client->ps.ammo += self->damage;
}
Ejemplo n.º 9
0
static void CG_CompleteClass()
{
	int i = 0;

	if ( cgs.clientinfo[ cg.clientNum ].team == TEAM_ALIENS )
	{
		// TODO: Add iterator for alien/human classes
		for ( i = PCL_ALIEN_BUILDER0; i < PCL_HUMAN_NAKED; i++ )
		{
			trap_CompleteCallback( BG_Class( i )->name );
		}
	}
	else if ( cgs.clientinfo[ cg.clientNum ].team == TEAM_HUMANS )
	{
		trap_CompleteCallback( BG_Weapon( WP_HBUILD )->name );
		trap_CompleteCallback( BG_Weapon( WP_MACHINEGUN )->name );
	}
}
Ejemplo n.º 10
0
static void CG_CompleteBuy_internal( bool negatives )
{
	int i;

	for( i = 0; i < UP_NUM_UPGRADES; i++ )
	{
		const upgradeAttributes_t *item = BG_Upgrade( i );
		if ( item->purchasable && item->team == TEAM_HUMANS )
		{
			trap_CompleteCallback( item->name );

			if ( negatives )
			{
				trap_CompleteCallback( va( "-%s", item->name ) );
			}
		}
	}

	trap_CompleteCallback( "grenade" ); // called "gren" elsewhere, so special-case it

	if ( negatives )
	{
		trap_CompleteCallback( "-grenade" );

		i = BG_GetPlayerWeapon( &cg.snap->ps );

	}

	for( i = 0; i < WP_NUM_WEAPONS; i++ )
	{
		const weaponAttributes_t *item = BG_Weapon( i );
		if ( item->purchasable && item->team == TEAM_HUMANS )
		{
			trap_CompleteCallback( item->name );

			if ( negatives )
			{
				trap_CompleteCallback( va( "-%s", BG_Weapon( i )->name ) );
			}
		}
	}
}
Ejemplo n.º 11
0
static const char *UnlockableHumanName( unlockable_t *unlockable )
{
	switch ( unlockable->type )
	{
		case UNLT_WEAPON:    return BG_Weapon( unlockable->num )->humanName;
		case UNLT_UPGRADE:   return BG_Upgrade( unlockable->num )->humanName;
		case UNLT_BUILDABLE: return BG_Buildable( unlockable->num )->humanName;
		case UNLT_CLASS:     return BG_ClassModelConfig( unlockable->num )->humanName;
	}

	Com_Error( ERR_FATAL, "UnlockableHumanName: Unlockable has unknown type" );
	return nullptr;
}
Ejemplo n.º 12
0
/*
=================
CG_RegisterWeapon
=================
*/
void CG_RegisterWeapon( int weaponNum )
{
  weaponInfo_t  *weaponInfo;
  char          path[ MAX_QPATH ];
  vec3_t        mins, maxs;
  int           i;

  if( weaponNum <= WP_NONE || weaponNum >= WP_NUM_WEAPONS )
  {
    CG_Error( "CG_RegisterWeapon: out of range: %d", weaponNum );
    return;
  }

  weaponInfo = &cg_weapons[ weaponNum ];

  if( weaponInfo->registered )
  {
    CG_Printf( "CG_RegisterWeapon: already registered: (%d) %s\n", weaponNum,
      BG_Weapon( weaponNum )->name );
    return;
  }

  weaponInfo->registered = qtrue;

  if( !BG_Weapon( weaponNum )->name[ 0 ] )
    CG_Error( "Couldn't find weapon %i", weaponNum );

  Com_sprintf( path, MAX_QPATH, "models/weapons/%s/weapon.cfg", BG_Weapon( weaponNum )->name );

  weaponInfo->humanName = BG_Weapon( weaponNum )->humanName;

  if( !CG_ParseWeaponFile( path, weaponInfo ) )
    Com_Printf( S_COLOR_RED "ERROR: failed to parse %s\n", path );

  // calc midpoint for rotation
  trap_R_ModelBounds( weaponInfo->weaponModel, mins, maxs );
  for( i = 0 ; i < 3 ; i++ )
    weaponInfo->weaponMidpoint[ i ] = mins[ i ] + 0.5 * ( maxs[ i ] - mins[ i ] );
}
Ejemplo n.º 13
0
/*
==================
CG_PlayerIsBuilder
==================
*/
static qboolean CG_PlayerIsBuilder( buildable_t buildable )
{
  switch( cg.predictedPlayerState.weapon )
  {
    case WP_ABUILD:
    case WP_HBUILD:
      return BG_Buildable( buildable )->team ==
             BG_Weapon( cg.predictedPlayerState.weapon )->team;

    default:
      return qfalse;
  }
}
static void CG_Rocket_DFCMArmouryBuyWeapon( int handle, const char *data )
{
	weapon_t weapon = (weapon_t) atoi( Info_ValueForKey( data, "1" ) );
	const char *Class = "";
	const char *Icon = "";
	const char *action = "";
	playerState_t *ps = &cg.snap->ps;
	int credits = ps->persistant[ PERS_CREDIT ];
	weapon_t currentweapon = BG_PrimaryWeapon( ps->stats );
	credits += BG_Weapon( currentweapon )->price;

	if( BG_InventoryContainsWeapon( weapon, cg.predictedPlayerState.stats ) ){
		Class = "active";
		action =  va( "onClick='Cmd.exec(\"sell %s\")'", BG_Weapon( weapon )->name );
		//Check mark icon. UTF-8 encoding of \uf00c
		Icon = "<icon class=\"current\">\xEF\x80\x8C</icon>";
	}
	else if ( !BG_WeaponUnlocked( weapon ) || BG_WeaponDisabled( weapon ) )
	{
		Class = "locked";
		//Padlock icon. UTF-8 encoding of \uf023
		Icon = "<icon>\xEF\x80\xA3</icon>";
	}

	else if(BG_Weapon( weapon )->price > credits){

		Class = "expensive";
		//$1 bill icon. UTF-8 encoding of \uf0d6
		Icon = "<icon>\xEF\x83\x96</icon>";
	}
	else
	{
		Class = "available";
		action =  va( "onClick='Cmd.exec(\"buy +%s\")'", BG_Weapon( weapon )->name );
	}

	Rocket_DataFormatterFormattedData( handle, va( "<button class='armourybuy %s' onMouseover='Events.pushevent(\"setDS armouryBuyList weapons %s\", event)' %s>%s<img src='/%s'/></button>", Class, Info_ValueForKey( data, "2" ), action, Icon, CG_GetShaderNameFromHandle( cg_weapons[ weapon ].ammoIcon )), false );
}
Ejemplo n.º 15
0
/**
 * @brief Refills current ammo clip/charge.
 */
static void GiveFullClip( gentity_t *self )
{
	playerState_t *ps;
	const weaponAttributes_t *wa;

	if ( !self || !self->client )
	{
		return;
	}

	ps = &self->client->ps;
	wa = BG_Weapon( ps->stats[ STAT_WEAPON ] );

	ps->ammo = wa->maxAmmo;
}
Ejemplo n.º 16
0
/**
 * @brief Attempts to refill ammo from a close source.
 * @return Whether ammo was refilled.
 */
qboolean G_FindAmmo( gentity_t *self )
{
	gentity_t *neighbor = NULL;
	qboolean  foundSource = qfalse;

	// don't search for a source if refilling isn't possible
	if ( !CanUseAmmoRefill( self ) )
	{
		return qfalse;
	}

	// search for ammo source
	while ( ( neighbor = G_IterateEntitiesWithinRadius( neighbor, self->s.origin, ENTITY_BUY_RANGE ) ) )
	{
		// only friendly, living and powered buildables provide ammo
		if ( neighbor->s.eType != ET_BUILDABLE ||
		     !G_OnSameTeam( self, neighbor ) ||
		     !neighbor->spawned ||
		     !neighbor->powered ||
		     neighbor->health <= 0 )
		{
			continue;
		}

		switch ( neighbor->s.modelindex )
		{
			case BA_H_ARMOURY:
				foundSource = qtrue;
				break;

			case BA_H_REACTOR:
			case BA_H_REPEATER:
				if ( BG_Weapon( self->client->ps.stats[ STAT_WEAPON ] )->usesEnergy )
				{
					foundSource = qtrue;
				}
				break;
		}
	}

	if ( foundSource )
	{
		return G_RefillAmmo( self, qtrue );
	}

	return qfalse;
}
Ejemplo n.º 17
0
/*
======================================================================

BUILD GUN

======================================================================
*/
void CheckCkitRepair( gentity_t *ent )
{
	vec3_t    viewOrigin, forward, end;
	trace_t   tr;
	gentity_t *traceEnt;
	int       bHealth;
	//TODO find a solution to move dependency of ent->s.number and &ent->eventTime outside this function
	playerState_t *ps=&ent->client->ps;

	if ( ps->weaponTime > 0 ||
	     ps->stats[ STAT_MISC ] > 0 )
	{
		return;
	}

	BG_GetClientViewOrigin( ps, viewOrigin );
	AngleVectors( ps->viewangles, forward, NULL, NULL );
	VectorMA( viewOrigin, 100, forward, end );

	trap_Trace( &tr, viewOrigin, NULL, NULL, end, ent->s.number, MASK_PLAYERSOLID );
	traceEnt = &g_entities[ tr.entityNum ];

	if ( tr.fraction < 1.0f && traceEnt->spawned && traceEnt->health > 0 &&
	     traceEnt->s.eType == ET_BUILDABLE && traceEnt->buildableTeam == TEAM_HUMANS )
	{
		bHealth = BG_Buildable( traceEnt->s.modelindex )->health;

		if ( traceEnt->health < bHealth )
		{
			traceEnt->health += HBUILD_HEALRATE;

			if ( traceEnt->health >= bHealth )
			{
				traceEnt->health = bHealth;
				G_AddPlayerEvent( ps, EV_BUILD_REPAIRED, 0, ent->s.number, &ent->eventTime );
			}
			else
			{
				G_AddPlayerEvent( ps, EV_BUILD_REPAIR, 0, ent->s.number, &ent->eventTime );
			}

			ps->weaponTime += BG_Weapon( ps->weapon )->repeatRate1;
		}
	}
}
Ejemplo n.º 18
0
/*
======================================================================

BUILD GUN

======================================================================
*/
void CheckCkitRepair( gentity_t *ent )
{
	vec3_t    viewOrigin, forward, end;
	trace_t   tr;
	gentity_t *traceEnt;
	int       bHealth;

	if ( ent->client->ps.weaponTime > 0 ||
	     ent->client->ps.stats[ STAT_MISC ] > 0 )
	{
		return;
	}

	BG_GetClientViewOrigin( &ent->client->ps, viewOrigin );
	AngleVectors( ent->client->ps.viewangles, forward, NULL, NULL );
	VectorMA( viewOrigin, 100, forward, end );

	trap_Trace( &tr, viewOrigin, NULL, NULL, end, ent->s.number, MASK_PLAYERSOLID );
	traceEnt = &g_entities[ tr.entityNum ];

	if ( tr.fraction < 1.0f && traceEnt->spawned && traceEnt->health > 0 &&
	     traceEnt->s.eType == ET_BUILDABLE && traceEnt->buildableTeam == TEAM_HUMANS )
	{
		bHealth = BG_Buildable( traceEnt->s.modelindex )->health;

		if ( traceEnt->health < bHealth )
		{
			traceEnt->health += HBUILD_HEALRATE;

			if ( traceEnt->health >= bHealth )
			{
				traceEnt->health = bHealth;
				G_AddEvent( ent, EV_BUILD_REPAIRED, 0 );
			}
			else
			{
				G_AddEvent( ent, EV_BUILD_REPAIR, 0 );
			}

			ent->client->ps.weaponTime += BG_Weapon( ent->client->ps.weapon )->repeatRate1;
		}
	}
}
Ejemplo n.º 19
0
void G_CheckCkitRepair( gentity_t *self )
{
	vec3_t    viewOrigin, forward, end;
	trace_t   tr;
	gentity_t *traceEnt;

	if ( self->client->ps.weaponTime > 0 ||
	     self->client->ps.stats[ STAT_MISC ] > 0 )
	{
		return;
	}

	BG_GetClientViewOrigin( &self->client->ps, viewOrigin );
	AngleVectors( self->client->ps.viewangles, forward, NULL, NULL );
	VectorMA( viewOrigin, 100, forward, end );

	trap_Trace( &tr, viewOrigin, NULL, NULL, end, self->s.number, MASK_PLAYERSOLID );
	traceEnt = &g_entities[ tr.entityNum ];

	if ( tr.fraction < 1.0f && traceEnt->spawned && traceEnt->health > 0 &&
	     traceEnt->s.eType == ET_BUILDABLE && traceEnt->buildableTeam == TEAM_HUMANS )
	{
		const buildableAttributes_t *buildable;

		buildable = BG_Buildable( traceEnt->s.modelindex );

		if ( traceEnt->health < buildable->health )
		{
			if ( G_Heal( traceEnt, HBUILD_HEALRATE ) )
			{
				G_AddEvent( self, EV_BUILD_REPAIR, 0 );
			}
			else
			{
				G_AddEvent( self, EV_BUILD_REPAIRED, 0 );
			}

			self->client->ps.weaponTime += BG_Weapon( self->client->ps.weapon )->repeatRate1;
		}
	}
}
Ejemplo n.º 20
0
void G_CheckCkitRepair( gentity_t *self )
{
	vec3_t    viewOrigin, forward, end;
	trace_t   tr;
	gentity_t *traceEnt;

	if ( self->client->ps.weaponTime > 0 ||
	     self->client->ps.stats[ STAT_MISC ] > 0 )
	{
		return;
	}

	BG_GetClientViewOrigin( &self->client->ps, viewOrigin );
	AngleVectors( self->client->ps.viewangles, forward, nullptr, nullptr );
	VectorMA( viewOrigin, 100, forward, end );

	trap_Trace( &tr, viewOrigin, nullptr, nullptr, end, self->s.number, MASK_PLAYERSOLID, 0 );
	traceEnt = &g_entities[ tr.entityNum ];

	if ( tr.fraction < 1.0f && traceEnt->spawned && traceEnt->s.eType == ET_BUILDABLE &&
	     traceEnt->buildableTeam == TEAM_HUMANS )
	{
		HealthComponent *healthComponent = traceEnt->entity->Get<HealthComponent>();

		if (healthComponent && healthComponent->Alive() && !healthComponent->FullHealth()) {
			traceEnt->entity->Heal(HBUILD_HEALRATE, nullptr);

			if (healthComponent->FullHealth()) {
				G_AddEvent(self, EV_BUILD_REPAIRED, 0);
			} else {
				G_AddEvent(self, EV_BUILD_REPAIR, 0);
			}

			self->client->ps.weaponTime += BG_Weapon( self->client->ps.weapon )->repeatRate1;
		}
	}
}
Ejemplo n.º 21
0
bool AnimDelta::LoadData(clientInfo_t* ci)
{
	char newModelName[ MAX_QPATH ];
	// special handling for human_(naked|light|medium)
	if ( !Q_stricmp( ci->modelName, "human_naked"   ) ||
		!Q_stricmp( ci->modelName, "human_light"   ) ||
		!Q_stricmp( ci->modelName, "human_medium" ) )
	{
		Q_strncpyz( newModelName, "human_nobsuit_common", sizeof( newModelName ) );
	}
	else
	{
		Q_strncpyz( newModelName, ci->modelName, sizeof( newModelName ) );
	}

	refSkeleton_t base;
	refSkeleton_t delta;
	for ( int i = WP_NONE + 1; i < WP_NUM_WEAPONS; ++i )
	{
		int handle = LoadDeltaAnimation( static_cast<weapon_t>( i ), newModelName, ci->iqm );
		if ( !handle ) continue;
		Log::Debug("Loaded delta for %s %s", newModelName, BG_Weapon( i )->humanName);
		trap_R_BuildSkeleton( &delta, handle, 1, 1, 0, false );
		// Derive the delta from the base stand animation.
		trap_R_BuildSkeleton( &base, ci->animations[ TORSO_STAND ].handle, 1, 1, 0, false );
		auto ret = deltas_.insert( std::make_pair( i, std::vector<delta_t>( boneIndicies_.size() ) ) );
		auto& weaponDeltas = ret.first->second;
		for ( size_t j = 0; j < boneIndicies_.size(); ++j )
		{
			VectorSubtract( delta.bones[ boneIndicies_[ j ] ].t.trans, base.bones[ boneIndicies_[ j ] ].t.trans, weaponDeltas[ j ].delta );
			QuatInverse( base.bones[ boneIndicies_[ j ] ].t.rot );
			QuatMultiply( base.bones[ boneIndicies_[ j ] ].t.rot, delta.bones[ boneIndicies_[ j ] ].t.rot, weaponDeltas[ j ].rot );
		}
	}
	return true;
}
Ejemplo n.º 22
0
static int CG_CalcFov( void )
{
  float     y;
  float     phase;
  float     v;
  int       contents;
  float     fov_x, fov_y;
  float     zoomFov;
  float     f;
  int       inwater;
  int       attribFov;
  usercmd_t cmd;
  usercmd_t oldcmd;
  int       cmdNum;

  cmdNum = trap_GetCurrentCmdNumber( );
  trap_GetUserCmd( cmdNum, &cmd );
  trap_GetUserCmd( cmdNum - 1, &oldcmd );

  // switch follow modes if necessary: cycle between free -> follow -> third-person follow
  if( cmd.buttons & BUTTON_USE_HOLDABLE && !( oldcmd.buttons & BUTTON_USE_HOLDABLE ) )
  {
    if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) 
    {
      if( !cg.chaseFollow )
        cg.chaseFollow = qtrue;
      else
      {
        cg.chaseFollow = qfalse;
        trap_SendClientCommand( "follow\n" );
      }
    }
    else if ( cg.snap->ps.persistant[ PERS_SPECSTATE ] != SPECTATOR_NOT )
      trap_SendClientCommand( "follow\n" );
  }

  if( cg.predictedPlayerState.pm_type == PM_INTERMISSION ||
      ( cg.snap->ps.persistant[ PERS_SPECSTATE ] != SPECTATOR_NOT ) || 
      ( cg.renderingThirdPerson ) )
  {
    // if in intermission or third person, use a fixed value
    fov_y = BASE_FOV_Y;
  }
  else
  {
    // don't lock the fov globally - we need to be able to change it
    attribFov = BG_Class( cg.predictedPlayerState.stats[ STAT_CLASS ] )->fov * 0.75f;
    fov_y = attribFov;

    if ( fov_y < 1.0f )
      fov_y = 1.0f;
    else if ( fov_y > MAX_FOV_Y )
      fov_y = MAX_FOV_Y;

    if( cg.spawnTime > ( cg.time - FOVWARPTIME ) &&
        BG_ClassHasAbility( cg.predictedPlayerState.stats[ STAT_CLASS ], SCA_FOVWARPS ) )
    {
      float fraction = (float)( cg.time - cg.spawnTime ) / FOVWARPTIME;

      fov_y = MAX_FOV_WARP_Y - ( ( MAX_FOV_WARP_Y - fov_y ) * fraction );
    }

    // account for zooms
    zoomFov = BG_Weapon( cg.predictedPlayerState.weapon )->zoomFov * 0.75f;
    if ( zoomFov < 1.0f )
      zoomFov = 1.0f;
    else if ( zoomFov > attribFov )
      zoomFov = attribFov;

    // only do all the zoom stuff if the client CAN zoom
    // FIXME: zoom control is currently hard coded to BUTTON_ATTACK2
    if( BG_Weapon( cg.predictedPlayerState.weapon )->canZoom )
    {
      if ( cg.zoomed )
      {
        f = ( cg.time - cg.zoomTime ) / (float)ZOOM_TIME;

        if ( f > 1.0f )
          fov_y = zoomFov;
        else
          fov_y = fov_y + f * ( zoomFov - fov_y );

        // BUTTON_ATTACK2 isn't held so unzoom next time
        if( !( cmd.buttons & BUTTON_ATTACK2 ) )
        {
          cg.zoomed   = qfalse;
          cg.zoomTime = MIN( cg.time, 
              cg.time + cg.time - cg.zoomTime - ZOOM_TIME );
        }
      }
      else
      {
        f = ( cg.time - cg.zoomTime ) / (float)ZOOM_TIME;

        if ( f <= 1.0f )
          fov_y = zoomFov + f * ( fov_y - zoomFov );

        // BUTTON_ATTACK2 is held so zoom next time
        if( cmd.buttons & BUTTON_ATTACK2 )
        {
          cg.zoomed   = qtrue;
          cg.zoomTime = MIN( cg.time, 
              cg.time + cg.time - cg.zoomTime - ZOOM_TIME );
        }
      }
    }
  }

  y = cg.refdef.height / tan( 0.5f * DEG2RAD( fov_y ) );
  fov_x = atan2( cg.refdef.width, y );
  fov_x = 2.0f * RAD2DEG( fov_x );

  // warp if underwater
  contents = CG_PointContents( cg.refdef.vieworg, -1 );

  if( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) )
  {
    phase = cg.time / 1000.0f * WAVE_FREQUENCY * M_PI * 2.0f;
    v = WAVE_AMPLITUDE * sin( phase );
    fov_x += v;
    fov_y -= v;
    inwater = qtrue;
  }
  else
    inwater = qfalse;

  if( ( cg.predictedPlayerEntity.currentState.eFlags & EF_POISONCLOUDED ) &&
      ( cg.time - cg.poisonedTime < PCLOUD_DISORIENT_DURATION) &&
      cg.predictedPlayerState.stats[ STAT_HEALTH ] > 0 &&
      !( cg.snap->ps.pm_flags & PMF_FOLLOW ) )
  {
    float scale = 1.0f - (float)( cg.time - cg.poisonedTime ) /
                  BG_PlayerPoisonCloudTime( &cg.predictedPlayerState );
      
    phase = ( cg.time - cg.poisonedTime ) / 1000.0f * PCLOUD_ZOOM_FREQUENCY * M_PI * 2.0f;
    v = PCLOUD_ZOOM_AMPLITUDE * sin( phase ) * scale;
    fov_x += v;
    fov_y += v;
  }


  // set it
  cg.refdef.fov_x = fov_x;
  cg.refdef.fov_y = fov_y;

  if( !cg.zoomed )
    cg.zoomSensitivity = 1.0f;
  else
    cg.zoomSensitivity = cg.refdef.fov_y / 75.0f;

  return inwater;
}
Ejemplo n.º 23
0
void BG_ImportUnlockablesFromMask( int team, int mask )
{
	int              unlockableNum, teamUnlockableNum = 0, itemNum = 0, unlockThreshold;
	unlockable_t     *unlockable;
	int unlockableType = 0;
	team_t           currentTeam;
	bool         newStatus;
	int              statusChanges[ NUM_UNLOCKABLES ];
#ifdef BUILD_CGAME
	int statusChangeCount = 0;
#endif

	// maintain a cache to prevent redundant imports
	static int    lastMask = 0;
	static team_t lastTeam = TEAM_NONE;

	// just import if data is unavailable, cached mask is outdated or team has changed
	if ( unlockablesDataAvailable && team == lastTeam && mask == lastMask )
	{
		return;
	}

	// cache input
	lastMask = mask;
	lastTeam = (team_t) team;

	// no status change yet
	memset( statusChanges, 0, sizeof( statusChanges ) );

	for ( unlockableNum = 0; unlockableNum < NUM_UNLOCKABLES; unlockableNum++ )
	{
		unlockable = &unlockables[ unlockableNum ];

		// also iterate over item types, itemNum is a per-type counter
		if ( unlockableType < UNLT_NUM_UNLOCKABLETYPES - 1 &&
		     unlockableNum == unlockablesTypeOffset[ unlockableType + 1 ] )
		{
			unlockableType++;
			itemNum = 0;
		}

		switch ( unlockableType )
		{
			case UNLT_WEAPON:
				currentTeam     = BG_Weapon( itemNum )->team;
				unlockThreshold = BG_Weapon( itemNum )->unlockThreshold;
				break;

			case UNLT_UPGRADE:
				currentTeam     = TEAM_HUMANS;
				unlockThreshold = BG_Upgrade( itemNum )->unlockThreshold;
				break;

			case UNLT_BUILDABLE:
				currentTeam     = BG_Buildable( itemNum )->team;
				unlockThreshold = BG_Buildable( itemNum )->unlockThreshold;
				break;

			case UNLT_CLASS:
				currentTeam     = TEAM_ALIENS;
				unlockThreshold = BG_Class( itemNum )->unlockThreshold;
				break;

			default:
				Com_Error( ERR_FATAL, "BG_ImportUnlockablesFromMask: Unknown unlockable type" );
		}

		unlockThreshold = MAX( unlockThreshold, 0 );

		unlockable->type            = unlockableType;
		unlockable->num             = itemNum;
		unlockable->team            = currentTeam;
		unlockable->unlockThreshold = unlockThreshold;
		unlockable->lockThreshold   = UnlockToLockThreshold( unlockThreshold );

		// retrieve the item's locking state
		if ( !unlockThreshold )
		{
			unlockable->statusKnown = true;
			unlockable->unlocked    = true;
		}
		else if ( currentTeam == team )
		{
			newStatus = mask & ( 1 << teamUnlockableNum );

#ifdef BUILD_CGAME
			// notify client about single status change
			if ( unlockablesTeamKnowledge == team && unlockable->statusKnown &&
			     unlockable->unlocked != newStatus )
			{
				InformUnlockableStatusChange( unlockable, newStatus );

				statusChanges[ unlockableNum ] = newStatus ? 1 : -1;
				statusChangeCount++;
			}
#endif

			unlockable->statusKnown = true;
			unlockable->unlocked    = newStatus;

			teamUnlockableNum++;
		}
		else
		{
			unlockable->statusKnown = false;
			unlockable->unlocked    = false;
		}

		itemNum++;
	}

#ifdef BUILD_CGAME
	// notify client about all status changes
	if ( statusChangeCount )
	{
		InformUnlockableStatusChanges( statusChanges, statusChangeCount );
	}

	// export team and mask into cvar for UI
	trap_Cvar_Set( "ui_unlockables", va( "%d %d", team, mask ) );
#endif

	// we only know the state for one team
	unlockablesDataAvailable = true;
	unlockablesTeamKnowledge = (team_t) team;

	// save mask for later use
	unlockablesMask[ team ] = mask;
}
Ejemplo n.º 24
0
/*
===========
ClientSpawn

Called every time a client is placed fresh in the world:
after the first ClientBegin, and after each respawn
Initializes all non-persistant parts of playerState
============
*/
void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles )
{
    int                 index;
    vec3_t              spawn_origin, spawn_angles;
    gclient_t           *client;
    int                 i;
    clientPersistant_t  saved;
    clientSession_t     savedSess;
    int                 persistant[ MAX_PERSISTANT ];
    gentity_t           *spawnPoint = NULL;
    int                 flags;
    int                 savedPing;
    int                 teamLocal;
    int                 eventSequence;
    char                userinfo[ MAX_INFO_STRING ];
    vec3_t              up = { 0.0f, 0.0f, 1.0f };
    int                 maxAmmo, maxClips;
    weapon_t            weapon;

    index = ent - g_entities;
    client = ent->client;

    teamLocal = client->pers.teamSelection;

    //if client is dead and following teammate, stop following before spawning
    if( client->sess.spectatorClient != -1 )
    {
        client->sess.spectatorClient = -1;
        client->sess.spectatorState = SPECTATOR_FREE;
    }

    // only start client if chosen a class and joined a team
    if( client->pers.classSelection == PCL_NONE && teamLocal == TEAM_NONE )
        client->sess.spectatorState = SPECTATOR_FREE;
    else if( client->pers.classSelection == PCL_NONE )
        client->sess.spectatorState = SPECTATOR_LOCKED;

    // if client is dead and following teammate, stop following before spawning
    if( ent->client->sess.spectatorState == SPECTATOR_FOLLOW )
        G_StopFollowing( ent );

    if( origin != NULL )
        VectorCopy( origin, spawn_origin );

    if( angles != NULL )
        VectorCopy( angles, spawn_angles );

    // find a spawn point
    // do it before setting health back up, so farthest
    // ranging doesn't count this client
    if( client->sess.spectatorState != SPECTATOR_NOT )
    {
        if( teamLocal == TEAM_NONE )
            spawnPoint = G_SelectSpectatorSpawnPoint( spawn_origin, spawn_angles );
        else if( teamLocal == TEAM_ALIENS )
            spawnPoint = G_SelectAlienLockSpawnPoint( spawn_origin, spawn_angles );
        else if( teamLocal == TEAM_HUMANS )
            spawnPoint = G_SelectHumanLockSpawnPoint( spawn_origin, spawn_angles );
    }
    else
    {
        if( spawn == NULL )
        {
            G_Error( "ClientSpawn: spawn is NULL\n" );
            return;
        }

        spawnPoint = spawn;

        if( ent != spawn )
        {
            //start spawn animation on spawnPoint
            G_SetBuildableAnim( spawnPoint, BANIM_SPAWN1, qtrue );

            if( spawnPoint->buildableTeam == TEAM_ALIENS )
                spawnPoint->clientSpawnTime = ALIEN_SPAWN_REPEAT_TIME;
            else if( spawnPoint->buildableTeam == TEAM_HUMANS )
                spawnPoint->clientSpawnTime = HUMAN_SPAWN_REPEAT_TIME;
        }
    }

    // toggle the teleport bit so the client knows to not lerp
    flags = ( ent->client->ps.eFlags & EF_TELEPORT_BIT ) ^ EF_TELEPORT_BIT;
    G_UnlaggedClear( ent );

    // clear everything but the persistant data

    saved = client->pers;
    savedSess = client->sess;
    savedPing = client->ps.ping;

    for( i = 0; i < MAX_PERSISTANT; i++ )
        persistant[ i ] = client->ps.persistant[ i ];

    eventSequence = client->ps.eventSequence;
    memset( client, 0, sizeof( *client ) );

    client->pers = saved;
    client->sess = savedSess;
    client->ps.ping = savedPing;
    client->lastkilled_client = -1;

    for( i = 0; i < MAX_PERSISTANT; i++ )
        client->ps.persistant[ i ] = persistant[ i ];

    client->ps.eventSequence = eventSequence;

    // increment the spawncount so the client will detect the respawn
    client->ps.persistant[ PERS_SPAWN_COUNT ]++;
    client->ps.persistant[ PERS_SPECSTATE ] = client->sess.spectatorState;

    client->airOutTime = level.time + 12000;

    trap_GetUserinfo( index, userinfo, sizeof( userinfo ) );
    client->ps.eFlags = flags;

    //Com_Printf( "ent->client->pers->pclass = %i\n", ent->client->pers.classSelection );

    ent->s.groundEntityNum = ENTITYNUM_NONE;
    ent->client = &level.clients[ index ];
    ent->takedamage = qtrue;
    ent->inuse = qtrue;
    ent->classname = "player";
    ent->r.contents = CONTENTS_BODY;
    ent->clipmask = MASK_PLAYERSOLID;
    ent->die = player_die;
    ent->waterlevel = 0;
    ent->watertype = 0;
    ent->flags = 0;

    // calculate each client's acceleration
    ent->evaluateAcceleration = qtrue;

    client->ps.stats[ STAT_MISC ] = 0;

    client->ps.eFlags = flags;
    client->ps.clientNum = index;

    BG_ClassBoundingBox( ent->client->pers.classSelection, ent->r.mins, ent->r.maxs, NULL, NULL, NULL );

    if( client->sess.spectatorState == SPECTATOR_NOT )
        client->ps.stats[ STAT_MAX_HEALTH ] =
            BG_Class( ent->client->pers.classSelection )->health;
    else
        client->ps.stats[ STAT_MAX_HEALTH ] = 100;

    // clear entity values
    if( ent->client->pers.classSelection == PCL_HUMAN )
    {
        BG_AddUpgradeToInventory( UP_MEDKIT, client->ps.stats );
        weapon = client->pers.humanItemSelection;
    }
    else if( client->sess.spectatorState == SPECTATOR_NOT )
        weapon = BG_Class( ent->client->pers.classSelection )->startWeapon;
    else
        weapon = WP_NONE;

    maxAmmo = BG_Weapon( weapon )->maxAmmo;
    maxClips = BG_Weapon( weapon )->maxClips;
    client->ps.stats[ STAT_WEAPON ] = weapon;
    client->ps.ammo = maxAmmo;
    client->ps.clips = maxClips;

    // We just spawned, not changing weapons
    client->ps.persistant[ PERS_NEWWEAPON ] = 0;

    ent->client->ps.stats[ STAT_CLASS ] = ent->client->pers.classSelection;
    ent->client->ps.stats[ STAT_TEAM ] = ent->client->pers.teamSelection;

    ent->client->ps.stats[ STAT_BUILDABLE ] = BA_NONE;
    ent->client->ps.stats[ STAT_STATE ] = 0;
    VectorSet( ent->client->ps.grapplePoint, 0.0f, 0.0f, 1.0f );

    // health will count down towards max_health
    ent->health = client->ps.stats[ STAT_HEALTH ] = client->ps.stats[ STAT_MAX_HEALTH ]; //* 1.25;

    //if evolving scale health
    if( ent == spawn )
    {
        ent->health *= ent->client->pers.evolveHealthFraction;
        client->ps.stats[ STAT_HEALTH ] *= ent->client->pers.evolveHealthFraction;
    }

    //clear the credits array
    for( i = 0; i < MAX_CLIENTS; i++ )
        ent->credits[ i ] = 0;

    client->ps.stats[ STAT_STAMINA ] = STAMINA_MAX;

    G_SetOrigin( ent, spawn_origin );
    VectorCopy( spawn_origin, client->ps.origin );

#define UP_VEL  150.0f
#define F_VEL   50.0f

    //give aliens some spawn velocity
    if( client->sess.spectatorState == SPECTATOR_NOT &&
            client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
    {
        if( ent == spawn )
        {
            //evolution particle system
            G_AddPredictableEvent( ent, EV_ALIEN_EVOLVE, DirToByte( up ) );
        }
        else
        {
            spawn_angles[ YAW ] += 180.0f;
            AngleNormalize360( spawn_angles[ YAW ] );

            if( spawnPoint->s.origin2[ 2 ] > 0.0f )
            {
                vec3_t  forward, dir;

                AngleVectors( spawn_angles, forward, NULL, NULL );
                VectorScale( forward, F_VEL, forward );
                VectorAdd( spawnPoint->s.origin2, forward, dir );
                VectorNormalize( dir );

                VectorScale( dir, UP_VEL, client->ps.velocity );
            }

            G_AddPredictableEvent( ent, EV_PLAYER_RESPAWN, 0 );
        }
    }
    else if( client->sess.spectatorState == SPECTATOR_NOT &&
             client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
    {
        spawn_angles[ YAW ] += 180.0f;
        AngleNormalize360( spawn_angles[ YAW ] );
    }

    // the respawned flag will be cleared after the attack and jump keys come up
    client->ps.pm_flags |= PMF_RESPAWNED;

    trap_GetUsercmd( client - level.clients, &ent->client->pers.cmd );
    G_SetClientViewAngle( ent, spawn_angles );

    if( client->sess.spectatorState == SPECTATOR_NOT )
    {
        trap_LinkEntity( ent );

        // force the base weapon up
        if( client->pers.teamSelection == TEAM_HUMANS )
            G_ForceWeaponChange( ent, weapon );

        client->ps.weaponstate = WEAPON_READY;
    }

    // don't allow full run speed for a bit
    client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
    client->ps.pm_time = 100;

    client->respawnTime = level.time;
    ent->nextRegenTime = level.time;

    client->inactivityTime = level.time + g_inactivity.integer * 1000;
    client->latched_buttons = 0;

    // set default animations
    client->ps.torsoAnim = TORSO_STAND;
    client->ps.legsAnim = LEGS_IDLE;

    if( level.intermissiontime )
        MoveClientToIntermission( ent );
    else
    {
        // fire the targets of the spawn point
        if( !spawn )
            G_UseTargets( spawnPoint, ent );

        client->ps.weapon = client->ps.stats[ STAT_WEAPON ];
    }

    // run a client frame to drop exactly to the floor,
    // initialize animations and other things
    client->ps.commandTime = level.time - 100;
    ent->client->pers.cmd.serverTime = level.time;
    ClientThink( ent-g_entities );

    // positively link the client, even if the command times are weird
    if( client->sess.spectatorState == SPECTATOR_NOT )
    {
        BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue );
        VectorCopy( ent->client->ps.origin, ent->r.currentOrigin );
        trap_LinkEntity( ent );
    }

    // must do this here so the number of active clients is calculated
    CalculateRanks( );

    // run the presend to set anything else
    ClientEndFrame( ent );

    // clear entity state values
    BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue );

    client->pers.infoChangeTime = level.time;
}
Ejemplo n.º 25
0
void G_UpdateUnlockables()
{
	int              itemNum = 0, unlockableNum, unlockThreshold;
	float            momentum;
	unlockable_t     *unlockable;
	int              unlockableType = 0;
	team_t           team;

	for ( unlockableNum = 0; unlockableNum < NUM_UNLOCKABLES; unlockableNum++ )
	{
		unlockable = &unlockables[ unlockableNum ];

		// also iterate over item types, itemNum is a per-type counter
		while ( unlockableType < UNLT_NUM_UNLOCKABLETYPES - 1 &&
		        unlockableNum == unlockablesTypeOffset[ unlockableType + 1 ] )
		{
			unlockableType++;
			itemNum = 0;
		}

		switch ( unlockableType )
		{
			case UNLT_WEAPON:
				team            = BG_Weapon( itemNum )->team;
				unlockThreshold = BG_Weapon( itemNum )->unlockThreshold;
				break;

			case UNLT_UPGRADE:
				team            = TEAM_HUMANS;
				unlockThreshold = BG_Upgrade( itemNum )->unlockThreshold;
				break;

			case UNLT_BUILDABLE:
				team            = BG_Buildable( itemNum )->team;
				unlockThreshold = BG_Buildable( itemNum )->unlockThreshold;
				break;

			case UNLT_CLASS:
				team            = TEAM_ALIENS;
				unlockThreshold = BG_Class( itemNum )->unlockThreshold;
				break;

			default:
				Com_Error( ERR_FATAL, "G_UpdateUnlockables: Unknown unlockable type" );
		}

		unlockThreshold = MAX( unlockThreshold, 0 );
		momentum = level.team[ team ].momentum;

		unlockable->type            = unlockableType;
		unlockable->num             = itemNum;
		unlockable->team            = team;
		unlockable->statusKnown     = true;
		unlockable->unlockThreshold = unlockThreshold;
		unlockable->lockThreshold   = UnlockToLockThreshold( unlockThreshold );

		// calculate the item's locking state
		unlockable->unlocked = (
		    !unlockThreshold || momentum >= unlockThreshold ||
		    ( unlockable->unlocked && momentum >= unlockable->lockThreshold )
		);

		itemNum++;

		/*Com_Printf( "G_UpdateUnlockables: Team %s, Type %s, Item %s, Momentum %d, Threshold %d, "
		            "Unlocked %d, Synchronize %d\n",
		            BG_TeamName( team ), UnlockableTypeName( unlockable ), UnlockableName( unlockable ),
		            momentum, unlockThreshold, unlockable->unlocked, unlockable->synchronize );*/
	}

	// GAME knows about all teams
	unlockablesDataAvailable = true;
	unlockablesTeamKnowledge = TEAM_ALL;

	// generate masks for network transmission
	UpdateUnlockablesMask();
}
Ejemplo n.º 26
0
// TODO: Clean this mess further (split into helper functions)
void G_Damage( gentity_t *target, gentity_t *inflictor, gentity_t *attacker,
               vec3_t dir, vec3_t point, int damage, int damageFlags, int mod )
{
	gclient_t *client;
	int       take, loss;
	int       knockback;
	float     modifier;

	if ( !target || !target->takedamage || target->health <= 0 || level.intermissionQueued )
	{
		return;
	}

	client = target->client;

	// don't handle noclip clients
	if ( client && client->noclip )
	{
		return;
	}

	// set inflictor to world if missing
	if ( !inflictor )
	{
		inflictor = &g_entities[ ENTITYNUM_WORLD ];
	}

	// set attacker to world if missing
	if ( !attacker )
	{
		attacker = &g_entities[ ENTITYNUM_WORLD ];
	}

	// don't handle ET_MOVER w/o die or pain function
	if ( target->s.eType == ET_MOVER && !( target->die || target->pain ) )
	{
		// special case for ET_MOVER with act function in initial position
		if ( ( target->moverState == MOVER_POS1 || target->moverState == ROTATOR_POS1 ) &&
		     target->act )
		{
			target->act( target, inflictor, attacker );
		}

		return;
	}

	// do knockback against clients
	if ( client && !( damageFlags & DAMAGE_NO_KNOCKBACK ) && dir )
	{
		// scale knockback by weapon
		if ( inflictor->s.weapon != WP_NONE )
		{
			knockback = ( int )( ( float )damage * BG_Weapon( inflictor->s.weapon )->knockbackScale );
		}
		else
		{
			knockback = damage;
		}

		// apply generic damage to knockback modifier
		knockback *= DAMAGE_TO_KNOCKBACK;

		// HACK: Too much knockback from falling makes you bounce and looks silly
		if ( mod == MOD_FALLING )
		{
			knockback = MIN( knockback, MAX_FALLDMG_KNOCKBACK );
		}

		G_KnockbackByDir( target, dir, knockback, qfalse );
	}
	else
	{
		// damage knockback gets saved, so initialize it here
		knockback = 0;
	}

	// godmode prevents damage
	if ( target->flags & FL_GODMODE )
	{
		return;
	}

	// check for protection
	if ( !( damageFlags & DAMAGE_NO_PROTECTION ) )
	{
		// check for protection from friendly damage
		if ( target != attacker && G_OnSameTeam( target, attacker ) )
		{
			// check if friendly fire has been disabled
			if ( !g_friendlyFire.integer )
			{
				return;
			}

			// don't do friendly damage on movement attacks
			switch ( mod )
			{
				case MOD_LEVEL3_POUNCE:
				case MOD_LEVEL4_TRAMPLE:
					return;

				default:
					break;
			}

			// if dretchpunt is enabled and this is a dretch, do dretchpunt instead of damage
			if ( g_dretchPunt.integer && target->client &&
			     ( target->client->ps.stats[ STAT_CLASS ] == PCL_ALIEN_LEVEL0 ||
			       target->client->ps.stats[ STAT_CLASS ] == PCL_ALIEN_LEVEL0_UPG ) )
			{
				vec3_t dir, push;

				VectorSubtract( target->r.currentOrigin, attacker->r.currentOrigin, dir );
				VectorNormalizeFast( dir );
				VectorScale( dir, ( damage * 10.0f ), push );
				push[ 2 ] = 64.0f;

				VectorAdd( target->client->ps.velocity, push, target->client->ps.velocity );

				return;
			}
		}

		// for buildables, never protect from damage dealt by building actions
		if ( target->s.eType == ET_BUILDABLE && attacker->client &&
		     mod != MOD_DECONSTRUCT && mod != MOD_SUICIDE &&
		     mod != MOD_REPLACE     && mod != MOD_NOCREEP )
		{
			// check for protection from friendly buildable damage
			if ( G_OnSameTeam( target, attacker ) && !g_friendlyBuildableFire.integer )
			{
				return;
			}
		}
	}

	// update combat timers
	if ( target->client && attacker->client && target != attacker )
	{
		target->client->lastCombatTime   = level.time;
		attacker->client->lastCombatTime = level.time;
	}

	if ( client )
	{
		// save damage (w/o armor modifier), knockback
		client->damage_received  += damage;
		client->damage_knockback += knockback;

		// save damage direction
		if ( dir )
		{
			VectorCopy( dir, client->damage_from );
			client->damage_fromWorld = qfalse;
		}
		else
		{
			VectorCopy( target->r.currentOrigin, client->damage_from );
			client->damage_fromWorld = qtrue;
		}

		// drain jetpack fuel
		client->ps.stats[ STAT_FUEL ] -= damage * JETPACK_FUEL_PER_DMG;
		if ( client->ps.stats[ STAT_FUEL ] < 0 )
		{
			client->ps.stats[ STAT_FUEL ] = 0;
		}

		// apply damage modifier
		modifier = CalcDamageModifier( point, target, (class_t) client->ps.stats[ STAT_CLASS ], damageFlags );
		take = ( int )( ( float )damage * modifier + 0.5f );

		// if boosted poison every attack
		if ( attacker->client &&
		     ( attacker->client->ps.stats[ STAT_STATE ] & SS_BOOSTED ) &&
		     target->client->pers.team == TEAM_HUMANS &&
		     target->client->poisonImmunityTime < level.time )
		{
			switch ( mod )
			{
				case MOD_POISON:
				case MOD_LEVEL1_PCLOUD:
				case MOD_LEVEL2_ZAP:
					break;

				default:
					target->client->ps.stats[ STAT_STATE ] |= SS_POISONED;
					target->client->lastPoisonTime   = level.time;
					target->client->lastPoisonClient = attacker;
			}
		}
	}
	else
	{
		take = damage;
	}

	// make sure damage is done
	if ( take < 1 )
	{
		take = 1;
	}

	if ( g_debugDamage.integer > 0 )
	{
		G_Printf( "G_Damage: %3i (%3i → %3i)\n",
		          take, target->health, target->health - take );
	}

	// do the damage
	target->health = target->health - take;

	if ( target->client )
	{
		target->client->ps.stats[ STAT_HEALTH ] = target->health;
		target->client->pers.infoChangeTime = level.time; // ?
	}

	target->lastDamageTime = level.time;

	// TODO: gentity_t->nextRegenTime only affects alien clients, remove it and use lastDamageTime
	// Optionally (if needed for some reason), move into client struct and add "Alien" to name
	target->nextRegenTime = level.time + ALIEN_CLIENT_REGEN_WAIT;

	// handle non-self damage
	if ( attacker != target )
	{
		if ( target->health < 0 )
		{
			loss = ( take + target->health );
		}
		else
		{
			loss = take;
		}

		if ( attacker->client )
		{
			// add to the attacker's account on the target
			target->credits[ attacker->client->ps.clientNum ] += ( float )loss;

			// notify the attacker of a hit
			NotifyClientOfHit( attacker );
		}

		// update buildable stats
		if ( attacker->s.eType == ET_BUILDABLE && attacker->health > 0 )
		{
			attacker->buildableStatsTotal += loss;
		}
	}

	// handle dying target
	if ( target->health <= 0 )
	{
		// set no knockback flag for clients
		if ( client )
		{
			target->flags |= FL_NO_KNOCKBACK;
		}

		// cap negative health
		if ( target->health < -999 )
		{
			target->health = -999;
		}

		// call die function
		if ( target->die )
		{
			target->die( target, inflictor, attacker, mod );
		}

		// update buildable stats
		if ( attacker->s.eType == ET_BUILDABLE && attacker->health > 0 )
		{
			attacker->buildableStatsCount++;
		}

		// for non-client victims, fire ON_DIE event
		if( !target->client )
		{
			G_EventFireEntity( target, attacker, ON_DIE );
		}

		return;
	}
	else if ( target->pain )
	{
		target->pain( target, attacker, take );
	}
}
Ejemplo n.º 27
0
static int CG_CalcFov( void )
{
	float     y;
	float     phase;
	float     v;
	int       contents;
	float     fov_x, fov_y;
	float     zoomFov;
	float     f;
	int       inwater;
	int       attribFov;
	usercmd_t cmd;
	usercmd_t oldcmd;
	int       cmdNum;

	cmdNum = trap_GetCurrentCmdNumber();
	trap_GetUserCmd( cmdNum, &cmd );
	trap_GetUserCmd( cmdNum - 1, &oldcmd );

	// switch follow modes if necessary: cycle between free -> follow -> third-person follow
	if ( usercmdButtonPressed( cmd.buttons, BUTTON_USE_HOLDABLE ) && !usercmdButtonPressed( oldcmd.buttons, BUTTON_USE_HOLDABLE ) )
	{
		if ( cg.snap->ps.pm_flags & PMF_FOLLOW )
		{
			if ( !cg.chaseFollow )
			{
				cg.chaseFollow = qtrue;
			}
			else
			{
				cg.chaseFollow = qfalse;
				trap_SendClientCommand( "follow\n" );
			}
		}
		else if ( cg.snap->ps.persistant[ PERS_SPECSTATE ] != SPECTATOR_NOT )
		{
			trap_SendClientCommand( "follow\n" );
		}
	}

	if ( cg.predictedPlayerState.pm_type == PM_INTERMISSION ||
	     ( cg.snap->ps.persistant[ PERS_SPECSTATE ] != SPECTATOR_NOT ) ||
	     ( cg.renderingThirdPerson ) )
	{
		// if in intermission or third person, use a fixed value
		fov_y = BASE_FOV_Y;
	}
	else
	{
		// don't lock the fov globally - we need to be able to change it
		if ( ( attribFov = trap_Cvar_VariableIntegerValue( BG_Class( cg.predictedPlayerState.stats[ STAT_CLASS ] )->fovCvar ) ) )
		{
			if ( attribFov < 80 )
			{
				attribFov = 80;
			}
			else if ( attribFov >= 140 )
			{
				attribFov = 140;
			}
		}
		else
		{
			attribFov = BG_Class( cg.predictedPlayerState.stats[ STAT_CLASS ] )->fov;
		}
		attribFov *= 0.75;
		fov_y = attribFov;

		if ( fov_y < 1.0f )
		{
			fov_y = 1.0f;
		}
		else if ( fov_y > MAX_FOV_Y )
		{
			fov_y = MAX_FOV_Y;
		}

		if ( cg.spawnTime > ( cg.time - FOVWARPTIME ) &&
		     BG_ClassHasAbility( cg.predictedPlayerState.stats[ STAT_CLASS ], SCA_FOVWARPS ) )
		{
			float fraction = ( float )( cg.time - cg.spawnTime ) / FOVWARPTIME;

			fov_y = MAX_FOV_WARP_Y - ( ( MAX_FOV_WARP_Y - fov_y ) * fraction );
		}

		// account for zooms
		zoomFov = BG_Weapon( cg.predictedPlayerState.weapon )->zoomFov * 0.75f;

		if ( zoomFov < 1.0f )
		{
			zoomFov = 1.0f;
		}
		else if ( zoomFov > attribFov )
		{
			zoomFov = attribFov;
		}

		// only do all the zoom stuff if the client CAN zoom
		// FIXME: zoom control is currently hard coded to WBUTTON_ATTACK2
		if ( BG_Weapon( cg.predictedPlayerState.weapon )->canZoom )
		{
			if ( cg.zoomed )
			{
				f = ( cg.time - cg.zoomTime ) / ( float ) ZOOM_TIME;

				if ( f > 1.0f )
				{
					fov_y = zoomFov;
				}
				else
				{
					fov_y = fov_y + f * ( zoomFov - fov_y );
				}

				// WBUTTON_ATTACK2 isn't held so unzoom next time
				if ( !usercmdButtonPressed( cmd.buttons, BUTTON_ATTACK2 ) || cg.snap->ps.weaponstate == WEAPON_RELOADING )
				{
					cg.zoomed = qfalse;
					cg.zoomTime = MIN( cg.time,
					                   cg.time + cg.time - cg.zoomTime - ZOOM_TIME );
				}
			}
			else
			{
				f = ( cg.time - cg.zoomTime ) / ( float ) ZOOM_TIME;

				if ( f < 1.0f )
				{
					fov_y = zoomFov + f * ( fov_y - zoomFov );
				}

				// WBUTTON_ATTACK2 is held so zoom next time
				if ( usercmdButtonPressed( cmd.buttons, BUTTON_ATTACK2 ) && cg.snap->ps.weaponstate != WEAPON_RELOADING )
				{
					cg.zoomed = qtrue;
					cg.zoomTime = MIN( cg.time,
					                   cg.time + cg.time - cg.zoomTime - ZOOM_TIME );
				}
			}
		}
		else if ( cg.zoomed )
		{
			cg.zoomed = qfalse;
		}
	}

	y = cg.refdef.height / tan( 0.5f * DEG2RAD( fov_y ) );
	fov_x = atan2( cg.refdef.width, y );
	fov_x = 2.0f * RAD2DEG( fov_x );

	// warp if underwater
	contents = CG_PointContents( cg.refdef.vieworg, -1 );

	if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) )
	{
		phase = cg.time / 1000.0f * WAVE_FREQUENCY * M_PI * 2.0f;
		v = WAVE_AMPLITUDE * sin( phase );
		fov_x += v;
		fov_y -= v;
		inwater = qtrue;
	}
	else
	{
		inwater = qfalse;
	}

	// set it
	cg.refdef.fov_x = fov_x;
	cg.refdef.fov_y = fov_y;

	if ( !cg.zoomed )
	{
		cg.zoomSensitivity = 1.0f;
	}
	else
	{
		cg.zoomSensitivity = cg.refdef.fov_y / 75.0f;
	}

	return inwater;
}
Ejemplo n.º 28
0
/*
=================================================================================

trigger_ammo

=================================================================================
*/
void env_afx_ammo_touch( gentity_t *self, gentity_t *other, trace_t* )
{
	int      maxClips, maxAmmo;
	weapon_t weapon;

	if ( !other->client )
	{
		return;
	}

	if ( other->client->pers.team != TEAM_HUMANS )
	{
		return;
	}

	if ( self->timestamp > level.time )
	{
		return;
	}

	if ( other->client->ps.weaponstate != WEAPON_READY )
	{
		return;
	}

	weapon = BG_PrimaryWeapon( other->client->ps.stats );

	if ( BG_Weapon( weapon )->usesEnergy && ( self->spawnflags & 2 ) )
	{
		return;
	}

	if ( !BG_Weapon( weapon )->usesEnergy && ( self->spawnflags & 4 ) )
	{
		return;
	}

	if ( self->spawnflags & 1 )
	{
		self->timestamp = level.time + 1000;
	}
	else
	{
		self->timestamp = level.time + FRAMETIME;
	}

	maxAmmo = BG_Weapon( weapon )->maxAmmo;
	maxClips = BG_Weapon( weapon )->maxClips;

	if ( ( other->client->ps.ammo + self->config.amount ) > maxAmmo )
	{
		if ( other->client->ps.clips < maxClips )
		{
			other->client->ps.clips++;
			other->client->ps.ammo = 1;
		}
		else
		{
			other->client->ps.ammo = maxAmmo;
		}
	}
	else
	{
		other->client->ps.ammo += self->config.amount;
	}
}
Ejemplo n.º 29
0
/*
===========
ClientSpawn

Called every time a client is placed fresh in the world:
after the first ClientBegin, and after each respawn and evolve
Initializes all non-persistent parts of playerState
============
*/
void ClientSpawn( gentity_t *ent, gentity_t *spawn, const vec3_t origin, const vec3_t angles )
{
	int                index;
	vec3_t             spawn_origin, spawn_angles;
	gclient_t          *client;
	int                i;
	clientPersistant_t saved;
	clientSession_t    savedSess;
	bool           savedNoclip, savedCliprcontents;
	int                persistant[ MAX_PERSISTANT ];
	gentity_t          *spawnPoint = nullptr;
	int                flags;
	int                savedPing;
	int                teamLocal;
	int                eventSequence;
	char               userinfo[ MAX_INFO_STRING ];
	vec3_t             up = { 0.0f, 0.0f, 1.0f };
	int                maxAmmo, maxClips;
	weapon_t           weapon;

	ClientSpawnCBSE(ent, ent == spawn);

	index = ent - g_entities;
	client = ent->client;

	teamLocal = client->pers.team;

	//if client is dead and following teammate, stop following before spawning
	if ( client->sess.spectatorClient != -1 )
	{
		client->sess.spectatorClient = -1;
		client->sess.spectatorState = SPECTATOR_FREE;
	}

	// only start client if chosen a class and joined a team
	if ( client->pers.classSelection == PCL_NONE && teamLocal == TEAM_NONE )
	{
		client->sess.spectatorState = SPECTATOR_FREE;
	}
	else if ( client->pers.classSelection == PCL_NONE )
	{
		client->sess.spectatorState = SPECTATOR_LOCKED;
	}

	// if client is dead and following teammate, stop following before spawning
	if ( ent->client->sess.spectatorState == SPECTATOR_FOLLOW )
	{
		G_StopFollowing( ent );
	}

	if ( origin != nullptr )
	{
		VectorCopy( origin, spawn_origin );
	}

	if ( angles != nullptr )
	{
		VectorCopy( angles, spawn_angles );
	}

	// find a spawn point
	// do it before setting health back up, so farthest
	// ranging doesn't count this client
	if ( client->sess.spectatorState != SPECTATOR_NOT )
	{
		if ( teamLocal == TEAM_NONE )
		{
			spawnPoint = G_SelectSpectatorSpawnPoint( spawn_origin, spawn_angles );
		}
		else if ( teamLocal == TEAM_ALIENS )
		{
			spawnPoint = G_SelectAlienLockSpawnPoint( spawn_origin, spawn_angles );
		}
		else if ( teamLocal == TEAM_HUMANS )
		{
			spawnPoint = G_SelectHumanLockSpawnPoint( spawn_origin, spawn_angles );
		}
	}
	else
	{
		if ( spawn == nullptr )
		{
			Com_Error(errorParm_t::ERR_DROP,  "ClientSpawn: spawn is NULL" );
		}

		spawnPoint = spawn;

		if ( spawnPoint->s.eType == entityType_t::ET_BUILDABLE )
		{
			G_SetBuildableAnim( spawnPoint, BANIM_SPAWN1, true );

			if ( spawnPoint->buildableTeam == TEAM_ALIENS )
			{
				spawnPoint->clientSpawnTime = ALIEN_SPAWN_REPEAT_TIME;
			}
			else if ( spawnPoint->buildableTeam == TEAM_HUMANS )
			{
				spawnPoint->clientSpawnTime = HUMAN_SPAWN_REPEAT_TIME;
			}
		}
	}

	// toggle the teleport bit so the client knows to not lerp
	flags = ( ent->client->ps.eFlags & EF_TELEPORT_BIT ) ^ EF_TELEPORT_BIT;
	G_UnlaggedClear( ent );

	// clear everything but the persistent data

	saved = client->pers;
	savedSess = client->sess;
	savedPing = client->ps.ping;
	savedNoclip = client->noclip;
	savedCliprcontents = client->cliprcontents;

	for ( i = 0; i < MAX_PERSISTANT; i++ )
	{
		persistant[ i ] = client->ps.persistant[ i ];
	}

	eventSequence = client->ps.eventSequence;
	memset( client, 0, sizeof( *client ) );

	client->pers = saved;
	client->sess = savedSess;
	client->ps.ping = savedPing;
	client->noclip = savedNoclip;
	client->cliprcontents = savedCliprcontents;

	for ( i = 0; i < MAX_PERSISTANT; i++ )
	{
		client->ps.persistant[ i ] = persistant[ i ];
	}

	client->ps.eventSequence = eventSequence;

	// increment the spawncount so the client will detect the respawn
	client->ps.persistant[ PERS_SPAWN_COUNT ]++;
	client->ps.persistant[ PERS_SPECSTATE ] = client->sess.spectatorState;

	client->airOutTime = level.time + 12000;

	trap_GetUserinfo( index, userinfo, sizeof( userinfo ) );
	client->ps.eFlags = flags;

	//Log::Notice( "ent->client->pers->pclass = %i\n", ent->client->pers.classSelection );

	ent->s.groundEntityNum = ENTITYNUM_NONE;
	ent->client = &level.clients[ index ];
	ent->classname = S_PLAYER_CLASSNAME;
	if ( client->noclip )
	{
		client->cliprcontents = CONTENTS_BODY;
	}
	else
	{
		ent->r.contents = CONTENTS_BODY;
	}
	ent->clipmask = MASK_PLAYERSOLID;
	ent->die = G_PlayerDie;
	ent->waterlevel = 0;
	ent->watertype = 0;
	ent->flags &= FL_GODMODE | FL_NOTARGET;

	// calculate each client's acceleration
	ent->evaluateAcceleration = true;

	client->ps.stats[ STAT_MISC ] = 0;

	client->ps.eFlags = flags;
	client->ps.clientNum = index;

	BG_ClassBoundingBox( ent->client->pers.classSelection, ent->r.mins, ent->r.maxs, nullptr, nullptr, nullptr );

	// clear entity values
	if ( ent->client->pers.classSelection == PCL_HUMAN_NAKED )
	{
		BG_AddUpgradeToInventory( UP_MEDKIT, client->ps.stats );
		weapon = client->pers.humanItemSelection;
	}
	else if ( client->sess.spectatorState == SPECTATOR_NOT )
	{
		weapon = BG_Class( ent->client->pers.classSelection )->startWeapon;
	}
	else
	{
		weapon = WP_NONE;
	}

	maxAmmo = BG_Weapon( weapon )->maxAmmo;
	maxClips = BG_Weapon( weapon )->maxClips;
	client->ps.stats[ STAT_WEAPON ] = weapon;
	client->ps.ammo = maxAmmo;
	client->ps.clips = maxClips;

	// We just spawned, not changing weapons
	client->ps.persistant[ PERS_NEWWEAPON ] = 0;

	client->ps.persistant[ PERS_TEAM ] = client->pers.team;

	// TODO: Check whether stats can be cleared at once instead of per field
	client->ps.stats[ STAT_STAMINA ] = STAMINA_MAX;
	client->ps.stats[ STAT_FUEL ]    = JETPACK_FUEL_MAX;
	client->ps.stats[ STAT_CLASS ] = ent->client->pers.classSelection;
	client->ps.stats[ STAT_BUILDABLE ] = BA_NONE;
	client->ps.stats[ STAT_PREDICTION ] = 0;
	client->ps.stats[ STAT_STATE ] = 0;

	VectorSet( client->ps.grapplePoint, 0.0f, 0.0f, 1.0f );

	//clear the credits array
	// TODO: Handle in HealthComponent or ClientComponent.
	for ( i = 0; i < MAX_CLIENTS; i++ )
	{
		ent->credits[ i ].value = 0.0f;
		ent->credits[ i ].time = 0;
		ent->credits[ i ].team = TEAM_NONE;
	}

	G_SetOrigin( ent, spawn_origin );
	VectorCopy( spawn_origin, client->ps.origin );

	//give aliens some spawn velocity
	if ( client->sess.spectatorState == SPECTATOR_NOT &&
	     client->pers.team == TEAM_ALIENS )
	{
		if ( ent == spawn )
		{
			//evolution particle system
			G_AddPredictableEvent( ent, EV_ALIEN_EVOLVE, DirToByte( up ) );
		}
		else
		{
			spawn_angles[ YAW ] += 180.0f;
			AngleNormalize360( spawn_angles[ YAW ] );

			if ( spawnPoint->s.origin2[ 2 ] > 0.0f )
			{
				vec3_t forward, dir;

				AngleVectors( spawn_angles, forward, nullptr, nullptr );
				VectorAdd( spawnPoint->s.origin2, forward, dir );
				VectorNormalize( dir );
				VectorScale( dir, BG_Class( ent->client->pers.classSelection )->jumpMagnitude,
				             client->ps.velocity );
			}

			G_AddPredictableEvent( ent, EV_PLAYER_RESPAWN, 0 );
		}
	}
	else if ( client->sess.spectatorState == SPECTATOR_NOT &&
	          client->pers.team == TEAM_HUMANS )
	{
		spawn_angles[ YAW ] += 180.0f;
		AngleNormalize360( spawn_angles[ YAW ] );
	}

	// the respawned flag will be cleared after the attack and jump keys come up
	client->ps.pm_flags |= PMF_RESPAWNED;

	trap_GetUsercmd( client - level.clients, &ent->client->pers.cmd );
	G_SetClientViewAngle( ent, spawn_angles );

	if ( client->sess.spectatorState == SPECTATOR_NOT )
	{
		trap_LinkEntity( ent );

		// force the base weapon up
		if ( client->pers.team == TEAM_HUMANS )
		{
			G_ForceWeaponChange( ent, weapon );
		}

		client->ps.weaponstate = WEAPON_READY;
	}

	// don't allow full run speed for a bit
	client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
	client->ps.pm_time = 100;

	client->respawnTime = level.time;
	ent->nextRegenTime = level.time;

	client->inactivityTime = level.time + g_inactivity.integer * 1000;
	usercmdClearButtons( client->latched_buttons );

	// set default animations
	client->ps.torsoAnim = TORSO_STAND;
	client->ps.legsAnim = LEGS_IDLE;

	if ( level.intermissiontime )
	{
		MoveClientToIntermission( ent );
	}
	else
	{
		// fire the targets of the spawn point
		if ( !spawn && spawnPoint )
		{
			G_EventFireEntity( spawnPoint, ent, ON_SPAWN );
		}

		// select the highest weapon number available, after any
		// spawn given items have fired
		client->ps.weapon = 1;

		for ( i = WP_NUM_WEAPONS - 1; i > 0; i-- )
		{
			if ( BG_InventoryContainsWeapon( i, client->ps.stats ) )
			{
				client->ps.weapon = i;
				break;
			}
		}
	}

	// run a client frame to drop exactly to the floor,
	// initialize animations and other things
	client->ps.commandTime = level.time - 100;
	ent->client->pers.cmd.serverTime = level.time;
	ClientThink( ent - g_entities );

	// positively link the client, even if the command times are weird
	if ( client->sess.spectatorState == SPECTATOR_NOT )
	{
		BG_PlayerStateToEntityState( &client->ps, &ent->s, true );
		VectorCopy( ent->client->ps.origin, ent->r.currentOrigin );
		trap_LinkEntity( ent );
	}

	// must do this here so the number of active clients is calculated
	CalculateRanks();

	// run the presend to set anything else
	ClientEndFrame( ent );

	// clear entity state values
	BG_PlayerStateToEntityState( &client->ps, &ent->s, true );

	client->pers.infoChangeTime = level.time;

	// (re)tag the client for its team
	Beacon::DeleteTags( ent );
	Beacon::Tag( ent, (team_t)ent->client->ps.persistant[ PERS_TEAM ], true );
}
Ejemplo n.º 30
0
/*
===============
CG_HumanText
===============
*/
static void CG_HumanText( char *text, playerState_t *ps )
{
	const char *name;
	upgrade_t upgrade = UP_NONE;

	if ( cg.weaponSelect < 32 )
	{
		name = cg_weapons[ cg.weaponSelect ].humanName;
	}
	else
	{
		name = cg_upgrades[ cg.weaponSelect - 32 ].humanName;
		upgrade = (upgrade_t) ( cg.weaponSelect - 32 );
	}

	if ( !ps->ammo && !ps->clips && !BG_Weapon( ps->weapon )->infiniteAmmo )
	{
		//no ammo
		switch ( ps->weapon )
		{
			case WP_MACHINEGUN:
			case WP_CHAINGUN:
			case WP_SHOTGUN:
			case WP_FLAMER:
				Q_strcat( text, MAX_TUTORIAL_TEXT,
				          _( "Find an Armoury for more ammo\n" ) );
				break;

			case WP_LAS_GUN:
			case WP_PULSE_RIFLE:
			case WP_MASS_DRIVER:
			case WP_LUCIFER_CANNON:
				Q_strcat( text, MAX_TUTORIAL_TEXT,
				          _( "Find an Armoury, Reactor, or Repeater for more ammo\n" ) );
				break;

			default:
				break;
		}
	}
	else
	{
		switch ( ps->weapon )
		{
			case WP_BLASTER:
			case WP_MACHINEGUN:
			case WP_SHOTGUN:
			case WP_LAS_GUN:
			case WP_CHAINGUN:
			case WP_PULSE_RIFLE:
			case WP_FLAMER:
				Q_strcat( text, MAX_TUTORIAL_TEXT,
				          va( _( "Press %s to fire the %s\n" ),
				              CG_KeyNameForCommand( "+attack" ),
				              _( BG_Weapon( ps->weapon )->humanName ) ) );
				break;

			case WP_MASS_DRIVER:
				Q_strcat( text, MAX_TUTORIAL_TEXT,
				          va( _( "Press %s to fire the %s\n" ),
				              CG_KeyNameForCommand( "+attack" ),
				              _( BG_Weapon( ps->weapon )->humanName ) ) );

				Q_strcat( text, MAX_TUTORIAL_TEXT,
				          va( _( "Hold %s to zoom\n" ),
				              CG_KeyNameForCommand( "+attack2" ) ) );
				break;

			case WP_PAIN_SAW:
				Q_strcat( text, MAX_TUTORIAL_TEXT,
				          va( _( "Hold %s to activate the %s\n" ),
				              CG_KeyNameForCommand( "+attack" ),
				              _( BG_Weapon( ps->weapon )->humanName ) ) );
				break;

			case WP_LUCIFER_CANNON:
				Q_strcat( text, MAX_TUTORIAL_TEXT,
				          va( _( "Hold and release %s to fire a charged shot\n" ),
				              CG_KeyNameForCommand( "+attack" ) ) );

				Q_strcat( text, MAX_TUTORIAL_TEXT,
				          va( _( "Press %s to fire the %s\n" ),
				              CG_KeyNameForCommand( "+attack2" ),
				              _( BG_Weapon( ps->weapon )->humanName ) ) );
				break;

			case WP_HBUILD:
				CG_HumanCkitText( text, ps );
				break;

			default:
				break;
		}
	}

	if ( upgrade == UP_NONE ||
	     ( upgrade > UP_NONE && BG_Upgrade( upgrade )->usable ) )
	{
		Q_strcat( text, MAX_TUTORIAL_TEXT,
		          va( _( "Press %s to use the %s\n" ),
		              CG_KeyNameForCommand( "+useitem" ),
		              name ) );
	}

	if ( ps->stats[ STAT_HEALTH ] <= 35 &&
	     BG_InventoryContainsUpgrade( UP_MEDKIT, ps->stats ) )
	{
		Q_strcat( text, MAX_TUTORIAL_TEXT,
		          va( _( "Press %s to use your %s\n" ),
		              CG_KeyNameForCommand( "itemact medkit" ),
		              _( BG_Upgrade( UP_MEDKIT )->humanName ) ) );
	}

	switch ( cg.nearUsableBuildable )
	{
		case BA_H_ARMOURY:
			Q_strcat( text, MAX_TUTORIAL_TEXT,
			          va( _( "Press %s to buy equipment upgrades at the %s\n" ),
			              CG_KeyNameForCommand( "+activate" ),
			              _( BG_Buildable( cg.nearUsableBuildable )->humanName ) ) );
			break;

		case BA_NONE:
			break;

		default:
			Q_strcat( text, MAX_TUTORIAL_TEXT,
			          va( _( "Press %s to use the %s\n" ),
			              CG_KeyNameForCommand( "+activate" ),
			              _( BG_Buildable( cg.nearUsableBuildable )->humanName ) ) );
			break;
	}

	Q_strcat( text, MAX_TUTORIAL_TEXT,
	          va( _( "Press %s and any direction to sprint\n" ),
	              CG_KeyNameForCommand( "+sprint" ) ) );

	if ( BG_InventoryContainsUpgrade( UP_FIREBOMB, ps->stats ) ||
		BG_InventoryContainsUpgrade( UP_GRENADE, ps->stats ) )
	{
		Q_strcat( text, MAX_TUTORIAL_TEXT, va( _( "Press %s to throw a grenade\n" ),
			CG_KeyNameForCommand( "itemact grenade" )
		));
	}
}