const int FL_MONSTER = 32; /* BIT(4) */
const int FL_GODMODE = 64; /* BIT(5) */ // player cheat
const int FL_NOTARGET = 128; /* BIT(6) */ // player cheat
-const int FL_ITEM = 256; /* BIT(7) */ // extra wide size for bonus items
+const int FL_ITEM = 256; /* BIT(7) */ // extra wide size for bonus items IF sv_legacy_bbox_expand is 1
const int FL_ONGROUND = 512; /* BIT(8) */ // standing on something
const int FL_PARTIALGROUND = 1024; /* BIT(9) */ // not all corners are valid
const int FL_WATERJUMP = 2048; /* BIT(10) */ // player jumping out of water
#include <common/gamemodes/sv_rules.qh>
CLASS(Flag, Pickup)
- ATTRIB(Flag, m_mins, vector, (PL_MIN_CONST + '0 0 -13') * 1.4); // scaling be damned
- ATTRIB(Flag, m_maxs, vector, (PL_MAX_CONST + '0 0 -13') * 1.4);
+ ATTRIB(Flag, m_mins, vector, (PL_MIN_CONST + '-10 -10 -13') * 1.4); // scaling be damned
+ ATTRIB(Flag, m_maxs, vector, (PL_MAX_CONST + '10 10 -13') * 1.4); // 0.8.5 used '0 0 -13' with sv_legacy_bbox_expand 1
ENDCLASS(Flag)
Flag CTF_FLAG;
void ctf_Initialize();
if(!this.flags & FL_ITEM)
IL_PUSH(g_items, this);
this.flags = FL_ITEM;
- setsize(this, '-32 -32 -32', '32 32 32');
+ setsize(this, '-48 -48 -32', '48 48 32'); // 0.8.5 used '-32 -32 -32', '32 32 32' with sv_legacy_bbox_expand 1
setorigin(this, this.origin + '0 0 20');
droptofloor(this);
#endif
const float KH_KEY_WP_ZSHIFT = 20;
-const vector KH_KEY_MIN = '-10 -10 -46';
-const vector KH_KEY_MAX = '10 10 3';
+const vector KH_KEY_MIN = '-25 -25 -46'; // 0.8.5 used '-10 -10 -46' with sv_legacy_bbox_expand 1
+const vector KH_KEY_MAX = '25 25 3'; // 0.8.5 used '10 10 3' with sv_legacy_bbox_expand 1
const float KH_KEY_BRIGHTNESS = 2;
bool kh_no_radar_circles;
const int ITS_ALLOWSI = BIT(5);
const int ITS_GLOW = BIT(6);
+// item bboxes for sv_legacy_bbox_expand 0
+// Small, Default and Large (large maxs are used with default mins)
+const vector ITEM_S_MINS = '-16 -16 0'; // smaller items now get the same "unexpanded" bbox that normal items
+const vector ITEM_S_MAXS = '16 16 48'; // had during MoveOutOfSolid and DropToFloor (before expansion) in 0.8.5
+const vector ITEM_D_MINS = '-30 -30 0'; // 0.8.5 set '-16 -16 0' then DP subtracted '15 15 1' but NetRadiant used '-30 -30 0'
+const vector ITEM_D_MAXS = '30 30 48'; // 0.8.5 set '16 16 48' then DP added '15 15 1' but NetRadiant used '30 30 32'
+const vector ITEM_L_MAXS = '30 30 70'; // 0.8.5 set '16 16 80' for powerups, '16 16 70' for megas, '16 16 60' for buffs
+
.float fade_start;
.float fade_end;
#include "pickup.qh"
CLASS(Armor, Pickup)
#ifdef SVQC
- ATTRIB(Armor, m_mins, vector, '-16 -16 0');
- ATTRIB(Armor, m_maxs, vector, '16 16 48');
ATTRIB(Armor, m_pickupevalfunc, float(entity player, entity item), healtharmor_pickupevalfunc);
ATTRIB(Armor, m_botvalue, int, 5000);
#endif
this.m_icon = "armor"; // compatible with Xonotic v0.8.2 or lower
#endif
#ifdef SVQC
+ this.m_mins = ITEM_S_MINS;
+ this.m_maxs = ITEM_S_MAXS;
this.m_itemid = IT_RESOURCE;
this.m_respawntime = GET(g_pickup_respawntime_short);
this.m_respawntimejitter = GET(g_pickup_respawntimejitter_short);
this.m_icon = "armor"; // compatible with Xonotic v0.8.2 or lower
#endif
#ifdef SVQC
+ this.m_mins = ITEM_S_MINS;
+ this.m_maxs = ITEM_S_MAXS;
this.m_itemid = IT_RESOURCE;
this.m_respawntime = GET(g_pickup_respawntime_medium);
this.m_respawntimejitter = GET(g_pickup_respawntimejitter_medium);
this.m_waypoint = _("Mega armor");
this.m_waypointblink = 2;
#ifdef SVQC
- this.m_maxs = '16 16 70';
+ this.m_maxs = ITEM_L_MAXS;
this.m_itemid = IT_RESOURCE;
this.m_respawntime = GET(g_pickup_respawntime_long);
this.m_respawntimejitter = GET(g_pickup_respawntimejitter_long);
#include "pickup.qh"
CLASS(Health, Pickup)
#ifdef SVQC
- ATTRIB(Health, m_mins, vector, '-16 -16 0');
- ATTRIB(Health, m_maxs, vector, '16 16 48');
ATTRIB(Health, m_pickupevalfunc, float(entity player, entity item), healtharmor_pickupevalfunc);
ATTRIB(Health, m_botvalue, int, 5000);
#endif
this.m_icon = "health"; // compatible with Xonotic v0.8.2 or lower
#endif
#ifdef SVQC
+ this.m_mins = ITEM_S_MINS;
+ this.m_maxs = ITEM_S_MAXS;
this.m_itemid = IT_RESOURCE;
this.m_respawntime = GET(g_pickup_respawntime_short);
this.m_respawntimejitter = GET(g_pickup_respawntimejitter_short);
this.m_icon = "health"; // compatible with Xonotic v0.8.2 or lower
#endif
#ifdef SVQC
+ this.m_mins = ITEM_S_MINS;
+ this.m_maxs = ITEM_S_MAXS;
this.m_itemid = IT_RESOURCE;
this.m_respawntime = GET(g_pickup_respawntime_short);
this.m_respawntimejitter = GET(g_pickup_respawntimejitter_short);
this.m_waypoint = _("Mega health");
this.m_waypointblink = 2;
#ifdef SVQC
- this.m_maxs = '16 16 70';
+ this.m_maxs = ITEM_L_MAXS;
this.m_itemid = IT_RESOURCE;
this.m_respawntime = GET(g_pickup_respawntime_long);
this.m_respawntimejitter = GET(g_pickup_respawntimejitter_long);
}
ATTRIB(Pickup, m_itemid, int, 0);
#ifdef SVQC
- ATTRIB(Pickup, m_mins, vector, '-16 -16 0');
- ATTRIB(Pickup, m_maxs, vector, '16 16 48');
+ ATTRIB(Pickup, m_mins, vector, ITEM_D_MINS);
+ ATTRIB(Pickup, m_maxs, vector, ITEM_D_MAXS);
ATTRIB(Pickup, m_botvalue, int, 0);
ATTRIB(Pickup, m_itemflags, int, 0);
float generic_pickupevalfunc(entity player, entity item);
{
FOREACH_ENTITY_RADIUS((this.absmin + this.absmax) * 0.5, vlen(this.absmax - this.absmin) * 0.5 + 1, it.conveyor.active == ACTIVE_NOT && isPushable(it),
{
- vector emin = it.absmin;
- vector emax = it.absmax;
- if(this.solid == SOLID_BSP)
+ if (WarpZoneLib_ExactTrigger_Touch(this, it, false))
{
- emin -= '1 1 1';
- emax += '1 1 1';
+ if(!it.conveyor)
+ IL_PUSH(g_conveyed, it);
+ it.conveyor = this;
}
- if(boxesoverlap(emin, emax, this.absmin, this.absmax)) // quick
- if(WarpZoneLib_BoxTouchesBrush(emin, emax, this, it)) // accurate
- {
- if(!it.conveyor)
- IL_PUSH(g_conveyed, it);
- it.conveyor = this;
- }
});
IL_EACH(g_conveyed, it.conveyor == this,
void func_ladder_think(entity this)
{
+
#ifdef CSQC
// TODO: check if this is what is causing the glitchiness when switching between them
float dt = time - this.move_time;
FOREACH_ENTITY_RADIUS((this.absmin + this.absmax) * 0.5, vlen(this.absmax - this.absmin) * 0.5 + 1, !it.ladder_entity && IS_PLAYER(it) && it.move_movetype != MOVETYPE_NOCLIP && !IS_DEAD(it),
{
- vector emin = it.absmin;
- vector emax = it.absmax;
- if(this.solid == SOLID_BSP || (IS_CSQC && this.solid == SOLID_TRIGGER)) // CSQC doesn't expand properly
- {
- emin -= '1 1 1';
- emax += '1 1 1';
- }
- if(boxesoverlap(emin, emax, this.absmin, this.absmax)) // quick
+ if (WarpZoneLib_ExactTrigger_Touch(this, it, false))
{
- if(WarpZoneLib_BoxTouchesBrush(emin, emax, this, it)) // accurate
- {
- if(!it.ladder_entity)
- IL_PUSH(g_ladderents, it);
- it.ladder_entity = this;
- }
+ if(!it.ladder_entity)
+ IL_PUSH(g_ladderents, it);
+ it.ladder_entity = this;
}
});
this.move_time = time;
this.entremove = func_ladder_remove;
- // NOTE: CSQC's version of setorigin doesn't expand
- this.absmin -= '1 1 1';
- this.absmax += '1 1 1';
-
return true;
}
#endif
{
FOREACH_ENTITY_RADIUS((this.absmin + this.absmax) * 0.5, vlen(this.absmax - this.absmin) * 0.5 + 1, it.swampslug.active == ACTIVE_NOT && IS_PLAYER(it) && !IS_DEAD(it),
{
- vector emin = it.absmin;
- vector emax = it.absmax;
- if(this.solid == SOLID_BSP)
+ if (WarpZoneLib_ExactTrigger_Touch(this, it, false))
{
- emin -= '1 1 1';
- emax += '1 1 1';
+ if(!it.swampslug)
+ IL_PUSH(g_swamped, it);
+ it.swampslug = this;
}
- if(boxesoverlap(emin, emax, this.absmin, this.absmax)) // quick
- if(WarpZoneLib_BoxTouchesBrush(emin, emax, this, it)) // accurate
- {
- if(!it.swampslug)
- IL_PUSH(g_swamped, it);
- it.swampslug = this;
- }
});
IL_EACH(g_swamped, it.swampslug == this,
#if 1
FOREACH_CLIENT(!it.viewloc && IS_PLAYER(it),
{
- vector emin = it.absmin;
- vector emax = it.absmax;
- if(this.solid == SOLID_BSP)
- {
- emin -= '1 1 1';
- emax += '1 1 1';
- }
- if(boxesoverlap(emin, emax, this.absmin, this.absmax)) // quick
- {
- if(WarpZoneLib_BoxTouchesBrush(emin, emax, this, it)) // accurate
- it.viewloc = this;
- }
+ if (WarpZoneLib_ExactTrigger_Touch(this, it, false))
+ it.viewloc = this;
});
#else
-
- for(e = findradius((this.absmin + this.absmax) * 0.5, vlen(this.absmax - this.absmin) * 0.5 + 1); e; e = e.chain)
- if(!e.viewloc)
- if(IS_PLAYER(e)) // should we support non-player entities with this?
- //if(!IS_DEAD(e)) // death view is handled separately, we can't override this just yet
- {
- vector emin = e.absmin;
- vector emax = e.absmax;
- if(this.solid == SOLID_BSP)
- {
- emin -= '1 1 1';
- emax += '1 1 1';
- }
- if(boxesoverlap(emin, emax, this.absmin, this.absmax)) // quick
- if(WarpZoneLib_BoxTouchesBrush(emin, emax, this, e)) // accurate
- e.viewloc = this;
- }
+ for(e = findradius((this.absmin + this.absmax) * 0.5, vlen(this.absmax - this.absmin) * 0.5 + 1); e; e = e.chain)
+ if(!e.viewloc)
+ if(IS_PLAYER(e)) // should we support non-player entities with this?
+ //if(!IS_DEAD(e)) // death view is handled separately, we can't override this just yet
+ if (WarpZoneLib_ExactTrigger_Touch(this, it, false))
+ e.viewloc = this;
#endif
this.nextthink = time;
this.skin = buff.m_skin;
setmodel(this, MDL_BUFF);
- setsize(this, BUFF_MIN, BUFF_MAX);
+ setsize(this, ITEM_D_MINS, ITEM_L_MAXS);
if(this.buff_waypoint)
{
setthink(this, buff_Think);
settouch(this, buff_Touch);
setmodel(this, MDL_BUFF);
- setsize(this, BUFF_MIN, BUFF_MAX);
+ setsize(this, ITEM_D_MINS, ITEM_L_MAXS);
this.reset = buff_Reset;
this.nextthink = time + 0.1;
this.gravity = 1;
.float buff_shield; // delay for players to keep them from spamming buff pickups
.entity buff_model; // controls effects (TODO: make csqc)
-const vector BUFF_MIN = ('-16 -16 0');
-const vector BUFF_MAX = ('16 16 60');
-
float buff_Available(entity buff);
void buff_RemoveAll(entity actor, int removal_type);
#include <common/items/item/pickup.qh>
CLASS(Powerup, Pickup)
#ifdef SVQC
- ATTRIB(Powerup, m_mins, vector, '-16 -16 0');
- ATTRIB(Powerup, m_maxs, vector, '16 16 80');
+ ATTRIB(Powerup, m_maxs, vector, ITEM_L_MAXS);
ATTRIB(Powerup, m_botvalue, int, 11000);
ATTRIB(Powerup, m_itemflags, int, FL_POWERUP);
ATTRIB(Powerup, m_respawntime, float(), GET(g_pickup_respawntime_powerup));
{
if(autocvar__movetype_debug)
{
- vector mi, ma;
- if(this.solid == SOLID_BSP)
- {
- // TODO set the absolute bbox
- mi = this.mins;
- ma = this.maxs;
- }
- else
- {
- mi = this.mins;
- ma = this.maxs;
- }
- mi += this.origin;
- ma += this.origin;
-
- if(this.flags & FL_ITEM)
- {
- mi -= '15 15 1';
- ma += '15 15 1';
- }
- else
- {
- mi -= '1 1 1';
- ma += '1 1 1';
- }
-
- this.absmin = mi;
- this.absmax = ma;
+ this.absmin = this.origin + this.mins;
+ this.absmax = this.origin + this.maxs;
}
else
- {
setorigin(this, this.origin); // calls SV_LinkEdict
- #ifdef CSQC
- // NOTE: CSQC's version of setorigin doesn't expand
- this.absmin -= '1 1 1';
- this.absmax += '1 1 1';
- #endif
- }
if(touch_triggers)
_Movetype_LinkEdict_TouchAreaGrid(this);
if(this.cnt < 0 && !failhard && this.realowner.playerid == this.playerid && !IS_DEAD(this.realowner) && !(STAT(WEAPONS, this.realowner) & WEPSET(PORTO)))
{
- setsize(this, '-16 -16 0', '16 16 48');
+ // FIXME: item properties should be obtained from the registry
+ setsize(this, ITEM_D_MINS, ITEM_D_MAXS);
setorigin(this, this.origin + trace_plane_normal);
if(move_out_of_solid(this))
{
bool WarpZoneLib_ExactTrigger_Touch(entity this, entity toucher, bool touchfunc)
{
vector emin = toucher.absmin, emax = toucher.absmax;
- if(STAT(Q3COMPAT))
+ if (!Q3COMPAT_COMMON)
{
- // DP's tracebox enlarges absolute bounding boxes by a single quake unit
- // we must undo that here to allow accurate touching
- emin += '1 1 1';
- emax -= '1 1 1';
+ // Xonotic and Nexuiz maps assume triggers will be activated by adjacent players
+ // prior to sv_legacy_bbox_expand 0 DP always did this for SVQC and never for CSQC
+ emin -= '1 1 1';
+ emax += '1 1 1';
}
// if called from a touch func, we can assume the boxes do overlap
return WarpZoneLib_BoxTouchesBrush(emin, emax, this, toucher); // accurate
}
-
void WarpZoneLib_MoveOutOfSolid_Expand(entity e, vector by)
{
const float eps = 0.0625;
setsize(this, this.mins, this.maxs);
set_movetype(this, MOVETYPE_NONE);
this.model = "";
+
+ // Xonotic and Nexuiz maps assume triggers will be activated by adjacent players
+ // this causes the touch func to be called in that case
+ // prior to sv_legacy_bbox_expand 0 DP always did this for SVQC and never for CSQC
+ if (!Q3COMPAT_COMMON)
+ setsize(this, this.mins - '1 1 1', this.maxs + '1 1 1');
}
IL_EACH(g_ladders, true,
{
if(it.bot_pickup)
- if(boxesoverlap(org + m1 + '-1 -1 -1', org + m2 + '1 1 1', it.absmin, it.absmax))
- if(boxesoverlap(end, end2, it.absmin + vec2(m1) + '-1 -1 0', it.absmax + vec2(m2) + '1 1 0'))
+ if(boxesoverlap(org + m1, org + m2, it.absmin, it.absmax))
+ if(boxesoverlap(end, end2, it.absmin + vec2(m1), it.absmax + vec2(m2)))
{
vector top = org;
top.z = it.absmax.z + (PL_MAX_CONST.z - PL_MIN_CONST.z);
e = it; break;
});
if (!e)
- e = waypoint_spawn(jp.absmin - PL_MAX_CONST + '1 1 1', jp.absmax - PL_MIN_CONST + '-1 -1 -1', WAYPOINTFLAG_TELEPORT);
+ e = waypoint_spawn(jp.absmin - PL_MAX_CONST, jp.absmax - PL_MIN_CONST, WAYPOINTFLAG_TELEPORT);
if (!pl.wp_locked)
pl.wp_locked = e;
}
void waypoint_spawnforteleporter(entity e, vector destination, float timetaken, entity tracetest_ent)
{
destination = waypoint_fixorigin(destination, tracetest_ent);
- waypoint_spawnforteleporter_boxes(e, WAYPOINTFLAG_TELEPORT, e.absmin - PL_MAX_CONST + '1 1 1', e.absmax - PL_MIN_CONST + '-1 -1 -1', destination, destination, timetaken);
+ waypoint_spawnforteleporter_boxes(e, WAYPOINTFLAG_TELEPORT, e.absmin - PL_MAX_CONST, e.absmax - PL_MIN_CONST, destination, destination, timetaken);
}
entity waypoint_spawnpersonal(entity this, vector position)
set timelimit_min 5 "shortest match time achieveable with reducematchtime and timelimit votes"
set timelimit_max 60 "maximum match time achieveable with extendmatchtime and timelimit votes"
-sv_gameplayfix_delayprojectiles 0
-sv_gameplayfix_q2airaccelerate 1
-sv_gameplayfix_stepmultipletimes 1
-sv_gameplayfix_stepdown 2
-// only available in qc physics
-set sv_gameplayfix_stepdown_maxspeed 0 "maximum speed walking entities can be moving for stepping down to apply"
-
// delay for "kill" to prevent abuse
set g_balance_kill_delay 2 "timer before death when using the kill command"
set g_balance_kill_antispam 5 "additional time added to the kill delay if used repeatedly"
-// this feature is currently buggy in the engine (it appears to PREVENT any dropping in lots of maps, leading to weirdly aligned entities, and in some cases even CAUSES them to drop through solid, like in facing worlds nex)
-sv_gameplayfix_droptofloorstartsolid 0
-
set sv_foginterval 1 "force enable fog in regular intervals"
set sv_maxidle 0 "kick players idle for more than this amount of time in seconds"
set debug_text_3d_default_duration 10 "Default duration for debug_text_3d()"
set debug_text_3d_default_velocity "0 -10 0" "Default velocity for debug_text_3d() in screen coords (X and Y from top left)"
+sv_gameplayfix_delayprojectiles 0
+sv_gameplayfix_q2airaccelerate 1
+sv_gameplayfix_stepmultipletimes 1
+sv_gameplayfix_stepdown 2
+
+// only available in qc physics
+set sv_gameplayfix_stepdown_maxspeed 0 "maximum speed walking entities can be moving for stepping down to apply"
+
+// this feature is currently buggy in the engine (it appears to PREVENT any dropping in lots of maps, leading to weirdly aligned entities, and in some cases even CAUSES them to drop through solid, like in facing worlds nex)
+sv_gameplayfix_droptofloorstartsolid 0
+
// otherwise, antilag breaks
sv_gameplayfix_consistentplayerprethink 1
sv_gameplayfix_gravityunaffectedbyticrate 1
sv_gameplayfix_nogravityonground 1
+// avoid needing to work around Quake bbox expansion in many places
+sv_legacy_bbox_expand 0
+
set sv_q3compat_changehitbox 0 "use Q3 player hitbox dimensions and camera height on Q3 maps (maps with an entry in a .arena or .defi file)"
set g_movement_highspeed 1 "multiplier scale for movement speed (applies to sv_maxspeed and sv_maxairspeed, also applies to air acceleration when g_movement_highspeed_q3_compat is set to 0)"