minstagib_stop_countdown(self);
Portal_ClearAll(self);
-
+
if(self.alivetime)
{
- PlayerStats_Event(self, PLAYERSTATS_ALIVETIME, time - self.alivetime);
+ if(!inWarmupStage)
+ PlayerStats_Event(self, PLAYERSTATS_ALIVETIME, time - self.alivetime);
self.alivetime = 0;
}
{
if(self.version_mismatch)
{
+ self.frags = FRAGS_SPECTATOR;
Spawnqueue_Unmark(self);
Spawnqueue_Remove(self);
}
else
{
+ self.frags = FRAGS_LMS_LOSER;
Spawnqueue_Insert(self);
}
}
else
self.frags = FRAGS_SPECTATOR;
}
+ else if((g_race && g_race_qualifying) || g_cts)
+ {
+ if(PlayerScore_Add(self, SP_RACE_FASTEST, 0))
+ self.frags = FRAGS_LMS_LOSER;
+ else
+ self.frags = FRAGS_SPECTATOR;
+ }
else
self.frags = FRAGS_SPECTATOR;
}
self.weaponname = "";
self.switchingweapon = 0;
- if(!self.alivetime)
- self.alivetime = time;
+ if(!inWarmupStage)
+ if(!self.alivetime)
+ self.alivetime = time;
antilag_clear(self);
readyrestart_happened = 1;
game_starttime = time;
if(!g_ca && !g_arena) { game_starttime += RESTART_COUNTDOWN; }
-
+
+ // clear alivetime
+ FOR_EACH_CLIENT(tmp_player)
+ {
+ tmp_player.alivetime = 0;
+ PlayerStats_Event(tmp_player, PLAYERSTATS_ALIVETIME, -PlayerStats_Event(tmp_player, PLAYERSTATS_ALIVETIME, 0));
+ }
+
restart_mapalreadyrestarted = 0; // reset this var, needed when cvar sv_ready_restart_repeatable is in use
// disable the warmup global for the server
PlayerStats_AddEvent(PLAYERSTATS_MATCHES);
PlayerStats_AddEvent(PLAYERSTATS_JOINS);
PlayerStats_AddEvent(PLAYERSTATS_SCOREBOARD_VALID);
+ PlayerStats_AddEvent(PLAYERSTATS_SCOREBOARD_POS);
PlayerStats_AddEvent(PLAYERSTATS_RANK);
// accuracy stats
}
}
-void PlayerStats_Event(entity e, string event_id, float value)
+float PlayerStats_Event(entity e, string event_id, float value)
{
if((e.playerstats_id == "") || playerstats_db < 0)
- return;
+ return 0;
string key;
float val;
val = stof(db_get(playerstats_db, key));
val += value;
db_put(playerstats_db, key, ftos(val));
+ return val;
}
void PlayerStats_TeamScore(float t, string event_id, float value) // TODO: doesn't this remain unused?
switch(status)
{
case URL_READY_CANWRITE:
- url_fputs(fh, "V 5\n");
+ url_fputs(fh, "V 6\n");
#ifdef WATERMARK
url_fputs(fh, sprintf("R %s\n", WATERMARK));
#endif
}
db_put(playerstats_db, sprintf("%s:_playerid", p.playerstats_id), ftos(p.playerid));
-
+
if(p.cvar_cl_allow_uid2name == 1 || clienttype(p) == CLIENTTYPE_BOT)
db_put(playerstats_db, sprintf("%s:_netname", p.playerstats_id), p.netname);
- if(teamplay)
+ if(teamplay)
db_put(playerstats_db, sprintf("%s:_team", p.playerstats_id), ftos(p.team));
if(stof(db_get(playerstats_db, sprintf("%d:%s", p.playerstats_id, PLAYERSTATS_ALIVETIME))) > 0)
PlayerStats_Accuracy(p);
+ if(clienttype(p) == CLIENTTYPE_REAL)
+ {
+ if(p.latency_cnt)
+ {
+ float latency = (p.latency_sum / p.latency_cnt);
+ if(latency) { PlayerStats_Event(p, PLAYERSTATS_AVGLATENCY, latency); }
+ }
+ }
+
strunzone(p.playerstats_id);
p.playerstats_id = string_null;
}
void PlayerStats_EndMatch(float finished)
{
entity p;
- PlayerScore_Sort(score_dummyfield, 0);
- PlayerScore_Sort(scoreboard_pos, 1);
+ PlayerScore_Sort(score_dummyfield, 0, 0, 0);
+ PlayerScore_Sort(scoreboard_pos, 1, 1, 1);
FOR_EACH_CLIENT(p)
{
- //PlayerStats_Accuracy(p); // stats are already written with PlayerStats_AddGlobalInfo(entity), don't double them up.
+ // add personal score rank
+ PlayerStats_Event(p, PLAYERSTATS_RANK, p.score_dummyfield);
- if(p.frags == FRAGS_SPECTATOR)
+ if(!p.scoreboard_pos)
continue;
- if(clienttype(p) == CLIENTTYPE_REAL)
- {
- if(p.latency_cnt)
- {
- float latency = (p.latency_sum / p.latency_cnt);
- if(latency) { PlayerStats_Event(p, PLAYERSTATS_AVGLATENCY, latency); }
- }
- }
-
- PlayerScore_PlayerStats(p);
+ // scoreboard is valid!
PlayerStats_Event(p, PLAYERSTATS_SCOREBOARD_VALID, 1);
+
+ // add scoreboard position
+ PlayerStats_Event(p, PLAYERSTATS_SCOREBOARD_POS, p.scoreboard_pos);
+
+ // add scoreboard data
+ PlayerScore_PlayerStats(p);
+
+ // if the match ended normally, add winning info
if(finished)
{
PlayerStats_Event(p, PLAYERSTATS_WINS, p.winning);
PlayerStats_Event(p, PLAYERSTATS_MATCHES, 1);
- PlayerStats_Event(p, PLAYERSTATS_RANK, p.score_dummyfield);
- PlayerStats_Event(p, PLAYERSTATS_SCOREBOARD_POS, p.scoreboard_pos);
}
}
}
void PlayerStats_AddEvent(string event_id);
// call on each event to track, or at player disconnect OR match end for "global stuff"
-void PlayerStats_Event(entity e, string event_id, float value);
+float PlayerStats_Event(entity e, string event_id, float value);
// add a team score
void PlayerStats_TeamScore(float t, string event_id, float value);
}
else
{
+ s = PlayerScore_Add(e, SP_RACE_FASTEST, 0);
+ if(!s || t < s)
+ PlayerScore_Add(e, SP_RACE_FASTEST, t - s);
+
s = PlayerScore_Add(e, SP_RACE_TIME, 0);
snew = TIME_ENCODE(time - game_starttime);
PlayerScore_Add(e, SP_RACE_TIME, snew - s);
Score_NicePrint(world);
race_ClearRecords();
- PlayerScore_Sort(race_place, 1);
+ PlayerScore_Sort(race_place, 0, 1, 0);
entity e;
FOR_EACH_CLIENT(e)
return TRUE;
}
-void PlayerScore_Clear(entity player)
+float PlayerScore_Clear(entity player)
{
entity sk;
float i;
if(teamscores_entities_count)
- return;
+ return 0;
- if(g_lms) return;
- if(g_arena || g_ca) return;
- if(g_cts) return; // in CTS, you don't lose score by observing
- if(g_race && g_race_qualifying) return; // in qualifying, you don't lose score by observing
+ if(g_lms) return 0;
+ if(g_arena || g_ca) return 0;
+ if(g_cts) return 0; // in CTS, you don't lose score by observing
+ if(g_race && g_race_qualifying) return 0; // in qualifying, you don't lose score by observing
sk = player.scorekeeper;
for(i = 0; i < MAX_SCORE; ++i)
sk.SendFlags |= pow(2, i);
sk.(scores[i]) = 0;
}
+
+ return 1;
}
void Score_ClearAll()
return out;
}
-float PlayerTeamScore_Compare(entity p1, entity p2, float strict)
+float PlayerTeamScore_Compare(entity p1, entity p2, float teams, float strict)
{
- if(teamscores_entities_count)
+ if(teams && teamscores_entities_count)
+ {
if(p1.team != p2.team)
{
entity t1, t2;
float r;
t1 = teamscorekeepers[p1.team - 1];
t2 = teamscorekeepers[p2.team - 1];
- r = TeamScore_Compare(t1, t2, strict);
+ r = TeamScore_Compare(t1, t2, ((teams >= 0) ? 1 : strict));
return r;
}
+ if(teams < 0)
+ return 0;
+ }
return PlayerScore_Compare(p1.scorekeeper, p2.scorekeeper, strict);
}
-entity PlayerScore_Sort(.float field, float strict)
+entity PlayerScore_Sort(.float field, float teams, float strict, float nospectators)
{
entity p, plist, pprev, pbest, pbestprev, pfirst, plast;
float i, j;
FOR_EACH_CLIENT(p)
p.field = 0;
- FOR_EACH_PLAYER(p) if(p.scorekeeper)
+ FOR_EACH_CLIENT(p) if(p.scorekeeper)
{
+ if(nospectators)
+ if(p.frags == FRAGS_SPECTATOR)
+ continue;
+
p.chain = plist;
plist = p;
}
pbest = plist;
for(p = plist; (pprev = p), (p = p.chain); )
{
- if(PlayerTeamScore_Compare(p, pbest, strict) > 0)
+ if(PlayerTeamScore_Compare(p, pbest, teams, strict) > 0)
{
pbest = p;
pbestprev = pprev;
pbest.chain = world;
++i;
- if(!plast || PlayerTeamScore_Compare(plast, pbest, 0))
+ if(!plast || PlayerTeamScore_Compare(plast, pbest, teams, 0))
j = i;
pbest.field = j;
++t;
w = bound(6, floor(SCORESWIDTH / t - 1), 9);
- p = PlayerScore_Sort(score_dummyfield, 1);
+ p = PlayerScore_Sort(score_dummyfield, 1, 1, 0);
t = -1;
if(!teamscores_entities_count)
* Initialize the score of this player if needed.
* Does nothing in teamplay.
* Use that when a spectator becomes a player.
+ * Returns whether clearing has been performed
*/
-void PlayerScore_Clear(entity player);
+float PlayerScore_Clear(entity player);
/**
* Adds a score to the player's team's scores.
* Sorts the players and stores their place in the given field, starting with
* 1. Non-players get 0 written into that field.
* Returns the beginning of a sorted chain of the non-spectators.
+ * teams: >0: sort by teams first (always strict ordering); <0: sort by teams only (respects strict flag)
+ * strict: return a strict ordering
+ * nospectators: exclude spectators
*/
-entity PlayerScore_Sort(.float field, float strict);
+entity PlayerScore_Sort(.float field, float teams, float strict, float nospectators);
// Race stuff
#define ST_RACE_LAPS 1
#define SP_RACE_LAPS 4
-#define SP_RACE_FASTEST 5
#define SP_RACE_TIME 5
-//#define SP_RACE_RANK 6
+#define SP_RACE_FASTEST 6
void ScoreRules_race()
{
ScoreRules_basics(race_teams, 0, 0, FALSE);
ScoreInfo_SetLabel_TeamScore( ST_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY);
ScoreInfo_SetLabel_PlayerScore(SP_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY);
ScoreInfo_SetLabel_PlayerScore(SP_RACE_TIME, "time", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER | SFL_TIME);
- //ScoreInfo_SetLabel_PlayerScore(SP_RACE_RANK, "rank", SFL_LOWER_IS_BETTER | SFL_RANK | SFL_ALLOW_HIDE);
+ ScoreInfo_SetLabel_PlayerScore(SP_RACE_FASTEST, "fastest", SFL_LOWER_IS_BETTER | SFL_TIME);
}
else if(g_race_qualifying)
{
}
else
{
- //ScoreInfo_SetLabel_TeamScore( ST_RACE_LAPS, "laps", 0);
ScoreInfo_SetLabel_PlayerScore(SP_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY);
ScoreInfo_SetLabel_PlayerScore(SP_RACE_TIME, "time", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER | SFL_TIME);
+ ScoreInfo_SetLabel_PlayerScore(SP_RACE_FASTEST, "fastest", SFL_LOWER_IS_BETTER | SFL_TIME);
}
ScoreRules_basics_end();
}