Example #1
0
void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
			   vec3_t dir, vec3_t point, int damage, int dflags, int mod ) {
	gclient_t	*client;
	int			take;
	int			save;
	int			asave;
	int			knockback;
	int			max;
#ifdef MISSIONPACK
	vec3_t		bouncedir, impactpoint;
#endif

	if (!targ->takedamage) {
		return;
	}

	// the intermission has allready been qualified for, so don't
	// allow any extra scoring
	if ( level.intermissionQueued ) {
		return;
	}
#ifdef MISSIONPACK
	if ( targ->client && mod != MOD_JUICED) {
		if ( targ->client->invulnerabilityTime > level.time) {
			if ( dir && point ) {
				G_InvulnerabilityEffect( targ, dir, point, impactpoint, bouncedir );
			}
			return;
		}
	}
#endif
	if ( !inflictor ) {
		inflictor = &g_entities[ENTITYNUM_WORLD];
	}
	if ( !attacker ) {
		attacker = &g_entities[ENTITYNUM_WORLD];
	}

	// shootable doors / buttons don't actually have any health
	if ( targ->s.eType == ET_MOVER ) {
		if ( targ->use && targ->moverState == MOVER_POS1 ) {
			targ->use( targ, inflictor, attacker );
		}
		return;
	}
#ifdef MISSIONPACK
	if( g_gametype.integer == GT_OBELISK && CheckObeliskAttack( targ, attacker ) ) {
		return;
	}
#endif
	// reduce damage by the attacker's handicap value
	// unless they are rocket jumping
	if ( attacker->client && attacker != targ ) {
		max = attacker->client->ps.stats[STAT_MAX_HEALTH];
#ifdef MISSIONPACK
		if( bg_itemlist[attacker->client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) {
			max /= 2;
		}
#endif
		damage = damage * max / 100;
	}

	client = targ->client;

	if ( client ) {
		if ( client->noclip ) {
			return;
		}
	}

	if ( !dir ) {
		dflags |= DAMAGE_NO_KNOCKBACK;
	} else {
		VectorNormalize(dir);
	}

	knockback = damage;
	if ( knockback > 200 ) {
		knockback = 200;
	}
	if ( targ->flags & FL_NO_KNOCKBACK ) {
		knockback = 0;
	}
	if ( dflags & DAMAGE_NO_KNOCKBACK ) {
		knockback = 0;
	}

	// figure momentum add, even if the damage won't be taken
	if ( knockback && targ->client ) {
		vec3_t	kvel;
		float	mass;

		mass = 200;

		VectorScale (dir, g_knockback.value * (float)knockback / mass, kvel);
		VectorAdd (targ->client->ps.velocity, kvel, targ->client->ps.velocity);

		// set the timer so that the other client can't cancel
		// out the movement immediately
		if ( !targ->client->ps.pm_time ) {
			int		t;

			t = knockback * 2;
			if ( t < 50 ) {
				t = 50;
			}
			if ( t > 200 ) {
				t = 200;
			}
			targ->client->ps.pm_time = t;
			targ->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
		}
	}

	// check for completely getting out of the damage
	if ( !(dflags & DAMAGE_NO_PROTECTION) ) {

		// if TF_NO_FRIENDLY_FIRE is set, don't do damage to the target
		// if the attacker was on the same team
#ifdef MISSIONPACK
		if ( mod != MOD_JUICED && targ != attacker && !(dflags & DAMAGE_NO_TEAM_PROTECTION) && OnSameTeam (targ, attacker)  ) {
#else	
		if ( targ != attacker && OnSameTeam (targ, attacker)  ) {
#endif
			if ( !g_friendlyFire.integer ) {
				return;
			}
		}
#ifdef MISSIONPACK
		if (mod == MOD_PROXIMITY_MINE) {
			if (inflictor && inflictor->parent && OnSameTeam(targ, inflictor->parent)) {
				return;
			}
			if (targ == attacker) {
				return;
			}
		}
#endif

		// check for godmode
		if ( targ->flags & FL_GODMODE ) {
			return;
		}
	}

	// battlesuit protects from all radius damage (but takes knockback)
	// and protects 50% against all damage
	if ( client && client->ps.powerups[PW_BATTLESUIT] ) {
		G_AddEvent( targ, EV_POWERUP_BATTLESUIT, 0 );
		if ( ( dflags & DAMAGE_RADIUS ) || ( mod == MOD_FALLING ) ) {
			return;
		}
		damage *= 0.5;
	}

	// add to the attacker's hit counter (if the target isn't a general entity like a prox mine)
	if ( attacker->client && client
			&& targ != attacker && targ->health > 0
			&& targ->s.eType != ET_MISSILE
			&& targ->s.eType != ET_GENERAL) {
		if ( OnSameTeam( targ, attacker ) ) {
			attacker->client->ps.persistant[PERS_HITS]--;
		} else {
			attacker->client->ps.persistant[PERS_HITS]++;
		}
		attacker->client->ps.persistant[PERS_ATTACKEE_ARMOR] = (targ->health<<8)|(client->ps.stats[STAT_ARMOR]);
	}

	// always give half damage if hurting self
	// calculated after knockback, so rocket jumping works
	if ( targ == attacker) {
		damage *= 0.5;
	}

	if ( damage < 1 ) {
		damage = 1;
	}
	take = damage;
	save = 0;

	// save some from armor
	asave = CheckArmor (targ, take, dflags);
	take -= asave;

	if ( g_debugDamage.integer ) {
		G_Printf( "%i: client:%i health:%i damage:%i armor:%i\n", level.time, targ->s.number,
			targ->health, take, asave );
	}

	// add to the damage inflicted on a player this frame
	// the total will be turned into screen blends and view angle kicks
	// at the end of the frame
	if ( client ) {
		if ( attacker ) {
			client->ps.persistant[PERS_ATTACKER] = attacker->s.number;
		} else {
			client->ps.persistant[PERS_ATTACKER] = ENTITYNUM_WORLD;
		}
		client->damage_armor += asave;
		client->damage_blood += take;
		client->damage_knockback += knockback;
		if ( dir ) {
			VectorCopy ( dir, client->damage_from );
			client->damage_fromWorld = qfalse;
		} else {
			VectorCopy ( targ->r.currentOrigin, client->damage_from );
			client->damage_fromWorld = qtrue;
		}
	}

	// See if it's the player hurting the emeny flag carrier
#ifdef MISSIONPACK
	if( g_gametype.integer == GT_CTF || g_gametype.integer == GT_1FCTF ) {
#else	
	if( g_gametype.integer == GT_CTF) {
#endif
		Team_CheckHurtCarrier(targ, attacker);
	}

	if (targ->client) {
		// set the last client who damaged the target
		targ->client->lasthurt_client = attacker->s.number;
		targ->client->lasthurt_mod = mod;
	}

	// do the damage
	if (take) {
		targ->health = targ->health - take;
		if ( targ->client ) {
			targ->client->ps.stats[STAT_HEALTH] = targ->health;
		}
			
		if ( targ->health <= 0 ) {
			if ( client )
				targ->flags |= FL_NO_KNOCKBACK;

			if (targ->health < -999)
				targ->health = -999;

			targ->enemy = attacker;
			targ->die (targ, inflictor, attacker, take, mod);
			return;
		} else if ( targ->pain ) {
			targ->pain (targ, attacker, take);
		}
	}

}


/*
============
CanDamage

Returns qtrue if the inflictor can directly damage the target.  Used for
explosions and melee attacks.
============
*/
qboolean CanDamage (gentity_t *targ, vec3_t origin) {
	vec3_t	dest;
	trace_t	tr;
	vec3_t	midpoint;

	// use the midpoint of the bounds instead of the origin, because
	// bmodels may have their origin is 0,0,0
	VectorAdd (targ->r.absmin, targ->r.absmax, midpoint);
	VectorScale (midpoint, 0.5, midpoint);

	VectorCopy (midpoint, dest);
	trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
	if (tr.fraction == 1.0 || tr.entityNum == targ->s.number)
		return qtrue;

	// this should probably check in the plane of projection, 
	// rather than in world coordinate, and also include Z
	VectorCopy (midpoint, dest);
	dest[0] += 15.0;
	dest[1] += 15.0;
	trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
	if (tr.fraction == 1.0)
		return qtrue;

	VectorCopy (midpoint, dest);
	dest[0] += 15.0;
	dest[1] -= 15.0;
	trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
	if (tr.fraction == 1.0)
		return qtrue;

	VectorCopy (midpoint, dest);
	dest[0] -= 15.0;
	dest[1] += 15.0;
	trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
	if (tr.fraction == 1.0)
		return qtrue;

	VectorCopy (midpoint, dest);
	dest[0] -= 15.0;
	dest[1] -= 15.0;
	trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
	if (tr.fraction == 1.0)
		return qtrue;


	return qfalse;
}


/*
============
G_RadiusDamage
============
*/
qboolean G_RadiusDamage ( vec3_t origin, gentity_t *attacker, float damage, float radius,
					 gentity_t *ignore, int mod) {
	float		points, dist;
	gentity_t	*ent;
	int			entityList[MAX_GENTITIES];
	int			numListedEntities;
	vec3_t		mins, maxs;
	vec3_t		v;
	vec3_t		dir;
	int			i, e;
	qboolean	hitClient = qfalse;

	if ( radius < 1 ) {
		radius = 1;
	}

	for ( i = 0 ; i < 3 ; i++ ) {
		mins[i] = origin[i] - radius;
		maxs[i] = origin[i] + radius;
	}

	numListedEntities = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );

	for ( e = 0 ; e < numListedEntities ; e++ ) {
		ent = &g_entities[entityList[ e ]];

		if (ent == ignore)
			continue;
		if (!ent->takedamage)
			continue;

		// find the distance from the edge of the bounding box
		for ( i = 0 ; i < 3 ; i++ ) {
			if ( origin[i] < ent->r.absmin[i] ) {
				v[i] = ent->r.absmin[i] - origin[i];
			} else if ( origin[i] > ent->r.absmax[i] ) {
				v[i] = origin[i] - ent->r.absmax[i];
			} else {
				v[i] = 0;
			}
		}

		dist = VectorLength( v );
		if ( dist >= radius ) {
			continue;
		}

		points = damage * ( 1.0 - dist / radius );

		if( CanDamage (ent, origin) ) {
			if( LogAccuracyHit( ent, attacker ) ) {
				hitClient = qtrue;
			}
			VectorSubtract (ent->r.currentOrigin, origin, dir);
			// push the center of mass higher than the origin so players
			// get knocked into the air more
			dir[2] += 24;
			G_Damage (ent, NULL, attacker, dir, origin, (int)points, DAMAGE_RADIUS, mod);
		}
	}

	return hitClient;
}
Example #2
0
void
T_Damage (edict_t * targ, edict_t * inflictor, edict_t * attacker, vec3_t dir,
	  vec3_t point, vec3_t normal, int damage, int knockback, int dflags,
	  int mod)
{
	gclient_t *client;
	char buf[256];
	int take, save;
	int asave, psave;
	int te_sparks, do_sparks = 0;
	int damage_type = 0;		// used for MOD later
	int bleeding = 0;		// damage causes bleeding
	int head_success = 0;
	int instant_dam = 1;
	float z_rel;
	int height;
	float from_top;
	vec_t dist;
	float targ_maxs2;		//FB 6/1/99

	// do this before teamplay check
	if (!targ->takedamage)
		return;

	//FIREBLADE
	if (teamplay->value && mod != MOD_TELEFRAG)
	{
		if (lights_camera_action)
			return;

		// AQ2:TNG - JBravo adding UVtime
		if (ctf->value && targ->client)
		{
			if(targ->client->ctf_uvtime > 0)
				return;
			if (attacker->client && attacker->client->ctf_uvtime > 0)
				return;
		}

		// AQ2:TNG - JBravo adding FF after rounds
		if (targ != attacker && targ->client && attacker->client &&
			targ->client->resp.team == attacker->client->resp.team &&
			((int)(dmflags->value) & (DF_NO_FRIENDLY_FIRE))) {
				if (team_round_going)
					return;
				else if (!ff_afterround->value)
					return;
		}
		// AQ:TNG
	}
	//FIREBLADE

	if (dm_shield->value && targ->client)
	{
		if (targ->client->ctf_uvtime > 0)
			return;
		if (attacker->client && attacker->client->ctf_uvtime > 0)
			return;
	}

	// damage reduction for shotgun
	// if far away, reduce it to original action levels
	if (mod == MOD_M3)
	{
		dist = Distance(targ->s.origin, inflictor->s.origin);
		if (dist > 450.0)
			damage = damage - 2;
	}

	targ_maxs2 = targ->maxs[2];
	if (targ_maxs2 == 4)
		targ_maxs2 = CROUCHING_MAXS2;	//FB 6/1/99

	height = abs (targ->mins[2]) + targ_maxs2;

	// locational damage code
	// base damage is head shot damage, so all the scaling is downwards
	if (targ->client)
	{
		if (!((targ != attacker) &&
		((deathmatch->value && ((int)dmflags->value
		& (DF_MODELTEAMS | DF_SKINTEAMS)))
		|| coop->value) && (attacker && attacker->client
		&& OnSameTeam (targ, attacker) &&	 
		((int)dmflags->value & DF_NO_FRIENDLY_FIRE)
		&& (team_round_going && ff_afterround->value))))

		{

			// TNG Stats - Add +1 to hit, make sure that hc and m3 are handles differently

			if ((attacker->client) && (mod != MOD_M3) && (mod != MOD_HC)) {
				strcpy(attacker->client->resp.last_damaged_players, targ->client->pers.netname);

				if (!teamplay->value || team_round_going || stats_afterround->value) {
					attacker->client->resp.stats_hits[mod]++;
					attacker->client->resp.stats_shots_h++;
				}
			}
 
			// TNG Stats END


			if (mod == MOD_MK23 || mod == MOD_MP5 || mod == MOD_M4 ||
				mod == MOD_SNIPER || mod == MOD_DUAL || mod == MOD_KNIFE ||
				mod == MOD_KNIFE_THROWN)
			{
				z_rel = point[2] - targ->s.origin[2];
				from_top = targ_maxs2 - z_rel;
				if (from_top < 0.0)	//FB 6/1/99
				from_top = 0.0;	//Slightly negative values were being handled wrong
				bleeding = 1;
				instant_dam = 0;

				// damage reduction for longer range pistol shots
				if (mod == MOD_MK23 || mod == MOD_DUAL)
				{
					dist = Distance(targ->s.origin, inflictor->s.origin);
					if (dist > 600.0 && dist < 1400.0)
						damage = (int) (damage * 2 / 3);
					else if (dist > 1400.0)
						damage = (int) (damage * 1 / 2);
				}


	      //gi.cprintf(targ, PRINT_HIGH, "z_rel is %f\n leg: %f stomach: %f chest: %f\n", z_rel, LEG_DAMAGE, STOMACH_DAMAGE, CHEST_DAMAGE );
	      //gi.cprintf(targ, PRINT_HIGH, "point[2]: %f targ->s.origin[2]: %f height: %d\n", point[2], targ->s.origin[2], height );
	      //gi.cprintf(targ, PRINT_HIGH, "abs(trag->min[2]): %d targ_max[2] %d\n", (int)abs(targ->mins[2]), (int)targ_maxs2);
	      //gi.cprintf(attacker, PRINT_HIGH, "abs(trag->min[2]): %d targ_max[2] %d\n", (int)abs(targ->mins[2]), (int)targ_maxs2); 
	      //gi.cprintf(attacker, PRINT_HIGH, "abs(trag->min[0]): %d targ_max[0] %d\n", (int)abs(targ->mins[0]), (int)targ->maxs[0]); 
	      //gi.cprintf(attacker, PRINT_HIGH, "abs(trag->min[1]): %d targ_max[1] %d\n", (int)abs(targ->mins[1]), (int)targ->maxs[1]); 


				if (from_top < 2 * HEAD_HEIGHT)
				{
					vec3_t new_point;
					VerifyHeadShot (point, dir, HEAD_HEIGHT, new_point);
					VectorSubtract (new_point, targ->s.origin, new_point);
					//gi.cprintf(attacker, PRINT_HIGH, "z: %d y: %d x: %d\n", (int)(targ_maxs2 - new_point[2]),(int)(new_point[1]) , (int)(new_point[0]) );

					if ((targ_maxs2 - new_point[2]) < HEAD_HEIGHT
						&& (abs (new_point[1])) < HEAD_HEIGHT * .8
						&& (abs (new_point[0])) < HEAD_HEIGHT * .8)
					{
						head_success = 1;
					}
				}

				if (head_success)
				{
					if (attacker->client)
					{
						if (!teamplay->value || team_round_going || stats_afterround->value) {
							attacker->client->resp.stats_headshot[mod]++;
						}
						//AQ2:TNG Slicer Last Damage Location
						if (INV_AMMO(targ, HELM_NUM)) {
							attacker->client->resp.last_damaged_part = LOC_KVLR_HELMET;
							if ((!teamplay->value || team_round_going || stats_afterround->value))
								attacker->client->resp.stats_locations[LOC_KVLR_HELMET]++;
						} else {
							attacker->client->resp.last_damaged_part = LOC_HDAM;
							if ((!teamplay->value || team_round_going || stats_afterround->value))
								attacker->client->resp.stats_locations[LOC_HDAM]++;
						}

						//AQ2:TNG END
						if (!OnSameTeam (targ, attacker))
							attacker->client->resp.hs_streak++;

						// AQ:TNG Igor[Rock] changing sound dir
						if (attacker->client->resp.hs_streak == 3)
						{
							if (use_rewards->value)
							{
								sprintf (buf, "ACCURACY %s!", attacker->client->pers.netname);
								CenterPrintAll (buf);
								gi.sound (&g_edicts[0], CHAN_VOICE | CHAN_NO_PHS_ADD,
									gi.soundindex ("tng/accuracy.wav"), 1.0, ATTN_NONE, 0.0);
							}
							attacker->client->resp.hs_streak = 0;
						}
						// end of changing sound dir
					}

					if (INV_AMMO(targ, HELM_NUM) && mod != MOD_KNIFE
						&& mod != MOD_KNIFE_THROWN && mod != MOD_SNIPER)
					{
						if (attacker->client)
						{
							gi.cprintf (attacker, PRINT_HIGH, "%s has a Kevlar Helmet - AIM FOR THE BODY!\n",
								targ->client->pers.netname);
							gi.cprintf (targ, PRINT_HIGH, "Kevlar Helmet absorbed a part of %s's shot\n",
								attacker->client->pers.netname);
						}
						gi.sound (targ, CHAN_ITEM, gi.soundindex("misc/vest.wav"), 1,
							ATTN_NORM, 0);
						damage = (int) (damage / 2);
						damage_type = LOC_HDAM;
						bleeding = 0;
						instant_dam = 1;
						stopAP = 1;
						do_sparks = 1;
					}
					else if (INV_AMMO(targ, HELM_NUM) && mod == MOD_SNIPER)
					{
						if (attacker->client)
						{
							gi.cprintf (attacker, PRINT_HIGH,
							"%s has a Kevlar Helmet, too bad you have AP rounds...\n",
							targ->client->pers.netname);
							gi.cprintf (targ, PRINT_HIGH,
							"Kevlar Helmet absorbed some of %s's AP sniper round\n",
							attacker->client->pers.netname);
						}
						damage = (int) (damage * 0.325);
						gi.sound (targ, CHAN_VOICE, gi.soundindex("misc/headshot.wav"), 1,
							ATTN_NORM, 0);
						damage_type = LOC_HDAM;
					}
					else
					{
						damage = damage * 1.8 + 1;
						gi.cprintf (targ, PRINT_HIGH, "Head damage\n");
						if (attacker->client)
							gi.cprintf (attacker, PRINT_HIGH, "You hit %s in the head\n",
								targ->client->pers.netname);
						damage_type = LOC_HDAM;
						if (mod != MOD_KNIFE && mod != MOD_KNIFE_THROWN)
							gi.sound (targ, CHAN_VOICE, gi.soundindex ("misc/headshot.wav"), 1,
								ATTN_NORM, 0);
					//else
					//      gi.sound(targ, CHAN_VOICE, gi.soundindex("misc/glurp.wav"), 1, ATTN_NORM, 0);                
					}
				}
				else if (z_rel < LEG_DAMAGE)
				{
					damage = damage * .25;
					gi.cprintf (targ, PRINT_HIGH, "Leg damage\n");
					if (attacker->client)
					{
						attacker->client->resp.hs_streak = 0;
						gi.cprintf (attacker, PRINT_HIGH, "You hit %s in the legs\n",
							targ->client->pers.netname);
					}
					damage_type = LOC_LDAM;
                    if (!heroes->value || targ->client->resp.team == 2) { // ESJ Heroes don't run out
                        targ->client->leg_damage = 1;
                        targ->client->leghits++;
                    }
					//AQ2:TNG Slicer Last Damage Location
					attacker->client->resp.last_damaged_part = LOC_LDAM;
					//AQ2:TNG END
					if (!teamplay->value || team_round_going || stats_afterround->value)
						attacker->client->resp.stats_locations[LOC_LDAM]++; // TNG Stats
				}
				else if (z_rel < STOMACH_DAMAGE)
				{
					damage = damage * .4;
					gi.cprintf (targ, PRINT_HIGH, "Stomach damage\n");
					if (attacker->client)
					{
						attacker->client->resp.hs_streak = 0;
						gi.cprintf (attacker, PRINT_HIGH, "You hit %s in the stomach\n",
							targ->client->pers.netname);
					}
					damage_type = LOC_SDAM;
					//TempFile bloody gibbing
					if (mod == MOD_SNIPER && sv_gib->value)
						ThrowGib (targ, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
					//AQ2:TNG Slicer Last Damage Location
					attacker->client->resp.last_damaged_part = LOC_SDAM;
					//AQ2:TNG END
					if (!teamplay->value || team_round_going || stats_afterround->value)
						attacker->client->resp.stats_locations[LOC_SDAM]++; // TNG Stats
				}
				else		//(z_rel < CHEST_DAMAGE)
				{
					if (attacker->client)
					{
						attacker->client->resp.hs_streak = 0;
					}

					if (INV_AMMO(targ, KEV_NUM) && mod != MOD_KNIFE
						&& mod != MOD_KNIFE_THROWN && mod != MOD_SNIPER)
					{
						if (attacker->client)
						{
							gi.cprintf (attacker, PRINT_HIGH, "%s has a Kevlar Vest - AIM FOR THE HEAD!\n",
								targ->client->pers.netname);
							gi.cprintf (targ, PRINT_HIGH, "Kevlar Vest absorbed most of %s's shot\n",
								attacker->client->pers.netname);
							/*
							if (IsFemale(targ))
							gi.cprintf(attacker, PRINT_HIGH, "You bruised %s through her Kevlar Vest\n", targ->client->pers.netname);
							else
							gi.cprintf(attacker, PRINT_HIGH, "You bruised %s through his Kevlar Vest\n", targ->client->pers.netname);
							*/
						}
						gi.sound (targ, CHAN_ITEM, gi.soundindex ("misc/vest.wav"), 1,
							ATTN_NORM, 0);
						damage = (int) (damage / 10);
						damage_type = LOC_CDAM;
						bleeding = 0;
						instant_dam = 1;
						stopAP = 1;
						do_sparks = 1;
					}
					else if (INV_AMMO(targ, KEV_NUM) && mod == MOD_SNIPER)
					{
						if (attacker->client)
						{
							gi.cprintf (attacker, PRINT_HIGH, "%s has a Kevlar Vest, too bad you have AP rounds...\n",
								targ->client->pers.netname);
							gi.cprintf (targ, PRINT_HIGH, "Kevlar Vest absorbed some of %s's AP sniper round\n",
								attacker->client->pers.netname);
						}
						damage = damage * .325;
						damage_type = LOC_CDAM;
					}
					else
					{
						damage = damage * .65;
						gi.cprintf (targ, PRINT_HIGH, "Chest damage\n");
						if (attacker->client)
							gi.cprintf (attacker, PRINT_HIGH, "You hit %s in the chest\n",
								targ->client->pers.netname);
						damage_type = LOC_CDAM;
						//TempFile bloody gibbing
						if (mod == MOD_SNIPER && sv_gib->value)
							ThrowGib (targ, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
					}
					//AQ2:TNG Slicer Last Damage Location
					if (INV_AMMO(targ, KEV_NUM) && mod != MOD_KNIFE && mod != MOD_KNIFE_THROWN) {
						attacker->client->resp.last_damaged_part = LOC_KVLR_VEST;
						if (!teamplay->value || team_round_going || stats_afterround->value)
							attacker->client->resp.stats_locations[LOC_KVLR_VEST]++; // TNG Stats
					} else {
						attacker->client->resp.last_damaged_part = LOC_CDAM;
						if (!teamplay->value || team_round_going || stats_afterround->value)
							attacker->client->resp.stats_locations[LOC_CDAM]++; // TNG Stats
					}
					//AQ2:TNG END

				}
	      /*else
	         {   

	         // no mod to damage 
	         gi.cprintf(targ, PRINT_HIGH, "Head damage\n"); 
	         if (attacker->client) 
	         gi.cprintf(attacker, PRINT_HIGH, "You hit %s in the head\n", targ->client->pers.netname); 
	         damage_type = LOC_HDAM;
	         gi.sound(targ, CHAN_VOICE, gi.soundindex("misc/headshot.wav"), 1, ATTN_NORM, 0);
	         } */
			}
			if (team_round_going && attacker->client && targ != attacker
				&& OnSameTeam (targ, attacker))
			{
				Add_TeamWound (attacker, targ, mod);
			}
		}
    }


	if (damage_type && !instant_dam)	// bullets but not vest hits
	{
		vec3_t temp;
		vec3_t temporig;
		//vec3_t forward;
		VectorMA (targ->s.origin, 50, dir, temp);
		//AngleVectors (attacker->client->v_angle, forward, NULL, NULL);
		VectorScale (dir, 20, temp);
		VectorAdd (point, temp, temporig);
		if (mod != MOD_SNIPER)
			spray_blood (targ, temporig, dir, damage, mod);
		else
			spray_sniper_blood (targ, temporig, dir);
	}

	if (mod == MOD_FALLING && !(targ->flags & FL_GODMODE) )
	{
        if (!heroes->value || targ->client->resp.team == 2) { // ESJ no limp for heroes
            if (targ->client && targ->health > 0)
            {
                gi.cprintf (targ, PRINT_HIGH, "Leg damage\n");
                targ->client->leg_damage = 1;
                targ->client->leghits++;
            //      bleeding = 1; for testing
            }
        }
    }

    if (heroes->value && targ->client && targ->client->resp.team == 1)  //ESJ take damage or give points, depending
    {
        if (attacker->client) //not fall damage or the like
        {
            attacker->client->points += damage;
            while (attacker->client->points >= 100)
            {
                attacker->client->resp.score++;
                attacker->client->points -= 100;
            }
        }
        damage = 0;
    }

	// friendly fire avoidance
	// if enabled you can't hurt teammates (but you can hurt yourself)
	// knockback still occurs
	if (targ != attacker &&
		((deathmatch->value && ((int)dmflags->value & (DF_MODELTEAMS | DF_SKINTEAMS)))
		|| coop->value))
	{
		if (OnSameTeam (targ, attacker))
		{
			if ((int)dmflags->value & DF_NO_FRIENDLY_FIRE &&
				(team_round_going || !ff_afterround->value))
				damage = 0;
			else
				mod |= MOD_FRIENDLY_FIRE;
		}
	}

	meansOfDeath = mod;
	locOfDeath = damage_type;	// location

	client = targ->client;

	if (dflags & DAMAGE_BULLET)
		te_sparks = TE_BULLET_SPARKS;
	else
		te_sparks = TE_SPARKS;

	VectorNormalize (dir);

  // bonus damage for suprising a monster
  //      if (!(dflags & DAMAGE_RADIUS) && (targ->svflags & SVF_MONSTER) && (attacker->client) && (!targ->enemy) && (targ->health > 0))
  //              damage *= 2;

	if (targ->flags & FL_NO_KNOCKBACK)
		knockback = 0;

	// figure momentum add
	if (!(dflags & DAMAGE_NO_KNOCKBACK))
	{
		if ((knockback) && (targ->movetype != MOVETYPE_NONE)
			&& (targ->movetype != MOVETYPE_BOUNCE)
			&& (targ->movetype != MOVETYPE_PUSH)
			&& (targ->movetype != MOVETYPE_STOP))
		{
			vec3_t kvel, flydir;
			float mass;

			if (mod != MOD_FALLING)
			{
				VectorCopy (dir, flydir);
				flydir[2] += 0.4f;
			}

			if (targ->mass < 50)
				mass = 50;
			else
				mass = targ->mass;

			if (targ->client && attacker == targ)
				VectorScale (flydir, 1600.0 * (float) knockback / mass, kvel);	// the rocket jump hack...
			else
				VectorScale (flydir, 500.0 * (float) knockback / mass, kvel);

			// FB
			//if (mod == MOD_KICK )
			//{
			//        kvel[2] = 0;
			//}

			VectorAdd (targ->velocity, kvel, targ->velocity);
		}
	}

	take = damage;
	save = 0;

	// check for godmode
	if ((targ->flags & FL_GODMODE) && !(dflags & DAMAGE_NO_PROTECTION))
	{
		take = 0;
		save = damage;
		SpawnDamage (te_sparks, point, normal, save);
	}

	// zucc don't need this stuff, but to remove it need to change how damagefeedback works with colors

	// check for invincibility
	if ((client && client->invincible_framenum > level.framenum)
		&& !(dflags & DAMAGE_NO_PROTECTION))
	{
		if (targ->pain_debounce_time < level.time)
		{
			gi.sound (targ, CHAN_ITEM, gi.soundindex ("items/protect4.wav"), 1,
				ATTN_NORM, 0);
			targ->pain_debounce_time = level.time + 2;
		}
		take = 0;
		save = damage;
	}

	psave = CheckPowerArmor (targ, point, normal, take, dflags);
	take -= psave;

	asave = CheckArmor (targ, point, normal, take, te_sparks, dflags);
	take -= asave;

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

	// team damage avoidance
	if (!(dflags & DAMAGE_NO_PROTECTION) && CheckTeamDamage (targ, attacker))
		return;
	if ((mod == MOD_M3) || (mod == MOD_HC)
	|| (mod == MOD_HELD_GRENADE) || (mod == MOD_HG_SPLASH)
	|| (mod == MOD_G_SPLASH) || (mod == MOD_BREAKINGGLASS))
	{
		//FB 6/3/99 - shotgun damage report stuff
		int playernum = targ - g_edicts;
		playernum--;
		if (playernum >= 0 && playernum <= game.maxclients - 1)
			*(took_damage + playernum) = 1;
		//FB 6/3/99

		bleeding = 1;
		instant_dam = 0;
	}

  /*        if ( (mod == MOD_M3) || (mod == MOD_HC) )
     {
     instant_dam = 1;            
     remain = take % 2;
     take = (int)(take/2); // balances out difference in how action and axshun handle damage/bleeding

     }
   */

	if (ctf->value)
		CTFCheckHurtCarrier (targ, attacker);

	// do the damage
	if (take)
	{
		// zucc added check for stopAP, if it hit a vest we want sparks
		if (((targ->svflags & SVF_MONSTER) || (client)) && !do_sparks)
			SpawnDamage (TE_BLOOD, point, normal, take);
		else
			SpawnDamage (te_sparks, point, normal, take);

		// all things that have at least some instantaneous damage, i.e. bruising/falling
		if (instant_dam)
			targ->health = targ->health - take;

		if (targ->health <= 0)
		{
			if (client && attacker->client)
			{
				//Added these here also, if this is the last shot and before shots is from
				//different attacker, msg's would go to wrong client -M
				if (!OnSameTeam (attacker, targ))
					attacker->client->resp.damage_dealt += damage;
			
				client->attacker = attacker;
				client->attacker_mod = mod;
				client->attacker_loc = damage_type;
			}

			if ((targ->svflags & SVF_MONSTER) || (client))
				targ->flags |= FL_NO_KNOCKBACK;
			Killed (targ, inflictor, attacker, take, point);
			return;
		}
	}

	if (targ->svflags & SVF_MONSTER)
	{
		M_ReactToDamage (targ, attacker);
		if (!(targ->monsterinfo.aiflags & AI_DUCKED) && (take))
		{
			targ->pain (targ, attacker, knockback, take);
			// nightmare mode monsters don't go into pain frames often
			if (skill->value == 3)
				targ->pain_debounce_time = level.time + 5;
		}
	}
	else if (client)
	{
		if (!(targ->flags & FL_GODMODE) && (take))
			targ->pain (targ, attacker, knockback, take);
	}
	else if (take)
	{
		if (targ->pain)
			targ->pain (targ, attacker, knockback, take);
	}

	// add to the damage inflicted on a player this frame
	// the total will be turned into screen blends and view angle kicks
	// at the end of the frame
	if (client)
	{
		client->damage_parmor += psave;
		client->damage_armor += asave;
		client->damage_blood += take;
		client->damage_knockback += knockback;
		//zucc handle adding bleeding here
		if (damage_type && bleeding)	// one of the hit location weapons
		{
			/* zucc add in partial bleeding, changed
			if ( client->bleeding < 4*damage*BLEED_TIME )
			{
			client->bleeding = 4*damage*BLEED_TIME + client->bleeding/2;

			}
			else
			{
			client->bleeding += damage*BLEED_TIME*2;

			} */
			client->bleeding += damage * BLEED_TIME;
			VectorSubtract (point, targ->absmax, targ->client->bleedloc_offset);
			//VectorSubtract(point, targ->s.origin,  client->bleedloc_offset);

		}
		else if (bleeding)
		{
			/*
			if ( client->bleeding < damage*BLEED_TIME )
			{
			client->bleeding = damage*BLEED_TIME;
			//client->bleedcount = 0;
			} */
			client->bleeding += damage * BLEED_TIME;
			VectorSubtract (point, targ->absmax, targ->client->bleedloc_offset);
			//VectorSubtract(point, targ->s.origin,  client->bleedloc_offset);

		}
		if (attacker->client)
		{
			if (!OnSameTeam (attacker, targ))
				attacker->client->resp.damage_dealt += damage;

			client->attacker = attacker;
			client->attacker_mod = mod;
			client->attacker_loc = damage_type;
			client->push_timeout = 50;
			//VectorCopy(dir, client->bleeddir );
			//VectorCopy(point, client->bleedpoint );
			//VectorCopy(normal, client->bleednormal);

		}
		VectorCopy (point, client->damage_from);
	}
}
Example #3
0
void T_Damage (edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t dir, vec3_t point, vec3_t normal, int damage, int knockback, int dflags, int mod)
{
	gclient_t	*client;
	int			take;
	int			save;
	int			asave;
	int			psave;
	int			te_sparks;

	if (!targ->takedamage)
		return;

	// friendly fire avoidance
	// if enabled you can't hurt teammates (but you can hurt yourself)
	// knockback still occurs
	if ((targ != attacker) && ((deathmatch->value && ((int)(dmflags->value) & (DF_MODELTEAMS | DF_SKINTEAMS))) || coop->value))
	{
		if (OnSameTeam (targ, attacker))
		{
			if ((int)(dmflags->value) & DF_NO_FRIENDLY_FIRE)
				damage = 0;
			else
				mod |= MOD_FRIENDLY_FIRE;
		}
	}
	meansOfDeath = mod;

	// easy mode takes half damage
	if (skill->value == 0 && deathmatch->value == 0 && targ->client)
	{
		damage *= 0.5;
		if (!damage)
			damage = 1;
	}

	client = targ->client;

	if (dflags & DAMAGE_BULLET)
		te_sparks = TE_BULLET_SPARKS;
	else
		te_sparks = TE_SPARKS;

	VectorNormalize(dir);

// bonus damage for suprising a monster
	if (!(dflags & DAMAGE_RADIUS) && (targ->svflags & SVF_MONSTER) && (attacker->client) && (!targ->enemy) && (targ->health > 0))
		damage *= 2;

	if (targ->flags & FL_NO_KNOCKBACK)
		knockback = 0;

// figure momentum add
	if (!(dflags & DAMAGE_NO_KNOCKBACK))
	{
		if ((knockback) && (targ->movetype != MOVETYPE_NONE) && (targ->movetype != MOVETYPE_BOUNCE) && (targ->movetype != MOVETYPE_PUSH) && (targ->movetype != MOVETYPE_STOP))
		{
			vec3_t	kvel;
			float	mass;

			if (targ->mass < 50)
				mass = 50;
			else
				mass = targ->mass;

			if (targ->client  && attacker == targ)
				VectorScale (dir, 1600.0 * (float)knockback / mass, kvel);	// the rocket jump hack...
			else
				VectorScale (dir, 500.0 * (float)knockback / mass, kvel);

			VectorAdd (targ->velocity, kvel, targ->velocity);
		}
	}

	take = damage;
	save = 0;

	// check for godmode
	if ( (targ->flags & FL_GODMODE) && !(dflags & DAMAGE_NO_PROTECTION) )
	{
		take = 0;
		save = damage;
		SpawnDamage (te_sparks, point, normal, save);
	}

	// check for invincibility
	if ((client && client->invincible_framenum > level.framenum ) && !(dflags & DAMAGE_NO_PROTECTION))
	{
		if (targ->pain_debounce_time < level.time)
		{
			gi.sound(targ, CHAN_ITEM, gi.soundindex("items/protect4.wav"), 1, ATTN_NORM, 0);
			targ->pain_debounce_time = level.time + 2;
		}
		take = 0;
		save = damage;
	}

	psave = CheckPowerArmor (targ, point, normal, take, dflags);
	take -= psave;

	asave = CheckArmor (targ, point, normal, take, te_sparks, dflags);
	take -= asave;

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

	// team damage avoidance
	if (!(dflags & DAMAGE_NO_PROTECTION) && CheckTeamDamage (targ, attacker))
		return;

// do the damage
	if (take)
	{
		if ((targ->svflags & SVF_MONSTER) || (client))
			SpawnDamage (TE_BLOOD, point, normal, take);
		else
			SpawnDamage (te_sparks, point, normal, take);


		targ->health = targ->health - take;
			
		if (targ->health <= 0)
		{
			if ((targ->svflags & SVF_MONSTER) || (client))
				targ->flags |= FL_NO_KNOCKBACK;
			Killed (targ, inflictor, attacker, take, point);
			return;
		}
	}

	if (targ->svflags & SVF_MONSTER)
	{
		M_ReactToDamage (targ, attacker);
		if (!(targ->monsterinfo.aiflags & AI_DUCKED) && (take))
		{
			targ->pain (targ, attacker, knockback, take);
			// nightmare mode monsters don't go into pain frames often
			if (skill->value == 3)
				targ->pain_debounce_time = level.time + 5;
		}
	}
	else if (client)
	{
		if (!(targ->flags & FL_GODMODE) && (take))
			targ->pain (targ, attacker, knockback, take);
	}
	else if (take)
	{
		if (targ->pain)
			targ->pain (targ, attacker, knockback, take);
	}

	// add to the damage inflicted on a player this frame
	// the total will be turned into screen blends and view angle kicks
	// at the end of the frame
	if (client)
	{
		client->damage_parmor += psave;
		client->damage_armor += asave;
		client->damage_blood += take;
		client->damage_knockback += knockback;
		VectorCopy (point, client->damage_from);
	}
}
Example #4
0
void T_Damage (edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t dir, vec3_t point, vec3_t normal, int damage, int knockback, int dflags, int mod)
{
    gclient_t	*client;
    int			take;
    int			save;
    int			asave;
    int			psave;
    int			te_sparks;
    int			sphere_notified;	// PGM

    if (!targ->takedamage)
        return;

    sphere_notified = false;		// PGM

    // friendly fire avoidance
    // if enabled you can't hurt teammates (but you can hurt yourself)
    // knockback still occurs
    if ((targ != attacker) && ((deathmatch->value && ((int)(dmflags->value) & (DF_MODELTEAMS | DF_SKINTEAMS))) || coop->value))
    {
        if (OnSameTeam (targ, attacker))
        {
            // PMM - nukes kill everyone
            if (((int)(dmflags->value) & DF_NO_FRIENDLY_FIRE) && (mod != MOD_NUKE))
                damage = 0;
            else
                mod |= MOD_FRIENDLY_FIRE;
        }
    }
    meansOfDeath = mod;

    //ROGUE
    // allow the deathmatch game to change values
    if (deathmatch->value && gamerules && gamerules->value)
    {
        if(DMGame.ChangeDamage)
            damage = DMGame.ChangeDamage(targ, attacker, damage, mod);
        if(DMGame.ChangeKnockback)
            knockback = DMGame.ChangeKnockback(targ, attacker, knockback, mod);

        if(!damage)
            return;
    }
    //ROGUE

    // easy mode takes half damage
    if (skill->value == 0 && deathmatch->value == 0 && targ->client)
    {
        damage *= 0.5;
        if (!damage)
            damage = 1;
    }

    client = targ->client;

    // PMM - defender sphere takes half damage
    if ((client) && (client->owned_sphere) && (client->owned_sphere->spawnflags == 1))
    {
        damage *= 0.5;
        if (!damage)
            damage = 1;
    }

    if (dflags & DAMAGE_BULLET)
        te_sparks = TE_BULLET_SPARKS;
    else
        te_sparks = TE_SPARKS;

    VectorNormalize(dir);

    // bonus damage for suprising a monster
    if (!(dflags & DAMAGE_RADIUS) && (targ->svflags & SVF_MONSTER) && (attacker->client) && (!targ->enemy) && (targ->health > 0))
        damage *= 2;

    if (targ->flags & FL_NO_KNOCKBACK)
        knockback = 0;

    // figure momentum add
    if (!(dflags & DAMAGE_NO_KNOCKBACK))
    {
        if ((knockback) && (targ->movetype != MOVETYPE_NONE) && (targ->movetype != MOVETYPE_BOUNCE) && (targ->movetype != MOVETYPE_PUSH) && (targ->movetype != MOVETYPE_STOP))
        {
            vec3_t	kvel;
            float	mass;

            if (targ->mass < 50)
                mass = 50;
            else
                mass = targ->mass;

            if (targ->client  && attacker == targ)
                VectorScale (dir, 1600.0 * (float)knockback / mass, kvel);	// the rocket jump hack...
            else
                VectorScale (dir, 500.0 * (float)knockback / mass, kvel);

            VectorAdd (targ->velocity, kvel, targ->velocity);
        }
    }

    take = damage;
    save = 0;

    // check for godmode
    if ( (targ->flags & FL_GODMODE) && !(dflags & DAMAGE_NO_PROTECTION) )
    {
        take = 0;
        save = damage;
        SpawnDamage (te_sparks, point, normal, save);
    }

    // check for invincibility
    if ((client && client->invincible_framenum > level.framenum ) && !(dflags & DAMAGE_NO_PROTECTION))
    {
        if (targ->pain_debounce_time < level.time)
        {
            gi.sound(targ, CHAN_ITEM, gi.soundindex("items/protect4.wav"), 1, ATTN_NORM, 0);
            targ->pain_debounce_time = level.time + 2;
        }
        take = 0;
        save = damage;
    }
    // ROGUE
    // check for monster invincibility
    if (((targ->svflags & SVF_MONSTER) && targ->monsterinfo.invincible_framenum > level.framenum ) && !(dflags & DAMAGE_NO_PROTECTION))
    {
        if (targ->pain_debounce_time < level.time)
        {
            gi.sound(targ, CHAN_ITEM, gi.soundindex("items/protect4.wav"), 1, ATTN_NORM, 0);
            targ->pain_debounce_time = level.time + 2;
        }
        take = 0;
        save = damage;
    }
    // ROGUE

    psave = CheckPowerArmor (targ, point, normal, take, dflags);
    take -= psave;

    asave = CheckArmor (targ, point, normal, take, te_sparks, dflags);
    take -= asave;

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

    // team damage avoidance
    if (!(dflags & DAMAGE_NO_PROTECTION) && CheckTeamDamage (targ, attacker))
        return;

    // ROGUE - this option will do damage both to the armor and person. originally for DPU rounds
    if (dflags & DAMAGE_DESTROY_ARMOR)
    {
        if(!(targ->flags & FL_GODMODE) && !(dflags & DAMAGE_NO_PROTECTION) &&
                !(client && client->invincible_framenum > level.framenum))
        {
            take = damage;
        }
    }
    // ROGUE

    // do the damage
    if (take)
    {
        //PGM		need more blood for chainfist.
        if(targ->flags & FL_MECHANICAL)
        {
            SpawnDamage ( TE_ELECTRIC_SPARKS, point, normal, take);
        }
        else if ((targ->svflags & SVF_MONSTER) || (client))
        {
            if(mod == MOD_CHAINFIST)
                SpawnDamage (TE_MOREBLOOD, point, normal, 255);
            else
                SpawnDamage (TE_BLOOD, point, normal, take);
        }
        else
            SpawnDamage (te_sparks, point, normal, take);
        //PGM

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

        //PGM - spheres need to know who to shoot at
        if(client && client->owned_sphere)
        {
            sphere_notified = true;
            if(client->owned_sphere->pain)
                client->owned_sphere->pain (client->owned_sphere, attacker, 0, 0);
        }
        //PGM

        if (targ->health <= 0)
        {
            if ((targ->svflags & SVF_MONSTER) || (client))
                targ->flags |= FL_NO_KNOCKBACK;
            Killed (targ, inflictor, attacker, take, point);
            return;
        }
    }

    //PGM - spheres need to know who to shoot at
    if (!sphere_notified)
    {
        if(client && client->owned_sphere)
        {
            if(client->owned_sphere->pain)
                client->owned_sphere->pain (client->owned_sphere, attacker, 0, 0);
        }
    }
    //PGM

    if (targ->svflags & SVF_MONSTER)
    {
        M_ReactToDamage (targ, attacker, inflictor);
        // PMM - fixme - if anyone else but the medic ever uses AI_MEDIC, check for it here instead
        // of in the medic's pain function
        if (!(targ->monsterinfo.aiflags & AI_DUCKED) && (take))
        {
            targ->pain (targ, attacker, knockback, take);
            // nightmare mode monsters don't go into pain frames often
            if (skill->value == 3)
                targ->pain_debounce_time = level.time + 5;
        }
    }
    else if (client)
    {
        if (!(targ->flags & FL_GODMODE) && (take))
            targ->pain (targ, attacker, knockback, take);
    }
    else if (take)
    {
        if (targ->pain)
            targ->pain (targ, attacker, knockback, take);
    }

    // add to the damage inflicted on a player this frame
    // the total will be turned into screen blends and view angle kicks
    // at the end of the frame
    if (client)
    {
        client->damage_parmor += psave;
        client->damage_armor += asave;
        client->damage_blood += take;
        client->damage_knockback += knockback;
        VectorCopy (point, client->damage_from);
    }
}
Example #5
0
void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
			   vec3_t dir, vec3_t point, int damage, int dflags, int mod ) {
	gclient_t   *client;
	int take;
	int save;
	int asave;
	int knockback;

	if ( !targ->takedamage ) {
		return;
	}

	// the intermission has allready been qualified for, so don't
	// allow any extra scoring
	if ( level.intermissionQueued || g_gamestate.integer != GS_PLAYING ) {
		return;
	}

	if ( !inflictor ) {
		inflictor = &g_entities[ENTITYNUM_WORLD];
	}
	if ( !attacker ) {
		attacker = &g_entities[ENTITYNUM_WORLD];
	}

// JPW NERVE
	if ( ( targ->waterlevel >= 3 ) && ( mod == MOD_FLAMETHROWER ) ) {
		return;
	}
// jpw

	// shootable doors / buttons don't actually have any health
	if ( targ->s.eType == ET_MOVER && !( targ->aiName ) && !( targ->isProp ) && !targ->scriptName ) {
		if ( targ->use && targ->moverState == MOVER_POS1 ) {
			targ->use( targ, inflictor, attacker );
		}
		return;
	}

	if ( targ->s.eType == ET_MOVER && targ->aiName && !( targ->isProp ) && !targ->scriptName ) {
		switch ( mod ) {
		case MOD_GRENADE:
		case MOD_GRENADE_SPLASH:
		case MOD_ROCKET:
		case MOD_ROCKET_SPLASH:
			break;
		default:
			return; // no damage from other weapons
		}
	} else if ( targ->s.eType == ET_EXPLOSIVE )   {
		// 32 Explosive
		// 64 Dynamite only
		if ( ( targ->spawnflags & 32 ) || ( targ->spawnflags & 64 ) ) {
			switch ( mod ) {
			case MOD_GRENADE:
			case MOD_GRENADE_SPLASH:
			case MOD_ROCKET:
			case MOD_ROCKET_SPLASH:
			case MOD_AIRSTRIKE:
			case MOD_GRENADE_PINEAPPLE:
			case MOD_MORTAR:
			case MOD_MORTAR_SPLASH:
			case MOD_EXPLOSIVE:
				if ( targ->spawnflags & 64 ) {
					return;
				}

				break;

			case MOD_DYNAMITE:
			case MOD_DYNAMITE_SPLASH:
				break;

			default:
				return;
			}
		}
	}

	client = targ->client;

	if ( client ) {
		if ( client->noclip ) {
			return;
		}
	}

	if ( !dir ) {
		dflags |= DAMAGE_NO_KNOCKBACK;
	} else {
		VectorNormalize( dir );
	}

	knockback = damage;
	if ( knockback > 200 ) {
		knockback = 200;
	}
	if ( targ->flags & FL_NO_KNOCKBACK ) {
		knockback = 0;
	}
	if ( dflags & DAMAGE_NO_KNOCKBACK ) {
		knockback = 0;
	}

	// figure momentum add, even if the damage won't be taken
	if ( knockback && targ->client && ( g_friendlyFire.integer || !OnSameTeam( targ, attacker ) ) ) {
		vec3_t kvel;
		float mass;

		mass = 200;

		if ( mod == MOD_LIGHTNING && !( ( level.time + targ->s.number * 50 ) % 400 ) ) {
			knockback = 60;
			dir[2] = 0.3;
		}

		VectorScale( dir, g_knockback.value * (float)knockback / mass, kvel );
		VectorAdd( targ->client->ps.velocity, kvel, targ->client->ps.velocity );

		if ( targ == attacker && !(  mod != MOD_ROCKET &&
									 mod != MOD_ROCKET_SPLASH &&
									 mod != MOD_GRENADE &&
									 mod != MOD_GRENADE_SPLASH &&
									 mod != MOD_DYNAMITE ) ) {
			targ->client->ps.velocity[2] *= 0.25;
		}

		// set the timer so that the other client can't cancel
		// out the movement immediately
		if ( !targ->client->ps.pm_time ) {
			int t;

			t = knockback * 2;
			if ( t < 50 ) {
				t = 50;
			}
			if ( t > 200 ) {
				t = 200;
			}
			targ->client->ps.pm_time = t;
			targ->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
		}
	}

	// check for completely getting out of the damage
	if ( !( dflags & DAMAGE_NO_PROTECTION ) ) {

		// if TF_NO_FRIENDLY_FIRE is set, don't do damage to the target
		// if the attacker was on the same team
		if ( targ != attacker && OnSameTeam( targ, attacker )  ) {
			if ( !g_friendlyFire.integer ) {
				return;
			}
		}

		// check for godmode
		if ( targ->flags & FL_GODMODE ) {
			return;
		}

		// RF, warzombie defense position is basically godmode for the time being
		if ( targ->flags & FL_DEFENSE_GUARD ) {
			return;
		}

		// check for invulnerability // (SA) moved from below so DAMAGE_NO_PROTECTION will still work
		if ( client && client->ps.powerups[PW_INVULNERABLE] ) { //----(SA)	added
			return;
		}

	}

	// battlesuit protects from all radius damage (but takes knockback)
	// and protects 50% against all damage
	if ( client && client->ps.powerups[PW_BATTLESUIT] ) {
		G_AddEvent( targ, EV_POWERUP_BATTLESUIT, 0 );
		if ( dflags & DAMAGE_RADIUS ) {
			return;
		}
		damage *= 0.5;
	}

	// add to the attacker's hit counter
	if ( attacker->client && targ != attacker && targ->health > 0 ) {
		if ( OnSameTeam( targ, attacker ) ) {
			attacker->client->ps.persistant[PERS_HITS] -= damage;
		} else {
			attacker->client->ps.persistant[PERS_HITS] += damage;
		}
	}

	if ( damage < 1 ) {
		damage = 1;
	}
	take = damage;
	save = 0;

	// save some from armor
	asave = CheckArmor( targ, take, dflags );
	take -= asave;

	if ( IsHeadShot( targ, qfalse, dir, point, mod ) ) {

		if ( take * 2 < 50 ) { // head shots, all weapons, do minimum 50 points damage
			take = 50;
		} else {
			take *= 2; // sniper rifles can do full-kill (and knock into limbo)

		}
		if ( !( targ->client->ps.eFlags & EF_HEADSHOT ) ) {  // only toss hat on first headshot
			G_AddEvent( targ, EV_LOSE_HAT, DirToByte( dir ) );
		}

		targ->client->ps.eFlags |= EF_HEADSHOT;
	}

	if ( g_debugDamage.integer ) {
		G_Printf( "client:%i health:%i damage:%i armor:%i\n", targ->s.number,
				  targ->health, take, asave );
	}

	// add to the damage inflicted on a player this frame
	// the total will be turned into screen blends and view angle kicks
	// at the end of the frame
	if ( client ) {
		if ( attacker ) {
			client->ps.persistant[PERS_ATTACKER] = attacker->s.number;
		} else {
			client->ps.persistant[PERS_ATTACKER] = ENTITYNUM_WORLD;
		}
		client->damage_armor += asave;
		client->damage_blood += take;
		client->damage_knockback += knockback;

		if ( dir ) {
			VectorCopy( dir, client->damage_from );
			client->damage_fromWorld = qfalse;
		} else {
			VectorCopy( targ->r.currentOrigin, client->damage_from );
			client->damage_fromWorld = qtrue;
		}
	}

	// See if it's the player hurting the emeny flag carrier
	Team_CheckHurtCarrier( targ, attacker );

	if ( targ->client ) {
		// set the last client who damaged the target
		targ->client->lasthurt_client = attacker->s.number;
		targ->client->lasthurt_mod = mod;
	}

	// do the damage
	if ( take ) {
		targ->health = targ->health - take;

		// Ridah, can't gib with bullet weapons (except VENOM)
		if ( mod != MOD_VENOM && attacker == inflictor && targ->health <= GIB_HEALTH ) {
			if ( targ->aiCharacter != AICHAR_ZOMBIE ) { // zombie needs to be able to gib so we can kill him (although he doesn't actually GIB, he just dies)
				targ->health = GIB_HEALTH + 1;
			}
		}

// JPW NERVE overcome previous chunk of code for making grenades work again
		if ( ( g_gametype.integer != GT_SINGLE_PLAYER ) && ( take > 190 ) ) { // 190 is greater than 2x mauser headshot, so headshots don't gib
			targ->health = GIB_HEALTH - 1;
		}
// jpw
		//G_Printf("health at: %d\n", targ->health);
		if ( targ->health <= 0 ) {
			if ( client ) {
				targ->flags |= FL_NO_KNOCKBACK;
// JPW NERVE -- repeated shooting sends to limbo
				if ( g_gametype.integer >= GT_WOLF ) {
					if ( ( targ->health < FORCE_LIMBO_HEALTH ) && ( targ->health > GIB_HEALTH ) && ( !( targ->client->ps.pm_flags & PMF_LIMBO ) ) ) {
						limbo( targ, qtrue );
					}
				}
// jpw
			}

			if ( targ->health < -999 ) {
				targ->health = -999;
			}

			targ->enemy = attacker;
			if ( targ->die ) { // Ridah, mg42 doesn't have die func (FIXME)
				targ->die( targ, inflictor, attacker, take, mod );
			}

			// if we freed ourselves in death function
			if ( !targ->inuse ) {
				return;
			}

			// RF, entity scripting
			if ( targ->s.number >= MAX_CLIENTS && targ->health <= 0 ) { // might have revived itself in death function
				G_Script_ScriptEvent( targ, "death", "" );
			}

		} else if ( targ->pain ) {
			if ( dir ) {  // Ridah, had to add this to fix NULL dir crash
				VectorCopy( dir, targ->rotate );
				VectorCopy( point, targ->pos3 ); // this will pass loc of hit
			} else {
				VectorClear( targ->rotate );
				VectorClear( targ->pos3 );
			}

			targ->pain( targ, attacker, take, point );

			// RF, entity scripting
			if ( targ->s.number >= MAX_CLIENTS ) {
				G_Script_ScriptEvent( targ, "pain", va( "%d %d", targ->health, targ->health + take ) );
			}
		}

		//G_ArmorDamage(targ);	//----(SA)	moved out to separate routine

		// Ridah, this needs to be done last, incase the health is altered in one of the event calls
		if ( targ->client ) {
			targ->client->ps.stats[STAT_HEALTH] = targ->health;
		}
	}

}
Example #6
0
void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
			   vec3_t dir, vec3_t point, int damage, int dflags, int mod ) {
	gclient_t	*client;
	int			take;
	//int			save;
	int			asave;
	int			knockback;
	int			max;
        
	vec3_t		bouncedir, impactpoint;

	if (!targ->takedamage) {
		return;
	}

	// the intermission has allready been qualified for, so don't
	// allow any extra scoring
	if ( level.intermissionQueued ) {
		return;
	}
	if ( targ->client && mod != MOD_JUICED) {
		if ( targ->client->invulnerabilityTime > level.time) {
			if ( dir && point ) {
				G_InvulnerabilityEffect( targ, dir, point, impactpoint, bouncedir );
			}
			return;
		}
	}
        //Sago: This was moved up
        client = targ->client;
        
        //Sago: See if the client was sent flying
        //Check if damage is by somebody who is not a player!
        if( (!attacker || attacker->s.eType != ET_PLAYER) && client && client->lastSentFlying>-1 && ( mod==MOD_FALLING || mod==MOD_LAVA || mod==MOD_SLIME || mod==MOD_TRIGGER_HURT || mod==MOD_SUICIDE) )  {
            if( client->lastSentFlyingTime+5000<level.time) {
                client->lastSentFlying = -1; //More than 5 seconds, not a kill!
            } else {
                //G_Printf("LastSentFlying %i\n",client->lastSentFlying);
                attacker = &g_entities[client->lastSentFlying];
            }
        }
        
	if ( !inflictor ) {
		inflictor = &g_entities[ENTITYNUM_WORLD];
	}
	if ( !attacker ) {
		attacker = &g_entities[ENTITYNUM_WORLD];
	}

	// shootable doors / buttons don't actually have any health
	if ( targ->s.eType == ET_MOVER ) {
		if ( targ->use && targ->moverState == MOVER_POS1 ) {
			targ->use( targ, inflictor, attacker );
		}
		return;
	}
	if( g_gametype.integer == GT_OBELISK && CheckObeliskAttack( targ, attacker ) ) {
		return;
	}
	// reduce damage by the attacker's handicap value
	// unless they are rocket jumping
	if ( attacker->client && attacker != targ ) {
		max = attacker->client->ps.stats[STAT_MAX_HEALTH];
		if( bg_itemlist[attacker->client->ps.stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) {
			max /= 2;
		}
		damage = damage * max / 100;
	}

        //Sago: I have moved this up
	//client = targ->client;

	if ( client ) {
		if ( client->noclip ) {
			return;
		}
	}

	if ( !dir ) {
		dflags |= DAMAGE_NO_KNOCKBACK;
	} else {
		VectorNormalize(dir);
	}

	knockback = damage;
	if ( knockback > 200 ) {
		knockback = 200;
	}
	if ( targ->flags & FL_NO_KNOCKBACK ) {
		knockback = 0;
	}
	if ( dflags & DAMAGE_NO_KNOCKBACK ) {
		knockback = 0;
	}

	// figure momentum add, even if the damage won't be taken
	if ( knockback && targ->client ) {
		vec3_t	kvel;
		float	mass;

		mass = 200;

		VectorScale (dir, g_knockback.value * (float)knockback / mass, kvel);
		VectorAdd (targ->client->ps.velocity, kvel, targ->client->ps.velocity);

		// set the timer so that the other client can't cancel
		// out the movement immediately
		if ( !targ->client->ps.pm_time ) {
			int		t;

			t = knockback * 2;
			if ( t < 50 ) {
				t = 50;
			}
			if ( t > 200 ) {
				t = 200;
			}
			targ->client->ps.pm_time = t;
			targ->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
		}
                //Remeber the last person to hurt the player
                if( !g_awardpushing.integer || targ==attacker || OnSameTeam (targ, attacker)) {
                    targ->client->lastSentFlying = -1;
                } else {
	/*if ( pm->waterlevel <= 1 ) {
		if ( pml.walking && !(pml.groundTrace.surfaceFlags & SURF_SLICK) ) {
			// if getting knocked back, no friction
			if ( ! (pm->ps->pm_flags & PMF_TIME_KNOCKBACK) ) {
				control = speed < pm_stopspeed ? pm_stopspeed : speed;
				drop += control*pm_friction*pml.frametime;
			}
		}
	}*/
                    targ->client->lastSentFlying = attacker->s.number;
                    targ->client->lastSentFlyingTime = level.time;
                }
	}

	// check for completely getting out of the damage
	if ( !(dflags & DAMAGE_NO_PROTECTION) ) {

		// if TF_NO_FRIENDLY_FIRE is set, don't do damage to the target
		// if the attacker was on the same team
		if ( mod != MOD_JUICED && mod != MOD_CRUSH && targ != attacker && !(dflags & DAMAGE_NO_TEAM_PROTECTION) && OnSameTeam (targ, attacker)  ) {
			if ( ( !g_friendlyFire.integer && g_gametype.integer != GT_ELIMINATION && g_gametype.integer != GT_CTF_ELIMINATION ) || ( g_elimination_selfdamage.integer<2 &&	(g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION) ) ) {
				return;
			}
		}
		if (mod == MOD_PROXIMITY_MINE) {
			if (inflictor && inflictor->parent && OnSameTeam(targ, inflictor->parent)) {
				return;
			}
			if (targ == attacker) {
				return;
			}
		}

		// check for godmode
		if ( targ->flags & FL_GODMODE ) {
			return;
		}

                if(targ->client && targ->client->spawnprotected) {
                   if(level.time>targ->client->respawnTime+g_spawnprotect.integer)
                       targ->client->spawnprotected = qfalse;
                   else
                       if( (mod > MOD_UNKNOWN && mod < MOD_WATER) || mod == MOD_TELEFRAG || mod>MOD_TRIGGER_HURT)
                       return;
                }
	}

	// battlesuit protects from all radius damage (but takes knockback)
	// and protects 50% against all damage
	if ( client && client->ps.powerups[PW_BATTLESUIT] ) {
		G_AddEvent( targ, EV_POWERUP_BATTLESUIT, 0 );
		if ( ( dflags & DAMAGE_RADIUS ) || ( mod == MOD_FALLING ) ) {
			return;
		}
		damage *= 0.5;
	}

	// add to the attacker's hit counter (if the target isn't a general entity like a prox mine)
	if ( attacker->client && client
			&& targ != attacker && targ->health > 0
			&& targ->s.eType != ET_MISSILE
			&& targ->s.eType != ET_GENERAL) {
		if ( OnSameTeam( targ, attacker ) ) {
			attacker->client->ps.persistant[PERS_HITS]--;
		} else {
			attacker->client->ps.persistant[PERS_HITS]++;
		}
		attacker->client->ps.persistant[PERS_ATTACKEE_ARMOR] = (targ->health<<8)|(client->ps.stats[STAT_ARMOR]);
	}

	// always give half damage if hurting self
	// calculated after knockback, so rocket jumping works
	if ( targ == attacker) {
		damage *= 0.5;
	}

        if(targ && targ->client && attacker->client )
            damage = catchup_damage(damage, attacker->client->ps.persistant[PERS_SCORE], targ->client->ps.persistant[PERS_SCORE]);
        
        if(g_damageModifier.value > 0.01) {
            damage *= g_damageModifier.value;
        }

	if ( damage < 1 ) {
		damage = 1;
	}
        
        if(targ == attacker && (g_dmflags.integer & DF_NO_SELF_DAMAGE) )
            damage = 0;

	if ((g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION || g_gametype.integer == GT_LMS || g_elimination_allgametypes.integer)
				&& g_elimination_selfdamage.integer<1 && ( targ == attacker ||  mod == MOD_FALLING )) {
		damage = 0;
	}


//So people can be telefragged!
	if ((g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_CTF_ELIMINATION || g_gametype.integer == GT_LMS) && level.time < level.roundStartTime && ((mod == MOD_LAVA) || (mod == MOD_SLIME)) ) {
		damage = 1000;
	}


	take = damage;
	//save = 0;

	// save some from armor
	asave = CheckArmor (targ, take, dflags);
	take -= asave;

	if ( g_debugDamage.integer ) {
		G_Printf( "%i: client:%i health:%i damage:%i armor:%i\n", level.time, targ->s.number,
			targ->health, take, asave );
	}

	// add to the damage inflicted on a player this frame
	// the total will be turned into screen blends and view angle kicks
	// at the end of the frame
	if ( client ) {
		if ( attacker ) {
			client->ps.persistant[PERS_ATTACKER] = attacker->s.number;
                } else if(client->lastSentFlying) {
                        client->ps.persistant[PERS_ATTACKER] = client->lastSentFlying;
                } else {
			client->ps.persistant[PERS_ATTACKER] = ENTITYNUM_WORLD;
		}
		client->damage_armor += asave;
		client->damage_blood += take;
		client->damage_knockback += knockback;
		if ( dir ) {
			VectorCopy ( dir, client->damage_from );
			client->damage_fromWorld = qfalse;
		} else {
			VectorCopy ( targ->r.currentOrigin, client->damage_from );
			client->damage_fromWorld = qtrue;
		}
	}

	// See if it's the player hurting the emeny flag carrier
	if( g_gametype.integer == GT_CTF || g_gametype.integer == GT_1FCTF || g_gametype.integer == GT_CTF_ELIMINATION) {
		Team_CheckHurtCarrier(targ, attacker);
	}

	if (targ->client) {
		// set the last client who damaged the target
		targ->client->lasthurt_client = attacker->s.number;
		targ->client->lasthurt_mod = mod;
	}

	//If vampire is enabled, gain health but not from self or teammate, cannot steal more than targ has
	if( g_vampire.value>0.0 && (targ != attacker) && take > 0 && 
                !(OnSameTeam(targ, attacker)) && attacker->health > 0 && targ->health > 0 )
	{
		if(take<targ->health)
			attacker->health += (int)(((float)take)*g_vampire.value);
		else
			attacker->health += (int)(((float)targ->health)*g_vampire.value);
		if(attacker->health>g_vampireMaxHealth.integer)
			attacker->health = g_vampireMaxHealth.integer;
	}

	// do the damage
	if (take) {
		targ->health = targ->health - take;
		if ( targ->client ) {
			targ->client->ps.stats[STAT_HEALTH] = targ->health;
		}
			
		if ( targ->health <= 0 ) {
			if ( client )
				targ->flags |= FL_NO_KNOCKBACK;

			if (targ->health < -999)
				targ->health = -999;
                        
			targ->enemy = attacker;
			targ->die (targ, inflictor, attacker, take, mod);
			return;
		} else if ( targ->pain ) {
			targ->pain (targ, attacker, take);
		}
	}

	
}
Example #7
0
int T_Damage (edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t dir, vec3_t point, vec3_t normal, int damage, int knockback, int dflags, int mod) {
	qboolean mod_magic = false;
	gclient_t	*client;
	int			take = 0;
	int			save = 0;
	int			asave = 0;
	int			psave = 0;
	int			rsave = 0;
	int			sasave = 0;
	int			te_sparks;

	if (!targ->takedamage)
		return 0;

// Can't heal monsters
	if ((damage < 0) && (targ->svflags & SVF_MONSTER)) {
		return 0;
	}

	if (mod & MOD_MAGIC) { //damage dealt by magic
		mod_magic = true;
		mod &= ~MOD_MAGIC;
	}
	// friendly fire avoidance
	// if enabled you can't hurt teammates (but you can hurt yourself)
	// knockback still occurs

	// team damage avoidance, if not telefrag
	if (mod != MOD_TELEFRAG) {
		if (deathmatch->value && attacker->client && targ->client && (targ != attacker) && (((targ->count == attacker->count) && teams->value) || (game.monsterhunt == 10)) && (damage > 0)) { // Two players on same team
			damage *= teamdamage->value;
		}
		if (coop->value && attacker->client && targ->client && (targ != attacker)) {
			damage *= teamdamage->value;
		}
	}
	meansOfDeath = mod;

	client = targ->client;

	if (dflags & DAMAGE_BULLET)
		te_sparks = TE_BULLET_SPARKS;
	else
		te_sparks = TE_SPARKS;

	VectorNormalize(dir);

	if (targ->flags & FL_NO_KNOCKBACK)
		knockback = 0;

// Simulate armor pierce and armor breaker on monsters
// This has been disabled, since it applies bonus AFTER all other bonuses, resulting in crazy total bonuses
/*	if ((targ->svflags & SVF_MONSTER) && (attacker->client) && (!mod_magic)) {
		if (attacker->client->pers.skill[2] > 0) {
			if (mod == MOD_BLASTER) {
				iteminfo_t *winfo = getWornItemInfo(attacker, 0);
				damage *= 1 + 0.75 * (winfo->arg4 + winfo->arg5 * attacker->client->pers.skill[2]);
			} else {
				damage *= 1 + 0.02 * attacker->client->pers.skill[2];
			}
		}
		if (attacker->client->pers.skill[72] > 0) {
			damage *= 1 + 0.02 * attacker->client->pers.skill[72];
		}
	}*/

	if ((targ->svflags & SVF_MONSTER) && (targ->health > 0)) {
		float manaburn_mult = 0.0f;
		float manaleech_mult = 0.0f;
		if ((targ->radius_dmg) && (targ->monsterinfo.ability) && (damage > 0)) {
			rsave = 0;
			if ((targ->monsterinfo.ability & GIEX_MABILITY_RES_EXPL) &&
				((mod == MOD_GRENADE) || (mod == MOD_G_SPLASH) ||
				(mod == MOD_ROCKET) || (mod == MOD_R_SPLASH) ||
				(mod == MOD_HANDGRENADE) || (mod == MOD_HG_SPLASH))) {
				rsave += 0.33 * damage;
			}
			if ((targ->monsterinfo.ability & GIEX_MABILITY_RES_IMPACT) &&
				((mod == MOD_MACHINEGUN) || (mod == MOD_CHAINGUN) ||
				(mod == MOD_SHOTGUN) || (mod == MOD_SSHOTGUN))) {
				rsave += 0.33 * damage;
			}
			if ((targ->monsterinfo.ability & GIEX_MABILITY_RES_ENERGY) &&
				((mod == MOD_BLASTER) || (mod == MOD_HYPERBLASTER) ||
				(mod == MOD_LASERMINE) || (mod == MOD_RAILGUN) ||
				(mod == MOD_BFG_LASER) || (mod == MOD_BFG_BLAST) || (mod == MOD_BFG_EFFECT))) {
				rsave += 0.33 * damage;
			}
			if ((targ->monsterinfo.ability & GIEX_MABILITY_RES_BMAGIC) &&
				((mod == MOD_PLAGUEBOMB) || (mod == MOD_DRAIN) || (mod == MOD_SPORE))) {
				rsave += 0.33 * damage;
			}
			if ((targ->monsterinfo.ability & GIEX_MABILITY_RES_FMAGIC) &&
				((mod == MOD_INFERNO) || (mod == MOD_FIREBOLT) ||
				(mod == MOD_FIREBALL) || (mod == MOD_CORPSEEXPLOSION))) {
				rsave += 0.33 * damage;
			}
			if ((targ->monsterinfo.ability & GIEX_MABILITY_RES_LMAGIC) &&
				((mod == MOD_LIGHTNING) || (mod == MOD_SPARK) || (mod == MOD_BOLT) || (mod == MOD_STORM))) {
				rsave += 0.33 * damage;
			}
			if (rsave > 0) {
				//Anti-resist
				int arlvl = getAuraLevel(attacker, 84);
				if (arlvl > 0) {
					int slot = getAuraSlot(attacker, 84);
					if (attacker->client->aura_caster[slot]->client->magic > 0) {
						attacker->client->aura_caster[slot]->client->magic -= 0.1 * rsave;
						attacker->client->aura_caster[slot]->client->magregentime = level.time + 1.0;
						rsave *= 1 - (arlvl * 0.02);
					}
				}
				damage -= rsave;
			}
		}

		if (attacker->client) {
			if (dflags & DAMAGE_10_MANABURN) // 10%
				manaburn_mult += 0.1;
			if (dflags & DAMAGE_25_MANABURN) // 25%
				manaburn_mult += 0.25;
			if (dflags & DAMAGE_50_MANABURN) // 50%
				manaburn_mult += 0.5;
			if (dflags & DAMAGE_100_MANABURN) // 100%
				manaburn_mult += 1.0;
			if (dflags & DAMAGE_200_MANABURN) // 200%
				manaburn_mult += 2.0;
			if (dflags & DAMAGE_400_MANABURN) // 400%
				manaburn_mult += 4.0;
			if (dflags & DAMAGE_50_MANALEECH) // 50%
				manaleech_mult += 0.5;
			if (dflags & DAMAGE_100_MANALEECH) // 100%
				manaleech_mult += 1.0;
			if (dflags & DAMAGE_200_MANALEECH) // 200%
				manaleech_mult += 2.0;

			if ((manaburn_mult > 0.0) && (attacker->client->magic < attacker->client->max_magic * 4)) {
				attacker->client->magic += (int) ceil(damage * manaburn_mult);
				if (attacker->client->magic > attacker->client->max_magic * 4) {
					attacker->client->magic = attacker->client->max_magic * 4;
				}
				gi.WriteByte (svc_muzzleflash);
				gi.WriteShort (targ-g_edicts);
				gi.WriteByte (MZ_NUKE4);
				gi.multicast (targ->s.origin, MULTICAST_PVS);
			}
			if (manaleech_mult > 0.0) {
				if (attacker->client->magic < attacker->client->max_magic * 4) {
					attacker->client->magic += (int) ceil(damage * manaleech_mult);
					if (attacker->client->magic > attacker->client->max_magic * 4) {
						attacker->client->magic = attacker->client->max_magic * 4;
					}
				}
				if (manaburn_mult == 0.0) {
					gi.WriteByte (svc_muzzleflash);
					gi.WriteShort (targ-g_edicts);
					gi.WriteByte (MZ_NUKE4);
					gi.multicast (targ->s.origin, MULTICAST_PVS);
				}
			}
		}
	}

	if (client && (damage > 0) && (targ->health > 0)) {
		int pre_damage = damage;
		int nosanc_damage = damage;
		int pre_magic = targ->client->magic;
		float res_boost = 0.15 * targ->client->pers.skill[45]; //Resistance boost
		float manaburn_mult = 0.0f;
		float manaleech_mult = 0.0f;
		if (targ->client->magic <= 0)
			res_boost = 0;

//Sanctuary aura
		if ((getAuraLevel(targ, 65) > 0) && (damage > 0)) {
			int slot = getAuraSlot(targ, 65);
			if (targ->client->aura_caster[slot]->client->magic > 0) {
				float bonus = getMagicBonuses(targ->client->aura_caster[slot], 65);
				float dmg_mult = 1.0;
				float cost_mult = 0.0;

				dmg_mult = (0.004 * targ->client->aura_level[slot] * (0.2 + bonus * 0.8));
				if (dmg_mult > 1)
					dmg_mult = 1.0;

				cost_mult = 0.002 * targ->client->aura_level[slot];
				if (targ->client->aura_level[slot] > 40) {
					cost_mult += 0.002 * (targ->client->aura_level[slot] - 40);
				}
				cost_mult *= ((float) (targ->client->aura_caster[slot]->client->max_magic + 800.0)) / 800.0;

				if (cost_mult * damage > targ->client->aura_caster[slot]->client->magic) {
					int dmgsave = (int) targ->client->aura_caster[slot]->client->magic / cost_mult;
					//gi.dprintf("%d %d %f %d %d\n", damage, dmgsave, cost_mult, targ->client->aura_caster[slot]->client->magic, (int) dmgsave * cost_mult);
					sasave += dmgsave * dmg_mult;
					damage -= dmgsave * dmg_mult;
					targ->client->aura_caster[slot]->client->magic -= dmgsave * cost_mult;
				} else {
					targ->client->aura_caster[slot]->client->magic -= cost_mult * damage;
					sasave += dmg_mult * damage;
					damage *= 1.0 - dmg_mult;
				}
				targ->client->aura_caster[slot]->client->magregentime = level.time + 1.0;
				gi.sound(targ, CHAN_ITEM, gi.soundindex("giex/magarm1.wav"), 0.5, ATTN_NORM, 0);
			}
		}

		rsave = 0;
		// Global (Damage resist)
		if (targ->client->pers.skill[46] > 0) {
			rsave += damage * 0.01 * targ->client->pers.skill[46];
		}

		// Bullet
		if ((targ->client->pers.skill[36] > 0) &&
			((mod == MOD_MACHINEGUN) || (mod == MOD_CHAINGUN))) {
			rsave += damage * 0.015 * targ->client->pers.skill[36] * res_boost;
			targ->client->magic -= RESBOOT_MAGUSE_MULT * ceil((pre_damage - damage) * res_boost);
		}
		// Pellet
		else if ((targ->client->pers.skill[37] > 0) &&
			((mod == MOD_SHOTGUN) || (mod == MOD_SSHOTGUN))) {
			rsave += damage * 0.015 * targ->client->pers.skill[37] * res_boost;
			targ->client->magic -= RESBOOT_MAGUSE_MULT * ceil((pre_damage - damage) * res_boost);
		}
		// Explosion
		else if ((targ->client->pers.skill[38] > 0) &&
			((mod == MOD_GRENADE) || (mod == MOD_G_SPLASH) ||
			(mod == MOD_ROCKET) || (mod == MOD_R_SPLASH) ||
			(mod == MOD_HANDGRENADE) || (mod == MOD_HG_SPLASH))) {
			rsave += damage * 0.015 * targ->client->pers.skill[38] * res_boost;
			targ->client->magic -= RESBOOT_MAGUSE_MULT * ceil((pre_damage - damage) * res_boost);
		}
		// Energy
		else if ((targ->client->pers.skill[39] > 0) &&
			((mod == MOD_BLASTER) || (mod == MOD_HYPERBLASTER) ||
			(mod == MOD_LASERMINE))) {
			rsave += damage * 0.015 * targ->client->pers.skill[39] * res_boost;
			targ->client->magic -= RESBOOT_MAGUSE_MULT * ceil((pre_damage - damage) * res_boost);
		}
		// High energy
		else if ((targ->client->pers.skill[40] > 0) &&
			((mod == MOD_RAILGUN) || (mod == MOD_BFG_LASER) ||
			(mod == MOD_BFG_BLAST) || (mod == MOD_BFG_EFFECT))) {
			rsave += damage * 0.015 * targ->client->pers.skill[40] * res_boost;
			targ->client->magic -= RESBOOT_MAGUSE_MULT * ceil((pre_damage - damage) * res_boost);
		}
		// World and hit damage
		else if (targ->client->pers.skill[41] > 0) {
			if ((mod == MOD_WATER) || (mod == MOD_SLIME) || (mod == MOD_FALLING) ||
				(mod == MOD_LAVA) || (mod == MOD_CRUSH)) {
				rsave += damage * 0.1 * targ->client->pers.skill[41];
			} else if (mod == MOD_HIT) {
				rsave += damage * 0.015 * targ->client->pers.skill[41] * res_boost;
				targ->client->magic -= RESBOOT_MAGUSE_MULT * ceil((pre_damage - damage) * res_boost);
			}
		}
		// Blood magic
		else if ((targ->client->pers.skill[42] > 0) &&
			((mod == MOD_PLAGUEBOMB) || (mod == MOD_DRAIN) || (mod == MOD_SPORE))) {
			rsave += damage * 0.015 * targ->client->pers.skill[42] * res_boost;
			targ->client->magic -= RESBOOT_MAGUSE_MULT * ceil((pre_damage - damage) * res_boost);
		}
		// Fire magic
		else if ((targ->client->pers.skill[43] > 0) &&
			((mod == MOD_INFERNO) || (mod == MOD_FIREBOLT) || (mod == MOD_FIREBALL) || (mod == MOD_CORPSEEXPLOSION))) {
			rsave += damage * 0.015 * targ->client->pers.skill[43] * res_boost;
			targ->client->magic -= RESBOOT_MAGUSE_MULT * ceil((pre_damage - damage) * res_boost);
		}
		// Lightning magic
		else if ((targ->client->pers.skill[69] > 0) &&
			((mod == MOD_LIGHTNING) || (mod == MOD_SPARK) || (mod == MOD_BOLT))) {
			rsave += damage * 0.015 * targ->client->pers.skill[69] * res_boost;
			targ->client->magic -= RESBOOT_MAGUSE_MULT * ceil((pre_damage - damage) * res_boost);
		}
		if (rsave > 0) {
			//Anti-resist
			int arlvl = getAuraLevel(attacker, 84);
			if (arlvl > 0) {
				int slot = getAuraSlot(attacker, 84);
				if (attacker->client->aura_caster[slot]->client->magic > 0) {
					attacker->client->aura_caster[slot]->client->magic -= 0.1 * rsave;
					attacker->client->aura_caster[slot]->client->magregentime = level.time + 1.0;
					rsave *= 1 - (arlvl * 0.02);
				}
			}
			damage -= rsave;
			nosanc_damage -= rsave;
		}

		if (dflags & DAMAGE_10_MANABURN) // 10%
			manaburn_mult += 0.1;
		if (dflags & DAMAGE_25_MANABURN) // 25%
			manaburn_mult += 0.25;
		if (dflags & DAMAGE_50_MANABURN) // 50%
			manaburn_mult += 0.5;
		if (dflags & DAMAGE_100_MANABURN) // 100%
			manaburn_mult += 1.0;
		if (dflags & DAMAGE_200_MANABURN) // 200%
			manaburn_mult += 2.0;
		if (dflags & DAMAGE_400_MANABURN) // 400%
			manaburn_mult += 4.0;
		if (dflags & DAMAGE_50_MANALEECH) // 50%
			manaleech_mult += 0.5;
		if (dflags & DAMAGE_100_MANALEECH) // 100%
			manaleech_mult += 1.0;
		if (dflags & DAMAGE_200_MANALEECH) // 200%
			manaleech_mult += 2.0;

		if ((attacker->svflags & SVF_MONSTER) && (attacker->monsterinfo.ability & GIEX_MABILITY_MANABURN)) {
			manaburn_mult += 1.0;
		}

		if (manaburn_mult > 0.0) {
			targ->client->magic -= nosanc_damage * manaburn_mult;
			if (targ->client->magic < 0)
				targ->client->magic = 0;
			if ((attacker->client) && (attacker->client->magic < attacker->client->max_magic * 4)) {
				attacker->client->magic += nosanc_damage * manaburn_mult;
				if (attacker->client->magic > attacker->client->max_magic * 4) {
					attacker->client->magic = attacker->client->max_magic * 4;
				}
			}
			gi.WriteByte (svc_muzzleflash);
			gi.WriteShort (targ-g_edicts);
			gi.WriteByte (MZ_NUKE4);
			gi.multicast (targ->s.origin, MULTICAST_PVS);
		}
		if (manaleech_mult > 0.0) {
			if (attacker->client->magic < attacker->client->max_magic * 4) {
				attacker->client->magic += (int) ceil(nosanc_damage * manaleech_mult);
				if (attacker->client->magic > attacker->client->max_magic * 4) {
					attacker->client->magic = attacker->client->max_magic * 4;
				}
			}
			if (manaburn_mult == 0.0) {
				gi.WriteByte (svc_muzzleflash);
				gi.WriteShort (targ-g_edicts);
				gi.WriteByte (MZ_NUKE4);
				gi.multicast (targ->s.origin, MULTICAST_PVS);
			}
		}

		if ((pre_magic != targ->client->magic) && (targ->client->magregentime < level.time + 1.0)) {
			targ->client->magregentime = level.time + 1.0;
		}

		if (damage < 0) {
			damage = 0;
		}
	}

// figure momentum add
	if (!(dflags & DAMAGE_NO_KNOCKBACK)) {
		if ((knockback) && (targ->movetype != MOVETYPE_NONE) && (targ->movetype != MOVETYPE_BOUNCE) && (targ->movetype != MOVETYPE_PUSH) && (targ->movetype != MOVETYPE_STOP)) {
			vec3_t	kvel;
			float	mass;

			if (targ->mass < 50)
				mass = 50;
			else
				mass = targ->mass;

			if (targ->client  && attacker == targ)
				VectorScale (dir, 1600.0 * (float)knockback / mass, kvel);	// the rocket jump hack...
			else
				VectorScale (dir, 500.0 * (float)knockback / mass, kvel);

			VectorAdd (targ->velocity, kvel, targ->velocity);
		}
	}

	take = damage;
	save = 0;

	// check for godmode
	if ((targ->flags & FL_GODMODE) && !(dflags & DAMAGE_NO_PROTECTION) && (damage > 0)) {
		take = 0;
		save = damage;
		SpawnDamage (te_sparks, point, normal, save);
	}

	// check for invincibility
	if ((client && client->invincible_framenum > level.framenum ) && !(dflags & DAMAGE_NO_PROTECTION) && (damage > 0)) {
		if (targ->pain_debounce_time < level.time) {
			gi.sound(targ, CHAN_ITEM, gi.soundindex("items/protect4.wav"), 1, ATTN_NORM, 0);
			targ->pain_debounce_time = level.time + 2;
		}
		take = 0;
		save = damage;
	}

	if (take > 0) {
		if ((targ->client) && (targ->client->damage_time < level.time + 0.5 + take * 0.001)) {
			targ->client->damage_time = level.time + 0.5 + take * 0.001;
		}
		psave = CheckPowerArmor (targ, point, normal, take, dflags);
		take -= psave;

		asave = CheckArmor (targ, attacker, point, normal, take, te_sparks, dflags, mod, mod_magic);
		take -= asave;
	}

// do the damage
/*	if ((attacker->client) && (targ->svflags & SVF_MONSTER)) {
		if (take <= 0) {
			gi.dprintf("NO DAMAGE\n", take);
			_asm int 3;
		}
	}*/
	if (rsave > 0) {
		SpawnDamage (TE_SCREEN_SPARKS, point, normal, rsave);
	}
	if (sasave > 0) {
		SpawnDamage (TE_SHIELD_SPARKS, point, normal, sasave);
	}

	if ((take > 0) || ( (take < 0) && (targ->health < 2 * targ->max_health)) ) {
		targ->health -= take;
	}
	if ( (targ->health > 0) && ((take != 0) || (take + asave > 0)) ) {
		addExp(attacker, targ, take + asave); //Also give exp for killing armor
	}
	if (take != 0) {
		if ((targ->svflags & SVF_MONSTER) || (client))
			SpawnDamage (TE_BLOOD, point, normal, take);
		else
			SpawnDamage (te_sparks, point, normal, take);


		if ((attacker->client) && (mod != MOD_TELEFRAG)) /* && (targ->health > 0))*/ {
			if ((damage > 0) && (attacker->client->pers.skill[34] /*|| (attacker->client->pers.skills.classLevel[4] > 0)*/) && ((targ->health + take) > 0)) {
				int maxhealth = attacker->max_health * 0.75;
				maxhealth += 13.5 * pow(attacker->client->pers.skills.classLevel[4], 1.05);
				if (attacker->health < maxhealth) {
					float amount = 0;
					float mult = 0;

					//mult += 0.001 * pow(attacker->client->pers.skills.classLevel[4], 1.1); // Vampire class level bonus
					//mult *= 0.4 + 0.6 * ((float) attacker->client->pers.skills.classLevel[4] / (float) attacker->radius_dmg); // Penalty if not pure Vampire
					mult += 0.01 * attacker->client->pers.skill[34]; //From item powerups
					if (attacker->client->damage_time > level.time) {
						mult *= 0.25;
					}
					amount = take * mult;
					if ((mod == MOD_TELEFRAG) || (attacker == targ))
						amount = 0;
					attacker->client->pers.add_health += amount;
					if (attacker->health > maxhealth)
						attacker->health = maxhealth;
				}
			}
		}

		if (targ->health <= 0) {
			if ((targ->svflags & SVF_MONSTER) || (client))
				targ->flags |= FL_NO_KNOCKBACK;
			Killed (targ, inflictor, attacker, take, point);
			return take;
		}
	}

	if (take > 0) {
		if (targ->svflags & SVF_MONSTER) {
			edict_t *oldenemy = targ->enemy;
			if (targ->radius_dmg && (targ != attacker) && (attacker->takedamage) && (targ->monsterinfo.ability & GIEX_MABILITY_SHARDARMOR) && targ->monsterinfo.shardtime < (level.time - 0.1)) {
				vec3_t aim, end;
				float mult = level.time - targ->monsterinfo.shardtime;
				if (mult > 1.7)
					mult = 1.7;
				mult += 0.2;
				targ->monsterinfo.shardtime = level.time + 0.2;

				VectorMA(attacker->s.origin, 0.3, attacker->velocity, end);
				end[2] += attacker->viewheight;
				VectorSubtract (end, point, aim);

				if (targ->monsterinfo.ability & GIEX_MABILITY_DAMAGE) // Damage ability shouldn't affect Shard armor, halve mult
					mult *= 0.5;

				monster_fire_blaster (targ, point, aim, (int) ceil((16 + 10 * targ->monsterinfo.skill) * mult), 2200, MZ2_SOLDIER_BLASTER_1, EF_BLASTER);
				gi.sound(targ, CHAN_AUTO, gi.soundindex("giex/magarm2.wav"), 0.8, ATTN_NORM, 0);
			}
			M_ReactToDamage (targ, attacker);
			if (!(targ->monsterinfo.aiflags & AI_DUCKED) && (take)) {
				targ->pain_debounce_time = level.time + 2 + 0.1 * targ->monsterinfo.skill;
				if (oldenemy != NULL)
					targ->pain (targ, attacker, knockback, take);
			}
		} else if (client) {
			if (!(targ->flags & FL_GODMODE) && (take))
				targ->pain (targ, attacker, knockback, take);
		} else if (take) {
			if (targ->pain)
				targ->pain (targ, attacker, knockback, take);
		}
	}

	// add to the damage inflicted on a player this frame
	// the total will be turned into screen blends and view angle kicks
	// at the end of the frame
	if (client) {
		client->damage_parmor += psave;
		client->damage_armor += (asave + save);
		client->damage_blood += take;
		client->damage_knockback += knockback;
		VectorCopy (point, client->damage_from);
	}
	return take;
}
Example #8
0
void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
			   vec3_t dir, vec3_t point, int damage, int dflags, int mod ) {
	gclient_t	*client;
	int			take;
	int			save;
	int			asave;
	int			knockback;
	int			max;

	if (!targ->takedamage) {
		return;
	}

	//in entityplus bots cannot harm other bots (unless it's a telefrag)
	if ( IsBot( targ ) && attacker && IsBot( attacker ) && mod != MOD_TELEFRAG )
		return;

	//if attacker is shooter which was configured not to harm target, do nothing
	if ( attacker && strstr(attacker->classname, "shooter_" )) {
		if ( (attacker->spawnflags & 2) && IsBot( targ ) ) //spawnflags 2 == NO_BOTS
			return;
		if ( (attacker->spawnflags & 4) && !IsBot( targ ) ) //spawnflag 4 = NO_HUMANS
			return;
	}

	// the intermission has allready been qualified for, so don't
	// allow any extra scoring
	if ( level.intermissionQueued ) {
		return;
	}

	if ( !inflictor ) {
		inflictor = &g_entities[ENTITYNUM_WORLD];
	}
	if ( !attacker ) {
		attacker = &g_entities[ENTITYNUM_WORLD];
	}


	// shootable doors / buttons don't actually have any health
	if ( targ->s.eType == ET_MOVER ) {
		if ( strcmp(targ->classname, "func_breakable") && targ->use && (targ->moverState == MOVER_POS1 || targ->moverState == ROTATOR_POS1) ) {
			targ->use( targ, inflictor, attacker );
		} else {	// entity is a func_breakable
			if ( (targ->spawnflags & 1024) && attacker == level.player )
				return;
			if ( (targ->spawnflags & 2048) && IsBot(attacker) )
				return;
			if ( (targ->spawnflags & 4096) && strstr(attacker->classname, "shooter_") )
				return;
			
			if ( !strcmp(targ->classname, "func_breakable") ) {
				targ->health -= damage;
				if ( targ->health <= 0 )
					Break_Breakable(targ, attacker);
			}
		}
		return;
	}

	// scale back damage from bots or shooters to humans in single player, based on skill level
	// "I can win" does 0.05 dmg
	// "Bring it on" does 0.15 dmg
	// "Hurt me plenty" does 0.25 dmg
	// "Hardcore" does 0.35 dmg
	// "Nightmare does 0.45 dmg
	if ( 
		attacker && (
			IsBot(attacker) || 
			!strcmp(attacker->classname, "shooter_bfg") || 
			!strcmp(attacker->classname, "shooter_grenade") || 
			!strcmp(attacker->classname, "shooter_plasma") || 
			!strcmp(attacker->classname, "shooter_rocket") 
		)
	) {
		float skill = trap_Cvar_VariableValue( "g_spSkill" );
		int orgdmg = damage;

		if ( attacker->parent && attacker->parent->skill )
			skill += attacker->parent->skill;

		if (skill < 1)
			skill = 1;	//relative skill level should not drop below 1 but is allowed to rise above 5
		
		damage *= ( ( 0.1 * skill  ) - 0.05 ); //damage is always rounded down.
		
		if ( damage < 1 )
			damage = 1;	//make sure bot does at least -some- damage

		//G_Printf("skill: %f -- mp: %f -- orgdmg: %i -- dmg: %i\n", skill, ( 0.1 * skill  ) - 0.05, orgdmg, damage);
	}

	client = targ->client;

	if ( client ) {
		if ( client->noclip ) {
			return;
		}
	}

	if ( !dir ) {
		dflags |= DAMAGE_NO_KNOCKBACK;
	} else {
		VectorNormalize(dir);
	}

	knockback = damage;
	if ( knockback > 200 ) {
		knockback = 200;
	}
	if ( targ->flags & FL_NO_KNOCKBACK ) {
		knockback = 0;
	}
	if ( dflags & DAMAGE_NO_KNOCKBACK ) {
		knockback = 0;
	}

	// figure momentum add, even if the damage won't be taken
	if ( knockback && targ->client ) {
		vec3_t	kvel;
		float	mass;

		mass = 200;

		VectorScale (dir, g_knockback.value * (float)knockback / mass, kvel);
		VectorAdd (targ->client->ps.velocity, kvel, targ->client->ps.velocity);

		// set the timer so that the other client can't cancel
		// out the movement immediately
		if ( !targ->client->ps.pm_time ) {
			int		t;

			t = knockback * 2;
			if ( t < 50 ) {
				t = 50;
			}
			if ( t > 200 ) {
				t = 200;
			}
			targ->client->ps.pm_time = t;
			targ->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
		}
	}

	// check for completely getting out of the damage
	if ( !(dflags & DAMAGE_NO_PROTECTION) ) {

		// if TF_NO_FRIENDLY_FIRE is set, don't do damage to the target
		// if the attacker was on the same team
		if ( targ != attacker && OnSameTeam (targ, attacker)  ) {
			if ( !g_friendlyFire.integer ) {
				return;
			}
		}

		// check for godmode
		if ( targ->flags & FL_GODMODE ) {
			return;
		}
	}

	// battlesuit protects from all radius damage (but takes knockback)
	// and protects 50% against all damage
	if ( client && client->ps.powerups[PW_BATTLESUIT] ) {
		G_AddEvent( targ, EV_POWERUP_BATTLESUIT, 0 );
		if ( ( dflags & DAMAGE_RADIUS ) || ( mod == MOD_FALLING ) ) {
			return;
		}
		damage *= 0.5;
	}

	// add to the attacker's hit counter (if the target isn't a general entity like a prox mine)
	if ( attacker->client && targ != attacker && targ->health > 0
			&& targ->s.eType != ET_MISSILE
			&& targ->s.eType != ET_GENERAL) {
		if ( OnSameTeam( targ, attacker ) ) {
			attacker->client->ps.persistant[PERS_HITS]--;
		} else {
			attacker->client->ps.persistant[PERS_HITS]++;
		}
		attacker->client->ps.persistant[PERS_ATTACKEE_ARMOR] = (targ->health<<8)|(client->ps.stats[STAT_ARMOR]);
	}

	// always give half damage if hurting self
	// calculated after knockback, so rocket jumping works
	if ( targ == attacker) {
		damage *= 0.5;
	}

	if ( damage < 1 ) {
		damage = 1;
	}
	take = damage;
	save = 0;

	// save some from armor
	asave = CheckArmor (targ, take, dflags);
	take -= asave;

	if ( g_debugDamage.integer ) {
		G_Printf( "%i: client:%i health:%i damage:%i armor:%i\n", level.time, targ->s.number,
			targ->health, take, asave );
	}

	// add to the damage inflicted on a player this frame
	// the total will be turned into screen blends and view angle kicks
	// at the end of the frame
	if ( client ) {
		if ( attacker ) {
			client->ps.persistant[PERS_ATTACKER] = attacker->s.number;
		} else {
			client->ps.persistant[PERS_ATTACKER] = ENTITYNUM_WORLD;
		}
		client->damage_armor += asave;
		client->damage_blood += take;
		client->damage_knockback += knockback;
		if ( dir ) {
			VectorCopy ( dir, client->damage_from );
			client->damage_fromWorld = qfalse;
		} else {
			VectorCopy ( targ->r.currentOrigin, client->damage_from );
			client->damage_fromWorld = qtrue;
		}
	}

	if (targ->client) {
		// set the last client who damaged the target
		targ->client->lasthurt_client = attacker->s.number;
		targ->client->lasthurt_mod = mod;
	}

	// do the damage
	if (take) {
		if ( g_mutators.integer & MT_INSTAGIB && IsBot( targ ) )
			targ->health = -999;
		else
			targ->health = targ->health - take;

		if ( targ->client ) {
			targ->client->ps.stats[STAT_HEALTH] = targ->health;
		}
			
		if ( targ->health <= 0 ) {
			if ( client )
				targ->flags |= FL_NO_KNOCKBACK;

			if (targ->health < -999)
				targ->health = -999;

			targ->enemy = attacker;
			targ->die (targ, inflictor, attacker, take, mod);
			return;
		} else if ( targ->pain ) {
			targ->pain (targ, attacker, take);
		}
	}
}
Example #9
0
File: g_combat.c Project: ZwS/qudos
void T_Damage (edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t dir, vec3_t point, vec3_t normal, int damage, int knockback, int dflags, int mod)
{
	gclient_t	*client;
	int			take;
	int			save;
	int			asave;
	int			psave;
	int			te_sparks;

	if (!targ->takedamage)
		return;

	if(mod == MOD_CRUSH)
	{
		//bot's state change
		if((targ->svflags & SVF_MONSTER) && targ->client)
		{
			if((targ->client->zc.waitin_obj == inflictor && targ->client->zc.zcstate)
				|| targ->groundentity == inflictor)
			{
//				gi.bprintf(PRINT_HIGH,"MOOOOOOOOOOOOOOOOOOOO\n");
				targ->client->zc.zcstate |= STS_W_DONT;
			}
		}
	}

	// friendly fire avoidance
	// if enabled you can't hurt teammates (but you can hurt yourself)
	// knockback still occurs
	if ((targ != attacker) && ((deathmatch->value && ((int)(dmflags->value) & (DF_MODELTEAMS | DF_SKINTEAMS))) || coop->value))
	{
		if (OnSameTeam (targ, attacker))
		{
			if ((int)(dmflags->value) & DF_NO_FRIENDLY_FIRE)
				damage = 0;
			else
				mod |= MOD_FRIENDLY_FIRE;
		}
		else if(targ->client && !(targ->svflags & SVF_MONSTER))
		{
			if(attacker->client) targ->client->zc.first_target = attacker;
		}
	}
	meansOfDeath = mod;

	// easy mode takes half damage
	if (skill->value == 0 && deathmatch->value == 0 && targ->client)
	{
		damage *= 0.5;
		if (!damage)
			damage = 1;
	}

	client = targ->client;

	if (dflags & DAMAGE_BULLET)
		te_sparks = TE_BULLET_SPARKS;
	else
		te_sparks = TE_SPARKS;

	VectorNormalize(dir);

// bonus damage for suprising a monster
	if (!(dflags & DAMAGE_RADIUS) && (targ->svflags & SVF_MONSTER) && (attacker->client) && (!targ->enemy) && (targ->health > 0))
		damage *= 2;

//ZOID
//strength tech
	damage = CTFApplyStrength(attacker, damage);
//ZOID

	if (targ->flags & FL_NO_KNOCKBACK)
		knockback = 0;

// figure momentum add
	if (!(dflags & DAMAGE_NO_KNOCKBACK))
	{
		if ((knockback) && (targ->movetype != MOVETYPE_NONE) && (targ->movetype != MOVETYPE_BOUNCE) && (targ->movetype != MOVETYPE_PUSH) && (targ->movetype != MOVETYPE_STOP))
		{
			vec3_t	kvel;
			float	mass;

			if (targ->mass < 50)
				mass = 50;
			else
				mass = targ->mass;

			if (targ->client  && attacker == targ)
				VectorScale (dir, 1600.0 * (float)knockback / mass, kvel);	// the rocket jump hack...
			else
				VectorScale (dir, 500.0 * (float)knockback / mass, kvel);

			VectorAdd (targ->velocity, kvel, targ->velocity);
		}
	}

	take = damage;
	save = 0;

	// check for godmode
	if ( (targ->flags & FL_GODMODE) && !(dflags & DAMAGE_NO_PROTECTION) )
	{
		take = 0;
		save = damage;
		SpawnDamage (te_sparks, point, normal, save);
	}

	// check for invincibility
	if ((client && client->invincible_framenum > level.framenum ) && !(dflags & DAMAGE_NO_PROTECTION))
	{
		if (targ->pain_debounce_time < level.time)
		{
			gi.sound(targ, CHAN_ITEM, gi.soundindex("items/protect3.wav"), 1, ATTN_NORM, 0);
//			gi.sound(targ, CHAN_ITEM, gi.soundindex("items/protect4.wav"), 1, ATTN_NORM, 0);
			targ->pain_debounce_time = level.time + 2;
		}
		take = 0;
		save = damage;
	}

//ZOID
//team armor protect
	if (ctf->value && targ->client && attacker->client &&
		targ->client->resp.ctf_team == attacker->client->resp.ctf_team &&
		targ != attacker && ((int)dmflags->value & DF_ARMOR_PROTECT)) {
		psave = asave = 0;
	} else {
//ZOID

		psave = CheckPowerArmor (targ, point, normal, take, dflags);
		take -= psave;

		asave = CheckArmor (targ, point, normal, take, te_sparks, dflags);
		take -= asave;
	}
	//treat cheat/powerup savings the same as armor
	asave += save;

//ZOID
//resistance tech
	take = CTFApplyResistance(targ, take);
//ZOID

	// team damage avoidance
	if (!(dflags & DAMAGE_NO_PROTECTION) && CheckTeamDamage (targ, attacker))
		return;

//ZOID
	CTFCheckHurtCarrier(targ, attacker);
//ZOID

// do the damage
	if (take)
	{
		if ((targ->svflags & SVF_MONSTER) || (client))
		{
			SpawnDamage (TE_BLOOD, point, normal, take);
			if(client && (targ->svflags & SVF_MONSTER) && attacker)
			{
				if(client->zc.battlemode & FIRE_CHIKEN) client->zc.battlemode &= ~FIRE_CHIKEN;

				if(mod == MOD_RAILGUN 
				|| mod == MOD_BFG_LASER
				|| mod == MOD_ROCKET
				|| mod == MOD_BLASTER
				|| mod == MOD_RIPPER
				|| mod == MOD_HYPERBLASTER
				|| mod == MOD_PHALANX)
				{
					if(attacker->client
						&& (9 * random() < Bot[client->zc.botindex].param[BOP_REACTION])
						&& !client->zc.first_target)
					{
						if(!OnSameTeam (targ, attacker)) client->zc.first_target = attacker;
					}
				}
			}
		}
		else
			SpawnDamage (te_sparks, point, normal, take);


		targ->health = targ->health - take;
			
		if (targ->health <= 0)
		{
			if ((targ->svflags & SVF_MONSTER) || (client))
				targ->flags |= FL_NO_KNOCKBACK;
			Killed (targ, inflictor, attacker, take, point);
			return;
		}
	}

	if (client)
	{
		if (!(targ->flags & FL_GODMODE) && (take))
			targ->pain (targ, attacker, knockback, take);
	}
	else if (take)
	{
		if (targ->pain)
			targ->pain (targ, attacker, knockback, take);
	}

	// add to the damage inflicted on a player this frame
	// the total will be turned into screen blends and view angle kicks
	// at the end of the frame
	if (client)
	{
		client->damage_parmor += psave;
		client->damage_armor += asave;
		client->damage_blood += take;
		client->damage_knockback += knockback;
		VectorCopy (point, client->damage_from);
	}
}
Example #10
0
void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
			   vec3_t dir, vec3_t point, int damage, int dflags, int mod ) {
	gclient_t   *client;
	int take;
	int save;
	int asave;
	int knockback;

	if ( !targ->takedamage ) {
		return;
	}

//----(SA)	added
	if ( g_gametype.integer == GT_SINGLE_PLAYER && !targ->aiCharacter && targ->client && targ->client->cameraPortal ) {
		// get out of damage in sp if in cutscene.
		return;
	}
//----(SA)	end

//	if (reloading || saveGamePending) {	// map transition is happening, don't do anything
	if ( g_reloading.integer || saveGamePending ) {
		return;
	}

	// the intermission has allready been qualified for, so don't
	// allow any extra scoring
	if ( level.intermissionQueued ) {
		return;
	}

	// RF, track pain for player
	// This is used by AI to determine how long it has been since their enemy was injured

	if ( attacker ) { // (SA) whoops, for falling damage there's no attacker
		if ( targ->client && attacker->client && !( targ->r.svFlags & SVF_CASTAI ) && ( attacker->r.svFlags & SVF_CASTAI ) ) {
			AICast_RegisterPain( targ->s.number );
		}
	}
#ifdef AUTOAIM
	//If player shoots target
	if (attacker && !(attacker->r.svFlags& SVF_CASTAI) && (targ->r.svFlags & SVF_CASTAI))
	{
		if (targ->health > 0) //if target is already dead then ignore
		{
		    g_autoAimEntity = targ;
		}
		else
		{
		    g_autoAimEntity = NULL;
		}
	}
#endif
	if ( ( g_gametype.integer == GT_SINGLE_PLAYER ) && !( targ->r.svFlags & SVF_CASTAI ) ) { // the player
		switch ( mod )
		{
		case MOD_GRENADE:
		case MOD_GRENADE_SPLASH:
		case MOD_ROCKET:
		case MOD_ROCKET_SPLASH:
			// Rafael - had to change this since the
			// we added a new lvl of diff
			if ( g_gameskill.integer == GSKILL_EASY ) {
				damage *= 0.25;
			} else if ( g_gameskill.integer == GSKILL_MEDIUM ) {
				damage *= 0.75;
			} else if ( g_gameskill.integer == GSKILL_HARD ) {
				damage *= 0.9;
			} else {
				damage *= 0.9;
			}
		default:
			break;
		}
	}

	if ( !inflictor ) {
		inflictor = &g_entities[ENTITYNUM_WORLD];
	}
	if ( !attacker ) {
		attacker = &g_entities[ENTITYNUM_WORLD];
	}

	// shootable doors / buttons don't actually have any health
	if ( targ->s.eType == ET_MOVER && !( targ->aiName ) && !( targ->isProp ) && !targ->scriptName ) {
		if ( targ->use && targ->moverState == MOVER_POS1 ) {
			targ->use( targ, inflictor, attacker );
		}
		return;
	}

	if ( targ->s.eType == ET_MOVER && targ->aiName && !( targ->isProp ) && !targ->scriptName ) {
		switch ( mod ) {
		case MOD_GRENADE:
		case MOD_GRENADE_SPLASH:
		case MOD_ROCKET:
		case MOD_ROCKET_SPLASH:
			break;
		default:
			return; // no damage from other weapons
		}
	} else if ( targ->s.eType == ET_EXPLOSIVE )   {
		// 32 Explosive
		// 64 Dynamite only
		if ( ( targ->spawnflags & 32 ) || ( targ->spawnflags & 64 ) ) {
			switch ( mod ) {
			case MOD_GRENADE:
			case MOD_GRENADE_SPLASH:
			case MOD_ROCKET:
			case MOD_ROCKET_SPLASH:
			case MOD_AIRSTRIKE:
			case MOD_GRENADE_PINEAPPLE:
			case MOD_MORTAR:
			case MOD_MORTAR_SPLASH:
			case MOD_EXPLOSIVE:
				if ( targ->spawnflags & 64 ) {
					return;
				}

				break;

			case MOD_DYNAMITE:
			case MOD_DYNAMITE_SPLASH:
				break;

			default:
				return;
			}
		}
	}

	// reduce damage by the attacker's handicap value
	// unless they are rocket jumping

	// Ridah, not in single player (skill levels?)
// JPW NERVE pulled this from multiplayer too
/*
	if (g_gametype.integer != GT_SINGLE_PLAYER)
	// done.
	if ( attacker->client && attacker != targ ) {
		damage = damage * attacker->client->ps.stats[STAT_MAX_HEALTH] / 100;
	}
*/
// jpw

	// Ridah, Cast AI's don't hurt other Cast AI's as much
	if ( ( attacker->r.svFlags & SVF_CASTAI ) && ( targ->r.svFlags & SVF_CASTAI ) ) {
		if ( !AICast_AIDamageOK( AICast_GetCastState( targ->s.number ), AICast_GetCastState( attacker->s.number ) ) ) {
			return;
		}
		damage = (int)( ceil( (float)damage * 0.5 ) );
	}
	// done.

	client = targ->client;

	if ( client ) {
		if ( client->noclip ) {
			return;
		}
	}

	if ( !dir ) {
		dflags |= DAMAGE_NO_KNOCKBACK;
	} else {
		VectorNormalize( dir );
	}

	knockback = damage;

//	if ( knockback > 200 )
//		knockback = 200;
	if ( knockback > 60 ) { // /way/ lessened for SP.  keeps dynamite-jumping potential down
		knockback = 60;
	}

	if ( targ->flags & FL_NO_KNOCKBACK ) {
		knockback = 0;
	}
	if ( dflags & DAMAGE_NO_KNOCKBACK ) {
		knockback = 0;
	}

	// figure momentum add, even if the damage won't be taken
	if ( knockback && targ->client ) {
		vec3_t kvel;
		float mass;

		mass = 200;

		if ( mod == MOD_LIGHTNING && !( ( level.time + targ->s.number * 50 ) % 400 ) ) {
			knockback = 60;
			dir[2] = 0.3;
		}

		VectorScale( dir, g_knockback.value * (float)knockback / mass, kvel );
		VectorAdd( targ->client->ps.velocity, kvel, targ->client->ps.velocity );

		if ( targ == attacker && !(  mod != MOD_ROCKET &&
									 mod != MOD_ROCKET_SPLASH &&
									 mod != MOD_GRENADE &&
									 mod != MOD_GRENADE_SPLASH &&
									 mod != MOD_DYNAMITE ) ) {
			targ->client->ps.velocity[2] *= 0.25;
		}

		// set the timer so that the other client can't cancel
		// out the movement immediately
		if ( !targ->client->ps.pm_time ) {
			int t;

			t = knockback * 2;
			if ( t < 50 ) {
				t = 50;
			}
			if ( t > 200 ) {
				t = 200;
			}
			targ->client->ps.pm_time = t;
			targ->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
		}
	}

	// check for completely getting out of the damage
	if ( !( dflags & DAMAGE_NO_PROTECTION ) ) {

		// if TF_NO_FRIENDLY_FIRE is set, don't do damage to the target
		// if the attacker was on the same team
		if ( targ != attacker && OnSameTeam( targ, attacker )  ) {
			if ( !g_friendlyFire.integer ) {
				return;
			}
		}

		// check for godmode
		if ( targ->flags & FL_GODMODE ) {
			return;
		}

		// RF, warzombie defense position is basically godmode for the time being
		if ( targ->flags & FL_DEFENSE_GUARD ) {
			return;
		}

		// check for invulnerability // (SA) moved from below so DAMAGE_NO_PROTECTION will still work
		if ( client && client->ps.powerups[PW_INVULNERABLE] ) { //----(SA)	added
			return;
		}

	}

	// battlesuit protects from all radius damage (but takes knockback)
	// and protects 50% against all damage
	if ( client && client->ps.powerups[PW_BATTLESUIT] ) {
		G_AddEvent( targ, EV_POWERUP_BATTLESUIT, 0 );
		if ( dflags & DAMAGE_RADIUS ) {
			return;
		}
		damage *= 0.5;
	}

	// Ridah, don't play these in single player
	if ( g_gametype.integer != GT_SINGLE_PLAYER ) {
		// done.
		// add to the attacker's hit counter
		if ( attacker->client && targ != attacker && targ->health > 0 ) {
			if ( OnSameTeam( targ, attacker ) ) {
				attacker->client->ps.persistant[PERS_HITS] -= damage;
			} else {
				attacker->client->ps.persistant[PERS_HITS] += damage;
			}
		}
	}

	// always give half damage if hurting self
	// calculated after knockback, so rocket jumping works
	if ( g_gametype.integer == GT_SINGLE_PLAYER ) {     // JPW NERVE -- removed from multiplayer -- plays havoc with pfaust & demolition balancing

		qboolean dynamite = (qboolean)( mod == MOD_DYNAMITE || mod == MOD_DYNAMITE_SPLASH );

		if ( targ == attacker ) {
			if ( !dynamite ) {
				damage *= 0.5;
			}
		}

		if ( dynamite && targ->aiCharacter == AICHAR_HELGA ) {
			//helga gets special dynamite damage
			damage *= 0.5;
		}

	}

	if ( damage < 1 ) {
		damage = 1;
	}
	take = damage;
	save = 0;

	// save some from armor
	asave = CheckArmor( targ, take, dflags );
	take -= asave;


	if ( IsHeadShot( targ, attacker, dir, point, mod ) ) {
		// JPW NERVE -- different headshot behavior in multiplayer
		if ( g_gametype.integer != GT_SINGLE_PLAYER ) {
			if ( take * 2 < 50 ) { // head shots, all weapons, do minimum 50 points damage
				take = 50;
			} else {
				take *= 2; // sniper rifles can do full-kill (and knock into limbo)
			}
			if ( !( targ->client->ps.eFlags & EF_HEADSHOT ) ) {  // only toss hat on first headshot
				G_AddEvent( targ, EV_LOSE_HAT, DirToByte( dir ) );
			}
		} // jpw
		else {
			// by default, a headshot means damage x2
			take *= 2;

			// RF, allow headshot damage multiplier (helmets, etc)
			// yes, headshotDamageScale of 0 gives no damage, thats because
			// the bullet hit the head which is fully protected.
			take *= targ->headshotDamageScale;

			// player only code
			if ( !attacker->aiCharacter ) {
				// (SA) id reqests one-shot kills for head shots on common humanoids

				// (SA) except pistols.
				// first pistol head shot does normal 2x damage and flings hat, second gets kill
				//			if((mod != MOD_LUGER && mod != MOD_COLT ) || (targ->client->ps.eFlags & EF_HEADSHOT))	{	// (SA) DM requests removing double shot pistol head shots (3/19)

				// (SA) removed BG for DM.

				if ( !( dflags & DAMAGE_PASSTHRU ) ) {     // ignore headshot 2x damage and snooper-instant-death if the bullet passed through something.  just do reg damage.
					switch ( targ->aiCharacter ) {
					case AICHAR_BLACKGUARD:
						if ( !( targ->client->ps.eFlags & EF_HEADSHOT ) ) { // only obliterate him after he's lost his helmet
							break;
						}
					case AICHAR_SOLDIER:
					case AICHAR_AMERICAN:
					case AICHAR_ELITEGUARD:
					case AICHAR_PARTISAN:
					case AICHAR_CIVILIAN:
						take = 200;
						break;
					default:
						break;
					}
				}

				if ( !( targ->client->ps.eFlags & EF_HEADSHOT ) ) {  // only toss hat on first headshot
					G_AddEvent( targ, EV_LOSE_HAT, DirToByte( dir ) );
				}
			}
		} // JPW

		// shared by both player and ai
		targ->client->ps.eFlags |= EF_HEADSHOT;

	} else {    // non headshot

		if ( !( dflags & DAMAGE_PASSTHRU ) ) {     // ignore headshot 2x damage and snooper-instant-death if the bullet passed through something.  just do reg damage.
			// snooper kills these types in one shot with any contact
			if ( ( mod == MOD_SNOOPERSCOPE || mod == MOD_GARAND ) && !( attacker->aiCharacter ) ) {
				switch ( targ->aiCharacter ) {
				case AICHAR_SOLDIER:
				case AICHAR_AMERICAN:
				case AICHAR_ELITEGUARD:
				case AICHAR_BLACKGUARD:
				case AICHAR_PARTISAN:
				case AICHAR_CIVILIAN:
					take = 200;
					break;
				default:
					break;
				}
			}
		}
	}


	if ( g_debugDamage.integer ) {
		G_Printf( "client:%i health:%i damage:%i armor:%i\n", targ->s.number,
				  targ->health, take, asave );
	}

	// add to the damage inflicted on a player this frame
	// the total will be turned into screen blends and view angle kicks
	// at the end of the frame
	if ( client ) {
		if ( attacker ) {
			client->ps.persistant[PERS_ATTACKER] = attacker->s.number;
		} else {
			client->ps.persistant[PERS_ATTACKER] = ENTITYNUM_WORLD;
		}
		client->damage_armor += asave;
		client->damage_blood += take;
		client->damage_knockback += knockback;

		if ( dir ) {
			VectorCopy( dir, client->damage_from );
			client->damage_fromWorld = qfalse;
		} else {
			VectorCopy( targ->r.currentOrigin, client->damage_from );
			client->damage_fromWorld = qtrue;
		}
	}

	// See if it's the player hurting the emeny flag carrier
	Team_CheckHurtCarrier( targ, attacker );

	if ( targ->client ) {
		// set the last client who damaged the target
		targ->client->lasthurt_client = attacker->s.number;
		targ->client->lasthurt_mod = mod;
	}

	// do the damage
	if ( take ) {
		targ->health = targ->health - take;

		// Ridah, can't gib with bullet weapons (except VENOM)
		if ( targ->client ) {
			if ( mod != MOD_VENOM && attacker == inflictor && targ->health <= GIB_HEALTH ) {
				if ( targ->aiCharacter != AICHAR_ZOMBIE ) { // zombie needs to be able to gib so we can kill him (although he doesn't actually GIB, he just dies)
					targ->health = GIB_HEALTH + 1;
				}
			}
		}

		//G_Printf("health at: %d\n", targ->health);
		if ( targ->health <= 0 ) {
			if ( client ) {
				targ->flags |= FL_NO_KNOCKBACK;
			}

			if ( targ->health < -999 ) {
				targ->health = -999;
			}

			targ->enemy = attacker;
			if ( targ->die ) { // Ridah, mg42 doesn't have die func (FIXME)
				targ->die( targ, inflictor, attacker, take, mod );
			}

			// if we freed ourselves in death function
			if ( !targ->inuse ) {
				return;
			}

			// RF, entity scripting
			if ( targ->s.number >= MAX_CLIENTS && targ->health <= 0 ) { // might have revived itself in death function
				G_Script_ScriptEvent( targ, "death", "" );
			}

		} else if ( targ->pain ) {
			if ( dir ) {  // Ridah, had to add this to fix NULL dir crash
				VectorCopy( dir, targ->rotate );
				VectorCopy( point, targ->pos3 ); // this will pass loc of hit
			} else {
				VectorClear( targ->rotate );
				VectorClear( targ->pos3 );
			}

			targ->pain( targ, attacker, take, point );
		}

		G_ArmorDamage( targ );    //----(SA)	moved out to separate routine

		// Ridah, this needs to be done last, incase the health is altered in one of the event calls
		if ( targ->client ) {
			targ->client->ps.stats[STAT_HEALTH] = targ->health;
		}
	}

}