ATTRIB(Powerup, m_itemflags, int, FL_POWERUP);
ATTRIB(Powerup, m_respawntime, float(), GET(g_pickup_respawntime_powerup));
ATTRIB(Powerup, m_respawntimejitter, float(), GET(g_pickup_respawntimejitter_powerup));
+ ATTRIB(Powerup, count, float);
#endif
ENDCLASS(Powerup)
#endif
#ifdef SVQC
+ float autocvar_g_balance_powerup_strength_damage;
+ float autocvar_g_balance_powerup_strength_force;
+ float autocvar_g_balance_powerup_strength_selfdamage;
+ float autocvar_g_balance_powerup_strength_selfforce;
float autocvar_g_balance_powerup_strength_time;
void powerup_strength_init(Pickup this, entity item)
{
if(!item.strength_finished)
- item.strength_finished = autocvar_g_balance_powerup_strength_time;
+ item.strength_finished = (item.count) ? item.count : autocvar_g_balance_powerup_strength_time;
}
#endif
REGISTER_ITEM(Strength, Powerup) {
#endif
#ifdef SVQC
+ float autocvar_g_balance_powerup_invincible_takedamage;
+ float autocvar_g_balance_powerup_invincible_takeforce = 0.33;
float autocvar_g_balance_powerup_invincible_time;
void powerup_shield_init(Pickup this, entity item)
{
if(!item.invincible_finished)
- item.invincible_finished = autocvar_g_balance_powerup_invincible_time;
+ item.invincible_finished = (item.count) ? item.count : autocvar_g_balance_powerup_invincible_time;
}
#endif
REGISTER_ITEM(Shield, Powerup) {
return false;
vector org = targ.origin;
-#ifdef SVQC
- if(autocvar_sv_q3defragcompat)
-#elif defined(CSQC)
- if(STAT(Q3DEFRAGCOMPAT))
-#endif
+
+ if(STAT(Q3COMPAT))
{
org.z += targ.mins_z;
org.z += 1; // off by 1!
// reset tracking of oldvelocity for impact damage (sudden velocity changes)
targ.oldvelocity = targ.velocity;
- if(this.pushltime < time) // prevent "snorring" sound when a player hits the jumppad more than once
+ // prevent sound spam when a player hits the jumppad more than once
+ // or when a dead player gets stuck in the jumppad for some reason
+ if(this.pushltime < time && !(IS_DEAD(targ) && targ.velocity == '0 0 0'))
{
// flash when activated
Send_Effect(EFFECT_JUMPPAD, targ.origin, targ.velocity, 1);
#include "sv_buffs.qh"
#include <common/mapobjects/target/music.qh>
+ #include <common/mutators/mutator/instagib/_mod.qh>
#include <common/gamemodes/_mod.qh>
#include <server/items/items.qh>
- void buffs_DelayedInit(entity this);
-
- AUTOCVAR(g_buffs, int, -1, "Enable buffs, -1: enabled but no auto location or replacing powerups, 1: enabled and can replace them");
-
- REGISTER_MUTATOR(buffs, autocvar_g_buffs)
- {
- MUTATOR_ONADD
- {
- if(autocvar_g_buffs > 0)
- InitializeEntity(NULL, buffs_DelayedInit, INITPRIO_FINDTARGET);
- }
- }
-
bool buffs_BuffModel_Customize(entity this, entity client)
{
entity player = WaypointSprite_getviewentity(client);
vector buff_GlowColor(entity buff)
{
- //if(buff.team) { return Team_ColorRGB(buff.team); }
+ //if(buff.team_forced) { return Team_ColorRGB(buff.team_forced); }
return buff.m_color;
}
if (STAT(BUFFS, view))
{
- return CS(view).cvar_cl_buffs_autoreplace == false || STAT(BUFFS, view) != STAT(BUFFS, this.owner);
+ return CS_CVAR(view).cvar_cl_buffs_autoreplace == false || STAT(BUFFS, view) != STAT(BUFFS, this.owner);
}
return WaypointSprite_visible_for_player(this, player, view);
if(autocvar_g_buffs_waypoint_distance <= 0) return;
entity buff = buff_FirstFromFlags(STAT(BUFFS, e));
- entity wp = WaypointSprite_Spawn(WP_Buff, 0, autocvar_g_buffs_waypoint_distance, e, '0 0 1' * e.maxs.z, NULL, e.team, e, buff_waypoint, true, RADARICON_Buff);
+ entity wp = WaypointSprite_Spawn(WP_Buff, 0, autocvar_g_buffs_waypoint_distance, e, '0 0 1' * e.maxs.z, NULL, e.team_forced, e, buff_waypoint, true, RADARICON_Buff);
wp.wp_extra = buff.m_id;
WaypointSprite_UpdateTeamRadar(e.buff_waypoint, RADARICON_Buff, e.glowmod);
e.buff_waypoint.waypointsprite_visible_for_player = buff_Waypoint_visible_for_player;
if(!IS_PLAYER(toucher))
return; // incase mutator changed toucher
- if((this.team && DIFF_TEAM(toucher, this))
+ if((this.team_forced && toucher.team != this.team_forced)
|| (STAT(FROZEN, toucher))
|| (toucher.vehicle)
|| (time < PS(toucher).buff_shield)
if (STAT(BUFFS, toucher))
{
- if (CS(toucher).cvar_cl_buffs_autoreplace && STAT(BUFFS, toucher) != STAT(BUFFS, this))
+ if (CS_CVAR(toucher).cvar_cl_buffs_autoreplace && STAT(BUFFS, toucher) != STAT(BUFFS, this))
{
// TODO: lost-gained notification for this case
int buffid = buff_FirstFromFlags(STAT(BUFFS, toucher)).m_id;
if(this.buff_active)
{
- if(this.team && !this.buff_waypoint)
+ if(this.team_forced && !this.buff_waypoint)
buff_Waypoint_Spawn(this);
if(this.lifetime && time >= this.lifetime)
bool buff_Customize(entity this, entity client)
{
entity player = WaypointSprite_getviewentity(client);
- if(!this.buff_active || (this.team && DIFF_TEAM(player, this)))
+ if(!this.buff_active || (this.team_forced && player.team != this.team_forced))
{
this.alpha = 0.3;
if(this.effects & EF_FULLBRIGHT) { this.effects &= ~(EF_FULLBRIGHT); }
{
if(!cvar("g_buffs")) { delete(this); return; }
- if(!teamplay && this.team) { this.team = 0; }
-
entity buff = buff_FirstFromFlags(STAT(BUFFS, this));
if(!STAT(BUFFS, this) || !buff_Available(buff))
void buff_Init_Compat(entity ent, entity replacement)
{
- if (ent.spawnflags & 2)
- ent.team = NUM_TEAM_1;
- else if (ent.spawnflags & 4)
- ent.team = NUM_TEAM_2;
+ if (teamplay)
+ {
+ if (ent.spawnflags & 2)
+ ent.team_forced = NUM_TEAM_1;
+ else if (ent.spawnflags & 4)
+ ent.team_forced = NUM_TEAM_2;
+ }
STAT(BUFFS, ent) = replacement.m_itemid;
return;
}
- // note: only really useful in teamplay
- void buff_Medic_Heal(entity this)
- {
- FOREACH_CLIENT(IS_PLAYER(it) && it != this && vdist(it.origin - this.origin, <=, autocvar_g_buffs_medic_heal_range),
- {
- if (DIFF_TEAM(it, this))
- {
- continue;
- }
- float hp = GetResource(it, RES_HEALTH);
- if(hp >= autocvar_g_balance_health_regenstable)
- {
- continue;
- }
- Send_Effect(EFFECT_HEALING, it.origin, '0 0 0', 1);
- SetResource(it, RES_HEALTH, bound(0, hp + autocvar_g_buffs_medic_heal_amount, autocvar_g_balance_health_regenstable));
- });
- }
-
float buff_Inferno_CalculateTime(float damg, float offset_x, float offset_y, float intersect_x, float intersect_y, float base)
{
return offset_y + (intersect_y - offset_y) * logn(((damg - offset_x) * ((base - 1) / intersect_x)) + 1, base);
if(frag_attacker != frag_target)
if(!ITEM_DAMAGE_NEEDKILL(frag_deathtype))
{
- entity dmgent = new(dmgent);
+ entity dmgent = new_pure(dmgent);
dmgent.dmg = frag_damage * autocvar_g_buffs_vengeance_damage_multiplier;
dmgent.enemy = frag_attacker;
Fire_AddDamage(frag_target, frag_attacker, (frag_damage * autocvar_g_buffs_inferno_damagemultiplier), btime, DEATH_BUFF.m_id);
}
- // this... is ridiculous (TODO: fix!)
- if(STAT(BUFFS, frag_attacker) & BUFF_VAMPIRE.m_itemid)
- if(!frag_target.vehicle)
- if(!ITEM_DAMAGE_NEEDKILL(frag_deathtype))
- if(!IS_DEAD(frag_target))
- if(IS_PLAYER(frag_target) || IS_MONSTER(frag_target))
- if(frag_attacker != frag_target)
- if(!STAT(FROZEN, frag_target))
- if(frag_target.takedamage)
- if(DIFF_TEAM(frag_attacker, frag_target))
- {
- float amount = bound(0, frag_damage * autocvar_g_buffs_vampire_damage_steal,
- GetResource(frag_target, RES_HEALTH));
- GiveResourceWithLimit(frag_attacker, RES_HEALTH, amount, g_pickup_healthsmall_max);
- if (GetResource(frag_target, RES_ARMOR))
- {
- amount = bound(0, frag_damage * autocvar_g_buffs_vampire_damage_steal,
- GetResource(frag_target, RES_ARMOR));
- GiveResourceWithLimit(frag_attacker, RES_ARMOR, amount, g_pickup_armorsmall_max);
- }
- }
-
M_ARGV(4, float) = frag_damage;
M_ARGV(6, vector) = frag_force;
}
+ MUTATOR_HOOKFUNCTION(buffs, PlayerDamage_SplitHealthArmor)
+ {
+ entity frag_attacker = M_ARGV(1, entity);
+ entity frag_target = M_ARGV(2, entity);
+ if(!(STAT(BUFFS, frag_attacker) & BUFF_VAMPIRE.m_itemid))
+ return;
+ float health_take = bound(0, M_ARGV(4, float), GetResource(frag_target, RES_HEALTH));
+
+ if(time >= frag_target.spawnshieldtime &&
+ frag_target != frag_attacker &&
+ IS_PLAYER(frag_attacker) &&
+ !IS_DEAD(frag_target) && !STAT(FROZEN, frag_target))
+ {
+ GiveResource(frag_attacker, RES_HEALTH,
+ autocvar_g_buffs_vampire_damage_steal * health_take);
+ }
+ }
+
MUTATOR_HOOKFUNCTION(buffs, PlayerSpawn)
{
entity player = M_ARGV(0, entity);
if((STAT(BUFFS, player) & BUFF_INVISIBLE.m_itemid) && (player.oldbuffs & BUFF_INVISIBLE.m_itemid))
player.alpha = ((autocvar_g_buffs_invisible_alpha) ? autocvar_g_buffs_invisible_alpha : -1); // powerups reset alpha, so we must enforce this (TODO)
- if(STAT(BUFFS, player) & BUFF_MEDIC.m_itemid)
- if(teamplay && time >= player.buff_medic_healtime)
- {
- buff_Medic_Heal(player);
- player.buff_medic_healtime = time + autocvar_g_buffs_medic_heal_delay;
- }
-
#define BUFF_ONADD(b) if ( (STAT(BUFFS, player) & (b).m_itemid) && !(player.oldbuffs & (b).m_itemid))
#define BUFF_ONREM(b) if (!(STAT(BUFFS, player) & (b).m_itemid) && (player.oldbuffs & (b).m_itemid))
}
}
}
+
+ void buffs_Initialize()
+ {
+ // if buffs are above 0, allow random spawning
+ if(autocvar_g_buffs > 0 && autocvar_g_buffs_spawn_count > 0)
+ InitializeEntity(NULL, buffs_DelayedInit, INITPRIO_FINDTARGET);
+ }
#pragma once
+ #include <common/mutators/base.qh>
+
#include "buffs.qh"
- #include "../instagib/_mod.qh"
+ void buffs_Initialize();
+
+ AUTOCVAR(g_buffs, int, -1, "Enable buffs, -1: enabled but no auto location or replacing powerups, 1: enabled and can replace them");
+
+ REGISTER_MUTATOR(buffs, autocvar_g_buffs)
+ {
+ MUTATOR_ONADD
+ {
+ buffs_Initialize();
+ }
+ }
bool autocvar_g_buffs_effects;
float autocvar_g_buffs_waypoint_distance;
float autocvar_g_buffs_medic_rot;
float autocvar_g_buffs_medic_max;
float autocvar_g_buffs_medic_regen;
- float autocvar_g_buffs_medic_heal_amount = 15;
- float autocvar_g_buffs_medic_heal_delay = 1;
- float autocvar_g_buffs_medic_heal_range = 400;
float autocvar_g_buffs_vengeance_damage_multiplier;
float autocvar_g_buffs_bash_force;
float autocvar_g_buffs_bash_force_self;
.int buff_ammo_prev_clipload;
// invisible
.float buff_invisible_prev_alpha;
- // medic
- .float buff_medic_healtime;
// disability
.float buff_disability_time;
.float buff_disability_effect_time;
.float buff_effect_delay;
// buff definitions
-.float buff_active;
+.bool buff_active;
.float buff_activetime;
-.float buff_activetime_updated;
+.bool buff_activetime_updated;
.entity buff_waypoint;
.int oldbuffs; // for updating effects
.float buff_shield; // delay for players to keep them from spamming buff pickups
if(!autocvar_g_physics_clientselect)
return defaultval;
- if(IS_REAL_CLIENT(this) && Physics_Valid(CS(this).cvar_cl_physics))
+ if(IS_REAL_CLIENT(this) && Physics_Valid(CS_CVAR(this).cvar_cl_physics))
{
- string s = strcat("g_physics_", CS(this).cvar_cl_physics, "_", option);
+ string s = strcat("g_physics_", CS_CVAR(this).cvar_cl_physics, "_", option);
if(cvar_type(s) & CVAR_TYPEFLAG_EXISTS)
return cvar(s);
}
: 0;
STAT(MOVEVARS_AIRSPEEDLIMIT_NONQW, this) = Physics_ClientOption(this, "airspeedlimit_nonqw", autocvar_sv_airspeedlimit_nonqw) * maxspd_mod;
}
- bool q3dfcompat = autocvar_sv_q3defragcompat && autocvar_sv_q3defragcompat_changehitbox; // NOTE: these hitboxes are off by 1 due to engine differences
- STAT(PL_MIN, this) = (q3dfcompat) ? '-15 -15 -20' : autocvar_sv_player_mins;
- STAT(PL_MAX, this) = (q3dfcompat) ? '15 15 36' : autocvar_sv_player_maxs;
- STAT(PL_VIEW_OFS, this) = (q3dfcompat) ? '0 0 30' : autocvar_sv_player_viewoffset;
- STAT(PL_CROUCH_MIN, this) = (q3dfcompat) ? '-15 -15 -20' : autocvar_sv_player_crouch_mins;
- STAT(PL_CROUCH_MAX, this) = (q3dfcompat) ? '15 15 20' : autocvar_sv_player_crouch_maxs;
- STAT(PL_CROUCH_VIEW_OFS, this) = (q3dfcompat) ? '0 0 16' : autocvar_sv_player_crouch_viewoffset;
+ bool q3hb = q3compat && autocvar_sv_q3compat_changehitbox;
+ STAT(PL_MIN, this) = (q3hb) ? '-15 -15 -20' : autocvar_sv_player_mins;
+ STAT(PL_MAX, this) = (q3hb) ? '15 15 36' : autocvar_sv_player_maxs;
+ STAT(PL_VIEW_OFS, this) = (q3hb) ? '0 0 30' : autocvar_sv_player_viewoffset;
+ STAT(PL_CROUCH_MIN, this) = (q3hb) ? '-15 -15 -20' : autocvar_sv_player_crouch_mins;
+ STAT(PL_CROUCH_MAX, this) = (q3hb) ? '15 15 20' : autocvar_sv_player_crouch_maxs;
+ STAT(PL_CROUCH_VIEW_OFS, this) = (q3hb) ? '0 0 16' : autocvar_sv_player_crouch_viewoffset;
// old stats
// fix some new settings
#ifdef SVQC
- #define JETPACK_JUMP(s) CS(s).cvar_cl_jetpack_jump
+ #define JETPACK_JUMP(s) CS_CVAR(s).cvar_cl_jetpack_jump
#elif defined(CSQC)
float autocvar_cl_jetpack_jump;
#define JETPACK_JUMP(s) autocvar_cl_jetpack_jump
#pragma once
+ // you're next
+
#ifdef SVQC
- #include <server/autocvars.qh>
#include <server/client.qh>
+#include <server/compat/quake3.qh>
+ #include <server/main.qh>
+ #include <common/gamemodes/sv_rules.qh>
+ #include <common/mapobjects/teleporters.qh>
#include <common/mapobjects/trigger/secret.qh>
+ #include <common/mutators/mutator/doublejump/doublejump.qh>
+ #include <common/mutators/mutator/itemstime/itemstime.qh>
+ #include <common/physics/player.qh>
#endif
// Full list of all stat constants, included in a single location for easy reference
float round_starttime; //point in time when the countdown to round start is over
bool autocvar_g_allow_oldvortexbeam;
int autocvar_leadlimit;
+ // TODO: world.qh can't be included here due to circular includes!
+ #define autocvar_fraglimit cvar("fraglimit")
+ #define autocvar_fraglimit_override cvar("fraglimit_override")
+ #define autocvar_timelimit cvar("timelimit")
+ #define autocvar_timelimit_override cvar("timelimit_override")
#endif
REGISTER_STAT(WEAPONRATEFACTOR, float, W_WeaponRateFactor(this))
REGISTER_STAT(GAME_STOPPED, int, game_stopped)
REGISTER_STAT(VEIL_ORB_ALPHA, float)
#ifdef SVQC
- float autocvar_sv_showfps = 5;
+ float autocvar_sv_showfps = 0;
#endif
REGISTER_STAT(SHOWFPS, float, autocvar_sv_showfps)
int autocvar_sv_gameplayfix_noairborncorpse = 1;
int autocvar_sv_gameplayfix_noairborncorpse_allowsuspendeditems = 1;
int autocvar_sv_gameplayfix_delayprojectiles = 0;
+ bool autocvar_sv_gameplayfix_upwardvelocityclearsongroundflag = true;
#endif
REGISTER_STAT(GAMEPLAYFIX_DOWNTRACEONGROUND, int, autocvar_sv_gameplayfix_downtracesupportsongroundflag)
REGISTER_STAT(GAMEPLAYFIX_EASIERWATERJUMP, int, autocvar_sv_gameplayfix_easierwaterjump)
REGISTER_STAT(MOVEVARS_JUMPSTEP, int, cvar("sv_jumpstep"))
REGISTER_STAT(NOSTEP, int, cvar("sv_nostep"))
+ #ifdef SVQC
+ float autocvar_sv_friction_on_land;
+ var float autocvar_sv_friction_slick = 0.5;
+ #endif
REGISTER_STAT(MOVEVARS_FRICTION, float)
REGISTER_STAT(MOVEVARS_FRICTION_SLICK, float, autocvar_sv_friction_slick)
REGISTER_STAT(MOVEVARS_FRICTION_ONLAND, float, autocvar_sv_friction_on_land)
REGISTER_STAT(DODGING_FROZEN, int, autocvar_sv_dodging_frozen)
REGISTER_STAT(DODGING_TIMEOUT, float)
+ #ifdef SVQC
+ float autocvar_g_jetpack_acceleration_side;
+ float autocvar_g_jetpack_acceleration_up;
+ float autocvar_g_jetpack_antigravity;
+ int autocvar_g_jetpack_fuel;
+ float autocvar_g_jetpack_maxspeed_side;
+ float autocvar_g_jetpack_maxspeed_up;
+ float autocvar_g_jetpack_reverse_thrust;
+ #endif
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_ANTIGRAVITY, float, autocvar_g_jetpack_antigravity)
REGISTER_STAT(DOM_PPS_YELLOW, float)
REGISTER_STAT(DOM_PPS_PINK, float)
+ #ifdef SVQC
+ float autocvar_g_teleport_maxspeed;
+ #endif
REGISTER_STAT(TELEPORT_MAXSPEED, float, autocvar_g_teleport_maxspeed)
REGISTER_STAT(TELEPORT_TELEFRAG_AVOID, int, autocvar_g_telefrags_avoid)
#endif
REGISTER_STAT(SLICK_APPLYGRAVITY, bool, autocvar_sv_slick_applygravity)
-#ifdef SVQC
-bool autocvar_sv_q3defragcompat;
-#endif
-REGISTER_STAT(Q3DEFRAGCOMPAT, bool, autocvar_sv_q3defragcompat)
+REGISTER_STAT(Q3COMPAT, int, q3compat)
#ifdef SVQC
#include "physics/movetypes/movetypes.qh"
REGISTER_STAT(MOVEVARS_AIRCONTROL_POWER, float)
REGISTER_STAT(MOVEVARS_AIRCONTROL_BACKWARDS, bool)
REGISTER_STAT(MOVEVARS_AIRCONTROL_SIDEWARDS, bool)
- noref bool autocvar_sv_gameplayfix_nogravityonground = true;
+ #ifdef SVQC
+ float autocvar_sv_gameplayfix_q2airaccelerate = 1;
+ bool autocvar_sv_gameplayfix_nogravityonground = true;
+ bool autocvar_sv_gameplayfix_gravityunaffectedbyticrate = true;
+ #endif
REGISTER_STAT(MOVEFLAGS, int, MOVEFLAG_VALID
| (autocvar_sv_gameplayfix_q2airaccelerate ? MOVEFLAG_Q2AIRACCELERATE : 0)
| (autocvar_sv_gameplayfix_nogravityonground ? MOVEFLAG_NOGRAVITYONGROUND : 0)
REGISTER_STAT(WARMUP_TIMELIMIT, float, warmup_limit)
#ifdef SVQC
float autocvar_sv_wallfriction;
+ #define autocvar_sv_gravity cvar("sv_gravity")
+ float autocvar_sv_stepheight;
#endif
REGISTER_STAT(MOVEVARS_WALLFRICTION, int, autocvar_sv_wallfriction)
REGISTER_STAT(MOVEVARS_TICRATE, float, autocvar_sys_ticrate)
#define WEAPONS_ALL_C
#if defined(CSQC)
- #include <client/autocvars.qh>
#include <client/main.qh>
#include <common/constants.qh>
#include <common/deathtypes/all.qh>
#include <lib/warpzone/common.qh>
#include <lib/warpzone/server.qh>
#include <lib/warpzone/util_server.qh>
- #include <server/autocvars.qh>
#include <server/command/_mod.qh>
#include <server/hook.qh>
#include <server/items/spawning.qh>
}
}
+entity GetAmmoItem(int ammotype)
+{
+ switch (ammotype)
+ {
+ case RES_SHELLS: return ITEM_Shells;
+ case RES_BULLETS: return ITEM_Bullets;
+ case RES_ROCKETS: return ITEM_Rockets;
+ case RES_CELLS: return ITEM_Cells;
+ case RES_PLASMA: return ITEM_Plasma;
+ case RES_FUEL: return ITEM_JetpackFuel;
+ }
+ LOG_WARNF("Invalid ammo type %d ", ammotype);
+ return NULL;
+ // WEAPONTODO: use this generic func to reduce duplication ?
+ // GetAmmoPicture GetAmmoName notif_arg_item_wepammo ammo_pickupevalfunc ?
+}
+
#ifdef CSQC
int GetAmmoTypeFromNum(int i)
{
LOG_INFOF("Incorrect parameters for ^2%s^7", argv(0));
case CMD_REQUEST_USAGE:
{
- LOG_HELP("Usage:^3 cl_cmd weapon_find weapon");
- LOG_HELP(" Where 'weapon' is the lowercase weapon name, 'all' or 'unowned'.");
+ LOG_HELP("Usage:^3 cl_cmd weapon_find <weapon>");
+ LOG_HELP(" Where <weapon> is the lowercase weapon name, 'all' or 'unowned'.");
return;
}
}
REGISTER_NET_TEMP(TE_CSQC_SHOCKWAVEPARTICLE)
#ifdef SVQC
-// enable when shockwave replaces shotgun
-#if 0
-METHOD(Shockwave, m_spawnfunc_hookreplace, Weapon(Shockwave this, entity e))
-{
- //if(autocvar_sv_q3acompat_machineshockwaveswap) // WEAPONTODO
- if (autocvar_sv_q3acompat_machineshotgunswap && !Item_IsLoot(e))
- {
- return WEP_MACHINEGUN;
- }
- return this;
-}
-#endif
const float MAX_SHOCKWAVE_HITS = 10;
//#define DEBUG_SHOCKWAVE
);
float lag = ((IS_REAL_CLIENT(actor)) ? ANTILAG_LATENCY(actor) : 0);
- bool noantilag = ((IS_CLIENT(actor)) ? CS(actor).cvar_cl_noantilag : false);
+ bool noantilag = ((IS_CLIENT(actor)) ? CS_CVAR(actor).cvar_cl_noantilag : false);
if(lag < 0.001)
lag = 0;
if(autocvar_g_antilag == 0 || noantilag)
noref bool require_spawnfunc_prefix;
.bool spawnfunc_checked;
/** Not for production use, provides access to a dump of the entity's fields when it is parsed from map data */
-//noref string __fullspawndata;
+noref string __fullspawndata;
+.string fullspawndata;
// Optional type checking; increases compile time too much to be enabled by default
#if 0
FIELD_SCALAR(fld, noise2) \
FIELD_SCALAR(fld, noise3) \
FIELD_SCALAR(fld, noise) \
+ FIELD_SCALAR(fld, notcpm) \
+ FIELD_SCALAR(fld, notfree) \
+ FIELD_SCALAR(fld, notta) \
+ FIELD_SCALAR(fld, notteam) \
+ FIELD_SCALAR(fld, notvq3) \
FIELD_SCALAR(fld, phase) \
FIELD_SCALAR(fld, platmovetype) \
FIELD_SCALAR(fld, race_place) \
this.classname = #id; \
if (!this.spawnfunc_checked) { \
_checkWhitelisted(this, #id); \
+ if (__fullspawndata) { \
+ /* not supported in old DP */ \
+ /* must be read inside the real spawnfunc */ \
+ this.fullspawndata = __fullspawndata; \
+ } \
this.spawnfunc_checked = true; \
if (this) { \
/* not worldspawn, delay spawn */ \
+ /* clear some dangerous fields (TODO: properly support these in the map!) */ \
+ this.think = func_null; \
+ this.nextthink = 0; \
__spawnfunc_defer(this, __spawnfunc_##id); \
} else { \
/* world might not be "worldspawn" */ \
#include <common/minigames/sv_minigames.qh>
#include <common/monsters/sv_monsters.qh>
#include <common/mutators/mutator/instagib/sv_instagib.qh>
+ #include <common/mutators/mutator/nades/nades.qh>
#include <common/mutators/mutator/overkill/oknex.qh>
#include <common/mutators/mutator/waypoints/all.qh>
#include <common/net_linked.qh>
#include <server/anticheat.qh>
#include <server/antilag.qh>
#include <server/bot/api.qh>
+ #include <server/bot/default/cvars.qh>
#include <server/campaign.qh>
#include <server/chat.qh>
#include <server/cheats.qh>
#include <server/weapons/common.qh>
#include <server/weapons/hitplot.qh>
#include <server/weapons/selection.qh>
+ #include <server/weapons/tracing.qh>
#include <server/weapons/weaponsystem.qh>
#include <server/world.qh>
FallbackPlayerModel = strzone(cvar_defstring("_cl_playermodel"));
}
// only in right path
- if( substring(plyermodel,0,14) != "models/player/")
+ if(substring(plyermodel, 0, 14) != "models/player/")
return FallbackPlayerModel;
// only good file extensions
- if(substring(plyermodel,-4,4) != ".zym")
- if(substring(plyermodel,-4,4) != ".dpm")
- if(substring(plyermodel,-4,4) != ".iqm")
- if(substring(plyermodel,-4,4) != ".md3")
- if(substring(plyermodel,-4,4) != ".psk")
+ if(substring(plyermodel, -4, 4) != ".iqm"
+ && substring(plyermodel, -4, 4) != ".zym"
+ && substring(plyermodel, -4, 4) != ".dpm"
+ && substring(plyermodel, -4, 4) != ".md3"
+ && substring(plyermodel, -4, 4) != ".psk")
+ {
return FallbackPlayerModel;
+ }
// forbid the LOD models
- if(substring(plyermodel, -9,5) == "_lod1")
- return FallbackPlayerModel;
- if(substring(plyermodel, -9,5) == "_lod2")
+ if(substring(plyermodel, -9, 5) == "_lod1" || substring(plyermodel, -9, 5) == "_lod2")
return FallbackPlayerModel;
if(plyermodel != strtolower(plyermodel))
return FallbackPlayerModel;
if (vote_called) { VoteCount(false); }
ReadyCount();
}
+ entcs_update_players(this);
}
entity spot = SelectSpawnPoint(this, true);
this.respawn_flags = 0;
this.respawn_time = 0;
STAT(RESPAWN_TIME, this) = 0;
- bool q3dfcompat = autocvar_sv_q3defragcompat && autocvar_sv_q3defragcompat_changehitbox;
- this.scale = ((q3dfcompat) ? 0.9 : autocvar_sv_player_scale);
+ this.scale = ((q3compat && autocvar_sv_q3compat_changehitbox) ? 0.9 : autocvar_sv_player_scale);
this.fade_time = 0;
this.pain_finished = 0;
this.pushltime = 0;
if (CS(this).impulse) ImpulseCommands(this);
- W_ResetGunAlign(this, CS(this).cvar_cl_gunalign);
+ W_ResetGunAlign(this, CS_CVAR(this).cvar_cl_gunalign);
for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
{
.entity weaponentity = weaponentities[slot];
=============
*/
.entity chatbubbleentity;
+ void player_powerups_remove_all(entity this);
+
void ClientDisconnect(entity this)
{
assert(IS_CLIENT(this), return);
MUTATOR_CALLHOOK(ClientDisconnect, this);
strfree(CS(this).netname_previous); // needs to be before the CS entity is removed!
- strfree(CS(this).weaponorder_byimpulse);
+ strfree(CS_CVAR(this).weaponorder_byimpulse);
ClientState_detach(this);
Portal_ClearAll(this);
ReadyCount();
if (vote_called && IS_REAL_CLIENT(this)) VoteCount(false);
+ player_powerups_remove_all(this); // stop powerup sound
+
ONREMOVE(this);
}
sound (this, CH_INFO, samp, VOL_BASE, ATTEN_NORM);
}
+ void player_powerups_remove_all(entity this)
+ {
+ if (this.items & (ITEM_Strength.m_itemid | ITEM_Shield.m_itemid | IT_SUPERWEAPON))
+ {
+ // don't play the poweroff sound when the game restarts or the player disconnects
+ if (time > game_starttime + 1 && IS_CLIENT(this))
+ sound(this, CH_INFO, SND_POWEROFF, VOL_BASE, ATTEN_NORM);
+ stopsound(this, CH_TRIGGER_SINGLE); // get rid of the pickup sound
+ this.items &= ~ITEM_Strength.m_itemid;
+ this.items &= ~ITEM_Shield.m_itemid;
+ this.items -= (this.items & IT_SUPERWEAPON);
+ }
+ }
+
void player_powerups(entity this)
{
if((this.items & IT_USING_JETPACK) && !IS_DEAD(this) && !game_stopped)
this.effects &= ~(EF_RED | EF_BLUE | EF_ADDITIVE | EF_FULLBRIGHT | EF_FLAME | EF_NODEPTHTEST);
if (IS_DEAD(this))
- {
- if (this.items & (ITEM_Strength.m_itemid | ITEM_Shield.m_itemid | IT_SUPERWEAPON))
- {
- sound(this, CH_INFO, SND_POWEROFF, VOL_BASE, ATTEN_NORM);
- stopsound(this, CH_TRIGGER_SINGLE); // get rid of the pickup sound
- this.items &= ~ITEM_Strength.m_itemid;
- this.items &= ~ITEM_Shield.m_itemid;
- this.items -= (this.items & IT_SUPERWEAPON);
- }
- }
+ player_powerups_remove_all(this);
if((this.alpha < 0 || IS_DEAD(this)) && !this.vehicle) // don't apply the flags if the player is gibbed
return;
void GetPressedKeys(entity this)
{
MUTATOR_CALLHOOK(GetPressedKeys, this);
+ if (game_stopped)
+ {
+ CS(this).pressedkeys = 0;
+ STAT(PRESSED_KEYS, this) = 0;
+ return;
+ }
+
+ // NOTE: GetPressedKeys and PM_dodging_GetPressedKeys use similar code
int keys = STAT(PRESSED_KEYS, this);
keys = BITSET(keys, KEY_FORWARD, CS(this).movement.x > 0);
keys = BITSET(keys, KEY_BACKWARD, CS(this).movement.x < 0);
bool dualwielding = W_DualWielding(this);
if(this.dualwielding_prev != dualwielding)
{
- W_ResetGunAlign(this, CS(this).cvar_cl_gunalign);
+ W_ResetGunAlign(this, CS_CVAR(this).cvar_cl_gunalign);
this.dualwielding_prev = dualwielding;
}
}
.bool would_spectate;
+ // merged SpectatorThink and ObserverThink (old names are here so you can grep for them)
void ObserverOrSpectatorThink(entity this)
{
bool is_spec = IS_SPEC(this);
}
}
else {
- int preferred_movetype = ((!PHYS_INPUT_BUTTON_USE(this) ? CS(this).cvar_cl_clippedspectating : !CS(this).cvar_cl_clippedspectating) ? MOVETYPE_FLY_WORLDONLY : MOVETYPE_NOCLIP);
+ int preferred_movetype = ((!PHYS_INPUT_BUTTON_USE(this) ? CS_CVAR(this).cvar_cl_clippedspectating : !CS_CVAR(this).cvar_cl_clippedspectating) ? MOVETYPE_FLY_WORLDONLY : MOVETYPE_NOCLIP);
set_movetype(this, preferred_movetype);
}
- } else {
+ } else { // jump pressed
if ((is_spec && !(PHYS_INPUT_BUTTON_ATCK(this) || PHYS_INPUT_BUTTON_ATCK2(this)))
|| (!is_spec && !(PHYS_INPUT_BUTTON_ATCK(this) || PHYS_INPUT_BUTTON_JUMP(this)))) {
this.flags |= FL_JUMPRELEASED;
.float last_vehiclecheck;
void PlayerPreThink (entity this)
{
- STAT(GUNALIGN, this) = CS(this).cvar_cl_gunalign; // TODO
- STAT(MOVEVARS_CL_TRACK_CANJUMP, this) = CS(this).cvar_cl_movement_track_canjump;
+ STAT(GUNALIGN, this) = CS_CVAR(this).cvar_cl_gunalign; // TODO
+ STAT(MOVEVARS_CL_TRACK_CANJUMP, this) = CS_CVAR(this).cvar_cl_movement_track_canjump;
WarpZone_PlayerPhysics_FixVAngle(this);
}
// version nagging
- if (CS(this).version_nagtime && CS(this).cvar_g_xonoticversion && time > CS(this).version_nagtime) {
+ if (CS(this).version_nagtime && CS_CVAR(this).cvar_g_xonoticversion && time > CS(this).version_nagtime) {
CS(this).version_nagtime = 0;
- if (strstrofs(CS(this).cvar_g_xonoticversion, "git", 0) >= 0 || strstrofs(CS(this).cvar_g_xonoticversion, "autobuild", 0) >= 0) {
+ if (strstrofs(CS_CVAR(this).cvar_g_xonoticversion, "git", 0) >= 0 || strstrofs(CS_CVAR(this).cvar_g_xonoticversion, "autobuild", 0) >= 0) {
// git client
} else if (strstrofs(autocvar_g_xonoticversion, "git", 0) >= 0 || strstrofs(autocvar_g_xonoticversion, "autobuild", 0) >= 0) {
// git server
- Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_VERSION_BETA, autocvar_g_xonoticversion, CS(this).cvar_g_xonoticversion);
+ Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_VERSION_BETA, autocvar_g_xonoticversion, CS_CVAR(this).cvar_g_xonoticversion);
} else {
- int r = vercmp(CS(this).cvar_g_xonoticversion, autocvar_g_xonoticversion);
+ int r = vercmp(CS_CVAR(this).cvar_g_xonoticversion, autocvar_g_xonoticversion);
if (r < 0) { // old client
- Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_VERSION_OUTDATED, autocvar_g_xonoticversion, CS(this).cvar_g_xonoticversion);
+ Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_VERSION_OUTDATED, autocvar_g_xonoticversion, CS_CVAR(this).cvar_g_xonoticversion);
} else if (r > 0) { // old server
- Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_VERSION_OLD, autocvar_g_xonoticversion, CS(this).cvar_g_xonoticversion);
+ Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_VERSION_OLD, autocvar_g_xonoticversion, CS_CVAR(this).cvar_g_xonoticversion);
}
}
}
this.max_armorvalue = 0;
}
- if (frametime && IS_PLAYER(this))
+ if (frametime && IS_PLAYER(this) && time >= game_starttime)
{
if (STAT(FROZEN, this) == FROZEN_TEMP_REVIVING)
{
this.last_vehiclecheck = time + 1;
}
- if(!CS(this).cvar_cl_newusekeysupported) // FIXME remove this - it was a stupid idea to begin with, we can JUST use the button
+ if(!CS_CVAR(this).cvar_cl_newusekeysupported) // FIXME remove this - it was a stupid idea to begin with, we can JUST use the button
{
if(PHYS_INPUT_BUTTON_USE(this) && !CS(this).usekeypressed)
PlayerUseKey(this);
}
target_voicescript_next(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
- 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)
DrownPlayer(this);
UpdateChatBubble(this);
if (CS(this).impulse) ImpulseCommands(this);
+ GetPressedKeys(this);
if (game_stopped)
{
CSQCMODEL_AUTOUPDATE(this);
return;
}
- GetPressedKeys(this);
}
else if (IS_OBSERVER(this) && STAT(PRESSED_KEYS, this))
{
#pragma once
-bool autocvar_sv_q3acompat_machineshotgunswap;
-bool autocvar_sv_q3defragcompat_changehitbox = false;
+int q3compat = 0;
+#define Q3COMPAT_ARENA BIT(0)
+#define Q3COMPAT_DEFI BIT(1)
+
++bool autocvar_sv_q3compat_changehitbox;
+
bool DoesQ3ARemoveThisEntity(entity this);
+int GetAmmoConsumptionQ3(string netname);
.int fragsfilter_cnt;
+
+/* We tell the ammo spawnfunc which weapon will use the ammo so it can
+ * calculate the amount required for the number of shots in the count field,
+ * and so the type can be looked up rather than specified in quake3.qc
+ */
+// Ammo only, unconditional
+#define SPAWNFUNC_Q3AMMO(ammo_classname, xonwep) \
+ spawnfunc(ammo_classname) \
+ { \
+ if(this.count && xonwep.ammo_type) \
+ SetResource(this, xonwep.ammo_type, this.count * GetAmmoConsumptionQ3(xonwep.netname)); \
+ SPAWNFUNC_BODY(GetAmmoItem(xonwep.ammo_type)) \
+ }
+
+// Ammo only, conditional
+#define SPAWNFUNC_Q3AMMO_COND(ammo_classname, cond, xonwep1, xonwep0) \
+ SPAWNFUNC_Q3AMMO(ammo_classname, (cond ? xonwep1 : xonwep0))
+
+// Weapon & ammo, unconditional
+#define SPAWNFUNC_Q3(weapon_classname, ammo_classname, xonwep) \
+ SPAWNFUNC_WEAPON(weapon_classname, xonwep) \
+ SPAWNFUNC_Q3AMMO(ammo_classname, xonwep)
+
+// Weapon & ammo, conditional
+#define SPAWNFUNC_Q3_COND(weapon_classname, ammo_classname, cond, xonwep1, xonwep0) \
+ SPAWNFUNC_WEAPON_COND(weapon_classname, cond, xonwep1, xonwep0) \
+ SPAWNFUNC_Q3AMMO_COND(ammo_classname, cond, xonwep1, xonwep0)
+
#include <common/constants.qh>
#include <common/deathtypes/all.qh>
+ #include <common/gamemodes/gamemode/cts/cts.qh>
#include <common/items/_mod.qh>
#include <common/mapobjects/subs.qh>
#include <common/mapobjects/triggers.qh>
// 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(CS(player).autoswitch)
+ if(CS_CVAR(player).autoswitch)
{
for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
{
return false;
// crude hack to enforce switching weapons
- if(g_cts && item.itemdef.instanceOfWeaponPickup && !CS(player).cvar_cl_cts_noautoswitch)
+ if(g_cts && item.itemdef.instanceOfWeaponPickup && !CS_CVAR(player).cvar_cl_cts_noautoswitch)
{
for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
{
if(autocvar_spawn_debug >= 2)
{
- // why not flags & fl_item?
- FOREACH_ENTITY_RADIUS(this.origin, 3, it.is_item, {
- LOG_TRACE("XXX Found duplicated item: ", itemname, vtos(this.origin));
- LOG_TRACE(" vs ", it.netname, vtos(it.origin));
- error("Mapper sucks.");
- });
+ // why not flags & fl_item?
+ FOREACH_ENTITY_RADIUS(this.origin, 3, it.is_item, {
+ LOG_TRACE("XXX Found duplicated item: ", itemname, vtos(this.origin));
+ LOG_TRACE(" vs ", it.netname, vtos(it.origin));
+ error("Mapper sucks.");
+ });
this.is_item = true;
}
weaponsInMap |= WepSet_FromWeapon(REGISTRY_GET(Weapons, weaponid));
- if ( def.instanceOfPowerup
- || def.instanceOfWeaponPickup
+ if ( def.instanceOfPowerup
+ || def.instanceOfWeaponPickup
|| (def.instanceOfHealth && def != ITEM_HealthSmall)
|| (def.instanceOfArmor && def != ITEM_ArmorSmall)
|| (itemid & (IT_KEY1 | IT_KEY2))
this.bot_pickupevalfunc = pickupevalfunc;
this.bot_pickupbasevalue = pickupbasevalue;
this.mdl = this.model ? this.model : strzone(this.item_model_ent.model_str());
- this.netname = itemname;
+ this.netname = (def.m_weapon) ? def.m_weapon.netname : def.netname;
settouch(this, Item_Touch);
setmodel(this, MDL_Null); // precision set below
//this.effects |= EF_LOWPRECISION;
void StartItem(entity this, GameItem def)
{
- def = def.m_spawnfunc_hookreplace(def, this);
- if (def.spawnflags & ITEM_FLAG_MUTATORBLOCKED)
- {
- delete(this);
- return;
- }
- this.classname = def.m_canonical_spawnfunc;
- _StartItem(
- this,
- this.itemdef = def,
- def.m_respawntime(), // defaultrespawntime
- def.m_respawntimejitter() // defaultrespawntimejitter
+ def = def.m_spawnfunc_hookreplace(def, this);
+
+ if (def.spawnflags & ITEM_FLAG_MUTATORBLOCKED)
+ {
+ delete(this);
+ return;
+ }
+
+ this.classname = def.m_canonical_spawnfunc;
+
+ _StartItem(
+ this,
+ this.itemdef = def,
+ def.m_respawntime(), // defaultrespawntime
+ def.m_respawntimejitter() // defaultrespawntimejitter
);
}
int _switchweapon = 0;
- if(CS(e).autoswitch)
+ if(CS_CVAR(e).autoswitch)
{
for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
{
#include <common/sounds/sound.qh>
+ float autocvar_g_balance_superweapons_time;
+ bool autocvar_g_fullbrightitems;
+ int autocvar_g_powerups;
+ float autocvar_g_items_mindist;
+ float autocvar_g_items_maxdist;
+ int autocvar_g_pickup_items;
+ bool autocvar_g_nodepthtestitems;
+ #define autocvar_g_weapon_stay cvar("g_weapon_stay")
+
void StartItem(entity this, entity a);
.int item_group;
.int item_group_count;
.float max_armorvalue;
.float pickup_anyway;
+.int count;
.float scheduledrespawntime;
.float respawntime;
return false;
}
+void defrag_waypointsprites(entity targeted, entity checkpoint)
+{
+ for(entity t = findchain(target, targeted.targetname); t; t = t.chain)
+ {
+ if(t.modelindex)
+ {
+ entity s = WP_RaceStart;
+
+ if(checkpoint.classname == "target_checkpoint")
+ s = WP_RaceCheckpoint;
+ else if(checkpoint.classname == "target_stopTimer")
+ s = WP_RaceFinish;
+
+ vector o = (t.absmin + t.absmax) * 0.5;
+
+ WaypointSprite_SpawnFixed(s, o, t, sprite, RADARICON_NONE);
+
+ t.sprite.realowner = checkpoint;
+ t.sprite.waypointsprite_visible_for_player = race_waypointsprite_visible_for_player;
+ }
+
+ if(t.targetname)
+ defrag_waypointsprites(t, checkpoint);
+ }
+}
+
void trigger_race_checkpoint_verify(entity this)
{
- static bool have_verified;
+ static bool have_verified;
if (have_verified) return;
have_verified = true;
pl_race_place = 0;
if (!Spawn_FilterOutBadSpots(this, findchain(classname, "info_player_deathmatch"), 0, false, true)) {
error(strcat("Checkpoint ", ftos(i), " misses a spawnpoint with race_place==", ftos(pl_race_place), " (used for respawning in race) - bailing out"));
- }
+ }
if (i == 0) {
// qualifying only
pl_race_place = race_lowest_place_spawn;
if (!Spawn_FilterOutBadSpots(this, findchain(classname, "info_player_deathmatch"), 0, false, true)) {
error(strcat("Checkpoint ", ftos(i), " misses a spawnpoint with race_place==", ftos(pl_race_place), " (used for qualifying) - bailing out"));
- }
+ }
// race only (initial spawn)
g_race_qualifying = 0;
pl_race_place = p;
if (!Spawn_FilterOutBadSpots(this, findchain(classname, "info_player_deathmatch"), 0, false, true)) {
error(strcat("Checkpoint ", ftos(i), " misses a spawnpoint with race_place==", ftos(pl_race_place), " (used for initially spawning in race) - bailing out"));
- }
+ }
}
}
}
pl_race_place = race_lowest_place_spawn;
if (!Spawn_FilterOutBadSpots(this, findchain(classname, "info_player_deathmatch"), 0, false, true)) {
error(strcat("Checkpoint 0 misses a spawnpoint with race_place==", ftos(pl_race_place), " (used for qualifying) - bailing out"));
- }
+ }
} else {
pl_race_checkpoint = race_NextCheckpoint(0);
g_race_qualifying = 1;
for (entity cp = NULL; (cp = find(cp, classname, "target_checkpoint"));) {
if (argv(0) == cp.targetname) {
cp.race_checkpoint = stof(argv(1));
- }
- }
+ }
+ }
}
fclose(fh);
}
g_race_qualifying = qual;
- IL_EACH(g_race_targets, it.classname == "target_checkpoint" || it.classname == "target_startTimer" || it.classname == "target_stopTimer",
- {
- if(it.targetname == "" || !it.targetname) // somehow this is a case...
- continue;
- 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) {
IL_EACH(g_race_targets, it.classname == "target_checkpoint" || it.classname == "target_startTimer" || it.classname == "target_stopTimer",
{
- entity cpt = it;
- if(it.classname == "target_startTimer" || it.classname == "target_stopTimer") {
- if(it.targetname == "" || !it.targetname) // somehow this is a case...
- continue;
- FOREACH_ENTITY_STRING(target, cpt.targetname, {
- if(it.sprite)
- WaypointSprite_UpdateSprites(it.sprite, ((cpt.classname == "target_startTimer") ? WP_RaceStart : WP_RaceFinish), WP_Null, WP_Null);
- });
- }
+ defrag_waypointsprites(it, it);
+
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
for (entity cp = NULL; (cp = find(cp, classname, "target_checkpoint"));) {
if (cp.race_checkpoint > largest_cp_id) {
largest_cp_id = cp.race_checkpoint;
- }
- }
+ }
+ }
for (entity cp = NULL; (cp = find(cp, classname, "target_stopTimer"));) {
cp.race_checkpoint = largest_cp_id + 1; // finish line
- }
+ }
race_highest_checkpoint = largest_cp_id + 1;
race_timed_checkpoint = largest_cp_id + 1;
} else {
for (entity cp = NULL; (cp = find(cp, classname, "target_stopTimer"));) {
cp.race_checkpoint = 255; // finish line
- }
+ }
race_highest_checkpoint = 255;
race_timed_checkpoint = 255;
}
{
if (it.race_checkpoint == 0) {
WaypointSprite_UpdateSprites(it.sprite, WP_RaceStart, WP_Null, WP_Null);
- } else if (it.race_checkpoint == race_timed_checkpoint) {
+ } else if (it.race_checkpoint == race_timed_checkpoint) {
WaypointSprite_UpdateSprites(it.sprite, WP_RaceFinish, WP_Null, WP_Null);
}
- });
+ });
}
}
- if (defrag_ents) {
+ if (defrag_ents) { /* The following hack shall be removed when per-player trigger_multiple.wait is implemented for cts */
for (entity trigger = NULL; (trigger = find(trigger, classname, "trigger_multiple")); ) {
for (entity targ = NULL; (targ = find(targ, targetname, trigger.target)); ) {
if (targ.classname == "target_checkpoint" || targ.classname == "target_startTimer" || targ.classname == "target_stopTimer") {
InitializeEntity(this, trigger_race_checkpoint_verify, INITPRIO_FINDTARGET);
}
- spawnfunc(target_checkpoint) // defrag entity
+ void target_checkpoint_setup(entity this)
{
if(!g_race && !g_cts) { delete(this); return; }
defrag_ents = 1;
InitializeEntity(this, trigger_race_checkpoint_verify, INITPRIO_FINDTARGET);
}
- spawnfunc(target_startTimer) { spawnfunc_target_checkpoint(this); }
- spawnfunc(target_stopTimer) { spawnfunc_target_checkpoint(this); }
+ spawnfunc(target_checkpoint)
+ {
+ // xonotic defrag entity
+ target_checkpoint_setup(this);
+ }
+
+ // compatibility entity names
+ spawnfunc(target_startTimer) { target_checkpoint_setup(this); }
+ spawnfunc(target_stopTimer) { target_checkpoint_setup(this); }
void race_AbandonRaceCheck(entity p)
{
#include <common/gamemodes/_mod.qh>
#include <common/teams.qh>
#include <server/bot/api.qh>
+ #include <server/bot/default/cvars.qh>
+ #include <server/campaign.qh>
#include <server/client.qh>
#include <server/command/vote.qh>
#include <server/damage.qh>
/// \brief Indicates that the player is not allowed to join a team.
const int TEAM_NOT_ALLOWED = -1;
-.float team_forced; // can be a team number to force a team, or 0 for default action, or -1 for forced spectator
-
.int m_team_balance_state; ///< Holds the state of the team balance entity.
.entity m_team_balance_team[NUM_TEAMS]; ///< ???
{
for (int i = 0; i < NUM_TEAMS; ++i)
{
- g_team_entities[i] = spawn();
+ g_team_entities[i] = new_pure();
}
}
{
SetPlayerColors(player, new_color);
}
- // TODO: Should we really bother with this?
if(!IS_CLIENT(player))
{
- // since this is an engine function, and gamecode doesn't have any calls earlier than this, do the connecting message here
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_CONNECTING,
- player.netname);
return;
}
if (!teamplay)
{
return;
}
- Player_SetTeamIndexChecked(player, Team_TeamToIndex((new_color & 0x0F) +
- 1));
+ Player_SetTeamIndexChecked(player, Team_TeamToIndex((new_color & 0x0F) + 1));
}
bool autocvar_g_balance_teams;
bool autocvar_g_balance_teams_prevent_imbalance;
+ string autocvar_g_forced_team_otherwise;
+
bool lockteams;
+.int team_forced; // can be a team number to force a team, or 0 for default action, or -1 for forced spectator
+
// ========================== Global teams API ================================
/// \brief Returns the global team entity at the given index.
int TeamBalance_CompareTeamsInternal(entity team_a, entity team_index_b,
entity player, bool use_score);
- /// \brief Called when the player connects or when they change their color with
- /// the "color" command.
+ /// \brief Called when the player changes color with the "color" command.
+ /// Note that the "color" command is always called early on player connection
/// \param[in,out] player Player that requested a new color.
/// \param[in] new_color Requested color.
void SV_ChangeTeam(entity player, int new_color);
#include <server/hook.qh>
#include <server/intermission.qh>
#include <server/ipban.qh>
+ #include <server/items/items.qh>
#include <server/main.qh>
#include <server/mapvoting.qh>
#include <server/mutators/_mod.qh>
{
WriteHeader(MSG_BROADCAST, TE_CSQC_PINGPLREPORT);
WriteByte(MSG_BROADCAST, this.cnt);
- WriteShort(MSG_BROADCAST, bound(1, CS(e).ping, 65535));
+ WriteShort(MSG_BROADCAST, bound(1, CS(e).ping, 32767));
WriteByte(MSG_BROADCAST, min(ceil(CS(e).ping_packetloss * 255), 255));
WriteByte(MSG_BROADCAST, min(ceil(CS(e).ping_movementloss * 255), 255));
}
const float SPAWNFLAG_NO_WAYPOINTS_FOR_ITEMS = 1;
- float world_initialized;
void SetDefaultAlpha()
{
#define BADPREFIX(p) if(substring(k, 0, strlen(p)) == p) continue
#define BADPRESUFFIX(p,s) if(substring(k, 0, strlen(p)) == p && substring(k, -strlen(s), -1) == s) continue
#define BADCVAR(p) if(k == p) continue
+ #define BADVALUE(p, val) if (k == p && v == val) continue
// general excludes and namespaces for server admin used cvars
BADPREFIX("help_"); // PN's server has this listed as changed, let's not rat him out for THAT
BADCVAR("sv_motd");
BADCVAR("sv_public");
BADCVAR("sv_ready_restart");
+ BADCVAR("sv_showfps");
BADCVAR("sv_status_privacy");
BADCVAR("sv_taunt");
BADCVAR("sv_vote_call");
BADCVAR("sv_vote_master_commands");
BADCVAR("sv_vote_master_password");
BADCVAR("sv_vote_simple_majority_factor");
+ BADVALUE("sys_ticrate", "0.0166667");
+ BADVALUE("sys_ticrate", "0.0333333");
BADCVAR("teamplay_mode");
BADCVAR("timelimit_override");
BADPREFIX("g_warmup_");
BADCVAR("g_lms_weaponarena");
BADCVAR("g_ctf_stalemate_time");
- if(cvar_string("g_mod_balance") == "Testing")
- {
- // (temporary) while using the Testing balance, any weapon balance cvars are allowed to be changed
- BADPREFIX("g_balance_");
- }
-
#undef BADPRESUFFIX
#undef BADPREFIX
#undef BADCVAR
+ #undef BADVALUE
if(pureadding)
{
MapInfo_Enumerate();
MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 1);
- if(fexists(strcat("scripts/", mapname, ".arena")))
- cvar_settemp("sv_q3acompat_machineshotgunswap", "1");
-
- if(fexists(strcat("scripts/", mapname, ".defi")))
- cvar_settemp("sv_q3defragcompat", "1");
+ q3compat = BITSET(q3compat, Q3COMPAT_ARENA, fexists(strcat("scripts/", mapname, ".arena")));
+ q3compat = BITSET(q3compat, Q3COMPAT_DEFI, fexists(strcat("scripts/", mapname, ".defi")));
if(whichpack(strcat("maps/", mapname, ".cfg")) != "")
{
maplist_reply = strzone(getmaplist());
lsmaps_reply = strzone(getlsmaps());
monsterlist_reply = strzone(getmonsterlist());
+ bool records_available = false;
for(int i = 0; i < 10; ++i)
{
string s = getrecords(i);
- if (s)
+ if (s != "")
+ {
records_reply[i] = strzone(s);
+ records_available = true;
+ }
}
+ if (!records_available)
+ records_reply[0] = "No records available for the current game mode.\n";
ladder_reply = strzone(getladder());
rankings_reply = strzone(getrankings());
s = strcat(s, GetGametype(), "_", GetMapname(), ":", ftos(rint(time)));
if(to_console)
- LOG_INFO(s);
+ LOG_HELP(s);
if(to_eventlog)
GameLogEcho(s);
s = strcat(":labels:player:", GetPlayerScoreString(NULL, 0));
if(to_console)
- LOG_INFO(s);
+ LOG_HELP(s);
if(to_eventlog)
GameLogEcho(s);
if(to_file)
s = strcat(s, "spectator:");
if(to_console)
- LOG_INFO(s, playername(it.netname, it.team, false));
+ LOG_HELP(s, playername(it.netname, it.team, false));
if(to_eventlog)
GameLogEcho(strcat(s, ftos(it.playerid), ":", playername(it.netname, it.team, false)));
if(to_file)
{
s = strcat(":labels:teamscores:", GetTeamScoreString(0, 0));
if(to_console)
- LOG_INFO(s);
+ LOG_HELP(s);
if(to_eventlog)
GameLogEcho(s);
if(to_file)
s = strcat(":teamscores:see-labels:", GetTeamScoreString(i, 0));
s = strcat(s, ":", ftos(i));
if(to_console)
- LOG_INFO(s);
+ LOG_HELP(s);
if(to_eventlog)
GameLogEcho(s);
if(to_file)
}
if(to_console)
- LOG_INFO(":end");
+ LOG_HELP(":end");
if(to_eventlog)
GameLogEcho(":end");
if(to_file)
void NextLevel()
{
game_stopped = true;
- intermission_running = 1; // game over
+ intermission_running = true; // game over
// enforce a wait time before allowing changelevel
if(player_count > 0)
start_ammo_plasma = 0;
if (random_start_ammo == NULL)
{
- random_start_ammo = new(random_start_ammo);
+ random_start_ammo = new_pure(random_start_ammo);
}
start_health = cvar("g_balance_health_start");
start_armorvalue = cvar("g_balance_armor_start");
random_start_weapons_count = cvar("g_random_start_weapons_count");
SetResource(random_start_ammo, RES_SHELLS, cvar("g_random_start_shells"));
SetResource(random_start_ammo, RES_BULLETS, cvar("g_random_start_bullets"));
- SetResource(random_start_ammo, RES_ROCKETS,cvar("g_random_start_rockets"));
+ SetResource(random_start_ammo, RES_ROCKETS, cvar("g_random_start_rockets"));
SetResource(random_start_ammo, RES_CELLS, cvar("g_random_start_cells"));
SetResource(random_start_ammo, RES_PLASMA, cvar("g_random_start_plasma"));
}
start_ammo_cells = max(0, start_ammo_cells);
start_ammo_plasma = max(0, start_ammo_plasma);
start_ammo_fuel = max(0, start_ammo_fuel);
- SetResource(random_start_ammo, RES_SHELLS,
- max(0, GetResource(random_start_ammo, RES_SHELLS)));
- SetResource(random_start_ammo, RES_BULLETS,
- max(0, GetResource(random_start_ammo, RES_BULLETS)));
- SetResource(random_start_ammo, RES_ROCKETS,
- max(0, GetResource(random_start_ammo, RES_ROCKETS)));
- SetResource(random_start_ammo, RES_CELLS,
- max(0, GetResource(random_start_ammo, RES_CELLS)));
- SetResource(random_start_ammo, RES_PLASMA,
- max(0, GetResource(random_start_ammo, RES_PLASMA)));
+ SetResource(random_start_ammo, RES_SHELLS, max(0, GetResource(random_start_ammo, RES_SHELLS)));
+ SetResource(random_start_ammo, RES_BULLETS, max(0, GetResource(random_start_ammo, RES_BULLETS)));
+ SetResource(random_start_ammo, RES_ROCKETS, max(0, GetResource(random_start_ammo, RES_ROCKETS)));
+ SetResource(random_start_ammo, RES_CELLS, max(0, GetResource(random_start_ammo, RES_CELLS)));
+ SetResource(random_start_ammo, RES_PLASMA, max(0, GetResource(random_start_ammo, RES_PLASMA)));
warmup_start_ammo_shells = max(0, warmup_start_ammo_shells);
warmup_start_ammo_nails = max(0, warmup_start_ammo_nails);
set g_grab_range 200 "distance at which dragable objects can be grabbed"
- set g_cloaked 0 "display all players mostly invisible"
set g_player_alpha 1 "default opacity of players"
set g_player_brightness 0 "set to 2 for brighter players"
set g_player_damageforcescale 2 "push multiplier of attacks against players"
- set g_balance_cloaked_alpha 0.25 "opacity of cloaked players"
set g_playerclip_collisions 1 "0 = disable collision testing against playerclips, might be useful on some defrag maps"
set g_botclip_collisions 1 "0 = disable collision testing against botclips, might be useful on some defrag maps"
sv_gameplayfix_gravityunaffectedbyticrate 1
sv_gameplayfix_nogravityonground 1
-set sv_q3acompat_machineshotgunswap 0 "shorthand for swapping machinegun and shotgun (for Q3A map compatibility in mapinfo files)"
-set sv_q3defragcompat 0 "toggle for some compatibility hacks (for Q3DF map compatibility)"
+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)"
set g_movement_highspeed_q3_compat 0 "apply speed modifiers to air movement in a more Q3-compatible way (only apply speed buffs and g_movement_highspeed to max air speed, not to acceleration)"
set sv_damagetext 2 "<= 0: disabled, >= 1: visible to spectators, >= 2: visible to attacker, >= 3: all players see everyone's damage"
- set sv_showfps 5 "Show player's FPS counters in the scoreboard. This setting acts as a delay in seconds between updates"
+ set sv_showfps 0 "Show player's FPS counters in the scoreboard. This setting acts as a delay in seconds between updates. NOTE: this feature gathers performance telemetry, it may require consent from players on the server depending on your legislation"
set sv_doors_always_open 0 "If set to 1 don't close doors which after they were open"
set sv_warpzone_allow_selftarget 0 "do not touch"