X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Fweapons%2Fweaponsystem.qc;h=e64391d83db1fe6d4bf7f29bf40ea1ef53f57d6e;hb=12a59812090d46f90f91b332fbe27da18a179ab2;hp=4f072c4c085bb7e829c6355da495a14c0ad33888;hpb=129fa209a7798b37270a888523974533c1b4aa87;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/weapons/weaponsystem.qc b/qcsrc/server/weapons/weaponsystem.qc index 4f072c4c0..e64391d83 100644 --- a/qcsrc/server/weapons/weaponsystem.qc +++ b/qcsrc/server/weapons/weaponsystem.qc @@ -1,10 +1,9 @@ #include "weaponsystem.qh" -#include "../_all.qh" #include "selection.qh" #include "../command/common.qh" -#include "../mutators/mutators_include.qh" +#include "../mutators/all.qh" #include "../round_handler.qh" #include "../t_items.qh" #include "../../common/animdecide.qh" @@ -13,26 +12,70 @@ #include "../../common/notifications.qh" #include "../../common/util.qh" #include "../../common/weapons/all.qh" -#include "../../csqcmodellib/sv_model.qh" +#include "../../lib/csqcmodel/sv_model.qh" -/* -=========================================================================== +vector shotorg_adjustfromclient(vector vecs, float y_is_right, float algn) +{ + switch (algn) + { + default: case 3: break; // right alignment + case 4: vecs.y = -vecs.y; + break; // left + case 1: case 2: vecs.y = 0; + vecs.z -= 2; + break; // center + } + + return vecs; +} + +vector shotorg_adjust_values(vector vecs, bool y_is_right, bool visual, int algn) +{ + string s; + + if (visual) + { + vecs = shotorg_adjustfromclient(vecs, y_is_right, algn); + } + else if (autocvar_g_shootfromeye) + { + vecs.y = vecs.z = 0; + } + else if (autocvar_g_shootfromcenter) + { + vecs.y = 0; + vecs.z -= 2; + } + else if ((s = autocvar_g_shootfromfixedorigin) != "") + { + vector v = stov(s); + if (y_is_right) v.y = -v.y; + if (v.x != 0) vecs.x = v.x; + vecs.y = v.y; + vecs.z = v.z; + } + else // just do the same as top + { + vecs = shotorg_adjustfromclient(vecs, y_is_right, algn); + } - CLIENT WEAPONSYSTEM CODE - Bring back W_Weaponframe + return vecs; +} + +vector shotorg_adjust(vector vecs, bool y_is_right, bool visual, int algn) +{ + return shotorg_adjust_values(vecs, y_is_right, visual, algn); +} -=========================================================================== -*/ +.int state; .float weapon_frametime; float W_WeaponRateFactor() { - float t; - t = 1.0 / g_weaponratefactor; + float t = 1.0 / g_weaponratefactor; - weapon_rate = t; - MUTATOR_CALLHOOK(WeaponRateFactor); + MUTATOR_CALLHOOK(WeaponRateFactor, t); t = weapon_rate; return t; @@ -40,25 +83,23 @@ float W_WeaponRateFactor() float W_WeaponSpeedFactor() { - float t; - t = 1.0 * g_weaponspeedfactor; + float t = 1.0 * g_weaponspeedfactor; - ret_float = t; - MUTATOR_CALLHOOK(WeaponSpeedFactor); + MUTATOR_CALLHOOK(WeaponSpeedFactor, t); t = ret_float; return t; } -void(float fr, float t, void() func) weapon_thinkf; +void weapon_thinkf(entity actor, int slot, float fr, float t, + void(Weapon thiswep, entity actor, int slot, int fire) func); -float CL_Weaponentity_CustomizeEntityForClient() +bool CL_Weaponentity_CustomizeEntityForClient() { - self.viewmodelforclient = self.owner; - if(IS_SPEC(other)) - if(other.enemy == self.owner) - self.viewmodelforclient = other; + SELFPARAM(); + this.viewmodelforclient = this.owner; + if (IS_SPEC(other) && other.enemy == this.owner) this.viewmodelforclient = other; return true; } @@ -105,673 +146,647 @@ float CL_Weaponentity_CustomizeEntityForClient() */ // writes: -// self.origin, self.angles -// self.weaponentity -// self.movedir, self.view_ofs +// this.origin, this.angles +// this.weaponentity +// this.movedir, this.view_ofs // attachment stuff // anim stuff // to free: // call again with "" // remove the ent -void CL_WeaponEntity_SetModel(string name) +void CL_WeaponEntity_SetModel(entity this, int slot, string name) { - float v_shot_idx; if (name != "") { // if there is a child entity, hide it until we're sure we use it - if (self.weaponentity) - self.weaponentity.model = ""; - setmodel(self, strcat("models/weapons/v_", name, ".md3")); // precision set below - v_shot_idx = gettagindex(self, "shot"); // used later - if(!v_shot_idx) - v_shot_idx = gettagindex(self, "tag_shot"); - - setmodel(self, strcat("models/weapons/h_", name, ".iqm")); // precision set below + if (this.weaponentity[slot]) this.weaponentity[slot].model = ""; + _setmodel(this, W_Model(strcat("v_", name, ".md3"))); + int v_shot_idx = gettagindex(this, "shot"); // used later + if (!v_shot_idx) v_shot_idx = gettagindex(this, "tag_shot"); + + _setmodel(this, W_Model(strcat("h_", name, ".iqm"))); // preset some defaults that work great for renamed zym files (which don't need an animinfo) - self.anim_fire1 = animfixfps(self, '0 1 0.01', '0 0 0'); - self.anim_fire2 = animfixfps(self, '1 1 0.01', '0 0 0'); - self.anim_idle = animfixfps(self, '2 1 0.01', '0 0 0'); - self.anim_reload = animfixfps(self, '3 1 0.01', '0 0 0'); + this.anim_fire1 = animfixfps(this, '0 1 0.01', '0 0 0'); + this.anim_fire2 = animfixfps(this, '1 1 0.01', '0 0 0'); + this.anim_idle = animfixfps(this, '2 1 0.01', '0 0 0'); + this.anim_reload = animfixfps(this, '3 1 0.01', '0 0 0'); // if we have a "weapon" tag, let's attach the v_ model to it ("invisible hand" style model) // if we don't, this is a "real" animated model - if(gettagindex(self, "weapon")) + if (gettagindex(this, "weapon")) { - if (!self.weaponentity) - self.weaponentity = spawn(); - setmodel(self.weaponentity, strcat("models/weapons/v_", name, ".md3")); // precision does not matter - setattachment(self.weaponentity, self, "weapon"); + if (!this.weaponentity[slot]) this.weaponentity[slot] = spawn(); + _setmodel(this.weaponentity[slot], W_Model(strcat("v_", name, ".md3"))); + setattachment(this.weaponentity[slot], this, "weapon"); } - else if(gettagindex(self, "tag_weapon")) + else if (gettagindex(this, "tag_weapon")) { - if (!self.weaponentity) - self.weaponentity = spawn(); - setmodel(self.weaponentity, strcat("models/weapons/v_", name, ".md3")); // precision does not matter - setattachment(self.weaponentity, self, "tag_weapon"); + if (!this.weaponentity[slot]) this.weaponentity[slot] = spawn(); + _setmodel(this.weaponentity[slot], W_Model(strcat("v_", name, ".md3"))); + setattachment(this.weaponentity[slot], this, "tag_weapon"); } else { - if(self.weaponentity) - remove(self.weaponentity); - self.weaponentity = world; + if (this.weaponentity[slot]) remove(this.weaponentity[slot]); + this.weaponentity[slot] = NULL; } - setorigin(self,'0 0 0'); - self.angles = '0 0 0'; - self.frame = 0; - self.viewmodelforclient = world; + setorigin(this, '0 0 0'); + this.angles = '0 0 0'; + this.frame = 0; + this.viewmodelforclient = NULL; float idx; - if(v_shot_idx) // v_ model attached to invisible h_ model + if (v_shot_idx) // v_ model attached to invisible h_ model { - self.movedir = gettaginfo(self.weaponentity, v_shot_idx); + this.movedir = gettaginfo(this.weaponentity[slot], v_shot_idx); } else { - idx = gettagindex(self, "shot"); - if(!idx) - idx = gettagindex(self, "tag_shot"); - if(idx) - self.movedir = gettaginfo(self, idx); + idx = gettagindex(this, "shot"); + if (!idx) idx = gettagindex(this, "tag_shot"); + if (idx) + { + this.movedir = gettaginfo(this, idx); + } else { - print("WARNING: weapon model ", self.model, " does not support the 'shot' tag, will display shots TOTALLY wrong\n"); - self.movedir = '0 0 0'; + LOG_INFO("WARNING: weapon model ", this.model, + " does not support the 'shot' tag, will display shots TOTALLY wrong\n"); + this.movedir = '0 0 0'; } } - if(self.weaponentity) // v_ model attached to invisible h_ model + if (this.weaponentity[slot]) // v_ model attached to invisible h_ model { - idx = gettagindex(self.weaponentity, "shell"); - if(!idx) - idx = gettagindex(self.weaponentity, "tag_shell"); - if(idx) - self.spawnorigin = gettaginfo(self.weaponentity, idx); + idx = gettagindex(this.weaponentity[slot], "shell"); + if (!idx) idx = gettagindex(this.weaponentity[slot], "tag_shell"); + if (idx) this.spawnorigin = gettaginfo(this.weaponentity[slot], idx); } else + { idx = 0; - if(!idx) + } + if (!idx) { - idx = gettagindex(self, "shell"); - if(!idx) - idx = gettagindex(self, "tag_shell"); - if(idx) - self.spawnorigin = gettaginfo(self, idx); + idx = gettagindex(this, "shell"); + if (!idx) idx = gettagindex(this, "tag_shell"); + if (idx) + { + this.spawnorigin = gettaginfo(this, idx); + } else { - print("WARNING: weapon model ", self.model, " does not support the 'shell' tag, will display casings wrong\n"); - self.spawnorigin = self.movedir; + LOG_INFO("WARNING: weapon model ", this.model, + " does not support the 'shell' tag, will display casings wrong\n"); + this.spawnorigin = this.movedir; } } - if(v_shot_idx) + if (v_shot_idx) { - self.oldorigin = '0 0 0'; // use regular attachment + this.oldorigin = '0 0 0'; // use regular attachment } else { - if(self.weaponentity) + if (this.weaponentity[slot]) { - idx = gettagindex(self, "weapon"); - if(!idx) - idx = gettagindex(self, "tag_weapon"); + idx = gettagindex(this, "weapon"); + if (!idx) idx = gettagindex(this, "tag_weapon"); } else { - idx = gettagindex(self, "handle"); - if(!idx) - idx = gettagindex(self, "tag_handle"); + idx = gettagindex(this, "handle"); + if (!idx) idx = gettagindex(this, "tag_handle"); } - if(idx) + if (idx) { - self.oldorigin = self.movedir - gettaginfo(self, idx); + this.oldorigin = this.movedir - gettaginfo(this, idx); } else { - print("WARNING: weapon model ", self.model, " does not support the 'handle' tag and neither does the v_ model support the 'shot' tag, will display muzzle flashes TOTALLY wrong\n"); - self.oldorigin = '0 0 0'; // there is no way to recover from this + LOG_INFO("WARNING: weapon model ", this.model, + " does not support the 'handle' tag and neither does the v_ model support the 'shot' tag, will display muzzle flashes TOTALLY wrong\n"); + this.oldorigin = '0 0 0'; // there is no way to recover from this } } - self.viewmodelforclient = self.owner; + this.viewmodelforclient = this.owner; } else { - self.model = ""; - if(self.weaponentity) - remove(self.weaponentity); - self.weaponentity = world; - self.movedir = '0 0 0'; - self.spawnorigin = '0 0 0'; - self.oldorigin = '0 0 0'; - self.anim_fire1 = '0 1 0.01'; - self.anim_fire2 = '0 1 0.01'; - self.anim_idle = '0 1 0.01'; - self.anim_reload = '0 1 0.01'; + this.model = ""; + if (this.weaponentity[slot]) remove(this.weaponentity[slot]); + this.weaponentity[slot] = NULL; + this.movedir = '0 0 0'; + this.spawnorigin = '0 0 0'; + this.oldorigin = '0 0 0'; + this.anim_fire1 = '0 1 0.01'; + this.anim_fire2 = '0 1 0.01'; + this.anim_idle = '0 1 0.01'; + this.anim_reload = '0 1 0.01'; } - self.view_ofs = '0 0 0'; + this.view_ofs = '0 0 0'; - if(self.movedir.x >= 0) + if (this.movedir.x >= 0) { - vector v0; - v0 = self.movedir; - self.movedir = shotorg_adjust(v0, false, false); - self.view_ofs = shotorg_adjust(v0, false, true) - v0; + vector v0 = this.movedir; + this.movedir = shotorg_adjust(v0, false, false, this.owner.cvar_cl_gunalign); + this.view_ofs = shotorg_adjust(v0, false, true, this.owner.cvar_cl_gunalign) - v0; } - self.owner.stat_shotorg = compressShotOrigin(self.movedir); - self.movedir = decompressShotOrigin(self.owner.stat_shotorg); // make them match perfectly + this.owner.stat_shotorg = compressShotOrigin(this.movedir); + this.movedir = decompressShotOrigin(this.owner.stat_shotorg); // make them match perfectly - self.spawnorigin += self.view_ofs; // offset the casings origin by the same amount + this.spawnorigin += this.view_ofs; // offset the casings origin by the same amount // check if an instant weapon switch occurred - setorigin(self, self.view_ofs); + setorigin(this, this.view_ofs); // reset animstate now - self.wframe = WFRAME_IDLE; - setanim(self, self.anim_idle, true, false, true); + this.wframe = WFRAME_IDLE; + setanim(this, this.anim_idle, true, false, true); } vector CL_Weapon_GetShotOrg(float wpn) { - entity wi, oldself; - vector ret; - wi = get_weaponinfo(wpn); - oldself = self; - self = spawn(); - CL_WeaponEntity_SetModel(wi.mdl); - ret = self.movedir; - CL_WeaponEntity_SetModel(""); - remove(self); - self = oldself; + entity wi = get_weaponinfo(wpn); + entity e = spawn(); + CL_WeaponEntity_SetModel(e, 0, wi.mdl); + vector ret = e.movedir; + CL_WeaponEntity_SetModel(e, 0, ""); + remove(e); return ret; } void CL_Weaponentity_Think() { - int tb; - self.nextthink = time; - if (intermission_running) - self.frame = self.anim_idle.x; - if (self.owner.weaponentity != self) - { - if (self.weaponentity) - remove(self.weaponentity); - remove(self); + SELFPARAM(); + this.nextthink = time; + if (intermission_running) this.frame = this.anim_idle.x; + int slot = 0; // TODO: unhardcode + if (this.owner.weaponentity[slot] != this) + { + if (this.weaponentity[slot]) remove(this.weaponentity[slot]); + remove(this); return; } - if (self.owner.deadflag != DEAD_NO) + if (this.owner.deadflag != DEAD_NO) { - self.model = ""; - if (self.weaponentity) - self.weaponentity.model = ""; + this.model = ""; + if (this.weaponentity[slot]) this.weaponentity[slot].model = ""; return; } - if (self.weaponname != self.owner.weaponname || self.dmg != self.owner.modelindex || self.deadflag != self.owner.deadflag) + if (this.weaponname != this.owner.weaponname || this.dmg != this.owner.modelindex + || this.deadflag != this.owner.deadflag) { - self.weaponname = self.owner.weaponname; - self.dmg = self.owner.modelindex; - self.deadflag = self.owner.deadflag; + this.weaponname = this.owner.weaponname; + this.dmg = this.owner.modelindex; + this.deadflag = this.owner.deadflag; - CL_WeaponEntity_SetModel(self.owner.weaponname); + CL_WeaponEntity_SetModel(this, slot, this.owner.weaponname); } - tb = (self.effects & (EF_TELEPORT_BIT | EF_RESTARTANIM_BIT)); - self.effects = self.owner.effects & EFMASK_CHEAP; - self.effects &= ~EF_LOWPRECISION; - self.effects &= ~EF_FULLBRIGHT; // can mask team color, so get rid of it - self.effects &= ~EF_TELEPORT_BIT; - self.effects &= ~EF_RESTARTANIM_BIT; - self.effects |= tb; - - if(self.owner.alpha == default_player_alpha) - self.alpha = default_weapon_alpha; - else if(self.owner.alpha != 0) - self.alpha = self.owner.alpha; - else - self.alpha = 1; - - self.glowmod = self.owner.weaponentity_glowmod; - self.colormap = self.owner.colormap; - if (self.weaponentity) + int tb = (this.effects & (EF_TELEPORT_BIT | EF_RESTARTANIM_BIT)); + this.effects = this.owner.effects & EFMASK_CHEAP; + this.effects &= ~EF_LOWPRECISION; + this.effects &= ~EF_FULLBRIGHT; // can mask team color, so get rid of it + this.effects &= ~EF_TELEPORT_BIT; + this.effects &= ~EF_RESTARTANIM_BIT; + this.effects |= tb; + + if (this.owner.alpha == default_player_alpha) this.alpha = default_weapon_alpha; + else if (this.owner.alpha != 0) this.alpha = this.owner.alpha; + else this.alpha = 1; + + this.glowmod = this.owner.weaponentity_glowmod; + this.colormap = this.owner.colormap; + if (this.weaponentity[slot]) { - self.weaponentity.effects = self.effects; - self.weaponentity.alpha = self.alpha; - self.weaponentity.colormap = self.colormap; - self.weaponentity.glowmod = self.glowmod; + this.weaponentity[slot].effects = this.effects; + this.weaponentity[slot].alpha = this.alpha; + this.weaponentity[slot].colormap = this.colormap; + this.weaponentity[slot].glowmod = this.glowmod; } - self.angles = '0 0 0'; + this.angles = '0 0 0'; - float f = (self.owner.weapon_nextthink - time); - if (self.state == WS_RAISE && !intermission_running) + float f = (this.owner.weapon_nextthink - time); + if (this.state == WS_RAISE && !intermission_running) { - entity newwep = get_weaponinfo(self.owner.switchweapon); + entity newwep = get_weaponinfo(this.owner.switchweapon); f = f * g_weaponratefactor / max(f, newwep.switchdelay_raise); - self.angles_x = -90 * f * f; + this.angles_x = -90 * f * f; } - else if (self.state == WS_DROP && !intermission_running) + else if (this.state == WS_DROP && !intermission_running) { - entity oldwep = get_weaponinfo(self.owner.weapon); + entity oldwep = get_weaponinfo(this.owner.weapon); f = 1 - f * g_weaponratefactor / max(f, oldwep.switchdelay_drop); - self.angles_x = -90 * f * f; + this.angles_x = -90 * f * f; } - else if (self.state == WS_CLEAR) + else if (this.state == WS_CLEAR) { f = 1; - self.angles_x = -90 * f * f; + this.angles_x = -90 * f * f; } } void CL_ExteriorWeaponentity_Think() { - float tag_found; - self.nextthink = time; - if (self.owner.exteriorweaponentity != self) + SELFPARAM(); + this.nextthink = time; + if (this.owner.exteriorweaponentity != this) { - remove(self); + remove(this); return; } - if (self.owner.deadflag != DEAD_NO) + if (this.owner.deadflag != DEAD_NO) { - self.model = ""; + this.model = ""; return; } - if (self.weaponname != self.owner.weaponname || self.dmg != self.owner.modelindex || self.deadflag != self.owner.deadflag) + if (this.weaponname != this.owner.weaponname || this.dmg != this.owner.modelindex + || this.deadflag != this.owner.deadflag) { - self.weaponname = self.owner.weaponname; - self.dmg = self.owner.modelindex; - self.deadflag = self.owner.deadflag; - if (self.owner.weaponname != "") - setmodel(self, strcat("models/weapons/v_", self.owner.weaponname, ".md3")); // precision set below - else - self.model = ""; - - if((tag_found = gettagindex(self.owner, "tag_weapon"))) + this.weaponname = this.owner.weaponname; + this.dmg = this.owner.modelindex; + this.deadflag = this.owner.deadflag; + if (this.owner.weaponname != "") _setmodel(this, W_Model(strcat("v_", this.owner.weaponname, ".md3"))); + else this.model = ""; + + int tag_found; + if ((tag_found = gettagindex(this.owner, "tag_weapon"))) { - self.tag_index = tag_found; - self.tag_entity = self.owner; + this.tag_index = tag_found; + this.tag_entity = this.owner; } else - setattachment(self, self.owner, "bip01 r hand"); - } - self.effects = self.owner.effects; - self.effects |= EF_LOWPRECISION; - self.effects = self.effects & EFMASK_CHEAP; // eat performance - if(self.owner.alpha == default_player_alpha) - self.alpha = default_weapon_alpha; - else if(self.owner.alpha != 0) - self.alpha = self.owner.alpha; - else - self.alpha = 1; + { + setattachment(this, this.owner, "bip01 r hand"); + } + } + this.effects = this.owner.effects; + this.effects |= EF_LOWPRECISION; + this.effects = this.effects & EFMASK_CHEAP; // eat performance + if (this.owner.alpha == default_player_alpha) this.alpha = default_weapon_alpha; + else if (this.owner.alpha != 0) this.alpha = this.owner.alpha; + else this.alpha = 1; - self.glowmod = self.owner.weaponentity_glowmod; - self.colormap = self.owner.colormap; + this.glowmod = this.owner.weaponentity_glowmod; + this.colormap = this.owner.colormap; - CSQCMODEL_AUTOUPDATE(); + CSQCMODEL_AUTOUPDATE(this); } // spawning weaponentity for client -void CL_SpawnWeaponentity() +void CL_SpawnWeaponentity(entity e, int slot) { - self.weaponentity = spawn(); - self.weaponentity.classname = "weaponentity"; - self.weaponentity.solid = SOLID_NOT; - self.weaponentity.owner = self; - setmodel(self.weaponentity, ""); // precision set when changed - setorigin(self.weaponentity, '0 0 0'); - self.weaponentity.angles = '0 0 0'; - self.weaponentity.viewmodelforclient = self; - self.weaponentity.flags = 0; - self.weaponentity.think = CL_Weaponentity_Think; - self.weaponentity.customizeentityforclient = CL_Weaponentity_CustomizeEntityForClient; - self.weaponentity.nextthink = time; - - self.exteriorweaponentity = spawn(); - self.exteriorweaponentity.classname = "exteriorweaponentity"; - self.exteriorweaponentity.solid = SOLID_NOT; - self.exteriorweaponentity.exteriorweaponentity = self.exteriorweaponentity; - self.exteriorweaponentity.owner = self; - setorigin(self.exteriorweaponentity, '0 0 0'); - self.exteriorweaponentity.angles = '0 0 0'; - self.exteriorweaponentity.think = CL_ExteriorWeaponentity_Think; - self.exteriorweaponentity.nextthink = time; - - { - entity oldself = self; - self = self.exteriorweaponentity; - CSQCMODEL_AUTOINIT(); - self = oldself; + entity view = e.weaponentity[slot] = new(weaponentity); + view.solid = SOLID_NOT; + view.owner = e; + setmodel(view, MDL_Null); // precision set when changed + setorigin(view, '0 0 0'); + view.angles = '0 0 0'; + view.viewmodelforclient = e; + view.flags = 0; + view.think = CL_Weaponentity_Think; + view.customizeentityforclient = CL_Weaponentity_CustomizeEntityForClient; + view.nextthink = time; + + if (slot == 0) + { + entity exterior = e.exteriorweaponentity = spawn(); + exterior.classname = "exteriorweaponentity"; + exterior.solid = SOLID_NOT; + exterior.exteriorweaponentity = exterior; + exterior.owner = e; + setorigin(exterior, '0 0 0'); + exterior.angles = '0 0 0'; + exterior.think = CL_ExteriorWeaponentity_Think; + exterior.nextthink = time; + + CSQCMODEL_AUTOINIT(exterior); } } // Weapon subs -void w_clear() +void w_clear(Weapon thiswep, entity actor, int slot, int fire) { - if (self.weapon != -1) + if (actor.weapon != -1) { - self.weapon = 0; - self.switchingweapon = 0; + actor.weapon = 0; + actor.switchingweapon = 0; } - if (self.weaponentity) + if (actor.weaponentity[slot]) { - self.weaponentity.state = WS_CLEAR; - self.weaponentity.effects = 0; + actor.weaponentity[slot].state = WS_CLEAR; + actor.weaponentity[slot].effects = 0; } } -void w_ready() +void w_ready(Weapon thiswep, entity actor, int slot, int fire) { - if (self.weaponentity) - self.weaponentity.state = WS_READY; - weapon_thinkf(WFRAME_IDLE, 1000000, w_ready); + if (actor.weaponentity[slot]) actor.weaponentity[slot].state = WS_READY; + weapon_thinkf(actor, slot, WFRAME_IDLE, 1000000, w_ready); } .float prevdryfire; .float prevwarntime; -float weapon_prepareattack_checkammo(float secondary) +bool weapon_prepareattack_checkammo(Weapon thiswep, entity actor, bool secondary) { - if (!(self.items & IT_UNLIMITED_WEAPON_AMMO)) - if (!WEP_ACTION(self.weapon, WR_CHECKAMMO1 + secondary)) + if ((actor.items & IT_UNLIMITED_WEAPON_AMMO)) return true; + bool ammo = false; + if (secondary) WITH(entity, self, actor, ammo = thiswep.wr_checkammo2(thiswep)); + else WITH(entity, self, actor, ammo = thiswep.wr_checkammo1(thiswep)); + if (ammo) return true; + // always keep the Mine Layer if we placed mines, so that we can detonate them + if (thiswep == WEP_MINE_LAYER) + for (entity mine; (mine = find(mine, classname, "mine")); ) + if (mine.owner == actor) return false; + + if (thiswep == WEP_SHOTGUN) + if (!secondary && WEP_CVAR(shotgun, secondary) == 1) return false; // no clicking, just allow + + if (thiswep == get_weaponinfo(actor.switchweapon) && time - actor.prevdryfire > 1) // only play once BEFORE starting to switch weapons { - // always keep the Mine Layer if we placed mines, so that we can detonate them - entity mine; - if(self.weapon == WEP_MINE_LAYER) - for(mine = world; (mine = find(mine, classname, "mine")); ) if(mine.owner == self) - return false; - - if(self.weapon == WEP_SHOTGUN) - if(!secondary && WEP_CVAR(shotgun, secondary) == 1) - return false; // no clicking, just allow - - if(self.weapon == self.switchweapon && time - self.prevdryfire > 1) // only play once BEFORE starting to switch weapons - { - sound (self, CH_WEAPON_A, "weapons/dryfire.wav", VOL_BASE, ATTEN_NORM); - self.prevdryfire = time; - } + sound(actor, CH_WEAPON_A, SND_DRYFIRE, VOL_BASE, ATTEN_NORM); + actor.prevdryfire = time; + } - if(WEP_ACTION(self.weapon, WR_CHECKAMMO2 - secondary)) // check if the other firing mode has enough ammo - { - if(time - self.prevwarntime > 1) - { - Send_Notification( - NOTIF_ONE, - self, - MSG_MULTI, - ITEM_WEAPON_PRIMORSEC, - self.weapon, - secondary, - (1 - secondary) - ); - } - self.prevwarntime = time; - } - else // this weapon is totally unable to fire, switch to another one + // check if the other firing mode has enough ammo + bool ammo_other = false; + if (secondary) WITH(entity, self, actor, ammo_other = thiswep.wr_checkammo1(thiswep)); + else WITH(entity, self, actor, ammo_other = thiswep.wr_checkammo2(thiswep)); + if (ammo_other) + { + if (time - actor.prevwarntime > 1) { - W_SwitchToOtherWeapon(self); + Send_Notification( + NOTIF_ONE, + actor, + MSG_MULTI, + ITEM_WEAPON_PRIMORSEC, + thiswep.m_id, + secondary, + (1 - secondary) + ); } - - return false; + actor.prevwarntime = time; } - return true; + else // this weapon is totally unable to fire, switch to another one + { + W_SwitchToOtherWeapon(actor); + } + + return false; } + .float race_penalty; -float weapon_prepareattack_check(float secondary, float attacktime) +bool weapon_prepareattack_check(Weapon thiswep, entity actor, int slot, bool secondary, float attacktime) { - if(!weapon_prepareattack_checkammo(secondary)) - return false; + if (!weapon_prepareattack_checkammo(thiswep, actor, secondary)) return false; - //if sv_ready_restart_after_countdown is set, don't allow the player to shoot - //if all players readied up and the countdown is running - if(time < game_starttime || time < self.race_penalty) { - return false; - } + // if sv_ready_restart_after_countdown is set, don't allow the player to shoot + // if all players readied up and the countdown is running + if (time < game_starttime || time < actor.race_penalty) return false; - if (timeout_status == TIMEOUT_ACTIVE) //don't allow the player to shoot while game is paused + if (timeout_status == TIMEOUT_ACTIVE) // don't allow the player to shoot while game is paused return false; // do not even think about shooting if switching - if(self.switchweapon != self.weapon) - return false; + if (actor.switchweapon != actor.weapon) return false; - if(attacktime >= 0) + if (attacktime >= 0) { // don't fire if previous attack is not finished - if (ATTACK_FINISHED(self) > time + self.weapon_frametime * 0.5) - return false; + if (ATTACK_FINISHED(actor, slot) > time + actor.weapon_frametime * 0.5) return false; // don't fire while changing weapon - if (self.weaponentity.state != WS_READY) - return false; + if (actor.weaponentity[slot].state != WS_READY) return false; } - return true; } -float weapon_prepareattack_do(float secondary, float attacktime) + +void weapon_prepareattack_do(entity actor, int slot, bool secondary, float attacktime) { - self.weaponentity.state = WS_INUSE; + actor.weaponentity[slot].state = WS_INUSE; - self.spawnshieldtime = min(self.spawnshieldtime, time); // kill spawn shield when you fire + actor.spawnshieldtime = min(actor.spawnshieldtime, time); // kill spawn shield when you fire // if the weapon hasn't been firing continuously, reset the timer - if(attacktime >= 0) + if (attacktime >= 0) { - if (ATTACK_FINISHED(self) < time - self.weapon_frametime * 1.5) + if (ATTACK_FINISHED(actor, slot) < time - actor.weapon_frametime * 1.5) { - ATTACK_FINISHED(self) = time; - //dprint("resetting attack finished to ", ftos(time), "\n"); + ATTACK_FINISHED(actor, slot) = time; + // dprint("resetting attack finished to ", ftos(time), "\n"); } - ATTACK_FINISHED(self) = ATTACK_FINISHED(self) + attacktime * W_WeaponRateFactor(); + ATTACK_FINISHED(actor, slot) = ATTACK_FINISHED(actor, slot) + attacktime * W_WeaponRateFactor(); } - self.bulletcounter += 1; - //dprint("attack finished ", ftos(ATTACK_FINISHED(self)), "\n"); - return true; + actor.bulletcounter += 1; + // dprint("attack finished ", ftos(ATTACK_FINISHED(actor, slot)), "\n"); } -float weapon_prepareattack(float secondary, float attacktime) + +bool weapon_prepareattack(Weapon thiswep, entity actor, int slot, bool secondary, float attacktime) { - if(weapon_prepareattack_check(secondary, attacktime)) + if (weapon_prepareattack_check(thiswep, actor, slot, secondary, attacktime)) { - weapon_prepareattack_do(secondary, attacktime); + weapon_prepareattack_do(actor, slot, secondary, attacktime); return true; } - else - return false; + return false; } -void weapon_thinkf(float fr, float t, void() func) +void weapon_thinkf(entity actor, int slot, float fr, float t, + void(Weapon thiswep, entity actor, int slot, int fire) func) { - vector a; - vector of, or, ou; - float restartanim; - - if(fr == WFRAME_DONTCHANGE) + bool restartanim; + if (fr == WFRAME_DONTCHANGE) { - fr = self.weaponentity.wframe; + fr = actor.weaponentity[slot].wframe; restartanim = false; } else if (fr == WFRAME_IDLE) + { restartanim = false; + } else + { restartanim = true; + } + + vector of = v_forward; + vector or = v_right; + vector ou = v_up; - of = v_forward; - or = v_right; - ou = v_up; - - if (self.weaponentity) - { - self.weaponentity.wframe = fr; - a = '0 0 0'; - if (fr == WFRAME_IDLE) - a = self.weaponentity.anim_idle; - else if (fr == WFRAME_FIRE1) - a = self.weaponentity.anim_fire1; - else if (fr == WFRAME_FIRE2) - a = self.weaponentity.anim_fire2; - else // if (fr == WFRAME_RELOAD) - a = self.weaponentity.anim_reload; + if (actor.weaponentity[slot]) + { + actor.weaponentity[slot].wframe = fr; + vector a = '0 0 0'; + if (fr == WFRAME_IDLE) a = actor.weaponentity[slot].anim_idle; + else if (fr == WFRAME_FIRE1) a = actor.weaponentity[slot].anim_fire1; + else if (fr == WFRAME_FIRE2) a = actor.weaponentity[slot].anim_fire2; + else // if (fr == WFRAME_RELOAD) + a = actor.weaponentity[slot].anim_reload; a.z *= g_weaponratefactor; - setanim(self.weaponentity, a, restartanim == false, restartanim, restartanim); + setanim(actor.weaponentity[slot], a, restartanim == false, restartanim, restartanim); } v_forward = of; v_right = or; v_up = ou; - if(self.weapon_think == w_ready && func != w_ready && self.weaponentity.state == WS_RAISE) - { - backtrace("Tried to override initial weapon think function - should this really happen?"); - } + if (actor.weapon_think == w_ready && func != w_ready && actor.weaponentity[slot].state == WS_RAISE) backtrace( + "Tried to override initial weapon think function - should this really happen?"); t *= W_WeaponRateFactor(); // VorteX: haste can be added here - if (self.weapon_think == w_ready) + if (actor.weapon_think == w_ready) { - self.weapon_nextthink = time; - //dprint("started firing at ", ftos(time), "\n"); + actor.weapon_nextthink = time; + // dprint("started firing at ", ftos(time), "\n"); } - if (self.weapon_nextthink < time - self.weapon_frametime * 1.5 || self.weapon_nextthink > time + self.weapon_frametime * 1.5) + if (actor.weapon_nextthink < time - actor.weapon_frametime * 1.5 + || actor.weapon_nextthink > time + actor.weapon_frametime * 1.5) { - self.weapon_nextthink = time; - //dprint("reset weapon animation timer at ", ftos(time), "\n"); + actor.weapon_nextthink = time; + // dprint("reset weapon animation timer at ", ftos(time), "\n"); } - self.weapon_nextthink = self.weapon_nextthink + t; - self.weapon_think = func; - //dprint("next ", ftos(self.weapon_nextthink), "\n"); + actor.weapon_nextthink = actor.weapon_nextthink + t; + actor.weapon_think = func; + // dprint("next ", ftos(actor.weapon_nextthink), "\n"); - if((fr == WFRAME_FIRE1 || fr == WFRAME_FIRE2) && t) + if ((fr == WFRAME_FIRE1 || fr == WFRAME_FIRE2) && t) { - if((self.weapon == WEP_SHOCKWAVE || self.weapon == WEP_SHOTGUN) && fr == WFRAME_FIRE2) - animdecide_setaction(self, ANIMACTION_MELEE, restartanim); - else - animdecide_setaction(self, ANIMACTION_SHOOT, restartanim); + if ((actor.weapon == WEP_SHOCKWAVE.m_id || actor.weapon == WEP_SHOTGUN.m_id) + && fr == WFRAME_FIRE2) animdecide_setaction(actor, ANIMACTION_MELEE, restartanim); + else animdecide_setaction(actor, ANIMACTION_SHOOT, restartanim); } else { - if(self.anim_upper_action == ANIMACTION_SHOOT || self.anim_upper_action == ANIMACTION_MELEE) - self.anim_upper_action = 0; + if (actor.anim_upper_action == ANIMACTION_SHOOT + || actor.anim_upper_action == ANIMACTION_MELEE) actor.anim_upper_action = 0; } } -float forbidWeaponUse() +bool forbidWeaponUse(entity player) { - if(time < game_starttime && !autocvar_sv_ready_restart_after_countdown) - return 1; - if(round_handler_IsActive() && !round_handler_IsRoundStarted()) - return 1; - if(self.player_blocked) - return 1; - if(self.frozen) - return 1; - if(self.weapon_blocked) - return 1; - return 0; + if (time < game_starttime && !autocvar_sv_ready_restart_after_countdown) return true; + if (round_handler_IsActive() && !round_handler_IsRoundStarted()) return true; + if (player.player_blocked) return true; + if (player.frozen) return true; + if (player.weapon_blocked) return true; + return false; } -void W_WeaponFrame() -{ - vector fo, ri, up; +.bool hook_switchweapon; - if (frametime) - self.weapon_frametime = frametime; +void W_WeaponFrame(entity actor) +{ + int slot = 0; // TODO: unhardcode + if (frametime) actor.weapon_frametime = frametime; - if (!self.weaponentity || self.health < 1) - return; // Dead player can't use weapons and injure impulse commands + if (!actor.weaponentity[slot] || actor.health < 1) return; // Dead player can't use weapons and injure impulse commands - if(forbidWeaponUse()) - if(self.weaponentity.state != WS_CLEAR) + if (forbidWeaponUse(actor)) { - w_ready(); - return; + if (actor.weaponentity[slot].state != WS_CLEAR) + { + Weapon wpn = get_weaponinfo(actor.weapon); + w_ready(wpn, actor, 0, (actor.BUTTON_ATCK ? 1 : 0) | (actor.BUTTON_ATCK2 ? 2 : 0)); + return; + } } - if(!self.switchweapon) + if (!actor.switchweapon) { - self.weapon = 0; - self.switchingweapon = 0; - self.weaponentity.state = WS_CLEAR; - self.weaponname = ""; - //self.items &= ~IT_AMMO; + actor.weapon = 0; + actor.switchingweapon = 0; + actor.weaponentity[slot].state = WS_CLEAR; + actor.weaponname = ""; + // actor.items &= ~IT_AMMO; return; } - makevectors(self.v_angle); - fo = v_forward; // save them in case the weapon think functions change it - ri = v_right; - up = v_up; + makevectors(actor.v_angle); + vector fo = v_forward; // save them in case the weapon think functions change it + vector ri = v_right; + vector up = v_up; // Change weapon - if (self.weapon != self.switchweapon) + if (actor.weapon != actor.switchweapon) { - if (self.weaponentity.state == WS_CLEAR) + if (actor.weaponentity[slot].state == WS_CLEAR) { // end switching! - self.switchingweapon = self.switchweapon; - entity newwep = get_weaponinfo(self.switchweapon); + actor.switchingweapon = actor.switchweapon; + entity newwep = get_weaponinfo(actor.switchweapon); // the two weapon entities will notice this has changed and update their models - self.weapon = self.switchweapon; - self.weaponname = newwep.mdl; - self.bulletcounter = 0; - self.ammo_field = newwep.ammo_field; - WEP_ACTION(self.switchweapon, WR_SETUP); - self.weaponentity.state = WS_RAISE; + actor.weapon = actor.switchweapon; + actor.weaponname = newwep.mdl; + actor.bulletcounter = 0; + actor.ammo_field = newwep.ammo_field; + Weapon w = get_weaponinfo(actor.switchweapon); + w.wr_setup(w); + actor.weaponentity[slot].state = WS_RAISE; // set our clip load to the load of the weapon we switched to, if it's reloadable - if(newwep.spawnflags & WEP_FLAG_RELOADABLE && newwep.reloading_ammo) // prevent accessing undefined cvars + if (newwep.spawnflags & WEP_FLAG_RELOADABLE && newwep.reloading_ammo) // prevent accessing undefined cvars { - self.clip_load = self.(weapon_load[self.switchweapon]); - self.clip_size = newwep.reloading_ammo; + actor.clip_load = actor.(weapon_load[actor.switchweapon]); + actor.clip_size = newwep.reloading_ammo; } else - self.clip_load = self.clip_size = 0; + { + actor.clip_load = actor.clip_size = 0; + } - weapon_thinkf(WFRAME_IDLE, newwep.switchdelay_raise, w_ready); + weapon_thinkf(actor, slot, WFRAME_IDLE, newwep.switchdelay_raise, w_ready); } - else if (self.weaponentity.state == WS_DROP) + else if (actor.weaponentity[slot].state == WS_DROP) { // in dropping phase we can switch at any time - self.switchingweapon = self.switchweapon; + actor.switchingweapon = actor.switchweapon; } - else if (self.weaponentity.state == WS_READY) + else if (actor.weaponentity[slot].state == WS_READY) { // start switching! - self.switchingweapon = self.switchweapon; - entity oldwep = get_weaponinfo(self.weapon); + actor.switchingweapon = actor.switchweapon; + entity oldwep = get_weaponinfo(actor.weapon); // set up weapon switch think in the future, and start drop anim - #ifndef INDEPENDENT_ATTACK_FINISHED - if(ATTACK_FINISHED(self) <= time + self.weapon_frametime * 0.5) + if ( +#if INDEPENDENT_ATTACK_FINISHED + true +#else + ATTACK_FINISHED(actor, slot) <= time + actor.weapon_frametime * 0.5 +#endif + ) { - #endif - sound(self, CH_WEAPON_SINGLE, "weapons/weapon_switch.wav", VOL_BASE, ATTN_NORM); - self.weaponentity.state = WS_DROP; - weapon_thinkf(WFRAME_DONTCHANGE, oldwep.switchdelay_drop, w_clear); - #ifndef INDEPENDENT_ATTACK_FINISHED + sound(actor, CH_WEAPON_SINGLE, SND_WEAPON_SWITCH, VOL_BASE, ATTN_NORM); + actor.weaponentity[slot].state = WS_DROP; + weapon_thinkf(actor, slot, WFRAME_DONTCHANGE, oldwep.switchdelay_drop, w_clear); } - #endif } } // LordHavoc: network timing test code - //if (self.button0) - // print(ftos(frametime), " ", ftos(time), " >= ", ftos(ATTACK_FINISHED(self)), " >= ", ftos(self.weapon_nextthink), "\n"); + // if (actor.button0) + // print(ftos(frametime), " ", ftos(time), " >= ", ftos(ATTACK_FINISHED(actor, slot)), " >= ", ftos(actor.weapon_nextthink), "\n"); - float w; - w = self.weapon; + int w = actor.weapon; // call the think code which may fire the weapon // and do so multiple times to resolve framerate dependency issues if the // server framerate is very low and the weapon fire rate very high - float c; - c = 0; + int c = 0; while (c < W_TICSPERFRAME) { - c = c + 1; - if(w && !(self.weapons & WepSet_FromWeapon(w))) + c += 1; + if (w && !(actor.weapons & WepSet_FromWeapon(w))) { - if(self.weapon == self.switchweapon) - W_SwitchWeapon_Force(self, w_getbestweapon(self)); + if (actor.weapon == actor.switchweapon) W_SwitchWeapon_Force(actor, w_getbestweapon(actor)); w = 0; } @@ -779,82 +794,108 @@ void W_WeaponFrame() v_right = ri; v_up = up; - if(w) - WEP_ACTION(self.weapon, WR_THINK); - else - WEP_ACTION(self.weapon, WR_GONETHINK); + bool block_weapon = false; + { + bool key_pressed = actor.BUTTON_HOOK && !actor.vehicle; + Weapon off = actor.offhand; + if (off && !(actor.weapons & WEPSET(HOOK))) + { + if (off.offhand_think) off.offhand_think(off, actor, key_pressed); + } + else + { + if (key_pressed && actor.switchweapon != WEP_HOOK.m_id && !actor.hook_switchweapon) W_SwitchWeapon( + WEP_HOOK.m_id); + actor.hook_switchweapon = key_pressed; + Weapon h = WEP_HOOK; + block_weapon = (actor.weapon == h.m_id && (actor.BUTTON_ATCK || key_pressed)); + h.wr_think(h, actor, 0, block_weapon ? 1 : 0); + } + } - if (time + self.weapon_frametime * 0.5 >= self.weapon_nextthink) + if (!block_weapon) { - if(self.weapon_think) + if (w) + { + Weapon e = get_weaponinfo(actor.weapon); + e.wr_think(e, actor, 0, (actor.BUTTON_ATCK ? 1 : 0) | (actor.BUTTON_ATCK2 ? 2 : 0)); + } + else + { + Weapon w = get_weaponinfo(actor.weapon); + w.wr_gonethink(w); + } + } + + if (time + actor.weapon_frametime * 0.5 >= actor.weapon_nextthink) + { + if (actor.weapon_think) { v_forward = fo; v_right = ri; v_up = up; - self.weapon_think(); + Weapon wpn = get_weaponinfo(actor.weapon); + actor.weapon_think(wpn, actor, 0, (actor.BUTTON_ATCK ? 1 : 0) | (actor.BUTTON_ATCK2 ? 2 : 0)); } else - bprint("\{1}^1ERROR: undefined weapon think function for ", self.netname, "\n"); + { + bprint("\{1}^1ERROR: undefined weapon think function for ", actor.netname, "\n"); + } } } } -void W_AttachToShotorg(entity flash, vector offset) +void W_AttachToShotorg(entity actor, entity flash, vector offset) { - entity xflash; - flash.owner = self; + int slot = 0; + flash.owner = actor; flash.angles_z = random() * 360; - if(gettagindex(self.weaponentity, "shot")) - setattachment(flash, self.weaponentity, "shot"); - else - setattachment(flash, self.weaponentity, "tag_shot"); + if (gettagindex(actor.weaponentity[slot], "shot")) setattachment(flash, actor.weaponentity[slot], "shot"); + else setattachment(flash, actor.weaponentity[slot], "tag_shot"); setorigin(flash, offset); - xflash = spawn(); + entity xflash = spawn(); copyentity(flash, xflash); - flash.viewmodelforclient = self; + flash.viewmodelforclient = actor; - if(self.weaponentity.oldorigin.x > 0) + if (actor.weaponentity[slot].oldorigin.x > 0) { - setattachment(xflash, self.exteriorweaponentity, ""); - setorigin(xflash, self.weaponentity.oldorigin + offset); + setattachment(xflash, actor.exteriorweaponentity, ""); + setorigin(xflash, actor.weaponentity[slot].oldorigin + offset); } else { - if(gettagindex(self.exteriorweaponentity, "shot")) - setattachment(xflash, self.exteriorweaponentity, "shot"); - else - setattachment(xflash, self.exteriorweaponentity, "tag_shot"); + if (gettagindex(actor.exteriorweaponentity, "shot")) setattachment(xflash, actor.exteriorweaponentity, "shot"); + else setattachment(xflash, actor.exteriorweaponentity, "tag_shot"); setorigin(xflash, offset); } } -void W_DecreaseAmmo(float ammo_use) +void W_DecreaseAmmo(Weapon wep, entity actor, float ammo_use) { - entity wep = get_weaponinfo(self.weapon); - - if(cvar("g_overkill")) - if(self.ok_use_ammocharge) + if (cvar("g_overkill")) { - ok_DecreaseCharge(self, self.weapon); - return; // TODO + if (actor.ok_use_ammocharge) + { + ok_DecreaseCharge(actor, actor.weapon); + return; // TODO + } } - if((self.items & IT_UNLIMITED_WEAPON_AMMO) && !wep.reloading_ammo) - return; + if ((actor.items & IT_UNLIMITED_WEAPON_AMMO) && !wep.reloading_ammo) return; // if this weapon is reloadable, decrease its load. Else decrease the player's ammo - if(wep.reloading_ammo) + if (wep.reloading_ammo) { - self.clip_load -= ammo_use; - self.(weapon_load[self.weapon]) = self.clip_load; + actor.clip_load -= ammo_use; + actor.(weapon_load[actor.weapon]) = actor.clip_load; } - else if(wep.ammo_field != ammo_none) + else if (wep.ammo_field != ammo_none) { - self.(wep.ammo_field) -= ammo_use; - if(self.(wep.ammo_field) < 0) + actor.(wep.ammo_field) -= ammo_use; + if (actor.(wep.ammo_field) < 0) { backtrace(sprintf( "W_DecreaseAmmo(%.2f): '%s' subtracted too much %s from '%s', resulting with '%.2f' left... " @@ -862,9 +903,9 @@ void W_DecreaseAmmo(float ammo_use) ammo_use, wep.netname, GetAmmoPicture(wep.ammo_field), - self.netname, - self.(wep.ammo_field) - )); + actor.netname, + actor.(wep.ammo_field) + )); } } } @@ -875,115 +916,118 @@ void W_DecreaseAmmo(float ammo_use) .float reload_complain; .string reload_sound; -void W_ReloadedAndReady() +void W_ReloadedAndReady(Weapon thiswep, entity actor, int slot, int fire) { // finish the reloading process, and do the ammo transfer - self.clip_load = self.old_clip_load; // restore the ammo counter, in case we still had ammo in the weapon before reloading + actor.clip_load = actor.old_clip_load; // restore the ammo counter, in case we still had ammo in the weapon before reloading // if the gun uses no ammo, max out weapon load, else decrease ammo as we increase weapon load - if(!self.reload_ammo_min || self.items & IT_UNLIMITED_WEAPON_AMMO || self.ammo_field == ammo_none) - self.clip_load = self.reload_ammo_amount; + if (!actor.reload_ammo_min || actor.items & IT_UNLIMITED_WEAPON_AMMO || actor.ammo_field == ammo_none) + { + actor.clip_load = actor.reload_ammo_amount; + } else { // make sure we don't add more ammo than we have - float load = min(self.reload_ammo_amount - self.clip_load, self.(self.ammo_field)); - self.clip_load += load; - self.(self.ammo_field) -= load; + float load = min(actor.reload_ammo_amount - actor.clip_load, actor.(actor.ammo_field)); + actor.clip_load += load; + actor.(actor.ammo_field) -= load; } - self.(weapon_load[self.weapon]) = self.clip_load; + actor.(weapon_load[actor.weapon]) = actor.clip_load; // do not set ATTACK_FINISHED in reload code any more. This causes annoying delays if eg: You start reloading a weapon, // then quickly switch to another weapon and back. Reloading is canceled, but the reload delay is still there, // so your weapon is disabled for a few seconds without reason - //ATTACK_FINISHED(self) -= self.reload_time - 1; + // ATTACK_FINISHED(actor, slot) -= actor.reload_time - 1; - w_ready(); + Weapon wpn = get_weaponinfo(actor.weapon); + w_ready(wpn, actor, slot, (actor.BUTTON_ATCK ? 1 : 0) | (actor.BUTTON_ATCK2 ? 2 : 0)); } -void W_Reload(float sent_ammo_min, string sent_sound) +void W_Reload(entity actor, float sent_ammo_min, string sent_sound) { + int slot = 0; // set global values to work with - entity e; - e = get_weaponinfo(self.weapon); + entity e = get_weaponinfo(actor.weapon); - if(cvar("g_overkill")) - if(self.ok_use_ammocharge) - return; // TODO + if (cvar("g_overkill")) + if (actor.ok_use_ammocharge) return; + // TODO - self.reload_ammo_min = sent_ammo_min; - self.reload_ammo_amount = e.reloading_ammo; - self.reload_time = e.reloading_time; - self.reload_sound = sent_sound; + actor.reload_ammo_min = sent_ammo_min; + actor.reload_ammo_amount = e.reloading_ammo; + actor.reload_time = e.reloading_time; + actor.reload_sound = sent_sound; // don't reload weapons that don't have the RELOADABLE flag if (!(e.spawnflags & WEP_FLAG_RELOADABLE)) { - dprint("Warning: Attempted to reload a weapon that does not have the WEP_FLAG_RELOADABLE flag. Fix your code!\n"); + LOG_TRACE( + "Warning: Attempted to reload a weapon that does not have the WEP_FLAG_RELOADABLE flag. Fix your code!\n"); return; } // return if reloading is disabled for this weapon - if(!self.reload_ammo_amount) - return; + if (!actor.reload_ammo_amount) return; // our weapon is fully loaded, no need to reload - if (self.clip_load >= self.reload_ammo_amount) - return; + if (actor.clip_load >= actor.reload_ammo_amount) return; // no ammo, so nothing to load - if(self.ammo_field != ammo_none) - if(!self.(self.ammo_field) && self.reload_ammo_min) - if (!(self.items & IT_UNLIMITED_WEAPON_AMMO)) + if (actor.ammo_field != ammo_none) { - if(IS_REAL_CLIENT(self) && self.reload_complain < time) - { - play2(self, "weapons/unavailable.wav"); - sprint(self, strcat("You don't have enough ammo to reload the ^2", WEP_NAME(self.weapon), "\n")); - self.reload_complain = time + 1; - } - // switch away if the amount of ammo is not enough to keep using this weapon - if (!(WEP_ACTION(self.weapon, WR_CHECKAMMO1) + WEP_ACTION(self.weapon, WR_CHECKAMMO2))) + if (!actor.(actor.ammo_field) && actor.reload_ammo_min) { - self.clip_load = -1; // reload later - W_SwitchToOtherWeapon(self); + if (!(actor.items & IT_UNLIMITED_WEAPON_AMMO)) + { + if (IS_REAL_CLIENT(actor) && actor.reload_complain < time) + { + play2(actor, SND(UNAVAILABLE)); + sprint(actor, strcat("You don't have enough ammo to reload the ^2", WEP_NAME(actor.weapon), "\n")); + actor.reload_complain = time + 1; + } + // switch away if the amount of ammo is not enough to keep using this weapon + Weapon w = get_weaponinfo(actor.weapon); + if (!(w.wr_checkammo1(w) + w.wr_checkammo2(w))) + { + actor.clip_load = -1; // reload later + W_SwitchToOtherWeapon(actor); + } + return; + } } - return; } - if (self.weaponentity) + if (actor.weaponentity[slot]) { - if (self.weaponentity.wframe == WFRAME_RELOAD) - return; + if (actor.weaponentity[slot].wframe == WFRAME_RELOAD) return; // allow switching away while reloading, but this will cause a new reload! - self.weaponentity.state = WS_READY; + actor.weaponentity[slot].state = WS_READY; } // now begin the reloading process - sound(self, CH_WEAPON_SINGLE, self.reload_sound, VOL_BASE, ATTEN_NORM); + _sound(actor, CH_WEAPON_SINGLE, actor.reload_sound, VOL_BASE, ATTEN_NORM); // do not set ATTACK_FINISHED in reload code any more. This causes annoying delays if eg: You start reloading a weapon, // then quickly switch to another weapon and back. Reloading is canceled, but the reload delay is still there, // so your weapon is disabled for a few seconds without reason - //ATTACK_FINISHED(self) = max(time, ATTACK_FINISHED(self)) + self.reload_time + 1; + // ATTACK_FINISHED(actor, slot) = max(time, ATTACK_FINISHED(actor, slot)) + actor.reload_time + 1; - weapon_thinkf(WFRAME_RELOAD, self.reload_time, W_ReloadedAndReady); + weapon_thinkf(actor, slot, WFRAME_RELOAD, actor.reload_time, W_ReloadedAndReady); - if(self.clip_load < 0) - self.clip_load = 0; - self.old_clip_load = self.clip_load; - self.clip_load = self.(weapon_load[self.weapon]) = -1; + if (actor.clip_load < 0) actor.clip_load = 0; + actor.old_clip_load = actor.clip_load; + actor.clip_load = actor.(weapon_load[actor.weapon]) = -1; } -void W_DropEvent(float event, entity player, float weapon_type, entity weapon_item) +void W_DropEvent(.void(Weapon) event, entity player, float weapon_type, entity weapon_item) { - entity oldself = self; - self = player; + Weapon w = get_weaponinfo(weapon_type); weapon_dropevent_item = weapon_item; - WEP_ACTION(weapon_type, event); - self = oldself; + WITH(entity, self, player, w.event(w)); }