From: Mario Date: Sun, 20 Nov 2016 18:09:38 +0000 (+1000) Subject: Merge branch 'master' into Mario/wepent_experimental X-Git-Tag: xonotic-v0.8.2~326^2~31 X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=commitdiff_plain;h=cbca1a79315fe08c4796273a490a4d12b7d3291d;hp=6386150f532a0e6d86c074d81191465ee8586b00 Merge branch 'master' into Mario/wepent_experimental # Conflicts: # qcsrc/client/view.qc --- diff --git a/mutators.cfg b/mutators.cfg index b5e9b76df6..54517d9f7b 100644 --- a/mutators.cfg +++ b/mutators.cfg @@ -55,22 +55,6 @@ set g_overkill_filter_armormedium 0 set g_overkill_filter_armorbig 0 set g_overkill_filter_armorlarge 0 -set g_overkill_ammo_charge 0 -set g_overkill_ammo_charge_notice 1 -set g_overkill_ammo_charge_limit 1 -set g_overkill_ammo_charge_rate 0.5 -set g_overkill_ammo_charge_rate_vortex 0.5 -set g_overkill_ammo_charge_rate_machinegun 0.5 -set g_overkill_ammo_charge_rate_shotgun 0.5 -set g_overkill_ammo_charge_rate_hmg 0.25 -set g_overkill_ammo_charge_rate_rpc 1.5 -set g_overkill_ammo_decharge 0.1 -set g_overkill_ammo_decharge_machinegun 0.025 -set g_overkill_ammo_decharge_shotgun 0.15 -set g_overkill_ammo_decharge_vortex 0.2 -set g_overkill_ammo_decharge_rpc 1 -set g_overkill_ammo_decharge_hmg 0.01 - // ========= // vampire diff --git a/qcsrc/client/_all.qh b/qcsrc/client/_all.qh index 077b5f450a..5935342ae4 100644 --- a/qcsrc/client/_all.qh +++ b/qcsrc/client/_all.qh @@ -11,5 +11,7 @@ #include "defs.qh" #include "main.qh" #include "miscfunctions.qh" +#include "view.qh" #include +#include diff --git a/qcsrc/client/defs.qh b/qcsrc/client/defs.qh index 437e1dd75b..b89ecf55ac 100644 --- a/qcsrc/client/defs.qh +++ b/qcsrc/client/defs.qh @@ -98,10 +98,6 @@ const float MAX_DAMAGEEXTRARADIUS = 16; .float damageextraradius; .void(entity this, float thisdmg, int hittype, vector org, vector thisforce) event_damage; -// only for Porto -float angles_held_status; -vector angles_held; - // weapons .bool silent; diff --git a/qcsrc/client/hud/hud.qh b/qcsrc/client/hud/hud.qh index 06a3491145..7ea0ce5791 100644 --- a/qcsrc/client/hud/hud.qh +++ b/qcsrc/client/hud/hud.qh @@ -90,8 +90,8 @@ float complain_weapon_time; PlayerScoreField ps_primary, ps_secondary; int ts_primary, ts_secondary; -Weapon last_switchweapon; -Weapon last_activeweapon; +.Weapon last_switchweapon; +.Weapon last_activeweapon; float weapontime; float weaponprevtime; diff --git a/qcsrc/client/hud/panel/ammo.qc b/qcsrc/client/hud/panel/ammo.qc index e299d1416e..94545ac4bf 100644 --- a/qcsrc/client/hud/panel/ammo.qc +++ b/qcsrc/client/hud/panel/ammo.qc @@ -169,7 +169,9 @@ void HUD_Ammo() ammo_size.y = newSize; } - Weapon wep = switchweapon; + entity wepent = viewmodels[0]; // TODO: unhardcode + + Weapon wep = wepent.switchweapon; int i; bool infinite_ammo = (STAT(ITEMS) & IT_UNLIMITED_WEAPON_AMMO); row = column = 0; diff --git a/qcsrc/client/hud/panel/weapons.qc b/qcsrc/client/hud/panel/weapons.qc index db25d532a0..69fd82c9e0 100644 --- a/qcsrc/client/hud/panel/weapons.qc +++ b/qcsrc/client/hud/panel/weapons.qc @@ -373,10 +373,12 @@ void HUD_Weapons() switch_speed = frametime * autocvar_hud_panel_weapons_selection_speed; vector radius_size = weapon_size * (autocvar_hud_panel_weapons_selection_radius + 1); - if(switchweapon == WEP_Null) + entity wepent = viewmodels[0]; // TODO: unhardcode + + if(wepent.switchweapon == WEP_Null) panel_switchweapon = NULL; else if(!panel_switchweapon) - panel_switchweapon = switchweapon; + panel_switchweapon = wepent.switchweapon; // draw background behind currently selected weapon // do it earlier to make sure bg is drawn behind every weapon icons while it's moving diff --git a/qcsrc/client/main.qc b/qcsrc/client/main.qc index 36ca217240..f48c0c530a 100644 --- a/qcsrc/client/main.qc +++ b/qcsrc/client/main.qc @@ -494,16 +494,6 @@ NET_HANDLE(ENT_CLIENT_CLIENTDATA, bool isnew) spectatorbutton_zoom = (f & 4); - if(f & 8) - { - angles_held_status = 1; - angles_held.x = ReadAngle(); - angles_held.y = ReadAngle(); - angles_held.z = 0; - } - else - angles_held_status = 0; - if(f & 16) { num_spectators = ReadByte(); diff --git a/qcsrc/client/main.qh b/qcsrc/client/main.qh index 54ed9e2c39..bbf69d28d1 100644 --- a/qcsrc/client/main.qh +++ b/qcsrc/client/main.qh @@ -53,9 +53,6 @@ bool button_zoom; bool spectatorbutton_zoom; bool button_attack2; -Weapon activeweapon; -Weapon switchingweapon; -Weapon switchweapon; float current_viewzoom; float zoomin_effect; float warmup_stage; diff --git a/qcsrc/client/view.qc b/qcsrc/client/view.qc index c85d075a66..b98e5df0fc 100644 --- a/qcsrc/client/view.qc +++ b/qcsrc/client/view.qc @@ -284,9 +284,11 @@ void viewmodel_animate(entity this) .float weapon_eta_last; .float weapon_switchdelay; +.string name_last; + void viewmodel_draw(entity this) { - if(!activeweapon || !autocvar_r_drawviewmodel) + if(!this.activeweapon || !autocvar_r_drawviewmodel) return; int mask = (intermission || (STAT(HEALTH) <= 0) || autocvar_chase_active) ? 0 : MASK_NORMAL; float a = this.alpha; @@ -295,9 +297,9 @@ void viewmodel_draw(entity this) if (invehicle) a = -1; else if (wasinvehicle) a = 1; wasinvehicle = invehicle; - Weapon wep = activeweapon; + Weapon wep = this.activeweapon; int c = entcs_GetClientColors(current_player); - vector g = weaponentity_glowmod(wep, NULL, c); + vector g = weaponentity_glowmod(wep, NULL, c, this); entity me = CSQCModel_server2csqc(player_localentnum - 1); int fx = ((me.csqcmodel_effects & EFMASK_CHEAP) | EF_NODEPTHTEST) @@ -312,15 +314,14 @@ void viewmodel_draw(entity this) CSQCModel_Effects_Apply(e); } { - static string name_last; string name = wep.mdl; string newname = wep.wr_viewmodel(wep, this); if(newname) name = newname; - bool swap = name != name_last; + bool swap = name != this.name_last; // if (swap) { - name_last = name; + this.name_last = name; CL_WeaponEntity_SetModel(this, name, swap); this.viewmodel_origin = this.origin; this.viewmodel_angles = this.angles; @@ -359,9 +360,9 @@ void viewmodel_draw(entity this) setorigin(this, this.origin); } -entity viewmodel; STATIC_INIT(viewmodel) { - viewmodel = new(viewmodel); + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + viewmodels[slot] = new(viewmodel); } void Porto_Draw(entity this); @@ -374,65 +375,70 @@ STATIC_INIT(Porto) } const int polyline_length = 16; -vector polyline[polyline_length]; +.vector polyline[polyline_length]; void Porto_Draw(entity this) { - if (activeweapon != WEP_PORTO) return; - if (spectatee_status) return; - if (WEP_CVAR(porto, secondary)) return; - if (intermission == 1) return; - if (intermission == 2) return; - if (STAT(HEALTH) <= 0) return; - - vector pos = view_origin; - vector dir = view_forward; - if (angles_held_status) + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) { - makevectors(angles_held); - dir = v_forward; - } + entity wepent = viewmodels[slot]; - polyline[0] = pos; + if (wepent.activeweapon != WEP_PORTO) continue; + if (spectatee_status) continue; + if (WEP_CVAR(porto, secondary)) continue; + if (intermission == 1) continue; + if (intermission == 2) continue; + if (STAT(HEALTH) <= 0) continue; - int portal_number = 0, portal1_idx = 1, portal_max = 2; - int n = 1 + 2; // 2 lines == 3 points - for (int idx = 0; idx < n && idx < polyline_length - 1; ) - { - traceline(pos, pos + 65536 * dir, true, this); - dir = reflect(dir, trace_plane_normal); - pos = trace_endpos; - polyline[++idx] = pos; - if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SLICK || trace_dphitcontents & DPCONTENTS_PLAYERCLIP) + vector pos = view_origin; + vector dir = view_forward; + if (wepent.angles_held_status) { - n += 1; - continue; + makevectors(wepent.angles_held); + dir = v_forward; } - if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT) - { - n = max(2, idx); - break; - } - // check size + + wepent.polyline[0] = pos; + + int portal_number = 0, portal1_idx = 1, portal_max = 2; + int n = 1 + 2; // 2 lines == 3 points + for (int idx = 0; idx < n && idx < polyline_length - 1; ) { - vector ang = vectoangles2(trace_plane_normal, dir); - ang.x = -ang.x; - makevectors(ang); - if (!CheckWireframeBox(this, pos - 48 * v_right - 48 * v_up + 16 * v_forward, 96 * v_right, 96 * v_up, 96 * v_forward)) + traceline(pos, pos + 65536 * dir, true, this); + dir = reflect(dir, trace_plane_normal); + pos = trace_endpos; + wepent.polyline[++idx] = pos; + if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SLICK || trace_dphitcontents & DPCONTENTS_PLAYERCLIP) + { + n += 1; + continue; + } + if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT) { n = max(2, idx); break; } + // check size + { + vector ang = vectoangles2(trace_plane_normal, dir); + ang.x = -ang.x; + makevectors(ang); + if (!CheckWireframeBox(this, pos - 48 * v_right - 48 * v_up + 16 * v_forward, 96 * v_right, 96 * v_up, 96 * v_forward)) + { + n = max(2, idx); + break; + } + } + portal_number += 1; + if (portal_number >= portal_max) break; + if (portal_number == 1) portal1_idx = idx; + } + for (int idx = 0; idx < n - 1; ++idx) + { + vector p = wepent.polyline[idx], q = wepent.polyline[idx + 1]; + if (idx == 0) p -= view_up * 16; // line from player + vector rgb = (idx < portal1_idx) ? '1 0 0' : '0 0 1'; + Draw_CylindricLine(p, q, 4, "", 1, 0, rgb, 0.5, DRAWFLAG_NORMAL, view_origin); } - portal_number += 1; - if (portal_number >= portal_max) break; - if (portal_number == 1) portal1_idx = idx; - } - for (int idx = 0; idx < n - 1; ++idx) - { - vector p = polyline[idx], q = polyline[idx + 1]; - if (idx == 0) p -= view_up * 16; // line from player - vector rgb = (idx < portal1_idx) ? '1 0 0' : '0 0 1'; - Draw_CylindricLine(p, q, 4, "", 1, 0, rgb, 0.5, DRAWFLAG_NORMAL, view_origin); } } @@ -454,10 +460,17 @@ vector GetCurrentFov(float fov) zoomspeed = 3.5; zoomdir = button_zoom; + if(hud == HUD_NORMAL && !spectatee_status) - if(switchweapon == activeweapon) - if((activeweapon == WEP_VORTEX && !WEP_CVAR(vortex, secondary)) || (activeweapon == WEP_RIFLE && !WEP_CVAR(rifle, secondary))) // do NOT use switchweapon here - zoomdir += button_attack2; + { + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + entity wepent = viewmodels[slot]; + if(wepent.switchweapon == wepent.activeweapon) + if((wepent.activeweapon == WEP_VORTEX && !WEP_CVAR(vortex, secondary)) || (wepent.activeweapon == WEP_RIFLE && !WEP_CVAR(rifle, secondary))) // do NOT use switchweapon here + zoomdir += button_attack2; + } + } if(spectatee_status > 0 || isdemo()) { if(spectatorbutton_zoom) @@ -624,7 +637,7 @@ float EnemyHitCheck() return SHOTTYPE_HITENEMY; } -float TrueAimCheck() +float TrueAimCheck(entity wepent) { float nudge = 1; // added to traceline target and subtracted from result TOOD(divVerent): do we still need this? Doesn't the engine do this now for us? vector vecs, trueaimpoint, w_shotorg; @@ -637,7 +650,7 @@ float TrueAimCheck() ta = trueaim; mv = MOVE_NOMONSTERS; - switch(activeweapon) // WEAPONTODO + switch(wepent.activeweapon) // WEAPONTODO { case WEP_TUBA: // no aim case WEP_PORTO: // shoots from eye @@ -720,7 +733,6 @@ float camera_mode; const float CAMERA_FREE = 1; const float CAMERA_CHASE = 2; float reticle_type; -string reticle_image; string NextFrameCommand; vector freeze_org, freeze_ang; @@ -812,9 +824,18 @@ void HitSound() { // varying sound pitch + bool have_arc = false; + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + entity wepent = viewmodels[slot]; + + if(wepent.activeweapon == WEP_ARC) + have_arc = true; + } + static float hitsound_time_prev = 0; // HACK: the only way to get the arc to sound consistent with pitch shift is to ignore cl_hitsound_antispam_time - float arc_hack = activeweapon == WEP_ARC && autocvar_cl_hitsound >= 2; + bool arc_hack = have_arc && autocvar_cl_hitsound >= 2; if (arc_hack || COMPARE_INCREASING(time, hitsound_time_prev) > autocvar_cl_hitsound_antispam_time) { if (autocvar_cl_hitsound && unaccounted_damage) @@ -978,8 +999,9 @@ void HUD_Crosshair(entity this) if(autocvar_crosshair_hittest) { vector wcross_oldorigin; + entity thiswep = viewmodels[0]; // TODO: unhardcode wcross_oldorigin = wcross_origin; - shottype = TrueAimCheck(); + shottype = TrueAimCheck(thiswep); if(shottype == SHOTTYPE_HITWORLD) { v = wcross_origin - wcross_oldorigin; @@ -1001,7 +1023,8 @@ void HUD_Crosshair(entity this) entity e = WEP_Null; if(autocvar_crosshair_per_weapon || (autocvar_crosshair_color_special == 1)) { - e = switchingweapon; + entity wepent = viewmodels[0]; // TODO: unhardcode + e = wepent.switchingweapon; if(e) { if(autocvar_crosshair_per_weapon) @@ -1146,10 +1169,6 @@ void HUD_Crosshair(entity this) weapon_clipload = STAT(WEAPON_CLIPLOAD); weapon_clipsize = STAT(WEAPON_CLIPSIZE); - float ok_ammo_charge, ok_ammo_chargepool; - ok_ammo_charge = STAT(OK_AMMO_CHARGE); - ok_ammo_chargepool = STAT(OK_AMMO_CHARGEPOOL); - float vortex_charge, vortex_chargepool; vortex_charge = STAT(VORTEX_CHARGE); vortex_chargepool = STAT(VORTEX_CHARGEPOOL); @@ -1159,9 +1178,10 @@ void HUD_Crosshair(entity this) if(vortex_charge_movingavg == 0) // this should only happen if we have just loaded up the game vortex_charge_movingavg = vortex_charge; + entity wepent = viewmodels[0]; // TODO: unhardcode // handle the values - if (autocvar_crosshair_ring && activeweapon == WEP_VORTEX && vortex_charge && autocvar_crosshair_ring_vortex) // ring around crosshair representing velocity-dependent damage for the vortex + if (autocvar_crosshair_ring && wepent.activeweapon == WEP_VORTEX && vortex_charge && autocvar_crosshair_ring_vortex) // ring around crosshair representing velocity-dependent damage for the vortex { if (vortex_chargepool || use_vortex_chargepool) { use_vortex_chargepool = 1; @@ -1181,27 +1201,20 @@ void HUD_Crosshair(entity this) ring_rgb = wcross_color; ring_image = "gfx/crosshair_ring_nexgun.tga"; } - else if (autocvar_crosshair_ring && activeweapon == WEP_MINE_LAYER && WEP_CVAR(minelayer, limit) && autocvar_crosshair_ring_minelayer) + else if (autocvar_crosshair_ring && wepent.activeweapon == WEP_MINE_LAYER && WEP_CVAR(minelayer, limit) && autocvar_crosshair_ring_minelayer) { ring_value = bound(0, STAT(LAYED_MINES) / WEP_CVAR(minelayer, limit), 1); // if you later need to use the count of bullets in another place, then add a float for it. For now, no need to. ring_alpha = autocvar_crosshair_ring_minelayer_alpha; ring_rgb = wcross_color; ring_image = "gfx/crosshair_ring.tga"; } - else if (activeweapon == WEP_HAGAR && STAT(HAGAR_LOAD) && autocvar_crosshair_ring_hagar) + else if (wepent.activeweapon == WEP_HAGAR && STAT(HAGAR_LOAD) && autocvar_crosshair_ring_hagar) { ring_value = bound(0, STAT(HAGAR_LOAD) / WEP_CVAR_SEC(hagar, load_max), 1); ring_alpha = autocvar_crosshair_ring_hagar_alpha; ring_rgb = wcross_color; ring_image = "gfx/crosshair_ring.tga"; } - else if (ok_ammo_charge) - { - ring_value = ok_ammo_chargepool; - ring_alpha = autocvar_crosshair_ring_reload_alpha; - ring_rgb = wcross_color; - ring_image = "gfx/crosshair_ring.tga"; - } else if(autocvar_crosshair_ring_reload && weapon_clipsize) // forces there to be only an ammo ring { ring_value = bound(0, weapon_clipload / weapon_clipsize, 1); @@ -1211,12 +1224,12 @@ void HUD_Crosshair(entity this) // Note: This is to stop Taoki from complaining that the image doesn't match all potential balances. // if a new image for another weapon is added, add the code (and its respective file/value) here - if ((activeweapon == WEP_RIFLE) && (weapon_clipsize == 80)) + if ((wepent.activeweapon == WEP_RIFLE) && (weapon_clipsize == 80)) ring_image = "gfx/crosshair_ring_rifle.tga"; else ring_image = "gfx/crosshair_ring.tga"; } - else if ( autocvar_crosshair_ring && autocvar_crosshair_ring_arc && arc_heat && activeweapon == WEP_ARC ) + else if ( autocvar_crosshair_ring && autocvar_crosshair_ring_arc && arc_heat && wepent.activeweapon == WEP_ARC ) { ring_value = arc_heat; ring_alpha = (1-arc_heat)*autocvar_crosshair_ring_arc_cold_alpha + @@ -1705,7 +1718,8 @@ void CSQC_UpdateView(entity this, float w, float h) // run viewmodel_draw before updating view_angles to the angles calculated by WarpZone_FixView // viewmodel_draw needs to use the view_angles set by the engine on every CSQC_UpdateView call - viewmodel_draw(viewmodel); + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + viewmodel_draw(viewmodels[slot]); // Render the Scene view_origin = getpropertyvec(VF_ORIGIN); @@ -1783,39 +1797,36 @@ void CSQC_UpdateView(entity this, float w, float h) ColorTranslateMode = autocvar_cl_stripcolorcodes; - // currently switching-to weapon (for crosshair) - switchingweapon = Weapons_from(STAT(SWITCHINGWEAPON)); - - // actually active weapon (for zoom) - activeweapon = Weapons_from(STAT(ACTIVEWEAPON)); - - switchweapon = Weapons_from(STAT(SWITCHWEAPON)); - - if(last_switchweapon != switchweapon) + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) { - weapontime = time; - last_switchweapon = switchweapon; - if(button_zoom && autocvar_cl_unpress_zoom_on_weapon_switch) + entity wepent = viewmodels[slot]; + + if(wepent.last_switchweapon != wepent.switchweapon) { - localcmd("-zoom\n"); - button_zoom = false; + weapontime = time; + wepent.last_switchweapon = wepent.switchweapon; + if(slot == 0 && button_zoom && autocvar_cl_unpress_zoom_on_weapon_switch) + { + localcmd("-zoom\n"); + button_zoom = false; + } + if(slot == 0 && autocvar_cl_unpress_attack_on_weapon_switch) + { + localcmd("-fire\n"); + localcmd("-fire2\n"); + button_attack2 = false; + } } - if(autocvar_cl_unpress_attack_on_weapon_switch) + if(wepent.last_activeweapon != wepent.activeweapon) { - localcmd("-fire\n"); - localcmd("-fire2\n"); - button_attack2 = false; - } - } - if(last_activeweapon != activeweapon) - { - last_activeweapon = activeweapon; + wepent.last_activeweapon = wepent.activeweapon; - e = activeweapon; - if(e.netname != "") - localcmd(strcat("\ncl_hook_activeweapon ", e.netname), "\n"); - else - localcmd("\ncl_hook_activeweapon none\n"); + e = wepent.activeweapon; + if(e.netname != "") + localcmd(strcat("\ncl_hook_activeweapon ", e.netname), "\n"); + else if(slot == 0) + localcmd("\ncl_hook_activeweapon none\n"); + } } // ALWAYS Clear Current Scene First @@ -1943,7 +1954,20 @@ void CSQC_UpdateView(entity this, float w, float h) if(autocvar_cl_reticle) { - Weapon wep = activeweapon; + string reticle_image = ""; + bool wep_zoomed = false; + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + entity wepe = viewmodels[slot]; + Weapon wep = wepe.activeweapon; + if(wep != WEP_Null && wep.wr_zoom) + { + bool do_zoom = wep.wr_zoom(wep, NULL); + if(wep.w_reticle && wep.w_reticle != "") + reticle_image = wep.w_reticle; + wep_zoomed += do_zoom; + } + } // Draw the aiming reticle for weapons that use it // reticle_type is changed to the item we are zooming / aiming with, to decide which reticle to use // It must be a persisted float for fading out to work properly (you let go of the zoom button for @@ -1953,9 +1977,9 @@ void CSQC_UpdateView(entity this, float w, float h) // no zoom reticle while dead reticle_type = 0; } - else if(wep.wr_zoomreticle(wep) && autocvar_cl_reticle_weapon) + else if(wep_zoomed && autocvar_cl_reticle_weapon) { - if(reticle_image != "") { reticle_type = 2; } + if(reticle_image && reticle_image != "") { reticle_type = 2; } else { reticle_type = 0; } } else if(button_zoom || zoomscript_caught) diff --git a/qcsrc/client/view.qh b/qcsrc/client/view.qh index f8c8bd26b6..01d4546374 100644 --- a/qcsrc/client/view.qh +++ b/qcsrc/client/view.qh @@ -1,3 +1,5 @@ #pragma once vector crosshair_getcolor(entity this, float health_stat); + +entity viewmodels[MAX_WEAPONSLOTS]; diff --git a/qcsrc/common/_all.inc b/qcsrc/common/_all.inc index 988413f7a9..56681b099e 100644 --- a/qcsrc/common/_all.inc +++ b/qcsrc/common/_all.inc @@ -5,6 +5,7 @@ noref float autocvar_net_connecttimeout = 30; #include "animdecide.qc" #include "ent_cs.qc" #include "net_notice.qc" +#include "wepent.qc" #endif #include "mapinfo.qc" diff --git a/qcsrc/common/_mod.inc b/qcsrc/common/_mod.inc index 90edfa6185..0ac07a19aa 100644 --- a/qcsrc/common/_mod.inc +++ b/qcsrc/common/_mod.inc @@ -11,3 +11,4 @@ #include #include #include +#include diff --git a/qcsrc/common/gamemodes/gamemode/nexball/nexball.qc b/qcsrc/common/gamemodes/gamemode/nexball/nexball.qc index d67ce5ff07..a9bd737ca0 100644 --- a/qcsrc/common/gamemodes/gamemode/nexball/nexball.qc +++ b/qcsrc/common/gamemodes/gamemode/nexball/nexball.qc @@ -168,6 +168,7 @@ void GiveBall(entity plyr, entity ball) ball.teamtime = time + autocvar_g_nexball_basketball_delay_hold_forteam; ball.owner = ball.pusher = plyr; //"owner" is set to the player carrying, "pusher" to the last player who touched it + ball.weaponentity_fld = weaponentity; ball.team = plyr.team; plyr.ballcarried = ball; ball.nb_dropper = plyr; @@ -191,12 +192,12 @@ void GiveBall(entity plyr, entity ball) } plyr.(weaponentity).weapons = plyr.weapons; - plyr.(weaponentity).m_switchweapon = PS(plyr).m_weapon; + plyr.m_switchweapon = plyr.(weaponentity).m_weapon; plyr.weapons = WEPSET(NEXBALL); Weapon w = WEP_NEXBALL; w.wr_resetplayer(w, plyr); - PS(plyr).m_switchweapon = WEP_NEXBALL; - W_SwitchWeapon(plyr, WEP_NEXBALL); + plyr.(weaponentity).m_switchweapon = WEP_NEXBALL; + W_SwitchWeapon(plyr, WEP_NEXBALL, weaponentity); } void DropBall(entity ball, vector org, vector vel) @@ -219,7 +220,7 @@ void DropBall(entity ball, vector org, vector vel) if(ball.owner.metertime) { ball.owner.metertime = 0; - .entity weaponentity = weaponentities[0]; // TODO: find ballstealer + .entity weaponentity = ball.weaponentity_fld; ball.owner.(weaponentity).state = WS_READY; } @@ -903,19 +904,19 @@ METHOD(BallStealer, wr_think, void(BallStealer thiswep, entity actor, .entity we } } -METHOD(BallStealer, wr_setup, void(BallStealer this, entity actor)) +METHOD(BallStealer, wr_setup, void(BallStealer this, entity actor, .entity weaponentity)) { TC(BallStealer, this); //weapon_setup(WEP_PORTO.m_id); } -METHOD(BallStealer, wr_checkammo1, bool(BallStealer this, entity actor)) +METHOD(BallStealer, wr_checkammo1, bool(BallStealer this, entity actor, .entity weaponentity)) { TC(BallStealer, this); return true; } -METHOD(BallStealer, wr_checkammo2, bool(BallStealer this, entity actor)) +METHOD(BallStealer, wr_checkammo2, bool(BallStealer this, entity actor, .entity weaponentity)) { TC(BallStealer, this); return true; @@ -998,16 +999,20 @@ MUTATOR_HOOKFUNCTION(nb, PlayerPreThink) } else { - .entity weaponentity = weaponentities[0]; // TODO - if(player.(weaponentity).weapons) + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) { - player.weapons = player.(weaponentity).weapons; - Weapon w = WEP_NEXBALL; - w.wr_resetplayer(w, player); - PS(player).m_switchweapon = player.(weaponentity).m_switchweapon; - W_SwitchWeapon(player, PS(player).m_switchweapon); + .entity weaponentity = weaponentities[slot]; - player.(weaponentity).weapons = '0 0 0'; + if(player.(weaponentity).weapons) + { + player.weapons = player.(weaponentity).weapons; + Weapon w = WEP_NEXBALL; + w.wr_resetplayer(w, player); + player.(weaponentity).m_switchweapon = player.m_switchweapon; + W_SwitchWeapon(player, player.(weaponentity).m_switchweapon, weaponentity); + + player.(weaponentity).weapons = '0 0 0'; + } } } @@ -1029,8 +1034,11 @@ MUTATOR_HOOKFUNCTION(nb, PlayerSpawn) entity player = M_ARGV(0, entity); player.metertime = 0; - .entity weaponentity = weaponentities[0]; - player.(weaponentity).weapons = '0 0 0'; + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + player.(weaponentity).weapons = '0 0 0'; + } if (nexball_mode & NBM_BASKETBALL) player.weapons |= WEPSET(NEXBALL); @@ -1056,16 +1064,18 @@ MUTATOR_HOOKFUNCTION(nb, PlayerPhysics) MUTATOR_HOOKFUNCTION(nb, ForbidThrowCurrentWeapon) { - entity player = M_ARGV(0, entity); + //entity player = M_ARGV(0, entity); + entity wepent = M_ARGV(1, entity); - return PS(player).m_weapon == WEP_NEXBALL; + return wepent.m_weapon == WEP_NEXBALL; } MUTATOR_HOOKFUNCTION(nb, ForbidDropCurrentWeapon) { - entity player = M_ARGV(0, entity); + //entity player = M_ARGV(0, entity); + int wep = M_ARGV(1, int); - return PS(player).m_weapon == WEP_MORTAR; // TODO: what is this for? + return wep == WEP_MORTAR.m_id; // TODO: what is this for? } MUTATOR_HOOKFUNCTION(nb, FilterItem) diff --git a/qcsrc/common/monsters/monster.qh b/qcsrc/common/monsters/monster.qh index ab644988aa..8e086a085c 100644 --- a/qcsrc/common/monsters/monster.qh +++ b/qcsrc/common/monsters/monster.qh @@ -15,7 +15,7 @@ const int MONSTER_TYPE_PASSIVE = BIT(14); // doesn't target or chase enemies const int MONSTER_TYPE_UNDEAD = BIT(15); // monster is by most definitions a zombie (doesn't fully die unless gibbed) // entity properties of monsterinfo: -.bool(int, entity actor, entity targ) monster_attackfunc; +.bool(int, entity actor, entity targ, .entity weaponentity) monster_attackfunc; // animations .vector anim_blockend; diff --git a/qcsrc/common/monsters/monster/mage.qc b/qcsrc/common/monsters/monster/mage.qc index 71bca32c64..de2a99e2e0 100644 --- a/qcsrc/common/monsters/monster/mage.qc +++ b/qcsrc/common/monsters/monster/mage.qc @@ -323,9 +323,8 @@ void M_Mage_Defend_Shield(entity this) this.anim_finished = time + 1; } -bool M_Mage_Attack(int attack_type, entity actor, entity targ) +bool M_Mage_Attack(int attack_type, entity actor, entity targ, .entity weaponentity) { - .entity weaponentity = weaponentities[0]; switch(attack_type) { case MONSTER_ATTACK_MELEE: diff --git a/qcsrc/common/monsters/monster/shambler.qc b/qcsrc/common/monsters/monster/shambler.qc index aae268666f..6baa453475 100644 --- a/qcsrc/common/monsters/monster/shambler.qc +++ b/qcsrc/common/monsters/monster/shambler.qc @@ -156,7 +156,7 @@ void M_Shambler_Attack_Lightning(entity this) .int state; -bool M_Shambler_Attack(int attack_type, entity actor, entity targ) +bool M_Shambler_Attack(int attack_type, entity actor, entity targ, .entity weaponentity) { switch(attack_type) { diff --git a/qcsrc/common/monsters/monster/spider.qc b/qcsrc/common/monsters/monster/spider.qc index a122865321..8c90ade8a4 100644 --- a/qcsrc/common/monsters/monster/spider.qc +++ b/qcsrc/common/monsters/monster/spider.qc @@ -170,9 +170,8 @@ void M_Spider_Attack_Web(entity this) CSQCProjectile(proj, true, PROJECTILE_ELECTRO, true); } -bool M_Spider_Attack(int attack_type, entity actor, entity targ) +bool M_Spider_Attack(int attack_type, entity actor, entity targ, .entity weaponentity) { - .entity weaponentity = weaponentities[0]; switch(attack_type) { Weapon wep = WEP_SPIDER_ATTACK; diff --git a/qcsrc/common/monsters/monster/wyvern.qc b/qcsrc/common/monsters/monster/wyvern.qc index cd53ff26f7..92a098abf2 100644 --- a/qcsrc/common/monsters/monster/wyvern.qc +++ b/qcsrc/common/monsters/monster/wyvern.qc @@ -46,7 +46,7 @@ METHOD(WyvernAttack, wr_think, void(WyvernAttack thiswep, entity actor, .entity } } -METHOD(WyvernAttack, wr_checkammo1, bool(WyvernAttack this, entity actor)) { +METHOD(WyvernAttack, wr_checkammo1, bool(WyvernAttack this, entity actor, .entity weaponentity)) { TC(WyvernAttack, this); return true; } @@ -88,9 +88,8 @@ void M_Wyvern_Attack_Fireball_Touch(entity this, entity toucher) M_Wyvern_Attack_Fireball_Explode(this); } -bool M_Wyvern_Attack(int attack_type, entity actor, entity targ) +bool M_Wyvern_Attack(int attack_type, entity actor, entity targ, .entity weaponentity) { - .entity weaponentity = weaponentities[0]; switch(attack_type) { case MONSTER_ATTACK_MELEE: diff --git a/qcsrc/common/monsters/monster/zombie.qc b/qcsrc/common/monsters/monster/zombie.qc index 8bbb300c76..d9f866e9d1 100644 --- a/qcsrc/common/monsters/monster/zombie.qc +++ b/qcsrc/common/monsters/monster/zombie.qc @@ -94,7 +94,7 @@ bool M_Zombie_Defend_Block(entity this) return true; } -bool M_Zombie_Attack(int attack_type, entity actor, entity targ) +bool M_Zombie_Attack(int attack_type, entity actor, entity targ, .entity weaponentity) { switch(attack_type) { diff --git a/qcsrc/common/monsters/sv_monsters.qc b/qcsrc/common/monsters/sv_monsters.qc index b8c3bab21e..a89e55b1ce 100644 --- a/qcsrc/common/monsters/sv_monsters.qc +++ b/qcsrc/common/monsters/sv_monsters.qc @@ -412,16 +412,18 @@ bool Monster_Attack_Leap(entity this, vector anm, void(entity this, entity touch return true; } -void Monster_Attack_Check(entity this, entity targ) +void Monster_Attack_Check(entity this, entity targ, .entity weaponentity) { + int slot = weaponslot(weaponentity); + if((this == NULL || targ == NULL) || (!this.monster_attackfunc) - || (time < this.attack_finished_single[0]) + || (time < this.attack_finished_single[slot]) ) { return; } if(vdist(targ.origin - this.origin, <=, this.attack_range)) { - bool attack_success = this.monster_attackfunc(MONSTER_ATTACK_MELEE, this, targ); + bool attack_success = this.monster_attackfunc(MONSTER_ATTACK_MELEE, this, targ, weaponentity); if(attack_success == 1) Monster_Sound(this, monstersound_melee, 0, false, CH_VOICE); else if(attack_success > 0) @@ -430,7 +432,7 @@ void Monster_Attack_Check(entity this, entity targ) if(vdist(targ.origin - this.origin, >, this.attack_range)) { - float attack_success = this.monster_attackfunc(MONSTER_ATTACK_RANGED, this, targ); + float attack_success = this.monster_attackfunc(MONSTER_ATTACK_RANGED, this, targ, weaponentity); if(attack_success == 1) Monster_Sound(this, monstersound_melee, 0, false, CH_VOICE); else if(attack_success > 0) @@ -695,7 +697,7 @@ void Monster_Move(entity this, float runspeed, float walkspeed, float stpspeed) // update goal entity if lost if(this.target2 && this.goalentity.targetname != this.target2) { this.goalentity = find(NULL, targetname, this.target2); } - entity targ; + entity targ = this.goalentity; if(STAT(FROZEN, this) == 2) { @@ -781,8 +783,6 @@ void Monster_Move(entity this, float runspeed, float walkspeed, float stpspeed) } } - targ = this.goalentity; - if (MUTATOR_CALLHOOK(MonsterMove, this, runspeed, walkspeed, targ) || gameover || this.draggedby != NULL @@ -895,7 +895,8 @@ void Monster_Move(entity this, float runspeed, float walkspeed, float stpspeed) this.angles_y += turny; } - Monster_Attack_Check(this, this.enemy); + .entity weaponentity = weaponentities[0]; // TODO? + Monster_Attack_Check(this, this.enemy, weaponentity); } void Monster_Remove(entity this) @@ -1036,7 +1037,10 @@ void Monster_Dead(entity this, entity attacker, float gibbed) mon.mr_death(mon, this); if(this.candrop && this.weapon) - W_ThrowNewWeapon(this, this.weapon, 0, this.origin, randomvec() * 150 + '0 0 325'); + { + .entity weaponentity = weaponentities[0]; // TODO: unhardcode + W_ThrowNewWeapon(this, this.weapon, 0, this.origin, randomvec() * 150 + '0 0 325', weaponentity); + } } void Monster_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force) diff --git a/qcsrc/common/mutators/mutator/breakablehook/sv_breakablehook.qc b/qcsrc/common/mutators/mutator/breakablehook/sv_breakablehook.qc index fdb0dc38d1..dfde6ed73b 100644 --- a/qcsrc/common/mutators/mutator/breakablehook/sv_breakablehook.qc +++ b/qcsrc/common/mutators/mutator/breakablehook/sv_breakablehook.qc @@ -23,7 +23,7 @@ MUTATOR_HOOKFUNCTION(breakablehook, PlayerDamage_Calculate) if(DIFF_TEAM(frag_attacker, frag_target.realowner)) { Damage (frag_target.realowner, frag_attacker, frag_attacker, 5, WEP_HOOK.m_id | HITTYPE_SPLASH, frag_target.realowner.origin, '0 0 0'); - RemoveGrapplingHook(frag_target.realowner); + RemoveHook(frag_target); return; // dead } } diff --git a/qcsrc/common/mutators/mutator/buffs/sv_buffs.qc b/qcsrc/common/mutators/mutator/buffs/sv_buffs.qc index 32c61eb6aa..21ce55bcc4 100644 --- a/qcsrc/common/mutators/mutator/buffs/sv_buffs.qc +++ b/qcsrc/common/mutators/mutator/buffs/sv_buffs.qc @@ -842,8 +842,14 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerPreThink) } if(player.buffs & BUFF_AMMO.m_itemid) - if(player.clip_size) - player.clip_load = player.(weapon_load[PS(player).m_switchweapon.m_id]) = player.clip_size; + { + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + if(player.(weaponentity).clip_size) + player.(weaponentity).clip_load = player.(weaponentity).(weapon_load[player.(weaponentity).m_switchweapon.m_id]) = player.(weaponentity).clip_size; + } + } if((player.buffs & BUFF_INVISIBLE.m_itemid) && (player.oldbuffs & BUFF_INVISIBLE.m_itemid)) if(player.alpha != autocvar_g_buffs_invisible_alpha) @@ -870,9 +876,17 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerPreThink) player.buff_ammo_prev_infitems = (player.items & IT_UNLIMITED_WEAPON_AMMO); player.items |= IT_UNLIMITED_WEAPON_AMMO; - if(player.clip_load) - player.buff_ammo_prev_clipload = player.clip_load; - player.clip_load = player.(weapon_load[PS(player).m_switchweapon.m_id]) = player.clip_size; + if(player.buffs & BUFF_AMMO.m_itemid) + { + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + if(player.(weaponentity).clip_load) + player.(weaponentity).buff_ammo_prev_clipload = player.(weaponentity).clip_load; + if(player.(weaponentity).clip_size) + player.(weaponentity).clip_load = player.(weaponentity).(weapon_load[player.(weaponentity).m_switchweapon.m_id]) = player.(weaponentity).clip_size; + } + } } BUFF_ONREM(BUFF_AMMO) @@ -882,8 +896,15 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerPreThink) else player.items &= ~IT_UNLIMITED_WEAPON_AMMO; - if(player.buff_ammo_prev_clipload) - player.clip_load = player.buff_ammo_prev_clipload; + if(player.buffs & BUFF_AMMO.m_itemid) + { + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + if(player.(weaponentity).buff_ammo_prev_clipload) + player.(weaponentity).clip_load = player.(weaponentity).buff_ammo_prev_clipload; + } + } } BUFF_ONADD(BUFF_INVISIBLE) diff --git a/qcsrc/common/mutators/mutator/nades/nades.qc b/qcsrc/common/mutators/mutator/nades/nades.qc index 6ec9c23213..24d8c87cc0 100644 --- a/qcsrc/common/mutators/mutator/nades/nades.qc +++ b/qcsrc/common/mutators/mutator/nades/nades.qc @@ -736,7 +736,7 @@ void nade_boom(entity this) IL_EACH(g_projectiles, it.classname == "grapplinghook" && it.aiment == this, { - RemoveGrapplingHook(it.realowner); + RemoveHook(it); }); delete(this); @@ -785,7 +785,7 @@ void nade_touch(entity this, entity toucher) { IL_EACH(g_projectiles, it.classname == "grapplinghook" && it.aiment == this, { - RemoveGrapplingHook(it.realowner); + RemoveHook(it); }); delete(this); return; @@ -891,7 +891,7 @@ void toss_nade(entity e, bool set_owner, vector _velocity, float _time) makevectors(e.v_angle); // NOTE: always throw from first weapon entity? - W_SetupShot(e, weaponentities[0], false, false, SND_Null, CH_WEAPON_A, 0); + W_SetupShot(e, _nade.weaponentity_fld, false, false, SND_Null, CH_WEAPON_A, 0); Kill_Notification(NOTIF_ONE_ONLY, e, MSG_CENTER, CPID_NADES); @@ -1034,6 +1034,8 @@ void spawn_held_nade(entity player, entity nowner, float ntime, int ntype, strin if(Nades_from(n.nade_type) == NADE_TYPE_Null) n.nade_type = NADE_TYPE_NORMAL.m_id; + .entity weaponentity = weaponentities[0]; // TODO: unhardcode + setmodel(n, MDL_PROJECTILE_NADE); //setattachment(n, player, "bip01 l hand"); n.exteriormodeltoclient = player; @@ -1048,9 +1050,9 @@ void spawn_held_nade(entity player, entity nowner, float ntime, int ntype, strin setthink(n, nade_beep); n.nextthink = max(n.wait - 3, time); n.projectiledeathtype = DEATH_NADE.m_id; + n.weaponentity_fld = weaponentity; setmodel(fn, MDL_NADE_VIEW); - .entity weaponentity = weaponentities[0]; // TODO: unhardcode setattachment(fn, player.(weaponentity), ""); fn.realowner = fn.owner = player; fn.colormod = Nades_from(n.nade_type).m_color; @@ -1058,6 +1060,7 @@ void spawn_held_nade(entity player, entity nowner, float ntime, int ntype, strin fn.glowmod = player.glowmod; setthink(fn, SUB_Remove); fn.nextthink = n.wait; + fn.weaponentity_fld = weaponentity; player.nade = n; player.fake_nade = fn; diff --git a/qcsrc/common/mutators/mutator/nix/sv_nix.qc b/qcsrc/common/mutators/mutator/nix/sv_nix.qc index 143b3c6edf..a06f5364d4 100644 --- a/qcsrc/common/mutators/mutator/nix/sv_nix.qc +++ b/qcsrc/common/mutators/mutator/nix/sv_nix.qc @@ -63,8 +63,14 @@ REGISTER_MUTATOR(nix, cvar("g_nix") && !cvar("g_instagib") && !cvar("g_overkill" it.ammo_rockets = start_ammo_rockets; it.ammo_fuel = start_ammo_fuel; it.weapons = start_weapons; - if(!client_hasweapon(it, PS(it).m_weapon, true, false)) - PS(it).m_switchweapon = w_getbestweapon(it); + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + if(it.(weaponentity).m_weapon == WEP_Null && slot != 0) + continue; + if(!client_hasweapon(it, it.(weaponentity).m_weapon, weaponentity, true, false)) + it.(weaponentity).m_switchweapon = w_getbestweapon(it, weaponentity); + } }); } @@ -164,14 +170,24 @@ void NIX_GiveCurrentWeapon(entity this) // all weapons must be fully loaded when we spawn if(e.spawnflags & WEP_FLAG_RELOADABLE) // prevent accessing undefined cvars - this.(weapon_load[nix_weapon]) = e.reloading_ammo; + { + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + this.(weaponentity).(weapon_load[nix_weapon]) = e.reloading_ammo; + } + } // vortex too if(WEP_CVAR(vortex, charge)) { if(WEP_CVAR_SEC(vortex, chargepool)) this.vortex_chargepool_ammo = 1; - this.vortex_charge = WEP_CVAR(vortex, charge_start); + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + this.(weaponentity).vortex_charge = WEP_CVAR(vortex, charge_start); + } } // set last change info @@ -205,12 +221,19 @@ void NIX_GiveCurrentWeapon(entity this) this.weapons |= e.m_wepset; Weapon w = Weapons_from(nix_weapon); - if(PS(this).m_switchweapon != w) - if(!client_hasweapon(this, PS(this).m_switchweapon, true, false)) + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + if(this.(weaponentity).m_weapon == WEP_Null && slot != 0) + continue; + + if(this.(weaponentity).m_switchweapon != w) + if(!client_hasweapon(this, this.(weaponentity).m_switchweapon, weaponentity, true, false)) { - if(client_hasweapon(this, w, true, false)) - W_SwitchWeapon(this, w); + if(client_hasweapon(this, w, weaponentity, true, false)) + W_SwitchWeapon(this, w, weaponentity); } + } } MUTATOR_HOOKFUNCTION(nix, ForbidThrowCurrentWeapon) diff --git a/qcsrc/common/mutators/mutator/overkill/hmg.qc b/qcsrc/common/mutators/mutator/overkill/hmg.qc index 024fdb1cc7..caf96a67b3 100644 --- a/qcsrc/common/mutators/mutator/overkill/hmg.qc +++ b/qcsrc/common/mutators/mutator/overkill/hmg.qc @@ -20,14 +20,14 @@ void W_HeavyMachineGun_Attack_Auto(Weapon thiswep, entity actor, .entity weapone return; } - if((!thiswep.wr_checkammo1(thiswep, actor) && !(actor.items & IT_UNLIMITED_WEAPON_AMMO)) || (!(actor.items & IT_SUPERWEAPON) && !(actor.items & IT_UNLIMITED_SUPERWEAPONS))) + if((!thiswep.wr_checkammo1(thiswep, actor, weaponentity) && !(actor.items & IT_UNLIMITED_WEAPON_AMMO)) || (!(actor.items & IT_SUPERWEAPON) && !(actor.items & IT_UNLIMITED_SUPERWEAPONS))) { - W_SwitchWeapon_Force(actor, w_getbestweapon(actor)); + W_SwitchWeapon_Force(actor, w_getbestweapon(actor, weaponentity), weaponentity); w_ready(thiswep, actor, weaponentity, fire); return; } - W_DecreaseAmmo(WEP_HMG, actor, WEP_CVAR(hmg, ammo)); + W_DecreaseAmmo(WEP_HMG, actor, WEP_CVAR(hmg, ammo), weaponentity); W_SetupShot (actor, weaponentity, true, 0, SND_UZI_FIRE, CH_WEAPON_A, WEP_CVAR(hmg, damage)); @@ -37,10 +37,10 @@ void W_HeavyMachineGun_Attack_Auto(Weapon thiswep, entity actor, .entity weapone 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(actor, w_shotorg, w_shotdir, hmg_spread, WEP_CVAR(hmg, solidpenetration), WEP_CVAR(hmg, damage), WEP_CVAR(hmg, force), WEP_HMG.m_id, 0); + float hmg_spread = bound(WEP_CVAR(hmg, spread_min), WEP_CVAR(hmg, spread_min) + (WEP_CVAR(hmg, spread_add) * actor.(weaponentity).misc_bulletcounter), WEP_CVAR(hmg, spread_max)); + fireBullet(actor, weaponentity, 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; + actor.(weaponentity).misc_bulletcounter = actor.(weaponentity).misc_bulletcounter + 1; Send_Effect(EFFECT_MACHINEGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1); @@ -58,45 +58,45 @@ void W_HeavyMachineGun_Attack_Auto(Weapon thiswep, entity actor, .entity weapone weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(hmg, refire), W_HeavyMachineGun_Attack_Auto); } -METHOD(HeavyMachineGun, wr_aim, void(entity thiswep, entity actor)) +METHOD(HeavyMachineGun, wr_aim, void(entity thiswep, entity actor, .entity weaponentity)) { if(vdist(actor.origin - actor.enemy.origin, <, 3000 - bound(0, skill, 10) * 200)) - PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, 1000000, 0, 0.001, false); + PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false); else - PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, 1000000, 0, 0.001, false); + PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, 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 + if(WEP_CVAR(hmg, reload_ammo) && actor.(weaponentity).clip_load < WEP_CVAR(hmg, ammo)) { // forced reload thiswep.wr_reload(thiswep, actor, weaponentity); } else { if (fire & 1) if (weapon_prepareattack(thiswep, actor, weaponentity, false, 0)) { - actor.misc_bulletcounter = 0; + actor.(weaponentity).misc_bulletcounter = 0; W_HeavyMachineGun_Attack_Auto(thiswep, actor, weaponentity, fire); } } } -METHOD(HeavyMachineGun, wr_checkammo1, bool(entity thiswep, entity actor)) +METHOD(HeavyMachineGun, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity)) { float ammo_amount = actor.ammo_nails >= WEP_CVAR(hmg, ammo); if(autocvar_g_balance_hmg_reload_ammo) - ammo_amount += actor.(weapon_load[WEP_HMG.m_id]) >= WEP_CVAR(hmg, ammo); + ammo_amount += actor.(weaponentity).(weapon_load[WEP_HMG.m_id]) >= WEP_CVAR(hmg, ammo); return ammo_amount; } -METHOD(HeavyMachineGun, wr_checkammo2, bool(entity thiswep, entity actor)) +METHOD(HeavyMachineGun, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity)) { float ammo_amount = actor.ammo_nails >= WEP_CVAR(hmg, ammo); if(autocvar_g_balance_hmg_reload_ammo) - ammo_amount += actor.(weapon_load[WEP_HMG.m_id]) >= WEP_CVAR(hmg, ammo); + ammo_amount += actor.(weaponentity).(weapon_load[WEP_HMG.m_id]) >= WEP_CVAR(hmg, ammo); return ammo_amount; } diff --git a/qcsrc/common/mutators/mutator/overkill/rpc.qc b/qcsrc/common/mutators/mutator/overkill/rpc.qc index ad2ee3f029..745b87f853 100644 --- a/qcsrc/common/mutators/mutator/overkill/rpc.qc +++ b/qcsrc/common/mutators/mutator/overkill/rpc.qc @@ -68,7 +68,7 @@ void W_RocketPropelledChainsaw_Attack (Weapon thiswep, entity actor, .entity wea entity missile = spawn(); //WarpZone_RefSys_SpawnSameRefSys(actor); entity flash = spawn (); - W_DecreaseAmmo(thiswep, actor, WEP_CVAR(rpc, ammo)); + W_DecreaseAmmo(thiswep, actor, WEP_CVAR(rpc, ammo), weaponentity); W_SetupShot_ProjectileSize (actor, weaponentity, '-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); @@ -111,14 +111,14 @@ void W_RocketPropelledChainsaw_Attack (Weapon thiswep, entity actor, .entity wea MUTATOR_CALLHOOK(EditProjectile, actor, missile); } -METHOD(RocketPropelledChainsaw, wr_aim, void(entity thiswep, entity actor)) +METHOD(RocketPropelledChainsaw, wr_aim, void(entity thiswep, entity actor, .entity weaponentity)) { - PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, WEP_CVAR(rpc, speed), 0, WEP_CVAR(rpc, lifetime), false); + PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, 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)) { + if(WEP_CVAR(rpc, reload_ammo) && actor.(weaponentity).clip_load < WEP_CVAR(rpc, ammo)) { thiswep.wr_reload(thiswep, actor, weaponentity); } else { @@ -138,14 +138,14 @@ METHOD(RocketPropelledChainsaw, wr_think, void(entity thiswep, entity actor, .en } } -METHOD(RocketPropelledChainsaw, wr_checkammo1, bool(entity thiswep, entity actor)) +METHOD(RocketPropelledChainsaw, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity)) { float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR(rpc, ammo); - ammo_amount += actor.(weapon_load[WEP_RPC.m_id]) >= WEP_CVAR(rpc, ammo); + ammo_amount += actor.(weaponentity).(weapon_load[WEP_RPC.m_id]) >= WEP_CVAR(rpc, ammo); return ammo_amount; } -METHOD(RocketPropelledChainsaw, wr_checkammo2, bool(entity thiswep, entity actor)) +METHOD(RocketPropelledChainsaw, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity)) { return false; } diff --git a/qcsrc/common/mutators/mutator/overkill/sv_overkill.qc b/qcsrc/common/mutators/mutator/overkill/sv_overkill.qc index 21a191a0e6..85beb641f0 100644 --- a/qcsrc/common/mutators/mutator/overkill/sv_overkill.qc +++ b/qcsrc/common/mutators/mutator/overkill/sv_overkill.qc @@ -4,24 +4,15 @@ #include "rpc.qh" bool autocvar_g_overkill_powerups_replace; -bool autocvar_g_overkill_ammo_charge; -float autocvar_g_overkill_ammo_charge_notice; -float autocvar_g_overkill_ammo_charge_limit; bool autocvar_g_overkill_filter_healthmega; bool autocvar_g_overkill_filter_armormedium; bool autocvar_g_overkill_filter_armorbig; bool autocvar_g_overkill_filter_armorlarge; -.float ok_lastwep; .float ok_item; -.float ok_notice_time; -.float ammo_charge[Weapons_MAX]; -.float ok_use_ammocharge = _STAT(OK_AMMO_CHARGE); -.float ok_ammo_charge = _STAT(OK_AMMO_CHARGEPOOL); - -void(entity ent, float wep) ok_DecreaseCharge; +.Weapon ok_lastwep[MAX_WEAPONSLOTS]; void ok_Initialize(); @@ -39,59 +30,10 @@ REGISTER_MUTATOR(ok, cvar("g_overkill") && !cvar("g_instagib") && !g_nexball && } } -MUTATOR_HOOKFUNCTION(ok, W_DecreaseAmmo) -{ - entity actor = M_ARGV(0, entity); - if (actor.ok_use_ammocharge) - { - ok_DecreaseCharge(actor, PS(actor).m_weapon.m_id); - return true; - } -} - -MUTATOR_HOOKFUNCTION(ok, W_Reload) -{ - entity actor = M_ARGV(0, entity); - return actor.ok_use_ammocharge; -} - void W_Blaster_Attack(entity, .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 = Weapons_from(wep); - - if (wepent == WEP_Null) 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 = Weapons_from(wep); - - if (wepent == WEP_Null) return; // dummy - - if(ent.ok_use_ammocharge) - if(!PHYS_INPUT_BUTTON_ATCK(ent)) // 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 = Weapons_from(wep); - - if(wepent == WEP_Null) return false; // dummy - - return (ent.ammo_charge[wep] >= cvar(sprintf("g_overkill_ammo_decharge_%s", wepent.netname))); -} - MUTATOR_HOOKFUNCTION(ok, PlayerDamage_Calculate, CBC_ORDER_LAST) { entity frag_attacker = M_ARGV(1, entity); @@ -141,7 +83,12 @@ MUTATOR_HOOKFUNCTION(ok, PlayerDies) ok_DropItem(frag_target, targ); - frag_target.ok_lastwep = PS(frag_target).m_switchweapon.m_id; + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + + frag_target.ok_lastwep[slot] = frag_target.(weaponentity).m_switchweapon; + } } MUTATOR_HOOKFUNCTION(ok, MonsterDropItem) @@ -172,18 +119,22 @@ MUTATOR_HOOKFUNCTION(ok, PlayerPreThink) if(IS_DEAD(player) || !IS_PLAYER(player) || STAT(FROZEN, player)) return; - if(player.ok_lastwep) + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) { - Weapon newwep = Weapons_from(player.ok_lastwep); - if(player.ok_lastwep == WEP_HMG.m_id) - newwep = WEP_MACHINEGUN; - if(player.ok_lastwep == WEP_RPC.m_id) - newwep = WEP_VORTEX; - PS(player).m_switchweapon = newwep; - player.ok_lastwep = 0; - } + .entity weaponentity = weaponentities[slot]; + entity thiswep = player.(weaponentity); - ok_IncreaseCharge(player, PS(player).m_weapon.m_id); + if(player.ok_lastwep[slot] && player.ok_lastwep[slot] != WEP_Null) + { + Weapon newwep = player.ok_lastwep[slot]; + if(player.ok_lastwep[slot] == WEP_HMG) + newwep = WEP_MACHINEGUN; + if(player.ok_lastwep[slot] == WEP_RPC) + newwep = WEP_VORTEX; + thiswep.m_switchweapon = newwep; + player.ok_lastwep[slot] = WEP_Null; + } + } if(PHYS_INPUT_BUTTON_ATCK2(player)) if( !forbidWeaponUse(player) || player.weapon_blocked // allow if weapon is blocked @@ -193,44 +144,31 @@ MUTATOR_HOOKFUNCTION(ok, PlayerPreThink) player.jump_interval = time + WEP_CVAR_PRI(blaster, refire) * W_WeaponRateFactor(player); makevectors(player.v_angle); - Weapon oldwep = PS(player).m_weapon; - PS(player).m_weapon = WEP_BLASTER; - W_Blaster_Attack( - player, - weaponentities[0], // TODO: unhardcode - 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) - ); - PS(player).m_weapon = oldwep; - } - - player.weapon_blocked = false; - - player.ok_ammo_charge = player.ammo_charge[PS(player).m_weapon.m_id]; - - if(player.ok_use_ammocharge) - if(!ok_CheckWeaponCharge(player, PS(player).m_weapon.m_id)) - { - if(autocvar_g_overkill_ammo_charge_notice && time > player.ok_notice_time && PHYS_INPUT_BUTTON_ATCK(player) && IS_REAL_CLIENT(player) && PS(player).m_weapon == PS(player).m_switchweapon) + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) { - //Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_OVERKILL_CHARGE); - player.ok_notice_time = time + 2; - play2(player, SND(DRYFIRE)); + .entity weaponentity = weaponentities[slot]; + + if(player.(weaponentity).m_weapon == WEP_Null && slot != 0) + continue; + + Weapon oldwep = player.(weaponentity).m_weapon; + player.(weaponentity).m_weapon = WEP_BLASTER; + W_Blaster_Attack( + player, + weaponentity, + 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) + ); + player.(weaponentity).m_weapon = oldwep; } - Weapon wpn = PS(player).m_weapon; - .entity weaponentity = weaponentities[0]; // TODO: unhardcode - if(player.(weaponentity).state != WS_CLEAR) - w_ready(wpn, player, weaponentity, PHYS_INPUT_BUTTON_ATCK(player) | (PHYS_INPUT_BUTTON_ATCK2(player) << 1)); - - player.weapon_blocked = true; } PHYS_INPUT_BUTTON_ATCK2(player) = false; @@ -240,19 +178,14 @@ MUTATOR_HOOKFUNCTION(ok, PlayerSpawn) { entity player = M_ARGV(0, entity); - if(autocvar_g_overkill_ammo_charge) - { - FOREACH(Weapons, it != WEP_Null, LAMBDA(player.ammo_charge[it.m_id] = autocvar_g_overkill_ammo_charge_limit)); - - player.ok_use_ammocharge = 1; - player.ok_notice_time = time; - } - else - player.ok_use_ammocharge = 0; - // if player changed their weapon while dead, don't switch to their death weapon if(player.impulse) - player.ok_lastwep = 0; + { + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + player.ok_lastwep[slot] = WEP_Null; + } + } } void self_spawnfunc_weapon_hmg(entity this) { spawnfunc_weapon_hmg(this); } @@ -321,15 +254,6 @@ MUTATOR_HOOKFUNCTION(ok, FilterItem) return true; } -MUTATOR_HOOKFUNCTION(ok, SpectateCopy) -{ - entity spectatee = M_ARGV(0, entity); - entity client = M_ARGV(1, entity); - - client.ammo_charge[PS(client).m_weapon.m_id] = spectatee.ammo_charge[PS(spectatee).m_weapon.m_id]; - client.ok_use_ammocharge = spectatee.ok_use_ammocharge; -} - MUTATOR_HOOKFUNCTION(ok, SetStartItems, CBC_ORDER_LAST) { WepSet ok_start_items = (WEPSET(MACHINEGUN) | WEPSET(VORTEX) | WEPSET(SHOTGUN)); diff --git a/qcsrc/common/mutators/mutator/pinata/sv_pinata.qc b/qcsrc/common/mutators/mutator/pinata/sv_pinata.qc index bc3887e860..ff942db310 100644 --- a/qcsrc/common/mutators/mutator/pinata/sv_pinata.qc +++ b/qcsrc/common/mutators/mutator/pinata/sv_pinata.qc @@ -6,12 +6,20 @@ MUTATOR_HOOKFUNCTION(pinata, PlayerDies) { entity frag_target = M_ARGV(2, entity); - FOREACH(Weapons, it != WEP_Null, LAMBDA( - if(frag_target.weapons & WepSet_FromWeapon(it)) - if(PS(frag_target).m_switchweapon != it) - if(W_IsWeaponThrowable(frag_target, it.m_id)) - W_ThrowNewWeapon(frag_target, it.m_id, false, CENTER_OR_VIEWOFS(frag_target), randomvec() * 175 + '0 0 325'); - )); + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + + if(frag_target.(weaponentity).m_weapon == WEP_Null && slot != 0) + continue; + + FOREACH(Weapons, it != WEP_Null, LAMBDA( + if(frag_target.weapons & WepSet_FromWeapon(it)) + if(frag_target.(weaponentity).m_switchweapon != it) + if(W_IsWeaponThrowable(frag_target, it.m_id)) + W_ThrowNewWeapon(frag_target, it.m_id, false, CENTER_OR_VIEWOFS(frag_target), randomvec() * 175 + '0 0 325', weaponentity); + )); + } return true; } diff --git a/qcsrc/common/physics/player.qc b/qcsrc/common/physics/player.qc index b5635e0945..76b81266ed 100644 --- a/qcsrc/common/physics/player.qc +++ b/qcsrc/common/physics/player.qc @@ -96,8 +96,15 @@ void PM_ClientMovement_UpdateStatus(entity this) // set crouched bool do_crouch = PHYS_INPUT_BUTTON_CROUCH(this); - if(this.hook && !wasfreed(this.hook)) - do_crouch = false; + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + entity wep = viewmodels[slot]; + if(wep.hook && !wasfreed(wep.hook)) + { + do_crouch = false; + break; // don't bother checking the others + } + } if(this.waterlevel >= WATERLEVEL_SWIMMING) do_crouch = false; if(hud != HUD_NORMAL) @@ -608,7 +615,12 @@ void PM_check_hitground(entity this) this.wasFlying = false; if (this.waterlevel >= WATERLEVEL_SWIMMING) return; if (time < this.ladder_time) return; - if (this.hook) return; + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + if(this.(weaponentity).hook) + return; + } this.nextstep = time + 0.3 + random() * 0.1; trace_dphitq3surfaceflags = 0; tracebox(this.origin, this.mins, this.maxs, this.origin - '0 0 1', MOVE_NOMONSTERS, this); diff --git a/qcsrc/common/state.qc b/qcsrc/common/state.qc index 1a2fb1e7bf..a9bc3e5e3c 100644 --- a/qcsrc/common/state.qc +++ b/qcsrc/common/state.qc @@ -17,10 +17,6 @@ void PlayerState_detach(entity this) PS(this) = NULL; if (ps.m_client != this) return; // don't own state, spectator - ps.m_switchweapon = WEP_Null; - ps.m_weapon = WEP_Null; - ps.m_switchingweapon = WEP_Null; - ps.ps_push(ps, this); FOREACH_CLIENT(PS(it) == ps, { PS(it) = NULL; }); delete(ps); diff --git a/qcsrc/common/state.qh b/qcsrc/common/state.qh index 94b9bc325f..850e7ac9db 100644 --- a/qcsrc/common/state.qh +++ b/qcsrc/common/state.qh @@ -12,16 +12,6 @@ CLASS(PlayerState, Object) CONSTRUCT(PlayerState); this.m_client = client; } - ATTRIB(PlayerState, m_switchingweapon, Weapon, Weapons_from(-1)); - ATTRIB(PlayerState, m_switchweapon, Weapon, Weapons_from(-1)); - ATTRIB(PlayerState, m_weapon, Weapon, Weapons_from(-1)); - METHOD(PlayerState, ps_push, void(PlayerState this, entity cl)) - { - TC(PlayerState, this); - STAT(ACTIVEWEAPON, cl) = this.m_weapon.m_id; - STAT(SWITCHINGWEAPON, cl) = this.m_switchingweapon.m_id; - STAT(SWITCHWEAPON, cl) = this.m_switchweapon.m_id; - } ENDCLASS(PlayerState) .PlayerState _ps; diff --git a/qcsrc/common/stats.qh b/qcsrc/common/stats.qh index 82398aa56b..c4c5172aaf 100644 --- a/qcsrc/common/stats.qh +++ b/qcsrc/common/stats.qh @@ -55,13 +55,7 @@ REGISTER_STAT(PL_CROUCH_MAX, vector, autocvar_sv_player_crouch_maxs) REGISTER_STAT(KH_KEYS, int) -/** weapon requested to switch to; next WANTED weapon (for HUD) */ -REGISTER_STAT(SWITCHWEAPON, int) -/** weapon currently being switched to (is copied from switchweapon once switch is possible) */ -REGISTER_STAT(SWITCHINGWEAPON, int) -REGISTER_STAT(WEAPON_NEXTTHINK, float) #ifdef SVQC -SPECTATE_COPYFIELD(_STAT(WEAPON_NEXTTHINK)) float W_WeaponRateFactor(entity this); #endif REGISTER_STAT(WEAPONRATEFACTOR, float, W_WeaponRateFactor(this)) @@ -114,8 +108,6 @@ REGISTER_STAT(NADE_BONUS_SCORE, float) REGISTER_STAT(HEALING_ORB, float) REGISTER_STAT(HEALING_ORB_ALPHA, float) REGISTER_STAT(PLASMA, int) -REGISTER_STAT(OK_AMMO_CHARGE, float) -REGISTER_STAT(OK_AMMO_CHARGEPOOL, float) REGISTER_STAT(FROZEN, int) REGISTER_STAT(REVIVE_PROGRESS, float) REGISTER_STAT(ROUNDLOST, int) diff --git a/qcsrc/common/t_items.qc b/qcsrc/common/t_items.qc index 2f1a4c3aa6..293f5ae997 100644 --- a/qcsrc/common/t_items.qc +++ b/qcsrc/common/t_items.qc @@ -673,21 +673,30 @@ LABEL(YEAH) float Item_GiveTo(entity item, entity player) { - float _switchweapon; float pickedup; // if nothing happens to player, just return without taking the item pickedup = false; - _switchweapon = false; + int _switchweapon = 0; // in case the player has autoswitch enabled do the following: // if the player is using their best weapon before items are given, they // probably want to switch to an even better weapon after items are given - if (player.autoswitch) - if (PS(player).m_switchweapon == w_getbestweapon(player)) - _switchweapon = true; - if (!(player.weapons & WepSet_FromWeapon(PS(player).m_switchweapon))) - _switchweapon = true; + if(player.autoswitch) + { + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + if(player.(weaponentity).m_weapon != WEP_Null || slot == 0) + { + if(player.(weaponentity).m_switchweapon == w_getbestweapon(player, weaponentity)) + _switchweapon |= BIT(slot); + + if(!(player.weapons & WepSet_FromWeapon(player.(weaponentity).m_switchweapon))) + _switchweapon |= BIT(slot); + } + } + } pickedup |= Item_GiveAmmoTo(item, player, ammo_fuel, g_pickup_fuel_max, ITEM_MODE_FUEL); pickedup |= Item_GiveAmmoTo(item, player, ammo_shells, g_pickup_shells_max, ITEM_MODE_NONE); @@ -710,7 +719,12 @@ float Item_GiveTo(entity item, entity player) FOREACH(Weapons, it != WEP_Null, { if(w & (it.m_wepset)) { - W_DropEvent(wr_pickup, player, it.m_id, item); + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + if(player.(weaponentity).m_weapon != WEP_Null || slot == 0) + W_DropEvent(wr_pickup, player, it.m_id, item, weaponentity); + } W_GiveWeapon(player, it.m_id); } }); @@ -761,13 +775,25 @@ LABEL(skip) // crude hack to enforce switching weapons if(g_cts && item.itemdef.instanceOfWeaponPickup) { - W_SwitchWeapon_Force(player, Weapons_from(item.weapon)); + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + if(player.(weaponentity).m_weapon != WEP_Null || slot == 0) + W_SwitchWeapon_Force(player, Weapons_from(item.weapon), weaponentity); + } return 1; } - if (_switchweapon) - if (PS(player).m_switchweapon != w_getbestweapon(player)) - W_SwitchWeapon_Force(player, w_getbestweapon(player)); + if(_switchweapon) + { + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + if(_switchweapon & BIT(slot)) + if(player.(weaponentity).m_switchweapon != w_getbestweapon(player, weaponentity)) + W_SwitchWeapon_Force(player, w_getbestweapon(player, weaponentity), weaponentity); + } + } return 1; } @@ -1646,7 +1672,6 @@ void GiveRot(entity e, float v0, float v1, .float rotfield, float rottime, .floa float GiveItems(entity e, float beginarg, float endarg) { float got, i, val, op; - float _switchweapon; string cmd; val = 999; @@ -1654,10 +1679,18 @@ float GiveItems(entity e, float beginarg, float endarg) got = 0; - _switchweapon = false; - if (e.autoswitch) - if (PS(e).m_switchweapon == w_getbestweapon(e)) - _switchweapon = true; + int _switchweapon = 0; + + if(e.autoswitch) + { + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + if(e.(weaponentity).m_weapon != WEP_Null || slot == 0) + if(e.(weaponentity).m_switchweapon == w_getbestweapon(e, weaponentity)) + _switchweapon |= BIT(slot); + } + } e.strength_finished = max(0, e.strength_finished - time); e.invincible_finished = max(0, e.invincible_finished - time); @@ -1823,10 +1856,23 @@ float GiveItems(entity e, float beginarg, float endarg) else e.superweapons_finished += time; - if (!(e.weapons & WepSet_FromWeapon(PS(e).m_switchweapon))) - _switchweapon = true; + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + if(e.(weaponentity).m_weapon != WEP_Null || slot == 0) + if(!(e.weapons & WepSet_FromWeapon(e.(weaponentity).m_switchweapon))) + _switchweapon |= BIT(slot); + } + if(_switchweapon) - W_SwitchWeapon_Force(e, w_getbestweapon(e)); + { + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + if(_switchweapon & BIT(slot)) + W_SwitchWeapon_Force(e, w_getbestweapon(e, weaponentity), weaponentity); + } + } return got; } diff --git a/qcsrc/common/triggers/trigger/magicear.qc b/qcsrc/common/triggers/trigger/magicear.qc index 065d8c932a..354ed1bfed 100644 --- a/qcsrc/common/triggers/trigger/magicear.qc +++ b/qcsrc/common/triggers/trigger/magicear.qc @@ -1,7 +1,7 @@ #include "magicear.qh" #ifdef SVQC float magicear_matched; -float W_Tuba_HasPlayed(entity pl, string melody, float instrument, float ignorepitch, float mintempo, float maxtempo); +float W_Tuba_HasPlayed(entity pl, .entity weaponentity, string melody, float instrument, float ignorepitch, float mintempo, float maxtempo); string trigger_magicear_processmessage(entity ear, entity source, float teamsay, entity privatesay, string msgin) { float domatch, dotrigger, matchstart, l; @@ -22,8 +22,12 @@ string trigger_magicear_processmessage(entity ear, entity source, float teamsay, if (!(ear.spawnflags & 256)) return msgin; - if(!W_Tuba_HasPlayed(source, ear.message, ear.movedir_x, !(ear.spawnflags & 512), ear.movedir_y, ear.movedir_z)) - return msgin; + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + if(!W_Tuba_HasPlayed(source, weaponentity, ear.message, ear.movedir_x, !(ear.spawnflags & 512), ear.movedir_y, ear.movedir_z)) + return msgin; + } magicear_matched = true; diff --git a/qcsrc/common/triggers/trigger/teleport.qc b/qcsrc/common/triggers/trigger/teleport.qc index c3de654609..1fabc80a57 100644 --- a/qcsrc/common/triggers/trigger/teleport.qc +++ b/qcsrc/common/triggers/trigger/teleport.qc @@ -43,7 +43,7 @@ void Teleport_Touch(entity this, entity toucher) #ifdef SVQC if(IS_PLAYER(toucher)) - RemoveGrapplingHook(toucher); + RemoveGrapplingHooks(toucher); #endif entity e; diff --git a/qcsrc/common/turrets/turret/machinegun_weapon.qc b/qcsrc/common/turrets/turret/machinegun_weapon.qc index 44c8d64599..c60cd3b37e 100644 --- a/qcsrc/common/turrets/turret/machinegun_weapon.qc +++ b/qcsrc/common/turrets/turret/machinegun_weapon.qc @@ -19,7 +19,7 @@ METHOD(MachineGunTurretAttack, wr_think, void(entity thiswep, entity actor, .ent actor.tur_head = actor; weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, 0, w_ready); } - fireBullet (actor, actor.tur_shotorg, actor.tur_shotdir_updated, actor.shot_spread, 0, actor.shot_dmg, actor.shot_force, DEATH_TURRET_MACHINEGUN.m_id, 0); + fireBullet (actor, weaponentity, actor.tur_shotorg, actor.tur_shotdir_updated, actor.shot_spread, 0, actor.shot_dmg, actor.shot_force, DEATH_TURRET_MACHINEGUN.m_id, 0); W_MachineGun_MuzzleFlash(actor, weaponentity); setattachment(actor.(weaponentity).muzzle_flash, actor.tur_head, "tag_fire"); } diff --git a/qcsrc/common/turrets/turret/plasma.qc b/qcsrc/common/turrets/turret/plasma.qc index d161436ab0..ed7d4f1608 100644 --- a/qcsrc/common/turrets/turret/plasma.qc +++ b/qcsrc/common/turrets/turret/plasma.qc @@ -10,7 +10,8 @@ METHOD(PlasmaTurret, tr_attack, void(PlasmaTurret this, entity it)) { if(g_instagib) { - FireRailgunBullet (it, it.tur_shotorg, it.tur_shotorg + it.tur_shotdir_updated * MAX_SHOT_DISTANCE, 10000000000, + .entity weaponentity = weaponentities[0]; // TODO: unhardcode + FireRailgunBullet (it, weaponentity, it.tur_shotorg, it.tur_shotorg + it.tur_shotdir_updated * MAX_SHOT_DISTANCE, 10000000000, 800, 0, 0, 0, 0, DEATH_TURRET_PLASMA.m_id); Send_Effect(EFFECT_VORTEX_MUZZLEFLASH, it.tur_shotorg, it.tur_shotdir_updated * 1000, 1); diff --git a/qcsrc/common/turrets/turret/plasma_dual.qc b/qcsrc/common/turrets/turret/plasma_dual.qc index 9e6d80b2fd..b1e7d5850a 100644 --- a/qcsrc/common/turrets/turret/plasma_dual.qc +++ b/qcsrc/common/turrets/turret/plasma_dual.qc @@ -9,7 +9,8 @@ spawnfunc(turret_plasma_dual) { if (!turret_initialize(this, TUR_PLASMA_DUAL)) d METHOD(DualPlasmaTurret, tr_attack, void(DualPlasmaTurret thistur, entity it)) { if (g_instagib) { - FireRailgunBullet (it, it.tur_shotorg, it.tur_shotorg + it.tur_shotdir_updated * MAX_SHOT_DISTANCE, 10000000000, + .entity weaponentity = weaponentities[0]; // TODO: unhardcode + FireRailgunBullet (it, weaponentity, it.tur_shotorg, it.tur_shotorg + it.tur_shotdir_updated * MAX_SHOT_DISTANCE, 10000000000, 800, 0, 0, 0, 0, DEATH_TURRET_PLASMA.m_id); diff --git a/qcsrc/common/turrets/turret/walker_weapon.qc b/qcsrc/common/turrets/turret/walker_weapon.qc index 88b18b9198..9bcf902902 100644 --- a/qcsrc/common/turrets/turret/walker_weapon.qc +++ b/qcsrc/common/turrets/turret/walker_weapon.qc @@ -18,7 +18,7 @@ METHOD(WalkerTurretAttack, wr_think, void(entity thiswep, entity actor, .entity weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready); } sound (actor, CH_WEAPON_A, SND_UZI_FIRE, VOL_BASE, ATTEN_NORM); - fireBullet (actor, actor.tur_shotorg, actor.tur_shotdir_updated, actor.shot_spread, 0, actor.shot_dmg, actor.shot_force, DEATH_TURRET_WALK_GUN.m_id, 0); + fireBullet (actor, weaponentity, actor.tur_shotorg, actor.tur_shotdir_updated, actor.shot_spread, 0, actor.shot_dmg, actor.shot_force, DEATH_TURRET_WALK_GUN.m_id, 0); Send_Effect(EFFECT_BLASTER_MUZZLEFLASH, actor.tur_shotorg, actor.tur_shotdir_updated * 1000, 1); } } diff --git a/qcsrc/common/vehicles/sv_vehicles.qc b/qcsrc/common/vehicles/sv_vehicles.qc index b165bb3e48..491962b67a 100644 --- a/qcsrc/common/vehicles/sv_vehicles.qc +++ b/qcsrc/common/vehicles/sv_vehicles.qc @@ -806,7 +806,12 @@ void vehicles_exit(entity vehic, bool eject) player.view_ofs = STAT(PL_VIEW_OFS, NULL); player.event_damage = PlayerDamage; player.hud = HUD_NORMAL; - PS(player).m_switchweapon = vehic.m_switchweapon; + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++ slot) + { + .entity weaponentity = weaponentities[slot]; + player.(weaponentity).m_switchweapon = vehic.(weaponentity).m_switchweapon; + delete(vehic.(weaponentity)); // no longer needed + } player.last_vehiclecheck = time + 3; player.vehicle_enter_delay = time + 2; @@ -942,7 +947,7 @@ void vehicles_enter(entity pl, entity veh) } else return; - RemoveGrapplingHook(pl); + RemoveGrapplingHooks(pl); veh.vehicle_ammo1 = 0; veh.vehicle_ammo2 = 0; @@ -976,7 +981,12 @@ void vehicles_enter(entity pl, entity veh) veh.colormap = pl.colormap; if(veh.tur_head) veh.tur_head.colormap = pl.colormap; - veh.m_switchweapon = PS(pl).m_switchweapon; + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + veh.(weaponentity) = new(temp_wepent); + veh.(weaponentity).m_switchweapon = pl.(weaponentity).m_switchweapon; + } pl.hud = veh.vehicleid; pl.PlayerPhysplug = veh.PlayerPhysplug; @@ -1099,7 +1109,15 @@ void vehicles_spawn(entity this) if(this.vehicle_controller) this.team = this.vehicle_controller.team; - FOREACH_CLIENT(IS_PLAYER(it) && it.hook.aiment == this, RemoveGrapplingHook(it)); + FOREACH_CLIENT(IS_PLAYER(it), + { + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + if(it.(weaponentity).hook.aiment == this) + RemoveHook(it.(weaponentity).hook); + } + }); vehicles_reset_colors(this); diff --git a/qcsrc/common/vehicles/vehicle/bumblebee.qc b/qcsrc/common/vehicles/vehicle/bumblebee.qc index 3f5f404358..7bc10b4ecd 100644 --- a/qcsrc/common/vehicles/vehicle/bumblebee.qc +++ b/qcsrc/common/vehicles/vehicle/bumblebee.qc @@ -236,7 +236,12 @@ void bumblebee_gunner_exit(entity this, int _exitflag) player.event_damage = PlayerDamage; player.hud = HUD_NORMAL; player.teleportable = TELEPORT_NORMAL; - PS(player).m_switchweapon = gunner.m_switchweapon; + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + player.(weaponentity).m_switchweapon = gunner.(weaponentity).m_switchweapon; + delete(gunner.(weaponentity)); + } player.vehicle_enter_delay = time + 2; fixedmakevectors(vehic.angles); @@ -304,9 +309,15 @@ bool bumblebee_gunner_enter(entity this, entity player) player.vehicle_energy = vehic.vehicle_energy; UNSET_ONGROUND(player); - RemoveGrapplingHook(player); + RemoveGrapplingHooks(player); - gunner.m_switchweapon = PS(player).m_switchweapon; + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + + gunner.(weaponentity) = new(temp_wepent); + gunner.(weaponentity).m_switchweapon = player.(weaponentity).m_switchweapon; + } gunner.vehicle_exit = bumblebee_gunner_exit; gunner.vehicle_hudmodel.viewmodelforclient = player; diff --git a/qcsrc/common/vehicles/vehicle/racer.qc b/qcsrc/common/vehicles/vehicle/racer.qc index 0cdfc8cb87..c3f3d84050 100644 --- a/qcsrc/common/vehicles/vehicle/racer.qc +++ b/qcsrc/common/vehicles/vehicle/racer.qc @@ -289,9 +289,10 @@ bool racer_frame(entity this, float dt) #ifdef SVQC Weapon wep1 = WEP_RACER; + .entity weaponentity = weaponentities[0]; // TODO: unhardcode if (!forbidWeaponUse(this)) if (PHYS_INPUT_BUTTON_ATCK(this)) - if (wep1.wr_checkammo1(wep1, vehic)) + if (wep1.wr_checkammo1(wep1, vehic, weaponentity)) { string tagname = (vehic.cnt) ? (vehic.cnt = 0, "tag_fire1") @@ -302,7 +303,6 @@ bool racer_frame(entity this, float dt) // Fix z-aim (for chase mode) crosshair_trace(this); w_shotdir.z = normalize(trace_endpos - org).z * 0.5; - .entity weaponentity = weaponentities[0]; wep1.wr_think(wep1, vehic, weaponentity, 1); } diff --git a/qcsrc/common/vehicles/vehicle/racer_weapon.qc b/qcsrc/common/vehicles/vehicle/racer_weapon.qc index d20210c611..838f0cf427 100644 --- a/qcsrc/common/vehicles/vehicle/racer_weapon.qc +++ b/qcsrc/common/vehicles/vehicle/racer_weapon.qc @@ -34,7 +34,7 @@ METHOD(RacerAttack, wr_think, void(entity thiswep, entity actor, .entity weapone } } -METHOD(RacerAttack, wr_checkammo1, bool(RacerAttack thiswep, entity actor)) +METHOD(RacerAttack, wr_checkammo1, bool(RacerAttack thiswep, entity actor, .entity weaponentity)) { bool isPlayer = IS_PLAYER(actor); entity player = isPlayer ? actor : actor.owner; diff --git a/qcsrc/common/vehicles/vehicle/raptor.qc b/qcsrc/common/vehicles/vehicle/raptor.qc index 1068e7430d..8ede8f2c5d 100644 --- a/qcsrc/common/vehicles/vehicle/raptor.qc +++ b/qcsrc/common/vehicles/vehicle/raptor.qc @@ -356,11 +356,11 @@ bool raptor_frame(entity this, float dt) */ Weapon wep1 = WEP_RAPTOR; + .entity weaponentity = weaponentities[0]; if(!forbidWeaponUse(this)) if(PHYS_INPUT_BUTTON_ATCK(this)) - if (wep1.wr_checkammo1(wep1, vehic)) + if (wep1.wr_checkammo1(wep1, vehic, weaponentity)) { - .entity weaponentity = weaponentities[0]; wep1.wr_think(wep1, vehic, weaponentity, 1); } diff --git a/qcsrc/common/vehicles/vehicle/raptor_weapons.qc b/qcsrc/common/vehicles/vehicle/raptor_weapons.qc index 4e16efbcc9..5cb0f271c5 100644 --- a/qcsrc/common/vehicles/vehicle/raptor_weapons.qc +++ b/qcsrc/common/vehicles/vehicle/raptor_weapons.qc @@ -30,7 +30,7 @@ METHOD(RaptorCannon, wr_think, void(entity thiswep, entity actor, .entity weapon weapon_thinkf(player, weaponentity, WFRAME_FIRE1, 0, w_ready); } } -METHOD(RaptorCannon, wr_checkammo1, bool(RacerAttack thiswep, entity actor)) { +METHOD(RaptorCannon, wr_checkammo1, bool(RacerAttack thiswep, entity actor, .entity weaponentity)) { bool isPlayer = IS_PLAYER(actor); entity player = isPlayer ? actor : actor.owner; entity veh = player.vehicle; diff --git a/qcsrc/common/vehicles/vehicle/spiderbot.qc b/qcsrc/common/vehicles/vehicle/spiderbot.qc index d99335a51c..d05d9f45f6 100644 --- a/qcsrc/common/vehicles/vehicle/spiderbot.qc +++ b/qcsrc/common/vehicles/vehicle/spiderbot.qc @@ -60,7 +60,11 @@ bool spiderbot_frame(entity this, float dt) PHYS_INPUT_BUTTON_ZOOM(this) = false; PHYS_INPUT_BUTTON_CROUCH(this) = false; - PS(this).m_switchweapon = WEP_Null; + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + this.(weaponentity).m_switchweapon = WEP_Null; + } this.vehicle_weapon2mode = vehic.vehicle_weapon2mode; @@ -260,7 +264,8 @@ bool spiderbot_frame(entity this, float dt) v_forward = normalize(v_forward); v += v_forward * 50; - fireBullet(this, v, v_forward, autocvar_g_vehicle_spiderbot_minigun_spread, autocvar_g_vehicle_spiderbot_minigun_solidpenetration, + .entity weaponentity = weaponentities[0]; // TODO: unhardcode + fireBullet(this, weaponentity, v, v_forward, autocvar_g_vehicle_spiderbot_minigun_spread, autocvar_g_vehicle_spiderbot_minigun_solidpenetration, autocvar_g_vehicle_spiderbot_minigun_damage, autocvar_g_vehicle_spiderbot_minigun_force, DEATH_VH_SPID_MINIGUN.m_id, 0); sound (gun, CH_WEAPON_A, SND_UZI_FIRE, VOL_BASE, ATTEN_NORM); diff --git a/qcsrc/common/weapons/all.qc b/qcsrc/common/weapons/all.qc index 763dd6e8de..c236bb47c4 100644 --- a/qcsrc/common/weapons/all.qc +++ b/qcsrc/common/weapons/all.qc @@ -391,7 +391,9 @@ void CL_WeaponEntity_SetModel(entity this, string name, bool _anim) { if (name == "") { - this.model = ""; + vector oldmin = this.mins, oldmax = this.maxs; + setmodel(this, MDL_Null); + setsize(this, oldmin, oldmax); if (this.weaponchild) delete(this.weaponchild); this.weaponchild = NULL; this.movedir = '0 0 0'; @@ -523,7 +525,11 @@ void CL_WeaponEntity_SetModel(entity this, string name, bool _anim) if (this.movedir.x >= 0) { - int algn = STAT(GUNALIGN, this.owner); + //int algn = STAT(GUNALIGN, this.owner); + int algn = W_GunAlign(this, STAT(GUNALIGN, this.owner)); + #ifdef SVQC + this.m_gunalign = algn; + #endif vector v = this.movedir; this.movedir = shotorg_adjust(v, false, false, algn); this.view_ofs = shotorg_adjust(v, false, true, algn) - v; @@ -557,21 +563,22 @@ NET_HANDLE(wframe, bool isNew) a.x = ReadCoord(); a.y = ReadCoord(); a.z = ReadCoord(); + int slot = ReadByte(); bool restartanim = ReadByte(); - anim_set(viewmodel, a, !restartanim, restartanim, restartanim); - viewmodel.state = ReadByte(); - viewmodel.weapon_nextthink = ReadFloat(); - viewmodel.alpha = ReadByte() / 255; - switch (viewmodel.state) + entity wepent = viewmodels[slot]; + anim_set(wepent, a, !restartanim, restartanim, restartanim); + wepent.state = ReadByte(); + wepent.weapon_nextthink = ReadFloat(); + switch (wepent.state) { case WS_RAISE: - viewmodel.weapon_switchdelay = activeweapon.switchdelay_raise; + wepent.weapon_switchdelay = wepent.activeweapon.switchdelay_raise; break; case WS_DROP: - viewmodel.weapon_switchdelay = activeweapon.switchdelay_drop; + wepent.weapon_switchdelay = wepent.activeweapon.switchdelay_drop; break; default: - viewmodel.weapon_switchdelay = 0; + wepent.weapon_switchdelay = 0; break; } return true; @@ -588,10 +595,10 @@ void wframe_send(entity actor, entity weaponentity, vector a, bool restartanim) WriteCoord(channel, a.x); WriteCoord(channel, a.y); WriteCoord(channel, a.z); + WriteByte(channel, weaponslot(weaponentity.weaponentity_fld)); WriteByte(channel, restartanim); WriteByte(channel, weaponentity.state); WriteFloat(channel, weaponentity.weapon_nextthink); - WriteByte(channel, weaponentity.m_alpha * 255); } #endif diff --git a/qcsrc/common/weapons/all.qh b/qcsrc/common/weapons/all.qh index a805ce5fd4..22d0e294eb 100644 --- a/qcsrc/common/weapons/all.qh +++ b/qcsrc/common/weapons/all.qh @@ -328,13 +328,15 @@ STATIC_INIT(register_weapons_done) .entity weaponchild; .entity exteriorweaponentity; -vector weaponentity_glowmod(Weapon wep, entity actor, int c) +vector weaponentity_glowmod(Weapon wep, entity actor, int c, entity wepent) { vector g; - if (!(g = wep.wr_glow(wep, actor))) g = colormapPaletteColor(c & 0x0F, true) * 2; + if (!(g = wep.wr_glow(wep, actor, wepent))) g = colormapPaletteColor(c & 0x0F, true) * 2; return g; } +.int m_gunalign; + //.int weapon; // current weapon .string weaponname; // name of .weapon diff --git a/qcsrc/common/weapons/calculations.qc b/qcsrc/common/weapons/calculations.qc index c35b1930c4..367bab6afb 100644 --- a/qcsrc/common/weapons/calculations.qc +++ b/qcsrc/common/weapons/calculations.qc @@ -144,6 +144,45 @@ vector findperpendicular(vector v) return normalize(cliptoplane(p, v)); } +#ifdef SVQC + int W_GunAlign(entity this, int preferred_align) + { + if(this.m_gunalign) + return this.m_gunalign; // no adjustment needed + + entity own = this.owner; + + if(preferred_align < 1 || preferred_align > 4) + preferred_align = 3; // default + + for(int j = 4; j > 1; --j) // > 1 as 1 is just center again + { + int taken = 0; + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + if(own.(weaponentity).m_gunalign == j) // we know it can't be ours thanks to the above check + taken |= BIT(j); + if(own.(weaponentity).m_gunalign == preferred_align) + taken |= BIT(preferred_align); + } + + if(!(taken & BIT(preferred_align))) + return preferred_align; // prefer the recommended + if(!(taken & BIT(j))) + return j; // or fall back if it's not available + } + + return preferred_align; // return it anyway + } +#else + int W_GunAlign(entity this, int preferred_align) + { + return this.m_gunalign > 0 ? this.m_gunalign : preferred_align; + } +#endif + +#if 0 int W_GetGunAlignment(entity player) { int gunalign = STAT(GUNALIGN, player); @@ -153,6 +192,7 @@ int W_GetGunAlignment(entity player) return gunalign; } +#endif vector W_CalculateSpread(vector forward, float spread, float spreadfactor, float spreadstyle) { diff --git a/qcsrc/common/weapons/calculations.qh b/qcsrc/common/weapons/calculations.qh index c349eeca4f..d749cc15ee 100644 --- a/qcsrc/common/weapons/calculations.qh +++ b/qcsrc/common/weapons/calculations.qh @@ -2,5 +2,6 @@ vector damage_explosion_calcpush(vector explosion_f, vector target_v, float speedfactor); vector W_CalculateSpread(vector forward, float spread, float spreadfactor, float spreadstyle); -int W_GetGunAlignment(entity player); +int W_GunAlign(entity this, int preferred_align); +//int W_GetGunAlignment(entity player); float explosion_calcpush_getmultiplier(vector explosion_v, vector target_v); diff --git a/qcsrc/common/weapons/weapon.qh b/qcsrc/common/weapons/weapon.qh index b287b148f3..c873f44633 100644 --- a/qcsrc/common/weapons/weapon.qh +++ b/qcsrc/common/weapons/weapon.qh @@ -75,6 +75,8 @@ CLASS(Weapon, Object) ATTRIB(Weapon, w_crosshair, string, "gfx/crosshair1"); /** A: crosshair : per-weapon crosshair size (argument two of "crosshair" field) */ ATTRIB(Weapon, w_crosshair_size, float, 1); + /** A: reticle : per-weapon zoom reticle */ + ATTRIB(Weapon, w_reticle, string, ""); /** M: wepimg : "weaponfoobar" side view image file of weapon. WEAPONTODO: Move out of skin files, move to common files */ ATTRIB(Weapon, model2, string, ""); /** M: refname : reference name name */ @@ -85,15 +87,15 @@ CLASS(Weapon, Object) ATTRIB(Weapon, m_pickup, entity); /** (SERVER) setup weapon data */ - METHOD(Weapon, wr_setup, void(Weapon this, entity actor)) {} + METHOD(Weapon, wr_setup, void(Weapon this, entity actor, .entity weaponentity)) {} /** (SERVER) logic to run every frame */ METHOD(Weapon, wr_think, void(Weapon this, entity actor, .entity weaponentity, int fire)) {} /** (SERVER) checks ammo for weapon primary */ - METHOD(Weapon, wr_checkammo1, bool(Weapon this, entity actor)) {return false;} + METHOD(Weapon, wr_checkammo1, bool(Weapon this, entity actor, .entity weaponentity)) {return false;} /** (SERVER) checks ammo for weapon second */ - METHOD(Weapon, wr_checkammo2, bool(Weapon this, entity actor)) {return false;} + METHOD(Weapon, wr_checkammo2, bool(Weapon this, entity actor, .entity weaponentity)) {return false;} /** (SERVER) runs bot aiming code for this weapon */ - METHOD(Weapon, wr_aim, void(Weapon this, entity actor)) {} + METHOD(Weapon, wr_aim, void(Weapon this, entity actor, .entity weaponentity)) {} /** (BOTH) precaches models/sounds used by this weapon, also sets up weapon properties */ METHOD(Weapon, wr_init, void(Weapon this)) {} /** (SERVER) notification number for suicide message (may inspect w_deathtype for details) */ @@ -112,19 +114,19 @@ CLASS(Weapon, Object) METHOD(Weapon, wr_gonethink, void(Weapon this, entity actor, .entity weaponentity)) {} /** (ALL) dump weapon cvars to config in data directory (see: sv_cmd dumpweapons) */ METHOD(Weapon, wr_config, void(Weapon this)) {} - /** (CLIENT) weapon specific zoom reticle */ - METHOD(Weapon, wr_zoomreticle, bool(Weapon this)) { + /** (BOTH) weapon specific zoom reticle */ + METHOD(Weapon, wr_zoom, bool(Weapon this, entity actor)) { // no weapon specific image for this weapon return false; } /** (CLIENT) weapon specific view model */ METHOD(Weapon, wr_viewmodel, string(Weapon this, entity wep)) { return string_null; } /** (CLIENT) weapon specific glow */ - METHOD(Weapon, wr_glow, vector(Weapon this, entity actor)) { return '0 0 0'; } + METHOD(Weapon, wr_glow, vector(Weapon this, entity actor, entity wepent)) { return '0 0 0'; } /** (SERVER) the weapon is dropped */ - METHOD(Weapon, wr_drop, void(Weapon this, entity actor)) {} + METHOD(Weapon, wr_drop, void(Weapon this, entity actor, .entity weaponentity)) {} /** (SERVER) a weapon is picked up */ - METHOD(Weapon, wr_pickup, void(Weapon this, entity actor)) {} + METHOD(Weapon, wr_pickup, void(Weapon this, entity actor, .entity weaponentity)) {} /** (SERVER) update cvar based properties */ METHOD(Weapon, wr_update, void(Weapon this)) {} METHOD(Weapon, display, void(entity this, void(string name, string icon) returns)) { diff --git a/qcsrc/common/weapons/weapon/arc.qc b/qcsrc/common/weapons/weapon/arc.qc index 4c9415305a..88ba1c768c 100644 --- a/qcsrc/common/weapons/weapon/arc.qc +++ b/qcsrc/common/weapons/weapon/arc.qc @@ -102,7 +102,7 @@ const int ARC_SF_LOCALMASK = ARC_SF_START | ARC_SF_WANTDIR | ARC_SF_BEAMDIR; #endif #ifdef SVQC .entity arc_beam; -.bool arc_BUTTON_ATCK_prev[MAX_WEAPONSLOTS]; // for better animation control +.bool arc_BUTTON_ATCK_prev; // for better animation control .float beam_prev; .float beam_initialized; .float beam_bursting; @@ -159,6 +159,7 @@ bool W_Arc_Beam_Send(entity this, entity to, int sf) if(drawlocal) { sf &= ~ARC_SF_LOCALMASK; } WriteByte(MSG_ENTITY, sf); + WriteByte(MSG_ENTITY, weaponslot(this.weaponentity_fld)); if(sf & ARC_SF_SETTINGS) // settings information { @@ -273,7 +274,7 @@ void W_Arc_Attack_Bolt(Weapon thiswep, entity actor, .entity weaponentity) { entity missile; - W_DecreaseAmmo(thiswep, actor, WEP_CVAR(arc, bolt_ammo)); + W_DecreaseAmmo(thiswep, actor, WEP_CVAR(arc, bolt_ammo), weaponentity); W_SetupShot(actor, weaponentity, false, 2, SND_LASERGUN_FIRE, CH_WEAPON_A, WEP_CVAR(arc, bolt_damage)); @@ -341,7 +342,7 @@ void W_Arc_Beam_Think(entity this) || forbidWeaponUse(this.owner) || - PS(this.owner).m_switchweapon != WEP_ARC + this.owner.(weaponentity).m_switchweapon != WEP_ARC || (!PHYS_INPUT_BUTTON_ATCK(this.owner) && !burst ) || @@ -380,11 +381,11 @@ void W_Arc_Beam_Think(entity this) if(this == this.owner.(weaponentity).arc_beam) { this.owner.(weaponentity).arc_beam = NULL; } entity own = this.owner; Weapon w = WEP_ARC; - if(!w.wr_checkammo1(w, own) && !w.wr_checkammo2(w, own)) + if(!w.wr_checkammo1(w, own, weaponentity) && !w.wr_checkammo2(w, own, weaponentity)) if(!(own.items & IT_UNLIMITED_WEAPON_AMMO)) { // note: this doesn't force the switch - W_SwitchToOtherWeapon(own); + W_SwitchToOtherWeapon(own, weaponentity); } delete(this); return; @@ -677,7 +678,7 @@ void W_Arc_Beam_Think(entity this) this.beam_type = new_beam_type; } - this.owner.beam_prev = time; + this.owner.(weaponentity).beam_prev = time; this.nextthink = time; } @@ -685,7 +686,7 @@ void W_Arc_Beam(float burst, entity actor, .entity weaponentity) { // only play fire sound if 1 sec has passed since player let go the fire button - if(time - actor.beam_prev > 1) + if(time - actor.(weaponentity).beam_prev > 1) sound(actor, CH_WEAPON_A, SND_ARC_FIRE, VOL_BASE, ATTN_NORM); entity beam = actor.(weaponentity).arc_beam = new(W_Arc_Beam); @@ -731,19 +732,20 @@ void Arc_Smoke(entity actor, .entity weaponentity) } if ( actor.arc_smoke_sound && ( actor.arc_overheat <= time || - !( PHYS_INPUT_BUTTON_ATCK(actor) || PHYS_INPUT_BUTTON_ATCK2(actor) ) ) || PS(actor).m_switchweapon != WEP_ARC ) + !( PHYS_INPUT_BUTTON_ATCK(actor) || PHYS_INPUT_BUTTON_ATCK2(actor) ) ) || actor.(weaponentity).m_switchweapon != WEP_ARC ) { actor.arc_smoke_sound = 0; sound(actor, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, ATTEN_NORM); } } -METHOD(Arc, wr_aim, void(entity thiswep, entity actor)) +METHOD(Arc, wr_aim, void(entity thiswep, entity actor, .entity weaponentity)) { if(WEP_CVAR(arc, beam_botaimspeed)) { PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim( actor, + weaponentity, WEP_CVAR(arc, beam_botaimspeed), 0, WEP_CVAR(arc, beam_botaimlifetime), @@ -754,6 +756,7 @@ METHOD(Arc, wr_aim, void(entity thiswep, entity actor)) { PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim( actor, + weaponentity, 1000000, 0, 0.001, @@ -767,13 +770,12 @@ METHOD(Arc, wr_think, void(entity thiswep, entity actor, .entity weaponentity, i Arc_Smoke(actor, weaponentity); bool beam_fire2 = ((fire & 2) && !WEP_CVAR(arc, bolt)); - int slot = weaponslot(weaponentity); if (time >= actor.arc_overheat) if ((fire & 1) || beam_fire2 || actor.(weaponentity).arc_beam.beam_bursting) { - if(actor.arc_BUTTON_ATCK_prev[slot]) + if(actor.(weaponentity).arc_BUTTON_ATCK_prev) { #if 0 if(actor.animstate_startframe == actor.anim_shoot.x && actor.animstate_numframes == actor.anim_shoot.y) @@ -789,10 +791,10 @@ METHOD(Arc, wr_think, void(entity thiswep, entity actor, .entity weaponentity, i { W_Arc_Beam(boolean(beam_fire2), actor, weaponentity); - if(!actor.arc_BUTTON_ATCK_prev[slot]) + if(!actor.(weaponentity).arc_BUTTON_ATCK_prev) { weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(arc, beam_animtime), w_ready); - actor.arc_BUTTON_ATCK_prev[slot] = true; + actor.(weaponentity).arc_BUTTON_ATCK_prev = true; } } } @@ -808,13 +810,14 @@ METHOD(Arc, wr_think, void(entity thiswep, entity actor, .entity weaponentity, i } } - if(actor.arc_BUTTON_ATCK_prev[slot]) + if(actor.(weaponentity).arc_BUTTON_ATCK_prev) { + int slot = weaponslot(weaponentity); sound(actor, CH_WEAPON_A, SND_ARC_STOP, VOL_BASE, ATTN_NORM); weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(arc, beam_animtime), w_ready); ATTACK_FINISHED(actor, slot) = time + WEP_CVAR(arc, beam_refire) * W_WeaponRateFactor(actor); } - actor.arc_BUTTON_ATCK_prev[slot] = false; + actor.(weaponentity).arc_BUTTON_ATCK_prev = false; #if 0 if(fire & 2) @@ -837,16 +840,16 @@ METHOD(Arc, wr_init, void(entity thiswep)) arc_shotorigin[3] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_ARC.m_id), false, false, 4); } } -METHOD(Arc, wr_checkammo1, bool(entity thiswep, entity actor)) +METHOD(Arc, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity)) { return ((!WEP_CVAR(arc, beam_ammo)) || (actor.(thiswep.ammo_field) > 0)); } -METHOD(Arc, wr_checkammo2, bool(entity thiswep, entity actor)) +METHOD(Arc, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity)) { if(WEP_CVAR(arc, bolt)) { float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR(arc, bolt_ammo); - ammo_amount += actor.(weapon_load[WEP_ARC.m_id]) >= WEP_CVAR(arc, bolt_ammo); + ammo_amount += actor.(weaponentity).(weapon_load[WEP_ARC.m_id]) >= WEP_CVAR(arc, bolt_ammo); return ammo_amount; } else @@ -860,18 +863,17 @@ METHOD(Arc, wr_killmessage, Notification(entity thiswep)) else return WEAPON_ARC_MURDER; } -METHOD(Arc, wr_drop, void(entity thiswep, entity actor)) +METHOD(Arc, wr_drop, void(entity thiswep, entity actor, .entity weaponentity)) { weapon_dropevent_item.arc_overheat = actor.arc_overheat; weapon_dropevent_item.arc_cooldown = actor.arc_cooldown; actor.arc_overheat = 0; actor.arc_cooldown = 0; - for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) - actor.arc_BUTTON_ATCK_prev[slot] = false; + actor.(weaponentity).arc_BUTTON_ATCK_prev = false; } -METHOD(Arc, wr_pickup, void(entity thiswep, entity actor)) +METHOD(Arc, wr_pickup, void(entity thiswep, entity actor, .entity weaponentity)) { - if ( !client_hasweapon(actor, thiswep, false, false) && + if ( !client_hasweapon(actor, thiswep, weaponentity, false, false) && weapon_dropevent_item.arc_overheat > time ) { actor.arc_overheat = weapon_dropevent_item.arc_overheat; @@ -883,14 +885,16 @@ METHOD(Arc, wr_resetplayer, void(entity thiswep, entity actor)) actor.arc_overheat = 0; actor.arc_cooldown = 0; for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) - actor.arc_BUTTON_ATCK_prev[slot] = false; + { + .entity weaponentity = weaponentities[slot]; + actor.(weaponentity).arc_BUTTON_ATCK_prev = false; + } } METHOD(Arc, wr_playerdeath, void(entity thiswep, entity actor, .entity weaponentity)) { actor.arc_overheat = 0; actor.arc_cooldown = 0; - int slot = weaponslot(weaponentity); - actor.arc_BUTTON_ATCK_prev[slot] = false; + actor.(weaponentity).arc_BUTTON_ATCK_prev = false; } #endif #ifdef CSQC @@ -1300,11 +1304,12 @@ void Remove_ArcBeam(entity this) NET_HANDLE(ENT_CLIENT_ARC_BEAM, bool isnew) { int sf = ReadByte(); + int slot = ReadByte(); entity flash; if(isnew) { - int gunalign = W_GetGunAlignment(NULL); + int gunalign = W_GunAlign(viewmodels[slot], STAT(GUNALIGN)) - 1; this.beam_shotorigin = arc_shotorigin[gunalign]; diff --git a/qcsrc/common/weapons/weapon/blaster.qc b/qcsrc/common/weapons/weapon/blaster.qc index 2eb8f00b41..cc2fedccfe 100644 --- a/qcsrc/common/weapons/weapon/blaster.qc +++ b/qcsrc/common/weapons/weapon/blaster.qc @@ -154,17 +154,17 @@ void W_Blaster_Attack( } } -METHOD(Blaster, wr_aim, void(entity thiswep, entity actor)) +METHOD(Blaster, wr_aim, void(entity thiswep, entity actor, .entity weaponentity)) { if(WEP_CVAR(blaster, secondary)) { if((random() * (WEP_CVAR_PRI(blaster, damage) + WEP_CVAR_SEC(blaster, damage))) > WEP_CVAR_PRI(blaster, damage)) - { PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, WEP_CVAR_SEC(blaster, speed), 0, WEP_CVAR_SEC(blaster, lifetime), false); } + { PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, WEP_CVAR_SEC(blaster, speed), 0, WEP_CVAR_SEC(blaster, lifetime), false); } else - { PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, WEP_CVAR_PRI(blaster, speed), 0, WEP_CVAR_PRI(blaster, lifetime), false); } + { PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR_PRI(blaster, speed), 0, WEP_CVAR_PRI(blaster, lifetime), false); } } else - { PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, WEP_CVAR_PRI(blaster, speed), 0, WEP_CVAR_PRI(blaster, lifetime), false); } + { PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR_PRI(blaster, speed), 0, WEP_CVAR_PRI(blaster, lifetime), false); } } METHOD(Blaster, wr_think, void(Blaster thiswep, entity actor, .entity weaponentity, int fire)) @@ -196,8 +196,8 @@ METHOD(Blaster, wr_think, void(Blaster thiswep, entity actor, .entity weaponenti { case 0: // switch to last used weapon { - if(PS(actor).m_switchweapon == WEP_BLASTER) // don't do this if already switching - W_LastWeapon(actor); + if(actor.(weaponentity).m_switchweapon == WEP_BLASTER) // don't do this if already switching + W_LastWeapon(actor, weaponentity); break; } @@ -228,17 +228,12 @@ METHOD(Blaster, wr_think, void(Blaster thiswep, entity actor, .entity weaponenti } } -METHOD(Blaster, wr_setup, void(entity thiswep, entity actor)) -{ - actor.ammo_field = ammo_none; -} - -METHOD(Blaster, wr_checkammo1, bool(entity thiswep, entity actor)) +METHOD(Blaster, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity)) { return true; // infinite ammo } -METHOD(Blaster, wr_checkammo2, bool(entity thiswep, entity actor)) +METHOD(Blaster, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity)) { return true; // blaster has infinite ammo } diff --git a/qcsrc/common/weapons/weapon/crylink.qc b/qcsrc/common/weapons/weapon/crylink.qc index 58214bf390..e4d66ebe60 100644 --- a/qcsrc/common/weapons/weapon/crylink.qc +++ b/qcsrc/common/weapons/weapon/crylink.qc @@ -98,8 +98,9 @@ void W_Crylink_CheckLinks(entity e) void W_Crylink_Dequeue_Raw(entity own, entity prev, entity me, entity next) { W_Crylink_CheckLinks(next); - if(me == own.crylink_lastgroup) - own.crylink_lastgroup = ((me == next) ? NULL : next); + .entity weaponentity = me.weaponentity_fld; + if(me == own.(weaponentity).crylink_lastgroup) + own.(weaponentity).crylink_lastgroup = ((me == next) ? NULL : next); prev.queuenext = next; next.queueprev = prev; me.classname = "spike_oktoremove"; @@ -128,8 +129,9 @@ void W_Crylink_LinkExplode(entity e, entity e2, entity directhitentity) a = bound(0, 1 - (time - e.fade_time) * e.fade_rate, 1); - if(e == e.realowner.crylink_lastgroup) - e.realowner.crylink_lastgroup = NULL; + .entity weaponentity = e.weaponentity_fld; + if(e == e.realowner.(weaponentity).crylink_lastgroup) + e.realowner.(weaponentity).crylink_lastgroup = NULL; float isprimary = !(e.projectiledeathtype & HITTYPE_SECONDARY); @@ -235,7 +237,8 @@ void W_Crylink_LinkJoinEffect_Think(entity this) // is there at least 2 projectiles very close? entity e, p; float n; - e = this.owner.crylink_lastgroup; + .entity weaponentity = this.weaponentity_fld; + e = this.owner.(weaponentity).crylink_lastgroup; n = 0; if(e) { @@ -317,8 +320,9 @@ void W_Crylink_Touch(entity this, entity toucher) if(totaldamage && ((WEP_CVAR_BOTH(crylink, isprimary, linkexplode) == 2) || ((WEP_CVAR_BOTH(crylink, isprimary, linkexplode) == 1) && !W_Crylink_Touch_WouldHitFriendly(this, WEP_CVAR_BOTH(crylink, isprimary, radius))))) { - if(this == this.realowner.crylink_lastgroup) - this.realowner.crylink_lastgroup = NULL; + .entity weaponentity = this.weaponentity_fld; + if(this == this.realowner.(weaponentity).crylink_lastgroup) + this.realowner.(weaponentity).crylink_lastgroup = NULL; W_Crylink_LinkExplode(this.queuenext, this, toucher); this.classname = "spike_oktoremove"; delete(this); @@ -354,7 +358,7 @@ void W_Crylink_Attack(Weapon thiswep, entity actor, .entity weaponentity) vector forward, right, up; float maxdmg; - W_DecreaseAmmo(thiswep, actor, WEP_CVAR_PRI(crylink, ammo)); + W_DecreaseAmmo(thiswep, actor, WEP_CVAR_PRI(crylink, ammo), weaponentity); maxdmg = WEP_CVAR_PRI(crylink, damage) * WEP_CVAR_PRI(crylink, shots); maxdmg *= 1 + WEP_CVAR_PRI(crylink, bouncedamagefactor) * WEP_CVAR_PRI(crylink, bounces); @@ -374,6 +378,7 @@ void W_Crylink_Attack(Weapon thiswep, entity actor, .entity weaponentity) proj = new(spike); proj.reset = W_Crylink_Reset; proj.realowner = proj.owner = actor; + proj.weaponentity_fld = weaponentity; proj.bot_dodge = true; proj.bot_dodgerating = WEP_CVAR_PRI(crylink, damage); if(shots == 1) { @@ -450,9 +455,9 @@ void W_Crylink_Attack(Weapon thiswep, entity actor, .entity weaponentity) } if(WEP_CVAR_PRI(crylink, joinspread) != 0) { - actor.crylink_lastgroup = proj; + actor.(weaponentity).crylink_lastgroup = proj; W_Crylink_CheckLinks(proj); - actor.crylink_waitrelease = 1; + actor.(weaponentity).crylink_waitrelease = 1; } } @@ -464,7 +469,7 @@ void W_Crylink_Attack2(Weapon thiswep, entity actor, .entity weaponentity) vector forward, right, up; float maxdmg; - W_DecreaseAmmo(thiswep, actor, WEP_CVAR_SEC(crylink, ammo)); + W_DecreaseAmmo(thiswep, actor, WEP_CVAR_SEC(crylink, ammo), weaponentity); maxdmg = WEP_CVAR_SEC(crylink, damage) * WEP_CVAR_SEC(crylink, shots); maxdmg *= 1 + WEP_CVAR_SEC(crylink, bouncedamagefactor) * WEP_CVAR_SEC(crylink, bounces); @@ -482,6 +487,7 @@ void W_Crylink_Attack2(Weapon thiswep, entity actor, .entity weaponentity) for(counter = 0; counter < shots; ++counter) { proj = new(spike); + proj.weaponentity_fld = weaponentity; proj.reset = W_Crylink_Reset; proj.realowner = proj.owner = actor; proj.bot_dodge = true; @@ -567,28 +573,28 @@ void W_Crylink_Attack2(Weapon thiswep, entity actor, .entity weaponentity) } if(WEP_CVAR_SEC(crylink, joinspread) != 0) { - actor.crylink_lastgroup = proj; + actor.(weaponentity).crylink_lastgroup = proj; W_Crylink_CheckLinks(proj); - actor.crylink_waitrelease = 2; + actor.(weaponentity).crylink_waitrelease = 2; } } -METHOD(Crylink, wr_aim, void(entity thiswep, entity actor)) +METHOD(Crylink, wr_aim, void(entity thiswep, entity actor, .entity weaponentity)) { if(random() < 0.10) - PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, WEP_CVAR_PRI(crylink, speed), 0, WEP_CVAR_PRI(crylink, middle_lifetime), false); + PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR_PRI(crylink, speed), 0, WEP_CVAR_PRI(crylink, middle_lifetime), false); else - PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, WEP_CVAR_SEC(crylink, speed), 0, WEP_CVAR_SEC(crylink, middle_lifetime), false); + PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, WEP_CVAR_SEC(crylink, speed), 0, WEP_CVAR_SEC(crylink, middle_lifetime), false); } METHOD(Crylink, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) { - if(autocvar_g_balance_crylink_reload_ammo && actor.clip_load < min(WEP_CVAR_PRI(crylink, ammo), WEP_CVAR_SEC(crylink, ammo))) { // forced reload + if(autocvar_g_balance_crylink_reload_ammo && actor.(weaponentity).clip_load < min(WEP_CVAR_PRI(crylink, ammo), WEP_CVAR_SEC(crylink, ammo))) { // forced reload thiswep.wr_reload(thiswep, actor, weaponentity); } if(fire & 1) { - if(actor.crylink_waitrelease != 1) + if(actor.(weaponentity).crylink_waitrelease != 1) if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(crylink, refire))) { W_Crylink_Attack(thiswep, actor, weaponentity); @@ -598,7 +604,7 @@ METHOD(Crylink, wr_think, void(entity thiswep, entity actor, .entity weaponentit if((fire & 2) && autocvar_g_balance_crylink_secondary) { - if(actor.crylink_waitrelease != 2) + if(actor.(weaponentity).crylink_waitrelease != 2) if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(crylink, refire))) { W_Crylink_Attack2(thiswep, actor, weaponentity); @@ -606,54 +612,55 @@ METHOD(Crylink, wr_think, void(entity thiswep, entity actor, .entity weaponentit } } - if((actor.crylink_waitrelease == 1 && !(fire & 1)) || (actor.crylink_waitrelease == 2 && !(fire & 2))) + if((actor.(weaponentity).crylink_waitrelease == 1 && !(fire & 1)) || (actor.(weaponentity).crylink_waitrelease == 2 && !(fire & 2))) { - if(!actor.crylink_lastgroup || time > actor.crylink_lastgroup.teleport_time) + if(!actor.(weaponentity).crylink_lastgroup || time > actor.(weaponentity).crylink_lastgroup.teleport_time) { // fired and released now! - if(actor.crylink_lastgroup) + if(actor.(weaponentity).crylink_lastgroup) { vector pos; entity linkjoineffect; - float isprimary = (actor.crylink_waitrelease == 1); + float isprimary = (actor.(weaponentity).crylink_waitrelease == 1); - pos = W_Crylink_LinkJoin(actor.crylink_lastgroup, WEP_CVAR_BOTH(crylink, isprimary, joinspread) * WEP_CVAR_BOTH(crylink, isprimary, speed)); + pos = W_Crylink_LinkJoin(actor.(weaponentity).crylink_lastgroup, WEP_CVAR_BOTH(crylink, isprimary, joinspread) * WEP_CVAR_BOTH(crylink, isprimary, speed)); linkjoineffect = new(linkjoineffect); + linkjoineffect.weaponentity_fld = weaponentity; setthink(linkjoineffect, W_Crylink_LinkJoinEffect_Think); linkjoineffect.nextthink = time + w_crylink_linkjoin_time; linkjoineffect.owner = actor; setorigin(linkjoineffect, pos); } - actor.crylink_waitrelease = 0; - if(!thiswep.wr_checkammo1(thiswep, actor) && !thiswep.wr_checkammo2(thiswep, actor)) + actor.(weaponentity).crylink_waitrelease = 0; + if(!thiswep.wr_checkammo1(thiswep, actor, weaponentity) && !thiswep.wr_checkammo2(thiswep, actor, weaponentity)) if(!(actor.items & IT_UNLIMITED_WEAPON_AMMO)) { // ran out of ammo! actor.cnt = WEP_CRYLINK.m_id; - PS(actor).m_switchweapon = w_getbestweapon(actor); + actor.(weaponentity).m_switchweapon = w_getbestweapon(actor, weaponentity); } } } } -METHOD(Crylink, wr_checkammo1, bool(entity thiswep, entity actor)) +METHOD(Crylink, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity)) { // don't "run out of ammo" and switch weapons while waiting for release - if(actor.crylink_lastgroup && actor.crylink_waitrelease) + if(actor.(weaponentity).crylink_lastgroup && actor.(weaponentity).crylink_waitrelease) return true; float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_PRI(crylink, ammo); - ammo_amount += actor.(weapon_load[WEP_CRYLINK.m_id]) >= WEP_CVAR_PRI(crylink, ammo); + ammo_amount += actor.(weaponentity).(weapon_load[WEP_CRYLINK.m_id]) >= WEP_CVAR_PRI(crylink, ammo); return ammo_amount; } -METHOD(Crylink, wr_checkammo2, bool(entity thiswep, entity actor)) +METHOD(Crylink, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity)) { // don't "run out of ammo" and switch weapons while waiting for release - if(actor.crylink_lastgroup && actor.crylink_waitrelease) + if(actor.(weaponentity).crylink_lastgroup && actor.(weaponentity).crylink_waitrelease) return true; float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_SEC(crylink, ammo); - ammo_amount += actor.(weapon_load[WEP_CRYLINK.m_id]) >= WEP_CVAR_SEC(crylink, ammo); + ammo_amount += actor.(weaponentity).(weapon_load[WEP_CRYLINK.m_id]) >= WEP_CVAR_SEC(crylink, ammo); return ammo_amount; } METHOD(Crylink, wr_reload, void(entity thiswep, entity actor, .entity weaponentity)) diff --git a/qcsrc/common/weapons/weapon/devastator.qc b/qcsrc/common/weapons/weapon/devastator.qc index 7e63e760ec..a6473b3927 100644 --- a/qcsrc/common/weapons/weapon/devastator.qc +++ b/qcsrc/common/weapons/weapon/devastator.qc @@ -63,7 +63,7 @@ ENDCLASS(Devastator) REGISTER_WEAPON(DEVASTATOR, devastator, NEW(Devastator)); #ifdef SVQC -.float rl_release[MAX_WEAPONSLOTS]; +.float rl_release; .float rl_detonate_later; #endif #endif @@ -116,15 +116,16 @@ void W_Devastator_Explode(entity this, entity directhitentity) ); Weapon thiswep = WEP_DEVASTATOR; - if(PS(this.realowner).m_weapon == thiswep) + .entity weaponentity = this.weaponentity_fld; + if(this.realowner.(weaponentity).m_weapon == thiswep) { if(this.realowner.(thiswep.ammo_field) < WEP_CVAR(devastator, ammo)) if(!(this.realowner.items & IT_UNLIMITED_WEAPON_AMMO)) { this.realowner.cnt = WEP_DEVASTATOR.m_id; - int slot = 0; // TODO: unhardcode + int slot = weaponslot(weaponentity); ATTACK_FINISHED(this.realowner, slot) = time; - PS(this.realowner).m_switchweapon = w_getbestweapon(this.realowner); + this.realowner.(weaponentity).m_switchweapon = w_getbestweapon(this.realowner, weaponentity); } } delete(this); @@ -208,7 +209,7 @@ void W_Devastator_DoRemoteExplode(entity this, .entity weaponentity) ); Weapon thiswep = WEP_DEVASTATOR; - if(PS(this.realowner).m_weapon == thiswep) + if(this.realowner.(weaponentity).m_weapon == thiswep) { if(this.realowner.(thiswep.ammo_field) < WEP_CVAR(devastator, ammo)) if(!(this.realowner.items & IT_UNLIMITED_WEAPON_AMMO)) @@ -216,7 +217,7 @@ void W_Devastator_DoRemoteExplode(entity this, .entity weaponentity) this.realowner.cnt = WEP_DEVASTATOR.m_id; int slot = weaponslot(weaponentity); ATTACK_FINISHED(this.realowner, slot) = time; - PS(this.realowner).m_switchweapon = w_getbestweapon(this.realowner); + this.realowner.(weaponentity).m_switchweapon = w_getbestweapon(this.realowner, weaponentity); } } delete(this); @@ -289,13 +290,11 @@ void W_Devastator_Think(entity this) this.velocity = this.velocity + v_forward * min(WEP_CVAR(devastator, speedaccel) * W_WeaponSpeedFactor(this.realowner) * frametime, velspeed); // laser guided, or remote detonation - if(PS(this.realowner).m_weapon == WEP_DEVASTATOR) + .entity weaponentity = this.weaponentity_fld; + if(this.realowner.(weaponentity).m_weapon == WEP_DEVASTATOR) { - .entity weaponentity = this.weaponentity_fld; - int slot = weaponslot(weaponentity); - if(this == this.realowner.(weaponentity).lastrocket) - if(!this.realowner.rl_release[slot]) + if(!this.realowner.(weaponentity).rl_release) if(!PHYS_INPUT_BUTTON_ATCK2(this)) if(WEP_CVAR(devastator, guiderate)) if(time > this.pushltime) @@ -368,7 +367,7 @@ void W_Devastator_Damage(entity this, entity inflictor, entity attacker, float d void W_Devastator_Attack(Weapon thiswep, entity actor, .entity weaponentity) { - W_DecreaseAmmo(thiswep, actor, WEP_CVAR(devastator, ammo)); + W_DecreaseAmmo(thiswep, actor, WEP_CVAR(devastator, ammo), weaponentity); W_SetupShot_ProjectileSize(actor, weaponentity, '-3 -3 -3', '3 3 3', false, 5, SND_ROCKET_FIRE, CH_WEAPON_A, WEP_CVAR(devastator, damage)); Send_Effect(EFFECT_ROCKET_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1); @@ -424,10 +423,10 @@ void W_Devastator_Attack(Weapon thiswep, entity actor, .entity weaponentity) MUTATOR_CALLHOOK(EditProjectile, actor, missile); } -METHOD(Devastator, wr_aim, void(entity thiswep, entity actor)) +METHOD(Devastator, wr_aim, void(entity thiswep, entity actor, .entity weaponentity)) { // aim and decide to fire if appropriate - PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, WEP_CVAR(devastator, speed), 0, WEP_CVAR(devastator, lifetime), false); + PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR(devastator, speed), 0, WEP_CVAR(devastator, lifetime), false); if(skill >= 2) // skill 0 and 1 bots won't detonate rockets! { // decide whether to detonate rockets @@ -505,25 +504,24 @@ METHOD(Devastator, wr_aim, void(entity thiswep, entity actor)) METHOD(Devastator, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) { - if(WEP_CVAR(devastator, reload_ammo) && actor.clip_load < WEP_CVAR(devastator, ammo)) { // forced reload + if(WEP_CVAR(devastator, reload_ammo) && actor.(weaponentity).clip_load < WEP_CVAR(devastator, ammo)) { // forced reload thiswep.wr_reload(thiswep, actor, weaponentity); } else { - int slot = weaponslot(weaponentity); if(fire & 1) { - if(actor.rl_release[slot] || WEP_CVAR(devastator, guidestop)) + if(actor.(weaponentity).rl_release || WEP_CVAR(devastator, guidestop)) if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(devastator, refire))) { W_Devastator_Attack(thiswep, actor, weaponentity); weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(devastator, animtime), w_ready); - actor.rl_release[slot] = 0; + actor.(weaponentity).rl_release = 0; } } else - actor.rl_release[slot] = 1; + actor.(weaponentity).rl_release = 1; if(fire & 2) - if(PS(actor).m_switchweapon == WEP_DEVASTATOR) + if(actor.(weaponentity).m_switchweapon == WEP_DEVASTATOR) { bool rockfound = false; IL_EACH(g_projectiles, it.realowner == actor && it.classname == "rocket", @@ -539,12 +537,11 @@ METHOD(Devastator, wr_think, void(entity thiswep, entity actor, .entity weaponen } } } -METHOD(Devastator, wr_setup, void(entity thiswep, entity actor)) +METHOD(Devastator, wr_setup, void(entity thiswep, entity actor, .entity weaponentity)) { - for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) - actor.rl_release[slot] = 1; + actor.(weaponentity).rl_release = 1; } -METHOD(Devastator, wr_checkammo1, bool(entity thiswep, entity actor)) +METHOD(Devastator, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity)) { #if 0 // don't switch while guiding a missile @@ -553,7 +550,7 @@ METHOD(Devastator, wr_checkammo1, bool(entity thiswep, entity actor)) ammo_amount = false; if(WEP_CVAR(devastator, reload_ammo)) { - if(actor.(thiswep.ammo_field) < WEP_CVAR(devastator, ammo) && actor.(weapon_load[WEP_DEVASTATOR.m_id]) < WEP_CVAR(devastator, ammo)) + if(actor.(thiswep.ammo_field) < WEP_CVAR(devastator, ammo) && actor.(weaponentity).(weapon_load[WEP_DEVASTATOR.m_id]) < WEP_CVAR(devastator, ammo)) ammo_amount = true; } else if(actor.(thiswep.ammo_field) < WEP_CVAR(devastator, ammo)) @@ -570,17 +567,17 @@ METHOD(Devastator, wr_checkammo1, bool(entity thiswep, entity actor)) else { ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR(devastator, ammo); - ammo_amount += actor.(weapon_load[WEP_DEVASTATOR.m_id]) >= WEP_CVAR(devastator, ammo); + ammo_amount += actor.(weaponentity).(weapon_load[WEP_DEVASTATOR.m_id]) >= WEP_CVAR(devastator, ammo); LOG_INFOF("W_Devastator(WR_CHECKAMMO1): %d, %.2f, %d: %s\n", actor.rl_release, actor.(thiswep.ammo_field), WEP_CVAR(devastator, ammo), (ammo_amount ? "TRUE" : "FALSE")); return ammo_amount; } #else float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR(devastator, ammo); - ammo_amount += actor.(weapon_load[WEP_DEVASTATOR.m_id]) >= WEP_CVAR(devastator, ammo); + ammo_amount += actor.(weaponentity).(weapon_load[WEP_DEVASTATOR.m_id]) >= WEP_CVAR(devastator, ammo); return ammo_amount; #endif } -METHOD(Devastator, wr_checkammo2, bool(entity thiswep, entity actor)) +METHOD(Devastator, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity)) { return false; } @@ -590,7 +587,7 @@ METHOD(Devastator, wr_resetplayer, void(entity thiswep, entity actor)) { .entity weaponentity = weaponentities[slot]; actor.(weaponentity).lastrocket = NULL; // stop rocket guiding, no revenge from the grave! - actor.rl_release[slot] = 0; + actor.(weaponentity).rl_release = 0; } } METHOD(Devastator, wr_reload, void(entity thiswep, entity actor, .entity weaponentity)) diff --git a/qcsrc/common/weapons/weapon/electro.qc b/qcsrc/common/weapons/weapon/electro.qc index 319f0d1d70..46e46c2405 100644 --- a/qcsrc/common/weapons/weapon/electro.qc +++ b/qcsrc/common/weapons/weapon/electro.qc @@ -265,7 +265,7 @@ void W_Electro_Attack_Bolt(Weapon thiswep, entity actor, .entity weaponentity) { entity proj; - W_DecreaseAmmo(thiswep, actor, WEP_CVAR_PRI(electro, ammo)); + W_DecreaseAmmo(thiswep, actor, WEP_CVAR_PRI(electro, ammo), weaponentity); W_SetupShot_ProjectileSize( actor, @@ -411,7 +411,7 @@ void W_Electro_Orb_Damage(entity this, entity inflictor, entity attacker, float void W_Electro_Attack_Orb(Weapon thiswep, entity actor, .entity weaponentity) { - W_DecreaseAmmo(thiswep, actor, WEP_CVAR_SEC(electro, ammo)); + W_DecreaseAmmo(thiswep, actor, WEP_CVAR_SEC(electro, ammo), weaponentity); W_SetupShot_ProjectileSize( actor, @@ -476,12 +476,12 @@ void W_Electro_Attack_Orb(Weapon thiswep, entity actor, .entity weaponentity) void W_Electro_CheckAttack(Weapon thiswep, entity actor, .entity weaponentity, int fire) { - if(actor.electro_count > 1) + if(actor.(weaponentity).electro_count > 1) if(PHYS_INPUT_BUTTON_ATCK2(actor)) if(weapon_prepareattack(thiswep, actor, weaponentity, true, -1)) { W_Electro_Attack_Orb(WEP_ELECTRO, actor, weaponentity); - actor.electro_count -= 1; + actor.(weaponentity).electro_count -= 1; weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(electro, animtime), W_Electro_CheckAttack); return; } @@ -491,7 +491,7 @@ void W_Electro_CheckAttack(Weapon thiswep, entity actor, .entity weaponentity, i .float bot_secondary_electromooth; -METHOD(Electro, wr_aim, void(entity thiswep, entity actor)) +METHOD(Electro, wr_aim, void(entity thiswep, entity actor, .entity weaponentity)) { PHYS_INPUT_BUTTON_ATCK(actor) = PHYS_INPUT_BUTTON_ATCK2(actor) = false; if(vdist(actor.origin - actor.enemy.origin, >, 1000)) { actor.bot_secondary_electromooth = 0; } @@ -500,9 +500,9 @@ METHOD(Electro, wr_aim, void(entity thiswep, entity actor)) float shoot; if(WEP_CVAR_PRI(electro, speed)) - shoot = bot_aim(actor, WEP_CVAR_PRI(electro, speed), 0, WEP_CVAR_PRI(electro, lifetime), false); + shoot = bot_aim(actor, weaponentity, WEP_CVAR_PRI(electro, speed), 0, WEP_CVAR_PRI(electro, lifetime), false); else - shoot = bot_aim(actor, 1000000, 0, 0.001, false); + shoot = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false); if(shoot) { @@ -512,7 +512,7 @@ METHOD(Electro, wr_aim, void(entity thiswep, entity actor)) } else { - if(bot_aim(actor, WEP_CVAR_SEC(electro, speed), WEP_CVAR_SEC(electro, speed_up), WEP_CVAR_SEC(electro, lifetime), true)) + if(bot_aim(actor, weaponentity, WEP_CVAR_SEC(electro, speed), WEP_CVAR_SEC(electro, speed_up), WEP_CVAR_SEC(electro, lifetime), true)) { PHYS_INPUT_BUTTON_ATCK2(actor) = true; if(random() < 0.03) actor.bot_secondary_electromooth = 0; @@ -524,9 +524,9 @@ METHOD(Electro, wr_think, void(entity thiswep, entity actor, .entity weaponentit if(autocvar_g_balance_electro_reload_ammo) // forced reload // WEAPONTODO { float ammo_amount = 0; - if(actor.clip_load >= WEP_CVAR_PRI(electro, ammo)) + if(actor.(weaponentity).clip_load >= WEP_CVAR_PRI(electro, ammo)) ammo_amount = 1; - if(actor.clip_load >= WEP_CVAR_SEC(electro, ammo)) + if(actor.(weaponentity).clip_load >= WEP_CVAR_SEC(electro, ammo)) ammo_amount += 1; if(!ammo_amount) @@ -546,40 +546,44 @@ METHOD(Electro, wr_think, void(entity thiswep, entity actor, .entity weaponentit } else if(fire & 2) { - if(time >= actor.electro_secondarytime) + if(time >= actor.(weaponentity).electro_secondarytime) if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(electro, refire))) { W_Electro_Attack_Orb(thiswep, actor, weaponentity); - actor.electro_count = WEP_CVAR_SEC(electro, count); + actor.(weaponentity).electro_count = WEP_CVAR_SEC(electro, count); weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(electro, animtime), W_Electro_CheckAttack); - actor.electro_secondarytime = time + WEP_CVAR_SEC(electro, refire2) * W_WeaponRateFactor(actor); + actor.(weaponentity).electro_secondarytime = time + WEP_CVAR_SEC(electro, refire2) * W_WeaponRateFactor(actor); } } } -METHOD(Electro, wr_checkammo1, bool(entity thiswep, entity actor)) +METHOD(Electro, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity)) { float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_PRI(electro, ammo); - ammo_amount += actor.(weapon_load[WEP_ELECTRO.m_id]) >= WEP_CVAR_PRI(electro, ammo); + ammo_amount += actor.(weaponentity).(weapon_load[WEP_ELECTRO.m_id]) >= WEP_CVAR_PRI(electro, ammo); return ammo_amount; } -METHOD(Electro, wr_checkammo2, bool(entity thiswep, entity actor)) +METHOD(Electro, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity)) { float ammo_amount; if(WEP_CVAR(electro, combo_safeammocheck)) // true if you can fire at least one secondary blob AND one primary shot after it, otherwise false. { ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_SEC(electro, ammo) + WEP_CVAR_PRI(electro, ammo); - ammo_amount += actor.(weapon_load[WEP_ELECTRO.m_id]) >= WEP_CVAR_SEC(electro, ammo) + WEP_CVAR_PRI(electro, ammo); + ammo_amount += actor.(weaponentity).(weapon_load[WEP_ELECTRO.m_id]) >= WEP_CVAR_SEC(electro, ammo) + WEP_CVAR_PRI(electro, ammo); } else { ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_SEC(electro, ammo); - ammo_amount += actor.(weapon_load[WEP_ELECTRO.m_id]) >= WEP_CVAR_SEC(electro, ammo); + ammo_amount += actor.(weaponentity).(weapon_load[WEP_ELECTRO.m_id]) >= WEP_CVAR_SEC(electro, ammo); } return ammo_amount; } METHOD(Electro, wr_resetplayer, void(entity thiswep, entity actor)) { - actor.electro_secondarytime = time; + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + actor.(weaponentity).electro_secondarytime = time; + } } METHOD(Electro, wr_reload, void(entity thiswep, entity actor, .entity weaponentity)) { diff --git a/qcsrc/common/weapons/weapon/fireball.qc b/qcsrc/common/weapons/weapon/fireball.qc index ae1e48bb2c..dff721aa1a 100644 --- a/qcsrc/common/weapons/weapon/fireball.qc +++ b/qcsrc/common/weapons/weapon/fireball.qc @@ -56,7 +56,7 @@ REGISTER_WEAPON(FIREBALL, fireball, NEW(Fireball)); #ifdef SVQC .float bot_primary_fireballmooth; // whatever a mooth is .vector fireball_impactvec; -.float fireball_primarytime[MAX_WEAPONSLOTS]; +.float fireball_primarytime; #endif #endif #ifdef IMPLEMENTATION @@ -314,7 +314,7 @@ void W_Fireball_Attack2(entity actor, .entity weaponentity) vector f_diff; float c; - c = actor.bulletcounter % 4; + c = actor.(weaponentity).bulletcounter % 4; switch(c) { case 0: @@ -364,13 +364,13 @@ void W_Fireball_Attack2(entity actor, .entity weaponentity) MUTATOR_CALLHOOK(EditProjectile, actor, proj); } -METHOD(Fireball, wr_aim, void(entity thiswep, entity actor)) +METHOD(Fireball, wr_aim, void(entity thiswep, entity actor, .entity weaponentity)) { PHYS_INPUT_BUTTON_ATCK(actor) = false; PHYS_INPUT_BUTTON_ATCK2(actor) = false; if(actor.bot_primary_fireballmooth == 0) { - if(bot_aim(actor, WEP_CVAR_PRI(fireball, speed), 0, WEP_CVAR_PRI(fireball, lifetime), false)) + if(bot_aim(actor, weaponentity, WEP_CVAR_PRI(fireball, speed), 0, WEP_CVAR_PRI(fireball, lifetime), false)) { PHYS_INPUT_BUTTON_ATCK(actor) = true; if(random() < 0.02) actor.bot_primary_fireballmooth = 0; @@ -378,7 +378,7 @@ METHOD(Fireball, wr_aim, void(entity thiswep, entity actor)) } else { - if(bot_aim(actor, WEP_CVAR_SEC(fireball, speed), WEP_CVAR_SEC(fireball, speed_up), WEP_CVAR_SEC(fireball, lifetime), true)) + if(bot_aim(actor, weaponentity, WEP_CVAR_SEC(fireball, speed), WEP_CVAR_SEC(fireball, speed_up), WEP_CVAR_SEC(fireball, lifetime), true)) { PHYS_INPUT_BUTTON_ATCK2(actor) = true; if(random() < 0.01) actor.bot_primary_fireballmooth = 1; @@ -389,12 +389,11 @@ METHOD(Fireball, wr_think, void(entity thiswep, entity actor, .entity weaponenti { if(fire & 1) { - int slot = weaponslot(weaponentity); - if(time >= actor.fireball_primarytime[slot]) + if(time >= actor.(weaponentity).fireball_primarytime) if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(fireball, refire))) { W_Fireball_Attack1_Frame0(thiswep, actor, weaponentity, fire); - actor.fireball_primarytime[slot] = time + WEP_CVAR_PRI(fireball, refire2) * W_WeaponRateFactor(actor); + actor.(weaponentity).fireball_primarytime = time + WEP_CVAR_PRI(fireball, refire2) * W_WeaponRateFactor(actor); } } else if(fire & 2) @@ -406,22 +405,21 @@ METHOD(Fireball, wr_think, void(entity thiswep, entity actor, .entity weaponenti } } } -METHOD(Fireball, wr_setup, void(entity thiswep, entity actor)) -{ - actor.ammo_field = ammo_none; -} -METHOD(Fireball, wr_checkammo1, bool(entity thiswep, entity actor)) +METHOD(Fireball, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity)) { return true; // infinite ammo } -METHOD(Fireball, wr_checkammo2, bool(entity thiswep, entity actor)) +METHOD(Fireball, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity)) { return true; // fireball has infinite ammo } METHOD(Fireball, wr_resetplayer, void(entity thiswep, entity actor)) { for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) - actor.fireball_primarytime[slot] = time; + { + .entity weaponentity = weaponentities[slot]; + actor.(weaponentity).fireball_primarytime = time; + } } METHOD(Fireball, wr_suicidemessage, Notification(entity thiswep)) { diff --git a/qcsrc/common/weapons/weapon/hagar.qc b/qcsrc/common/weapons/weapon/hagar.qc index 684ee75d37..eff656a6e1 100644 --- a/qcsrc/common/weapons/weapon/hagar.qc +++ b/qcsrc/common/weapons/weapon/hagar.qc @@ -139,7 +139,7 @@ void W_Hagar_Attack(Weapon thiswep, entity actor, .entity weaponentity) { entity missile; - W_DecreaseAmmo(thiswep, actor, WEP_CVAR_PRI(hagar, ammo)); + W_DecreaseAmmo(thiswep, actor, WEP_CVAR_PRI(hagar, ammo), weaponentity); W_SetupShot(actor, weaponentity, false, 2, SND_HAGAR_FIRE, CH_WEAPON_A, WEP_CVAR_PRI(hagar, damage)); @@ -184,7 +184,7 @@ void W_Hagar_Attack2(Weapon thiswep, entity actor, .entity weaponentity) { entity missile; - W_DecreaseAmmo(thiswep, actor, WEP_CVAR_SEC(hagar, ammo)); + W_DecreaseAmmo(thiswep, actor, WEP_CVAR_SEC(hagar, ammo), weaponentity); W_SetupShot(actor, weaponentity, false, 2, SND_HAGAR_FIRE, CH_WEAPON_A, WEP_CVAR_SEC(hagar, damage)); @@ -236,7 +236,7 @@ void W_Hagar_Attack2_Load_Release(entity actor, .entity weaponentity) vector s; vector forward, right, up; - if(!actor.hagar_load) + if(!actor.(weaponentity).hagar_load) return; weapon_prepareattack_do(actor, weaponentity, true, WEP_CVAR_SEC(hagar, refire)); @@ -248,7 +248,7 @@ void W_Hagar_Attack2_Load_Release(entity actor, .entity weaponentity) right = v_right; up = v_up; - shots = actor.hagar_load; + shots = actor.(weaponentity).hagar_load; missile = NULL; for(counter = 0; counter < shots; ++counter) { @@ -305,8 +305,11 @@ void W_Hagar_Attack2_Load_Release(entity actor, .entity weaponentity) } weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(hagar, load_animtime), w_ready); - actor.hagar_loadstep = time + WEP_CVAR_SEC(hagar, refire) * W_WeaponRateFactor(actor); - actor.hagar_load = 0; + actor.(weaponentity).hagar_loadstep = time + WEP_CVAR_SEC(hagar, refire) * W_WeaponRateFactor(actor); + actor.(weaponentity).hagar_load = 0; + + if(weaponslot(weaponentity) == 0) + actor.hagar_load = 0; } void W_Hagar_Attack2_Load(Weapon thiswep, entity actor, .entity weaponentity) @@ -316,14 +319,14 @@ void W_Hagar_Attack2_Load(Weapon thiswep, entity actor, .entity weaponentity) if(time < game_starttime) return; - bool loaded = actor.hagar_load >= WEP_CVAR_SEC(hagar, load_max); + bool loaded = actor.(weaponentity).hagar_load >= WEP_CVAR_SEC(hagar, load_max); // this is different than WR_CHECKAMMO when it comes to reloading bool enough_ammo; if(actor.items & IT_UNLIMITED_WEAPON_AMMO) enough_ammo = true; else if(autocvar_g_balance_hagar_reload_ammo) - enough_ammo = actor.(weapon_load[WEP_HAGAR.m_id]) >= WEP_CVAR_SEC(hagar, ammo); + enough_ammo = actor.(weaponentity).(weapon_load[WEP_HAGAR.m_id]) >= WEP_CVAR_SEC(hagar, ammo); else enough_ammo = actor.(thiswep.ammo_field) >= WEP_CVAR_SEC(hagar, ammo); @@ -333,19 +336,21 @@ void W_Hagar_Attack2_Load(Weapon thiswep, entity actor, .entity weaponentity) { if(PHYS_INPUT_BUTTON_ATCK(actor) && WEP_CVAR_SEC(hagar, load_abort)) { - if(actor.hagar_load) + if(actor.(weaponentity).hagar_load) { // if we pressed primary fire while loading, unload all rockets and abort actor.(weaponentity).state = WS_READY; - W_DecreaseAmmo(thiswep, actor, WEP_CVAR_SEC(hagar, ammo) * actor.hagar_load * -1); // give back ammo - actor.hagar_load = 0; + W_DecreaseAmmo(thiswep, actor, WEP_CVAR_SEC(hagar, ammo) * actor.(weaponentity).hagar_load * -1, weaponentity); // give back ammo + actor.(weaponentity).hagar_load = 0; + if(weaponslot(weaponentity) == 0) + actor.hagar_load = 0; sound(actor, CH_WEAPON_A, SND_HAGAR_BEEP, VOL_BASE, ATTN_NORM); // pause until we can load rockets again, once we re-press the alt fire button - actor.hagar_loadstep = time + WEP_CVAR_SEC(hagar, load_speed) * W_WeaponRateFactor(actor); + actor.(weaponentity).hagar_loadstep = time + WEP_CVAR_SEC(hagar, load_speed) * W_WeaponRateFactor(actor); // require letting go of the alt fire button before we can load again - actor.hagar_loadblock = true; + actor.(weaponentity).hagar_loadblock = true; } } else @@ -353,49 +358,49 @@ void W_Hagar_Attack2_Load(Weapon thiswep, entity actor, .entity weaponentity) // check if we can attempt to load another rocket if(!stopped) { - if(!actor.hagar_loadblock && actor.hagar_loadstep < time) + if(!actor.(weaponentity).hagar_loadblock && actor.(weaponentity).hagar_loadstep < time) { - W_DecreaseAmmo(thiswep, actor, WEP_CVAR_SEC(hagar, ammo)); + W_DecreaseAmmo(thiswep, actor, WEP_CVAR_SEC(hagar, ammo), weaponentity); actor.(weaponentity).state = WS_INUSE; - actor.hagar_load += 1; + actor.(weaponentity).hagar_load += 1; sound(actor, CH_WEAPON_B, SND_HAGAR_LOAD, VOL_BASE * 0.8, ATTN_NORM); // sound is too loud according to most - if(actor.hagar_load >= WEP_CVAR_SEC(hagar, load_max)) + if(actor.(weaponentity).hagar_load >= WEP_CVAR_SEC(hagar, load_max)) stopped = true; else - actor.hagar_loadstep = time + WEP_CVAR_SEC(hagar, load_speed) * W_WeaponRateFactor(actor); + actor.(weaponentity).hagar_loadstep = time + WEP_CVAR_SEC(hagar, load_speed) * W_WeaponRateFactor(actor); } } - if(stopped && !actor.hagar_loadbeep && actor.hagar_load) // prevents the beep from playing each frame + if(stopped && !actor.(weaponentity).hagar_loadbeep && actor.(weaponentity).hagar_load) // prevents the beep from playing each frame { // if this is the last rocket we can load, play a beep sound to notify the player sound(actor, CH_WEAPON_A, SND_HAGAR_BEEP, VOL_BASE, ATTN_NORM); - actor.hagar_loadbeep = true; - actor.hagar_loadstep = time + WEP_CVAR_SEC(hagar, load_hold) * W_WeaponRateFactor(actor); + actor.(weaponentity).hagar_loadbeep = true; + actor.(weaponentity).hagar_loadstep = time + WEP_CVAR_SEC(hagar, load_hold) * W_WeaponRateFactor(actor); } } } - else if(actor.hagar_loadblock) + else if(actor.(weaponentity).hagar_loadblock) { // the alt fire button has been released, so re-enable loading if blocked - actor.hagar_loadblock = false; + actor.(weaponentity).hagar_loadblock = false; } - if(actor.hagar_load) + if(actor.(weaponentity).hagar_load) { // play warning sound if we're about to release - if(stopped && actor.hagar_loadstep - 0.5 < time && WEP_CVAR_SEC(hagar, load_hold) >= 0) + if(stopped && actor.(weaponentity).hagar_loadstep - 0.5 < time && WEP_CVAR_SEC(hagar, load_hold) >= 0) { - if(!actor.hagar_warning) // prevents the beep from playing each frame + if(!actor.(weaponentity).hagar_warning) // prevents the beep from playing each frame { // we're about to automatically release after holding time, play a beep sound to notify the player sound(actor, CH_WEAPON_A, SND_HAGAR_BEEP, VOL_BASE, ATTN_NORM); - actor.hagar_warning = true; + actor.(weaponentity).hagar_warning = true; } } // release if player let go of button or if they've held it in too long - if(!PHYS_INPUT_BUTTON_ATCK2(actor) || (stopped && actor.hagar_loadstep < time && WEP_CVAR_SEC(hagar, load_hold) >= 0)) + if(!PHYS_INPUT_BUTTON_ATCK2(actor) || (stopped && actor.(weaponentity).hagar_loadstep < time && WEP_CVAR_SEC(hagar, load_hold) >= 0)) { actor.(weaponentity).state = WS_READY; W_Hagar_Attack2_Load_Release(actor, weaponentity); @@ -403,15 +408,15 @@ void W_Hagar_Attack2_Load(Weapon thiswep, entity actor, .entity weaponentity) } else { - actor.hagar_loadbeep = false; - actor.hagar_warning = false; + actor.(weaponentity).hagar_loadbeep = false; + actor.(weaponentity).hagar_warning = false; // we aren't checking ammo during an attack, so we must do it here - if(!(thiswep.wr_checkammo1(thiswep, actor) + thiswep.wr_checkammo2(thiswep, actor))) + if(!(thiswep.wr_checkammo1(thiswep, actor, weaponentity) + thiswep.wr_checkammo2(thiswep, actor, weaponentity))) if(!(actor.items & IT_UNLIMITED_WEAPON_AMMO)) { // note: this doesn't force the switch - W_SwitchToOtherWeapon(actor); + W_SwitchToOtherWeapon(actor, weaponentity); return; } } @@ -419,16 +424,16 @@ void W_Hagar_Attack2_Load(Weapon thiswep, entity actor, .entity weaponentity) void W_Hagar_Attack_Auto(Weapon thiswep, entity actor, .entity weaponentity, int fire) { - if(!(fire & 1) || actor.hagar_load || actor.hagar_loadblock || PS(actor).m_switchweapon != WEP_HAGAR) + if(!(fire & 1) || actor.(weaponentity).hagar_load || actor.(weaponentity).hagar_loadblock || actor.(weaponentity).m_switchweapon != WEP_HAGAR) { w_ready(thiswep, actor, weaponentity, fire); return; } - if(!thiswep.wr_checkammo1(thiswep, actor)) + if(!thiswep.wr_checkammo1(thiswep, actor, weaponentity)) if(!(actor.items & IT_UNLIMITED_WEAPON_AMMO)) { - W_SwitchWeapon_Force(actor, w_getbestweapon(actor)); + W_SwitchWeapon_Force(actor, w_getbestweapon(actor, weaponentity), weaponentity); w_ready(thiswep, actor, weaponentity, fire); return; } @@ -447,24 +452,26 @@ void W_Hagar_Attack_Auto(Weapon thiswep, entity actor, .entity weaponentity, int weapon_thinkf(actor, weaponentity, theframe, WEP_CVAR_PRI(hagar, refire), W_Hagar_Attack_Auto); } -METHOD(Hagar, wr_aim, void(entity thiswep, entity actor)) +METHOD(Hagar, wr_aim, void(entity thiswep, entity actor, .entity weaponentity)) { if(random()>0.15) - PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, WEP_CVAR_PRI(hagar, speed), 0, WEP_CVAR_PRI(hagar, lifetime), false); + PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR_PRI(hagar, speed), 0, WEP_CVAR_PRI(hagar, lifetime), false); else // not using secondary_speed since these are only 15% and should cause some ricochets without re-aiming - PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, WEP_CVAR_PRI(hagar, speed), 0, WEP_CVAR_PRI(hagar, lifetime), false); + PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, WEP_CVAR_PRI(hagar, speed), 0, WEP_CVAR_PRI(hagar, lifetime), false); } METHOD(Hagar, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) { float loadable_secondary; loadable_secondary = (WEP_CVAR_SEC(hagar, load) && WEP_CVAR(hagar, secondary)); + if(weaponslot(weaponentity) == 0) + actor.hagar_load = actor.(weaponentity).hagar_load; if(loadable_secondary) W_Hagar_Attack2_Load(thiswep, actor, weaponentity); // must always run each frame - if(autocvar_g_balance_hagar_reload_ammo && actor.clip_load < min(WEP_CVAR_PRI(hagar, ammo), WEP_CVAR_SEC(hagar, ammo))) { // forced reload + if(autocvar_g_balance_hagar_reload_ammo && actor.(weaponentity).clip_load < min(WEP_CVAR_PRI(hagar, ammo), WEP_CVAR_SEC(hagar, ammo))) { // forced reload thiswep.wr_reload(thiswep, actor, weaponentity); } - else if((fire & 1) && !actor.hagar_load && !actor.hagar_loadblock) // not while secondary is loaded or awaiting reset + else if((fire & 1) && !actor.(weaponentity).hagar_load && !actor.(weaponentity).hagar_loadblock) // not while secondary is loaded or awaiting reset { if(weapon_prepareattack(thiswep, actor, weaponentity, false, 0)) W_Hagar_Attack_Auto(thiswep, actor, weaponentity, fire); @@ -481,47 +488,52 @@ METHOD(Hagar, wr_think, void(entity thiswep, entity actor, .entity weaponentity, METHOD(Hagar, wr_gonethink, void(entity thiswep, entity actor, .entity weaponentity)) { // we lost the weapon and want to prepare switching away - if(actor.hagar_load) + if(actor.(weaponentity).hagar_load) { actor.(weaponentity).state = WS_READY; W_Hagar_Attack2_Load_Release(actor, weaponentity); } } -METHOD(Hagar, wr_setup, void(entity thiswep, entity actor)) +METHOD(Hagar, wr_setup, void(entity thiswep, entity actor, .entity weaponentity)) { - actor.hagar_loadblock = false; - - if(actor.hagar_load) + actor.hagar_load = 0; + actor.(weaponentity).hagar_loadblock = false; + if(actor.(weaponentity).hagar_load) { - W_DecreaseAmmo(thiswep, actor, WEP_CVAR_SEC(hagar, ammo) * actor.hagar_load * -1); // give back ammo if necessary - actor.hagar_load = 0; + W_DecreaseAmmo(thiswep, actor, WEP_CVAR_SEC(hagar, ammo) * actor.(weaponentity).hagar_load * -1, weaponentity); // give back ammo if necessary + actor.(weaponentity).hagar_load = 0; } } -METHOD(Hagar, wr_checkammo1, bool(entity thiswep, entity actor)) +METHOD(Hagar, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity)) { float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_PRI(hagar, ammo); - ammo_amount += actor.(weapon_load[WEP_HAGAR.m_id]) >= WEP_CVAR_PRI(hagar, ammo); + ammo_amount += actor.(weaponentity).(weapon_load[WEP_HAGAR.m_id]) >= WEP_CVAR_PRI(hagar, ammo); return ammo_amount; } -METHOD(Hagar, wr_checkammo2, bool(entity thiswep, entity actor)) +METHOD(Hagar, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity)) { float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_SEC(hagar, ammo); - ammo_amount += actor.(weapon_load[WEP_HAGAR.m_id]) >= WEP_CVAR_SEC(hagar, ammo); + ammo_amount += actor.(weaponentity).(weapon_load[WEP_HAGAR.m_id]) >= WEP_CVAR_SEC(hagar, ammo); return ammo_amount; } METHOD(Hagar, wr_resetplayer, void(entity thiswep, entity actor)) { actor.hagar_load = 0; + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + actor.(weaponentity).hagar_load = 0; + } } METHOD(Hagar, wr_playerdeath, void(entity thiswep, entity actor, .entity weaponentity)) { // if we have any rockets loaded when we die, release them - if(actor.hagar_load && WEP_CVAR_SEC(hagar, load_releasedeath)) + if(actor.(weaponentity).hagar_load && WEP_CVAR_SEC(hagar, load_releasedeath)) W_Hagar_Attack2_Load_Release(actor, weaponentity); } METHOD(Hagar, wr_reload, void(entity thiswep, entity actor, .entity weaponentity)) { - if(!actor.hagar_load) // require releasing loaded rockets first + if(!actor.(weaponentity).hagar_load) // require releasing loaded rockets first W_Reload(actor, weaponentity, min(WEP_CVAR_PRI(hagar, ammo), WEP_CVAR_SEC(hagar, ammo)), SND_RELOAD); } METHOD(Hagar, wr_suicidemessage, Notification(entity thiswep)) diff --git a/qcsrc/common/weapons/weapon/hlac.qc b/qcsrc/common/weapons/weapon/hlac.qc index 79bf08193e..010ca4fe8e 100644 --- a/qcsrc/common/weapons/weapon/hlac.qc +++ b/qcsrc/common/weapons/weapon/hlac.qc @@ -75,9 +75,9 @@ void W_HLAC_Attack(Weapon thiswep, entity actor, .entity weaponentity) entity missile; float spread; - W_DecreaseAmmo(thiswep, actor, WEP_CVAR_PRI(hlac, ammo)); + W_DecreaseAmmo(thiswep, actor, WEP_CVAR_PRI(hlac, ammo), weaponentity); - spread = WEP_CVAR_PRI(hlac, spread_min) + (WEP_CVAR_PRI(hlac, spread_add) * actor.misc_bulletcounter); + spread = WEP_CVAR_PRI(hlac, spread_min) + (WEP_CVAR_PRI(hlac, spread_add) * actor.(weaponentity).misc_bulletcounter); spread = min(spread,WEP_CVAR_PRI(hlac, spread_max)); if(actor.crouch) spread = spread * WEP_CVAR_PRI(hlac, spread_crouchmod); @@ -168,7 +168,7 @@ void W_HLAC_Attack2(entity actor, .entity weaponentity) // weapon frames void W_HLAC_Attack_Frame(Weapon thiswep, entity actor, .entity weaponentity, int fire) { - if(PS(actor).m_weapon != PS(actor).m_switchweapon) // abort immediately if switching + if(actor.(weaponentity).m_weapon != actor.(weaponentity).m_switchweapon) // abort immediately if switching { w_ready(thiswep, actor, weaponentity, fire); return; @@ -176,10 +176,10 @@ void W_HLAC_Attack_Frame(Weapon thiswep, entity actor, .entity weaponentity, int if(PHYS_INPUT_BUTTON_ATCK(actor)) { - if(!thiswep.wr_checkammo1(thiswep, actor)) + if(!thiswep.wr_checkammo1(thiswep, actor, weaponentity)) if(!(actor.items & IT_UNLIMITED_WEAPON_AMMO)) { - W_SwitchWeapon_Force(actor, w_getbestweapon(actor)); + W_SwitchWeapon_Force(actor, w_getbestweapon(actor, weaponentity), weaponentity); w_ready(thiswep, actor, weaponentity, fire); return; } @@ -187,7 +187,7 @@ void W_HLAC_Attack_Frame(Weapon thiswep, entity actor, .entity weaponentity, int int slot = weaponslot(weaponentity); ATTACK_FINISHED(actor, slot) = time + WEP_CVAR_PRI(hlac, refire) * W_WeaponRateFactor(actor); W_HLAC_Attack(WEP_HLAC, actor, weaponentity); - actor.misc_bulletcounter = actor.misc_bulletcounter + 1; + actor.(weaponentity).misc_bulletcounter = actor.(weaponentity).misc_bulletcounter + 1; weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(hlac, refire), W_HLAC_Attack_Frame); } else @@ -200,7 +200,7 @@ void W_HLAC_Attack2_Frame(Weapon thiswep, entity actor, .entity weaponentity) { float i; - W_DecreaseAmmo(thiswep, actor, WEP_CVAR_SEC(hlac, ammo)); + W_DecreaseAmmo(thiswep, actor, WEP_CVAR_SEC(hlac, ammo), weaponentity); for(i=WEP_CVAR_SEC(hlac, shots);i>0;--i) W_HLAC_Attack2(actor, weaponentity); @@ -212,19 +212,19 @@ void W_HLAC_Attack2_Frame(Weapon thiswep, entity actor, .entity weaponentity) } } -METHOD(HLAC, wr_aim, void(entity thiswep, entity actor)) +METHOD(HLAC, wr_aim, void(entity thiswep, entity actor, .entity weaponentity)) { - PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, WEP_CVAR_PRI(hlac, speed), 0, WEP_CVAR_PRI(hlac, lifetime), false); + PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR_PRI(hlac, speed), 0, WEP_CVAR_PRI(hlac, lifetime), false); } METHOD(HLAC, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) { - if(autocvar_g_balance_hlac_reload_ammo && actor.clip_load < min(WEP_CVAR_PRI(hlac, ammo), WEP_CVAR_SEC(hlac, ammo))) { // forced reload + if(autocvar_g_balance_hlac_reload_ammo && actor.(weaponentity).clip_load < min(WEP_CVAR_PRI(hlac, ammo), WEP_CVAR_SEC(hlac, ammo))) { // forced reload thiswep.wr_reload(thiswep, actor, weaponentity); } else if(fire & 1) { if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(hlac, refire))) { - actor.misc_bulletcounter = 0; + actor.(weaponentity).misc_bulletcounter = 0; W_HLAC_Attack(thiswep, actor, weaponentity); weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(hlac, refire), W_HLAC_Attack_Frame); } @@ -239,16 +239,16 @@ METHOD(HLAC, wr_think, void(entity thiswep, entity actor, .entity weaponentity, } } } -METHOD(HLAC, wr_checkammo1, bool(entity thiswep, entity actor)) +METHOD(HLAC, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity)) { float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_PRI(hlac, ammo); - ammo_amount += actor.(weapon_load[WEP_HLAC.m_id]) >= WEP_CVAR_PRI(hlac, ammo); + ammo_amount += actor.(weaponentity).(weapon_load[WEP_HLAC.m_id]) >= WEP_CVAR_PRI(hlac, ammo); return ammo_amount; } -METHOD(HLAC, wr_checkammo2, bool(entity thiswep, entity actor)) +METHOD(HLAC, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity)) { float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_SEC(hlac, ammo); - ammo_amount += actor.(weapon_load[WEP_HLAC.m_id]) >= WEP_CVAR_SEC(hlac, ammo); + ammo_amount += actor.(weaponentity).(weapon_load[WEP_HLAC.m_id]) >= WEP_CVAR_SEC(hlac, ammo); return ammo_amount; } METHOD(HLAC, wr_reload, void(entity thiswep, entity actor, .entity weaponentity)) diff --git a/qcsrc/common/weapons/weapon/hook.qc b/qcsrc/common/weapons/weapon/hook.qc index f5dd96e4c3..ff815d4619 100644 --- a/qcsrc/common/weapons/weapon/hook.qc +++ b/qcsrc/common/weapons/weapon/hook.qc @@ -192,19 +192,19 @@ void W_Hook_Attack2(Weapon thiswep, entity actor, .entity weaponentity) METHOD(Hook, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) { if (fire & 1) { - if(!actor.hook) - if(!(actor.hook_state & HOOK_WAITING_FOR_RELEASE)) - if(time > actor.hook_refire) + if(!actor.(weaponentity).hook) + if(!(actor.(weaponentity).hook_state & HOOK_WAITING_FOR_RELEASE)) + if(time > actor.(weaponentity).hook_refire) if(weapon_prepareattack(thiswep, actor, weaponentity, false, -1)) { - W_DecreaseAmmo(thiswep, actor, thiswep.ammo_factor * WEP_CVAR_PRI(hook, ammo)); - actor.hook_state |= HOOK_FIRING; - actor.hook_state |= HOOK_WAITING_FOR_RELEASE; + W_DecreaseAmmo(thiswep, actor, thiswep.ammo_factor * WEP_CVAR_PRI(hook, ammo), weaponentity); + actor.(weaponentity).hook_state |= HOOK_FIRING; + actor.(weaponentity).hook_state |= HOOK_WAITING_FOR_RELEASE; weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(hook, animtime), w_ready); } } else { - actor.hook_state |= HOOK_REMOVING; - actor.hook_state &= ~HOOK_WAITING_FOR_RELEASE; + actor.(weaponentity).hook_state |= HOOK_REMOVING; + actor.(weaponentity).hook_state &= ~HOOK_WAITING_FOR_RELEASE; } if(fire & 2) @@ -216,43 +216,43 @@ METHOD(Hook, wr_think, void(entity thiswep, entity actor, .entity weaponentity, } } - if(actor.hook) + if(actor.(weaponentity).hook) { // if hooked, no bombs, and increase the timer - actor.hook_refire = max(actor.hook_refire, time + WEP_CVAR_PRI(hook, refire) * W_WeaponRateFactor(actor)); + actor.(weaponentity).hook_refire = max(actor.(weaponentity).hook_refire, time + WEP_CVAR_PRI(hook, refire) * W_WeaponRateFactor(actor)); // hook also inhibits health regeneration, but only for 1 second if(!(actor.items & IT_UNLIMITED_WEAPON_AMMO)) actor.pauseregen_finished = max(actor.pauseregen_finished, time + autocvar_g_balance_pause_fuel_regen); } - if(actor.hook && actor.hook.state == 1) + if(actor.(weaponentity).hook && actor.(weaponentity).hook.state == 1) { float hooked_time_max = WEP_CVAR_PRI(hook, hooked_time_max); if(hooked_time_max > 0) { - if( time > actor.hook_time_hooked + hooked_time_max ) - actor.hook_state |= HOOK_REMOVING; + if( time > actor.(weaponentity).hook_time_hooked + hooked_time_max ) + actor.(weaponentity).hook_state |= HOOK_REMOVING; } float hooked_fuel = thiswep.ammo_factor * WEP_CVAR_PRI(hook, hooked_ammo); if(hooked_fuel > 0) { - if( time > actor.hook_time_fueldecrease ) + if( time > actor.(weaponentity).hook_time_fueldecrease ) { if(!(actor.items & IT_UNLIMITED_WEAPON_AMMO)) { - if( actor.ammo_fuel >= (time - actor.hook_time_fueldecrease) * hooked_fuel ) + if( actor.ammo_fuel >= (time - actor.(weaponentity).hook_time_fueldecrease) * hooked_fuel ) { - W_DecreaseAmmo(thiswep, actor, (time - actor.hook_time_fueldecrease) * hooked_fuel); - actor.hook_time_fueldecrease = time; + W_DecreaseAmmo(thiswep, actor, (time - actor.(weaponentity).hook_time_fueldecrease) * hooked_fuel, weaponentity); + actor.(weaponentity).hook_time_fueldecrease = time; // decrease next frame again } else { actor.ammo_fuel = 0; - actor.hook_state |= HOOK_REMOVING; - W_SwitchWeapon_Force(actor, w_getbestweapon(actor)); + actor.(weaponentity).hook_state |= HOOK_REMOVING; + W_SwitchWeapon_Force(actor, w_getbestweapon(actor, weaponentity), weaponentity); } } } @@ -260,49 +260,54 @@ METHOD(Hook, wr_think, void(entity thiswep, entity actor, .entity weaponentity, } else { - actor.hook_time_hooked = time; - actor.hook_time_fueldecrease = time + WEP_CVAR_PRI(hook, hooked_time_free); + actor.(weaponentity).hook_time_hooked = time; + actor.(weaponentity).hook_time_fueldecrease = time + WEP_CVAR_PRI(hook, hooked_time_free); } - actor.hook_state = BITSET(actor.hook_state, HOOK_PULLING, (!PHYS_INPUT_BUTTON_CROUCH(actor) || !autocvar_g_balance_grapplehook_crouchslide)); + actor.(weaponentity).hook_state = BITSET(actor.(weaponentity).hook_state, HOOK_PULLING, (!PHYS_INPUT_BUTTON_CROUCH(actor) || !autocvar_g_balance_grapplehook_crouchslide)); - if (actor.hook_state & HOOK_FIRING) + if (actor.(weaponentity).hook_state & HOOK_FIRING) { - if (actor.hook) - RemoveGrapplingHook(actor); - FireGrapplingHook(actor); - actor.hook_state &= ~HOOK_FIRING; - actor.hook_refire = max(actor.hook_refire, time + autocvar_g_balance_grapplehook_refire * W_WeaponRateFactor(actor)); + if (actor.(weaponentity).hook) + RemoveHook(actor.(weaponentity).hook); + FireGrapplingHook(actor, weaponentity); + actor.(weaponentity).hook_state &= ~HOOK_FIRING; + actor.(weaponentity).hook_refire = max(actor.(weaponentity).hook_refire, time + autocvar_g_balance_grapplehook_refire * W_WeaponRateFactor(actor)); } - else if (actor.hook_state & HOOK_REMOVING) + else if (actor.(weaponentity).hook_state & HOOK_REMOVING) { - if (actor.hook) - RemoveGrapplingHook(actor); - actor.hook_state &= ~HOOK_REMOVING; + if (actor.(weaponentity).hook) + RemoveHook(actor.(weaponentity).hook); + actor.(weaponentity).hook_state &= ~HOOK_REMOVING; } } -METHOD(Hook, wr_setup, void(entity thiswep, entity actor)) +METHOD(Hook, wr_setup, void(entity thiswep, entity actor, .entity weaponentity)) { - actor.hook_state &= ~HOOK_WAITING_FOR_RELEASE; + actor.(weaponentity).hook_state &= ~HOOK_WAITING_FOR_RELEASE; } -METHOD(Hook, wr_checkammo1, bool(Hook thiswep, entity actor)) +METHOD(Hook, wr_checkammo1, bool(Hook thiswep, entity actor, .entity weaponentity)) { if (!thiswep.ammo_factor) return true; - if(actor.hook) - return actor.ammo_fuel > 0; - else - return actor.ammo_fuel >= WEP_CVAR_PRI(hook, ammo); + + if(actor.(weaponentity).hook) + return actor.ammo_fuel > 0; + + return actor.ammo_fuel >= WEP_CVAR_PRI(hook, ammo); } -METHOD(Hook, wr_checkammo2, bool(Hook thiswep, entity actor)) +METHOD(Hook, wr_checkammo2, bool(Hook thiswep, entity actor, .entity weaponentity)) { // infinite ammo for now return true; // actor.ammo_cells >= WEP_CVAR_SEC(hook, ammo); // WEAPONTODO: see above } METHOD(Hook, wr_resetplayer, void(entity thiswep, entity actor)) { - RemoveGrapplingHook(actor); - actor.hook_time = 0; - actor.hook_refire = time; + RemoveGrapplingHooks(actor); + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + actor.(weaponentity).hook_time = 0; + actor.(weaponentity).hook_refire = time; + } } METHOD(Hook, wr_killmessage, Notification(entity thiswep)) { @@ -371,7 +376,7 @@ void Draw_GrapplingHook(entity this) InterpolateOrigin_Do(this); - int s = W_GetGunAlignment(NULL); + int s = W_GunAlign(viewmodels[this.cnt], STAT(GUNALIGN)) - 1; switch(this.HookType) { @@ -514,10 +519,12 @@ NET_HANDLE(ENT_CLIENT_HOOK, bool bIsNew) if(sf & 1) { int myowner = ReadByte(); + int slot = ReadByte(); this.owner = playerslots[myowner - 1]; this.sv_entnum = myowner; - if(csqcplayer && myowner == player_localentnum) - csqcplayer.hook = this; + if(myowner == player_localentnum) + viewmodels[slot].hook = this; + this.cnt = slot; switch(this.HookType) { default: diff --git a/qcsrc/common/weapons/weapon/machinegun.qc b/qcsrc/common/weapons/weapon/machinegun.qc index 81da28ddb0..7344ba9d0d 100644 --- a/qcsrc/common/weapons/weapon/machinegun.qc +++ b/qcsrc/common/weapons/weapon/machinegun.qc @@ -111,7 +111,7 @@ void W_MachineGun_MuzzleFlash(entity actor, .entity weaponentity) void W_MachineGun_Attack(Weapon thiswep, int deathtype, entity actor, .entity weaponentity) { - W_SetupShot(actor, weaponentity, true, 0, SND_UZI_FIRE, CH_WEAPON_A, ((actor.misc_bulletcounter == 1) ? WEP_CVAR(machinegun, first_damage) : WEP_CVAR(machinegun, sustained_damage))); + W_SetupShot(actor, weaponentity, true, 0, SND_UZI_FIRE, CH_WEAPON_A, ((actor.(weaponentity).misc_bulletcounter == 1) ? WEP_CVAR(machinegun, first_damage) : WEP_CVAR(machinegun, sustained_damage))); if(!autocvar_g_norecoil) { actor.punchangle_x = random() - 0.5; @@ -121,10 +121,10 @@ void W_MachineGun_Attack(Weapon thiswep, int deathtype, entity actor, .entity we // this attack_finished just enforces a cooldown at the end of a burst ATTACK_FINISHED(actor, slot) = time + WEP_CVAR(machinegun, first_refire) * W_WeaponRateFactor(actor); - if(actor.misc_bulletcounter == 1) - fireBullet(actor, w_shotorg, w_shotdir, WEP_CVAR(machinegun, first_spread), WEP_CVAR(machinegun, solidpenetration), WEP_CVAR(machinegun, first_damage), WEP_CVAR(machinegun, first_force), deathtype, 0); + if(actor.(weaponentity).misc_bulletcounter == 1) + fireBullet(actor, weaponentity, w_shotorg, w_shotdir, WEP_CVAR(machinegun, first_spread), WEP_CVAR(machinegun, solidpenetration), WEP_CVAR(machinegun, first_damage), WEP_CVAR(machinegun, first_force), deathtype, 0); else - fireBullet(actor, w_shotorg, w_shotdir, WEP_CVAR(machinegun, sustained_spread), WEP_CVAR(machinegun, solidpenetration), WEP_CVAR(machinegun, sustained_damage), WEP_CVAR(machinegun, sustained_force), deathtype, 0); + fireBullet(actor, weaponentity, w_shotorg, w_shotdir, WEP_CVAR(machinegun, sustained_spread), WEP_CVAR(machinegun, solidpenetration), WEP_CVAR(machinegun, sustained_damage), WEP_CVAR(machinegun, sustained_force), deathtype, 0); Send_Effect(EFFECT_MACHINEGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1); @@ -138,30 +138,30 @@ void W_MachineGun_Attack(Weapon thiswep, int deathtype, entity actor, .entity we 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, weaponentity); } - if(actor.misc_bulletcounter == 1) - W_DecreaseAmmo(thiswep, actor, WEP_CVAR(machinegun, first_ammo)); + if(actor.(weaponentity).misc_bulletcounter == 1) + W_DecreaseAmmo(thiswep, actor, WEP_CVAR(machinegun, first_ammo), weaponentity); else - W_DecreaseAmmo(thiswep, actor, WEP_CVAR(machinegun, sustained_ammo)); + W_DecreaseAmmo(thiswep, actor, WEP_CVAR(machinegun, sustained_ammo), weaponentity); } // weapon frames void W_MachineGun_Attack_Frame(Weapon thiswep, entity actor, .entity weaponentity, int fire) { - if(PS(actor).m_weapon != PS(actor).m_switchweapon) // abort immediately if switching + if(actor.(weaponentity).m_weapon != actor.(weaponentity).m_switchweapon) // abort immediately if switching { w_ready(thiswep, actor, weaponentity, fire); return; } if(PHYS_INPUT_BUTTON_ATCK(actor)) { - if(!thiswep.wr_checkammo2(thiswep, actor)) + if(!thiswep.wr_checkammo2(thiswep, actor, weaponentity)) if(!(actor.items & IT_UNLIMITED_WEAPON_AMMO)) { - W_SwitchWeapon_Force(actor, w_getbestweapon(actor)); + W_SwitchWeapon_Force(actor, w_getbestweapon(actor, weaponentity), weaponentity); w_ready(thiswep, actor, weaponentity, fire); return; } - actor.misc_bulletcounter = actor.misc_bulletcounter + 1; + actor.(weaponentity).misc_bulletcounter = actor.(weaponentity).misc_bulletcounter + 1; W_MachineGun_Attack(WEP_MACHINEGUN, WEP_MACHINEGUN.m_id, actor, weaponentity); weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(machinegun, sustained_refire), W_MachineGun_Attack_Frame); } @@ -180,15 +180,15 @@ void W_MachineGun_Attack_Auto(Weapon thiswep, entity actor, .entity weaponentity return; } - if(!thiswep.wr_checkammo1(thiswep, actor)) + if(!thiswep.wr_checkammo1(thiswep, actor, weaponentity)) if(!(actor.items & IT_UNLIMITED_WEAPON_AMMO)) { - W_SwitchWeapon_Force(actor, w_getbestweapon(actor)); + W_SwitchWeapon_Force(actor, w_getbestweapon(actor, weaponentity), weaponentity); w_ready(thiswep, actor, weaponentity, fire); return; } - W_DecreaseAmmo(WEP_MACHINEGUN, actor, WEP_CVAR(machinegun, sustained_ammo)); + W_DecreaseAmmo(WEP_MACHINEGUN, actor, WEP_CVAR(machinegun, sustained_ammo), weaponentity); W_SetupShot(actor, weaponentity, true, 0, SND_UZI_FIRE, CH_WEAPON_A, WEP_CVAR(machinegun, sustained_damage)); if(!autocvar_g_norecoil) @@ -197,10 +197,10 @@ void W_MachineGun_Attack_Auto(Weapon thiswep, entity actor, .entity weaponentity actor.punchangle_y = random() - 0.5; } - machinegun_spread = bound(WEP_CVAR(machinegun, spread_min), WEP_CVAR(machinegun, spread_min) + (WEP_CVAR(machinegun, spread_add) * actor.misc_bulletcounter), WEP_CVAR(machinegun, spread_max)); - fireBullet(actor, w_shotorg, w_shotdir, machinegun_spread, WEP_CVAR(machinegun, solidpenetration), WEP_CVAR(machinegun, sustained_damage), WEP_CVAR(machinegun, sustained_force), WEP_MACHINEGUN.m_id, 0); + machinegun_spread = bound(WEP_CVAR(machinegun, spread_min), WEP_CVAR(machinegun, spread_min) + (WEP_CVAR(machinegun, spread_add) * actor.(weaponentity).misc_bulletcounter), WEP_CVAR(machinegun, spread_max)); + fireBullet(actor, weaponentity, w_shotorg, w_shotdir, machinegun_spread, WEP_CVAR(machinegun, solidpenetration), WEP_CVAR(machinegun, sustained_damage), WEP_CVAR(machinegun, sustained_force), WEP_MACHINEGUN.m_id, 0); - actor.misc_bulletcounter = actor.misc_bulletcounter + 1; + actor.(weaponentity).misc_bulletcounter = actor.(weaponentity).misc_bulletcounter + 1; Send_Effect(EFFECT_MACHINEGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1); @@ -227,7 +227,7 @@ void W_MachineGun_Attack_Burst(Weapon thiswep, entity actor, .entity weaponentit actor.punchangle_y = random() - 0.5; } - fireBullet(actor, w_shotorg, w_shotdir, WEP_CVAR(machinegun, burst_speed), WEP_CVAR(machinegun, solidpenetration), WEP_CVAR(machinegun, sustained_damage), WEP_CVAR(machinegun, sustained_force), WEP_MACHINEGUN.m_id, 0); + fireBullet(actor, weaponentity, w_shotorg, w_shotdir, WEP_CVAR(machinegun, burst_speed), WEP_CVAR(machinegun, solidpenetration), WEP_CVAR(machinegun, sustained_damage), WEP_CVAR(machinegun, sustained_force), WEP_MACHINEGUN.m_id, 0); Send_Effect(EFFECT_MACHINEGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1); @@ -240,8 +240,8 @@ void W_MachineGun_Attack_Burst(Weapon thiswep, entity actor, .entity weaponentit 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, weaponentity); } - actor.misc_bulletcounter = actor.misc_bulletcounter + 1; - if(actor.misc_bulletcounter == 0) + actor.(weaponentity).misc_bulletcounter = actor.(weaponentity).misc_bulletcounter + 1; + if(actor.(weaponentity).misc_bulletcounter == 0) { int slot = weaponslot(weaponentity); ATTACK_FINISHED(actor, slot) = time + WEP_CVAR(machinegun, burst_refire2) * W_WeaponRateFactor(actor); @@ -254,16 +254,16 @@ void W_MachineGun_Attack_Burst(Weapon thiswep, entity actor, .entity weaponentit } -METHOD(MachineGun, wr_aim, void(entity thiswep, entity actor)) +METHOD(MachineGun, wr_aim, void(entity thiswep, entity actor, .entity weaponentity)) { if(vdist(actor.origin - actor.enemy.origin, <, 3000 - bound(0, skill, 10) * 200)) - PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, 1000000, 0, 0.001, false); + PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false); else - PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, 1000000, 0, 0.001, false); + PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false); } METHOD(MachineGun, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) { - if(WEP_CVAR(machinegun, reload_ammo) && actor.clip_load < min(max(WEP_CVAR(machinegun, sustained_ammo), WEP_CVAR(machinegun, first_ammo)), WEP_CVAR(machinegun, burst_ammo))) { // forced reload + if(WEP_CVAR(machinegun, reload_ammo) && actor.(weaponentity).clip_load < min(max(WEP_CVAR(machinegun, sustained_ammo), WEP_CVAR(machinegun, first_ammo)), WEP_CVAR(machinegun, burst_ammo))) { // forced reload thiswep.wr_reload(thiswep, actor, weaponentity); } else if(WEP_CVAR(machinegun, mode) == 1) @@ -271,24 +271,24 @@ METHOD(MachineGun, wr_think, void(entity thiswep, entity actor, .entity weaponen if(fire & 1) if(weapon_prepareattack(thiswep, actor, weaponentity, false, 0)) { - actor.misc_bulletcounter = 0; + actor.(weaponentity).misc_bulletcounter = 0; W_MachineGun_Attack_Auto(thiswep, actor, weaponentity, fire); } if(fire & 2) if(weapon_prepareattack(thiswep, actor, weaponentity, true, 0)) { - if(!thiswep.wr_checkammo2(thiswep, actor)) + if(!thiswep.wr_checkammo2(thiswep, actor, weaponentity)) if(!(actor.items & IT_UNLIMITED_WEAPON_AMMO)) { - W_SwitchWeapon_Force(actor, w_getbestweapon(actor)); + W_SwitchWeapon_Force(actor, w_getbestweapon(actor, weaponentity), weaponentity); w_ready(thiswep, actor, weaponentity, fire); return; } - W_DecreaseAmmo(thiswep, actor, WEP_CVAR(machinegun, burst_ammo)); + W_DecreaseAmmo(thiswep, actor, WEP_CVAR(machinegun, burst_ammo), weaponentity); - actor.misc_bulletcounter = WEP_CVAR(machinegun, burst) * -1; + actor.(weaponentity).misc_bulletcounter = WEP_CVAR(machinegun, burst) * -1; W_MachineGun_Attack_Burst(thiswep, actor, weaponentity, fire); } } @@ -298,7 +298,7 @@ METHOD(MachineGun, wr_think, void(entity thiswep, entity actor, .entity weaponen if(fire & 1) if(weapon_prepareattack(thiswep, actor, weaponentity, false, 0)) { - actor.misc_bulletcounter = 1; + actor.(weaponentity).misc_bulletcounter = 1; W_MachineGun_Attack(WEP_MACHINEGUN, WEP_MACHINEGUN.m_id, actor, weaponentity); // sets attack_finished weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(machinegun, sustained_refire), W_MachineGun_Attack_Frame); } @@ -306,13 +306,13 @@ METHOD(MachineGun, wr_think, void(entity thiswep, entity actor, .entity weaponen if((fire & 2) && WEP_CVAR(machinegun, first)) if(weapon_prepareattack(thiswep, actor, weaponentity, true, 0)) { - actor.misc_bulletcounter = 1; + actor.(weaponentity).misc_bulletcounter = 1; W_MachineGun_Attack(WEP_MACHINEGUN, WEP_MACHINEGUN.m_id | HITTYPE_SECONDARY, actor, weaponentity); // sets attack_finished weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR(machinegun, first_refire), w_ready); } } } -METHOD(MachineGun, wr_checkammo1, bool(entity thiswep, entity actor)) +METHOD(MachineGun, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity)) { float ammo_amount; if(WEP_CVAR(machinegun, mode) == 1) @@ -323,13 +323,13 @@ METHOD(MachineGun, wr_checkammo1, bool(entity thiswep, entity actor)) if(WEP_CVAR(machinegun, reload_ammo)) { if(WEP_CVAR(machinegun, mode) == 1) - ammo_amount += actor.(weapon_load[WEP_MACHINEGUN.m_id]) >= WEP_CVAR(machinegun, sustained_ammo); + ammo_amount += actor.(weaponentity).(weapon_load[WEP_MACHINEGUN.m_id]) >= WEP_CVAR(machinegun, sustained_ammo); else - ammo_amount += actor.(weapon_load[WEP_MACHINEGUN.m_id]) >= WEP_CVAR(machinegun, first_ammo); + ammo_amount += actor.(weaponentity).(weapon_load[WEP_MACHINEGUN.m_id]) >= WEP_CVAR(machinegun, first_ammo); } return ammo_amount; } -METHOD(MachineGun, wr_checkammo2, bool(entity thiswep, entity actor)) +METHOD(MachineGun, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity)) { float ammo_amount; if(WEP_CVAR(machinegun, mode) == 1) @@ -340,9 +340,9 @@ METHOD(MachineGun, wr_checkammo2, bool(entity thiswep, entity actor)) if(WEP_CVAR(machinegun, reload_ammo)) { if(WEP_CVAR(machinegun, mode) == 1) - ammo_amount += actor.(weapon_load[WEP_MACHINEGUN.m_id]) >= WEP_CVAR(machinegun, burst_ammo); + ammo_amount += actor.(weaponentity).(weapon_load[WEP_MACHINEGUN.m_id]) >= WEP_CVAR(machinegun, burst_ammo); else - ammo_amount += actor.(weapon_load[WEP_MACHINEGUN.m_id]) >= WEP_CVAR(machinegun, first_ammo); + ammo_amount += actor.(weaponentity).(weapon_load[WEP_MACHINEGUN.m_id]) >= WEP_CVAR(machinegun, first_ammo); } return ammo_amount; } diff --git a/qcsrc/common/weapons/weapon/minelayer.qc b/qcsrc/common/weapons/weapon/minelayer.qc index 7df6984baa..00f729b113 100644 --- a/qcsrc/common/weapons/weapon/minelayer.qc +++ b/qcsrc/common/weapons/weapon/minelayer.qc @@ -72,6 +72,7 @@ void W_MineLayer_Stick(entity this, entity to) entity newmine = spawn(); IL_PUSH(g_mines, newmine); + newmine.weaponentity_fld = this.weaponentity_fld; newmine.classname = this.classname; newmine.bot_dodge = this.bot_dodge; @@ -127,20 +128,20 @@ void W_MineLayer_Explode(entity this, entity directhitentity) RadiusDamage(this, this.realowner, WEP_CVAR(minelayer, damage), WEP_CVAR(minelayer, edgedamage), WEP_CVAR(minelayer, radius), NULL, NULL, WEP_CVAR(minelayer, force), this.projectiledeathtype, directhitentity); - if(PS(this.realowner).m_weapon == WEP_MINE_LAYER) + .entity weaponentity = this.weaponentity_fld; + if(this.realowner.(weaponentity).m_weapon == WEP_MINE_LAYER) { entity own = this.realowner; Weapon w = WEP_MINE_LAYER; - if(!w.wr_checkammo1(w, own)) + if(!w.wr_checkammo1(w, own, weaponentity)) { own.cnt = WEP_MINE_LAYER.m_id; - .entity weaponentity = this.weaponentity_fld; int slot = weaponslot(weaponentity); ATTACK_FINISHED(own, slot) = time; - PS(own).m_switchweapon = w_getbestweapon(own); + own.(weaponentity).m_switchweapon = w_getbestweapon(own, weaponentity); } } - this.realowner.minelayer_mines -= 1; + this.realowner.(weaponentity).minelayer_mines -= 1; delete(this); } @@ -159,20 +160,20 @@ void W_MineLayer_DoRemoteExplode(entity this) RadiusDamage(this, this.realowner, WEP_CVAR(minelayer, remote_damage), WEP_CVAR(minelayer, remote_edgedamage), WEP_CVAR(minelayer, remote_radius), NULL, NULL, WEP_CVAR(minelayer, remote_force), this.projectiledeathtype | HITTYPE_BOUNCE, NULL); - if(PS(this.realowner).m_weapon == WEP_MINE_LAYER) + .entity weaponentity = this.weaponentity_fld; + if(this.realowner.(weaponentity).m_weapon == WEP_MINE_LAYER) { entity own = this.realowner; Weapon w = WEP_MINE_LAYER; - if(!w.wr_checkammo1(w, own)) + if(!w.wr_checkammo1(w, own, weaponentity)) { own.cnt = WEP_MINE_LAYER.m_id; - .entity weaponentity = this.weaponentity_fld; int slot = weaponslot(weaponentity); ATTACK_FINISHED(own, slot) = time; - PS(own).m_switchweapon = w_getbestweapon(own); + own.(weaponentity).m_switchweapon = w_getbestweapon(own, weaponentity); } } - this.realowner.minelayer_mines -= 1; + this.realowner.(weaponentity).minelayer_mines -= 1; delete(this); } @@ -207,10 +208,10 @@ void W_MineLayer_ProximityExplode(entity this) W_MineLayer_Explode(this, NULL); } -int W_MineLayer_Count(entity e) +int W_MineLayer_Count(entity e, .entity weaponentity) { int minecount = 0; - IL_EACH(g_mines, it.realowner == e, + IL_EACH(g_mines, it.realowner == e && it.weaponentity_fld == weaponentity, { minecount += 1; }); @@ -274,7 +275,8 @@ void W_MineLayer_Think(entity this) } // remote detonation - if(PS(this.realowner).m_weapon == WEP_MINE_LAYER) + .entity weaponentity = this.weaponentity_fld; + if(this.realowner.(weaponentity).m_weapon == WEP_MINE_LAYER) if(!IS_DEAD(this.realowner)) if(this.minelayer_detonate) W_MineLayer_RemoteExplode(this); @@ -288,13 +290,16 @@ void W_MineLayer_Touch(entity this, entity toucher) if(WarpZone_Projectile_Touch(this, toucher)) { if(wasfreed(this)) - this.realowner.minelayer_mines -= 1; + { + .entity weaponentity = this.weaponentity_fld; + this.realowner.(weaponentity).minelayer_mines -= 1; + } return; } - if(toucher && IS_PLAYER(toucher) && !IS_DEAD(toucher)) + if((toucher && IS_PLAYER(toucher) && !IS_DEAD(toucher)) || toucher.owner == this.owner) { - // hit a player + // hit a player or other mine // don't stick } else @@ -328,7 +333,7 @@ void W_MineLayer_Attack(Weapon thiswep, entity actor, .entity weaponentity) // scan how many mines we placed, and return if we reached our limit if(WEP_CVAR(minelayer, limit)) { - if(actor.minelayer_mines >= WEP_CVAR(minelayer, limit)) + if(actor.(weaponentity).minelayer_mines >= WEP_CVAR(minelayer, limit)) { // the refire delay keeps this message from being spammed Send_Notification(NOTIF_ONE, actor, MSG_MULTI, WEAPON_MINELAYER_LIMIT, WEP_CVAR(minelayer, limit)); @@ -337,7 +342,7 @@ void W_MineLayer_Attack(Weapon thiswep, entity actor, .entity weaponentity) } } - W_DecreaseAmmo(thiswep, actor, WEP_CVAR(minelayer, ammo)); + W_DecreaseAmmo(thiswep, actor, WEP_CVAR(minelayer, ammo), weaponentity); W_SetupShot_ProjectileSize(actor, weaponentity, '-4 -4 -4', '4 4 4', false, 5, SND_MINE_FIRE, CH_WEAPON_A, WEP_CVAR(minelayer, damage)); Send_Effect(EFFECT_ROCKET_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1); @@ -394,14 +399,14 @@ void W_MineLayer_Attack(Weapon thiswep, entity actor, .entity weaponentity) MUTATOR_CALLHOOK(EditProjectile, actor, mine); - actor.minelayer_mines = W_MineLayer_Count(actor); + actor.(weaponentity).minelayer_mines = W_MineLayer_Count(actor, weaponentity); } -bool W_MineLayer_PlacedMines(entity this, bool detonate) +bool W_MineLayer_PlacedMines(entity this, .entity weaponentity, bool detonate) { bool minfound = false; - IL_EACH(g_mines, it.realowner == this, + IL_EACH(g_mines, it.realowner == this && it.weaponentity_fld == weaponentity, { if(detonate) { @@ -417,13 +422,13 @@ bool W_MineLayer_PlacedMines(entity this, bool detonate) return minfound; } -METHOD(MineLayer, wr_aim, void(entity thiswep, entity actor)) +METHOD(MineLayer, wr_aim, void(entity thiswep, entity actor, .entity weaponentity)) { // aim and decide to fire if appropriate - if(actor.minelayer_mines >= WEP_CVAR(minelayer, limit)) + if(actor.(weaponentity).minelayer_mines >= WEP_CVAR(minelayer, limit)) PHYS_INPUT_BUTTON_ATCK(actor) = false; else - PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, WEP_CVAR(minelayer, speed), 0, WEP_CVAR(minelayer, lifetime), false); + PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR(minelayer, speed), 0, WEP_CVAR(minelayer, lifetime), false); if(skill >= 2) // skill 0 and 1 bots won't detonate mines! { // decide whether to detonate mines @@ -503,10 +508,13 @@ METHOD(MineLayer, wr_aim, void(entity thiswep, entity actor)) } METHOD(MineLayer, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) { - if(autocvar_g_balance_minelayer_reload_ammo && actor.clip_load < WEP_CVAR(minelayer, ammo)) // forced reload + if(weaponslot(weaponentity) == 0) + actor.minelayer_mines = actor.(weaponentity).minelayer_mines; + + if(autocvar_g_balance_minelayer_reload_ammo && actor.(weaponentity).clip_load < WEP_CVAR(minelayer, ammo)) // forced reload { // not if we're holding the minelayer without enough ammo, but can detonate existing mines - if(!(W_MineLayer_PlacedMines(actor, false) && actor.(thiswep.ammo_field) < WEP_CVAR(minelayer, ammo))) { + if(!(W_MineLayer_PlacedMines(actor, weaponentity, false) && actor.(thiswep.ammo_field) < WEP_CVAR(minelayer, ammo))) { thiswep.wr_reload(thiswep, actor, weaponentity); } } @@ -521,25 +529,25 @@ METHOD(MineLayer, wr_think, void(entity thiswep, entity actor, .entity weaponent if(fire & 2) { - if(W_MineLayer_PlacedMines(actor, true)) + if(W_MineLayer_PlacedMines(actor, weaponentity, true)) sound(actor, CH_WEAPON_B, SND_MINE_DET, VOL_BASE, ATTN_NORM); } } -METHOD(MineLayer, wr_checkammo1, bool(entity thiswep, entity actor)) +METHOD(MineLayer, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity)) { //int slot = 0; // TODO: unhardcode // actually do // don't switch while placing a mine //if(ATTACK_FINISHED(actor, slot) <= time || PS(actor).m_weapon != WEP_MINE_LAYER) //{ float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR(minelayer, ammo); - ammo_amount += actor.(weapon_load[WEP_MINE_LAYER.m_id]) >= WEP_CVAR(minelayer, ammo); + ammo_amount += actor.(weaponentity).(weapon_load[WEP_MINE_LAYER.m_id]) >= WEP_CVAR(minelayer, ammo); return ammo_amount; //} //return true; } -METHOD(MineLayer, wr_checkammo2, bool(entity thiswep, entity actor)) +METHOD(MineLayer, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity)) { - if(W_MineLayer_PlacedMines(actor, false)) + if(W_MineLayer_PlacedMines(actor, weaponentity, false)) return true; else return false; @@ -547,6 +555,11 @@ METHOD(MineLayer, wr_checkammo2, bool(entity thiswep, entity actor)) METHOD(MineLayer, wr_resetplayer, void(entity thiswep, entity actor)) { actor.minelayer_mines = 0; + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + actor.(weaponentity).minelayer_mines = 0; + } } METHOD(MineLayer, wr_reload, void(entity thiswep, entity actor, .entity weaponentity)) { diff --git a/qcsrc/common/weapons/weapon/mortar.qc b/qcsrc/common/weapons/weapon/mortar.qc index 89ff5bbd88..56338da171 100644 --- a/qcsrc/common/weapons/weapon/mortar.qc +++ b/qcsrc/common/weapons/weapon/mortar.qc @@ -212,7 +212,7 @@ void W_Mortar_Grenade_Touch2(entity this, entity toucher) void W_Mortar_Attack(Weapon thiswep, entity actor, .entity weaponentity) { - W_DecreaseAmmo(thiswep, actor, WEP_CVAR_PRI(mortar, ammo)); + W_DecreaseAmmo(thiswep, actor, WEP_CVAR_PRI(mortar, ammo), weaponentity); W_SetupShot_ProjectileSize(actor, weaponentity, '-3 -3 -3', '3 3 3', false, 4, SND_GRENADE_FIRE, CH_WEAPON_A, WEP_CVAR_PRI(mortar, damage)); w_shotdir = v_forward; // no TrueAim for grenades please @@ -263,7 +263,7 @@ void W_Mortar_Attack2(Weapon thiswep, entity actor, .entity weaponentity) { entity gren; - W_DecreaseAmmo(thiswep, actor, WEP_CVAR_SEC(mortar, ammo)); + W_DecreaseAmmo(thiswep, actor, WEP_CVAR_SEC(mortar, ammo), weaponentity); W_SetupShot_ProjectileSize(actor, weaponentity, '-3 -3 -3', '3 3 3', false, 4, SND_GRENADE_FIRE, CH_WEAPON_A, WEP_CVAR_SEC(mortar, damage)); w_shotdir = v_forward; // no TrueAim for grenades please @@ -311,13 +311,13 @@ void W_Mortar_Attack2(Weapon thiswep, entity actor, .entity weaponentity) .float bot_secondary_grenademooth; -METHOD(Mortar, wr_aim, void(entity thiswep, entity actor)) +METHOD(Mortar, wr_aim, void(entity thiswep, entity actor, .entity weaponentity)) { PHYS_INPUT_BUTTON_ATCK(actor) = false; PHYS_INPUT_BUTTON_ATCK2(actor) = false; if(actor.bot_secondary_grenademooth == 0) // WEAPONTODO: merge this into using WEP_CVAR_BOTH { - if(bot_aim(actor, WEP_CVAR_PRI(mortar, speed), WEP_CVAR_PRI(mortar, speed_up), WEP_CVAR_PRI(mortar, lifetime), true)) + if(bot_aim(actor, weaponentity, WEP_CVAR_PRI(mortar, speed), WEP_CVAR_PRI(mortar, speed_up), WEP_CVAR_PRI(mortar, lifetime), true)) { PHYS_INPUT_BUTTON_ATCK(actor) = true; if(random() < 0.01) actor.bot_secondary_grenademooth = 1; @@ -325,7 +325,7 @@ METHOD(Mortar, wr_aim, void(entity thiswep, entity actor)) } else { - if(bot_aim(actor, WEP_CVAR_SEC(mortar, speed), WEP_CVAR_SEC(mortar, speed_up), WEP_CVAR_SEC(mortar, lifetime), true)) + if(bot_aim(actor, weaponentity, WEP_CVAR_SEC(mortar, speed), WEP_CVAR_SEC(mortar, speed_up), WEP_CVAR_SEC(mortar, lifetime), true)) { PHYS_INPUT_BUTTON_ATCK2(actor) = true; if(random() < 0.02) actor.bot_secondary_grenademooth = 0; @@ -350,7 +350,7 @@ METHOD(Mortar, wr_aim, void(entity thiswep, entity actor)) */ METHOD(Mortar, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) { - if(autocvar_g_balance_mortar_reload_ammo && actor.clip_load < min(WEP_CVAR_PRI(mortar, ammo), WEP_CVAR_SEC(mortar, ammo))) { // forced reload + if(autocvar_g_balance_mortar_reload_ammo && actor.(weaponentity).clip_load < min(WEP_CVAR_PRI(mortar, ammo), WEP_CVAR_SEC(mortar, ammo))) { // forced reload thiswep.wr_reload(thiswep, actor, weaponentity); } else if(fire & 1) { @@ -383,16 +383,16 @@ METHOD(Mortar, wr_think, void(entity thiswep, entity actor, .entity weaponentity } } } -METHOD(Mortar, wr_checkammo1, bool(entity thiswep, entity actor)) +METHOD(Mortar, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity)) { float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_PRI(mortar, ammo); - ammo_amount += actor.(weapon_load[WEP_MORTAR.m_id]) >= WEP_CVAR_PRI(mortar, ammo); + ammo_amount += actor.(weaponentity).(weapon_load[WEP_MORTAR.m_id]) >= WEP_CVAR_PRI(mortar, ammo); return ammo_amount; } -METHOD(Mortar, wr_checkammo2, bool(entity thiswep, entity actor)) +METHOD(Mortar, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity)) { float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_SEC(mortar, ammo); - ammo_amount += actor.(weapon_load[WEP_MORTAR.m_id]) >= WEP_CVAR_SEC(mortar, ammo); + ammo_amount += actor.(weaponentity).(weapon_load[WEP_MORTAR.m_id]) >= WEP_CVAR_SEC(mortar, ammo); return ammo_amount; } METHOD(Mortar, wr_reload, void(entity thiswep, entity actor, .entity weaponentity)) diff --git a/qcsrc/common/weapons/weapon/porto.qc b/qcsrc/common/weapons/weapon/porto.qc index 3e4654fcbb..8c5ade911c 100644 --- a/qcsrc/common/weapons/weapon/porto.qc +++ b/qcsrc/common/weapons/weapon/porto.qc @@ -66,7 +66,7 @@ void W_Porto_Success(entity this) delete(this); } -string W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vector velo); +string W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vector velo, .entity weaponentity); void W_Porto_Fail(entity this, float failhard) { if(this.realowner == NULL) @@ -95,7 +95,8 @@ void W_Porto_Fail(entity this, float failhard) tracetoss(this, this); if(vdist(trace_endpos - this.realowner.origin, <, 128)) { - W_ThrowNewWeapon(this.realowner, WEP_PORTO.m_id, 0, this.origin, this.velocity); + .entity weaponentity = this.weaponentity_fld; + W_ThrowNewWeapon(this.realowner, WEP_PORTO.m_id, 0, this.origin, this.velocity, weaponentity); Send_Notification(NOTIF_ONE, this.realowner, MSG_CENTER, CENTER_PORTO_FAILED); } } @@ -147,7 +148,7 @@ void W_Porto_Touch(entity this, entity toucher) sound(this, CH_SHOTS, SND_PORTO_UNSUPPORTED, VOL_BASE, ATTEN_NORM); delete(this); } - else if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SLICK || trace_dphitcontents & DPCONTENTS_PLAYERCLIP) + else if((trace_dphitq3surfaceflags & Q3SURFACEFLAG_SLICK) || (trace_dphitcontents & DPCONTENTS_PLAYERCLIP)) { spamsound(this, CH_SHOTS, SND(PORTO_BOUNCE), VOL_BASE, ATTEN_NORM); // just reflect @@ -254,6 +255,7 @@ void W_Porto_Attack(entity actor, .entity weaponentity, float type) //Send_Effect(EFFECT_GRENADE_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1); gren = new(porto); + gren.weaponentity_fld = weaponentity; gren.cnt = type; gren.owner = gren.realowner = actor; gren.playerid = actor.playerid; @@ -296,12 +298,12 @@ void W_Porto_Attack(entity actor, .entity weaponentity, float type) MUTATOR_CALLHOOK(EditProjectile, actor, gren); } -METHOD(PortoLaunch, wr_aim, void(entity thiswep, entity actor)) +METHOD(PortoLaunch, wr_aim, void(entity thiswep, entity actor, .entity weaponentity)) { PHYS_INPUT_BUTTON_ATCK(actor) = false; PHYS_INPUT_BUTTON_ATCK2(actor) = false; if(!WEP_CVAR(porto, secondary)) - if(bot_aim(actor, WEP_CVAR_PRI(porto, speed), 0, WEP_CVAR_PRI(porto, lifetime), false)) + if(bot_aim(actor, weaponentity, WEP_CVAR_PRI(porto, speed), 0, WEP_CVAR_PRI(porto, lifetime), false)) PHYS_INPUT_BUTTON_ATCK(actor) = true; } METHOD(PortoLaunch, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) @@ -328,27 +330,21 @@ METHOD(PortoLaunch, wr_think, void(entity thiswep, entity actor, .entity weapone } else { - if(actor.porto_v_angle_held) + if(actor.(weaponentity).porto_v_angle_held) { if(!(fire & 2)) - { - actor.porto_v_angle_held = 0; - - ClientData_Touch(actor); - } + actor.(weaponentity).porto_v_angle_held = 0; } else { if(fire & 2) { - actor.porto_v_angle = actor.v_angle; - actor.porto_v_angle_held = 1; - - ClientData_Touch(actor); + actor.(weaponentity).porto_v_angle = actor.v_angle; + actor.(weaponentity).porto_v_angle_held = 1; } } - if(actor.porto_v_angle_held) - makevectors(actor.porto_v_angle); // override the previously set angles + if(actor.(weaponentity).porto_v_angle_held) + makevectors(actor.(weaponentity).porto_v_angle); // override the previously set angles if(fire & 1) if(!actor.porto_current) @@ -360,20 +356,16 @@ METHOD(PortoLaunch, wr_think, void(entity thiswep, entity actor, .entity weapone } } } -METHOD(PortoLaunch, wr_checkammo1, bool(entity thiswep, entity this)) +METHOD(PortoLaunch, wr_checkammo1, bool(entity thiswep, entity this, .entity weaponentity)) { // always allow infinite ammo return true; } -METHOD(PortoLaunch, wr_checkammo2, bool(entity thiswep, entity this)) +METHOD(PortoLaunch, wr_checkammo2, bool(entity thiswep, entity this, .entity weaponentity)) { // always allow infinite ammo return true; } -METHOD(PortoLaunch, wr_setup, void(entity thiswep, entity actor)) -{ - actor.ammo_field = ammo_none; -} METHOD(PortoLaunch, wr_resetplayer, void(entity thiswep, entity actor)) { actor.porto_current = NULL; diff --git a/qcsrc/common/weapons/weapon/rifle.qc b/qcsrc/common/weapons/weapon/rifle.qc index 478a315253..37d8e0e23a 100644 --- a/qcsrc/common/weapons/weapon/rifle.qc +++ b/qcsrc/common/weapons/weapon/rifle.qc @@ -12,6 +12,7 @@ CLASS(Rifle, Weapon) #endif /* crosshair */ ATTRIB(Rifle, w_crosshair, string, "gfx/crosshairrifle"); /* crosshair */ ATTRIB(Rifle, w_crosshair_size, float, 0.6); +/* reticle */ ATTRIB(Rifle, w_reticle, string, "gfx/reticle_nex"); /* wepimg */ ATTRIB(Rifle, model2, string, "weaponrifle"); /* refname */ ATTRIB(Rifle, netname, string, "rifle"); /* wepname */ ATTRIB(Rifle, m_name, string, _("Rifle")); @@ -61,7 +62,7 @@ void W_Rifle_FireBullet(Weapon thiswep, .entity weaponentity, float pSpread, flo { float i; - W_DecreaseAmmo(thiswep, actor, pAmmo); + W_DecreaseAmmo(thiswep, actor, pAmmo, weaponentity); W_SetupShot(actor, weaponentity, true, 2, pSound, CH_WEAPON_A, pDamage * pShots); @@ -74,7 +75,7 @@ void W_Rifle_FireBullet(Weapon thiswep, .entity weaponentity, float pSpread, flo } for(i = 0; i < pShots; ++i) - fireBullet(actor, w_shotorg, w_shotdir, pSpread, pSolidPenetration, pDamage, pForce, deathtype, (pTracer ? EF_RED : EF_BLUE)); + fireBullet(actor, weaponentity, w_shotorg, w_shotdir, pSpread, pSolidPenetration, pDamage, pForce, deathtype, (pTracer ? EF_RED : EF_BLUE)); if(autocvar_g_casings >= 2) { @@ -101,14 +102,14 @@ void W_Rifle_BulletHail_Continue(Weapon thiswep, entity actor, .entity weaponent { float r, af; - Weapon sw = PS(actor).m_switchweapon; // make it not detect weapon changes as reason to abort firing + Weapon sw = actor.(weaponentity).m_switchweapon; // make it not detect weapon changes as reason to abort firing int slot = weaponslot(weaponentity); af = ATTACK_FINISHED(actor, slot); - PS(actor).m_switchweapon = PS(actor).m_weapon; + actor.(weaponentity).m_switchweapon = actor.(weaponentity).m_weapon; ATTACK_FINISHED(actor, slot) = time; r = weapon_prepareattack(thiswep, actor, weaponentity, actor.rifle_bullethail_frame == WFRAME_FIRE2, actor.rifle_bullethail_refire); - if(PS(actor).m_switchweapon == PS(actor).m_weapon) - PS(actor).m_switchweapon = sw; + if(actor.(weaponentity).m_switchweapon == actor.(weaponentity).m_weapon) + actor.(weaponentity).m_switchweapon = sw; if(r) { actor.rifle_bullethail_attackfunc(actor, weaponentity); @@ -142,7 +143,7 @@ void W_Rifle_BulletHail(entity actor, .entity weaponentity, float mode, void(ent .float bot_secondary_riflemooth; -METHOD(Rifle, wr_aim, void(entity thiswep, entity actor)) +METHOD(Rifle, wr_aim, void(entity thiswep, entity actor, .entity weaponentity)) { PHYS_INPUT_BUTTON_ATCK(actor) = false; PHYS_INPUT_BUTTON_ATCK2(actor) = false; @@ -150,7 +151,7 @@ METHOD(Rifle, wr_aim, void(entity thiswep, entity actor)) actor.bot_secondary_riflemooth = 0; if(actor.bot_secondary_riflemooth == 0) { - if(bot_aim(actor, 1000000, 0, 0.001, false)) + if(bot_aim(actor, weaponentity, 1000000, 0, 0.001, false)) { PHYS_INPUT_BUTTON_ATCK(actor) = true; if(random() < 0.01) actor.bot_secondary_riflemooth = 1; @@ -158,7 +159,7 @@ METHOD(Rifle, wr_aim, void(entity thiswep, entity actor)) } else { - if(bot_aim(actor, 1000000, 0, 0.001, false)) + if(bot_aim(actor, weaponentity, 1000000, 0, 0.001, false)) { PHYS_INPUT_BUTTON_ATCK2(actor) = true; if(random() < 0.03) actor.bot_secondary_riflemooth = 0; @@ -167,7 +168,7 @@ METHOD(Rifle, wr_aim, void(entity thiswep, entity actor)) } METHOD(Rifle, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) { - if(autocvar_g_balance_rifle_reload_ammo && actor.clip_load < min(WEP_CVAR_PRI(rifle, ammo), WEP_CVAR_SEC(rifle, ammo))) { // forced reload + if(autocvar_g_balance_rifle_reload_ammo && actor.(weaponentity).clip_load < min(WEP_CVAR_PRI(rifle, ammo), WEP_CVAR_SEC(rifle, ammo))) { // forced reload thiswep.wr_reload(thiswep, actor, weaponentity); } else { @@ -200,16 +201,16 @@ METHOD(Rifle, wr_think, void(entity thiswep, entity actor, .entity weaponentity, } } } -METHOD(Rifle, wr_checkammo1, bool(entity thiswep, entity actor)) +METHOD(Rifle, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity)) { float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_PRI(rifle, ammo); - ammo_amount += actor.(weapon_load[WEP_RIFLE.m_id]) >= WEP_CVAR_PRI(rifle, ammo); + ammo_amount += actor.(weaponentity).(weapon_load[WEP_RIFLE.m_id]) >= WEP_CVAR_PRI(rifle, ammo); return ammo_amount; } -METHOD(Rifle, wr_checkammo2, bool(entity thiswep, entity actor)) +METHOD(Rifle, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity)) { float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_SEC(rifle, ammo); - ammo_amount += actor.(weapon_load[WEP_RIFLE.m_id]) >= WEP_CVAR_SEC(rifle, ammo); + ammo_amount += actor.(weaponentity).(weapon_load[WEP_RIFLE.m_id]) >= WEP_CVAR_SEC(rifle, ammo); return ammo_amount; } METHOD(Rifle, wr_resetplayer, void(entity thiswep, entity actor)) @@ -241,6 +242,10 @@ METHOD(Rifle, wr_killmessage, Notification(entity thiswep)) return WEAPON_RIFLE_MURDER; } } +METHOD(Rifle, wr_zoom, bool(entity thiswep, entity actor)) +{ + return PHYS_INPUT_BUTTON_ATCK2(actor) && WEP_CVAR(rifle, secondary) == 0; +} #endif #ifdef CSQC @@ -262,11 +267,10 @@ METHOD(Rifle, wr_init, void(entity thiswep)) precache_pic("gfx/reticle_nex"); } } -METHOD(Rifle, wr_zoomreticle, bool(entity thiswep)) +METHOD(Rifle, wr_zoom, bool(entity thiswep, entity actor)) { if(button_zoom || zoomscript_caught) { - reticle_image = "gfx/reticle_nex"; return true; } else diff --git a/qcsrc/common/weapons/weapon/seeker.qc b/qcsrc/common/weapons/weapon/seeker.qc index 0e73adf2d3..20f5995e54 100644 --- a/qcsrc/common/weapons/weapon/seeker.qc +++ b/qcsrc/common/weapons/weapon/seeker.qc @@ -256,7 +256,7 @@ void W_Seeker_Missile_Animate(entity this) void W_Seeker_Fire_Missile(Weapon thiswep, entity actor, .entity weaponentity, vector f_diff, entity m_target) { - W_DecreaseAmmo(thiswep, actor, WEP_CVAR(seeker, missile_ammo)); + W_DecreaseAmmo(thiswep, actor, WEP_CVAR(seeker, missile_ammo), weaponentity); makevectors(actor.v_angle); W_SetupShot_ProjectileSize(actor, weaponentity, '-2 -2 -2', '2 2 2', false, 2, SND_SEEKER_FIRE, CH_WEAPON_A, 0); @@ -336,9 +336,9 @@ void W_Seeker_Fire_Flac(Weapon thiswep, entity actor, .entity weaponentity) vector f_diff; float c; - W_DecreaseAmmo(thiswep, actor, WEP_CVAR(seeker, flac_ammo)); + W_DecreaseAmmo(thiswep, actor, WEP_CVAR(seeker, flac_ammo), weaponentity); - c = actor.bulletcounter % 4; + c = actor.(weaponentity).bulletcounter % 4; switch(c) { case 0: @@ -393,11 +393,11 @@ void W_Seeker_Fire_Flac(Weapon thiswep, entity actor, .entity weaponentity) // ============================ // Begin: Tag and rocket controllers // ============================ -entity W_Seeker_Tagged_Info(entity isowner, entity istarget) +entity W_Seeker_Tagged_Info(entity isowner, .entity weaponentity, entity istarget) { entity tag; for(tag = NULL; (tag = find(tag, classname, "tag_tracker")); ) - if((tag.realowner == isowner) && (tag.tag_target == istarget)) + if((tag.realowner == isowner) && (tag.tag_target == istarget) && (tag.weaponentity_fld == weaponentity)) return tag; return NULL; @@ -433,7 +433,8 @@ void W_Seeker_Vollycontroller_Think(entity this) // TODO: Merge this with W_Seek this.cnt = this.cnt - 1; Weapon thiswep = WEP_SEEKER; - if((!(this.realowner.items & IT_UNLIMITED_AMMO) && this.realowner.(thiswep.ammo_field) < WEP_CVAR(seeker, missile_ammo)) || (this.cnt <= -1) || (IS_DEAD(this.realowner)) || (PS(this.realowner).m_switchweapon != WEP_SEEKER)) + .entity weaponentity = this.weaponentity_fld; + if((!(this.realowner.items & IT_UNLIMITED_AMMO) && this.realowner.(thiswep.ammo_field) < WEP_CVAR(seeker, missile_ammo)) || (this.cnt <= -1) || (IS_DEAD(this.realowner)) || (this.realowner.(weaponentity).m_switchweapon != WEP_SEEKER)) { delete(this); return; @@ -445,7 +446,6 @@ void W_Seeker_Vollycontroller_Think(entity this) // TODO: Merge this with W_Seek oldenemy = own.enemy; own.enemy = this.enemy; - .entity weaponentity = this.weaponentity_fld; c = own.cnt % 4; switch(c) @@ -470,8 +470,9 @@ void W_Seeker_Vollycontroller_Think(entity this) // TODO: Merge this with W_Seek void W_Seeker_Tracker_Think(entity this) { + .entity weaponentity = this.weaponentity_fld; // commit suicide if: You die OR target dies OR you switch away from the seeker OR commit suicide if lifetime is up - if((IS_DEAD(this.realowner)) || (IS_DEAD(this.tag_target)) || (PS(this.realowner).m_switchweapon != WEP_SEEKER) + if((IS_DEAD(this.realowner)) || (IS_DEAD(this.tag_target)) || (this.realowner.(weaponentity).m_switchweapon != WEP_SEEKER) || (time > this.tag_time + WEP_CVAR(seeker, tag_tracker_lifetime))) { if(this) @@ -526,7 +527,8 @@ void W_Seeker_Tag_Touch(entity this, entity toucher) if(toucher.takedamage == DAMAGE_AIM && !IS_DEAD(toucher)) { // check to see if this person is already tagged by me - entity tag = W_Seeker_Tagged_Info(this.realowner, toucher); + .entity weaponentity = this.weaponentity_fld; + entity tag = W_Seeker_Tagged_Info(this.realowner, weaponentity, toucher); if(tag != NULL) { @@ -572,7 +574,7 @@ void W_Seeker_Tag_Touch(entity this, entity toucher) void W_Seeker_Fire_Tag(Weapon thiswep, entity actor, .entity weaponentity) { - W_DecreaseAmmo(thiswep, actor, WEP_CVAR(seeker, tag_ammo)); + W_DecreaseAmmo(thiswep, actor, WEP_CVAR(seeker, tag_ammo), weaponentity); W_SetupShot_ProjectileSize(actor, weaponentity, '-2 -2 -2', '2 2 2', false, 2, SND_TAG_FIRE, CH_WEAPON_A, WEP_CVAR(seeker, missile_damage) * WEP_CVAR(seeker, missile_count)); @@ -613,19 +615,19 @@ void W_Seeker_Fire_Tag(Weapon thiswep, entity actor, .entity weaponentity) // Begin: Genereal weapon functions // ============================ -METHOD(Seeker, wr_aim, void(entity thiswep, entity actor)) +METHOD(Seeker, wr_aim, void(entity thiswep, entity actor, .entity weaponentity)) { if(WEP_CVAR(seeker, type) == 1) - if(W_Seeker_Tagged_Info(actor, actor.enemy) != NULL) - PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, WEP_CVAR(seeker, missile_speed_max), 0, WEP_CVAR(seeker, missile_lifetime), false); + if(W_Seeker_Tagged_Info(actor, weaponentity, actor.enemy) != NULL) + PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR(seeker, missile_speed_max), 0, WEP_CVAR(seeker, missile_lifetime), false); else - PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, WEP_CVAR(seeker, tag_speed), 0, WEP_CVAR(seeker, tag_lifetime), false); + PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, WEP_CVAR(seeker, tag_speed), 0, WEP_CVAR(seeker, tag_lifetime), false); else - PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, WEP_CVAR(seeker, tag_speed), 0, WEP_CVAR(seeker, tag_lifetime), false); + PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR(seeker, tag_speed), 0, WEP_CVAR(seeker, tag_lifetime), false); } METHOD(Seeker, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) { - if(autocvar_g_balance_seeker_reload_ammo && actor.clip_load < min(WEP_CVAR(seeker, missile_ammo), WEP_CVAR(seeker, tag_ammo))) { // forced reload + if(autocvar_g_balance_seeker_reload_ammo && actor.(weaponentity).clip_load < min(WEP_CVAR(seeker, missile_ammo), WEP_CVAR(seeker, tag_ammo))) { // forced reload thiswep.wr_reload(thiswep, actor, weaponentity); } else if(fire & 1) { @@ -667,33 +669,33 @@ METHOD(Seeker, wr_think, void(entity thiswep, entity actor, .entity weaponentity } } } -METHOD(Seeker, wr_checkammo1, bool(entity thiswep, entity actor)) +METHOD(Seeker, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity)) { float ammo_amount; if(WEP_CVAR(seeker, type) == 1) { ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR(seeker, missile_ammo); - ammo_amount += actor.(weapon_load[WEP_SEEKER.m_id]) >= WEP_CVAR(seeker, missile_ammo); + ammo_amount += actor.(weaponentity).(weapon_load[WEP_SEEKER.m_id]) >= WEP_CVAR(seeker, missile_ammo); } else { ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR(seeker, tag_ammo); - ammo_amount += actor.(weapon_load[WEP_SEEKER.m_id]) >= WEP_CVAR(seeker, tag_ammo); + ammo_amount += actor.(weaponentity).(weapon_load[WEP_SEEKER.m_id]) >= WEP_CVAR(seeker, tag_ammo); } return ammo_amount; } -METHOD(Seeker, wr_checkammo2, bool(entity thiswep, entity actor)) +METHOD(Seeker, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity)) { float ammo_amount; if(WEP_CVAR(seeker, type) == 1) { ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR(seeker, tag_ammo); - ammo_amount += actor.(weapon_load[WEP_SEEKER.m_id]) >= WEP_CVAR(seeker, tag_ammo); + ammo_amount += actor.(weaponentity).(weapon_load[WEP_SEEKER.m_id]) >= WEP_CVAR(seeker, tag_ammo); } else { ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR(seeker, flac_ammo); - ammo_amount += actor.(weapon_load[WEP_SEEKER.m_id]) >= WEP_CVAR(seeker, flac_ammo); + ammo_amount += actor.(weaponentity).(weapon_load[WEP_SEEKER.m_id]) >= WEP_CVAR(seeker, flac_ammo); } return ammo_amount; } diff --git a/qcsrc/common/weapons/weapon/shockwave.qc b/qcsrc/common/weapons/weapon/shockwave.qc index 28cbe69bbe..823aac11c1 100644 --- a/qcsrc/common/weapons/weapon/shockwave.qc +++ b/qcsrc/common/weapons/weapon/shockwave.qc @@ -695,23 +695,23 @@ void W_Shockwave_Attack(entity actor, .entity weaponentity) } } -METHOD(Shockwave, wr_aim, void(entity thiswep, entity actor)) +METHOD(Shockwave, wr_aim, void(entity thiswep, entity actor, .entity weaponentity)) { if(vdist(actor.origin - actor.enemy.origin, <=, WEP_CVAR(shockwave, melee_range))) - { PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, 1000000, 0, 0.001, false); } + { PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false); } else - { PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, 1000000, 0, 0.001, false); } + { PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false); } } METHOD(Shockwave, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) { if(fire & 1) { - if(time >= actor.shockwave_blasttime) // handle refire separately so the secondary can be fired straight after a primary + if(time >= actor.(weaponentity).shockwave_blasttime) // handle refire separately so the secondary can be fired straight after a primary { if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(shockwave, blast_animtime))) { W_Shockwave_Attack(actor, weaponentity); - actor.shockwave_blasttime = time + WEP_CVAR(shockwave, blast_refire) * W_WeaponRateFactor(actor); + actor.(weaponentity).shockwave_blasttime = time + WEP_CVAR(shockwave, blast_refire) * W_WeaponRateFactor(actor); weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(shockwave, blast_animtime), w_ready); } } @@ -726,11 +726,11 @@ METHOD(Shockwave, wr_think, void(entity thiswep, entity actor, .entity weaponent } } } -METHOD(Shockwave, wr_checkammo1, bool(entity thiswep, entity actor)) +METHOD(Shockwave, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity)) { return true; // infinite ammo } -METHOD(Shockwave, wr_checkammo2, bool(entity thiswep, entity actor)) +METHOD(Shockwave, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity)) { // shockwave has infinite ammo return true; diff --git a/qcsrc/common/weapons/weapon/shotgun.qc b/qcsrc/common/weapons/weapon/shotgun.qc index 9ae0c6069a..f6d730fcb1 100644 --- a/qcsrc/common/weapons/weapon/shotgun.qc +++ b/qcsrc/common/weapons/weapon/shotgun.qc @@ -61,11 +61,11 @@ spawnfunc(weapon_shotgun) { weapon_defaultspawnfunc(this, WEP_SHOTGUN); } void W_Shotgun_Attack(Weapon thiswep, entity actor, .entity weaponentity, float isprimary) { - W_DecreaseAmmo(thiswep, actor, WEP_CVAR_PRI(shotgun, ammo)); + W_DecreaseAmmo(thiswep, actor, WEP_CVAR_PRI(shotgun, ammo), weaponentity); W_SetupShot(actor, weaponentity, true, 5, SND_SHOTGUN_FIRE, ((isprimary) ? CH_WEAPON_A : CH_WEAPON_SINGLE), WEP_CVAR_PRI(shotgun, damage) * WEP_CVAR_PRI(shotgun, bullets)); for(int sc = 0;sc < WEP_CVAR_PRI(shotgun, bullets);sc = sc + 1) - fireBullet(actor, w_shotorg, w_shotdir, WEP_CVAR_PRI(shotgun, spread), WEP_CVAR_PRI(shotgun, solidpenetration), WEP_CVAR_PRI(shotgun, damage), WEP_CVAR_PRI(shotgun, force), WEP_SHOTGUN.m_id, 0); + fireBullet(actor, weaponentity, w_shotorg, w_shotdir, WEP_CVAR_PRI(shotgun, spread), WEP_CVAR_PRI(shotgun, solidpenetration), WEP_CVAR_PRI(shotgun, damage), WEP_CVAR_PRI(shotgun, force), WEP_SHOTGUN.m_id, 0); Send_Effect(EFFECT_SHOTGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, WEP_CVAR_PRI(shotgun, ammo)); @@ -199,10 +199,10 @@ void W_Shotgun_Attack2(Weapon thiswep, entity actor, .entity weaponentity, int f // alternate secondary weapon frames void W_Shotgun_Attack3_Frame2(Weapon thiswep, entity actor, .entity weaponentity, int fire) { - if (!thiswep.wr_checkammo2(thiswep, actor)) + if (!thiswep.wr_checkammo2(thiswep, actor, weaponentity)) if (!(actor.items & IT_UNLIMITED_WEAPON_AMMO)) { - W_SwitchWeapon_Force(actor, w_getbestweapon(actor)); + W_SwitchWeapon_Force(actor, w_getbestweapon(actor, weaponentity), weaponentity); w_ready(thiswep, actor, weaponentity, fire); return; } @@ -213,10 +213,10 @@ void W_Shotgun_Attack3_Frame2(Weapon thiswep, entity actor, .entity weaponentity } void W_Shotgun_Attack3_Frame1(Weapon thiswep, entity actor, .entity weaponentity, int fire) { - if (!thiswep.wr_checkammo2(thiswep, actor)) + if (!thiswep.wr_checkammo2(thiswep, actor, weaponentity)) if (!(actor.items & IT_UNLIMITED_WEAPON_AMMO)) { - W_SwitchWeapon_Force(actor, w_getbestweapon(actor)); + W_SwitchWeapon_Force(actor, w_getbestweapon(actor, weaponentity), weaponentity); w_ready(thiswep, actor, weaponentity, fire); return; } @@ -225,18 +225,18 @@ void W_Shotgun_Attack3_Frame1(Weapon thiswep, entity actor, .entity weaponentity weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_SEC(shotgun, alt_animtime), W_Shotgun_Attack3_Frame2); } -.float shotgun_primarytime[MAX_WEAPONSLOTS]; +.float shotgun_primarytime; -METHOD(Shotgun, wr_aim, void(entity thiswep, entity actor)) +METHOD(Shotgun, wr_aim, void(entity thiswep, entity actor, .entity weaponentity)) { if(vdist(actor.origin - actor.enemy.origin, <=, WEP_CVAR_SEC(shotgun, melee_range))) - PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, 1000000, 0, 0.001, false); + PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false); else - PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, 1000000, 0, 0.001, false); + PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false); } METHOD(Shotgun, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) { - if(WEP_CVAR(shotgun, reload_ammo) && actor.clip_load < WEP_CVAR_PRI(shotgun, ammo)) // forced reload + if(WEP_CVAR(shotgun, reload_ammo) && actor.(weaponentity).clip_load < WEP_CVAR_PRI(shotgun, ammo)) // forced reload { // don't force reload an empty shotgun if its melee attack is active if(WEP_CVAR(shotgun, secondary) < 2) { @@ -247,32 +247,30 @@ METHOD(Shotgun, wr_think, void(entity thiswep, entity actor, .entity weaponentit { if(fire & 1) { - int slot = weaponslot(weaponentity); - if(time >= actor.shotgun_primarytime[slot]) // handle refire separately so the secondary can be fired straight after a primary + if(time >= actor.(weaponentity).shotgun_primarytime) // handle refire separately so the secondary can be fired straight after a primary { if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(shotgun, animtime))) { W_Shotgun_Attack(thiswep, actor, weaponentity, true); - actor.shotgun_primarytime[slot] = time + WEP_CVAR_PRI(shotgun, refire) * W_WeaponRateFactor(actor); + actor.(weaponentity).shotgun_primarytime = time + WEP_CVAR_PRI(shotgun, refire) * W_WeaponRateFactor(actor); weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(shotgun, animtime), w_ready); } } } else if((fire & 2) && WEP_CVAR(shotgun, secondary) == 2) { - int slot = weaponslot(weaponentity); - if(time >= actor.shotgun_primarytime[slot]) // handle refire separately so the secondary can be fired straight after a primary + if(time >= actor.(weaponentity).shotgun_primarytime) // handle refire separately so the secondary can be fired straight after a primary { if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_SEC(shotgun, alt_animtime))) { W_Shotgun_Attack(thiswep, actor, weaponentity, false); - actor.shotgun_primarytime[slot] = time + WEP_CVAR_SEC(shotgun, alt_refire) * W_WeaponRateFactor(actor); + actor.(weaponentity).shotgun_primarytime = time + WEP_CVAR_SEC(shotgun, alt_refire) * W_WeaponRateFactor(actor); weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_SEC(shotgun, alt_animtime), W_Shotgun_Attack3_Frame1); } } } } - if(actor.clip_load >= 0) // we are not currently reloading + if(actor.(weaponentity).clip_load >= 0) // we are not currently reloading if(WEP_CVAR(shotgun, secondary) == 1) if(((fire & 1) && actor.(thiswep.ammo_field) <= 0 && !(actor.items & IT_UNLIMITED_WEAPON_AMMO)) || (fire & 2)) if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(shotgun, refire))) @@ -281,17 +279,13 @@ METHOD(Shotgun, wr_think, void(entity thiswep, entity actor, .entity weaponentit weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, 0, W_Shotgun_Attack2); } } -METHOD(Shotgun, wr_setup, void(entity thiswep, entity actor)) -{ - actor.ammo_field = ammo_none; -} -METHOD(Shotgun, wr_checkammo1, bool(entity thiswep, entity actor)) +METHOD(Shotgun, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity)) { float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_PRI(shotgun, ammo); - ammo_amount += actor.(weapon_load[WEP_SHOTGUN.m_id]) >= WEP_CVAR_PRI(shotgun, ammo); + ammo_amount += actor.(weaponentity).(weapon_load[WEP_SHOTGUN.m_id]) >= WEP_CVAR_PRI(shotgun, ammo); return ammo_amount; } -METHOD(Shotgun, wr_checkammo2, bool(entity thiswep, entity actor)) +METHOD(Shotgun, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity)) { if(IS_BOT_CLIENT(actor)) if(vdist(actor.origin - actor.enemy.origin, >, WEP_CVAR_SEC(shotgun, melee_range))) @@ -302,7 +296,7 @@ METHOD(Shotgun, wr_checkammo2, bool(entity thiswep, entity actor)) case 2: // secondary triple shot { float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_PRI(shotgun, ammo); - ammo_amount += actor.(weapon_load[WEP_SHOTGUN.m_id]) >= WEP_CVAR_PRI(shotgun, ammo); + ammo_amount += actor.(weaponentity).(weapon_load[WEP_SHOTGUN.m_id]) >= WEP_CVAR_PRI(shotgun, ammo); return ammo_amount; } default: return false; // secondary unavailable diff --git a/qcsrc/common/weapons/weapon/tuba.qc b/qcsrc/common/weapons/weapon/tuba.qc index e3e1f5228d..09d050833b 100644 --- a/qcsrc/common/weapons/weapon/tuba.qc +++ b/qcsrc/common/weapons/weapon/tuba.qc @@ -47,7 +47,6 @@ REGISTER_WEAPON(TUBA, tuba, NEW(Tuba)); .entity tuba_note; .float tuba_smoketime; -.float tuba_instrument; #define MAX_TUBANOTES 32 .float tuba_lastnotes_last; @@ -56,23 +55,23 @@ REGISTER_WEAPON(TUBA, tuba, NEW(Tuba)); spawnfunc(weapon_tuba) { weapon_defaultspawnfunc(this, WEP_TUBA); } -bool W_Tuba_HasPlayed(entity pl, string melody, int instrument, bool ignorepitch, float mintempo, float maxtempo) +bool W_Tuba_HasPlayed(entity pl, .entity weaponentity, string melody, int instrument, bool ignorepitch, float mintempo, float maxtempo) { float i, j, mmin, mmax, nolength; float n = tokenize_console(melody); - if(n > pl.tuba_lastnotes_cnt) + if(n > pl.(weaponentity).tuba_lastnotes_cnt) return false; float pitchshift = 0; if(instrument >= 0) - if(pl.tuba_instrument != instrument) + if(pl.(weaponentity).tuba_instrument != instrument) return false; // verify notes... nolength = false; for(i = 0; i < n; ++i) { - vector v = pl.(tuba_lastnotes[(pl.tuba_lastnotes_last - i + MAX_TUBANOTES) % MAX_TUBANOTES]); + vector v = pl.(weaponentity).(tuba_lastnotes[(pl.(weaponentity).tuba_lastnotes_last - i + MAX_TUBANOTES) % MAX_TUBANOTES]); float ai = stof(argv(n - i - 1)); float np = floor(ai); if(ai == np) @@ -109,13 +108,13 @@ bool W_Tuba_HasPlayed(entity pl, string melody, int instrument, bool ignorepitch for(i = 0; i < n; ++i) { - vector vi = pl.(tuba_lastnotes[(pl.tuba_lastnotes_last - i + MAX_TUBANOTES) % MAX_TUBANOTES]); + vector vi = pl.(weaponentity).(tuba_lastnotes[(pl.(weaponentity).tuba_lastnotes_last - i + MAX_TUBANOTES) % MAX_TUBANOTES]); float ai = stof(argv(n - i - 1)); ti -= 1 / (ai - floor(ai)); float tj = ti; for(j = i+1; j < n; ++j) { - vector vj = pl.(tuba_lastnotes[(pl.tuba_lastnotes_last - j + MAX_TUBANOTES) % MAX_TUBANOTES]); + vector vj = pl.(weaponentity).(tuba_lastnotes[(pl.(weaponentity).tuba_lastnotes_last - j + MAX_TUBANOTES) % MAX_TUBANOTES]); float aj = stof(argv(n - j - 1)); tj -= (aj - floor(aj)); @@ -142,7 +141,7 @@ bool W_Tuba_HasPlayed(entity pl, string melody, int instrument, bool ignorepitch return false; } - pl.tuba_lastnotes_cnt = 0; + pl.(weaponentity).tuba_lastnotes_cnt = 0; return true; } @@ -154,12 +153,13 @@ void W_Tuba_NoteOff(entity this) // on: this.spawnshieldtime // off: time // note: this.cnt - if (actor.tuba_note == this) + .entity weaponentity = this.weaponentity_fld; + if (actor.(weaponentity).tuba_note == this) { - actor.tuba_lastnotes_last = (actor.tuba_lastnotes_last + 1) % MAX_TUBANOTES; - actor.(tuba_lastnotes[actor.tuba_lastnotes_last]) = eX * this.spawnshieldtime + eY * time + eZ * this.cnt; - actor.tuba_note = NULL; - actor.tuba_lastnotes_cnt = bound(0, actor.tuba_lastnotes_cnt + 1, MAX_TUBANOTES); + actor.(weaponentity).tuba_lastnotes_last = (actor.(weaponentity).tuba_lastnotes_last + 1) % MAX_TUBANOTES; + actor.(weaponentity).(tuba_lastnotes[actor.(weaponentity).tuba_lastnotes_last]) = eX * this.spawnshieldtime + eY * time + eZ * this.cnt; + actor.(weaponentity).tuba_note = NULL; + actor.(weaponentity).tuba_lastnotes_cnt = bound(0, actor.(weaponentity).tuba_lastnotes_cnt + 1, MAX_TUBANOTES); string s = trigger_magicear_processmessage_forallears(actor, 0, NULL, string_null); if (s != "") @@ -320,47 +320,49 @@ void W_Tuba_NoteOn(entity actor, .entity weaponentity, float hittype) n = W_Tuba_GetNote(actor, hittype); hittype = 0; - if(actor.tuba_instrument & 1) + if(actor.(weaponentity).tuba_instrument & 1) hittype |= HITTYPE_SECONDARY; - if(actor.tuba_instrument & 2) + if(actor.(weaponentity).tuba_instrument & 2) hittype |= HITTYPE_BOUNCE; - if(actor.tuba_note) + if(actor.(weaponentity).tuba_note) { - if(actor.tuba_note.cnt != n || actor.tuba_note.tuba_instrument != actor.tuba_instrument) + if(actor.(weaponentity).tuba_note.cnt != n || actor.(weaponentity).tuba_note.tuba_instrument != actor.(weaponentity).tuba_instrument) { - W_Tuba_NoteOff(actor.tuba_note); + W_Tuba_NoteOff(actor.(weaponentity).tuba_note); } } - if(!actor.tuba_note) + if(!actor.(weaponentity).tuba_note) { - actor.tuba_note = new(tuba_note); - actor.tuba_note.owner = actor.tuba_note.realowner = actor; - actor.tuba_note.cnt = n; - actor.tuba_note.tuba_instrument = actor.tuba_instrument; - setthink(actor.tuba_note, W_Tuba_NoteThink); - actor.tuba_note.nextthink = time; - actor.tuba_note.spawnshieldtime = time; - Net_LinkEntity(actor.tuba_note, false, 0, W_Tuba_NoteSendEntity); + entity note = new(tuba_note); + note.weaponentity_fld = weaponentity; + actor.(weaponentity).tuba_note = note; + note.owner = note.realowner = actor; + note.cnt = n; + note.tuba_instrument = actor.(weaponentity).tuba_instrument; + setthink(note, W_Tuba_NoteThink); + note.nextthink = time; + note.spawnshieldtime = time; + Net_LinkEntity(note, false, 0, W_Tuba_NoteSendEntity); } - actor.tuba_note.teleport_time = time + WEP_CVAR(tuba, refire) * 2 * W_WeaponRateFactor(actor); // so it can get prolonged safely + actor.(weaponentity).tuba_note.teleport_time = time + WEP_CVAR(tuba, refire) * 2 * W_WeaponRateFactor(actor); // so it can get prolonged safely //sound(actor, c, TUBA_NOTE(n), bound(0, VOL_BASE * cvar("g_balance_tuba_volume"), 1), autocvar_g_balance_tuba_attenuation); RadiusDamage(actor, actor, WEP_CVAR(tuba, damage), WEP_CVAR(tuba, edgedamage), WEP_CVAR(tuba, radius), NULL, NULL, WEP_CVAR(tuba, force), hittype | WEP_TUBA.m_id, NULL); o = gettaginfo(actor.exteriorweaponentity, 0); - if(time > actor.tuba_smoketime) + if(time > actor.(weaponentity).tuba_smoketime) { Send_Effect(EFFECT_SMOKE_RING, o + v_up * 45 + v_right * -6 + v_forward * 8, v_up * 100, 1); - actor.tuba_smoketime = time + 0.25; + actor.(weaponentity).tuba_smoketime = time + 0.25; } } #endif #ifdef SVQC -METHOD(Tuba, wr_aim, void(Tuba this, entity actor)) +METHOD(Tuba, wr_aim, void(Tuba this, entity actor, .entity weaponentity)) { // bots cannot play the Tuba well yet // I think they should start with the recorder first @@ -387,73 +389,40 @@ METHOD(Tuba, wr_think, void(Tuba this, entity actor, .entity weaponentity, int f W_Tuba_NoteOn(actor, weaponentity, HITTYPE_SECONDARY); weapon_thinkf(actor, weaponentity, WFRAME_IDLE, WEP_CVAR(tuba, animtime), w_ready); } - if (actor.tuba_note) + if (actor.(weaponentity).tuba_note) { if (!(fire & 1) && !(fire & 2)) { - W_Tuba_NoteOff(actor.tuba_note); + W_Tuba_NoteOff(actor.(weaponentity).tuba_note); } } } -void tuba_instrument_send(entity this, int instr); -METHOD(Tuba, wr_setup, void(Tuba this, entity actor)) +METHOD(Tuba, wr_setup, void(Tuba this, entity actor, .entity weaponentity)) { - actor.ammo_field = ammo_none; - actor.tuba_instrument = 0; - tuba_instrument_send(actor, actor.tuba_instrument); + actor.(weaponentity).tuba_instrument = 0; } -#endif -REGISTER_NET_S2C(tuba_instrument) -#ifdef CSQC -NET_HANDLE(tuba_instrument, bool) -{ - int i = ReadByte(); - return = true; - string s = (i == 0) ? "tuba" : - (i == 1) ? "akordeon" : - "kleinbottle" ; - viewmodel.tuba_instrument = i; - CL_WeaponEntity_SetModel(viewmodel, s, true); -} -#endif -#ifdef SVQC -void tuba_instrument_send(entity this, int instr) -{ - msg_entity = this; - if (!IS_REAL_CLIENT(this)) - return; - int chan = MSG_ONE; - WriteHeader(chan, tuba_instrument); - WriteByte(chan, instr); -} -SPECTATE_COPY() -{ - if (this.tuba_instrument != spectatee.tuba_instrument) - tuba_instrument_send(this, this.tuba_instrument = spectatee.tuba_instrument); -} METHOD(Tuba, wr_reload, void(Tuba this, entity actor, .entity weaponentity)) { // switch to alternate instruments :) if (actor.(weaponentity).state == WS_READY) { - switch (actor.tuba_instrument) + switch (actor.(weaponentity).tuba_instrument) { case 0: - actor.tuba_instrument = 1; - actor.weaponname = "akordeon"; + actor.(weaponentity).tuba_instrument = 1; + actor.(weaponentity).weaponname = "akordeon"; break; case 1: - actor.tuba_instrument = 2; - actor.weaponname = "kleinbottle"; + actor.(weaponentity).tuba_instrument = 2; + actor.(weaponentity).weaponname = "kleinbottle"; break; case 2: - actor.tuba_instrument = 0; - actor.weaponname = "tuba"; + actor.(weaponentity).tuba_instrument = 0; + actor.(weaponentity).weaponname = "tuba"; break; } - tuba_instrument_send(actor, actor.tuba_instrument); W_SetupShot(actor, weaponentity, false, 0, SND_Null, 0, 0); Send_Effect(EFFECT_TELEPORT, w_shotorg, '0 0 0', 1); actor.(weaponentity).state = WS_INUSE; @@ -465,8 +434,8 @@ METHOD(Tuba, wr_reload, void(Tuba this, entity actor, .entity weaponentity)) #ifdef SVQC // infinite ammo -METHOD(Tuba, wr_checkammo1, bool(Tuba this, entity actor)) { return true; } -METHOD(Tuba, wr_checkammo2, bool(Tuba this, entity actor)) { return true; } +METHOD(Tuba, wr_checkammo1, bool(Tuba this, entity actor, .entity weaponentity)) { return true; } +METHOD(Tuba, wr_checkammo2, bool(Tuba this, entity actor, .entity weaponentity)) { return true; } METHOD(Tuba, wr_suicidemessage, Notification(Tuba this)) { diff --git a/qcsrc/common/weapons/weapon/vaporizer.qc b/qcsrc/common/weapons/weapon/vaporizer.qc index e11e4d8d52..7866f1b828 100644 --- a/qcsrc/common/weapons/weapon/vaporizer.qc +++ b/qcsrc/common/weapons/weapon/vaporizer.qc @@ -12,6 +12,7 @@ CLASS(Vaporizer, Weapon) #endif /* crosshair */ ATTRIB(Vaporizer, w_crosshair, string, "gfx/crosshairminstanex"); /* crosshair */ ATTRIB(Vaporizer, w_crosshair_size, float, 0.6); +/* reticle */ ATTRIB(Vaporizer, w_reticle, string, "gfx/reticle_nex"); /* wepimg */ ATTRIB(Vaporizer, model2, string, "weaponminstanex"); /* refname */ ATTRIB(Vaporizer, netname, string, "vaporizer"); /* wepname */ ATTRIB(Vaporizer, m_name, string, _("Vaporizer")); @@ -193,7 +194,7 @@ void W_Vaporizer_Attack(Weapon thiswep, entity actor, .entity weaponentity) yoda = 0; damage_goodhits = 0; - FireRailgunBullet(actor, w_shotorg, w_shotorg + w_shotdir * MAX_SHOT_DISTANCE, vaporizer_damage, 800, 0, 0, 0, 0, WEP_VAPORIZER.m_id); + FireRailgunBullet(actor, weaponentity, w_shotorg, w_shotorg + w_shotdir * MAX_SHOT_DISTANCE, vaporizer_damage, 800, 0, 0, 0, 0, WEP_VAPORIZER.m_id); // do this now, as goodhits is disabled below SendCSQCVaporizerBeamParticle(actor, damage_goodhits); @@ -212,7 +213,7 @@ void W_Vaporizer_Attack(Weapon thiswep, entity actor, .entity weaponentity) if(!(trace_dphitq3surfaceflags & (Q3SURFACEFLAG_SKY | Q3SURFACEFLAG_NOIMPACT))) W_RocketMinsta_Explosion(actor, trace_endpos); - W_DecreaseAmmo(thiswep, actor, ((g_instagib) ? 1 : WEP_CVAR_PRI(vaporizer, ammo))); + W_DecreaseAmmo(thiswep, actor, ((g_instagib) ? 1 : WEP_CVAR_PRI(vaporizer, ammo)), weaponentity); } void W_RocketMinsta_Laser_Explode (entity this) @@ -253,10 +254,10 @@ void W_RocketMinsta_Attack2(entity actor, .entity weaponentity) float spread = autocvar_g_rm_laser_spread; float rndspread = autocvar_g_rm_laser_spread_random; - Weapon w = PS(actor).m_weapon; - PS(actor).m_weapon = WEP_ELECTRO; + Weapon w = actor.(weaponentity).m_weapon; + actor.(weaponentity).m_weapon = WEP_ELECTRO; W_SetupShot_ProjectileSize (actor, weaponentity, '0 0 -3', '0 0 -3', false, 2, SND_CRYLINK_FIRE, CH_WEAPON_A, autocvar_g_rm_laser_damage); - PS(actor).m_weapon = w; + actor.(weaponentity).m_weapon = w; Send_Effect(EFFECT_ELECTRO_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1); @@ -307,10 +308,10 @@ void W_RocketMinsta_Attack3 (entity actor, .entity weaponentity) float counter = 0; float total = 1; - Weapon w = PS(actor).m_weapon; - PS(actor).m_weapon = WEP_ELECTRO; + Weapon w = actor.(weaponentity).m_weapon; + actor.(weaponentity).m_weapon = WEP_ELECTRO; W_SetupShot_ProjectileSize (actor, weaponentity, '0 0 -3', '0 0 -3', false, 2, SND_ELECTRO_FIRE2, CH_WEAPON_A, autocvar_g_rm_laser_damage); - PS(actor).m_weapon = w; + actor.(weaponentity).m_weapon = w; Send_Effect(EFFECT_ELECTRO_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1); @@ -351,20 +352,20 @@ void W_RocketMinsta_Attack3 (entity actor, .entity weaponentity) } } -METHOD(Vaporizer, wr_aim, void(entity thiswep, entity actor)) +METHOD(Vaporizer, wr_aim, void(entity thiswep, entity actor, .entity weaponentity)) { if(actor.(thiswep.ammo_field) > 0) - PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, 1000000, 0, 1, false); + PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, 1000000, 0, 1, false); else - PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, WEP_CVAR_SEC(vaporizer, speed), 0, WEP_CVAR_SEC(vaporizer, lifetime), false); // WEAPONTODO: replace with proper vaporizer cvars + PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, WEP_CVAR_SEC(vaporizer, speed), 0, WEP_CVAR_SEC(vaporizer, lifetime), false); // WEAPONTODO: replace with proper vaporizer cvars } METHOD(Vaporizer, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) { float vaporizer_ammo = ((g_instagib) ? 1 : WEP_CVAR_PRI(vaporizer, ammo)); // if the laser uses load, we also consider its ammo for reloading - if(WEP_CVAR(vaporizer, reload_ammo) && WEP_CVAR_SEC(vaporizer, ammo) && actor.clip_load < min(vaporizer_ammo, WEP_CVAR_SEC(vaporizer, ammo))) { // forced reload + if(WEP_CVAR(vaporizer, reload_ammo) && WEP_CVAR_SEC(vaporizer, ammo) && actor.(weaponentity).clip_load < min(vaporizer_ammo, WEP_CVAR_SEC(vaporizer, ammo))) { // forced reload thiswep.wr_reload(thiswep, actor, weaponentity); - } else if(WEP_CVAR(vaporizer, reload_ammo) && actor.clip_load < vaporizer_ammo) { // forced reload + } else if(WEP_CVAR(vaporizer, reload_ammo) && actor.(weaponentity).clip_load < vaporizer_ammo) { // forced reload thiswep.wr_reload(thiswep, actor, weaponentity); } if((fire & 1) && (actor.ammo_cells || !autocvar_g_rm) && !forbidWeaponUse(actor)) @@ -380,36 +381,36 @@ METHOD(Vaporizer, wr_think, void(entity thiswep, entity actor, .entity weaponent if((autocvar_g_rm && autocvar_g_rm_laser) || autocvar_g_rm_laser == 2) { bool rapid = autocvar_g_rm_laser_rapid; - if(actor.jump_interval <= time && !actor.held_down) + if(actor.(weaponentity).jump_interval <= time && !actor.(weaponentity).held_down) { if(rapid) - actor.held_down = true; - actor.jump_interval = time + autocvar_g_rm_laser_refire; - actor.jump_interval2 = time + autocvar_g_rm_laser_rapid_delay; + actor.(weaponentity).held_down = true; + actor.(weaponentity).jump_interval = time + autocvar_g_rm_laser_refire; + actor.(weaponentity).jump_interval2 = time + autocvar_g_rm_laser_rapid_delay; damage_goodhits = 0; W_RocketMinsta_Attack2(actor, weaponentity); } - else if(rapid && actor.jump_interval2 <= time && actor.held_down) + else if(rapid && actor.(weaponentity).jump_interval2 <= time && actor.(weaponentity).held_down) { - actor.jump_interval2 = time + autocvar_g_rm_laser_rapid_refire; + actor.(weaponentity).jump_interval2 = time + autocvar_g_rm_laser_rapid_refire; damage_goodhits = 0; W_RocketMinsta_Attack3(actor, weaponentity); //weapon_thinkf(actor, WFRAME_FIRE2, autocvar_g_rm_laser_rapid_animtime, w_ready); } } - else if (actor.jump_interval <= time) + else if (actor.(weaponentity).jump_interval <= time) { // handle refire manually, so that primary and secondary can be fired without conflictions (important for instagib) - actor.jump_interval = time + WEP_CVAR_SEC(vaporizer, refire) * W_WeaponRateFactor(actor); + actor.(weaponentity).jump_interval = time + WEP_CVAR_SEC(vaporizer, refire) * W_WeaponRateFactor(actor); // decrease ammo for the laser? if(WEP_CVAR_SEC(vaporizer, ammo)) - W_DecreaseAmmo(thiswep, actor, WEP_CVAR_SEC(vaporizer, ammo)); + W_DecreaseAmmo(thiswep, actor, WEP_CVAR_SEC(vaporizer, ammo), weaponentity); // ugly instagib hack to reuse the fire mode of the laser makevectors(actor.v_angle); - Weapon oldwep = PS(actor).m_weapon; // we can't avoid this hack - PS(actor).m_weapon = WEP_BLASTER; + Weapon oldwep = actor.(weaponentity).m_weapon; // we can't avoid this hack + actor.(weaponentity).m_weapon = WEP_BLASTER; W_Blaster_Attack( actor, weaponentity, @@ -424,33 +425,32 @@ METHOD(Vaporizer, wr_think, void(entity thiswep, entity actor, .entity weaponent WEP_CVAR_SEC(vaporizer, delay), WEP_CVAR_SEC(vaporizer, lifetime) ); - PS(actor).m_weapon = oldwep; + actor.(weaponentity).m_weapon = oldwep; // now do normal refire weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(vaporizer, animtime), w_ready); } } else - actor.held_down = false; + actor.(weaponentity).held_down = false; } -METHOD(Vaporizer, wr_setup, void(entity thiswep, entity actor)) +METHOD(Vaporizer, wr_setup, void(entity thiswep, entity actor, .entity weaponentity)) { - actor.ammo_field = (thiswep.ammo_field); actor.vaporizer_lasthit = 0; } -METHOD(Vaporizer, wr_checkammo1, bool(entity thiswep, entity actor)) +METHOD(Vaporizer, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity)) { float vaporizer_ammo = ((g_instagib) ? 1 : WEP_CVAR_PRI(vaporizer, ammo)); float ammo_amount = actor.(thiswep.ammo_field) >= vaporizer_ammo; - ammo_amount += actor.(weapon_load[WEP_VAPORIZER.m_id]) >= vaporizer_ammo; + ammo_amount += actor.(weaponentity).(weapon_load[WEP_VAPORIZER.m_id]) >= vaporizer_ammo; return ammo_amount; } -METHOD(Vaporizer, wr_checkammo2, bool(entity thiswep, entity actor)) +METHOD(Vaporizer, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity)) { if(!WEP_CVAR_SEC(vaporizer, ammo)) return true; float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_SEC(vaporizer, ammo); - ammo_amount += actor.(weapon_load[WEP_VAPORIZER.m_id]) >= WEP_CVAR_SEC(vaporizer, ammo); + ammo_amount += actor.(weaponentity).(weapon_load[WEP_VAPORIZER.m_id]) >= WEP_CVAR_SEC(vaporizer, ammo); return ammo_amount; } METHOD(Vaporizer, wr_resetplayer, void(entity thiswep, entity actor)) @@ -501,11 +501,10 @@ METHOD(Vaporizer, wr_init, void(entity thiswep)) precache_pic("gfx/reticle_nex"); } } -METHOD(Vaporizer, wr_zoomreticle, bool(entity thiswep)) +METHOD(Vaporizer, wr_zoom, bool(entity thiswep, entity actor)) { if(button_zoom || zoomscript_caught) { - reticle_image = "gfx/reticle_nex"; return true; } else diff --git a/qcsrc/common/weapons/weapon/vortex.qc b/qcsrc/common/weapons/weapon/vortex.qc index bf3ce8185f..b3ba65c505 100644 --- a/qcsrc/common/weapons/weapon/vortex.qc +++ b/qcsrc/common/weapons/weapon/vortex.qc @@ -12,6 +12,7 @@ CLASS(Vortex, Weapon) #endif /* crosshair */ ATTRIB(Vortex, w_crosshair, string, "gfx/crosshairnex"); /* crosshair */ ATTRIB(Vortex, w_crosshair_size, float, 0.65); +/* reticle */ ATTRIB(Vortex, w_reticle, string, "gfx/reticle_nex"); /* wepimg */ ATTRIB(Vortex, model2, string, "weaponnex"); /* refname */ ATTRIB(Vortex, netname, string, "vortex"); /* wepname */ ATTRIB(Vortex, m_name, string, _("Vortex")); @@ -78,10 +79,10 @@ float autocvar_g_weapon_charge_colormod_blue_half; float autocvar_g_weapon_charge_colormod_green_half; float autocvar_g_weapon_charge_colormod_hdrmultiplier; -METHOD(Vortex, wr_glow, vector(Vortex this, entity actor)) +METHOD(Vortex, wr_glow, vector(Vortex this, entity actor, entity wepent)) { if (!STAT(WEP_CVAR_vortex_charge, actor)) return '0 0 0'; - float charge = STAT(VORTEX_CHARGE, actor); + float charge = wepent.vortex_charge; float animlimit = STAT(WEP_CVAR_vortex_charge_animlimit, actor); vector g; g.x = autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_red_half * min(1, charge / animlimit); @@ -147,15 +148,23 @@ MUTATOR_HOOKFUNCTION(vortex_charge, GetPressedKeys) entity player = M_ARGV(0, entity); // WEAPONTODO - float xyspeed = vlen(vec2(player.velocity)); - if (PS(player).m_weapon == WEP_VORTEX && WEP_CVAR(vortex, charge) && WEP_CVAR(vortex, charge_velocity_rate) && xyspeed > WEP_CVAR(vortex, charge_minspeed)) - { - // add a maximum of charge_velocity_rate when going fast (f = 1), gradually increasing from minspeed (f = 0) to maxspeed - xyspeed = min(xyspeed, WEP_CVAR(vortex, charge_maxspeed)); - float f = (xyspeed - WEP_CVAR(vortex, charge_minspeed)) / (WEP_CVAR(vortex, charge_maxspeed) - WEP_CVAR(vortex, charge_minspeed)); - // add the extra charge - player.vortex_charge = min(1, player.vortex_charge + WEP_CVAR(vortex, charge_velocity_rate) * f * PHYS_INPUT_TIMELENGTH); - } + if(!WEP_CVAR(vortex, charge) || !WEP_CVAR(vortex, charge_velocity_rate)) + return; + + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + + if (player.(weaponentity).m_weapon == WEP_VORTEX && WEP_CVAR(vortex, charge) && WEP_CVAR(vortex, charge_velocity_rate) && vdist(vec2(player.velocity), >, WEP_CVAR(vortex, charge_minspeed))) + { + float xyspeed = vlen(vec2(player.velocity)); + // add a maximum of charge_velocity_rate when going fast (f = 1), gradually increasing from minspeed (f = 0) to maxspeed + xyspeed = min(xyspeed, WEP_CVAR(vortex, charge_maxspeed)); + float f = (xyspeed - WEP_CVAR(vortex, charge_minspeed)) / (WEP_CVAR(vortex, charge_maxspeed) - WEP_CVAR(vortex, charge_minspeed)); + // add the extra charge + player.(weaponentity).vortex_charge = min(1, player.(weaponentity).vortex_charge + WEP_CVAR(vortex, charge_velocity_rate) * f * PHYS_INPUT_TIMELENGTH); + } + } } void W_Vortex_Attack(Weapon thiswep, entity actor, .entity weaponentity, float issecondary) @@ -175,8 +184,8 @@ void W_Vortex_Attack(Weapon thiswep, entity actor, .entity weaponentity, float i if(WEP_CVAR(vortex, charge)) { - charge = WEP_CVAR(vortex, charge_mindmg) / mydmg + (1 - WEP_CVAR(vortex, charge_mindmg) / mydmg) * actor.vortex_charge; - actor.vortex_charge *= WEP_CVAR(vortex, charge_shot_multiplier); // do this AFTER setting mydmg/myforce + charge = WEP_CVAR(vortex, charge_mindmg) / mydmg + (1 - WEP_CVAR(vortex, charge_mindmg) / mydmg) * actor.(weaponentity).vortex_charge; + actor.(weaponentity).vortex_charge *= WEP_CVAR(vortex, charge_shot_multiplier); // do this AFTER setting mydmg/myforce // O RLY? -- divVerent // YA RLY -- FruitieX } @@ -193,7 +202,7 @@ void W_Vortex_Attack(Weapon thiswep, entity actor, .entity weaponentity, float i yoda = 0; damage_goodhits = 0; - FireRailgunBullet(actor, w_shotorg, w_shotorg + w_shotdir * MAX_SHOT_DISTANCE, mydmg, myforce, mymindist, mymaxdist, myhalflife, myforcehalflife, WEP_VORTEX.m_id); + FireRailgunBullet(actor, weaponentity, w_shotorg, w_shotorg + w_shotdir * MAX_SHOT_DISTANCE, mydmg, myforce, mymindist, mymaxdist, myhalflife, myforcehalflife, WEP_VORTEX.m_id); if(yoda && flying) Send_Notification(NOTIF_ONE, actor, MSG_ANNCE, ANNCE_ACHIEVEMENT_YODA); @@ -208,14 +217,14 @@ void W_Vortex_Attack(Weapon thiswep, entity actor, .entity weaponentity, float i //beam and muzzle flash done on client SendCSQCVortexBeamParticle(charge); - W_DecreaseAmmo(thiswep, actor, myammo); + W_DecreaseAmmo(thiswep, actor, myammo, weaponentity); } .float vortex_chargepool_pauseregen_finished; -METHOD(Vortex, wr_aim, void(entity thiswep, entity actor)) +METHOD(Vortex, wr_aim, void(entity thiswep, entity actor, .entity weaponentity)) { - if(bot_aim(actor, 1000000, 0, 1, false)) + if(bot_aim(actor, weaponentity, 1000000, 0, 1, false)) PHYS_INPUT_BUTTON_ATCK(actor) = true; else { @@ -225,18 +234,24 @@ METHOD(Vortex, wr_aim, void(entity thiswep, entity actor)) } METHOD(Vortex, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) { - if(WEP_CVAR(vortex, charge) && actor.vortex_charge < WEP_CVAR(vortex, charge_limit)) - actor.vortex_charge = min(1, actor.vortex_charge + WEP_CVAR(vortex, charge_rate) * frametime / W_TICSPERFRAME); + if(WEP_CVAR(vortex, charge) && actor.(weaponentity).vortex_charge < WEP_CVAR(vortex, charge_limit)) + actor.(weaponentity).vortex_charge = min(1, actor.(weaponentity).vortex_charge + WEP_CVAR(vortex, charge_rate) * frametime / W_TICSPERFRAME); + + if(weaponslot(weaponentity) == 0) + actor.vortex_charge = actor.(weaponentity).vortex_charge; if(WEP_CVAR_SEC(vortex, chargepool)) - if(actor.vortex_chargepool_ammo < 1) + if(actor.(weaponentity).vortex_chargepool_ammo < 1) { if(actor.vortex_chargepool_pauseregen_finished < time) - actor.vortex_chargepool_ammo = min(1, actor.vortex_chargepool_ammo + WEP_CVAR_SEC(vortex, chargepool_regen) * frametime / W_TICSPERFRAME); + actor.(weaponentity).vortex_chargepool_ammo = min(1, actor.(weaponentity).vortex_chargepool_ammo + WEP_CVAR_SEC(vortex, chargepool_regen) * frametime / W_TICSPERFRAME); actor.pauseregen_finished = max(actor.pauseregen_finished, time + WEP_CVAR_SEC(vortex, chargepool_pause_regen)); } - if(autocvar_g_balance_vortex_reload_ammo && actor.clip_load < min(WEP_CVAR_PRI(vortex, ammo), WEP_CVAR_SEC(vortex, ammo))) { // forced reload + if(weaponslot(weaponentity) == 0) + actor.vortex_chargepool_ammo = actor.(weaponentity).vortex_chargepool_ammo; + + if(autocvar_g_balance_vortex_reload_ammo && actor.(weaponentity).clip_load < min(WEP_CVAR_PRI(vortex, ammo), WEP_CVAR_SEC(vortex, ammo))) { // forced reload thiswep.wr_reload(thiswep, actor, weaponentity); } else { @@ -252,10 +267,10 @@ METHOD(Vortex, wr_think, void(entity thiswep, entity actor, .entity weaponentity { if(WEP_CVAR(vortex, charge)) { - actor.vortex_charge_rottime = time + WEP_CVAR(vortex, charge_rot_pause); + actor.(weaponentity).vortex_charge_rottime = time + WEP_CVAR(vortex, charge_rot_pause); float dt = frametime / W_TICSPERFRAME; - if(actor.vortex_charge < 1) + if(actor.(weaponentity).vortex_charge < 1) { if(WEP_CVAR_SEC(vortex, chargepool)) { @@ -264,12 +279,12 @@ METHOD(Vortex, wr_think, void(entity thiswep, entity actor, .entity weaponentity // always deplete if secondary is held actor.vortex_chargepool_ammo = max(0, actor.vortex_chargepool_ammo - WEP_CVAR_SEC(vortex, ammo) * dt); - dt = min(dt, (1 - actor.vortex_charge) / WEP_CVAR(vortex, charge_rate)); + dt = min(dt, (1 - actor.(weaponentity).vortex_charge) / WEP_CVAR(vortex, charge_rate)); actor.vortex_chargepool_pauseregen_finished = time + WEP_CVAR_SEC(vortex, chargepool_pause_regen); dt = min(dt, actor.vortex_chargepool_ammo); dt = max(0, dt); - actor.vortex_charge += dt * WEP_CVAR(vortex, charge_rate); + actor.(weaponentity).vortex_charge += dt * WEP_CVAR(vortex, charge_rate); } } @@ -277,19 +292,19 @@ METHOD(Vortex, wr_think, void(entity thiswep, entity actor, .entity weaponentity { if(fire & 2) // only eat ammo when the button is pressed { - dt = min(dt, (1 - actor.vortex_charge) / WEP_CVAR(vortex, charge_rate)); + dt = min(dt, (1 - actor.(weaponentity).vortex_charge) / WEP_CVAR(vortex, charge_rate)); if(!(actor.items & IT_UNLIMITED_WEAPON_AMMO)) { // if this weapon is reloadable, decrease its load. Else decrease the player's ammo if(autocvar_g_balance_vortex_reload_ammo) { - dt = min(dt, (actor.clip_load - WEP_CVAR_PRI(vortex, ammo)) / WEP_CVAR_SEC(vortex, ammo)); + dt = min(dt, (actor.(weaponentity).clip_load - WEP_CVAR_PRI(vortex, ammo)) / WEP_CVAR_SEC(vortex, ammo)); dt = max(0, dt); if(dt > 0) { - actor.clip_load = max(WEP_CVAR_SEC(vortex, ammo), actor.clip_load - WEP_CVAR_SEC(vortex, ammo) * dt); + actor.(weaponentity).clip_load = max(WEP_CVAR_SEC(vortex, ammo), actor.(weaponentity).clip_load - WEP_CVAR_SEC(vortex, ammo) * dt); } - actor.(weapon_load[WEP_VORTEX.m_id]) = actor.clip_load; + actor.(weaponentity).(weapon_load[WEP_VORTEX.m_id]) = actor.(weaponentity).clip_load; } else { @@ -301,14 +316,14 @@ METHOD(Vortex, wr_think, void(entity thiswep, entity actor, .entity weaponentity } } } - actor.vortex_charge += dt * WEP_CVAR(vortex, charge_rate); + actor.(weaponentity).vortex_charge += dt * WEP_CVAR(vortex, charge_rate); } } else { - dt = min(dt, (1 - actor.vortex_charge) / WEP_CVAR(vortex, charge_rate)); - actor.vortex_charge += dt * WEP_CVAR(vortex, charge_rate); + dt = min(dt, (1 - actor.(weaponentity).vortex_charge) / WEP_CVAR(vortex, charge_rate)); + actor.(weaponentity).vortex_charge += dt * WEP_CVAR(vortex, charge_rate); } } } @@ -323,23 +338,23 @@ METHOD(Vortex, wr_think, void(entity thiswep, entity actor, .entity weaponentity } } } -METHOD(Vortex, wr_setup, void(entity thiswep, entity actor)) +METHOD(Vortex, wr_setup, void(entity thiswep, entity actor, .entity weaponentity)) { actor.vortex_lasthit = 0; } -METHOD(Vortex, wr_checkammo1, bool(entity thiswep, entity actor)) +METHOD(Vortex, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity)) { float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_PRI(vortex, ammo); - ammo_amount += (autocvar_g_balance_vortex_reload_ammo && actor.(weapon_load[WEP_VORTEX.m_id]) >= WEP_CVAR_PRI(vortex, ammo)); + ammo_amount += (autocvar_g_balance_vortex_reload_ammo && actor.(weaponentity).(weapon_load[WEP_VORTEX.m_id]) >= WEP_CVAR_PRI(vortex, ammo)); return ammo_amount; } -METHOD(Vortex, wr_checkammo2, bool(entity thiswep, entity actor)) +METHOD(Vortex, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity)) { if(WEP_CVAR(vortex, secondary)) { // don't allow charging if we don't have enough ammo float ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR_SEC(vortex, ammo); - ammo_amount += actor.(weapon_load[WEP_VORTEX.m_id]) >= WEP_CVAR_SEC(vortex, ammo); + ammo_amount += actor.(weaponentity).(weapon_load[WEP_VORTEX.m_id]) >= WEP_CVAR_SEC(vortex, ammo); return ammo_amount; } else @@ -354,6 +369,14 @@ METHOD(Vortex, wr_resetplayer, void(entity thiswep, entity actor)) actor.vortex_chargepool_ammo = 1; } actor.vortex_charge = WEP_CVAR(vortex, charge_start); + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + actor.(weaponentity).vortex_charge = WEP_CVAR(vortex, charge_start); + + if (WEP_CVAR_SEC(vortex, chargepool)) + actor.(weaponentity).vortex_chargepool_ammo = 1; + } } actor.vortex_lasthit = 0; } @@ -369,6 +392,10 @@ METHOD(Vortex, wr_killmessage, Notification(entity thiswep)) { return WEAPON_VORTEX_MURDER; } +METHOD(Vortex, wr_zoom, bool(entity thiswep, entity actor)) +{ + return PHYS_INPUT_BUTTON_ATCK2(actor) && !WEP_CVAR(vortex, secondary); +} #endif #ifdef CSQC @@ -388,11 +415,10 @@ METHOD(Vortex, wr_init, void(entity thiswep)) precache_pic("gfx/reticle_nex"); } } -METHOD(Vortex, wr_zoomreticle, bool(entity thiswep)) +METHOD(Vortex, wr_zoom, bool(entity thiswep, entity actor)) { if(button_zoom || zoomscript_caught || (!WEP_CVAR(vortex, secondary) && button_attack2)) { - reticle_image = "gfx/reticle_nex"; return true; } else diff --git a/qcsrc/common/wepent.qc b/qcsrc/common/wepent.qc new file mode 100644 index 0000000000..1b6e407786 --- /dev/null +++ b/qcsrc/common/wepent.qc @@ -0,0 +1,174 @@ +#include "wepent.qh" + +#define WEPENT_SET_NORMAL(var, x) MACRO_BEGIN \ + var = x; \ +MACRO_END + +/** the engine player name strings are mutable! */ +#define WEPENT_SET_MUTABLE_STRING(var, x) MACRO_BEGIN \ + if (var) strunzone(var); \ + var = strzone(x); \ +MACRO_END + +// #define PROP(public, fld, set, sv, cl) +#define WEPENT_NETPROPS(PROP) PROP(false, sv_entnum, WEPENT_SET_NORMAL, {}, {}) /* sentinel */ \ + PROP(false, m_switchweapon, WEPENT_SET_NORMAL, \ + { WriteByte(chan, this.m_switchweapon.m_id); }, \ + { (viewmodels[this.m_wepent_slot]).switchweapon = Weapons_from(ReadByte()); }) \ + \ + PROP(false, m_switchingweapon, WEPENT_SET_NORMAL, \ + { WriteByte(chan, this.m_switchingweapon.m_id); }, \ + { (viewmodels[this.m_wepent_slot]).switchingweapon = Weapons_from(ReadByte()); }) \ + \ + PROP(false, m_weapon, WEPENT_SET_NORMAL, \ + { WriteByte(chan, this.m_weapon.m_id); }, \ + { (viewmodels[this.m_wepent_slot]).activeweapon = Weapons_from(ReadByte()); }) \ + \ + PROP(false, m_alpha, WEPENT_SET_NORMAL, \ + { WriteByte(chan, this.m_alpha * 16); }, \ + { (viewmodels[this.m_wepent_slot]).alpha = ReadByte() / 16; }) \ + \ + PROP(false, vortex_charge, WEPENT_SET_NORMAL, \ + { WriteByte(chan, this.vortex_charge * 16); }, \ + { (viewmodels[this.m_wepent_slot]).vortex_charge = ReadByte() / 16; }) \ + \ + PROP(false, m_gunalign, WEPENT_SET_NORMAL, \ + { WriteByte(chan, this.m_gunalign); }, \ + { (viewmodels[this.m_wepent_slot]).m_gunalign = ReadByte(); }) \ + \ + PROP(false, porto_v_angle_held, WEPENT_SET_NORMAL, \ + { WriteByte(chan, this.porto_v_angle_held); if(this.porto_v_angle_held) { \ + WriteAngle(chan, this.porto_v_angle.x); WriteAngle(chan, this.porto_v_angle.y); \ + } }, \ + { (viewmodels[this.m_wepent_slot]).angles_held_status = ReadByte(); if((viewmodels[this.m_wepent_slot]).angles_held_status) { \ + (viewmodels[this.m_wepent_slot]).angles_held_x = ReadAngle(); (viewmodels[this.m_wepent_slot]).angles_held_y = ReadAngle(); (viewmodels[this.m_wepent_slot]).angles_held_z = 0; } \ + else { (viewmodels[this.m_wepent_slot]).angles_held = '0 0 0'; } }) \ + \ + PROP(false, tuba_instrument, WEPENT_SET_NORMAL, \ + { WriteByte(chan, this.tuba_instrument); }, \ + { (viewmodels[this.m_wepent_slot]).tuba_instrument = ReadByte(); }) \ + \ + /**/ + +#ifdef SVQC + + int WEPENT_PUBLICMASK = 0; + STATIC_INIT(WEPENT_PUBLICMASK) + { + int i = 0; + #define X(public, fld, set, sv, cl) { \ + if (public) { \ + WEPENT_PUBLICMASK |= BIT(i); \ + } \ + i += 1; \ + } + WEPENT_NETPROPS(X); + #undef X + if (i >= BITS(16 - 1)) LOG_FATAL("Exceeded WEPENT_NETPROPS limit"); + } + + bool _wepent_send(entity this, entity to, int sf, int chan) + { + sf |= this.m_forceupdate; + this.m_forceupdate = 0; + if (chan == MSG_ENTITY) + WriteHeader(chan, ENT_CLIENT_WEPENT); + else + WriteHeader(chan, CLIENT_WEPENT); + .entity weaponentity = this.owner.weaponentity_fld; + WriteByte(chan, weaponslot(weaponentity)); + WriteShort(chan, sf); + int i = 0; + #define X(public, fld, set, sv, cl) { \ + if (sf & BIT(i)) { \ + sv; \ + } \ + i += 1; \ + } + WEPENT_NETPROPS(X); + #undef X + return true; + } + + bool wepent_send(entity this, entity to, int sf) + { + return _wepent_send(this, to, sf, MSG_ENTITY); + } + + void wepent_think(entity this) + { + if(wasfreed(this.owner) || !this.owner) + { + delete(this); + return; + } + + this.nextthink = time; + + entity o = this.owner; + + int i = 0; + #define X(public, fld, set, sv, cl) { \ + if (this.fld != o.fld) { \ + set(this.fld, o.fld); \ + this.SendFlags |= BIT(i); \ + } \ + i += 1; \ + } + WEPENT_NETPROPS(X); + #undef X + } + + bool wepent_customize(entity this, entity client) + { + //entity e = WaypointSprite_getviewentity(client); + .entity weaponentity = this.owner.weaponentity_fld; + return client.(weaponentity) == this.owner; + } + + void wepent_link(entity wep) + { + entity e = new(wepent_sender); + e.owner = wep; + setthink(e, wepent_think); + e.nextthink = time; + //e.drawonlytoclient = wep.owner; + setcefc(e, wepent_customize); + Net_LinkEntity(e, false, 0, wepent_send); + } + +#endif + +#ifdef CSQC + + bool ReadWepent(entity this) + { + int slot = ReadByte(); + this.m_wepent_slot = slot; + viewmodels[slot].m_wepent_slot = slot; + int sf = ReadShort(); + int i = 0; + #define X(public, fld, set, sv, cl) { \ + if (sf & BIT(i)) { \ + cl; \ + } \ + i += 1; \ + } + WEPENT_NETPROPS(X); + #undef X + return true; + } + + NET_HANDLE(ENT_CLIENT_WEPENT, bool isnew) + { + if (isnew) + this.classname = "wepent_receiver"; + return ReadWepent(this); + } + + NET_HANDLE(CLIENT_WEPENT, bool isnew) + { + return ReadWepent(NULL); + } + +#endif diff --git a/qcsrc/common/wepent.qh b/qcsrc/common/wepent.qh new file mode 100644 index 0000000000..46180d7c0b --- /dev/null +++ b/qcsrc/common/wepent.qh @@ -0,0 +1,33 @@ +#pragma once + +REGISTER_NET_LINKED(ENT_CLIENT_WEPENT) +REGISTER_NET_TEMP(CLIENT_WEPENT) + +.float vortex_charge; +.int tuba_instrument; + +#ifdef SVQC + + bool wepent_send(entity this, entity to, int sf); + + void wepent_link(entity wep); + + .int m_forceupdate; + + .Weapon m_switchweapon; + .Weapon m_weapon; + .Weapon m_switchingweapon; + +#endif + +#ifdef CSQC + .int m_wepent_slot; + + .Weapon activeweapon; + .Weapon switchingweapon; + .Weapon switchweapon; + + // only for Porto + .bool angles_held_status; + .vector angles_held; +#endif diff --git a/qcsrc/server/bot/api.qh b/qcsrc/server/bot/api.qh index 64957b92e0..7a43efa852 100644 --- a/qcsrc/server/bot/api.qh +++ b/qcsrc/server/bot/api.qh @@ -46,7 +46,7 @@ float skill; .float wpcost; .int wpflags; -bool bot_aim(entity this, float shotspeed, float shotspeedupward, float maxshottime, float applygravity); +bool bot_aim(entity this, .entity weaponentity, float shotspeed, float shotspeedupward, float maxshottime, float applygravity); void bot_clientconnect(entity this); void bot_clientdisconnect(entity this); void bot_cmdhelp(string scmd); diff --git a/qcsrc/server/bot/default/aim.qc b/qcsrc/server/bot/default/aim.qc index 1624676b82..c278be915a 100644 --- a/qcsrc/server/bot/default/aim.qc +++ b/qcsrc/server/bot/default/aim.qc @@ -323,7 +323,7 @@ vector bot_shotlead(vector targorigin, vector targvelocity, float shotspeed, flo return targorigin + targvelocity * (shotdelay + vlen(targorigin - shotorg) / shotspeed); } -bool bot_aim(entity this, float shotspeed, float shotspeedupward, float maxshottime, bool applygravity) +bool bot_aim(entity this, .entity weaponentity, float shotspeed, float shotspeedupward, float maxshottime, bool applygravity) { float f, r, hf, distanceratio; vector v; @@ -343,12 +343,12 @@ bool bot_aim(entity this, float shotspeed, float shotspeedupward, float maxshott shotspeedupward *= W_WeaponSpeedFactor(this); if (!shotspeed) { - LOG_TRACE("bot_aim: WARNING: weapon ", PS(this).m_weapon.m_name, " shotspeed is zero!"); + LOG_TRACE("bot_aim: WARNING: weapon ", this.(weaponentity).m_weapon.m_name, " shotspeed is zero!"); shotspeed = 1000000; } if (!maxshottime) { - LOG_TRACE("bot_aim: WARNING: weapon ", PS(this).m_weapon.m_name, " maxshottime is zero!"); + LOG_TRACE("bot_aim: WARNING: weapon ", this.(weaponentity).m_weapon.m_name, " maxshottime is zero!"); maxshottime = 1; } makevectors(this.v_angle); diff --git a/qcsrc/server/bot/default/aim.qh b/qcsrc/server/bot/default/aim.qh index dfe10e2656..e7c60758ae 100644 --- a/qcsrc/server/bot/default/aim.qh +++ b/qcsrc/server/bot/default/aim.qh @@ -91,7 +91,7 @@ void bot_lagfunc(entity this, float t, float f1, float f2, entity e1, vector v1, float bot_shouldattack(entity this, entity targ); float bot_aimdir(entity this, vector v, float maxfiredeviation); -bool bot_aim(entity this, float shotspeed, float shotspeedupward, float maxshottime, bool applygravity); +bool bot_aim(entity this, .entity weaponentity, float shotspeed, float shotspeedupward, float maxshottime, bool applygravity); float findtrajectorywithleading(vector org, vector m1, vector m2, entity targ, float shotspeed, float shotspeedupward, float maxtime, float shotdelay, entity ignore); vector bot_shotlead(vector targorigin, vector targvelocity, float shotspeed, float shotdelay); diff --git a/qcsrc/server/bot/default/havocbot/havocbot.qc b/qcsrc/server/bot/default/havocbot/havocbot.qc index dd44bbb4e6..d76865646e 100644 --- a/qcsrc/server/bot/default/havocbot/havocbot.qc +++ b/qcsrc/server/bot/default/havocbot/havocbot.qc @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -89,10 +90,16 @@ void havocbot_ai(entity this) return; havocbot_chooseenemy(this); - if (this.bot_chooseweapontime < time ) + + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) { - this.bot_chooseweapontime = time + autocvar_bot_ai_chooseweaponinterval; - havocbot_chooseweapon(this); + .entity weaponentity = weaponentities[slot]; + if(this.(weaponentity).m_weapon != WEP_Null || slot == 0) + if(this.(weaponentity).bot_chooseweapontime < time) + { + this.(weaponentity).bot_chooseweapontime = time + autocvar_bot_ai_chooseweaponinterval; + havocbot_chooseweapon(this, weaponentity); + } } havocbot_aim(this); lag_update(this); @@ -103,8 +110,6 @@ void havocbot_ai(entity this) if(this.weapons) { - Weapon w = PS(this).m_weapon; - w.wr_aim(w, this); if (autocvar_bot_nofire || IS_INDEPENDENT_PLAYER(this)) { PHYS_INPUT_BUTTON_ATCK(this) = false; @@ -112,8 +117,16 @@ void havocbot_ai(entity this) } else { - if(PHYS_INPUT_BUTTON_ATCK(this) || PHYS_INPUT_BUTTON_ATCK2(this)) - this.lastfiredweapon = PS(this).m_weapon.m_id; + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + Weapon w = this.(weaponentity).m_weapon; + if(w == WEP_Null && slot != 0) + continue; + w.wr_aim(w, this, weaponentity); + if(PHYS_INPUT_BUTTON_ATCK(this) || PHYS_INPUT_BUTTON_ATCK2(this)) // TODO: what if we didn't fire this weapon, but the previous? + this.(weaponentity).lastfiredweapon = this.(weaponentity).m_weapon.m_id; + } } } else @@ -160,20 +173,28 @@ void havocbot_ai(entity this) // if the bot is not attacking, consider reloading weapons if (!(this.aistatus & AI_STATUS_ATTACKING)) { - // we are currently holding a weapon that's not fully loaded, reload it - if(skill >= 2) // bots can only reload the held weapon on purpose past this skill - if(this.clip_load < this.clip_size) - this.impulse = 20; // "press" the reload button, not sure if this is done right - - // if we're not reloading a weapon, switch to any weapon in our invnetory that's not fully loaded to reload it next - // the code above executes next frame, starting the reloading then - if(skill >= 5) // bots can only look for unloaded weapons past this skill - if(this.clip_load >= 0) // only if we're not reloading a weapon already + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) { - FOREACH(Weapons, it != WEP_Null, LAMBDA( - if((this.weapons & (it.m_wepset)) && (it.spawnflags & WEP_FLAG_RELOADABLE) && (this.weapon_load[it.m_id] < it.reloading_ammo)) - PS(this).m_switchweapon = it; - )); + .entity weaponentity = weaponentities[slot]; + + if(this.(weaponentity).m_weapon == WEP_Null && slot != 0) + continue; + + // we are currently holding a weapon that's not fully loaded, reload it + if(skill >= 2) // bots can only reload the held weapon on purpose past this skill + if(this.(weaponentity).clip_load < this.(weaponentity).clip_size) + this.impulse = 20; // "press" the reload button, not sure if this is done right + + // if we're not reloading a weapon, switch to any weapon in our invnetory that's not fully loaded to reload it next + // the code above executes next frame, starting the reloading then + if(skill >= 5) // bots can only look for unloaded weapons past this skill + if(this.(weaponentity).clip_load >= 0) // only if we're not reloading a weapon already + { + FOREACH(Weapons, it != WEP_Null, LAMBDA( + if((this.weapons & (it.m_wepset)) && (it.spawnflags & WEP_FLAG_RELOADABLE) && (this.(weaponentity).weapon_load[it.m_id] < it.reloading_ammo)) + this.(weaponentity).m_switchweapon = it; + )); + } } } } @@ -589,25 +610,35 @@ void havocbot_movetogoal(entity this) else if(this.health>WEP_CVAR(devastator, damage)*0.5) { if(this.velocity.z < 0) - if(client_hasweapon(this, WEP_DEVASTATOR, true, false)) { - this.movement_x = maxspeed; - - if(this.rocketjumptime) + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) { - if(time > this.rocketjumptime) + .entity weaponentity = weaponentities[slot]; + + if(this.(weaponentity).m_weapon == WEP_Null && slot != 0) + continue; + + if(client_hasweapon(this, WEP_DEVASTATOR, weaponentity, true, false)) { - PHYS_INPUT_BUTTON_ATCK2(this) = true; - this.rocketjumptime = 0; + this.movement_x = maxspeed; + + if(this.rocketjumptime) + { + if(time > this.rocketjumptime) + { + PHYS_INPUT_BUTTON_ATCK2(this) = true; + this.rocketjumptime = 0; + } + return; + } + + this.(weaponentity).m_switchweapon = WEP_DEVASTATOR; + this.v_angle_x = 90; + PHYS_INPUT_BUTTON_ATCK(this) = true; + this.rocketjumptime = time + WEP_CVAR(devastator, detonatedelay); + return; } - return; } - - PS(this).m_switchweapon = WEP_DEVASTATOR; - this.v_angle_x = 90; - PHYS_INPUT_BUTTON_ATCK(this) = true; - this.rocketjumptime = time + WEP_CVAR(devastator, detonatedelay); - return; } } else @@ -978,7 +1009,7 @@ LABEL(scan_targets) this.havocbot_stickenemy = false; } -float havocbot_chooseweapon_checkreload(entity this, int new_weapon) +float havocbot_chooseweapon_checkreload(entity this, .entity weaponentity, int new_weapon) { // bots under this skill cannot find unloaded weapons to reload idly when not in combat, // so skip this for them, or they'll never get to reload their weapons at all. @@ -987,11 +1018,11 @@ float havocbot_chooseweapon_checkreload(entity this, int new_weapon) return false; // if this weapon is scheduled for reloading, don't switch to it during combat - if (this.weapon_load[new_weapon] < 0) + if (this.(weaponentity).weapon_load[new_weapon] < 0) { bool other_weapon_available = false; FOREACH(Weapons, it != WEP_Null, LAMBDA( - if(it.wr_checkammo1(it, this) + it.wr_checkammo2(it, this)) + if(it.wr_checkammo1(it, this, weaponentity) + it.wr_checkammo2(it, this, weaponentity)) other_weapon_available = true; )); if(other_weapon_available) @@ -1001,14 +1032,14 @@ float havocbot_chooseweapon_checkreload(entity this, int new_weapon) return false; } -void havocbot_chooseweapon(entity this) +void havocbot_chooseweapon(entity this, .entity weaponentity) { int i; // ;) if(g_weaponarena_weapons == WEPSET(TUBA)) { - PS(this).m_switchweapon = WEP_TUBA; + this.(weaponentity).m_switchweapon = WEP_TUBA; return; } @@ -1016,11 +1047,11 @@ void havocbot_chooseweapon(entity this) if(this.enemy==NULL) { // If no weapon was chosen get the first available weapon - if(PS(this).m_weapon==WEP_Null) + if(this.(weaponentity).m_weapon==WEP_Null) FOREACH(Weapons, it != WEP_Null, LAMBDA( - if(client_hasweapon(this, it, true, false)) + if(client_hasweapon(this, it, weaponentity, true, false)) { - PS(this).m_switchweapon = it; + this.(weaponentity).m_switchweapon = it; return; } )); @@ -1048,7 +1079,7 @@ void havocbot_chooseweapon(entity this) combo = false; if(autocvar_bot_ai_weapon_combo) - if(PS(this).m_weapon.m_id == this.lastfiredweapon) + if(this.(weaponentity).m_weapon.m_id == this.(weaponentity).lastfiredweapon) if(af > combo_time) { combo = true; @@ -1064,11 +1095,11 @@ void havocbot_chooseweapon(entity this) if ( distance > bot_distance_far ) { for(i=0; i < Weapons_COUNT && bot_weapons_far[i] != -1 ; ++i){ w = bot_weapons_far[i]; - if ( client_hasweapon(this, Weapons_from(w), true, false) ) + if ( client_hasweapon(this, Weapons_from(w), weaponentity, true, false) ) { - if ((PS(this).m_weapon.m_id == w && combo) || havocbot_chooseweapon_checkreload(this, w)) + if ((this.(weaponentity).m_weapon.m_id == w && combo) || havocbot_chooseweapon_checkreload(this, weaponentity, w)) continue; - PS(this).m_switchweapon = Weapons_from(w); + this.(weaponentity).m_switchweapon = Weapons_from(w); return; } } @@ -1078,11 +1109,11 @@ void havocbot_chooseweapon(entity this) if ( distance > bot_distance_close) { for(i=0; i < Weapons_COUNT && bot_weapons_mid[i] != -1 ; ++i){ w = bot_weapons_mid[i]; - if ( client_hasweapon(this, Weapons_from(w), true, false) ) + if ( client_hasweapon(this, Weapons_from(w), weaponentity, true, false) ) { - if ((PS(this).m_weapon.m_id == w && combo) || havocbot_chooseweapon_checkreload(this, w)) + if ((this.(weaponentity).m_weapon.m_id == w && combo) || havocbot_chooseweapon_checkreload(this, weaponentity, w)) continue; - PS(this).m_switchweapon = Weapons_from(w); + this.(weaponentity).m_switchweapon = Weapons_from(w); return; } } @@ -1091,11 +1122,11 @@ void havocbot_chooseweapon(entity this) // Choose weapons for close distance for(i=0; i < Weapons_COUNT && bot_weapons_close[i] != -1 ; ++i){ w = bot_weapons_close[i]; - if ( client_hasweapon(this, Weapons_from(w), true, false) ) + if ( client_hasweapon(this, Weapons_from(w), weaponentity, true, false) ) { - if ((PS(this).m_weapon.m_id == w && combo) || havocbot_chooseweapon_checkreload(this, w)) + if ((this.(weaponentity).m_weapon.m_id == w && combo) || havocbot_chooseweapon_checkreload(this, weaponentity, w)) continue; - PS(this).m_switchweapon = Weapons_from(w); + this.(weaponentity).m_switchweapon = Weapons_from(w); return; } } diff --git a/qcsrc/server/bot/default/havocbot/havocbot.qh b/qcsrc/server/bot/default/havocbot/havocbot.qh index 4a391b6e7c..8ab4cba6e9 100644 --- a/qcsrc/server/bot/default/havocbot/havocbot.qh +++ b/qcsrc/server/bot/default/havocbot/havocbot.qh @@ -39,7 +39,7 @@ void havocbot_setupbot(entity this); void havocbot_movetogoal(entity this); void havocbot_chooserole(entity this); void havocbot_chooseenemy(entity this); -void havocbot_chooseweapon(entity this); +void havocbot_chooseweapon(entity this, .entity weaponentity); void havocbot_bunnyhop(entity this, vector dir); void havocbot_keyboard_movement(entity this, vector destorg); diff --git a/qcsrc/server/bot/default/scripting.qc b/qcsrc/server/bot/default/scripting.qc index f96099087b..252708a118 100644 --- a/qcsrc/server/bot/default/scripting.qc +++ b/qcsrc/server/bot/default/scripting.qc @@ -4,6 +4,7 @@ #include #include +#include #include "bot.qh" @@ -568,9 +569,22 @@ float bot_cmd_select_weapon(entity this) if(id < WEP_FIRST || id > WEP_LAST) return CMD_STATUS_ERROR; - if(client_hasweapon(this, Weapons_from(id), true, false)) - PS(this).m_switchweapon = Weapons_from(id); - else + bool success = false; + + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + if(this.(weaponentity).m_weapon == WEP_Null && slot != 0) + continue; + + if(client_hasweapon(this, Weapons_from(id), weaponentity, true, false)) + { + success = true; + this.(weaponentity).m_switchweapon = Weapons_from(id); + } + } + + if(!success) return CMD_STATUS_ERROR; return CMD_STATUS_FINISHED; @@ -1054,7 +1068,7 @@ float bot_cmd_debug_assert_canfire(entity this) if(f) { this.colormod = '0 8 8'; - LOG_INFO("Bot ", this.netname, " using ", this.weaponname, " wants to fire, inhibited by weaponentity state\n"); + LOG_INFO("Bot ", this.netname, " using ", this.(weaponentity).weaponname, " wants to fire, inhibited by weaponentity state\n"); } } else if(ATTACK_FINISHED(this, slot) > time) @@ -1062,15 +1076,15 @@ float bot_cmd_debug_assert_canfire(entity this) if(f) { this.colormod = '8 0 8'; - LOG_INFO("Bot ", this.netname, " using ", this.weaponname, " wants to fire, inhibited by ATTACK_FINISHED (", ftos(ATTACK_FINISHED(this, slot) - time), " seconds left)\n"); + LOG_INFO("Bot ", this.netname, " using ", this.(weaponentity).weaponname, " wants to fire, inhibited by ATTACK_FINISHED (", ftos(ATTACK_FINISHED(this, slot) - time), " seconds left)\n"); } } - else if(this.tuba_note) + else if(this.(weaponentity).tuba_note) { if(f) { this.colormod = '8 0 0'; - LOG_INFO("Bot ", this.netname, " using ", this.weaponname, " wants to fire, bot still has an active tuba note\n"); + LOG_INFO("Bot ", this.netname, " using ", this.(weaponentity).weaponname, " wants to fire, bot still has an active tuba note\n"); } } else @@ -1078,7 +1092,7 @@ float bot_cmd_debug_assert_canfire(entity this) if(!f) { this.colormod = '8 8 0'; - LOG_INFO("Bot ", this.netname, " using ", this.weaponname, " thinks it has fired, but apparently did not; ATTACK_FINISHED says ", ftos(ATTACK_FINISHED(this, slot) - time), " seconds left\n"); + LOG_INFO("Bot ", this.netname, " using ", this.(weaponentity).weaponname, " thinks it has fired, but apparently did not; ATTACK_FINISHED says ", ftos(ATTACK_FINISHED(this, slot) - time), " seconds left\n"); } } diff --git a/qcsrc/server/bot/null/bot_null.qc b/qcsrc/server/bot/null/bot_null.qc index b4102cb6c0..68ae416706 100644 --- a/qcsrc/server/bot/null/bot_null.qc +++ b/qcsrc/server/bot/null/bot_null.qc @@ -1,7 +1,7 @@ #include "bot_null.qh" #if 0 -bool bot_aim(entity this, float shotspeed, float shotspeedupward, float maxshottime, float applygravity) { return false; } +bool bot_aim(entity this, .entity weaponentity, float shotspeed, float shotspeedupward, float maxshottime, float applygravity) { return false; } void bot_clientconnect(entity this) { } void bot_clientdisconnect(entity this) { } void bot_cmdhelp(string scmd) { } diff --git a/qcsrc/server/client.qc b/qcsrc/server/client.qc index f9c4662c36..58e512a382 100644 --- a/qcsrc/server/client.qc +++ b/qcsrc/server/client.qc @@ -23,6 +23,7 @@ #include "bot/api.qh" #include "../common/ent_cs.qh" +#include "../common/wepent.qh" #include #include @@ -112,7 +113,6 @@ bool ClientData_Send(entity this, entity to, int sf) if (e.race_completed) sf |= 1; // forced scoreboard if (to.spectatee_status) sf |= 2; // spectator ent number follows if (e.zoomstate) sf |= 4; // zoomed - if (e.porto_v_angle_held) sf |= 8; // angles held if (autocvar_sv_showspectators) sf |= 16; // show spectators WriteHeader(MSG_ENTITY, ENT_CLIENT_CLIENTDATA); @@ -122,11 +122,6 @@ bool ClientData_Send(entity this, entity to, int sf) { WriteByte(MSG_ENTITY, to.spectatee_status); } - if (sf & 8) - { - WriteAngle(MSG_ENTITY, e.v_angle.x); - WriteAngle(MSG_ENTITY, e.v_angle.y); - } if(sf & 16) { @@ -257,7 +252,7 @@ void PutObserverInServer(entity this) this.view_ofs = '0 0 0'; } - RemoveGrapplingHook(this); + RemoveGrapplingHooks(this); Portal_ClearAll(this); Unfreeze(this); SetSpectatee(this, NULL); @@ -336,7 +331,6 @@ void PutObserverInServer(entity this) this.istypefrag = 0; setthink(this, func_null); this.nextthink = 0; - this.hook_time = 0; this.deadflag = DEAD_NO; this.crouch = false; this.revival_time = 0; @@ -345,10 +339,13 @@ void PutObserverInServer(entity this) this.weapons = '0 0 0'; this.drawonlytoclient = this; - this.weaponname = ""; this.weaponmodel = ""; for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) { + if(!this.weaponentities[slot]) + continue; // first load + this.weaponentities[slot].hook_time = 0; + this.weaponentities[slot].weaponname = ""; this.weaponentities[slot] = NULL; } this.exteriorweaponentity = NULL; @@ -360,10 +357,6 @@ void PutObserverInServer(entity this) this.oldvelocity = this.velocity; this.fire_endtime = -1; this.event_damage = func_null; - - STAT(ACTIVEWEAPON, this) = WEP_Null.m_id; - STAT(SWITCHINGWEAPON, this) = WEP_Null.m_id; - STAT(SWITCHWEAPON, this) = WEP_Null.m_id; } int player_getspecies(entity this) @@ -662,7 +655,8 @@ void PutClientInServer(entity this) for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) { - CL_SpawnWeaponentity(this, weaponentities[slot]); + .entity weaponentity = weaponentities[slot]; + CL_SpawnWeaponentity(this, weaponentity); } this.alpha = default_player_alpha; this.colormod = '1 1 1' * autocvar_g_player_brightness; @@ -677,7 +671,11 @@ void PutClientInServer(entity this) it.wr_resetplayer(it, this); // reload all reloadable weapons if (it.spawnflags & WEP_FLAG_RELOADABLE) { - this.weapon_load[it.m_id] = it.reloading_ammo; + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + this.(weaponentity).weapon_load[it.m_id] = it.reloading_ammo; + } } )); @@ -698,11 +696,18 @@ void PutClientInServer(entity this) delete(spot); // usefull for checking if there are spawnpoints, that let drop through the floor } - PS(this).m_switchweapon = w_getbestweapon(this); - this.cnt = -1; // W_LastWeapon will not complain - PS(this).m_weapon = WEP_Null; - this.weaponname = ""; - PS(this).m_switchingweapon = WEP_Null; + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + if(slot == 0) + this.(weaponentity).m_switchweapon = w_getbestweapon(this, weaponentity); + else + this.(weaponentity).m_switchweapon = WEP_Null; + this.(weaponentity).m_weapon = WEP_Null; + this.(weaponentity).weaponname = ""; + this.(weaponentity).m_switchingweapon = WEP_Null; + this.(weaponentity).cnt = -1; + } if (!warmup_stage && !this.alivetime) this.alivetime = time; @@ -1256,7 +1261,7 @@ void ClientDisconnect(entity this) Unfreeze(this); - RemoveGrapplingHook(this); + RemoveGrapplingHooks(this); // Here, everything has been done that requires this player to be a client. @@ -1687,6 +1692,12 @@ void SpectateCopy(entity this, entity spectatee) setsize(this, spectatee.mins, spectatee.maxs); SetZoomState(this, spectatee.zoomstate); + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + this.(weaponentity) = spectatee.(weaponentity); + } + anticheat_spectatecopy(this, spectatee); this.hud = spectatee.hud; if(spectatee.vehicle) @@ -2435,13 +2446,17 @@ void PlayerPreThink (entity this) { this.items &= ~this.items_added; - //for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) - //{ - //.entity weaponentity = weaponentities[slot]; - //W_WeaponFrame(this, weaponentity); - //} - .entity weaponentity = weaponentities[0]; // TODO - W_WeaponFrame(this, weaponentity); + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + W_WeaponFrame(this, weaponentity); + + if(slot == 0) + { + this.clip_load = this.(weaponentity).clip_load; + this.clip_size = this.(weaponentity).clip_size; + } + } this.items_added = 0; if (this.items & ITEM_Jetpack.m_itemid && (this.items & ITEM_JetpackRegen.m_itemid || this.ammo_fuel >= 0.01)) @@ -2454,8 +2469,12 @@ void PlayerPreThink (entity this) // WEAPONTODO: Add a weapon request for this // rot vortex charge to the charge limit - if (WEP_CVAR(vortex, charge_rot_rate) && this.vortex_charge > WEP_CVAR(vortex, charge_limit) && this.vortex_charge_rottime < time) - this.vortex_charge = bound(WEP_CVAR(vortex, charge_limit), this.vortex_charge - WEP_CVAR(vortex, charge_rot_rate) * frametime / W_TICSPERFRAME, 1); + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + if (WEP_CVAR(vortex, charge_rot_rate) && this.(weaponentity).vortex_charge > WEP_CVAR(vortex, charge_limit) && this.(weaponentity).vortex_charge_rottime < time) + this.(weaponentity).vortex_charge = bound(WEP_CVAR(vortex, charge_limit), this.(weaponentity).vortex_charge - WEP_CVAR(vortex, charge_rot_rate) * frametime / W_TICSPERFRAME, 1); + } if (frametime) player_anim(this); @@ -2480,11 +2499,15 @@ void PlayerPreThink (entity this) // WEAPONTODO: Add weapon request for this if (!zoomstate_set) { - SetZoomState(this, - PHYS_INPUT_BUTTON_ZOOM(this) || PHYS_INPUT_BUTTON_ZOOMSCRIPT(this) - || (PHYS_INPUT_BUTTON_ATCK2(this) && PS(this).m_weapon == WEP_VORTEX) - || (PHYS_INPUT_BUTTON_ATCK2(this) && PS(this).m_weapon == WEP_RIFLE && WEP_CVAR(rifle, secondary) == 0) - ); + bool wep_zoomed = false; + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + Weapon thiswep = this.(weaponentity).m_weapon; + if(thiswep != WEP_Null && thiswep.wr_zoom) + wep_zoomed += thiswep.wr_zoom(thiswep, this); + } + SetZoomState(this, PHYS_INPUT_BUTTON_ZOOM(this) || PHYS_INPUT_BUTTON_ZOOMSCRIPT(this) || wep_zoomed); } if (this.teamkill_soundtime && time > this.teamkill_soundtime) @@ -2507,8 +2530,12 @@ void PlayerPreThink (entity this) // WEAPONTODO: Move into weaponsystem somehow // if a player goes unarmed after holding a loaded weapon, empty his clip size and remove the crosshair ammo ring - if (PS(this).m_weapon == WEP_Null) - this.clip_load = this.clip_size = 0; + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + if(this.(weaponentity).m_weapon == WEP_Null) + this.(weaponentity).clip_load = this.(weaponentity).clip_size = 0; + } } void DrownPlayer(entity this) diff --git a/qcsrc/server/defs.qh b/qcsrc/server/defs.qh index 52153fcd7e..a149906288 100644 --- a/qcsrc/server/defs.qh +++ b/qcsrc/server/defs.qh @@ -116,7 +116,7 @@ const float MAX_DAMAGEEXTRARADIUS = 16; // WEAPONTODO .float autoswitch; -bool client_hasweapon(entity this, Weapon wpn, float andammo, bool complain); +bool client_hasweapon(entity this, Weapon wpn, .entity weaponentity, float andammo, bool complain); void w_clear(Weapon thiswep, entity actor, .entity weaponentity, int fire); void w_ready(Weapon thiswep, entity actor, .entity weaponentity, int fire); // VorteX: standalone think for weapons, so normal think on weaponentity can be reserved by weaponflashes (which needs update even player dies) @@ -209,7 +209,7 @@ float bot_waypoints_for_items; #else #define ATTACK_FINISHED_FOR(ent, w, slot) ((ent).attack_finished_single[slot]) #endif -#define ATTACK_FINISHED(ent, slot) ATTACK_FINISHED_FOR(ent, PS(ent).m_weapon.m_id, slot) +#define ATTACK_FINISHED(ent, slot) ATTACK_FINISHED_FOR(ent, ent.(weaponentity).m_weapon.m_id, slot) // assault game mode: Which team is attacking in this round? float assault_attacker_team; diff --git a/qcsrc/server/g_damage.qc b/qcsrc/server/g_damage.qc index a604a2bade..ac19363cca 100644 --- a/qcsrc/server/g_damage.qc +++ b/qcsrc/server/g_damage.qc @@ -58,13 +58,15 @@ void GiveFrags (entity attacker, entity targ, float f, int deathtype) PlayerScore_Add(targ, SP_DEATHS, 1); + .entity weaponentity = weaponentities[0]; // TODO: unhardcode + if(targ != attacker) // not for suicides if(g_weaponarena_random) { // after a frag, exchange the current weapon (or the culprit, if detectable) by a new random weapon Weapon culprit = DEATH_WEAPONOF(deathtype); - if(!culprit) culprit = PS(attacker).m_weapon; - else if(!(attacker.weapons & (culprit.m_wepset))) culprit = PS(attacker).m_weapon; + if(!culprit) culprit = attacker.(weaponentity).m_weapon; + else if(!(attacker.weapons & (culprit.m_wepset))) culprit = attacker.(weaponentity).m_weapon; if(g_weaponarena_random_with_blaster && culprit == WEP_BLASTER) // WEAPONTODO: Shouldn't this be in a mutator? { @@ -97,8 +99,8 @@ void GiveFrags (entity attacker, entity targ, float f, int deathtype) } // after a frag, choose another random weapon set - if (!(attacker.weapons & WepSet_FromWeapon(PS(attacker).m_weapon))) - W_SwitchWeapon_Force(attacker, w_getbestweapon(attacker)); + if (!(attacker.weapons & WepSet_FromWeapon(attacker.(weaponentity).m_weapon))) + W_SwitchWeapon_Force(attacker, w_getbestweapon(attacker, weaponentity), weaponentity); } // FIXME fix the mess this is (we have REAL points now!) @@ -115,12 +117,15 @@ void GiveFrags (entity attacker, entity targ, float f, int deathtype) string AppendItemcodes(string s, entity player) { - int w = PS(player).m_weapon.m_id; - //if(w == 0) - // w = player.switchweapon; - if(w == 0) - w = player.cnt; // previous weapon! - s = strcat(s, ftos(w)); + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + int w = player.(weaponentity).m_weapon.m_id; + if(w == 0) + w = player.(weaponentity).cnt; // previous weapon + if(w != 0 || slot == 0) + s = strcat(s, ftos(w)); + } if(time < player.strength_finished) s = strcat(s, "S"); if(time < player.invincible_finished) @@ -556,9 +561,17 @@ void Freeze (entity targ, float freeze_time, float frozen_type, float show_waypo Ice_Think(ice); - RemoveGrapplingHook(targ); + RemoveGrapplingHooks(targ); - FOREACH_CLIENT(IS_PLAYER(it) && it.hook.aiment == targ, LAMBDA(RemoveGrapplingHook(it))); + FOREACH_CLIENT(IS_PLAYER(it), + { + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + if(it.(weaponentity).hook.aiment == targ) + RemoveHook(it.(weaponentity).hook); + } + }); // add waypoint if(show_waypoint) @@ -585,7 +598,15 @@ void Unfreeze (entity targ) WaypointSprite_Kill(targ.waypointsprite_attached); - FOREACH_CLIENT(IS_PLAYER(it) && it.hook.aiment == targ, LAMBDA(RemoveGrapplingHook(it))); + FOREACH_CLIENT(IS_PLAYER(it), + { + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + if(it.(weaponentity).hook.aiment == targ) + RemoveHook(it.(weaponentity).hook); + } + }); // remove the ice block if(targ.iceblock) @@ -611,10 +632,14 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, int d attacker_save = attacker; if(IS_PLAYER(targ)) - if(targ.hook) - if(targ.hook.aiment) - if(targ.hook.aiment == attacker) - RemoveGrapplingHook(targ); // STOP THAT, you parasite! + { + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + if(targ.(weaponentity).hook && targ.(weaponentity).hook.aiment == attacker) + RemoveHook(targ.(weaponentity).hook); + } + } // special rule: gravity bomb does not hit team mates (other than for disconnecting the hook) if(DEATH_ISWEAPON(deathtype, WEP_HOOK) || DEATH_ISWEAPON(deathtype, WEP_TUBA)) diff --git a/qcsrc/server/g_damage.qh b/qcsrc/server/g_damage.qh index 019c8fc9a8..9a4a8b95d7 100644 --- a/qcsrc/server/g_damage.qh +++ b/qcsrc/server/g_damage.qh @@ -55,7 +55,7 @@ float IsFlying(entity a); void UpdateFrags(entity player, int f); // NOTE: f=0 means still count as a (positive) kill, but count no frags for it -void W_SwitchWeapon_Force(Player this, Weapon w); +void W_SwitchWeapon_Force(Player this, Weapon w, .entity weaponentity); entity GiveFrags_randomweapons; void GiveFrags (entity attacker, entity targ, float f, int deathtype); diff --git a/qcsrc/server/g_hook.qc b/qcsrc/server/g_hook.qc index fd725ad35e..36e1e4e52b 100644 --- a/qcsrc/server/g_hook.qc +++ b/qcsrc/server/g_hook.qc @@ -71,24 +71,41 @@ And you should be done! .float hook_length; -void RemoveGrapplingHook(entity pl) +void RemoveGrapplingHooks(entity pl) { - if(pl.hook == NULL) - return; - delete(pl.hook); - pl.hook = NULL; if(pl.move_movetype == MOVETYPE_FLY) set_movetype(pl, MOVETYPE_WALK); + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + if(pl.(weaponentity).hook) + { + delete(pl.(weaponentity).hook); + pl.(weaponentity).hook = NULL; + } + } + //pl.disableclientprediction = false; } +void RemoveHook(entity this) +{ + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + if(this.realowner.(weaponentity).hook == this) + this.realowner.(weaponentity).hook = NULL; + } + + if(this.realowner.move_movetype == MOVETYPE_FLY) + set_movetype(this.realowner, MOVETYPE_WALK); + delete(this); +} + void GrapplingHookReset(entity this) { - if(this.realowner.hook == this) - RemoveGrapplingHook(this.owner); - else // in any case: - delete(this); + RemoveHook(this); } void GrapplingHookThink(entity this); @@ -117,6 +134,7 @@ bool GrapplingHookSend(entity this, entity to, int sf) if(sf & 1) { WriteByte(MSG_ENTITY, etof(this.realowner)); + WriteByte(MSG_ENTITY, weaponslot(this.weaponentity_fld)); } if(sf & 2) { @@ -139,14 +157,15 @@ void GrapplingHookThink(entity this) { float spd, dist, minlength, pullspeed, ropestretch, ropeairfriction, rubberforce, newlength, rubberforce_overstretch; vector dir, org, end, v0, dv, v, myorg, vs; - if(this.realowner.hook != this) // how did that happen? + .entity weaponentity = this.weaponentity_fld; + if(this.realowner.(weaponentity).hook != this) // how did that happen? { error("Owner lost the hook!\n"); return; } if(LostMovetypeFollow(this) || intermission_running || (round_handler_IsActive() && !round_handler_IsRoundStarted()) || ((this.aiment.flags & FL_PROJECTILE) && this.aiment.classname != "nade")) { - RemoveGrapplingHook(this.realowner); + RemoveHook(this); return; } if(this.aiment) @@ -154,7 +173,7 @@ void GrapplingHookThink(entity this) this.nextthink = time; - int s = W_GetGunAlignment(this.realowner); + int s = W_GunAlign(this.realowner.(weaponentity), STAT(GUNALIGN, this.realowner)) - 1; vs = hook_shotorigin[s]; makevectors(this.realowner.v_angle); @@ -206,7 +225,7 @@ void GrapplingHookThink(entity this) v = v0 = WarpZone_RefSys_TransformVelocity(pull_entity, this, pull_entity.velocity); // first pull the rope... - if(this.realowner.hook_state & HOOK_PULLING) + if(this.realowner.(weaponentity).hook_state & HOOK_PULLING) { newlength = this.hook_length; newlength = max(newlength - pullspeed * frametime, minlength); @@ -224,7 +243,7 @@ void GrapplingHookThink(entity this) if(pull_entity.move_movetype == MOVETYPE_FLY) set_movetype(pull_entity, MOVETYPE_WALK); - if(this.realowner.hook_state & HOOK_RELEASING) + if(this.realowner.(weaponentity).hook_state & HOOK_RELEASING) { newlength = dist; this.hook_length = newlength; @@ -266,7 +285,7 @@ void GrapplingHookThink(entity this) if(frozen_pulling && autocvar_g_balance_grapplehook_pull_frozen == 2 && !STAT(FROZEN, this.aiment)) { - RemoveGrapplingHook(this.realowner); + RemoveHook(this); return; } } @@ -338,36 +357,33 @@ void GrapplingHook_Damage(entity this, entity inflictor, entity attacker, float this.realowner.pushltime = time + autocvar_g_maxpushtime; this.realowner.istypefrag = PHYS_INPUT_BUTTON_CHAT(this.realowner); } - RemoveGrapplingHook(this.realowner); + RemoveHook(this); } } -void FireGrapplingHook(entity actor) +void FireGrapplingHook(entity actor, .entity weaponentity) { - entity missile; - vector org; - vector vs; - if(forbidWeaponUse(actor)) return; if(actor.vehicle) return; makevectors(actor.v_angle); - int s = W_GetGunAlignment(actor); - vs = hook_shotorigin[s]; + int s = W_GunAlign(actor.(weaponentity), STAT(GUNALIGN, actor)) - 1; + vector vs = hook_shotorigin[s]; // UGLY WORKAROUND: play this on CH_WEAPON_B so it can't cut off fire sounds sound (actor, CH_WEAPON_B, SND_HOOK_FIRE, VOL_BASE, ATTEN_NORM); - org = actor.origin + actor.view_ofs + v_forward * vs.x + v_right * -vs.y + v_up * vs.z; + vector org = actor.origin + actor.view_ofs + v_forward * vs.x + v_right * -vs.y + v_up * vs.z; tracebox(actor.origin + actor.view_ofs, '-3 -3 -3', '3 3 3', org, MOVE_NORMAL, actor); org = trace_endpos; Send_Effect(EFFECT_HOOK_MUZZLEFLASH, org, '0 0 0', 1); - missile = WarpZone_RefSys_SpawnSameRefSys(actor); + entity missile = WarpZone_RefSys_SpawnSameRefSys(actor); missile.owner = missile.realowner = actor; - actor.hook = missile; + actor.(weaponentity).hook = missile; + missile.weaponentity_fld = weaponentity; missile.reset = GrapplingHookReset; missile.classname = "grapplinghook"; missile.flags = FL_PROJECTILE; diff --git a/qcsrc/server/g_hook.qh b/qcsrc/server/g_hook.qh index 900c23d36a..719bf5b605 100644 --- a/qcsrc/server/g_hook.qh +++ b/qcsrc/server/g_hook.qh @@ -2,7 +2,8 @@ // Wazat's grappling hook .entity hook; -void RemoveGrapplingHook(entity pl); +void RemoveGrapplingHooks(entity pl); +void RemoveHook(entity this); // (note: you can change the hook impulse #'s to whatever you please) .float hook_time; diff --git a/qcsrc/server/g_world.qc b/qcsrc/server/g_world.qc index 8edcf3b8f5..4a9656d26a 100644 --- a/qcsrc/server/g_world.qc +++ b/qcsrc/server/g_world.qc @@ -2092,10 +2092,6 @@ void EndFrame() { antilag_record(it, it, altime); }); - FOREACH_CLIENT(PS(it), { - PlayerState s = PS(it); - s.ps_push(s, it); - }); systems_update(); IL_ENDFRAME(); } diff --git a/qcsrc/server/impulse.qc b/qcsrc/server/impulse.qc index 8a10a6d752..89e2744c2d 100644 --- a/qcsrc/server/impulse.qc +++ b/qcsrc/server/impulse.qc @@ -52,6 +52,8 @@ // weapon switching impulses +bool autocvar_g_weaponswitch_debug; + #define X(slot) \ IMPULSE(weapon_group_##slot) \ { \ @@ -60,7 +62,13 @@ this.impulse = IMP_weapon_group_##slot.impulse; \ return; \ } \ - W_NextWeaponOnImpulse(this, slot); \ + for(int wepslot = 0; wepslot < MAX_WEAPONSLOTS; ++wepslot) \ + { \ + .entity weaponentity = weaponentities[wepslot]; \ + W_NextWeaponOnImpulse(this, slot, weaponentity); \ + if(wepslot == 0 && !autocvar_g_weaponswitch_debug) \ + break; \ + } \ } X(1) X(2) @@ -88,7 +96,13 @@ X(0) noref int prev = -1; \ noref int best = 0; \ noref int next = +1; \ - W_CycleWeapon(this, this.cvar_cl_weaponpriorities[slot], dir); \ + for(int wepslot = 0; wepslot < MAX_WEAPONSLOTS; ++wepslot) \ + { \ + .entity weaponentity = weaponentities[wepslot]; \ + W_CycleWeapon(this, this.cvar_cl_weaponpriorities[slot], dir, weaponentity); \ + if(wepslot == 0 && !autocvar_g_weaponswitch_debug) \ + break; \ + } \ } X(0, prev) X(1, prev) @@ -135,7 +149,13 @@ X(9, next) this.impulse = IMP_weapon_byid_##i.impulse; \ return; \ } \ - W_SwitchWeapon(this, Weapons_from(WEP_FIRST + i)); \ + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) \ + { \ + .entity weaponentity = weaponentities[slot]; \ + W_SwitchWeapon(this, Weapons_from(WEP_FIRST + i), weaponentity); \ + if(slot == 0 && !autocvar_g_weaponswitch_debug) \ + break; \ + } \ } X(0) X(1) @@ -171,7 +191,14 @@ IMPULSE(weapon_next_byid) this.impulse = IMP_weapon_next_byid.impulse; return; } - W_NextWeapon(this, 0); + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + W_NextWeapon(this, 0, weaponentity); + + if(slot == 0 && !autocvar_g_weaponswitch_debug) + break; + } } IMPULSE(weapon_prev_byid) @@ -182,7 +209,14 @@ IMPULSE(weapon_prev_byid) this.impulse = IMP_weapon_prev_byid.impulse; return; } - W_PreviousWeapon(this, 0); + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + W_PreviousWeapon(this, 0, weaponentity); + + if(slot == 0 && !autocvar_g_weaponswitch_debug) + break; + } } IMPULSE(weapon_next_bygroup) @@ -193,7 +227,14 @@ IMPULSE(weapon_next_bygroup) this.impulse = IMP_weapon_next_bygroup.impulse; return; } - W_NextWeapon(this, 1); + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + W_NextWeapon(this, 1, weaponentity); + + if(slot == 0 && !autocvar_g_weaponswitch_debug) + break; + } } IMPULSE(weapon_prev_bygroup) @@ -204,7 +245,14 @@ IMPULSE(weapon_prev_bygroup) this.impulse = IMP_weapon_prev_bygroup.impulse; return; } - W_PreviousWeapon(this, 1); + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + W_PreviousWeapon(this, 1, weaponentity); + + if(slot == 0 && !autocvar_g_weaponswitch_debug) + break; + } } IMPULSE(weapon_next_bypriority) @@ -215,7 +263,14 @@ IMPULSE(weapon_next_bypriority) this.impulse = IMP_weapon_next_bypriority.impulse; return; } - W_NextWeapon(this, 2); + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + W_NextWeapon(this, 2, weaponentity); + + if(slot == 0 && !autocvar_g_weaponswitch_debug) + break; + } } IMPULSE(weapon_prev_bypriority) @@ -226,28 +281,56 @@ IMPULSE(weapon_prev_bypriority) this.impulse = IMP_weapon_prev_bypriority.impulse; return; } - W_PreviousWeapon(this, 2); + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + W_PreviousWeapon(this, 2, weaponentity); + + if(slot == 0 && !autocvar_g_weaponswitch_debug) + break; + } } IMPULSE(weapon_last) { if (this.vehicle) return; if (IS_DEAD(this)) return; - W_LastWeapon(this); + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + W_LastWeapon(this, weaponentity); + + if(slot == 0 && !autocvar_g_weaponswitch_debug) + break; + } } IMPULSE(weapon_best) { if (this.vehicle) return; if (IS_DEAD(this)) return; - W_SwitchWeapon(this, w_getbestweapon(this)); + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + W_SwitchWeapon(this, w_getbestweapon(this, weaponentity), weaponentity); + + if(slot == 0 && !autocvar_g_weaponswitch_debug) + break; + } } IMPULSE(weapon_drop) { if (this.vehicle) return; if (IS_DEAD(this)) return; - W_ThrowWeapon(this, weaponentities[0], W_CalculateProjectileVelocity(this, this.velocity, v_forward * 750, false), '0 0 0', true); + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + W_ThrowWeapon(this, weaponentity, W_CalculateProjectileVelocity(this, this.velocity, v_forward * 750, false), '0 0 0', true); + + if(slot == 0 && !autocvar_g_weaponswitch_debug) + break; + } } IMPULSE(weapon_reload) @@ -255,12 +338,15 @@ IMPULSE(weapon_reload) if (this.vehicle) return; if (IS_DEAD(this)) return; if (forbidWeaponUse(this)) return; - Weapon w = PS(this).m_weapon; entity actor = this; for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) { .entity weaponentity = weaponentities[slot]; + Weapon w = this.(weaponentity).m_weapon; w.wr_reload(w, actor, weaponentity); + + if(slot == 0 && !autocvar_g_weaponswitch_debug) + break; } } diff --git a/qcsrc/server/miscfunctions.qc b/qcsrc/server/miscfunctions.qc index e90dbeb966..220ebc3af1 100644 --- a/qcsrc/server/miscfunctions.qc +++ b/qcsrc/server/miscfunctions.qc @@ -26,6 +26,7 @@ #include "../common/items/_mod.qh" #include "../common/state.qh" #include "../common/effects/qc/globalsound.qh" +#include "../common/wepent.qh" #include "../lib/csqcmodel/sv_model.qh" #include "../lib/warpzone/anglestransform.qh" #include "../lib/warpzone/server.qh" @@ -260,6 +261,8 @@ string formatmessage(entity this, string msg) replacement = substring(msg, p, 2); escape = substring(msg, p + 1, 1); + .entity weaponentity = weaponentities[0]; // TODO: unhardcode + switch(escape) { case "%": replacement = "%"; break; @@ -270,7 +273,7 @@ string formatmessage(entity this, string msg) case "l": replacement = NearestLocation(this.origin); break; case "y": replacement = NearestLocation(cursor); break; case "d": replacement = NearestLocation(this.death_origin); break; - case "w": replacement = ((PS(this).m_weapon == WEP_Null) ? ((PS(this).m_switchweapon == WEP_Null) ? Weapons_from(this.cnt) : PS(this).m_switchweapon) : PS(this).m_weapon).m_name; break; + case "w": replacement = ((this.(weaponentity).m_weapon == WEP_Null) ? ((this.(weaponentity).m_switchweapon == WEP_Null) ? Weapons_from(this.(weaponentity).cnt) : this.(weaponentity).m_switchweapon) : this.(weaponentity).m_weapon).m_name; break; case "W": replacement = ammoitems; break; case "x": replacement = ((cursor_ent.netname == "" || !cursor_ent) ? "nothing" : cursor_ent.netname); break; case "s": replacement = ftos(vlen(this.velocity - this.velocity_z * '0 0 1')); break; @@ -448,7 +451,14 @@ void GetCvars(entity this, int f) if (f > 0) { if (s == "cl_weaponpriority") - if (PS(this)) PS(this).m_switchweapon = w_getbestweapon(this); + { + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + if (this.(weaponentity) && (this.(weaponentity).m_weapon != WEP_Null || slot == 0)) + this.(weaponentity).m_switchweapon = w_getbestweapon(this, weaponentity); + } + } if (s == "cl_allow_uidtracking") PlayerStats_GameReport_AddPlayer(this); } @@ -1074,7 +1084,7 @@ bool WarpZone_Projectile_Touch_ImpactFilter_Callback(entity this, entity toucher if(this.classname == "nade") return false; // no checks here else if(this.classname == "grapplinghook") - RemoveGrapplingHook(this.realowner); + RemoveHook(this); else if(this.classname == "spike") { W_Crylink_Dequeue(this); diff --git a/qcsrc/server/mutators/events.qh b/qcsrc/server/mutators/events.qh index 21c8ef9a5c..5276a64e93 100644 --- a/qcsrc/server/mutators/events.qh +++ b/qcsrc/server/mutators/events.qh @@ -137,12 +137,14 @@ MUTATOR_HOOKABLE(FormatMessage, EV_FormatMessage); /** returns true if throwing the current weapon shall not be allowed */ #define EV_ForbidThrowCurrentWeapon(i, o) \ /** player */ i(entity, MUTATOR_ARGV_0_entity) \ + /** weapon entity */ i(entity, MUTATOR_ARGV_1_entity) \ /**/ MUTATOR_HOOKABLE(ForbidThrowCurrentWeapon, EV_ForbidThrowCurrentWeapon); /** returns true if dropping the current weapon shall not be allowed at any time including death */ #define EV_ForbidDropCurrentWeapon(i, o) \ - /** player */ i(entity, MUTATOR_ARGV_0_entity) \ + /** player */ i(entity, MUTATOR_ARGV_0_entity) \ + /** weapon id */ i(int, MUTATOR_ARGV_1_int) \ /**/ MUTATOR_HOOKABLE(ForbidDropCurrentWeapon, EV_ForbidDropCurrentWeapon); @@ -367,7 +369,8 @@ MUTATOR_HOOKABLE(PlayerDamaged, EV_PlayerDamaged); * Called by W_DecreaseAmmo */ #define EV_W_DecreaseAmmo(i, o) \ - /** actor */ i(entity, MUTATOR_ARGV_0_entity) \ + /** actor */ i(entity, MUTATOR_ARGV_0_entity) \ + /** weapon entity */ i(entity, MUTATOR_ARGV_1_entity) \ /**/ MUTATOR_HOOKABLE(W_DecreaseAmmo, EV_W_DecreaseAmmo); diff --git a/qcsrc/server/player.qc b/qcsrc/server/player.qc index 9125b50d7c..ce71f6b5e3 100644 --- a/qcsrc/server/player.qc +++ b/qcsrc/server/player.qc @@ -24,6 +24,7 @@ #include "../common/effects/qc/all.qh" #include "../common/mutators/mutator/waypoints/waypointsprites.qh" #include "../common/triggers/include.qh" +#include "../common/wepent.qh" #include "weapons/weaponstats.qh" @@ -485,6 +486,7 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, valid_damage_for_weaponstats = 0; Weapon awep = WEP_Null; + .entity weaponentity = weaponentities[0]; // TODO: unhardcode if(vbot || IS_REAL_CLIENT(this)) if(abot || IS_REAL_CLIENT(attacker)) @@ -492,7 +494,7 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, if(DIFF_TEAM(this, attacker)) { if(DEATH_ISSPECIAL(deathtype)) - awep = PS(attacker).m_weapon; + awep = attacker.(weaponentity).m_weapon; else awep = DEATH_WEAPONOF(deathtype); valid_damage_for_weaponstats = 1; @@ -502,7 +504,7 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, da = da - max(this.armorvalue, 0); if(valid_damage_for_weaponstats) { - WeaponStats_LogDamage(awep.m_id, abot, PS(this).m_weapon.m_id, vbot, dh + da); + WeaponStats_LogDamage(awep.m_id, abot, this.(weaponentity).m_weapon.m_id, vbot, dh + da); } if (damage) { @@ -521,7 +523,7 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, } if(valid_damage_for_weaponstats) - WeaponStats_LogKill(awep.m_id, abot, PS(this).m_weapon.m_id, vbot); + WeaponStats_LogKill(awep.m_id, abot, this.(weaponentity).m_weapon.m_id, vbot); if(autocvar_sv_gentle < 1) if(sound_allowed(MSG_BROADCAST, attacker)) @@ -560,16 +562,14 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, MUTATOR_CALLHOOK(PlayerDies, inflictor, attacker, this, deathtype, damage); excess = M_ARGV(4, float); - Weapon wep = PS(this).m_weapon; - /*for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + Weapon wep = this.(weaponentity).m_weapon; + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) { - .entity weaponentity = weaponentities[slot]; - wep.wr_playerdeath(wep, this, weaponentity); - }*/ - .entity weaponentity = weaponentities[0]; // TODO: unhardcode - wep.wr_playerdeath(wep, this, weaponentity); + .entity went = weaponentities[slot]; + wep.wr_playerdeath(wep, this, went); + } - RemoveGrapplingHook(this); + RemoveGrapplingHooks(this); Portal_ClearAllLater(this); @@ -591,7 +591,11 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, // clear waypoints WaypointSprite_PlayerDead(this); // throw a weapon - SpawnThrownWeapon(this, this.origin + (this.mins + this.maxs) * 0.5, PS(this).m_switchweapon.m_id); + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity went = weaponentities[slot]; + SpawnThrownWeapon(this, this.origin + (this.mins + this.maxs) * 0.5, this.(went).m_switchweapon.m_id, went); + } // become fully visible this.alpha = default_player_alpha; diff --git a/qcsrc/server/portals.qc b/qcsrc/server/portals.qc index 12083e423c..b41c53bbcc 100644 --- a/qcsrc/server/portals.qc +++ b/qcsrc/server/portals.qc @@ -481,8 +481,12 @@ void Portal_Think(entity this) if(it != o || time >= this.portal_activatetime) Portal_Think_TryTeleportPlayer(this, it, g); - if(it.hook) - Portal_Think_TryTeleportPlayer(this, it.hook, g); + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + if(it.(weaponentity).hook) + Portal_Think_TryTeleportPlayer(this, it.(weaponentity).hook, g); + } )); this.solid = SOLID_TRIGGER; this.aiment = o; diff --git a/qcsrc/server/sv_main.qc b/qcsrc/server/sv_main.qc index 0c36a77c5b..b510b43c80 100644 --- a/qcsrc/server/sv_main.qc +++ b/qcsrc/server/sv_main.qc @@ -99,7 +99,17 @@ void CreatureFrame_FallDamage(entity this) { // check for falling damage float velocity_len = vlen(this.velocity); - if(!this.hook.state) + bool have_hook = false; + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + if(this.(weaponentity).hook && this.(weaponentity).hook.state) + { + have_hook = true; + break; + } + } + if(!have_hook) { float dm = vlen(this.oldvelocity) - velocity_len; // dm is now the velocity DECREASE. Velocity INCREASE should never cause a sound or any damage. if (IS_DEAD(this)) diff --git a/qcsrc/server/tests.qc b/qcsrc/server/tests.qc index 96674db702..50dc5a35bc 100644 --- a/qcsrc/server/tests.qc +++ b/qcsrc/server/tests.qc @@ -26,7 +26,7 @@ TEST(Weapons, Hurt) it.items |= IT_UNLIMITED_AMMO; Weapon wep = WEP_VORTEX; W_GiveWeapon(it, wep.m_id); - W_SwitchWeapon_Force(it, wep); + W_SwitchWeapon_Force(it, wep, weaponentities[0]); it = b; PHYS_INPUT_BUTTON_JUMP(it) = true; diff --git a/qcsrc/server/weapons/hitplot.qc b/qcsrc/server/weapons/hitplot.qc index 372f7357b4..d148ab54f4 100644 --- a/qcsrc/server/weapons/hitplot.qc +++ b/qcsrc/server/weapons/hitplot.qc @@ -4,6 +4,7 @@ #include "../g_subs.qh" #include #include +#include vector W_HitPlotUnnormalizedUntransform(vector screenforward, vector screenright, vector screenup, vector v) { @@ -51,7 +52,7 @@ vector W_HitPlotNormalizedUntransform(vector org, entity targ, vector screenforw return ret; } -void W_HitPlotAnalysis(entity player, vector screenforward, vector screenright, vector screenup) +void W_HitPlotAnalysis(entity player, .entity weaponentity, vector screenforward, vector screenright, vector screenup) { vector hitplot; vector org; @@ -73,7 +74,7 @@ void W_HitPlotAnalysis(entity player, vector screenforward, vector screenright, antilag_takeback(trace_ent, store, time - lag); hitplot = W_HitPlotNormalizedUntransform(org, trace_ent, screenforward, screenright, screenup, trace_endpos); antilag_restore(trace_ent, store); - fputs(player.hitplotfh, strcat(ftos(hitplot.x), " ", ftos(hitplot.y), " ", ftos(hitplot.z), " ", ftos(PS(player).m_switchweapon.m_id), "\n")); + fputs(player.hitplotfh, strcat(ftos(hitplot.x), " ", ftos(hitplot.y), " ", ftos(hitplot.z), " ", ftos(player.(weaponentity).m_switchweapon.m_id), "\n")); //print(strcat(ftos(hitplot_x), " ", ftos(hitplot_y), " ", ftos(hitplot_z), "\n")); } } diff --git a/qcsrc/server/weapons/hitplot.qh b/qcsrc/server/weapons/hitplot.qh index 8aa15a61b4..89f7f50504 100644 --- a/qcsrc/server/weapons/hitplot.qh +++ b/qcsrc/server/weapons/hitplot.qh @@ -2,6 +2,6 @@ .float hitplotfh; -void W_HitPlotAnalysis(entity player, vector screenforward, vector screenright, vector screenup); +void W_HitPlotAnalysis(entity player, .entity weaponentity, vector screenforward, vector screenright, vector screenup); void W_HitPlotOpen(entity player); void W_HitPlotClose(entity player); diff --git a/qcsrc/server/weapons/selection.qc b/qcsrc/server/weapons/selection.qc index 539371a53c..d7d8fc9c1f 100644 --- a/qcsrc/server/weapons/selection.qc +++ b/qcsrc/server/weapons/selection.qc @@ -9,6 +9,7 @@ #include #include #include +#include // switch between weapons void Send_WeaponComplain(entity e, float wpn, float type) @@ -39,7 +40,7 @@ void Weapon_whereis(Weapon this, entity cl) }); } -bool client_hasweapon(entity this, Weapon wpn, float andammo, bool complain) +bool client_hasweapon(entity this, Weapon wpn, .entity weaponentity, float andammo, bool complain) { float f = 0; @@ -70,11 +71,11 @@ bool client_hasweapon(entity this, Weapon wpn, float andammo, bool complain) } else { - f = wpn.wr_checkammo1(wpn, this) + wpn.wr_checkammo2(wpn, this); + f = wpn.wr_checkammo1(wpn, this, weaponentity) + wpn.wr_checkammo2(wpn, this, weaponentity); // always allow selecting the Mine Layer if we placed mines, so that we can detonate them if(wpn == WEP_MINE_LAYER) - IL_EACH(g_mines, it.owner == this, + IL_EACH(g_mines, it.owner == this && it.weaponentity_fld == weaponentity, { f = 1; break; // no need to continue @@ -120,7 +121,7 @@ bool client_hasweapon(entity this, Weapon wpn, float andammo, bool complain) return false; } -float W_GetCycleWeapon(entity this, string weaponorder, float dir, float imp, float complain, float skipmissing) +float W_GetCycleWeapon(entity this, string weaponorder, float dir, float imp, float complain, float skipmissing, .entity weaponentity) { // We cannot tokenize in this function, as GiveItems calls this // function. Thus we must use car/cdr. @@ -131,10 +132,10 @@ float W_GetCycleWeapon(entity this, string weaponorder, float dir, float imp, fl float weaponcur; entity wep; - if(skipmissing || this.selectweapon == 0) - weaponcur = PS(this).m_switchweapon.m_id; + if(skipmissing || this.(weaponentity).selectweapon == 0) + weaponcur = this.(weaponentity).m_switchweapon.m_id; else - weaponcur = this.selectweapon; + weaponcur = this.(weaponentity).selectweapon; if(dir == 0) switchtonext = 1; @@ -167,7 +168,7 @@ float W_GetCycleWeapon(entity this, string weaponorder, float dir, float imp, fl ++c; - if(!skipmissing || client_hasweapon(this, wep, true, false)) + if(!skipmissing || client_hasweapon(this, wep, weaponentity, true, false)) { if(switchtonext) return weaponwant; @@ -224,7 +225,7 @@ float W_GetCycleWeapon(entity this, string weaponorder, float dir, float imp, fl --c; if(c == 0) { - client_hasweapon(this, wep, true, true); + client_hasweapon(this, wep, weaponentity, true, true); break; } } @@ -232,97 +233,94 @@ float W_GetCycleWeapon(entity this, string weaponorder, float dir, float imp, fl return 0; } -void W_SwitchWeapon_Force(Player this, Weapon wep) +void W_SwitchWeapon_Force(Player this, Weapon wep, .entity weaponentity) { - TC(Player, this); TC(Weapon, wep); - this.cnt = PS(this).m_switchweapon.m_id; - PS(this).m_switchweapon = wep; - this.selectweapon = wep.m_id; + TC(Weapon, wep); + this.(weaponentity).cnt = this.(weaponentity).m_switchweapon.m_id; + this.(weaponentity).m_switchweapon = wep; + this.(weaponentity).selectweapon = wep.m_id; } // perform weapon to attack (weaponstate and attack_finished check is here) -void W_SwitchToOtherWeapon(entity this) +void W_SwitchToOtherWeapon(entity this, .entity weaponentity) { // hack to ensure it switches to an OTHER weapon (in case the other fire mode still has ammo, we want that anyway) Weapon ww; - WepSet set = WepSet_FromWeapon(PS(this).m_weapon); + WepSet set = WepSet_FromWeapon(this.(weaponentity).m_weapon); if (this.weapons & set) { this.weapons &= ~set; - ww = w_getbestweapon(this); + ww = w_getbestweapon(this, weaponentity); this.weapons |= set; } else { - ww = w_getbestweapon(this); + ww = w_getbestweapon(this, weaponentity); } if (ww == WEP_Null) return; - W_SwitchWeapon_Force(this, ww); + W_SwitchWeapon_Force(this, ww, weaponentity); } -void W_SwitchWeapon(entity this, Weapon w) +void W_SwitchWeapon(entity this, Weapon w, .entity weaponentity) { - if (PS(this).m_switchweapon != w) + if(this.(weaponentity).m_switchweapon != w) { - if (client_hasweapon(this, w, true, true)) - W_SwitchWeapon_Force(this, w); + if(client_hasweapon(this, w, weaponentity, true, true)) + W_SwitchWeapon_Force(this, w, weaponentity); else - this.selectweapon = w.m_id; // update selectweapon ANYWAY + this.(weaponentity).selectweapon = w.m_id; // update selectweapon anyway } - else if(!forbidWeaponUse(this)) { + else if(!forbidWeaponUse(this)) + { entity actor = this; - for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) - { - .entity weaponentity = weaponentities[slot]; - w.wr_reload(w, actor, weaponentity); - } + w.wr_reload(w, actor, weaponentity); } } -void W_CycleWeapon(entity this, string weaponorder, float dir) +void W_CycleWeapon(entity this, string weaponorder, float dir, .entity weaponentity) { float w; - w = W_GetCycleWeapon(this, weaponorder, dir, -1, 1, true); + w = W_GetCycleWeapon(this, weaponorder, dir, -1, 1, true, weaponentity); if(w > 0) - W_SwitchWeapon(this, Weapons_from(w)); + W_SwitchWeapon(this, Weapons_from(w), weaponentity); } -void W_NextWeaponOnImpulse(entity this, float imp) +void W_NextWeaponOnImpulse(entity this, float imp, .entity weaponentity) { float w; - w = W_GetCycleWeapon(this, this.cvar_cl_weaponpriority, +1, imp, 1, (this.cvar_cl_weaponimpulsemode == 0)); + w = W_GetCycleWeapon(this, this.cvar_cl_weaponpriority, +1, imp, 1, (this.cvar_cl_weaponimpulsemode == 0), weaponentity); if(w > 0) - W_SwitchWeapon(this, Weapons_from(w)); + W_SwitchWeapon(this, Weapons_from(w), weaponentity); } // next weapon -void W_NextWeapon(entity this, int list) +void W_NextWeapon(entity this, int list, .entity weaponentity) { if(list == 0) - W_CycleWeapon(this, weaponorder_byid, -1); + W_CycleWeapon(this, weaponorder_byid, -1, weaponentity); else if(list == 1) - W_CycleWeapon(this, this.weaponorder_byimpulse, -1); + W_CycleWeapon(this, this.weaponorder_byimpulse, -1, weaponentity); else if(list == 2) - W_CycleWeapon(this, this.cvar_cl_weaponpriority, -1); + W_CycleWeapon(this, this.cvar_cl_weaponpriority, -1, weaponentity); } // prev weapon -void W_PreviousWeapon(entity this, float list) +void W_PreviousWeapon(entity this, float list, .entity weaponentity) { if(list == 0) - W_CycleWeapon(this, weaponorder_byid, +1); + W_CycleWeapon(this, weaponorder_byid, +1, weaponentity); else if(list == 1) - W_CycleWeapon(this, this.weaponorder_byimpulse, +1); + W_CycleWeapon(this, this.weaponorder_byimpulse, +1, weaponentity); else if(list == 2) - W_CycleWeapon(this, this.cvar_cl_weaponpriority, +1); + W_CycleWeapon(this, this.cvar_cl_weaponpriority, +1, weaponentity); } // previously used if exists and has ammo, (second) best otherwise -void W_LastWeapon(entity this) +void W_LastWeapon(entity this, .entity weaponentity) { - Weapon wep = Weapons_from(this.cnt); - if (client_hasweapon(this, wep, true, false)) - W_SwitchWeapon(this, wep); + Weapon wep = Weapons_from(this.(weaponentity).cnt); + if (client_hasweapon(this, wep, weaponentity, true, false)) + W_SwitchWeapon(this, wep, weaponentity); else - W_SwitchToOtherWeapon(this); + W_SwitchToOtherWeapon(this, weaponentity); } diff --git a/qcsrc/server/weapons/selection.qh b/qcsrc/server/weapons/selection.qh index 0c30b7c121..071a0fea8b 100644 --- a/qcsrc/server/weapons/selection.qh +++ b/qcsrc/server/weapons/selection.qh @@ -4,28 +4,28 @@ void Send_WeaponComplain(entity e, float wpn, float type); .float hasweapon_complain_spam; -bool client_hasweapon(entity this, Weapon wpn, float andammo, bool complain); +bool client_hasweapon(entity this, Weapon wpn, .entity weaponentity, float andammo, bool complain); .int weaponcomplainindex; -float W_GetCycleWeapon(entity this, string weaponorder, float dir, float imp, float complain, float skipmissing); +float W_GetCycleWeapon(entity this, string weaponorder, float dir, float imp, float complain, float skipmissing, .entity weaponentity); -#define w_getbestweapon(ent) Weapons_from(W_GetCycleWeapon(ent, ent.cvar_cl_weaponpriority, 0, -1, false, true)) +#define w_getbestweapon(ent,wepent) Weapons_from(W_GetCycleWeapon(ent, ent.cvar_cl_weaponpriority, 0, -1, false, true, wepent)) -void W_SwitchWeapon_Force(Player this, Weapon w); +void W_SwitchWeapon_Force(Player this, Weapon w, .entity weaponentity); // perform weapon to attack (weaponstate and attack_finished check is here) -void W_SwitchToOtherWeapon(entity this); -void W_SwitchWeapon(entity this, Weapon imp); +void W_SwitchToOtherWeapon(entity this, .entity weaponentity); +void W_SwitchWeapon(entity this, Weapon imp, .entity weaponentity); -void W_CycleWeapon(entity this, string weaponorder, float dir); +void W_CycleWeapon(entity this, string weaponorder, float dir, .entity weaponentity); -void W_NextWeaponOnImpulse(entity this, float imp); +void W_NextWeaponOnImpulse(entity this, float imp, .entity weaponentity); // next weapon -void W_NextWeapon(entity this, float list); +void W_NextWeapon(entity this, float list, .entity weaponentity); // prev weapon -void W_PreviousWeapon(entity this, float list); +void W_PreviousWeapon(entity this, float list, .entity weaponentity); // previously used if exists and has ammo, (second) best otherwise -void W_LastWeapon(entity this); +void W_LastWeapon(entity this, .entity weaponentity); diff --git a/qcsrc/server/weapons/throwing.qc b/qcsrc/server/weapons/throwing.qc index bd69e33246..4114c3c58b 100644 --- a/qcsrc/server/weapons/throwing.qc +++ b/qcsrc/server/weapons/throwing.qc @@ -11,6 +11,7 @@ #include #include #include +#include void thrown_wep_think(entity this) { @@ -31,7 +32,7 @@ void thrown_wep_think(entity this) } // returns amount of ammo used as string, or -1 for failure, or 0 for no ammo count -string W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vector velo) +string W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vector velo, .entity weaponentity) { float thisammo; string s; @@ -45,9 +46,9 @@ string W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vecto wep.owner = wep.enemy = own; wep.flags |= FL_TOSSED; wep.colormap = own.colormap; - wep.glowmod = weaponentity_glowmod(info, own, own.clientcolors); + wep.glowmod = weaponentity_glowmod(info, own, own.clientcolors, own.(weaponentity)); - W_DropEvent(wr_drop,own,wpn,wep); + W_DropEvent(wr_drop,own,wpn,wep,weaponentity); if(WepSet_FromWeapon(Weapons_from(wpn)) & WEPSET_SUPERWEAPONS) { @@ -97,11 +98,11 @@ string W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vecto if(doreduce && g_weapon_stay == 2) { // if our weapon is loaded, give its load back to the player - int i = PS(own).m_weapon.m_id; - if(own.(weapon_load[i]) > 0) + int i = own.(weaponentity).m_weapon.m_id; + if(own.(weaponentity).(weapon_load[i]) > 0) { - own.(ammotype) += own.(weapon_load[i]); - own.(weapon_load[i]) = -1; // schedule the weapon for reloading + own.(ammotype) += own.(weaponentity).(weapon_load[i]); + own.(weaponentity).(weapon_load[i]) = -1; // schedule the weapon for reloading } wep.(ammotype) = 0; @@ -109,11 +110,11 @@ string W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vecto else if(doreduce) { // if our weapon is loaded, give its load back to the player - int i = PS(own).m_weapon.m_id; - if(own.(weapon_load[i]) > 0) + int i = own.(weaponentity).m_weapon.m_id; + if(own.(weaponentity).(weapon_load[i]) > 0) { - own.(ammotype) += own.(weapon_load[i]); - own.(weapon_load[i]) = -1; // schedule the weapon for reloading + own.(ammotype) += own.(weaponentity).(weapon_load[i]); + own.(weaponentity).(weapon_load[i]) = -1; // schedule the weapon for reloading } thisammo = min(own.(ammotype), wep.(ammotype)); @@ -138,7 +139,7 @@ string W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vecto bool W_IsWeaponThrowable(entity this, int w) { - if (MUTATOR_CALLHOOK(ForbidDropCurrentWeapon, this)) + if (MUTATOR_CALLHOOK(ForbidDropCurrentWeapon, this, w)) return false; if (!autocvar_g_pickup_items) return false; @@ -167,10 +168,10 @@ bool W_IsWeaponThrowable(entity this, int w) // toss current weapon void W_ThrowWeapon(entity this, .entity weaponentity, vector velo, vector delta, float doreduce) { - Weapon w = PS(this).m_weapon; + Weapon w = this.(weaponentity).m_weapon; if (w == WEP_Null) return; // just in case - if(MUTATOR_CALLHOOK(ForbidThrowCurrentWeapon, this)) + if(MUTATOR_CALLHOOK(ForbidThrowCurrentWeapon, this, this.(weaponentity))) return; if(!autocvar_g_weapon_throwable) return; @@ -183,16 +184,18 @@ void W_ThrowWeapon(entity this, .entity weaponentity, vector velo, vector delta, if(!(this.weapons & set)) return; this.weapons &= ~set; - W_SwitchWeapon_Force(this, w_getbestweapon(this)); - string a = W_ThrowNewWeapon(this, w.m_id, doreduce, this.origin + delta, velo); + W_SwitchWeapon_Force(this, w_getbestweapon(this, weaponentity), weaponentity); + string a = W_ThrowNewWeapon(this, w.m_id, doreduce, this.origin + delta, velo, weaponentity); if(!a) return; Send_Notification(NOTIF_ONE, this, MSG_MULTI, ITEM_WEAPON_DROP, a, w.m_id); } -void SpawnThrownWeapon(entity this, vector org, float w) +void SpawnThrownWeapon(entity this, vector org, float w, .entity weaponentity) { - if(this.weapons & WepSet_FromWeapon(PS(this).m_weapon)) - if(W_IsWeaponThrowable(this, PS(this).m_weapon.m_id)) - W_ThrowNewWeapon(this, PS(this).m_weapon.m_id, false, org, randomvec() * 125 + '0 0 200'); + entity wep = this.(weaponentity).m_weapon; + + if(this.weapons & WepSet_FromWeapon(wep)) + if(W_IsWeaponThrowable(this, wep.m_id)) + W_ThrowNewWeapon(this, wep.m_id, false, org, randomvec() * 125 + '0 0 200', weaponentity); } diff --git a/qcsrc/server/weapons/throwing.qh b/qcsrc/server/weapons/throwing.qh index a03968083e..01ab21ba63 100644 --- a/qcsrc/server/weapons/throwing.qh +++ b/qcsrc/server/weapons/throwing.qh @@ -4,11 +4,11 @@ void thrown_wep_think(entity this); // returns amount of ammo used as string, or -1 for failure, or 0 for no ammo count -string W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vector velo); +string W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vector velo, .entity weaponentity); bool W_IsWeaponThrowable(entity this, int w); // toss current weapon void W_ThrowWeapon(entity this, .entity weaponentity, vector velo, vector delta, float doreduce); -void SpawnThrownWeapon(entity this, vector org, float w); +void SpawnThrownWeapon(entity this, vector org, float w, .entity weaponentity); diff --git a/qcsrc/server/weapons/tracing.qc b/qcsrc/server/weapons/tracing.qc index b49ed88f59..1417717e83 100644 --- a/qcsrc/server/weapons/tracing.qc +++ b/qcsrc/server/weapons/tracing.qc @@ -28,7 +28,7 @@ void W_SetupShot_Dir_ProjectileSize_Range(entity ent, .entity weaponentity, vect float oldsolid; vector vecs, dv; oldsolid = ent.dphitcontentsmask; - if (IS_PLAYER(ent) && PS(ent).m_weapon == WEP_RIFLE) + if (IS_PLAYER(ent) && ent.(weaponentity).m_weapon == WEP_RIFLE) ent.dphitcontentsmask = DPCONTENTS_BODY | DPCONTENTS_CORPSE; else ent.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE; @@ -54,10 +54,10 @@ void W_SetupShot_Dir_ProjectileSize_Range(entity ent, .entity weaponentity, vect // track max damage if (IS_PLAYER(ent) && accuracy_canbegooddamage(ent)) - accuracy_add(ent, PS(ent).m_weapon.m_id, maxdamage, 0); + accuracy_add(ent, ent.(weaponentity).m_weapon.m_id, maxdamage, 0); if(IS_PLAYER(ent)) - W_HitPlotAnalysis(ent, v_forward, v_right, v_up); + W_HitPlotAnalysis(ent, weaponentity, v_forward, v_right, v_up); vector md = ent.(weaponentity).movedir; if(md.x > 0) @@ -197,7 +197,7 @@ void W_SetupProjVelocity_Explicit(entity proj, vector dir, vector upDir, float p // Ballistics Tracing // ==================== -void FireRailgunBullet (entity this, vector start, vector end, float bdamage, float bforce, float mindist, float maxdist, float halflifedist, float forcehalflifedist, int deathtype) +void FireRailgunBullet (entity this, .entity weaponentity, vector start, vector end, float bdamage, float bforce, float mindist, float maxdist, float halflifedist, float forcehalflifedist, int deathtype) { vector hitloc, force, endpoint, dir; entity ent, endent; @@ -334,7 +334,7 @@ void FireRailgunBullet (entity this, vector start, vector end, float bdamage, fl } // calculate hits and fired shots for hitscan - accuracy_add(this, PS(this).m_weapon.m_id, 0, min(bdamage, totaldmg)); + accuracy_add(this, this.(weaponentity).m_weapon.m_id, 0, min(bdamage, totaldmg)); trace_endpos = endpoint; trace_ent = endent; @@ -349,7 +349,7 @@ void fireBullet_trace_callback(vector start, vector hit, vector end) fireBullet_last_hit = NULL; } -void fireBullet(entity this, vector start, vector dir, float spread, float max_solid_penetration, float damage, float force, float dtype, int tracereffects) +void fireBullet(entity this, .entity weaponentity, vector start, vector dir, float spread, float max_solid_penetration, float damage, float force, float dtype, int tracereffects) { vector end; @@ -442,7 +442,7 @@ void fireBullet(entity this, vector start, vector dir, float spread, float max_s // do not exceed 100% float added_damage = min(damage - total_damage, damage * solid_penetration_left); total_damage += damage * solid_penetration_left; - accuracy_add(this, PS(this).m_weapon.m_id, 0, added_damage); + accuracy_add(this, this.(weaponentity).m_weapon.m_id, 0, added_damage); } } diff --git a/qcsrc/server/weapons/tracing.qh b/qcsrc/server/weapons/tracing.qh index 21f12c1e4c..aec274143b 100644 --- a/qcsrc/server/weapons/tracing.qh +++ b/qcsrc/server/weapons/tracing.qh @@ -49,9 +49,9 @@ void W_SetupProjVelocity_Explicit(entity proj, vector dir, vector upDir, float p .float railgundistance; .vector railgunforce; -void FireRailgunBullet (entity this, vector start, vector end, float bdamage, float bforce, float mindist, float maxdist, float halflifedist, float forcehalflifedist, int deathtype); +void FireRailgunBullet (entity this, .entity weaponentity, vector start, vector end, float bdamage, float bforce, float mindist, float maxdist, float halflifedist, float forcehalflifedist, int deathtype); entity fireBullet_trace_callback_eff; entity fireBullet_last_hit; void fireBullet_trace_callback(vector start, vector hit, vector end); -void fireBullet(entity this, vector start, vector dir, float spread, float max_solid_penetration, float damage, float force, float dtype, int tracereffects); +void fireBullet(entity this, .entity weaponentity, vector start, vector dir, float spread, float max_solid_penetration, float damage, float force, float dtype, int tracereffects); diff --git a/qcsrc/server/weapons/weaponsystem.qc b/qcsrc/server/weapons/weaponsystem.qc index c0d302e223..6139f2879c 100644 --- a/qcsrc/server/weapons/weaponsystem.qc +++ b/qcsrc/server/weapons/weaponsystem.qc @@ -15,6 +15,7 @@ #include #include #include +#include .int state; @@ -61,8 +62,10 @@ vector CL_Weapon_GetShotOrg(int wpn) return ret; } -..entity weaponentity_fld; .float m_alpha; +.string w_weaponname; +.int w_dmg; +.int w_deadflag; void CL_Weaponentity_Think(entity this) { @@ -83,16 +86,16 @@ void CL_Weaponentity_Think(entity this) if (this.weaponchild) this.weaponchild.model = ""; return; } - if (this.weaponname != this.owner.weaponname - || this.dmg != this.owner.modelindex - || this.deadflag != this.owner.deadflag) + if (this.w_weaponname != this.weaponname + || this.w_dmg != this.modelindex + || this.w_deadflag != this.deadflag) { // owner changed weapons; update appearance - this.weaponname = this.owner.weaponname; - this.dmg = this.owner.modelindex; - this.deadflag = this.owner.deadflag; + this.w_weaponname = this.weaponname; + this.w_dmg = this.modelindex; + this.w_deadflag = this.deadflag; - CL_WeaponEntity_SetModel(this, this.owner.weaponname, true); + CL_WeaponEntity_SetModel(this, this.weaponname, true); } this.alpha = -1; // TODO: don't render this entity at all @@ -111,6 +114,8 @@ void CL_Weaponentity_Think(entity this) void CL_ExteriorWeaponentity_Think(entity this) { this.nextthink = time; + .entity weaponentity = this.weaponentity_fld; + entity w_ent = this.owner.(weaponentity); if (this.owner.exteriorweaponentity != this) { delete(this); @@ -121,15 +126,15 @@ void CL_ExteriorWeaponentity_Think(entity this) this.model = ""; return; } - if (this.weaponname != this.owner.weaponname || this.dmg != this.owner.modelindex - || this.deadflag != this.owner.deadflag) + if (this.weaponname != w_ent.weaponname || this.dmg != w_ent.modelindex + || this.deadflag != w_ent.deadflag) { - this.weaponname = this.owner.weaponname; - this.dmg = this.owner.modelindex; - this.deadflag = this.owner.deadflag; - if (this.owner.weaponname != "") + this.weaponname = w_ent.weaponname; + this.dmg = w_ent.modelindex; + this.deadflag = w_ent.deadflag; + if (w_ent.weaponname != "") { - _setmodel(this, W_Model(strcat("v_", this.owner.weaponname, ".md3"))); + _setmodel(this, W_Model(strcat("v_", w_ent.weaponname, ".md3"))); setsize(this, '0 0 0', '0 0 0'); } else this.model = ""; @@ -152,8 +157,8 @@ void CL_ExteriorWeaponentity_Think(entity this) else if (this.owner.alpha != 0) this.alpha = this.owner.alpha; else this.alpha = 1; - Weapon wep = PS(this.owner).m_weapon; - if (wep) this.glowmod = weaponentity_glowmod(wep, this.owner, this.owner.clientcolors); + 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; CSQCMODEL_AUTOUPDATE(this); @@ -173,11 +178,14 @@ void CL_SpawnWeaponentity(entity actor, .entity weaponentity) view.viewmodelforclient = actor; setcefc(view, CL_Weaponentity_CustomizeEntityForClient); - if (weaponentity == weaponentities[0]) + wepent_link(view); + + if (weaponentity == weaponentities[0]) // only one exterior model, thank you very much { entity exterior = actor.exteriorweaponentity = new(exteriorweaponentity); exterior.solid = SOLID_NOT; exterior.owner = actor; + exterior.weaponentity_fld = weaponentity; setorigin(exterior, '0 0 0'); setthink(exterior, CL_ExteriorWeaponentity_Think); exterior.nextthink = time; @@ -189,8 +197,8 @@ void CL_SpawnWeaponentity(entity actor, .entity weaponentity) // Weapon subs void w_clear(Weapon thiswep, entity actor, .entity weaponentity, int fire) { - PS(actor).m_weapon = WEP_Null; - PS(actor).m_switchingweapon = WEP_Null; + actor.(weaponentity).m_weapon = WEP_Null; + actor.(weaponentity).m_switchingweapon = WEP_Null; entity this = actor.(weaponentity); if (this) { @@ -208,17 +216,17 @@ void w_ready(Weapon thiswep, entity actor, .entity weaponentity, int fire) .float prevdryfire; .float prevwarntime; -bool weapon_prepareattack_checkammo(Weapon thiswep, entity actor, bool secondary) +bool weapon_prepareattack_checkammo(Weapon thiswep, entity actor, bool secondary, .entity weaponentity) { if ((actor.items & IT_UNLIMITED_WEAPON_AMMO)) return true; bool ammo = false; - if (secondary) ammo = thiswep.wr_checkammo2(thiswep, actor); - else ammo = thiswep.wr_checkammo1(thiswep, actor); + if (secondary) ammo = thiswep.wr_checkammo2(thiswep, actor, weaponentity); + else ammo = thiswep.wr_checkammo1(thiswep, actor, weaponentity); if (ammo) return true; // always keep the Mine Layer if we placed mines, so that we can detonate them if (thiswep == WEP_MINE_LAYER) { - IL_EACH(g_mines, it.owner == actor, + IL_EACH(g_mines, it.owner == actor && it.weaponentity_fld == weaponentity, { return false; }); @@ -227,7 +235,7 @@ bool weapon_prepareattack_checkammo(Weapon thiswep, entity actor, bool secondary if (thiswep == WEP_SHOTGUN) if (!secondary && WEP_CVAR(shotgun, secondary) == 1) return false; // no clicking, just allow - if (thiswep == PS(actor).m_switchweapon && time - actor.prevdryfire > 1) // only play once BEFORE starting to switch weapons + if (thiswep == actor.(weaponentity).m_switchweapon && time - actor.prevdryfire > 1) // only play once BEFORE starting to switch weapons { sound(actor, CH_WEAPON_A, SND_DRYFIRE, VOL_BASE, ATTEN_NORM); actor.prevdryfire = time; @@ -235,8 +243,8 @@ bool weapon_prepareattack_checkammo(Weapon thiswep, entity actor, bool secondary // check if the other firing mode has enough ammo bool ammo_other = false; - if (secondary) ammo_other = thiswep.wr_checkammo1(thiswep, actor); - else ammo_other = thiswep.wr_checkammo2(thiswep, actor); + if (secondary) ammo_other = thiswep.wr_checkammo1(thiswep, actor, weaponentity); + else ammo_other = thiswep.wr_checkammo2(thiswep, actor, weaponentity); if (ammo_other) { if (time - actor.prevwarntime > 1) @@ -255,7 +263,7 @@ bool weapon_prepareattack_checkammo(Weapon thiswep, entity actor, bool secondary } else // this weapon is totally unable to fire, switch to another one { - W_SwitchToOtherWeapon(actor); + W_SwitchToOtherWeapon(actor, weaponentity); } return false; @@ -265,7 +273,7 @@ bool weapon_prepareattack_checkammo(Weapon thiswep, entity actor, bool secondary bool weapon_prepareattack_check(Weapon thiswep, entity actor, .entity weaponentity, bool secondary, float attacktime) { if (actor.weaponentity == NULL) return true; - if (!weapon_prepareattack_checkammo(thiswep, actor, secondary)) return false; + if (!weapon_prepareattack_checkammo(thiswep, actor, secondary, weaponentity)) 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 @@ -275,13 +283,13 @@ bool weapon_prepareattack_check(Weapon thiswep, entity actor, .entity weaponenti return false; // do not even think about shooting if switching - if (PS(actor).m_switchweapon != PS(actor).m_weapon) return false; + if (actor.(weaponentity).m_switchweapon != actor.(weaponentity).m_weapon) return false; if (attacktime >= 0) { 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; + if (ATTACK_FINISHED(actor, slot) > time + actor.(weaponentity).weapon_frametime * 0.5) return false; entity this = actor.(weaponentity); // don't fire while changing weapon if (this.state != WS_READY) return false; @@ -301,14 +309,14 @@ void weapon_prepareattack_do(entity actor, .entity weaponentity, bool secondary, if (attacktime >= 0) { int slot = weaponslot(weaponentity); - if (ATTACK_FINISHED(actor, slot) < time - actor.weapon_frametime * 1.5) + if (ATTACK_FINISHED(actor, slot) < time - this.weapon_frametime * 1.5) { ATTACK_FINISHED(actor, slot) = time; // dprint("resetting attack finished to ", ftos(time), "\n"); } ATTACK_FINISHED(actor, slot) = ATTACK_FINISHED(actor, slot) + attacktime * W_WeaponRateFactor(actor); } - actor.bulletcounter += 1; + this.bulletcounter += 1; // dprint("attack finished ", ftos(ATTACK_FINISHED(actor, slot)), "\n"); } @@ -372,14 +380,13 @@ 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 - actor.weapon_frametime * 1.5 - || this.weapon_nextthink > time + actor.weapon_frametime * 1.5) + if (this.weapon_nextthink < time - this.weapon_frametime * 1.5 + || this.weapon_nextthink > time + this.weapon_frametime * 1.5) { this.weapon_nextthink = time; // dprint("reset weapon animation timer at ", ftos(time), "\n"); } this.weapon_nextthink += t; - if (weaponentity == weaponentities[0]) STAT(WEAPON_NEXTTHINK, actor) = this.weapon_nextthink; this.weapon_think = func; // dprint("next ", ftos(this.weapon_nextthink), "\n"); @@ -393,8 +400,8 @@ void weapon_thinkf(entity actor, .entity weaponentity, WFRAME fr, float t, void( if ((fr == WFRAME_FIRE1 || fr == WFRAME_FIRE2) && t) { - bool primary_melee = boolean(fr == WFRAME_FIRE1 && (PS(actor).m_weapon.spawnflags & WEP_TYPE_MELEE_PRI)); - bool secondary_melee = boolean(fr == WFRAME_FIRE2 && (PS(actor).m_weapon.spawnflags & WEP_TYPE_MELEE_SEC)); + 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 @@ -426,27 +433,27 @@ void W_WeaponFrame(Player actor, .entity weaponentity) TC(Player, actor); TC(PlayerState, PS(actor)); entity this = actor.(weaponentity); - if (frametime) actor.weapon_frametime = frametime; + if (frametime) this.weapon_frametime = frametime; if (!this || actor.health < 1) return; // Dead player can't use weapons and injure impulse commands if (forbidWeaponUse(actor)) { - if (actor.(weaponentity).state != WS_CLEAR) + if (this.state != WS_CLEAR) { - Weapon wpn = PS(actor).m_weapon; + Weapon wpn = this.m_weapon; w_ready(wpn, actor, weaponentity, PHYS_INPUT_BUTTON_ATCK(actor) | (PHYS_INPUT_BUTTON_ATCK2(actor) << 1)); return; } } - if (PS(actor).m_switchweapon == WEP_Null) + if (this.m_switchweapon == WEP_Null) { - PS(actor).m_weapon = WEP_Null; - PS(actor).m_switchingweapon = WEP_Null; + this.m_weapon = WEP_Null; + this.m_switchingweapon = WEP_Null; this.state = WS_CLEAR; - actor.weaponname = ""; + this.weaponname = ""; // actor.items &= ~IT_AMMO; return; } @@ -457,7 +464,7 @@ void W_WeaponFrame(Player actor, .entity weaponentity) vector up = v_up; // Change weapon - if (PS(actor).m_weapon != PS(actor).m_switchweapon) + if (this.m_weapon != this.m_switchweapon) { switch (this.state) { @@ -470,26 +477,25 @@ void W_WeaponFrame(Player actor, .entity weaponentity) case WS_CLEAR: { // end switching! - Weapon newwep = PS(actor).m_switchweapon; - PS(actor).m_switchingweapon = newwep; + Weapon newwep = this.m_switchweapon; + this.m_switchingweapon = newwep; // the two weapon entities will notice this has changed and update their models - PS(actor).m_weapon = newwep; - actor.weaponname = newwep.mdl; - actor.bulletcounter = 0; - actor.ammo_field = newwep.ammo_field; - newwep.wr_setup(newwep, actor); + this.m_weapon = newwep; + this.weaponname = newwep.mdl; + this.bulletcounter = 0; + newwep.wr_setup(newwep, actor, weaponentity); 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 { - actor.clip_load = actor.(weapon_load[PS(actor).m_switchweapon.m_id]); - actor.clip_size = newwep.reloading_ammo; + this.clip_load = this.(weapon_load[this.m_switchweapon.m_id]); + this.clip_size = newwep.reloading_ammo; } else { - actor.clip_load = actor.clip_size = 0; + this.clip_load = this.clip_size = 0; } weapon_thinkf(actor, weaponentity, WFRAME_IDLE, newwep.switchdelay_raise, w_ready); @@ -498,17 +504,17 @@ void W_WeaponFrame(Player actor, .entity weaponentity) case WS_DROP: { // in dropping phase we can switch at any time - PS(actor).m_switchingweapon = PS(actor).m_switchweapon; + this.m_switchingweapon = this.m_switchweapon; break; } case WS_READY: { // start switching! - PS(actor).m_switchingweapon = PS(actor).m_switchweapon; - entity oldwep = PS(actor).m_weapon; + this.m_switchingweapon = this.m_switchweapon; + entity oldwep = this.m_weapon; // set up weapon switch think in the future, and start drop anim - if (INDEPENDENT_ATTACK_FINISHED || ATTACK_FINISHED(actor, weaponslot(weaponentity)) <= time + actor.weapon_frametime * 0.5) + if (INDEPENDENT_ATTACK_FINISHED || ATTACK_FINISHED(actor, weaponslot(weaponentity)) <= time + this.weapon_frametime * 0.5) { sound(actor, CH_WEAPON_SINGLE, SND_WEAPON_SWITCH, VOL_BASE, ATTN_NORM); this.state = WS_DROP; @@ -523,7 +529,7 @@ void W_WeaponFrame(Player actor, .entity weaponentity) // if (actor.button0) // print(ftos(frametime), " ", ftos(time), " >= ", ftos(ATTACK_FINISHED(actor, slot)), " >= ", ftos(this.weapon_nextthink), "\n"); - Weapon w = PS(actor).m_weapon; + Weapon w = this.m_weapon; // call the think code which may fire the weapon // and do so multiple times to resolve framerate dependency issues if the @@ -532,7 +538,7 @@ void W_WeaponFrame(Player actor, .entity weaponentity) { if (w != WEP_Null && !(actor.weapons & WepSet_FromWeapon(w))) { - if (PS(actor).m_weapon == PS(actor).m_switchweapon) W_SwitchWeapon_Force(actor, w_getbestweapon(actor)); + if (this.m_weapon == this.m_switchweapon) W_SwitchWeapon_Force(actor, w_getbestweapon(actor, weaponentity), weaponentity); w = WEP_Null; } @@ -550,11 +556,11 @@ void W_WeaponFrame(Player actor, .entity weaponentity) } else { - if (key_pressed && PS(actor).m_switchweapon != WEP_HOOK && !actor.hook_switchweapon) - W_SwitchWeapon(actor, WEP_HOOK); + if (key_pressed && this.m_switchweapon != WEP_HOOK && !actor.hook_switchweapon) + W_SwitchWeapon(actor, WEP_HOOK, weaponentity); actor.hook_switchweapon = key_pressed; Weapon h = WEP_HOOK; - block_weapon = (PS(actor).m_weapon == h && (PHYS_INPUT_BUTTON_ATCK(actor) || key_pressed)); + block_weapon = (this.m_weapon == h && (PHYS_INPUT_BUTTON_ATCK(actor) || key_pressed)); h.wr_think(h, actor, weaponentity, block_weapon ? 1 : 0); } } @@ -565,7 +571,7 @@ void W_WeaponFrame(Player actor, .entity weaponentity) if (!block_weapon) { - Weapon e = PS(actor).m_weapon; + Weapon e = this.m_weapon; TC(Weapon, e); if (w != WEP_Null) { @@ -577,14 +583,14 @@ void W_WeaponFrame(Player actor, .entity weaponentity) } } - if (time + actor.weapon_frametime * 0.5 >= this.weapon_nextthink) + if (time + this.weapon_frametime * 0.5 >= this.weapon_nextthink) { if (this.weapon_think) { v_forward = fo; v_right = ri; v_up = up; - Weapon wpn = PS(actor).m_weapon; + Weapon wpn = this.m_weapon; this.weapon_think(wpn, actor, weaponentity, PHYS_INPUT_BUTTON_ATCK(actor) | (PHYS_INPUT_BUTTON_ATCK2(actor) << 1)); } @@ -626,17 +632,17 @@ void W_AttachToShotorg(entity actor, .entity weaponentity, entity flash, vector } } -void W_DecreaseAmmo(Weapon wep, entity actor, float ammo_use) +void W_DecreaseAmmo(Weapon wep, entity actor, float ammo_use, .entity weaponentity) { - if (MUTATOR_CALLHOOK(W_DecreaseAmmo, actor)) return; + if (MUTATOR_CALLHOOK(W_DecreaseAmmo, actor, actor.(weaponentity))) 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) { - actor.clip_load -= ammo_use; - actor.(weapon_load[PS(actor).m_weapon.m_id]) = actor.clip_load; + actor.(weaponentity).clip_load -= ammo_use; + actor.(weaponentity).(weapon_load[actor.(weaponentity).m_weapon.m_id]) = actor.(weaponentity).clip_load; } else if (wep.ammo_field != ammo_none) { @@ -666,29 +672,30 @@ void W_ReloadedAndReady(Weapon thiswep, entity actor, .entity weaponentity, int { // finish the reloading process, and do the ammo transfer - actor.clip_load = actor.old_clip_load; // restore the ammo counter, in case we still had ammo in the weapon before reloading + Weapon wpn = actor.(weaponentity).m_weapon; + + actor.(weaponentity).clip_load = actor.(weaponentity).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 (!actor.reload_ammo_min || actor.items & IT_UNLIMITED_WEAPON_AMMO || actor.ammo_field == ammo_none) + if (!actor.(weaponentity).reload_ammo_min || (actor.items & IT_UNLIMITED_WEAPON_AMMO) || wpn.ammo_field == ammo_none) { - actor.clip_load = actor.reload_ammo_amount; + actor.(weaponentity).clip_load = actor.(weaponentity).reload_ammo_amount; } else { // make sure we don't add more ammo than we have - float load = min(actor.reload_ammo_amount - actor.clip_load, actor.(actor.ammo_field)); - actor.clip_load += load; - actor.(actor.ammo_field) -= load; + float load = min(actor.(weaponentity).reload_ammo_amount - actor.(weaponentity).clip_load, actor.(wpn.ammo_field)); + actor.(weaponentity).clip_load += load; + actor.(wpn.ammo_field) -= load; } - actor.(weapon_load[PS(actor).m_weapon.m_id]) = actor.clip_load; + actor.(weaponentity).(weapon_load[actor.(weaponentity).m_weapon.m_id]) = actor.(weaponentity).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(actor, slot) -= actor.reload_time - 1; + // ATTACK_FINISHED(actor, slot) -= actor.(weaponentity).reload_time - 1; - Weapon wpn = Weapons_from(PS(actor).m_weapon.m_id); w_ready(wpn, actor, weaponentity, PHYS_INPUT_BUTTON_ATCK(actor) | (PHYS_INPUT_BUTTON_ATCK2(actor) << 1)); } @@ -696,13 +703,13 @@ void W_Reload(entity actor, .entity weaponentity, float sent_ammo_min, Sound sen { TC(Sound, sent_sound); // set global values to work with - Weapon e = PS(actor).m_weapon; + Weapon e = actor.(weaponentity).m_weapon; if (MUTATOR_CALLHOOK(W_Reload, actor)) return; - actor.reload_ammo_min = sent_ammo_min; - actor.reload_ammo_amount = e.reloading_ammo; - actor.reload_time = e.reloading_time; + actor.(weaponentity).reload_ammo_min = sent_ammo_min; + actor.(weaponentity).reload_ammo_amount = e.reloading_ammo; + actor.(weaponentity).reload_time = e.reloading_time; if (actor.reload_sound) strunzone(actor.reload_sound); actor.reload_sound = strzone(Sound_fixpath(sent_sound)); @@ -715,30 +722,29 @@ void W_Reload(entity actor, .entity weaponentity, float sent_ammo_min, Sound sen } // return if reloading is disabled for this weapon - if (!actor.reload_ammo_amount) return; + if (!actor.(weaponentity).reload_ammo_amount) return; // our weapon is fully loaded, no need to reload - if (actor.clip_load >= actor.reload_ammo_amount) return; + if (actor.(weaponentity).clip_load >= actor.(weaponentity).reload_ammo_amount) return; // no ammo, so nothing to load - if (actor.ammo_field != ammo_none) + if (e.ammo_field != ammo_none) { - if (!actor.(actor.ammo_field) && actor.reload_ammo_min) + if (!actor.(e.ammo_field) && actor.(weaponentity).reload_ammo_min) { 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", PS(actor).m_weapon.m_name, "\n")); + sprint(actor, strcat("You don't have enough ammo to reload the ^2", actor.(weaponentity).m_weapon.m_name, "\n")); actor.reload_complain = time + 1; } // switch away if the amount of ammo is not enough to keep using this weapon - Weapon w = PS(actor).m_weapon; - if (!(w.wr_checkammo1(w, actor) + w.wr_checkammo2(w, actor))) + if (!(e.wr_checkammo1(e, actor, weaponentity) + e.wr_checkammo2(e, actor, weaponentity))) { - actor.clip_load = -1; // reload later - W_SwitchToOtherWeapon(actor); + actor.(weaponentity).clip_load = -1; // reload later + W_SwitchToOtherWeapon(actor, weaponentity); } return; } @@ -762,18 +768,18 @@ void W_Reload(entity actor, .entity weaponentity, float sent_ammo_min, Sound sen // 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(actor, slot) = max(time, ATTACK_FINISHED(actor, slot)) + actor.reload_time + 1; + // ATTACK_FINISHED(actor, slot) = max(time, ATTACK_FINISHED(actor, slot)) + actor.(weaponentity).reload_time + 1; - weapon_thinkf(actor, weaponentity, WFRAME_RELOAD, actor.reload_time, W_ReloadedAndReady); + weapon_thinkf(actor, weaponentity, WFRAME_RELOAD, this.reload_time, W_ReloadedAndReady); - if (actor.clip_load < 0) actor.clip_load = 0; - actor.old_clip_load = actor.clip_load; - actor.clip_load = actor.(weapon_load[PS(actor).m_weapon.m_id]) = -1; + if (this.clip_load < 0) this.clip_load = 0; + this.old_clip_load = this.clip_load; + this.clip_load = this.(weapon_load[this.m_weapon.m_id]) = -1; } -void W_DropEvent(.void(Weapon, entity actor) event, entity player, float weapon_type, entity weapon_item) +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_dropevent_item = weapon_item; - w.event(w, player); + w.event(w, player, weaponentity); } diff --git a/qcsrc/server/weapons/weaponsystem.qh b/qcsrc/server/weapons/weaponsystem.qh index b7ca597046..2fb0f99568 100644 --- a/qcsrc/server/weapons/weaponsystem.qh +++ b/qcsrc/server/weapons/weaponsystem.qh @@ -4,6 +4,8 @@ float internalteam; float weaponswapping; entity weapon_dropevent_item; +..entity weaponentity_fld; + void CL_SpawnWeaponentity(entity e, .entity weaponentity); vector CL_Weapon_GetShotOrg(float wpn); @@ -12,9 +14,9 @@ bool forbidWeaponUse(entity player); void W_AttachToShotorg(entity actor, .entity weaponentity, entity flash, vector offset); -void W_DecreaseAmmo(Weapon wep, entity actor, float ammo_use); +void W_DecreaseAmmo(Weapon wep, entity actor, float ammo_use, .entity weaponentity); -void W_DropEvent(.void(Weapon, entity actor) event, entity player, float weapon_type, entity weapon_item); +void W_DropEvent(.void(Weapon, entity actor, .entity) event, entity player, float weapon_type, entity weapon_item, .entity weaponentity); void W_Reload(entity actor, .entity weaponentity, float sent_ammo_min, Sound sent_sound);