float yoda;
float damage_goodhits;
float damage_gooddamage;
-float headshot;
-float damage_headshotbonus; // bonus multiplier for head shots, set to 0 after use
.float dmg_team;
.float teamkill_complain;
.float teamkill_soundtime;
.entity teamkill_soundsource;
.entity pusher;
+.float istypefrag;
.float taunt_soundtime;
return 1;
}
-vector GetHeadshotMins(entity targ)
-{
- return '-0.5 0 0' * PL_HEAD_x + '0 -0.5 0' * PL_HEAD_y + '0 0 1' * (targ.maxs_z - PL_HEAD_z);
-}
-vector GetHeadshotMaxs(entity targ)
-{
- return '0.5 0 0' * PL_HEAD_x + '0 0.5 0' * PL_HEAD_y + '0 0 1' * targ.maxs_z;
-}
-
void UpdateFrags(entity player, float f)
{
PlayerTeamScore_AddScore(player, f);
PlayerScore_Add(targ, SP_DEATHS, 1);
- if(g_arena || g_ca)
- if(autocvar_g_arena_roundbased)
- return;
-
if(targ != attacker) // not for suicides
if(g_weaponarena_random)
{
}
f = 0;
}
- else if(g_ctf)
- {
- if(g_ctf_ignore_frags)
- f = 0;
- }
}
attacker.totalfrags += f;
void Send_KillNotification (string s1, string s2, string s3, float msg, float type)
{
- WriteByte(MSG_ALL, SVC_TEMPENTITY);
- WriteByte(MSG_ALL, TE_CSQC_KILLNOTIFY);
- WriteString(MSG_ALL, s1);
- WriteString(MSG_ALL, s2);
- WriteString(MSG_ALL, s3);
- WriteShort(MSG_ALL, msg);
- WriteByte(MSG_ALL, type);
+ WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
+ WriteByte(MSG_BROADCAST, TE_CSQC_KILLNOTIFY);
+ WriteString(MSG_BROADCAST, s1);
+ WriteString(MSG_BROADCAST, s2);
+ WriteString(MSG_BROADCAST, s3);
+ WriteShort(MSG_BROADCAST, msg);
+ WriteByte(MSG_BROADCAST, type);
}
// Function is used to send a generic centerprint whose content CSQC gets to decide (gentle version or not in the below cases)
void Obituary (entity attacker, entity inflictor, entity targ, float deathtype)
{
string s, a, msg;
- float w, type;
+ float type;
if (targ.classname == "player")
{
deathtype = KILL_TEAM_BLUE;
}
- Send_KillNotification(s, msg, ftos(w), deathtype, MSG_SUICIDE);
+ Send_KillNotification(s, msg, "", deathtype, MSG_SUICIDE);
}
else if (attacker.classname == "player")
{
PlayerStats_Event(targ, PLAYERSTATS_ACHIEVEMENT_FIRSTVICTIM, 1);
}
- if(targ.BUTTON_CHAT) {
+ if(targ.istypefrag) {
Send_CSQC_KillCenterprint(attacker, s, Obituary_ExtraFragInfo(targ), KILL_TYPEFRAG, MSG_KILL);
Send_CSQC_KillCenterprint(targ, a, Obituary_ExtraFragInfo(attacker), KILL_TYPEFRAGGED, MSG_KILL);
} else {
Send_KillNotification(a, s, msg, deathtype, MSG_KILL);
- if(g_ctf && targ.flagcarried)
- {
- UpdateFrags(attacker, ctf_score_value("score_kill"));
- PlayerScore_Add(attacker, SP_CTF_FCKILLS, 1);
- GiveFrags(attacker, targ, 0, deathtype); // for logging
- }
- else
- GiveFrags(attacker, targ, 1, deathtype);
+ GiveFrags(attacker, targ, 1, deathtype);
if (targ.killcount > 2) {
Send_KillNotification(s, ftos(targ.killcount), a, KILL_END_SPREE, MSG_SPREE);
attacker.killcount = attacker.killcount + 1;
- if (attacker.killcount > 2) {
- Send_KillNotification(a, ftos(attacker.killcount), "", KILL_SPREE, MSG_SPREE);
- }
- else if (attacker.killcount == 3)
+ if (attacker.killcount == 3)
{
Send_KillNotification(a, "", "", KILL_SPREE_3, MSG_SPREE);
AnnounceTo(attacker, "03kills");
AnnounceTo(attacker, "30kills");
PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_30, 1);
}
+ else if (attacker.killcount > 2) {
+ Send_KillNotification(a, ftos(attacker.killcount), "", KILL_SPREE, MSG_SPREE);
+ }
LogDeath("frag", deathtype, attacker, targ);
}
}
if(autocvar_g_mirrordamage_virtual)
{
- vector v = healtharmor_applydamage(attacker.armorvalue, autocvar_g_balance_armor_blockpercent, mirrordamage);
+ vector v = healtharmor_applydamage(attacker.armorvalue, autocvar_g_balance_armor_blockpercent, mirrordamage);
attacker.dmg_take += v_x;
attacker.dmg_save += v_y;
attacker.dmg_inflictor = inflictor;
- mirrordamage = 0;
+ mirrordamage = v_z; // = 0, to make fteqcc stfu
mirrorforce = 0;
}
damage = damage * autocvar_g_balance_selfdamagepercent; // Partial damage if the attacker hits himself
}
- // CTF: reduce damage/force
- if(g_ctf)
- if(targ == attacker)
- if(targ.flagcarried)
- {
- damage = damage * autocvar_g_ctf_flagcarrier_selfdamage;
- force = force * autocvar_g_ctf_flagcarrier_selfforce;
- }
-
if(g_runematch)
{
// apply strength rune
if(targ.takedamage == DAMAGE_AIM)
if(targ != attacker)
{
- if(damage_headshotbonus)
- {
- if(targ.classname == "player")
- {
- // HEAD SHOT:
- // find height of hit on player axis
- // if above view_ofs and below maxs, and also in the middle half of the bbox, it is head shot
- vector headmins, headmaxs, org;
- org = antilag_takebackorigin(targ, time - ANTILAG_LATENCY(attacker));
- headmins = org + GetHeadshotMins(targ);
- headmaxs = org + GetHeadshotMaxs(targ);
- if(trace_hits_box(railgun_start, railgun_end, headmins, headmaxs))
- {
- deathtype |= HITTYPE_HEADSHOT;
- }
- }
- else if(targ.classname == "turret_head")
- {
- deathtype |= HITTYPE_HEADSHOT;
- }
- if(deathtype & HITTYPE_HEADSHOT)
- if(damage_headshotbonus > 0)
- damage *= 1 + damage_headshotbonus;
- }
-
entity victim;
if((targ.vehicle_flags & VHF_ISVEHICLE) && targ.owner)
victim = targ.owner;
if(g_minstagib)
if(victim.items & IT_STRENGTH)
yoda = 1;
-
- if(deathtype & HITTYPE_HEADSHOT)
- headshot = 1;
}
- if(g_ca)
- PlayerScore_Add(attacker, SP_SCORE, damage * autocvar_g_ca_damage2score_multiplier);
}
}
else
myblastorigin = WarpZone_TransformOrigin(targ, blastorigin);
// if it's a player, use the view origin as reference
- if (targ.classname == "player")
- center = targ.origin + targ.view_ofs;
- else
- center = targ.origin + (targ.mins + targ.maxs) * 0.5;
+ center = CENTER_OR_VIEWOFS(targ);
force = normalize(center - myblastorigin);
force = force * (finaldmg / coredamage) * forceintensity;
// but we can't exceed maxtime * maxdps!
totaldamage = min(maxdamage, maxtime * maxdps);
+ // LEMMA:
+ // Look at:
+ // totaldamage = min(mindamage + d, maxtime * maxdps)
+ // We see:
+ // totaldamage <= maxtime * maxdps
+ // ==> totaldamage / maxdps <= maxtime.
+ // We also see:
+ // totaldamage / mindps = min(mindamage / mindps + d, maxtime * maxdps / mindps)
+ // >= min(mintime, maxtime)
+ // ==> totaldamage / maxdps >= mintime.
+
/*
// how long do we damage then?
// at least as long as before
// but, never exceed maxdps
- totaltime = max(mintime, totaldamage / maxdps); // always <= maxtime
+ totaltime = max(mintime, totaldamage / maxdps); // always <= maxtime due to lemma
*/
// alternate:
// at most as long as maximum allowed
- // but, try mindps
- totaltime = min(maxtime, totaldamage / mindps); // always >= mintime
-
- // can these two ever differ?
+ // but, never below mindps
+ totaltime = min(maxtime, totaldamage / mindps); // always >= mintime due to lemma
+
+ // assuming t > mintime, dps > mindps:
+ // we get d = t * dps = maxtime * maxdps
+ // totaldamage = min(maxdamage, maxtime * maxdps) = min(... + d, maxtime * maxdps) = maxtime * maxdps
+ // totaldamage / maxdps = maxtime
+ // totaldamage / mindps > totaldamage / maxdps = maxtime
+ // FROM THIS:
+ // a) totaltime = max(mintime, maxtime) = maxtime
+ // b) totaltime = min(maxtime, totaldamage / maxdps) = maxtime
+
+ // assuming t <= mintime:
+ // we get maxtime = mintime
+ // a) totaltime = max(mintime, ...) >= mintime, also totaltime <= maxtime by the lemma, therefore totaltime = mintime = maxtime
+ // b) totaltime = min(maxtime, ...) <= maxtime, also totaltime >= mintime by the lemma, therefore totaltime = mintime = maxtime
+
+ // assuming dps <= mindps:
+ // we get mindps = maxdps.
+ // With this, the lemma says that mintime <= totaldamage / mindps = totaldamage / maxdps <= maxtime.
+ // a) totaltime = max(mintime, totaldamage / maxdps) = totaldamage / maxdps
+ // b) totaltime = min(maxtime, totaldamage / mindps) = totaldamage / maxdps
e.fire_damagepersec = totaldamage / totaltime;
e.fire_endtime = time + totaltime;