Exemple #1
0
/*
================
G_ForceWeaponChange
================
*/
void G_ForceWeaponChange( gentity_t *ent, weapon_t weapon )
{
  int i;

  if( ent )
  {
    ent->client->ps.pm_flags |= PMF_WEAPON_SWITCH;

    if( weapon == WP_NONE )
    {
      //switch to the first non blaster weapon
      for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ )
      {
        if( i == WP_BLASTER )
          continue;

        if( BG_InventoryContainsWeapon( i, ent->client->ps.stats ) )
        {
          ent->client->ps.persistant[ PERS_NEWWEAPON ] = i;
          break;
        }
      }

      //only got the blaster to switch to
      if( i == WP_NUM_WEAPONS )
        ent->client->ps.persistant[ PERS_NEWWEAPON ] = WP_BLASTER;
    }
    else
      ent->client->ps.persistant[ PERS_NEWWEAPON ] = weapon;
  }
}
Exemple #2
0
/*
================
G_ForceWeaponChange
================
*/
void G_ForceWeaponChange( playerState_t *ps, weapon_t weapon )
{
	// stop a reload in progress
	if ( ps->weaponstate == WEAPON_RELOADING )
	{
		ps->torsoAnim = ( ( ps->torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | TORSO_RAISE;
		ps->weaponTime = 250;
		ps->weaponstate = WEAPON_READY;
	}

	if ( weapon == WP_NONE ||
	     !BG_InventoryContainsWeapon( weapon, ps->stats ) )
	{
		// switch to the first non blaster weapon
		ps->persistant[ PERS_NEWWEAPON ] =
		  BG_PrimaryWeapon( ps->stats );
	}
	else
	{
		ps->persistant[ PERS_NEWWEAPON ] = weapon;
	}

	// force this here to prevent flamer effect from continuing
	ps->generic1 = WPM_NOTFIRING;

	// The PMove will do an animated drop, raise, and set the new weapon
	ps->pm_flags |= PMF_WEAPON_SWITCH;
}
Exemple #3
0
/*
===============
CG_WeaponSelectable
===============
*/
static qboolean CG_WeaponSelectable( weapon_t weapon )
{
  if( !BG_InventoryContainsWeapon( weapon, cg.snap->ps.stats ) )
    return qfalse;

  return qtrue;
}
Exemple #4
0
/*
===============
CG_SetUIVars

Set some cvars used by the UI
===============
*/
static void CG_SetUIVars( void )
{
	int  i;
	char carriageCvar[ MAX_TOKEN_CHARS ];

	*carriageCvar = 0;

	//determine what the player is carrying
	for ( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ )
	{
		if ( BG_InventoryContainsWeapon( i, cg.snap->ps.stats ) &&
		     BG_FindPurchasableForWeapon( i ) )
		{
			strcat( carriageCvar, va( "W%d ", i ) );
		}
	}

	for ( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ )
	{
		if ( BG_InventoryContainsUpgrade( i, cg.snap->ps.stats ) &&
		     BG_FindPurchasableForUpgrade( i ) )
		{
			strcat( carriageCvar, va( "U%d ", i ) );
		}
	}

	strcat( carriageCvar, "$" );

	trap_Cvar_Set( "ui_carriage", carriageCvar );

	trap_Cvar_Set( "ui_stages", va( "%d %d", cgs.alienStage, cgs.humanStage ) );
}
/*
===============
trigger_equipment_match
===============
*/
qboolean trigger_equipment_match( gentity_t *self, gentity_t *activator )
{
    int i = 0;

    if( !activator )
        return qfalse;

    //if there is no equipment list all equipment triggers (stupid case)
    if( self->wTriggers[ i ] == WP_NONE && self->uTriggers[ i ] == UP_NONE )
        return qtrue;
    else
    {
        //otherwise check against the lists
        for( i = 0; self->wTriggers[ i ] != WP_NONE; i++ )
        {
            if( BG_InventoryContainsWeapon( self->wTriggers[ i ], activator->client->ps.stats ) )
                return qtrue;
        }

        for( i = 0; self->uTriggers[ i ] != UP_NONE; i++ )
        {
            if( BG_InventoryContainsUpgrade( self->uTriggers[ i ], activator->client->ps.stats ) )
                return qtrue;
        }
    }

    return qfalse;
}
Exemple #6
0
/*
===============
trigger_equipment_trigger
===============
*/
void trigger_equipment_trigger(gentity_t * self, gentity_t * activator)
{
	int             i = 0;

	//sanity check
	if(!activator->client)
		return;

	if(activator->client->ps.stats[STAT_PTEAM] != PTE_HUMANS)
		return;

	self->activator = activator;
	if(self->nextthink)
		return;					// can't retrigger until the wait is over

	//if there is no equipment list all equipment triggers (stupid case)
	if(self->wTriggers[i] == WP_NONE && self->wTriggers[i] == UP_NONE)
		G_UseTargets(self, activator);
	else
	{
		//otherwise check against the lists
		for(i = 0; self->wTriggers[i] != WP_NONE; i++)
		{
			if(BG_InventoryContainsWeapon(self->wTriggers[i], activator->client->ps.stats))
			{
				G_UseTargets(self, activator);
				return;
			}
		}

		for(i = 0; self->uTriggers[i] != UP_NONE; i++)
		{
			if(BG_InventoryContainsUpgrade(self->uTriggers[i], activator->client->ps.stats))
			{
				G_UseTargets(self, activator);
				return;
			}
		}
	}

	if(self->wait > 0)
	{
		self->think = multi_wait;
		self->nextthink = level.time + (self->wait + self->random * crandom()) * 1000;
	}
	else
	{
		// we can't just remove (self) here, because this is a touch function
		// called while looping through area links...
		self->touch = 0;
		self->nextthink = level.time + FRAMETIME;
		self->think = G_FreeEntity;
	}
}
/*
================
G_ForceWeaponChange
================
*/
void G_ForceWeaponChange( gentity_t *ent, weapon_t weapon )
{
  int i;

  if( ent )
  {
    ent->client->ps.pm_flags |= PMF_WEAPON_SWITCH;

    if( weapon == WP_NONE 
      || !BG_InventoryContainsWeapon( weapon, ent->client->ps.stats ))
    {
      //switch to the first non blaster weapon
      for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ )
      {
        if( i == WP_BLASTER )
          continue;

        if( BG_InventoryContainsWeapon( i, ent->client->ps.stats ) )
        {
          ent->client->ps.persistant[ PERS_NEWWEAPON ] = i;
          break;
        }
      }

      //only got the blaster to switch to
      if( i == WP_NUM_WEAPONS )
        ent->client->ps.persistant[ PERS_NEWWEAPON ] = WP_BLASTER;
    }
    else
      ent->client->ps.persistant[ PERS_NEWWEAPON ] = weapon;
   
    // Lak: The following hack has been moved to PM_BeginWeaponChange, but I'm going to
    // redundantly leave it here as well just in case there's a case I'm forgetting
    // because I don't want to face the gameplay consequences such an error would have

    // force this here to prevent flamer effect from continuing 
    ent->client->ps.generic1 = WPM_NOTFIRING;

    ent->client->ps.weapon = ent->client->ps.persistant[ PERS_NEWWEAPON ];
  }
}
Exemple #8
0
/*
================
G_ForceWeaponChange
================
*/
void G_ForceWeaponChange( gentity_t *ent, weapon_t weapon )
{
    int i;

    if( ent )
    {
        ent->client->ps.pm_flags |= PMF_WEAPON_SWITCH;

        if( weapon == WP_NONE
                || !BG_InventoryContainsWeapon( weapon, ent->client->ps.stats ))
        {
            //switch to the first non blaster weapon
            for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ )
            {
                if( i == WP_BLASTER )
                    continue;

                if( BG_InventoryContainsWeapon( i, ent->client->ps.stats ) )
                {
                    ent->client->ps.persistant[ PERS_NEWWEAPON ] = i;
                    break;
                }
            }

            //only got the blaster to switch to
            if( i == WP_NUM_WEAPONS )
                ent->client->ps.persistant[ PERS_NEWWEAPON ] = WP_BLASTER;
        }
        else
            ent->client->ps.persistant[ PERS_NEWWEAPON ] = weapon;

        // force this here to prevent flamer effect from continuing
        ent->client->ps.generic1 = WPM_NOTFIRING;

        ent->client->ps.weapon = ent->client->ps.persistant[ PERS_NEWWEAPON ];
    }
}
Exemple #9
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 );
	}
}
Exemple #10
0
/*
===============
CG_WeaponSelectable
===============
*/
static qboolean CG_WeaponSelectable( weapon_t weapon )
{
  //int ammo, clips;
  //
  //BG_UnpackAmmoArray( i, cg.snap->ps.ammo, cg.snap->ps.powerups, &ammo, &clips );
  //
  //TA: this is a pain in the ass
  //if( !ammo && !clips && !BG_FindInfinteAmmoForWeapon( i ) )
  //  return qfalse;

  if( !BG_InventoryContainsWeapon( weapon, cg.snap->ps.stats ) )
    return qfalse;

  return qtrue;
}
Exemple #11
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 );
	}
}
/*
=================
G_GiveClientMaxAmmo
=================
*/
void G_GiveClientMaxAmmo( gentity_t *ent, qboolean buyingEnergyAmmo )
{
  int       i;
  int       maxAmmo, maxClips;
  qboolean  weaponType, restoredAmmo = qfalse;

  for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ )
  {
    if( buyingEnergyAmmo )
      weaponType = BG_FindUsesEnergyForWeapon( i );
    else
      weaponType = !BG_FindUsesEnergyForWeapon( i );

    if( BG_InventoryContainsWeapon( i, ent->client->ps.stats ) &&
        weaponType && !BG_FindInfinteAmmoForWeapon( i ) &&
        !BG_WeaponIsFull( i, ent->client->ps.stats,
          ent->client->ps.ammo, ent->client->ps.powerups ) )
    {
      BG_FindAmmoForWeapon( i, &maxAmmo, &maxClips );

	if(ent->client->pers.trippleammo == 1)
    {
		maxAmmo*=3;
    }

      if( buyingEnergyAmmo )
      {
        G_AddEvent( ent, EV_RPTUSE_SOUND, 0 );

        if( BG_InventoryContainsUpgrade( UP_BATTPACK, ent->client->ps.stats ) )
          maxAmmo = (int)( (float)maxAmmo * BATTPACK_MODIFIER );
      }

      BG_PackAmmoArray( i, ent->client->ps.ammo, ent->client->ps.powerups,
                        maxAmmo, maxClips );

      restoredAmmo = qtrue;
    }
  }

  if( restoredAmmo )
    G_ForceWeaponChange( ent, ent->client->ps.weapon );
}
Exemple #13
0
/*
===================
CG_DrawItemSelectText
===================
*/
void CG_DrawItemSelectText( rectDef_t *rect, float scale, int textStyle )
{
  int x, w;
  char  *name;
  float *color;

  color = CG_FadeColor( cg.weaponSelectTime, WEAPON_SELECT_TIME );
  if( !color )
    return;

  trap_R_SetColor( color );

  // draw the selected name
  if( cg.weaponSelect <= 32 )
  {
    if( cg_weapons[ cg.weaponSelect ].registered &&
        BG_InventoryContainsWeapon( cg.weaponSelect, cg.snap->ps.stats ) )
    {
      if( ( name = cg_weapons[ cg.weaponSelect ].humanName ) )
      {
        w = CG_Text_Width( name, scale, 0 );
        x = rect->x + rect->w / 2;
        CG_Text_Paint( x - w / 2, rect->y + rect->h, scale, color, name, 0, 0, textStyle );
      }
    }
  }
  else if( cg.weaponSelect > 32 )
  {
    if( cg_upgrades[ cg.weaponSelect - 32 ].registered &&
        BG_InventoryContainsUpgrade( cg.weaponSelect - 32, cg.snap->ps.stats ) )
    {
      if( ( name = cg_upgrades[ cg.weaponSelect - 32 ].humanName ) )
      {
        w = CG_Text_Width( name, scale, 0 );
        x = rect->x + rect->w / 2;
        CG_Text_Paint( x - w / 2, rect->y + rect->h, scale, color, name, 0, 0, textStyle );
      }
    }
  }

  trap_R_SetColor( NULL );
}
Exemple #14
0
void G_ForceWeaponChange( gentity_t *ent, weapon_t weapon )
{
	playerState_t *ps = &ent->client->ps;

	if ( weapon == WP_NONE || !BG_InventoryContainsWeapon( weapon, ps->stats ) )
	{
		// switch to the first non blaster weapon
		ps->persistant[ PERS_NEWWEAPON ] = BG_PrimaryWeapon( ent->client->ps.stats );
	}
	else
	{
		ps->persistant[ PERS_NEWWEAPON ] = weapon;
	}

	// force this here to prevent flamer effect from continuing
	ps->generic1 = WPM_NOTFIRING;

	// The PMove will do an animated drop, raise, and set the new weapon
	ps->pm_flags |= PMF_WEAPON_SWITCH;
}
Exemple #15
0
/*
===============
CG_Weapon_f
===============
*/
void CG_Weapon_f( void )
{
  int   num;

  if( !cg.snap )
    return;

  if( cg.snap->ps.pm_flags & PMF_FOLLOW )
    return;

  num = atoi( CG_Argv( 1 ) );

  if( num < 1 || num > 31 )
    return;

  cg.weaponSelectTime = cg.time;

  if( !BG_InventoryContainsWeapon( num, cg.snap->ps.stats ) )
    return;   // don't have the weapon

  cg.weaponSelect = num;
}
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 );
}
/*
===============
sensor_equipment_match
===============
*/
qboolean sensor_equipment_match( gentity_t *self, gentity_t *activator )
{
	int i = 0;

	if ( !activator )
	{
		return qfalse;
	}

	if ( self->conditions.weapons[ i ] == WP_NONE && self->conditions.upgrades[ i ] == UP_NONE )
	{
		//if there is no equipment list all equipment triggers for the old behavior of target_equipment, but not the new or different one
		return qtrue;
	}
	else
	{
		//otherwise check against the lists
		for ( i = 0; self->conditions.weapons[ i ] != WP_NONE; i++ )
		{
			if ( BG_InventoryContainsWeapon( self->conditions.weapons[ i ], activator->client->ps.stats ) )
			{
				return qtrue;
			}
		}

		for ( i = 0; self->conditions.upgrades[ i ] != UP_NONE; i++ )
		{
			if ( BG_InventoryContainsUpgrade( self->conditions.upgrades[ i ], activator->client->ps.stats ) )
			{
				return qtrue;
			}
		}
	}

	return qfalse;
}
Exemple #18
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 );

    // 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, 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 );
}
Exemple #19
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 );
}
static AIValue_t haveWeapon( gentity_t *self, const AIValue_t *params )
{
	return AIBoxInt( BG_InventoryContainsWeapon( AIUnBoxInt( params[ 0 ] ), self->client->ps.stats ) );
}
Exemple #21
0
/*
===================
CG_DrawItemSelect
===================
*/
void CG_DrawItemSelect( rectDef_t *rect, vec4_t color )
{
  int           i;
  int           x = rect->x;
  int           y = rect->y;
  int           width = rect->w;
  int           height = rect->h;
  int           iconsize;
  int           items[ 64 ];
  int           numItems = 0, selectedItem = 0;
  int           length;
  int           selectWindow;
  qboolean      vertical;
  centity_t     *cent;
  playerState_t *ps;

  cent = &cg_entities[ cg.snap->ps.clientNum ];
  ps = &cg.snap->ps;

  // don't display if dead
  if( cg.predictedPlayerState.stats[ STAT_HEALTH ] <= 0 )
    return;

  if( !( cg.snap->ps.pm_flags & PMF_FOLLOW ) )
  {
    // first make sure that whatever it selected is actually selectable
    if( cg.weaponSelect <= 32 && !CG_WeaponSelectable( cg.weaponSelect ) )
      CG_NextWeapon_f( );
    else if( cg.weaponSelect > 32 && !CG_UpgradeSelectable( cg.weaponSelect - 32 ) )
      CG_NextWeapon_f( );
  }

  // showing weapon select clears pickup item display, but not the blend blob
  cg.itemPickupTime = 0;

  if( height > width )
  {
    vertical = qtrue;
    iconsize = width;
    length = height / width;
  }
  else if( height <= width )
  {
    vertical = qfalse;
    iconsize = height;
    length = width / height;
  }

  selectWindow = length / 2;

  for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ )
  {
    if( !BG_InventoryContainsWeapon( i, cg.snap->ps.stats ) )
      continue;

    if( i == cg.weaponSelect )
      selectedItem = numItems;

    CG_RegisterWeapon( i );
    items[ numItems ] = i;
    numItems++;
  }

  for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ )
  {
    if( !BG_InventoryContainsUpgrade( i, cg.snap->ps.stats ) )
      continue;

    if( i == cg.weaponSelect - 32 )
      selectedItem = numItems;

    CG_RegisterUpgrade( i );
    items[ numItems ] = i + 32;
    numItems++;
  }

  for( i = 0; i < length; i++ )
  {
    int displacement = i - selectWindow;
    int item = displacement + selectedItem;

    if( ( item >= 0 ) && ( item < numItems ) )
    {
      trap_R_SetColor( color );

      if( items[ item ] <= 32 )
        CG_DrawPic( x, y, iconsize, iconsize, cg_weapons[ items[ item ] ].weaponIcon );
      else if( items[ item ] > 32 )
        CG_DrawPic( x, y, iconsize, iconsize, cg_upgrades[ items[ item ] - 32 ].upgradeIcon );

      trap_R_SetColor( NULL );
    }

    if( vertical )
      y += iconsize;
    else
      x += iconsize;
  }
}
Exemple #22
0
/*
================
ClientEvents

Events will be passed on to the clients for presentation,
but any server game effects are handled here
================
*/
void ClientEvents( gentity_t *ent, int oldEventSequence )
{
  int       i;
  int       event;
  gclient_t *client;
  int       damage;
  vec3_t    dir;
  vec3_t    point, mins;
  float     fallDistance;
  pClass_t  _class;

  client = ent->client;
  _class = (pClass_t)client->ps.stats[ STAT_PCLASS ];

  if( oldEventSequence < client->ps.eventSequence - MAX_EVENTS )
    oldEventSequence = client->ps.eventSequence - MAX_EVENTS;

  for( i = oldEventSequence; i < client->ps.eventSequence; i++ )
  {
    event = client->ps.events[ i & ( MAX_EVENTS - 1 ) ];

    switch( event )
    {
      case EV_FALL_MEDIUM:
      case EV_FALL_FAR:
        if( ent->s.eType != ET_PLAYER )
          break;    // not in the player model

        fallDistance = ( (float)client->ps.stats[ STAT_FALLDIST ] - MIN_FALL_DISTANCE ) /
                         ( MAX_FALL_DISTANCE - MIN_FALL_DISTANCE );

        if( fallDistance < 0.0f )
          fallDistance = 0.0f;
        else if( fallDistance > 1.0f )
          fallDistance = 1.0f;

        damage = (int)( (float)BG_FindHealthForClass( _class ) *
                 BG_FindFallDamageForClass( _class ) * fallDistance );

        VectorSet( dir, 0, 0, 1 );
        BG_FindBBoxForClass( _class, mins, NULL, NULL, NULL, NULL );
        mins[ 0 ] = mins[ 1 ] = 0.0f;
        VectorAdd( client->ps.origin, mins, point );

        ent->pain_debounce_time = level.time + 200; // no normal pain sound
        G_Damage( ent, NULL, NULL, dir, point, damage, DAMAGE_NO_LOCDAMAGE, MOD_FALLING );
        break;

      case EV_FIRE_WEAPON:
        FireWeapon( ent );
        break;

      case EV_FIRE_WEAPON2:
        FireWeapon2( ent );
        break;

      case EV_FIRE_WEAPON3:
        FireWeapon3( ent );
        break;

      case EV_NOAMMO:
        //if we just ran out of grenades, remove the inventory item
        if( ent->s.weapon == WP_GRENADE )
        {
          int j;

          BG_RemoveWeaponFromInventory( ent->s.weapon, ent->client->ps.stats );

          //switch to the first non blaster weapon
          for( j = WP_NONE + 1; j < WP_NUM_WEAPONS; j++ )
          {
            if( j == WP_BLASTER )
              continue;

            if( BG_InventoryContainsWeapon( j, ent->client->ps.stats ) )
            {
              G_ForceWeaponChange( ent, (weapon_t)j );
              break;
            }
          }

          //only got the blaster to switch to
          if( j == WP_NUM_WEAPONS )
            G_ForceWeaponChange( ent, WP_BLASTER );

          //update ClientInfo
          ClientUserinfoChanged( ent->client->ps.clientNum );
        }

        break;

      default:
        break;
    }
  }
}
Exemple #23
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, *event;
  int                 flags;
  int                 savedPing;
  int                 teamLocal;
  int                 eventSequence;
  char                userinfo[ MAX_INFO_STRING ];
  vec3_t              up = { 0.0f, 0.0f, 1.0f }, implant_dir, implant_angles, spawnPoint_velocity;
  int                 maxAmmo, maxClips;
  weapon_t            weapon;
  qboolean            fromImplant = qfalse, hatchingFailed = qfalse;

  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 )
    {
      if( !spawnPoint->client ) //might be a human
      {
        //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;
      }
      else
      {
        qboolean crouch;
        int i;
        float zoffs = 0.0f;
        trace_t tr;
        vec3_t neworigin, mins, maxs;
        
        fromImplant = qtrue; //spawning from a human
        
        // move the origin a bit on the Z axis so the aliens jumps out of the chest, not knees
        // also prevents grangers from getting stuck in ceilings and floors
        crouch = spawnPoint->client->ps.pm_flags & PMF_DUCKED;
        switch( client->pers.classSelection )
        {
          case PCL_ALIEN_BUILDER0:
            if( !crouch )
              zoffs = 19.0f;
            else
              zoffs = -4.0f;
            break;
          case PCL_ALIEN_BUILDER0_UPG:
            if( !crouch )
              zoffs = 16.5f;
            else
              zoffs = -4.0f;
            break;
          case PCL_ALIEN_LEVEL0:
            if( !crouch )
              zoffs = 15.0f;
            else
              zoffs = -9.1f;
            break;
        }
        spawn_origin[ 2 ] += zoffs;
        
        // check if the spot would block
        BG_ClassBoundingBox( client->pers.classSelection, mins, maxs, NULL, NULL, NULL );
        trap_Trace( &tr, spawn_origin, mins, maxs, spawn_origin, spawnPoint->s.number, MASK_PLAYERSOLID );
        
        // try to unblock the player
        if( tr.startsolid )
        {
          Com_Printf("DEBUG: player is stuck!\n");
          for( i = 0; i < 16*2; i++ )
          {
            float a, r;
            
            VectorCopy( spawn_origin, neworigin );
            
            a = (float)i / 16.0f * 2.0f * M_PI;
            #define fmod(a,n) ((a)-(n)*floor((a)/(n)))
            r = ( i < 16 ? 5.5f : 11.0f ) * 1.0f / cos( fmod( a+0.25f*M_PI, 0.5f*M_PI ) - 0.25f*M_PI );
            neworigin[ 0 ] += cos( a ) * r;
            neworigin[ 1 ] += sin( a ) * r;
            
            trap_Trace( &tr, neworigin, mins, maxs, neworigin, spawnPoint->s.number, MASK_PLAYERSOLID );
            
            if( !tr.startsolid )
            {
             Com_Printf("DEBUG: player position fixed at iteration %i\n",i);
             VectorCopy( neworigin, spawn_origin );
             break;
            }
          }
        }
        
        //reward the player that implanted this one
        if( spawnPoint->client->impregnatedBy >= 0 )
        {
          gentity_t *granger;
          
          granger = &g_entities[ spawnPoint->client->impregnatedBy ];
          G_AddCreditToClient( granger->client, ALIEN_IMPREGNATION_REWARD, qtrue );  
          AddScore( granger, ALIEN_IMPREGNATION_REWARD_SCORE );
        }
        
        // kill the human, set up angles and velocity for the new alien
        if( !BG_InventoryContainsUpgrade( UP_BATTLESUIT, spawnPoint->client->ps.stats ) //humans without battlesuits always die
            || spawnPoint->client->ps.stats[ STAT_HEALTH ] < ALIEN_HATCHING_MAX_BATTLESUIT_HEALTH ) //battlesuits survive if high hp
        {
          //save viewangles and spawn velocity for velocity calculation
          VectorCopy( spawnPoint->client->ps.viewangles, implant_angles );
          AngleVectors( implant_angles, implant_dir, NULL, NULL );
          VectorCopy( spawnPoint->client->ps.velocity, spawnPoint_velocity );

          //fire a nice chest exploding effect
          event = G_TempEntity( spawnPoint->s.pos.trBase, EV_ALIEN_HATCH );
          VectorCopy( implant_dir, event->s.angles );

          //kill the player
          G_Damage( spawnPoint, NULL, ent, NULL, NULL, spawnPoint->client->ps.stats[ STAT_HEALTH ], DAMAGE_NO_ARMOR, MOD_ALIEN_HATCH );
        }
        else //human survives
        {
          //clear impregnation so the human won't explode again
          spawnPoint->client->isImpregnated = qfalse;
          spawnPoint->client->isImplantMature = qfalse;
          
          //make a sound
          event = G_TempEntity( spawnPoint->s.pos.trBase, EV_ALIEN_HATCH_FAILURE );

          //damage the human
          G_Damage( spawnPoint, NULL, ent, NULL, NULL, ALIEN_FAILED_HATCH_DAMAGE, DAMAGE_NO_ARMOR, MOD_ALIEN_HATCH );

          //kill the newly spawned alien
          VectorCopy( spawnPoint->client->ps.viewangles, implant_angles );
          implant_dir[0] = 0.0f;
          implant_dir[1] = 0.0f;
          implant_dir[2] = 0.0f;
          hatchingFailed = qtrue;
        }
      }
    }
  }

  // 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->buildTimer = 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;
  
  //never impregnated after respawning
  client->isImpregnated = qfalse;
  client->isImplantMature = qfalse;
  
  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 if( !fromImplant ) //regular egg
    {
      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 //implanted egg
    {
      VectorCopy( implant_angles, spawn_angles );
      VectorScale( implant_dir, ALIEN_HATCHING_VELOCITY, client->ps.velocity );
      VectorAdd( client->ps.velocity, spawnPoint_velocity, client->ps.velocity );
    }
  }
  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 );

    // 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;
      }
    }
  }

  client->lastRantBombTime = level.time;
  
  // 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 );
  
  // kill him instantly after respawning if hatching failed
  if( fromImplant && hatchingFailed )
  {
    VectorCopy( spawnPoint->client->ps.velocity, client->ps.velocity );
    client->ps.stats[ STAT_HEALTH ] = ent->health = 0;
    player_die( ent, NULL, spawnPoint, 0, MOD_ALIEN_HATCH_FAILED );
  }
  
}
Exemple #24
0
/*
===================
CG_DrawItemSelect
===================
*/
void CG_DrawItemSelect( rectDef_t *rect, vec4_t color )
{
  int           i;
  float         x = rect->x;
  float         y = rect->y;
  float         width = rect->w;
  float         height = rect->h;
  float         iconWidth;
  float         iconHeight;
  int           items[ 64 ];
  int           colinfo[ 64 ];
  int           numItems = 0, selectedItem = 0;
  int           length;
  qboolean      vertical;
  centity_t *cent;
  playerState_t *ps;

  cent = &cg_entities[ cg.snap->ps.clientNum ];
  ps = &cg.snap->ps;

  // don't display if dead
  if( cg.predictedPlayerState.stats[ STAT_HEALTH ] <= 0 )
    return;

  if( !( cg.snap->ps.pm_flags & PMF_FOLLOW ) )
  {
    // first make sure that whatever it selected is actually selectable
    if( cg.weaponSelect < 32 )
    {
      if( !CG_WeaponSelectable( cg.weaponSelect ) )
        CG_NextWeapon_f( );
    }
    else
    {
      if( !CG_UpgradeSelectable( cg.weaponSelect - 32 ) )
        CG_NextWeapon_f( );
    }
  }

  // showing weapon select clears pickup item display, but not the blend blob
  cg.itemPickupTime = 0;

  // put all weapons in the items list
  for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ )
  {
    if( !BG_InventoryContainsWeapon( i, cg.snap->ps.stats ) )
      continue;

    if( !ps->ammo && !ps->clips && !BG_Weapon( i )->infiniteAmmo )
      colinfo[ numItems ] = 1;
    else
      colinfo[ numItems ] = 0;

    if( i == cg.weaponSelect )
      selectedItem = numItems;

    if( !cg_weapons[ i ].registered )
    {
      Com_Printf( S_COLOR_YELLOW "WARNING: CG_DrawItemSelect: weapon %d (%s) "
  	"is not registered\n", i, BG_Weapon( i )->name );
      continue;
    }
    items[ numItems ] = i;
    numItems++;
  }

  // put all upgrades in the weapons list
  for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ )
  {
    if( !BG_InventoryContainsUpgrade( i, cg.snap->ps.stats ) )
      continue;
    colinfo[ numItems ] = 0;
    if( !BG_Upgrade( i )->usable )
      colinfo[ numItems ] = 2;

    if( i == cg.weaponSelect - 32 )
      selectedItem = numItems;

    if( !cg_upgrades[ i ].registered )
    {
      Com_Printf( S_COLOR_YELLOW "WARNING: CG_DrawItemSelect: upgrade %d (%s) "
  	"is not registered\n", i, BG_Upgrade( i )->name );
      continue;
    }
    items[ numItems ] = i + 32;
    numItems++;
  }

  // compute the length of the display window and determine orientation
  vertical = height > width;
  if( vertical )
  {
    iconWidth = width * cgDC.aspectScale;
    iconHeight = width;
    length = height / ( width * cgDC.aspectScale );
  }
  else
  {
    iconWidth = height * cgDC.aspectScale;
    iconHeight = height;
    length = width / ( height * cgDC.aspectScale );
  }

  // render icon ring
  for( i = 0; i < length; i++ )
  {
    int item = i - length / 2 + selectedItem;

    if( item < 0 )
      item += length;
    else if( item >= length )
      item -= length;
    if( item >= 0 && item < numItems )
    {
      switch( colinfo[ item ] )
      {
       case 0:
         color = colorCyan;
         break;
       case 1:
         color = colorRed;
         break;
       case 2:
         color = colorMdGrey;
         break;
      }
      color[3] = 0.5;
      trap_R_SetColor( color );

      if( items[ item ] < 32 )
        CG_DrawPic( x, y, iconWidth, iconHeight,
                    cg_weapons[ items[ item ] ].weaponIcon );
      else
        CG_DrawPic( x, y, iconWidth, iconHeight,
                    cg_upgrades[ items[ item ] - 32 ].upgradeIcon );
    }
    if( vertical )
      y += iconHeight;
    else
      x += iconWidth;
  }
  trap_R_SetColor( NULL );
}