Example #1
0
static int CheckArmor(edict_t * ent, vec3_t point, vec3_t normal, int damage,
		      int te_sparks, int dflags)
{
	gclient_t *client;
	int save;
	int index;
	gitem_t *armor;

	if (!damage)
		return 0;

	client = ent->client;

	if (!client)
		return 0;

	if (dflags & DAMAGE_NO_ARMOR)
		return 0;

	index = ArmorIndex(ent);
	if (!index)
		return 0;

	armor = GetItemByIndex(index);

	if (dflags & DAMAGE_ENERGY)
		save =
		    ceil(((gitem_armor_t *) armor->info)->energy_protection *
			 damage);
	else
		save =
		    ceil(((gitem_armor_t *) armor->info)->normal_protection *
			 damage);
	if (save >= client->pers.inventory[index])
		save = client->pers.inventory[index];

	if (!save)
		return 0;

	client->pers.inventory[index] -= save;
	SpawnDamage(te_sparks, point, normal, save);

	return save;
}
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;
	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 #3
0
/*
============
T_Damage

targ		entity that is being damaged
inflictor	entity that is causing the damage
attacker	entity that caused the inflictor to damage targ
	example: targ=monster, inflictor=rocket, attacker=player

dir			direction of the attack
point		point at which the damage is being inflicted
normal		normal vector from that point
damage		amount of damage being inflicted
knockback	force to be applied against targ as a result of the damage

dflags		these flags are used to control how T_Damage works
	DAMAGE_RADIUS			damage was indirect (from a nearby explosion)
	DAMAGE_NO_ARMOR			armor does not protect from this damage
	DAMAGE_ENERGY			damage is from an energy based weapon
	DAMAGE_NO_KNOCKBACK		do not affect velocity, just view angles
	DAMAGE_BULLET			damage is from a bullet (used for ricochets)
	DAMAGE_NO_PROTECTION	kills godmode, armor, everything
============
*/
static int CheckPowerArmor (edict_t *ent, vec3_t point, vec3_t normal, int damage, int dflags)
{
	gclient_t	*client;
	int			save;
	int			power_armor_type;
	int			index;
	int			damagePerCell;
	int			pa_te_type;
	int			power;
	int			power_used;

	if (!damage)
		return 0;

	client = ent->client;

	if (dflags & DAMAGE_NO_ARMOR)
		return 0;

	if (client)
	{
		power_armor_type = PowerArmorType (ent);
		if (power_armor_type != POWER_ARMOR_NONE)
		{
			index = ITEM_INDEX(FindItem("Cells"));
			power = client->pers.inventory[index];
		}
	}
	else if (ent->svflags & SVF_MONSTER)
	{
		power_armor_type = ent->monsterinfo.power_armor_type;
		power = ent->monsterinfo.power_armor_power;
	}
	else
		return 0;

	if (power_armor_type == POWER_ARMOR_NONE)
		return 0;
	if (!power)
		return 0;

	if (power_armor_type == POWER_ARMOR_SCREEN)
	{
		vec3_t		vec;
		float		dot;
		vec3_t		forward;

		// only works if damage point is in front
		AngleVectors (ent->s.angles, forward, NULL, NULL);
		VectorSubtract (point, ent->s.origin, vec);
		VectorNormalize (vec);
		dot = DotProduct (vec, forward);
		if (dot <= 0.3)
			return 0;

		damagePerCell = 1;
		pa_te_type = TE_SCREEN_SPARKS;
		damage = damage / 3;
	}
	else
	{
		damagePerCell = 2;
		pa_te_type = TE_SHIELD_SPARKS;
		damage = (2 * damage) / 3;
	}

	save = power * damagePerCell;
	if (!save)
		return 0;
	if (save > damage)
		save = damage;

	SpawnDamage (pa_te_type, point, normal, save);
	ent->powerarmor_time = level.time + 0.2;

	power_used = save / damagePerCell;

	if (client)
		client->pers.inventory[index] -= power_used;
	else
		ent->monsterinfo.power_armor_power -= power_used;
	return save;
}
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;
	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 #5
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 #6
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 #7
0
static int CheckArmor (edict_t *ent, edict_t *attacker, vec3_t point, vec3_t normal, int damage, int te_sparks, int dflags, int mod, qboolean mod_magic) {
	gclient_t	*client;
	float armor_save = 0;
	float pierce = 0;
	float breaker = 1.0;
	int			save;
	float		armoraff;
	int			armoraffsave;
	int			index;
	iteminfo_t *ainfo = NULL;

	if (!damage)
		return 0;

	client = ent->client;

	if (!client)
		return 0;
	ainfo = getWornItemInfo(ent, 1);

	if (dflags & DAMAGE_NO_ARMOR)
		return 0;

	if (ent->health <= 0)
		return 0;

	index = ITEM_INDEX(FindItem("Body Armor"));
	if (!index)
		return 0;

	if (attacker->client && attacker->client->pers.skill[2] > 0) { // Armor piercing
		int item = getWornItem(attacker, GIEX_ITEM_WEAPON);
		if (mod == MOD_BLASTER) {
			iteminfo_t *winfo = getWornItemInfo(attacker, GIEX_ITEM_WEAPON);
			pierce = getBlasterPierce(attacker, item, winfo);//winfo->arg4 + winfo->arg5 * attacker->client->pers.skill[2];
		} else if (!mod_magic) {
			pierce = getWeaponPierce(attacker, item);
		}
	}
	if (attacker->client && (attacker->client->pers.skill[71] > 0) && (!mod_magic)) { // Armor breaker (extra damage to armor)
		breaker += 0.05 * attacker->client->pers.skill[71];
	}

	if (dflags & DAMAGE_25_PIERCE) {
		pierce += 0.25;
	} else if (dflags & DAMAGE_50_PIERCE) {
		pierce += 0.5;
	} else if (dflags & DAMAGE_75_PIERCE) {
		pierce += 0.75;
	} else if (dflags & DAMAGE_100_PIERCE) {
		pierce += 1.0;
	}

	if ((attacker->svflags & SVF_MONSTER) && (attacker->monsterinfo.ability & GIEX_MABILITY_ARMORPIERCE)) {
		pierce += 0.5;
	}

	armor_save = ainfo->arg3 + ainfo->arg4 * client->pers.skill[23]/* + 0.002 * pow(ent->client->pers.skills.classLevel[1], 1.2)*/ - pierce;
	if (armor_save > 1)
		armor_save = 1;
	if (armor_save <= 0)
		return 0;

	save = ceil(armor_save * damage * breaker);
	if (save < 1) {
		return 0;
	}

	armoraff = 0.015 * client->pers.skill[44];
	if (armoraff > 0.8)
		armoraff = 0.8;
	armoraffsave = (int) ceil(save * armoraff);
	if (armoraffsave > 0) {
		if (armoraff > 0.5) {
			if ((client->silencer_shots > 0) && (client->pers.skill[58] > 5)) {
				client->silencer_shots -= 1;
			} else {
				gi.sound(ent, CHAN_ITEM, gi.soundindex("giex/magarm2.wav"), 1, ATTN_NORM, 0);
			}
		} else if (armoraff > 0.25) {
			if ((client->silencer_shots > 0) && (client->pers.skill[58] > 5)) {
				client->silencer_shots -= 1;
			} else {
				gi.sound(ent, CHAN_ITEM, gi.soundindex("giex/magarm1.wav"), 1, ATTN_NORM, 0);
			}
		}
	}

	save -= armoraffsave;
	if (save >= client->pers.inventory[index])
		save = client->pers.inventory[index];

	if (!save) {
		if (armoraffsave > 0)
			return 1;
		return 0;
	}
	client->pers.inventory[index] -= save;
	SpawnDamage (te_sparks, point, normal, save);

	return (int) ((save + armoraffsave) / breaker);
}
Example #8
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);
	}
}