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; }
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); } }
/* ============ 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; }
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); } }
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); } }
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; }
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); }
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); } }