set g_balance_machinegun_mode 1
set g_balance_machinegun_reload_ammo 30
set g_balance_machinegun_reload_time 1.5
-set g_balance_machinegun_solidpenetration 13.1
+set g_balance_machinegun_solidpenetration 63
set g_balance_machinegun_spread_add 0.012
set g_balance_machinegun_spread_max 0.05
set g_balance_machinegun_spread_min 0
set g_pickup_fuel_jetpack 100
set g_pickup_fuel_max 100
set g_pickup_armorsmall 5
-set g_pickup_armorsmall_max 20
+set g_pickup_armorsmall_max 100
set g_pickup_armorsmall_anyway 1
set g_pickup_armormedium 25
set g_pickup_armormedium_max 100
-// ================
-// Overkill Mode
-// ================
+// ==============
+// Overkill Mod
+// ==============
exec defaultXonotic.cfg
exec balance-overkill.cfg
// general gameplay
set g_overkill 1
+set g_respawn_ghosts 0
+
set g_nades 1
+set g_nades_nade_small 1
+set g_nades_spread 0
+set g_nades_nade_refire 10
+set g_nades_nade_newton_style 2
+
set g_dodging 1
set sv_dodging_wall_dodging 1
+
set g_spawn_near_teammate 1
set g_spawn_near_teammate_ignore_spawnpoint 1
+set g_spawnshieldtime 0.5
+set g_respawn_delay_forced 2
+
+set g_lms_start_armor 100
// waypoint editor enable
set g_waypointeditor 0
set g_waypointeditor_auto 0 "Automatically create waypoints for bots while playing; BEWARE, this currently creates too many of them"
+set g_waypointeditor_symmetrical 0 "Enable symmetrical editing of waypoints, useful in symmetrical CTF maps. NOTE: it assumes that the map is perfectly symmetrical"
+set g_waypointeditor_symmetrical_center "0 0" "Center (x y) for symmetrical editing of waypoints"
set bot_ignore_bots 0 "When set, bots don't shoot at other bots"
set bot_join_empty 0 "When set, bots also play if no player has joined the server"
set bot_vs_human 0 "Bots and humans play in different teams when set. positive values to make an all-bot blue team, set to negative values to make an all-bot red team, the absolute value is the ratio bots vs humans (1 for equal count). Changes will be correctly applied only from the next game"
set g_overkill 0 "enable overkill"
set g_overkill_powerups_replace 1
+set g_overkill_itemwaypoints 1
set g_overkill_filter_healthmega 0
set g_overkill_filter_armormedium 0
set g_overkill_filter_armorbig 0
set g_nades_nade_edgedamage 90
set g_nades_nade_radius 300
set g_nades_nade_force 650
-set g_nades_nade_newton_style 0
+set g_nades_nade_newton_style 0 "0 is absolute, 1 is relative (takes into account player speed), 2 is something in between"
set g_nades_nade_type 1 "Type of the off-hand grenade. 1:normal 2:napalm 3:ice 4:translocate 5:spawn 6:heal 7:pokenade 8:entrap"
seta cl_nade_timer 1 "show a visual timer for nades, 1 = only circle, 2 = circle with text"
sv_aircontrol_penalty 180
sv_aircontrol_power 2
sv_aircontrol_backwards 0
-sv_airspeedlimit_nonqw 800
+sv_airspeedlimit_nonqw 900
sv_warsowbunny_turnaccel 0
sv_warsowbunny_accel 0.1593
sv_warsowbunny_topspeed 925
sv_warsowbunny_topspeed 925
sv_warsowbunny_backtosideratio 0.8
sv_friction_on_land 0
-sv_friction_slick 0.5
+sv_friction_slick 0
sv_doublejump 1
sv_jumpspeedcap_min 0
sv_jumpspeedcap_max 0.5
sound(NULL, CH_INFO, SND_TYPEHIT, VOL_BASE, ATTN_NONE);
typehit_time_prev = typehit_time;
}
+
+ static float kill_time_prev = 0;
+ float kill_time = STAT(KILL_TIME);
+ if (COMPARE_INCREASING(kill_time, kill_time_prev) > autocvar_cl_hitsound_antispam_time)
+ {
+ sound(NULL, CH_INFO, SND_KILL, VOL_BASE, ATTN_NONE);
+ kill_time_prev = kill_time;
+ }
}
vector crosshair_getcolor(entity this, float health_stat)
this.colormap = ReadShort();
else
this.colormap = 0;
+ this.skin = ReadByte();
}
if(f & 2)
#include "ent_cs.qh"
+REGISTRY(EntCSProps, BITS(16) - 1)
+#define EntCSProps_from(i) _EntCSProps_from(i, NULL)
+REGISTER_REGISTRY(EntCSProps)
+REGISTRY_SORT(EntCSProps)
+REGISTRY_CHECK(EntCSProps)
+STATIC_INIT(RegisterEntCSProps_renumber) { FOREACH(EntCSProps, true, it.m_id = i); }
+
+.bool m_public;
+.bool(entity ent, entity player) m_check;
+.void(entity ent, entity player) m_set;
+.void(int chan, entity ent) m_send;
+.void(entity ent) m_receive;
+
+#ifdef SVQC
+#define ENTCS_PROP(id, ispublic, checkprop, setprop, svsend, clreceive) \
+ bool id##_check(entity ent, entity player) { return (ent.(checkprop) != player.(checkprop)); } \
+ void id##_set(entity ent, entity player) { setprop(ent.(checkprop), player.(checkprop)); } \
+ void id##_send(int chan, entity ent) { LAMBDA(svsend); } \
+ REGISTER(EntCSProps, ENTCS_PROP, id, m_id, new_pure(entcs_prop)) { \
+ this.m_public = ispublic; \
+ this.m_check = id##_check; \
+ this.m_set = id##_set; \
+ this.m_send = id##_send; \
+ }
+#elif defined(CSQC)
+#define ENTCS_PROP(id, ispublic, checkprop, setprop, svsend, clreceive) \
+ void id##_receive(entity ent) { LAMBDA(clreceive); } \
+ REGISTER(EntCSProps, ENTCS_PROP, id, m_id, new_pure(entcs_prop)) { \
+ this.m_public = ispublic; \
+ this.m_receive = id##_receive; \
+ }
+#endif
+
#define ENTCS_SET_NORMAL(var, x) MACRO_BEGIN \
var = x; \
MACRO_END
var = strzone(x); \
MACRO_END
-// #define PROP(public, fld, set, sv, cl)
-#define ENTCS_NETPROPS(ent, PROP) PROP(false, sv_entnum, ENTCS_SET_NORMAL, {}, {}) /* sentinel */ \
- PROP(false, origin, ENTCS_SET_NORMAL, \
- { WriteCoord(chan, ent.origin.x); WriteCoord(chan, ent.origin.y); \
- WriteCoord(chan, ent.origin.z); }, \
- { ent.has_sv_origin = true; vector v; v.x = ReadCoord(); v.y = ReadCoord(); v.z = ReadCoord(); setorigin(ent, v); }) \
- \
- PROP(false, angles_y, ENTCS_SET_NORMAL, \
- { WriteByte(chan, ent.angles.y / 360 * 256); }, \
- { vector v = '0 0 0'; v.y = ReadByte() / 256 * 360; ent.angles = v; }) \
- \
- PROP(false, health, ENTCS_SET_NORMAL, \
- { WriteByte(chan, bound(0, ent.health / 10, 255)); /* FIXME: use a better scale? */ }, \
- { ent.healthvalue = ReadByte() * 10; }) \
- \
- PROP(false, armorvalue, ENTCS_SET_NORMAL, \
- { WriteByte(chan, bound(0, ent.armorvalue / 10, 255)); /* FIXME: use a better scale? */ }, \
- { ent.armorvalue = ReadByte() * 10; }) \
- \
- PROP(true, netname, ENTCS_SET_MUTABLE_STRING, \
- { WriteString(chan, ent.netname); }, \
- { if (ent.netname) strunzone(ent.netname); ent.netname = strzone(ReadString()); }) \
- \
- PROP(true, model, ENTCS_SET_NORMAL, \
- { WriteString(chan, ent.model); }, \
- { if (ent.model) strunzone(ent.model); ent.model = strzone(ReadString()); }) \
- \
- PROP(true, skin, ENTCS_SET_NORMAL, \
- { WriteByte(chan, ent.skin); }, \
- { ent.skin = ReadByte(); }) \
- \
- PROP(true, clientcolors, ENTCS_SET_NORMAL, \
- { WriteByte(chan, ent.clientcolors); }, \
- { ent.colormap = ReadByte(); }) \
- \
- PROP(true, frags, ENTCS_SET_NORMAL, \
- { WriteShort(chan, ent.frags); }, \
- { ent.frags = ReadShort(); }) \
- \
- /**/
+ENTCS_PROP(ENTNUM, false, sv_entnum, ENTCS_SET_NORMAL, {}, {}) /* sentinel */
+
+ENTCS_PROP(ORIGIN, false, origin, ENTCS_SET_NORMAL,
+ { WriteVector(chan, ent.origin); },
+ { ent.has_sv_origin = true; vector v = ReadVector(); setorigin(ent, v); })
+
+ENTCS_PROP(ANGLES, false, angles_y, ENTCS_SET_NORMAL,
+ { WriteByte(chan, ent.angles.y / 360 * 256); },
+ { vector v = '0 0 0'; v.y = ReadByte() / 256 * 360; ent.angles = v; })
+
+ENTCS_PROP(HEALTH, false, health, ENTCS_SET_NORMAL,
+ { WriteByte(chan, bound(0, ent.health / 10, 255)); /* FIXME: use a better scale? */ },
+ { ent.healthvalue = ReadByte() * 10; })
+
+ENTCS_PROP(ARMOR, false, armorvalue, ENTCS_SET_NORMAL,
+ { WriteByte(chan, bound(0, ent.armorvalue / 10, 255)); /* FIXME: use a better scale? */ },
+ { ent.armorvalue = ReadByte() * 10; })
+
+ENTCS_PROP(NAME, true, netname, ENTCS_SET_MUTABLE_STRING,
+ { WriteString(chan, ent.netname); },
+ { if (ent.netname) strunzone(ent.netname); ent.netname = strzone(ReadString()); })
+
+ENTCS_PROP(MODEL, true, model, ENTCS_SET_NORMAL,
+ { WriteString(chan, ent.model); },
+ { if (ent.model) strunzone(ent.model); ent.model = strzone(ReadString()); })
+
+ENTCS_PROP(SKIN, true, skin, ENTCS_SET_NORMAL,
+ { WriteByte(chan, ent.skin); },
+ { ent.skin = ReadByte(); })
+
+ENTCS_PROP(CLIENTCOLORS, true, clientcolors, ENTCS_SET_NORMAL,
+ { WriteByte(chan, ent.clientcolors); },
+ { ent.colormap = ReadByte(); })
+
+ENTCS_PROP(FRAGS, true, frags, ENTCS_SET_NORMAL,
+ { WriteShort(chan, ent.frags); },
+ { ent.frags = ReadShort(); })
#ifdef SVQC
int ENTCS_PUBLICMASK = 0;
STATIC_INIT(ENTCS_PUBLICMASK)
{
- int i = 0;
- #define X(public, fld, set, sv, cl) { \
- if (public) { \
- ENTCS_PUBLICMASK |= BIT(i); \
- } \
- i += 1; \
- }
- ENTCS_NETPROPS(this, X);
- #undef X
- if (i >= BITS(16 - 1)) LOG_FATAL("Exceeded ENTCS_NETPROPS limit");
+ FOREACH(EntCSProps, it.m_public,
+ {
+ ENTCS_PUBLICMASK |= BIT(it.m_id);
+ });
}
bool _entcs_send(entity this, entity to, int sf, int chan)
WriteHeader(chan, CLIENT_ENTCS);
WriteByte(chan, etof(player) - 1);
WriteShort(chan, sf);
- int i = 0;
- #define X(public, fld, set, sv, cl) { \
- if (sf & BIT(i)) { \
- sv; \
- } \
- i += 1; \
- }
- ENTCS_NETPROPS(this, X);
- #undef X
+ FOREACH(EntCSProps, sf & BIT(it.m_id),
+ {
+ it.m_send(chan, this);
+ });
return true;
}
{
this.nextthink = time + 0.033333333333; // TODO: increase this to like 0.15 once the client can do smoothing
entity o = this.owner;
- int i = 0;
- #define X(public, fld, set, sv, cl) { \
- if (o.fld != this.fld) { \
- set(this.fld, o.fld); \
- this.SendFlags |= BIT(i); \
- } \
- i += 1; \
- }
- ENTCS_NETPROPS(this, X);
- #undef X
+ FOREACH(EntCSProps, it.m_check(this, o),
+ {
+ it.m_set(this, o);
+ this.SendFlags |= BIT(it.m_id);
+ });
setorigin(this, this.origin); // relink
}
int sf = ReadShort();
e.has_sv_origin = false;
e.m_entcs_private = boolean(sf & BIT(0));
- int i = 0;
- #define X(public, fld, set, sv, cl) { \
- if (sf & BIT(i)) { \
- cl; \
- } \
- i += 1; \
- }
- ENTCS_NETPROPS(e, X);
- #undef X
+ FOREACH(EntCSProps, sf & BIT(it.m_id),
+ {
+ it.m_receive(e);
+ });
e.iflags |= IFLAG_ORIGIN;
InterpolateOrigin_Note(e);
getthink(e)(e);
FOREACH(Buffs, buff_Available(it),
{
// if it's already been chosen, give it a lower priority
- RandomSelection_AddEnt(it, 1, max(0.2, 1 / it.buff_seencount));
+ RandomSelection_AddEnt(it, max(0.2, 1 / it.buff_seencount), 1);
});
entity newbuff = RandomSelection_chosen_ent;
newbuff.buff_seencount += 1; // lower chances of seeing this buff again soon
player.buff_disability_effect_time = 0;
}
-.float stat_sv_maxspeed;
-.float stat_sv_airspeedlimit_nonqw;
-.float stat_sv_jumpvelocity;
-
-MUTATOR_HOOKFUNCTION(buffs, PlayerPhysics)
+MUTATOR_HOOKFUNCTION(buffs, PlayerPhysics_UpdateStats)
{
entity player = M_ARGV(0, entity);
+ // these automatically reset, no need to worry
if(player.buffs & BUFF_SPEED.m_itemid)
- {
- player.stat_sv_maxspeed *= autocvar_g_buffs_speed_speed;
- player.stat_sv_airspeedlimit_nonqw *= autocvar_g_buffs_speed_speed;
- }
+ STAT(MOVEVARS_HIGHSPEED, player) *= autocvar_g_buffs_speed_speed;
if(time < player.buff_disability_time)
- {
- player.stat_sv_maxspeed *= autocvar_g_buffs_disability_speed;
- player.stat_sv_airspeedlimit_nonqw *= autocvar_g_buffs_disability_speed;
- }
-
- if(player.buffs & BUFF_JUMP.m_itemid)
- {
- // automatically reset, no need to worry
- player.stat_sv_jumpvelocity = autocvar_g_buffs_jump_height;
- }
+ STAT(MOVEVARS_HIGHSPEED, player) *= autocvar_g_buffs_disability_speed;
}
-MUTATOR_HOOKFUNCTION(buffs, PlayerJump)
+MUTATOR_HOOKFUNCTION(buffs, PlayerPhysics)
{
entity player = M_ARGV(0, entity);
+ // these automatically reset, no need to worry
if(player.buffs & BUFF_JUMP.m_itemid)
- M_ARGV(1, float) = autocvar_g_buffs_jump_height;
+ STAT(MOVEVARS_JUMPVELOCITY, player) = autocvar_g_buffs_jump_height;
}
MUTATOR_HOOKFUNCTION(buffs, MonsterMove)
#include "sv_dodging.qh"
+#define PHYS_DODGING g_dodging
+#define PHYS_DODGING_DELAY autocvar_sv_dodging_delay
+#define PHYS_DODGING_DISTANCE_THRESHOLD autocvar_sv_dodging_wall_distance_threshold
+#define PHYS_DODGING_FROZEN_NODOUBLETAP autocvar_sv_dodging_frozen_doubletap
+#define PHYS_DODGING_HEIGHT_THRESHOLD autocvar_sv_dodging_height_threshold
+#define PHYS_DODGING_HORIZ_SPEED autocvar_sv_dodging_horiz_speed
+#define PHYS_DODGING_HORIZ_SPEED_FROZEN autocvar_sv_dodging_horiz_speed_frozen
+#define PHYS_DODGING_RAMP_TIME autocvar_sv_dodging_ramp_time
+#define PHYS_DODGING_UP_SPEED autocvar_sv_dodging_up_speed
+#define PHYS_DODGING_WALL autocvar_sv_dodging_wall_dodging
+#define PHYS_DODGING_AIR autocvar_sv_dodging_air_dodging
+#define PHYS_DODGING_MAXSPEED autocvar_sv_dodging_maxspeed
+#define PHYS_DODGING_PRESSED_KEYS(s) (s).pressedkeys
+
+// we ran out of stats slots! TODO: re-enable this when prediction is available for dodging
+#if 0
#define PHYS_DODGING STAT(DODGING, this)
#define PHYS_DODGING_DELAY STAT(DODGING_DELAY, this)
#define PHYS_DODGING_DISTANCE_THRESHOLD STAT(DODGING_DISTANCE_THRESHOLD, this)
#define PHYS_DODGING_WALL STAT(DODGING_WALL, this)
#define PHYS_DODGING_AIR STAT(DODGING_AIR, this)
#define PHYS_DODGING_MAXSPEED STAT(DODGING_MAXSPEED, this)
-#define PHYS_DODGING_PRESSED_KEYS(s) (s).pressedkeys
+#endif
#ifdef CSQC
#define PHYS_DODGING_FRAMETIME (1 / (frametime <= 0 ? 60 : frametime))
bool autocvar_g_overkill_powerups_replace;
+bool autocvar_g_overkill_itemwaypoints = true;
+
bool autocvar_g_overkill_filter_healthmega;
bool autocvar_g_overkill_filter_armormedium;
bool autocvar_g_overkill_filter_armorbig;
}
}
+bool ok_HandleItemWaypoints(entity e)
+{
+ if(!autocvar_g_overkill_itemwaypoints)
+ return false; // don't handle it
+
+ switch(e.itemdef)
+ {
+ case ITEM_HealthMega: return true;
+ case ITEM_ArmorMedium: return true;
+ case ITEM_ArmorBig: return true;
+ case ITEM_ArmorMega: return true;
+ }
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(ok, Item_RespawnCountdown)
+{
+ entity item = M_ARGV(0, entity);
+ return ok_HandleItemWaypoints(item);
+}
+
+MUTATOR_HOOKFUNCTION(ok, Item_ScheduleRespawn)
+{
+ entity item = M_ARGV(0, entity);
+ return ok_HandleItemWaypoints(item);
+}
+
MUTATOR_HOOKFUNCTION(ok, FilterItem)
{
entity item = M_ARGV(0, entity);
SOUND(HIT, "misc/hit");
SOUND(TYPEHIT, "misc/typehit");
+SOUND(KILL, "misc/kill");
SOUND(SPAWN, "misc/spawn");
REGISTER_STAT(ENTRAP_ORB, float)
REGISTER_STAT(ENTRAP_ORB_ALPHA, float)
REGISTER_STAT(ITEMSTIME, int, autocvar_sv_itemstime)
+REGISTER_STAT(KILL_TIME, float)
#ifdef SVQC
bool autocvar_g_ctf_leaderboard;
float autocvar_sv_dodging_maxspeed = 450;
#endif
+#if 0
REGISTER_STAT(DODGING, int, g_dodging)
REGISTER_STAT(DODGING_DELAY, float, autocvar_sv_dodging_delay)
REGISTER_STAT(DODGING_DISTANCE_THRESHOLD, float, autocvar_sv_dodging_wall_distance_threshold)
-REGISTER_STAT(DODGING_FROZEN, int, autocvar_sv_dodging_frozen)
REGISTER_STAT(DODGING_FROZEN_NO_DOUBLETAP, int, autocvar_sv_dodging_frozen_doubletap)
REGISTER_STAT(DODGING_HEIGHT_THRESHOLD, float, autocvar_sv_dodging_height_threshold)
REGISTER_STAT(DODGING_HORIZ_SPEED, float, autocvar_sv_dodging_horiz_speed)
REGISTER_STAT(DODGING_HORIZ_SPEED_FROZEN, float, autocvar_sv_dodging_horiz_speed_frozen)
REGISTER_STAT(DODGING_RAMP_TIME, float, autocvar_sv_dodging_ramp_time)
-/** cvar loopback */
-REGISTER_STAT(DODGING_TIMEOUT, float)
REGISTER_STAT(DODGING_UP_SPEED, float, autocvar_sv_dodging_up_speed)
REGISTER_STAT(DODGING_WALL, bool, autocvar_sv_dodging_wall_dodging)
REGISTER_STAT(DODGING_AIR, bool, autocvar_sv_dodging_air_dodging)
REGISTER_STAT(DODGING_MAXSPEED, float, autocvar_sv_dodging_maxspeed)
+#endif
+/** cvar loopback */
+REGISTER_STAT(DODGING_FROZEN, int, autocvar_sv_dodging_frozen)
+REGISTER_STAT(DODGING_TIMEOUT, float)
REGISTER_STAT(JETPACK_ACCEL_SIDE, float, autocvar_g_jetpack_acceleration_side)
REGISTER_STAT(JETPACK_ACCEL_UP, float, autocvar_g_jetpack_acceleration_up)
REGISTER_STAT(JETPACK_MAXSPEED_UP, float, autocvar_g_jetpack_maxspeed_up)
REGISTER_STAT(JETPACK_REVERSE_THRUST, float, autocvar_g_jetpack_reverse_thrust)
-REGISTER_STAT(MOVEVARS_HIGHSPEED, float, autocvar_g_movement_highspeed)
+REGISTER_STAT(MOVEVARS_HIGHSPEED, float)
#ifdef SVQC
AUTOCVAR(g_walljump, bool, false, "Enable wall jumping mutator");
this.count += 1;
if(this.count == 1)
{
- MUTATOR_CALLHOOK(Item_RespawnCountdown, string_null, '0 0 0');
do {
{
entity wi = Weapons_from(this.weapon);
}
}
} while (0);
+ bool mutator_returnvalue = MUTATOR_CALLHOOK(Item_RespawnCountdown, this);
if(this.waypointsprite_attached)
{
GameItem def = this.itemdef;
- if (Item_ItemsTime_SpectatorOnly(def))
+ if (Item_ItemsTime_SpectatorOnly(def) && !mutator_returnvalue)
WaypointSprite_UpdateRule(this.waypointsprite_attached, 0, SPRITERULE_SPECTATOR);
WaypointSprite_UpdateBuildFinished(this.waypointsprite_attached, time + ITEM_RESPAWN_TICKS);
}
void Item_ScheduleRespawnIn(entity e, float t)
{
// if the respawn time is longer than 10 seconds, show a waypoint, otherwise, just respawn normally
- if ((Item_ItemsTime_Allow(e.itemdef) || (e.weapons & WEPSET_SUPERWEAPONS)) && (t - ITEM_RESPAWN_TICKS) > 0)
+ if ((Item_ItemsTime_Allow(e.itemdef) || (e.weapons & WEPSET_SUPERWEAPONS) || MUTATOR_CALLHOOK(Item_ScheduleRespawn, e, t)) && (t - ITEM_RESPAWN_TICKS) > 0)
{
setthink(e, Item_RespawnCountdown);
e.nextthink = time + max(0, t - ITEM_RESPAWN_TICKS);
e.scheduledrespawntime = e.nextthink + ITEM_RESPAWN_TICKS;
e.count = 0;
- t = Item_ItemsTime_UpdateTime(e, e.scheduledrespawntime);
- Item_ItemsTime_SetTime(e, t);
- Item_ItemsTime_SetTimesForAllPlayers();
+ if(Item_ItemsTime_Allow(e.itemdef) || (e.weapons & WEPSET_SUPERWEAPONS))
+ {
+ t = Item_ItemsTime_UpdateTime(e, e.scheduledrespawntime);
+ Item_ItemsTime_SetTime(e, t);
+ Item_ItemsTime_SetTimesForAllPlayers();
+ }
}
else
{
const float ITEM_RESPAWN_TICKS = 10;
-#define ITEM_RESPAWNTIME(i) ((i).respawntime + (crandom() * (i).respawntimejitter))
+#define ITEM_RESPAWNTIME(i) ((i).respawntime + crandom() * (i).respawntimejitter)
// range: respawntime - respawntimejitter .. respawntime + respawntimejitter
-#define ITEM_RESPAWNTIME_INITIAL(i) (ITEM_RESPAWN_TICKS + (random() * ((i).respawntime + (i).respawntimejitter - ITEM_RESPAWN_TICKS)))
+#define ITEM_RESPAWNTIME_INITIAL(i) (ITEM_RESPAWN_TICKS + random() * ((i).respawntime + (i).respawntimejitter - ITEM_RESPAWN_TICKS))
// range: 10 .. respawntime + respawntimejitter
.float max_armorvalue;
SUB_SETORIGIN (this, this.finaldest);
this.SUB_VELOCITY = '0 0 0';
this.SUB_NEXTTHINK = -1;
- if (this.think1)
+ if (this.think1 && this.think1 != SUB_CalcMoveDone)
this.think1 (this);
}
this.angles = this.finalangle;
this.SUB_AVELOCITY = '0 0 0';
this.SUB_NEXTTHINK = -1;
- if (this.think1)
+ if (this.think1 && this.think1 != SUB_CalcAngleMoveDone) // avoid endless loops
this.think1 (this);
}
void sys_phys_fix(entity this, float dt)
{
WarpZone_PlayerPhysics_FixVAngle(this);
+ STAT(MOVEVARS_HIGHSPEED, this) = autocvar_g_movement_highspeed;
+ MUTATOR_CALLHOOK(PlayerPhysics_UpdateStats, this); // do it BEFORE the function so we can modify highspeed!
Physics_UpdateStats(this, PHYS_HIGHSPEED(this));
}
#include "dialog_settings_effects.qh"
#include "slider_picmip.qh"
-#include "slider_particles.qh"
#include "slider_sbfadetime.qh"
#include "weaponslist.qh"
#include "keybinder.qh"
me.TDempty(me, 0.2);
me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Quality:")));
setDependent(e, "cl_particles", 1, 1);
- me.TD(me, 1, 2, e = makeXonoticParticlesSlider());
+ me.TD(me, 1, 2, e = makeXonoticSlider_T(0, 3.0, 0.25, "cl_particles_quality",
+ _("Multiplier for amount of particles. Less means less particles, which in turn gives for better performance (default: 1.0)")));
setDependent(e, "cl_particles", 1, 1);
me.TR(me);
me.TDempty(me, 0.2);
me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Distance:")));
setDependent(e, "cl_particles", 1, 1);
- me.TD(me, 1, 2, e = makeXonoticSlider_T(200, 500, 20, "r_drawparticles_drawdistance",
+ me.TD(me, 1, 2, e = makeXonoticSlider_T(200, 3000, 200, "r_drawparticles_drawdistance",
_("Particles further away than this will not be drawn (default: 1000)")));
setDependent(e, "cl_particles", 1, 1);
{
me.configureXonoticTextSlider(me, "cl_particles_quality",
_("Multiplier for amount of particles. Less means less particles, which in turn gives for better performance (default: 1)"));
- if(cvar("developer")) { me.addValue(me, ZCTX(_("PART^OMG")), "0.4 250 0"); }
- me.addValue(me, ZCTX(_("PART^Low")), "0.4 500 0");
- me.addValue(me, ZCTX(_("PART^Medium")), "0.8 750 0");
+ if(cvar("developer")) { me.addValue(me, ZCTX(_("PART^OMG")), "0.25 250 0"); }
+ me.addValue(me, ZCTX(_("PART^Low")), "0.5 500 0");
+ me.addValue(me, ZCTX(_("PART^Medium")), "0.75 750 0");
me.addValue(me, ZCTX(_("PART^Normal")), "1.0 1000 1");
- me.addValue(me, ZCTX(_("PART^High")), "1.0 1500 1");
- me.addValue(me, ZCTX(_("PART^Ultra")), "1.0 2000 2");
- if(cvar("developer")) { me.addValue(me, ZCTX(_("PART^Ultimate")), "1.0 3000 2"); }
+ me.addValue(me, ZCTX(_("PART^High")), "1.5 1500 1");
+ me.addValue(me, ZCTX(_("PART^Ultra")), "2.0 2000 2");
+ if(cvar("developer")) { me.addValue(me, ZCTX(_("PART^Ultimate")), "3.0 3000 2"); }
me.configureXonoticTextSliderValues(me);
}
void XonoticParticlesSlider_loadCvars(entity me)
}
+bool show_propermenu = false;
+
float preMenuInit()
{
vector sz;
vector boxA, boxB;
+ if(random() < 0.1)
+ show_propermenu = true;
+
updateCheck();
MapInfo_Cache_Create();
fs = ((1/draw_scale.x) * eX + (1/draw_scale.y) * eY) * 12;
line = eY * fs.y;
string l1, l2;
- l1 = sprintf(_("Update to %s now!"), _Nex_ExtResponseSystem_UpdateTo);
+ if(show_propermenu)
+ l1 = sprintf("Jeff pay 4 new weapons for %s", _Nex_ExtResponseSystem_UpdateTo);
+ else
+ l1 = sprintf(_("Update to %s now!"), _Nex_ExtResponseSystem_UpdateTo);
l2 = "http://www.xonotic.org/";
if(_Nex_ExtResponseSystem_UpdateToURL)
l2 = _Nex_ExtResponseSystem_UpdateToURL;
float autocvar_g_turrets_targetscan_mindelay;
bool autocvar_g_use_ammunition;
bool autocvar_g_waypointeditor;
+bool autocvar_g_waypointeditor_symmetrical;
+vector autocvar_g_waypointeditor_symmetrical_center;
bool autocvar_g_waypoints_for_items;
#define autocvar_g_weapon_stay cvar("g_weapon_stay")
bool autocvar_g_weapon_throwable;
.float wp24mincost, wp25mincost, wp26mincost, wp27mincost, wp28mincost, wp29mincost, wp30mincost, wp31mincost;
.float wpconsidered;
.float wpcost;
+.float wphardwired;
.int wpflags;
bool bot_aim(entity this, .entity weaponentity, float shotspeed, float shotspeedupward, float maxshottime, float applygravity);
return;
}
- else if(this.health>WEP_CVAR(devastator, damage)*0.5)
+ else if(this.health > WEP_CVAR(devastator, damage) * 0.5 * ((this.strength_finished < time) ? autocvar_g_balance_powerup_strength_selfdamage : 1))
{
if(this.velocity.z < 0)
{
evadeobstacle = '0 0 0';
evadelava = '0 0 0';
+ this.aistatus &= ~AI_STATUS_DANGER_AHEAD;
makevectors(this.v_angle.y * '0 1 0');
if (this.waterlevel)
{
// Check for water/slime/lava and dangerous edges
// (only when the bot is on the ground or jumping intentionally)
- this.aistatus &= ~AI_STATUS_DANGER_AHEAD;
vector dst_ahead = this.origin + this.view_ofs + offset;
vector dst_down = dst_ahead - '0 0 3000';
void havocbot_aim(entity this)
{
- vector myvel, enemyvel;
-// if(this.flags & FL_INWATER)
-// return;
if (time < this.nextaim)
return;
this.nextaim = time + 0.1;
- myvel = this.velocity;
+ vector myvel = this.velocity;
if (!this.waterlevel)
myvel.z = 0;
- if (this.enemy)
+ if(MUTATOR_CALLHOOK(HavocBot_Aim, this)) { /* do nothing */ }
+ else if (this.enemy)
{
- enemyvel = this.enemy.velocity;
+ vector enemyvel = this.enemy.velocity;
if (!this.enemy.waterlevel)
enemyvel.z = 0;
lag_additem(this, time + this.ping, 0, 0, this.enemy, this.origin, myvel, (this.enemy.absmin + this.enemy.absmax) * 0.5, enemyvel);
float dist;
float totaldist;
float stepdist;
- float yaw;
float ignorehazards;
float swimming;
+ entity tw_ladder = NULL;
if(autocvar_bot_debug_tracewalk)
{
}
// Movement loop
- yaw = vectoyaw(move);
move = end - org;
for (;;)
{
org = trace_endpos - normalize(org - trace_endpos) * stepdist;
for (; org.z < end.z + e.maxs.z; org.z += stepdist)
{
- if(autocvar_bot_debug_tracewalk)
- debugnode(e, org);
+ if(autocvar_bot_debug_tracewalk)
+ debugnode(e, org);
- if(pointcontents(org) == CONTENT_EMPTY)
- break;
+ if(pointcontents(org) == CONTENT_EMPTY)
+ break;
}
if(pointcontents(org + '0 0 1') != CONTENT_EMPTY)
if(autocvar_bot_debug_tracewalk)
debugnodestatus(trace_endpos, DEBUG_NODE_WARNING);
- // check for doors
+ FOREACH_ENTITY_CLASS("func_ladder", true,
+ { it.solid = SOLID_BSP; });
+
traceline( org, move, movemode, e);
+
+ FOREACH_ENTITY_CLASS("func_ladder", true,
+ { it.solid = SOLID_TRIGGER; });
+
if ( trace_ent.classname == "door_rotating" || trace_ent.classname == "door")
{
vector nextmove;
move = nextmove;
}
}
+ else if (trace_ent.classname == "func_ladder")
+ {
+ tw_ladder = trace_ent;
+ vector ladder_bottom = trace_endpos - dir * m2.x;
+ vector ladder_top = ladder_bottom;
+ ladder_top.z = trace_ent.absmax.z + (-m1.z + 1);
+ tracebox(ladder_bottom, m1, m2, ladder_top, movemode, e);
+ if (trace_fraction < 1 || trace_startsolid)
+ {
+ if(autocvar_bot_debug_tracewalk)
+ debugnodestatus(trace_endpos, DEBUG_NODE_FAIL);
+
+ return false; // failed
+ }
+ org = ladder_top + dir * m2.x;
+ move = org + dir * stepdist;
+ continue;
+ }
else
{
if(autocvar_bot_debug_tracewalk)
org = trace_endpos;
}
+
+ if(tw_ladder && org.z < tw_ladder.absmax.z)
+ {
+ // stop tracewalk if destination height is lower than the top of the ladder
+ // otherwise bot can't easily figure out climbing direction
+ if(autocvar_bot_debug_tracewalk)
+ debugnodestatus(org, DEBUG_NODE_FAIL);
+
+ return false;
+ }
}
//print("tracewalk: ", vtos(start), " did not arrive at ", vtos(end), " but at ", vtos(org), "\n");
return w;
}
+void waypoint_showlink(entity wp1, entity wp2, int display_type)
+{
+ if (!(wp1 && wp2))
+ return;
+
+ if (wp1.wphardwired && wp2.wphardwired)
+ te_beam(NULL, wp1.origin, wp2.origin);
+ else if (display_type == 1)
+ te_lightning2(NULL, wp1.origin, wp2.origin);
+}
+
void botframe_showwaypointlinks()
{
if (time < botframe_waypointeditorlightningtime)
botframe_waypointeditorlightningtime = time + 0.5;
FOREACH_CLIENT(IS_PLAYER(it) && !it.isbot,
{
- if(IS_ONGROUND(it) || it.waterlevel > WATERLEVEL_NONE)
+ int display_type = 0;
+ entity head = navigation_findnearestwaypoint(it, false);
+ if (IS_ONGROUND(it) || it.waterlevel > WATERLEVEL_NONE)
+ display_type = 1; // default
+ else if(head && (head.wphardwired))
+ display_type = 2; // only hardwired
+
+ if (display_type)
{
//navigation_testtracewalk = true;
- entity head = navigation_findnearestwaypoint(it, false);
- // print("currently selected WP is ", etos(head), "\n");
+ //print("currently selected WP is ", etos(head), "\n");
//navigation_testtracewalk = false;
if (head)
{
- entity w;
- w = head ;if (w) te_lightning2(NULL, w.origin, it.origin);
- w = head.wp00;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp01;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp02;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp03;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp04;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp05;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp06;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp07;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp08;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp09;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp10;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp11;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp12;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp13;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp14;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp15;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp16;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp17;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp18;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp19;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp20;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp21;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp22;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp23;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp24;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp25;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp26;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp27;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp28;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp29;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp30;if (w) te_lightning2(NULL, w.origin, head.origin);
- w = head.wp31;if (w) te_lightning2(NULL, w.origin, head.origin);
+ te_lightning2(NULL, head.origin, it.origin);
+ waypoint_showlink(head.wp00, head, display_type);
+ waypoint_showlink(head.wp01, head, display_type);
+ waypoint_showlink(head.wp02, head, display_type);
+ waypoint_showlink(head.wp03, head, display_type);
+ waypoint_showlink(head.wp04, head, display_type);
+ waypoint_showlink(head.wp05, head, display_type);
+ waypoint_showlink(head.wp06, head, display_type);
+ waypoint_showlink(head.wp07, head, display_type);
+ waypoint_showlink(head.wp08, head, display_type);
+ waypoint_showlink(head.wp09, head, display_type);
+ waypoint_showlink(head.wp10, head, display_type);
+ waypoint_showlink(head.wp11, head, display_type);
+ waypoint_showlink(head.wp12, head, display_type);
+ waypoint_showlink(head.wp13, head, display_type);
+ waypoint_showlink(head.wp14, head, display_type);
+ waypoint_showlink(head.wp15, head, display_type);
+ waypoint_showlink(head.wp16, head, display_type);
+ waypoint_showlink(head.wp17, head, display_type);
+ waypoint_showlink(head.wp18, head, display_type);
+ waypoint_showlink(head.wp19, head, display_type);
+ waypoint_showlink(head.wp20, head, display_type);
+ waypoint_showlink(head.wp21, head, display_type);
+ waypoint_showlink(head.wp22, head, display_type);
+ waypoint_showlink(head.wp23, head, display_type);
+ waypoint_showlink(head.wp24, head, display_type);
+ waypoint_showlink(head.wp25, head, display_type);
+ waypoint_showlink(head.wp26, head, display_type);
+ waypoint_showlink(head.wp27, head, display_type);
+ waypoint_showlink(head.wp28, head, display_type);
+ waypoint_showlink(head.wp29, head, display_type);
+ waypoint_showlink(head.wp30, head, display_type);
+ waypoint_showlink(head.wp31, head, display_type);
}
}
});
sv_notice_join(this);
// update physics stats (players can spawn before physics runs)
+ STAT(MOVEVARS_HIGHSPEED, this) = autocvar_g_movement_highspeed;
+ MUTATOR_CALLHOOK(PlayerPhysics_UpdateStats, this); // do it BEFORE the function so we can modify highspeed!
Physics_UpdateStats(this, PHYS_HIGHSPEED(this));
IL_EACH(g_initforplayer, it.init_for_player, {
.float dmgtime;
.float killcount;
-.float damage_dealt, typehitsound;
+.float damage_dealt, typehitsound, killsound;
.float watersound_finished;
.float iscreature;
.float hit_time = _STAT(HIT_TIME);
.float typehit_time = _STAT(TYPEHIT_TIME);
+.float kill_time = _STAT(KILL_TIME);
.float damage_dealt_total = _STAT(DAMAGE_DEALT_TOTAL);
attacker.taunt_soundtime = time + 1;
attacker.killcount = attacker.killcount + 1;
+ attacker.killsound += 1;
+
#define SPREE_ITEM(counta,countb,center,normal,gentle) \
case counta: \
{ \
{
if(sf & 0x40)
WriteShort(MSG_ENTITY, this.colormap);
+ WriteByte(MSG_ENTITY, this.skin);
}
if(sf & BIT(1))
entity e = IS_SPEC(it) ? it.enemy : it;
if (e.typehitsound) {
it.typehit_time = time;
+ } else if (e.killsound) {
+ it.kill_time = time;
} else if (e.damage_dealt) {
it.hit_time = time;
it.damage_dealt_total += ceil(e.damage_dealt);
FOREACH_CLIENT(true, {
it.typehitsound = false;
it.damage_dealt = 0;
+ it.killsound = false;
antilag_record(it, CS(it), altime);
});
IL_EACH(g_monsters, true,
IMPULSE(navwaypoint_spawn)
{
if (!autocvar_g_waypointeditor) return;
- waypoint_schedulerelink(waypoint_spawn(this.origin, this.origin, 0));
- bprint(strcat("Waypoint spawned at ", vtos(this.origin), "\n"));
+ vector org = this.origin;
+ bool sym = boolean(autocvar_g_waypointeditor_symmetrical);
+
+ LABEL(add_wp);
+ waypoint_schedulerelink(waypoint_spawn(org, org, 0));
+ bprint(strcat("Waypoint spawned at ", vtos(org), "\n"));
+ if(sym)
+ {
+ vector map_center = autocvar_g_waypointeditor_symmetrical_center;
+ org = this.origin;
+ org.x = map_center.x - (org.x - map_center.x);
+ org.y = map_center.y - (org.y - map_center.y);
+ if (vdist(org - this.origin, >, 10))
+ {
+ sym = false;
+ goto add_wp;
+ }
+ }
}
IMPULSE(navwaypoint_remove)
{
if (!autocvar_g_waypointeditor) return;
entity e = navigation_findnearestwaypoint(this, false);
+ bool sym = boolean(autocvar_g_waypointeditor_symmetrical);
+
+ 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 map_center = autocvar_g_waypointeditor_symmetrical_center;
+ vector org = this.origin;
+ org.x = map_center.x - (org.x - map_center.x);
+ org.y = map_center.y - (org.y - map_center.y);
+ FOREACH_ENTITY_CLASS("waypoint", !(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;
+ sym = false;
+ goto remove_wp;
+ }
}
IMPULSE(navwaypoint_relink)
/** called when an item is about to respawn */
#define EV_Item_RespawnCountdown(i, o) \
- /** item name */ i(string, MUTATOR_ARGV_0_string) \
- /**/ o(string, MUTATOR_ARGV_0_string) \
- /** item colour */ i(vector, MUTATOR_ARGV_1_vector) \
- /**/ o(vector, MUTATOR_ARGV_1_vector) \
+ /** item */ i(entity, MUTATOR_ARGV_0_entity) \
/**/
MUTATOR_HOOKABLE(Item_RespawnCountdown, EV_Item_RespawnCountdown);
/** player */ i(entity, MUTATOR_ARGV_0_entity) \
/**/
MUTATOR_HOOKABLE(HideTeamNagger, EV_HideTeamNagger);
+
+/** return true to show a waypoint while the item is spawning */
+#define EV_Item_ScheduleRespawn(i, o) \
+ /** item */ i(entity, MUTATOR_ARGV_0_entity) \
+ /** respawn time */ i(float, MUTATOR_ARGV_1_float) \
+ /**/
+MUTATOR_HOOKABLE(Item_ScheduleRespawn, EV_Item_ScheduleRespawn);
+
+/** called before physics stats are set on a player, allows limited early customization */
+#define EV_PlayerPhysics_UpdateStats(i, o) \
+ /** player */ i(entity, MUTATOR_ARGV_0_entity) \
+ /**/
+MUTATOR_HOOKABLE(PlayerPhysics_UpdateStats, EV_PlayerPhysics_UpdateStats);
+
+/** return true to use your own aim target (or none at all) */
+#define EV_HavocBot_Aim(i, o) \
+ /** bot */ i(entity, MUTATOR_ARGV_0_entity) \
+ /**/
+MUTATOR_HOOKABLE(HavocBot_Aim, EV_HavocBot_Aim);
#include "../lib/warpzone/common.qh"
#include "../common/mutators/mutator/waypoints/waypointsprites.qh"
+IntrusiveList g_race_targets;
+STATIC_INIT(g_race_targets) { g_race_targets = IL_NEW(); }
+
void race_InitSpectator()
{
if(g_race_qualifying)
bool race_waypointsprite_visible_for_player(entity this, entity player, entity view)
{
- if(view.race_checkpoint == -1 || this.owner.race_checkpoint == -2)
+ entity own = this.owner;
+ if(this.realowner)
+ own = this.realowner; // target support
+
+ if(view.race_checkpoint == -1 || own.race_checkpoint == -2)
return true;
- else if(view.race_checkpoint == this.owner.race_checkpoint)
+ else if(view.race_checkpoint == own.race_checkpoint)
return true;
else
return false;
g_race_qualifying = qual;
+ IL_EACH(g_race_targets, true,
+ {
+ entity cpt = it;
+ FOREACH_ENTITY_STRING(target, cpt.targetname,
+ {
+ vector org = (it.absmin + it.absmax) * 0.5;
+ if(cpt.race_checkpoint == 0)
+ WaypointSprite_SpawnFixed(WP_RaceStart, org, it, sprite, RADARICON_NONE);
+ else
+ WaypointSprite_SpawnFixed(WP_RaceCheckpoint, org, it, sprite, RADARICON_NONE);
+
+ it.sprite.realowner = cpt;
+ it.sprite.waypointsprite_visible_for_player = race_waypointsprite_visible_for_player;
+ });
+ });
+
if (race_timed_checkpoint) {
if (defrag_ents) {
- for (entity cp = NULL; (cp = find(cp, classname, "target_startTimer"));) {
- WaypointSprite_UpdateSprites(cp.sprite, WP_RaceStart, WP_Null, WP_Null);
- }
- for (entity cp = NULL; (cp = find(cp, classname, "target_stopTimer"));) {
- WaypointSprite_UpdateSprites(cp.sprite, WP_RaceFinish, WP_Null, WP_Null);
- }
- for (entity cp = NULL; (cp = find(cp, classname, "target_checkpoint"));) {
- if (cp.race_checkpoint == -2) { // something's wrong with the defrag cp file or it has not been written yet, set defragcpexists to -1 so that it will be rewritten when someone finishes
- defragcpexists = -1;
- }
- }
+ IL_EACH(g_race_targets, true,
+ {
+ entity cpt = it;
+ if(it.classname == "target_startTimer" || it.classname == "target_stopTimer") {
+ FOREACH_ENTITY_STRING(target, cpt.targetname, {
+ WaypointSprite_UpdateSprites(it.sprite, ((cpt.classname == "target_startTimer") ? WP_RaceStart : WP_RaceFinish), WP_Null, WP_Null);
+ });
+ }
+ if(it.classname == "target_checkpoint") {
+ if(it.race_checkpoint == -2)
+ defragcpexists = -1; // something's wrong with the defrag cp file or it has not been written yet, set defragcpexists to -1 so that it will be rewritten when someone finishes
+ }
+ });
if (defragcpexists != -1) {
float largest_cp_id = 0;
for (entity cp = NULL; (cp = find(cp, classname, "target_checkpoint"));) {
race_timed_checkpoint = 1;
- if(this.race_checkpoint == 0)
- WaypointSprite_SpawnFixed(WP_RaceStart, org, this, sprite, RADARICON_NONE);
- else
- WaypointSprite_SpawnFixed(WP_RaceCheckpoint, org, this, sprite, RADARICON_NONE);
-
- this.sprite.waypointsprite_visible_for_player = race_waypointsprite_visible_for_player;
+ IL_PUSH(g_race_targets, this);
InitializeEntity(this, trigger_race_checkpoint_verify, INITPRIO_FINDTARGET);
}