X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Fweapons%2Fweaponsystem.qc;h=a6961aec87196383bb63f383e850fc873c7f92fb;hb=8890092ab43c20f30fbed1a24a8bb739e2957a4d;hp=d01135310bce530f148d6cd2999284b920f122d3;hpb=37903827937b44f174275a75d2dab5301b8ab53e;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/weapons/weaponsystem.qc b/qcsrc/server/weapons/weaponsystem.qc index d01135310..a6961aec8 100644 --- a/qcsrc/server/weapons/weaponsystem.qc +++ b/qcsrc/server/weapons/weaponsystem.qc @@ -1,23 +1,19 @@ -#if defined(CSQC) -#elif defined(MENUQC) -#elif defined(SVQC) - #include "../../dpdefs/progsdefs.qh" - #include "../../dpdefs/dpextensions.qh" - #include "../../common/constants.qh" - #include "../../common/util.qh" - #include "../../common/animdecide.qh" - #include "../../common/monsters/monsters.qh" - #include "../../common/weapons/weapons.qh" - #include "weaponsystem.qh" - #include "../t_items.qh" - #include "../autocvars.qh" - #include "../defs.qh" - #include "../../common/notifications.qh" - #include "../mutators/mutators_include.qh" - #include "../command/common.qh" - #include "../../csqcmodellib/sv_model.qh" - #include "../round_handler.qh" -#endif +#include "weaponsystem.qh" +#include "../_all.qh" + +#include "selection.qh" + +#include "../command/common.qh" +#include "../mutators/mutators_include.qh" +#include "../round_handler.qh" +#include "../t_items.qh" +#include "../../common/animdecide.qh" +#include "../../common/constants.qh" +#include "../../common/monsters/all.qh" +#include "../../common/notifications.qh" +#include "../../common/util.qh" +#include "../../common/weapons/all.qh" +#include "../../csqcmodellib/sv_model.qh" /* =========================================================================== @@ -32,21 +28,29 @@ 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; } +float W_WeaponSpeedFactor() +{ + float t = 1.0 * g_weaponspeedfactor; + + MUTATOR_CALLHOOK(WeaponSpeedFactor, t); + t = ret_float; -void(float fr, float t, void() func) weapon_thinkf; + return t; +} + + +void weapon_thinkf(float fr, float t, void(Weapon thiswep, bool fire1, bool fire2) func); float CL_Weaponentity_CustomizeEntityForClient() -{ +{SELFPARAM(); self.viewmodelforclient = self.owner; if(IS_SPEC(other)) if(other.enemy == self.owner) @@ -106,19 +110,19 @@ float CL_Weaponentity_CustomizeEntityForClient() // call again with "" // remove the ent void CL_WeaponEntity_SetModel(string name) -{ +{SELFPARAM(); 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 + _setmodel(self, W_Model(strcat("v_", name, ".md3"))); 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 + _setmodel(self, 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'); @@ -131,14 +135,14 @@ void CL_WeaponEntity_SetModel(string name) { if (!self.weaponentity) self.weaponentity = spawn(); - setmodel(self.weaponentity, strcat("models/weapons/v_", name, ".md3")); // precision does not matter + _setmodel(self.weaponentity, W_Model(strcat("v_", name, ".md3"))); setattachment(self.weaponentity, self, "weapon"); } else if(gettagindex(self, "tag_weapon")) { if (!self.weaponentity) self.weaponentity = spawn(); - setmodel(self.weaponentity, strcat("models/weapons/v_", name, ".md3")); // precision does not matter + _setmodel(self.weaponentity, W_Model(strcat("v_", name, ".md3"))); setattachment(self.weaponentity, self, "tag_weapon"); } else @@ -168,7 +172,7 @@ void CL_WeaponEntity_SetModel(string name) self.movedir = gettaginfo(self, idx); else { - print("WARNING: weapon model ", self.model, " does not support the 'shot' tag, will display shots TOTALLY wrong\n"); + LOG_INFO("WARNING: weapon model ", self.model, " does not support the 'shot' tag, will display shots TOTALLY wrong\n"); self.movedir = '0 0 0'; } } @@ -192,7 +196,7 @@ void CL_WeaponEntity_SetModel(string name) self.spawnorigin = gettaginfo(self, idx); else { - print("WARNING: weapon model ", self.model, " does not support the 'shell' tag, will display casings wrong\n"); + LOG_INFO("WARNING: weapon model ", self.model, " does not support the 'shell' tag, will display casings wrong\n"); self.spawnorigin = self.movedir; } } @@ -221,7 +225,7 @@ void CL_WeaponEntity_SetModel(string name) } 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"); + LOG_INFO("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 } } @@ -265,22 +269,19 @@ void CL_WeaponEntity_SetModel(string name) } vector CL_Weapon_GetShotOrg(float wpn) -{ - entity wi, oldself; - vector ret; - wi = get_weaponinfo(wpn); - oldself = self; - self = spawn(); +{SELFPARAM(); + entity wi = get_weaponinfo(wpn); + setself(spawn()); CL_WeaponEntity_SetModel(wi.mdl); - ret = self.movedir; + vector ret = self.movedir; CL_WeaponEntity_SetModel(""); remove(self); - self = oldself; + setself(this); return ret; } void CL_Weaponentity_Think() -{ +{SELFPARAM(); int tb; self.nextthink = time; if (intermission_running) @@ -356,7 +357,7 @@ void CL_Weaponentity_Think() } void CL_ExteriorWeaponentity_Think() -{ +{SELFPARAM(); float tag_found; self.nextthink = time; if (self.owner.exteriorweaponentity != self) @@ -375,7 +376,7 @@ void CL_ExteriorWeaponentity_Think() 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 + _setmodel(self, W_Model(strcat("v_", self.owner.weaponname, ".md3"))); else self.model = ""; @@ -400,46 +401,41 @@ void CL_ExteriorWeaponentity_Think() self.glowmod = self.owner.weaponentity_glowmod; self.colormap = self.owner.colormap; - CSQCMODEL_AUTOUPDATE(); + CSQCMODEL_AUTOUPDATE(self); } // spawning weaponentity for client -void CL_SpawnWeaponentity() +void CL_SpawnWeaponentity(entity e) { - 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 = spawn(); + view.classname = "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; + + 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, bool fire1, bool fire2) +{SELFPARAM(); if (self.weapon != -1) { self.weapon = 0; @@ -452,8 +448,8 @@ void w_clear() } } -void w_ready() -{ +void w_ready(Weapon thiswep, bool fire1, bool fire2) +{SELFPARAM(); if (self.weaponentity) self.weaponentity.state = WS_READY; weapon_thinkf(WFRAME_IDLE, 1000000, w_ready); @@ -462,27 +458,27 @@ void w_ready() .float prevdryfire; .float prevwarntime; float weapon_prepareattack_checkammo(float secondary) -{ +{SELFPARAM(); if (!(self.items & IT_UNLIMITED_WEAPON_AMMO)) - if (!WEP_ACTION(self.weapon, WR_CHECKAMMO1 + secondary)) + if (!_WEP_ACTION(self.weapon, WR_CHECKAMMO1 + secondary)) { // always keep the Mine Layer if we placed mines, so that we can detonate them entity mine; - if(self.weapon == WEP_MINE_LAYER) + if(self.weapon == WEP_MINE_LAYER.m_id) for(mine = world; (mine = find(mine, classname, "mine")); ) if(mine.owner == self) return false; - if(self.weapon == WEP_SHOTGUN) + if(self.weapon == WEP_SHOTGUN.m_id) 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); + sound (self, CH_WEAPON_A, SND_DRYFIRE, VOL_BASE, ATTEN_NORM); self.prevdryfire = time; } - if(WEP_ACTION(self.weapon, WR_CHECKAMMO2 - secondary)) // check if the other firing mode has enough ammo + if(_WEP_ACTION(self.weapon, WR_CHECKAMMO2 - secondary)) // check if the other firing mode has enough ammo { if(time - self.prevwarntime > 1) { @@ -509,7 +505,7 @@ float weapon_prepareattack_checkammo(float secondary) } .float race_penalty; float weapon_prepareattack_check(float secondary, float attacktime) -{ +{SELFPARAM(); if(!weapon_prepareattack_checkammo(secondary)) return false; @@ -539,7 +535,7 @@ float weapon_prepareattack_check(float secondary, float attacktime) return true; } float weapon_prepareattack_do(float secondary, float attacktime) -{ +{SELFPARAM(); self.weaponentity.state = WS_INUSE; self.spawnshieldtime = min(self.spawnshieldtime, time); // kill spawn shield when you fire @@ -569,8 +565,8 @@ float weapon_prepareattack(float secondary, float attacktime) return false; } -void weapon_thinkf(float fr, float t, void() func) -{ +void weapon_thinkf(float fr, float t, void(Weapon thiswep, bool fire1, bool fire2) func) +{SELFPARAM(); vector a; vector of, or, ou; float restartanim; @@ -633,7 +629,7 @@ void weapon_thinkf(float fr, float t, void() func) if((fr == WFRAME_FIRE1 || fr == WFRAME_FIRE2) && t) { - if((self.weapon == WEP_SHOCKWAVE || self.weapon == WEP_SHOTGUN) && fr == WFRAME_FIRE2) + if((self.weapon == WEP_SHOCKWAVE.m_id || self.weapon == WEP_SHOTGUN.m_id) && fr == WFRAME_FIRE2) animdecide_setaction(self, ANIMACTION_MELEE, restartanim); else animdecide_setaction(self, ANIMACTION_SHOOT, restartanim); @@ -661,7 +657,7 @@ float forbidWeaponUse(entity player) } void W_WeaponFrame() -{ +{SELFPARAM(); vector fo, ri, up; if (frametime) @@ -673,7 +669,8 @@ void W_WeaponFrame() if(forbidWeaponUse(self)) if(self.weaponentity.state != WS_CLEAR) { - w_ready(); + Weapon wpn = get_weaponinfo(self.weapon); + w_ready(wpn, self.BUTTON_ATCK, self.BUTTON_ATCK2); return; } @@ -706,7 +703,7 @@ void W_WeaponFrame() self.weaponname = newwep.mdl; self.bulletcounter = 0; self.ammo_field = newwep.ammo_field; - WEP_ACTION(self.switchweapon, WR_SETUP); + _WEP_ACTION(self.switchweapon, WR_SETUP); self.weaponentity.state = WS_RAISE; // set our clip load to the load of the weapon we switched to, if it's reloadable @@ -736,7 +733,7 @@ void W_WeaponFrame() if(ATTACK_FINISHED(self) <= time + self.weapon_frametime * 0.5) { #endif - sound(self, CH_WEAPON_SINGLE, "weapons/weapon_switch.wav", VOL_BASE, ATTN_NORM); + sound(self, CH_WEAPON_SINGLE, SND_WEAPON_SWITCH, VOL_BASE, ATTN_NORM); self.weaponentity.state = WS_DROP; weapon_thinkf(WFRAME_DONTCHANGE, oldwep.switchdelay_drop, w_clear); #ifndef INDEPENDENT_ATTACK_FINISHED @@ -771,10 +768,18 @@ 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 key_pressed = self.BUTTON_HOOK; + Weapon wpn = self.offhand; + if (wpn.offhand_think) wpn.offhand_think(wpn, self, key_pressed); + } + + if (w) { + entity e = get_weaponinfo(self.weapon); + if (e.wr_think) e.wr_think(e, self.BUTTON_ATCK, self.BUTTON_ATCK2); + } else { + _WEP_ACTION(self.weapon, WR_GONETHINK); + } if (time + self.weapon_frametime * 0.5 >= self.weapon_nextthink) { @@ -783,7 +788,8 @@ void W_WeaponFrame() v_forward = fo; v_right = ri; v_up = up; - self.weapon_think(); + Weapon wpn = get_weaponinfo(self.weapon); + self.weapon_think(wpn, self.BUTTON_ATCK, self.BUTTON_ATCK2); } else bprint("\{1}^1ERROR: undefined weapon think function for ", self.netname, "\n"); @@ -792,7 +798,7 @@ void W_WeaponFrame() } void W_AttachToShotorg(entity flash, vector offset) -{ +{SELFPARAM(); entity xflash; flash.owner = self; flash.angles_z = random() * 360; @@ -823,9 +829,8 @@ void W_AttachToShotorg(entity flash, vector offset) } } -void W_DecreaseAmmo(float ammo_use) -{ - entity wep = get_weaponinfo(self.weapon); +void W_DecreaseAmmo(Weapon wep, float ammo_use) +{SELFPARAM(); if(cvar("g_overkill")) if(self.ok_use_ammocharge) @@ -867,8 +872,8 @@ void W_DecreaseAmmo(float ammo_use) .float reload_complain; .string reload_sound; -void W_ReloadedAndReady() -{ +void W_ReloadedAndReady(Weapon thiswep, bool fire1, bool fire2) +{SELFPARAM(); // 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 @@ -891,11 +896,12 @@ void W_ReloadedAndReady() //ATTACK_FINISHED(self) -= self.reload_time - 1; - w_ready(); + Weapon wpn = get_weaponinfo(self.weapon); + w_ready(wpn, self.BUTTON_ATCK, self.BUTTON_ATCK2); } void W_Reload(float sent_ammo_min, string sent_sound) -{ +{SELFPARAM(); // set global values to work with entity e; e = get_weaponinfo(self.weapon); @@ -912,7 +918,7 @@ void W_Reload(float sent_ammo_min, string 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; } @@ -931,12 +937,12 @@ void W_Reload(float sent_ammo_min, string sent_sound) { if(IS_REAL_CLIENT(self) && self.reload_complain < time) { - play2(self, "weapons/unavailable.wav"); + play2(self, SND(UNAVAILABLE)); 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 (!(_WEP_ACTION(self.weapon, WR_CHECKAMMO1) + _WEP_ACTION(self.weapon, WR_CHECKAMMO2))) { self.clip_load = -1; // reload later W_SwitchToOtherWeapon(self); @@ -955,7 +961,7 @@ void W_Reload(float sent_ammo_min, string sent_sound) // now begin the reloading process - sound(self, CH_WEAPON_SINGLE, self.reload_sound, VOL_BASE, ATTEN_NORM); + _sound(self, CH_WEAPON_SINGLE, self.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, @@ -972,10 +978,9 @@ void W_Reload(float sent_ammo_min, string sent_sound) } void W_DropEvent(float event, entity player, float weapon_type, entity weapon_item) -{ - entity oldself = self; - self = player; +{SELFPARAM(); + setself(player); weapon_dropevent_item = weapon_item; - WEP_ACTION(weapon_type, event); - self = oldself; + _WEP_ACTION(weapon_type, event); + setself(this); }