/*** * * Copyright (c) 2016-2019 Marco 'eukara' Hladik. All rights reserved. * * See the file LICENSE attached with the sources for usage details. * ****/ /* ================= Damage_CastOrbituary Sends a message to the clients to display a death message ================= */ void Damage_CastOrbituary(entity eAttacker, entity eTarget, float fWeapon, float fHeadShot) { WriteByte(MSG_BROADCAST, SVC_CGAMEPACKET); WriteByte(MSG_BROADCAST, EV_ORBITUARY); WriteByte(MSG_BROADCAST, num_for_edict(eAttacker) - 1); WriteByte(MSG_BROADCAST, eAttacker.team); WriteByte(MSG_BROADCAST, num_for_edict(eTarget) - 1); WriteByte(MSG_BROADCAST, eTarget.team); WriteByte(MSG_BROADCAST, fWeapon); WriteByte(MSG_BROADCAST, fHeadShot); msg_entity = self; multicast([0,0,0], MULTICAST_ALL); } /* ================= Damage_GetHitLocation Debug function ================= */ string Damage_GetHitLocation(int iSurface) { #ifdef CSTRIKE switch (iSurface) { case BODY_HEAD: return "Head"; break; case BODY_CHEST: return "Chest"; break; case BODY_STOMACH: return "Stomach"; break; case BODY_ARMLEFT: return "Left Arm"; break; case BODY_ARMRIGHT: return "Right Arm"; break; case BODY_LEGLEFT: return "Left leg"; break; case BODY_LEGRIGHT: return "Right Leg"; break; default: return "Generic"; } #endif } int Damage_ShouldDamage(float fTargetTeam, float fAttackerTeam) { #ifdef CSTRIKE if (fTargetTeam == TEAM_VIP) { fTargetTeam = TEAM_CT; } else if (fAttackerTeam == TEAM_VIP) { fAttackerTeam = TEAM_CT; } if (fTargetTeam == fAttackerTeam) { return FALSE; } return TRUE; #endif } /* ================= Damage_Apply Generic function that applies damage, pain and suffering ================= */ void Damage_Apply(entity eTarget, entity eAttacker, float iDamage, vector vHitPos, int iSkipArmor) { #ifdef CSTRIKE // Modify the damage based on the location if (trace_surface_id == BODY_HEAD) { if (eTarget.iEquipment & EQUIPMENT_HELMET) { sound(self, CHAN_ITEM, "weapons/ric_metal-2.wav", 1, ATTN_IDLE); iDamage = 0; eTarget.iEquipment -= EQUIPMENT_HELMET; } else { iDamage *= 4; } } else if (trace_surface_id == BODY_STOMACH) { iDamage *= 0.9; } else if (trace_surface_id == BODY_LEGLEFT) { iDamage *= 0.4; } else if (trace_surface_id == BODY_LEGRIGHT) { iDamage *= 0.4; } dprint(sprintf("[DEBUG] Hit Bodypart: %s\n", Damage_GetHitLocation(trace_surface_id))); if (eTarget != eAttacker) { if (!Damage_ShouldDamage(eTarget.team, eAttacker.team)) { if (!autocvar_mp_friendlyfire) { return; } } } eTarget.velocity = [0,0,0]; // Apply the damage finally if (eTarget.armor) { float fRatio = 0.5; if (eAttacker.weapon) { fRatio *= wptTable[eAttacker.weapon].fWeaponArmorRatio; } // Simple implementation of how kevlar damage is calculated float fNewDmg = iDamage * fRatio; float fNewArmor = (iDamage - fNewDmg) / 2; if (fNewArmor > eTarget.armor) { fNewArmor = eTarget.armor; fNewArmor *= (1/0.5); fNewDmg = rint(iDamage - fNewArmor); eTarget.armor = 0; eTarget.iEquipment -= EQUIPMENT_KEVLAR; } else { if (fNewArmor < 0) { fNewArmor = 1; } eTarget.armor = rint(eTarget.armor - fNewArmor); } if (iSkipArmor == TRUE) { eTarget.health = rint(eTarget.health -= iDamage); eTarget.dmg_take = (float)iDamage; } else { eTarget.health = rint(eTarget.health -= fNewDmg); eTarget.dmg_take = (float)fNewDmg; } } else { // No armor eTarget.health -= iDamage; eTarget.dmg_take = (float)iDamage; } eTarget.dmg_inflictor = eAttacker; // Special monetary punishment for hostage murderers if (eTarget.classname == "hostage_entity") { if (eTarget.health > 0) { Money_AddMoney(eAttacker, autocvar_fcs_penalty_pain); // Pain } else { Money_AddMoney(eAttacker, autocvar_fcs_penalty_kill); // Death } } // Target is dead and a client.... if (eTarget.health <= 0) { if (eTarget.flags & FL_CLIENT) { eTarget.fDeaths++; forceinfokey(eTarget, "*deaths", ftos(eTarget.fDeaths)); } if ((eTarget.flags & FL_CLIENT) && (eAttacker.flags & FL_CLIENT)) { // Don't encourage them to kill their own team members for $$$ if (Damage_ShouldDamage(eTarget.team, eAttacker.team) == TRUE) { eAttacker.frags++; Money_AddMoney(eAttacker, autocvar_fcs_reward_kill); } else { eAttacker.frags--; } Damage_CastOrbituary(eAttacker, eTarget, eAttacker.weapon, trace_surface_id == BODY_HEAD ? TRUE:FALSE); } } entity eOld = self; self = eTarget; if (self.health <= 0) { self.health = 0; self.vDeath(trace_surface_id); } else { self.vPain(trace_surface_id); } self = eOld; #endif } /* ================= Damage_CheckAttack This verifies that the entity is actually able to receive some damage, from a plain geographical standpoint ================= */ float Damage_CheckAttack(entity eTarget, vector vAttackPos) { if (eTarget.movetype == MOVETYPE_PUSH) { traceline(vAttackPos, 0.5 * (eTarget.absmin + eTarget.absmax), TRUE, self); if (trace_fraction == 1) { return TRUE; } if (trace_ent == eTarget) { return TRUE; } return FALSE; } traceline(vAttackPos, eTarget.origin, TRUE, self); if (trace_fraction == 1) { return TRUE; } traceline(vAttackPos, eTarget.origin + '15 15 0', TRUE, self); if (trace_fraction == 1) { return TRUE; } traceline(vAttackPos, eTarget.origin + '-15 -15 0', TRUE, self); if (trace_fraction == 1) { return TRUE; } traceline(vAttackPos, eTarget.origin + '-15 15 0', TRUE, self); if (trace_fraction == 1) { return TRUE; } traceline(vAttackPos, eTarget.origin + '15 -15 0', TRUE, self); if (trace_fraction == 1) { return TRUE; } return FALSE; } /* ================= Damage_Radius Even more pain and suffering, mostly used for explosives ================= */ void Damage_Radius(vector vOrigin, entity eAttacker, float fDamage, float fRadius, int iCheckClip) { for (entity eDChain = world; (eDChain = findfloat(eDChain, takedamage, DAMAGE_YES));) { vector vecRealPos; vecRealPos[0] = eDChain.absmin[0] + (0.5 * (eDChain.absmax[0] - eDChain.absmin[0])); vecRealPos[1] = eDChain.absmin[1] + (0.5 * (eDChain.absmax[1] - eDChain.absmin[1])); vecRealPos[2] = eDChain.absmin[2] + (0.5 * (eDChain.absmax[2] - eDChain.absmin[2])); float fDist = vlen(vOrigin - vecRealPos); //vector vPush; if (fDist > fRadius) { continue; } if (Damage_CheckAttack(eDChain, vOrigin) || iCheckClip == FALSE) { float fDiff = vlen(vOrigin - vecRealPos); fDiff = (fRadius - fDiff) / fRadius; fDamage = rint(fDamage * fDiff); if (fDiff > 0) { Damage_Apply(eDChain, eAttacker, fDamage, eDChain.origin, TRUE); /*if (eDChain.movetype != MOVETYPE_NONE) { vPush = vectoangles(vecRealPos - vOrigin); makevectors(vPush); eDChain.velocity += (v_forward * fDamage * 5) + (v_up * fDamage * 2.5); }*/ } } } }