diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b40dc4894..1f084fedf 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,7 +18,7 @@ env: -Dvariable-fps=true -Dwerror=false -Daqtion-build=true - -Ddiscord-sdk=true + -Ddiscord-sdk=false MESON_ARGS_WIN: >- -Dsdl2=disabled diff --git a/src/action/g_cmds.c b/src/action/g_cmds.c index ee31abc8c..ad4e1fbe2 100644 --- a/src/action/g_cmds.c +++ b/src/action/g_cmds.c @@ -1841,19 +1841,37 @@ void Cmd_HighScores_f(edict_t *ent) return; } - gi.cprintf(ent, PRINT_HIGH, - "\n" - " # Name FPH Date\n" - "-- --------------- ---- ----------------\n"); - for (i = 0; i < level.numscores; i++) { - s = &level.scores[i]; - - tm = localtime(&s->time); - if (!tm || !strftime(date, sizeof(date), "%Y-%m-%d %H:%M", tm)) - strcpy(date, "???"); - gi.cprintf(ent, PRINT_HIGH, "%2d %-15.15s %4d %s\n", - i + 1, s->name, s->score, date); - } + if (teamplay->value){ + gi.cprintf(ent, PRINT_HIGH, + "\n" + " # Name Score FPR Acc Date\n" + "-- --------------- ----- ---- --- -------------\n"); + for (i = 0; i < level.numscores; i++) { + s = &level.scores[i]; + + tm = localtime(&s->time); + if (!tm || !strftime(date, sizeof(date), "%Y-%m-%d %H:%M", tm)) + strcpy(date, "???"); + gi.cprintf(ent, PRINT_HIGH, "%2d %-15.15s %5d %5.1i %5.1f %2s\n", + i + 1, s->name, s->score, (int)s->fragsper, s->accuracy, date); + } + + } else { + gi.cprintf(ent, PRINT_HIGH, + "\n" + " # Name Score FPH Acc Date\n" + "-- --------------- ----- ---- --- -------------\n"); + + for (i = 0; i < level.numscores; i++) { + s = &level.scores[i]; + + tm = localtime(&s->time); + if (!tm || !strftime(date, sizeof(date), "%Y-%m-%d %H:%M", tm)) + strcpy(date, "???"); + gi.cprintf(ent, PRINT_HIGH, "%2d %-15.15s %5d %5.1i %5.1f %2s\n", + i + 1, s->name, s->score, (int)s->fragsper, s->accuracy, date); + } + } } #define CMDF_CHEAT 1 //Need cheat to be enabled diff --git a/src/action/g_local.h b/src/action/g_local.h index c19b44627..ba78e1966 100644 --- a/src/action/g_local.h +++ b/src/action/g_local.h @@ -655,6 +655,8 @@ typedef struct highscore_s { char name[MAX_CLIENT_NAME]; int score; + float fragsper; + float accuracy; time_t time; } highscore_t; @@ -774,6 +776,7 @@ typedef struct // High Scores support from OpenFFA char dir[MAX_OSPATH]; // where variable data is stored + char mode[MAX_QPATH]; // current game mode } game_locals_t; diff --git a/src/action/g_spawn.c b/src/action/g_spawn.c index e40ba1dbb..e50a063d6 100644 --- a/src/action/g_spawn.c +++ b/src/action/g_spawn.c @@ -863,20 +863,28 @@ int Gamemode(void) int gamemode = 0; if (teamdm->value) { gamemode = GM_TEAMDM; + strcpy(game.mode, "teamdm"); } else if (ctf->value) { gamemode = GM_CTF; + strcpy(game.mode, "ctf"); } else if (use_tourney->value) { gamemode = GM_TOURNEY; + strcpy(game.mode, "tourney"); } else if (teamplay->value) { gamemode = GM_TEAMPLAY; + strcpy(game.mode, "teamplay"); } else if (dom->value) { gamemode = GM_DOMINATION; + strcpy(game.mode, "dom"); } else if (deathmatch->value) { gamemode = GM_DEATHMATCH; + strcpy(game.mode, "deathmatch"); } else if (esp->value && atl->value) { gamemode = GM_ASSASSINATE_THE_LEADER; + strcpy(game.mode, "atl"); } else if (esp->value && etv->value) { gamemode = GM_ESCORT_THE_VIP; + strcpy(game.mode, "etv"); } return gamemode; } @@ -1235,8 +1243,9 @@ void SpawnEntities (const char *mapname, const char *entities, const char *spawn gi.FreeTags(TAG_LEVEL); - // Set serverinfo correctly for gamemodeflags + // Set serverinfo correctly for gamemodeflags and game.mode Gamemodeflag(); + Gamemode(); #if USE_AQTION generate_uuid(); // Run this once every time a map loads to generate a unique id for stats (game.matchid) diff --git a/src/action/tng_stats.c b/src/action/tng_stats.c index 92599f8a4..ccdcea3ce 100644 --- a/src/action/tng_stats.c +++ b/src/action/tng_stats.c @@ -649,8 +649,8 @@ static void G_SaveScores(void) int i; size_t len; - len = Q_snprintf(path, sizeof(path), "%s%s%s/%s.txt", - GAMEVERSION, SD(g_highscores_dir->string), level.mapname); + len = Q_snprintf(path, sizeof(path), "%s%s%s/%s/%s.txt", + GAMEVERSION, SD(g_highscores_dir->string), game.mode, level.mapname); if (len >= sizeof(path)) { return; } @@ -665,8 +665,8 @@ static void G_SaveScores(void) for (i = 0; i < level.numscores; i++) { s = &level.scores[i]; - fprintf(fp, "\"%s\" %d %lu\n", - s->name, s->score, (unsigned long)s->time); + fprintf(fp, "\"%s\" %d %f %f %lu\n", + s->name, s->score, s->fragsper, s->accuracy, (unsigned long)s->time); } fclose(fp); @@ -711,24 +711,42 @@ void G_RegisterScore(void) { gclient_t *ranks[MAX_CLIENTS]; gclient_t *c; - highscore_t *s; + highscore_t *s; int total; - int sec, score; + int score; + int sec; + float accuracy, fragsper; total = G_CalcRanks(ranks); if (!total) { return; } + if (teamplay->value && game.roundNum > 0){ + return; // No rounds were played, so skip + } + // grab our champion c = ranks[0]; - // calculate FPH - sec = (level.framenum - c->resp.enterframe) / HZ; - if (!sec) { - sec = 1; - } - score = c->resp.score * 3600 / sec; + // Just straight up score + score = c->resp.score; + + // Calculate FPR, if mode is teamplay, else FPH + if (teamplay->value && game.roundNum > 0){ + fragsper = c->resp.score / game.roundNum; + } else { + sec = (level.framenum - c->resp.enterframe) / HZ; + if (!sec) + sec = 1; + fragsper = c->resp.score * 3600 / sec; + } + + int shots = min(c->resp.shotsTotal, 9999 ); + if (shots) + accuracy = (double)c->resp.hitsTotal * 100.0 / (double)c->resp.shotsTotal; + else + accuracy = 0; if (score < 1) { return; // do not record bogus results @@ -745,13 +763,15 @@ void G_RegisterScore(void) strcpy(s->name, c->pers.netname); s->score = score; + s->fragsper = fragsper; + s->accuracy = accuracy; time(&s->time); level.record = s->time; qsort(level.scores, level.numscores, sizeof(highscore_t), ScoreCmp); - gi.dprintf("Added highscore entry for %s with %d FPH\n", + gi.dprintf("Added highscore entry for %s with %d score\n", c->pers.netname, score); G_SaveScores(); @@ -765,7 +785,7 @@ void G_LoadScores(void) load_file_t *f; int i; - f = G_LoadFile("%s%s%s/%s.txt", GAMEVERSION, SD(g_highscores_dir->string), level.mapname); + f = G_LoadFile("%s%s%s/%s/%s.txt", GAMEVERSION, SD(g_highscores_dir->string), game.mode, level.mapname); if (!f) { gi.dprintf("No high scores file loaded for %s\n", level.mapname); return; @@ -789,6 +809,13 @@ void G_LoadScores(void) token = COM_Parse(&data); s->score = strtoul(token, NULL, 10); + token = COM_Parse(&data); + s->fragsper = strtoul(token, NULL, 10); // Load fragsper value + + token = COM_Parse(&data); + s->accuracy = strtoul(token, NULL, 10); // Load accuracy value + + token = COM_Parse(&data); s->time = strtoul(token, NULL, 10); }