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, bool icon_right_align, vector color, float theAlpha)
+void DrawNumIcon(vector myPos, vector mySize, float x, string icon, bool vertical, int icon_right_align, vector color, float theAlpha)
{
- TC(bool, vertical); TC(bool, icon_right_align);
+ TC(bool, vertical); TC(int, icon_right_align);
DrawNumIcon_expanding(myPos, mySize, x, icon, vertical, icon_right_align, color, theAlpha, 0);
}
bool superspec_Spectate(entity _player)
{SELFPARAM();
if(Spectate(_player) == 1)
- self.classname = STR_SPECTATOR;
+ TRANSMUTE(Spectator, self);
return true;
}
#define NEW(cname, ...) \
OVERLOAD_(spawn##cname, new_pure(cname) P99_IF_EMPTY(__VA_ARGS__)()(, __VA_ARGS__))
- #define TRANSMUTE(cname, this, ...) \
- OVERLOAD_(spawn##cname, (this.transmute = true, this.classname = #cname, this) P99_IF_EMPTY(__VA_ARGS__)()(, __VA_ARGS__))
+ #define _TRANSMUTE(cname, this, ...) \
+ OVERLOAD_(spawn##cname, this P99_IF_EMPTY(__VA_ARGS__)()(, __VA_ARGS__))
#define CONSTRUCT(cname, ...) \
OVERLOAD_(spawn##cname, this P99_IF_EMPTY(__VA_ARGS__)()(, __VA_ARGS__))
#define NEW(cname, ...) \
OVERLOAD(spawn##cname, new_pure(cname),##__VA_ARGS__)
- #define TRANSMUTE(cname, this, ...) \
- OVERLOAD(spawn##cname, (this.transmute = true, this.classname = #cname, this),##__VA_ARGS__)
+ #define _TRANSMUTE(cname, this, ...) \
+ OVERLOAD(spawn##cname, this,##__VA_ARGS__)
#define CONSTRUCT(cname, ...) \
OVERLOAD(spawn##cname, this,##__VA_ARGS__)
#endif
+#define TRANSMUTE(cname, this, ...) MACRO_BEGIN \
+ entity _e = (this); \
+ if (_e.vtblbase != cname##_vtbl) { \
+ _e.transmute = true; \
+ _e.classname = #cname; \
+ _TRANSMUTE(cname, _e, __VA_ARGS__); \
+ } \
+ MACRO_END
+
#define CONSTRUCTOR(cname, ...) \
cname OVERLOAD(spawn##cname, cname this, __VA_ARGS__) \
{ \
METHOD(cname, dtor, void(cname this)) \
{ \
METHOD_REFERENCE(cname, dtorimpl)(this); \
+ this.instanceOf##cname = false; \
entity super = SUPER(cname); \
if (super != cname##_vtbl) super.dtor(this); \
} \
this.spectatortime = time;
this.bot_attack = false;
this.hud = HUD_NORMAL;
- this.classname = STR_OBSERVER;
+ TRANSMUTE(Observer, this);
this.iscreature = false;
this.teleportable = TELEPORT_SIMPLE;
this.damagedbycontents = false;
{
SELFPARAM();
if (IS_BOT_CLIENT(this)) {
- this.classname = STR_PLAYER;
+ TRANSMUTE(Player, this);
} else if (IS_REAL_CLIENT(this)) {
msg_entity = this;
WriteByte(MSG_ONE, SVC_SETVIEW);
WriteEntity(MSG_ONE, this);
}
if (gameover) {
- this.classname = STR_OBSERVER;
+ TRANSMUTE(Observer, this);
}
SetSpectatee(this, NULL);
return; // spawn failed
}
- this.classname = STR_PLAYER;
+ TRANSMUTE(Player, this);
this.wasplayer = true;
this.iscreature = true;
this.teleportable = TELEPORT_NORMAL;
assert(!IS_CLIENT(this), return);
assert(player_count >= 0, player_count = 0);
TRANSMUTE(Client, this);
- this.classname = "player_joining";
#ifdef WATERMARK
Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_WATERMARK, WATERMARK);
#endif
this.version_nagtime = time + 10 + random() * 10;
- ClientState_attach(this);
-
// identify the right forced team
if (autocvar_g_campaign)
{
JoinBestTeam(this, false, false); // if the team number is valid, keep it
if (autocvar_sv_spectate || autocvar_g_campaign || this.team_forced < 0) {
- this.classname = STR_OBSERVER;
+ TRANSMUTE(Observer, this);
} else {
if (!teamplay || autocvar_g_balance_teams)
{
- this.classname = STR_PLAYER;
+ TRANSMUTE(Player, this);
campaign_bots_may_start = 1;
}
else
{
- this.classname = STR_OBSERVER; // do it anyway
+ TRANSMUTE(Observer, this); // do it anyway
}
}
- this.playerid = ++playerid_last;
-
PlayerStats_GameReport_AddEvent(sprintf("kills-%d", this.playerid));
// always track bots, don't ask for cl_allow_uidtracking
{
if(!teamplay || autocvar_g_campaign || autocvar_g_balance_teams || (self.wasplayer && autocvar_g_changeteam_banned) || self.team_forced > 0)
{
- self.classname = STR_PLAYER;
+ TRANSMUTE(Player, self);
if(autocvar_g_campaign || autocvar_g_balance_teams)
{ JoinBestTeam(self, false, true); }
} else if(PHYS_INPUT_BUTTON_ATCK(self) && !self.version_mismatch) {
self.flags &= ~FL_JUMPRELEASED;
if(SpectateNext()) {
- self.classname = STR_SPECTATOR;
+ TRANSMUTE(Spectator, self);
}
} else {
prefered_movetype = ((!PHYS_INPUT_BUTTON_USE(self) ? self.cvar_cl_clippedspectating : !self.cvar_cl_clippedspectating) ? MOVETYPE_FLY_WORLDONLY : MOVETYPE_NOCLIP);
} else if(PHYS_INPUT_BUTTON_ATCK(self) || self.impulse == 10 || self.impulse == 15 || self.impulse == 18 || (self.impulse >= 200 && self.impulse <= 209)) {
self.flags &= ~FL_JUMPRELEASED;
if(SpectateNext()) {
- self.classname = STR_SPECTATOR;
+ TRANSMUTE(Spectator, self);
} else {
- self.classname = STR_OBSERVER;
+ TRANSMUTE(Observer, self);
PutClientInServer();
}
self.impulse = 0;
} else if(self.impulse == 12 || self.impulse == 16 || self.impulse == 19 || (self.impulse >= 220 && self.impulse <= 229)) {
self.flags &= ~FL_JUMPRELEASED;
if(SpectatePrev()) {
- self.classname = STR_SPECTATOR;
+ TRANSMUTE(Spectator, self);
} else {
- self.classname = STR_OBSERVER;
+ TRANSMUTE(Observer, self);
PutClientInServer();
}
self.impulse = 0;
} else if (PHYS_INPUT_BUTTON_ATCK2(self)) {
self.flags &= ~FL_JUMPRELEASED;
- self.classname = STR_OBSERVER;
+ TRANSMUTE(Observer, self);
PutClientInServer();
} else {
if(!SpectateUpdate())
#pragma once
+void ClientState_attach(entity this);
+
CLASS(Client, Object)
/** Client name */
ATTRIB(Client, netname, string, this.netname)
ATTRIB(Client, crypto_encryptmethod, string, this.crypto_encryptmethod)
/** the string "HMAC-SHA256" if signing, and string_null if plaintext */
ATTRIB(Client, crypto_signmethod, string, this.crypto_signmethod)
+
+ // custom
+
+ ATTRIB(Client, flags, int, 0)
+ ATTRIB(Client, playerid, int, 0)
+
+ METHOD(Client, m_unwind, bool(Client this));
+
INIT(Client) {
+ if (this.m_unwind(this)) return this;
+ this.classname = "player_joining";
this.flags = FL_CLIENT;
+ static int playerid_last;
+ this.playerid = ++playerid_last;
+ ClientState_attach(this);
}
ENDCLASS(Client)
+CLASS(Observer, Client)
+ INIT(Observer) {
+ this.classname = STR_OBSERVER;
+ }
+ DESTRUCTOR(Observer) { }
+ENDCLASS(Observer)
+
+CLASS(Spectator, Client)
+ INIT(Spectator) {
+ this.classname = STR_SPECTATOR;
+ }
+ DESTRUCTOR(Spectator) { }
+ENDCLASS(Spectator)
+
+CLASS(Player, Client)
+ INIT(Player) {
+ this.classname = STR_PLAYER;
+ }
+ DESTRUCTOR(Player) { }
+ENDCLASS(Player)
+
+METHOD(Client, m_unwind, bool(Client this))
+{
+ TC(Client, this);
+ #define UNWIND(class) MACRO_BEGIN if (this.instanceOf##class) { METHOD_REFERENCE(class, dtorimpl)(this); } MACRO_END
+ switch (this.classname) {
+ case "Observer":
+ UNWIND(Spectator);
+ UNWIND(Player);
+ return true;
+ case "Spectator":
+ UNWIND(Observer);
+ UNWIND(Player);
+ return true;
+ case "Player":
+ UNWIND(Observer);
+ UNWIND(Spectator);
+ return true;
+ }
+ #undef UNWIND
+ return false;
+}
+
float c1, c2, c3, c4;
void play_countdown(float finished, Sound samp);
}
else if (teamplay && !autocvar_sv_spectate && !(self.team_forced > 0))
{
- self.classname = STR_OBSERVER; // really?
+ TRANSMUTE(Observer, self); // really?
stuffcmd(self, "menu_showteamselect\n");
}
}
if (nJoinAllowed(self, self))
{
if (autocvar_g_campaign) campaign_bots_may_start = 1;
- self.classname = STR_PLAYER;
+ TRANSMUTE(Player, self);
PlayerScore_Clear(self);
Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CPID_PREVENT_JOIN);
Send_Notification(NOTIF_ALL, world, MSG_INFO, ((teamplay && self.team != -1) ? APP_TEAM_ENT(this, INFO_JOIN_PLAY_TEAM) : INFO_JOIN_PLAY), self.netname);
.entity flagcarried;
.int playerid;
-float playerid_last;
.float noalign; // if set to 1, the item or spawnpoint won't be dropped to the floor
.vector death_origin;
SELFPARAM();
if (!allowed_to_spawn && IS_PLAYER(this)) // this is true even when player is trying to join
{
- this.classname = STR_OBSERVER;
+ TRANSMUTE(Observer, this);
if (this.jointime != time && !this.caplayer) // not when connecting
{
this.caplayer = 0.5;
}
if (it.caplayer)
{
- it.classname = STR_PLAYER;
+ TRANSMUTE(Player, it);
it.caplayer = 1;
WITH(entity, self, it, PutClientInServer());
}
MUTATOR_HOOKFUNCTION(ca, ClientConnect)
{
SELFPARAM();
- this.classname = STR_OBSERVER;
+ TRANSMUTE(Observer, this);
return true;
}
// FIXME fix LMS scoring for new system
if(PlayerScore_Add(self, SP_LMS_RANK, 0) > 0)
{
- self.classname = STR_OBSERVER;
+ TRANSMUTE(Observer, self);
Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_LMS_NOLIVES);
}
}
MUTATOR_HOOKFUNCTION(lms, ClientConnect)
{SELFPARAM();
- self.classname = STR_PLAYER;
+ TRANSMUTE(Player, self);
campaign_bots_may_start = 1;
if(PlayerScore_Add(self, SP_LMS_LIVES, LMS_NewPlayerLives()) <= 0)
qual = g_race_qualifying;
setself(spawn());
- self.classname = STR_PLAYER;
+ TRANSMUTE(Player, self);
if(g_race)
{