From: TimePath Date: Wed, 4 Nov 2015 22:57:37 +0000 (+1100) Subject: Mutators: add hooks for overkill X-Git-Tag: xonotic-v0.8.2~1719 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=a1e75a32dbbbcdcc08c5e90a3a19ec5b76377937;p=xonotic%2Fxonotic-data.pk3dir.git Mutators: add hooks for overkill --- diff --git a/qcsrc/client/progs.inc b/qcsrc/client/progs.inc index 5c110e2b8..e3e8c00c0 100644 --- a/qcsrc/client/progs.inc +++ b/qcsrc/client/progs.inc @@ -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 index 000000000..22046dd20 --- /dev/null +++ b/qcsrc/common/casings.qc @@ -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 diff --git a/qcsrc/common/mutators/all.inc b/qcsrc/common/mutators/all.inc index 6b19a0bc6..d3e63de45 100644 --- a/qcsrc/common/mutators/all.inc +++ b/qcsrc/common/mutators/all.inc @@ -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" diff --git a/qcsrc/common/mutators/events.qh b/qcsrc/common/mutators/events.qh index 7ba24fa7a..bb845b801 100644 --- a/qcsrc/common/mutators/events.qh +++ b/qcsrc/common/mutators/events.qh @@ -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 index 2ad32cf32..000000000 --- a/qcsrc/common/mutators/mutator/casings.qc +++ /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 index ac451ca54..000000000 --- a/qcsrc/common/mutators/mutator/damagetext.qc +++ /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 index 000000000..923ca3bcc --- /dev/null +++ b/qcsrc/common/mutators/mutator/damagetext/damagetext.qc @@ -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 index 000000000..8e70be7c6 --- /dev/null +++ b/qcsrc/common/mutators/mutator/damagetext/module.inc @@ -0,0 +1 @@ +#include "damagetext.qc" diff --git a/qcsrc/common/mutators/mutator/instagib/instagib.qc b/qcsrc/common/mutators/mutator/instagib/instagib.qc index 391302be0..16b5b86d1 100644 --- a/qcsrc/common/mutators/mutator/instagib/instagib.qc +++ b/qcsrc/common/mutators/mutator/instagib/instagib.qc @@ -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 index 000000000..7270067d3 --- /dev/null +++ b/qcsrc/common/mutators/mutator/instagib/module.inc @@ -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 index 000000000..7f2341fb0 --- /dev/null +++ b/qcsrc/common/mutators/mutator/overkill/hmg.qc @@ -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 index 000000000..a8bde27b5 --- /dev/null +++ b/qcsrc/common/mutators/mutator/overkill/module.inc @@ -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 index 000000000..c146f1c1a --- /dev/null +++ b/qcsrc/common/mutators/mutator/overkill/overkill.qc @@ -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 index 000000000..fa037e00b --- /dev/null +++ b/qcsrc/common/mutators/mutator/overkill/rpc.qc @@ -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 index 000000000..50bb5b4d6 --- /dev/null +++ b/qcsrc/common/mutators/mutator/waypoints/module.inc @@ -0,0 +1 @@ +#include "waypointsprites.qc" diff --git a/qcsrc/common/weapons/all.inc b/qcsrc/common/weapons/all.inc index fc89a0cd2..99c7225ac 100644 --- a/qcsrc/common/weapons/all.inc +++ b/qcsrc/common/weapons/all.inc @@ -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 index d701870ec..000000000 --- a/qcsrc/common/weapons/weapon/hmg.qc +++ /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 index fa037e00b..000000000 --- a/qcsrc/common/weapons/weapon/rpc.qc +++ /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 diff --git a/qcsrc/server/autocvars.qh b/qcsrc/server/autocvars.qh index 16f9898ad..d72617fac 100644 --- a/qcsrc/server/autocvars.qh +++ b/qcsrc/server/autocvars.qh @@ -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; diff --git a/qcsrc/server/mutators/all.inc b/qcsrc/server/mutators/all.inc index d1cd583b1..e12e9c58b 100644 --- a/qcsrc/server/mutators/all.inc +++ b/qcsrc/server/mutators/all.inc @@ -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" diff --git a/qcsrc/server/mutators/events.qh b/qcsrc/server/mutators/events.qh index 7bc65791c..9cd9045d5 100644 --- a/qcsrc/server/mutators/events.qh +++ b/qcsrc/server/mutators/events.qh @@ -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) \ diff --git a/qcsrc/server/mutators/mutator/mutator_nades.qc b/qcsrc/server/mutators/mutator/mutator_nades.qc index cdca4c485..9cfc2ec41 100644 --- a/qcsrc/server/mutators/mutator/mutator_nades.qc +++ b/qcsrc/server/mutators/mutator/mutator_nades.qc @@ -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 index a65efd53b..000000000 --- a/qcsrc/server/mutators/mutator/mutator_overkill.qc +++ /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 diff --git a/qcsrc/server/progs.inc b/qcsrc/server/progs.inc index ab94c42bd..b51ae73a6 100644 --- a/qcsrc/server/progs.inc +++ b/qcsrc/server/progs.inc @@ -61,20 +61,21 @@ #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" @@ -82,11 +83,11 @@ #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" diff --git a/qcsrc/server/weapons/weaponsystem.qc b/qcsrc/server/weapons/weaponsystem.qc index 132740eaa..3ea45ad46 100644 --- a/qcsrc/server/weapons/weaponsystem.qc +++ b/qcsrc/server/weapons/weaponsystem.qc @@ -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;