// Hyperbolic Rogue -- local highscore lists // Copyright (C) 2011-2018 Zeno Rogue, see 'hyper.cpp' for details /** \file scores.cpp * \brief local highscore lists */ #include "hyper.h" #if CAP_SAVE namespace hr { namespace scores { vector scores; score *currentgame; int scorefrom = 0; bool scorerev = false; string csub(const string& str, int q) { int i = 0; for(int j=0; j column_width(POSSCORE+1, 4); int colwidth(int scoredisplay) { return column_width[scoredisplay]; /* if(scoredisplay == 0) return 5; if(scoredisplay == 1) return 16; if(scoredisplay == 5) return 8; if(scoredisplay == POSSCORE) return 8; if(scoredisplay == 68) return yasc_width; return 4; */ } bool isHardcore(score *S) { return S->box[117] && S->box[118] < PUREHARDCORE_LEVEL; } int modediff(score *S) { int diff = 0; eGeometry g = (eGeometry) S->box[116]; if(S->box[306] != inv::on) diff += 4; if(S->box[238]) g = gSphere; if(S->box[239]) g = gElliptic; if(max(S->box[197], 1) != multi::players) diff += 8; eVariation savevar = S->box[341] ? eVariation::goldberg : S->box[344] ? eVariation::irregular : eVariation(S->box[186]); if(variation != savevar) diff += 16; if(GOLDBERG && savevar == eVariation::goldberg && (S->box[342] != gp::param.first || S->box[343] != gp::param.second)) diff += 16; if(S->box[196] != (int) land_structure) diff += 32; if(S->box[119] != shmup::on) diff += 64; if(pureHardcore() && !isHardcore(S)) diff += 128; if(g != gNormal && S->box[120] != specialland) diff += 256; if(g != geometry) { diff += 512; } return -diff; } string modedesc(score *S) { eGeometry g = (eGeometry) S->box[116]; if(S->box[238]) g = gSphere; if(S->box[239]) g = gElliptic; string s = ginf[g].shortname; if(g != gNormal) s += " " + csub(XLATT1((eLand) S->box[120]), 3); if(S->box[341]) s += "/GP(" + its(S->box[342])+","+its(S->box[343])+")"; else if(S->box[186]) s += "/7"; if(S->box[196]) s += "/C"; if(S->box[119]) s += "/s"; if(S->box[197] > 1) s += "/P" + its(S->box[197]); if(S->box[306]) s += "/i"; if(isHardcore(S)) s += "/h"; return s; } string displayfor(int scoredisplay, score* S, bool shorten = false) { // printf("S=%p, scoredisplay = %d\n", S, scoredisplay); if(S == NULL) { if(scoredisplay == POSSCORE) return "mode"; string str = XLATN(boxname[scoredisplay]); if(!shorten) return str; if(scoredisplay == 0 || scoredisplay == 65) return XLAT("time"); if(scoredisplay == 2) return "$$$"; if(scoredisplay == 3) return XLAT("kills"); if(scoredisplay == 4) return XLAT("turns"); if(scoredisplay == 5) return XLAT("cells"); if(scoredisplay == 67) return XLAT("cheats"); if(scoredisplay == 66) return XLAT("saves"); if(scoredisplay == 197) return XLAT("players"); if(scoredisplay == 68) return XLAT("where"); return csub(str, 5); } if(scoredisplay == 0 || scoredisplay == 65) { char buf[20]; int t = S->box[0]; if(t >= 3600) snprintf(buf, 20, "%d:%02d:%02d", t/3600, (t/60)%60, t%60); else snprintf(buf, 20, "%d:%02d", t/60, t%60); return buf; } if(scoredisplay == POSSCORE) return modedesc(S); if(scoredisplay == 68) { eLand which = eLand(S->box[68]); if(which >= landtypes || which < 0) return "fail"; return S->yasc_message + XLAT(" in %the1", which); } if(scoredisplay == 1) { time_t tim = S->box[1]; char buf[128]; strftime(buf, 128, "%c", localtime(&tim)); return buf; } return its(S->box[scoredisplay]); } int curcol; vector columns; bool monsterpage = false; void showPickScores() { dialog::v.clear(); scorerev = false; for(int i=0; i<=POSSCORE; i++) { int scoredisplay = i; if(!fakebox[scoredisplay]) { string s = displayfor(scoredisplay, NULL); if(dialog::hasInfix(s)) dialog::v.push_back(make_pair(s, i)); } } sort(dialog::v.begin(), dialog::v.end()); cmode = 0; gamescreen(); dialog::init(XLAT("pick scores")); if(dialog::infix != "") mouseovers = dialog::infix; dialog::addBreak(50); dialog::start_list(900, 900, '1'); for(auto& vi: dialog::v) { dialog::addItem(vi.first, dialog::list_fake_key++); dialog::add_action([&vi] { int scoredisplay = vi.second; for(int i=0; i<=POSSCORE; i++) if(columns[i] == scoredisplay) swap(columns[i], columns[curcol]); popScreen(); }); } dialog::end_list(); dialog::addBack(); dialog::display(); mouseovers = dialog::infix; keyhandler = [] (int sym, int uni) { dialog::handleNavigation(sym, uni); if(dialog::editInfix(uni)) dialog::list_skip = 0; else if(doexiton(sym, uni)) popScreen(); }; } int scale = 2; void show() { if(columns.size() == 0) { columns.push_back(POSSCORE); for(int i=0; i vid.xres) break; string s = displayfor(c, NULL, true); auto& cw = column_width[c]; cw = max(cw, textwidth(score_size, s) / bx + 1); if(displaystr(bx*at, score_size, 0, score_size, s, i == curcol ? 0xFFD500 : forecolor, 0)) getcstat = 1000+i; at += colwidth(c); } vector next_column_width(POSSCORE+1, 0); if(scorefrom < 0) scorefrom = 0; int id = 0; int omit = scorefrom; int rank = 0; while(y < (ISMOBILE ? vid.yres - 5*vid.fsize : vid.yres - 2 * vid.fsize)) { if(id >= isize(scores)) break; score& S(scores[id]); if(omit) { omit--; rank++; id++; continue; } bool cur = S.box[MAXBOX-1]; if(cur) { saveBox(); for(int i=0; i vid.xres) break; string s = displayfor(c, &S); auto& ncw = next_column_width[c]; ncw = max(ncw, textwidth(score_size, s) / bx + 1); if(c == 68) { if(displaystr(bx*at, y, 0, score_size, s, col, 0)) getcstat = 1000+i; at += colwidth(c); } else { at += colwidth(c); if(displaystr(bx*(at-1), y, 0, score_size, s, col, 16)) getcstat = 1000+i; } } y += score_size*5/4; id++; } column_width = next_column_width; int i0 = vid.yres - vid.fsize; int xr = vid.xres / 80; displayButton(xr*10, i0, IFM("s - ") + XLAT("sort"), 's', 8); displayButton(xr*30, i0, IFM("t - ") + XLAT("choose"), 't', 8); displayButton(xr*50, i0, IFM("z - ") + XLAT("zoom"), 'z', 8); displayButton(xr*70, i0, IFM(dialog::keyname(SDLK_ESCAPE) + " - ") + XLAT("go back"), '0', 8); keyhandler = [] (int sym, int uni) { if(DKEY == SDLK_LEFT || uni == 'h' || uni == 'a') { scorerev = false; if(curcol > 0) curcol--; } else if(DKEY == SDLK_RIGHT || uni == 'l' || uni == 'd') { scorerev = false; if(curcol < POSSCORE) curcol++; } else if(sym >= 1000 && sym <= 1000+POSSCORE) { scorerev = false; curcol = sym - 1000; } else if(uni == 't') { dialog::infix = ""; pushScreen(showPickScores); } else if(DKEY == SDLK_UP || uni == 'k' || uni == 'w') scorefrom -= 5; else if(DKEY == SDLK_DOWN || uni == 'j' || uni == 'x') scorefrom += 5; else if(uni == 'z') scale = 3 - scale; else if(sym == PSEUDOKEY_WHEELUP) scorefrom--; else if(sym == PSEUDOKEY_WHEELDOWN) scorefrom++; else if(uni == 's') { if(scorerev) reverse(scores.begin(), scores.end()); else { scorerev = true; stable_sort(scores.begin(), scores.end(), [] (const score& s1, const score &s2) { return s1.box[columns[curcol]] > s2.box[columns[curcol]]; }); } } else if(doexiton(sym, uni)) popScreen(); static int scoredragy; static bool lclicked; if(mousepressed) { if(!lclicked) { // scoredragx = mousex; scoredragy = mousey; } else { while(mousey > scoredragy + vid.fsize) scoredragy += vid.fsize, scorefrom--; while(mousey < scoredragy - vid.fsize) scoredragy -= vid.fsize, scorefrom++; } lclicked = mousepressed; } }; } void load() { if(scorefile == "") return; scores.clear(); FILE *f = fopen(scorefile.c_str(), "rt"); if(!f) { printf("Could not open the score file '%s'!\n", scorefile.c_str()); addMessage(s0 + "Could not open the score file: " + scorefile); return; } string *yasc = nullptr; while(!feof(f)) { const int buflen = 1200; char buf[buflen]; if(fgets(buf, buflen, f) == NULL) break; if(buf[0] == 'H' && buf[1] == 'y') { score sc; bool ok = true; sc.box[MAXBOX-1] = 0; {if(fscanf(f, "%s", buf) <= 0) break;} sc.ver = buf; for(int i=0; i 1420000000 && sc.box[65] < 1430000000) { sc.box[0] = sc.box[65] - sc.box[1]; sc.box[65] = sc.box[0]; } // do not include saves if(sc.box[65 + 4 + itOrbSafety - itOrbLightning]) ok = false; } else sc.box[0] = sc.box[1] - sc.box[0]; // could not save then if(sc.box[2] == 0) continue; // do not list zero scores sc.box[POSSCORE] = modediff(&sc); if(ok && boxid > 20) { scores.push_back(sc); yasc = &scores.back().yasc_message; } } if(buf[0] == 'Y' && buf[1] == 'A' && buf[2] == 'S' && buf[3] == 'C' && buf[4] == ' ') { for(int i=5; i tie(s2.box[POSSCORE], s2.box[2]); }); } } EX map qty_scores_for; EX void count_scores() { qty_scores_for.clear(); for(auto s: scores::scores) qty_scores_for[scores::MODECODE_BOX]++; } } #endif