#include "bot/navigation.qh"
#include "../common/ent_cs.qh"
-#include "../common/vehicles/all.qh"
+#include "../common/state.qh"
+
#include "../common/triggers/teleporters.qh"
+#include "../common/vehicles/all.qh"
+
#include "weapons/hitplot.qh"
#include "weapons/weaponsystem.qh"
#include "../common/net_notice.qh"
-#include "../common/physics.qh"
+#include "../common/physics/player.qh"
#include "../common/items/all.qc"
bool ClientData_Send(entity this, entity to, int sf)
{
- if(to != self.owner)
- {
- error("wtf");
- return false;
- }
+ assert(to == this.owner, return false);
- entity e;
-
- e = to;
- if(IS_SPEC(to))
- e = to.enemy;
+ entity e = to;
+ if (IS_SPEC(e)) e = e.enemy;
sf = 0;
-
- if(e.race_completed)
- sf |= 1; // forced scoreboard
- 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 (e.race_completed) sf |= 1; // forced scoreboard
+ 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
WriteHeader(MSG_ENTITY, ENT_CLIENT_CLIENTDATA);
WriteByte(MSG_ENTITY, sf);
- if(sf & 2)
+ if (sf & 2)
+ {
WriteByte(MSG_ENTITY, to.spectatee_status);
-
- if(sf & 8)
+ }
+ if (sf & 8)
{
WriteAngle(MSG_ENTITY, e.v_angle.x);
WriteAngle(MSG_ENTITY, e.v_angle.y);
}
-
return true;
}
-void ClientData_Attach()
-{SELFPARAM();
+void ClientData_Attach(entity this)
+{
Net_LinkEntity(this.clientdata = new(clientdata), false, 0, ClientData_Send);
make_pure(this.clientdata);
self.clientdata.drawonlytoclient = this;
self.clientdata.owner = this;
}
-void ClientData_Detach()
-{SELFPARAM();
- remove(self.clientdata);
- self.clientdata = world;
+void ClientData_Detach(entity this)
+{
+ remove(this.clientdata);
+ self.clientdata = NULL;
}
void ClientData_Touch(entity e)
e.clientdata.SendFlags = 1;
// make it spectatable
- entity e2;
- FOR_EACH_REALCLIENT(e2)
- {
- if(e2 != e)
- if(IS_SPEC(e2))
- if(e2.enemy == e)
- e2.clientdata.SendFlags = 1;
- }
+ FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != e && IS_SPEC(it) && it.enemy == e, LAMBDA(it.clientdata.SendFlags = 1));
}
.string netname_previous;
*/
void FixPlayermodel(entity player);
void PutObserverInServer()
-{SELFPARAM();
+{
+ SELFPARAM();
+ PlayerState_detach(this);
entity spot;
self.hud = HUD_NORMAL;
if(self.vehicle)
vehicles_exit(VHEF_RELEASE);
- WaypointSprite_PlayerDead();
+ WaypointSprite_PlayerDead(self);
if(!mutator_returnvalue) // mutator prevents resetting teams
self.team = -1; // move this as it is needed to log the player spectating in eventlog
self.crouch = false;
self.revival_time = 0;
- setorigin (self, (spot.origin + PL_VIEW_OFS)); // offset it so that the spectator spawns higher off the ground, looks better this way
+ setorigin (self, (spot.origin + STAT(PL_VIEW_OFS, NULL))); // offset it so that the spectator spawns higher off the ground, looks better this way
self.prevorigin = self.origin;
self.items = 0;
self.weapons = '0 0 0';
setmodel(self, MDL_Null);
self.drawonlytoclient = self;
- setsize (self, PL_CROUCH_MIN, PL_CROUCH_MAX); // give the spectator some space between walls for MOVETYPE_FLY_WORLDONLY
+ setsize (self, STAT(PL_CROUCH_MIN, NULL), STAT(PL_CROUCH_MAX, NULL)); // give the spectator some space between walls for MOVETYPE_FLY_WORLDONLY
self.view_ofs = '0 0 0'; // so that your view doesn't go into the ceiling with MOVETYPE_FLY_WORLDONLY, previously "PL_VIEW_OFS"
- self.weapon = 0;
+ PS(self).m_weapon = WEP_Null;
self.weaponname = "";
- self.switchingweapon = 0;
+ PS(self).m_switchingweapon = WEP_Null;
self.weaponmodel = "";
for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
{
if (IS_OBSERVER(this)) {
PutObserverInServer();
} else if (IS_PLAYER(this)) {
+ PlayerState_attach(this);
accuracy_resend(this);
if (this.team < 0)
this.drawonlytoclient = NULL;
this.crouch = false;
- this.view_ofs = PL_VIEW_OFS;
- setsize(this, PL_MIN, PL_MAX);
+ this.view_ofs = STAT(PL_VIEW_OFS, NULL);
+ setsize(this, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL));
this.spawnorigin = spot.origin;
setorigin(this, spot.origin + '0 0 1' * (1 - this.mins.z - 24));
// don't reset back to last position, even if new position is stuck in solid
remove(spot); // usefull for checking if there are spawnpoints, that let drop through the floor
}
- this.switchweapon = w_getbestweapon(this);
+ PS(this).m_switchweapon = w_getbestweapon(this);
this.cnt = -1; // W_LastWeapon will not complain
- this.weapon = 0;
+ PS(this).m_weapon = WEP_Null;
this.weaponname = "";
- this.switchingweapon = 0;
+ PS(this).m_switchingweapon = WEP_Null;
if (!warmup_stage && !this.alivetime)
this.alivetime = time;
}
}
+void ClientInit_misc();
+
.float ebouncefactor, ebouncestop; // electro's values
// TODO do we need all these fields, or should we stop autodetecting runtime
// changes and just have a console command to update this?
WriteHeader(MSG_ENTITY, _ENT_CLIENT_INIT);
return = true;
msg_entity = to;
+ // MSG_INIT replacement
+ // TODO: make easier to use
Registry_send_all();
+ W_PROP_reload(MSG_ONE, to);
+ ClientInit_misc();
+ MUTATOR_CALLHOOK(Ent_Init);
+}
+void ClientInit_misc()
+{
int channel = MSG_ONE;
WriteHeader(channel, ENT_CLIENT_INIT);
WriteByte(channel, g_nexball_meter_period * 32);
else
WriteString(channel, "");
WriteByte(channel, self.count * 255.0); // g_balance_armor_blockpercent
- WriteCoord(channel, self.bouncefactor); // g_balance_mortar_bouncefactor // WEAPONTODO
- WriteCoord(channel, self.bouncestop); // g_balance_mortar_bouncestop
- WriteCoord(channel, self.ebouncefactor); // g_balance_mortar_bouncefactor
- WriteCoord(channel, self.ebouncestop); // g_balance_mortar_bouncestop
- WriteByte(channel, WEP_CVAR(vortex, secondary)); // client has to know if it should zoom or not // WEAPONTODO
- WriteByte(channel, WEP_CVAR(rifle, secondary)); // client has to know if it should zoom or not // WEAPONTODO
WriteByte(channel, serverflags); // client has to know if it should zoom or not
- WriteByte(channel, WEP_CVAR(minelayer, limit)); // minelayer max mines // WEAPONTODO
- WriteByte(channel, WEP_CVAR_SEC(hagar, load_max)); // hagar max loadable rockets // WEAPONTODO
WriteCoord(channel, autocvar_g_trueaim_minrange);
- WriteByte(channel, WEP_CVAR(porto, secondary)); // WEAPONTODO
-
- MUTATOR_CALLHOOK(Ent_Init);
}
void ClientInit_CheckUpdate()
self.count = autocvar_g_balance_armor_blockpercent;
self.SendFlags |= 1;
}
- if(self.bouncefactor != autocvar_g_balance_mortar_bouncefactor) // WEAPONTODO
- {
- self.bouncefactor = autocvar_g_balance_mortar_bouncefactor;
- self.SendFlags |= 1;
- }
- if(self.bouncestop != autocvar_g_balance_mortar_bouncestop)
- {
- self.bouncestop = autocvar_g_balance_mortar_bouncestop;
- self.SendFlags |= 1;
- }
- if(self.ebouncefactor != autocvar_g_balance_electro_secondary_bouncefactor)
- {
- self.ebouncefactor = autocvar_g_balance_electro_secondary_bouncefactor;
- self.SendFlags |= 1;
- }
- if(self.ebouncestop != autocvar_g_balance_electro_secondary_bouncestop)
- {
- self.ebouncestop = autocvar_g_balance_electro_secondary_bouncestop;
- self.SendFlags |= 1;
- }
}
void ClientInit_Spawn()
DecodeLevelParms
=============
*/
-void DecodeLevelParms ()
-{SELFPARAM();
+void DecodeLevelParms(entity this)
+{
// load parms
- self.parm_idlesince = parm1;
- if(self.parm_idlesince == -(86400 * 366))
- self.parm_idlesince = time;
+ this.parm_idlesince = parm1;
+ if (this.parm_idlesince == -(86400 * 366))
+ this.parm_idlesince = time;
// whatever happens, allow 60 seconds of idling directly after connect for map loading
- self.parm_idlesince = max(self.parm_idlesince, time - sv_maxidle + 60);
+ this.parm_idlesince = max(this.parm_idlesince, time - sv_maxidle + 60);
MUTATOR_CALLHOOK(DecodeLevelParms);
}
*/
.float clientkill_nexttime;
-void ClientKill_Now_TeamChange()
-{SELFPARAM();
- if(self.killindicator_teamchange == -1)
+void ClientKill_Now_TeamChange(entity this)
+{
+ if(this.killindicator_teamchange == -1)
{
- JoinBestTeam( self, false, true );
+ JoinBestTeam( this, false, true );
}
- else if(self.killindicator_teamchange == -2)
+ else if(this.killindicator_teamchange == -2)
{
if(blockSpectators)
- Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime);
- PutObserverInServer();
+ Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime);
+ WITH(entity, self, this, PutObserverInServer());
}
else
- SV_ChangeTeam(self.killindicator_teamchange - 1);
- self.killindicator_teamchange = 0;
+ WITH(entity, self, this, SV_ChangeTeam(this.killindicator_teamchange - 1));
+ this.killindicator_teamchange = 0;
}
void ClientKill_Now()
self.killindicator = world;
if(self.killindicator_teamchange)
- ClientKill_Now_TeamChange();
+ ClientKill_Now_TeamChange(self);
if(IS_PLAYER(self))
Damage(self, self, self, 100000, DEATH_KILL.m_id, self.origin, '0 0 0');
if(!self.killindicator)
{
- if(self.deadflag == DEAD_NO)
+ if(!IS_DEAD(self))
{
killtime = max(killtime, self.clientkill_nexttime - time);
self.clientkill_nexttime = time + killtime + autocvar_g_balance_kill_antispam;
}
- if(killtime <= 0 || !IS_PLAYER(self) || self.deadflag != DEAD_NO)
+ if(killtime <= 0 || !IS_PLAYER(self) || IS_DEAD(self))
{
ClientKill_Now();
}
{SELFPARAM();
if(gameover) return;
if(self.player_blocked) return;
- if(self.frozen) return;
+ if(STAT(FROZEN, self)) return;
ClientKill_TeamChange(0);
}
stuffcmd(e, "cl_cmd settemp cl_prydoncursor_notrace 0\n");
if(autocvar_sv_gentle)
stuffcmd(e, "cl_cmd settemp cl_gentle 1\n");
+
+ MUTATOR_CALLHOOK(FixClientCvars, e);
}
float PlayerInIDList(entity p, string idlist)
{
GameLogEcho(sprintf(":connect:%d:%d:%s",
self.playerid,
- num_for_edict(self),
+ etof(self),
((IS_REAL_CLIENT(self)) ? self.netaddress : "bot")
));
}
}
#endif
-/*
+/**
=============
ClientConnect
Called when a client connects to the server
=============
*/
-void DecodeLevelParms ();
-void ClientConnect ()
-{SELFPARAM();
- float t;
-
- if(IS_CLIENT(self))
- {
- LOG_INFO("Warning: ClientConnect, but already connected!\n");
- return;
- }
-
- if(Ban_MaybeEnforceBanOnce(self))
- return;
-
- DecodeLevelParms();
+void ClientConnect()
+{
+ SELFPARAM();
+ if (Ban_MaybeEnforceBanOnce(this)) return;
+ assert(!IS_CLIENT(this), return);
+ assert(player_count >= 0, player_count = 0);
+ this.classname = "player_joining";
+ this.flags = FL_CLIENT;
#ifdef WATERMARK
- Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_WATERMARK, WATERMARK);
+ Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_WATERMARK, WATERMARK);
#endif
+ this.version_nagtime = time + 10 + random() * 10;
- self.classname = "player_joining";
-
- self.flags = FL_CLIENT;
- self.version_nagtime = time + 10 + random() * 10;
-
- if(player_count<0)
- {
- LOG_TRACE("BUG player count is lower than zero, this cannot happen!\n");
- player_count = 0;
- }
-
- if(IS_REAL_CLIENT(self)) { PlayerStats_PlayerBasic_CheckUpdate(self); }
+ // TODO: xonstat elo.txt support, until then just 404s
+ if (false && IS_REAL_CLIENT(this)) { PlayerStats_PlayerBasic_CheckUpdate(this); }
- PlayerScore_Attach(self);
- ClientData_Attach();
- accuracy_init(self);
- Inventory_new(self);
+ ClientState_attach(this);
+ // TODO: fold all of these into ClientState
+ DecodeLevelParms(this);
+ PlayerScore_Attach(this);
+ ClientData_Attach(this);
+ accuracy_init(this);
+ Inventory_new(this);
+ playerdemo_init(this);
+ anticheat_init(this);
+ entcs_attach(this);
+ W_HitPlotOpen(this);
- bot_clientconnect();
-
- playerdemo_init();
-
- anticheat_init();
+ bot_clientconnect(this);
// identify the right forced team
- if(autocvar_g_campaign)
+ if (autocvar_g_campaign)
{
- if(IS_REAL_CLIENT(self)) // only players, not bots
+ if (IS_REAL_CLIENT(this)) // only players, not bots
{
- switch(autocvar_g_campaign_forceteam)
+ switch (autocvar_g_campaign_forceteam)
{
- case 1: self.team_forced = NUM_TEAM_1; break;
- case 2: self.team_forced = NUM_TEAM_2; break;
- case 3: self.team_forced = NUM_TEAM_3; break;
- case 4: self.team_forced = NUM_TEAM_4; break;
- default: self.team_forced = 0;
+ case 1: this.team_forced = NUM_TEAM_1; break;
+ case 2: this.team_forced = NUM_TEAM_2; break;
+ case 3: this.team_forced = NUM_TEAM_3; break;
+ case 4: this.team_forced = NUM_TEAM_4; break;
+ default: this.team_forced = 0;
}
}
}
- else if(PlayerInIDList(self, autocvar_g_forced_team_red))
- self.team_forced = NUM_TEAM_1;
- else if(PlayerInIDList(self, autocvar_g_forced_team_blue))
- self.team_forced = NUM_TEAM_2;
- else if(PlayerInIDList(self, autocvar_g_forced_team_yellow))
- self.team_forced = NUM_TEAM_3;
- else if(PlayerInIDList(self, autocvar_g_forced_team_pink))
- self.team_forced = NUM_TEAM_4;
- else if(autocvar_g_forced_team_otherwise == "red")
- self.team_forced = NUM_TEAM_1;
- else if(autocvar_g_forced_team_otherwise == "blue")
- self.team_forced = NUM_TEAM_2;
- else if(autocvar_g_forced_team_otherwise == "yellow")
- self.team_forced = NUM_TEAM_3;
- else if(autocvar_g_forced_team_otherwise == "pink")
- self.team_forced = NUM_TEAM_4;
- else if(autocvar_g_forced_team_otherwise == "spectate")
- self.team_forced = -1;
- else if(autocvar_g_forced_team_otherwise == "spectator")
- self.team_forced = -1;
- else
- self.team_forced = 0;
-
- if(!teamplay)
- if(self.team_forced > 0)
- self.team_forced = 0;
+ else if (PlayerInIDList(this, autocvar_g_forced_team_red)) this.team_forced = NUM_TEAM_1;
+ else if (PlayerInIDList(this, autocvar_g_forced_team_blue)) this.team_forced = NUM_TEAM_2;
+ else if (PlayerInIDList(this, autocvar_g_forced_team_yellow)) this.team_forced = NUM_TEAM_3;
+ else if (PlayerInIDList(this, autocvar_g_forced_team_pink)) this.team_forced = NUM_TEAM_4;
+ else switch (autocvar_g_forced_team_otherwise)
+ {
+ default: this.team_forced = 0; break;
+ case "red": this.team_forced = NUM_TEAM_1; break;
+ case "blue": this.team_forced = NUM_TEAM_2; break;
+ case "yellow": this.team_forced = NUM_TEAM_3; break;
+ case "pink": this.team_forced = NUM_TEAM_4; break;
+ case "spectate":
+ case "spectator":
+ this.team_forced = -1;
+ break;
+ }
+ if (!teamplay && this.team_forced > 0) this.team_forced = 0;
- JoinBestTeam(self, false, false); // if the team number is valid, keep it
+ JoinBestTeam(this, false, false); // if the team number is valid, keep it
- if((autocvar_sv_spectate == 1) || autocvar_g_campaign || self.team_forced < 0) {
- self.classname = STR_OBSERVER;
+ if (autocvar_sv_spectate || autocvar_g_campaign || this.team_forced < 0) {
+ this.classname = STR_OBSERVER;
} else {
- if(teamplay)
+ if (!teamplay || autocvar_g_balance_teams)
{
- if(autocvar_g_balance_teams)
- {
- self.classname = STR_PLAYER;
- campaign_bots_may_start = 1;
- }
- else
- {
- self.classname = STR_OBSERVER; // do it anyway
- }
+ this.classname = STR_PLAYER;
+ campaign_bots_may_start = 1;
}
else
{
- self.classname = STR_PLAYER;
- campaign_bots_may_start = 1;
+ this.classname = STR_OBSERVER; // do it anyway
}
}
- self.playerid = (playerid_last = playerid_last + 1);
+ this.playerid = ++playerid_last;
- PlayerStats_GameReport_AddEvent(sprintf("kills-%d", self.playerid));
+ PlayerStats_GameReport_AddEvent(sprintf("kills-%d", this.playerid));
- if(IS_BOT_CLIENT(self))
- PlayerStats_GameReport_AddPlayer(self);
+ // always track bots, don't ask for cl_allow_uidtracking
+ if (IS_BOT_CLIENT(this)) PlayerStats_GameReport_AddPlayer(this);
- if(autocvar_sv_eventlog)
- GameLogEcho(strcat(":join:", ftos(self.playerid), ":", ftos(num_for_edict(self)), ":", ((IS_REAL_CLIENT(self)) ? self.netaddress : "bot"), ":", self.netname));
+ if (autocvar_sv_eventlog)
+ GameLogEcho(strcat(":join:", ftos(this.playerid), ":", ftos(etof(this)), ":", ((IS_REAL_CLIENT(this)) ? this.netaddress : "bot"), ":", this.netname));
- LogTeamchange(self.playerid, self.team, 1);
+ LogTeamchange(this.playerid, this.team, 1);
- self.just_joined = true; // stop spamming the eventlog with additional lines when the client connects
+ this.just_joined = true; // stop spamming the eventlog with additional lines when the client connects
- self.netname_previous = strzone(self.netname);
+ this.netname_previous = strzone(this.netname);
- if(IS_PLAYER(self) && teamplay)
- Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_4(self, INFO_JOIN_CONNECT_TEAM_), self.netname);
- else
- Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_JOIN_CONNECT, self.netname);
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, ((teamplay && IS_PLAYER(this)) ? APP_TEAM_ENT_4(this, INFO_JOIN_CONNECT_TEAM_) : INFO_JOIN_CONNECT), this.netname);
- stuffcmd(self, strcat(clientstuff, "\n"));
- stuffcmd(self, "cl_particles_reloadeffects\n"); // TODO do we still need this?
+ stuffcmd(this, clientstuff, "\n");
+ stuffcmd(this, "cl_particles_reloadeffects\n"); // TODO do we still need this?
- FixClientCvars(self);
+ FixClientCvars(this);
- // spawnfunc_waypoint sprites
- WaypointSprite_InitClient(self);
-
- // Wazat's grappling hook
- SetGrappleHookBindings();
+ // Grappling hook
+ stuffcmd(this, "alias +hook +button6\n");
+ stuffcmd(this, "alias -hook -button6\n");
// Jetpack binds
- stuffcmd(self, "alias +jetpack +button10\n");
- stuffcmd(self, "alias -jetpack -button10\n");
+ stuffcmd(this, "alias +jetpack +button10\n");
+ stuffcmd(this, "alias -jetpack -button10\n");
// get version info from player
- stuffcmd(self, "cmd clientversion $gameversion\n");
+ stuffcmd(this, "cmd clientversion $gameversion\n");
// get other cvars from player
GetCvars(0);
// notify about available teams
- if(teamplay)
+ if (teamplay)
{
- CheckAllowedTeams(self);
- t = 0; if(c1 >= 0) t |= 1; if(c2 >= 0) t |= 2; if(c3 >= 0) t |= 4; if(c4 >= 0) t |= 8;
- stuffcmd(self, strcat("set _teams_available ", ftos(t), "\n"));
+ CheckAllowedTeams(this);
+ int t = 0;
+ if (c1 >= 0) t |= BIT(0);
+ if (c2 >= 0) t |= BIT(1);
+ if (c3 >= 0) t |= BIT(2);
+ if (c4 >= 0) t |= BIT(3);
+ stuffcmd(this, sprintf("set _teams_available %d\n", t));
}
else
- stuffcmd(self, "set _teams_available 0\n");
-
- entcs_attach(self);
+ {
+ stuffcmd(this, "set _teams_available 0\n");
+ }
bot_relinkplayerlist();
- self.spectatortime = time;
- if(blockSpectators)
+ this.spectatortime = time;
+ if (blockSpectators)
{
- Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime);
+ Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime);
}
- self.jointime = time;
- self.allowed_timeouts = autocvar_sv_timeout_number;
+ this.jointime = time;
+ this.allowed_timeouts = autocvar_sv_timeout_number;
- if(IS_REAL_CLIENT(self))
+ if (IS_REAL_CLIENT(this))
{
- if(!autocvar_g_campaign)
+ if (!autocvar_g_campaign)
{
- self.motd_actived_time = -1;
- Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_MOTD, getwelcomemessage());
+ this.motd_actived_time = -1;
+ Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_MOTD, getwelcomemessage());
}
- if(g_weaponarena_weapons == WEPSET(TUBA))
- stuffcmd(self, "cl_cmd settemp chase_active 1\n");
+ if (g_weaponarena_weapons == WEPSET(TUBA))
+ stuffcmd(this, "cl_cmd settemp chase_active 1\n");
}
- if(!sv_foginterval && world.fog != "")
- stuffcmd(self, strcat("\nfog ", world.fog, "\nr_fog_exp2 0\nr_drawfog 1\n"));
+ if (!sv_foginterval && world.fog != "")
+ stuffcmd(this, strcat("\nfog ", world.fog, "\nr_fog_exp2 0\nr_drawfog 1\n"));
- W_HitPlotOpen(self);
+ if (autocvar_sv_teamnagger && !(autocvar_bot_vs_human && (c3==-1 && c4==-1)))
+ if (!g_ca && !g_cts && !g_race) // teamnagger is currently bad for ca, race & cts
+ send_CSQC_teamnagger();
- if(autocvar_sv_teamnagger && !(autocvar_bot_vs_human && (c3==-1 && c4==-1)) && !g_ca && !g_cts && !g_race) // teamnagger is currently bad for ca, race & cts
- send_CSQC_teamnagger();
+ CSQCMODEL_AUTOINIT(this);
- CheatInitClient();
+ this.model_randomizer = random();
- CSQCMODEL_AUTOINIT(self);
+ if (IS_REAL_CLIENT(this))
+ sv_notice_join(this);
- self.model_randomizer = random();
+ FOREACH_ENTITY_FLOAT(init_for_player_needed, true, {
+ WITH(entity, self, it, it.init_for_player(it));
+ });
- if(IS_REAL_CLIENT(self))
- sv_notice_join(self);
-
- for (entity e = world; (e = findfloat(e, init_for_player_needed, 1)); ) {
- WITH(entity, self, e, e.init_for_player(this));
- }
-
- MUTATOR_CALLHOOK(ClientConnect, self);
+ MUTATOR_CALLHOOK(ClientConnect, this);
}
/*
=============
.entity chatbubbleentity;
void ReadyCount();
void ClientDisconnect ()
-{SELFPARAM();
+{
+ SELFPARAM();
+ ClientState_detach(this);
if(self.vehicle)
vehicles_exit(VHEF_RELEASE);
accuracy_free(self);
Inventory_delete(self);
- ClientData_Detach();
+ ClientData_Detach(this);
PlayerScore_Detach(self);
if(self.netname_previous)
self.mdl = "";
- if ( !self.owner.deadflag && IS_PLAYER(self.owner) )
+ if ( !IS_DEAD(self.owner) && IS_PLAYER(self.owner) )
{
if ( self.owner.active_minigame )
self.mdl = "models/sprites/minigame_busy.iqm";
SUB_SetFade (self, time + autocvar_g_respawn_ghosts_maxtime / 2 + random () * (autocvar_g_respawn_ghosts_maxtime - autocvar_g_respawn_ghosts_maxtime / 2), 1.5);
}
- CopyBody(1);
+ CopyBody(self, 1);
self.effects |= EF_NODRAW; // prevent another CopyBody
PutClientInServer();
// add a way to see what the items were BEFORE all of these checks for the mutator hook
int items_prev = self.items;
- if((self.items & IT_USING_JETPACK) && !self.deadflag && !gameover)
+ if((self.items & IT_USING_JETPACK) && !IS_DEAD(self) && !gameover)
self.modelflags |= MF_ROCKET;
else
self.modelflags &= ~MF_ROCKET;
self.effects &= ~(EF_RED | EF_BLUE | EF_ADDITIVE | EF_FULLBRIGHT | EF_FLAME | EF_NODEPTHTEST);
- if((self.alpha < 0 || self.deadflag) && !self.vehicle) // don't apply the flags if the player is gibbed
+ if((self.alpha < 0 || IS_DEAD(self)) && !self.vehicle) // don't apply the flags if the player is gibbed
return;
Fire_ApplyDamage(self);
regen_health_stable = autocvar_g_balance_health_regenstable;
regen_health_rotstable = autocvar_g_balance_health_rotstable;
if(!MUTATOR_CALLHOOK(PlayerRegen))
- if(!self.frozen)
+ if(!STAT(FROZEN, self))
{
float mina, maxa, limith, limita;
maxa = autocvar_g_balance_armor_rotstable;
{
if(self.vehicle)
vehicles_exit(VHEF_RELEASE);
- self.event_damage(self, self, 1, DEATH_ROT.m_id, self.origin, '0 0 0');
+ if(self.event_damage)
+ self.event_damage(self, self, self, 1, DEATH_ROT.m_id, self.origin, '0 0 0');
}
if (!(self.items & IT_UNLIMITED_WEAPON_AMMO))
self.invincible_finished = spectatee.invincible_finished;
self.pressedkeys = spectatee.pressedkeys;
self.weapons = spectatee.weapons;
- self.switchweapon = spectatee.switchweapon;
- self.switchingweapon = spectatee.switchingweapon;
- self.weapon = spectatee.weapon;
+ PS(self).m_switchweapon = PS(spectatee).m_switchweapon;
+ PS(self).m_switchingweapon = PS(spectatee).m_switchingweapon;
+ PS(self).m_weapon = PS(spectatee).m_weapon;
self.vortex_charge = spectatee.vortex_charge;
self.vortex_chargepool_ammo = spectatee.vortex_chargepool_ammo;
self.hagar_load = spectatee.hagar_load;
self.dmg_inflictor = spectatee.dmg_inflictor;
self.v_angle = spectatee.v_angle;
self.angles = spectatee.v_angle;
- self.frozen = spectatee.frozen;
+ STAT(FROZEN, self) = STAT(FROZEN, spectatee);
self.revive_progress = spectatee.revive_progress;
if(!self.BUTTON_USE)
self.fixangle = true;
bool SpectateNext()
{SELFPARAM();
- other = find(self.enemy, classname, "player");
+ other = find(self.enemy, classname, STR_PLAYER);
if (MUTATOR_CALLHOOK(SpectateNext, self, other))
other = spec_player;
else if (!other)
- other = find(other, classname, "player");
+ other = find(other, classname, STR_PLAYER);
if(other) { SetSpectatee(self, other); }
bool SpectatePrev()
{SELFPARAM();
// NOTE: chain order is from the highest to the lower entnum (unlike find)
- other = findchain(classname, "player");
+ other = findchain(classname, STR_PLAYER);
if (!other) // no player
return false;
void ShowRespawnCountdown()
{SELFPARAM();
float number;
- if(self.deadflag == DEAD_NO) // just respawned?
+ if(!IS_DEAD(self)) // just respawned?
return;
else
{
{SELFPARAM();
if(self.caplayer)
return;
- if(nJoinAllowed(self))
+ if(nJoinAllowed(self, self))
{
if(!teamplay || autocvar_g_campaign || autocvar_g_balance_teams || (self.wasplayer && autocvar_g_changeteam_banned) || self.team_forced > 0)
{
PutClientInServer();
- if(IS_PLAYER(self)) { Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_JOIN_PLAY, self.netname); }
+ if(IS_PLAYER(self)) { Send_Notification(NOTIF_ALL, world, MSG_INFO, ((teamplay) ? APP_TEAM_ENT_4(this, INFO_JOIN_PLAY_TEAM_) : INFO_JOIN_PLAY), self.netname); }
}
else
stuffcmd(self, "menu_showteamselect\n");
* it checks whether the number of currently playing players exceeds g_maxplayers.
* @return int number of free slots for players, 0 if none
*/
-float nJoinAllowed(entity ignore)
-{SELFPARAM();
+bool nJoinAllowed(entity this, entity ignore)
+{
if(!ignore)
// this is called that way when checking if anyone may be able to join (to build qcstatus)
// so report 0 free slots if restricted
{
if(autocvar_g_forced_team_otherwise == "spectate")
- return 0;
+ return false;
if(autocvar_g_forced_team_otherwise == "spectator")
- return 0;
+ return false;
}
- if(self.team_forced < 0)
- return 0; // forced spectators can never join
+ if(this.team_forced < 0)
+ return false; // forced spectators can never join
// TODO simplify this
- entity e;
- float totalClients = 0;
- FOR_EACH_CLIENT(e)
- if(e != ignore)
- totalClients += 1;
+ int totalClients = 0;
+ int currentlyPlaying = 0;
+ FOREACH_CLIENT(true, LAMBDA(
+ if(it != ignore)
+ ++totalClients;
+ if(IS_REAL_CLIENT(it))
+ if(IS_PLAYER(it) || it.caplayer)
+ ++currentlyPlaying;
+ ));
if (!autocvar_g_maxplayers)
return maxclients - totalClients;
- float currentlyPlaying = 0;
- FOR_EACH_REALCLIENT(e)
- if(IS_PLAYER(e) || e.caplayer)
- currentlyPlaying += 1;
-
if(currentlyPlaying < autocvar_g_maxplayers)
return min(maxclients - totalClients, autocvar_g_maxplayers - currentlyPlaying);
- return 0;
+ return false;
}
/**
{SELFPARAM();
if ( self.impulse )
{
- MinigameImpulse(self.impulse);
+ MinigameImpulse(self, self.impulse);
self.impulse = 0;
}
float prefered_movetype;
{SELFPARAM();
if ( self.impulse )
{
- if(MinigameImpulse(self.impulse))
+ if(MinigameImpulse(self, self.impulse))
self.impulse = 0;
}
if (self.flags & FL_JUMPRELEASED) {
}
else if(autocvar_g_vehicles_enter)
{
- if(!self.frozen)
- if(self.deadflag == DEAD_NO)
+ if(!STAT(FROZEN, self))
+ if(!IS_DEAD(self))
if(!gameover)
{
entity head, closest_target = world;
- head = WarpZone_FindRadius(self.origin, autocvar_g_vehicles_enter_radius, TRUE);
+ head = WarpZone_FindRadius(self.origin, autocvar_g_vehicles_enter_radius, true);
while(head) // find the closest acceptable target to enter
{
if(head.vehicle_flags & VHF_ISVEHICLE)
- if(head.deadflag == DEAD_NO)
+ if(!IS_DEAD(head))
if(!head.owner || ((head.vehicle_flags & VHF_MULTISLOT) && SAME_TEAM(head.owner, self)))
if(head.takedamage != DAMAGE_NO)
{
self.max_armorvalue = 0;
}
- if(self.frozen == 2)
+ if(STAT(FROZEN, self) == 2)
{
self.revive_progress = bound(0, self.revive_progress + frametime * self.revive_speed, 1);
self.health = max(1, self.revive_progress * start_health);
if(self.revive_progress >= 1)
Unfreeze(self);
}
- else if(self.frozen == 3)
+ else if(STAT(FROZEN, self) == 3)
{
self.revive_progress = bound(0, self.revive_progress - frametime * self.revive_speed, 1);
self.health = max(0, autocvar_g_nades_ice_health + (start_health-autocvar_g_nades_ice_health) * self.revive_progress );
{
if(self.vehicle)
vehicles_exit(VHEF_RELEASE);
- self.event_damage(self, self.frozen_by, 1, DEATH_NADE_ICE_FREEZE.m_id, self.origin, '0 0 0');
+ self.event_damage(self, self, self.frozen_by, 1, DEATH_NADE_ICE_FREEZE.m_id, self.origin, '0 0 0');
}
else if ( self.revive_progress <= 0 )
Unfreeze(self);
if(time > self.last_vehiclecheck)
if(IS_PLAYER(self))
if(!gameover)
- if(!self.frozen)
+ if(!STAT(FROZEN, self))
if(!self.vehicle)
- if(self.deadflag == DEAD_NO)
+ if(!IS_DEAD(self))
{
entity veh;
for(veh = world; (veh = findflags(veh, vehicle_flags, VHF_ISVEHICLE)); )
if(vlen(veh.origin - self.origin) < autocvar_g_vehicles_enter_radius)
- if(veh.deadflag == DEAD_NO)
+ if(!IS_DEAD(veh))
if(veh.takedamage != DAMAGE_NO)
if((veh.vehicle_flags & VHF_MULTISLOT) && SAME_TEAM(veh.owner, self))
Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_VEHICLE_ENTER_GUNNER);
player_powerups();
}
- if (self.deadflag != DEAD_NO)
+ if (IS_DEAD(self))
{
if(self.personal && g_race_qualifying)
{
do_crouch = 0;
if(self.vehicle)
do_crouch = 0;
- if(self.frozen)
+ if(STAT(FROZEN, self))
do_crouch = 0;
// WEAPONTODO: THIS SHIT NEEDS TO GO EVENTUALLY
// It cannot be predicted by the engine!
.entity weaponentity = weaponentities[0]; // TODO: unhardcode
- if((self.weapon == WEP_SHOCKWAVE.m_id || self.weapon == WEP_SHOTGUN.m_id) && self.(weaponentity).wframe == WFRAME_FIRE2 && time < self.(weaponentity).weapon_nextthink)
+ if((PS(self).m_weapon == WEP_SHOCKWAVE || PS(self).m_weapon == WEP_SHOTGUN) && self.(weaponentity).wframe == WFRAME_FIRE2 && time < self.(weaponentity).weapon_nextthink)
do_crouch = 0;
if (do_crouch)
secrets_setstatus();
// monsters status
- monsters_setstatus();
+ monsters_setstatus(self);
self.dmg_team = max(0, self.dmg_team - autocvar_g_teamdamage_resetspeed * frametime);
// WEAPONTODO: Add weapon request for this
if(!zoomstate_set)
- SetZoomState(self.BUTTON_ZOOM || self.BUTTON_ZOOMSCRIPT || (self.BUTTON_ATCK2 && self.weapon == WEP_VORTEX.m_id) || (self.BUTTON_ATCK2 && self.weapon == WEP_RIFLE.m_id && WEP_CVAR(rifle, secondary) == 0)); // WEAPONTODO
+ SetZoomState(
+ self.BUTTON_ZOOM
+ || self.BUTTON_ZOOMSCRIPT
+ || (self.BUTTON_ATCK2 && PS(self).m_weapon == WEP_VORTEX)
+ || (self.BUTTON_ATCK2 && PS(self).m_weapon == WEP_RIFLE && WEP_CVAR(rifle, secondary) == 0)
+ ); // WEAPONTODO
float oldspectatee_status;
oldspectatee_status = self.spectatee_status;
if(IS_SPEC(self))
- self.spectatee_status = num_for_edict(self.enemy);
+ self.spectatee_status = etof(self.enemy);
else if(IS_OBSERVER(self))
- self.spectatee_status = num_for_edict(self);
+ self.spectatee_status = etof(self);
else
self.spectatee_status = 0;
if(self.spectatee_status != oldspectatee_status)
// WEAPONTODO: Move into weaponsystem somehow
// if a player goes unarmed after holding a loaded weapon, empty his clip size and remove the crosshair ammo ring
- if(!self.weapon)
+ if (PS(self).m_weapon == WEP_Null)
self.clip_load = self.clip_size = 0;
}
void DrownPlayer(entity this)
{
- if(this.deadflag != DEAD_NO)
+ if(IS_DEAD(this))
return;
if (this.waterlevel != WATERLEVEL_SUBMERGED)
CheckRules_Player();
UpdateChatBubble();
if (self.impulse)
- ImpulseCommands();
+ ImpulseCommands(self);
if (intermission_running)
return; // intermission or finale
GetPressedKeys();