diff --git a/achievement.cpp b/achievement.cpp index 4dc60282..0cfd70b9 100644 --- a/achievement.cpp +++ b/achievement.cpp @@ -71,6 +71,7 @@ const char* leadernames[NUMLEADER] = { #define LB_STATISTICS 62 #define LB_HALLOWEEN 63 +#define LB_RACING 81 void upload_score(int id, int v); @@ -87,7 +88,8 @@ bool wrongMode(char flags) { if(geometry != gNormal) return true; } - if(shmup::on != (flags == rg::shmup)) return true; + if(shmup::on != (flags == rg::shmup || flags == rg::racing)) return true; + if(racing::on != (flags == rg::racing)) return true; #if CAP_DAILY if(daily::on != (flags == rg::daily)) return true; #endif @@ -521,10 +523,11 @@ void achievement_score(int cat, int number) { else if(geometry) return; if(CHANGED_VARIATION) return; if(randomPatternsMode) return; - if(shmup::on && cat != LB_PURE_TACTICS_SHMUP && cat != LB_PURE_TACTICS_COOP) return; + if(shmup::on && cat != LB_PURE_TACTICS_SHMUP && cat != LB_PURE_TACTICS_COOP && cat != LB_RACING) return; if(yendor::on && cat != LB_YENDOR_CHALLENGE) return; if(tactic::on && cat != LB_PURE_TACTICS && cat != LB_PURE_TACTICS_SHMUP && cat != LB_PURE_TACTICS_COOP) return; + if(racing::on && cat != LB_RACING) return; upload_score(cat, number); #endif } diff --git a/hyper.h b/hyper.h index 20f554c7..c731a91d 100644 --- a/hyper.h +++ b/hyper.h @@ -162,6 +162,7 @@ void addMessage(string s, char spamtype = 0); #define NUMLEADER 82 #define LB_PURE_TACTICS_SHMUP 49 #define LB_PURE_TACTICS_COOP 50 +#define LB_RACING 81 #if ISMOBILE || ISWEB || ISPANDORA || 1 typedef double ld; @@ -4699,6 +4700,7 @@ namespace racing { void apply_seed(); string racetimeformat(int t); void add_debug(cell *c); + void displayScore(eLand l); } bool subscreen_split(reaction_t for_each_subscreen); diff --git a/racing.cpp b/racing.cpp index 05170d72..0ce0c808 100644 --- a/racing.cpp +++ b/racing.cpp @@ -15,6 +15,8 @@ bool on; bool player_relative = false; bool track_ready; +bool official_race = false; + int TWIDTH; ld race_advance = 0; @@ -75,7 +77,7 @@ struct ghost { vector history; }; -using raceset = map>; +typedef map> raceset; map, raceset> race_ghosts; map, raceset> official_race_ghosts; @@ -83,6 +85,14 @@ map, raceset> official_race_ghosts; raceset& ghostset() { return race_ghosts[make_pair(track_code, modecode())]; } raceset& oghostset() { return official_race_ghosts[make_pair(track_code, modecode())]; } +int get_score_in_land(eLand l) { + auto& gh = ghostset(); + if(!gh.count(l)) return 0; + auto& v = gh[l]; + if(!isize(v)) return 0; + return v[0].result; + } + array, MAXPLAYER> current_history; string ghost_prefix = "default"; @@ -172,6 +182,10 @@ bool read_ghosts(string seed, int mcode) { for(auto gh: v) println(hlog, " ", racetimeformat(gh.result), " : ", format("%08X", gh.checksum), " = ", minf[gh.cs.uicolor].name); } + + fhstream f("officials.data", "wb"); + hwrite(f, (const int&) VERNUM_HEX); + hwrite(f, ghostset()); } string fname = ghost_filename(seed, mcode); @@ -659,6 +673,12 @@ void generate_track() { race_start_tick = 0; for(int i=0; i landmap; char let = 'a'; for(eLand l: race_lands) { @@ -848,6 +870,7 @@ void track_chooser(string new_track) { int best = LOST; for(auto& gc: gh) best = min(best, gc.result); string s = (best == LOST) ? "" : racetimeformat(best); + landmap[let] = l; dialog::addSelItem(XLAT1(linf[l].name), s, let++); dialog::add_action([l, new_track] () { stop_game(); @@ -1051,6 +1074,40 @@ void prepare_subscreens() { } } +map > scoreboard; + +void uploadScore() { + int tscore = 0; + for(eLand l: race_lands) { + int i = get_score_in_land(l); + if(!i) continue; + int score = 60000000 / i; // 1000 points for minute, 2000 points for 30 sec + tscore += score; + } + + achievement_score(LB_RACING, tscore); + } + +void displayScore(eLand l) { + int vf = min((vid.yres-64) / 70, vid.xres/80); + int x = vid.xres / 4; + + if(get_sync_status() == 1) { + displayfr(x, 56, 1, vf, "(syncing)", 0xC0C0C0, 0); + } + else { + vector > scores; + for(auto p: scoreboard) if(p.second.count(l)) scores.emplace_back(p.second[l], p.first); + sort(scores.begin(), scores.end()); + int i = 0; + for(auto& sc: scores) { + int i0 = 56 + (i++) * vf; + displayfr(x, i0, 1, vf, racetimeformat(sc.first), 0xC0C0C0, 16); + displayfr(x+8, i0, 1, vf, sc.second, 0xC0C0C0, 0); + } + } + } + void race_won() { if(!race_finish_tick[current_player]) { int result = ticks - race_start_tick; @@ -1064,6 +1121,9 @@ void race_won() { if(place == 2) trophy[current_player] = 0xFFFFC0FF; if(place == 3) trophy[current_player] = 0x967444FF; + if(place == 1 && losers && official_race) + achievement_gain("RACEWON", rg::racing); + race_finish_tick[current_player] = ticks; charstyle gcs = getcs(); for(color_t *x: {&gcs.skincolor, &gcs.haircolor, &gcs.dresscolor, &gcs.swordcolor, &gcs.dresscolor2}) { @@ -1080,6 +1140,8 @@ void race_won() { subtrack.resize(ghosts_to_save); if(ghosts_to_save > 0) write_ghosts(track_code, modecode()); + + if(official_race) uploadScore(); } }