Beispiel #1
0
/*
* Pickup_Weapon
*/
qboolean Pickup_Weapon( edict_t *ent, edict_t *other )
{
	int ammo_tag;

	other->r.client->ps.inventory[ent->item->tag]++;

	// never allow the player to carry more than 2 copies of the same weapon
	if( other->r.client->ps.inventory[ent->item->tag] > ent->item->inventory_max )
		other->r.client->ps.inventory[ent->item->tag] = ent->item->inventory_max;

	if( !( ent->spawnflags & DROPPED_ITEM ) )
	{
		// give them some ammo with it
		ammo_tag = ent->item->weakammo_tag;

		if( ammo_tag )
			Add_Ammo( other->r.client, GS_FindItemByTag( ammo_tag ), GS_FindItemByTag( ammo_tag )->quantity, qtrue );
	}
	else
	{    //it's a dropped weapon
		ammo_tag = ent->item->weakammo_tag;
		if( ent->count && ammo_tag )
			Add_Ammo( other->r.client, GS_FindItemByTag( ammo_tag ), ent->count, qtrue );
	}

	return qtrue;
}
Beispiel #2
0
/*
* Pickup_Weapon
*/
bool Pickup_Weapon( edict_t *other, const gsitem_t *item, int flags, int ammo_count )
{
	int ammo_tag;
	gs_weapon_definition_t *weapondef;

	weapondef = GS_GetWeaponDef( item->tag );

	other->r.client->ps.inventory[item->tag]++;

	// never allow the player to carry more than 2 copies of the same weapon
	if( other->r.client->ps.inventory[item->tag] > item->inventory_max )
		other->r.client->ps.inventory[item->tag] = item->inventory_max;

	if( !(flags & DROPPED_ITEM) )
	{
		// give them some ammo with it
		ammo_tag = item->ammo_tag;
		if( ammo_tag )
			Add_Ammo( other->r.client, GS_FindItemByTag( ammo_tag ), weapondef->firedef.weapon_pickup, true );
	}
	else
	{    
		// it's a dropped weapon
		ammo_tag = item->ammo_tag;
		if( ammo_count && ammo_tag )
			Add_Ammo( other->r.client, GS_FindItemByTag( ammo_tag ), ammo_count, true );
	}

	return true;
}
Beispiel #3
0
int GS_Armor_TagForCount( float armorcount )
{
	int count = ARMOR_TO_INT( armorcount );

	if( count > GS_FindItemByTag( ARMOR_YA )->inventory_max )
		return ARMOR_RA;
	if( count > GS_FindItemByTag( ARMOR_GA )->inventory_max )
		return ARMOR_YA;
	if( count )
		return ARMOR_GA;

	return ARMOR_NONE;
}
Beispiel #4
0
int GS_Armor_MaxCountForTag( int tag )
{
	gsitem_t *item = GS_FindItemByTag( tag );
	if( item )
		return item->inventory_max;
	return 255;
}
Beispiel #5
0
int GS_Armor_PickupCountForTag( int tag )
{
	gsitem_t *item = GS_FindItemByTag( tag );
	if( item )
		return item->quantity;
	return 0;
}
Beispiel #6
0
BotItemsSelector::ItemAndGoalWeights BotItemsSelector::ComputeAmmoWeights( const gsitem_t *item ) const {
	if( Inventory()[item->tag] < item->inventory_max ) {
		float quantityFactor = 1.0f - Inventory()[item->tag] / (float)item->inventory_max;
		if( quantityFactor > 0 ) {
			quantityFactor = 1.0f / Q_RSqrt( quantityFactor );
		}

		for( int weapon = WEAP_GUNBLADE; weapon < WEAP_TOTAL; weapon++ ) {
			// TODO: Preache
			const gsitem_t *weaponItem = GS_FindItemByTag( weapon );
			if( weaponItem->ammo_tag == item->tag ) {
				if( Inventory()[weaponItem->tag] ) {
					switch( weaponItem->tag ) {
						case WEAP_ELECTROBOLT:
							return ItemAndGoalWeights( quantityFactor, quantityFactor );
						case WEAP_LASERGUN:
							return ItemAndGoalWeights( quantityFactor * 1.1f, quantityFactor );
						case WEAP_PLASMAGUN:
							return ItemAndGoalWeights( quantityFactor * 1.1f, quantityFactor );
						case WEAP_ROCKETLAUNCHER:
							return ItemAndGoalWeights( quantityFactor, quantityFactor );
						default:
							return ItemAndGoalWeights( 0.5f * quantityFactor, quantityFactor );
					}
				}
				return ItemAndGoalWeights( quantityFactor * 0.33f, quantityFactor * 0.5f );
			}
		}
	}
	return ItemAndGoalWeights( 0.0, 0.0f );
}
Beispiel #7
0
static void WeaponString( edict_t *who, int weapon, char *buf, int buflen, const char *current_color )
{
	int strong_ammo, weak_ammo;
	gs_weapon_definition_t *weapondef = GS_GetWeaponDef( weapon );

	Q_snprintfz( buf, buflen, "%s%s%s", ( GS_FindItemByTag( weapon )->color ? GS_FindItemByTag( weapon )->color : "" ),
		GS_FindItemByTag( weapon )->shortname, current_color );

	strong_ammo = who->r.client->ps.inventory[weapondef->firedef.ammo_id];
	weak_ammo = who->r.client->ps.inventory[weapondef->firedef_weak.ammo_id];
	if( weapon == WEAP_GUNBLADE )
		Q_strncatz( buf, va( ":%i", strong_ammo ), buflen );
	else if( strong_ammo > 0 )
		Q_strncatz( buf, va( ":%i/%i", strong_ammo, weak_ammo ), buflen );
	else
		Q_strncatz( buf, va( ":%i", weak_ammo ), buflen );
}
Beispiel #8
0
/*
* GS_InitWeapons
*/
void GS_InitWeapons( void )
{
	int i;
	gsitem_t *item;
	gs_weapon_definition_t *weapondef;

	for( i = WEAP_GUNBLADE; i < WEAP_TOTAL; i++ )
	{
		item = GS_FindItemByTag( i );
		weapondef = GS_GetWeaponDef( i );

		assert( item && weapondef );

		// hack : use the firedef pickup counts on items
		if( item->weakammo_tag && GS_FindItemByTag( item->weakammo_tag ) )
		{
			GS_FindItemByTag( item->weakammo_tag )->quantity = weapondef->firedef_weak.ammo_pickup;
			GS_FindItemByTag( item->weakammo_tag )->inventory_max = weapondef->firedef_weak.ammo_max;
		}

		if( item->ammo_tag && GS_FindItemByTag( item->ammo_tag ) )
		{
			GS_FindItemByTag( item->ammo_tag )->quantity = weapondef->firedef.ammo_pickup;
			GS_FindItemByTag( item->ammo_tag )->inventory_max = weapondef->firedef.ammo_max;
		}
	}
}
Beispiel #9
0
/*
* G_StatsMessage
* 
* Generates stats message for the entity
* The returned string must be freed by the caller using G_Free
* Note: This string must never contain " characters
*/
char *G_StatsMessage( edict_t *ent )
{
	gclient_t *client;
	gsitem_t *item;
	int i, shot_weak, hit_weak, shot_strong, hit_strong, shot_total, hit_total;
	static char entry[MAX_TOKEN_CHARS];

	assert( ent && ent->r.client );
	client = ent->r.client;

	// message header
	Q_snprintfz( entry, sizeof( entry ), "%d", PLAYERNUM( ent ) );

	for( i = WEAP_GUNBLADE; i < WEAP_TOTAL; i++ )
	{
		item = GS_FindItemByTag( i );
		assert( item );

		hit_weak = hit_strong = 0;
		shot_weak = shot_strong = 0;

		if( item->weakammo_tag != AMMO_NONE )
		{
			hit_weak = client->level.stats.accuracy_hits[item->weakammo_tag - AMMO_GUNBLADE];
			shot_weak = client->level.stats.accuracy_shots[item->weakammo_tag - AMMO_GUNBLADE];
		}

		if( item->ammo_tag != AMMO_NONE )
		{
			hit_strong = client->level.stats.accuracy_hits[item->ammo_tag - AMMO_GUNBLADE];
			shot_strong = client->level.stats.accuracy_shots[item->ammo_tag - AMMO_GUNBLADE];
		}

		hit_total = hit_weak + hit_strong;
		shot_total = shot_weak + shot_strong;

		Q_strncatz( entry, va( " %d", shot_total ), sizeof( entry ) );
		if( shot_total < 1 )
			continue;
		Q_strncatz( entry, va( " %d", hit_total ), sizeof( entry ) );

		// strong
		Q_strncatz( entry, va( " %d", shot_strong ), sizeof( entry ) );
		if( shot_strong != shot_total )
			Q_strncatz( entry, va( " %d", hit_strong ), sizeof( entry ) );
	}

	Q_strncatz( entry, va( " %d %d", client->level.stats.total_damage_given, client->level.stats.total_damage_received ), sizeof( entry ) );
	Q_strncatz( entry, va( " %d %d", client->level.stats.health_taken, client->level.stats.armor_taken ), sizeof( entry ) );

	// add enclosing quote
	Q_strncatz( entry, "\"", sizeof( entry ) );

	return entry;
}
Beispiel #10
0
static void Say_Team_Armor( edict_t *who, char *buf, int buflen, const char *current_color )
{
	if( GS_Armor_TagForCount( who->r.client->resp.armor ) != ARMOR_NONE )
	{
		Q_snprintfz( buf, buflen, "%s%i%s", GS_FindItemByTag( GS_Armor_TagForCount( who->r.client->resp.armor ) )->color,
			ARMOR_TO_INT( who->r.client->resp.armor ), current_color );
	}
	else
	{
		Q_snprintfz( buf, buflen, "%s0%s", S_COLOR_GREEN, current_color );
	}
}
Beispiel #11
0
/*
* SetItemNames
* 
* Called by worldspawn
*/
void G_PrecacheItems( void )
{
	int i;
	gsitem_t *item;

	// precache item names and weapondefs
	for( i = 1; ( item = GS_FindItemByTag( i ) ) != NULL; i++ )
	{
		trap_ConfigString( CS_ITEMS + i, item->name );

		if( item->type & IT_WEAPON && GS_GetWeaponDef( item->tag ) )
		{
			G_PrecacheWeapondef( i, &GS_GetWeaponDef( item->tag )->firedef );
			G_PrecacheWeapondef( i, &GS_GetWeaponDef( item->tag )->firedef_weak );
		}
	}

	// precache items
	if( GS_Instagib() )
	{
		item = GS_FindItemByTag( WEAP_INSTAGUN );
		PrecacheItem( item );
	}
	else
	{
		for( i = WEAP_GUNBLADE; i < WEAP_TOTAL; i++ )
		{
			item = GS_FindItemByTag( i );
			PrecacheItem( item );
		}
	}

	// Vic: precache ammo pack if it's droppable
	item = GS_FindItemByClassname( "item_ammopack" );
	if( item && G_Gametype_CanDropItem( item, qtrue ) )
	{
		PrecacheItem( item );
	}
}
Beispiel #12
0
void G_Gametype_GENERIC_PlayerKilled( edict_t *targ, edict_t *attacker, edict_t *inflictor )
{
	if( !attacker || GS_MatchState() != MATCH_STATE_PLAYTIME || ( targ->r.svflags & SVF_CORPSE ) )
		return;

	if( !attacker->r.client || attacker == targ || attacker == world )
		teamlist[targ->s.team].stats.score--;
	else
	{
		if( GS_InvidualGameType() )
			teamlist[attacker->s.team].stats.score = attacker->r.client->level.stats.score;
		if( GS_IsTeamDamage( &targ->s, &attacker->s ) )
			teamlist[attacker->s.team].stats.score--;
		else
			teamlist[attacker->s.team].stats.score++;
	}

	// drop items
	if( targ->r.client && !( G_PointContents( targ->s.origin ) & CONTENTS_NODROP ) )
	{
		// drop the weapon
		if ( targ->r.client->ps.stats[STAT_WEAPON] > WEAP_GUNBLADE )
		{
			gsitem_t *weaponItem = GS_FindItemByTag( targ->r.client->ps.stats[STAT_WEAPON] );
			if( weaponItem )
			{
				edict_t *drop = Drop_Item( targ, weaponItem );
				if( drop )
				{
					drop->count = targ->r.client->ps.inventory[ weaponItem->weakammo_tag ];
					targ->r.client->ps.inventory[ weaponItem->weakammo_tag ] = 0;
				}
			}
		}

		// drop ammo pack (won't drop anything if player doesn't have any strong ammo)
		Drop_Item( targ, GS_FindItemByTag( AMMO_PACK ) );
	}
}
Beispiel #13
0
BotItemsSelector::ItemAndGoalWeights BotItemsSelector::ComputeWeaponWeights( const gsitem_t *item, bool onlyGotGB ) const {
	if( Inventory()[item->tag] ) {
		// TODO: Precache
		const gsitem_t *ammo = GS_FindItemByTag( item->ammo_tag );
		if( Inventory()[ammo->tag] >= ammo->inventory_max ) {
			return ItemAndGoalWeights( 0, 0 );
		}

		float ammoQuantityFactor = 1.0f - Inventory()[ammo->tag] / (float)ammo->inventory_max;
		if( ammoQuantityFactor > 0 ) {
			ammoQuantityFactor = 1.0f / Q_RSqrt( ammoQuantityFactor );
		}

		switch( item->tag ) {
			case WEAP_ELECTROBOLT:
				return ItemAndGoalWeights( ammoQuantityFactor, 0.5f * ammoQuantityFactor );
			case WEAP_LASERGUN:
				return ItemAndGoalWeights( ammoQuantityFactor * 1.1f, 0.6f * ammoQuantityFactor );
			case WEAP_PLASMAGUN:
				return ItemAndGoalWeights( ammoQuantityFactor * 1.1f, 0.6f * ammoQuantityFactor );
			case WEAP_ROCKETLAUNCHER:
				return ItemAndGoalWeights( ammoQuantityFactor, 0.5f * ammoQuantityFactor );
			default:
				return ItemAndGoalWeights( 0.75f * ammoQuantityFactor, 0.75f * ammoQuantityFactor );
		}
	}

	// We may consider plasmagun in a bot's hand as a top tier weapon too
	const int topTierWeapons[4] = { WEAP_ELECTROBOLT, WEAP_LASERGUN, WEAP_ROCKETLAUNCHER, WEAP_PLASMAGUN };

	// TODO: Precompute
	float topTierWeaponGreed = 0.0f;
	for( int i = 0; i < 4; ++i ) {
		if( !Inventory()[topTierWeapons[i]] ) {
			topTierWeaponGreed += 1.0f;
		}
	}

	for( int i = 0; i < 4; ++i ) {
		if( topTierWeapons[i] == item->tag ) {
			float weight = ( onlyGotGB ? 2.0f : 0.9f ) + ( topTierWeaponGreed - 1.0f ) / 3.0f;
			return ItemAndGoalWeights( weight, weight );
		}
	}

	return onlyGotGB ? ItemAndGoalWeights( 1.5f, 2.0f ) : ItemAndGoalWeights( 0.75f, 0.75f );
}
Beispiel #14
0
static qboolean Pickup_AmmoPack( edict_t *ent, edict_t *other )
{
	gsitem_t *item;
	int i;

	if( !other->r.client )
		return qfalse;

	for( i = AMMO_GUNBLADE; i < AMMO_TOTAL; i++ )
	{
		item = GS_FindItemByTag( i );
		if( item )
			Add_Ammo( other->r.client, item, ent->invpak[i], qtrue );
	}

	return qtrue;
}
Beispiel #15
0
static bool Pickup_AmmoPack( edict_t *other, const int *invpack )
{
	gsitem_t *item;
	int i;

	if( !other->r.client )
		return false;
	if( !invpack )
		return false;

	for( i = AMMO_GUNBLADE + 1; i < AMMO_TOTAL; i++ )
	{
		item = GS_FindItemByTag( i );
		if( item )
			Add_Ammo( other->r.client, item, invpack[i], true );
	}

	return true;
}
Beispiel #16
0
/*
* G_TickOutPowerUps
*/
static void G_TickOutPowerUps( void )
{
	edict_t *ent;
	gsitem_t *item;
	int i;

	for( ent = game.edicts + 1; PLAYERNUM( ent ) < gs.maxclients; ent++ )
	{
		if( ent->r.inuse && trap_GetClientState( PLAYERNUM( ent ) ) >= CS_SPAWNED )
		{
			for( i = POWERUP_QUAD; i < POWERUP_TOTAL; i++ )
			{
				item = GS_FindItemByTag( i );
				if( item && item->quantity && ent->r.client->ps.inventory[item->tag] > 0 )
				{
					ent->r.client->ps.inventory[item->tag]--;
				}
			}
		}
	}

	// also tick out dropped powerups
	for( ent = game.edicts + gs.maxclients + BODY_QUEUE_SIZE; ENTNUM( ent ) < game.numentities; ent++ )
	{
		if( !ent->r.inuse || !ent->item )
			continue;

		if( !( ent->item->type & IT_POWERUP ) )
			continue;

		if( ent->spawnflags & DROPPED_ITEM )
		{
			ent->count--;
			if( ent->count <= 0 )
			{
				G_FreeEdict( ent );
				continue;
			}
		}
	}
}
Beispiel #17
0
/*
* CG_RegisterWeaponModel
*/
struct weaponinfo_s *CG_RegisterWeaponModel( char *cgs_name, int weaponTag )
{
	char filename[MAX_QPATH];
	weaponinfo_t *weaponinfo;

	Q_strncpyz( filename, cgs_name, sizeof( filename ) );
	COM_StripExtension( filename );

	weaponinfo = CG_FindWeaponModelSpot( filename );

	if( weaponinfo->inuse == true )
		return weaponinfo;

	weaponinfo->inuse = CG_WeaponModelUpdateRegistration( weaponinfo, filename );
	if( !weaponinfo->inuse )
	{
		if( cg_debugWeaponModels->integer )
			CG_Printf( "%sWEAPmodel: Failed:%s%s\n", S_COLOR_YELLOW, filename, S_COLOR_WHITE );

		return NULL;
	}

	// find the item for this weapon and try to assign the outline color
	if( weaponTag )
	{
		gsitem_t *item = GS_FindItemByTag( weaponTag );
		if( item )
		{
			if( item->color && strlen( item->color ) > 1 )
			{
				byte_vec4_t colorByte;

				Vector4Scale( color_table[ColorIndex( item->color[1] )], 255, colorByte );
				CG_SetOutlineColor( weaponinfo->outlineColor, colorByte );
			}
		}
	}

	return weaponinfo;
}
Beispiel #18
0
/*
* Drop_Weapon
*/
void Drop_Weapon( edict_t *ent, const gsitem_t *item )
{
	int otherweapon;
	edict_t *drop;
	int ammodrop = 0;

	if( item->tag < 1 || item->tag >= WEAP_TOTAL )
	{
		G_PrintMsg( ent, "Can't drop unknown weapon\n" );
		return;
	}

	// find out the amount of ammo to drop
	if( ent->r.client->ps.inventory[item->tag] > 1 && ent->r.client->ps.inventory[item->ammo_tag] > 5 )
	{
		ammodrop = ent->r.client->ps.inventory[item->ammo_tag] / 2;
	}
	else // drop all
	{
		ammodrop = ent->r.client->ps.inventory[item->ammo_tag];
	}

	drop = Drop_Item( ent, item );
	if( drop )
	{
		ent->r.client->ps.inventory[item->ammo_tag] -= ammodrop;
		drop->count = ammodrop;
		drop->spawnflags |= DROPPED_PLAYER_ITEM;
		ent->r.client->ps.inventory[item->tag]--;

		if( !ent->r.client->ps.inventory[item->tag] )
		{
			otherweapon = GS_SelectBestWeapon( &ent->r.client->ps );
			Use_Weapon( ent, GS_FindItemByTag( otherweapon ) );
		}
	}
}
Beispiel #19
0
/*
* SCB_DrawPlayerStats
*/
static int SCB_DrawPlayerStats( int x, int y, struct qfontface_s *font )
{
	int xoffset, yoffset, lines;
	int i, j, num_weapons, weap, xpos, width, done;
	gsitem_t *it;
	char string[MAX_STRING_CHARS];
	vec4_t color = { 0.5, 0.5, 0.5, 0.5f };

	// don't display stats
	if( !cg_scoreboardStats->integer )
		return 0;

	// total number of weapon
	num_weapons = WEAP_TOTAL-WEAP_GUNBLADE;

	width = ( SCB_TINYFIELD_PIXELWIDTH + 2 * SCB_SMALLFIELD_PIXELWIDTH ) * 2 + SCB_SMALLFIELD_PIXELWIDTH;

	xpos = -width / 2;

	// Center the box
	xoffset = xpos;
	yoffset = trap_SCR_FontHeight( font );

	// Room for header, it's actually written later if we have at least one stat
	yoffset += trap_SCR_FontHeight( font );

	lines = 0;
	for( i = 0; i < num_weapons; )
	{
		xoffset = xpos;

		// two weapons per line
		for( j = 0, done = 0; done < 2 && i + j < num_weapons; j++ )
		{
			weap = WEAP_GUNBLADE + i + j;

			if( scb_player_stats[2*( i+j )] == -1 && scb_player_stats[2*( i+j )+1] == -1 )
				continue;

			it = GS_FindItemByTag( weap );

			// short name
			Q_snprintfz( string, sizeof( string ), "%s%2s", it->color, it->shortname );
			trap_SCR_DrawStringWidth( x + xoffset, y + yoffset, ALIGN_LEFT_TOP, string, SCB_TINYFIELD_PIXELWIDTH, font, colorWhite );

			Q_snprintfz( string, sizeof( string ), "%2d%c", scb_player_stats[2*( i+j )+1], '%' );
			trap_SCR_DrawStringWidth( x + xoffset + 2 * SCB_TINYFIELD_PIXELWIDTH, y + yoffset, ALIGN_CENTER_TOP, string, 2*SCB_SMALLFIELD_PIXELWIDTH, font, colorWhite );

			// separator
			xoffset = 0;
			done++;
		}

		// next line
		if( done > 0 )
		{
			lines++;
			yoffset += trap_SCR_FontHeight( font );
		}

		i += j;
	}

	if( lines )
	{
		// if we drew anything, draw header and box too
		xoffset = xpos;
		yoffset = trap_SCR_FontHeight( font );

		// header
		trap_SCR_DrawStringWidth( x + xoffset, y + yoffset, ALIGN_LEFT_TOP, 
			CG_TranslateString( "Weapon stats" ), width, font, colorMdGrey );
		yoffset += trap_SCR_FontHeight( font );

		// box
		trap_R_DrawStretchPic( x + xoffset - SCB_TINYFIELD_PIXELWIDTH/2, y + yoffset, width + SCB_TINYFIELD_PIXELWIDTH,
			lines * trap_SCR_FontHeight( font ), 0, 0, 1, 1, color, cgs.shaderWhite );

		return ( trap_SCR_FontHeight( font ) * ( 2+lines ) );
	}

	return 0;
}
Beispiel #20
0
/*
* Cmd_Give_f
* 
* Give items to a client
*/
static void Cmd_Give_f( edict_t *ent )
{
	char *name;
	gsitem_t	*it;
	int i;
	bool give_all;

	if( !sv_cheats->integer )
	{
		G_PrintMsg( ent, "Cheats are not enabled on this server.\n" );
		return;
	}

	name = trap_Cmd_Args();

	if( !Q_stricmp( name, "all" ) )
		give_all = true;
	else
		give_all = false;

	if( give_all || !Q_stricmp( trap_Cmd_Argv( 1 ), "health" ) )
	{
		if( trap_Cmd_Argc() == 3 )
			ent->health = atoi( trap_Cmd_Argv( 2 ) );
		else
			ent->health = ent->max_health;
		if( !give_all )
			return;
	}

	if( give_all || !Q_stricmp( name, "weapons" ) )
	{
		for( i = 0; i < GS_MAX_ITEM_TAGS; i++ )
		{
			it = GS_FindItemByTag( i );
			if( !it )
				continue;

			if( !( it->flags & ITFLAG_PICKABLE ) )
				continue;

			if( !( it->type & IT_WEAPON ) )
				continue;

			ent->r.client->ps.inventory[i] += 1;
		}
		if( !give_all )
			return;
	}

	if( give_all || !Q_stricmp( name, "ammo" ) )
	{
		for( i = 0; i < GS_MAX_ITEM_TAGS; i++ )
		{
			it = GS_FindItemByTag( i );
			if( !it )
				continue;

			if( !( it->flags & ITFLAG_PICKABLE ) )
				continue;

			if( !( it->type & IT_AMMO ) )
				continue;

			Add_Ammo( ent->r.client, it, 1000, true );
		}
		if( !give_all )
			return;
	}

	if( give_all || !Q_stricmp( name, "armor" ) )
	{
		ent->r.client->resp.armor = GS_Armor_MaxCountForTag( ARMOR_RA );
		if( !give_all )
			return;
	}

	if( give_all )
	{
		for( i = 0; i < GS_MAX_ITEM_TAGS; i++ )
		{
			it = GS_FindItemByTag( i );
			if( !it )
				continue;

			if( !( it->flags & ITFLAG_PICKABLE ) )
				continue;

			if( it->type & ( IT_ARMOR|IT_WEAPON|IT_AMMO ) )
				continue;

			ent->r.client->ps.inventory[i] = 1;
		}
		return;
	}

	it = GS_FindItemByName( name );
	if( !it )
	{
		name = trap_Cmd_Argv( 1 );
		it = GS_FindItemByName( name );
		if( !it )
		{
			G_PrintMsg( ent, "unknown item\n" );
			return;
		}
	}

	if( !( it->flags & ITFLAG_PICKABLE ) )
	{
		G_PrintMsg( ent, "non-pickup (givable) item\n" );
		return;
	}

	if( it->type & IT_AMMO )
	{
		if( trap_Cmd_Argc() == 3 )
			ent->r.client->ps.inventory[it->tag] = atoi( trap_Cmd_Argv( 2 ) );
		else
			ent->r.client->ps.inventory[it->tag] += it->quantity;
	}
	else
	{
		if( it->tag && ( it->tag > 0 ) && ( it->tag < GS_MAX_ITEM_TAGS ) )
		{
			if( GS_FindItemByTag( it->tag ) != NULL )
				ent->r.client->ps.inventory[it->tag]++;
		}
		else
			G_PrintMsg( ent, "non-pickup (givable) item\n" );
	}
}
Beispiel #21
0
//==========================================
// BOT_DMclass_UpdateStatus
// update ai.status values based on bot state,
// so ai can decide based on these settings
//==========================================
static void BOT_DMclass_UpdateStatus( edict_t *self )
{
	float LowNeedFactor = 0.5;
	gclient_t *client;
	int i;
	qboolean onlyGotGB = qtrue;
	edict_t *ent;
	ai_handle_t *ai;

	client = self->r.client;

	ai = &self->ai;

	for( i = 0; i < nav.num_goalEnts; i++ )
	{
		ent = nav.goalEnts[i].ent;

		// item timing disabled by now
		if( ent->r.solid == SOLID_NOT )
		{
			ai->status.entityWeights[i] = 0;
			continue;
		}

		if( ent->r.client )
		{
			ai->status.entityWeights[i] = BOT_DMclass_PlayerWeight( self, ent ) * self->ai.pers.cha.offensiveness;
			continue;
		}

		if( ent->item )
		{
			if( ent->r.solid == SOLID_NOT )
			{
				ai->status.entityWeights[i] = 0;
				continue;
			}

			if( ent->item->type & IT_WEAPON )
			{
				if( client->ps.inventory[ent->item->tag] )
				{
					ai->status.entityWeights[i] *= LowNeedFactor;
					onlyGotGB = qfalse;
				}
			}
			else if( ent->item->type & IT_AMMO )
			{
				if( client->ps.inventory[ent->item->tag] >= ent->item->inventory_max )
				{
					ai->status.entityWeights[i] = 0.0;
				}
				else
				{
					// find weapon item for this ammo
					gsitem_t *weaponItem;
					int weapon;

					for( weapon = WEAP_GUNBLADE; weapon < WEAP_TOTAL; weapon++ )
					{
						weaponItem = GS_FindItemByTag( weapon );
						if( weaponItem->ammo_tag == ent->item->tag )
						{
							if( !client->ps.inventory[weaponItem->tag] )
								self->ai.status.entityWeights[i] *= LowNeedFactor;
						}
					}
				}
			}
			else if( ent->item->type & IT_ARMOR )
			{
				if ( self->r.client->resp.armor < ent->item->inventory_max || !ent->item->inventory_max )
				{
					if( ent->item->inventory_max )
					{
						if( ( (float)self->r.client->resp.armor / (float)ent->item->inventory_max ) > 0.75 )
							ai->status.entityWeights[i] = self->ai.pers.inventoryWeights[ent->item->tag] * LowNeedFactor;
					}
					else
						ai->status.entityWeights[i] = self->ai.pers.inventoryWeights[ent->item->tag];
				}
				else
				{
					ai->status.entityWeights[i] = 0;
				}
			}
			else if( ent->item->type & IT_HEALTH )
			{
				if( ent->item->tag == HEALTH_MEGA || ent->item->tag == HEALTH_ULTRA )
					ai->status.entityWeights[i] = self->ai.pers.inventoryWeights[ent->item->tag];
				else
				{
					if( self->health == self->max_health )
						ai->status.entityWeights[i] = 0;
					else
					{
						float health_func;

						health_func = self->health / self->max_health;
						health_func *= health_func;

						ai->status.entityWeights[i] = self->ai.pers.inventoryWeights[ent->item->tag] + ( 1.1f - health_func );
					}
				}
			}
			else if( ent->item->type & IT_POWERUP )
			{
				ai->status.entityWeights[i] = self->ai.pers.inventoryWeights[ent->item->tag];
			}
		}
	}

	if( onlyGotGB )
	{
		for( i = 0; i < nav.num_goalEnts; i++ )
		{
			ent = nav.goalEnts[i].ent;

			if( ent->item && ent->item->type & IT_WEAPON )
				self->ai.status.entityWeights[i] *= 2.0f;
		}
	}
}
Beispiel #22
0
/*
* CG_SC_PrintPlayerStats
*/
static void CG_SC_PrintPlayerStats( const char *s, void ( *pp ) )
{
	int playerNum;
	int i, shot_weak, hit_weak, shot_strong, hit_strong, hit_total, shot_total;
	int total_damage_given, total_damage_received, health_taken, armor_taken;
	gsitem_t *item;
	void ( *print )( const char *format, ... ) = pp;

	playerNum = CG_ParseValue( &s );
	if( playerNum < 0 || playerNum >= gs.maxclients )
		return;

	// print stats to console/file
	print( "Stats for %s" S_COLOR_WHITE ":\r\n\r\n", cgs.clientInfo[playerNum].name );
	print( "   Weapon             Weak               Strong\r\n" );
	print( "    hit/shot percent   hit/shot percent   hit/shot percent\r\n" );

	for( i = WEAP_GUNBLADE; i < WEAP_TOTAL; i++ )
	{
		item = GS_FindItemByTag( i );
		assert( item );

		shot_total = CG_ParseValue( &s );
		if( shot_total < 1 )  // only continue with registered shots
			continue;
		hit_total = CG_ParseValue( &s );

		shot_strong = CG_ParseValue( &s );
		hit_strong = (shot_strong != shot_total ? CG_ParseValue( &s ) : hit_total);

		shot_weak = shot_total - shot_strong;
		hit_weak = hit_total - hit_strong;

		// name
		print( "%s%2s" S_COLOR_WHITE ": ", item->color, item->shortname );

#define STATS_PERCENT(hit,total) ((total) == 0 ? 0 : ((hit) == (total) ? 100 : (float)(hit) * 100.0f / (float)(total)))

		// total
		print( S_COLOR_GREEN "%3i" S_COLOR_WHITE "/" S_COLOR_CYAN "%3i      " S_COLOR_YELLOW "%2.1f",
			hit_total, shot_total, STATS_PERCENT( hit_total, shot_total ) );

		// weak
		print( "    " S_COLOR_GREEN "%3i" S_COLOR_WHITE "/" S_COLOR_CYAN "%3i      " S_COLOR_YELLOW "%2.1f",
			hit_weak, shot_weak,  STATS_PERCENT( hit_weak, shot_weak ) );

		// strong
		print( "   " S_COLOR_GREEN "%3i" S_COLOR_WHITE "/" S_COLOR_CYAN "%3i      " S_COLOR_YELLOW "%2.1f",
			hit_strong, shot_strong, STATS_PERCENT( hit_strong, shot_strong ) );

		print( "\r\n" );
	}

	print( "\r\n" );

	total_damage_given = CG_ParseValue( &s );
	total_damage_received = CG_ParseValue( &s );

	print( S_COLOR_YELLOW "Damage given/received: " S_COLOR_WHITE "%i/%i " S_COLOR_YELLOW "ratio: %s%3.2f\r\n",
		total_damage_given, total_damage_received,
		( total_damage_given > total_damage_received ? S_COLOR_GREEN : S_COLOR_RED ),
		STATS_PERCENT( total_damage_given, total_damage_given + total_damage_received ) );

	health_taken = CG_ParseValue( &s );
	armor_taken = CG_ParseValue( &s );

	print( S_COLOR_YELLOW "Health/Armor taken : " S_COLOR_CYAN "%i" S_COLOR_WHITE "/" S_COLOR_CYAN "%i\r\n",
		health_taken, armor_taken );

#undef STATS_PERCENT
}
Beispiel #23
0
/*
* G_PlayerStatsMessage
* generic one to add the stats of the current player into the scoreboard message at cgame
*/
static const char *G_PlayerStatsMessage( edict_t *ent )
{
	gsitem_t *it;
	int i;
	int weakhit, weakshot;
	int hit, shot;
	edict_t *target;
	gclient_t *client;
	static char entry[MAX_TOKEN_CHARS];

	// when chasing generate from target
	target = ent;
	client = ent->r.client;

	if( client->resp.chase.active && game.edicts[client->resp.chase.target].r.client )
	{
		target = &game.edicts[client->resp.chase.target];
		client = target->r.client;
	}

	// message header
	entry[0] = '\0';
	Q_snprintfz( entry, sizeof( entry ), "plstats 0 \"" );
	Q_strncatz( entry, va( " %d", PLAYERNUM( target ) ), sizeof( entry ) );

	// weapon loop
	for( i = WEAP_GUNBLADE; i < WEAP_TOTAL; i++ )
	{
		it = GS_FindItemByTag( i );
		assert( it );

		weakhit = hit = 0;
		weakshot = shot = 0;

		if( it->weakammo_tag != AMMO_NONE )
		{
			weakhit = client->level.stats.accuracy_hits[it->weakammo_tag-AMMO_GUNBLADE];
			weakshot = client->level.stats.accuracy_shots[it->weakammo_tag-AMMO_GUNBLADE];
		}

		if( it->ammo_tag != AMMO_NONE )
		{
			hit = client->level.stats.accuracy_hits[it->ammo_tag-AMMO_GUNBLADE];
			shot = client->level.stats.accuracy_shots[it->ammo_tag-AMMO_GUNBLADE];
		}

		// both in one
		Q_strncatz( entry, va( " %d", weakshot+shot ), sizeof( entry ) );
		if( weakshot+shot > 0 )
		{
			Q_strncatz( entry, va( " %d", weakhit+hit ), sizeof( entry ) );

			if( i == WEAP_LASERGUN || i == WEAP_ELECTROBOLT )
			{
				// strong
				Q_strncatz( entry, va( " %d", shot ), sizeof( entry ) );
				if( shot != (weakshot+shot) )
					Q_strncatz( entry, va( " %d", hit ), sizeof( entry ) );
			}
		}
	}

	// add enclosing quote
	Q_strncatz( entry, "\"", sizeof( entry ) );

	return entry;
}
Beispiel #24
0
/*
* GS_Cmd_UseItem
*/
gsitem_t *GS_Cmd_UseItem( player_state_t *playerState, const char *string, int typeMask )
{
	gsitem_t *item = NULL;

	assert( playerState );

	if( playerState->pmove.pm_type >= PM_SPECTATOR )
		return NULL;

	if( !string || !string[0] )
		return NULL;

	if( Q_isdigit( string ) )
	{
		int tag = atoi( string );
		item = GS_FindItemByTag( tag );
	}
	else
		item = GS_FindItemByName( string );

	if( !item )
		return NULL;

	if( typeMask && !( item->type & typeMask ) )
		return NULL;

	// we don't have this item in the inventory
	if( !playerState->inventory[item->tag] )
	{
		if( gs.module == GS_MODULE_CGAME && !( item->type & IT_WEAPON ) )
			module_Printf( "Item %s is not in inventory\n", item->name );
		return NULL;
	}

	// see if we can use it

	if( !(item->flags & ITFLAG_USABLE) )
		return NULL;

	if( item->type & IT_WEAPON )
	{
		if( !( playerState->pmove.stats[PM_STAT_FEATURES] & PMFEAT_WEAPONSWITCH ) )
			return NULL;

		if( item->tag == playerState->stats[STAT_PENDING_WEAPON] )  // it's already being loaded
			return NULL;

		// check for need of any kind of ammo/fuel/whatever
		if( item->ammo_tag != AMMO_NONE && item->weakammo_tag != AMMO_NONE )
		{
			gs_weapon_definition_t *weapondef = GS_GetWeaponDef( item->tag );

			if( weapondef )
			{	
				// do we have any of these ammos ?
				if( playerState->inventory[item->weakammo_tag] >= weapondef->firedef_weak.usage_count )
					return item;

				if( playerState->inventory[item->ammo_tag] >= weapondef->firedef.usage_count )
					return item;
			}

			return NULL;
		}

		return item; // one of the weapon modes doesn't require ammo to be fired
	}

	if( item->type & IT_AMMO )
		return item;

	if( item->type & IT_HEALTH )
		return item;

	if( item->type & IT_POWERUP )
		return item;

	return NULL;
}
Beispiel #25
0
edict_t *Drop_Item( edict_t *ent, gsitem_t *item )
{
	edict_t	*dropped;
	vec3_t forward, right;
	vec3_t offset;

	if( !G_Gametype_CanDropItem( item, qfalse ) )
		return NULL;

	dropped = G_Spawn();
	dropped->classname = item->classname;
	dropped->item = item;
	dropped->spawnflags = DROPPED_ITEM;
	VectorCopy( item_box_mins, dropped->r.mins );
	VectorCopy( item_box_maxs, dropped->r.maxs );
	dropped->r.solid = SOLID_TRIGGER;
	dropped->movetype = MOVETYPE_TOSS;
	dropped->touch = drop_temp_touch;
	dropped->stop = AI_AddGoalEntity;
	dropped->r.owner = ent;
	dropped->r.svflags &= ~SVF_NOCLIENT;
	dropped->s.team = ent->s.team;
	dropped->s.type = ET_ITEM;
	dropped->s.itemNum = item->tag;
	dropped->s.effects = 0; // default effects are applied client side
	dropped->s.modelindex = trap_ModelIndex( dropped->item->world_model[0] );
	dropped->s.modelindex2 = trap_ModelIndex( dropped->item->world_model[1] );
	dropped->attenuation = 1;

	if( ent->r.client )
	{
		trace_t	trace;

		AngleVectors( ent->r.client->ps.viewangles, forward, right, NULL );
		VectorSet( offset, 24, 0, -16 );
		G_ProjectSource( ent->s.origin, offset, forward, right, dropped->s.origin );
		G_Trace( &trace, ent->s.origin, dropped->r.mins, dropped->r.maxs,
			dropped->s.origin, ent, CONTENTS_SOLID );
		VectorCopy( trace.endpos, dropped->s.origin );

		dropped->spawnflags |= DROPPED_PLAYER_ITEM;

		// ugly hack for dropping backpacks
		if( item->tag == AMMO_PACK_WEAK || item->tag == AMMO_PACK_STRONG || item->tag == AMMO_PACK )
		{
			int w;
			qboolean anything = qfalse;

			for( w = WEAP_GUNBLADE + 1; w < WEAP_TOTAL; w++ )
			{
				if( item->tag == AMMO_PACK_WEAK || item->tag == AMMO_PACK )
				{
					int weakTag = GS_FindItemByTag( w )->weakammo_tag;
					if( ent->r.client->ps.inventory[weakTag] > 0 )
					{
						dropped->invpak[weakTag] = ent->r.client->ps.inventory[weakTag];
						ent->r.client->ps.inventory[weakTag] = 0;
						anything = qtrue;
					}
				}

				if( item->tag == AMMO_PACK_STRONG || item->tag == AMMO_PACK )
				{
					int strongTag = GS_FindItemByTag( w )->ammo_tag;
					if( ent->r.client->ps.inventory[strongTag] )
					{
						dropped->invpak[strongTag] = ent->r.client->ps.inventory[strongTag];
						ent->r.client->ps.inventory[strongTag] = 0;
						anything = qtrue;
					}
				}
			}

			if( !anything ) // if nothing was added to the pack, don't bother spawning it
			{
				G_FreeEdict( dropped );
				return NULL;
			}
		}

		// power-ups are special
		if( ( item->type & IT_POWERUP ) && item->quantity )
		{
			if( ent->r.client->ps.inventory[item->tag] )
			{
				dropped->count = ent->r.client->ps.inventory[item->tag];
				ent->r.client->ps.inventory[item->tag] = 0;
			}
			else
			{
				dropped->count = item->quantity;
			}
		}
	}
	else
	{
		AngleVectors( ent->s.angles, forward, right, NULL );
		VectorCopy( ent->s.origin, dropped->s.origin );

		// ugly hack for dropping backpacks
		if( item->tag == AMMO_PACK_WEAK || item->tag == AMMO_PACK_STRONG || item->tag == AMMO_PACK )
		{
			int w;

			for( w = WEAP_GUNBLADE + 1; w < WEAP_TOTAL; w++ )
			{
				if( item->tag == AMMO_PACK_WEAK || item->tag == AMMO_PACK )
				{
					gsitem_t *ammo = GS_FindItemByTag( GS_FindItemByTag( w )->weakammo_tag );
					if( ammo )
						dropped->invpak[ammo->tag] = ammo->quantity;
				}

				if( item->tag == AMMO_PACK_STRONG || item->tag == AMMO_PACK )
				{
					gsitem_t *ammo = GS_FindItemByTag( GS_FindItemByTag( w )->ammo_tag );
					if( ammo )
						dropped->invpak[ammo->tag] = ammo->quantity;
				}
			}
		}

		// power-ups are special
		if( ( item->type & IT_POWERUP ) && item->quantity )
		{
			dropped->count = item->quantity;
		}
	}

	VectorScale( forward, 100, dropped->velocity );
	dropped->velocity[2] = 300;

	dropped->think = drop_make_touchable;
	dropped->nextThink = level.time + 1000;

	ent->r.client->teamstate.last_drop_item = item;
	VectorCopy( dropped->s.origin, ent->r.client->teamstate.last_drop_location );

	GClip_LinkEntity( dropped );

	return dropped;
}
//==========================================
// BOT_DMclass_InitPersistant
// Persistant after respawns.
//==========================================
void BOT_DMclass_InitPersistant( edict_t *self )
{
	gsitem_t *item;
	int i, w;

	self->classname = "dmbot";

	if( self->r.client->netname )
		self->ai->pers.netname = self->r.client->netname;
	else
		self->ai->pers.netname = "dmBot";

	//set 'class' functions
	self->ai->pers.RunFrame = BOT_DMclass_RunFrame;
	self->ai->pers.UpdateStatus = BOT_DMclass_UpdateStatus;
	self->ai->pers.blockedTimeout = BOT_DMClass_BlockedTimeout;

	//available moveTypes for this class
	self->ai->pers.moveTypesMask = ( LINK_MOVE|LINK_STAIRS|LINK_FALL|LINK_WATER|LINK_WATERJUMP|LINK_JUMPPAD|LINK_PLATFORM|LINK_TELEPORT|LINK_LADDER|LINK_JUMP|LINK_CROUCH );

	//Persistant Inventory Weights (0 = can not pick)
	memset( self->ai->pers.inventoryWeights, 0, sizeof( self->ai->pers.inventoryWeights ) );

	// weapons
	self->ai->pers.inventoryWeights[WEAP_GUNBLADE] = 0.0f;
	self->ai->pers.inventoryWeights[WEAP_MACHINEGUN] = 0.75f;
	self->ai->pers.inventoryWeights[WEAP_RIOTGUN] = 0.75f;
	self->ai->pers.inventoryWeights[WEAP_GRENADELAUNCHER] = 0.7f;
	self->ai->pers.inventoryWeights[WEAP_ROCKETLAUNCHER] = 0.8f;
	self->ai->pers.inventoryWeights[WEAP_PLASMAGUN] = 0.75f;
	self->ai->pers.inventoryWeights[WEAP_ELECTROBOLT] = 0.8f;
	self->ai->pers.inventoryWeights[WEAP_LASERGUN] = 0.8f;

	// ammo
	self->ai->pers.inventoryWeights[AMMO_WEAK_GUNBLADE] = 0.0f;
	self->ai->pers.inventoryWeights[AMMO_BULLETS] = 0.7f;
	self->ai->pers.inventoryWeights[AMMO_SHELLS] = 0.7f;
	self->ai->pers.inventoryWeights[AMMO_GRENADES] = 0.7f;
	self->ai->pers.inventoryWeights[AMMO_ROCKETS] = 0.7f;
	self->ai->pers.inventoryWeights[AMMO_PLASMA] = 0.7f;
	self->ai->pers.inventoryWeights[AMMO_BOLTS] = 0.7f;
	self->ai->pers.inventoryWeights[AMMO_LASERS] = 0.7f;

	// armor
	self->ai->pers.inventoryWeights[ARMOR_RA] = self->ai->pers.cha.armor_grabber * 2.0f;
	self->ai->pers.inventoryWeights[ARMOR_YA] = self->ai->pers.cha.armor_grabber * 1.0f;
	self->ai->pers.inventoryWeights[ARMOR_GA] = self->ai->pers.cha.armor_grabber * 0.75f;
	self->ai->pers.inventoryWeights[ARMOR_SHARD] = self->ai->pers.cha.armor_grabber * 0.5f;

	// health
	self->ai->pers.inventoryWeights[HEALTH_MEGA] = /*self->ai->pers.cha.health_grabber **/ 2.0f;
	self->ai->pers.inventoryWeights[HEALTH_ULTRA] = /*self->ai->pers.cha.health_grabber **/ 2.0f;
	self->ai->pers.inventoryWeights[HEALTH_LARGE] = /*self->ai->pers.cha.health_grabber **/ 1.0f;
	self->ai->pers.inventoryWeights[HEALTH_MEDIUM] = /*self->ai->pers.cha.health_grabber **/ 0.9f;
	self->ai->pers.inventoryWeights[HEALTH_SMALL] = /*self->ai->pers.cha.health_grabber **/ 0.4f;

	// backpack
	self->ai->pers.inventoryWeights[AMMO_PACK] = 0.4f;

	self->ai->pers.inventoryWeights[POWERUP_QUAD] = self->ai->pers.cha.offensiveness * 2.0f;
	self->ai->pers.inventoryWeights[POWERUP_SHELL] = self->ai->pers.cha.offensiveness * 2.0f;

	// scale the inventoryWeights by the character weapon affinities
	// FIXME: rewrite this loop!
	for( i = 1; i < MAX_ITEMS; i++ )
	{
		if( ( item = GS_FindItemByTag( i ) ) == NULL )
			continue;

		if( item->type & IT_WEAPON )
		{
			self->ai->pers.inventoryWeights[i] *= self->ai->pers.cha.weapon_affinity[ i - ( WEAP_GUNBLADE - 1 ) ];
		}
		else if( item->type & IT_AMMO )
		{
			// find weapon for ammo
			for( w = WEAP_GUNBLADE; w < WEAP_TOTAL; w++ )
			{
				if( GS_FindItemByTag( w )->ammo_tag == item->tag ||
					GS_FindItemByTag( w )->weakammo_tag == item->tag )
				{
					self->ai->pers.inventoryWeights[i] *= self->ai->pers.cha.weapon_affinity[ w - ( WEAP_GUNBLADE - 1 ) ];
					break;
				}
			}
		}
	}
}
//==========================================
// BOT_DMclass_UpdateStatus
// update ai.status values based on bot state,
// so ai can decide based on these settings
//==========================================
static void BOT_DMclass_UpdateStatus( edict_t *self )
{
	float LowNeedFactor = 0.5;
	gclient_t *client;
	int i;
	bool onlyGotGB = true;
	edict_t *ent;
	ai_handle_t *ai;
	nav_ents_t *goalEnt;

	client = self->r.client;

	ai = self->ai;

	FOREACH_GOALENT( goalEnt )
	{
		i = goalEnt->id;
		ent = goalEnt->ent;

		// item timing disabled by now
		if( ent->r.solid == SOLID_NOT )
		{
			ai->status.entityWeights[i] = 0;
			continue;
		}

		if( ent->r.client )
		{
			ai->status.entityWeights[i] = BOT_DMclass_PlayerWeight( self, ent ) * self->ai->pers.cha.offensiveness;
			continue;
		}

		if( ent->item )
		{
			if( ent->r.solid == SOLID_NOT )
			{
				ai->status.entityWeights[i] = 0;
				continue;
			}

			if( ent->item->type & IT_WEAPON )
			{
				if( client->ps.inventory[ent->item->tag] )
				{
					if( client->ps.inventory[ent->item->ammo_tag] )
					{
						// find ammo item for this weapon
						gsitem_t *ammoItem = GS_FindItemByTag( ent->item->ammo_tag );
						if( ammoItem->inventory_max )
						{
							ai->status.entityWeights[i] *= (0.5 + 0.5 * (1.0 - (float)client->ps.inventory[ent->item->ammo_tag] / ammoItem->inventory_max));
						}
						ai->status.entityWeights[i] *= LowNeedFactor;
					}
					else
					{
						// we need some ammo
						ai->status.entityWeights[i] *= LowNeedFactor;
					}
					onlyGotGB = false;
				}
			}
			else if( ent->item->type & IT_AMMO )
			{
				if( client->ps.inventory[ent->item->tag] >= ent->item->inventory_max )
				{
					ai->status.entityWeights[i] = 0.0;
				}
				else
				{
#if 0
					// find weapon item for this ammo
					gsitem_t *weaponItem;
					int weapon;

					for( weapon = WEAP_GUNBLADE; weapon < WEAP_TOTAL; weapon++ )
					{
						weaponItem = GS_FindItemByTag( weapon );
						if( weaponItem->ammo_tag == ent->item->tag )
						{
							if( !client->ps.inventory[weaponItem->tag] )
								self->ai->status.entityWeights[i] *= LowNeedFactor;
						}
					}
#endif
				}
			}
			else if( ent->item->type & IT_ARMOR )
			{
				if ( self->r.client->resp.armor < ent->item->inventory_max || !ent->item->inventory_max )
				{
					if( ent->item->inventory_max )
					{
						if( ( (float)self->r.client->resp.armor / (float)ent->item->inventory_max ) > 0.75 )
							ai->status.entityWeights[i] = self->ai->pers.inventoryWeights[ent->item->tag] * LowNeedFactor;
					}
					else
						ai->status.entityWeights[i] = self->ai->pers.inventoryWeights[ent->item->tag];
				}
				else
				{
					ai->status.entityWeights[i] = 0;
				}
			}
			else if( ent->item->type & IT_HEALTH )
			{
				if( ent->item->tag == HEALTH_MEGA || ent->item->tag == HEALTH_ULTRA || ent->item->tag == HEALTH_SMALL )
					ai->status.entityWeights[i] = self->ai->pers.inventoryWeights[ent->item->tag];
				else
				{
					if( self->health >= self->max_health )
						ai->status.entityWeights[i] = 0;
					else
					{
						float health_func;

						health_func = self->health / self->max_health;
						health_func *= health_func;

						ai->status.entityWeights[i] = self->ai->pers.inventoryWeights[ent->item->tag] + ( 1.1f - health_func );
					}
				}
			}
			else if( ent->item->type & IT_POWERUP )
			{
				ai->status.entityWeights[i] = self->ai->pers.inventoryWeights[ent->item->tag];
			}
		}
	}

	if( onlyGotGB )
	{
		FOREACH_GOALENT( goalEnt )
		{
			i = goalEnt->id;
			ent = goalEnt->ent;

			if( ent->item && ent->item->type & IT_WEAPON )
				self->ai->status.entityWeights[i] *= 2.0f;
		}
	}
}
Beispiel #28
0
/*
* ClientThink
*/
void ClientThink( edict_t *ent, usercmd_t *ucmd, int timeDelta )
{
	gclient_t *client;
	int i, j;
	static pmove_t pm;
	int delta, count;

	client = ent->r.client;

	client->ps.POVnum = ENTNUM( ent );
	client->ps.playerNum = PLAYERNUM( ent );

	// anti-lag
	if( ent->r.svflags & SVF_FAKECLIENT )
	{
		client->timeDelta = 0;
	}
	else
	{
		int nudge;
		int fixedNudge = ( game.snapFrameTime ) * 0.5; // fixme: find where this nudge comes from.

		// add smoothing to timeDelta between the last few ucmds and a small fine-tuning nudge.
		nudge = fixedNudge + g_antilag_timenudge->integer;
		timeDelta += nudge;
		clamp( timeDelta, -g_antilag_maxtimedelta->integer, 0 );

		// smooth using last valid deltas
		i = client->timeDeltasHead - 6;
		if( i < 0 ) i = 0;
		for( count = 0, delta = 0; i < client->timeDeltasHead; i++ )
		{
			if( client->timeDeltas[i & G_MAX_TIME_DELTAS_MASK] < 0 )
			{
				delta += client->timeDeltas[i & G_MAX_TIME_DELTAS_MASK];
				count++;
			}
		}

		if( !count )
			client->timeDelta = timeDelta;
		else
		{
			delta /= count;
			client->timeDelta = ( delta + timeDelta ) * 0.5;
		}

		client->timeDeltas[client->timeDeltasHead & G_MAX_TIME_DELTAS_MASK] = timeDelta;
		client->timeDeltasHead++;

#ifdef UCMDTIMENUDGE
		client->timeDelta += client->pers.ucmdTimeNudge;
#endif
	}

	clamp( client->timeDelta, -g_antilag_maxtimedelta->integer, 0 );

	// update activity if he touched any controls
	if( ucmd->forwardmove != 0 || ucmd->sidemove != 0 || ucmd->upmove != 0 || ( ucmd->buttons & ~BUTTON_BUSYICON ) != 0
		|| client->ucmd.angles[PITCH] != ucmd->angles[PITCH] || client->ucmd.angles[YAW] != ucmd->angles[YAW] )
		G_Client_UpdateActivity( client );

	client->ucmd = *ucmd;

	// can exit intermission after two seconds, not counting postmatch
	if( GS_MatchState() == MATCH_STATE_WAITEXIT && ( ucmd->buttons & BUTTON_ATTACK ) && game.serverTime > GS_MatchStartTime() + 2000 )
		level.exitNow = true;

	// (is this really needed?:only if not cared enough about ps in the rest of the code)
	// refresh player state position from the entity
	VectorCopy( ent->s.origin, client->ps.pmove.origin );
	VectorCopy( ent->velocity, client->ps.pmove.velocity );
	VectorCopy( ent->s.angles, client->ps.viewangles );

	client->ps.pmove.gravity = level.gravity;

	if( GS_MatchState() >= MATCH_STATE_POSTMATCH || GS_MatchPaused() 
		|| ( ent->movetype != MOVETYPE_PLAYER && ent->movetype != MOVETYPE_NOCLIP ) )
		client->ps.pmove.pm_type = PM_FREEZE;
	else if( ent->s.type == ET_GIB )
		client->ps.pmove.pm_type = PM_GIB;
	else if( ent->movetype == MOVETYPE_NOCLIP || client->isTV )
		client->ps.pmove.pm_type = PM_SPECTATOR;
	else
		client->ps.pmove.pm_type = PM_NORMAL;

	// set up for pmove
	memset( &pm, 0, sizeof( pmove_t ) );
	pm.playerState = &client->ps;

	if( !client->isTV )
		pm.cmd = *ucmd;

	if( memcmp( &client->old_pmove, &client->ps.pmove, sizeof( pmove_state_t ) ) )
		pm.snapinitial = true;

	// perform a pmove
	Pmove( &pm );

	// save results of pmove
	client->old_pmove = client->ps.pmove;

	// update the entity with the new position
	VectorCopy( client->ps.pmove.origin, ent->s.origin );
	VectorCopy( client->ps.pmove.velocity, ent->velocity );
	VectorCopy( client->ps.viewangles, ent->s.angles );
	ent->viewheight = client->ps.viewheight;
	VectorCopy( pm.mins, ent->r.mins );
	VectorCopy( pm.maxs, ent->r.maxs );

	ent->waterlevel = pm.waterlevel;
	ent->watertype = pm.watertype;
	if( pm.groundentity == -1 )
	{
		ent->groundentity = NULL;
	}
	else
	{
		G_AwardResetPlayerComboStats( ent );

		ent->groundentity = &game.edicts[pm.groundentity];
		ent->groundentity_linkcount = ent->groundentity->linkcount;
	}
	
	GClip_LinkEntity( ent );

	GS_AddLaserbeamPoint( &ent->r.client->resp.trail, &ent->r.client->ps, ucmd->serverTimeStamp );

	// Regeneration
	if( ent->r.client->ps.inventory[POWERUP_REGEN] > 0 && ent->health < 200)
	{
		ent->health += ( game.frametime * 0.001f ) * 10.0f;

		// Regen expires if health reaches 200
		if ( ent->health >= 199.0f )
			ent->r.client->ps.inventory[POWERUP_REGEN]--;
	}

	// fire touch functions
	if( ent->movetype != MOVETYPE_NOCLIP )
	{
		edict_t *other;

		// touch other objects
		for( i = 0; i < pm.numtouch; i++ )
		{
			other = &game.edicts[pm.touchents[i]];
			for( j = 0; j < i; j++ )
			{
				if( &game.edicts[pm.touchents[j]] == other )
					break;
			}
			if( j != i )
				continue; // duplicated

			// player can't touch projectiles, only projectiles can touch the player
			G_CallTouch( other, ent, NULL, 0 );
		}
	}

	ent->s.weapon = GS_ThinkPlayerWeapon( &client->ps, ucmd->buttons, ucmd->msec, client->timeDelta );

	if( G_IsDead( ent ) )
	{
		if( ent->deathTimeStamp + g_respawn_delay_min->integer <= level.time )
			client->resp.snap.buttons |= ucmd->buttons;
	}
	else if( client->ps.pmove.stats[PM_STAT_NOUSERCONTROL] <= 0 )
		client->resp.snap.buttons |= ucmd->buttons;

	// trigger the instashield
	if( GS_Instagib() && g_instashield->integer )
	{
		if( client->ps.pmove.pm_type == PM_NORMAL && pm.cmd.upmove < 0 &&
			client->resp.instashieldCharge == INSTA_SHIELD_MAX && 
			client->ps.inventory[POWERUP_SHELL] == 0 )
		{
			client->ps.inventory[POWERUP_SHELL] = client->resp.instashieldCharge;
			G_Sound( ent, CHAN_AUTO, trap_SoundIndex( GS_FindItemByTag( POWERUP_SHELL )->pickup_sound ), ATTN_NORM );
		}
	}	

	// 
	if( client->ps.pmove.pm_type == PM_NORMAL )
		client->level.stats.had_playtime = true;

	// generating plrkeys (optimized for net communication)
	ClientMakePlrkeys( client, ucmd );
}
//==========================================
// BOT_DMclass_ChooseWeapon
// Choose weapon based on range & weights
//==========================================
static float BOT_DMclass_ChooseWeapon( edict_t *self )
{
	float dist;
	int i;
	float best_weight = 0.0;
	gsitem_t *weaponItem;
	int curweapon, weapon_range = 0, best_weapon = WEAP_NONE;

	curweapon = self->r.client->ps.stats[STAT_PENDING_WEAPON];

	// if no enemy, then what are we doing here?
	if( !self->enemy )
	{
		weapon_range = AIWEAP_MEDIUM_RANGE;
		if( curweapon == WEAP_GUNBLADE || curweapon == WEAP_NONE )
			self->ai->changeweapon_timeout = level.time;
	}
	else // Base weapon selection on distance:
	{
		dist = DistanceFast( self->s.origin, self->enemy->s.origin );

		if( dist < 150 )
			weapon_range = AIWEAP_MELEE_RANGE;
		else if( dist < 500 )  // Medium range limit is Grenade launcher range
			weapon_range = AIWEAP_SHORT_RANGE;
		else if( dist < 900 )
			weapon_range = AIWEAP_MEDIUM_RANGE;
		else
			weapon_range = AIWEAP_LONG_RANGE;
	}

	if( self->ai->changeweapon_timeout > level.time )
		return AIWeapons[curweapon].RangeWeight[weapon_range];

	for( i = WEAP_GUNBLADE; i < WEAP_TOTAL; i++ )
	{
		float rangeWeight;

		if( ( weaponItem = GS_FindItemByTag( i ) ) == NULL )
			continue;

		if( !GS_CheckAmmoInWeapon( &self->r.client->ps, i ) )
			continue;

		rangeWeight = AIWeapons[i].RangeWeight[weapon_range] * self->ai->pers.cha.weapon_affinity[i - ( WEAP_GUNBLADE - 1 )];

		// weigh up if having strong ammo
		if( self->r.client->ps.inventory[weaponItem->ammo_tag] )
			rangeWeight *= 1.25;

		// add a small random factor (less random the more skill)
		rangeWeight += brandom( -( 1.0 - self->ai->pers.skillLevel ), 1.0 - self->ai->pers.skillLevel );

		// compare range weights
		if( rangeWeight > best_weight )
		{
			best_weight = rangeWeight;
			best_weapon = i;
		}
	}

	// do the change (same weapon, or null best_weapon is covered at ChangeWeapon)
	if( best_weapon != WEAP_NONE )
		BOT_DMClass_ChangeWeapon( self, best_weapon );

	return AIWeapons[curweapon].RangeWeight[weapon_range]; // return current
}
Beispiel #30
0
/*
* PrecacheItem
* 
* Precaches all data needed for a given item.
* This will be called for each item spawned in a level,
* and for each item in each client's inventory.
*/
void PrecacheItem( gsitem_t *it )
{
	int i;
	const char *s, *start;
	char data[MAX_QPATH];
	int len;
	gsitem_t	*ammo;

	if( !it )
		return;

	if( it->pickup_sound )
		trap_SoundIndex( it->pickup_sound );
	for( i = 0; i < MAX_ITEM_MODELS; i++ )
	{
		if( it->world_model[i] )
			trap_ModelIndex( it->world_model[i] );
	}

	if( it->icon )
		trap_ImageIndex( it->icon );

	// parse everything for its ammo
	if( it->ammo_tag )
	{
		ammo = GS_FindItemByTag( it->ammo_tag );
		if( ammo != it )
			PrecacheItem( ammo );
	}

	// parse the space separated precache string for other items
	for( i = 0; i < 3; i++ )
	{
		if( i == 0 )
			s = it->precache_models;
		else if( i == 1 )
			s = it->precache_sounds;
		else
			s = it->precache_images;

		if( !s || !s[0] )
			continue;

		while( *s )
		{
			start = s;
			while( *s && *s != ' ' )
				s++;

			len = s-start;
			if( len >= MAX_QPATH || len < 5 )
				G_Error( "PrecacheItem: %s has bad precache string", it->classname );
			memcpy( data, start, len );
			data[len] = 0;
			if( *s )
				s++;

			if( i == 0 )
				trap_ModelIndex( data );
			else if( i == 1 )
				trap_SoundIndex( data );
			else
				trap_ImageIndex( data );
		}
	}
}