コード例 #1
0
ファイル: g_items.cpp プロジェクト: Clever-Boy/qfusion
static bool Pickup_Health( edict_t *other, const gsitem_t *item, int flags )
{
	if( !(flags & ITEM_IGNORE_MAX) )
		if( HEALTH_TO_INT( other->health ) >= other->max_health )
			return false;

	// start from at least 0.5, so the player sees his health increase the correct amount
	if( other->health < 0.5 )
		other->health = 0.5;

	other->health += item->quantity;

	if( other->r.client )
	{
		other->r.client->level.stats.health_taken += item->quantity;
		teamlist[other->s.team].stats.health_taken += item->quantity;
	}

	if( !(flags & ITEM_IGNORE_MAX) )
	{
		if( other->health > other->max_health )
			other->health = other->max_health;
	}
	else
	{
		if( other->health > 200 )
			other->health = 200;
	}

	return true;
}
コード例 #2
0
ファイル: g_items.c プロジェクト: hettoo/racesow
static qboolean Pickup_Health( edict_t *ent, edict_t *other )
{
	if( !( ent->style & HEALTH_IGNORE_MAX ) )
		if( HEALTH_TO_INT( other->health ) >= other->max_health )
			return qfalse;

	// start from at least 0.5, so the player sees his health increase the correct amount
	if( other->health < 0.5 )
		other->health = 0.5;

	other->health += ent->item->quantity;

	if( other->r.client )
	{
		other->r.client->level.stats.health_taken += ent->item->quantity;
		teamlist[other->s.team].stats.health_taken += ent->item->quantity;
	}

	if( !( ent->style & HEALTH_IGNORE_MAX ) )
	{
		if( other->health > other->max_health )
			other->health = other->max_health;
	}
	else
	{
		if( other->health > 200 )
			other->health = 200;
	}

	if( ent->style & HEALTH_TIMED )
		ent->r.owner = other;

	return qtrue;
}
コード例 #3
0
ファイル: g_gameteams.cpp プロジェクト: tenght/qfusion
static void Say_Team_Health( edict_t *who, char *buf, int buflen, const char *current_color )
{
	int health = HEALTH_TO_INT( who->health );

	if( health <= 0 )
		Q_snprintfz( buf, buflen, "%s0%s", S_COLOR_RED, current_color );
	else if( health <= 50 )
		Q_snprintfz( buf, buflen, "%s%i%s", S_COLOR_YELLOW, health, current_color );
	else if( health <= 100 )
		Q_snprintfz( buf, buflen, "%s%i%s", S_COLOR_WHITE, health, current_color );
	else
		Q_snprintfz( buf, buflen, "%s%i%s", S_COLOR_GREEN, health, current_color );
}
コード例 #4
0
ファイル: g_items.c プロジェクト: hettoo/racesow
void MegaHealth_think( edict_t *self )
{
	self->nextThink = level.time + 1;

	if( self->r.owner )
	{
		if( self->r.owner->r.inuse && self->r.owner->s.team != TEAM_SPECTATOR &&
			HEALTH_TO_INT( self->r.owner->health ) > self->r.owner->max_health )
		{
			return;
		}

		// disable the link to the owner
		self->r.owner = NULL;
	}

	// player is back under max health so we can set respawn time for next MH
	if( !( self->spawnflags & ( DROPPED_ITEM | DROPPED_PLAYER_ITEM ) ) && G_Gametype_CanRespawnItem( self->item ) )
		SetRespawn( self, G_Gametype_RespawnTimeForItem( self->item ) );
	else
		G_FreeEdict( self );
}
コード例 #5
0
ファイル: g_gameteams.cpp プロジェクト: tenght/qfusion
/*
* G_Teams_TDM_UpdateTeamInfoMessages
*/
void G_Teams_UpdateTeamInfoMessages( void )
{
	static int nexttime = 0;
	static char teammessage[MAX_STRING_CHARS];
	edict_t	*ent, *e;
	size_t len;
	int i, j, team;
	char entry[MAX_TOKEN_CHARS];
	int locationTag;

	nexttime -= game.snapFrameTime;
	if( nexttime > 0 )
		return;

	while( nexttime <= 0 )
		nexttime += 2000;

	// time for a new update

	for( team = TEAM_ALPHA; team < GS_MAX_TEAMS; team++ )
	{
		*teammessage = 0;
		Q_snprintfz( teammessage, sizeof( teammessage ), "ti \"" );
		len = strlen( teammessage );

		// add our team info to the string
		for( i = 0; i < teamlist[team].numplayers; i++ )
		{
			ent = game.edicts + teamlist[team].playerIndices[i];

			if( G_IsDead( ent ) )  // don't show dead players
				continue;

			if( ent->r.client->teamstate.is_coach )  // don't show coachs
				continue;

			// get location name
			locationTag = G_MapLocationTAGForOrigin( ent->s.origin );
			if( locationTag == -1 )
				continue;

			*entry = 0;

			Q_snprintfz( entry, sizeof( entry ), "%i %i %i %i ", PLAYERNUM( ent ), locationTag, HEALTH_TO_INT( ent->health ), ARMOR_TO_INT( ent->r.client->resp.armor ) );

			if( MAX_STRING_CHARS - len > strlen( entry ) )
			{
				Q_strncatz( teammessage, entry, sizeof( teammessage ) );
				len = strlen( teammessage );
			}
		}

		// add closing quote
		*entry = 0;
		Q_snprintfz( entry, sizeof( entry ), "\"" );
		if( MAX_STRING_CHARS - len > strlen( entry ) )
		{
			Q_strncatz( teammessage, entry, sizeof( teammessage ) );
			len = strlen( teammessage );
		}

		for( i = 0; i < teamlist[team].numplayers; i++ )
		{
			ent = game.edicts + teamlist[team].playerIndices[i];

			if( !ent->r.inuse || !ent->r.client )
				continue;

			trap_GameCmd( ent, teammessage );

			// see if there are spectators chasing this player and send them the layout too
			for( j = 0; j < teamlist[TEAM_SPECTATOR].numplayers; j++ )
			{
				e = game.edicts + teamlist[TEAM_SPECTATOR].playerIndices[j];

				if( !e->r.inuse || !e->r.client )
					continue;

				if( e->r.client->resp.chase.active && e->r.client->resp.chase.target == ENTNUM( ent ) )
					trap_GameCmd( e, teammessage );
			}
		}
	}
}
コード例 #6
0
ファイル: g_frame.cpp プロジェクト: ShaitanShootout/BM
/*
* G_EdictsAddSnapEffects
* add effects based on accumulated info along the server frame
*/
static void G_SnapEntities( void )
{
	edict_t *ent;
	int i;
	vec3_t dir, origin;

	for( i = 0, ent = &game.edicts[0]; i < game.numentities; i++, ent++ )
	{
		if( !ent->r.inuse || ( ent->r.svflags & SVF_NOCLIENT ) )
			continue;

		if( ent->s.type == ET_PARTICLES ) // particles use a special configuration
		{
			ent->s.frame = ent->particlesInfo.speed;
			ent->s.modelindex = ent->particlesInfo.shaderIndex;
			ent->s.modelindex2 = ent->particlesInfo.spread;
			ent->s.counterNum = ent->particlesInfo.time;
			ent->s.weapon = ent->particlesInfo.frequency;

			ent->s.effects = ent->particlesInfo.size & 0xFF;
			if( ent->particlesInfo.spherical )
				ent->s.effects |= ( 1<<8 );
			if( ent->particlesInfo.bounce )
				ent->s.effects |= ( 1<<9 );
			if( ent->particlesInfo.gravity )
				ent->s.effects |= ( 1<<10 );
			if( ent->particlesInfo.expandEffect )
				ent->s.effects |= ( 1<<11 );
			if( ent->particlesInfo.shrinkEffect )
				ent->s.effects |= ( 1<<11 );

			GClip_LinkEntity( ent );

			continue;
		}

		if( ent->s.type == ET_PLAYER || ent->s.type == ET_CORPSE )
		{
			// this is pretty hackish. We exploit the fact that 0.5 servers *do not* transmit
			// origin2/old_origin for ET_PLAYER/ET_CORPSE entities, and we use it for sending the player velocity
			if( !G_ISGHOSTING( ent ) )
			{
				ent->r.svflags |= SVF_TRANSMITORIGIN2;
				VectorCopy( ent->velocity, ent->s.origin2 );
			}
			else
				ent->r.svflags &= ~SVF_TRANSMITORIGIN2;
		}

		if( ISEVENTENTITY( ent ) || G_ISGHOSTING( ent ) || !ent->takedamage )
			continue;

		// types which can have accumulated damage effects
		if( ( ent->s.type == ET_GENERIC || ent->s.type == ET_PLAYER || ent->s.type == ET_CORPSE ) ) // doors don't bleed
		{
			// Until we get a proper damage saved effect, we accumulate both into the blood fx
			// so, at least, we don't send 2 entities where we can send one
			ent->snap.damage_taken += ent->snap.damage_saved;
			//ent->snap.damage_saved = 0;

			//spawn accumulated damage
			if( ent->snap.damage_taken && !( ent->flags & FL_GODMODE ) && HEALTH_TO_INT( ent->health ) > 0 )
			{
				edict_t *event;
				float damage = ent->snap.damage_taken;
				if( damage > 120 )
					damage = 120;

				VectorCopy( ent->snap.damage_dir, dir );
				VectorNormalize( dir );
				VectorAdd( ent->s.origin, ent->snap.damage_at, origin );

				if( ent->s.type == ET_PLAYER || ent->s.type == ET_CORPSE )
				{
					event = G_SpawnEvent( EV_BLOOD, DirToByte( dir ), origin );
					event->s.damage = HEALTH_TO_INT( damage );
					event->s.ownerNum = i; // set owner

					// ET_PLAYERS can also spawn sound events
					if( ent->s.type == ET_PLAYER )
					{
						// play an apropriate pain sound
						if( level.time >= ent->pain_debounce_time )
						{
							// see if it should pain for a FALL or for damage received
							if( ent->snap.damage_fall )
							{
								ent->pain_debounce_time = level.time + 200;
							}
							else if( !G_IsDead( ent ) )
							{
								if( ent->r.client->ps.inventory[POWERUP_SHELL] > 0 )
									G_AddEvent( ent, EV_PAIN, PAIN_WARSHELL, true );
								else if( ent->health <= 20 )
									G_AddEvent( ent, EV_PAIN, PAIN_20, true );
								else if( ent->health <= 35 )
									G_AddEvent( ent, EV_PAIN, PAIN_30, true );
								else if( ent->health <= 60 )
									G_AddEvent( ent, EV_PAIN, PAIN_60, true );
								else
									G_AddEvent( ent, EV_PAIN, PAIN_100, true );

								ent->pain_debounce_time = level.time + 400;
							}
						}
					}
				}
				else
				{
					event = G_SpawnEvent( EV_SPARKS, DirToByte( dir ), origin );
					event->s.damage = HEALTH_TO_INT( damage );
				}
			}
		}
	}
}
コード例 #7
0
ファイル: p_hud.cpp プロジェクト: Clever-Boy/qfusion
/*
* G_SetClientStats
*/
void G_SetClientStats( edict_t *ent )
{
	gclient_t *client = ent->r.client;
	int team, i;

	if( ent->r.client->resp.chase.active )  // in chasecam it copies the other player stats
		return;

	//
	// layouts
	//
	client->ps.stats[STAT_LAYOUTS] = 0;

	// don't force scoreboard when dead during timeout
	if( ent->r.client->level.showscores || GS_MatchState() >= MATCH_STATE_POSTMATCH )
		client->ps.stats[STAT_LAYOUTS] |= STAT_LAYOUT_SCOREBOARD;
	if( GS_TeamBasedGametype() && !GS_InvidualGameType() )
		client->ps.stats[STAT_LAYOUTS] |= STAT_LAYOUT_TEAMTAB;
	if( GS_HasChallengers() && ent->r.client->queueTimeStamp )
		client->ps.stats[STAT_LAYOUTS] |= STAT_LAYOUT_CHALLENGER;
	if( GS_MatchState() <= MATCH_STATE_WARMUP && level.ready[PLAYERNUM( ent )] )
		client->ps.stats[STAT_LAYOUTS] |= STAT_LAYOUT_READY;
	if( G_SpawnQueue_GetSystem( ent->s.team ) == SPAWNSYSTEM_INSTANT )
		client->ps.stats[STAT_LAYOUTS] |= STAT_LAYOUT_INSTANTRESPAWN;

	//
	// team
	//
	client->ps.stats[STAT_TEAM] = client->ps.stats[STAT_REALTEAM] = ent->s.team;

	//
	// health
	//
	if( ent->s.team == TEAM_SPECTATOR )
		client->ps.stats[STAT_HEALTH] = STAT_NOTSET; // no health for spectator
	else
		client->ps.stats[STAT_HEALTH] = HEALTH_TO_INT( ent->health );
	client->r.frags = client->ps.stats[STAT_SCORE];

	//
	// armor
	//
	if( GS_Instagib() )
	{
		if( g_instashield->integer )
			client->ps.stats[STAT_ARMOR] = ARMOR_TO_INT( 100.0f * ( client->resp.instashieldCharge / INSTA_SHIELD_MAX ) );
		else
			client->ps.stats[STAT_ARMOR] = 0;
	}
	else
		client->ps.stats[STAT_ARMOR] = ARMOR_TO_INT( client->resp.armor );

	//
	// pickup message
	//
	if( level.time > client->resp.pickup_msg_time )
	{
		client->ps.stats[STAT_PICKUP_ITEM] = 0;
	}

	//
	// frags
	//
	if( ent->s.team == TEAM_SPECTATOR )
	{
		client->ps.stats[STAT_SCORE] = STAT_NOTSET; // no frags for spectators
	}
	else
	{
		client->ps.stats[STAT_SCORE] = ent->r.client->level.stats.score;
	}

	//
	// Team scores
	//
	if( GS_TeamBasedGametype() )
	{
		// team based
		i = 0;
		for( team = TEAM_ALPHA; team < GS_MAX_TEAMS; team++ )
		{
			client->ps.stats[STAT_TEAM_ALPHA_SCORE+i] = teamlist[team].stats.score;
			i++;
		}
		// mark the rest as not set
		for(; team < GS_MAX_TEAMS; team++ )
		{
			client->ps.stats[STAT_TEAM_ALPHA_SCORE+i] = STAT_NOTSET;
			i++;
		}
	}
	else
	{
		// not team based
		i = 0;
		for( team = TEAM_ALPHA; team < GS_MAX_TEAMS; team++ )
		{
			client->ps.stats[STAT_TEAM_ALPHA_SCORE+i] = STAT_NOTSET;
			i++;
		}
	}

	// spawn system
	client->ps.stats[STAT_NEXT_RESPAWN] = ceil( G_SpawnQueue_NextRespawnTime( client->team ) * 0.001f );

	// pointed player
	client->ps.stats[STAT_POINTED_TEAMPLAYER] = 0;
	client->ps.stats[STAT_POINTED_PLAYER] = G_FindPointedPlayer( ent );
	if( client->ps.stats[STAT_POINTED_PLAYER] && GS_TeamBasedGametype() )
	{
		edict_t	*e = &game.edicts[client->ps.stats[STAT_POINTED_PLAYER]];
		if( e->s.team == ent->s.team )
		{
			int pointedhealth = HEALTH_TO_INT( e->health );
			int pointedarmor = 0;
			int available_bits = 0;
			bool mega = false;

			if( pointedhealth < 0 ) pointedhealth = 0;
			if( pointedhealth > 100 )
			{
				pointedhealth -= 100;
				mega = true;
				if( pointedhealth > 100 )
					pointedhealth = 100;
			}
			pointedhealth /= 3.2;

			if( GS_Armor_TagForCount( e->r.client->resp.armor ) )
			{
				pointedarmor = ARMOR_TO_INT( e->r.client->resp.armor );
			}
			if( pointedarmor > 150 )
			{
				pointedarmor = 150;
			}
			pointedarmor /= 5;

			client->ps.stats[STAT_POINTED_TEAMPLAYER] = ( ( pointedhealth &0x1F )|( pointedarmor&0x3F )<<6|( available_bits&0xF )<<12 );
			if( mega )
			{
				client->ps.stats[STAT_POINTED_TEAMPLAYER] |= 0x20;
			}
		}
	}

	// last killer. ignore world and team kills
	if( client->teamstate.last_killer )
	{
		edict_t *targ = ent, *attacker = client->teamstate.last_killer;
		client->ps.stats[STAT_LAST_KILLER] = (attacker->r.client && !GS_IsTeamDamage( &targ->s, &attacker->s ) ? 
			ENTNUM( attacker ) : 0);
	}
	else
	{
		client->ps.stats[STAT_LAST_KILLER] = 0;
	}
}
コード例 #8
0
ファイル: g_combat.c プロジェクト: Kaperstone/warsow
/*
* G_Damage
* targ		entity that is being damaged
* inflictor	entity that is causing the damage
* attacker	entity that caused the inflictor to damage targ
* example: targ=enemy, inflictor=rocket, attacker=player
*
* dir			direction of the attack
* point		point at which the damage is being inflicted
* normal		normal vector from that point
* damage		amount of damage being inflicted
* knockback	force to be applied against targ as a result of the damage
*
* dflags		these flags are used to control how T_Damage works
*/
void G_Damage( edict_t *targ, edict_t *inflictor, edict_t *attacker, const vec3_t pushdir, const vec3_t dmgdir, const vec3_t point, float damage, float knockback, float stun, int dflags, int mod )
{
	gclient_t *client;
	float take;
	float save;
	float asave;
	qboolean statDmg;

	if( !targ || !targ->takedamage )
		return;

	if( !attacker )
	{
		attacker = world;
		mod = MOD_TRIGGER_HURT;
	}

	meansOfDeath = mod;

	client = targ->r.client;

	// Cgg - race mode: players don't interact with one another
	if( GS_RaceGametype() )
	{
		if( attacker->r.client && targ->r.client && attacker != targ )
			return;
	}

	// push
	if( !( dflags & DAMAGE_NO_KNOCKBACK ) )
		G_KnockBackPush( targ, attacker, pushdir, knockback, dflags );

	// stun
	if( g_allow_stun->integer && !( dflags & (DAMAGE_NO_STUN|FL_GODMODE) )
		&& (int)stun > 0 && targ->r.client && targ->r.client->resp.takeStun &&
		!GS_IsTeamDamage( &targ->s, &attacker->s ) && ( targ != attacker ) )
	{
		if( dflags & DAMAGE_STUN_CLAMP )
		{
			if( targ->r.client->ps.pmove.stats[PM_STAT_STUN] < (int)stun )
				targ->r.client->ps.pmove.stats[PM_STAT_STUN] = (int)stun;
		}
		else
			targ->r.client->ps.pmove.stats[PM_STAT_STUN] += (int)stun;

		clamp( targ->r.client->ps.pmove.stats[PM_STAT_STUN], 0, MAX_STUN_TIME );
	}

	// dont count self-damage cause it just adds the same to both stats
	statDmg = ( attacker != targ ) && ( mod != MOD_TELEFRAG );

	// apply handicap on the damage given
	if( statDmg && attacker->r.client && !GS_Instagib() )
	{
		// handicap is a percentage value
		if( attacker->r.client->handicap != 0 )
			damage *= 1.0 - (attacker->r.client->handicap * 0.01f);
	}

	take = damage;
	save = 0;

	// check for cases where damage is protected
	if( !( dflags & DAMAGE_NO_PROTECTION ) )
	{
		// check for godmode
		if( targ->flags & FL_GODMODE )
		{
			take = 0;
			save = damage;
		}
		// never damage in timeout
		else if( GS_MatchPaused() )
		{
			take = save = 0;
		}
		// ca has self splash damage disabled
		else if( ( dflags & DAMAGE_RADIUS ) && attacker == targ && !GS_SelfDamage() )
		{
			take = save = 0;
		}
		// don't get damage from players in race
		else if( ( GS_RaceGametype() ) && attacker->r.client && targ->r.client &&
			( attacker->r.client != targ->r.client ) )
		{
			take = save = 0;
		}
		// team damage avoidance
		else if( GS_IsTeamDamage( &targ->s, &attacker->s ) && !G_Gametype_CanTeamDamage( dflags ) )
		{
			take = save = 0;
		}
		// apply warShell powerup protection
		else if( targ->r.client && targ->r.client->ps.inventory[POWERUP_SHELL] > 0 )
		{
			// warshell offers full protection in instagib
			if( GS_Instagib() )
			{
				take = 0;
				save = damage;
			}
			else
			{
				take = ( damage * 0.25f );
				save = damage - take;
			}
			// todo : add protection sound
		}
	}

	asave = G_CheckArmor( targ, take, dflags );
	take -= asave;

	//treat cheat/powerup savings the same as armor
	asave += save;

	// APPLY THE DAMAGES

	if( !take && !asave )
		return;

	// do the damage
	if( take <= 0 )
		return;

	// adding damage given/received to stats
	if( statDmg && attacker->r.client && !targ->deadflag && targ->movetype != MOVETYPE_PUSH && targ->s.type != ET_CORPSE )
	{
		attacker->r.client->level.stats.total_damage_given += take + asave;
		teamlist[attacker->s.team].stats.total_damage_given += take + asave;
		if( GS_IsTeamDamage( &targ->s, &attacker->s ) )
		{
			attacker->r.client->level.stats.total_teamdamage_given += take + asave;
			teamlist[attacker->s.team].stats.total_teamdamage_given += take + asave;
		}
	}

	G_Gametype_ScoreEvent( attacker->r.client, "dmg", va( "%i %f %i", targ->s.number, damage, attacker->s.number ) );

	if( statDmg && client )
	{
		client->level.stats.total_damage_received += take + asave;
		teamlist[targ->s.team].stats.total_damage_received += take + asave;
		if( GS_IsTeamDamage( &targ->s, &attacker->s ) )
		{
			client->level.stats.total_teamdamage_received += take + asave;
			teamlist[targ->s.team].stats.total_teamdamage_received += take + asave;
		}
	}

	// accumulate received damage for snapshot effects
	{
		vec3_t dorigin;

		if( inflictor == world && mod == MOD_FALLING ) // it's fall damage
			targ->snap.damage_fall += take + save;

		if( point[0] != 0.0f || point[1] != 0.0f || point[2] != 0.0f )
			VectorCopy( point, dorigin );
		else
			VectorSet( dorigin,
			targ->s.origin[0],
			targ->s.origin[1],
			targ->s.origin[2] + targ->viewheight );

		G_BlendFrameDamage( targ, take, &targ->snap.damage_taken, dorigin, dmgdir, targ->snap.damage_at, targ->snap.damage_dir );
		G_BlendFrameDamage( targ, save, &targ->snap.damage_saved, dorigin, dmgdir, targ->snap.damage_at, targ->snap.damage_dir );

		if( targ->r.client )
		{
			if( mod != MOD_FALLING && mod != MOD_TELEFRAG && mod != MOD_SUICIDE )
			{
				if( inflictor == world || attacker == world )
				{
					// for world inflicted damage use always 'frontal'
					G_ClientAddDamageIndicatorImpact( targ->r.client, take + save, NULL );
				}
				else if( dflags & DAMAGE_RADIUS )
				{
					// for splash hits the direction is from the inflictor origin
					G_ClientAddDamageIndicatorImpact( targ->r.client, take + save, pushdir );
				}
				else
				{	// for direct hits the direction is the projectile direction
					G_ClientAddDamageIndicatorImpact( targ->r.client, take + save, dmgdir );
				}
			}
		}
	}

	targ->health = targ->health - take;

	// add damage done to stats
	if( !GS_IsTeamDamage( &targ->s, &attacker->s ) && statDmg && G_ModToAmmo( mod ) != AMMO_NONE && client && attacker->r.client )
	{
		attacker->r.client->level.stats.accuracy_hits[G_ModToAmmo( mod )-AMMO_GUNBLADE]++;
		attacker->r.client->level.stats.accuracy_damage[G_ModToAmmo( mod )-AMMO_GUNBLADE] += damage;
		teamlist[attacker->s.team].stats.accuracy_hits[G_ModToAmmo( mod )-AMMO_GUNBLADE]++;
		teamlist[attacker->s.team].stats.accuracy_damage[G_ModToAmmo( mod )-AMMO_GUNBLADE] += damage;

		G_AwardPlayerHit( targ, attacker, mod );
	}

	// accumulate given damage for hit sounds
	if( ( take || asave ) && targ != attacker && client && !targ->deadflag )
	{
		if( attacker )
		{
			if( GS_IsTeamDamage( &targ->s, &attacker->s ) )
				attacker->snap.damageteam_given += take + asave; // we want to know how good our hit was, so saved also matters
			else
				attacker->snap.damage_given += take + asave;
		}
	}

	if( G_IsDead( targ ) )
	{
		if( client )
			targ->flags |= FL_NO_KNOCKBACK;
		G_Killed( targ, inflictor, attacker, HEALTH_TO_INT( take ), point, mod );
	}
	else 
	{
		G_CallPain( targ, attacker, knockback, take );
	}
}
コード例 #9
0
ファイル: p_view.cpp プロジェクト: codetwister/qfusion
/*
* G_PlayerWorldEffects
*/
static void G_PlayerWorldEffects( edict_t *ent )
{
	int waterlevel, old_waterlevel;
	int watertype, old_watertype;

	if( ent->movetype == MOVETYPE_NOCLIP )
	{
		ent->air_finished = level.time + ( 12*1000 ); // don't need air
		return;
	}

	waterlevel = ent->waterlevel;
	watertype = ent->watertype;
	old_waterlevel = ent->r.client->resp.old_waterlevel;
	old_watertype = ent->r.client->resp.old_watertype;
	ent->r.client->resp.old_waterlevel = waterlevel;
	ent->r.client->resp.old_watertype = watertype;

	//
	// if just entered a water volume, play a sound
	//
	if( !old_waterlevel && waterlevel )
	{
		if( ent->watertype & CONTENTS_LAVA )
			G_Sound( ent, CHAN_AUTO, trap_SoundIndex( S_WORLD_LAVA_IN ), ATTN_NORM );
		else if( ent->watertype & CONTENTS_SLIME )
			G_Sound( ent, CHAN_AUTO, trap_SoundIndex( S_WORLD_SLIME_IN ), ATTN_NORM );
		else if( ent->watertype & CONTENTS_WATER )
			G_Sound( ent, CHAN_AUTO, trap_SoundIndex( S_WORLD_WATER_IN ), ATTN_NORM );

		ent->flags |= FL_INWATER;
	}

	//
	// if just completely exited a water volume, play a sound
	//
	if( old_waterlevel && !waterlevel )
	{
		if( old_watertype & CONTENTS_LAVA )
			G_Sound( ent, CHAN_AUTO, trap_SoundIndex( S_WORLD_LAVA_OUT ), ATTN_NORM );
		else if( old_watertype & CONTENTS_SLIME )
			G_Sound( ent, CHAN_AUTO, trap_SoundIndex( S_WORLD_SLIME_OUT ), ATTN_NORM );
		else if( old_watertype & CONTENTS_WATER )
			G_Sound( ent, CHAN_AUTO, trap_SoundIndex( S_WORLD_WATER_OUT ), ATTN_NORM );

		ent->flags &= ~FL_INWATER;
	}

	//
	// check for head just coming out of water
	//
	if( old_waterlevel == 3 && waterlevel != 3 )
	{
		if( ent->air_finished < level.time )
		{ // gasp for air
			// wsw : jal : todo : better variations of gasp sounds
			G_AddEvent( ent, EV_SEXEDSOUND, 1, true );
		}
		else if( ent->air_finished < level.time + 11000 )
		{ // just break surface
			// wsw : jal : todo : better variations of gasp sounds
			G_AddEvent( ent, EV_SEXEDSOUND, 2, true );
		}
	}

	//
	// check for drowning
	//
	if( waterlevel == 3 )
	{
		// if out of air, start drowning
		if( ent->air_finished < level.time )
		{ // drown!
			if( ent->r.client->resp.next_drown_time < level.time && !G_IsDead( ent ) )
			{
				ent->r.client->resp.next_drown_time = level.time + 1000;

				// take more damage the longer underwater
				ent->r.client->resp.drowningDamage += 2;
				if( ent->r.client->resp.drowningDamage > 15 )
					ent->r.client->resp.drowningDamage = 15;

				// wsw : jal : todo : better variations of gasp sounds
				// play a gurp sound instead of a normal pain sound
				if( HEALTH_TO_INT( ent->health ) - ent->r.client->resp.drowningDamage <= 0 )
					G_AddEvent( ent, EV_SEXEDSOUND, 2, true );
				else
					G_AddEvent( ent, EV_SEXEDSOUND, 1, true );
				ent->pain_debounce_time = level.time;

				G_Damage( ent, world, world, vec3_origin, vec3_origin, ent->s.origin, ent->r.client->resp.drowningDamage, 0, 0, DAMAGE_NO_ARMOR, MOD_WATER );
			}
		}
	}
	else
	{
		ent->air_finished = level.time + 12000;
		ent->r.client->resp.drowningDamage = 2;
	}

	//
	// check for sizzle damage
	//
	if( waterlevel && ( ent->watertype & ( CONTENTS_LAVA|CONTENTS_SLIME ) ) )
	{
		if( ent->watertype & CONTENTS_LAVA )
		{
			// wsw: Medar: We don't have the sounds yet and this seems to overwrite the normal pain sounds
			//if( !G_IsDead(ent) && ent->pain_debounce_time <= level.time )
			//{
			//	G_Sound( ent, CHAN_BODY, trap_SoundIndex(va(S_PLAYER_BURN_1_to_2, (rand()&1)+1)), 1, ATTN_NORM );
			//	ent->pain_debounce_time = level.time + 1000;
			//}
			G_Damage( ent, world, world, vec3_origin, vec3_origin, ent->s.origin,
				( 30 * waterlevel ) * game.snapFrameTime / 1000.0f, 0, 0, 0, MOD_LAVA );
		}

		if( ent->watertype & CONTENTS_SLIME )
		{
			G_Damage( ent, world, world, vec3_origin, vec3_origin, ent->s.origin,
				( 10 * waterlevel ) * game.snapFrameTime / 1000.0f, 0, 0, 0, MOD_SLIME );
		}
	}
}