]> git.rm.cloudns.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Mutators: add hooks for overkill
authorTimePath <andrew.hardaker1995@gmail.com>
Wed, 4 Nov 2015 22:57:37 +0000 (09:57 +1100)
committerTimePath <andrew.hardaker1995@gmail.com>
Wed, 4 Nov 2015 22:57:37 +0000 (09:57 +1100)
25 files changed:
qcsrc/client/progs.inc
qcsrc/common/casings.qc [new file with mode: 0644]
qcsrc/common/mutators/all.inc
qcsrc/common/mutators/events.qh
qcsrc/common/mutators/mutator/casings.qc [deleted file]
qcsrc/common/mutators/mutator/damagetext.qc [deleted file]
qcsrc/common/mutators/mutator/damagetext/damagetext.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/damagetext/module.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/instagib/instagib.qc
qcsrc/common/mutators/mutator/instagib/module.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/overkill/hmg.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/overkill/module.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/overkill/overkill.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/overkill/rpc.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/waypoints/module.inc [new file with mode: 0644]
qcsrc/common/weapons/all.inc
qcsrc/common/weapons/weapon/hmg.qc [deleted file]
qcsrc/common/weapons/weapon/rpc.qc [deleted file]
qcsrc/server/autocvars.qh
qcsrc/server/mutators/all.inc
qcsrc/server/mutators/events.qh
qcsrc/server/mutators/mutator/mutator_nades.qc
qcsrc/server/mutators/mutator/mutator_overkill.qc [deleted file]
qcsrc/server/progs.inc
qcsrc/server/weapons/weaponsystem.qc

index 5c110e2b8986547e93e16b0e3bc1ba96b4cf24ce..e3e8c00c067a151710e8f6b4c156be1c2394e67a 100644 (file)
@@ -33,6 +33,7 @@
 #include "weapons/projectile.qc" // TODO
 
 #include "../common/animdecide.qc"
+#include "../common/casings.qc"
 #include "../common/effects/effectinfo.qc"
 #include "../common/mapinfo.qc"
 #include "../common/movetypes/include.qc"
diff --git a/qcsrc/common/casings.qc b/qcsrc/common/casings.qc
new file mode 100644 (file)
index 0000000..22046dd
--- /dev/null
@@ -0,0 +1,175 @@
+#include "util.qh"
+
+#ifdef CSQC
+#include "movetypes/movetypes.qh"
+#include "../client/rubble.qh"
+#endif
+
+REGISTER_NET_TEMP(casings)
+
+#ifdef SVQC
+void SpawnCasing(vector vel, float randomvel, vector ang, vector avel, float randomavel, int casingtype, entity casingowner)
+{SELFPARAM();
+    .entity weaponentity = weaponentities[0]; // TODO: parameter
+    entity wep = self.(weaponentity);
+    vector org = self.origin + self.view_ofs + wep.spawnorigin.x * v_forward - wep.spawnorigin.y * v_right + wep.spawnorigin.z * v_up;
+
+    if (!sound_allowed(MSG_BROADCAST, casingowner))
+        casingtype |= 0x80;
+
+    WriteHeader(MSG_ALL, casings);
+    WriteByte(MSG_ALL, casingtype);
+    WriteCoord(MSG_ALL, org.x);
+    WriteCoord(MSG_ALL, org.y);
+    WriteCoord(MSG_ALL, org.z);
+    WriteShort(MSG_ALL, compressShortVector(vel)); // actually compressed velocity
+    WriteByte(MSG_ALL, ang.x * 256 / 360);
+    WriteByte(MSG_ALL, ang.y * 256 / 360);
+    WriteByte(MSG_ALL, ang.z * 256 / 360);
+}
+#endif
+
+#ifdef CSQC
+entityclass(Casing);
+class(Casing) .float alpha;
+class(Casing) .bool silent;
+class(Casing) .int state;
+class(Casing) .float cnt;
+
+void Casing_Delete()
+{SELFPARAM();
+    remove(self);
+}
+
+void Casing_Draw(entity this)
+{
+    if (self.move_flags & FL_ONGROUND)
+    {
+        self.move_angles_x = 0;
+        self.move_angles_z = 0;
+        self.flags &= ~FL_ONGROUND;
+    }
+
+    Movetype_Physics_MatchTicrate(autocvar_cl_casings_ticrate, autocvar_cl_casings_sloppy);
+    if (wasfreed(self))
+        return; // deleted by touch function
+
+    self.renderflags = 0;
+    self.alpha = bound(0, self.cnt - time, 1);
+
+    if (self.alpha < ALPHA_MIN_VISIBLE)
+    {
+        Casing_Delete();
+        self.drawmask = 0;
+    }
+}
+
+SOUND(BRASS1, W_Sound("brass1"));
+SOUND(BRASS2, W_Sound("brass2"));
+SOUND(BRASS3, W_Sound("brass3"));
+Sound SND_BRASS_RANDOM() {
+    return Sounds_from(SND_BRASS1.m_id + floor(prandom() * 3));
+}
+SOUND(CASINGS1, W_Sound("casings1"));
+SOUND(CASINGS2, W_Sound("casings2"));
+SOUND(CASINGS3, W_Sound("casings3"));
+Sound SND_CASINGS_RANDOM() {
+    return Sounds_from(SND_CASINGS1.m_id + floor(prandom() * 3));
+}
+
+void Casing_Touch()
+{SELFPARAM();
+    if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
+    {
+        Casing_Delete();
+        return;
+    }
+
+    if (!self.silent)
+    if (!trace_ent || trace_ent.solid == SOLID_BSP)
+    {
+        if (vlen(self.velocity) > 50)
+        {
+            if (time >= self.nextthink)
+            {
+                Sound s;
+                switch (self.state)
+                {
+                    case 1:
+                        s = SND_CASINGS_RANDOM();
+                        break;
+                    default:
+                        s = SND_BRASS_RANDOM();
+                        break;
+                }
+
+                sound (self, CH_SHOTS, s, VOL_BASE, ATTEN_LARGE);
+            }
+        }
+    }
+
+    self.nextthink = time + 0.2;
+}
+
+void Casing_Damage(float thisdmg, int hittype, vector org, vector thisforce)
+{SELFPARAM();
+    if (thisforce.z < 0)
+        thisforce.z = 0;
+    self.move_velocity = self.move_velocity + thisforce + '0 0 100';
+    self.move_flags &= ~FL_ONGROUND;
+}
+
+NET_HANDLE(casings, bool isNew)
+{
+    int _state = ReadByte();
+    vector org;
+    org_x = ReadCoord();
+    org_y = ReadCoord();
+    org_z = ReadCoord();
+    vector vel = decompressShortVector(ReadShort());
+    vector ang;
+    ang_x = ReadByte() * 360 / 256;
+    ang_y = ReadByte() * 360 / 256;
+    ang_z = ReadByte() * 360 / 256;
+    return = true;
+
+    if (!autocvar_cl_casings) return;
+
+    Casing casing = RubbleNew("casing");
+    casing.silent = (_state & 0x80);
+    casing.state = (_state & 0x7F);
+    casing.origin = org;
+    setorigin(casing, casing.origin);
+    casing.velocity = vel;
+    casing.angles = ang;
+    casing.drawmask = MASK_NORMAL;
+
+    casing.draw = Casing_Draw;
+    casing.move_origin = casing.origin;
+    casing.move_velocity = casing.velocity + 2 * prandomvec();
+    casing.move_angles = casing.angles;
+    casing.move_avelocity = '0 250 0' + 100 * prandomvec();
+    casing.move_movetype = MOVETYPE_BOUNCE;
+    casing.move_touch = Casing_Touch;
+    casing.move_time = time;
+    casing.event_damage = Casing_Damage;
+    casing.solid = SOLID_TRIGGER;
+
+    switch (casing.state)
+    {
+        case 1:
+            setmodel(casing, MDL_CASING_SHELL);
+            casing.cnt = time + autocvar_cl_casings_shell_time;
+            break;
+        default:
+            setmodel(casing, MDL_CASING_BULLET);
+            casing.cnt = time + autocvar_cl_casings_bronze_time;
+            break;
+    }
+
+    setsize(casing, '0 0 -1', '0 0 -1');
+
+    RubbleLimit("casing", autocvar_cl_casings_maxcount, Casing_Delete);
+}
+
+#endif
index 6b19a0bc6eb2043ab937335f731b675f8c91e24d..d3e63de453851d05388b757a119da8f49054cce7 100644 (file)
@@ -1,5 +1,8 @@
-#include "mutator/casings.qc"
-#include "mutator/damagetext.qc"
-#include "mutator/instagib/instagib.qc"
+#include "mutator/instagib/module.inc"
 #include "mutator/itemstime.qc"
-#include "mutator/waypoints/waypointsprites.qc"
+#include "mutator/waypoints/module.inc"
+
+// completely self contained
+
+#include "mutator/damagetext/module.inc"
+#include "mutator/overkill/module.inc"
index 7ba24fa7a42a63c20ff3e979c06697683a5c1a51..bb845b8015785cd4bf7c679c83f9a1ff8a969003 100644 (file)
@@ -15,7 +15,8 @@ string ret_string;
     _(x, string) \
     /**/
 
-#define MUTATOR_NEWGLOBAL(x, type) type mutator_argv_##type##_##x;
+#define MUTATOR_ARGV(x, type) MUTATOR_ARGV_##x##_##type
+#define MUTATOR_NEWGLOBAL(x, type) type MUTATOR_ARGV(x, type);
 
 MUTATOR_TYPES(MUTATOR_NEWGLOBAL, 0)
 MUTATOR_TYPES(MUTATOR_NEWGLOBAL, 1)
diff --git a/qcsrc/common/mutators/mutator/casings.qc b/qcsrc/common/mutators/mutator/casings.qc
deleted file mode 100644 (file)
index 2ad32cf..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-#ifdef IMPLEMENTATION
-
-#include "../../util.qh"
-
-#ifdef CSQC
-#include "../../movetypes/movetypes.qh"
-#include "../../../client/rubble.qh"
-#endif
-
-REGISTER_MUTATOR(casings, true);
-
-REGISTER_NET_TEMP(casings)
-
-#ifdef SVQC
-void SpawnCasing(vector vel, float randomvel, vector ang, vector avel, float randomavel, int casingtype, entity casingowner)
-{SELFPARAM();
-    .entity weaponentity = weaponentities[0]; // TODO: parameter
-    entity wep = self.(weaponentity);
-    vector org = self.origin + self.view_ofs + wep.spawnorigin.x * v_forward - wep.spawnorigin.y * v_right + wep.spawnorigin.z * v_up;
-
-    if (!sound_allowed(MSG_BROADCAST, casingowner))
-        casingtype |= 0x80;
-
-    WriteHeader(MSG_ALL, casings);
-    WriteByte(MSG_ALL, casingtype);
-    WriteCoord(MSG_ALL, org.x);
-    WriteCoord(MSG_ALL, org.y);
-    WriteCoord(MSG_ALL, org.z);
-    WriteShort(MSG_ALL, compressShortVector(vel)); // actually compressed velocity
-    WriteByte(MSG_ALL, ang.x * 256 / 360);
-    WriteByte(MSG_ALL, ang.y * 256 / 360);
-    WriteByte(MSG_ALL, ang.z * 256 / 360);
-}
-#endif
-
-#ifdef CSQC
-entityclass(Casing);
-class(Casing) .float alpha;
-class(Casing) .bool silent;
-class(Casing) .int state;
-class(Casing) .float cnt;
-
-void Casing_Delete()
-{SELFPARAM();
-    remove(self);
-}
-
-void Casing_Draw(entity this)
-{
-    if (self.move_flags & FL_ONGROUND)
-    {
-        self.move_angles_x = 0;
-        self.move_angles_z = 0;
-        self.flags &= ~FL_ONGROUND;
-    }
-
-    Movetype_Physics_MatchTicrate(autocvar_cl_casings_ticrate, autocvar_cl_casings_sloppy);
-    if (wasfreed(self))
-        return; // deleted by touch function
-
-    self.renderflags = 0;
-    self.alpha = bound(0, self.cnt - time, 1);
-
-    if (self.alpha < ALPHA_MIN_VISIBLE)
-    {
-        Casing_Delete();
-        self.drawmask = 0;
-    }
-}
-
-SOUND(BRASS1, W_Sound("brass1"));
-SOUND(BRASS2, W_Sound("brass2"));
-SOUND(BRASS3, W_Sound("brass3"));
-Sound SND_BRASS_RANDOM() {
-    return Sounds_from(SND_BRASS1.m_id + floor(prandom() * 3));
-}
-SOUND(CASINGS1, W_Sound("casings1"));
-SOUND(CASINGS2, W_Sound("casings2"));
-SOUND(CASINGS3, W_Sound("casings3"));
-Sound SND_CASINGS_RANDOM() {
-    return Sounds_from(SND_CASINGS1.m_id + floor(prandom() * 3));
-}
-
-void Casing_Touch()
-{SELFPARAM();
-    if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
-    {
-        Casing_Delete();
-        return;
-    }
-
-    if (!self.silent)
-    if (!trace_ent || trace_ent.solid == SOLID_BSP)
-    {
-        if (vlen(self.velocity) > 50)
-        {
-            if (time >= self.nextthink)
-            {
-                Sound s;
-                switch (self.state)
-                {
-                    case 1:
-                        s = SND_CASINGS_RANDOM();
-                        break;
-                    default:
-                        s = SND_BRASS_RANDOM();
-                        break;
-                }
-
-                sound (self, CH_SHOTS, s, VOL_BASE, ATTEN_LARGE);
-            }
-        }
-    }
-
-    self.nextthink = time + 0.2;
-}
-
-void Casing_Damage(float thisdmg, int hittype, vector org, vector thisforce)
-{SELFPARAM();
-    if (thisforce.z < 0)
-        thisforce.z = 0;
-    self.move_velocity = self.move_velocity + thisforce + '0 0 100';
-    self.move_flags &= ~FL_ONGROUND;
-}
-
-NET_HANDLE(casings, bool isNew)
-{
-    int _state = ReadByte();
-    vector org;
-    org_x = ReadCoord();
-    org_y = ReadCoord();
-    org_z = ReadCoord();
-    vector vel = decompressShortVector(ReadShort());
-    vector ang;
-    ang_x = ReadByte() * 360 / 256;
-    ang_y = ReadByte() * 360 / 256;
-    ang_z = ReadByte() * 360 / 256;
-    return = true;
-
-    if (!autocvar_cl_casings) return;
-
-    Casing casing = RubbleNew("casing");
-    casing.silent = (_state & 0x80);
-    casing.state = (_state & 0x7F);
-    casing.origin = org;
-    setorigin(casing, casing.origin);
-    casing.velocity = vel;
-    casing.angles = ang;
-    casing.drawmask = MASK_NORMAL;
-
-    casing.draw = Casing_Draw;
-    casing.move_origin = casing.origin;
-    casing.move_velocity = casing.velocity + 2 * prandomvec();
-    casing.move_angles = casing.angles;
-    casing.move_avelocity = '0 250 0' + 100 * prandomvec();
-    casing.move_movetype = MOVETYPE_BOUNCE;
-    casing.move_touch = Casing_Touch;
-    casing.move_time = time;
-    casing.event_damage = Casing_Damage;
-    casing.solid = SOLID_TRIGGER;
-
-    switch (casing.state)
-    {
-        case 1:
-            setmodel(casing, MDL_CASING_SHELL);
-            casing.cnt = time + autocvar_cl_casings_shell_time;
-            break;
-        default:
-            setmodel(casing, MDL_CASING_BULLET);
-            casing.cnt = time + autocvar_cl_casings_bronze_time;
-            break;
-    }
-
-    setsize(casing, '0 0 -1', '0 0 -1');
-
-    RubbleLimit("casing", autocvar_cl_casings_maxcount, Casing_Delete);
-}
-
-#endif
-#endif
diff --git a/qcsrc/common/mutators/mutator/damagetext.qc b/qcsrc/common/mutators/mutator/damagetext.qc
deleted file mode 100644 (file)
index ac451ca..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-#ifndef MUTATOR_DAMAGETEXT_H
-#define MUTATOR_DAMAGETEXT_H
-
-#ifdef MENUQC
-#include "../../../menu/xonotic/tab.qc"
-#endif
-
-#endif
-
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(damagetext, true);
-
-#if defined(CSQC) || defined(MENUQC)
-AUTOCVAR_SAVE(cl_damagetext,                    bool,   false,      _("Draw damage dealt. 0: disabled, 1: enabled"));
-AUTOCVAR_SAVE(cl_damagetext_format,             string, "-%3$d",    _("How to format the damage text. 1$ is health, 2$ is armor, 3$ is both"));
-AUTOCVAR_SAVE(cl_damagetext_color,              vector, '1 1 0',    _("Default damage text color"));
-AUTOCVAR_SAVE(cl_damagetext_color_per_weapon,   bool,   false,      _("Damage text uses weapon color"));
-AUTOCVAR_SAVE(cl_damagetext_size,               float,  8,          _("Damage text font size"));
-AUTOCVAR_SAVE(cl_damagetext_alpha_start,        float,  1,          _("Damage text initial alpha"));
-AUTOCVAR_SAVE(cl_damagetext_alpha_lifetime,     float,  3,          _("Damage text lifetime in seconds"));
-AUTOCVAR_SAVE(cl_damagetext_velocity,           vector, '0 0 20',   _("Damage text move direction"));
-AUTOCVAR_SAVE(cl_damagetext_offset,             vector, '0 -40 0',  _("Damage text offset"));
-AUTOCVAR_SAVE(cl_damagetext_accumulate_range,   float,  30,         _("Damage text spawned within this range is accumulated"));
-#endif
-
-#ifdef CSQC
-CLASS(DamageText, Object)
-    ATTRIB(DamageText, m_color, vector, autocvar_cl_damagetext_color)
-    ATTRIB(DamageText, m_size, float, autocvar_cl_damagetext_size)
-    ATTRIB(DamageText, alpha, float, autocvar_cl_damagetext_alpha_start)
-    ATTRIB(DamageText, fade_rate, float, 1 / autocvar_cl_damagetext_alpha_lifetime)
-    ATTRIB(DamageText, velocity, vector, autocvar_cl_damagetext_velocity)
-    ATTRIB(DamageText, m_group, int, 0)
-    ATTRIB(DamageText, m_damage, int, 0)
-    ATTRIB(DamageText, m_armordamage, int, 0)
-    ATTRIB(DamageText, m_deathtype, int, 0)
-    ATTRIB(DamageText, time_prev, float, time)
-
-    void DamageText_draw2d(DamageText this) {
-        float dt = time - this.time_prev;
-        this.time_prev = time;
-        setorigin(this, this.origin + dt * this.velocity);
-        this.alpha -= dt * this.fade_rate;
-        if (this.alpha < 0) remove(this);
-        vector pos = project_3d_to_2d(this.origin) + autocvar_cl_damagetext_offset;
-        if (pos.z >= 0 && this.m_size > 0) {
-            pos.z = 0;
-            vector rgb = this.m_color;
-            if (autocvar_cl_damagetext_color_per_weapon) {
-                Weapon w = DEATH_WEAPONOF(this.m_deathtype);
-                if (w != WEP_Null) rgb = w.wpcolor;
-            }
-            string s = sprintf(autocvar_cl_damagetext_format, this.m_damage, this.m_armordamage, this.m_damage + this.m_armordamage);
-            drawcolorcodedstring2(pos, s, this.m_size * '1 1 0', rgb, this.alpha, DRAWFLAG_NORMAL);
-        }
-    }
-    ATTRIB(DamageText, draw2d, void(DamageText), DamageText_draw2d)
-
-    void DamageText_update(DamageText this, vector _origin, int _health, int _armor, int _deathtype) {
-        this.m_damage = _health;
-        this.m_armordamage = _armor;
-        this.m_deathtype = _deathtype;
-        setorigin(this, _origin);
-        this.alpha = 1;
-    }
-
-    CONSTRUCTOR(DamageText, int _group, vector _origin, int _health, int _armor, int _deathtype) {
-        CONSTRUCT(DamageText);
-        this.m_group = _group;
-        DamageText_update(this, _origin, _health, _armor, _deathtype);
-    }
-ENDCLASS(DamageText)
-#endif
-
-REGISTER_NET_TEMP(damagetext)
-
-#ifdef SVQC
-AUTOCVAR(sv_damagetext, int, 2, _("<= 0: disabled, >= 1: spectators, >= 2: players, >= 3: all players"));
-#define SV_DAMAGETEXT_DISABLED()        (autocvar_sv_damagetext <= 0 /* disabled */)
-#define SV_DAMAGETEXT_SPECTATORS_ONLY() (autocvar_sv_damagetext >= 1 /* spectators only */)
-#define SV_DAMAGETEXT_PLAYERS()         (autocvar_sv_damagetext >= 2 /* players */)
-#define SV_DAMAGETEXT_ALL()             (autocvar_sv_damagetext >= 3 /* all players */)
-MUTATOR_HOOKFUNCTION(damagetext, PlayerDamaged) {
-    if (SV_DAMAGETEXT_DISABLED()) return;
-    const entity attacker = mutator_argv_entity_0;
-    const entity hit = mutator_argv_entity_1; if (hit == attacker) return;
-    const int health = mutator_argv_int_0;
-    const int armor = mutator_argv_int_1;
-    const int deathtype = mutator_argv_int_2;
-    const vector location = hit.origin;
-    entity e;
-    FOR_EACH_REALCLIENT(e) if (
-        (SV_DAMAGETEXT_ALL()) ||
-        (SV_DAMAGETEXT_PLAYERS() && e == attacker) ||
-        (SV_DAMAGETEXT_SPECTATORS_ONLY() && IS_SPEC(e) && e.enemy == attacker) ||
-        (SV_DAMAGETEXT_SPECTATORS_ONLY() && IS_OBSERVER(e))
-    ) {
-        msg_entity = e;
-        WriteHeader(MSG_ONE, damagetext);
-        WriteShort(MSG_ONE, health);
-        WriteShort(MSG_ONE, armor);
-        WriteEntity(MSG_ONE, hit);
-        WriteCoord(MSG_ONE, location.x);
-        WriteCoord(MSG_ONE, location.y);
-        WriteCoord(MSG_ONE, location.z);
-        WriteInt24_t(MSG_ONE, deathtype);
-    }
-}
-#endif
-
-#ifdef CSQC
-NET_HANDLE(damagetext, bool isNew)
-{
-    int health = ReadShort();
-    int armor = ReadShort();
-    int group = ReadShort();
-    vector location = vec3(ReadCoord(), ReadCoord(), ReadCoord());
-    int deathtype = ReadInt24_t();
-    return = true;
-    if (autocvar_cl_damagetext) {
-        if (autocvar_cl_damagetext_accumulate_range) {
-            for (entity e = findradius(location, autocvar_cl_damagetext_accumulate_range); e; e = e.chain) {
-                if (e.instanceOfDamageText && e.m_group == group) {
-                    DamageText_update(e, location, e.m_damage + health, e.m_armordamage + armor, deathtype);
-                    return;
-                }
-            }
-        }
-        NEW(DamageText, group, location, health, armor, deathtype);
-    }
-}
-#endif
-
-#ifdef MENUQC
-CLASS(XonoticDamageTextSettings, XonoticTab)
-    #include "../../../menu/gamesettings.qh"
-    REGISTER_SETTINGS(damagetext, NEW(XonoticDamageTextSettings));
-    ATTRIB(XonoticDamageTextSettings, title, string, _("Damage text"))
-    ATTRIB(XonoticDamageTextSettings, intendedWidth, float, 0.9)
-    ATTRIB(XonoticDamageTextSettings, rows, float, 13)
-    ATTRIB(XonoticDamageTextSettings, columns, float, 5)
-    INIT(XonoticDamageTextSettings) { this.configureDialog(this); }
-    METHOD(XonoticDamageTextSettings, showNotify, void(entity this)) { loadAllCvars(this); }
-    METHOD(XonoticDamageTextSettings, fill, void(entity this))
-    {
-        this.gotoRC(this, 0, 1); this.setFirstColumn(this, this.currentColumn);
-            this.TD(this, 1, 3, makeXonoticCheckBox(0, "cl_damagetext", _("Draw damage numbers")));
-        this.TR(this);
-            this.TD(this, 1, 1, makeXonoticTextLabel(0, _("Font size:")));
-            this.TD(this, 1, 2, makeXonoticSlider(0, 50, 1, "cl_damagetext_size"));
-        this.TR(this);
-            this.TD(this, 1, 1, makeXonoticTextLabel(0, _("Accumulate range:")));
-            this.TD(this, 1, 2, makeXonoticSlider(0, 500, 1, "cl_damagetext_accumulate_range"));
-        this.TR(this);
-            this.TD(this, 1, 1, makeXonoticTextLabel(0, _("Lifetime:")));
-            this.TD(this, 1, 2, makeXonoticSlider(0, 10, 1, "cl_damagetext_alpha_lifetime"));
-        this.TR(this);
-            this.TD(this, 1, 1, makeXonoticTextLabel(0, _("Color:")));
-            this.TD(this, 2, 2, makeXonoticColorpickerString("cl_damagetext_color", "cl_damagetext_color"));
-    }
-ENDCLASS(XonoticDamageTextSettings)
-#endif
-#endif
diff --git a/qcsrc/common/mutators/mutator/damagetext/damagetext.qc b/qcsrc/common/mutators/mutator/damagetext/damagetext.qc
new file mode 100644 (file)
index 0000000..923ca3b
--- /dev/null
@@ -0,0 +1,163 @@
+#ifndef MUTATOR_DAMAGETEXT_H
+#define MUTATOR_DAMAGETEXT_H
+
+#ifdef MENUQC
+#include "../../../../menu/xonotic/tab.qc"
+#endif
+
+#endif
+
+#ifdef IMPLEMENTATION
+REGISTER_MUTATOR(damagetext, true);
+
+#if defined(CSQC) || defined(MENUQC)
+AUTOCVAR_SAVE(cl_damagetext,                    bool,   false,      _("Draw damage dealt. 0: disabled, 1: enabled"));
+AUTOCVAR_SAVE(cl_damagetext_format,             string, "-%3$d",    _("How to format the damage text. 1$ is health, 2$ is armor, 3$ is both"));
+AUTOCVAR_SAVE(cl_damagetext_color,              vector, '1 1 0',    _("Default damage text color"));
+AUTOCVAR_SAVE(cl_damagetext_color_per_weapon,   bool,   false,      _("Damage text uses weapon color"));
+AUTOCVAR_SAVE(cl_damagetext_size,               float,  8,          _("Damage text font size"));
+AUTOCVAR_SAVE(cl_damagetext_alpha_start,        float,  1,          _("Damage text initial alpha"));
+AUTOCVAR_SAVE(cl_damagetext_alpha_lifetime,     float,  3,          _("Damage text lifetime in seconds"));
+AUTOCVAR_SAVE(cl_damagetext_velocity,           vector, '0 0 20',   _("Damage text move direction"));
+AUTOCVAR_SAVE(cl_damagetext_offset,             vector, '0 -40 0',  _("Damage text offset"));
+AUTOCVAR_SAVE(cl_damagetext_accumulate_range,   float,  30,         _("Damage text spawned within this range is accumulated"));
+#endif
+
+#ifdef CSQC
+CLASS(DamageText, Object)
+    ATTRIB(DamageText, m_color, vector, autocvar_cl_damagetext_color)
+    ATTRIB(DamageText, m_size, float, autocvar_cl_damagetext_size)
+    ATTRIB(DamageText, alpha, float, autocvar_cl_damagetext_alpha_start)
+    ATTRIB(DamageText, fade_rate, float, 1 / autocvar_cl_damagetext_alpha_lifetime)
+    ATTRIB(DamageText, velocity, vector, autocvar_cl_damagetext_velocity)
+    ATTRIB(DamageText, m_group, int, 0)
+    ATTRIB(DamageText, m_damage, int, 0)
+    ATTRIB(DamageText, m_armordamage, int, 0)
+    ATTRIB(DamageText, m_deathtype, int, 0)
+    ATTRIB(DamageText, time_prev, float, time)
+
+    void DamageText_draw2d(DamageText this) {
+        float dt = time - this.time_prev;
+        this.time_prev = time;
+        setorigin(this, this.origin + dt * this.velocity);
+        this.alpha -= dt * this.fade_rate;
+        if (this.alpha < 0) remove(this);
+        vector pos = project_3d_to_2d(this.origin) + autocvar_cl_damagetext_offset;
+        if (pos.z >= 0 && this.m_size > 0) {
+            pos.z = 0;
+            vector rgb = this.m_color;
+            if (autocvar_cl_damagetext_color_per_weapon) {
+                Weapon w = DEATH_WEAPONOF(this.m_deathtype);
+                if (w != WEP_Null) rgb = w.wpcolor;
+            }
+            string s = sprintf(autocvar_cl_damagetext_format, this.m_damage, this.m_armordamage, this.m_damage + this.m_armordamage);
+            drawcolorcodedstring2(pos, s, this.m_size * '1 1 0', rgb, this.alpha, DRAWFLAG_NORMAL);
+        }
+    }
+    ATTRIB(DamageText, draw2d, void(DamageText), DamageText_draw2d)
+
+    void DamageText_update(DamageText this, vector _origin, int _health, int _armor, int _deathtype) {
+        this.m_damage = _health;
+        this.m_armordamage = _armor;
+        this.m_deathtype = _deathtype;
+        setorigin(this, _origin);
+        this.alpha = 1;
+    }
+
+    CONSTRUCTOR(DamageText, int _group, vector _origin, int _health, int _armor, int _deathtype) {
+        CONSTRUCT(DamageText);
+        this.m_group = _group;
+        DamageText_update(this, _origin, _health, _armor, _deathtype);
+    }
+ENDCLASS(DamageText)
+#endif
+
+REGISTER_NET_TEMP(damagetext)
+
+#ifdef SVQC
+AUTOCVAR(sv_damagetext, int, 2, _("<= 0: disabled, >= 1: spectators, >= 2: players, >= 3: all players"));
+#define SV_DAMAGETEXT_DISABLED()        (autocvar_sv_damagetext <= 0 /* disabled */)
+#define SV_DAMAGETEXT_SPECTATORS_ONLY() (autocvar_sv_damagetext >= 1 /* spectators only */)
+#define SV_DAMAGETEXT_PLAYERS()         (autocvar_sv_damagetext >= 2 /* players */)
+#define SV_DAMAGETEXT_ALL()             (autocvar_sv_damagetext >= 3 /* all players */)
+MUTATOR_HOOKFUNCTION(damagetext, PlayerDamaged) {
+    if (SV_DAMAGETEXT_DISABLED()) return;
+    const entity attacker = MUTATOR_ARGV(0, entity);
+    const entity hit = MUTATOR_ARGV(1, entity); if (hit == attacker) return;
+    const int health = MUTATOR_ARGV(0, int);
+    const int armor = MUTATOR_ARGV(1, int);
+    const int deathtype = MUTATOR_ARGV(2, int);
+    const vector location = hit.origin;
+    entity e;
+    FOR_EACH_REALCLIENT(e) if (
+        (SV_DAMAGETEXT_ALL()) ||
+        (SV_DAMAGETEXT_PLAYERS() && e == attacker) ||
+        (SV_DAMAGETEXT_SPECTATORS_ONLY() && IS_SPEC(e) && e.enemy == attacker) ||
+        (SV_DAMAGETEXT_SPECTATORS_ONLY() && IS_OBSERVER(e))
+    ) {
+        msg_entity = e;
+        WriteHeader(MSG_ONE, damagetext);
+        WriteShort(MSG_ONE, health);
+        WriteShort(MSG_ONE, armor);
+        WriteEntity(MSG_ONE, hit);
+        WriteCoord(MSG_ONE, location.x);
+        WriteCoord(MSG_ONE, location.y);
+        WriteCoord(MSG_ONE, location.z);
+        WriteInt24_t(MSG_ONE, deathtype);
+    }
+}
+#endif
+
+#ifdef CSQC
+NET_HANDLE(damagetext, bool isNew)
+{
+    int health = ReadShort();
+    int armor = ReadShort();
+    int group = ReadShort();
+    vector location = vec3(ReadCoord(), ReadCoord(), ReadCoord());
+    int deathtype = ReadInt24_t();
+    return = true;
+    if (autocvar_cl_damagetext) {
+        if (autocvar_cl_damagetext_accumulate_range) {
+            for (entity e = findradius(location, autocvar_cl_damagetext_accumulate_range); e; e = e.chain) {
+                if (e.instanceOfDamageText && e.m_group == group) {
+                    DamageText_update(e, location, e.m_damage + health, e.m_armordamage + armor, deathtype);
+                    return;
+                }
+            }
+        }
+        NEW(DamageText, group, location, health, armor, deathtype);
+    }
+}
+#endif
+
+#ifdef MENUQC
+CLASS(XonoticDamageTextSettings, XonoticTab)
+    #include "../../../../menu/gamesettings.qh"
+    REGISTER_SETTINGS(damagetext, NEW(XonoticDamageTextSettings));
+    ATTRIB(XonoticDamageTextSettings, title, string, _("Damage text"))
+    ATTRIB(XonoticDamageTextSettings, intendedWidth, float, 0.9)
+    ATTRIB(XonoticDamageTextSettings, rows, float, 13)
+    ATTRIB(XonoticDamageTextSettings, columns, float, 5)
+    INIT(XonoticDamageTextSettings) { this.configureDialog(this); }
+    METHOD(XonoticDamageTextSettings, showNotify, void(entity this)) { loadAllCvars(this); }
+    METHOD(XonoticDamageTextSettings, fill, void(entity this))
+    {
+        this.gotoRC(this, 0, 1); this.setFirstColumn(this, this.currentColumn);
+            this.TD(this, 1, 3, makeXonoticCheckBox(0, "cl_damagetext", _("Draw damage numbers")));
+        this.TR(this);
+            this.TD(this, 1, 1, makeXonoticTextLabel(0, _("Font size:")));
+            this.TD(this, 1, 2, makeXonoticSlider(0, 50, 1, "cl_damagetext_size"));
+        this.TR(this);
+            this.TD(this, 1, 1, makeXonoticTextLabel(0, _("Accumulate range:")));
+            this.TD(this, 1, 2, makeXonoticSlider(0, 500, 1, "cl_damagetext_accumulate_range"));
+        this.TR(this);
+            this.TD(this, 1, 1, makeXonoticTextLabel(0, _("Lifetime:")));
+            this.TD(this, 1, 2, makeXonoticSlider(0, 10, 1, "cl_damagetext_alpha_lifetime"));
+        this.TR(this);
+            this.TD(this, 1, 1, makeXonoticTextLabel(0, _("Color:")));
+            this.TD(this, 2, 2, makeXonoticColorpickerString("cl_damagetext_color", "cl_damagetext_color"));
+    }
+ENDCLASS(XonoticDamageTextSettings)
+#endif
+#endif
diff --git a/qcsrc/common/mutators/mutator/damagetext/module.inc b/qcsrc/common/mutators/mutator/damagetext/module.inc
new file mode 100644 (file)
index 0000000..8e70be7
--- /dev/null
@@ -0,0 +1 @@
+#include "damagetext.qc"
index 391302be07d693c421e37e2b90b1553ddf65cef7..16b5b86d1a565ba14a10f5fc950b76d7093b9159 100644 (file)
@@ -8,6 +8,10 @@
 #ifdef IMPLEMENTATION
 #ifdef SVQC
 
+int autocvar_g_instagib_ammo_drop;
+int autocvar_g_instagib_extralives;
+float autocvar_g_instagib_speed_highspeed;
+
 #include "../../../../server/cl_client.qh"
 #include "../../../buffs/all.qh"
 
diff --git a/qcsrc/common/mutators/mutator/instagib/module.inc b/qcsrc/common/mutators/mutator/instagib/module.inc
new file mode 100644 (file)
index 0000000..7270067
--- /dev/null
@@ -0,0 +1 @@
+#include "instagib.qc"
diff --git a/qcsrc/common/mutators/mutator/overkill/hmg.qc b/qcsrc/common/mutators/mutator/overkill/hmg.qc
new file mode 100644 (file)
index 0000000..7f2341f
--- /dev/null
@@ -0,0 +1,178 @@
+#ifndef IMPLEMENTATION
+CLASS(HeavyMachineGun, Weapon)
+/* ammotype  */ ATTRIB(HeavyMachineGun, ammo_field, .int, ammo_nails)
+/* impulse   */ ATTRIB(HeavyMachineGun, impulse, int, 3)
+/* flags     */ ATTRIB(HeavyMachineGun, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_HIDDEN | WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN | WEP_FLAG_SUPERWEAPON);
+/* rating    */ ATTRIB(HeavyMachineGun, bot_pickupbasevalue, float, BOT_PICKUP_RATING_HIGH);
+/* color     */ ATTRIB(HeavyMachineGun, wpcolor, vector, '0.5 0.5 0');
+/* modelname */ ATTRIB(HeavyMachineGun, mdl, string, "ok_hmg");
+#ifndef MENUQC
+/* model     */ ATTRIB(HeavyMachineGun, m_model, Model, MDL_HMG_ITEM);
+#endif
+/* crosshair */ ATTRIB(HeavyMachineGun, w_crosshair, string, "gfx/crosshairuzi");
+/* crosshair */ ATTRIB(HeavyMachineGun, w_crosshair_size, float, 0.6);
+/* wepimg    */ ATTRIB(HeavyMachineGun, model2, string, "weaponhmg");
+/* refname   */ ATTRIB(HeavyMachineGun, netname, string, "hmg");
+/* wepname   */ ATTRIB(HeavyMachineGun, m_name, string, _("Heavy Machine Gun"));
+ENDCLASS(HeavyMachineGun)
+REGISTER_WEAPON(HMG, NEW(HeavyMachineGun));
+
+#define HMG_SETTINGS(w_cvar,w_prop) HMG_SETTINGS_LIST(w_cvar, w_prop, HMG, hmg)
+#define HMG_SETTINGS_LIST(w_cvar,w_prop,id,sn) \
+       w_cvar(id, sn, NONE, spread_min) \
+       w_cvar(id, sn, NONE, spread_max) \
+       w_cvar(id, sn, NONE, spread_add) \
+       w_cvar(id, sn, NONE, solidpenetration) \
+       w_cvar(id, sn, NONE, damage) \
+       w_cvar(id, sn, NONE, force) \
+       w_cvar(id, sn, NONE, refire) \
+       w_cvar(id, sn, NONE, ammo) \
+       w_prop(id, sn, float,  reloading_ammo, reload_ammo) \
+       w_prop(id, sn, float,  reloading_time, reload_time) \
+       w_prop(id, sn, float,  switchdelay_raise, switchdelay_raise) \
+       w_prop(id, sn, float,  switchdelay_drop, switchdelay_drop) \
+       w_prop(id, sn, string, weaponreplace, weaponreplace) \
+       w_prop(id, sn, float,  weaponstart, weaponstart) \
+       w_prop(id, sn, float,  weaponstartoverride, weaponstartoverride) \
+       w_prop(id, sn, float,  weaponthrowable, weaponthrowable)
+
+#ifdef SVQC
+HMG_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
+#endif
+#endif
+#ifdef IMPLEMENTATION
+#ifdef SVQC
+
+REGISTER_MUTATOR(hmg_nadesupport, true);
+MUTATOR_HOOKFUNCTION(hmg_nadesupport, Nade_Damage)
+{
+       if (MUTATOR_ARGV(0, entity) != WEP_HMG) return;
+       return = true;
+       MUTATOR_ARGV(0, float) /* damage */ = self.max_health * 0.1;
+}
+
+spawnfunc(weapon_hmg) { weapon_defaultspawnfunc(this, WEP_HMG); }
+
+void W_HeavyMachineGun_Attack_Auto(Weapon thiswep, entity actor, .entity weaponentity, int fire)
+{
+       if (!actor.BUTTON_ATCK)
+       {
+               w_ready(thiswep, actor, weaponentity, fire);
+               return;
+       }
+
+       Weapon w = get_weaponinfo(actor.weapon);
+       if(!w.wr_checkammo1(w))
+       if(!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
+       {
+               W_SwitchWeapon_Force(actor, w_getbestweapon(actor));
+               w_ready(thiswep, actor, weaponentity, fire);
+               return;
+       }
+
+       W_DecreaseAmmo(WEP_HMG, self, WEP_CVAR(hmg, ammo));
+
+       W_SetupShot (actor, true, 0, SND(UZI_FIRE), CH_WEAPON_A, WEP_CVAR(hmg, damage));
+
+       if(!autocvar_g_norecoil)
+       {
+               actor.punchangle_x = random () - 0.5;
+               actor.punchangle_y = random () - 0.5;
+       }
+
+       float hmg_spread = bound(WEP_CVAR(hmg, spread_min), WEP_CVAR(hmg, spread_min) + (WEP_CVAR(hmg, spread_add) * actor.misc_bulletcounter), WEP_CVAR(hmg, spread_max));
+       fireBullet(w_shotorg, w_shotdir, hmg_spread, WEP_CVAR(hmg, solidpenetration), WEP_CVAR(hmg, damage), WEP_CVAR(hmg, force), WEP_HMG.m_id, 0);
+
+       actor.misc_bulletcounter = actor.misc_bulletcounter + 1;
+
+       Send_Effect(EFFECT_MACHINEGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
+
+       W_MachineGun_MuzzleFlash();
+       W_AttachToShotorg(actor, actor.muzzle_flash, '5 0 0');
+
+       if (autocvar_g_casings >= 2) // casing code
+               SpawnCasing (((random () * 50 + 50) * v_right) - (v_forward * (random () * 25 + 25)) - ((random () * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, actor);
+
+       int slot = weaponslot(weaponentity);
+       ATTACK_FINISHED(actor, slot) = time + WEP_CVAR(hmg, refire) * W_WeaponRateFactor();
+       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(hmg, refire), W_HeavyMachineGun_Attack_Auto);
+}
+
+               METHOD(HeavyMachineGun, wr_aim, void(entity thiswep))
+               {
+                       if(vlen(self.origin-self.enemy.origin) < 3000 - bound(0, skill, 10) * 200)
+                               self.BUTTON_ATCK = bot_aim(1000000, 0, 0.001, false);
+                       else
+                               self.BUTTON_ATCK2 = bot_aim(1000000, 0, 0.001, false);
+               }
+               METHOD(HeavyMachineGun, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
+               {
+                       if(WEP_CVAR(hmg, reload_ammo) && actor.clip_load < WEP_CVAR(hmg, ammo)) { // forced reload
+                               Weapon w = get_weaponinfo(actor.weapon);
+                               w.wr_reload(w);
+                       } else
+                       {
+                               if (fire & 1)
+                               if (weapon_prepareattack(thiswep, actor, weaponentity, false, 0))
+                               {
+                                       actor.misc_bulletcounter = 0;
+                                       W_HeavyMachineGun_Attack_Auto(thiswep, actor, weaponentity, fire);
+                               }
+                       }
+               }
+               METHOD(HeavyMachineGun, wr_init, void(entity thiswep))
+               {
+                       HMG_SETTINGS(WEP_SKIP_CVAR, WEP_SET_PROP);
+               }
+               METHOD(HeavyMachineGun, wr_checkammo1, bool(entity thiswep))
+               {
+                       float ammo_amount = self.ammo_nails >= WEP_CVAR(hmg, ammo);
+
+                       if(autocvar_g_balance_hmg_reload_ammo)
+                               ammo_amount += self.(weapon_load[WEP_HMG.m_id]) >= WEP_CVAR(hmg, ammo);
+
+                       return ammo_amount;
+               }
+               METHOD(HeavyMachineGun, wr_checkammo2, bool(entity thiswep))
+               {
+                       float ammo_amount = self.ammo_nails >= WEP_CVAR(hmg, ammo);
+
+                       if(autocvar_g_balance_hmg_reload_ammo)
+                               ammo_amount += self.(weapon_load[WEP_HMG.m_id]) >= WEP_CVAR(hmg, ammo);
+
+                       return ammo_amount;
+               }
+               METHOD(HeavyMachineGun, wr_config, void(entity thiswep))
+               {
+                       HMG_SETTINGS(WEP_CONFIG_WRITE_CVARS, WEP_CONFIG_WRITE_PROPS);
+               }
+               METHOD(HeavyMachineGun, wr_reload, void(entity thiswep))
+               {
+                       W_Reload(self, WEP_CVAR(hmg, ammo), SND(RELOAD));
+               }
+               METHOD(HeavyMachineGun, wr_suicidemessage, int(entity thiswep))
+               {
+                       return WEAPON_THINKING_WITH_PORTALS;
+               }
+               METHOD(HeavyMachineGun, wr_killmessage, int(entity thiswep))
+               {
+                       if(w_deathtype & HITTYPE_SECONDARY)
+                               return WEAPON_HMG_MURDER_SNIPE;
+                       else
+                               return WEAPON_HMG_MURDER_SPRAY;
+               }
+
+#endif
+#ifdef CSQC
+
+               METHOD(HeavyMachineGun, wr_impacteffect, void(entity thiswep))
+               {
+                       vector org2;
+                       org2 = w_org + w_backoff * 2;
+                       pointparticles(EFFECT_MACHINEGUN_IMPACT, org2, w_backoff * 1000, 1);
+                       if(!w_issilent)
+                               sound(self, CH_SHOTS, SND_RIC_RANDOM(), VOL_BASE, ATTEN_NORM);
+               }
+
+#endif
+#endif
diff --git a/qcsrc/common/mutators/mutator/overkill/module.inc b/qcsrc/common/mutators/mutator/overkill/module.inc
new file mode 100644 (file)
index 0000000..a8bde27
--- /dev/null
@@ -0,0 +1,6 @@
+#include "hmg.qc"
+#include "rpc.qc"
+
+#ifdef SVQC
+       #include "overkill.qc"
+#endif
diff --git a/qcsrc/common/mutators/mutator/overkill/overkill.qc b/qcsrc/common/mutators/mutator/overkill/overkill.qc
new file mode 100644 (file)
index 0000000..c146f1c
--- /dev/null
@@ -0,0 +1,385 @@
+#ifdef IMPLEMENTATION
+bool autocvar_g_overkill_powerups_replace;
+float autocvar_g_overkill_superguns_respawn_time;
+bool autocvar_g_overkill_100h_anyway;
+bool autocvar_g_overkill_100a_anyway;
+bool autocvar_g_overkill_ammo_charge;
+float autocvar_g_overkill_ammo_charge_notice;
+float autocvar_g_overkill_ammo_charge_limit;
+
+.vector ok_deathloc;
+.float ok_spawnsys_timer;
+.float ok_lastwep;
+.float ok_item;
+
+.float ok_notice_time;
+.float ammo_charge[Weapons_MAX];
+.float ok_use_ammocharge;
+.float ok_ammo_charge;
+
+.float ok_pauseregen_finished;
+
+void(entity ent, float wep) ok_DecreaseCharge;
+
+void ok_Initialize();
+
+REGISTER_MUTATOR(ok, cvar("g_overkill") && !cvar("g_instagib") && !g_nexball && cvar_string("g_mod_balance") == "Overkill")
+{
+       MUTATOR_ONADD
+       {
+               ok_Initialize();
+       }
+
+       MUTATOR_ONREMOVE
+       {
+               WEP_RPC.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
+               WEP_HMG.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
+       }
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ok, W_DecreaseAmmo)
+{
+       entity actor = MUTATOR_ARGV(0, entity);
+       if (actor.ok_use_ammocharge)
+       {
+               ok_DecreaseCharge(actor, actor.weapon);
+               return true;
+       }
+}
+
+MUTATOR_HOOKFUNCTION(ok, W_Reload)
+{
+       entity actor = MUTATOR_ARGV(0, entity);
+       return actor.ok_use_ammocharge;
+}
+
+void W_Blaster_Attack(entity, float, float, float, float, float, float, float, float, float, float);
+spawnfunc(weapon_hmg);
+spawnfunc(weapon_rpc);
+
+void ok_DecreaseCharge(entity ent, int wep)
+{
+       if(!ent.ok_use_ammocharge) return;
+
+       entity wepent = get_weaponinfo(wep);
+
+       if(wepent.weapon == 0)
+               return; // dummy
+
+       ent.ammo_charge[wep] -= max(0, cvar(sprintf("g_overkill_ammo_decharge_%s", wepent.netname)));
+}
+
+void ok_IncreaseCharge(entity ent, int wep)
+{
+       entity wepent = get_weaponinfo(wep);
+
+       if(wepent.weapon == 0)
+               return; // dummy
+
+       if(ent.ok_use_ammocharge)
+       if(!ent.BUTTON_ATCK) // not while attacking?
+               ent.ammo_charge[wep] = min(autocvar_g_overkill_ammo_charge_limit, ent.ammo_charge[wep] + cvar(sprintf("g_overkill_ammo_charge_rate_%s", wepent.netname)) * frametime / W_TICSPERFRAME);
+}
+
+float ok_CheckWeaponCharge(entity ent, int wep)
+{
+       if(!ent.ok_use_ammocharge) return true;
+
+       entity wepent = get_weaponinfo(wep);
+
+       if(wepent.weapon == 0)
+               return 0; // dummy
+
+       return (ent.ammo_charge[wep] >= cvar(sprintf("g_overkill_ammo_decharge_%s", wepent.netname)));
+}
+
+MUTATOR_HOOKFUNCTION(ok, PlayerDamage_Calculate, CBC_ORDER_LAST)
+{
+       if(IS_PLAYER(frag_attacker) && IS_PLAYER(frag_target))
+       if(DEATH_ISWEAPON(frag_deathtype, WEP_BLASTER))
+       {
+               frag_damage = 0;
+
+               if(frag_attacker != frag_target)
+               if(frag_target.health > 0)
+               if(frag_target.frozen == 0)
+               if(frag_target.deadflag == DEAD_NO)
+               {
+                       Send_Notification(NOTIF_ONE, frag_attacker, MSG_CENTER, CENTER_SECONDARY_NODAMAGE);
+                       frag_force = '0 0 0';
+               }
+       }
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ok, PlayerDamage_SplitHealthArmor)
+{SELFPARAM();
+       if(damage_take)
+               self.ok_pauseregen_finished = max(self.ok_pauseregen_finished, time + 2);
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ok, PlayerDies)
+{SELFPARAM();
+       entity targ = ((frag_attacker) ? frag_attacker : frag_target);
+
+       if(IS_MONSTER(self))
+       {
+               remove(other); // remove default item
+               other = world;
+       }
+
+       setself(new(droppedweapon)); // hax
+       self.ok_item = true;
+       self.noalign = true;
+       self.pickup_anyway = true;
+       spawnfunc_item_armor_small(this);
+       self.movetype = MOVETYPE_TOSS;
+       self.gravity = 1;
+       self.reset = SUB_Remove;
+       setorigin(self, frag_target.origin + '0 0 32');
+       self.velocity = '0 0 200' + normalize(targ.origin - self.origin) * 500;
+       SUB_SetFade(self, time + 5, 1);
+       setself(this);
+
+       self.ok_lastwep = self.switchweapon;
+
+       return false;
+}
+MUTATOR_HOOKFUNCTION(ok, MonsterDropItem) { ok_PlayerDies(); }
+
+MUTATOR_HOOKFUNCTION(ok, PlayerRegen)
+{SELFPARAM();
+       // overkill's values are different, so use custom regen
+       if(!self.frozen)
+       {
+               self.armorvalue = CalcRotRegen(self.armorvalue, autocvar_g_balance_armor_regenstable, autocvar_g_balance_armor_regen, autocvar_g_balance_armor_regenlinear, 1 * frametime * (time > self.ok_pauseregen_finished), 0, 0, 1, 1 * frametime * (time > self.pauserotarmor_finished), autocvar_g_balance_armor_limit);
+               self.health = CalcRotRegen(self.health, autocvar_g_balance_health_regenstable, 0, 100, 1 * frametime * (time > self.ok_pauseregen_finished), 200, 0, autocvar_g_balance_health_rotlinear, 1 * frametime * (time > self.pauserothealth_finished), autocvar_g_balance_health_limit);
+
+               float minf, maxf, limitf;
+
+               maxf = autocvar_g_balance_fuel_rotstable;
+               minf = autocvar_g_balance_fuel_regenstable;
+               limitf = autocvar_g_balance_fuel_limit;
+
+               self.ammo_fuel = CalcRotRegen(self.ammo_fuel, minf, autocvar_g_balance_fuel_regen, autocvar_g_balance_fuel_regenlinear, frametime * (time > self.pauseregen_finished) * ((self.items & ITEM_JetpackRegen.m_itemid) != 0), maxf, autocvar_g_balance_fuel_rot, autocvar_g_balance_fuel_rotlinear, frametime * (time > self.pauserotfuel_finished), limitf);
+       }
+       return true; // return true anyway, as frozen uses no regen
+}
+
+MUTATOR_HOOKFUNCTION(ok, ForbidThrowCurrentWeapon)
+{
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(ok, PlayerPreThink)
+{SELFPARAM();
+       if(intermission_running || gameover)
+               return false;
+
+       if(self.deadflag != DEAD_NO || !IS_PLAYER(self) || self.frozen)
+               return false;
+
+       if(self.ok_lastwep)
+       {
+               self.switchweapon = self.ok_lastwep;
+               self.ok_lastwep = 0;
+       }
+
+       ok_IncreaseCharge(self, self.weapon);
+
+       if(self.BUTTON_ATCK2)
+       if(!forbidWeaponUse(self) || self.weapon_blocked) // allow if weapon is blocked
+       if(time >= self.jump_interval)
+       {
+               self.jump_interval = time + WEP_CVAR_PRI(blaster, refire) * W_WeaponRateFactor();
+               makevectors(self.v_angle);
+
+               int oldwep = self.weapon;
+               self.weapon = WEP_BLASTER.m_id;
+               W_Blaster_Attack(
+                       self,
+                       WEP_BLASTER.m_id | HITTYPE_SECONDARY,
+                       WEP_CVAR_SEC(vaporizer, shotangle),
+                       WEP_CVAR_SEC(vaporizer, damage),
+                       WEP_CVAR_SEC(vaporizer, edgedamage),
+                       WEP_CVAR_SEC(vaporizer, radius),
+                       WEP_CVAR_SEC(vaporizer, force),
+                       WEP_CVAR_SEC(vaporizer, speed),
+                       WEP_CVAR_SEC(vaporizer, spread),
+                       WEP_CVAR_SEC(vaporizer, delay),
+                       WEP_CVAR_SEC(vaporizer, lifetime)
+               );
+               self.weapon = oldwep;
+       }
+
+       self.weapon_blocked = false;
+
+       self.ok_ammo_charge = self.ammo_charge[self.weapon];
+
+       if(self.ok_use_ammocharge)
+       if(!ok_CheckWeaponCharge(self, self.weapon))
+       {
+               if(autocvar_g_overkill_ammo_charge_notice && time > self.ok_notice_time && self.BUTTON_ATCK && IS_REAL_CLIENT(self) && self.weapon == self.switchweapon)
+               {
+                       //Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_OVERKILL_CHARGE);
+                       self.ok_notice_time = time + 2;
+                       play2(self, SND(DRYFIRE));
+               }
+               Weapon wpn = get_weaponinfo(self.weapon);
+               .entity weaponentity = weaponentities[0]; // TODO: unhardcode
+               if(self.(weaponentity).state != WS_CLEAR)
+                       w_ready(wpn, self, weaponentity, (self.BUTTON_ATCK ? 1 : 0) | (self.BUTTON_ATCK2 ? 2 : 0));
+
+               self.weapon_blocked = true;
+       }
+
+       self.BUTTON_ATCK2 = 0;
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ok, PlayerSpawn)
+{SELFPARAM();
+       if(autocvar_g_overkill_ammo_charge)
+       {
+               for(int i = WEP_FIRST; i <= WEP_LAST; ++i)
+                       self.ammo_charge[i] = autocvar_g_overkill_ammo_charge_limit;
+
+               self.ok_use_ammocharge = 1;
+               self.ok_notice_time = time;
+       }
+       else
+               self.ok_use_ammocharge = 0;
+
+       self.ok_pauseregen_finished = time + 2;
+
+       return false;
+}
+
+void _spawnfunc_weapon_hmg() { SELFPARAM(); spawnfunc_weapon_hmg(this); }
+void _spawnfunc_weapon_rpc() { SELFPARAM(); spawnfunc_weapon_rpc(this); }
+
+MUTATOR_HOOKFUNCTION(ok, OnEntityPreSpawn)
+{SELFPARAM();
+       if(autocvar_g_powerups)
+       if(autocvar_g_overkill_powerups_replace)
+       {
+               if(self.classname == "item_strength")
+               {
+                       entity wep = new(weapon_hmg);
+                       setorigin(wep, self.origin);
+                       setmodel(wep, MDL_OK_HMG);
+                       wep.ok_item = true;
+                       wep.noalign = self.noalign;
+                       wep.cnt = self.cnt;
+                       wep.team = self.team;
+                       wep.respawntime = autocvar_g_overkill_superguns_respawn_time;
+                       wep.pickup_anyway = true;
+                       wep.think = _spawnfunc_weapon_hmg;
+                       wep.nextthink = time + 0.1;
+                       return true;
+               }
+
+               if(self.classname == "item_invincible")
+               {
+                       entity wep = new(weapon_rpc);
+                       setorigin(wep, self.origin);
+                       setmodel(wep, MDL_OK_RPC);
+                       wep.ok_item = true;
+                       wep.noalign = self.noalign;
+                       wep.cnt = self.cnt;
+                       wep.team = self.team;
+                       wep.respawntime = autocvar_g_overkill_superguns_respawn_time;
+                       wep.pickup_anyway = true;
+                       wep.think = _spawnfunc_weapon_rpc;
+                       wep.nextthink = time + 0.1;
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ok, FilterItem)
+{SELFPARAM();
+       if(self.ok_item)
+               return false;
+
+       switch(self.items)
+       {
+               case ITEM_HealthMega.m_itemid: return !(autocvar_g_overkill_100h_anyway);
+               case ITEM_ArmorMega.m_itemid: return !(autocvar_g_overkill_100a_anyway);
+       }
+
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(ok, SpectateCopy)
+{SELFPARAM();
+       self.ammo_charge[self.weapon] = other.ammo_charge[other.weapon];
+       self.ok_use_ammocharge = other.ok_use_ammocharge;
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ok, SetStartItems)
+{
+       WepSet ok_start_items = (WEPSET(MACHINEGUN) | WEPSET(VORTEX) | WEPSET(SHOTGUN));
+
+       if(WEP_RPC.weaponstart > 0) { ok_start_items |= WEPSET(RPC); }
+       if(WEP_HMG.weaponstart > 0) { ok_start_items |= WEPSET(HMG); }
+
+       start_items |= IT_UNLIMITED_WEAPON_AMMO;
+       start_weapons = warmup_start_weapons = ok_start_items;
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ok, BuildMutatorsString)
+{
+       ret_string = strcat(ret_string, ":OK");
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ok, BuildMutatorsPrettyString)
+{
+       ret_string = strcat(ret_string, ", Overkill");
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ok, SetModname)
+{
+       modname = "Overkill";
+       return true;
+}
+
+void ok_SetCvars()
+{
+       // hack to force overkill playermodels
+       cvar_settemp("sv_defaultcharacter", "1");
+       cvar_settemp("sv_defaultplayermodel", "models/ok_player/okrobot1.dpm models/ok_player/okrobot2.dpm models/ok_player/okrobot3.dpm models/ok_player/okrobot4.dpm models/ok_player/okmale1.dpm models/ok_player/okmale2.dpm models/ok_player/okmale3.dpm models/ok_player/okmale4.dpm");
+       cvar_settemp("sv_defaultplayermodel_red", "models/ok_player/okrobot1.dpm models/ok_player/okrobot2.dpm models/ok_player/okrobot3.dpm models/ok_player/okrobot4.dpm");
+       cvar_settemp("sv_defaultplayermodel_blue", "models/ok_player/okmale1.dpm models/ok_player/okmale2.dpm models/ok_player/okmale3.dpm models/ok_player/okmale4.dpm");
+}
+
+void ok_Initialize()
+{
+       ok_SetCvars();
+
+       precache_all_playermodels("models/ok_player/*.dpm");
+
+       addstat(STAT_OK_AMMO_CHARGE, AS_FLOAT, ok_use_ammocharge);
+       addstat(STAT_OK_AMMO_CHARGEPOOL, AS_FLOAT, ok_ammo_charge);
+
+       WEP_RPC.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
+       WEP_HMG.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
+
+       WEP_SHOTGUN.mdl = "ok_shotgun";
+       WEP_MACHINEGUN.mdl = "ok_mg";
+       WEP_VORTEX.mdl = "ok_sniper";
+}
+#endif
diff --git a/qcsrc/common/mutators/mutator/overkill/rpc.qc b/qcsrc/common/mutators/mutator/overkill/rpc.qc
new file mode 100644 (file)
index 0000000..fa037e0
--- /dev/null
@@ -0,0 +1,231 @@
+#ifndef IMPLEMENTATION
+CLASS(RocketPropelledChainsaw, Weapon)
+/* ammotype  */ ATTRIB(RocketPropelledChainsaw, ammo_field, .int, ammo_rockets)
+/* impulse   */ ATTRIB(RocketPropelledChainsaw, impulse, int, 7)
+/* flags     */ ATTRIB(RocketPropelledChainsaw, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_HIDDEN | WEP_FLAG_NORMAL | WEP_FLAG_CANCLIMB | WEP_FLAG_RELOADABLE | WEP_TYPE_SPLASH | WEP_FLAG_SUPERWEAPON);
+/* rating    */ ATTRIB(RocketPropelledChainsaw, bot_pickupbasevalue, float, BOT_PICKUP_RATING_HIGH);
+/* color     */ ATTRIB(RocketPropelledChainsaw, wpcolor, vector, '0.5 0.5 0');
+/* modelname */ ATTRIB(RocketPropelledChainsaw, mdl, string, "ok_rl");
+#ifndef MENUQC
+/* model     */ ATTRIB(RocketPropelledChainsaw, m_model, Model, MDL_RPC_ITEM);
+#endif
+/* crosshair */ ATTRIB(RocketPropelledChainsaw, w_crosshair, string, "gfx/crosshairrocketlauncher");
+/* crosshair */ ATTRIB(RocketPropelledChainsaw, w_crosshair_size, float, 0.6);
+/* wepimg    */ ATTRIB(RocketPropelledChainsaw, model2, string, "weaponrpc");
+/* refname   */ ATTRIB(RocketPropelledChainsaw, netname, string, "rpc");
+/* wepname   */ ATTRIB(RocketPropelledChainsaw, m_name, string, _("Rocket Propelled Chainsaw"));
+ENDCLASS(RocketPropelledChainsaw)
+REGISTER_WEAPON(RPC, NEW(RocketPropelledChainsaw));
+
+#define RPC_SETTINGS(w_cvar,w_prop) RPC_SETTINGS_LIST(w_cvar, w_prop, RPC, rpc)
+#define RPC_SETTINGS_LIST(w_cvar,w_prop,id,sn) \
+       w_cvar(id, sn, NONE, ammo) \
+       w_cvar(id, sn, NONE, animtime) \
+       w_cvar(id, sn, NONE, damage) \
+       w_cvar(id, sn, NONE, damage2) \
+       w_cvar(id, sn, NONE, damageforcescale) \
+       w_cvar(id, sn, NONE, edgedamage) \
+       w_cvar(id, sn, NONE, force) \
+       w_cvar(id, sn, NONE, health) \
+       w_cvar(id, sn, NONE, lifetime) \
+       w_cvar(id, sn, NONE, radius) \
+       w_cvar(id, sn, NONE, refire) \
+       w_cvar(id, sn, NONE, speed) \
+       w_cvar(id, sn, NONE, speedaccel) \
+       w_prop(id, sn, float,  reloading_ammo, reload_ammo) \
+       w_prop(id, sn, float,  reloading_time, reload_time) \
+       w_prop(id, sn, float,  switchdelay_raise, switchdelay_raise) \
+       w_prop(id, sn, float,  switchdelay_drop, switchdelay_drop) \
+       w_prop(id, sn, string, weaponreplace, weaponreplace) \
+       w_prop(id, sn, float,  weaponstart, weaponstart) \
+       w_prop(id, sn, float,  weaponstartoverride, weaponstartoverride) \
+       w_prop(id, sn, float,  weaponthrowable, weaponthrowable)
+
+#ifdef SVQC
+RPC_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
+#endif
+#endif
+#ifdef IMPLEMENTATION
+#ifdef SVQC
+spawnfunc(weapon_rpc) { weapon_defaultspawnfunc(this, WEP_RPC); }
+
+void W_RocketPropelledChainsaw_Explode()
+{SELFPARAM();
+       self.event_damage = func_null;
+       self.takedamage = DAMAGE_NO;
+
+       RadiusDamage (self, self.realowner, WEP_CVAR(rpc, damage), WEP_CVAR(rpc, edgedamage), WEP_CVAR(rpc, radius), world, world, WEP_CVAR(rpc, force), self.projectiledeathtype, other);
+
+       remove (self);
+}
+
+void W_RocketPropelledChainsaw_Touch (void)
+{SELFPARAM();
+       if(WarpZone_Projectile_Touch())
+               if(wasfreed(self))
+                       return;
+
+       W_RocketPropelledChainsaw_Explode();
+}
+
+void W_RocketPropelledChainsaw_Damage (entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+{SELFPARAM();
+       if (self.health <= 0)
+               return;
+
+       if (!W_CheckProjectileDamage(inflictor.realowner, self.realowner, deathtype, -1)) // no exceptions
+               return; // g_projectiles_damage says to halt
+
+       self.health = self.health - damage;
+
+       if (self.health <= 0)
+               W_PrepareExplosionByDamage(attacker, W_RocketPropelledChainsaw_Explode);
+}
+
+void W_RocketPropelledChainsaw_Think()
+{SELFPARAM();
+       if(self.cnt <= time)
+       {
+               remove(self);
+               return;
+       }
+
+       self.cnt = vlen(self.velocity);
+       self.wait = self.cnt * sys_frametime;
+       self.pos1 = normalize(self.velocity);
+
+       tracebox(self.origin, self.mins, self.maxs, self.origin + self.pos1 * (2 * self.wait), MOVE_NORMAL, self);
+       if(IS_PLAYER(trace_ent))
+               Damage (trace_ent, self, self.realowner, WEP_CVAR(rpc, damage2), self.projectiledeathtype, self.origin, normalize(self.origin - other.origin) * WEP_CVAR(rpc, force));
+
+       self.velocity = self.pos1 * (self.cnt + (WEP_CVAR(rpc, speedaccel) * sys_frametime));
+
+       UpdateCSQCProjectile(self);
+       self.nextthink = time;
+}
+
+void W_RocketPropelledChainsaw_Attack (Weapon thiswep)
+{SELFPARAM();
+       entity missile = spawn(); //WarpZone_RefSys_SpawnSameRefSys(self);
+       entity flash = spawn ();
+
+       W_DecreaseAmmo(thiswep, self, WEP_CVAR(rpc, ammo));
+       W_SetupShot_ProjectileSize (self, '-3 -3 -3', '3 3 3', false, 5, SND(ROCKET_FIRE), CH_WEAPON_A, WEP_CVAR(rpc, damage));
+       Send_Effect(EFFECT_ROCKET_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
+       PROJECTILE_MAKETRIGGER(missile);
+
+       missile.owner = missile.realowner = self;
+       missile.bot_dodge = true;
+       missile.bot_dodgerating = WEP_CVAR(rpc, damage) * 2;
+
+       missile.takedamage = DAMAGE_YES;
+       missile.damageforcescale = WEP_CVAR(rpc, damageforcescale);
+       missile.health = WEP_CVAR(rpc, health);
+       missile.event_damage = W_RocketPropelledChainsaw_Damage;
+       missile.damagedbycontents = true;
+       missile.movetype = MOVETYPE_FLY;
+
+       missile.projectiledeathtype = WEP_RPC.m_id;
+       setsize (missile, '-3 -3 -3', '3 3 3'); // give it some size so it can be shot
+
+       setorigin (missile, w_shotorg - v_forward * 3); // move it back so it hits the wall at the right point
+       W_SetupProjVelocity_Basic(missile, WEP_CVAR(rpc, speed), 0);
+
+       missile.touch = W_RocketPropelledChainsaw_Touch;
+
+       missile.think = W_RocketPropelledChainsaw_Think;
+       missile.cnt = time + WEP_CVAR(rpc, lifetime);
+       missile.nextthink = time;
+       missile.flags = FL_PROJECTILE;
+
+       CSQCProjectile(missile, true, PROJECTILE_RPC, false);
+
+       setmodel(flash, MDL_RPC_MUZZLEFLASH); // precision set below
+       SUB_SetFade (flash, time, 0.1);
+       flash.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
+       W_AttachToShotorg(self, flash, '5 0 0');
+       missile.pos1 = missile.velocity;
+
+       MUTATOR_CALLHOOK(EditProjectile, self, missile);
+}
+
+               METHOD(RocketPropelledChainsaw, wr_aim, void(entity thiswep))
+               {
+                       self.BUTTON_ATCK = bot_aim(WEP_CVAR(rpc, speed), 0, WEP_CVAR(rpc, lifetime), false);
+               }
+               METHOD(RocketPropelledChainsaw, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
+               {
+                       if(WEP_CVAR(rpc, reload_ammo) && actor.clip_load < WEP_CVAR(rpc, ammo)) {
+                               Weapon w = get_weaponinfo(actor.weapon);
+                               w.wr_reload(w);
+                       } else
+                       {
+                               if (fire & 1)
+                               {
+                                       if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(rpc, refire)))
+                                       {
+                                               W_RocketPropelledChainsaw_Attack(thiswep);
+                                               weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(rpc, animtime), w_ready);
+                                       }
+                               }
+
+                               if (fire & 2)
+                               {
+                                       // to-do
+                               }
+                       }
+               }
+               METHOD(RocketPropelledChainsaw, wr_init, void(entity thiswep))
+               {
+                       RPC_SETTINGS(WEP_SKIP_CVAR, WEP_SET_PROP);
+               }
+               METHOD(RocketPropelledChainsaw, wr_checkammo1, bool(entity thiswep))
+               {
+                       float ammo_amount = self.WEP_AMMO(RPC) >= WEP_CVAR(rpc, ammo);
+                       ammo_amount += self.(weapon_load[WEP_RPC.m_id]) >= WEP_CVAR(rpc, ammo);
+                       return ammo_amount;
+               }
+               METHOD(RocketPropelledChainsaw, wr_checkammo2, bool(entity thiswep))
+               {
+                       return false;
+               }
+               METHOD(RocketPropelledChainsaw, wr_config, void(entity thiswep))
+               {
+                       RPC_SETTINGS(WEP_CONFIG_WRITE_CVARS, WEP_CONFIG_WRITE_PROPS);
+               }
+               METHOD(RocketPropelledChainsaw, wr_reload, void(entity thiswep))
+               {
+                       W_Reload(self, WEP_CVAR(rpc, ammo), SND(RELOAD));
+               }
+               METHOD(RocketPropelledChainsaw, wr_suicidemessage, int(entity thiswep))
+               {
+                       if((w_deathtype & HITTYPE_BOUNCE) || (w_deathtype & HITTYPE_SPLASH))
+                               return WEAPON_RPC_SUICIDE_SPLASH;
+                       else
+                               return WEAPON_RPC_SUICIDE_DIRECT;
+               }
+               METHOD(RocketPropelledChainsaw, wr_killmessage, int(entity thiswep))
+               {
+                       if(w_deathtype & HITTYPE_SECONDARY)
+                               return WEAPON_BLASTER_MURDER;
+                       else if((w_deathtype & HITTYPE_BOUNCE) || (w_deathtype & HITTYPE_SPLASH))
+                               return WEAPON_RPC_MURDER_SPLASH;
+                       else
+                               return WEAPON_RPC_MURDER_DIRECT;
+               }
+
+#endif
+
+#ifdef CSQC
+
+               METHOD(RocketPropelledChainsaw, wr_impacteffect, void(entity thiswep))
+               {
+                       vector org2;
+                       org2 = w_org + w_backoff * 12;
+                       pointparticles(EFFECT_ROCKET_EXPLODE, org2, '0 0 0', 1);
+                       if(!w_issilent)
+                               sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
+               }
+
+#endif
+#endif
diff --git a/qcsrc/common/mutators/mutator/waypoints/module.inc b/qcsrc/common/mutators/mutator/waypoints/module.inc
new file mode 100644 (file)
index 0000000..50bb5b4
--- /dev/null
@@ -0,0 +1 @@
+#include "waypointsprites.qc"
index fc89a0cd20360dc8f447542253a57c3e886d61d6..99c7225ac1a4402f475e907a820d07b6d97bfc3f 100644 (file)
@@ -25,5 +25,3 @@
 #include "weapon/seeker.qc"
 #include "weapon/shockwave.qc"
 #include "weapon/arc.qc"
-#include "weapon/hmg.qc"
-#include "weapon/rpc.qc"
diff --git a/qcsrc/common/weapons/weapon/hmg.qc b/qcsrc/common/weapons/weapon/hmg.qc
deleted file mode 100644 (file)
index d701870..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-#ifndef IMPLEMENTATION
-CLASS(HeavyMachineGun, Weapon)
-/* ammotype  */ ATTRIB(HeavyMachineGun, ammo_field, .int, ammo_nails)
-/* impulse   */ ATTRIB(HeavyMachineGun, impulse, int, 3)
-/* flags     */ ATTRIB(HeavyMachineGun, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_HIDDEN | WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN | WEP_FLAG_SUPERWEAPON);
-/* rating    */ ATTRIB(HeavyMachineGun, bot_pickupbasevalue, float, BOT_PICKUP_RATING_HIGH);
-/* color     */ ATTRIB(HeavyMachineGun, wpcolor, vector, '0.5 0.5 0');
-/* modelname */ ATTRIB(HeavyMachineGun, mdl, string, "ok_hmg");
-#ifndef MENUQC
-/* model     */ ATTRIB(HeavyMachineGun, m_model, Model, MDL_HMG_ITEM);
-#endif
-/* crosshair */ ATTRIB(HeavyMachineGun, w_crosshair, string, "gfx/crosshairuzi");
-/* crosshair */ ATTRIB(HeavyMachineGun, w_crosshair_size, float, 0.6);
-/* wepimg    */ ATTRIB(HeavyMachineGun, model2, string, "weaponhmg");
-/* refname   */ ATTRIB(HeavyMachineGun, netname, string, "hmg");
-/* wepname   */ ATTRIB(HeavyMachineGun, m_name, string, _("Heavy Machine Gun"));
-ENDCLASS(HeavyMachineGun)
-REGISTER_WEAPON(HMG, NEW(HeavyMachineGun));
-
-#define HMG_SETTINGS(w_cvar,w_prop) HMG_SETTINGS_LIST(w_cvar, w_prop, HMG, hmg)
-#define HMG_SETTINGS_LIST(w_cvar,w_prop,id,sn) \
-       w_cvar(id, sn, NONE, spread_min) \
-       w_cvar(id, sn, NONE, spread_max) \
-       w_cvar(id, sn, NONE, spread_add) \
-       w_cvar(id, sn, NONE, solidpenetration) \
-       w_cvar(id, sn, NONE, damage) \
-       w_cvar(id, sn, NONE, force) \
-       w_cvar(id, sn, NONE, refire) \
-       w_cvar(id, sn, NONE, ammo) \
-       w_prop(id, sn, float,  reloading_ammo, reload_ammo) \
-       w_prop(id, sn, float,  reloading_time, reload_time) \
-       w_prop(id, sn, float,  switchdelay_raise, switchdelay_raise) \
-       w_prop(id, sn, float,  switchdelay_drop, switchdelay_drop) \
-       w_prop(id, sn, string, weaponreplace, weaponreplace) \
-       w_prop(id, sn, float,  weaponstart, weaponstart) \
-       w_prop(id, sn, float,  weaponstartoverride, weaponstartoverride) \
-       w_prop(id, sn, float,  weaponthrowable, weaponthrowable)
-
-#ifdef SVQC
-HMG_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
-#endif
-#endif
-#ifdef IMPLEMENTATION
-#ifdef SVQC
-
-spawnfunc(weapon_hmg) { weapon_defaultspawnfunc(this, WEP_HMG); }
-
-void W_HeavyMachineGun_Attack_Auto(Weapon thiswep, entity actor, .entity weaponentity, int fire)
-{
-       if (!actor.BUTTON_ATCK)
-       {
-               w_ready(thiswep, actor, weaponentity, fire);
-               return;
-       }
-
-       Weapon w = get_weaponinfo(actor.weapon);
-       if(!w.wr_checkammo1(w))
-       if(!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
-       {
-               W_SwitchWeapon_Force(actor, w_getbestweapon(actor));
-               w_ready(thiswep, actor, weaponentity, fire);
-               return;
-       }
-
-       W_DecreaseAmmo(WEP_HMG, self, WEP_CVAR(hmg, ammo));
-
-       W_SetupShot (actor, true, 0, SND(UZI_FIRE), CH_WEAPON_A, WEP_CVAR(hmg, damage));
-
-       if(!autocvar_g_norecoil)
-       {
-               actor.punchangle_x = random () - 0.5;
-               actor.punchangle_y = random () - 0.5;
-       }
-
-       float hmg_spread = bound(WEP_CVAR(hmg, spread_min), WEP_CVAR(hmg, spread_min) + (WEP_CVAR(hmg, spread_add) * actor.misc_bulletcounter), WEP_CVAR(hmg, spread_max));
-       fireBullet(w_shotorg, w_shotdir, hmg_spread, WEP_CVAR(hmg, solidpenetration), WEP_CVAR(hmg, damage), WEP_CVAR(hmg, force), WEP_HMG.m_id, 0);
-
-       actor.misc_bulletcounter = actor.misc_bulletcounter + 1;
-
-       Send_Effect(EFFECT_MACHINEGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
-
-       W_MachineGun_MuzzleFlash();
-       W_AttachToShotorg(actor, actor.muzzle_flash, '5 0 0');
-
-       if (autocvar_g_casings >= 2) // casing code
-               SpawnCasing (((random () * 50 + 50) * v_right) - (v_forward * (random () * 25 + 25)) - ((random () * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, actor);
-
-       int slot = weaponslot(weaponentity);
-       ATTACK_FINISHED(actor, slot) = time + WEP_CVAR(hmg, refire) * W_WeaponRateFactor();
-       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(hmg, refire), W_HeavyMachineGun_Attack_Auto);
-}
-
-               METHOD(HeavyMachineGun, wr_aim, void(entity thiswep))
-               {
-                       if(vlen(self.origin-self.enemy.origin) < 3000 - bound(0, skill, 10) * 200)
-                               self.BUTTON_ATCK = bot_aim(1000000, 0, 0.001, false);
-                       else
-                               self.BUTTON_ATCK2 = bot_aim(1000000, 0, 0.001, false);
-               }
-               METHOD(HeavyMachineGun, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
-               {
-                       if(WEP_CVAR(hmg, reload_ammo) && actor.clip_load < WEP_CVAR(hmg, ammo)) { // forced reload
-                               Weapon w = get_weaponinfo(actor.weapon);
-                               w.wr_reload(w);
-                       } else
-                       {
-                               if (fire & 1)
-                               if (weapon_prepareattack(thiswep, actor, weaponentity, false, 0))
-                               {
-                                       actor.misc_bulletcounter = 0;
-                                       W_HeavyMachineGun_Attack_Auto(thiswep, actor, weaponentity, fire);
-                               }
-                       }
-               }
-               METHOD(HeavyMachineGun, wr_init, void(entity thiswep))
-               {
-                       HMG_SETTINGS(WEP_SKIP_CVAR, WEP_SET_PROP);
-               }
-               METHOD(HeavyMachineGun, wr_checkammo1, bool(entity thiswep))
-               {
-                       float ammo_amount = self.ammo_nails >= WEP_CVAR(hmg, ammo);
-
-                       if(autocvar_g_balance_hmg_reload_ammo)
-                               ammo_amount += self.(weapon_load[WEP_HMG.m_id]) >= WEP_CVAR(hmg, ammo);
-
-                       return ammo_amount;
-               }
-               METHOD(HeavyMachineGun, wr_checkammo2, bool(entity thiswep))
-               {
-                       float ammo_amount = self.ammo_nails >= WEP_CVAR(hmg, ammo);
-
-                       if(autocvar_g_balance_hmg_reload_ammo)
-                               ammo_amount += self.(weapon_load[WEP_HMG.m_id]) >= WEP_CVAR(hmg, ammo);
-
-                       return ammo_amount;
-               }
-               METHOD(HeavyMachineGun, wr_config, void(entity thiswep))
-               {
-                       HMG_SETTINGS(WEP_CONFIG_WRITE_CVARS, WEP_CONFIG_WRITE_PROPS);
-               }
-               METHOD(HeavyMachineGun, wr_reload, void(entity thiswep))
-               {
-                       W_Reload(self, WEP_CVAR(hmg, ammo), SND(RELOAD));
-               }
-               METHOD(HeavyMachineGun, wr_suicidemessage, int(entity thiswep))
-               {
-                       return WEAPON_THINKING_WITH_PORTALS;
-               }
-               METHOD(HeavyMachineGun, wr_killmessage, int(entity thiswep))
-               {
-                       if(w_deathtype & HITTYPE_SECONDARY)
-                               return WEAPON_HMG_MURDER_SNIPE;
-                       else
-                               return WEAPON_HMG_MURDER_SPRAY;
-               }
-
-#endif
-#ifdef CSQC
-
-               METHOD(HeavyMachineGun, wr_impacteffect, void(entity thiswep))
-               {
-                       vector org2;
-                       org2 = w_org + w_backoff * 2;
-                       pointparticles(EFFECT_MACHINEGUN_IMPACT, org2, w_backoff * 1000, 1);
-                       if(!w_issilent)
-                               sound(self, CH_SHOTS, SND_RIC_RANDOM(), VOL_BASE, ATTEN_NORM);
-               }
-
-#endif
-#endif
diff --git a/qcsrc/common/weapons/weapon/rpc.qc b/qcsrc/common/weapons/weapon/rpc.qc
deleted file mode 100644 (file)
index fa037e0..0000000
+++ /dev/null
@@ -1,231 +0,0 @@
-#ifndef IMPLEMENTATION
-CLASS(RocketPropelledChainsaw, Weapon)
-/* ammotype  */ ATTRIB(RocketPropelledChainsaw, ammo_field, .int, ammo_rockets)
-/* impulse   */ ATTRIB(RocketPropelledChainsaw, impulse, int, 7)
-/* flags     */ ATTRIB(RocketPropelledChainsaw, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_HIDDEN | WEP_FLAG_NORMAL | WEP_FLAG_CANCLIMB | WEP_FLAG_RELOADABLE | WEP_TYPE_SPLASH | WEP_FLAG_SUPERWEAPON);
-/* rating    */ ATTRIB(RocketPropelledChainsaw, bot_pickupbasevalue, float, BOT_PICKUP_RATING_HIGH);
-/* color     */ ATTRIB(RocketPropelledChainsaw, wpcolor, vector, '0.5 0.5 0');
-/* modelname */ ATTRIB(RocketPropelledChainsaw, mdl, string, "ok_rl");
-#ifndef MENUQC
-/* model     */ ATTRIB(RocketPropelledChainsaw, m_model, Model, MDL_RPC_ITEM);
-#endif
-/* crosshair */ ATTRIB(RocketPropelledChainsaw, w_crosshair, string, "gfx/crosshairrocketlauncher");
-/* crosshair */ ATTRIB(RocketPropelledChainsaw, w_crosshair_size, float, 0.6);
-/* wepimg    */ ATTRIB(RocketPropelledChainsaw, model2, string, "weaponrpc");
-/* refname   */ ATTRIB(RocketPropelledChainsaw, netname, string, "rpc");
-/* wepname   */ ATTRIB(RocketPropelledChainsaw, m_name, string, _("Rocket Propelled Chainsaw"));
-ENDCLASS(RocketPropelledChainsaw)
-REGISTER_WEAPON(RPC, NEW(RocketPropelledChainsaw));
-
-#define RPC_SETTINGS(w_cvar,w_prop) RPC_SETTINGS_LIST(w_cvar, w_prop, RPC, rpc)
-#define RPC_SETTINGS_LIST(w_cvar,w_prop,id,sn) \
-       w_cvar(id, sn, NONE, ammo) \
-       w_cvar(id, sn, NONE, animtime) \
-       w_cvar(id, sn, NONE, damage) \
-       w_cvar(id, sn, NONE, damage2) \
-       w_cvar(id, sn, NONE, damageforcescale) \
-       w_cvar(id, sn, NONE, edgedamage) \
-       w_cvar(id, sn, NONE, force) \
-       w_cvar(id, sn, NONE, health) \
-       w_cvar(id, sn, NONE, lifetime) \
-       w_cvar(id, sn, NONE, radius) \
-       w_cvar(id, sn, NONE, refire) \
-       w_cvar(id, sn, NONE, speed) \
-       w_cvar(id, sn, NONE, speedaccel) \
-       w_prop(id, sn, float,  reloading_ammo, reload_ammo) \
-       w_prop(id, sn, float,  reloading_time, reload_time) \
-       w_prop(id, sn, float,  switchdelay_raise, switchdelay_raise) \
-       w_prop(id, sn, float,  switchdelay_drop, switchdelay_drop) \
-       w_prop(id, sn, string, weaponreplace, weaponreplace) \
-       w_prop(id, sn, float,  weaponstart, weaponstart) \
-       w_prop(id, sn, float,  weaponstartoverride, weaponstartoverride) \
-       w_prop(id, sn, float,  weaponthrowable, weaponthrowable)
-
-#ifdef SVQC
-RPC_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
-#endif
-#endif
-#ifdef IMPLEMENTATION
-#ifdef SVQC
-spawnfunc(weapon_rpc) { weapon_defaultspawnfunc(this, WEP_RPC); }
-
-void W_RocketPropelledChainsaw_Explode()
-{SELFPARAM();
-       self.event_damage = func_null;
-       self.takedamage = DAMAGE_NO;
-
-       RadiusDamage (self, self.realowner, WEP_CVAR(rpc, damage), WEP_CVAR(rpc, edgedamage), WEP_CVAR(rpc, radius), world, world, WEP_CVAR(rpc, force), self.projectiledeathtype, other);
-
-       remove (self);
-}
-
-void W_RocketPropelledChainsaw_Touch (void)
-{SELFPARAM();
-       if(WarpZone_Projectile_Touch())
-               if(wasfreed(self))
-                       return;
-
-       W_RocketPropelledChainsaw_Explode();
-}
-
-void W_RocketPropelledChainsaw_Damage (entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
-{SELFPARAM();
-       if (self.health <= 0)
-               return;
-
-       if (!W_CheckProjectileDamage(inflictor.realowner, self.realowner, deathtype, -1)) // no exceptions
-               return; // g_projectiles_damage says to halt
-
-       self.health = self.health - damage;
-
-       if (self.health <= 0)
-               W_PrepareExplosionByDamage(attacker, W_RocketPropelledChainsaw_Explode);
-}
-
-void W_RocketPropelledChainsaw_Think()
-{SELFPARAM();
-       if(self.cnt <= time)
-       {
-               remove(self);
-               return;
-       }
-
-       self.cnt = vlen(self.velocity);
-       self.wait = self.cnt * sys_frametime;
-       self.pos1 = normalize(self.velocity);
-
-       tracebox(self.origin, self.mins, self.maxs, self.origin + self.pos1 * (2 * self.wait), MOVE_NORMAL, self);
-       if(IS_PLAYER(trace_ent))
-               Damage (trace_ent, self, self.realowner, WEP_CVAR(rpc, damage2), self.projectiledeathtype, self.origin, normalize(self.origin - other.origin) * WEP_CVAR(rpc, force));
-
-       self.velocity = self.pos1 * (self.cnt + (WEP_CVAR(rpc, speedaccel) * sys_frametime));
-
-       UpdateCSQCProjectile(self);
-       self.nextthink = time;
-}
-
-void W_RocketPropelledChainsaw_Attack (Weapon thiswep)
-{SELFPARAM();
-       entity missile = spawn(); //WarpZone_RefSys_SpawnSameRefSys(self);
-       entity flash = spawn ();
-
-       W_DecreaseAmmo(thiswep, self, WEP_CVAR(rpc, ammo));
-       W_SetupShot_ProjectileSize (self, '-3 -3 -3', '3 3 3', false, 5, SND(ROCKET_FIRE), CH_WEAPON_A, WEP_CVAR(rpc, damage));
-       Send_Effect(EFFECT_ROCKET_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
-       PROJECTILE_MAKETRIGGER(missile);
-
-       missile.owner = missile.realowner = self;
-       missile.bot_dodge = true;
-       missile.bot_dodgerating = WEP_CVAR(rpc, damage) * 2;
-
-       missile.takedamage = DAMAGE_YES;
-       missile.damageforcescale = WEP_CVAR(rpc, damageforcescale);
-       missile.health = WEP_CVAR(rpc, health);
-       missile.event_damage = W_RocketPropelledChainsaw_Damage;
-       missile.damagedbycontents = true;
-       missile.movetype = MOVETYPE_FLY;
-
-       missile.projectiledeathtype = WEP_RPC.m_id;
-       setsize (missile, '-3 -3 -3', '3 3 3'); // give it some size so it can be shot
-
-       setorigin (missile, w_shotorg - v_forward * 3); // move it back so it hits the wall at the right point
-       W_SetupProjVelocity_Basic(missile, WEP_CVAR(rpc, speed), 0);
-
-       missile.touch = W_RocketPropelledChainsaw_Touch;
-
-       missile.think = W_RocketPropelledChainsaw_Think;
-       missile.cnt = time + WEP_CVAR(rpc, lifetime);
-       missile.nextthink = time;
-       missile.flags = FL_PROJECTILE;
-
-       CSQCProjectile(missile, true, PROJECTILE_RPC, false);
-
-       setmodel(flash, MDL_RPC_MUZZLEFLASH); // precision set below
-       SUB_SetFade (flash, time, 0.1);
-       flash.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
-       W_AttachToShotorg(self, flash, '5 0 0');
-       missile.pos1 = missile.velocity;
-
-       MUTATOR_CALLHOOK(EditProjectile, self, missile);
-}
-
-               METHOD(RocketPropelledChainsaw, wr_aim, void(entity thiswep))
-               {
-                       self.BUTTON_ATCK = bot_aim(WEP_CVAR(rpc, speed), 0, WEP_CVAR(rpc, lifetime), false);
-               }
-               METHOD(RocketPropelledChainsaw, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
-               {
-                       if(WEP_CVAR(rpc, reload_ammo) && actor.clip_load < WEP_CVAR(rpc, ammo)) {
-                               Weapon w = get_weaponinfo(actor.weapon);
-                               w.wr_reload(w);
-                       } else
-                       {
-                               if (fire & 1)
-                               {
-                                       if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(rpc, refire)))
-                                       {
-                                               W_RocketPropelledChainsaw_Attack(thiswep);
-                                               weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(rpc, animtime), w_ready);
-                                       }
-                               }
-
-                               if (fire & 2)
-                               {
-                                       // to-do
-                               }
-                       }
-               }
-               METHOD(RocketPropelledChainsaw, wr_init, void(entity thiswep))
-               {
-                       RPC_SETTINGS(WEP_SKIP_CVAR, WEP_SET_PROP);
-               }
-               METHOD(RocketPropelledChainsaw, wr_checkammo1, bool(entity thiswep))
-               {
-                       float ammo_amount = self.WEP_AMMO(RPC) >= WEP_CVAR(rpc, ammo);
-                       ammo_amount += self.(weapon_load[WEP_RPC.m_id]) >= WEP_CVAR(rpc, ammo);
-                       return ammo_amount;
-               }
-               METHOD(RocketPropelledChainsaw, wr_checkammo2, bool(entity thiswep))
-               {
-                       return false;
-               }
-               METHOD(RocketPropelledChainsaw, wr_config, void(entity thiswep))
-               {
-                       RPC_SETTINGS(WEP_CONFIG_WRITE_CVARS, WEP_CONFIG_WRITE_PROPS);
-               }
-               METHOD(RocketPropelledChainsaw, wr_reload, void(entity thiswep))
-               {
-                       W_Reload(self, WEP_CVAR(rpc, ammo), SND(RELOAD));
-               }
-               METHOD(RocketPropelledChainsaw, wr_suicidemessage, int(entity thiswep))
-               {
-                       if((w_deathtype & HITTYPE_BOUNCE) || (w_deathtype & HITTYPE_SPLASH))
-                               return WEAPON_RPC_SUICIDE_SPLASH;
-                       else
-                               return WEAPON_RPC_SUICIDE_DIRECT;
-               }
-               METHOD(RocketPropelledChainsaw, wr_killmessage, int(entity thiswep))
-               {
-                       if(w_deathtype & HITTYPE_SECONDARY)
-                               return WEAPON_BLASTER_MURDER;
-                       else if((w_deathtype & HITTYPE_BOUNCE) || (w_deathtype & HITTYPE_SPLASH))
-                               return WEAPON_RPC_MURDER_SPLASH;
-                       else
-                               return WEAPON_RPC_MURDER_DIRECT;
-               }
-
-#endif
-
-#ifdef CSQC
-
-               METHOD(RocketPropelledChainsaw, wr_impacteffect, void(entity thiswep))
-               {
-                       vector org2;
-                       org2 = w_org + w_backoff * 12;
-                       pointparticles(EFFECT_ROCKET_EXPLODE, org2, '0 0 0', 1);
-                       if(!w_issilent)
-                               sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
-               }
-
-#endif
-#endif
index 16f9898ada8a35d70cf70708e6ea1e397aeccdec..d72617fac90f0087fb2d5eb74d32d7110f47fa04 100644 (file)
@@ -236,9 +236,6 @@ float autocvar_g_maxpushtime;
 float autocvar_g_maxspeed;
 float autocvar_g_midair_shieldtime;
 #define autocvar_g_instagib cvar("g_instagib")
-int autocvar_g_instagib_ammo_drop;
-int autocvar_g_instagib_extralives;
-float autocvar_g_instagib_speed_highspeed;
 float autocvar_g_instagib_invis_alpha;
 bool autocvar_g_instagib_damagedbycontents = true;
 bool autocvar_g_instagib_blaster_keepdamage = false;
@@ -600,13 +597,6 @@ float autocvar_g_campcheck_damage;
 float autocvar_g_campcheck_distance;
 float autocvar_g_campcheck_interval;
 bool autocvar_g_jump_grunt;
-bool autocvar_g_overkill_powerups_replace;
-float autocvar_g_overkill_superguns_respawn_time;
-bool autocvar_g_overkill_100h_anyway;
-bool autocvar_g_overkill_100a_anyway;
-bool autocvar_g_overkill_ammo_charge;
-float autocvar_g_overkill_ammo_charge_notice;
-float autocvar_g_overkill_ammo_charge_limit;
 float autocvar_g_spawn_near_teammate_distance;
 int autocvar_g_spawn_near_teammate_ignore_spawnpoint;
 float autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay;
index d1cd583b15503dffb5b5b1242325341d16f37217..e12e9c58bf944855fa471ec38714ad6e640534b4 100644 (file)
@@ -26,7 +26,6 @@
 #include "mutator/mutator_nades.qc"
 #include "mutator/mutator_new_toys.qc"
 #include "mutator/mutator_nix.qc"
-#include "mutator/mutator_overkill.qc"
 #include "mutator/mutator_physical_items.qc"
 #include "mutator/mutator_pinata.qc"
 #include "mutator/mutator_random_gravity.qc"
index 7bc65791ceaf39d1d50a3f77fc64c9a19db2dabe..9cd9045d538a8bd3cde4bda33bb471b47fe8952c 100644 (file)
@@ -337,15 +337,31 @@ MUTATOR_HOOKABLE(PlayerDamage_Calculate, EV_PlayerDamage_Calculate);
  * Called when a player is damaged
  */
 #define EV_PlayerDamaged(i, o) \
-    /** attacker */ i(entity, mutator_argv_entity_0) \
-    /** target */ i(entity, mutator_argv_entity_1) \
-    /** health */ i(int, mutator_argv_int_0) \
-    /** armor */ i(int, mutator_argv_int_1) \
-    /** location */ i(vector, mutator_argv_vector_0) \
-    /** deathtype */ i(int, mutator_argv_int_2) \
+    /** attacker  */ i(entity, MUTATOR_ARGV_0_entity) \
+    /** target    */ i(entity, MUTATOR_ARGV_1_entity) \
+    /** health    */ i(int,    MUTATOR_ARGV_0_int) \
+    /** armor     */ i(int,    MUTATOR_ARGV_1_int) \
+    /** location  */ i(vector, MUTATOR_ARGV_0_vector) \
+    /** deathtype */ i(int,    MUTATOR_ARGV_2_int) \
     /**/
 MUTATOR_HOOKABLE(PlayerDamaged, EV_PlayerDamaged);
 
+/**
+ * Called by W_DecreaseAmmo
+ */
+#define EV_W_DecreaseAmmo(i, o) \
+    /** actor */ i(entity, MUTATOR_ARGV_0_entity) \
+    /**/
+MUTATOR_HOOKABLE(W_DecreaseAmmo, EV_W_DecreaseAmmo);
+
+/**
+ * Called by W_Reload
+ */
+#define EV_W_Reload(i, o) \
+    /** actor */ i(entity, MUTATOR_ARGV_0_entity) \
+    /**/
+MUTATOR_HOOKABLE(W_Reload, EV_W_Reload);
+
 /** called at the end of player_powerups() in cl_client.qc, used for manipulating the values which are set by powerup items. */
 #define EV_PlayerPowerups(i, o) \
     /**/ i(entity, __self) \
index cdca4c4858661303f7d24b491c2a474c7b5c0fed..9cfc2ec410ac1e5cc408148f739f4577e03a92ea 100644 (file)
@@ -26,6 +26,18 @@ void(entity player, float score) nades_GiveBonus;
 // Remove all bonus nades from a player
 void(entity player) nades_RemoveBonus;
 
+/**
+ * called to adjust nade damage and force on hit
+ */
+#define EV_Nade_Damage(i, o) \
+       /** weapon */ i(entity, MUTATOR_ARGV_0_entity) \
+    /** force */  i(vector, MUTATOR_ARGV_0_vector) \
+    /**/          o(vector, MUTATOR_ARGV_0_vector) \
+       /** damage */ i(float,  MUTATOR_ARGV_0_float) \
+    /**/          o(float,  MUTATOR_ARGV_0_float) \
+    /**/
+MUTATOR_HOOKABLE(Nade_Damage, EV_Nade_Damage);
+
 #endif
 #ifdef IMPLEMENTATION
 
@@ -630,35 +642,34 @@ void nade_damage(entity inflictor, entity attacker, float damage, int deathtype,
        if(self.nade_type == NADE_TYPE_TRANSLOCATE.m_id || self.nade_type == NADE_TYPE_SPAWN.m_id)
                return;
 
-       if(DEATH_ISWEAPON(deathtype, WEP_BLASTER))
+       if (MUTATOR_CALLHOOK(Nade_Damage, DEATH_WEAPONOF(deathtype), force, damage)) {}
+       else if(DEATH_ISWEAPON(deathtype, WEP_BLASTER))
        {
                force *= 1.5;
                damage = 0;
        }
-
-       if(DEATH_ISWEAPON(deathtype, WEP_VAPORIZER) && (deathtype & HITTYPE_SECONDARY))
+       else if(DEATH_ISWEAPON(deathtype, WEP_VAPORIZER) && (deathtype & HITTYPE_SECONDARY))
        {
                force *= 0.5; // too much
-               frag_damage = 0;
+               damage = 0;
        }
-
-       if(DEATH_ISWEAPON(deathtype, WEP_VORTEX) || DEATH_ISWEAPON(deathtype, WEP_VAPORIZER))
+       else if(DEATH_ISWEAPON(deathtype, WEP_VORTEX) || DEATH_ISWEAPON(deathtype, WEP_VAPORIZER))
        {
                force *= 6;
                damage = self.max_health * 0.55;
        }
-
-       if(DEATH_ISWEAPON(deathtype, WEP_MACHINEGUN) || DEATH_ISWEAPON(deathtype, WEP_HMG))
+       else if(DEATH_ISWEAPON(deathtype, WEP_MACHINEGUN))
                damage = self.max_health * 0.1;
-
-       if(DEATH_ISWEAPON(deathtype, WEP_SHOCKWAVE) || DEATH_ISWEAPON(deathtype, WEP_SHOTGUN)) // WEAPONTODO
-       if(deathtype & HITTYPE_SECONDARY)
+       else if(DEATH_ISWEAPON(deathtype, WEP_SHOCKWAVE) || DEATH_ISWEAPON(deathtype, WEP_SHOTGUN)) // WEAPONTODO
        {
-               damage = self.max_health * 0.1;
-               force *= 10;
+               if(deathtype & HITTYPE_SECONDARY)
+               {
+                       damage = self.max_health * 0.1;
+                       force *= 10;
+               }
+               else
+                       damage = self.max_health * 1.15;
        }
-       else
-               damage = self.max_health * 1.15;
 
        self.velocity += force;
        UpdateCSQCProjectile(self);
diff --git a/qcsrc/server/mutators/mutator/mutator_overkill.qc b/qcsrc/server/mutators/mutator/mutator_overkill.qc
deleted file mode 100644 (file)
index a65efd5..0000000
+++ /dev/null
@@ -1,361 +0,0 @@
-#ifdef IMPLEMENTATION
-.vector ok_deathloc;
-.float ok_spawnsys_timer;
-.float ok_lastwep;
-.float ok_item;
-
-.float ok_notice_time;
-.float ammo_charge[Weapons_MAX];
-.float ok_use_ammocharge;
-.float ok_ammo_charge;
-
-.float ok_pauseregen_finished;
-
-void(entity ent, float wep) ok_DecreaseCharge;
-
-void ok_Initialize();
-
-REGISTER_MUTATOR(ok, cvar("g_overkill") && !cvar("g_instagib") && !g_nexball && cvar_string("g_mod_balance") == "Overkill")
-{
-       MUTATOR_ONADD
-       {
-               ok_Initialize();
-       }
-
-       MUTATOR_ONREMOVE
-       {
-               WEP_RPC.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
-               WEP_HMG.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
-       }
-
-       return false;
-}
-
-void W_Blaster_Attack(entity, float, float, float, float, float, float, float, float, float, float);
-spawnfunc(weapon_hmg);
-spawnfunc(weapon_rpc);
-
-void ok_DecreaseCharge(entity ent, int wep)
-{
-       if(!ent.ok_use_ammocharge) return;
-
-       entity wepent = get_weaponinfo(wep);
-
-       if(wepent.weapon == 0)
-               return; // dummy
-
-       ent.ammo_charge[wep] -= max(0, cvar(sprintf("g_overkill_ammo_decharge_%s", wepent.netname)));
-}
-
-void ok_IncreaseCharge(entity ent, int wep)
-{
-       entity wepent = get_weaponinfo(wep);
-
-       if(wepent.weapon == 0)
-               return; // dummy
-
-       if(ent.ok_use_ammocharge)
-       if(!ent.BUTTON_ATCK) // not while attacking?
-               ent.ammo_charge[wep] = min(autocvar_g_overkill_ammo_charge_limit, ent.ammo_charge[wep] + cvar(sprintf("g_overkill_ammo_charge_rate_%s", wepent.netname)) * frametime / W_TICSPERFRAME);
-}
-
-float ok_CheckWeaponCharge(entity ent, int wep)
-{
-       if(!ent.ok_use_ammocharge) return true;
-
-       entity wepent = get_weaponinfo(wep);
-
-       if(wepent.weapon == 0)
-               return 0; // dummy
-
-       return (ent.ammo_charge[wep] >= cvar(sprintf("g_overkill_ammo_decharge_%s", wepent.netname)));
-}
-
-MUTATOR_HOOKFUNCTION(ok, PlayerDamage_Calculate, CBC_ORDER_LAST)
-{
-       if(IS_PLAYER(frag_attacker) && IS_PLAYER(frag_target))
-       if(DEATH_ISWEAPON(frag_deathtype, WEP_BLASTER))
-       {
-               frag_damage = 0;
-
-               if(frag_attacker != frag_target)
-               if(frag_target.health > 0)
-               if(frag_target.frozen == 0)
-               if(frag_target.deadflag == DEAD_NO)
-               {
-                       Send_Notification(NOTIF_ONE, frag_attacker, MSG_CENTER, CENTER_SECONDARY_NODAMAGE);
-                       frag_force = '0 0 0';
-               }
-       }
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(ok, PlayerDamage_SplitHealthArmor)
-{SELFPARAM();
-       if(damage_take)
-               self.ok_pauseregen_finished = max(self.ok_pauseregen_finished, time + 2);
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(ok, PlayerDies)
-{SELFPARAM();
-       entity targ = ((frag_attacker) ? frag_attacker : frag_target);
-
-       if(IS_MONSTER(self))
-       {
-               remove(other); // remove default item
-               other = world;
-       }
-
-       setself(new(droppedweapon)); // hax
-       self.ok_item = true;
-       self.noalign = true;
-       self.pickup_anyway = true;
-       spawnfunc_item_armor_small(this);
-       self.movetype = MOVETYPE_TOSS;
-       self.gravity = 1;
-       self.reset = SUB_Remove;
-       setorigin(self, frag_target.origin + '0 0 32');
-       self.velocity = '0 0 200' + normalize(targ.origin - self.origin) * 500;
-       SUB_SetFade(self, time + 5, 1);
-       setself(this);
-
-       self.ok_lastwep = self.switchweapon;
-
-       return false;
-}
-MUTATOR_HOOKFUNCTION(ok, MonsterDropItem) { ok_PlayerDies(); }
-
-MUTATOR_HOOKFUNCTION(ok, PlayerRegen)
-{SELFPARAM();
-       // overkill's values are different, so use custom regen
-       if(!self.frozen)
-       {
-               self.armorvalue = CalcRotRegen(self.armorvalue, autocvar_g_balance_armor_regenstable, autocvar_g_balance_armor_regen, autocvar_g_balance_armor_regenlinear, 1 * frametime * (time > self.ok_pauseregen_finished), 0, 0, 1, 1 * frametime * (time > self.pauserotarmor_finished), autocvar_g_balance_armor_limit);
-               self.health = CalcRotRegen(self.health, autocvar_g_balance_health_regenstable, 0, 100, 1 * frametime * (time > self.ok_pauseregen_finished), 200, 0, autocvar_g_balance_health_rotlinear, 1 * frametime * (time > self.pauserothealth_finished), autocvar_g_balance_health_limit);
-
-               float minf, maxf, limitf;
-
-               maxf = autocvar_g_balance_fuel_rotstable;
-               minf = autocvar_g_balance_fuel_regenstable;
-               limitf = autocvar_g_balance_fuel_limit;
-
-               self.ammo_fuel = CalcRotRegen(self.ammo_fuel, minf, autocvar_g_balance_fuel_regen, autocvar_g_balance_fuel_regenlinear, frametime * (time > self.pauseregen_finished) * ((self.items & ITEM_JetpackRegen.m_itemid) != 0), maxf, autocvar_g_balance_fuel_rot, autocvar_g_balance_fuel_rotlinear, frametime * (time > self.pauserotfuel_finished), limitf);
-       }
-       return true; // return true anyway, as frozen uses no regen
-}
-
-MUTATOR_HOOKFUNCTION(ok, ForbidThrowCurrentWeapon)
-{
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ok, PlayerPreThink)
-{SELFPARAM();
-       if(intermission_running || gameover)
-               return false;
-
-       if(self.deadflag != DEAD_NO || !IS_PLAYER(self) || self.frozen)
-               return false;
-
-       if(self.ok_lastwep)
-       {
-               self.switchweapon = self.ok_lastwep;
-               self.ok_lastwep = 0;
-       }
-
-       ok_IncreaseCharge(self, self.weapon);
-
-       if(self.BUTTON_ATCK2)
-       if(!forbidWeaponUse(self) || self.weapon_blocked) // allow if weapon is blocked
-       if(time >= self.jump_interval)
-       {
-               self.jump_interval = time + WEP_CVAR_PRI(blaster, refire) * W_WeaponRateFactor();
-               makevectors(self.v_angle);
-
-               int oldwep = self.weapon;
-               self.weapon = WEP_BLASTER.m_id;
-               W_Blaster_Attack(
-                       self,
-                       WEP_BLASTER.m_id | HITTYPE_SECONDARY,
-                       WEP_CVAR_SEC(vaporizer, shotangle),
-                       WEP_CVAR_SEC(vaporizer, damage),
-                       WEP_CVAR_SEC(vaporizer, edgedamage),
-                       WEP_CVAR_SEC(vaporizer, radius),
-                       WEP_CVAR_SEC(vaporizer, force),
-                       WEP_CVAR_SEC(vaporizer, speed),
-                       WEP_CVAR_SEC(vaporizer, spread),
-                       WEP_CVAR_SEC(vaporizer, delay),
-                       WEP_CVAR_SEC(vaporizer, lifetime)
-               );
-               self.weapon = oldwep;
-       }
-
-       self.weapon_blocked = false;
-
-       self.ok_ammo_charge = self.ammo_charge[self.weapon];
-
-       if(self.ok_use_ammocharge)
-       if(!ok_CheckWeaponCharge(self, self.weapon))
-       {
-               if(autocvar_g_overkill_ammo_charge_notice && time > self.ok_notice_time && self.BUTTON_ATCK && IS_REAL_CLIENT(self) && self.weapon == self.switchweapon)
-               {
-                       //Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_OVERKILL_CHARGE);
-                       self.ok_notice_time = time + 2;
-                       play2(self, SND(DRYFIRE));
-               }
-               Weapon wpn = get_weaponinfo(self.weapon);
-               .entity weaponentity = weaponentities[0]; // TODO: unhardcode
-               if(self.(weaponentity).state != WS_CLEAR)
-                       w_ready(wpn, self, weaponentity, (self.BUTTON_ATCK ? 1 : 0) | (self.BUTTON_ATCK2 ? 2 : 0));
-
-               self.weapon_blocked = true;
-       }
-
-       self.BUTTON_ATCK2 = 0;
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(ok, PlayerSpawn)
-{SELFPARAM();
-       if(autocvar_g_overkill_ammo_charge)
-       {
-               for(int i = WEP_FIRST; i <= WEP_LAST; ++i)
-                       self.ammo_charge[i] = autocvar_g_overkill_ammo_charge_limit;
-
-               self.ok_use_ammocharge = 1;
-               self.ok_notice_time = time;
-       }
-       else
-               self.ok_use_ammocharge = 0;
-
-       self.ok_pauseregen_finished = time + 2;
-
-       return false;
-}
-
-void _spawnfunc_weapon_hmg() { SELFPARAM(); spawnfunc_weapon_hmg(this); }
-void _spawnfunc_weapon_rpc() { SELFPARAM(); spawnfunc_weapon_rpc(this); }
-
-MUTATOR_HOOKFUNCTION(ok, OnEntityPreSpawn)
-{SELFPARAM();
-       if(autocvar_g_powerups)
-       if(autocvar_g_overkill_powerups_replace)
-       {
-               if(self.classname == "item_strength")
-               {
-                       entity wep = new(weapon_hmg);
-                       setorigin(wep, self.origin);
-                       setmodel(wep, MDL_OK_HMG);
-                       wep.ok_item = true;
-                       wep.noalign = self.noalign;
-                       wep.cnt = self.cnt;
-                       wep.team = self.team;
-                       wep.respawntime = autocvar_g_overkill_superguns_respawn_time;
-                       wep.pickup_anyway = true;
-                       wep.think = _spawnfunc_weapon_hmg;
-                       wep.nextthink = time + 0.1;
-                       return true;
-               }
-
-               if(self.classname == "item_invincible")
-               {
-                       entity wep = new(weapon_rpc);
-                       setorigin(wep, self.origin);
-                       setmodel(wep, MDL_OK_RPC);
-                       wep.ok_item = true;
-                       wep.noalign = self.noalign;
-                       wep.cnt = self.cnt;
-                       wep.team = self.team;
-                       wep.respawntime = autocvar_g_overkill_superguns_respawn_time;
-                       wep.pickup_anyway = true;
-                       wep.think = _spawnfunc_weapon_rpc;
-                       wep.nextthink = time + 0.1;
-                       return true;
-               }
-       }
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(ok, FilterItem)
-{SELFPARAM();
-       if(self.ok_item)
-               return false;
-
-       switch(self.items)
-       {
-               case ITEM_HealthMega.m_itemid: return !(autocvar_g_overkill_100h_anyway);
-               case ITEM_ArmorMega.m_itemid: return !(autocvar_g_overkill_100a_anyway);
-       }
-
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ok, SpectateCopy)
-{SELFPARAM();
-       self.ammo_charge[self.weapon] = other.ammo_charge[other.weapon];
-       self.ok_use_ammocharge = other.ok_use_ammocharge;
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(ok, SetStartItems)
-{
-       WepSet ok_start_items = (WEPSET(MACHINEGUN) | WEPSET(VORTEX) | WEPSET(SHOTGUN));
-
-       if(WEP_RPC.weaponstart > 0) { ok_start_items |= WEPSET(RPC); }
-       if(WEP_HMG.weaponstart > 0) { ok_start_items |= WEPSET(HMG); }
-
-       start_items |= IT_UNLIMITED_WEAPON_AMMO;
-       start_weapons = warmup_start_weapons = ok_start_items;
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(ok, BuildMutatorsString)
-{
-       ret_string = strcat(ret_string, ":OK");
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(ok, BuildMutatorsPrettyString)
-{
-       ret_string = strcat(ret_string, ", Overkill");
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(ok, SetModname)
-{
-       modname = "Overkill";
-       return true;
-}
-
-void ok_SetCvars()
-{
-       // hack to force overkill playermodels
-       cvar_settemp("sv_defaultcharacter", "1");
-       cvar_settemp("sv_defaultplayermodel", "models/ok_player/okrobot1.dpm models/ok_player/okrobot2.dpm models/ok_player/okrobot3.dpm models/ok_player/okrobot4.dpm models/ok_player/okmale1.dpm models/ok_player/okmale2.dpm models/ok_player/okmale3.dpm models/ok_player/okmale4.dpm");
-       cvar_settemp("sv_defaultplayermodel_red", "models/ok_player/okrobot1.dpm models/ok_player/okrobot2.dpm models/ok_player/okrobot3.dpm models/ok_player/okrobot4.dpm");
-       cvar_settemp("sv_defaultplayermodel_blue", "models/ok_player/okmale1.dpm models/ok_player/okmale2.dpm models/ok_player/okmale3.dpm models/ok_player/okmale4.dpm");
-}
-
-void ok_Initialize()
-{
-       ok_SetCvars();
-
-       precache_all_playermodels("models/ok_player/*.dpm");
-
-       addstat(STAT_OK_AMMO_CHARGE, AS_FLOAT, ok_use_ammocharge);
-       addstat(STAT_OK_AMMO_CHARGEPOOL, AS_FLOAT, ok_ammo_charge);
-
-       WEP_RPC.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
-       WEP_HMG.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
-
-       WEP_SHOTGUN.mdl = "ok_shotgun";
-       WEP_MACHINEGUN.mdl = "ok_mg";
-       WEP_VORTEX.mdl = "ok_sniper";
-}
-#endif
index ab94c42bdd4d6215daef510455181d1ac5a8116f..b51ae73a6b3bdff08e3d6031f5b9244275ceabbf 100644 (file)
 #include "../common/animdecide.qc"
 #include "../common/campaign_file.qc"
 #include "../common/campaign_setup.qc"
+#include "../common/casings.qc"
 #include "../common/effects/effectinfo.qc"
 #include "../common/mapinfo.qc"
-#include "../common/monsters/spawn.qc"
-#include "../common/monsters/sv_monsters.qc"
 #include "../common/minigames/minigames.qc"
 #include "../common/minigames/sv_minigames.qc"
+#include "../common/monsters/spawn.qc"
+#include "../common/monsters/sv_monsters.qc"
 #include "../common/movetypes/include.qc"
 #include "../common/net_notice.qc"
 #include "../common/notifications.qc"
 #include "../common/physics.qc"
 #include "../common/playerstats.qc"
-#include "../common/viewloc.qc"
 #include "../common/triggers/include.qc"
 #include "../common/util.qc"
+#include "../common/viewloc.qc"
 
 #include "../common/deathtypes/all.qc"
 #include "../common/buffs/all.qc"
 #include "../common/gamemodes/all.qc"
 #include "../common/items/all.qc"
 #include "../common/monsters/all.qc"
-#include "../common/mutators/all.qc"
 #include "../common/nades/all.qc"
 #include "../common/turrets/all.qc"
 #include "../common/vehicles/all.qc"
 #include "../common/weapons/all.qc"
+#include "../common/mutators/all.qc"
 
 #include "../common/turrets/sv_turrets.qc"
 #include "../common/turrets/config.qc"
index 132740eaa88386f2cc99fcfc63849b71d6beb76c..3ea45ad46814ca7dfcc306288048b41cded229fb 100644 (file)
@@ -905,14 +905,7 @@ void W_AttachToShotorg(entity actor, entity flash, vector offset)
 
 void W_DecreaseAmmo(Weapon wep, entity actor, float ammo_use)
 {
-       if (cvar("g_overkill"))
-       {
-               if (actor.ok_use_ammocharge)
-               {
-                       ok_DecreaseCharge(actor, actor.weapon);
-                       return;  // TODO
-               }
-       }
+       if (MUTATOR_CALLHOOK(W_DecreaseAmmo, actor)) return;
 
        if ((actor.items & IT_UNLIMITED_WEAPON_AMMO) && !wep.reloading_ammo) return;
 
@@ -982,9 +975,7 @@ void W_Reload(entity actor, float sent_ammo_min, string sent_sound)
        // set global values to work with
        entity e = Weapons_from(actor.weapon);
 
-       if (cvar("g_overkill"))
-               if (actor.ok_use_ammocharge) return;
-       // TODO
+       if (MUTATOR_CALLHOOK(W_Reload, actor)) return;
 
        actor.reload_ammo_min = sent_ammo_min;
        actor.reload_ammo_amount = e.reloading_ammo;