set bot_ai_aimskill_offset 0.3 "Amount of error induced to the bots aim"
set bot_ai_aimskill_think 1 "Aiming velocity. Use values below 1 for slower aiming"
set bot_ai_custom_weapon_priority_distances "300 850" "Define close and far distances in any order. Based on the distance to the enemy bots will choose different weapons"
-set bot_ai_custom_weapon_priority_far "vaporizer vortex rifle electro devastator mortar hagar hlac crylink blaster machinegun fireball seeker shotgun tuba minelayer" "Desired weapons for far distances ordered by priority"
-set bot_ai_custom_weapon_priority_mid "vaporizer devastator vortex fireball seeker mortar electro machinegun crylink hlac hagar shotgun blaster rifle tuba minelayer arc shockwave" "Desired weapons for middle distances ordered by priority"
-set bot_ai_custom_weapon_priority_close "vaporizer shotgun vortex machinegun hlac tuba seeker hagar crylink mortar electro devastator blaster fireball rifle minelayer arc shockwave" "Desired weapons for close distances ordered by priority"
+set bot_ai_custom_weapon_priority_far "vaporizer vortex rifle electro devastator mortar hagar hlac crylink blaster machinegun fireball seeker shotgun shockwave tuba minelayer" "Desired weapons for far distances ordered by priority"
+set bot_ai_custom_weapon_priority_mid "vaporizer devastator vortex fireball seeker mortar electro machinegun arc crylink hlac hagar shotgun shockwave blaster rifle tuba minelayer" "Desired weapons for middle distances ordered by priority"
+set bot_ai_custom_weapon_priority_close "vaporizer shotgun shockwave vortex machinegun arc hlac tuba seeker hagar crylink mortar electro devastator blaster fireball rifle minelayer" "Desired weapons for close distances ordered by priority"
set bot_ai_weapon_combo 1 "Enable bots to do weapon combos"
set bot_ai_weapon_combo_threshold 0.4 "Try to make a combo N seconds after the last attack"
set bot_ai_friends_aware_pickup_radius "500" "Bots will not pickup items if a team mate is this distance near the item"
set g_tdm 0 "Team Deathmatch: the team who kills their opponents most often wins"
set g_tdm_on_dm_maps 0 "when this is set, all DM maps automatically support TDM"
-seta teamplay_mode 4 "default teamplay setting in team games. 1 = no friendly fire, self damage. 2 = friendly fire and self damage enabled. 3 = no friendly fire, but self damage enabled. 4 = obey the cvars g_mirrordamage*, g_friendlyfire* and g_teamdamage_threshold*"
-seta g_mirrordamage 0.700000 "for teamplay 4: mirror damage factor"
-seta g_mirrordamage_virtual 1 "for teamplay 4: do not actually apply mirror damage, just show graphics effect for it"
-seta g_mirrordamage_onlyweapons 0 "for teamplay 4: only apply mirror damage if the attack was from a weapon"
-seta g_friendlyfire 0.500000 "for teamplay 4: fiendly fire factor"
-seta g_friendlyfire_virtual 1 "for teamplay 4: do not actually apply friendly fire, just show graphics effect for it"
-seta g_friendlyfire_virtual_force 1 "for teamplay 4: apply force even though damage was made virtual only"
-seta g_teamdamage_threshold 40 "for teamplay 4: threshold over which to apply mirror damage"
-seta g_teamdamage_resetspeed 20 "for teamplay 4: how fast player's teamdamage count decreases"
+seta teamplay_mode 4 "default teamplay setting in team games. 1 = no friendly fire, self damage. 2 = friendly fire and self damage enabled. 3 = no friendly fire, but self damage enabled. 4 = obey the cvars g_mirrordamage*, g_friendlyfire* and g_teamdamage*"
+seta g_mirrordamage 0.7 "for teamplay_mode 4: mirror damage factor"
+seta g_mirrordamage_virtual 1 "for teamplay_mode 4: do not actually apply mirror damage, just show graphics effect for it"
+seta g_mirrordamage_onlyweapons 0 "for teamplay_mode 4: only apply mirror damage if the attack was from a weapon"
+seta g_friendlyfire 0.5 "for teamplay_mode 4: friendly fire factor"
+seta g_friendlyfire_virtual 1 "for teamplay_mode 4: do not actually apply friendly fire, just show graphics effect for it"
+seta g_friendlyfire_virtual_force 1 "for teamplay_mode 4: apply force even though damage was made virtual only"
+seta g_teamdamage_threshold 40 "for teamplay_mode 4: threshold over which to apply mirror damage"
+seta g_teamdamage_resetspeed 20 "for teamplay_mode 4: how fast player's teamdamage count decreases"
seta g_balance_teams 1 "automatically balance out players entering instead of asking them for their preferred team"
seta g_balance_teams_prevent_imbalance 1 "prevent players from changing to larger teams"
// helper
// these non-saved engine cvars shall be saved
-alias makesaved "seta $1 \"${$1 ?}\"
+alias makesaved "seta $1 \"${$1 ?}\""
makesaved cl_maxfps_alwayssleep
makesaved cl_port
makesaved gl_finish
sv_gameplayfix_q2airaccelerate 1
sv_gameplayfix_stepmultipletimes 1
-cl_gameplayfix_fixedcheckwatertransition 1
-
// delay for "kill" to prevent abuse
set g_balance_kill_delay 2
set g_balance_kill_antispam 5
set g_jump_grunt 0 "Do you make a grunting noise every time you jump? Is it the same grunting noise every time?"
-seta cl_weaponpriority "vaporizer vortex fireball mortar machinegun hagar rifle arc electro devastator crylink minelayer shotgun hlac tuba blaster porto seeker hook" "weapon priority list"
+seta cl_weaponpriority "vaporizer vortex fireball mortar machinegun hagar rifle arc electro devastator crylink minelayer shotgun shockwave hlac tuba blaster porto seeker hook" "weapon priority list"
seta cl_weaponpriority_useforcycling 0 "when set, weapon cycling by the mouse wheel makes use of the weapon priority list (the special value 2 uses the weapon ID list for cycling)"
seta cl_weaponpriority0 "devastator mortar hagar seeker fireball" "use weapon_priority_0_prev for prev gun from this list, weapon_priority_0_best for best gun, weapon_priority_0_next for next gun. Default value: explosives"
seta cl_weaponpriority1 "vaporizer vortex crylink hlac arc electro blaster shockwave" "use weapon_priority_1_prev for prev gun from this list, weapon_priority_1_best for best gun, weapon_priority_1_next for next gun. Default value: energy"
seta cl_weaponpriority2 "vaporizer vortex rifle" "use weapon_priority_2_prev for prev gun from this list, weapon_priority_2_best for best gun, weapon_priority_2_next for next gun. Default value: hitscan exact"
-seta cl_weaponpriority3 "vaporizer vortex rifle machinegun shotgun" "use weapon_priority_3_prev for prev gun from this list, weapon_priority_3_best for best gun, weapon_priority_3_next for next gun. Default value: hitscan all"
-seta cl_weaponpriority4 "mortar minelayer hlac hagar crylink seeker shotgun" "use weapon_priority_4_prev for prev gun from this list, weapon_priority_4_best for best gun, weapon_priority_4_next for next gun. Default value: spam weapons"
+seta cl_weaponpriority3 "vaporizer vortex rifle machinegun shotgun shockwave" "use weapon_priority_3_prev for prev gun from this list, weapon_priority_3_best for best gun, weapon_priority_3_next for next gun. Default value: hitscan all"
+seta cl_weaponpriority4 "mortar minelayer hlac hagar crylink seeker shotgun shockwave" "use weapon_priority_4_prev for prev gun from this list, weapon_priority_4_best for best gun, weapon_priority_4_next for next gun. Default value: spam weapons"
seta cl_weaponpriority5 "blaster shockwave hook porto" "use weapon_priority_5_prev for prev gun from this list, weapon_priority_5_best for best gun, weapon_priority_5_next for next gun. Default value: weapons for moving"
seta cl_weaponpriority6 "" "use weapon_priority_6_prev for prev gun from this list, weapon_priority_6_best for best gun, weapon_priority_6_next for next gun"
seta cl_weaponpriority7 "" "use weapon_priority_7_prev for prev gun from this list, weapon_priority_7_best for best gun, weapon_priority_7_next for next gun"
set cl_weapon_stay_color "2 0.5 0.5" "Color of picked up weapons when g_weapon_stay > 0"
set cl_weapon_stay_alpha 0.75 "Alpha of picked up weapons when g_weapon_stay > 0"
+ set sv_showspectators 0 "Show who's spectating who in the player info panel. Shouldn't be used on competitive servers, also disable when watching a suspected cheater"
+ seta cl_showspectators 1
+
// Facility for config.cfg use ONLY.
// Interpreted in post-config.cfg.
seta menu_forced_saved_cvars "" "These cvars will always be saved, despite engine/Xonotic cvar saving status"
// Info messages panel (#14)
-#define drawInfoMessage(s) MACRO_BEGIN { \
- if(autocvar_hud_panel_infomessages_flip) \
- o.x = pos.x + mySize.x - stringwidth(s, true, fontsize); \
- drawcolorcodedstring(o, s, fontsize, a, DRAWFLAG_NORMAL); \
- o.y += fontsize.y; \
+float autocvar_hud_panel_infomessages_group_fadetime = 0.4;
+float autocvar_hud_panel_infomessages_group_time = 6;
+const int IMG_COUNT = 1; // number of InfoMessage Groups
+float img_fade[IMG_COUNT];
+int img_cur_msg[IMG_COUNT];
+float img_time[IMG_COUNT];
+
+int img_select(int group_id)
+{
+ float fadetime = max(0.001, autocvar_hud_panel_infomessages_group_fadetime);
+ if(time > img_time[group_id])
+ {
+ img_fade[group_id] = max(0, img_fade[group_id] - frametime / fadetime);
+ if(!img_fade[group_id])
+ {
+ ++img_cur_msg[group_id];
+ img_time[group_id] = floor(time) + autocvar_hud_panel_infomessages_group_time;
+ }
+ }
+ else
+ img_fade[group_id] = min(1, img_fade[group_id] + frametime / fadetime);
+ return img_cur_msg[group_id];
+}
+
+float stringwidth_colors(string s, vector theSize);
+vector InfoMessages_drawstring(string s, vector pos, vector sz, float a, vector fontsize)
+{
+ getWrappedLine_remaining = s;
+ float offset = 0;
+ while(getWrappedLine_remaining)
+ {
+ s = getWrappedLine(sz.x - offset, fontsize, stringwidth_colors);
+ if(autocvar_hud_panel_infomessages_flip)
+ offset = sz.x - stringwidth_colors(s, fontsize) - offset;
+ drawcolorcodedstring(pos + eX * offset, s, fontsize, a, DRAWFLAG_NORMAL);
+ pos.y += fontsize.y;
+ offset = fontsize.x;
+ }
+ pos.y += fontsize.y * 0.25;
+ return pos;
+}
+
+#define InfoMessage(s) MACRO_BEGIN { \
+ pos = InfoMessages_drawstring(s, pos, mySize, ((img_curr_group >= 0) ? panel_fg_alpha * img_fade[img_curr_group] : panel_fg_alpha), fontsize); \
+ img_curr_group = -1; \
} MACRO_END
+
void HUD_InfoMessages()
{
if(!autocvar__hud_configure)
mySize -= '2 2 0' * panel_bg_padding;
}
- // always force 5:1 aspect
- vector newSize = '0 0 0';
- if(mySize.x/mySize.y > 5)
- {
- newSize.x = 5 * mySize.y;
- newSize.y = mySize.y;
-
- pos.x = pos.x + (mySize.x - newSize.x) / 2;
- }
- else
- {
- newSize.y = 1/5 * mySize.x;
- newSize.x = mySize.x;
-
- pos.y = pos.y + (mySize.y - newSize.y) / 2;
- }
-
- mySize = newSize;
- entity tm;
- vector o;
- o = pos;
-
- vector fontsize;
- fontsize = '0.20 0.20 0' * mySize.y;
-
- float a;
- a = panel_fg_alpha;
-
+ vector fontsize = '0.2 0.2 0' * mySize.y;
string s;
+ int img_curr_group = -1;
if(!autocvar__hud_configure)
{
if(spectatee_status)
{
- a = 1;
if(spectatee_status == -1)
s = _("^1Observing");
else
s = sprintf(_("^1Spectating: ^7%s"), entcs_GetName(current_player));
- drawInfoMessage(s);
+ InfoMessage(s);
- if(spectatee_status == -1)
- s = sprintf(_("^1Press ^3%s^1 to spectate"), getcommandkey("primary fire", "+fire"));
- else
- s = sprintf(_("^1Press ^3%s^1 or ^3%s^1 for next or previous player"), getcommandkey("next weapon", "weapnext"), getcommandkey("previous weapon", "weapprev"));
- drawInfoMessage(s);
-
- if(spectatee_status == -1)
- s = sprintf(_("^1Use ^3%s^1 or ^3%s^1 to change the speed"), getcommandkey("next weapon", "weapnext"), getcommandkey("previous weapon", "weapprev"));
- else
- s = sprintf(_("^1Press ^3%s^1 to observe"), getcommandkey("secondary fire", "+fire2"));
- drawInfoMessage(s);
-
- s = sprintf(_("^1Press ^3%s^1 for gamemode info"), getcommandkey("server info", "+show_info"));
- drawInfoMessage(s);
+ img_curr_group = 0;
+ switch(img_select(img_curr_group) % 3)
+ {
+ default:
+ case 0:
+ if(spectatee_status == -1)
+ s = sprintf(_("^1Press ^3%s^1 to spectate"), getcommandkey(_("primary fire"), "+fire"));
+ else
+ s = sprintf(_("^1Press ^3%s^1 or ^3%s^1 for next or previous player"), getcommandkey(_("next weapon"), "weapnext"), getcommandkey(_("previous weapon"), "weapprev"));
+ break;
+ case 1:
+ if(spectatee_status == -1)
+ s = sprintf(_("^1Use ^3%s^1 or ^3%s^1 to change the speed"), getcommandkey(_("next weapon"), "weapnext"), getcommandkey(_("previous weapon"), "weapprev"));
+ else
+ s = sprintf(_("^1Press ^3%s^1 to observe, ^3%s^1 to change camera mode"), getcommandkey(_("secondary fire"), "+fire2"), getcommandkey(_("drop weapon"), "dropweapon"));
+ break;
+ case 2:
+ s = sprintf(_("^1Press ^3%s^1 for gamemode info"), getcommandkey(_("server info"), "+show_info"));
+ break;
+ }
+ InfoMessage(s);
if(gametype == MAPINFO_TYPE_LMS)
{
else if(sk.(scores[ps_primary]) > 0)
s = _("^1You have no more lives left");
else
- s = sprintf(_("^1Press ^3%s^1 to join"), getcommandkey("jump", "+jump"));
+ s = sprintf(_("^1Press ^3%s^1 to join"), getcommandkey(_("jump"), "+jump"));
}
else
- s = sprintf(_("^1Press ^3%s^1 to join"), getcommandkey("jump", "+jump"));
- drawInfoMessage(s);
+ s = sprintf(_("^1Press ^3%s^1 to join"), getcommandkey(_("jump"), "+jump"));
+ InfoMessage(s);
}
if (time < STAT(GAMESTARTTIME))
//we need to ceil, otherwise the countdown would be off by .5 when using round()
float countdown = ceil(STAT(GAMESTARTTIME) - time);
s = sprintf(_("^1Game starts in ^3%d^1 seconds"), countdown);
- drawInfoMessage(s);
+ InfoMessage(s);
}
if(warmup_stage)
{
s = _("^2Currently in ^1warmup^2 stage!");
- drawInfoMessage(s);
+ InfoMessage(s);
}
string blinkcolor;
if(ready_waiting_for_me)
{
if(warmup_stage)
- s = sprintf(_("%sPress ^3%s%s to end warmup"), blinkcolor, getcommandkey("ready", "ready"), blinkcolor);
+ s = sprintf(_("%sPress ^3%s%s to end warmup"), blinkcolor, getcommandkey(_("ready"), "ready"), blinkcolor);
else
- s = sprintf(_("%sPress ^3%s%s once you are ready"), blinkcolor, getcommandkey("ready", "ready"), blinkcolor);
+ s = sprintf(_("%sPress ^3%s%s once you are ready"), blinkcolor, getcommandkey(_("ready"), "ready"), blinkcolor);
}
else
{
else
s = _("^2Waiting for others to ready up...");
}
- drawInfoMessage(s);
+ InfoMessage(s);
}
else if(warmup_stage && !spectatee_status)
{
- s = sprintf(_("^2Press ^3%s^2 to end warmup"), getcommandkey("ready", "ready"));
- drawInfoMessage(s);
+ s = sprintf(_("^2Press ^3%s^2 to end warmup"), getcommandkey(_("ready"), "ready"));
+ InfoMessage(s);
}
if(teamplay && !spectatee_status && gametype != MAPINFO_TYPE_CA && teamnagger)
{
float ts_min = 0, ts_max = 0;
- tm = teams.sort_next;
+ entity tm = teams.sort_next;
if (tm)
{
for (; tm.sort_next; tm = tm.sort_next)
{
s = strcat(blinkcolor, _("Teamnumbers are unbalanced!"));
tm = GetTeam(myteam, false);
- if (tm)
- if (tm.team != NUM_SPECTATOR)
- if (tm.team_size == ts_max)
- s = strcat(s, sprintf(_(" Press ^3%s%s to adjust"), getcommandkey("team menu", "menu_showteamselect"), blinkcolor));
- drawInfoMessage(s);
+ if (tm && tm.team != NUM_SPECTATOR && tm.team_size == ts_max)
+ s = strcat(s, sprintf(_(" Press ^3%s%s to adjust"), getcommandkey(_("team menu"), "menu_showteamselect"), blinkcolor));
+ InfoMessage(s);
}
}
}
+
+ if(autocvar_cl_showspectators)
+ if(num_spectators)
+ //if(spectatee_status != -1)
+ {
+ s = ((spectatee_status) ? _("^1Spectating this player:") : _("^1Spectating you:"));
+ //drawInfoMessage(s)
+ int limit = min(num_spectators, MAX_SPECTATORS);
+ for(int i = 0; i < limit; ++i)
+ {
+ float slot = spectatorlist[i];
+ if(i == 0)
+ s = strcat(s, " ^7", entcs_GetName(slot));
+ else
+ s = strcat("^7", entcs_GetName(slot));
+ drawInfoMessage(s);
+ }
+ }
}
else
{
- s = _("^7Press ^3ESC ^7to show HUD options.");
- drawInfoMessage(s);
- s = _("^3Doubleclick ^7a panel for panel-specific options.");
- drawInfoMessage(s);
- s = _("^3CTRL ^7to disable collision testing, ^3SHIFT ^7and");
- drawInfoMessage(s);
- s = _("^3ALT ^7+ ^3ARROW KEYS ^7for fine adjustments.");
- drawInfoMessage(s);
+ InfoMessage(_("^7Press ^3ESC ^7to show HUD options."));
+ InfoMessage(_("^3Doubleclick ^7a panel for panel-specific options."));
+ InfoMessage(_("^3CTRL ^7to disable collision testing, ^3SHIFT ^7and"));
+ InfoMessage(_("^3ALT ^7+ ^3ARROW KEYS ^7for fine adjustments."));
}
}
{
WarpZone_Shutdown();
- remove(teams);
- remove(players);
+ delete(teams);
+ delete(players);
db_close(binddb);
db_close(tempdb);
if(autocvar_cl_db_saveasdump)
else
angles_held_status = 0;
+ if(f & 16)
+ {
+ num_spectators = ReadByte();
+
+ float i, slot;
+
+ for(i = 0; i < MAX_SPECTATORS; ++i)
+ spectatorlist[i] = 0; // reset list first
+
+ for(i = 0; i < num_spectators; ++i)
+ {
+ slot = ReadByte();
+ spectatorlist[i] = slot - 1;
+ }
+ }
+
return = true;
if(newspectatee_status != spectatee_status)
precache_model(this.mdl);
setmodel(this, this.mdl);
this.drawmask = MASK_NORMAL;
- //this.movetype = MOVETYPE_NOCLIP;
+ //this.move_movetype = MOVETYPE_NOCLIP;
//this.draw = Spawn_Draw;
+ IL_PUSH(g_drawables, this);
}*/
if(autocvar_cl_spawn_point_particles)
{
else { this.cnt = particleeffectnum(EFFECT_SPAWNPOINT_NEUTRAL); }
this.draw = Spawn_Draw;
+ if (is_new) IL_PUSH(g_drawables, this);
setpredraw(this, Spawn_PreDraw);
this.fade_start = autocvar_cl_spawn_point_dist_min;
this.fade_end = autocvar_cl_spawn_point_dist_max;
return;
}
if (this.enttype) Ent_Remove(this);
- remove(this);
+ delete(this);
}
void Gamemode_Init()
}
}
-string getcommandkey(string text, string command)
+string _getcommandkey(string cmd_name, string command, bool forcename)
{
string keys;
float n, j, k, l = 0;
if (!autocvar_hud_showbinds)
- return text;
+ return cmd_name;
keys = db_get(binddb, command);
if (keys == "")
if (keys == "NO_KEY") {
if (autocvar_hud_showbinds > 1)
- return sprintf(_("%s (not bound)"), text);
+ return sprintf(_("%s (not bound)"), cmd_name);
else
- return text;
+ return cmd_name;
}
- else if (autocvar_hud_showbinds > 1)
- return sprintf("%s (%s)", text, keys);
+ else if (autocvar_hud_showbinds > 1 || forcename)
+ return sprintf("%s (%s)", cmd_name, keys);
else
return keys;
}
.float eliminated;
.void(entity) draw;
+IntrusiveList g_drawables;
+STATIC_INIT(g_drawables) { g_drawables = IL_NEW(); }
.void(entity) draw2d;
+IntrusiveList g_drawables_2d;
+STATIC_INIT(g_drawables_2d) { g_drawables_2d = IL_NEW(); }
.void(entity) entremove;
float drawframetime;
vector view_origin, view_forward, view_right, view_up;
+IntrusiveList g_radarlinks;
+STATIC_INIT(g_radarlinks) { g_radarlinks = IL_NEW(); }
+IntrusiveList g_radaricons;
+STATIC_INIT(g_radaricons) { g_radaricons = IL_NEW(); }
+
bool button_zoom;
bool spectatorbutton_zoom;
bool button_attack2;
void Fog_Force();
-string getcommandkey(string text, string command);
+string _getcommandkey(string text, string command, bool forcename);
+#define getcommandkey(cmd_name, command) _getcommandkey(cmd_name, command, false)
+#define getcommandkey_forcename(cmd_name, command) _getcommandkey(cmd_name, command, true)
string vote_called_vote;
float ready_waiting;
float hud;
float view_quality;
+
+ int num_spectators;
+ const int MAX_SPECTATORS = 7;
+ int spectatorlist[MAX_SPECTATORS];
+
int framecount;
.float health;
int autocvar_sv_gentle;
#define autocvar_sv_gravity cvar("sv_gravity")
string autocvar_sv_intermission_cdtrack;
-float autocvar_sv_itemstime;
+int autocvar_sv_itemstime;
string autocvar_sv_jumpspeedcap_max;
float autocvar_sv_jumpspeedcap_max_disable_on_ramps;
string autocvar_sv_jumpspeedcap_min;
float autocvar_sv_airaccelerate;
float autocvar_sv_airstopaccelerate;
float autocvar_sv_track_canjump;
+ bool autocvar_sv_showspectators;
WriteHeader(MSG_BROADCAST, TE_CSQC_TEAMNAGGER);
}
+ int CountSpectators(entity player, entity to)
+ {
+ if(!player) { return 0; } // not sure how, but best to be safe
+
+ int spec_count = 0;
+
+ FOREACH_CLIENT(IS_REAL_CLIENT(it) && IS_SPEC(it) && it != to && it.enemy == player,
+ {
+ spec_count++;
+ });
+
+ return spec_count;
+ }
+
+ void WriteSpectators(entity player, entity to)
+ {
+ if(!player) { return; } // not sure how, but best to be safe
+
+ FOREACH_CLIENT(IS_REAL_CLIENT(it) && IS_SPEC(it) && it != to && it.enemy == player,
+ {
+ WriteByte(MSG_ENTITY, num_for_edict(it));
+ });
+ }
+
bool ClientData_Send(entity this, entity to, int sf)
{
assert(to == this.owner, return false);
if (to.spectatee_status) sf |= 2; // spectator ent number follows
if (e.zoomstate) sf |= 4; // zoomed
if (e.porto_v_angle_held) sf |= 8; // angles held
+ if (autocvar_sv_showspectators) sf |= 16; // show spectators
WriteHeader(MSG_ENTITY, ENT_CLIENT_CLIENTDATA);
WriteByte(MSG_ENTITY, sf);
WriteAngle(MSG_ENTITY, e.v_angle.x);
WriteAngle(MSG_ENTITY, e.v_angle.y);
}
+
+ if(sf & 16)
+ {
+ float specs = CountSpectators(e, to);
+ WriteByte(MSG_ENTITY, specs);
+ WriteSpectators(e, to);
+ }
+
return true;
}
void ClientData_Detach(entity this)
{
- remove(this.clientdata);
+ delete(this.clientdata);
this.clientdata = NULL;
}
RemoveGrapplingHook(this);
Portal_ClearAll(this);
Unfreeze(this);
+ SetSpectatee(this, NULL);
if (this.alivetime)
{
this.health = FRAGS_SPECTATOR;
this.takedamage = DAMAGE_NO;
this.solid = SOLID_NOT;
- this.movetype = MOVETYPE_FLY_WORLDONLY; // user preference is controlled by playerprethink
+ set_movetype(this, MOVETYPE_FLY_WORLDONLY); // user preference is controlled by playerprethink
this.flags = FL_CLIENT | FL_NOTARGET;
this.armorvalue = 666;
this.effects = 0;
this.iscreature = true;
this.teleportable = TELEPORT_NORMAL;
this.damagedbycontents = true;
- this.movetype = MOVETYPE_WALK;
+ set_movetype(this, MOVETYPE_WALK);
this.solid = SOLID_SLIDEBOX;
this.dphitcontentsmask = DPCONTENTS_BODY | DPCONTENTS_SOLID;
if (autocvar_g_playerclip_collisions)
if (autocvar_spawn_debug)
{
sprint(this, strcat("spawnpoint origin: ", vtos(spot.origin), "\n"));
- remove(spot); // usefull for checking if there are spawnpoints, that let drop through the floor
+ delete(spot); // usefull for checking if there are spawnpoints, that let drop through the floor
}
PS(this).m_switchweapon = w_getbestweapon(this);
}
if(this.killindicator && !wasfreed(this.killindicator))
- remove(this.killindicator);
+ delete(this.killindicator);
this.killindicator = NULL;
if (gameover)
{
this.owner.killindicator = NULL;
- remove(this);
+ delete(this);
return;
}
if (this.owner.alpha < 0 && !this.owner.vehicle)
{
this.owner.killindicator = NULL;
- remove(this);
+ delete(this);
return;
}
if (!sv_foginterval && world.fog != "")
stuffcmd(this, strcat("\nfog ", world.fog, "\nr_fog_exp2 0\nr_drawfog 1\n"));
- if (autocvar_sv_teamnagger && !(autocvar_bot_vs_human && (c3==-1 && c4==-1)))
+ if (autocvar_sv_teamnagger && !(autocvar_bot_vs_human && AvailableTeams() == 2))
if (!g_ca && !g_cts && !g_race) // teamnagger is currently bad for ca, race & cts
send_CSQC_teamnagger();
Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_DISCONNECT, this.netname);
+ SetSpectatee(this, NULL);
+
MUTATOR_CALLHOOK(ClientDisconnect, this);
ClientState_detach(this);
this.flags &= ~FL_CLIENT;
- if (this.chatbubbleentity) remove(this.chatbubbleentity);
- if (this.killindicator) remove(this.killindicator);
+ if (this.chatbubbleentity) delete(this.chatbubbleentity);
+ if (this.killindicator) delete(this.killindicator);
WaypointSprite_PlayerGone(this);
if (this.netname_previous) strunzone(this.netname_previous);
if (this.clientstatus) strunzone(this.clientstatus);
if (this.weaponorder_byimpulse) strunzone(this.weaponorder_byimpulse);
- if (this.personal) remove(this.personal);
+ if (this.personal) delete(this.personal);
this.playerid = 0;
ReadyCount();
{
if(this.owner) // but why can that ever be NULL?
this.owner.chatbubbleentity = NULL;
- remove(this);
+ delete(this);
return;
}
{
this.solid = SOLID_NOT;
this.takedamage = DAMAGE_NO;
- this.movetype = MOVETYPE_FLY;
+ set_movetype(this, MOVETYPE_FLY);
this.velocity = '0 0 1' * autocvar_g_respawn_ghosts_speed;
this.avelocity = randomvec() * autocvar_g_respawn_ghosts_speed * 3 - randomvec() * autocvar_g_respawn_ghosts_speed * 3;
this.effects |= CSQCMODEL_EF_RESPAWNGHOST;
this.angles = spectatee.v_angle;
STAT(FROZEN, this) = STAT(FROZEN, spectatee);
this.revive_progress = spectatee.revive_progress;
- if(!PHYS_INPUT_BUTTON_USE(this))
+ if(!PHYS_INPUT_BUTTON_USE(this) && STAT(CAMERA_SPECTATOR, this) != 2)
this.fixangle = true;
setorigin(this, spectatee.origin);
setsize(this, spectatee.mins, spectatee.maxs);
if(!IS_PLAYER(this.enemy))
return false;
+ ClientData_Touch(this.enemy);
+
msg_entity = this;
WriteByte(MSG_ONE, SVC_SETVIEW);
WriteEntity(MSG_ONE, this.enemy);
- this.movetype = MOVETYPE_NONE;
+ set_movetype(this, MOVETYPE_NONE);
accuracy_resend(this);
if(!SpectateUpdate(this))
// these are required to fix the spectator bug with arc
if(old_spectatee && old_spectatee.arc_beam) { old_spectatee.arc_beam.SendFlags |= ARC_SF_SETTINGS; }
if(this.enemy && this.enemy.arc_beam) { this.enemy.arc_beam.SendFlags |= ARC_SF_SETTINGS; }
+
+ // needed to update spectator list
+ if(old_spectatee) { ClientData_Touch(old_spectatee); }
}
bool Spectate(entity this, entity pl)
{
TRANSMUTE(Player, this);
+ SetSpectatee(this, NULL);
+
if(autocvar_g_campaign || autocvar_g_balance_teams)
{ JoinBestTeam(this, false, true); }
MinigameImpulse(this, this.impulse);
this.impulse = 0;
}
- float prefered_movetype;
if (this.flags & FL_JUMPRELEASED) {
if (PHYS_INPUT_BUTTON_JUMP(this) && !this.version_mismatch) {
this.flags &= ~FL_JUMPRELEASED;
TRANSMUTE(Spectator, this);
}
} else {
- prefered_movetype = ((!PHYS_INPUT_BUTTON_USE(this) ? this.cvar_cl_clippedspectating : !this.cvar_cl_clippedspectating) ? MOVETYPE_FLY_WORLDONLY : MOVETYPE_NOCLIP);
- if (this.movetype != prefered_movetype)
- this.movetype = prefered_movetype;
+ int preferred_movetype = ((!PHYS_INPUT_BUTTON_USE(this) ? this.cvar_cl_clippedspectating : !this.cvar_cl_clippedspectating) ? MOVETYPE_FLY_WORLDONLY : MOVETYPE_NOCLIP);
+ set_movetype(this, preferred_movetype);
}
} else {
if (!(PHYS_INPUT_BUTTON_ATCK(this) || PHYS_INPUT_BUTTON_JUMP(this))) {
{
if(MinigameImpulse(this, this.impulse))
this.impulse = 0;
+
+ if (this.impulse == IMP_weapon_drop.impulse)
+ {
+ STAT(CAMERA_SPECTATOR, this) = (STAT(CAMERA_SPECTATOR, this) + 1) % 3;
+ this.impulse = 0;
+ return;
+ }
}
if (this.flags & FL_JUMPRELEASED) {
if (PHYS_INPUT_BUTTON_JUMP(this) && !this.version_mismatch) {
.entity weaponentity = weaponentities[0]; // TODO: unhardcode
if (this.hook.state) {
do_crouch = false;
+ } else if (this.waterlevel >= WATERLEVEL_SWIMMING) {
+ do_crouch = false;
} else if (this.vehicle) {
do_crouch = false;
} else if (STAT(FROZEN, this)) {
do_crouch = false;
- } else if ((PS(this).m_weapon == WEP_SHOTGUN || PS(this).m_weapon == WEP_SHOCKWAVE) && this.(weaponentity).wframe == WFRAME_FIRE2 && time < this.(weaponentity).weapon_nextthink) {
- // WEAPONTODO: predict
+ } else if ((PS(this).m_weapon.spawnflags & WEP_TYPE_MELEE_PRI) && this.(weaponentity).wframe == WFRAME_FIRE1 && time < this.(weaponentity).weapon_nextthink) {
+ do_crouch = false;
+ } else if ((PS(this).m_weapon.spawnflags & WEP_TYPE_MELEE_SEC) && this.(weaponentity).wframe == WFRAME_FIRE2 && time < this.(weaponentity).weapon_nextthink) {
do_crouch = false;
}
}
}
+void Player_Physics(entity this)
+{
+ set_movetype(this, ((this.move_qcphysics) ? MOVETYPE_NONE : this.move_movetype));
+
+ if(!this.move_qcphysics)
+ return;
+
+ int mt = this.move_movetype;
+
+ if(mt == MOVETYPE_PUSH || mt == MOVETYPE_FAKEPUSH || mt == MOVETYPE_PHYSICS)
+ {
+ this.move_qcphysics = false;
+ set_movetype(this, mt);
+ return;
+ }
+
+ if(!frametime && !this.pm_frametime)
+ return;
+
+ Movetype_Physics_NoMatchTicrate(this, this.pm_frametime, true);
+
+ this.pm_frametime = 0;
+}
+
/*
=============
PlayerPostThink
.float idlekick_lasttimeleft;
void PlayerPostThink (entity this)
{
+ Player_Physics(this);
+
if (sv_maxidle > 0)
if (frametime) // WORKAROUND: only use dropclient in server frames (frametime set). Never use it in cl_movement frames (frametime zero).
if (IS_REAL_CLIENT(this))