- wget -O data/maps/g-23.waypoints.cache https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/g-23.waypoints.cache
- wget -O data/maps/g-23.waypoints.hardwired https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/g-23.waypoints.hardwired
- make
- - EXPECT=0a9ea83e32e148da989cbbadc7421ea0
+ - EXPECT=b58f9c7587f1a14e5c52176d4e62a9fb
- HASH=$(${ENGINE} -noconfig -nohome +exec serverbench.cfg
| tee /dev/stderr
| grep '^:'
seta hud_panel_infomessages_group_fadetime 0.4 "group message fade in/out time"
seta hud_panel_scoreboard_namesize 15 "size limit of player names and relative column (multiplied by fontsize)"
-seta hud_panel_scoreboard_maxheight 0.5 "max height of the scoreboard; a few players that wouldn't fit into the scoreboard are listed in the last row"
+seta hud_panel_scoreboard_maxheight 0.6 "max height of the scoreboard; a few players that wouldn't fit into the scoreboard are listed in the last row"
seta hud_panel_scoreboard_others_showscore 1 "show scores of players listed in the last row when the scoreboard reaches the max height"
seta hud_panel_scoreboard_spectators_showping 1 "show ping of spectators"
seta hud_panel_scoreboard_spectators_aligned 0 "align spectators in columns"
set g_balance_vaporizer_weaponreplace ""
set g_balance_vaporizer_weaponstart 0
set g_balance_vaporizer_weaponstartoverride -1
-set g_balance_vaporizer_weaponthrowable 0
+set g_balance_vaporizer_weaponthrowable 1
// }}}
// {{{ #13: Grappling Hook
set g_balance_hook_primary_ammo 5
set g_balance_vaporizer_weaponreplace ""
set g_balance_vaporizer_weaponstart 0
set g_balance_vaporizer_weaponstartoverride -1
-set g_balance_vaporizer_weaponthrowable 0
+set g_balance_vaporizer_weaponthrowable 1
// }}}
// {{{ #13: Grappling Hook
set g_balance_hook_primary_ammo 5
alias -hook -button6
alias +jetpack +button10
alias -jetpack -button10
+alias +dodge +button11
+alias -dodge -button11
alias use "impulse 21"
// for backwards compatibility
seta cl_eventchase_mins "-12 -12 -8" "min size of eventchase camera bbox"
seta cl_eventchase_viewoffset "0 0 20" "viewoffset of eventchase camera"
seta cl_eventchase_generator_viewoffset "0 0 80" "viewoffset of eventchase camera while viewing generator explosion"
+seta cl_eventchase_vehicle 1 "camera goes into 3rd person mode when inside a vehicle"
+seta cl_eventchase_vehicle_viewoffset "0 0 80"
+seta cl_eventchase_vehicle_distance 250
+
+set _vehicles_shownchasemessage 0
//nifreks lockonrestart feature, used in team-based game modes, if set to 1 and all players readied up no other player can then join the game anymore, useful to block spectators from joining
set teamplay_lockonrestart 0 "lock teams once all players readied up and the game restarted (no new players can join after restart unless using the server-command unlockteams)"
set bot_ai_navigation_jetpack_mindistance 3500 "Bots will try fly to objects located farther than this distance"
// Better don't touch these, there are hard to tweak!
set bot_ai_aimskill_order_mix_1st 0.01 "Amount of the 1st filter output to apply to the aiming angle"
-set bot_ai_aimskill_order_mix_2nd 0.1 "Amount of the 1st filter output to apply to the aiming angle"
-set bot_ai_aimskill_order_mix_3th 0.01 "Amount of the 1st filter output to apply to the aiming angle"
-set bot_ai_aimskill_order_mix_4th 0.05 "Amount of the 1st filter output to apply to the aiming angle"
-set bot_ai_aimskill_order_mix_5th 0.01 "Amount of the 1st filter output to apply to the aiming angle"
+set bot_ai_aimskill_order_mix_2nd 0.1 "Amount of the 2nd filter output to apply to the aiming angle"
+set bot_ai_aimskill_order_mix_3th 0.01 "Amount of the 3th filter output to apply to the aiming angle"
+set bot_ai_aimskill_order_mix_4th 0.05 "Amount of the 4th filter output to apply to the aiming angle"
+set bot_ai_aimskill_order_mix_5th 0.01 "Amount of the 5th filter output to apply to the aiming angle"
set bot_ai_aimskill_order_filter_1st 0.4 "Position filter"
set bot_ai_aimskill_order_filter_2nd 0.4 "Movement filter"
set bot_ai_aimskill_order_filter_3th 0.2 "Acceleration filter"
seta g_waypointsprite_tactical 1 "tactical overlay on turrets when in a vehicle"
seta cl_damagetext "1" "Draw damage dealt where you hit the enemy"
-seta cl_damagetext_format "-{total}" "How to format the damage text. {health}, {armor}, {total}"
+seta cl_damagetext_format "-{total}" "How to format the damage text. {health}, {armor}, {total}, {potential}: full damage not capped to target's health, {potential_health}: health damage not capped to target's health"
+seta cl_damagetext_format_verbose 0 "{health} shows {potential_health} too when they differ; {total} shows {potential} too when they differ"
seta cl_damagetext_color "1 1 0" "Damage text color"
seta cl_damagetext_color_per_weapon "0" "Damage text uses weapon color"
seta cl_damagetext_size "8" "Damage text font size"
seta cl_damagetext_friendlyfire "1" "Show damage text for friendlyfire too"
seta cl_damagetext_friendlyfire_color "1 0 0" "Damage text color for friendlyfire"
-set sv_itemstime 1 "enable networking of left time until respawn for items such as mega health and large armor"
+seta cl_vehicles_alarm 1 "Play an alarm sound when the vehicle you are driving is heavily damaged"
+seta cl_vehicles_hud_tactical 1
+seta cl_vehicles_hudscale 0.5
+seta cl_vehicles_notify_time 15
+seta cl_vehicles_crosshair_size 0.5
+seta cl_vehicles_crosshair_colorize 1
+
+set sv_itemstime 1 "enable networking of time left until respawn for items such as mega health/armor and powerups"
// so it can be stuffcmd-ed still
set cl_gravity 800 "but ignored anyway"
// debug
set _independent_players 0 "DO NOT TOUCH"
set _notarget 0 "NO, REALLY, DON'T"
+set debugdraw 0
+set debugdraw_filter ""
+set debugdraw_filterout ""
+set debugtrace 0
// define some engine cvars that we need even on dedicated server
set r_showbboxes 0
set g_frozen_damage_trigger 1 "if 1, frozen players falling into the void will die instead of teleporting to spawn"
set g_frozen_force 0.6 "How much to multiply the force on a frozen player with"
-// player statistics server URI
+// player statistics
set g_playerstats_gamereport_uri "http://stats.xonotic.org/stats/submit" "Output player statistics information to either: URL (with ://), console (with a dash like this: -), or supply a filename to output to data directory."
+set g_playerstats_gamereport_ladder ""
+set g_playerstats_playerbasic_uri "http://stats.xonotic.org"
+set g_playerstats_playerdetail_uri "http://stats.xonotic.org/player/me"
+set g_playerstats_playerdetail_autoupdatetime 1800 // automatically update every 30 minutes anyway
// autoscreenshots
set g_max_info_autoscreenshot 3 "how many info_autoscreenshot entities are allowed"
set sv_minigames_snake_delay_multiplier 50 "Multiplier of incremental of movement speed (player_score / cvar)"
set sv_minigames_snake_delay_min 0.1 "Minimum delay between snake movement (at fastest rate)"
set sv_minigames_snake_lives 3
+
+
+// Bulldozer
+set sv_minigames_bulldozer_startlevel "level1"
set g_monsters_max 20
set g_monsters_max_perplayer 0
set g_monsters_armor_blockpercent 0.5
+set g_monsters_damageforcescale 0.8
+set g_monsters_quake_resize 1
+set g_monsters_healthbars 0
// }}}
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, if 2, clients can ignore this option"
+set g_spawn_near_teammate_ignore_spawnpoint_max 10 "if set, test at most this many of the available teammates"
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_delay_death 3 "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_spawn_near_teammate_ignore_spawnpoint_closetodeath 1 "spawn as close to death location as possible"
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_multijump_maxspeed 0
+set g_multijump_dodging 1
// ===========
set g_walljump_delay 1 "Minimum delay between wall jumps"
set g_walljump_force 300 "How far to bounce/jump off the wall"
set g_walljump_velocity_xy_factor 1.15 "How much to slow down along horizontal axis, higher value = higher deceleration, if factor is < 1, you accelerate by wall jumping"
-set g_walljump_velocity_z_factor 0.5 "Upwards velocity factor, multiplied by normal jump velocity"
\ No newline at end of file
+set g_walljump_velocity_z_factor 0.5 "Upwards velocity factor, multiplied by normal jump velocity"
+
+
+// ===============
+// global forces
+// ===============
+set g_globalforces 0 "Global forces: knockback affects everyone"
+set g_globalforces_noself 1 "Global forces: ignore self damage"
+set g_globalforces_self 1 "Global forces: knockback self scale"
+set g_globalforces_range 1000 "Global forces: max range of effect"
set g_physics_bones_airaccelerate 1
set g_physics_bones_airstopaccelerate 2.5
set g_physics_bones_track_canjump 0
+
+// ==========
+// Overkill
+// ==========
+set g_physics_overkill_airaccel_qw -0.8
+set g_physics_overkill_airstrafeaccel_qw -0.95
+set g_physics_overkill_airspeedlimit_nonqw 900
+set g_physics_overkill_maxspeed 400
+set g_physics_overkill_jumpvelocity 260
+set g_physics_overkill_maxairstrafespeed 100
+set g_physics_overkill_maxairspeed 360
+set g_physics_overkill_airstrafeaccelerate 24
+set g_physics_overkill_warsowbunny_turnaccel 0
+set g_physics_overkill_airaccel_qw_stretchfactor 2
+set g_physics_overkill_airaccel_sideways_friction 0
+set g_physics_overkill_aircontrol 125
+set g_physics_overkill_aircontrol_power 2
+set g_physics_overkill_aircontrol_backwards 0
+set g_physics_overkill_aircontrol_penalty 180
+set g_physics_overkill_warsowbunny_airforwardaccel 1.00001
+set g_physics_overkill_warsowbunny_topspeed 925
+set g_physics_overkill_warsowbunny_accel 0.1593
+set g_physics_overkill_warsowbunny_backtosideratio 0.8
+set g_physics_overkill_friction 8
+set g_physics_overkill_accelerate 15
+set g_physics_overkill_stopspeed 100
+set g_physics_overkill_airaccelerate 2
+set g_physics_overkill_airstopaccelerate 3
+set g_physics_overkill_track_canjump 0
float autocvar_crosshair_hitindication_speed;
bool autocvar_crosshair_hittest;
bool autocvar_crosshair_hittest_blur;
-float autocvar_crosshair_hittest_scale = 1.25;
+//float autocvar_crosshair_hittest_scale = 1.25;
bool autocvar_crosshair_hittest_showimpact;
bool autocvar_crosshair_per_weapon;
float autocvar_crosshair_pickup;
bool autocvar_hud_panel_infomessages_dynamichud = false;
bool autocvar_hud_panel_physics_dynamichud = true;
bool autocvar_hud_panel_centerprint_dynamichud = true;
-bool autocvar_hud_panel_itemstime_dynamichud = true;
+//bool autocvar_hud_panel_itemstime_dynamichud = true;
bool autocvar_hud_panel_healtharmor_hide_ondeath = false;
bool autocvar_hud_panel_ammo_hide_ondeath = false;
bool autocvar_hud_panel_powerups_hide_ondeath = false;
bool autocvar_developer_csqcentities;
float autocvar_g_jetpack_attenuation;
bool autocvar_cl_showspectators;
-string autocvar_crosshair_hmg = "";
-vector autocvar_crosshair_hmg_color = '0.2 1.0 0.2';
-float autocvar_crosshair_hmg_alpha = 1;
-float autocvar_crosshair_hmg_size = 1;
-string autocvar_crosshair_rpc = "";
-vector autocvar_crosshair_rpc_color = '0.2 1.0 0.2';
-float autocvar_crosshair_rpc_alpha = 1;
-float autocvar_crosshair_rpc_size = 1;
int autocvar_cl_nade_timer;
bool autocvar_r_drawviewmodel;
==================
*/
-vector HUD_Get_Num_Color (float x, float maxvalue)
+vector HUD_Get_Num_Color (float hp, float maxvalue)
{
float blinkingamt;
vector color;
- if(x >= maxvalue) {
+ if(hp >= maxvalue) {
color.x = sin(2*M_PI*time);
color.y = 1;
color.z = sin(2*M_PI*time);
}
- else if(x > maxvalue * 0.75) {
- color.x = 0.4 - (x-150)*0.02 * 0.4; //red value between 0.4 -> 0
- color.y = 0.9 + (x-150)*0.02 * 0.1; // green value between 0.9 -> 1
+ else if(hp > maxvalue * 0.75) {
+ color.x = 0.4 - (hp-150)*0.02 * 0.4; //red value between 0.4 -> 0
+ color.y = 0.9 + (hp-150)*0.02 * 0.1; // green value between 0.9 -> 1
color.z = 0;
}
- else if(x > maxvalue * 0.5) {
- color.x = 1 - (x-100)*0.02 * 0.6; //red value between 1 -> 0.4
- color.y = 1 - (x-100)*0.02 * 0.1; // green value between 1 -> 0.9
- color.z = 1 - (x-100)*0.02; // blue value between 1 -> 0
+ else if(hp > maxvalue * 0.5) {
+ color.x = 1 - (hp-100)*0.02 * 0.6; //red value between 1 -> 0.4
+ color.y = 1 - (hp-100)*0.02 * 0.1; // green value between 1 -> 0.9
+ color.z = 1 - (hp-100)*0.02; // blue value between 1 -> 0
}
- else if(x > maxvalue * 0.25) {
+ else if(hp > maxvalue * 0.25) {
color.x = 1;
color.y = 1;
- color.z = 0.2 + (x-50)*0.02 * 0.8; // blue value between 0.2 -> 1
+ color.z = 0.2 + (hp-50)*0.02 * 0.8; // blue value between 0.2 -> 1
}
- else if(x > maxvalue * 0.1) {
+ else if(hp > maxvalue * 0.1) {
color.x = 1;
- color.y = (x-20)*90/27/100; // green value between 0 -> 1
- color.z = (x-20)*90/27/100 * 0.2; // blue value between 0 -> 0.2
+ color.y = (hp-20)*90/27/100; // green value between 0 -> 1
+ color.z = (hp-20)*90/27/100 * 0.2; // blue value between 0 -> 0.2
}
else {
color.x = 1;
color.z = 0;
}
- blinkingamt = (1 - x/maxvalue/0.25);
+ blinkingamt = (1 - hp/maxvalue/0.25);
if(blinkingamt > 0)
{
color.x = color.x - color.x * blinkingamt * sin(2*M_PI*time);
drawsubpic(pos + eX * mySize.x - eX * min(mySize.x * 0.5, mySize.y), eX * min(mySize.x * 0.5, mySize.y) + eY * mySize.y, pic, '0.75 0 0', '0.25 1 0', color, theAlpha, drawflag);
}
-void DrawNumIcon_expanding(vector myPos, vector mySize, float x, string icon, bool vertical, int icon_right_align, vector color, float theAlpha, float fadelerp)
+void DrawNumIcon_expanding(vector myPos, vector mySize, float theTime, string icon, bool vertical, int icon_right_align, vector color, float theAlpha, float fadelerp)
{
TC(bool, vertical); TC(int, icon_right_align);
vector newPos = '0 0 0', newSize = '0 0 0';
// reduce only y to draw numbers with different number of digits with the same y size
numpos.y += newSize.y * ((1 - 0.7) / 2);
newSize.y *= 0.7;
- drawstring_aspect(numpos, ftos(x), newSize, color, panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL);
+ drawstring_aspect(numpos, ftos(theTime), newSize, color, panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL);
return;
}
// NOTE: newSize_x is always equal to 3 * mySize_y so we can use
// '2 1 0' * newSize_y instead of eX * (2/3) * newSize_x + eY * newSize_y
- drawstring_aspect_expanding(numpos, ftos(x), '2 1 0' * newSize.y, color, panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL, fadelerp);
+ drawstring_aspect_expanding(numpos, ftos(theTime), '2 1 0' * newSize.y, color, panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL, fadelerp);
drawpic_aspect_skin_expanding(picpos, icon, '1 1 0' * newSize.y, '1 1 1', panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL, fadelerp);
}
-void DrawNumIcon(vector myPos, vector mySize, float x, string icon, bool vertical, int icon_right_align, vector color, float theAlpha)
+void DrawNumIcon(vector myPos, vector mySize, float theTime, string icon, bool vertical, int icon_right_align, vector color, float theAlpha)
{
TC(bool, vertical); TC(int, icon_right_align);
- DrawNumIcon_expanding(myPos, mySize, x, icon, vertical, icon_right_align, color, theAlpha, 0);
+ DrawNumIcon_expanding(myPos, mySize, theTime, icon, vertical, icon_right_align, color, theAlpha, 0);
}
/*
void HUD_Radar_Hide_Maximized();
float HUD_GetRowCount(int item_count, vector size, float item_aspect);
-vector HUD_Get_Num_Color (float x, float maxvalue);
-void DrawNumIcon(vector myPos, vector mySize, float x, string icon, bool vertical, bool icon_right_align, vector color, float theAlpha);
-void DrawNumIcon_expanding(vector myPos, vector mySize, float x, string icon, bool vertical, int icon_right_align, vector color, float theAlpha, float fadelerp);
+vector HUD_Get_Num_Color (float hp, float maxvalue);
+void DrawNumIcon(vector myPos, vector mySize, float theTime, string icon, bool vertical, bool icon_right_align, vector color, float theAlpha);
+void DrawNumIcon_expanding(vector myPos, vector mySize, float theTime, string icon, bool vertical, int icon_right_align, vector color, float theAlpha, float fadelerp);
void HUD_Panel_DrawHighlight(vector pos, vector mySize, vector color, float theAlpha, int drawflag);
vector HUD_GetTableSize_BestItemAR(int item_count, vector psize, float item_aspect);
vector v;
v = healtharmor_maxdamage(health, armor, armorblockpercent, DEATH_WEAPON.m_id);
- float x;
- x = floor(v.x + 1);
+ float hp = floor(v.x + 1);
float maxtotal = maxhealth + maxarmor;
string biggercount;
{
biggercount = "health";
if(autocvar_hud_panel_healtharmor_progressbar)
- HUD_Panel_DrawProgressBar(pos, mySize, autocvar_hud_panel_healtharmor_progressbar_health, x/maxtotal, 0, (baralign == 1 || baralign == 2), autocvar_hud_progressbar_health_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+ HUD_Panel_DrawProgressBar(pos, mySize, autocvar_hud_panel_healtharmor_progressbar_health, hp/maxtotal, 0, (baralign == 1 || baralign == 2), autocvar_hud_progressbar_health_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
if(armor)
if(autocvar_hud_panel_healtharmor_text)
drawpic_aspect_skin(pos + eX * mySize.x - eX * 0.5 * mySize.y, "armor", '0.5 0.5 0' * mySize.y, '1 1 1', panel_fg_alpha * armor / health, DRAWFLAG_NORMAL);
{
biggercount = "armor";
if(autocvar_hud_panel_healtharmor_progressbar)
- HUD_Panel_DrawProgressBar(pos, mySize, autocvar_hud_panel_healtharmor_progressbar_armor, x/maxtotal, 0, (baralign == 1 || baralign == 2), autocvar_hud_progressbar_armor_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+ HUD_Panel_DrawProgressBar(pos, mySize, autocvar_hud_panel_healtharmor_progressbar_armor, hp/maxtotal, 0, (baralign == 1 || baralign == 2), autocvar_hud_progressbar_armor_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
if(health)
if(autocvar_hud_panel_healtharmor_text)
drawpic_aspect_skin(pos + eX * mySize.x - eX * 0.5 * mySize.y, "health", '0.5 0.5 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
}
if(autocvar_hud_panel_healtharmor_text)
- DrawNumIcon(pos, mySize, x, biggercount, 0, iconalign, HUD_Get_Num_Color(x, maxtotal), 1);
+ DrawNumIcon(pos, mySize, hp, biggercount, 0, iconalign, HUD_Get_Num_Color(hp, maxtotal), 1);
if(fuel)
HUD_Panel_DrawProgressBar(pos, eX * mySize.x + eY * 0.2 * mySize.y, "progressbar", fuel/100, 0, (baralign == 1 || baralign == 3), autocvar_hud_progressbar_fuel_color, panel_fg_alpha * 0.8, DRAWFLAG_NORMAL);
InfoMessage(s);
}
- if(gametype == MAPINFO_TYPE_LMS)
+ if(!warmup_stage && gametype == MAPINFO_TYPE_LMS)
{
entity sk;
sk = playerslots[player_localnum];
// provide basic panel cvars to old clients
// TODO remove them after a future release (0.8.2+)
-string autocvar_hud_panel_scoreboard_pos = "0.150000 0.150000";
-string autocvar_hud_panel_scoreboard_size = "0.700000 0.700000";
-string autocvar_hud_panel_scoreboard_bg = "border_default";
-string autocvar_hud_panel_scoreboard_bg_color = "0 0.3 0.5";
-string autocvar_hud_panel_scoreboard_bg_color_team = "";
-string autocvar_hud_panel_scoreboard_bg_alpha = "0.7";
-string autocvar_hud_panel_scoreboard_bg_border = "";
-string autocvar_hud_panel_scoreboard_bg_padding = "";
+noref string autocvar_hud_panel_scoreboard_pos = "0.150000 0.150000";
+noref string autocvar_hud_panel_scoreboard_size = "0.700000 0.700000";
+noref string autocvar_hud_panel_scoreboard_bg = "border_default";
+noref string autocvar_hud_panel_scoreboard_bg_color = "0 0.3 0.5";
+noref string autocvar_hud_panel_scoreboard_bg_color_team = "";
+noref string autocvar_hud_panel_scoreboard_bg_alpha = "0.7";
+noref string autocvar_hud_panel_scoreboard_bg_border = "";
+noref string autocvar_hud_panel_scoreboard_bg_padding = "";
float autocvar_hud_panel_scoreboard_fadeinspeed = 10;
float autocvar_hud_panel_scoreboard_fadeoutspeed = 5;
bool autocvar_hud_panel_scoreboard_dynamichud = false;
-float autocvar_hud_panel_scoreboard_maxheight = 0.5;
+float autocvar_hud_panel_scoreboard_maxheight = 0.6;
bool autocvar_hud_panel_scoreboard_others_showscore = true;
bool autocvar_hud_panel_scoreboard_spectators_showping = true;
bool autocvar_hud_panel_scoreboard_spectators_aligned = false;
case SP_DMG: case SP_DMGTAKEN:
return sprintf("%.1f k", pl.(scores(field)) / 1000);
- default:
+ default: case SP_SCORE:
tmp = pl.(scores(field));
f = scores_flags(field);
if(field == ps_primary)
field = Scoreboard_GetField(pl, SP_PING);
}
else if(autocvar_hud_panel_scoreboard_others_showscore)
- field = ftos(pl.(scores(ps_primary)));
+ field = Scoreboard_GetField(pl, SP_SCORE);
string str = textShortenToWidth(entcs_GetName(pl.sv_entnum), namesize, hud_fontsize, stringwidth_colors);
float column_width = stringwidth(str, true, hud_fontsize);
int max_players = 999;
if(autocvar_hud_panel_scoreboard_maxheight > 0)
{
- max_players = autocvar_hud_panel_scoreboard_maxheight * vid_conheight;
+ float height = autocvar_hud_panel_scoreboard_maxheight * vid_conheight;
if(teamplay)
- max_players = (max_players - hud_fontsize.y * 1.25 - panel_bg_padding * 2) / 2;
- max_players = floor(max_players / (hud_fontsize.y * 1.25));
+ {
+ height -= (panel_bg_padding * 2 + hud_fontsize.y * 1.25) * team_count; // - padding and header
+ height -= hud_fontsize.y * (team_count - 1); // - spacing between tables
+ height /= team_count;
+ }
+ else
+ height -= panel_bg_padding * 2; // - padding
+ max_players = floor(height / (hud_fontsize.y * 1.25));
if(max_players <= 1)
max_players = 1;
if(max_players == tm.team_size)
int weapon_stats = weapon_accuracy[i - WEP_FIRST];
WepSet set = it.m_wepset;
- if (weapon_stats < 0)
+ if (weapon_stats < 0 && !((weapons_stat & set) || (weapons_inmap & set)))
{
- if (!(weapons_stat & set) && (it.spawnflags & WEP_FLAG_HIDDEN || it.spawnflags & WEP_FLAG_MUTATORBLOCKED))
- nHidden += 1;
- else if (!(weapons_stat & set || weapons_inmap & set))
+ if (((it.spawnflags & WEP_FLAG_HIDDEN) || (it.spawnflags & WEP_FLAG_MUTATORBLOCKED)))
+ ++nHidden;
+ else
++disownedcnt;
}
});
int weapon_stats = weapon_accuracy[i - WEP_FIRST];
WepSet set = it.m_wepset;
- if (weapon_stats < 0 && !(weapons_stat & set || weapons_inmap & set))
+ if (weapon_stats < 0 && !((weapons_stat & set) || (weapons_inmap & set)))
continue;
float weapon_alpha;
void DrawCircleClippedPic(vector centre, float radi, string pic, float f, vector rgb, float a, float drawflag)
{
- float x, y, q, d;
+ float d;
vector ringsize, v, t;
ringsize = radi * '1 1 0';
- x = cos(f * 2 * M_PI);
- y = sin(f * 2 * M_PI);
- q = fabs(x) + fabs(y);
- x /= q;
- y /= q;
+ float co = cos(f * 2 * M_PI);
+ float si = sin(f * 2 * M_PI);
+ float q = fabs(co) + fabs(si);
+ co /= q;
+ si /= q;
if(f >= 1)
{
if(d > 0)
{
v = centre; t = '0.5 0.5 0';
- v.x += x * 0.5 * ringsize.x; t += x * '0.5 0.5 0';
- v.y += y * 0.5 * ringsize.y; t += y * '0.5 -0.5 0';
+ v.x += co * 0.5 * ringsize.x; t += co * '0.5 0.5 0';
+ v.y += si * 0.5 * ringsize.y; t += si * '0.5 -0.5 0';
R_PolygonVertex(v, t, rgb, a);
R_EndPolygon();
}
hit = !(trace_fraction < 1 && (trace_networkentity != this.sv_entnum && trace_ent.entnum != this.sv_entnum));
}
// handle tag fading
- bool overlap = false;
+ int overlap = -1;
vector o = project_3d_to_2d(this.origin + eZ * autocvar_hud_shownames_offset);
+ if (autocvar_hud_shownames_crosshairdistance)
+ {
+ float d = autocvar_hud_shownames_crosshairdistance;
+ float w = o.x - vid_conwidth / 2;
+ float h = o.y - vid_conheight / 2;
+ if (d * d > w * w + h * h) this.pointtime = time;
+ if (this.pointtime + autocvar_hud_shownames_crosshairdistance_time <= time)
+ overlap = 1;
+ else if(!autocvar_hud_shownames_crosshairdistance_antioverlap)
+ overlap = 0;
+ }
+
float dist = vlen(this.origin - view_origin);
- if (autocvar_hud_shownames_antioverlap)
+ if (overlap == -1 && autocvar_hud_shownames_antioverlap)
{
// fade tag out if another tag that is closer to you overlaps
- LL_EACH(shownames_ent, it != this && entcs_receiver(i), {
+ entity entcs = NULL;
+ LL_EACH(shownames_ent, it != this, {
+ entcs = entcs_receiver(i);
+ if (!(entcs && entcs.has_sv_origin))
+ continue;
vector eo = project_3d_to_2d(it.origin);
if (eo.z < 0 || eo.x < 0 || eo.y < 0 || eo.x > vid_conwidth || eo.y > vid_conheight) continue;
eo.z = 0;
if (vdist(((eX * o.x + eY * o.y) - eo), <, autocvar_hud_shownames_antioverlap_distance)
&& vdist((it.origin - view_origin), <, dist))
{
- overlap = true;
+ overlap = 1;
break;
}
});
}
bool onscreen = (o.z >= 0 && o.x >= 0 && o.y >= 0 && o.x <= vid_conwidth && o.y <= vid_conheight);
- if (autocvar_hud_shownames_crosshairdistance)
- {
- float d = autocvar_hud_shownames_crosshairdistance;
- float w = o.x - vid_conwidth / 2;
- float h = o.y - vid_conheight / 2;
- if (d * d > w * w + h * h) this.pointtime = time;
- if (this.pointtime + autocvar_hud_shownames_crosshairdistance_time <= time) overlap = true;
- else overlap = (autocvar_hud_shownames_crosshairdistance_antioverlap ? overlap : false); // override what antioverlap says unless allowed by cvar.
- }
if (!this.fadedelay) this.fadedelay = time + SHOWNAMES_FADEDELAY;
if (this.csqcmodel_isdead) // dead player, fade out slowly
{
this.alpha = max(0, this.alpha - SHOWNAMES_FADESPEED * frametime);
this.fadedelay = 0; // reset fade in delay, enemy has left the view
}
- else if (overlap) // tag overlap detected, fade out
+ else if (overlap > 0) // tag overlap detected, fade out
{
this.alpha = max(0, this.alpha - SHOWNAMES_FADESPEED * frametime);
}
return out;
}
-vector teamradar_texcoord_to_3dcoord(vector in,float z)
+vector teamradar_texcoord_to_3dcoord(vector in,float oz)
{
vector out;
out_x = in_x * (mi_picmax_x - mi_picmin_x) + mi_picmin_x;
out_y = in_y * (mi_picmax_y - mi_picmin_y) + mi_picmin_y;
- out_z = z;
+ out_z = oz;
return out;
}
vector teamradar_texcoord_to_2dcoord(vector in);
-vector teamradar_texcoord_to_3dcoord(vector in,float z);
+vector teamradar_texcoord_to_3dcoord(vector in,float oz);
void draw_teamradar_background(float fg);
float frac;
vector gunorg = '0 0 0';
static vector vel_average;
- static vector gunorg_prev = '0 0 0';
static vector gunorg_adjustment_highpass;
static vector gunorg_adjustment_lowpass;
{
static string name_last;
string name = wep.mdl;
- if(wep == WEP_TUBA)
- {
- name = (this.tuba_instrument == 0) ? "tuba" :
- (this.tuba_instrument == 1) ? "akordeon" :
- "kleinbottle";
- }
+ string newname = wep.wr_viewmodel(wep, this);
+ if(newname)
+ name = newname;
bool swap = name != name_last;
// if (swap)
{
float a = autocvar_cl_hitsound_max_pitch;
float b = autocvar_cl_hitsound_min_pitch;
float c = autocvar_cl_hitsound_nom_damage;
- float x = unaccounted_damage;
- float pitch_shift = (b*x*(a-1) + a*c*(1-b)) / (x*(a-1) + c*(1-b));
+ float d = unaccounted_damage;
+ float pitch_shift = (b*d*(a-1) + a*c*(1-b)) / (d*(a-1) + c*(1-b));
// if sound variation is disabled, set pitch_shift to 1
if (autocvar_cl_hitsound == 1)
case 2: // crosshair_color_by_health
{
- float x = health_stat;
+ float hp = health_stat;
//x = red
//y = green
wcross_color.z = 0;
- if(x > 200)
+ if(hp > 200)
{
wcross_color.x = 0;
wcross_color.y = 1;
}
- else if(x > 150)
+ else if(hp > 150)
{
- wcross_color.x = 0.4 - (x-150)*0.02 * 0.4;
- wcross_color.y = 0.9 + (x-150)*0.02 * 0.1;
+ wcross_color.x = 0.4 - (hp-150)*0.02 * 0.4;
+ wcross_color.y = 0.9 + (hp-150)*0.02 * 0.1;
}
- else if(x > 100)
+ else if(hp > 100)
{
- wcross_color.x = 1 - (x-100)*0.02 * 0.6;
- wcross_color.y = 1 - (x-100)*0.02 * 0.1;
- wcross_color.z = 1 - (x-100)*0.02;
+ wcross_color.x = 1 - (hp-100)*0.02 * 0.6;
+ wcross_color.y = 1 - (hp-100)*0.02 * 0.1;
+ wcross_color.z = 1 - (hp-100)*0.02;
}
- else if(x > 50)
+ else if(hp > 50)
{
wcross_color.x = 1;
wcross_color.y = 1;
- wcross_color.z = 0.2 + (x-50)*0.02 * 0.8;
+ wcross_color.z = 0.2 + (hp-50)*0.02 * 0.8;
}
- else if(x > 20)
+ else if(hp > 20)
{
wcross_color.x = 1;
- wcross_color.y = (x-20)*90/27/100;
- wcross_color.z = (x-20)*90/27/100 * 0.2;
+ wcross_color.y = (hp-20)*90/27/100;
+ wcross_color.z = (hp-20)*90/27/100 * 0.2;
}
else
{
-float autocvar_net_connecttimeout = 30;
+noref float autocvar_net_connecttimeout = 30;
#ifdef GAMEQC
#include "anim.qc"
const int FRAGS_PLAYER = 0;
const int FRAGS_SPECTATOR = -666;
const int FRAGS_LMS_LOSER = -616;
-const int FRAGS_PLAYER_NONSOLID = -616;
+const int FRAGS_PLAYER_NONSOLID = FRAGS_LMS_LOSER;
// we can use this frags value for both
// water levels
const int SERVERFLAG_TEAMPLAY = 2;
const int SERVERFLAG_PLAYERSTATS = 4;
+#ifdef SVQC
// FIXME/EXPLAINME: why? Mario: because
vector autocvar_sv_player_maxs = '16 16 45';
vector autocvar_sv_player_mins = '-16 -16 -24';
vector autocvar_sv_player_crouch_maxs = '16 16 25';
vector autocvar_sv_player_crouch_mins = '-16 -16 -24';
vector autocvar_sv_player_crouch_viewoffset = '0 0 20';
-vector autocvar_sv_player_headsize = '24 24 12';
+//vector autocvar_sv_player_headsize = '24 24 12';
+#endif
// a bit more constant
entity player = this.owner;
sf |= BIT(0); // assume private
do {
+ if (!(IS_PLAYER(player)))
+ {
+ sf &= ENTCS_PUBLICMASK; // no private updates
+ break;
+ }
if (radar_showennemies) break;
if (SAME_TEAM(to, player)) break;
if (!(IS_PLAYER(to) || to.caplayer) && time > game_starttime) break;
{
int n = ReadByte();
entity e = entcs_receiver(n);
- #define X(e) { \
- setthink(e, entcs_think); \
- entcs_receiver(n, e); \
- }
if (e == NULL)
{
if (!this)
- {
// initial = temp
e = new_pure(entcs_receiver);
- X(e);
- }
else
- {
// initial = linked
e = this;
- X(e);
- }
+ setthink(e, entcs_think);
+ entcs_receiver(n, e);
}
else if (e != this && this)
{
// upgrade to linked
delete(e);
e = this;
- X(e);
+ setthink(e, entcs_think);
+ entcs_receiver(n, e);
}
- #undef X
+
InterpolateOrigin_Undo(e);
e.sv_entnum = n;
int sf = ReadShort();
#pragma once
+#include <common/t_items.qh>
const int IT_UNLIMITED_WEAPON_AMMO = BIT(0); // when this bit is set, using a weapon does not reduce ammo. Checkpoints can give this powerup.
const int IT_UNLIMITED_SUPERWEAPONS = BIT(1); // when this bit is set, superweapons don't expire. Checkpoints can give this powerup.
ATTRIB(GameItem, m_color, vector, '1 1 1');
ATTRIB(GameItem, m_waypoint, string);
ATTRIB(GameItem, m_waypointblink, int, 1);
+#ifdef GAMEQC
+ ATTRIB(GameItem, m_glow, bool, false);
+ ATTRIB(GameItem, m_respawnsound, Sound, SND_ITEMRESPAWN);
+#endif
METHOD(GameItem, display, void(GameItem this, void(string name, string icon) returns))
{
TC(GameItem, this);
this.m_waypoint = _("Mega armor");
this.m_waypointblink = 2;
#ifdef SVQC
+ this.m_maxs = '16 16 70';
this.m_botvalue = BOT_PICKUP_RATING_HIGH;
this.m_itemid = IT_ARMOR;
this.m_respawntime = GET(g_pickup_respawntime_long);
this.m_waypoint = _("Mega health");
this.m_waypointblink = 2;
#ifdef SVQC
+ this.m_maxs = '16 16 70';
this.m_botvalue = BOT_PICKUP_RATING_HIGH;
this.m_itemid = IT_HEALTH;
this.m_respawntime = GET(g_pickup_respawntime_long);
CLASS(Powerup, Pickup)
#ifdef SVQC
ATTRIB(Powerup, m_mins, vector, '-16 -16 0');
- ATTRIB(Powerup, m_maxs, vector, '16 16 48');
+ ATTRIB(Powerup, m_maxs, vector, '16 16 80');
ATTRIB(Powerup, m_botvalue, int, 100000);
ATTRIB(Powerup, m_itemflags, int, FL_POWERUP);
ATTRIB(Powerup, m_respawntime, float(), GET(g_pickup_respawntime_powerup));
#ifdef GAMEQC
this.m_model = MDL_Strength_ITEM;
this.m_sound = SND_Strength;
+ this.m_glow = true;
+ this.m_respawnsound = SND_STRENGTH_RESPAWN;
#endif
this.m_name = "Strength Powerup";
this.m_icon = "strength";
#ifdef GAMEQC
this.m_model = MDL_Shield_ITEM;
this.m_sound = SND_Shield;
+ this.m_glow = true;
+ this.m_respawnsound = SND_SHIELD_RESPAWN;
#endif
this.m_name = "Shield";
this.m_icon = "shield";
const int BD_DIR_LF = 2;
const int BD_DIR_RT = 3;
+#ifdef SVQC
string autocvar_sv_minigames_bulldozer_startlevel = "level1";
+#endif
// find same game piece given its tile name
entity bd_find_piece(entity minig, string tile, bool check_target)
float autocvar_sv_minigames_snake_delay_initial = 0.7;
float autocvar_sv_minigames_snake_delay_multiplier = 50;
float autocvar_sv_minigames_snake_delay_min = 0.1;
+#ifdef SVQC
int autocvar_sv_minigames_snake_lives = 3;
+#endif
.int snake_score;
const int MON_FLAG_RIDE = BIT(12); // monster can be ridden in special modes
const int MONSTER_SIZE_QUAKE = BIT(13);
const int MONSTER_TYPE_PASSIVE = BIT(14); // doesn't target or chase enemies
+const int MONSTER_TYPE_UNDEAD = BIT(15); // monster is by most definitions a zombie (doesn't fully die unless gibbed)
// entity properties of monsterinfo:
.bool(int, entity actor, entity targ) monster_attackfunc;
#endif
CLASS(Zombie, Monster)
- ATTRIB(Zombie, spawnflags, int, MON_FLAG_MELEE | MON_FLAG_RIDE);
+ ATTRIB(Zombie, spawnflags, int, MONSTER_TYPE_UNDEAD | MON_FLAG_MELEE | MON_FLAG_RIDE);
ATTRIB(Zombie, mins, vector, '-18 -18 -25');
ATTRIB(Zombie, maxs, vector, '18 18 47');
#ifdef GAMEQC
}
// Monster_Spawn checks if monster is valid
- Monster_Spawn(e, false, monster_id);
+ if(!Monster_Spawn(e, false, monster_id))
+ {
+ delete(e);
+ return NULL; // remove even if told not to, as we didn't spawn any kind of monster
+ }
return e;
}
this.skin = buff.m_skin;
setmodel(this, MDL_BUFF);
+ setsize(this, BUFF_MIN, BUFF_MAX);
if(this.buff_waypoint)
{
});
}
-float buff_Inferno_CalculateTime(float x, float offset_x, float offset_y, float intersect_x, float intersect_y, float base)
+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(((x - offset_x) * ((base - 1) / intersect_x)) + 1, base);
+ return offset_y + (intersect_y - offset_y) * logn(((damg - offset_x) * ((base - 1) / intersect_x)) + 1, base);
}
// mutator hooks
if(player.buffs & BUFF_MAGNET.m_itemid)
{
vector pickup_size;
- IL_EACH(g_items, it.classname != "item_flag_team" && it.classname != "item_kh_key",
+ IL_EACH(g_items, it.itemdef,
{
if(it.buffs)
pickup_size = '1 1 1' * autocvar_g_buffs_magnet_range_buff;
.int oldbuffs; // for updating effects
.entity buff_model; // controls effects (TODO: make csqc)
-const vector BUFF_MIN = ('-16 -16 -20');
-const vector BUFF_MAX = ('16 16 20');
+const vector BUFF_MIN = ('-16 -16 0');
+const vector BUFF_MAX = ('16 16 60');
// client side options
.float cvar_cl_buffs_autoreplace;
#define DAMAGETEXT_PRECISION_MULTIPLIER 128
#define DAMAGETEXT_SHORT_LIMIT 256 // the smallest value that we can't send as short - 2^15 (signed short) / DAMAGETEXT_PRECISION_MULTIPLIER
+const int DTFLAG_SAMETEAM = BIT(0);
+const int DTFLAG_BIG_HEALTH = BIT(1);
+const int DTFLAG_BIG_ARMOR = BIT(2);
+const int DTFLAG_BIG_POTENTIAL = BIT(3);
+const int DTFLAG_NO_ARMOR = BIT(4);
+const int DTFLAG_NO_POTENTIAL = BIT(5);
+
REGISTER_MUTATOR(damagetext, true);
-#if defined(CSQC) || defined(MENUQC)
+// || defined(MENUQC)
+#if defined(CSQC)
// no translatable cvar description please
AUTOCVAR_SAVE(cl_damagetext, bool, true, "Draw damage dealt where you hit the enemy");
-AUTOCVAR_SAVE(cl_damagetext_format, string, "-{total}", "How to format the damage text. {health}, {armor}, {total}");
+AUTOCVAR_SAVE(cl_damagetext_format, string, "-{total}", "How to format the damage text. {health}, {armor}, {total}, {potential}: full damage not capped to target's health, {potential_health}: health damage not capped to target's health");
+AUTOCVAR_SAVE(cl_damagetext_format_verbose, bool, false, "{health} shows {potential_health} too when they differ; {total} shows {potential} too when they differ");
STATIC_INIT(DamageText_LegacyFormat) {
if (strstrofs(autocvar_cl_damagetext_format, "{", 0) < 0) autocvar_cl_damagetext_format = "-{total}";
}
ATTRIB(DamageText, m_friendlyfire, bool, false);
ATTRIB(DamageText, m_damage, int, 0);
ATTRIB(DamageText, m_armordamage, int, 0);
+ ATTRIB(DamageText, m_potential_damage, int, 0);
ATTRIB(DamageText, m_deathtype, int, 0);
ATTRIB(DamageText, time_prev, float, time);
Weapon w = DEATH_WEAPONOF(this.m_deathtype);
if (w != WEP_Null) rgb = w.wpcolor;
}
+ int health = rint(this.m_damage / DAMAGETEXT_PRECISION_MULTIPLIER);
+ int total = rint((this.m_damage + this.m_armordamage) / DAMAGETEXT_PRECISION_MULTIPLIER);
+ int potential = rint(this.m_potential_damage / DAMAGETEXT_PRECISION_MULTIPLIER);
+ int potential_health = rint((this.m_potential_damage - this.m_armordamage) / DAMAGETEXT_PRECISION_MULTIPLIER);
+
string s = autocvar_cl_damagetext_format;
- s = strreplace("{health}", sprintf("%d", rint(this.m_damage / DAMAGETEXT_PRECISION_MULTIPLIER)), s);
s = strreplace("{armor}", sprintf("%d", rint(this.m_armordamage / DAMAGETEXT_PRECISION_MULTIPLIER)), s);
- s = strreplace("{total}", sprintf("%d", rint((this.m_damage + this.m_armordamage) / DAMAGETEXT_PRECISION_MULTIPLIER)), s);
+ s = strreplace("{potential}", sprintf("%d", potential), s);
+ s = strreplace("{potential_health}", sprintf("%d", potential_health), s);
+
+ s = strreplace("{health}", (
+ (health == potential_health || !autocvar_cl_damagetext_format_verbose)
+ ? sprintf("%d", health)
+ : sprintf("%d (%d)", health, potential_health)
+ ), s);
+ s = strreplace("{total}", (
+ (total == potential || !autocvar_cl_damagetext_format_verbose)
+ ? sprintf("%d", total)
+ : sprintf("%d (%d)", total, potential)
+ ), s);
drawcolorcodedstring2_builtin(pos, s, this.m_size * '1 1 0', rgb, this.alpha, DRAWFLAG_NORMAL);
}
}
ATTRIB(DamageText, draw2d, void(DamageText), DamageText_draw2d);
- void DamageText_update(DamageText this, vector _origin, int _health, int _armor, int _deathtype) {
+ void DamageText_update(DamageText this, vector _origin, int _health, int _armor, int _potential_damage, int _deathtype) {
this.m_damage = _health;
this.m_armordamage = _armor;
+ this.m_potential_damage = _potential_damage;
this.m_deathtype = _deathtype;
setorigin(this, _origin);
this.alpha = autocvar_cl_damagetext_alpha_start;
}
- CONSTRUCTOR(DamageText, int _group, vector _origin, int _health, int _armor, int _deathtype, bool _friendlyfire) {
+ CONSTRUCTOR(DamageText, int _group, vector _origin, int _health, int _armor, int _potential_damage, int _deathtype, bool _friendlyfire) {
CONSTRUCT(DamageText);
this.m_group = _group;
this.m_friendlyfire = _friendlyfire;
- DamageText_update(this, _origin, _health, _armor, _deathtype);
+ DamageText_update(this, _origin, _health, _armor, _potential_damage, _deathtype);
IL_PUSH(g_drawables_2d, this);
}
ENDCLASS(DamageText)
const float health = M_ARGV(2, float);
const float armor = M_ARGV(3, float);
const int deathtype = M_ARGV(5, int);
+ const float potential_damage = M_ARGV(6, float);
const vector location = hit.origin;
FOREACH_CLIENT(IS_REAL_CLIENT(it), LAMBDA(
if (
(SV_DAMAGETEXT_SPECTATORS_ONLY() && IS_SPEC(it) && it.enemy == attacker) ||
(SV_DAMAGETEXT_SPECTATORS_ONLY() && IS_OBSERVER(it))
) {
- int flags = SAME_TEAM(hit, attacker); // BIT(0)
- if (health >= DAMAGETEXT_SHORT_LIMIT) flags |= BIT(1);
- if (armor >= DAMAGETEXT_SHORT_LIMIT) flags |= BIT(2);
+ int flags = 0;
+ if (SAME_TEAM(hit, attacker)) flags |= DTFLAG_SAMETEAM;
+ if (health >= DAMAGETEXT_SHORT_LIMIT) flags |= DTFLAG_BIG_HEALTH;
+ if (armor >= DAMAGETEXT_SHORT_LIMIT) flags |= DTFLAG_BIG_ARMOR;
+ if (potential_damage >= DAMAGETEXT_SHORT_LIMIT) flags |= DTFLAG_BIG_POTENTIAL;
+ if (!armor) flags |= DTFLAG_NO_ARMOR;
+ if (fabs((armor + health) - potential_damage) < 0.0001) flags |= DTFLAG_NO_POTENTIAL;
msg_entity = it;
WriteHeader(MSG_ONE, damagetext);
// we need to send a few decimal places to minimize errors when accumulating damage
// sending them multiplied saves bandwidth compared to using WriteCoord,
// however if the multiplied damage would be too much for (signed) short, we send an int24
- if (health >= DAMAGETEXT_SHORT_LIMIT) WriteInt24_t(MSG_ONE, health * DAMAGETEXT_PRECISION_MULTIPLIER);
+ if (flags & DTFLAG_BIG_HEALTH) WriteInt24_t(MSG_ONE, health * DAMAGETEXT_PRECISION_MULTIPLIER);
else WriteShort(MSG_ONE, health * DAMAGETEXT_PRECISION_MULTIPLIER);
- if (armor >= DAMAGETEXT_SHORT_LIMIT) WriteInt24_t(MSG_ONE, armor * DAMAGETEXT_PRECISION_MULTIPLIER);
- else WriteShort(MSG_ONE, armor * DAMAGETEXT_PRECISION_MULTIPLIER);
+ if (!(flags & DTFLAG_NO_ARMOR))
+ {
+ if (flags & DTFLAG_BIG_ARMOR) WriteInt24_t(MSG_ONE, armor * DAMAGETEXT_PRECISION_MULTIPLIER);
+ else WriteShort(MSG_ONE, armor * DAMAGETEXT_PRECISION_MULTIPLIER);
+ }
+ if (!(flags & DTFLAG_NO_POTENTIAL))
+ {
+ if (flags & DTFLAG_BIG_POTENTIAL) WriteInt24_t(MSG_ONE, potential_damage * DAMAGETEXT_PRECISION_MULTIPLIER);
+ else WriteShort(MSG_ONE, potential_damage * DAMAGETEXT_PRECISION_MULTIPLIER);
+ }
}
));
}
vector location = vec3(ReadCoord(), ReadCoord(), ReadCoord());
int deathtype = ReadInt24_t();
int flags = ReadByte();
- bool friendlyfire = flags & 1;
+ bool friendlyfire = flags & DTFLAG_SAMETEAM;
- int health, armor;
- if (flags & BIT(1)) health = ReadInt24_t();
+ int health, armor, potential_damage;
+ if (flags & DTFLAG_BIG_HEALTH) health = ReadInt24_t();
else health = ReadShort();
- if (flags & BIT(2)) armor = ReadInt24_t();
+ if (flags & DTFLAG_NO_ARMOR) armor = 0;
+ else if (flags & DTFLAG_BIG_ARMOR) armor = ReadInt24_t();
else armor = ReadShort();
+ if (flags & DTFLAG_NO_POTENTIAL) potential_damage = health + armor;
+ else if (flags & DTFLAG_BIG_POTENTIAL) potential_damage = ReadInt24_t();
+ else potential_damage = ReadShort();
return = true;
if (autocvar_cl_damagetext) {
if (autocvar_cl_damagetext_accumulate_range) {
for (entity e = findradius(location, autocvar_cl_damagetext_accumulate_range); e; e = e.chain) {
if (e.instanceOfDamageText && e.m_group == group && e.alpha > autocvar_cl_damagetext_accumulate_alpha_rel * autocvar_cl_damagetext_alpha_start) {
- DamageText_update(e, location, e.m_damage + health, e.m_armordamage + armor, deathtype);
+ DamageText_update(e, location, e.m_damage + health, e.m_armordamage + armor, e.m_potential_damage + potential_damage, deathtype);
return;
}
}
}
- make_impure(NEW(DamageText, group, location, health, armor, deathtype, friendlyfire));
+ make_impure(NEW(DamageText, group, location, health, armor, potential_damage, deathtype, friendlyfire));
}
}
#endif
setDependent(e, "cl_damagetext", 1, 1);
this.TR(this);
this.TR(this);
+ // friendly fire
this.TD(this, 1, 3, e = makeXonoticCheckBox(0, "cl_damagetext_friendlyfire", _("Draw damage numbers for friendly fire")));
setDependent(e, "cl_damagetext", 1, 1);
this.TR(this);
return IS_ONGROUND(this) ? true : false;
}
-float PM_dodging_checkpressedkeys(entity this)
+bool PM_dodging_checkpressedkeys(entity this)
{
if(!PHYS_DODGING)
return false;
- float frozen_dodging = (PHYS_FROZEN(this) && PHYS_DODGING_FROZEN(this));
- float frozen_no_doubletap = (frozen_dodging && !PHYS_DODGING_FROZEN_NODOUBLETAP);
+ bool frozen_dodging = (PHYS_FROZEN(this) && PHYS_DODGING_FROZEN(this));
+ bool frozen_no_doubletap = (frozen_dodging && !PHYS_DODGING_FROZEN_NODOUBLETAP);
// first check if the last dodge is far enough back in time so we can dodge again
if ((time - this.last_dodging_time) < PHYS_DODGING_DELAY)
if(!(PHYS_DODGING_PRESSED_KEYS(this) & KEY_##BTN) || frozen_no_doubletap) { \
tap_direction_##RESULT; \
if ((time - this.last_##BTN##_KEY_time) < PHYS_DODGING_TIMEOUT(this) || frozen_no_doubletap) \
- dodge_detected = true; \
+ dodge_detected = true; \
+ if(PHYS_INPUT_BUTTON_DODGE(this)) \
+ dodge_detected = true; \
this.last_##BTN##_KEY_time = time; \
}
X(x < 0, BACKWARD, x--);
start_items |= IT_UNLIMITED_SUPERWEAPONS;
}
+MUTATOR_HOOKFUNCTION(mutator_instagib, SetWeaponArena)
+{
+ // turn weapon arena off
+ M_ARGV(0, string) = "off";
+}
+
void replace_with_insta_cells(entity item)
{
entity e = spawn();
start_weapons = warmup_start_weapons = WEPSET(SHOTGUN);
}
+MUTATOR_HOOKFUNCTION(melee_only, SetWeaponArena)
+{
+ // turn weapon arena off
+ M_ARGV(0, string) = "off";
+}
+
MUTATOR_HOOKFUNCTION(melee_only, ForbidThrowCurrentWeapon)
{
return true;
{
entity item = M_ARGV(0, entity);
- switch (item.items)
+ switch (item.itemdef)
{
- case ITEM_HealthSmall.m_itemid:
- case ITEM_ArmorSmall.m_itemid:
+ case ITEM_HealthSmall:
+ case ITEM_ArmorSmall:
return false;
}
REGISTER_MUTATOR(nades, cvar("g_nades"));
.float nade_time_primed;
+.float nade_lifetime;
.entity nade_spawnloc;
+
void nade_timer_think(entity this)
{
- this.skin = 8 - (this.owner.wait - time) / (autocvar_g_nades_nade_lifetime / 10);
+ this.skin = 8 - (this.owner.wait - time) / (this.owner.nade_lifetime / 10);
this.nextthink = time;
if(!this.owner || wasfreed(this.owner))
delete(this);
if(this.health == this.max_health)
{
sound(this, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, 0.5 *(ATTEN_LARGE + ATTEN_MAX));
- this.nextthink = max(time + autocvar_g_nades_nade_lifetime, time);
+ this.nextthink = max(time + this.nade_lifetime, time);
setthink(this, nade_beep);
}
setthink(n, nade_beep);
n.nextthink = max(n.wait - 3, time);
n.projectiledeathtype = DEATH_NADE.m_id;
+ n.nade_lifetime = ntime;
setmodel(fn, MDL_NADE_VIEW);
.entity weaponentity = weaponentities[0]; // TODO: unhardcode
METHOD(NadeOffhand, offhand_think, void(NadeOffhand this, entity player, bool key_pressed))
{
entity held_nade = player.nade;
- if (held_nade)
- {
- player.nade_timer = bound(0, (time - held_nade.nade_time_primed) / autocvar_g_nades_nade_lifetime, 1);
- // LOG_TRACEF("%d %d", player.nade_timer, time - held_nade.nade_time_primed);
- makevectors(player.angles);
- held_nade.velocity = player.velocity;
- setorigin(held_nade, player.origin + player.view_ofs + v_forward * 8 + v_right * -8 + v_up * 0);
- held_nade.angles_y = player.angles.y;
-
- if (time + 0.1 >= held_nade.wait)
- toss_nade(player, false, '0 0 0', time + 0.05);
- }
if (!CanThrowNade(player)) return;
if (!(time > player.nade_refire)) return;
if (player.nade && (player.offhand != OFFHAND_NADE || (player.weapons & WEPSET(HOOK)))) OFFHAND_NADE.offhand_think(OFFHAND_NADE, player, player.nade_altbutton);
+ entity held_nade = player.nade;
+ if (held_nade)
+ {
+ player.nade_timer = bound(0, (time - held_nade.nade_time_primed) / held_nade.nade_lifetime, 1);
+ // LOG_TRACEF("%d %d", player.nade_timer, time - held_nade.nade_time_primed);
+ makevectors(player.angles);
+ held_nade.velocity = player.velocity;
+ setorigin(held_nade, player.origin + player.view_ofs + v_forward * 8 + v_right * -8 + v_up * 0);
+ held_nade.angles_y = player.angles.y;
+
+ if (time + 0.1 >= held_nade.wait)
+ toss_nade(player, false, '0 0 0', time + 0.05);
+ }
+
if(IS_PLAYER(player))
{
if ( autocvar_g_nades_bonus && autocvar_g_nades )
{
entity item = M_ARGV(0, entity);
- switch (item.items)
+ if(item.itemdef.instanceOfHealth || item.itemdef.instanceOfArmor)
{
- case ITEM_HealthSmall.m_itemid:
- case ITEM_HealthMedium.m_itemid:
- case ITEM_HealthLarge.m_itemid:
- case ITEM_HealthMega.m_itemid:
- case ITEM_ArmorSmall.m_itemid:
- case ITEM_ArmorMedium.m_itemid:
- case ITEM_ArmorLarge.m_itemid:
- case ITEM_ArmorMega.m_itemid:
- if (autocvar_g_nix_with_healtharmor)
- return false;
- break;
- case ITEM_Strength.m_itemid:
- case ITEM_Shield.m_itemid:
- if (autocvar_g_nix_with_powerups)
- return false;
- break;
+ return !autocvar_g_nix_with_healtharmor;
+ }
+ else if(item.itemdef.instanceOfPowerup)
+ {
+ return !autocvar_g_nix_with_powerups;
}
return true; // delete all other items
start_weapons = warmup_start_weapons = ok_start_items;
}
+MUTATOR_HOOKFUNCTION(ok, SetWeaponArena)
+{
+ // turn weapon arena off
+ M_ARGV(0, string) = "off";
+}
+
MUTATOR_HOOKFUNCTION(ok, BuildMutatorsString)
{
M_ARGV(0, string) = strcat(M_ARGV(0, string), ":OK");
#include "sv_spawn_near_teammate.qh"
+const float FLOAT_MAX = 340282346638528859811704183484516925440.0f;
+
float autocvar_g_spawn_near_teammate_distance;
int autocvar_g_spawn_near_teammate_ignore_spawnpoint;
+int autocvar_g_spawn_near_teammate_ignore_spawnpoint_max;
float autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay;
float autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay_death;
-int autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health;
+bool autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health;
bool autocvar_g_spawn_near_teammate_ignore_spawnpoint_closetodeath;
REGISTER_MUTATOR(spawn_near_teammate, cvar("g_spawn_near_teammate"));
.entity msnt_lookat;
.float msnt_timer;
-.vector msnt_deathloc;
.float cvar_cl_spawn_near_teammate;
player.msnt_timer = time + autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay_death;
entity best_mate = NULL;
- vector best_spot = '0 0 0';
- float pc = 0, best_dist = 0, dist = 0;
- FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(
- if((autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health >= 0 && it.health >= autocvar_g_balance_health_regenstable) || autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health == 0)
- if(!IS_DEAD(it))
- if(it.msnt_timer < time)
- if(SAME_TEAM(player, it))
- if(time > it.spawnshieldtime) // spawn shielding
- if(!forbidWeaponUse(it))
- if(STAT(FROZEN, it) == 0)
- if(it != player)
+ vector best_pos = '0 0 0';
+ float best_dist2 = FLOAT_MAX;
+ int tested = 0;
+ FOREACH_CLIENT_RANDOM(IS_PLAYER(it), LAMBDA(
+ if (autocvar_g_spawn_near_teammate_ignore_spawnpoint_max && tested >= autocvar_g_spawn_near_teammate_ignore_spawnpoint_max) break;
+
+ if (PHYS_INPUT_BUTTON_CHAT(it)) continue;
+ if (!SAME_TEAM(player, it)) continue;
+ if (autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health && it.health < autocvar_g_balance_health_regenstable) continue;
+ if (IS_DEAD(it)) continue;
+ if (time < it.msnt_timer) continue;
+ if (time < it.spawnshieldtime) continue;
+ if (forbidWeaponUse(it)) continue;
+ if (it == player) continue;
+
+ tested++; // i consider a teammate to be available when he passes the checks above
+
+ vector horiz_vel = vec2(it.velocity);
+ // when walking slowly sideways, we assume the player wants a clear shot ahead - spawn behind him according to where he's looking
+ // when running fast, spawn behind him according to his direction of movement to prevent colliding with the newly spawned player
+ if (vdist(horiz_vel, >, autocvar_sv_maxspeed + 50))
+ fixedmakevectors(vectoangles(horiz_vel));
+ else
+ fixedmakevectors(it.angles); // .angles is the angle of the model - usually/always 0 pitch
+
+ // test different spots close to mate - trace upwards so it works on uneven surfaces
+ // don't spawn in front of player or directly behind to avoid players shooting each other
+ // test the potential spots in pairs (first pair is better than second and so on) but don't prefer one side
+ RandomSelection_Init();
+ for(int i = 0; i < 6; ++i)
{
- tracebox(it.origin, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), it.origin - '0 0 100', MOVE_NOMONSTERS, it);
- if(trace_fraction != 1.0)
- if(!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY))
+ switch(i)
{
- pc = pointcontents(trace_endpos + '0 0 1');
- if(pc == CONTENT_EMPTY)
+ case 0:
+ tracebox(it.origin, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), it.origin - v_forward * 64 + v_right * 128 + v_up * 64, MOVE_NOMONSTERS, it);
+ break;
+ case 1:
+ tracebox(it.origin, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), it.origin - v_forward * 64 - v_right * 128 + v_up * 64, MOVE_NOMONSTERS, it);
+ break;
+ case 2:
+ tracebox(it.origin, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), it.origin + v_right * 192 + v_up * 64, MOVE_NOMONSTERS, it);
+ break;
+ case 3:
+ tracebox(it.origin, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), it.origin - v_right * 192 + v_up * 64, MOVE_NOMONSTERS, it);
+ break;
+ case 4:
+ tracebox(it.origin, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), it.origin - v_forward * 128 + v_right * 64 + v_up * 64, MOVE_NOMONSTERS, it);
+ break;
+ case 5:
+ tracebox(it.origin, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), it.origin - v_forward * 128 - v_right * 64 + v_up * 64, MOVE_NOMONSTERS, it);
+ break;
+ }
+
+ vector horizontal_trace_endpos = trace_endpos;
+ //te_lightning1(NULL, it.origin, horizontal_trace_endpos);
+ if (trace_fraction != 1.0) goto skip;
+
+ // 400 is about the height of a typical laser jump (in overkill)
+ // not traceline because we need space for the whole player, not just his origin
+ tracebox(horizontal_trace_endpos, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), horizontal_trace_endpos - '0 0 400', MOVE_NORMAL, it);
+ vector vectical_trace_endpos = trace_endpos;
+ //te_lightning1(NULL, horizontal_trace_endpos, vectical_trace_endpos);
+ if (trace_startsolid) goto skip; // inside another player
+ if (trace_fraction == 1.0) goto skip; // above void or too high
+ if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY) goto skip;
+ if (pointcontents(vectical_trace_endpos) != CONTENT_EMPTY) goto skip; // no lava or slime (or water which i assume would be annoying anyway)
+ if (tracebox_hits_trigger_hurt(horizontal_trace_endpos, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), vectical_trace_endpos)) goto skip;
+
+ // make sure the spawned player will have floor ahead (or at least a wall - he shouldn't fall as soon as he starts moving)
+ vector floor_test_start = vectical_trace_endpos + v_up * STAT(PL_MAX, NULL).z + v_forward * STAT(PL_MAX, NULL).x; // top front of player's bbox - highest point we know is not inside solid
+ traceline(floor_test_start, floor_test_start + v_forward * 100 - v_up * 128, MOVE_NOMONSTERS, it);
+ //te_beam(NULL, floor_test_start, trace_endpos);
+ if (trace_fraction == 1.0) goto skip;
+
+ if (autocvar_g_nades) {
+ bool nade_in_range = false;
+ IL_EACH(g_projectiles, it.classname == "nade",
{
- if(vdist(it.velocity, >, 5))
- fixedmakevectors(vectoangles(it.velocity));
- else
- fixedmakevectors(it.angles);
+ if (vdist(it.origin - vectical_trace_endpos, <, autocvar_g_nades_nade_radius)) {
+ nade_in_range = true;
+ goto skip;
+ }
+ });
+ if (nade_in_range) goto skip;
+ }
+
+ // here, we know we found a good spot
+ RandomSelection_Add(it, 0, string_null, vectical_trace_endpos, 1, 1);
+ //te_lightning1(NULL, vectical_trace_endpos, vectical_trace_endpos + v_forward * 10);
- for(pc = 0; pc < 4; ++pc) // test 4 diffrent spots close to mate
+LABEL(skip)
+ if (i % 2 == 1 && RandomSelection_chosen_ent)
+ {
+ if (autocvar_g_spawn_near_teammate_ignore_spawnpoint_closetodeath)
+ {
+ float dist2 = vlen2(RandomSelection_chosen_ent.origin - player.death_origin);
+ if (dist2 < best_dist2)
{
- switch(pc)
- {
- case 0:
- tracebox(it.origin , STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), it.origin + v_right * 128, MOVE_NOMONSTERS, it);
- break;
- case 1:
- tracebox(it.origin , STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), it.origin - v_right * 128 , MOVE_NOMONSTERS, it);
- break;
- case 2:
- tracebox(it.origin , STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), it.origin + v_right * 128 - v_forward * 64, MOVE_NOMONSTERS, it);
- break;
- case 3:
- tracebox(it.origin , STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), it.origin - v_right * 128 - v_forward * 64, MOVE_NOMONSTERS, it);
- break;
- //case 4:
- //tracebox(it.origin , STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), it.origin - v_forward * 128, MOVE_NOMONSTERS, it);
- //break;
- }
-
- if(trace_fraction == 1.0)
- {
- traceline(trace_endpos + '0 0 4', trace_endpos - '0 0 100', MOVE_NOMONSTERS, it);
- if(trace_fraction != 1.0)
- {
- if(autocvar_g_spawn_near_teammate_ignore_spawnpoint_closetodeath)
- {
- dist = vlen(trace_endpos - player.msnt_deathloc);
- if(dist < best_dist || best_dist == 0)
- {
- best_dist = dist;
- best_spot = trace_endpos;
- best_mate = it;
- }
- }
- else
- {
- setorigin(player, trace_endpos);
- player.angles = it.angles;
- player.angles_z = 0; // never spawn tilted even if the spot says to
- it.msnt_timer = time + autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay;
- return;
- }
- }
- }
+ best_dist2 = dist2;
+ best_pos = RandomSelection_chosen_vec;
+ best_mate = RandomSelection_chosen_ent;
}
}
+ else
+ {
+ setorigin(player, RandomSelection_chosen_vec);
+ player.angles = RandomSelection_chosen_ent.angles;
+ player.angles_z = 0; // never spawn tilted even if the spot says to
+ RandomSelection_chosen_ent.msnt_timer = time + autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay;
+ return;
+ }
+ break; // don't test the other spots near this teammate, go to the next one
}
}
));
if(autocvar_g_spawn_near_teammate_ignore_spawnpoint_closetodeath)
- if(best_dist)
+ if(best_mate)
{
- setorigin(player, best_spot);
+ setorigin(player, best_pos);
player.angles = best_mate.angles;
player.angles_z = 0; // never spawn tilted even if the spot says to
best_mate.msnt_timer = time + autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay;
}
}
-MUTATOR_HOOKFUNCTION(spawn_near_teammate, PlayerDies)
-{
- entity frag_target = M_ARGV(0, entity);
-
- frag_target.msnt_deathloc = frag_target.origin;
-}
-
REPLICATE(cvar_cl_spawn_near_teammate, bool, "cl_spawn_near_teammate");
InterpolateOrigin_Do(this);
- float t = entcs_GetTeam(player_localnum) + 1;
string spriteimage = "";
// choose the sprite
switch (this.rule)
{
case SPRITERULE_SPECTATOR:
+ float t = entcs_GetTeam(player_localnum) + 1;
if (!(
(autocvar_g_waypointsprite_itemstime == 1 && t == NUM_SPECTATOR + 1)
|| (autocvar_g_waypointsprite_itemstime == 2 && (t == NUM_SPECTATOR + 1 || warmup_stage || STAT(ITEMSTIME) == 2))
case SPRITERULE_DEFAULT:
if (this.team)
{
- if (this.team == t)
+ if (this.team == myteam + 1)
spriteimage = this.netname;
else
spriteimage = "";
spriteimage = this.netname;
break;
case SPRITERULE_TEAMPLAY:
- if (t == NUM_SPECTATOR + 1)
+ if (myteam == NUM_SPECTATOR)
spriteimage = this.netname3;
- else if (this.team == t)
+ else if (this.team == myteam + 1)
spriteimage = this.netname2;
else
spriteimage = this.netname;
float crosshairdistance = sqrt( pow(o.x - vid_conwidth/2, 2) + pow(o.y - vid_conheight/2, 2) );
- t = waypointsprite_scale;
+ float t = waypointsprite_scale;
a *= waypointsprite_alpha;
{
}
}
-float autocvar_notification_debug = false;
#ifdef NOTIFICATIONS_DEBUG
+bool autocvar_notification_debug = false;
void Debug_Notification(string input)
{
switch (autocvar_notification_debug)
float autocvar_notification_show_sprees_info_newline = true;
float autocvar_notification_show_sprees_info_specialonly = true;
float autocvar_notification_errors_are_fatal = true;
+#ifdef SVQC
float autocvar_notification_lifetime_runtime = 0.5;
float autocvar_notification_lifetime_mapload = 10;
+#endif
#ifdef SVQC
.float FRAG_VERBOSE;
{
v_forward = v_right = v_up = '0 0 0';
- float y = myangles.y * (M_PI * 2 / 360);
- float sy = sin(y);
- float cy = cos(y);
+ float yy = myangles.y * (M_PI * 2 / 360);
+ float sy = sin(yy);
+ float cy = cos(yy);
float p = myangles.x * (M_PI * 2 / 360);
float sp = sin(p);
float cp = cos(p);
return ret * angle_mult;
}
+#ifdef SVQC
string specialcommand = "xwxwxsxsxaxdxaxdx1x ";
.float specialcommand_pos;
void SpecialCommand(entity this)
{
-#ifdef SVQC
if (!CheatImpulse(this, CHIMPULSE_GIVE_ALL.impulse))
LOG_INFO("A hollow voice says \"Plugh\".\n");
-#endif
}
+#endif
bool PM_check_specialcommand(entity this, int buttons)
{
#define PHYS_INPUT_BUTTON_PRYDON(s) PHYS_INPUT_BUTTON_BUTTON_PRYDON(s)
#define PHYS_INPUT_BUTTON_ZOOMSCRIPT(s) PHYS_INPUT_BUTTON_BUTTON9(s)
#define PHYS_INPUT_BUTTON_JETPACK(s) PHYS_INPUT_BUTTON_BUTTON10(s)
+#define PHYS_INPUT_BUTTON_DODGE(s) PHYS_INPUT_BUTTON_BUTTON11(s)
#ifdef CSQC
STATIC_INIT(PHYS_INPUT_BUTTON_JETPACK)
localcmd("alias +jetpack +button10\n");
localcmd("alias -jetpack -button10\n");
}
+
+STATIC_INIT(PHYS_INPUT_BUTTON_DODGE)
+{
+ localcmd("alias +dodge +button11\n");
+ localcmd("alias -dodge -button11\n");
+}
#endif
// if more buttons are needed, start using impulse bits as buttons
#include "constants.qh"
#include "util.qh"
#include <common/weapons/_all.qh>
- #include "../server/weapons/accuracy.qh"
+ #include "../server/anticheat.qh"
#include "../server/defs.qh"
#include "../server/scores.qh"
+ #include "../server/weapons/accuracy.qh"
#endif
#ifdef SVQC
PS_GR_P_ADDVAL(p, PLAYERSTATS_JOINS, 1);
PlayerStats_GameReport_Accuracy(p);
+ anticheat_report_to_playerstats(p);
if(IS_REAL_CLIENT(p))
{
PlayerStats_GameReport_AddEvent(PLAYERSTATS_ACHIEVEMENT_BOTLIKE);
PlayerStats_GameReport_AddEvent(PLAYERSTATS_ACHIEVEMENT_FIRSTBLOOD);
PlayerStats_GameReport_AddEvent(PLAYERSTATS_ACHIEVEMENT_FIRSTVICTIM);
+
+ anticheat_register_to_playerstats();
}
else { PlayerStats_GameReport_DelayMapVote = false; }
}
const string PLAYERSTATS_TOTAL = "total-";
const string PLAYERSTATS_SCOREBOARD = "scoreboard-";
+const string PLAYERSTATS_ANTICHEAT = "anticheat-";
const string PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_3 = "achievement-kill-spree-3";
const string PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_5 = "achievement-kill-spree-5";
void bot_clientdisconnect(entity this);
void W_HitPlotClose(entity this);
-void anticheat_report(entity this);
+void anticheat_report_to_eventlog(entity this);
void playerdemo_shutdown(entity this);
void entcs_detach(entity this);
void accuracy_free(entity this);
bot_clientdisconnect(this);
W_HitPlotClose(this);
- anticheat_report(this);
+ anticheat_report_to_eventlog(this);
playerdemo_shutdown(this);
entcs_detach(this);
accuracy_free(this);
if(this.ItemStatus & ITS_ANIMATE2)
this.avelocity = '0 -90 0';
}
+
+ // delay is for blocking item's position for a while;
+ // it's a workaround for dropped weapons that receive the position
+ // another time right after they spawn overriding animation position
+ this.onground_time = time + 0.5;
}
}
else if (autocvar_cl_animate_items)
if(this.ItemStatus & ITS_ANIMATE1)
{
this.angles += this.avelocity * frametime;
- setorigin(this, '0 0 10' + this.oldorigin + '0 0 8' * sin(time * 2));
+ float fade_in = bound(0, time - this.onground_time, 1);
+ setorigin(this, this.oldorigin + fade_in * ('0 0 10' + '0 0 8' * sin((time - this.onground_time) * 2)));
}
if(this.ItemStatus & ITS_ANIMATE2)
{
this.angles += this.avelocity * frametime;
- setorigin(this, '0 0 8' + this.oldorigin + '0 0 4' * sin(time * 3));
+ float fade_in = bound(0, time - this.onground_time, 1);
+ setorigin(this, this.oldorigin + fade_in * ('0 0 8' + '0 0 4' * sin((time - this.onground_time) * 3)));
}
}
if(this.ItemStatus & ITS_ALLOWFB)
this.effects |= EF_FULLBRIGHT;
- if(this.ItemStatus & ITS_POWERUP)
+ if(this.ItemStatus & ITS_GLOW)
{
if(this.ItemStatus & ITS_AVAILABLE)
this.effects |= (EF_ADDITIVE | EF_FULLBRIGHT);
{
e.effects &= ~(EF_ADDITIVE | EF_STARDUST | EF_FULLBRIGHT | EF_NODEPTHTEST);
e.ItemStatus &= ~ITS_STAYWEP;
+ entity def = e.itemdef;
if (mode > 0)
{
// make the item look normal, and be touchable
e.ItemStatus &= ~ITS_AVAILABLE;
}
else {
- entity def = e.itemdef;
bool nostay = def.instanceOfWeaponPickup ? !!(def.m_weapon.weapons & WEPSET_SUPERWEAPONS) : false // no weapon-stay on superweapons
|| e.team // weapon stay isn't supported for teamed weapons
;
e.ItemStatus &= ~ITS_AVAILABLE;
}}
- if (e.items & ITEM_Strength.m_itemid || e.items & ITEM_Shield.m_itemid)
- e.ItemStatus |= ITS_POWERUP;
+ if (def.m_glow)
+ e.ItemStatus |= ITS_GLOW;
if (autocvar_g_nodepthtestitems)
e.effects |= EF_NODEPTHTEST;
void Item_Respawn (entity this)
{
Item_Show(this, 1);
- // this is ugly...
- if(this.items == ITEM_Strength.m_itemid)
- sound (this, CH_TRIGGER, SND_STRENGTH_RESPAWN, VOL_BASE, ATTEN_NORM); // play respawn sound
- else if(this.items == ITEM_Shield.m_itemid)
- sound (this, CH_TRIGGER, SND_SHIELD_RESPAWN, VOL_BASE, ATTEN_NORM); // play respawn sound
- else
- sound (this, CH_TRIGGER, SND_ITEMRESPAWN, VOL_BASE, ATTEN_NORM); // play respawn sound
+ sound(this, CH_TRIGGER, this.itemdef.m_respawnsound, VOL_BASE, ATTEN_NORM); // play respawn sound
setorigin(this, this.origin);
if (Item_ItemsTime_Allow(this.itemdef) || this.weapons & WEPSET_SUPERWEAPONS)
RandomSelection_Init();
IL_EACH(g_items, it.team == this.team,
{
- if(it.classname != "item_flag_team" && it.classname != "item_kh_key")
+ if(it.itemdef) // is a registered item
{
Item_Show(it, -1);
RandomSelection_AddEnt(it, it.cnt, 0);
RandomSelection_Init();
IL_EACH(g_items, it.team == this.team,
{
- if(it.classname != "item_flag_team" && it.classname != "item_kh_key")
+ if(it.itemdef) // is a registered item
RandomSelection_AddEnt(it, it.cnt, 0);
});
IL_EACH(g_items, it.team == this.team,
{
- if(it.classname != "item_flag_team" && it.classname != "item_kh_key")
+ if(it.itemdef) // is a registered item
{
if(it != e)
{
});
POSTGIVE_VALUE(e, strength_finished, 1, SND_POWERUP, SND_POWEROFF);
POSTGIVE_VALUE(e, invincible_finished, 1, SND_Shield, SND_POWEROFF);
+ //POSTGIVE_VALUE(e, superweapons_finished, 1, SND_Null, SND_Null);
POSTGIVE_VALUE(e, ammo_nails, 0, SND_ITEMPICKUP, SND_Null);
POSTGIVE_VALUE(e, ammo_cells, 0, SND_ITEMPICKUP, SND_Null);
POSTGIVE_VALUE(e, ammo_plasma, 0, SND_ITEMPICKUP, SND_Null);
const int ITS_AVAILABLE = BIT(3);
const int ITS_ALLOWFB = BIT(4);
const int ITS_ALLOWSI = BIT(5);
- const int ITS_POWERUP = BIT(6);
+ const int ITS_GLOW = BIT(6);
const int ISF_COLORMAP = BIT(4);
const int ISF_DROP = BIT(5);
const int ISF_ANGLES = BIT(6);
.int ItemStatus;
+.float onground_time;
.float fade_start;
.float fade_end;
#include "train.qh"
.float train_wait_turning;
+.entity future_target;
void train_next(entity this);
#ifdef SVQC
void train_use(entity this, entity actor, entity trigger);
{
entity targ, cp;
vector ang;
- targ = find(NULL, targetname, this.target);
+ targ = this.future_target;
if((this.spawnflags & 1) && targ.curvetarget)
cp = find(NULL, targetname, targ.curvetarget);
else
#endif
#ifdef SVQC
- entity tg = find(NULL, targetname, this.target);
+ entity tg = this.future_target;
if(tg.spawnflags & 4)
{
this.use = train_use;
}
}
+entity train_next_find(entity this)
+{
+ if(this.target_random)
+ {
+ RandomSelection_Init();
+ for(entity t = NULL; (t = find(t, targetname, this.target));)
+ {
+ RandomSelection_AddEnt(t, 1, 0);
+ }
+ return RandomSelection_chosen_ent;
+ }
+ else
+ {
+ return find(NULL, targetname, this.target);
+ }
+}
+
void train_next(entity this)
{
- entity targ, cp = NULL;
+ entity targ = NULL, cp = NULL;
vector cp_org = '0 0 0';
- targ = find(NULL, targetname, this.target);
+ targ = this.future_target;
+
this.target = targ.target;
+ this.target_random = targ.target_random;
+ this.future_target = train_next_find(targ);
+
if (this.spawnflags & 1)
{
if(targ.curvetarget)
void func_train_find(entity this)
{
- entity targ;
- targ = find(NULL, targetname, this.target);
+ entity targ = train_next_find(this);
this.target = targ.target;
+ this.target_random = targ.target_random;
+ // save the future target for later
+ this.future_target = train_next_find(targ);
if (this.target == "")
objerror(this, "func_train_find: no next target");
SUB_SETORIGIN(this, targ.origin - this.view_ofs);
return;
float dist = vlen(this.origin - view_origin);
- float t = (entcs_GetTeam(player_localnum) + 1);
vector o;
string txt;
if(autocvar_cl_vehicles_hud_tactical)
- if(dist < 10240 && t != this.team)
+ if(dist < 10240 && (myteam + 1 != this.team))
{
// TODO: Vehicle tactical hud
o = project_3d_to_2d(this.origin + '0 0 32');
else
txt = spritelookuptext(this, spriteimage);
- if(time - floor(time) > 0.5 && t == this.team)
+ if(time - floor(time) > 0.5 && (myteam + 1 == this.team))
{
if(this.helpme && time < this.helpme)
{
float crosshairdistance = sqrt( pow(o.x - vid_conwidth/2, 2) + pow(o.y - vid_conheight/2, 2) );
- t = waypointsprite_scale;
+ float t = waypointsprite_scale;
a *= waypointsprite_alpha;
{
void Dump_Turret_Settings()
{
- float x, totalsettings = 0;
+ int totalsettings = 0;
FOREACH(Turrets, it != TUR_Null, {
// step 1: clear the queue
TUR_CONFIG_COUNT = 0;
- for(x = 0; x <= MAX_TUR_CONFIG; ++x)
- { tur_config_queue[x] = string_null; }
+ for(int j = 0; j <= MAX_TUR_CONFIG; ++j)
+ { tur_config_queue[j] = string_null; }
// step 2: build new queue
it.tr_config(it);
// step 4: write queue
TUR_CONFIG_WRITETOFILE(sprintf("// {{{ #%d: %s\n", i, it.turret_name))
- for(x = 0; x <= TUR_CONFIG_COUNT; ++x)
- { TUR_CONFIG_WRITETOFILE(tur_config_queue[x]) }
+ for(int j = 0; j <= TUR_CONFIG_COUNT; ++j)
+ { TUR_CONFIG_WRITETOFILE(tur_config_queue[j]) }
TUR_CONFIG_WRITETOFILE("// }}}\n")
// step 5: debug info
// clear queue now that we're finished
TUR_CONFIG_COUNT = 0;
- for(x = 0; x <= MAX_TUR_CONFIG; ++x)
- { tur_config_queue[x] = string_null; }
+ for(int j = 0; j <= MAX_TUR_CONFIG; ++j)
+ { tur_config_queue[j] = string_null; }
// extra information
LOG_INFO(sprintf("Totals: %d turrets, %d settings\n", (Turrets_COUNT - 1), totalsettings));
float lengthLogTable[128];
-float invertLengthLog(float x)
+float invertLengthLog(float dist)
{
int l, r, m;
- if(x >= lengthLogTable[127])
+ if(dist >= lengthLogTable[127])
return 127;
- if(x <= lengthLogTable[0])
+ if(dist <= lengthLogTable[0])
return 0;
l = 0;
while(r - l > 1)
{
m = floor((l + r) / 2);
- if(lengthLogTable[m] < x)
+ if(lengthLogTable[m] < dist)
l = m;
else
r = m;
}
// now: r is >=, l is <
- float lerr = (x - lengthLogTable[l]);
- float rerr = (lengthLogTable[r] - x);
+ float lerr = (dist - lengthLogTable[l]);
+ float rerr = (lengthLogTable[r] - dist);
if(lerr < rerr)
return l;
return r;
if(data == 0)
return '0 0 0';
float p = (data & 0xF000) / 0x1000;
- float y = (data & 0x0F80) / 0x80;
+ float q = (data & 0x0F80) / 0x80;
int len = (data & 0x007F);
- //print("\ndecompress: p ", ftos(p)); print("y ", ftos(y)); print("len ", ftos(len), "\n");
+ //print("\ndecompress: p ", ftos(p)); print("q ", ftos(q)); print("len ", ftos(len), "\n");
if(p == 0)
{
out.x = 0;
out.y = 0;
- if(y == 31)
+ if(q == 31)
out.z = -1;
else
out.z = +1;
}
else
{
- y = .19634954084936207740 * y;
+ q = .19634954084936207740 * q;
p = .19634954084936207740 * p - 1.57079632679489661922;
- out.x = cos(y) * cos(p);
- out.y = sin(y) * cos(p);
+ out.x = cos(q) * cos(p);
+ out.y = sin(q) * cos(p);
out.z = -sin(p);
}
float compressShotOrigin(vector v)
{
- float x, y, z;
- x = rint(v.x * 2);
- y = rint(v.y * 4) + 128;
- z = rint(v.z * 4) + 128;
- if(x > 255 || x < 0)
+ float rx = rint(v.x * 2);
+ float ry = rint(v.y * 4) + 128;
+ float rz = rint(v.z * 4) + 128;
+ if(rx > 255 || rx < 0)
{
LOG_INFO("shot origin ", vtos(v), " x out of bounds\n");
- x = bound(0, x, 255);
+ rx = bound(0, rx, 255);
}
- if(y > 255 || y < 0)
+ if(ry > 255 || ry < 0)
{
LOG_INFO("shot origin ", vtos(v), " y out of bounds\n");
- y = bound(0, y, 255);
+ ry = bound(0, ry, 255);
}
- if(z > 255 || z < 0)
+ if(rz > 255 || rz < 0)
{
LOG_INFO("shot origin ", vtos(v), " z out of bounds\n");
- z = bound(0, z, 255);
+ rz = bound(0, rz, 255);
}
- return x * 0x10000 + y * 0x100 + z;
+ return rx * 0x10000 + ry * 0x100 + rz;
}
vector decompressShotOrigin(int f)
{
float almost_in_bounds(float a, float b, float c);
float power2of(float e);
-float log2of(float x);
+float log2of(float e);
vector rgb_to_hsl(vector rgb);
vector hsl_to_rgb(vector hsl);
// f(1) = 1
// f'(0) = startspeedfactor
// f'(1) = endspeedfactor
-float cubic_speedfunc(float startspeedfactor, float endspeedfactor, float x);
+float cubic_speedfunc(float startspeedfactor, float endspeedfactor, float spd);
// checks whether f'(x) = 0 anywhere from 0 to 1
// because if this is the case, the function is not usable for platforms
#include <common/weapons/_all.qh>
+#ifdef SVQC
float autocvar_g_vehicle_bumblebee_cannon_cost = 2;
float autocvar_g_vehicle_bumblebee_cannon_damage = 60;
float autocvar_g_vehicle_bumblebee_cannon_radius = 225;
float autocvar_g_vehicle_bumblebee_cannon_speed = 20000;
float autocvar_g_vehicle_bumblebee_cannon_spread = 0.02;
float autocvar_g_vehicle_bumblebee_cannon_force = -35;
+#endif
#ifdef SVQC
void bumblebee_fire_cannon(entity this, entity _gun, string _tagname, entity _owner);
float autocvar_g_vehicle_racer_water_time = 5;
-float autocvar_g_vehicle_racer_collision_multiplier = 0.05;
+//float autocvar_g_vehicle_racer_collision_multiplier = 0.05;
// 0 = hover, != 0 = maglev
int autocvar_g_vehicle_racer_hovertype = 0;
void racer_fire_rocket(entity player, vector org, vector dir, entity trg);
#endif
+#ifdef SVQC
float autocvar_g_vehicle_racer_cannon_cost = 2;
float autocvar_g_vehicle_racer_cannon_damage = 15;
float autocvar_g_vehicle_racer_cannon_radius = 100;
float autocvar_g_vehicle_racer_rocket_climbspeed = 1600;
float autocvar_g_vehicle_racer_rocket_locked_maxangle = 1.8;
+#endif
ENDCLASS(RaptorFlare)
REGISTER_WEAPON(RAPTOR_FLARE, NEW(RaptorFlare));
-
+#ifdef SVQC
float autocvar_g_vehicle_raptor_cannon_cost = 1;
float autocvar_g_vehicle_raptor_cannon_damage = 10;
float autocvar_g_vehicle_raptor_cannon_radius = 60;
float autocvar_g_vehicle_raptor_flare_lifetime = 10;
float autocvar_g_vehicle_raptor_flare_chase = 0.9;
float autocvar_g_vehicle_raptor_flare_range = 2000;
+#endif
#endif // SVQC
#ifdef CSQC
-float autocvar_cl_vehicle_spiderbot_cross_alpha = 0.6;
-float autocvar_cl_vehicle_spiderbot_cross_size = 1;
+//float autocvar_cl_vehicle_spiderbot_cross_alpha = 0.6;
+//float autocvar_cl_vehicle_spiderbot_cross_size = 1;
METHOD(Spiderbot, vr_hud, void(Spiderbot thisveh))
{
void spiderbot_rocket_do(entity this);
#endif
+#ifdef SVQC
// 400 (x2) DPS
float autocvar_g_vehicle_spiderbot_minigun_damage = 24;
float autocvar_g_vehicle_spiderbot_minigun_refire = 0.06;
float autocvar_g_vehicle_spiderbot_rocket_noise = 0.2;
float autocvar_g_vehicle_spiderbot_rocket_turnrate = 0.25;
float autocvar_g_vehicle_spiderbot_rocket_lifetime = 20;
+#endif
X(weaponstartoverride, float)
X(weaponstart, float)
X(weaponthrowable, float)
+#ifdef SVQC
X(reload_ammo, float)
.float reloading_ammo = reload_ammo;
X(reload_time, float)
.float reloading_time = reload_time;
+#endif
#undef X
// no weapon specific image for this weapon
return false;
}
+ /** (CLIENT) weapon specific view model */
+ METHOD(Weapon, wr_viewmodel, string(Weapon this, entity wep)) { return string_null; }
/** (CLIENT) weapon specific glow */
METHOD(Weapon, wr_glow, vector(Weapon this, entity actor)) { return '0 0 0'; }
/** (SERVER) the weapon is dropped */
{
// loadable hagar secondary attack, must always run each frame
- if(time < game_starttime || PS(actor).m_switchweapon != WEP_HAGAR)
+ if(time < game_starttime)
return;
bool loaded = actor.hagar_load >= WEP_CVAR_SEC(hagar, load_max);
return WEAPON_TUBA_MURDER;
}
+#elif defined(CSQC)
+
+METHOD(Tuba, wr_viewmodel, string(Tuba this, entity wep))
+{
+ return (wep.tuba_instrument == 0) ? "tuba" :
+ (wep.tuba_instrument == 1) ? "akordeon" :
+ "kleinbottle";
+}
+
#endif
#ifdef CSQC
*/
#define SYSTEM(sys, frameLimit, minfps) \
void sys_##sys##_update(entity this, float dt); \
- float autocvar_xon_sys_##sys##_dt = ((frameLimit) ? (1 / (frameLimit)) : 0); \
- float autocvar_xon_sys_##sys##_minfps = (1 / (1 / (minfps)))
+ noref float autocvar_xon_sys_##sys##_dt = ((frameLimit) ? (1 / (frameLimit)) : 0); \
+ noref float autocvar_xon_sys_##sys##_minfps = (1 / (1 / (minfps)))
#define SYSTEM_UPDATE(sys) \
MACRO_BEGIN \
/** for players */
void sys_phys_simulate(entity this, float dt)
{
- const vector g = -this.com_phys_gravity;
- const bool jump = this.com_in_jump;
-
if (!this.com_phys_ground && !this.com_phys_air) {
// noclipping
// flying
UNSET_ONGROUND(this);
if (this.com_phys_friction_air) {
+ const vector g = -this.com_phys_gravity;
this.velocity_z += g.z / 2;
this.velocity = this.velocity * (1 - dt * this.com_phys_friction);
this.velocity_z += g.z / 2;
if (this.com_phys_water) {
// water jump only in certain situations
// this mimics quakeworld code
- if (jump && this.waterlevel == WATERLEVEL_SWIMMING && this.velocity_z >= -180 && !this.viewloc) {
+ if (this.com_in_jump && this.waterlevel == WATERLEVEL_SWIMMING && this.velocity_z >= -180 && !this.viewloc) {
vector yawangles = '0 1 0' * this.v_angle.y;
makevectors(yawangles);
vector forward = v_forward;
}
// holding jump button swims upward slowly
- if (jump && !this.viewloc) {
+ if (this.com_in_jump && !this.viewloc) {
// was:
// lava: 50
// slime: 80
void sys_phys_pregame_hold(entity this)
{
if (!IS_PLAYER(this)) { return; }
- const bool allowed_to_move = (time >= game_starttime);
+ const bool allowed_to_move = (time >= game_starttime && !gameover);
if (!allowed_to_move) {
this.velocity = '0 0 0';
set_movetype(this, MOVETYPE_NONE);
void SetChangeParms() { ENGINE_EVENT(); if (_SetChangeParms) _SetChangeParms(this); }
#define SetChangeParms _SetChangeParms
+#ifdef DP_EXT_PRECONNECT
+ void _ClientPreConnect(entity this);
+ void ClientPreConnect() { ENGINE_EVENT(); if (_ClientPreConnect) _ClientPreConnect(this); }
+ #define ClientPreConnect _ClientPreConnect
+#endif
+
void _ClientConnect(entity this);
void ClientConnect() { ENGINE_EVENT(); if (_ClientConnect) _ClientConnect(this); }
#define ClientConnect _ClientConnect
+ (b - a) * 2;
}
-float cubic_speedfunc(float startspeedfactor, float endspeedfactor, float x)
+float cubic_speedfunc(float startspeedfactor, float endspeedfactor, float spd)
{
return (((startspeedfactor + endspeedfactor - 2
- ) * x - 2 * startspeedfactor - endspeedfactor + 3
- ) * x + startspeedfactor
- ) * x;
+ ) * spd - 2 * startspeedfactor - endspeedfactor + 3
+ ) * spd + startspeedfactor
+ ) * spd;
}
bool cubic_speedfunc_is_sane(float startspeedfactor, float endspeedfactor)
return pow(2, e);
}
-float log2of(float x)
+float log2of(float e)
{
// NOTE: generated code
- if (x > 2048)
- if (x > 131072)
- if (x > 1048576)
- if (x > 4194304) return 23;
+ if (e > 2048)
+ if (e > 131072)
+ if (e > 1048576)
+ if (e > 4194304) return 23;
else
- if (x > 2097152) return 22;
+ if (e > 2097152) return 22;
else return 21;
else
- if (x > 524288) return 20;
+ if (e > 524288) return 20;
else
- if (x > 262144) return 19;
+ if (e > 262144) return 19;
else return 18;
else
- if (x > 16384)
- if (x > 65536) return 17;
+ if (e > 16384)
+ if (e > 65536) return 17;
else
- if (x > 32768) return 16;
+ if (e > 32768) return 16;
else return 15;
else
- if (x > 8192) return 14;
+ if (e > 8192) return 14;
else
- if (x > 4096) return 13;
+ if (e > 4096) return 13;
else return 12;
else
- if (x > 32)
- if (x > 256)
- if (x > 1024) return 11;
+ if (e > 32)
+ if (e > 256)
+ if (e > 1024) return 11;
else
- if (x > 512) return 10;
+ if (e > 512) return 10;
else return 9;
else
- if (x > 128) return 8;
+ if (e > 128) return 8;
else
- if (x > 64) return 7;
+ if (e > 64) return 7;
else return 6;
else
- if (x > 4)
- if (x > 16) return 5;
+ if (e > 4)
+ if (e > 16) return 5;
else
- if (x > 8) return 4;
+ if (e > 8) return 4;
else return 3;
else
- if (x > 2) return 2;
+ if (e > 2) return 2;
else
- if (x > 1) return 1;
+ if (e > 1) return 1;
else return 0;
}
#define SELFWRAP(T, R, oldargs, args, forward) \
.R oldargs T; \
- .R oldargs __##T = T; \
+ noref .R oldargs __##T = T; \
.R args self##T; \
R T##_self oldargs { ENGINE_EVENT(); return this.self##T forward; }
noref bool __spawnfunc_expecting;
noref entity __spawnfunc_expect;
- bool __spawnfunc_unreachable_workaround = true;
+ noref bool __spawnfunc_unreachable_workaround = true;
#define spawnfunc_1(id) spawnfunc_2(id, FIELDS_UNION)
#define spawnfunc_2(id, whitelist) \
#elif defined(SVQC)
#endif
-int fpclassify(float x)
+int fpclassify(float e)
{
- if(isnan(x))
+ if(isnan(e))
return FP_NAN;
- if(isinf(x))
+ if(isinf(e))
return FP_INFINITE;
- if(x == 0)
+ if(e == 0)
return FP_ZERO;
return FP_NORMAL;
}
-bool isfinite(float x)
+bool isfinite(float e)
{
- return !(isnan(x) || isinf(x));
+ return !(isnan(e) || isinf(e));
}
-bool isinf(float x)
+bool isinf(float e)
{
- return (x != 0) && (x + x == x);
+ return (e != 0) && (e + e == e);
}
-bool isnan(float x)
+bool isnan(float e)
{
- float y;
- y = x;
- return (x != y);
+ float f = e;
+ return (e != f);
}
-bool isnormal(float x)
+bool isnormal(float e)
{
- return isfinite(x);
+ return isfinite(e);
}
-bool signbit(float x)
+bool signbit(float e)
{
- return (x < 0);
+ return (e < 0);
}
-float acosh(float x)
+float acosh(float e)
{
- return log(x + sqrt(x*x - 1));
+ return log(e + sqrt(e*e - 1));
}
-float asinh(float x)
+float asinh(float e)
{
- return log(x + sqrt(x*x + 1));
+ return log(e + sqrt(e*e + 1));
}
-float atanh(float x)
+float atanh(float e)
{
- return 0.5 * log((1+x) / (1-x));
+ return 0.5 * log((1+e) / (1-e));
}
-float cosh(float x)
+float cosh(float e)
{
- return 0.5 * (exp(x) + exp(-x));
+ return 0.5 * (exp(e) + exp(-e));
}
-float sinh(float x)
+float sinh(float e)
{
- return 0.5 * (exp(x) - exp(-x));
+ return 0.5 * (exp(e) - exp(-e));
}
-float tanh(float x)
+float tanh(float e)
{
- return sinh(x) / cosh(x);
+ return sinh(e) / cosh(e);
}
-float exp(float x)
+float exp(float e)
{
- return pow(M_E, x);
+ return pow(M_E, e);
}
-float exp2(float x)
+float exp2(float e)
{
- return pow(2, x);
+ return pow(2, e);
}
-float expm1(float x)
+float expm1(float e)
{
- return exp(x) - 1;
+ return exp(e) - 1;
}
-vector frexp(float x)
+vector frexp(float e)
{
vector v;
v.z = 0;
- v.y = ilogb(x) + 1;
- v.x = x / exp2(v.y);
+ v.y = ilogb(e) + 1;
+ v.x = e / exp2(v.y);
return v;
}
-int ilogb(float x)
+int ilogb(float e)
{
- return floor(log2(fabs(x)));
+ return floor(log2(fabs(e)));
}
-float ldexp(float x, int e)
+float ldexp(float e, int e)
{
- return x * pow(2, e);
+ return e * pow(2, e);
}
-float logn(float x, float base)
+float logn(float e, float base)
{
- return log(x) / log(base);
+ return log(e) / log(base);
}
-float log10(float x)
+float log10(float e)
{
- return log(x) * M_LOG10E;
+ return log(e) * M_LOG10E;
}
-float log1p(float x)
+float log1p(float e)
{
- return log(x + 1);
+ return log(e + 1);
}
-float log2(float x)
+float log2(float e)
{
- return log(x) * M_LOG2E;
+ return log(e) * M_LOG2E;
}
-float logb(float x)
+float logb(float e)
{
- return floor(log2(fabs(x)));
+ return floor(log2(fabs(e)));
}
vector modf(float f)
{
return '1 0 0' * (f - trunc(f)) + '0 1 0' * trunc(f);
}
-float scalbn(float x, int n)
+float scalbn(float e, int n)
{
- return x * pow(2, n);
+ return e * pow(2, n);
}
-float cbrt(float x)
+float cbrt(float e)
{
- return copysign(pow(fabs(x), 1.0/3.0), x);
+ return copysign(pow(fabs(e), 1.0/3.0), e);
}
-float hypot(float x, float y)
+float hypot(float e, float f)
{
- return sqrt(x*x + y*y);
+ return sqrt(e*e + f*f);
}
-float erf(float x)
+float erf(float e)
{
// approximation taken from wikipedia
- float y;
- y = x*x;
- return copysign(sqrt(1 - exp(-y * (1.273239544735163 + 0.14001228868667 * y) / (1 + 0.14001228868667 * y))), x);
+ float f;
+ f = e*e;
+ return copysign(sqrt(1 - exp(-f * (1.273239544735163 + 0.14001228868667 * f) / (1 + 0.14001228868667 * f))), e);
}
-float erfc(float x)
+float erfc(float e)
{
- return 1.0 - erf(x);
+ return 1.0 - erf(e);
}
-vector lgamma(float x)
+vector lgamma(float e)
{
// TODO improve accuracy
- if(!isfinite(x))
- return fabs(x) * '1 0 0' + copysign(1, x) * '0 1 0';
- if(x < 1 && x == floor(x))
+ if(!isfinite(e))
+ return fabs(e) * '1 0 0' + copysign(1, e) * '0 1 0';
+ if(e < 1 && e == floor(e))
return nan("gamma") * '1 1 1';
- if(x < 0.1)
+ if(e < 0.1)
{
vector v;
- v = lgamma(1.0 - x);
+ v = lgamma(1.0 - e);
// reflection formula:
// gamma(1-z) * gamma(z) = pi / sin(pi*z)
// lgamma(1-z) + lgamma(z) = log(pi) - log(sin(pi*z))
// sign of gamma(1-z) = sign of gamma(z) * sign of sin(pi*z)
- v.z = sin(M_PI * x);
+ v.z = sin(M_PI * e);
v.x = log(M_PI) - log(fabs(v.z)) - v.x;
if(v.z < 0)
v.y = -v.y;
v.z = 0;
return v;
}
- if(x < 1.1)
- return lgamma(x + 1) - log(x) * '1 0 0';
- x -= 1;
- return (0.5 * log(2 * M_PI * x) + x * (log(x) - 1)) * '1 0 0' + '0 1 0';
+ if(e < 1.1)
+ return lgamma(e + 1) - log(e) * '1 0 0';
+ e -= 1;
+ return (0.5 * log(2 * M_PI * e) + e * (log(e) - 1)) * '1 0 0' + '0 1 0';
}
-float tgamma(float x)
+float tgamma(float e)
{
- vector v;
- v = lgamma(x);
+ vector v = lgamma(e);
return exp(v.x) * v.y;
}
* 1 % -2 == -1
* -1 % -2 == -1
*/
-float pymod(float x, float y)
+float pymod(float e, float f)
{
- return x - y * floor(x / y);
+ return e - f * floor(e / f);
}
-float nearbyint(float x)
+float nearbyint(float e)
{
- return rint(x);
+ return rint(e);
}
-float trunc(float x)
+float trunc(float e)
{
- return (x>=0) ? floor(x) : ceil(x);
+ return (e>=0) ? floor(e) : ceil(e);
}
-float fmod(float x, float y)
+float fmod(float e, float f)
{
- return x - y * trunc(x / y);
+ return e - f * trunc(e / f);
}
-float remainder(float x, float y)
+float remainder(float e, float f)
{
- return x - y * rint(x / y);
+ return e - f * rint(e / f);
}
-vector remquo(float x, float y)
+vector remquo(float e, float f)
{
vector v;
v.z = 0;
- v.y = rint(x / y);
- v.x = x - y * v.y;
+ v.y = rint(e / f);
+ v.x = e - f * v.y;
return v;
}
-float copysign(float x, float y)
+float copysign(float e, float f)
{
- return fabs(x) * ((y>0) ? 1 : -1);
+ return fabs(e) * ((f>0) ? 1 : -1);
}
float nan(string tag)
{
return sqrt(-1);
}
-float nextafter(float x, float y)
+float nextafter(float e, float f)
{
// TODO very crude
- if(x == y)
+ if(e == f)
return nan("nextafter");
- if(x > y)
- return -nextafter(-x, -y);
- // now we know that x < y
- // so we need the next number > x
+ if(e > f)
+ return -nextafter(-e, -f);
+ // now we know that e < f
+ // so we need the next number > e
float d, a, b;
- d = max(fabs(x), 0.00000000000000000000001);
- a = x + d;
+ d = max(fabs(e), 0.00000000000000000000001);
+ a = e + d;
do
{
d *= 0.5;
b = a;
- a = x + d;
+ a = e + d;
}
- while(a != x);
+ while(a != e);
return b;
}
-float nexttoward(float x, float y)
+float nexttoward(float e, float f)
{
- return nextafter(x, y);
+ return nextafter(e, f);
}
-float fdim(float x, float y)
+float fdim(float e, float f)
{
- return max(x-y, 0);
+ return max(e-f, 0);
}
-float fmax(float x, float y)
+float fmax(float e, float f)
{
- return max(x, y);
+ return max(e, f);
}
-float fmin(float x, float y)
+float fmin(float e, float f)
{
- return min(x, y);
+ return min(e, f);
}
-float fma(float x, float y, float z)
+float fma(float e, float f, float g)
{
- return x * y + z;
+ return e * f + g;
}
-int isgreater(float x, float y)
+int isgreater(float e, float f)
{
- return x > y;
+ return e > f;
}
-int isgreaterequal(float x, float y)
+int isgreaterequal(float e, float f)
{
- return x >= y;
+ return e >= f;
}
-int isless(float x, float y)
+int isless(float e, float f)
{
- return x < y;
+ return e < f;
}
-int islessequal(float x, float y)
+int islessequal(float e, float f)
{
- return x <= y;
+ return e <= f;
}
-int islessgreater(float x, float y)
+int islessgreater(float e, float f)
{
- return x < y || x > y;
+ return e < f || e > f;
}
-int isunordered(float x, float y)
+int isunordered(float e, float f)
{
- return !(x < y || x == y || x > y);
+ return !(e < f || e == f || e > f);
}
const int FP_ZERO = 2;
const int FP_SUBNORMAL = 3;
const int FP_NORMAL = 4;
-int fpclassify(float x);
-bool isfinite(float x);
-bool isinf(float x);
-bool isnan(float x);
-bool isnormal(float x);
-bool signbit(float x);
-
-//float acos(float x);
-//float asin(float x);
-//float atan(float x);
-//float atan2(float y, float x);
-//float cos(float x);
-//float sin(float x);
-//float tan(float x);
-
-float acosh(float x);
-float asinh(float x);
-float atanh(float x);
-float cosh(float x);
-float sinh(float x);
-float tanh(float x);
-
-float exp(float x);
-float exp2(float x);
-float expm1(float x);
-
-vector frexp(float x); // returns mantissa as _x, exponent as _y
-int ilogb(float x);
-float ldexp(float x, int e);
-//float log(float x);
-float logn(float x, float base);
-float log10(float x);
-float log1p(float x);
-float log2(float x);
-float logb(float x);
+int fpclassify(float e);
+bool isfinite(float e);
+bool isinf(float e);
+bool isnan(float e);
+bool isnormal(float e);
+bool signbit(float e);
+
+//float acos(float e);
+//float asin(float e);
+//float atan(float e);
+//float atan2(float f, float e);
+//float cos(float e);
+//float sin(float e);
+//float tan(float e);
+
+float acosh(float e);
+float asinh(float e);
+float atanh(float e);
+float cosh(float e);
+float sinh(float e);
+float tanh(float e);
+
+float exp(float e);
+float exp2(float e);
+float expm1(float e);
+
+vector frexp(float e); // returns mantissa as _x, exponent as _y
+int ilogb(float e);
+float ldexp(float e, int e);
+//float log(float e);
+float logn(float e, float base);
+float log10(float e);
+float log1p(float e);
+float log2(float e);
+float logb(float e);
vector modf(float f); // fraction as _x, integer as _y
-float scalbn(float x, int n);
+float scalbn(float e, int n);
-float cbrt(float x);
-//float fabs(float x);
-float hypot(float x, float y);
-//float pow(float x, float y);
-//float sqrt(float x, float y);
+float cbrt(float e);
+//float fabs(float e);
+float hypot(float e, float f);
+//float pow(float e, float f);
+//float sqrt(float e, float f);
-float erf(float x);
-float erfc(float x);
-vector lgamma(float x); // value in _x, sign in _y
-float tgamma(float x);
+float erf(float e);
+float erfc(float e);
+vector lgamma(float e); // value in _x, sign in _y
+float tgamma(float e);
/**
* Pythonic mod:
* 1 % -2 == -1
* -1 % -2 == -1
*/
-float pymod(float x, float y);
+float pymod(float e, float f);
-//float ceil(float x);
-//float floor(float x);
-float nearbyint(float x);
-//float rint(float x);
-//float round(float x);
-float trunc(float x);
+//float ceil(float e);
+//float floor(float e);
+float nearbyint(float e);
+//float rint(float e);
+//float round(float e);
+float trunc(float e);
-float fmod(float x, float y);
-float remainder(float x, float y);
-vector remquo(float x, float y);
+float fmod(float e, float f);
+float remainder(float e, float f);
+vector remquo(float e, float f);
-float copysign(float x, float y);
+float copysign(float e, float f);
float nan(string tag);
-float nextafter(float x, float y);
-float nexttoward(float x, float y);
-
-float fdim(float x, float y);
-float fmax(float x, float y);
-float fmin(float x, float y);
-float fma(float x, float y, float z);
-
-int isgreater(float x, float y);
-int isgreaterequal(float x, float y);
-int isless(float x, float y);
-int islessequal(float x, float y);
-int islessgreater(float x, float y);
-int isunordered(float x, float y);
+float nextafter(float e, float f);
+float nexttoward(float e, float f);
+
+float fdim(float e, float f);
+float fmax(float e, float f);
+float fmin(float e, float f);
+float fma(float e, float f, float g);
+
+int isgreater(float e, float f);
+int isgreaterequal(float e, float f);
+int isless(float e, float f);
+int islessequal(float e, float f);
+int islessgreater(float e, float f);
+int isunordered(float e, float f);
const float M_E = 2.7182818284590452354; /* e */
const float M_LOG2E = 1.4426950408889634074; /* log_2 e */
}
return 1;
}
- void Image_setZoom(entity me, float z, float atMousePosition)
+ void Image_setZoom(entity me, float newzoom, float atMousePosition)
{
float prev_zoomFactor;
prev_zoomFactor = me.zoomFactor;
- if (z < 0) // multiply by the current zoomFactor (but can also snap to real dimensions or to box)
+ if (newzoom < 0) // multiply by the current zoomFactor (but can also snap to real dimensions or to box)
{
- me.zoomFactor *= -z;
+ me.zoomFactor *= -newzoom;
float realSize_in_the_middle, boxSize_in_the_middle;
realSize_in_the_middle = ((prev_zoomFactor - 1) * (me.zoomFactor - 1) < 0);
boxSize_in_the_middle = (me.zoomBox > 0 && (prev_zoomFactor - me.zoomBox) * (me.zoomFactor - me.zoomBox) < 0);
me.zoomFactor = me.zoomBox; // snap to box
}
}
- else if (z == 0) // reset (no zoom)
+ else if (newzoom == 0) // reset (no zoom)
{
if (me.zoomBox > 0) me.zoomFactor = me.zoomBox;
else me.zoomFactor = 1;
}
else // directly set
{
- me.zoomFactor = z;
+ me.zoomFactor = newzoom;
}
me.zoomFactor = bound(1 / 16, me.zoomFactor, 16);
if (me.zoomMax > 0 && me.zoomFactor > me.zoomMax) me.zoomFactor = me.zoomMax;
oldshift = draw_shift;
oldscale = draw_scale;
- float y;
i = me.getItemAtPos(me, me.scrollPos);
- y = me.getItemStart(me, i) - me.scrollPos;
- for ( ; i < me.nItems && y < 1; ++i)
+ float j = me.getItemStart(me, i) - me.scrollPos;
+ for ( ; i < me.nItems && j < 1; ++i)
{
- draw_shift = boxToGlobal(eY * y, oldshift, oldscale);
+ draw_shift = boxToGlobal(eY * j, oldshift, oldscale);
vector relSize = eX * (1 - me.controlWidth) + eY * me.getItemHeight(me, i);
absSize = boxToGlobalSize(relSize, me.size);
draw_scale = boxToGlobalSize(relSize, oldscale);
me.drawListBoxItem(me, i, absSize, (me.selectedItem == i), (me.focusedItem == i));
- y += relSize.y;
+ j += relSize.y;
}
draw_ClearClip();
entity makeXonoticCheckBox_T(float isInverted, string theCvar, string theText, string theTooltip)
{
- float y, n;
+ float m, n;
if(isInverted > 1)
{
n = isInverted - 1;
- y = -n;
+ m = -n;
}
else if(isInverted < -1)
{
n = isInverted + 1;
- y = -n;
+ m = -n;
}
else if(isInverted == 1)
{
n = 1;
- y = 0;
+ m = 0;
}
else
{
n = 0;
- y = 1;
+ m = 1;
}
- return makeXonoticCheckBoxEx_T(y, n, theCvar, theText, theTooltip);
+ return makeXonoticCheckBoxEx_T(m, n, theCvar, theText, theTooltip);
}
entity makeXonoticCheckBox(float isInverted, string theCvar, string theText)
{
}
void XonoticCreditsList_drawListBoxItem(entity me, int i, vector absSize, bool isSelected, bool isFocused)
{
- // layout: Ping, Credits name, Map name, NP, TP, MP
string s;
float theAlpha;
vector theColor;
t.configureXonoticTextSliderValues(t);
}
+void GameType_ConfigureSliders_for_CurrentGametype(entity me)
+{
+ switch(MapInfo_CurrentGametype())
+ {
+ case MAPINFO_TYPE_CA: GameType_ConfigureSliders(me, _("Frag limit:"), 5, 100, 5, "fraglimit_override", "g_ca_teams_override", _("The amount of frags needed before the match will end")); break;
+ case MAPINFO_TYPE_FREEZETAG: GameType_ConfigureSliders(me, _("Frag limit:"), 5, 100, 5, "fraglimit_override", "g_freezetag_teams_override", _("The amount of frags needed before the match will end")); break;
+ case MAPINFO_TYPE_CTF: GameType_ConfigureSliders(me, _("Capture limit:"), 1, 20, 1, "capturelimit_override", string_null, _("The amount of captures needed before the match will end")); break;
+ case MAPINFO_TYPE_DOMINATION: GameType_ConfigureSliders(me, _("Point limit:"), 50, 500, 10, "g_domination_point_limit", "g_domination_teams_override", _("The amount of points needed before the match will end")); break;
+ case MAPINFO_TYPE_KEYHUNT: GameType_ConfigureSliders(me, _("Point limit:"), 200, 1500, 50, "g_keyhunt_point_limit", "g_keyhunt_teams_override", _("The amount of points needed before the match will end")); break;
+ case MAPINFO_TYPE_LMS: GameType_ConfigureSliders(me, _("Lives:"), 3, 50, 1, "g_lms_lives_override", string_null, string_null); break;
+ case MAPINFO_TYPE_RACE: GameType_ConfigureSliders(me, _("Laps:"), 1, 25, 1, "g_race_laps_limit", string_null, string_null); break;
+ case MAPINFO_TYPE_NEXBALL: GameType_ConfigureSliders(me, _("Goals:"), 1, 50, 1, "g_nexball_goallimit", string_null, _("The amount of goals needed before the match will end")); break;
+ case MAPINFO_TYPE_ASSAULT: GameType_ConfigureSliders(me, _("Point limit:"), 50, 500, 10, string_null, string_null, string_null); break;
+ case MAPINFO_TYPE_ONSLAUGHT: GameType_ConfigureSliders(me, _("Point limit:"), 50, 500, 10, string_null, string_null, string_null); break;
+ case MAPINFO_TYPE_CTS: GameType_ConfigureSliders(me, _("Point limit:"), 50, 500, 10, string_null, string_null, string_null); break;
+ case MAPINFO_TYPE_INVASION: GameType_ConfigureSliders(me, _("Point limit:"), 50, 500, 10, string_null, string_null, string_null); break;
+ case MAPINFO_TYPE_TEAM_DEATHMATCH: GameType_ConfigureSliders(me, _("Point limit:"), 5, 100, 5, "g_tdm_point_limit", "g_tdm_teams_override", _("The amount of points needed before the match will end")); break;
+ default: GameType_ConfigureSliders(me, _("Frag limit:"), 5, 100, 5, "fraglimit_override", string_null, _("The amount of frags needed before the match will end")); break;
+ }
+}
+
entity makeXonoticServerCreateTab()
{
entity me;
e.onClickEntity = me.mapListBox;
me.mapListBox.startButton = e;
- me.gameTypeChangeNotify(me);
+ GameType_ConfigureSliders_for_CurrentGametype(me);
}
void XonoticServerCreateTab_gameTypeChangeNotify(entity me)
{
- switch(MapInfo_CurrentGametype())
- {
- case MAPINFO_TYPE_CA: GameType_ConfigureSliders(me, _("Frag limit:"), 5, 100, 5, "fraglimit_override", "g_ca_teams_override", _("The amount of frags needed before the match will end")); break;
- case MAPINFO_TYPE_FREEZETAG: GameType_ConfigureSliders(me, _("Frag limit:"), 5, 100, 5, "fraglimit_override", "g_freezetag_teams_override", _("The amount of frags needed before the match will end")); break;
- case MAPINFO_TYPE_CTF: GameType_ConfigureSliders(me, _("Capture limit:"), 1, 20, 1, "capturelimit_override", string_null, _("The amount of captures needed before the match will end")); break;
- case MAPINFO_TYPE_DOMINATION: GameType_ConfigureSliders(me, _("Point limit:"), 50, 500, 10, "g_domination_point_limit", "g_domination_teams_override", _("The amount of points needed before the match will end")); break;
- case MAPINFO_TYPE_KEYHUNT: GameType_ConfigureSliders(me, _("Point limit:"), 200, 1500, 50, "g_keyhunt_point_limit", "g_keyhunt_teams_override", _("The amount of points needed before the match will end")); break;
- case MAPINFO_TYPE_LMS: GameType_ConfigureSliders(me, _("Lives:"), 3, 50, 1, "g_lms_lives_override", string_null, string_null); break;
- case MAPINFO_TYPE_RACE: GameType_ConfigureSliders(me, _("Laps:"), 1, 25, 1, "g_race_laps_limit", string_null, string_null); break;
- case MAPINFO_TYPE_NEXBALL: GameType_ConfigureSliders(me, _("Goals:"), 1, 50, 1, "g_nexball_goallimit", string_null, _("The amount of goals needed before the match will end")); break;
- case MAPINFO_TYPE_ASSAULT: GameType_ConfigureSliders(me, _("Point limit:"), 50, 500, 10, string_null, string_null, string_null); break;
- case MAPINFO_TYPE_ONSLAUGHT: GameType_ConfigureSliders(me, _("Point limit:"), 50, 500, 10, string_null, string_null, string_null); break;
- case MAPINFO_TYPE_CTS: GameType_ConfigureSliders(me, _("Point limit:"), 50, 500, 10, string_null, string_null, string_null); break;
- case MAPINFO_TYPE_INVASION: GameType_ConfigureSliders(me, _("Point limit:"), 50, 500, 10, string_null, string_null, string_null); break;
- case MAPINFO_TYPE_TEAM_DEATHMATCH: GameType_ConfigureSliders(me, _("Point limit:"), 5, 100, 5, "g_tdm_point_limit", "g_tdm_teams_override", _("The amount of points needed before the match will end")); break;
- default: GameType_ConfigureSliders(me, _("Frag limit:"), 5, 100, 5, "fraglimit_override", string_null, _("The amount of frags needed before the match will end")); break;
- }
+ GameType_ConfigureSliders_for_CurrentGametype(me);
me.mapListBox.refilter(me.mapListBox);
}
return weaponarenastring;
}
-AUTOCVAR(g_grappling_hook, bool, _("let players spawn with the grappling hook which allows them to pull themselves up"));
-
string XonoticMutatorsDialog_toString(entity me)
{
string s;
s = strcat(s, ", ", _("Low gravity"));
if(cvar("g_cloaked"))
s = strcat(s, ", ", _("Cloaked"));
- if(autocvar_g_grappling_hook)
+ if(cvar("g_grappling_hook"))
s = strcat(s, ", ", _("Hook"));
if(cvar("g_midair"))
s = strcat(s, ", ", _("Midair"));
#include "rootdialog.qh"
CLASS(XonoticUid2NameDialog, XonoticRootDialog)
METHOD(XonoticUid2NameDialog, fill, void(entity));
- ATTRIB(XonoticUid2NameDialog, title, string);
+ ATTRIB(XonoticUid2NameDialog, title, string, "");
ATTRIB(XonoticUid2NameDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
ATTRIB(XonoticUid2NameDialog, intendedWidth, float, 0.5);
ATTRIB(XonoticUid2NameDialog, rows, float, 4);
if (time < me.zoomTime + 2) // 1 seconds at full alpha, 1 second fading out
{
string zoomString;
- float z;
- z = me.zoomFactor * 100;
- if (z - floor(z) == 0)
- zoomString = sprintf("%d%%", z);
+ float myzoom = me.zoomFactor * 100;
+ if (myzoom - floor(myzoom) == 0)
+ zoomString = sprintf("%d%%", myzoom);
else
- zoomString = sprintf("%.2f%%", z);
+ zoomString = sprintf("%.2f%%", myzoom);
theAlpha = (2 - (time - me.zoomTime));
draw_Text('0.05 0.95 0', zoomString, me.realFontSize, '1 1 1', theAlpha, false);
}
// entire list, otherwise there is no way to know which item is first in its category.
// binary search method suggested by div
- float x;
float begin = 0;
- for(x = 1; x <= category_ent_count; ++x) {
+ for(int j = 1; j <= category_ent_count; ++j) {
float first = begin;
float last = (itemcount - 1);
if (first > last) {
}
float catf = gethostcachenumber(SLIST_FIELD_CATEGORY, first);
float catl = gethostcachenumber(SLIST_FIELD_CATEGORY, last);
- if (catf > x) {
- // The first one is already > x.
- // Therefore, category x does not exist.
+ if (catf > j) {
+ // The first one is already > j.
+ // Therefore, category j does not exist.
// Higher numbered categories do exist though.
- } else if (catl < x) {
- // The last one is < x.
+ } else if (catl < j) {
+ // The last one is < j.
// Thus this category - and any following -
// don't exist.
break;
- } else if (catf == x) {
+ } else if (catf == j) {
// Starts at first. This breaks the loop
// invariant in the binary search and thus has
// to be handled separately.
- if(gethostcachenumber(SLIST_FIELD_CATEGORY, first) != x)
+ if(gethostcachenumber(SLIST_FIELD_CATEGORY, first) != j)
error("Category mismatch I");
if(first > 0)
- if(gethostcachenumber(SLIST_FIELD_CATEGORY, first - 1) == x)
+ if(gethostcachenumber(SLIST_FIELD_CATEGORY, first - 1) == j)
error("Category mismatch II");
- category_name[category_draw_count] = x;
+ category_name[category_draw_count] = j;
category_item[category_draw_count] = first;
++category_draw_count;
begin = first + 1;
} else {
- // At this point, catf <= x < catl, thus
+ // At this point, catf <= j < catl, thus
// catf < catl, thus first < last.
// INVARIANTS:
// last - first >= 1
// catf == gethostcachenumber(SLIST_FIELD_CATEGORY(first)
// catl == gethostcachenumber(SLIST_FIELD_CATEGORY(last)
- // catf < x
- // catl >= x
+ // catf < j
+ // catl >= j
while (last - first > 1) {
float middle = floor((first + last) / 2);
// By loop condition, middle != first && middle != last.
float cat = gethostcachenumber(SLIST_FIELD_CATEGORY, middle);
- if (cat >= x) {
+ if (cat >= j) {
last = middle;
catl = cat;
} else {
catf = cat;
}
}
- if (catl == x) {
- if(gethostcachenumber(SLIST_FIELD_CATEGORY, last) != x)
+ if (catl == j) {
+ if(gethostcachenumber(SLIST_FIELD_CATEGORY, last) != j)
error("Category mismatch III");
if(last > 0)
- if(gethostcachenumber(SLIST_FIELD_CATEGORY, last - 1) == x)
+ if(gethostcachenumber(SLIST_FIELD_CATEGORY, last - 1) == j)
error("Category mismatch IV");
- category_name[category_draw_count] = x;
+ category_name[category_draw_count] = j;
category_item[category_draw_count] = last;
++category_draw_count;
begin = last + 1; // already scanned through these, skip 'em
SLIST_CATEGORY(CAT_SERVERS, "CAT_NORMAL", "CAT_SERVERS", CTX(_("SLCAT^Servers"))) \
SLIST_CATEGORY(CAT_XPM, "CAT_NORMAL", "CAT_SERVERS", CTX(_("SLCAT^Competitive Mode"))) \
SLIST_CATEGORY(CAT_MODIFIED, "", "CAT_SERVERS", CTX(_("SLCAT^Modified Servers"))) \
- SLIST_CATEGORY(CAT_OVERKILL, "", "CAT_SERVERS", CTX(_("SLCAT^Overkill Mode"))) \
- SLIST_CATEGORY(CAT_INSTAGIB, "", "CAT_SERVERS", CTX(_("SLCAT^InstaGib Mode"))) \
+ SLIST_CATEGORY(CAT_OVERKILL, "", "CAT_SERVERS", CTX(_("SLCAT^Overkill"))) \
+ SLIST_CATEGORY(CAT_INSTAGIB, "", "CAT_SERVERS", CTX(_("SLCAT^InstaGib"))) \
SLIST_CATEGORY(CAT_DEFRAG, "", "CAT_SERVERS", CTX(_("SLCAT^Defrag Mode")))
#define SLIST_CATEGORY_AUTOCVAR(name) autocvar_menu_slist_categories_##name##_override
{
// linear scale part
float t = 1 / A + mi;
- float y = exp(1 + A * mi);
- if(f <= y)
- return mi + (t - mi) * (f / y);
+ float u = exp(1 + A * mi);
+ if(f <= u)
+ return mi + (t - mi) * (f / u);
}
return log(f) / A;
}
{
// linear scale part
float t = 1 / A + mi;
- float y = exp(1 + A * mi);
+ float u = exp(1 + A * mi);
if(f <= t)
- return y * ((f - mi) / (t - mi));
+ return u * ((f - mi) / (t - mi));
}
return exp(A * f);
}
#define FOREACH_CLIENT(cond, body) FOREACH_CLIENTSLOT(IS_CLIENT(it) && (cond), body)
+// using the "inside out" version of knuth-fisher-yates shuffle
+// https://en.wikipedia.org/wiki/Fisher–Yates_shuffle
+entity _FCR_clients[255];
+bool _FCR_entered = false;
+#define FOREACH_CLIENT_RANDOM(cond, body) \
+ MACRO_BEGIN { \
+ if (_FCR_entered) LOG_FATAL("FOREACH_CLIENT_RANDOM must not be nested"); \
+ _FCR_entered = true; \
+ int _cnt = 0; \
+ FOREACH_CLIENT(cond, LAMBDA( \
+ int _j = floor(random() * (_cnt + 1)); \
+ if (_j == _cnt) \
+ { \
+ _FCR_clients[_cnt] = it; \
+ } \
+ else \
+ { \
+ _FCR_clients[_cnt] = _FCR_clients[_j]; \
+ _FCR_clients[_j] = it; \
+ } \
+ _cnt++; \
+ )); \
+ for (int _i = 0; _i < _cnt; ++_i) \
+ { \
+ const noref int i = _i; \
+ ITER_CONST noref entity it = _FCR_clients[i]; \
+ if (cond) { LAMBDA(body) } \
+ } \
+ _FCR_entered = false; \
+ } MACRO_END
+
// NOTE: FOR_EACH_MONSTER deprecated! Use the following instead: IL_EACH(g_monsters, true, { code; });
#include <common/effects/all.qh>
#include "miscfunctions.qh"
#include "command/common.qh"
+#include <common/playerstats.qh>
#include <common/state.qh>
.float anticheat_jointime;
CS(this).anticheat_div0_evade_offset = 0;
}
-string anticheat_display(float f, float tmin, float mi, float ma)
+string anticheat_display(float f, float t, float tmin, float mi, float ma)
{
string s;
s = ftos(f);
- if(f <= mi)
- return strcat(s, ":N");
- if(f >= ma)
- return strcat(s, ":Y");
+ if (t >= tmin) {
+ if(f <= mi)
+ return strcat(s, ":N");
+ if(f >= ma)
+ return strcat(s, ":Y");
+ }
return strcat(s, ":-");
}
-void anticheat_report(entity this)
-{
+#define ANTICHEATS(ANTICHEAT) \
+ ANTICHEAT("speedhack", MEAN_EVALUATE(CS(this), anticheat_speedhack), 240, 0, 9999); /* Actually this one seems broken. */ \
+ ANTICHEAT("speedhack_m1", MEAN_EVALUATE(CS(this), anticheat_speedhack_m1), 240, 1.01, 1.25); \
+ ANTICHEAT("speedhack_m2", MEAN_EVALUATE(CS(this), anticheat_speedhack_m2), 240, 1.01, 1.25); \
+ ANTICHEAT("speedhack_m3", MEAN_EVALUATE(CS(this), anticheat_speedhack_m3), 240, 1.01, 1.25); \
+ ANTICHEAT("speedhack_m4", MEAN_EVALUATE(CS(this), anticheat_speedhack_m4), 240, 1.01, 1.25); \
+ ANTICHEAT("speedhack_m5", MEAN_EVALUATE(CS(this), anticheat_speedhack_m5), 240, 1.01, 1.25); \
+ ANTICHEAT("div0_strafebot_old", MEAN_EVALUATE(CS(this), anticheat_div0_strafebot_old), 120, 0.15, 0.4); \
+ ANTICHEAT("div0_strafebot_new", MEAN_EVALUATE(CS(this), anticheat_div0_strafebot_new), 120, 0.25, 0.8); \
+ ANTICHEAT("div0_evade", MEAN_EVALUATE(CS(this), anticheat_div0_evade), 120, 0.2, 0.5); \
+ ANTICHEAT("idle_snapaim", MEAN_EVALUATE(CS(this), anticheat_idle_snapaim_signal) - MEAN_EVALUATE(CS(this), anticheat_idle_snapaim_noise), 120, 0, 9999); \
+ ANTICHEAT("idle_snapaim_signal", MEAN_EVALUATE(CS(this), anticheat_idle_snapaim_signal), 120, 0, 9999); \
+ ANTICHEAT("idle_snapaim_noise", MEAN_EVALUATE(CS(this), anticheat_idle_snapaim_noise), 120, 0, 9999); \
+ ANTICHEAT("idle_snapaim_m2", MEAN_EVALUATE(CS(this), anticheat_idle_snapaim_m2), 120, 0, 9999); \
+ ANTICHEAT("idle_snapaim_m3", MEAN_EVALUATE(CS(this), anticheat_idle_snapaim_m3), 120, 0, 9999); \
+ ANTICHEAT("idle_snapaim_m4", MEAN_EVALUATE(CS(this), anticheat_idle_snapaim_m4), 120, 0, 9999); \
+ ANTICHEAT("idle_snapaim_m7", MEAN_EVALUATE(CS(this), anticheat_idle_snapaim_m7), 120, 0, 9999); \
+ ANTICHEAT("idle_snapaim_m10", MEAN_EVALUATE(CS(this), anticheat_idle_snapaim_m10), 120, 0, 9999)
+
+void anticheat_report_to_eventlog(entity this) {
if(!autocvar_sv_eventlog)
return;
- // TODO(divVerent): Use xonstat to acquire good thresholds.
GameLogEcho(strcat(":anticheat:_time:", ftos(this.playerid), ":", ftos(servertime - CS(this).anticheat_jointime)));
- GameLogEcho(strcat(":anticheat:speedhack:", ftos(this.playerid), ":", anticheat_display(MEAN_EVALUATE(CS(this), anticheat_speedhack), 240, 0, 9999))); // Actually this one seems broken.
- GameLogEcho(strcat(":anticheat:speedhack_m1:", ftos(this.playerid), ":", anticheat_display(MEAN_EVALUATE(CS(this), anticheat_speedhack_m1), 240, 1.01, 1.25)));
- GameLogEcho(strcat(":anticheat:speedhack_m2:", ftos(this.playerid), ":", anticheat_display(MEAN_EVALUATE(CS(this), anticheat_speedhack_m2), 240, 1.01, 1.25)));
- GameLogEcho(strcat(":anticheat:speedhack_m3:", ftos(this.playerid), ":", anticheat_display(MEAN_EVALUATE(CS(this), anticheat_speedhack_m3), 240, 1.01, 1.25)));
- GameLogEcho(strcat(":anticheat:speedhack_m4:", ftos(this.playerid), ":", anticheat_display(MEAN_EVALUATE(CS(this), anticheat_speedhack_m4), 240, 1.01, 1.25)));
- GameLogEcho(strcat(":anticheat:speedhack_m5:", ftos(this.playerid), ":", anticheat_display(MEAN_EVALUATE(CS(this), anticheat_speedhack_m5), 240, 1.01, 1.25)));
- GameLogEcho(strcat(":anticheat:div0_strafebot_old:", ftos(this.playerid), ":", anticheat_display(MEAN_EVALUATE(CS(this), anticheat_div0_strafebot_old), 120, 0.15, 0.4)));
- GameLogEcho(strcat(":anticheat:div0_strafebot_new:", ftos(this.playerid), ":", anticheat_display(MEAN_EVALUATE(CS(this), anticheat_div0_strafebot_new), 120, 0.25, 0.8)));
- GameLogEcho(strcat(":anticheat:div0_evade:", ftos(this.playerid), ":", anticheat_display(MEAN_EVALUATE(CS(this), anticheat_div0_evade), 120, 0.2, 0.5)));
- GameLogEcho(strcat(":anticheat:idle_snapaim:", ftos(this.playerid), ":", anticheat_display(MEAN_EVALUATE(CS(this), anticheat_idle_snapaim_signal) - MEAN_EVALUATE(CS(this), anticheat_idle_snapaim_noise), 120, 0, 9999)));
- GameLogEcho(strcat(":anticheat:idle_snapaim_signal:", ftos(this.playerid), ":", anticheat_display(MEAN_EVALUATE(CS(this), anticheat_idle_snapaim_signal), 120, 0, 9999)));
- GameLogEcho(strcat(":anticheat:idle_snapaim_noise:", ftos(this.playerid), ":", anticheat_display(MEAN_EVALUATE(CS(this), anticheat_idle_snapaim_noise), 120, 0, 9999)));
- GameLogEcho(strcat(":anticheat:idle_snapaim_m2:", ftos(this.playerid), ":", anticheat_display(MEAN_EVALUATE(CS(this), anticheat_idle_snapaim_m2), 120, 0, 9999)));
- GameLogEcho(strcat(":anticheat:idle_snapaim_m3:", ftos(this.playerid), ":", anticheat_display(MEAN_EVALUATE(CS(this), anticheat_idle_snapaim_m3), 120, 0, 9999)));
- GameLogEcho(strcat(":anticheat:idle_snapaim_m4:", ftos(this.playerid), ":", anticheat_display(MEAN_EVALUATE(CS(this), anticheat_idle_snapaim_m4), 120, 0, 9999)));
- GameLogEcho(strcat(":anticheat:idle_snapaim_m7:", ftos(this.playerid), ":", anticheat_display(MEAN_EVALUATE(CS(this), anticheat_idle_snapaim_m7), 120, 0, 9999)));
- GameLogEcho(strcat(":anticheat:idle_snapaim_m10:", ftos(this.playerid), ":", anticheat_display(MEAN_EVALUATE(CS(this), anticheat_idle_snapaim_m10), 120, 0, 9999)));
+#define ANTICHEAT_REPORT_ONE(name, f, tmin, mi, ma) \
+ GameLogEcho(strcat(":anticheat:", name, ":", anticheat_display(f, servertime - CS(this).anticheat_jointime, tmin, mi, ma)))
+ ANTICHEATS(ANTICHEAT_REPORT_ONE);
+#undef ANTICHEAT_REPORT_ONE
}
-float anticheat_getvalue(entity this, string id)
-{
- switch(id) {
- case "_time": return servertime - CS(this).anticheat_jointime;
- case "speedhack": return MEAN_EVALUATE(CS(this), anticheat_speedhack);
- case "speedhack_m1": return MEAN_EVALUATE(CS(this), anticheat_speedhack_m1);
- case "speedhack_m2": return MEAN_EVALUATE(CS(this), anticheat_speedhack_m2);
- case "speedhack_m3": return MEAN_EVALUATE(CS(this), anticheat_speedhack_m3);
- case "speedhack_m4": return MEAN_EVALUATE(CS(this), anticheat_speedhack_m4);
- case "speedhack_m5": return MEAN_EVALUATE(CS(this), anticheat_speedhack_m5);
- case "div0_strafebot_old": return MEAN_EVALUATE(CS(this), anticheat_div0_strafebot_old);
- case "div0_strafebot_new": return MEAN_EVALUATE(CS(this), anticheat_div0_strafebot_new);
- case "div0_evade": return MEAN_EVALUATE(CS(this), anticheat_div0_evade);
- case "idle_snapaim": return MEAN_EVALUATE(CS(this), anticheat_idle_snapaim_signal) - MEAN_EVALUATE(CS(this), anticheat_idle_snapaim_noise);
- case "idle_snapaim_signal": return MEAN_EVALUATE(CS(this), anticheat_idle_snapaim_signal);
- case "idle_snapaim_noise": return MEAN_EVALUATE(CS(this), anticheat_idle_snapaim_noise);
- case "idle_snapaim_m2": return MEAN_EVALUATE(CS(this), anticheat_idle_snapaim_m2);
- case "idle_snapaim_m3": return MEAN_EVALUATE(CS(this), anticheat_idle_snapaim_m3);
- case "idle_snapaim_m4": return MEAN_EVALUATE(CS(this), anticheat_idle_snapaim_m4);
- case "idle_snapaim_m7": return MEAN_EVALUATE(CS(this), anticheat_idle_snapaim_m7);
- case "idle_snapaim_m10": return MEAN_EVALUATE(CS(this), anticheat_idle_snapaim_m10);
- }
- return -1;
+void anticheat_report_to_playerstats(entity this) {
+ PS_GR_P_ADDVAL(this, strcat(PLAYERSTATS_ANTICHEAT, "_time"), servertime - CS(this).anticheat_jointime);
+#define ANTICHEAT_REPORT_ONE(name, f, tmin, mi, ma) \
+ PS_GR_P_ADDVAL(this, strcat(PLAYERSTATS_ANTICHEAT, name), f)
+ ANTICHEATS(ANTICHEAT_REPORT_ONE);
+#undef ANTICHEAT_REPORT_ONE
}
+void anticheat_register_to_playerstats() {
+ PlayerStats_GameReport_AddEvent(strcat(PLAYERSTATS_ANTICHEAT, "_time"));
+#define ANTICHEAT_REGISTER_ONE(name, unused_f, unused_tmin, unused_mi, unused_ma) \
+ PlayerStats_GameReport_AddEvent(strcat(PLAYERSTATS_ANTICHEAT, name))
+ ANTICHEATS(ANTICHEAT_REGISTER_ONE);
+#undef ANTICHEAT_REGISTER_ONE
+}
+
+#undef ANTICHEATS
+
void anticheat_startframe()
{
anticheat_div0_evade_evasion_delta += frametime * (0.5 + random());
#pragma once
void anticheat_init(entity this);
-void anticheat_report(entity this);
+void anticheat_report_to_eventlog(entity this);
+void anticheat_report_to_playerstats(entity this);
+void anticheat_register_to_playerstats();
void anticheat_physics(entity this);
void anticheat_spectatecopy(entity this, entity spectatee);
void anticheat_prethink(entity this);
-float anticheat_getvalue(entity this, string name);
-
void anticheat_startframe();
void anticheat_endframe();
if (!IS_PLAYER(this) || (autocvar_g_campaign && !campaign_bots_may_start))
{
+ this.movement = '0 0 0';
this.bot_nextthink = time + 0.5;
return;
}
// if dead, just wait until we can respawn
if (IS_DEAD(this))
{
+ this.movement = '0 0 0';
if (this.deadflag == DEAD_DEAD)
{
PHYS_INPUT_BUTTON_JUMP(this) = true; // press jump to respawn
if(bot_execute_commands(this))
return;
+ if(this.goalcurrent)
+ if(wasfreed(this.goalcurrent))
+ navigation_poproute(this);
+
if (bot_strategytoken == this)
if (!bot_strategytoken_taken)
{
// TODO: tracewalk() should take care of this job (better path finding under water)
// if we don't have a goal and we're under water look for a waypoint near the "shore" and push it
- if(IS_DEAD(this))
+ if(!(IS_DEAD(this)))
if(!this.goalcurrent)
if(this.waterlevel == WATERLEVEL_SWIMMING || (this.aistatus & AI_STATUS_OUT_WATER))
{
void havocbot_chooseenemy(entity this)
{
- entity head, best, head2;
- float rating, bestrating, hf;
- vector eye, v;
if (autocvar_bot_nofire || IS_INDEPENDENT_PLAYER(this))
{
this.enemy = NULL;
if (time < this.havocbot_chooseenemy_finished)
return;
this.havocbot_chooseenemy_finished = time + autocvar_bot_ai_enemydetectioninterval;
- eye = this.origin + this.view_ofs;
- best = NULL;
- bestrating = 100000000;
- head = head2 = findchainfloat(bot_attack, true);
+ vector eye = this.origin + this.view_ofs;
+ entity best = NULL;
+ float bestrating = 100000000;
// Backup hit flags
- hf = this.dphitcontentsmask;
+ int hf = this.dphitcontentsmask;
// Search for enemies, if no enemy can be seen directly try to look through transparent objects
{
scan_secondary_targets = false;
LABEL(scan_targets)
- for( ; head; head = head.chain)
+ IL_EACH(g_bot_targets, it.bot_attack,
{
if(!scan_secondary_targets)
{
- if(head.classname == "misc_breakablemodel")
+ if(it.classname == "misc_breakablemodel")
{
have_secondary_targets = true;
continue;
}
}
- else
- {
- if(head.classname != "misc_breakablemodel")
- continue;
- }
+ else if(it.classname != "misc_breakablemodel")
+ continue;
- v = (head.absmin + head.absmax) * 0.5;
- rating = vlen(v - eye);
- if (rating<autocvar_bot_ai_enemydetectionradius)
+ vector v = (it.absmin + it.absmax) * 0.5;
+ float rating = vlen2(v - eye);
+ if (vdist(v - eye, <, autocvar_bot_ai_enemydetectionradius))
if (bestrating > rating)
- if (bot_shouldattack(this, head))
+ if (bot_shouldattack(this, it))
{
traceline(eye, v, true, this);
- if (trace_ent == head || trace_fraction >= 1)
+ if (trace_ent == it || trace_fraction >= 1)
{
- best = head;
+ best = it;
bestrating = rating;
}
}
- }
+ });
if(!best && have_secondary_targets && !scan_secondary_targets)
{
scan_secondary_targets = true;
// restart the loop
- head = head2;
bestrating = 100000000;
goto scan_targets;
}
// Set flags to see through transparent objects
this.dphitcontentsmask |= DPCONTENTS_OPAQUE;
- head = head2;
scan_transparent = true;
}
if (!bot_waypoint_queue_owner)
{
- LOG_DEBUG(this.netname, " sutck, taking over the waypoints queue");
+ LOG_DEBUG(this.netname, " stuck, taking over the waypoints queue");
bot_waypoint_queue_owner = this;
bot_waypoint_queue_bestgoal = NULL;
bot_waypoint_queue_bestgoalrating = 0;
if (bot_waypoint_queue_goal)
{
// evaluate the next goal on the queue
- float d = vlen(this.origin - bot_waypoint_queue_goal.origin);
+ float d = vlen2(this.origin - bot_waypoint_queue_goal.origin);
LOG_DEBUG(this.netname, " evaluating ", bot_waypoint_queue_goal.classname, " with distance ", ftos(d));
if(tracewalk(bot_waypoint_queue_goal, this.origin, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), bot_waypoint_queue_goal.origin, bot_navigation_movemode))
{
// Find command
bot_setcurrentcommand(this);
- // if we have no bot command, better return
- // old logic kept pressing previously pressed keys, but that has problems
- // (namely, it means you cannot make a bot "normal" ever again)
- // to keep a bot walking for a while, use the "wait" bot command
- if(bot_cmd == NULL)
- return false;
-
// Ignore all commands except continue when the bot is paused
- if(this.bot_exec_status & BOT_EXEC_STATUS_PAUSED)
- if(bot_cmd.bot_cmd_type!=BOT_CMD_CONTINUE)
+ if(!(self.bot_exec_status & BOT_EXEC_STATUS_PAUSED))
+ {
+ // if we have no bot command, better return
+ // old logic kept pressing previously pressed keys, but that has problems
+ // (namely, it means you cannot make a bot "normal" ever again)
+ // to keep a bot walking for a while, use the "wait" bot command
+ if(bot_cmd == world)
+ return 0;
+ }
+ else if(bot_cmd.bot_cmd_type != BOT_CMD_CONTINUE)
{
if(bot_cmd.bot_cmd_type!=BOT_CMD_NULL)
{
this.hook_time = 0;
this.deadflag = DEAD_NO;
this.crouch = false;
+ this.revive_progress = 0;
this.revival_time = 0;
this.items = 0;
this.strength_finished = 0;
this.invincible_finished = 0;
this.fire_endtime = -1;
+ this.revive_progress = 0;
this.revival_time = 0;
this.air_finished = time + 12;
Called once (not at each match start) when a client begins a connection to the server
=============
*/
-void ClientPreConnect ()
-{ENGINE_EVENT();
+void ClientPreConnect(entity this)
+{
if(autocvar_sv_eventlog)
{
GameLogEcho(sprintf(":connect:%d:%d:%s",
if (IS_REAL_CLIENT(this))
{
- if (!autocvar_g_campaign)
- {
- this.motd_actived_time = -1;
- Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_MOTD, getwelcomemessage(this));
- }
-
if (g_weaponarena_weapons == WEPSET(TUBA))
stuffcmd(this, "cl_cmd settemp chase_active 1\n");
}
});
MUTATOR_CALLHOOK(ClientConnect, this);
+
+ if (IS_REAL_CLIENT(this))
+ {
+ if (!autocvar_g_campaign && !IS_PLAYER(this))
+ {
+ this.motd_actived_time = -1;
+ Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_MOTD, getwelcomemessage(this));
+ }
+ }
}
/*
=============
}
bool zoomstate_set;
-void SetZoomState(entity this, float z)
+void SetZoomState(entity this, float newzoom)
{
- if(z != this.zoomstate)
+ if(newzoom != this.zoomstate)
{
- this.zoomstate = z;
+ this.zoomstate = newzoom;
ClientData_Touch(this);
}
zoomstate_set = true;
.float cmd_floodtime;
.float cmd_floodcount;
-.float lms_spectate_warning;
string MapVote_Suggest(entity this, string m);
return white / (black + white);
}
-float RadarMapAtPoint_Trace(float x, float y, float w, float h, float zmin, float zsize, float q)
+float RadarMapAtPoint_Trace(float e, float f, float w, float h, float zmin, float zsize, float q)
{
vector a, b, mi, ma;
mi = '0 0 0';
ma = '1 0 0' * w + '0 1 0' * h;
- a = '1 0 0' * x + '0 1 0' * y + '0 0 1' * zmin;
- b = '1 0 0' * x + '0 1 0' * y + '0 0 1' * (zsize + zmin);
+ a = '1 0 0' * e + '0 1 0' * f + '0 0 1' * zmin;
+ b = '1 0 0' * e + '0 1 0' * f + '0 0 1' * (zsize + zmin);
return FullTraceFraction(a, mi, ma, b);
}
-float RadarMapAtPoint_LineBlock(float x, float y, float w, float h, float zmin, float zsize, float q)
+float RadarMapAtPoint_LineBlock(float e, float f, float w, float h, float zmin, float zsize, float q)
{
vector o, mi, ma;
float i, r;
mi = '0 0 0';
dz = (zsize / q) * '0 0 1';
ma = '1 0 0' * w + '0 1 0' * h + dz;
- o = '1 0 0' * x + '0 1 0' * y + '0 0 1' * zmin;
+ o = '1 0 0' * e + '0 1 0' * f + '0 0 1' * zmin;
- if (x < world.absmin.x - w) return 0;
- if (y < world.absmin.y - h) return 0;
- if (x > world.absmax.x) return 0;
- if (y > world.absmax.y) return 0;
+ if (e < world.absmin.x - w) return 0;
+ if (f < world.absmin.y - h) return 0;
+ if (e > world.absmax.x) return 0;
+ if (f > world.absmax.y) return 0;
r = 0;
for (i = 0; i < q; ++i)
}
return r / q;
}
-float RadarMapAtPoint_Block(float x, float y, float w, float h, float zmin, float zsize, float q)
+float RadarMapAtPoint_Block(float e, float f, float w, float h, float zmin, float zsize, float q)
{
vector o, mi, ma;
float i, r;
mi = '0 0 0';
dz = (zsize / q) * '0 0 1';
ma = '1 0 0' * w + '0 1 0' * h + dz;
- o = '1 0 0' * x + '0 1 0' * y + '0 0 1' * zmin;
+ o = '1 0 0' * e + '0 1 0' * f + '0 0 1' * zmin;
- if (x < world.absmin.x - w) return 0;
- if (y < world.absmin.y - h) return 0;
- if (x > world.absmax.x) return 0;
- if (y > world.absmax.y) return 0;
+ if (e < world.absmin.x - w) return 0;
+ if (f < world.absmin.y - h) return 0;
+ if (e > world.absmax.x) return 0;
+ if (f > world.absmax.y) return 0;
r = 0;
for (i = 0; i < q; ++i)
}
return r / q;
}
-float RadarMapAtPoint_Sample(float x, float y, float w, float h, float zmin, float zsize, float q)
+float RadarMapAtPoint_Sample(float e, float f, float w, float h, float zmin, float zsize, float q)
{
vector a, b, mi, ma;
mi = '0 0 0';
ma = '1 0 0' * w + '0 1 0' * h;
- a = '1 0 0' * x + '0 1 0' * y + '0 0 1' * zmin;
+ a = '1 0 0' * e + '0 1 0' * f + '0 0 1' * zmin;
b = '1 0 0' * w + '0 1 0' * h + '0 0 1' * zsize;
float c, i;
return c / q;
}
-void sharpen_set(int x, float v)
+void sharpen_set(int b, float v)
{
- sharpen_buffer[x + 2 * RADAR_WIDTH_MAX] = v;
+ sharpen_buffer[b + 2 * RADAR_WIDTH_MAX] = v;
}
-float sharpen_getpixel(int x, int y)
+float sharpen_getpixel(int b, int c)
{
- if (x < 0) return 0;
- if (x >= RADAR_WIDTH_MAX) return 0;
- if (y < 0) return 0;
- if (y > 2) return 0;
- return sharpen_buffer[x + y * RADAR_WIDTH_MAX];
+ if (b < 0) return 0;
+ if (b >= RADAR_WIDTH_MAX) return 0;
+ if (c < 0) return 0;
+ if (c > 2) return 0;
+ return sharpen_buffer[b + c * RADAR_WIDTH_MAX];
}
-float sharpen_get(float x, float a)
+float sharpen_get(float b, float a)
{
- float sum = sharpen_getpixel(x, 1);
+ float sum = sharpen_getpixel(b, 1);
if (a == 0) return sum;
sum *= (8 + 1 / a);
- sum -= sharpen_getpixel(x - 1, 0);
- sum -= sharpen_getpixel(x - 1, 1);
- sum -= sharpen_getpixel(x - 1, 2);
- sum -= sharpen_getpixel(x + 1, 0);
- sum -= sharpen_getpixel(x + 1, 1);
- sum -= sharpen_getpixel(x + 1, 2);
- sum -= sharpen_getpixel(x, 0);
- sum -= sharpen_getpixel(x, 2);
+ sum -= sharpen_getpixel(b - 1, 0);
+ sum -= sharpen_getpixel(b - 1, 1);
+ sum -= sharpen_getpixel(b - 1, 2);
+ sum -= sharpen_getpixel(b + 1, 0);
+ sum -= sharpen_getpixel(b + 1, 1);
+ sum -= sharpen_getpixel(b + 1, 2);
+ sum -= sharpen_getpixel(b, 0);
+ sum -= sharpen_getpixel(b, 2);
return bound(0, sum * a, 1);
}
void sharpen_shift(int w)
if (accepted > 0)
{
- anticheat_report(client);
+ anticheat_report_to_eventlog(client);
return;
}
else
{
if (teamplay)
{
- float x, t_teams, t_players, team_color;
+ float t_teams, t_players, team_color;
// count the total amount of players and total amount of teams
t_players = 0;
for (int i = 1; i <= t_teams; ++i)
{
// find out how many players to assign to this team
- x = (t_players / t_teams);
- x = ((i == 1) ? ceil(x) : floor(x));
+ int pnum = (t_players / t_teams);
+ pnum = ((i == 1) ? ceil(pnum) : floor(pnum));
team_color = Team_NumberToTeam(i);
// sort through the random list of players made earlier
for (int z = 1; z <= maxclients; ++z)
{
- if (!(shuffleteams_teams[i] >= x))
+ if (!(shuffleteams_teams[i] >= pnum))
{
if (!(shuffleteams_players[z])) continue; // not a player, move on to next random slot
// Resets the state of all clients, items, weapons, waypoints, ... of the map.
void reset_map(bool dorespawn)
{
- if (time <= game_starttime && round_handler_IsActive()) round_handler_Reset(game_starttime);
+ if (time <= game_starttime)
+ {
+ if (gameover)
+ return;
+ if (round_handler_IsActive())
+ round_handler_Reset(game_starttime);
+ }
MUTATOR_CALLHOOK(reset_map_global);
// Forces a restart of the game without actually reloading the map // this is a mess...
void ReadyRestart_force()
{
+ if (time <= game_starttime && gameover)
+ return;
+
bprint("^1Server is restarting...\n");
VoteReset();
cursor = trace_endpos;
cursor_ent = trace_ent;
+ MUTATOR_CALLHOOK(PreFormatMessage, this, msg);
+ msg = M_ARGV(1, string);
+
while (1) {
if (n < 1)
break; // too many replacements
/**/
MUTATOR_HOOKABLE(FormatMessage, EV_FormatMessage);
+/** called before any formatting is applied, handy for tweaking the message before scripts get ahold of it */
+#define EV_PreFormatMessage(i, o) \
+ /** player */ i(entity, MUTATOR_ARGV_0_entity) \
+ /** message */ i(string, MUTATOR_ARGV_1_string) \
+ /**/ o(string, MUTATOR_ARGV_1_string) \
+ /**/
+MUTATOR_HOOKABLE(PreFormatMessage, EV_PreFormatMessage);
+
/** returns true if throwing the current weapon shall not be allowed */
#define EV_ForbidThrowCurrentWeapon(i, o) \
/** player */ i(entity, MUTATOR_ARGV_0_entity) \
/** armor */ i(float, MUTATOR_ARGV_3_float) \
/** location */ i(vector, MUTATOR_ARGV_4_vector) \
/** deathtype */ i(int, MUTATOR_ARGV_5_int) \
+ /** potential_damage */ i(float, MUTATOR_ARGV_6_float) \
/**/
MUTATOR_HOOKABLE(PlayerDamaged, EV_PlayerDamaged);
/** keepvelocity? */ i(bool, MUTATOR_ARGV_2_bool) \
/**/
MUTATOR_HOOKABLE(CopyBody, EV_CopyBody);
+
+/** called when sending a chat message, ret argument can be changed to prevent the message */
+#define EV_ChatMessage(i, o) \
+ /** sender */ i(entity, MUTATOR_ARGV_0_entity) \
+ /** ret */ i(int, MUTATOR_ARGV_1_int) \
+ /**/ o(int, MUTATOR_ARGV_1_int) \
+ /**/
+MUTATOR_HOOKABLE(ChatMessage, EV_ChatMessage);
+
+/** return true to prevent sending a chat (private, team or regular) message from reaching a certain player */
+#define EV_ChatMessageTo(i, o) \
+ /** destination player */ i(entity, MUTATOR_ARGV_0_entity) \
+ /** sender */ i(entity, MUTATOR_ARGV_1_entity) \
+ /**/
+MUTATOR_HOOKABLE(ChatMessageTo, EV_ChatMessageTo);
int autocvar_g_ca_point_leadlimit;
float autocvar_g_ca_round_timelimit;
bool autocvar_g_ca_team_spawns;
-int autocvar_g_ca_teams;
+//int autocvar_g_ca_teams;
int autocvar_g_ca_teams_override;
float autocvar_g_ca_warmup;
allowed_to_spawn = true;
ca_teams = autocvar_g_ca_teams_override;
- if (ca_teams < 2) ca_teams = autocvar_g_ca_teams;
+ if (ca_teams < 2)
+ ca_teams = cvar("g_ca_teams"); // read the cvar directly as it gets written earlier in the same frame
ca_teams = bound(2, ca_teams, 4);
int teams = 0;
if(find(NULL, classname, "dom_team") == NULL || autocvar_g_domination_teams_override >= 2)
{
LOG_TRACE("No \"dom_team\" entities found on this map, creating them anyway.");
- domination_teams = bound(2, ((autocvar_g_domination_teams_override < 2) ? autocvar_g_domination_default_teams : autocvar_g_domination_teams_override), 4);
+ domination_teams = autocvar_g_domination_teams_override;
+ if (domination_teams < 2)
+ domination_teams = autocvar_g_domination_default_teams;
+ domination_teams = bound(2, domination_teams, 4);
dom_spawnteams(domination_teams);
}
float autocvar_g_freezetag_frozen_maxtime;
float autocvar_g_freezetag_revive_clearspeed;
float autocvar_g_freezetag_round_timelimit;
-int autocvar_g_freezetag_teams;
+//int autocvar_g_freezetag_teams;
int autocvar_g_freezetag_teams_override;
float autocvar_g_freezetag_warmup;
{
freezetag_teams = autocvar_g_freezetag_teams_override;
if(freezetag_teams < 2)
- freezetag_teams = autocvar_g_freezetag_teams;
+ freezetag_teams = cvar("g_freezetag_teams"); // read the cvar directly as it gets written earlier in the same frame
freezetag_teams = bound(2, freezetag_teams, 4);
int teams = 0;
this.classname = "invasion_spawnpoint";
IL_PUSH(g_invasion_spawns, this);
-
- if(autocvar_g_invasion_zombies_only) // precache only if it hasn't been already
- if(this.spawnmob)
- {
- FOREACH(Monsters, it.netname == this.spawnmob,
- {
- it.mr_precache(it);
- });
- }
}
Monster invasion_PickMonster(int supermonster_count)
{
- if(autocvar_g_invasion_zombies_only)
- return MON_ZOMBIE;
-
RandomSelection_Init();
FOREACH(Monsters, it != MON_Null,
{
if((it.spawnflags & MONSTER_TYPE_PASSIVE) || (it.spawnflags & MONSTER_TYPE_FLY) || (it.spawnflags & MONSTER_TYPE_SWIM) || (it.spawnflags & MONSTER_SIZE_QUAKE) || ((it.spawnflags & MON_FLAG_SUPERMONSTER) && supermonster_count >= 1))
continue;
+ if(autocvar_g_invasion_zombies_only && !(it.spawnflags & MONSTER_TYPE_UNDEAD))
+ continue;
RandomSelection_AddEnt(it, 1, 1);
});
setsize(e, mon.mins, mon.maxs);
if(MoveToRandomMapLocation(e, DPCONTENTS_SOLID | DPCONTENTS_CORPSE | DPCONTENTS_PLAYERCLIP, DPCONTENTS_SLIME | DPCONTENTS_LAVA | DPCONTENTS_SKY | DPCONTENTS_BODY | DPCONTENTS_DONOTENTER, Q3SURFACEFLAG_SKY, 10, 1024, 256))
- monster = spawnmonster(e, "", mon.m_id, NULL, NULL, e.origin, false, false, 2);
- else return;
+ monster = spawnmonster(e, "", mon.monsterid, NULL, NULL, e.origin, false, false, 2);
+ else
+ {
+ delete(e);
+ return;
+ }
}
else // if spawnmob field falls through (unset), fallback to mon (relying on spawnmonster for that behaviour)
- monster = spawnmonster(spawn(), spawn_point.spawnmob, mon.m_id, spawn_point, spawn_point, spawn_point.origin, false, false, 2);
+ monster = spawnmonster(spawn(), spawn_point.spawnmob, mon.monsterid, spawn_point, spawn_point, spawn_point.origin, false, false, 2);
+
+ if(!monster)
+ return;
if(spawn_point) monster.target2 = spawn_point.target2;
monster.spawnshieldtime = time;
void invasion_Initialize()
{
- if(autocvar_g_invasion_zombies_only) {
- Monster mon = MON_ZOMBIE;
- mon.mr_precache(mon);
- } else
- {
- float i;
- entity mon;
- for(i = MON_FIRST; i <= MON_LAST; ++i)
- {
- mon = get_monsterinfo(i);
- if((mon.spawnflags & MONSTER_TYPE_FLY) || (mon.spawnflags & MONSTER_TYPE_SWIM))
- continue; // flying/swimming monsters not yet supported
-
- mon.mr_precache(mon);
- }
- }
-
InitializeEntity(NULL, invasion_DelayedInit, INITPRIO_GAMETYPE);
}
int autocvar_g_balance_keyhunt_score_push;
float autocvar_g_balance_keyhunt_throwvelocity;
-int autocvar_g_keyhunt_teams;
+//int autocvar_g_keyhunt_teams;
int autocvar_g_keyhunt_teams_override;
// #define KH_PLAYER_USE_ATTACHMENT
// bits 5- 9: team of key 2, or 0 for no such key, or 30 for dropped, or 31 for self
// bits 10-14: team of key 3, or 0 for no such key, or 30 for dropped, or 31 for self
// bits 15-19: team of key 4, or 0 for no such key, or 30 for dropped, or 31 for self
-.float kh_state = _STAT(KH_KEYS);
+.int kh_state = _STAT(KH_KEYS);
.float siren_time; // time delay the siren
//.float stuff_time; // time delay to stuffcmd a cvar
-float kh_keystatus[17];
+int kh_keystatus[17];
//kh_keystatus[0] = status of dropped keys, kh_keystatus[1 - 16] = player #
//replace 17 with cvar("maxplayers") or similar !!!!!!!!!
//for(i = 0; i < maxplayers; ++i)
// kh_keystatus[i] = "0";
-float kh_Team_ByID(float t)
+int kh_Team_ByID(int t)
{
if(t == 0) return NUM_TEAM_1;
if(t == 1) return NUM_TEAM_2;
//entity kh_worldkeylist;
.entity kh_worldkeynext;
entity kh_controller;
-//float kh_tracking_enabled;
-float kh_teams;
-float kh_interferemsg_time, kh_interferemsg_team;
+//bool kh_tracking_enabled;
+int kh_teams;
+int kh_interferemsg_team;
+float kh_interferemsg_time;
.entity kh_next, kh_prev; // linked list
.float kh_droptime;
-.float kh_dropperteam;
+.int kh_dropperteam;
.entity kh_previous_owner;
-.float kh_previous_owner_playerid;
+.int kh_previous_owner_playerid;
-float kh_key_dropped, kh_key_carried;
+int kh_key_dropped, kh_key_carried;
int kh_Key_AllOwnedByWhichTeam();
void kh_update_state()
{
entity key;
- float s;
- float f;
-
- s = 0;
+ int f;
+ int s = 0;
FOR_EACH_KH_KEY(key)
{
if(key.owner)
if(gameover)
return;
if(this.cnt > 0)
- { if(getthink(this) != kh_WaitForPlayers) { this.cnt -= 1; } }
+ {
+ if(getthink(this) != kh_WaitForPlayers)
+ this.cnt -= 1;
+ }
else if(this.cnt == 0)
{
this.cnt -= 1;
void kh_Key_Attach(entity key) // runs when a player picks up a key and several times when a key is assigned to a player at the start of a round
{
#ifdef KH_PLAYER_USE_ATTACHMENT
- entity first;
- first = key.owner.kh_next;
+ entity first = key.owner.kh_next;
if(key == first)
{
setattachment(key, key.owner, KH_PLAYER_ATTACHMENT_BONE);
void kh_Key_Detach(entity key) // runs every time a key is dropped or lost. Runs several times times when all the keys are captured
{
#ifdef KH_PLAYER_USE_ATTACHMENT
- entity first;
- first = key.owner.kh_next;
+ entity first = key.owner.kh_next;
if(key == first)
{
if(key.kh_next)
void kh_Key_AssignTo(entity key, entity player) // runs every time a key is picked up or assigned. Runs prior to kh_key_attach
{
- entity k;
- float ownerteam0, ownerteam;
if(key.owner == player)
return;
- ownerteam0 = kh_Key_AllOwnedByWhichTeam();
+ int ownerteam0 = kh_Key_AllOwnedByWhichTeam();
if(key.owner)
{
key.pusher = NULL;
- ownerteam = kh_Key_AllOwnedByWhichTeam();
+ int ownerteam = kh_Key_AllOwnedByWhichTeam();
if(ownerteam != ownerteam0)
{
+ entity k;
if(ownerteam != -1)
{
kh_interferemsg_time = time + 0.2;
kh_interferemsg_team = player.team;
- // audit all key carrier sprites, update them to RUN HERE
+ // audit all key carrier sprites, update them to "Run here"
FOR_EACH_KH_KEY(k)
{
if (!k.owner) continue;
{
kh_interferemsg_time = 0;
- // audit all key carrier sprites, update them to RUN HERE
+ // audit all key carrier sprites, update them to "Key Carrier"
FOR_EACH_KH_KEY(k)
{
if (!k.owner) continue;
PlayerScore_Add(player, SP_KH_PICKUPS, 1);
}
key.kh_dropperteam = 0;
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(key.team, INFO_KEYHUNT_PICKUP), player.netname);
+ int realteam = kh_Team_ByID(key.count);
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(realteam, INFO_KEYHUNT_PICKUP), player.netname);
kh_Key_AssignTo(key, player); // this also updates .kh_state
}
void kh_Key_Remove(entity key) // runs after when all the keys have been collected or when a key has been dropped for more than X seconds
{
- entity o;
- o = key.owner;
+ entity o = key.owner;
kh_Key_AssignTo(key, NULL);
if(o) // it was attached
WaypointSprite_Kill(key.waypointsprite_attachedforcarrier);
void nades_GiveBonus(entity player, float score);
-void kh_WinnerTeam(float teem) // runs when a team wins // Samual: Teem?.... TEEM?!?! what the fuck is wrong with you people
+void kh_WinnerTeam(int winner_team) // runs when a team wins
{
// all key carriers get some points
- vector firstorigin, lastorigin, midpoint;
- float first;
entity key;
- float score;
- score = (NumTeams(kh_teams) - 1) * autocvar_g_balance_keyhunt_score_capture;
+ float score = (NumTeams(kh_teams) - 1) * autocvar_g_balance_keyhunt_score_capture;
DistributeEvenly_Init(score, NumTeams(kh_teams));
// twice the score for 3 team games, three times the score for 4 team games!
// note: for a win by destroying the key, this should NOT be applied
FOR_EACH_KH_KEY(key)
{
- float f;
- f = DistributeEvenly_Get(1);
+ float f = DistributeEvenly_Get(1);
kh_Scores_Event(key.owner, key, "capture", f, 0);
PlayerTeamScore_Add(key.owner, SP_KH_CAPS, ST_KH_CAPS, 1);
nades_GiveBonus(key.owner, autocvar_g_nades_bonus_score_high);
}
- first = true;
+ bool first = true;
string keyowner = "";
FOR_EACH_KH_KEY(key)
if(key.owner.kh_next == key)
first = false;
}
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(teem, INFO_KEYHUNT_CAPTURE), keyowner);
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(winner_team, INFO_KEYHUNT_CAPTURE), keyowner);
first = true;
- midpoint = '0 0 0';
- firstorigin = '0 0 0';
- lastorigin = '0 0 0';
+ vector firstorigin = '0 0 0', lastorigin = '0 0 0', midpoint = '0 0 0';
FOR_EACH_KH_KEY(key)
{
- vector thisorigin;
-
- thisorigin = kh_AttachedOrigin(key);
+ vector thisorigin = kh_AttachedOrigin(key);
//dprint("Key origin: ", vtos(thisorigin), "\n");
midpoint += thisorigin;
te_lightning2(NULL, lastorigin, firstorigin);
}
midpoint = midpoint * (1 / NumTeams(kh_teams));
- te_customflash(midpoint, 1000, 1, Team_ColorRGB(teem) * 0.5 + '0.5 0.5 0.5'); // make the color >=0.5 in each component
+ te_customflash(midpoint, 1000, 1, Team_ColorRGB(winner_team) * 0.5 + '0.5 0.5 0.5'); // make the color >=0.5 in each component
play2all(SND(KH_CAPTURE));
kh_FinishRound();
}
-void kh_LoserTeam(float teem, entity lostkey) // runs when a player pushes a flag carrier off the map
+void kh_LoserTeam(int loser_team, entity lostkey) // runs when a player pushes a flag carrier off the map
{
- entity key, attacker;
- float players;
- float keys;
float f;
-
- attacker = NULL;
+ entity attacker = NULL;
if(lostkey.pusher)
- if(lostkey.pusher.team != teem)
+ if(lostkey.pusher.team != loser_team)
if(IS_PLAYER(lostkey.pusher))
attacker = lostkey.pusher;
- players = keys = 0;
-
if(attacker)
{
if(lostkey.kh_previous_owner)
}
else
{
- float of, fragsleft, i, j, thisteam;
- of = autocvar_g_balance_keyhunt_score_destroyed_ownfactor;
+ int players = 0;
+ float of = autocvar_g_balance_keyhunt_score_destroyed_ownfactor;
- FOREACH_CLIENT(IS_PLAYER(it) && it.team != teem, LAMBDA(++players));
+ FOREACH_CLIENT(IS_PLAYER(it) && it.team != loser_team, LAMBDA(++players));
+ entity key;
+ int keys = 0;
FOR_EACH_KH_KEY(key)
- if(key.owner && key.team != teem)
+ if(key.owner && key.team != loser_team)
++keys;
if(lostkey.kh_previous_owner)
DistributeEvenly_Init(autocvar_g_balance_keyhunt_score_destroyed, keys * of + players);
FOR_EACH_KH_KEY(key)
- if(key.owner && key.team != teem)
+ if(key.owner && key.team != loser_team)
{
f = DistributeEvenly_Get(of);
kh_Scores_Event(key.owner, NULL, "destroyed_holdingkey", f, 0);
}
- fragsleft = DistributeEvenly_Get(players);
+ int fragsleft = DistributeEvenly_Get(players);
// Now distribute these among all other teams...
- j = NumTeams(kh_teams) - 1;
- for(i = 0; i < NumTeams(kh_teams); ++i)
+ int j = NumTeams(kh_teams) - 1;
+ for(int i = 0; i < NumTeams(kh_teams); ++i)
{
- thisteam = kh_Team_ByID(i);
- if(thisteam == teem) // bad boy, no cookie - this WILL happen
+ int thisteam = kh_Team_ByID(i);
+ if(thisteam == loser_team) // bad boy, no cookie - this WILL happen
continue;
players = 0;
}
}
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(lostkey.team, INFO_KEYHUNT_LOST), lostkey.kh_previous_owner.netname);
+ int realteam = kh_Team_ByID(lostkey.count);
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(realteam, INFO_KEYHUNT_LOST), lostkey.kh_previous_owner.netname);
play2all(SND(KH_DESTROY));
te_tarexplosion(lostkey.origin);
}
entity key;
- vector p;
- p = this.owner.origin;
+ vector p = this.owner.origin;
FOR_EACH_KH_KEY(key)
if(vdist(key.owner.origin - p, >, autocvar_g_balance_keyhunt_maxdist))
goto not_winning;
void kh_Key_DropOne(entity key)
{
// prevent collecting this one for some time
- entity player;
- player = key.owner;
+ entity player = key.owner;
key.kh_droptime = time;
key.enemy = player;
kh_Scores_Event(player, key, "dropkey", 0, 0);
PlayerScore_Add(player, SP_KH_LOSSES, 1);
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(key.team, INFO_KEYHUNT_DROP), player.netname);
+ int realteam = kh_Team_ByID(key.count);
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(realteam, INFO_KEYHUNT_DROP), player.netname);
kh_Key_AssignTo(key, NULL);
makevectors(player.v_angle);
void kh_Key_DropAll(entity player, float suicide) // runs whenever a player dies
{
- entity key;
- entity mypusher;
if(player.kh_next)
{
- mypusher = NULL;
+ entity mypusher = NULL;
if(player.pusher)
if(time < player.pushltime)
mypusher = player.pusher;
+
+ entity key;
while((key = player.kh_next))
{
kh_Scores_Event(player, key, "losekey", 0, 0);
PlayerScore_Add(player, SP_KH_LOSSES, 1);
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(key.team, INFO_KEYHUNT_LOST), player.netname);
+ int realteam = kh_Team_ByID(key.count);
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(realteam, INFO_KEYHUNT_LOST), player.netname);
kh_Key_AssignTo(key, NULL);
makevectors('-1 0 0' * (45 + 45 * random()) + '0 360 0' * random());
key.velocity = W_CalculateProjectileVelocity(player, player.velocity, autocvar_g_balance_keyhunt_dropvelocity * v_forward, false);
void kh_StartRound() // runs at the start of each round
{
- int i, players, teem;
-
if(time < game_starttime)
{
kh_Controller_SetThink(game_starttime - time + 0.1, kh_WaitForPlayers);
Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_KEYHUNT);
Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_KEYHUNT_OTHER);
- for(i = 0; i < NumTeams(kh_teams); ++i)
+ for(int i = 0; i < NumTeams(kh_teams); ++i)
{
- teem = kh_Team_ByID(i);
- players = 0;
+ int teem = kh_Team_ByID(i);
+ int players = 0;
entity my_player = NULL;
FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(
if(!IS_DEAD(it) && !PHYS_INPUT_BUTTON_CHAT(it) && it.team == teem)
{
if(attacker.team == targ.team)
{
- entity k;
- float nk;
- nk = 0;
- for(k = targ.kh_next; k != NULL; k = k.kh_next)
+ int nk = 0;
+ for(entity k = targ.kh_next; k != NULL; k = k.kh_next)
++nk;
kh_Scores_Event(attacker, targ.kh_next, "carrierfrag", -nk * autocvar_g_balance_keyhunt_score_collect, 0);
}
// setup variables
kh_teams = autocvar_g_keyhunt_teams_override;
if(kh_teams < 2)
- kh_teams = autocvar_g_keyhunt_teams;
+ kh_teams = cvar("g_keyhunt_teams"); // read the cvar directly as it gets written earlier in the same frame
kh_teams = bound(2, kh_teams, 4);
int teams = 0;
if (this.bot_strategytime < time)
{
- float key_owner_team;
-
this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
navigation_goalrating_start(this);
- key_owner_team = kh_Key_AllOwnedByWhichTeam();
+ int key_owner_team = kh_Key_AllOwnedByWhichTeam();
if(key_owner_team == this.team)
havocbot_goalrating_kh(this, 10, 0.1, 0.1); // defend anyway
else if(key_owner_team == -1)
// a winner!
// and assign him his first place
PlayerScore_Add(head, SP_LMS_RANK, 1);
- return WINNING_YES;
+ if(warmup_stage)
+ return WINNING_NO;
+ else
+ return WINNING_YES;
}
}
}
MUTATOR_HOOKFUNCTION(lms, reset_map_global)
{
lms_lowest_lives = 999;
- lms_next_place = player_count;
}
MUTATOR_HOOKFUNCTION(lms, reset_map_players)
{
- if(restart_mapalreadyrestarted || (time < game_starttime))
- FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(PlayerScore_Add(it, SP_LMS_LIVES, LMS_NewPlayerLives())));
+ FOREACH_CLIENT(true, {
+ TRANSMUTE(Player, it);
+ it.frags = FRAGS_PLAYER;
+ PlayerScore_Add(it, SP_LMS_LIVES, LMS_NewPlayerLives());
+ PutClientInServer(it);
+ });
}
MUTATOR_HOOKFUNCTION(lms, PutClientInServer)
{
entity player = M_ARGV(0, entity);
- // player is dead and becomes observer
- // FIXME fix LMS scoring for new system
- if(PlayerScore_Add(player, SP_LMS_RANK, 0) > 0)
- {
+ if(player.frags == FRAGS_SPECTATOR)
TRANSMUTE(Observer, player);
+ else
+ {
+ float tl = PlayerScore_Add(player, SP_LMS_LIVES, 0);
+ if(tl < lms_lowest_lives)
+ lms_lowest_lives = tl;
+ if(tl <= 0)
+ TRANSMUTE(Observer, player);
+ if(warmup_stage)
+ PlayerScore_Add(player, SP_LMS_RANK, -PlayerScore_Add(player, SP_LMS_RANK, 0));
+ }
+}
+
+MUTATOR_HOOKFUNCTION(lms, ForbidSpawn)
+{
+ entity player = M_ARGV(0, entity);
+
+ if(warmup_stage)
+ return false;
+ if(player.frags == FRAGS_SPECTATOR)
+ return true;
+ if(PlayerScore_Add(player, SP_LMS_LIVES, 0) <= 0)
+ {
Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_LMS_NOLIVES);
+ return true;
}
+ return false;
}
MUTATOR_HOOKFUNCTION(lms, PlayerDies)
void lms_RemovePlayer(entity player)
{
- // Only if the player cannot play at all
- if(PlayerScore_Add(player, SP_LMS_RANK, 0) == 666)
- player.frags = FRAGS_SPECTATOR;
- else
- player.frags = FRAGS_LMS_LOSER;
+ static int quitters = 0;
+ float player_rank = PlayerScore_Add(player, SP_LMS_RANK, 0);
+ if (!player_rank)
+ {
+ int pl_cnt = 0;
+ FOREACH_CLIENT(IS_PLAYER(it), { pl_cnt++; });
+ if (player.lms_spectate_warning != 2)
+ {
+ player.frags = FRAGS_LMS_LOSER;
+ PlayerScore_Add(player, SP_LMS_RANK, pl_cnt + 1);
+ }
+ else
+ {
+ lms_lowest_lives = 999;
+ FOREACH_CLIENT(true, {
+ if (it.frags == FRAGS_LMS_LOSER)
+ {
+ float it_rank = PlayerScore_Add(it, SP_LMS_RANK, 0);
+ if (it_rank > player_rank && it_rank <= 256)
+ PlayerScore_Add(it, SP_LMS_RANK, -1);
+ lms_lowest_lives = 0;
+ }
+ else if (it.frags != FRAGS_SPECTATOR)
+ {
+ float tl = PlayerScore_Add(it, SP_LMS_LIVES, 0);
+ if(tl < lms_lowest_lives)
+ lms_lowest_lives = tl;
+ }
+ });
+ PlayerScore_Add(player, SP_LMS_RANK, 665 - quitters); // different from 666
+ if(!warmup_stage)
+ {
+ PlayerScore_Add(player, SP_LMS_LIVES, -PlayerScore_Add(player, SP_LMS_LIVES, 0));
+ ++quitters;
+ }
+ player.frags = FRAGS_LMS_LOSER;
+ TRANSMUTE(Observer, player);
+ }
+ if (pl_cnt == 2 && !warmup_stage) // a player is forfeiting leaving only one player
+ lms_lowest_lives = 0; // end the game now!
+ }
if(player.killcount != FRAGS_SPECTATOR)
if(PlayerScore_Add(player, SP_LMS_RANK, 0) > 0 && player.lms_spectate_warning != 2)
if(PlayerScore_Add(player, SP_LMS_LIVES, LMS_NewPlayerLives()) <= 0)
{
- PlayerScore_Add(player, SP_LMS_RANK, 666);
+ PlayerScore_Add(player, SP_LMS_RANK, 666); // mark as forced spectator for the hud code
player.frags = FRAGS_SPECTATOR;
}
}
{
entity frag_target = M_ARGV(1, entity);
- // remove a life
- float tl;
- tl = PlayerScore_Add(frag_target, SP_LMS_LIVES, -1);
- if(tl < lms_lowest_lives)
- lms_lowest_lives = tl;
- if(tl <= 0)
+ if (!warmup_stage)
{
- if(!lms_next_place)
- lms_next_place = player_count;
- else
- lms_next_place = min(lms_next_place, player_count);
- PlayerScore_Add(frag_target, SP_LMS_RANK, lms_next_place); // won't ever spawn again
- --lms_next_place;
+ // remove a life
+ int tl = PlayerScore_Add(frag_target, SP_LMS_LIVES, -1);
+ if(tl < lms_lowest_lives)
+ lms_lowest_lives = tl;
+ if(tl <= 0)
+ {
+ int pl_cnt = 0;
+ FOREACH_CLIENT(IS_PLAYER(it), { pl_cnt++; });
+ frag_target.frags = FRAGS_LMS_LOSER;
+ PlayerScore_Add(frag_target, SP_LMS_RANK, pl_cnt);
+ }
}
- M_ARGV(2, float) = 0;
+ M_ARGV(2, float) = 0; // frag score
return true;
}
MUTATOR_HOOKFUNCTION(lms, Bot_FixCount, CBC_ORDER_EXCLUSIVE)
{
FOREACH_CLIENT(IS_REAL_CLIENT(it), LAMBDA(
- ++M_ARGV(0, int);
- ++M_ARGV(1, int);
+ ++M_ARGV(0, int); // activerealplayers
+ ++M_ARGV(1, int); // realplayers
));
return true;
{
entity player = M_ARGV(0, entity);
- if(player.lms_spectate_warning)
+ if(warmup_stage || player.lms_spectate_warning)
{
// for the forfeit message...
player.lms_spectate_warning = 2;
- // mark player as spectator
- PlayerScore_Add(player, SP_LMS_RANK, 666 - PlayerScore_Add(player, SP_LMS_RANK, 0));
}
else
{
- player.lms_spectate_warning = 1;
- sprint(player, "WARNING: you won't be able to enter the game again after spectating in LMS. Use the same command again to spectate anyway.\n");
+ if(player.frags != FRAGS_SPECTATOR && player.frags != FRAGS_LMS_LOSER)
+ {
+ player.lms_spectate_warning = 1;
+ sprint(player, "WARNING: you won't be able to enter the game again after spectating in LMS. Use the same command again to spectate anyway.\n");
+ }
return MUT_SPECCMD_RETURN;
}
return MUT_SPECCMD_CONTINUE;
void lms_Initialize()
{
lms_lowest_lives = 9999;
- lms_next_place = 0;
lms_ScoreRules();
}
#include "../gamemode.qh"
+.float lms_spectate_warning;
#define autocvar_g_lms_lives_override cvar("g_lms_lives_override")
void lms_Initialize();
// lives related defs
float lms_lowest_lives;
-float lms_next_place;
float LMS_NewPlayerLives();
}
-float Cosine_Interpolate(float a, float b, float x)
+float Cosine_Interpolate(float a, float b, float c)
{
float ft,f;
- ft = x * 3.1415927;
+ ft = c * 3.1415927;
f = (1 - cos(ft)) * 0.5;
return a*(1-f) + b*f;
damage /= sqrt(bound(1.0, attacker.cvar_cl_handicap, 100.0));
}
+ if (time < this.spawnshieldtime && autocvar_g_spawnshield_blockdamage < 1)
+ damage *= 1 - max(0, autocvar_g_spawnshield_blockdamage);
+
if(DEATH_ISWEAPON(deathtype, WEP_TUBA))
{
// tuba causes blood to come out of the ears
else
Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, this, attacker);
-
v = healtharmor_applydamage(this.armorvalue, autocvar_g_balance_armor_blockpercent, deathtype, damage);
take = v.x;
save = v.y;
this.istypefrag = 0;
}
- if (time < this.spawnshieldtime && autocvar_g_spawnshield_blockdamage < 1)
- {
- vector v = healtharmor_applydamage(this.armorvalue, max(0, autocvar_g_spawnshield_blockdamage), deathtype, damage);
- take = v.x;
- save = v.y;
- }
-
MUTATOR_CALLHOOK(PlayerDamage_SplitHealthArmor, inflictor, attacker, this, force, take, save, deathtype, damage);
take = bound(0, M_ARGV(4, float), this.health);
save = bound(0, M_ARGV(5, float), this.armorvalue);
{
WeaponStats_LogDamage(awep.m_id, abot, PS(this).m_weapon.m_id, vbot, dh + da);
}
- if (dh + da)
+ if (damage)
{
- MUTATOR_CALLHOOK(PlayerDamaged, attacker, this, dh, da, hitloc, deathtype);
+ MUTATOR_CALLHOOK(PlayerDamaged, attacker, this, dh, da, hitloc, deathtype, damage);
}
if (this.health < 1)
ret = 1;
}
+ MUTATOR_CALLHOOK(ChatMessage, source, ret);
+ ret = M_ARGV(1, int);
+
if(sourcemsgstr != "" && ret != 0)
{
if(ret < 0) // faked message, because the player is muted
else if(privatesay) // private message, between 2 people only
{
sprint(source, sourcemsgstr);
- sprint(privatesay, msgstr);
if (!autocvar_g_chat_tellprivacy) { dedicated_print(msgstr); } // send to server console too if "tellprivacy" is disabled
- if(cmsgstr != "")
- centerprint(privatesay, cmsgstr);
+ if(!MUTATOR_CALLHOOK(ChatMessageTo, privatesay, source))
+ {
+ sprint(privatesay, msgstr);
+ if(cmsgstr != "")
+ centerprint(privatesay, cmsgstr);
+ }
}
else if ( teamsay && source.active_minigame )
{
sprint(source, sourcemsgstr);
dedicated_print(msgstr); // send to server console too
- FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != source && it.active_minigame == source.active_minigame, sprint(it, msgstr));
+ FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != source && it.active_minigame == source.active_minigame && !MUTATOR_CALLHOOK(ChatMessageTo, it, source), sprint(it, msgstr));
}
else if(teamsay > 0) // team message, only sent to team mates
{
dedicated_print(msgstr); // send to server console too
if(sourcecmsgstr != "")
centerprint(source, sourcecmsgstr);
- FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it) && it != source && it.team == source.team, {
+ FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it) && it != source && it.team == source.team && !MUTATOR_CALLHOOK(ChatMessageTo, it, source), {
sprint(it, msgstr);
if(cmsgstr != "")
centerprint(it, cmsgstr);
{
sprint(source, sourcemsgstr);
dedicated_print(msgstr); // send to server console too
- FOREACH_CLIENT(!IS_PLAYER(it) && IS_REAL_CLIENT(it) && it != source, sprint(it, msgstr));
+ FOREACH_CLIENT(!IS_PLAYER(it) && IS_REAL_CLIENT(it) && it != source && !MUTATOR_CALLHOOK(ChatMessageTo, it, source), sprint(it, msgstr));
}
else
{
dedicated_print(msgstr); // send to server console too
MX_Say(strcat(playername(source), "^7: ", msgin));
}
- FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != source, sprint(it, msgstr));
+ FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != source && !MUTATOR_CALLHOOK(ChatMessageTo, it, source), sprint(it, msgstr));
}
}
#include "round_handler.qh"
+#include "campaign.qh"
#include "command/vote.qh"
#include "../common/util.qh"
if (this.cnt > 0) // countdown running
{
- if (this.canRoundStart())
+ if (this.canRoundStart() && !(autocvar_g_campaign && !campaign_bots_may_start))
{
if (this.cnt == this.count + 1) round_starttime = time + this.count;
int f = this.cnt - 1;
void Weapon_whereis(Weapon this, entity cl)
{
if (!autocvar_g_showweaponspawns) return;
- IL_EACH(g_items, it.weapon == this.m_id,
+ IL_EACH(g_items, it.weapon == this.m_id && (it.ItemStatus & ITS_AVAILABLE),
{
if (it.classname == "droppedweapon" && autocvar_g_showweaponspawns < 2)
continue;