diff options
| author | xolatile | 2025-08-04 22:53:42 +0200 |
|---|---|---|
| committer | xolatile | 2025-08-04 22:53:42 +0200 |
| commit | d309df4ce4d8ad0ed995a8e1c4267412a7782021 (patch) | |
| tree | 999ca8d785ecc1681e5eb7538ce2e6a18d244fa5 /src/fpsgame/scoreboard.cpp | |
| parent | 29d613d9cb65a0faa7e3f80e75bea0b6d910cb9a (diff) | |
| download | xolatile-badassbug-d309df4ce4d8ad0ed995a8e1c4267412a7782021.tar.xz xolatile-badassbug-d309df4ce4d8ad0ed995a8e1c4267412a7782021.tar.zst | |
Bunch of small changes...
Diffstat (limited to 'src/fpsgame/scoreboard.cpp')
| -rw-r--r-- | src/fpsgame/scoreboard.cpp | 1148 |
1 files changed, 574 insertions, 574 deletions
diff --git a/src/fpsgame/scoreboard.cpp b/src/fpsgame/scoreboard.cpp index 5e0ae17..96f8868 100644 --- a/src/fpsgame/scoreboard.cpp +++ b/src/fpsgame/scoreboard.cpp @@ -3,579 +3,579 @@ namespace game { - VARP(scoreboard2d, 0, 1, 1); - VARP(showservinfo, 0, 1, 1); - VARP(showclientnum, 0, 1, 1); - VARP(showpj, 0, 0, 1); - VARP(showping, 0, 1, 2); - VARP(showspectators, 0, 1, 1); - VARP(showspectatorping, 0, 1, 1); - VARP(highlightscore, 0, 1, 1); - VARP(showconnecting, 0, 0, 1); - VARP(hidefrags, 0, 0, 1); - VARP(showdeaths, 0, 1, 1); - VARP(showdamagedealt, 0, 1, 1); - - static hashset<teaminfo> teaminfos; - - void clearteaminfo() - { - teaminfos.clear(); - } - - void setteaminfo(const char *team, int frags) - { - teaminfo *t = teaminfos.access(team); - if(!t) { t = &teaminfos[team]; copystring(t->team, team, sizeof(t->team)); } - t->frags = frags; - } - - static inline bool playersort(const fpsent *a, const fpsent *b) - { - if(a->state==CS_SPECTATOR) - { - if(b->state==CS_SPECTATOR) return strcmp(a->name, b->name) < 0; - else return false; - } - else if(b->state==CS_SPECTATOR) return true; - if(a->frags > b->frags) return true; - if(a->frags < b->frags) return false; - return strcmp(a->name, b->name) < 0; - } - - void getbestplayers(vector<fpsent *> &best) - { - loopv(players) - { - fpsent *o = players[i]; - if(o->state!=CS_SPECTATOR) best.add(o); - } - best.sort(playersort); - while(best.length() > 1 && best.last()->frags < best[0]->frags) best.drop(); - } - - void getbestteams(vector<const char *> &best) - { - if(!hidefrags) - { - vector<teamscore> teamscores; - teamscores.sort(teamscore::compare); - while(teamscores.length() > 1 && teamscores.last().score < teamscores[0].score) teamscores.drop(); - loopv(teamscores) best.add(teamscores[i].team); - } - else - { - int bestfrags = INT_MIN; - enumerate(teaminfos, teaminfo, t, bestfrags = max(bestfrags, t.frags)); - if(bestfrags <= 0) loopv(players) - { - fpsent *o = players[i]; - if(o->state!=CS_SPECTATOR && !teaminfos.access(o->team) && best.htfind(o->team) < 0) { bestfrags = 0; best.add(o->team); } - } - enumerate(teaminfos, teaminfo, t, if(t.frags >= bestfrags) best.add(t.team)); - } - } - - struct scoregroup : teamscore - { - vector<fpsent *> players; - }; - static vector<scoregroup *> groups; - static vector<fpsent *> spectators; - - static inline bool scoregroupcmp(const scoregroup *x, const scoregroup *y) - { - if(!x->team) - { - if(y->team) return false; - } - else if(!y->team) return true; - if(x->score > y->score) return true; - if(x->score < y->score) return false; - if(x->players.length() > y->players.length()) return true; - if(x->players.length() < y->players.length()) return false; - return x->team && y->team && strcmp(x->team, y->team) < 0; - } - - static int groupplayers() - { - int numgroups = 0; - spectators.setsize(0); - loopv(players) - { - fpsent *o = players[i]; - if(!showconnecting && !o->name[0]) continue; - if(o->state==CS_SPECTATOR) { spectators.add(o); continue; } - const char *team = m_teammode && o->team[0] ? o->team : NULL; - bool found = false; - loopj(numgroups) - { - scoregroup &g = *groups[j]; - if(team!=g.team && (!team || !g.team || strcmp(team, g.team))) continue; - g.players.add(o); - found = true; - } - if(found) continue; - if(numgroups>=groups.length()) groups.add(new scoregroup); - scoregroup &g = *groups[numgroups++]; - g.team = team; - if(!team) g.score = 0; - else { teaminfo *ti = teaminfos.access(team); g.score = ti ? ti->frags : 0; } - g.players.setsize(0); - g.players.add(o); - } - loopi(numgroups) groups[i]->players.sort(playersort); - spectators.sort(playersort); - groups.sort(scoregroupcmp, 0, numgroups); - return numgroups; - } - - int statuscolor(fpsent *d, int color) - { - if(d->privilege) - { - color = d->privilege>=PRIV_ADMIN ? 0xFF8000 : (d->privilege>=PRIV_AUTH ? 0xC040C0 : 0x40FF80); - if(d->state==CS_DEAD) color = (color>>1)&0x7F7F7F; - } - else if(d->state==CS_DEAD) color = 0x606060; - return color; - } - - void renderscoreboard(g3d_gui &g, bool firstpass) - { - const ENetAddress *address = connectedpeer(); - if(showservinfo && address) - { - string hostname; - if(enet_address_get_host_ip(address, hostname, sizeof(hostname)) >= 0) - { - if(servinfo[0]) g.titlef("%.25s", 0xFFFF80, NULL, servinfo); - else g.titlef("%s:%d", 0xFFFF80, NULL, hostname, address->port); - } - } - - g.pushlist(); - g.spring(); - g.text(server::modename(gamemode), 0xFFFF80); - g.separator(); - const char *mname = getclientmap(); - g.text(mname[0] ? mname : "[new map]", 0xFFFF80); - extern int gamespeed; - if(gamespeed != 100) { g.separator(); g.textf("%d.%02dx", 0xFFFF80, NULL, gamespeed/100, gamespeed%100); } - if(m_timed && mname[0] && (maplimit >= 0 || intermission)) - { - g.separator(); - if(intermission) g.text("intermission", 0xFFFF80); - else - { - int secs = max(maplimit-lastmillis+999, 0)/1000, mins = secs/60; - secs %= 60; - g.pushlist(); - g.strut(mins >= 10 ? 4.5f : 3.5f); - g.textf("%d:%02d", 0xFFFF80, NULL, mins, secs); - g.poplist(); - } - } - if(ispaused()) { g.separator(); g.text("paused", 0xFFFF80); } - g.spring(); - g.poplist(); - - g.separator(); - - int numgroups = groupplayers(); - loopk(numgroups) - { - if((k%2)==0) g.pushlist(); // horizontal - - scoregroup &sg = *groups[k]; - int bgcolor = sg.team && m_teammode ? (isteam(player1->team, sg.team) ? 0x3030C0 : 0xC03030) : 0, - fgcolor = 0xFFFF80; - - g.pushlist(); // vertical - g.pushlist(); // horizontal - - #define loopscoregroup(o, b) \ - loopv(sg.players) \ - { \ - fpsent *o = sg.players[i]; \ - b; \ - } - - g.pushlist(); - if(sg.team && m_teammode) - { - g.pushlist(); - g.background(bgcolor, numgroups>1 ? 3 : 5); - g.strut(1); - g.poplist(); - } - g.text("", 0, " "); - loopscoregroup(o, - { - if(o==player1 && highlightscore && (multiplayer(false) || demoplayback || players.length() > 1)) - { - g.pushlist(); - g.background(0x808080, numgroups>1 ? 3 : 5); - } - const playermodelinfo &mdl = getplayermodelinfo(o); - const char *icon = sg.team && m_teammode ? (isteam(player1->team, sg.team) ? mdl.blueicon : mdl.redicon) : mdl.ffaicon; - g.text("", 0, icon); - if(o==player1 && highlightscore && (multiplayer(false) || demoplayback || players.length() > 1)) g.poplist(); - }); - g.poplist(); - - if(sg.team && m_teammode) - { - g.pushlist(); // vertical - - if(sg.score>=10000) g.textf("%s: WIN", fgcolor, NULL, sg.team); - else g.textf("%s: %d", fgcolor, NULL, sg.team, sg.score); - - g.pushlist(); // horizontal - } - - if(!hidefrags) - { - g.pushlist(); - g.strut(6); - g.text("frags", fgcolor); - loopscoregroup(o, g.textf("%d", 0xFFFFDD, NULL, o->frags)); - g.poplist(); - } - - if(showdeaths) - { - g.pushlist(); - g.strut(6); - g.text("deaths", fgcolor); - loopscoregroup(o, g.textf("%d", 0xFFFFDD, NULL, o->deaths)); - g.poplist(); - } - - if(showdamagedealt) - { - g.pushlist(); - g.strut(7); - g.text("damage", fgcolor); - loopscoregroup(o, g.textf("%d", 0xFFFFDD, NULL, o->totaldamage)); - g.poplist(); - } - - g.pushlist(); - g.text("name", fgcolor); - g.strut(12); - loopscoregroup(o, { g.textf("%s ", statuscolor(o, 0xFFFFDD), NULL, colorname(o)); }); - g.poplist(); - - if(multiplayer(false) || demoplayback) - { - if(showpj || showping) g.space(1); - - if(showpj && showping <= 1) - { - g.pushlist(); - g.strut(6); - g.text("pj", fgcolor); - loopscoregroup(o, - { - if(o->state==CS_LAGGED) g.text("LAG", 0xFFFFDD); - else g.textf("%d", 0xFFFFDD, NULL, o->plag); - }); - g.poplist(); - } - - if(showping > 1) - { - g.pushlist(); - g.strut(6); - - g.pushlist(); - g.text("ping", fgcolor); - g.space(1); - g.spring(); - g.text("pj", fgcolor); - g.poplist(); - - loopscoregroup(o, - { - fpsent *p = o->ownernum >= 0 ? getclient(o->ownernum) : o; - if(!p) p = o; - g.pushlist(); - if(p->state==CS_LAGGED) g.text("LAG", 0xFFFFDD); - else - { - g.textf("%d", 0xFFFFDD, NULL, p->ping); - g.space(1); - g.spring(); - g.textf("%d", 0xFFFFDD, NULL, o->plag); - } - g.poplist(); - - }); - g.poplist(); - } - else if(showping) - { - g.pushlist(); - g.text("ping", fgcolor); - g.strut(6); - loopscoregroup(o, - { - fpsent *p = o->ownernum >= 0 ? getclient(o->ownernum) : o; - if(!p) p = o; - if(!showpj && p->state==CS_LAGGED) g.text("LAG", 0xFFFFDD); - else g.textf("%d", 0xFFFFDD, NULL, p->ping); - }); - g.poplist(); - } - } - - if(showclientnum || player1->privilege>=PRIV_MASTER) - { - g.space(1); - g.pushlist(); - g.text("cn", fgcolor); - loopscoregroup(o, g.textf("%d", 0xFFFFDD, NULL, o->clientnum)); - g.poplist(); - } - - if(sg.team && m_teammode) - { - g.poplist(); // horizontal - g.poplist(); // vertical - } - - g.poplist(); // horizontal - g.poplist(); // vertical - - if(k+1<numgroups && (k+1)%2) g.space(2); - else g.poplist(); // horizontal - } - - if(showspectators && spectators.length()) - { - if(showclientnum || player1->privilege>=PRIV_MASTER) - { - g.pushlist(); - - g.pushlist(); - g.text("spectator", 0xFFFF80, " "); - g.strut(12); - loopv(spectators) - { - fpsent *o = spectators[i]; - if(o==player1 && highlightscore) - { - g.pushlist(); - g.background(0x808080, 3); - } - g.text(colorname(o), statuscolor(o, 0xFFFFDD), "spectator"); - if(o==player1 && highlightscore) g.poplist(); - } - g.poplist(); - - if((multiplayer(false) || demoplayback) && showspectatorping) - { - g.space(1); - g.pushlist(); - g.text("ping", 0xFFFF80); - g.strut(6); - loopv(spectators) - { - fpsent *o = spectators[i]; - fpsent *p = o->ownernum >= 0 ? getclient(o->ownernum) : o; - if(!p) p = o; - if(p->state==CS_LAGGED) g.text("LAG", 0xFFFFDD); - else g.textf("%d", 0xFFFFDD, NULL, p->ping); - } - g.poplist(); - } - - g.space(1); - g.pushlist(); - g.text("cn", 0xFFFF80); - loopv(spectators) g.textf("%d", 0xFFFFDD, NULL, spectators[i]->clientnum); - g.poplist(); - - g.poplist(); - } - else - { - g.textf("%d spectator%s", 0xFFFF80, " ", spectators.length(), spectators.length()!=1 ? "s" : ""); - loopv(spectators) - { - if((i%3)==0) - { - g.pushlist(); - g.text("", 0xFFFFDD, "spectator"); - } - fpsent *o = spectators[i]; - if(o==player1 && highlightscore) - { - g.pushlist(); - g.background(0x808080); - } - g.text(colorname(o), statuscolor(o, 0xFFFFDD)); - if(o==player1 && highlightscore) g.poplist(); - if(i+1<spectators.length() && (i+1)%3) g.space(1); - else g.poplist(); - } - } - } - - /// PW - g.separator(); - g.pushlist(); - g.textf(" %d%% ", 0x787878, "chainsaw.png", pwaccuracy[0]); - g.textf(" %d%% ", 0xfba6a6, "shotgun.png", pwaccuracy[1]); - g.textf(" %d%% ", 0x7bc77a, "chaingun.png", pwaccuracy[2]); - g.textf(" %d%% ", 0xefd7a6, "rocket_launcher.png", pwaccuracy[3]); - g.textf(" %d%% ", 0x8f91e7, "rifle.png", pwaccuracy[4]); - g.textf(" %d%% ", 0x9ee5e5, "grenade_launcher.png", pwaccuracy[5]); - g.textf(" %d%% ", 0xc3c3c3, "pistol.png", pwaccuracy[6]); - g.poplist(); - g.separator(); - g.pushlist(); - g.textf(" x %d ", 0xffffff, "blue_armour.png", pwitemspicked[0]); - g.textf(" x %d ", 0xffffff, "green_armour.png", pwitemspicked[1]); - g.textf(" x %d ", 0xffffff, "yellow_armour.png", pwitemspicked[2]); - g.textf(" x %d ", 0xffffff, "tiny_health.png", pwitemspicked[3]); - g.textf(" x %d ", 0xffffff, "health.png", pwitemspicked[4]); - g.textf(" x %d ", 0xffffff, "health_boost.png", pwitemspicked[5]); - g.textf(" x %d ", 0xffffff, "quad_damage.png", pwitemspicked[6]); - g.poplist(); - } - - struct scoreboardgui : g3d_callback - { - bool showing; - vec menupos; - int menustart; - - scoreboardgui() : showing(false) {} - - void show(bool on) - { - if(!showing && on) - { - menupos = menuinfrontofplayer(); - menustart = starttime(); - } - showing = on; - } - - void gui(g3d_gui &g, bool firstpass) - { - g.start(menustart, 0.03f, NULL, false); - renderscoreboard(g, firstpass); - g.end(); - } - - void render() - { - if(showing) g3d_addgui(this, menupos, (scoreboard2d ? GUI_FORCE_2D : GUI_2D | GUI_FOLLOW) | GUI_BOTTOM); - } - - } scoreboard; - - void g3d_gamemenus() - { - scoreboard.render(); - } - - VARFN(scoreboard, showscoreboard, 0, 0, 1, scoreboard.show(showscoreboard!=0)); - - void showscores(bool on) - { - showscoreboard = on ? 1 : 0; - scoreboard.show(on); - } - ICOMMAND(showscores, "D", (int *down), showscores(*down!=0)); - - VARP(hudscore, 0, 0, 1); - FVARP(hudscorescale, 1e-3f, 1.0f, 1e3f); - VARP(hudscorealign, -1, 0, 1); - FVARP(hudscorex, 0, 0.50f, 1); - FVARP(hudscorey, 0, 0.03f, 1); - HVARP(hudscoreplayercolour, 0, 0x60A0FF, 0xFFFFFF); - HVARP(hudscoreenemycolour, 0, 0xFF4040, 0xFFFFFF); - VARP(hudscorealpha, 0, 255, 255); - VARP(hudscoresep, 0, 200, 1000); - - void drawhudscore(int w, int h) - { - int numgroups = groupplayers(); - if(!numgroups) return; - - scoregroup *g = groups[0]; - int score = INT_MIN, score2 = INT_MIN; - bool best = false; - if(m_teammode) - { - score = g->score; - best = isteam(player1->team, g->team); - if(numgroups > 1) - { - if(best) score2 = groups[1]->score; - else for(int i = 1; i < groups.length(); ++i) if(isteam(player1->team, groups[i]->team)) { score2 = groups[i]->score; break; } - if(score2 == INT_MIN) - { - fpsent *p = followingplayer(player1); - if(p->state==CS_SPECTATOR) score2 = groups[1]->score; - } - } - } - else - { - fpsent *p = followingplayer(player1); - score = g->players[0]->frags; - best = p == g->players[0]; - if(g->players.length() > 1) - { - if(best || p->state==CS_SPECTATOR) score2 = g->players[1]->frags; - else score2 = p->frags; - } - } - if(score == score2 && !best) best = true; - - score = clamp(score, -999, 9999); - defformatstring(buf, "%d", score); - int tw = 0, th = 0; - text_bounds(buf, tw, th); - - string buf2; - int tw2 = 0, th2 = 0; - if(score2 > INT_MIN) - { - score2 = clamp(score2, -999, 9999); - formatstring(buf2, "%d", score2); - text_bounds(buf2, tw2, th2); - } - - int fw = 0, fh = 0; - text_bounds("00", fw, fh); - fw = max(fw, max(tw, tw2)); - - vec2 offset = vec2(hudscorex, hudscorey).mul(vec2(w, h).div(hudscorescale)); - if(hudscorealign == 1) offset.x -= 2*fw + hudscoresep; - else if(hudscorealign == 0) offset.x -= (2*fw + hudscoresep) / 2.0f; - vec2 offset2 = offset; - offset.x += (fw-tw)/2.0f; - offset.y -= th/2.0f; - offset2.x += fw + hudscoresep + (fw-tw2)/2.0f; - offset2.y -= th2/2.0f; - - pushhudmatrix(); - hudmatrix.scale(hudscorescale, hudscorescale, 1); - flushhudmatrix(); - - int color = hudscoreplayercolour, color2 = hudscoreenemycolour; - if(!best) swap(color, color2); - - draw_text(buf, int(offset.x), int(offset.y), (color>>16)&0xFF, (color>>8)&0xFF, color&0xFF, hudscorealpha); - if(score2 > INT_MIN) draw_text(buf2, int(offset2.x), int(offset2.y), (color2>>16)&0xFF, (color2>>8)&0xFF, color2&0xFF, hudscorealpha); - - pophudmatrix(); - } + VARP(scoreboard2d, 0, 1, 1); + VARP(showservinfo, 0, 1, 1); + VARP(showclientnum, 0, 1, 1); + VARP(showpj, 0, 0, 1); + VARP(showping, 0, 1, 2); + VARP(showspectators, 0, 1, 1); + VARP(showspectatorping, 0, 1, 1); + VARP(highlightscore, 0, 1, 1); + VARP(showconnecting, 0, 0, 1); + VARP(hidefrags, 0, 0, 1); + VARP(showdeaths, 0, 1, 1); + VARP(showdamagedealt, 0, 1, 1); + + static hashset<teaminfo> teaminfos; + + void clearteaminfo() + { + teaminfos.clear(); + } + + void setteaminfo(const char *team, int frags) + { + teaminfo *t = teaminfos.access(team); + if(!t) { t = &teaminfos[team]; copystring(t->team, team, sizeof(t->team)); } + t->frags = frags; + } + + static inline bool playersort(const fpsent *a, const fpsent *b) + { + if(a->state==CS_SPECTATOR) + { + if(b->state==CS_SPECTATOR) return strcmp(a->name, b->name) < 0; + else return false; + } + else if(b->state==CS_SPECTATOR) return true; + if(a->frags > b->frags) return true; + if(a->frags < b->frags) return false; + return strcmp(a->name, b->name) < 0; + } + + void getbestplayers(vector<fpsent *> &best) + { + loopv(players) + { + fpsent *o = players[i]; + if(o->state!=CS_SPECTATOR) best.add(o); + } + best.sort(playersort); + while(best.length() > 1 && best.last()->frags < best[0]->frags) best.drop(); + } + + void getbestteams(vector<const char *> &best) + { + if(!hidefrags) + { + vector<teamscore> teamscores; + teamscores.sort(teamscore::compare); + while(teamscores.length() > 1 && teamscores.last().score < teamscores[0].score) teamscores.drop(); + loopv(teamscores) best.add(teamscores[i].team); + } + else + { + int bestfrags = INT_MIN; + enumerate(teaminfos, teaminfo, t, bestfrags = max(bestfrags, t.frags)); + if(bestfrags <= 0) loopv(players) + { + fpsent *o = players[i]; + if(o->state!=CS_SPECTATOR && !teaminfos.access(o->team) && best.htfind(o->team) < 0) { bestfrags = 0; best.add(o->team); } + } + enumerate(teaminfos, teaminfo, t, if(t.frags >= bestfrags) best.add(t.team)); + } + } + + struct scoregroup : teamscore + { + vector<fpsent *> players; + }; + static vector<scoregroup *> groups; + static vector<fpsent *> spectators; + + static inline bool scoregroupcmp(const scoregroup *x, const scoregroup *y) + { + if(!x->team) + { + if(y->team) return false; + } + else if(!y->team) return true; + if(x->score > y->score) return true; + if(x->score < y->score) return false; + if(x->players.length() > y->players.length()) return true; + if(x->players.length() < y->players.length()) return false; + return x->team && y->team && strcmp(x->team, y->team) < 0; + } + + static int groupplayers() + { + int numgroups = 0; + spectators.setsize(0); + loopv(players) + { + fpsent *o = players[i]; + if(!showconnecting && !o->name[0]) continue; + if(o->state==CS_SPECTATOR) { spectators.add(o); continue; } + const char *team = m_teammode && o->team[0] ? o->team : NULL; + bool found = false; + loopj(numgroups) + { + scoregroup &g = *groups[j]; + if(team!=g.team && (!team || !g.team || strcmp(team, g.team))) continue; + g.players.add(o); + found = true; + } + if(found) continue; + if(numgroups>=groups.length()) groups.add(new scoregroup); + scoregroup &g = *groups[numgroups++]; + g.team = team; + if(!team) g.score = 0; + else { teaminfo *ti = teaminfos.access(team); g.score = ti ? ti->frags : 0; } + g.players.setsize(0); + g.players.add(o); + } + loopi(numgroups) groups[i]->players.sort(playersort); + spectators.sort(playersort); + groups.sort(scoregroupcmp, 0, numgroups); + return numgroups; + } + + int statuscolor(fpsent *d, int color) + { + if(d->privilege) + { + color = d->privilege>=PRIV_ADMIN ? 0xFF8000 : (d->privilege>=PRIV_AUTH ? 0xC040C0 : 0x40FF80); + if(d->state==CS_DEAD) color = (color>>1)&0x7F7F7F; + } + else if(d->state==CS_DEAD) color = 0x606060; + return color; + } + + void renderscoreboard(g3d_gui &g, bool firstpass) + { + const ENetAddress *address = connectedpeer(); + if(showservinfo && address) + { + string hostname; + if(enet_address_get_host_ip(address, hostname, sizeof(hostname)) >= 0) + { + if(servinfo[0]) g.titlef("%.25s", 0xFFFF80, NULL, servinfo); + else g.titlef("%s:%d", 0xFFFF80, NULL, hostname, address->port); + } + } + + g.pushlist(); + g.spring(); + g.text(server::modename(gamemode), 0xFFFF80); + g.separator(); + const char *mname = getclientmap(); + g.text(mname[0] ? mname : "[new map]", 0xFFFF80); + extern int gamespeed; + if(gamespeed != 100) { g.separator(); g.textf("%d.%02dx", 0xFFFF80, NULL, gamespeed/100, gamespeed%100); } + if(m_timed && mname[0] && (maplimit >= 0 || intermission)) + { + g.separator(); + if(intermission) g.text("intermission", 0xFFFF80); + else + { + int secs = max(maplimit-lastmillis+999, 0)/1000, mins = secs/60; + secs %= 60; + g.pushlist(); + g.strut(mins >= 10 ? 4.5f : 3.5f); + g.textf("%d:%02d", 0xFFFF80, NULL, mins, secs); + g.poplist(); + } + } + if(ispaused()) { g.separator(); g.text("paused", 0xFFFF80); } + g.spring(); + g.poplist(); + + g.separator(); + + int numgroups = groupplayers(); + loopk(numgroups) + { + if((k%2)==0) g.pushlist(); // horizontal + + scoregroup &sg = *groups[k]; + int bgcolor = sg.team && m_teammode ? (isteam(player1->team, sg.team) ? 0x3030C0 : 0xC03030) : 0, + fgcolor = 0xFFFF80; + + g.pushlist(); // vertical + g.pushlist(); // horizontal + + #define loopscoregroup(o, b) \ + loopv(sg.players) \ + { \ + fpsent *o = sg.players[i]; \ + b; \ + } + + g.pushlist(); + if(sg.team && m_teammode) + { + g.pushlist(); + g.background(bgcolor, numgroups>1 ? 3 : 5); + g.strut(1); + g.poplist(); + } + g.text("", 0, " "); + loopscoregroup(o, + { + if(o==player1 && highlightscore && (multiplayer(false) || demoplayback || players.length() > 1)) + { + g.pushlist(); + g.background(0x808080, numgroups>1 ? 3 : 5); + } + const playermodelinfo &mdl = getplayermodelinfo(o); + const char *icon = sg.team && m_teammode ? (isteam(player1->team, sg.team) ? mdl.blueicon : mdl.redicon) : mdl.ffaicon; + g.text("", 0, icon); + if(o==player1 && highlightscore && (multiplayer(false) || demoplayback || players.length() > 1)) g.poplist(); + }); + g.poplist(); + + if(sg.team && m_teammode) + { + g.pushlist(); // vertical + + if(sg.score>=10000) g.textf("%s: WIN", fgcolor, NULL, sg.team); + else g.textf("%s: %d", fgcolor, NULL, sg.team, sg.score); + + g.pushlist(); // horizontal + } + + if(!hidefrags) + { + g.pushlist(); + g.strut(6); + g.text("frags", fgcolor); + loopscoregroup(o, g.textf("%d", 0xFFFFDD, NULL, o->frags)); + g.poplist(); + } + + if(showdeaths) + { + g.pushlist(); + g.strut(6); + g.text("deaths", fgcolor); + loopscoregroup(o, g.textf("%d", 0xFFFFDD, NULL, o->deaths)); + g.poplist(); + } + + if(showdamagedealt) + { + g.pushlist(); + g.strut(7); + g.text("damage", fgcolor); + loopscoregroup(o, g.textf("%d", 0xFFFFDD, NULL, o->totaldamage)); + g.poplist(); + } + + g.pushlist(); + g.text("name", fgcolor); + g.strut(12); + loopscoregroup(o, { g.textf("%s ", statuscolor(o, 0xFFFFDD), NULL, colorname(o)); }); + g.poplist(); + + if(multiplayer(false) || demoplayback) + { + if(showpj || showping) g.space(1); + + if(showpj && showping <= 1) + { + g.pushlist(); + g.strut(6); + g.text("pj", fgcolor); + loopscoregroup(o, + { + if(o->state==CS_LAGGED) g.text("LAG", 0xFFFFDD); + else g.textf("%d", 0xFFFFDD, NULL, o->plag); + }); + g.poplist(); + } + + if(showping > 1) + { + g.pushlist(); + g.strut(6); + + g.pushlist(); + g.text("ping", fgcolor); + g.space(1); + g.spring(); + g.text("pj", fgcolor); + g.poplist(); + + loopscoregroup(o, + { + fpsent *p = o->ownernum >= 0 ? getclient(o->ownernum) : o; + if(!p) p = o; + g.pushlist(); + if(p->state==CS_LAGGED) g.text("LAG", 0xFFFFDD); + else + { + g.textf("%d", 0xFFFFDD, NULL, p->ping); + g.space(1); + g.spring(); + g.textf("%d", 0xFFFFDD, NULL, o->plag); + } + g.poplist(); + + }); + g.poplist(); + } + else if(showping) + { + g.pushlist(); + g.text("ping", fgcolor); + g.strut(6); + loopscoregroup(o, + { + fpsent *p = o->ownernum >= 0 ? getclient(o->ownernum) : o; + if(!p) p = o; + if(!showpj && p->state==CS_LAGGED) g.text("LAG", 0xFFFFDD); + else g.textf("%d", 0xFFFFDD, NULL, p->ping); + }); + g.poplist(); + } + } + + if(showclientnum || player1->privilege>=PRIV_MASTER) + { + g.space(1); + g.pushlist(); + g.text("cn", fgcolor); + loopscoregroup(o, g.textf("%d", 0xFFFFDD, NULL, o->clientnum)); + g.poplist(); + } + + if(sg.team && m_teammode) + { + g.poplist(); // horizontal + g.poplist(); // vertical + } + + g.poplist(); // horizontal + g.poplist(); // vertical + + if(k+1<numgroups && (k+1)%2) g.space(2); + else g.poplist(); // horizontal + } + + if(showspectators && spectators.length()) + { + if(showclientnum || player1->privilege>=PRIV_MASTER) + { + g.pushlist(); + + g.pushlist(); + g.text("spectator", 0xFFFF80, " "); + g.strut(12); + loopv(spectators) + { + fpsent *o = spectators[i]; + if(o==player1 && highlightscore) + { + g.pushlist(); + g.background(0x808080, 3); + } + g.text(colorname(o), statuscolor(o, 0xFFFFDD), "spectator"); + if(o==player1 && highlightscore) g.poplist(); + } + g.poplist(); + + if((multiplayer(false) || demoplayback) && showspectatorping) + { + g.space(1); + g.pushlist(); + g.text("ping", 0xFFFF80); + g.strut(6); + loopv(spectators) + { + fpsent *o = spectators[i]; + fpsent *p = o->ownernum >= 0 ? getclient(o->ownernum) : o; + if(!p) p = o; + if(p->state==CS_LAGGED) g.text("LAG", 0xFFFFDD); + else g.textf("%d", 0xFFFFDD, NULL, p->ping); + } + g.poplist(); + } + + g.space(1); + g.pushlist(); + g.text("cn", 0xFFFF80); + loopv(spectators) g.textf("%d", 0xFFFFDD, NULL, spectators[i]->clientnum); + g.poplist(); + + g.poplist(); + } + else + { + g.textf("%d spectator%s", 0xFFFF80, " ", spectators.length(), spectators.length()!=1 ? "s" : ""); + loopv(spectators) + { + if((i%3)==0) + { + g.pushlist(); + g.text("", 0xFFFFDD, "spectator"); + } + fpsent *o = spectators[i]; + if(o==player1 && highlightscore) + { + g.pushlist(); + g.background(0x808080); + } + g.text(colorname(o), statuscolor(o, 0xFFFFDD)); + if(o==player1 && highlightscore) g.poplist(); + if(i+1<spectators.length() && (i+1)%3) g.space(1); + else g.poplist(); + } + } + } + + /// PW + g.separator(); + g.pushlist(); + g.textf(" %d%% ", 0x787878, "chainsaw.png", pwaccuracy[0]); + g.textf(" %d%% ", 0xfba6a6, "shotgun.png", pwaccuracy[1]); + g.textf(" %d%% ", 0x7bc77a, "chaingun.png", pwaccuracy[2]); + g.textf(" %d%% ", 0xefd7a6, "rocket_launcher.png", pwaccuracy[3]); + g.textf(" %d%% ", 0x8f91e7, "rifle.png", pwaccuracy[4]); + g.textf(" %d%% ", 0x9ee5e5, "grenade_launcher.png", pwaccuracy[5]); + g.textf(" %d%% ", 0xc3c3c3, "pistol.png", pwaccuracy[6]); + g.poplist(); + g.separator(); + g.pushlist(); + g.textf(" x %d ", 0xffffff, "blue_armour.png", pwitemspicked[0]); + g.textf(" x %d ", 0xffffff, "green_armour.png", pwitemspicked[1]); + g.textf(" x %d ", 0xffffff, "yellow_armour.png", pwitemspicked[2]); + g.textf(" x %d ", 0xffffff, "tiny_health.png", pwitemspicked[3]); + g.textf(" x %d ", 0xffffff, "health.png", pwitemspicked[4]); + g.textf(" x %d ", 0xffffff, "health_boost.png", pwitemspicked[5]); + g.textf(" x %d ", 0xffffff, "quad_damage.png", pwitemspicked[6]); + g.poplist(); + } + + struct scoreboardgui : g3d_callback + { + bool showing; + vec menupos; + int menustart; + + scoreboardgui() : showing(false) {} + + void show(bool on) + { + if(!showing && on) + { + menupos = menuinfrontofplayer(); + menustart = starttime(); + } + showing = on; + } + + void gui(g3d_gui &g, bool firstpass) + { + g.start(menustart, 0.03f, NULL, false); + renderscoreboard(g, firstpass); + g.end(); + } + + void render() + { + if(showing) g3d_addgui(this, menupos, (scoreboard2d ? GUI_FORCE_2D : GUI_2D | GUI_FOLLOW) | GUI_BOTTOM); + } + + } scoreboard; + + void g3d_gamemenus() + { + scoreboard.render(); + } + + VARFN(scoreboard, showscoreboard, 0, 0, 1, scoreboard.show(showscoreboard!=0)); + + void showscores(bool on) + { + showscoreboard = on ? 1 : 0; + scoreboard.show(on); + } + ICOMMAND(showscores, "D", (int *down), showscores(*down!=0)); + + VARP(hudscore, 0, 0, 1); + FVARP(hudscorescale, 1e-3f, 1.0f, 1e3f); + VARP(hudscorealign, -1, 0, 1); + FVARP(hudscorex, 0, 0.50f, 1); + FVARP(hudscorey, 0, 0.03f, 1); + HVARP(hudscoreplayercolour, 0, 0x60A0FF, 0xFFFFFF); + HVARP(hudscoreenemycolour, 0, 0xFF4040, 0xFFFFFF); + VARP(hudscorealpha, 0, 255, 255); + VARP(hudscoresep, 0, 200, 1000); + + void drawhudscore(int w, int h) + { + int numgroups = groupplayers(); + if(!numgroups) return; + + scoregroup *g = groups[0]; + int score = INT_MIN, score2 = INT_MIN; + bool best = false; + if(m_teammode) + { + score = g->score; + best = isteam(player1->team, g->team); + if(numgroups > 1) + { + if(best) score2 = groups[1]->score; + else for(int i = 1; i < groups.length(); ++i) if(isteam(player1->team, groups[i]->team)) { score2 = groups[i]->score; break; } + if(score2 == INT_MIN) + { + fpsent *p = followingplayer(player1); + if(p->state==CS_SPECTATOR) score2 = groups[1]->score; + } + } + } + else + { + fpsent *p = followingplayer(player1); + score = g->players[0]->frags; + best = p == g->players[0]; + if(g->players.length() > 1) + { + if(best || p->state==CS_SPECTATOR) score2 = g->players[1]->frags; + else score2 = p->frags; + } + } + if(score == score2 && !best) best = true; + + score = clamp(score, -999, 9999); + defformatstring(buf, "%d", score); + int tw = 0, th = 0; + text_bounds(buf, tw, th); + + string buf2; + int tw2 = 0, th2 = 0; + if(score2 > INT_MIN) + { + score2 = clamp(score2, -999, 9999); + formatstring(buf2, "%d", score2); + text_bounds(buf2, tw2, th2); + } + + int fw = 0, fh = 0; + text_bounds("00", fw, fh); + fw = max(fw, max(tw, tw2)); + + vec2 offset = vec2(hudscorex, hudscorey).mul(vec2(w, h).div(hudscorescale)); + if(hudscorealign == 1) offset.x -= 2*fw + hudscoresep; + else if(hudscorealign == 0) offset.x -= (2*fw + hudscoresep) / 2.0f; + vec2 offset2 = offset; + offset.x += (fw-tw)/2.0f; + offset.y -= th/2.0f; + offset2.x += fw + hudscoresep + (fw-tw2)/2.0f; + offset2.y -= th2/2.0f; + + pushhudmatrix(); + hudmatrix.scale(hudscorescale, hudscorescale, 1); + flushhudmatrix(); + + int color = hudscoreplayercolour, color2 = hudscoreenemycolour; + if(!best) swap(color, color2); + + draw_text(buf, int(offset.x), int(offset.y), (color>>16)&0xFF, (color>>8)&0xFF, color&0xFF, hudscorealpha); + if(score2 > INT_MIN) draw_text(buf2, int(offset2.x), int(offset2.y), (color2>>16)&0xFF, (color2>>8)&0xFF, color2&0xFF, hudscorealpha); + + pophudmatrix(); + } } |
