set g_maplist_check_waypoints 0 "when 1, maps are skipped if there currently are bots, but the map has no waypoints"
set samelevel 0 "when 1, always play the same level over and over again"
+set g_items_mindist 0 "starting distance for the fading of items"
+set g_items_maxdist 0 "maximum distance at which an item can be viewed, after which it will be invisible"
+
set g_grab_range 200 "distance at which dragable objects can be grabbed"
set g_cloaked 0 "display all players mostly invisible"
set g_footsteps 1 "serverside footstep sounds"
-set g_multijump 0 "Number of multiple jumps to allow (jumping again in the air), -1 allows for infinite jumps"
-set g_multijump_add 0 "0 = make the current z velocity equal to jumpvelocity, 1 = add jumpvelocity to the current z velocity"
-set g_multijump_speed -999999 "Minimum vertical speed a player must have in order to jump again"
-
set g_throughfloor_debug 0 "enable debugging messages for throughfloor calculations"
set g_throughfloor_damage_max_stddev 2 "Maximum standard deviation for splash damage"
set g_throughfloor_force_max_stddev 10 "Maximum standard deviation for splash force"
set g_balance_keyhunt_damageforcescale 1
seta g_keyhunt_teams_override 0
set g_keyhunt_teams 0
+set g_keyhunt_team_spawns 0 "when 1, players spawn from the team spawnpoints of the map, if any"
// ===================
set g_instagib_ammo_drop 5 "how much ammo you'll get for weapons or cells"
set g_instagib_invis_alpha 0.15
set g_instagib_speed_highspeed 1.5 "speed-multiplier that applies while you carry the invincibility powerup"
+set g_instagib_damagedbycontents 1 "allow damage from lava pits in instagib"
// ==========
// =====================
// spawn near teammate
// =====================
+seta cl_spawn_near_teammate 1 "toggle for spawning near teammates (only effective if g_spawn_near_teammate_ignore_spawnpoint is 2)"
set g_spawn_near_teammate 0 "if set, players prefer spawns near a team mate"
set g_spawn_near_teammate_distance 640 "max distance to consider a spawn to be near a team mate"
-set g_spawn_near_teammate_ignore_spawnpoint 0 "ignore spawnpoints and spawn right at team mates"
+set g_spawn_near_teammate_ignore_spawnpoint 0 "ignore spawnpoints and spawn right at team mates, if 2, clients can ignore this option"
set g_spawn_near_teammate_ignore_spawnpoint_delay 2.5 "how long to wait before its OK to spawn at a player after someone just spawned at this player"
set g_spawn_near_teammate_ignore_spawnpoint_delay_death 0 "how long to wait before its OK to spawn at a player after death"
set g_spawn_near_teammate_ignore_spawnpoint_check_health 1 "only allow spawn at this player if their health is full"
set g_nades_bonus_type 2 "Type of the bonus grenade. 1:normal 2:napalm 3:ice 4:translocate 5:spawn 6:heal 7:pokenade"
set g_nades_bonus_onstrength 1 "Always give bonus grenades to players that have the strength powerup"
set g_nades_bonus_max 3 "Maximum number of bonus grenades"
+set g_nades_bonus_only 0 "Disallow regular nades, only bonus nades can be used"
// Bonus score
set g_nades_bonus_score_max 120 "Score value that will give a bonus nade"
set g_nades_bonus_score_minor 5 "Score given for minor actions (pickups, regular frags etc.)"
// ==========
set g_new_toys 0 "Mutator 'New Toys': enable extra fun guns"
set g_new_toys_autoreplace 2 "0: never replace, 1: always auto replace guns by available new toys, 2: randomly auto replace guns by available new toys"
+set g_new_toys_use_pickupsound 1 "play the 'new toys, new toys!' roflsound when picking up a new toys weapon"
// =======
// ================
set g_breakablehook 0 "enable breakable hook mutator (hook can be damaged, and returns damage to the owner when broken)"
set g_breakablehook_owner 0 "allow owner to break their own hook"
+
+
+// ===========
+// multijump
+// ===========
+seta cl_multijump 1 "allow multijump mutator"
+set g_multijump 0 "Number of multiple jumps to allow (jumping again in the air), -1 allows for infinite jumps"
+set g_multijump_add 0 "0 = make the current z velocity equal to jumpvelocity, 1 = add jumpvelocity to the current z velocity"
+set g_multijump_speed -999999 "Minimum vertical speed a player must have in order to jump again"
float autocvar_crosshair_rpc_alpha = 1;
float autocvar_crosshair_rpc_size = 1;
int autocvar_cl_nade_timer;
+bool autocvar_cl_items_nofade;
#endif
registercvar("cl_jumpspeedcap_min", "");
registercvar("cl_jumpspeedcap_max", "");
+ registercvar("cl_multijump", "1");
+
+ registercvar("cl_spawn_near_teammate", "1");
+
gametype = 0;
// hud_fields uses strunzone on the titles!
RegisterHooks();
RegisterCallbacks();
RegisterMutators();
+}
+
+STATIC_INIT_LATE(Mutators) {
FOREACH(MUTATORS, it.mutatorcheck(), LAMBDA(Mutator_Add(it)));
}
/**/
MUTATOR_HOOKABLE(BuildMutatorsPrettyString, EV_BuildMutatorsPrettyString);
+/** appends mutator string for displaying extra gameplay tips */
+#define EV_BuildGameplayTipsString(i, o) \
+ /**/ i(string, ret_string) \
+ /**/ o(string, ret_string) \
+ /**/
+MUTATOR_HOOKABLE(BuildGameplayTipsString, EV_BuildGameplayTipsString);
+
#endif
// 163 empty?
// 164 empty?
// 165 empty?
-// 166 empty?
-// 167 empty?
+const int STAT_MULTIJUMP_DODGING = 166;
+const int STAT_MULTIJUMP_MAXSPEED = 167;
const int STAT_GAMEPLAYFIX_UPVELOCITYCLEARSONGROUND = 168;
const int STAT_BUGRIGS_REVERSE_STOPPING = 169;
const int STAT_BUGRIGS_REVERSE_SPINNING = 170;
#undef spawn
+#define localcmd cmd
+
int(string str, string sub, int startpos) _strstrofs = #221;
#define strstrofs _strstrofs
int(string str, int ofs) _str2chr = #222;
#ifndef CVAR_H
#define CVAR_H
-#define CVAR_DESCRIBE(set, var, desc) localcmd(sprintf("\n"set" %1$s \"$%1$s\" \"%2$s\"\n", #var, desc))
+#include "Static.qh"
-#define AUTOCVAR_4(set, var, type, desc) \
- STATIC_INIT(autocvar_##var) { CVAR_DESCRIBE(set, var, desc); } \
+void RegisterCvars(void(string name, string desc, bool archive, string file) f) { }
+
+void RegisterCvars_Set(string name, string desc, bool archive, string file)
+{
+ localcmd(sprintf("\n%1$s %2$s \"$%2$s\" \"%3$s\"\n", (archive ? "seta" : "set"), name, desc));
+}
+
+STATIC_INIT_LATE(Cvars) { RegisterCvars(RegisterCvars_Set); }
+
+#define AUTOCVAR_5(file, archive, var, type, desc) \
+ [[accumulate]] void RegisterCvars(void(string, string, bool, string) f) { f(#var, desc, archive, file); } \
type autocvar_##var
-#define AUTOCVAR_5(set, var, type, default, desc) \
- AUTOCVAR_4(set, var, type, desc) = default
-#define _AUTOCVAR(...) OVERLOAD(AUTOCVAR, __VA_ARGS__)
-#define AUTOCVAR_SAVE(...) _AUTOCVAR("seta", __VA_ARGS__)
-#define AUTOCVAR(...) _AUTOCVAR("set", __VA_ARGS__)
+#define AUTOCVAR_6(file, archive, var, type, default, desc) \
+ AUTOCVAR_5(file, archive, var, type, desc) = default
+#define _AUTOCVAR(...) OVERLOAD(AUTOCVAR, __FILE__, __VA_ARGS__)
+#define AUTOCVAR_SAVE(...) _AUTOCVAR(true, __VA_ARGS__)
+#define AUTOCVAR(...) _AUTOCVAR(false, __VA_ARGS__)
#endif
ACCUMULATE_FUNCTION(initfunc, Register_##ns##_##id) \
REGISTER_INIT(ns, id)
-void __static_init() { }
-#define static_init() CALL_ACCUMULATED_FUNCTION(__static_init)
-#define REGISTER_REGISTRY(func) ACCUMULATE_FUNCTION(__static_init, func)
-
-#define STATIC_INIT(func) \
- void _static_##func(); \
- ACCUMULATE_FUNCTION(__static_init, _static_##func) \
- void _static_##func()
-
#endif
--- /dev/null
+#ifndef STATIC_H
+#define STATIC_H
+
+void __static_init_early() { }
+void __static_init() { CALL_ACCUMULATED_FUNCTION(__static_init_early); }
+#define static_init() CALL_ACCUMULATED_FUNCTION(__static_init)
+#define REGISTER_REGISTRY(func) ACCUMULATE_FUNCTION(__static_init_early, func)
+
+#define _STATIC_INIT(where, func) \
+ void _static_##func(); \
+ ACCUMULATE_FUNCTION(where, _static_##func) \
+ void _static_##func()
+
+#define STATIC_INIT(func) _STATIC_INIT(__static_init_early, func##_early)
+#define STATIC_INIT_LATE(func) _STATIC_INIT(__static_init, func)
+
+#endif
#include "Progname.qh"
#include "Registry.qh"
#include "sortlist.qc"
+#include "Static.qh"
#include "String.qh"
#include "Struct.qh"
#include "test.qc"
#include "../common/constants.qh"
#include "../common/util.qh"
-#define localcmd cmd
-
// constants
const int GAME_ISSERVER = 1;
s = strcat(s, ", ", _("Invincible Projectiles"));
if(cvar_string("g_weaponarena") != "0")
s = strcat(s, ", ", WeaponArenaString());
- if(cvar("g_balance_blaster_weaponstart") == 0)
+ else if(cvar("g_balance_blaster_weaponstart") == 0)
s = strcat(s, ", ", _("No start weapons"));
if(cvar("sv_gravity") < stof(cvar_defstring("sv_gravity")))
s = strcat(s, ", ", _("Low gravity"));
me.TD(me, 1, 2, e = makeXonoticRadioButton(1, string_null, string_null, _("Regular (no arena)")));
me.TR(me);
me.TD(me, 1, 2, e = makeXonoticRadioButton(1, "g_weaponarena", "menu_weaponarena", _("Weapon arenas:")));
- e.getCvarValueFromCvar = true;
+ e.cvarValueIsAnotherCvar = true;
e.cvarOffValue = "0";
for(i = WEP_FIRST, j = 0; i <= WEP_LAST; ++i)
{
ATTRIB(XonoticRadioButton, cvarName, string, string_null)
ATTRIB(XonoticRadioButton, cvarValue, string, string_null)
ATTRIB(XonoticRadioButton, cvarOffValue, string, string_null)
- ATTRIB(XonoticRadioButton, getCvarValueFromCvar, float, 0)
+ ATTRIB(XonoticRadioButton, cvarValueIsAnotherCvar, float, 0)
METHOD(XonoticRadioButton, loadCvars, void(entity));
METHOD(XonoticRadioButton, saveCvars, void(entity));
if(me.cvarValue)
{
if(me.cvarName)
- me.checked = (cvar_string(me.cvarName) == me.cvarValue);
+ {
+ if(me.cvarValueIsAnotherCvar)
+ me.checked = (cvar_string(me.cvarName) == cvar_string(me.cvarValue));
+ else
+ me.checked = (cvar_string(me.cvarName) == me.cvarValue);
+ }
}
else
{
{
if(me.checked)
{
- if(me.getCvarValueFromCvar)
+ if(me.cvarValueIsAnotherCvar)
cvar_set(me.cvarName, cvar_string(me.cvarValue));
else
cvar_set(me.cvarName, me.cvarValue);
float autocvar_g_keepawayball_respawntime;
int autocvar_g_keepawayball_trail_color;
int autocvar_g_keyhunt_point_leadlimit;
+bool autocvar_g_keyhunt_team_spawns;
#define autocvar_g_keyhunt_point_limit cvar("g_keyhunt_point_limit")
int autocvar_g_keyhunt_teams;
int autocvar_g_keyhunt_teams_override;
int autocvar_g_instagib_extralives;
float autocvar_g_instagib_speed_highspeed;
float autocvar_g_instagib_invis_alpha;
+bool autocvar_g_instagib_damagedbycontents = true;
#define autocvar_g_mirrordamage cvar("g_mirrordamage")
#define autocvar_g_mirrordamage_virtual cvar("g_mirrordamage_virtual")
int autocvar_g_multijump;
float autocvar_g_multijump_add;
float autocvar_g_multijump_speed;
+float autocvar_g_multijump_maxspeed;
+float autocvar_g_multijump_dodging = 1;
string autocvar_g_mutatormsg;
float autocvar_g_nexball_basketball_bouncefactor;
float autocvar_g_nexball_basketball_bouncestop;
bool autocvar_g_nodepthtestitems;
bool autocvar_g_nodepthtestplayers;
bool autocvar_g_norecoil;
+float autocvar_g_items_mindist;
+float autocvar_g_items_maxdist;
int autocvar_g_pickup_cells_max;
int autocvar_g_pickup_plasma_max;
int autocvar_g_pickup_fuel_max;
bool autocvar_g_nades_bonus;
bool autocvar_g_nades_bonus_onstrength;
bool autocvar_g_nades_bonus_client_select;
+bool autocvar_g_nades_bonus_only;
int autocvar_g_nades_bonus_max;
int autocvar_g_nades_bonus_score_max;
int autocvar_g_nades_bonus_score_time;
float autocvar_g_overkill_ammo_charge_notice;
float autocvar_g_overkill_ammo_charge_limit;
float autocvar_g_spawn_near_teammate_distance;
-bool autocvar_g_spawn_near_teammate_ignore_spawnpoint;
+int autocvar_g_spawn_near_teammate_ignore_spawnpoint;
float autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay;
float autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay_death;
float autocvar_g_onslaught_debug;
void PlayerPostThink (void)
{SELFPARAM();
if(sv_maxidle > 0 && frametime) // WORKAROUND: only use dropclient in server frames (frametime set). Never use it in cl_movement frames (frametime zero).
+ if(IS_REAL_CLIENT(self))
if(IS_PLAYER(self) || sv_maxidle_spectatorsareidle)
{
if (time - self.parm_idlesince < 1) // instead of (time == self.parm_idlesince) to support sv_maxidle <= 10
float DistributeEvenly_totalweight;
void objerror(string s);
void droptofloor();
-void() spawnfunc_info_player_deathmatch; // needed for the other spawnpoints
-void() spawnpoint_use;
void() SUB_Remove;
void attach_sameorigin(entity e, entity to, string tag);
// player is dead and becomes observer
// FIXME fix LMS scoring for new system
if(PlayerScore_Add(self, SP_LMS_RANK, 0) > 0)
+ {
self.classname = "observer";
+ Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_LMS_NOLIVES);
+ }
return false;
}
"cnt" Scoreboard color of the team (for example 4 is red and 13 is blue)... */
void spawnfunc_tdm_team()
{SELFPARAM();
- if(!g_tdm) { remove(self); return; }
+ if(!g_tdm || !self.cnt) { remove(self); return; }
self.classname = "tdm_team";
self.team = self.cnt + 1;
{
LOG_INFO("No ""tdm_team"" entities found on this map, creating them anyway.\n");
- float numteams = min(4, autocvar_g_tdm_teams_override);
+ int numteams = min(4, autocvar_g_tdm_teams_override);
if(numteams < 2) { numteams = autocvar_g_tdm_teams; }
numteams = bound(2, numteams, 4);
if(time >= self.bloodloss_timer)
{
- self.event_damage(self, self, 1, DEATH_ROT, self.origin, '0 0 0');
+ if(self.vehicle)
+ vehicles_exit(VHEF_RELEASE);
+ if(self.event_damage)
+ self.event_damage(self, self, 1, DEATH_ROT, self.origin, '0 0 0');
self.bloodloss_timer = time + 0.5 + random() * 0.5;
}
}
MUTATOR_HOOKFUNCTION(campcheck_PlayerDies)
{SELFPARAM();
- Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_CAMPCHECK);
+ Kill_Notification(NOTIF_ONE, self, MSG_CENTER_CPID, CPID_CAMPCHECK);
return false;
}
MUTATOR_HOOKFUNCTION(campcheck_PlayerThink)
{SELFPARAM();
+ if(!gameover)
+ if(!warmup_stage) // don't consider it camping during warmup?
+ if(time >= game_starttime)
if(IS_PLAYER(self))
+ if(IS_REAL_CLIENT(self)) // bots may camp, but that's no reason to constantly kill them
if(self.deadflag == DEAD_NO)
if(!self.frozen)
+ if(!self.BUTTON_CHAT)
if(autocvar_g_campcheck_interval)
{
vector dist;
self.campcheck_nextcheck = time + autocvar_g_campcheck_interval;
self.campcheck_traveled_distance = 0;
}
+
+ return false;
}
+ self.campcheck_nextcheck = time + autocvar_g_campcheck_interval; // one of the above checks failed, so keep the timer up to date
return false;
}
if(IS_PLAYER(frag_target))
{
- if ((frag_deathtype == DEATH_FALL) ||
- (frag_deathtype == DEATH_DROWN) ||
- (frag_deathtype == DEATH_SLIME) ||
- (frag_deathtype == DEATH_LAVA))
+ if(frag_deathtype == DEATH_FALL)
+ frag_damage = 0; // never count fall damage
+
+ if(!autocvar_g_instagib_damagedbycontents)
+ switch(frag_deathtype)
{
- frag_damage = 0;
+ case DEATH_DROWN:
+ case DEATH_SLIME:
+ case DEATH_LAVA:
+ frag_damage = 0;
+ break;
}
if(IS_PLAYER(frag_attacker))
{
entity e = spawn();
setorigin(e, self.origin);
+ e.noalign = self.noalign;
+ e.cnt = self.cnt;
+ e.team = self.team;
SELFCALL(e, spawnfunc_item_minst_cells());
SELFCALL_DONE();
return true;
#include "../antilag.qh"
#endif
-.float multijump_count;
-.float multijump_ready;
+.int multijump_count;
+.bool multijump_ready;
+.bool cvar_cl_multijump;
#ifdef CSQC
#define PHYS_MULTIJUMP getstati(STAT_MULTIJUMP)
#define PHYS_MULTIJUMP_SPEED getstatf(STAT_MULTIJUMP_SPEED)
#define PHYS_MULTIJUMP_ADD getstati(STAT_MULTIJUMP_ADD)
+#define PHYS_MULTIJUMP_MAXSPEED getstatf(STAT_MULTIJUMP_MAXSPEED)
+#define PHYS_MULTIJUMP_DODGING getstati(STAT_MULTIJUMP_DODGING)
#elif defined(SVQC)
#define PHYS_MULTIJUMP autocvar_g_multijump
#define PHYS_MULTIJUMP_SPEED autocvar_g_multijump_speed
#define PHYS_MULTIJUMP_ADD autocvar_g_multijump_add
+#define PHYS_MULTIJUMP_MAXSPEED autocvar_g_multijump_maxspeed
+#define PHYS_MULTIJUMP_DODGING autocvar_g_multijump_dodging
.float stat_multijump;
.float stat_multijump_speed;
.float stat_multijump_add;
+.float stat_multijump_maxspeed;
+.float stat_multijump_dodging;
void multijump_UpdateStats()
{SELFPARAM();
self.stat_multijump = PHYS_MULTIJUMP;
self.stat_multijump_speed = PHYS_MULTIJUMP_SPEED;
self.stat_multijump_add = PHYS_MULTIJUMP_ADD;
+ self.stat_multijump_maxspeed = PHYS_MULTIJUMP_MAXSPEED;
+ self.stat_multijump_dodging = PHYS_MULTIJUMP_DODGING;
}
void multijump_AddStats()
addstat(STAT_MULTIJUMP, AS_INT, stat_multijump);
addstat(STAT_MULTIJUMP_SPEED, AS_FLOAT, stat_multijump_speed);
addstat(STAT_MULTIJUMP_ADD, AS_INT, stat_multijump_add);
+ addstat(STAT_MULTIJUMP_MAXSPEED, AS_FLOAT, stat_multijump_maxspeed);
+ addstat(STAT_MULTIJUMP_DODGING, AS_INT, stat_multijump_dodging);
}
#endif
}
}
-float PM_multijump_checkjump()
+bool PM_multijump_checkjump()
{SELFPARAM();
if(!PHYS_MULTIJUMP) { return false; }
- if (!IS_JUMP_HELD(self) && !IS_ONGROUND(self)) // jump button pressed this frame and we are in midair
+#ifdef SVQC
+ bool client_multijump = self.cvar_cl_multijump;
+#elif defined(CSQC)
+ bool client_multijump = cvar("cl_multijump");
+
+ if(cvar("cl_multijump") > 1)
+ return false; // nope
+#endif
+
+ if (!IS_JUMP_HELD(self) && !IS_ONGROUND(self) && client_multijump) // jump button pressed this frame and we are in midair
self.multijump_ready = true; // this is necessary to check that we released the jump button and pressed it again
else
self.multijump_ready = false;
- if(!player_multijump && self.multijump_ready && (self.multijump_count < PHYS_MULTIJUMP || PHYS_MULTIJUMP == -1) && self.velocity_z > PHYS_MULTIJUMP_SPEED)
+ int phys_multijump = PHYS_MULTIJUMP;
+
+#ifdef CSQC
+ phys_multijump = (PHYS_MULTIJUMP) ? -1 : 0;
+#endif
+
+ if(!player_multijump && self.multijump_ready && (self.multijump_count < phys_multijump || phys_multijump == -1) && self.velocity_z > PHYS_MULTIJUMP_SPEED && (!PHYS_MULTIJUMP_MAXSPEED || vlen(self.velocity) <= PHYS_MULTIJUMP_MAXSPEED))
{
if (PHYS_MULTIJUMP)
{
if(player_multijump)
{
+ if(PHYS_MULTIJUMP_DODGING)
if(self.movement_x != 0 || self.movement_y != 0) // don't remove all speed if player isnt pressing any movement keys
{
float curspeed;
vector wishvel, wishdir;
-#ifdef SVQC
+/*#ifdef SVQC
curspeed = max(
vlen(vec2(self.velocity)), // current xy speed
vlen(vec2(antilag_takebackavgvelocity(self, max(self.lastteleporttime + sys_frametime, time - 0.25), time))) // average xy topspeed over the last 0.25 secs
);
-#elif defined(CSQC)
+#elif defined(CSQC)*/
curspeed = vlen(vec2(self.velocity));
-#endif
+//#endif
makevectors(self.v_angle_y * '0 1 0');
wishvel = v_forward * self.movement_x + v_right * self.movement_y;
self.velocity_y = wishdir_y * curspeed;
// keep velocity_z unchanged!
}
- self.multijump_count += 1;
+ if (PHYS_MULTIJUMP > 0)
+ {
+ self.multijump_count += 1;
+ }
}
}
self.multijump_ready = false; // require releasing and pressing the jump button again for the next jump
return PM_multijump_checkjump();
}
+MUTATOR_HOOKFUNCTION(multijump_GetCvars)
+{
+ GetCvars_handleFloat(get_cvars_s, get_cvars_f, cvar_cl_multijump, "cl_multijump");
+ return false;
+}
+
MUTATOR_HOOKFUNCTION(multijump_BuildMutatorsString)
{
ret_string = strcat(ret_string, ":multijump");
{
MUTATOR_HOOK(PlayerPhysics, multijump_PlayerPhysics, CBC_ORDER_ANY);
MUTATOR_HOOK(PlayerJump, multijump_PlayerJump, CBC_ORDER_ANY);
+ MUTATOR_HOOK(GetCvars, multijump_GetCvars, CBC_ORDER_ANY);
MUTATOR_HOOK(BuildMutatorsString, multijump_BuildMutatorsString, CBC_ORDER_ANY);
MUTATOR_HOOK(BuildMutatorsPrettyString, multijump_BuildMutatorsPrettyString, CBC_ORDER_ANY);
void nade_prime()
{SELFPARAM();
+ if(autocvar_g_nades_bonus_only)
+ if(!self.bonus_nades)
+ return; // only allow bonus nades
+
if(self.nade)
remove(self.nade);
.string new_toys;
float autocvar_g_new_toys_autoreplace;
+bool autocvar_g_new_toys_use_pickupsound = true;
const float NT_AUTOREPLACE_NEVER = 0;
const float NT_AUTOREPLACE_ALWAYS = 1;
const float NT_AUTOREPLACE_RANDOM = 2;
case "devastator": return "minelayer";
case "machinegun": return "hlac";
case "vortex": return "rifle";
- case "shotgun": return "shockwave";
+ //case "shotgun": return "shockwave";
default: return string_null;
}
}
MUTATOR_HOOKFUNCTION(nt_FilterItem)
{SELFPARAM();
- if(nt_IsNewToy(self.weapon))
+ if(nt_IsNewToy(self.weapon) && autocvar_g_new_toys_use_pickupsound)
self.item_pickupsound = W_Sound("weaponpickup_new_toys");
return 0;
}
// if the item is not spawned, make sure the invisible / ghost item returns to its origin and stays there
if(autocvar_g_physical_items_reset)
{
- if(self.owner.nextthink > time) // awaiting respawn
+ if(self.owner.wait > time) // awaiting respawn
{
setorigin(self, self.spawn_origin);
self.angles = self.spawn_angles;
self.solid = SOLID_NOT;
+ self.alpha = -1;
self.movetype = MOVETYPE_NONE;
}
else
{
+ self.alpha = 1;
self.solid = SOLID_CORPSE;
self.movetype = MOVETYPE_PHYSICS;
}
wep.touch = physical_item_touch;
wep.event_damage = physical_item_damage;
- wep.spawn_origin = self.origin;
+ if(!wep.cnt)
+ {
+ // fix the spawn origin
+ setorigin(wep, wep.origin + '0 0 1');
+ entity oldself;
+ oldself = self;
+ self = wep;
+ builtin_droptofloor();
+ self = oldself;
+ }
+
+ wep.spawn_origin = wep.origin;
wep.spawn_angles = self.angles;
self.effects |= EF_NODRAW; // hide the original weapon
self.movetype = MOVETYPE_FOLLOW;
self.aiment = wep; // attach the original weapon
+ self.SendEntity = func_null;
return false;
}
.float msnt_timer;
.vector msnt_deathloc;
+.float cvar_cl_spawn_near_teammate;
+
MUTATOR_HOOKFUNCTION(msnt_Spawn_Score)
{SELFPARAM();
- if(autocvar_g_spawn_near_teammate_ignore_spawnpoint)
+ if(autocvar_g_spawn_near_teammate_ignore_spawnpoint == 1 || (autocvar_g_spawn_near_teammate_ignore_spawnpoint == 2 && self.cvar_cl_spawn_near_teammate))
return 0;
entity p;
MUTATOR_HOOKFUNCTION(msnt_PlayerSpawn)
{SELFPARAM();
// Note: when entering this, fixangle is already set.
- if(autocvar_g_spawn_near_teammate_ignore_spawnpoint)
+ if(autocvar_g_spawn_near_teammate_ignore_spawnpoint == 1 || (autocvar_g_spawn_near_teammate_ignore_spawnpoint == 2 && self.cvar_cl_spawn_near_teammate))
{
if(autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay_death)
self.msnt_timer = time + autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay_death;
return 0;
}
+MUTATOR_HOOKFUNCTION(msnt_GetCvars)
+{
+ GetCvars_handleFloat(get_cvars_s, get_cvars_f, cvar_cl_spawn_near_teammate, "cl_spawn_near_teammate");
+ return false;
+}
+
MUTATOR_DEFINITION(mutator_spawn_near_teammate)
{
MUTATOR_HOOK(Spawn_Score, msnt_Spawn_Score, CBC_ORDER_ANY);
MUTATOR_HOOK(PlayerSpawn, msnt_PlayerSpawn, CBC_ORDER_ANY);
MUTATOR_HOOK(PlayerDies, msnt_PlayerDies, CBC_ORDER_ANY);
+ MUTATOR_HOOK(GetCvars, msnt_GetCvars, CBC_ORDER_ANY);
return 0;
}
return true;
entity _player;
- float _team = 0;
- float found = false;
+ int _team = 0;
+ bool found = false;
if(cmd_argc == 2)
{
- if(argv(1) == "red")
- _team = NUM_TEAM_1;
- else
- _team = NUM_TEAM_2;
+ switch(argv(1))
+ {
+ case "red": _team = NUM_TEAM_1; break;
+ case "blue": _team = NUM_TEAM_2; break;
+ case "yellow": if(ctf_teams >= 3) _team = NUM_TEAM_3; break;
+ case "pink": if(ctf_teams >= 4) _team = NUM_TEAM_4; break;
+ }
}
FOR_EACH_PLAYER(_player)
self.team = activator.team;
some_spawn_has_been_used = 1;
}
- LOG_INFO("spawnpoint was used!\n");
+ //LOG_INFO("spawnpoint was used!\n");
}
void relocate_spawnpoint()
float SpawnEvent_Send(entity to, int sf);
entity Spawn_FilterOutBadSpots(entity firstspot, float mindist, float teamcheck);
entity SelectSpawnPoint (float anypoint);
+void spawnfunc_info_player_deathmatch();
+void spawnpoint_use();
#endif
}
}
+void Item_PreDraw()
+{
+ vector org;
+ float alph;
+ org = getpropertyvec(VF_ORIGIN);
+ if(!checkpvs(org, self)) // this makes sense as long as we don't support recursive warpzones
+ alph = 0;
+ else if(self.fade_start)
+ alph = bound(0, (self.fade_end - vlen(org - self.origin - 0.5 * (self.mins + self.maxs))) / (self.fade_end - self.fade_start), 1);
+ else
+ alph = 1;
+ //printf("%v <-> %v\n", view_origin, self.origin + 0.5 * (self.mins + self.maxs));
+ if(self.ItemStatus & ITS_AVAILABLE)
+ self.alpha = alph;
+ if(alph <= 0)
+ self.drawmask = 0;
+ else
+ self.drawmask = MASK_NORMAL;
+}
+
void ItemRead(float _IsNew)
{SELFPARAM();
int sf = ReadByte();
if(sf & ISF_ANGLES)
{
- self.angles_x = ReadCoord();
- self.angles_y = ReadCoord();
- self.angles_z = ReadCoord();
+ self.angles_x = ReadAngle();
+ self.angles_y = ReadAngle();
+ self.angles_z = ReadAngle();
self.move_angles = self.angles;
}
if(sf & ISF_SIZE)
{
- self.mins_x = ReadCoord();
- self.mins_y = ReadCoord();
- self.mins_z = ReadCoord();
- self.maxs_x = ReadCoord();
- self.maxs_y = ReadCoord();
- self.maxs_z = ReadCoord();
- setsize(self, self.mins, self.maxs);
+ float use_bigsize = ReadByte();
+ setsize(self, '-16 -16 0', (use_bigsize) ? '16 16 48' : '16 16 32');
}
if(sf & ISF_STATUS) // need to read/write status frist so model can handle simple, fb etc.
if(sf & ISF_MODEL)
{
self.drawmask = MASK_NORMAL;
- self.movetype = MOVETYPE_TOSS;
+ self.move_movetype = self.movetype = MOVETYPE_TOSS;
self.draw = ItemDraw;
+ self.fade_end = ReadShort();
+ self.fade_start = ReadShort();
+ if(self.fade_start && !autocvar_cl_items_nofade)
+ self.predraw = Item_PreDraw;
+
if(self.mdl)
strunzone(self.mdl);
string _fn2 = substring(_fn, 0 , strlen(_fn) -4);
self.draw = ItemDrawSimple;
-
-
if(fexists(sprintf("%s%s.md3", _fn2, autocvar_cl_simpleitems_postfix)))
self.mdl = strzone(sprintf("%s%s.md3", _fn2, autocvar_cl_simpleitems_postfix));
else if(fexists(sprintf("%s%s.dpm", _fn2, autocvar_cl_simpleitems_postfix)))
#ifdef SVQC
bool ItemSend(entity to, int sf)
{SELFPARAM();
- if(self.gravity)
- sf |= ISF_DROP;
- else
- sf &= ~ISF_DROP;
+ if(self.gravity)
+ sf |= ISF_DROP;
+ else
+ sf &= ~ISF_DROP;
WriteByte(MSG_ENTITY, ENT_CLIENT_ITEM);
WriteByte(MSG_ENTITY, sf);
//WriteByte(MSG_ENTITY, self.cnt);
- if(sf & ISF_LOCATION)
- {
- WriteCoord(MSG_ENTITY, self.origin.x);
- WriteCoord(MSG_ENTITY, self.origin.y);
- WriteCoord(MSG_ENTITY, self.origin.z);
- }
+ if(sf & ISF_LOCATION)
+ {
+ WriteCoord(MSG_ENTITY, self.origin.x);
+ WriteCoord(MSG_ENTITY, self.origin.y);
+ WriteCoord(MSG_ENTITY, self.origin.z);
+ }
- if(sf & ISF_ANGLES)
- {
- WriteCoord(MSG_ENTITY, self.angles.x);
- WriteCoord(MSG_ENTITY, self.angles.y);
- WriteCoord(MSG_ENTITY, self.angles.z);
- }
+ if(sf & ISF_ANGLES)
+ {
+ WriteAngle(MSG_ENTITY, self.angles_x);
+ WriteAngle(MSG_ENTITY, self.angles_y);
+ WriteAngle(MSG_ENTITY, self.angles_z);
+ }
- if(sf & ISF_SIZE)
- {
- WriteCoord(MSG_ENTITY, self.mins.x);
- WriteCoord(MSG_ENTITY, self.mins.y);
- WriteCoord(MSG_ENTITY, self.mins.z);
- WriteCoord(MSG_ENTITY, self.maxs.x);
- WriteCoord(MSG_ENTITY, self.maxs.y);
- WriteCoord(MSG_ENTITY, self.maxs.z);
- }
+ if(sf & ISF_SIZE)
+ {
+ WriteByte(MSG_ENTITY, ((self.flags & FL_POWERUP) || self.health || self.armorvalue));
+ }
- if(sf & ISF_STATUS)
- WriteByte(MSG_ENTITY, self.ItemStatus);
+ if(sf & ISF_STATUS)
+ WriteByte(MSG_ENTITY, self.ItemStatus);
- if(sf & ISF_MODEL)
- {
+ if(sf & ISF_MODEL)
+ {
+ WriteShort(MSG_ENTITY, self.fade_end);
+ WriteShort(MSG_ENTITY, self.fade_start);
- if(self.mdl == "")
- LOG_TRACE("^1WARNING!^7 self.mdl is unset for item ", self.classname, "exspect a crash just aboute now\n");
+ if(self.mdl == "")
+ LOG_TRACE("^1WARNING!^7 self.mdl is unset for item ", self.classname, "exspect a crash just aboute now\n");
- WriteString(MSG_ENTITY, self.mdl);
- }
+ WriteString(MSG_ENTITY, self.mdl);
+ }
- if(sf & ISF_COLORMAP)
- WriteShort(MSG_ENTITY, self.colormap);
+ if(sf & ISF_COLORMAP)
+ WriteShort(MSG_ENTITY, self.colormap);
- if(sf & ISF_DROP)
- {
- WriteCoord(MSG_ENTITY, self.velocity.x);
- WriteCoord(MSG_ENTITY, self.velocity.y);
- WriteCoord(MSG_ENTITY, self.velocity.z);
- }
+ if(sf & ISF_DROP)
+ {
+ WriteCoord(MSG_ENTITY, self.velocity.x);
+ WriteCoord(MSG_ENTITY, self.velocity.y);
+ WriteCoord(MSG_ENTITY, self.velocity.z);
+ }
- return true;
+ return true;
}
void ItemUpdate(entity item)
}
if (e.items & ITEM_Strength.m_itemid || e.items & ITEM_Shield.m_itemid)
- e.ItemStatus |= ITS_POWERUP;
+ e.ItemStatus |= ITS_POWERUP;
if (autocvar_g_nodepthtestitems)
e.effects |= EF_NODEPTHTEST;
- if (autocvar_g_fullbrightitems)
+ if (autocvar_g_fullbrightitems)
e.ItemStatus |= ITS_ALLOWFB;
if (autocvar_sv_simple_items)
- e.ItemStatus |= ITS_ALLOWSI;
+ e.ItemStatus |= ITS_ALLOWSI;
// relink entity (because solid may have changed)
setorigin(e, e.origin);
- e.SendFlags |= ISF_STATUS;
+ e.SendFlags |= ISF_STATUS;
}
void Item_Think()
if (!pickedup)
return 0;
+ // crude hack to enforce switching weapons
+ if(g_cts && (item.flags & FL_WEAPON))
+ {
+ W_SwitchWeapon_Force(player, item.weapon);
+ return 1;
+ }
+
if (_switchweapon)
if (player.switchweapon != w_getbestweapon(player))
W_SwitchWeapon_Force(player, w_getbestweapon(player));
for(head = world; (head = findfloat(head, team, self.team)); )
{
if(head.flags & FL_ITEM)
+ if(head.classname != "item_flag_team" && head.classname != "item_key_team")
{
Item_Show(head, -1);
RandomSelection_Add(head, 0, string_null, head.cnt, 0);
// marker for item team search
LOG_TRACE("Initializing item team ", ftos(self.team), "\n");
RandomSelection_Init();
- for(head = world; (head = findfloat(head, team, self.team)); ) if(head.flags & FL_ITEM)
+ for(head = world; (head = findfloat(head, team, self.team)); )
+ if(head.flags & FL_ITEM)
+ if(head.classname != "item_flag_team" && head.classname != "item_key_team")
RandomSelection_Add(head, 0, string_null, head.cnt, 0);
e = RandomSelection_chosen_ent;
e.state = 0;
Item_Show(e, 1);
- for(head = world; (head = findfloat(head, team, self.team)); ) if(head.flags & FL_ITEM)
+ for(head = world; (head = findfloat(head, team, self.team)); )
+ if(head.flags & FL_ITEM)
+ if(head.classname != "item_flag_team" && head.classname != "item_key_team")
{
if(head != e)
{
// TODO: perhaps nice special effect?
void RemoveItem(void)
{SELFPARAM();
+ if(wasfreed(self) || !self) { return; }
Send_Effect(EFFECT_ITEM_PICKUP, CENTER_OR_VIEWOFS(self), '0 0 0', 1);
remove(self);
}
self.items = itemid;
self.weapon = weaponid;
+ if(!self.fade_end)
+ {
+ self.fade_start = autocvar_g_items_mindist;
+ self.fade_end = autocvar_g_items_maxdist;
+ }
+
if(weaponid)
self.weapons = WepSet_FromWeapon(weaponid);
return;
}
+ if(self.angles != '0 0 0')
+ self.SendFlags |= ISF_ANGLES;
+
self.reset = Item_Reset;
// it's a level item
if(self.spawnflags & 1)
setsize (self, '-16 -16 0', '16 16 48');
else
setsize (self, '-16 -16 0', '16 16 32');
-
+ self.SendFlags |= ISF_SIZE;
// note droptofloor returns false if stuck/or would fall too far
droptofloor();
waypoint_spawnforitem(self);
//self.effects |= EF_LOWPRECISION;
if((itemflags & FL_POWERUP) || self.health || self.armorvalue)
- {
- self.pos1 = '-16 -16 0';
- self.pos2 = '16 16 48';
- }
+ {
+ self.pos1 = '-16 -16 0';
+ self.pos2 = '16 16 48';
+ }
else
- {
- self.pos1 = '-16 -16 0';
- self.pos2 = '16 16 32';
- }
- setsize (self, self.pos1, self.pos2);
+ {
+ self.pos1 = '-16 -16 0';
+ self.pos2 = '16 16 32';
+ }
+ setsize (self, self.pos1, self.pos2);
- if(itemflags & FL_POWERUP)
- self.ItemStatus |= ITS_ANIMATE1;
+ self.SendFlags |= ISF_SIZE;
+
+ if(itemflags & FL_POWERUP)
+ self.ItemStatus |= ITS_ANIMATE1;
if(self.armorvalue || self.health)
- self.ItemStatus |= ITS_ANIMATE2;
+ self.ItemStatus |= ITS_ANIMATE2;
if(itemflags & FL_WEAPON)
{
if (self.classname != "droppedweapon") // if dropped, colormap is already set up nicely
- self.colormap = 1024; // color shirt=0 pants=0 grey
- else
- self.gravity = 1;
+ self.colormap = 1024; // color shirt=0 pants=0 grey
+ else
+ self.gravity = 1;
self.ItemStatus |= ITS_ANIMATE1;
self.ItemStatus |= ISF_COLORMAP;
else
Item_Reset();
- Net_LinkEntity(self, false, 0, ItemSend);
-
- self.SendFlags |= ISF_SIZE;
- if(self.angles)
- self.SendFlags |= ISF_ANGLES;
+ Net_LinkEntity(self, !((itemflags & FL_POWERUP) || self.health || self.armorvalue), 0, ItemSend);
// call this hook after everything else has been done
if(MUTATOR_CALLHOOK(Item_Spawn, self))
#define IT_KEY1 131072
// -Wdouble-declaration
#define IT_KEY2 262144
- // for players:
- const int IT_RED_FLAG_TAKEN = 32768;
- const int IT_RED_FLAG_LOST = 65536;
- const int IT_RED_FLAG_CARRYING = 98304;
- const int IT_BLUE_FLAG_TAKEN = 131072;
- const int IT_BLUE_FLAG_LOST = 262144;
- const int IT_BLUE_FLAG_CARRYING = 393216;
// end
const int IT_5HP = 524288;
.int ItemStatus;
+.float fade_start;
+.float fade_end;
+
#ifdef CSQC
float autocvar_cl_animate_items = 1;
ActivateTeamplay();
fraglimit_override = autocvar_g_keyhunt_point_limit;
leadlimit_override = autocvar_g_keyhunt_point_leadlimit;
+ if(autocvar_g_keyhunt_team_spawns)
+ have_team_spawns = -1; // request team spawns
MUTATOR_ADD(gamemode_keyhunt);
}
else
modifications = strcat(modifications, ", ", g_weaponarena_list, " Arena");
}
- if(cvar("g_balance_blaster_weaponstart") == 0)
+ else if(cvar("g_balance_blaster_weaponstart") == 0)
modifications = strcat(modifications, ", No start weapons");
if(cvar("sv_gravity") < stof(cvar_defstring("sv_gravity")))
modifications = strcat(modifications, ", Low gravity");
s = strcat(s, "\n\n^8special gameplay tips: ^7", cache_mutatormsg);
}
+ string mutator_msg = "";
+ MUTATOR_CALLHOOK(BuildGameplayTipsString, mutator_msg);
+ mutator_msg = ret_string;
+
+ s = strcat(s, mutator_msg); // trust that the mutator will do proper formatting
+
motd = autocvar_sv_motd;
if (motd != "") {
s = strcat(s, "\n\n^8MOTD: ^7", strreplace("\\n", "\n", motd));