#include "impulse.qh"
-#include "round_handler.qh"
-
-#include "bot/api.qh"
-
-#include "weapons/throwing.qh"
-#include "command/common.qh"
-#include "cheats.qh"
-#include "weapons/selection.qh"
-#include "weapons/tracing.qh"
-#include "weapons/weaponsystem.qh"
+#include <common/gamemodes/_mod.qh>
+#include <common/minigames/sv_minigames.qh>
+#include <common/mutators/mutator/waypoints/waypointsprites.qh>
#include <common/state.qh>
-
-#include "../common/minigames/sv_minigames.qh"
-
+#include <common/vehicles/sv_vehicles.qh>
#include <common/weapons/_all.qh>
-#include "../common/vehicles/sv_vehicles.qh"
-
-#include "../common/mutators/mutator/waypoints/waypointsprites.qh"
+#include <server/cheats.qh>
+#include <server/client.qh>
+#include <server/clientkill.qh>
+#include <server/command/common.qh>
+#include <server/damage.qh>
+#include <server/mutators/_mod.qh>
+#include <server/round_handler.qh>
+#include <server/weapons/selection.qh>
+#include <server/weapons/throwing.qh>
+#include <server/weapons/tracing.qh>
+#include <server/weapons/weaponsystem.qh>
.entity vehicle;
// weapon switching impulses
-#define X(slot) \
- IMPULSE(weapon_group_##slot) \
+void weapon_group_handle(entity this, int number, int imp)
+{
+ if (IS_DEAD(this))
+ {
+ this.impulse = imp;
+ return;
+ }
+ for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ {
+ .entity weaponentity = weaponentities[slot];
+ W_NextWeaponOnImpulse(this, number, weaponentity);
+ if(autocvar_g_weaponswitch_debug != 1)
+ break;
+ }
+}
+
+#define X(i) \
+ IMPULSE(weapon_group_##i) \
{ \
- if (IS_DEAD(this)) \
- { \
- this.impulse = IMP_weapon_group_##slot.impulse; \
- return; \
- } \
- for(int wepslot = 0; wepslot < MAX_WEAPONSLOTS; ++wepslot) \
- { \
- .entity weaponentity = weaponentities[wepslot]; \
- W_NextWeaponOnImpulse(this, slot, weaponentity); \
- if(wepslot == 0 && autocvar_g_weaponswitch_debug != 1) \
- break; \
- } \
+ weapon_group_handle(this, i, IMP_weapon_group_##i.impulse); \
}
X(1)
X(2)
// custom order weapon cycling
-#define X(slot, dir) \
- IMPULSE(weapon_priority_##slot##_##dir) \
+void weapon_priority_handle(entity this, int dir, int number, int imp)
+{
+ if (this.vehicle) return;
+ if (IS_DEAD(this))
+ {
+ this.impulse = imp;
+ return;
+ }
+ for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ {
+ .entity weaponentity = weaponentities[slot];
+ W_CycleWeapon(this, CS_CVAR(this).cvar_cl_weaponpriorities[number], dir, weaponentity);
+ if(autocvar_g_weaponswitch_debug != 1)
+ break;
+ }
+}
+
+#define X(i, dir) \
+ IMPULSE(weapon_priority_##i##_##dir) \
{ \
- if (this.vehicle) return; \
- if (IS_DEAD(this)) \
- { \
- this.impulse = IMP_weapon_priority_##slot##_##dir.impulse; \
- return; \
- } \
noref int prev = -1; \
noref int best = 0; \
noref int next = +1; \
- for(int wepslot = 0; wepslot < MAX_WEAPONSLOTS; ++wepslot) \
- { \
- .entity weaponentity = weaponentities[wepslot]; \
- W_CycleWeapon(this, CS(this).cvar_cl_weaponpriorities[slot], dir, weaponentity); \
- if(wepslot == 0 && autocvar_g_weaponswitch_debug != 1) \
- break; \
- } \
+ weapon_priority_handle(this, dir, i, IMP_weapon_priority_##i##_##dir.impulse); \
}
X(0, prev)
X(1, prev)
// direct weapons
+void weapon_byid_handle(entity this, int number, int imp)
+{
+ if (this.vehicle) return;
+ if (IS_DEAD(this))
+ {
+ this.impulse = imp;
+ return;
+ }
+ for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ {
+ .entity weaponentity = weaponentities[slot];
+ W_SwitchWeapon_TryOthers(this, REGISTRY_GET(Weapons, WEP_FIRST + number), weaponentity);
+ if(autocvar_g_weaponswitch_debug != 1)
+ break;
+ }
+}
+
#define X(i) \
IMPULSE(weapon_byid_##i) \
{ \
- if (this.vehicle) return; \
- if (IS_DEAD(this)) \
- { \
- this.impulse = IMP_weapon_byid_##i.impulse; \
- return; \
- } \
- 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 != 1) \
- break; \
- } \
+ weapon_byid_handle(this, i, IMP_weapon_byid_##i.impulse); \
}
X(0)
X(1)
.entity weaponentity = weaponentities[slot];
W_NextWeapon(this, 0, weaponentity);
- if(slot == 0 && autocvar_g_weaponswitch_debug != 1)
+ if(autocvar_g_weaponswitch_debug != 1)
break;
}
}
.entity weaponentity = weaponentities[slot];
W_PreviousWeapon(this, 0, weaponentity);
- if(slot == 0 && autocvar_g_weaponswitch_debug != 1)
+ if(autocvar_g_weaponswitch_debug != 1)
break;
}
}
.entity weaponentity = weaponentities[slot];
W_NextWeapon(this, 1, weaponentity);
- if(slot == 0 && autocvar_g_weaponswitch_debug != 1)
+ if(autocvar_g_weaponswitch_debug != 1)
break;
}
}
.entity weaponentity = weaponentities[slot];
W_PreviousWeapon(this, 1, weaponentity);
- if(slot == 0 && autocvar_g_weaponswitch_debug != 1)
+ if(autocvar_g_weaponswitch_debug != 1)
break;
}
}
.entity weaponentity = weaponentities[slot];
W_NextWeapon(this, 2, weaponentity);
- if(slot == 0 && autocvar_g_weaponswitch_debug != 1)
+ if(autocvar_g_weaponswitch_debug != 1)
break;
}
}
.entity weaponentity = weaponentities[slot];
W_PreviousWeapon(this, 2, weaponentity);
- if(slot == 0 && autocvar_g_weaponswitch_debug != 1)
+ if(autocvar_g_weaponswitch_debug != 1)
break;
}
}
.entity weaponentity = weaponentities[slot];
W_LastWeapon(this, weaponentity);
- if(slot == 0 && autocvar_g_weaponswitch_debug != 1)
+ if(autocvar_g_weaponswitch_debug != 1)
break;
}
}
.entity weaponentity = weaponentities[slot];
W_SwitchWeapon(this, w_getbestweapon(this, weaponentity), weaponentity);
- if(slot == 0 && autocvar_g_weaponswitch_debug != 1)
+ if(autocvar_g_weaponswitch_debug != 1)
break;
}
}
{
if (this.vehicle) return;
if (IS_DEAD(this)) return;
+ bool is_dualwielding = W_DualWielding(this);
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 != 1)
- break;
+ vector md = this.(weaponentity).movedir;
+ vector vecs = ((md.x > 0) ? md : '0 0 0');
+ vector dv = v_right * -vecs.y;
+ if(!is_dualwielding)
+ dv = '0 0 0'; // don't override!
+ W_ThrowWeapon(this, weaponentity, W_CalculateProjectileVelocity(this, this.velocity, v_forward * 750, false), dv, true);
+
+ if(autocvar_g_weaponswitch_debug == 2)
+ break; // in this mode, the off-hand weapon is selected based on the primary weapon, don't drop it twice!
}
}
{
if (this.vehicle) return;
if (IS_DEAD(this)) return;
- if (forbidWeaponUse(this)) return;
+ if (weaponLocked(this)) return;
entity actor = this;
for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
{
Weapon w = this.(weaponentity).m_weapon;
w.wr_reload(w, actor, weaponentity);
- if(slot == 0 && autocvar_g_weaponswitch_debug != 1)
- break;
+ // allow reloading all active slots?
+ //if(autocvar_g_weaponswitch_debug != 1)
+ //break;
}
}
if (timeout_status == TIMEOUT_ACTIVE) return; // don't allow any impulses while the game is paused
- // allow only weapon change impulses when not in round time
if (round_handler_IsActive() && !round_handler_IsRoundStarted())
{
+ // impulses forbidden while waiting for the start of a round
#define X(id) case IMP_##id.impulse:
switch (imp)
{
- X(weapon_group_0)
- X(weapon_group_1)
- X(weapon_group_2)
- X(weapon_group_3)
- X(weapon_group_4)
- X(weapon_group_5)
- X(weapon_group_6)
- X(weapon_group_7)
- X(weapon_group_8)
- X(weapon_group_9)
- X(weapon_next_byid)
- X(weapon_prev_byid)
- X(weapon_next_bygroup)
- X(weapon_prev_bygroup)
- X(weapon_next_bypriority)
- X(weapon_prev_bypriority)
- X(weapon_last)
- X(weapon_best)
+ X(weapon_drop)
X(weapon_reload)
- X(weapon_priority_0_prev)
- X(weapon_priority_1_prev)
- X(weapon_priority_2_prev)
- X(weapon_priority_3_prev)
- X(weapon_priority_4_prev)
- X(weapon_priority_5_prev)
- X(weapon_priority_6_prev)
- X(weapon_priority_7_prev)
- X(weapon_priority_8_prev)
- X(weapon_priority_9_prev)
- X(weapon_priority_0_next)
- X(weapon_priority_1_next)
- X(weapon_priority_2_next)
- X(weapon_priority_3_next)
- X(weapon_priority_4_next)
- X(weapon_priority_5_next)
- X(weapon_priority_6_next)
- X(weapon_priority_7_next)
- X(weapon_priority_8_next)
- X(weapon_priority_9_next)
- X(weapon_priority_0_best)
- X(weapon_priority_1_best)
- X(weapon_priority_2_best)
- X(weapon_priority_3_best)
- X(weapon_priority_4_best)
- X(weapon_priority_5_best)
- X(weapon_priority_6_best)
- X(weapon_priority_7_best)
- X(weapon_priority_8_best)
- X(weapon_priority_9_best)
- X(weapon_byid_0)
- X(weapon_byid_1)
- X(weapon_byid_2)
- X(weapon_byid_3)
- X(weapon_byid_4)
- X(weapon_byid_5)
- X(weapon_byid_6)
- X(weapon_byid_7)
- X(weapon_byid_8)
- X(weapon_byid_9)
- X(weapon_byid_10)
- X(weapon_byid_11)
- X(weapon_byid_12)
- X(weapon_byid_13)
- X(weapon_byid_14)
- X(weapon_byid_15)
- X(weapon_byid_16)
- X(weapon_byid_17)
- X(weapon_byid_18)
- X(weapon_byid_19)
- X(weapon_byid_20)
- X(weapon_byid_21)
- X(weapon_byid_22)
- X(weapon_byid_23)
- break;
- default: return;
+ X(use)
+ return;
}
#undef X
}
IMPULSE(waypoint_here_crosshair)
{
- WarpZone_crosshair_trace(this);
+ WarpZone_crosshair_trace_plusvisibletriggers(this);
entity wp = WaypointSprite_DeployFixed(WP_Here, false, this, trace_endpos, RADARICON_HERE);
if (wp) WaypointSprite_Ping(wp);
sprint(this, "HERE spawned at crosshair\n");
}
sprint(this, "all waypoints cleared\n");
}
-
-vector waypoint_getSymmetricalOrigin(vector org, int ctf_flags)
-{
- vector new_org = org;
- if (fabs(autocvar_g_waypointeditor_symmetrical) == 1)
- {
- vector map_center = havocbot_middlepoint;
- if (autocvar_g_waypointeditor_symmetrical == -1)
- map_center = autocvar_g_waypointeditor_symmetrical_origin;
-
- new_org = Rotate(org - map_center, 360 * DEG2RAD / ctf_flags) + map_center;
- }
- else if (fabs(autocvar_g_waypointeditor_symmetrical) == 2)
- {
- float m = havocbot_symmetryaxis_equation.x;
- float q = havocbot_symmetryaxis_equation.y;
- if (autocvar_g_waypointeditor_symmetrical == -2)
- {
- m = autocvar_g_waypointeditor_symmetrical_axis.x;
- q = autocvar_g_waypointeditor_symmetrical_axis.y;
- }
-
- new_org.x = (1 / (1 + m*m)) * ((1 - m*m) * org.x + 2 * m * org.y - 2 * m * q);
- new_org.y = (1 / (1 + m*m)) * (2 * m * org.x + (m*m - 1) * org.y + 2 * q);
- }
- new_org.z = org.z;
- return new_org;
-}
-
-IMPULSE(navwaypoint_spawn)
-{
- if (!autocvar_g_waypointeditor) return;
- entity e;
- vector org = this.origin;
- int ctf_flags = havocbot_symmetryaxis_equation.z;
- bool sym = ((autocvar_g_waypointeditor_symmetrical > 0 && ctf_flags >= 2)
- || (autocvar_g_waypointeditor_symmetrical < 0));
- int order = ctf_flags;
- if(autocvar_g_waypointeditor_symmetrical_order >= 2)
- {
- order = autocvar_g_waypointeditor_symmetrical_order;
- ctf_flags = order;
- }
-
- LABEL(add_wp);
- e = waypoint_spawn(org, org, 0);
- waypoint_schedulerelink(e);
- bprint(strcat("Waypoint spawned at ", vtos(org), "\n"));
- if(sym)
- {
- org = waypoint_getSymmetricalOrigin(e.origin, ctf_flags);
- if (vdist(org - this.origin, >, 32))
- {
- if(order > 2)
- order--;
- else
- sym = false;
- goto add_wp;
- }
- }
-}
-
-IMPULSE(navwaypoint_remove)
-{
- if (!autocvar_g_waypointeditor) return;
- entity e = navigation_findnearestwaypoint(this, false);
- int ctf_flags = havocbot_symmetryaxis_equation.z;
- bool sym = ((autocvar_g_waypointeditor_symmetrical > 0 && ctf_flags >= 2)
- || (autocvar_g_waypointeditor_symmetrical < 0));
- int order = ctf_flags;
- if(autocvar_g_waypointeditor_symmetrical_order >= 2)
- {
- order = autocvar_g_waypointeditor_symmetrical_order;
- ctf_flags = order;
- }
-
- LABEL(remove_wp);
- if (!e) return;
- if (e.wpflags & WAYPOINTFLAG_GENERATED) return;
-
- if (e.wphardwired)
- {
- LOG_INFO("^1Warning: ^7Removal of hardwired waypoints is not allowed in the editor. Please remove links from/to this waypoint (", vtos(e.origin), ") by hand from maps/", mapname, ".waypoints.hardwired\n");
- return;
- }
-
- entity wp_sym = NULL;
- if (sym)
- {
- vector org = waypoint_getSymmetricalOrigin(e.origin, ctf_flags);
- IL_EACH(g_waypoints, !(it.wpflags & WAYPOINTFLAG_GENERATED), {
- if(vdist(org - it.origin, <, 3))
- {
- wp_sym = it;
- break;
- }
- });
- }
- bprint(strcat("Waypoint removed at ", vtos(e.origin), "\n"));
- waypoint_remove(e);
- if (sym && wp_sym)
- {
- e = wp_sym;
- if(order > 2)
- order--;
- else
- sym = false;
- goto remove_wp;
- }
-}
-
-IMPULSE(navwaypoint_relink)
-{
- if (!autocvar_g_waypointeditor) return;
- waypoint_schedulerelinkall();
-}
-
-IMPULSE(navwaypoint_save)
-{
- if (!autocvar_g_waypointeditor) return;
- waypoint_saveall();
-}
-
-IMPULSE(navwaypoint_unreachable)
-{
- if (!autocvar_g_waypointeditor) return;
- IL_EACH(g_waypoints, true,
- {
- it.colormod = '0.5 0.5 0.5';
- it.effects &= ~(EF_NODEPTHTEST | EF_RED | EF_BLUE);
- });
- entity e2 = navigation_findnearestwaypoint(this, false);
- navigation_markroutes(this, e2);
-
- int j, m;
-
- j = 0;
- m = 0;
- IL_EACH(g_waypoints, it.wpcost >= 10000000,
- {
- LOG_INFO("unreachable: ", etos(it), " ", vtos(it.origin), "\n");
- it.colormod_z = 8;
- it.effects |= EF_NODEPTHTEST | EF_BLUE;
- ++j;
- ++m;
- });
- if (j) LOG_INFOF("%d waypoints cannot be reached from here in any way (marked with blue light)", j);
- navigation_markroutes_inverted(e2);
-
- j = 0;
- IL_EACH(g_waypoints, it.wpcost >= 10000000,
- {
- LOG_INFO("cannot reach me: ", etos(it), " ", vtos(it.origin), "\n");
- it.colormod_x = 8;
- if (!(it.effects & EF_NODEPTHTEST)) // not already reported before
- ++m;
- it.effects |= EF_NODEPTHTEST | EF_RED;
- ++j;
- });
- if (j) LOG_INFOF("%d waypoints cannot walk to here in any way (marked with red light)", j);
- if (m) LOG_INFOF("%d waypoints have been marked total", m);
-
- j = 0;
- IL_EACH(g_spawnpoints, true,
- {
- vector org = it.origin;
- tracebox(it.origin, PL_MIN_CONST, PL_MAX_CONST, it.origin - '0 0 512', MOVE_NOMONSTERS, NULL);
- setorigin(it, trace_endpos);
- if (navigation_findnearestwaypoint(it, false))
- {
- setorigin(it, org);
- it.effects &= ~EF_NODEPTHTEST;
- it.model = "";
- }
- else
- {
- setorigin(it, org);
- LOG_INFO("spawn without waypoint: ", etos(it), " ", vtos(it.origin), "\n");
- it.effects |= EF_NODEPTHTEST;
- _setmodel(it, this.model);
- it.frame = this.frame;
- it.skin = this.skin;
- it.colormod = '8 0.5 8';
- setsize(it, '0 0 0', '0 0 0');
- ++j;
- }
- });
- if (j) LOG_INFOF("%d spawnpoints have no nearest waypoint (marked by player model)", j);
-
- j = 0;
- IL_EACH(g_items, true,
- {
- it.effects &= ~(EF_NODEPTHTEST | EF_RED | EF_BLUE);
- it.colormod = '0.5 0.5 0.5';
- });
- IL_EACH(g_items, true,
- {
- if (navigation_findnearestwaypoint(it, false)) continue;
- LOG_INFO("item without waypoint: ", etos(it), " ", vtos(it.origin), "\n");
- it.effects |= EF_NODEPTHTEST | EF_RED;
- it.colormod_x = 8;
- ++j;
- });
- if (j) LOG_INFOF("%d items have no nearest waypoint and cannot be walked away from (marked with red light)", j);
-
- j = 0;
- IL_EACH(g_items, true,
- {
- if (navigation_findnearestwaypoint(it, true)) continue;
- LOG_INFO("item without waypoint: ", etos(it), " ", vtos(it.origin), "\n");
- it.effects |= EF_NODEPTHTEST | EF_BLUE;
- it.colormod_z = 8;
- ++j;
- });
- if (j) LOG_INFOF("%d items have no nearest waypoint and cannot be walked to (marked with blue light)", j);
-}