diff --git a/rogueviz/nilrider/level.cpp b/rogueviz/nilrider/level.cpp index 3abc60e6..2c2eac0e 100644 --- a/rogueviz/nilrider/level.cpp +++ b/rogueviz/nilrider/level.cpp @@ -582,7 +582,7 @@ void cleanup_textures() { void load_level(const string& fname, bool init) { fhstream f(fname, "r"); if(!f.f) throw hr_exception("could not open file "); - level lev("Untitled", '1', nrlUserCreated, "", -1, 1, 1, -1, {}, 0, 0, {}, rot_plane, { goal{0x40FF40, "Collect all the triangles", basic_check(999, 999), "", ""} }); + level lev("Untitled", '1', nrlUserCreated, "", -1, 1, 1, -1, {}, 0, 0, {}, rot_plane, { goal{0x40FF40, "Collect all the triangles", basic_check(999, 999), "", "", award_stars(0, 999, 0)} }); lev.filename = fname; level *csub = &lev; string s; diff --git a/rogueviz/nilrider/levels.cpp b/rogueviz/nilrider/levels.cpp index 376d52ac..cb7ab8ca 100644 --- a/rogueviz/nilrider/levels.cpp +++ b/rogueviz/nilrider/levels.cpp @@ -396,6 +396,14 @@ map > submaps = { }}, }; +auto award_stars(double mul, double t1, double t2) { + return [=] (ld t) { t = ilerp(t1, t2, t); t *= t; t += 1; t *= mul; return t; }; + } + +auto award_stars_distance(ld t) { + return -100 * t / 8; + } + level rotplane( "Trying to be horizontal", 'r', 0, "Collect all the triangles!\n\n" @@ -426,8 +434,8 @@ level rotplane( rot_plane, { // the solver[0.25] result is 36.92 - goal{0x40FF40, "Collect all the triangles in below 60 seconds", basic_check(60, 999), "ROTPLANE", "Trying to be horizontal"}, - goal{0xFFD500, "Collect all the triangles in below 38 seconds", basic_check(38, 999), "ROTPLANE2", ""} + goal{0x40FF40, "Collect all the triangles in below 60 seconds", basic_check(60, 999), "ROTPLANE", "Trying to be horizontal", award_stars(100, 60, 38)}, + goal{0xFFD500, "Collect all the triangles in below 38 seconds", basic_check(38, 999), "ROTPLANE2", "", award_stars(100, 60, 38)} } ); @@ -449,13 +457,13 @@ level longtrack( long_x, { // the solver[0.25] result is 1:08.56 (reduced to 1:08.45 by removing some points) - goal{0xFFD500, "Collect the triangle in below 1:15", basic_check(75, 999), "LONGTRACK", ""}, + goal{0xFFD500, "Collect the triangle in below 1:15", basic_check(75, 999), "LONGTRACK", "", award_stars(100, 70, 75)}, // the solver[0.25] + some manual modifications achieves 1:37.44 - goal{0xFF4040, "Stop where the triangle is in below 1:45", fullstop_check(75, 999), "LONGTRACKSTOP", ""}, + goal{0xFF4040, "Stop where the triangle is in below 1:45", fullstop_check(75, 999), "LONGTRACKSTOP", "", award_stars(100, 100, 105)}, // the solver[0.25] result is 1:45.52 - goal{0x303030, "Reach the triangle without going on the right side of the road below 2:00", yplus_check(120, 999), "LONGTRACKLEFT", ""}, + goal{0x303030, "Reach the triangle without going on the right side of the road below 2:00", yplus_check(120, 999), "LONGTRACKLEFT", "", award_stars(100, 105, 120)}, - goal{0x40FF40, "Stop where the triangle is without reversing time", basic_check(999, 0), "", "A Long Track"}, + goal{0x40FF40, "Stop where the triangle is without reversing time", basic_check(999, 0), "", "A Long Track", award_stars(100, 70, 900)}, } ); @@ -482,8 +490,8 @@ level geodesical( geodesics_0, { // the solver[0.25] result is 26.10 - goal{0xFFD500, "Collect both triangles in below 30 seconds", basic_check(30, 999), "GEODESICS", ""}, - goal{0x40FF40, "Collect both triangles without reversing time", basic_check(999, 0), "", "Roads are Geodesics"} + goal{0xFFD500, "Collect both triangles in below 30 seconds", basic_check(30, 999), "GEODESICS", "", award_stars(100, 27, 30)}, + goal{0x40FF40, "Collect both triangles without reversing time", basic_check(999, 0), "", "Roads are Geodesics", award_stars(100, 27, 30)} } ); @@ -506,8 +514,8 @@ level geodesical4( geodesics_at_4, { // the solver[0.25] result is 32.04 - goal{0xFFD500, "Collect the triangle in below 35 seconds", basic_check(35, 999), "HELICAL", ""}, - goal{0x40FF40, "Collect the triangle without reversing time", basic_check(999, 0), "", "Helical Geodesic"}, + goal{0xFFD500, "Collect the triangle in below 35 seconds", basic_check(35, 999), "HELICAL", "", award_stars(100, 33, 35)}, + goal{0x40FF40, "Collect the triangle without reversing time", basic_check(999, 0), "", "Helical Geodesic", award_stars(100, 35, 999)}, } ); @@ -536,8 +544,8 @@ level heisenberg0( f_heisenberg0, { // the solver[0.25] result is 49:15 - goal{0x40FFd0, "Collect all triangles in below 0:55", basic_check(55, 999), "HZERO", ""}, - goal{0x40c040, "Collect all triangle without reversing time", basic_check(999, 0), "", "Heisenberg Zero"}, + goal{0x40FFd0, "Collect all triangles in below 0:55", basic_check(55, 999), "HZERO", "", award_stars(100, 51, 55)}, + goal{0x40c040, "Collect all triangle without reversing time", basic_check(999, 0), "", "Heisenberg Zero", award_stars(100, 51, 999)}, } ); @@ -570,8 +578,8 @@ level rotwell( f_rot_well, { // the solver[0.5] result is 1:19.54 (obtained using get_ordered) - goal{0xFFD500, "Collect all triangles below 1:25", basic_check(85, 999), "ROTWELL", ""}, - goal{0x40c040, "Collect all triangle without reversing time", basic_check(999, 0), "", "Deep Well"} + goal{0xFFD500, "Collect all triangles below 1:25", basic_check(85, 999), "ROTWELL", "", award_stars(100, 80, 85)}, + goal{0x40c040, "Collect all triangle without reversing time", basic_check(999, 0), "", "Deep Well", award_stars(100, 80, 999)} } ); @@ -604,8 +612,8 @@ level labyrinth( // the solver[0.15] result is 1:06.58 // the solver[0.24] result is 1:08.54 // the solver[0.25] result is 1:22.09 (it goes north for some reason) - goal{0xFFD500, "Collect the triangle in below 1:15", basic_check(75, 999), "LABYRINTH", ""}, - goal{0x40c040, "Collect all triangle without reversing time", basic_check(999, 0), "", "Labyrinth"} + goal{0xFFD500, "Collect the triangle in below 1:15", basic_check(75, 999), "LABYRINTH", "", award_stars(100, 65, 75)}, + goal{0x40c040, "Collect all triangle without reversing time", basic_check(999, 0), "", "Labyrinth", award_stars(100, 75, 999)} } ); @@ -623,9 +631,9 @@ level obstacle( 0, 4, {}, long_x, { - goal{0xFFFFC0, "Collect the triangle in below 1:25, reversing time at most 3 times", basic_check(85, 3), "OBSTACLE1", ""}, - goal{0xFFD500, "Collect the triangle in below 1:10, reversing time at most 3 times", basic_check(70, 3), "OBSTACLE2", ""}, - goal{0x40c040, "Collect the triangle without reversing time", basic_check(999, 0), "", "Obstacle Course"} + goal{0xFFFFC0, "Collect the triangle in below 1:25, reversing time at most 3 times", basic_check(85, 3), "OBSTACLE1", "", award_stars(100, 70, 85)}, + goal{0xFFD500, "Collect the triangle in below 1:10, reversing time at most 3 times", basic_check(70, 3), "OBSTACLE2", "", award_stars(100, 65, 70)}, + goal{0x40c040, "Collect the triangle without reversing time", basic_check(999, 0), "", "Obstacle Course", award_stars(100, 65, 999)} } ); @@ -856,9 +864,9 @@ level spirallev( 1, 15.4, {}, spiral_level, { // the solver result is 55.239 - goal{0xFFD500, "Collect the triangle in below 60 seconds", basic_check(60, 999), "SPIRAL2", ""}, - goal{0xFF4040, "Collect the triangle in below 70 seconds", basic_check(70, 999), "SPIRAL1", ""}, - goal{0x40c040, "Collect the triangle without reversing time", basic_check(999, 0), "", "Square Spiral"} + goal{0xFFD500, "Collect the triangle in below 60 seconds", basic_check(60, 999), "SPIRAL2", "", award_stars(100, 56, 60)}, + goal{0xFF4040, "Collect the triangle in below 70 seconds", basic_check(70, 999), "SPIRAL1", "", award_stars(100, 56, 60)}, + goal{0x40c040, "Collect the triangle without reversing time", basic_check(999, 0), "", "Square Spiral", award_stars(100, 60, 999)} } ); @@ -889,8 +897,8 @@ level hilbertlev( 2.4, 15.4, {}, hilbert_level, { // the solver result is 50.94 - goal{0xFFD500, "Collect the triangle in below 55 seconds", basic_check(55, 999), "HILBERT", ""}, - goal{0xFF4040, "Collect the triangle in below 60 seconds", basic_check(60, 999), "", "Hilbert's Curve"}, + goal{0xFFD500, "Collect the triangle in below 55 seconds", basic_check(55, 999), "HILBERT", "", award_stars(100, 50, 55)}, + goal{0xFF4040, "Collect the triangle in below 60 seconds", basic_check(60, 999), "", "Hilbert's Curve", award_stars(100, 50, 60)}, } ); @@ -910,9 +918,9 @@ level cycloid_slalom( 0, 2, {}, brachistochrone, { - goal{0xFFFFC0, "Collect all triangles in below 1:25, reversing time at most 3 times", basic_check(85, 3), "CYCLOID1", ""}, - goal{0xFFD500, "Collect all triangles in below 1:10, reversing time at most 3 times", basic_check(70, 3), "CYCLOID2", ""}, - goal{0x40c040, "Collect the triangle without reversing time", basic_check(999, 0), "", "Cycloid slalom"} + goal{0xFFFFC0, "Collect all triangles in below 1:25, reversing time at most 3 times", basic_check(85, 3), "CYCLOID1", "", award_stars(100, 60, 85)}, + goal{0xFFD500, "Collect all triangles in below 1:10, reversing time at most 3 times", basic_check(70, 3), "CYCLOID2", "", award_stars(100, 60, 70)}, + goal{0x40c040, "Collect the triangle without reversing time", basic_check(999, 0), "", "Cycloid slalom", award_stars(100, 60, 999)} } ); @@ -929,8 +937,8 @@ level multifloor( 0, 1, {}, rot_plane, { - goal{0x40FF40, "Collect all the triangles in below 300 seconds, reversing time at most 3 times", basic_check(300, 3), "MULTIFLOOR", ""}, - goal{0xFFD500, "Collect all the triangles in below 150 seconds, reversing time at most once", basic_check(150, 1), "MULTIFLOOR2", ""} + goal{0x40FF40, "Collect all the triangles in below 300 seconds, reversing time at most 3 times", basic_check(300, 3), "MULTIFLOOR", "", award_stars(100, 100, 300)}, + goal{0xFFD500, "Collect all the triangles in below 150 seconds, reversing time at most once", basic_check(150, 1), "MULTIFLOOR2", "", award_stars(100, 100, 150)} } ); @@ -951,7 +959,7 @@ level skijump ( return h[0] * h[1] / 2 + 4 * (4.5 - h[0]) + 1 / (5 - h[0]); }, { - goal{0x40c040, "Jump as far as you can", ski_check, "", "Ski Jumping"} + goal{0x40c040, "Jump as far as you can", ski_check, "", "Ski Jumping", award_stars_distance} } ); @@ -975,7 +983,7 @@ level bumpy( 0, 4, {}, f_bumpy, { - goal{0xFFFFC0, "Collect the triangle in below 1:25, reversing time at most 3 times", basic_check(85, 3), "BUMPY", "Bumpy Ride"}, + goal{0xFFFFC0, "Collect the triangle in below 1:25, reversing time at most 3 times", basic_check(85, 3), "BUMPY", "Bumpy Ride", award_stars(100, 60, 85)}, } ); diff --git a/rogueviz/nilrider/nilrider.cpp b/rogueviz/nilrider/nilrider.cpp index 1e3e10d1..eec51018 100644 --- a/rogueviz/nilrider/nilrider.cpp +++ b/rogueviz/nilrider/nilrider.cpp @@ -324,10 +324,26 @@ void clear_path(level *l) { string fname = "horizontal.nrl"; +ld total_stars = 0; + void pick_level() { dialog::init(XLAT("select the track"), 0xC0C0FFFF, 150, 100); + ld cur_stars = 0; for(auto l: all_levels) { - dialog::addItem(l->name, l->hotkey); + ld score_here = 0; + for(int gid=0; gidgoals); gid++) { + if(isize(l->records[0])) { + auto man = l->records[0][gid]; + if(man) score_here += l->goals[gid].sa(man) * 2; + } + if(isize(l->records[1])) { + auto plan = l->records[1][gid]; + if(plan) score_here += l->goals[gid].sa(plan); + } + cur_stars += score_here; + } + + dialog::addSelItem(l->name, its(score_here), l->hotkey); dialog::add_action([l] { curlev = l; recompute_plan_transform = true; @@ -336,7 +352,9 @@ void pick_level() { popScreen(); }); } + total_stars = cur_stars; dialog::addBreak(100); + dialog::addSelItem("stars collected", its(total_stars), 0); dialog::addItem("load a level from a file", '0'); dialog::add_action([] { dialog::openFileDialog(fname, XLAT("level to load:"), ".nrl", [] () { @@ -382,11 +400,11 @@ void pick_game() { auto man = curlev->records[0][gid]; auto plan = curlev->records[1][gid]; if(man && plan) - dialog::addInfo("manual: " + format_timer(man) + " planning: " + format_timer(plan), g.color); + dialog::addInfo("manual: " + format_timer_goal(man, g, false) + " planning: " + format_timer_goal(plan, g, true), g.color); else if(man) - dialog::addInfo("manual: " + format_timer(man), g.color); + dialog::addInfo("manual: " + format_timer_goal(man, g, false), g.color); else if(plan) - dialog::addInfo("planning: " + format_timer(plan), g.color); + dialog::addInfo("planning: " + format_timer_goal(plan, g, true), g.color); else dialog::addInfo("goal not obtained:", g.color); dialog::addBreak(50); diff --git a/rogueviz/nilrider/timestamp.cpp b/rogueviz/nilrider/timestamp.cpp index 27e733bc..16c197ce 100644 --- a/rogueviz/nilrider/timestamp.cpp +++ b/rogueviz/nilrider/timestamp.cpp @@ -346,6 +346,14 @@ string format_timer(ld t) { return hr::format("%d:%02d.%02d", int(t / 60), int(t) % 60, int(frac(t) * 100)); } +string format_timer_goal(ld t, const goal& g, bool plan) { + int stars = g.sa(t) * (plan ? 1 : 2); + string s; + if(t > 0) s = format_timer(t); + else s = hr::format("%.02fm", -t); + return s + " (" + its(stars) + " stars)"; + } + void timestamp::draw_instruments(level* l) { dynamicval g(geometry, gEuclid); dynamicval pm(pmodel, mdDisk); @@ -482,7 +490,7 @@ void timestamp::draw_instruments(level* l) { poly_outline = 0xFF; color_t f = darkena(g.color, 0, 0xFF); if(gsuccess) { queuepoly(T * spin(90*degree), cgi.shGrail, f); - displaystr(cx+rad, cy+(gid-1)*rad/1.2, 0, vid.fsize*.75, format_timer(l->current_score[gid]), 0, 0); + displaystr(cx+rad, cy+(gid-1)*rad/1.2, 0, vid.fsize*.75, format_timer_goal(l->current_score[gid], g, planning_mode), 0, 0); } else { poly_outline = f; f = 0x40;