From: TimePath Date: Wed, 4 Nov 2015 02:32:38 +0000 (+1100) Subject: Weapons: independent `weapon_think` and `weapon_nextthink` X-Git-Tag: xonotic-v0.8.2~1731 X-Git-Url: https://git.xonotic.org/?a=commitdiff_plain;h=0ff9281921b10945aca1f6a0057b4206f45127b7;p=xonotic%2Fxonotic-data.pk3dir.git Weapons: independent `weapon_think` and `weapon_nextthink` --- diff --git a/qcsrc/server/cl_client.qc b/qcsrc/server/cl_client.qc index e8c5d2cd3..087827431 100644 --- a/qcsrc/server/cl_client.qc +++ b/qcsrc/server/cl_client.qc @@ -2436,7 +2436,7 @@ void PlayerPreThink (void) // WEAPONTODO: THIS SHIT NEEDS TO GO EVENTUALLY // It cannot be predicted by the engine! .entity weaponentity = weaponentities[0]; // TODO: unhardcode - if((self.weapon == WEP_SHOCKWAVE.m_id || self.weapon == WEP_SHOTGUN.m_id) && self.(weaponentity).wframe == WFRAME_FIRE2 && time < self.weapon_nextthink) + if((self.weapon == WEP_SHOCKWAVE.m_id || self.weapon == WEP_SHOTGUN.m_id) && self.(weaponentity).wframe == WFRAME_FIRE2 && time < self.(weaponentity).weapon_nextthink) do_crouch = 0; if (do_crouch) diff --git a/qcsrc/server/weapons/weaponsystem.qc b/qcsrc/server/weapons/weaponsystem.qc index 71217b9b9..2cd6d7574 100644 --- a/qcsrc/server/weapons/weaponsystem.qc +++ b/qcsrc/server/weapons/weaponsystem.qc @@ -320,12 +320,14 @@ vector CL_Weapon_GetShotOrg(float wpn) return ret; } +..entity weaponentity_fld; + void CL_Weaponentity_Think() { SELFPARAM(); this.nextthink = time; if (intermission_running) this.frame = this.anim_idle.x; - .entity weaponentity = weaponentities[0]; // TODO: unhardcode + .entity weaponentity = this.weaponentity_fld; if (this.owner.(weaponentity) != this) { if (this.(weaponentity)) remove(this.(weaponentity)); @@ -355,6 +357,7 @@ void CL_Weaponentity_Think() this.effects &= ~EF_TELEPORT_BIT; this.effects &= ~EF_RESTARTANIM_BIT; this.effects |= tb; + if (weaponentity != weaponentities[0]) this.effects |= EF_NODRAW; if (this.owner.alpha == default_player_alpha) this.alpha = default_weapon_alpha; else if (this.owner.alpha != 0) this.alpha = this.owner.alpha; @@ -372,7 +375,7 @@ void CL_Weaponentity_Think() this.angles = '0 0 0'; - float f = (this.owner.weapon_nextthink - time); + float f = this.weapon_nextthink - time; if (this.state == WS_RAISE && !intermission_running) { entity newwep = Weapons_from(this.owner.switchweapon); @@ -450,6 +453,7 @@ void CL_SpawnWeaponentity(entity e, .entity weaponentity) view.angles = '0 0 0'; view.viewmodelforclient = e; view.flags = 0; + view.weaponentity_fld = weaponentity; view.think = CL_Weaponentity_Think; view.customizeentityforclient = CL_Weaponentity_CustomizeEntityForClient; view.nextthink = time; @@ -478,16 +482,18 @@ void w_clear(Weapon thiswep, entity actor, .entity weaponentity, int fire) actor.weapon = 0; actor.switchingweapon = 0; } - if (actor.(weaponentity)) + entity this = actor.(weaponentity); + if (this) { - actor.(weaponentity).state = WS_CLEAR; - actor.(weaponentity).effects = 0; + this.state = WS_CLEAR; + this.effects = 0; } } void w_ready(Weapon thiswep, entity actor, .entity weaponentity, int fire) { - if (actor.(weaponentity)) actor.(weaponentity).state = WS_READY; + entity this = actor.(weaponentity); + if (this) this.state = WS_READY; weapon_thinkf(actor, weaponentity, WFRAME_IDLE, 1000000, w_ready); } @@ -562,15 +568,17 @@ bool weapon_prepareattack_check(Weapon thiswep, entity actor, .entity weaponenti int slot = weaponslot(weaponentity); // don't fire if previous attack is not finished if (ATTACK_FINISHED(actor, slot) > time + actor.weapon_frametime * 0.5) return false; + entity this = actor.(weaponentity); // don't fire while changing weapon - if (actor.(weaponentity).state != WS_READY) return false; + if (this.state != WS_READY) return false; } return true; } void weapon_prepareattack_do(entity actor, .entity weaponentity, bool secondary, float attacktime) { - actor.(weaponentity).state = WS_INUSE; + entity this = actor.(weaponentity); + this.state = WS_INUSE; actor.spawnshieldtime = min(actor.spawnshieldtime, time); // kill spawn shield when you fire @@ -602,10 +610,11 @@ bool weapon_prepareattack(Weapon thiswep, entity actor, .entity weaponentity, bo void weapon_thinkf(entity actor, .entity weaponentity, float fr, float t, void(Weapon thiswep, entity actor, .entity weaponentity, int fire) func) { + entity this = actor.(weaponentity); bool restartanim; if (fr == WFRAME_DONTCHANGE) { - fr = actor.(weaponentity).wframe; + fr = this.wframe; restartanim = false; } else if (fr == WFRAME_IDLE) @@ -621,43 +630,43 @@ void weapon_thinkf(entity actor, .entity weaponentity, float fr, float t, void(W vector or = v_right; vector ou = v_up; - if (actor.(weaponentity)) + if (this) { - actor.(weaponentity).wframe = fr; + this.wframe = fr; vector a = '0 0 0'; - if (fr == WFRAME_IDLE) a = actor.(weaponentity).anim_idle; - else if (fr == WFRAME_FIRE1) a = actor.(weaponentity).anim_fire1; - else if (fr == WFRAME_FIRE2) a = actor.(weaponentity).anim_fire2; + 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 = actor.(weaponentity).anim_reload; + a = this.anim_reload; a.z *= g_weaponratefactor; - setanim(actor.(weaponentity), a, restartanim == false, restartanim, restartanim); + setanim(this, a, restartanim == false, restartanim, restartanim); } v_forward = of; v_right = or; v_up = ou; - if (actor.weapon_think == w_ready && func != w_ready && actor.(weaponentity).state == WS_RAISE) backtrace( + 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(); // VorteX: haste can be added here - if (actor.weapon_think == w_ready) + if (this.weapon_think == w_ready) { - actor.weapon_nextthink = time; + this.weapon_nextthink = time; // dprint("started firing at ", ftos(time), "\n"); } - if (actor.weapon_nextthink < time - actor.weapon_frametime * 1.5 - || actor.weapon_nextthink > time + actor.weapon_frametime * 1.5) + if (this.weapon_nextthink < time - actor.weapon_frametime * 1.5 + || this.weapon_nextthink > time + actor.weapon_frametime * 1.5) { - actor.weapon_nextthink = time; + this.weapon_nextthink = time; // dprint("reset weapon animation timer at ", ftos(time), "\n"); } - actor.weapon_nextthink = actor.weapon_nextthink + t; - actor.weapon_think = func; - // dprint("next ", ftos(actor.weapon_nextthink), "\n"); + this.weapon_nextthink = this.weapon_nextthink + t; + this.weapon_think = func; + // dprint("next ", ftos(this.weapon_nextthink), "\n"); if ((fr == WFRAME_FIRE1 || fr == WFRAME_FIRE2) && t) { @@ -686,10 +695,12 @@ bool forbidWeaponUse(entity player) void W_WeaponFrame(entity actor) { - .entity weaponentity = weaponentities[0]; // TODO: unhardcode + .entity weaponentity = weaponentities[0]; // TODO: unhardcode + entity this = actor.(weaponentity); if (frametime) actor.weapon_frametime = frametime; - if (!actor.(weaponentity) || actor.health < 1) return; // Dead player can't use weapons and injure impulse commands + if (!this || actor.health < 1) return; // Dead player can't use weapons and injure impulse commands + if (forbidWeaponUse(actor)) { @@ -705,7 +716,7 @@ void W_WeaponFrame(entity actor) { actor.weapon = 0; actor.switchingweapon = 0; - actor.(weaponentity).state = WS_CLEAR; + this.state = WS_CLEAR; actor.weaponname = ""; // actor.items &= ~IT_AMMO; return; @@ -719,10 +730,10 @@ void W_WeaponFrame(entity actor) // Change weapon if (actor.weapon != actor.switchweapon) { - switch (actor.(weaponentity).state) + switch (this.state) { default: - LOG_WARNINGF("unhandled weaponentity (%i) state for player (%i): %d\n", actor.(weaponentity), actor, actor.(weaponentity).state); + LOG_WARNINGF("unhandled weaponentity (%i) state for player (%i): %d\n", this, actor, this.state); break; case WS_INUSE: case WS_RAISE: @@ -739,7 +750,7 @@ void W_WeaponFrame(entity actor) actor.bulletcounter = 0; actor.ammo_field = newwep.ammo_field; newwep.wr_setup(newwep); - actor.(weaponentity).state = WS_RAISE; + this.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 @@ -777,7 +788,7 @@ void W_WeaponFrame(entity actor) ) { sound(actor, CH_WEAPON_SINGLE, SND_WEAPON_SWITCH, VOL_BASE, ATTN_NORM); - actor.(weaponentity).state = WS_DROP; + this.state = WS_DROP; weapon_thinkf(actor, weaponentity, WFRAME_DONTCHANGE, oldwep.switchdelay_drop, w_clear); } break; @@ -787,17 +798,15 @@ void W_WeaponFrame(entity actor) // LordHavoc: network timing test code // if (actor.button0) - // print(ftos(frametime), " ", ftos(time), " >= ", ftos(ATTACK_FINISHED(actor, slot)), " >= ", ftos(actor.weapon_nextthink), "\n"); + // print(ftos(frametime), " ", ftos(time), " >= ", ftos(ATTACK_FINISHED(actor, slot)), " >= ", ftos(this.weapon_nextthink), "\n"); 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 - int c = 0; - while (c < W_TICSPERFRAME) + for (int c = 0; c < W_TICSPERFRAME; ++c) { - c += 1; if (w && !(actor.weapons & WepSet_FromWeapon(w))) { if (actor.weapon == actor.switchweapon) W_SwitchWeapon_Force(actor, w_getbestweapon(actor)); @@ -845,15 +854,15 @@ void W_WeaponFrame(entity actor) } } - if (time + actor.weapon_frametime * 0.5 >= actor.weapon_nextthink) + if (time + actor.weapon_frametime * 0.5 >= this.weapon_nextthink) { - if (actor.weapon_think) + if (this.weapon_think) { v_forward = fo; v_right = ri; v_up = up; Weapon wpn = Weapons_from(actor.weapon); - actor.weapon_think(wpn, actor, weaponentity, + this.weapon_think(wpn, actor, weaponentity, (actor.BUTTON_ATCK ? 1 : 0) | (actor.BUTTON_ATCK2 ? 2 : 0)); } else @@ -870,8 +879,9 @@ void W_AttachToShotorg(entity actor, entity flash, vector offset) flash.owner = actor; flash.angles_z = random() * 360; - if (gettagindex(actor.(weaponentity), "shot")) setattachment(flash, actor.(weaponentity), "shot"); - else setattachment(flash, actor.(weaponentity), "tag_shot"); + entity this = actor.(weaponentity); + if (gettagindex(this, "shot")) setattachment(flash, this, "shot"); + else setattachment(flash, this, "tag_shot"); setorigin(flash, offset); entity xflash = spawn(); @@ -879,10 +889,10 @@ void W_AttachToShotorg(entity actor, entity flash, vector offset) flash.viewmodelforclient = actor; - if (actor.(weaponentity).oldorigin.x > 0) + if (this.oldorigin.x > 0) { setattachment(xflash, actor.exteriorweaponentity, ""); - setorigin(xflash, actor.(weaponentity).oldorigin + offset); + setorigin(xflash, this.oldorigin + offset); } else { @@ -1019,12 +1029,13 @@ void W_Reload(entity actor, float sent_ammo_min, string sent_sound) } } - if (actor.(weaponentity)) + entity this = actor.(weaponentity); + if (this) { - if (actor.(weaponentity).wframe == WFRAME_RELOAD) return; + if (this.wframe == WFRAME_RELOAD) return; // allow switching away while reloading, but this will cause a new reload! - actor.(weaponentity).state = WS_READY; + this.state = WS_READY; } // now begin the reloading process