Beispiel #1
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);
	}
}
Beispiel #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);
	}
}
Beispiel #3
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;
}
Beispiel #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);
    }
}
Beispiel #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;

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