X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Fweapons%2Fweaponsystem.qc;h=200e6a3bd24c5ca66efbf05141750cebc5c1796e;hb=0ce97ac6e23a4bfa907cd5a25990b4abe90656cf;hp=19ba40aa0b6ce6bc6913f0abb2a7ee99a80f5cb0;hpb=af43b181a15f348a4de2045b716ebc7765ce8f9f;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/weapons/weaponsystem.qc b/qcsrc/server/weapons/weaponsystem.qc index 19ba40aa0..200e6a3bd 100644 --- a/qcsrc/server/weapons/weaponsystem.qc +++ b/qcsrc/server/weapons/weaponsystem.qc @@ -1,23 +1,30 @@ #include "weaponsystem.qh" -#include "selection.qh" - -#include "../command/common.qh" -#include -#include "../round_handler.qh" -#include -#include -#include #include #include -#include +#include +#include #include +#include +#include #include +#include #include +#include #include -#include -#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include .int state; @@ -26,8 +33,8 @@ float W_WeaponRateFactor(entity this) { float t = 1; - if(g_weaponratefactor > 0) - t = 1.0 / g_weaponratefactor; + if(autocvar_g_weaponratefactor > 0) + t = 1.0 / autocvar_g_weaponratefactor; MUTATOR_CALLHOOK(WeaponRateFactor, t, this); t = M_ARGV(0, float); @@ -37,7 +44,7 @@ float W_WeaponRateFactor(entity this) float W_WeaponSpeedFactor(entity this) { - float t = 1.0 * g_weaponspeedfactor; + float t = 1.0 * autocvar_g_weaponspeedfactor; MUTATOR_CALLHOOK(WeaponSpeedFactor, t, this); t = M_ARGV(0, float); @@ -55,7 +62,7 @@ bool CL_Weaponentity_CustomizeEntityForClient(entity this, entity client) vector CL_Weapon_GetShotOrg(int wpn) { - entity wi = Weapons_from(wpn); + entity wi = REGISTRY_GET(Weapons, wpn); entity e = spawn(); CL_WeaponEntity_SetModel(e, wi.mdl, false); vector ret = e.movedir; @@ -89,9 +96,7 @@ void CL_Weaponentity_Think(entity this) if (this.weaponchild) this.weaponchild.model = ""; return; } - if (this.w_weaponname != this.weaponname - || this.w_dmg != this.modelindex - || this.w_deadflag != this.deadflag) + if (this.w_weaponname != this.weaponname || this.w_dmg != this.modelindex || this.w_deadflag != this.deadflag) { // owner changed weapons; update appearance this.w_weaponname = this.weaponname; @@ -129,8 +134,7 @@ void CL_ExteriorWeaponentity_Think(entity this) this.model = ""; return; } - if (this.weaponname != w_ent.weaponname || this.dmg != w_ent.modelindex - || this.deadflag != w_ent.deadflag) + if (this.weaponname != w_ent.weaponname || this.dmg != w_ent.modelindex || this.deadflag != w_ent.deadflag) { this.weaponname = w_ent.weaponname; this.dmg = w_ent.modelindex; @@ -160,7 +164,7 @@ void CL_ExteriorWeaponentity_Think(entity this) else if (this.owner.alpha != 0) this.alpha = this.owner.alpha; else this.alpha = 1; - Weapon wep = this.owner.(weaponentity).m_weapon; + Weapon wep = this.owner.(weaponentity).m_weapon; if (wep) this.glowmod = weaponentity_glowmod(wep, this.owner, this.owner.clientcolors, this.owner.(weaponentity)); this.colormap = this.owner.colormap; this.skin = w_ent.skin; @@ -171,19 +175,19 @@ void CL_ExteriorWeaponentity_Think(entity this) // spawning weaponentity for client void CL_SpawnWeaponentity(entity actor, .entity weaponentity) { - entity view = actor.(weaponentity) = new(weaponentity); - view.solid = SOLID_NOT; - view.owner = actor; - setmodel(view, MDL_Null); // precision set when changed - setorigin(view, '0 0 0'); - view.weaponentity_fld = weaponentity; - setthink(view, CL_Weaponentity_Think); - view.nextthink = time; - view.viewmodelforclient = actor; - view.draggable = drag_undraggable; - setcefc(view, CL_Weaponentity_CustomizeEntityForClient); - - wepent_link(view); + entity w_ent = actor.(weaponentity) = new(weaponentity); + w_ent.solid = SOLID_NOT; + w_ent.owner = actor; + setmodel(w_ent, MDL_Null); // precision set when changed + setorigin(w_ent, '0 0 0'); + w_ent.weaponentity_fld = weaponentity; + setthink(w_ent, CL_Weaponentity_Think); + w_ent.nextthink = time; + w_ent.viewmodelforclient = actor; + w_ent.draggable = drag_undraggable; + setcefc(w_ent, CL_Weaponentity_CustomizeEntityForClient); + + wepent_link(w_ent); if (weaponentity == weaponentities[0]) // only one exterior model, thank you very much { @@ -203,20 +207,20 @@ void CL_SpawnWeaponentity(entity actor, .entity weaponentity) // Weapon subs void w_clear(Weapon thiswep, entity actor, .entity weaponentity, int fire) { - actor.(weaponentity).m_weapon = WEP_Null; - actor.(weaponentity).m_switchingweapon = WEP_Null; - entity this = actor.(weaponentity); - if (this) + entity w_ent = actor.(weaponentity); + if (w_ent) { - this.state = WS_CLEAR; - this.effects = 0; + w_ent.m_weapon = WEP_Null; + w_ent.m_switchingweapon = WEP_Null; + w_ent.state = WS_CLEAR; + w_ent.effects = 0; } } void w_ready(Weapon thiswep, entity actor, .entity weaponentity, int fire) { - entity this = actor.(weaponentity); - if (this) this.state = WS_READY; + entity w_ent = actor.(weaponentity); + if (w_ent) w_ent.state = WS_READY; weapon_thinkf(actor, weaponentity, WFRAME_IDLE, 1000000, w_ready); } @@ -224,7 +228,7 @@ void w_ready(Weapon thiswep, entity actor, .entity weaponentity, int fire) .float prevwarntime; bool weapon_prepareattack_checkammo(Weapon thiswep, entity actor, bool secondary, .entity weaponentity) { - if ((actor.items & IT_UNLIMITED_WEAPON_AMMO)) return true; + if ((actor.items & IT_UNLIMITED_AMMO)) return true; bool ammo = false; if (secondary) ammo = thiswep.wr_checkammo2(thiswep, actor, weaponentity); else ammo = thiswep.wr_checkammo1(thiswep, actor, weaponentity); @@ -254,17 +258,7 @@ bool weapon_prepareattack_checkammo(Weapon thiswep, entity actor, bool secondary if (ammo_other) { if (time - actor.prevwarntime > 1) - { - Send_Notification( - NOTIF_ONE, - actor, - MSG_MULTI, - ITEM_WEAPON_PRIMORSEC, - thiswep.m_id, - secondary, - (1 - secondary) - ); - } + Send_Notification(NOTIF_ONE, actor, MSG_MULTI, ITEM_WEAPON_PRIMORSEC, thiswep.m_id, secondary, (1 - secondary)); actor.prevwarntime = time; } else // this weapon is totally unable to fire, switch to another one @@ -308,7 +302,8 @@ void weapon_prepareattack_do(entity actor, .entity weaponentity, bool secondary, if (this == NULL) return; this.state = WS_INUSE; - actor.spawnshieldtime = min(actor.spawnshieldtime, time); // kill spawn shield when you fire + if(StatusEffects_active(STATUSEFFECT_SpawnShield, actor)) // given this is performed often, perform a lighter check first + StatusEffects_remove(STATUSEFFECT_SpawnShield, actor, STATUSEFFECT_REMOVE_CLEAR); // kill spawn shield when you fire // if the weapon hasn't been firing continuously, reset the timer if (attacktime >= 0) @@ -366,6 +361,9 @@ void weapon_thinkf(entity actor, .entity weaponentity, WFRAME fr, float t, void( bool restartanim; if (fr == WFRAME_DONTCHANGE) { + // this can happen when the weapon entity is newly spawned, since it has a clear state and no previous weapon frame + if (this.wframe == WFRAME_DONTCHANGE) + this.wframe = WFRAME_IDLE; fr = this.wframe; restartanim = false; } @@ -374,25 +372,10 @@ void weapon_thinkf(entity actor, .entity weaponentity, WFRAME fr, float t, void( restartanim = fr != WFRAME_IDLE; } - vector of = v_forward; - vector or = v_right; - vector ou = v_up; - - vector a = '0 0 0'; - this.wframe = fr; - if (fr == WFRAME_IDLE) a = this.anim_idle; - else if (fr == WFRAME_FIRE1) a = this.anim_fire1; - else if (fr == WFRAME_FIRE2) a = this.anim_fire2; - else // if (fr == WFRAME_RELOAD) - a = this.anim_reload; - a.z *= g_weaponratefactor; + this.wframe = fr; - v_forward = of; - v_right = or; - v_up = ou; - - if (this.weapon_think == w_ready && func != w_ready && this.state == WS_RAISE) backtrace( - "Tried to override initial weapon think function - should this really happen?"); + if (this.weapon_think == w_ready && func != w_ready && this.state == WS_RAISE) + backtrace("Tried to override initial weapon think function - should this really happen?"); t *= W_WeaponRateFactor(actor); @@ -402,8 +385,8 @@ void weapon_thinkf(entity actor, .entity weaponentity, WFRAME fr, float t, void( this.weapon_nextthink = time; // dprint("started firing at ", ftos(time), "\n"); } - if (this.weapon_nextthink < time - this.weapon_frametime * 1.5 - || this.weapon_nextthink > time + this.weapon_frametime * 1.5) + float w_frametime_limit = this.weapon_frametime * 1.5; + if (this.weapon_nextthink < time - w_frametime_limit || this.weapon_nextthink > time + w_frametime_limit) { this.weapon_nextthink = time; // dprint("reset weapon animation timer at ", ftos(time), "\n"); @@ -416,7 +399,7 @@ void weapon_thinkf(entity actor, .entity weaponentity, WFRAME fr, float t, void( { FOREACH_CLIENT(true, { if(it == actor || (IS_SPEC(it) && it.enemy == actor)) - wframe_send(it, this, a, restartanim); + wframe_send(it, this, fr, autocvar_g_weaponratefactor, restartanim); }); } @@ -424,10 +407,7 @@ void weapon_thinkf(entity actor, .entity weaponentity, WFRAME fr, float t, void( { bool primary_melee = boolean(fr == WFRAME_FIRE1 && (this.m_weapon.spawnflags & WEP_TYPE_MELEE_PRI)); bool secondary_melee = boolean(fr == WFRAME_FIRE2 && (this.m_weapon.spawnflags & WEP_TYPE_MELEE_SEC)); - int act = (primary_melee || secondary_melee) - ? ANIMACTION_MELEE - : ANIMACTION_SHOOT - ; + int act = (primary_melee || secondary_melee) ? ANIMACTION_MELEE : ANIMACTION_SHOOT; animdecide_setaction(actor, act, restartanim); } else if (actor.anim_upper_action == ANIMACTION_SHOOT || actor.anim_upper_action == ANIMACTION_MELEE) @@ -453,6 +433,28 @@ bool weaponLocked(entity player) return false; } +void W_ResetGunAlign(entity player, int preferred_alignment) +{ + if(W_DualWielding(player)) + preferred_alignment = 3; // right align, the second gun will default to left + + // clear current weapon slots' alignments so we can redo the calculations! + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + if (player.(weaponentity)) + player.(weaponentity).m_gunalign = 0; + } + + // now set the new values + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + if (player.(weaponentity)) + player.(weaponentity).m_gunalign = W_GunAlign(player.(weaponentity), preferred_alignment); + } +} + .bool hook_switchweapon; void W_WeaponFrame(Player actor, .entity weaponentity) @@ -493,6 +495,7 @@ void W_WeaponFrame(Player actor, .entity weaponentity) this.m_switchweapon = WEP_Null; this.state = WS_CLEAR; this.weaponname = ""; + this.clip_load = this.clip_size = this.old_clip_load = 0; return; } } @@ -505,13 +508,12 @@ void W_WeaponFrame(Player actor, .entity weaponentity) this.m_switchingweapon = WEP_Null; this.state = WS_CLEAR; this.weaponname = ""; + this.clip_load = this.clip_size = this.old_clip_load = 0; return; } - 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; + vector fo, ri, up; + MAKE_VECTORS(actor.v_angle, fo, ri, up); // Change weapon if (this.m_weapon != this.m_switchweapon) @@ -588,7 +590,8 @@ void W_WeaponFrame(Player actor, .entity weaponentity) { if (w != WEP_Null && !(STAT(WEAPONS, actor) & WepSet_FromWeapon(w))) { - if (this.m_weapon == this.m_switchweapon) W_SwitchWeapon_Force(actor, w_getbestweapon(actor, weaponentity), weaponentity); + if (this.m_weapon == this.m_switchweapon) + W_SwitchWeapon_Force(actor, w_getbestweapon(actor, weaponentity), weaponentity); w = WEP_Null; } @@ -644,8 +647,7 @@ void W_WeaponFrame(Player actor, .entity weaponentity) v_right = ri; v_up = up; Weapon wpn = this.m_weapon; - this.weapon_think(wpn, actor, weaponentity, - button_atck | (button_atck2 << 1)); + this.weapon_think(wpn, actor, weaponentity, button_atck | (button_atck2 << 1)); } else { @@ -660,11 +662,11 @@ void W_AttachToShotorg(entity actor, .entity weaponentity, entity flash, vector flash.owner = actor; flash.angles_z = random() * 360; - entity view = actor.(weaponentity); + entity w_ent = actor.(weaponentity); entity exterior = actor.exteriorweaponentity; - if (gettagindex(view, "shot")) setattachment(flash, view, "shot"); - else setattachment(flash, view, "tag_shot"); + if (gettagindex(w_ent, "shot")) setattachment(flash, w_ent, "shot"); + else setattachment(flash, w_ent, "tag_shot"); setorigin(flash, offset); entity xflash = spawn(); @@ -672,10 +674,10 @@ void W_AttachToShotorg(entity actor, .entity weaponentity, entity flash, vector flash.viewmodelforclient = actor; - if (view.oldorigin.x > 0) + if (w_ent.oldorigin.x > 0) { setattachment(xflash, exterior, ""); - setorigin(xflash, view.oldorigin + offset); + setorigin(xflash, w_ent.oldorigin + offset); } else { @@ -688,7 +690,7 @@ void W_AttachToShotorg(entity actor, .entity weaponentity, entity flash, vector void W_DecreaseAmmo(Weapon wep, entity actor, float ammo_use, .entity weaponentity) { if (MUTATOR_CALLHOOK(W_DecreaseAmmo, actor, actor.(weaponentity), ammo_use)) return; - if ((actor.items & IT_UNLIMITED_WEAPON_AMMO) && !wep.reloading_ammo) return; + if ((actor.items & IT_UNLIMITED_AMMO) && !wep.reloading_ammo) return; ammo_use = M_ARGV(2, float); @@ -708,12 +710,7 @@ void W_DecreaseAmmo(Weapon wep, entity actor, float ammo_use, .entity weaponenti backtrace(sprintf( "W_DecreaseAmmo(%.2f): '%s' subtracted too much %s from '%s', resulting with '%.2f' left... " "Please notify the developers immediately with a copy of this backtrace!\n", - ammo_use, - wep.netname, - GetAmmoPicture(wep.ammo_type), - actor.netname, - ammo - )); + ammo_use, wep.netname, GetAmmoPicture(wep.ammo_type), actor.netname, ammo)); } SetResource(actor, wep.ammo_type, ammo - ammo_use); } @@ -735,7 +732,7 @@ void W_ReloadedAndReady(Weapon thiswep, entity actor, .entity weaponentity, int w_ent.clip_load = w_ent.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 (!w_ent.reload_ammo_min || (actor.items & IT_UNLIMITED_WEAPON_AMMO) || wpn.ammo_type == RES_NONE) + if (!w_ent.reload_ammo_min || (actor.items & IT_UNLIMITED_AMMO) || wpn.ammo_type == RES_NONE) { w_ent.clip_load = w_ent.reload_ammo_amount; } @@ -791,8 +788,10 @@ void W_Reload(entity actor, .entity weaponentity, float sent_ammo_min, Sound sen { if (!GetResource(actor, e.ammo_type) && this.reload_ammo_min) { - if (!(actor.items & IT_UNLIMITED_WEAPON_AMMO)) + if (!(actor.items & IT_UNLIMITED_AMMO)) { + if (autocvar_g_weaponswitch_debug == 2 && weaponslot(weaponentity) > 0) + return; // in this case the primary weapon will do the switching when it runs out of ammo (TODO: do this same check but for other slots) if (IS_REAL_CLIENT(actor) && actor.reload_complain < time) { play2(actor, SND(UNAVAILABLE)); @@ -809,7 +808,6 @@ void W_Reload(entity actor, .entity weaponentity, float sent_ammo_min, Sound sen } } } - if (this) { if (this.wframe == WFRAME_RELOAD) return; @@ -837,7 +835,7 @@ void W_Reload(entity actor, .entity weaponentity, float sent_ammo_min, Sound sen void W_DropEvent(.void(Weapon, entity actor, .entity) event, entity player, float weapon_type, entity weapon_item, .entity weaponentity) { - Weapon w = Weapons_from(weapon_type); + Weapon w = REGISTRY_GET(Weapons, weapon_type); weapon_dropevent_item = weapon_item; w.event(w, player, weaponentity); }