diff --git a/rogueviz/ads/tour.cpp b/rogueviz/ads/tour.cpp index 6d73dbc0..e3e7d433 100644 --- a/rogueviz/ads/tour.cpp +++ b/rogueviz/ads/tour.cpp @@ -3,6 +3,7 @@ namespace hr { namespace ads_game { extern purehookset hooks_pre_ads_start; +extern bool changed_structure; namespace ads_tour { using namespace rogueviz::pres; @@ -28,9 +29,49 @@ cell *slv; transmatrix at0, at1; int t0, t1; +void straight_line_viz_rocks(presmode mode) { + if(mode == pmStart) { + rv_hook(shmup::hooks_draw, 100, [] (const shiftmatrix&, cell*, shmup::monster*) { + items[itOrbAether] = 0; items[itOrbShield] = 0; + return false; + }); + } + if(mode == pmFrame) { + items[itOrbLife] = 3; if(shmup::pc[0]) shmup::pc[0]->dead = false; + } + if(mode == pmKey) { + for(auto [c, mo]: shmup::monstersAt) if(mo->type == moAsteroid) mo->dead = true; + auto pc = shmup::pc[0]; + for(int r: {1, 2, 3}) + for(int i=0; i<36*r; i++) { + transmatrix T = spin(TAU*i/r/36) * xpush(cgi.scalefactor*r) * spin(-TAU*i/r/6); + + ld r = hypot_d(WDIM, pc->inertia), eps = 1e-3; + transmatrix In = lrspintox(pc->inertia) * lxpush(r * eps) * lspintox(pc->inertia); + + shmup::monster* child = new shmup::monster; + child->base = pc->base; + child->at = pc->at * T; + child->ori = pc->ori; + child->type = moAsteroid; + child->pid = pc->pid; + child->inertia = inverse(T) * In * T * C0; + auto f = child->inertia; + child->inertia = lrspintox(child->inertia) * eupoint(hdist0(child->inertia) / eps, 0); + println(hlog, "inertia = ", child->inertia, " f = ", f); + // child->inertia = eupoint(0, 0); + + child->hitpoints = 3; + shmup::additional.push_back(child); + } + if(tour_value == 1) quitmainloop = true; + } + } + void straight_line_viz(presmode mode) { if(mode == pmKey) slv_mode = (slv_mode == 0 ? 1 : 0); - if(mode == pmStart) rogueviz::rv_hook(hooks_markers, 100, [] { + if(mode == pmStart) rogueviz::rv_hook(hooks_frame, 100, [] { + if(inHighQual && slv_mode == 0) slv_mode = 1; println(hlog, "slv_mode = ", slv_mode, " tick = ", ticks); if(slv_mode == 1) { t0 = ticks; @@ -90,6 +131,13 @@ void set_spacerocks_ship() { tour::slide_backup(cs.eyecolor, 0x8080FFFF); tour::slide_backup(cs.dresscolor, 0xFFC0C0FF); tour::slide_backup(cs.haircolor, 0xC0FFC0FF); + tour::slide_backup(stdgridcolor, 0x808080FF); + tour::slide_backup(vid.multiplier_grid, 3); + tour::slide_backup(hide_kills, true); + tour::slide_backup(hide_watermark, true); + tour::slide_backup(gridbelow, true); + tour::slide_backup(nomap, false); + tour::slide_backup(mapeditor::drawplayer, true); } slide relhell_tour[] = { @@ -98,8 +146,10 @@ slide relhell_tour[] = { "Here is Space Rocks, a clone of the classic game Asteroids. It is based on Newtonian physics: " "if you accelerate, you move forever in that direction, unless you deaccelerate.", [] (presmode mode) { + kills[moAsteroid] = 0; setCanvas(mode, &ccolor::plain, [] { set_spacerocks_ship(); + tour::slide_backup(vid.creature_scale, 0.5); set_geometry(gEuclidSquare); set_variation(eVariation::pure); tour::slide_backup(land_structure, lsSingle); @@ -116,6 +166,45 @@ slide relhell_tour[] = { } }, + {"Euclidean symmetry: formation", 10, LEGAL::ANY | QUICKGEO | NOTITLE, + "In the previous slide, time was implemented as in most games, and " + "how Newton imagined it. It is assumed that objects move on geodesics " + "(great circles) if no force is acting on them.\n\n" + "Note that, in the world of Newton and Galileo, and also in the world of Einstein's special relativity, the spacetime is perfectly symmetric. " + "You cannot really tell that you are moving (except by looking at landmarks); you can create a frame of reference and a system of coordinates " + "in which the ship is not moving and the physics are the same.\n\n" + "While the spherical space is perfectly symmetric, the spacetime as shown in this slide is not. " + "The wings of our ship do not move in straight lines (instead they move in smaller circles, which are curved). " + "If we had unchained items there, they would move towards the center of the ship, allowing the " + "captain to tell that they are moving.\n\n" + "Press 5 to see a visualization of how various parts of the ships would move if they actually moved in straight lines." + , + + [] (presmode mode) { + kills[moAsteroid] = 0; + setCanvas(mode, &ccolor::plain, [] { + set_spacerocks_ship(); + set_geometry(gEuclidSquare); + set_variation(eVariation::pure); + tour::slide_backup(land_structure, lsSingle); + tour::slide_backup(specialland, laAsteroids); + auto& ua = euc::eu_input; + tour::slide_backup(ua, ua); + for(int i=0; i<2; i++) + for(int j=0; j<2; j++) ua.user_axes[i][j] = i == j ? 35 : 0; + ua.twisted = false; + euc::build_torus3(); + tour::slide_backup(shmup::on, true); + tour::slide_backup(pconf.scale, 0.3); + tour::slide_backup(dont_gen_asteroids, true); + tour::slide_backup(stdgridcolor, 0xC0C0C0C0); + tour::slide_backup(vid.multiplier_grid, 3); + tour::slide_backup(gridbelow, true); + }); + straight_line_viz_rocks(mode); + } + }, + {"Small Relativistic Effects", 10, LEGAL::ANY | QUICKGEO, "In our real world, the universe is expanding, and the spaceship would observe relativistic effects if it started to move very fast. " "Such effects can be also observed in this slide, although you still need to wait for a long time or move very fast. They will be more pronounced in Relative Hell, and in the later slides.", @@ -136,12 +225,35 @@ slide relhell_tour[] = { rockgen.cshift = 0; + rogueviz::rv_hook(multi::hooks_handleInput, 100, [] { + if(tour_value == 0) return; + auto& act = multi::action_states[1]; + if(ticks >= 1000 && ticks < 4000) act[multi::pcMoveLeft].held = true; + if(ticks >= 5500 && ticks < 8500) act[multi::pcMoveRight].held = true; + if(ticks >= 9500 && ticks < 12500) act[multi::pcMoveRight].held = true; + if(ticks >=14000 && ticks < 17000) act[multi::pcMoveLeft].held = true; + }); + if(1) { + + std::mt19937 gr; + gr.seed(617); + auto randd = [&] { return (gr() % 1000000 + .5) / 1000000; }; + dynamicval g(geometry, gSpace435); + for(int x=-10; x<=10; x++) for(int y=-10; y<=10; y++) if(hypot(x+0.5, y) >= 2) { rockgen.add(cspin(0, 2, (x + randd() - randd()) / sca) * cspin(1, 2, (y + randd() - randd()) / sca)); } + + for(int x: {-2.5}) { + auto r = rockgen.add(cspin(0, 2, x / sca) * cspin(1, 2, 0)); + r->type = oResource; + r->resource = rtFuel; + r->shape = rsrc_shape[rtFuel]; + r->col = rsrc_color[rtFuel]; + } } rockgen.cshift = 10; @@ -167,23 +279,45 @@ slide relhell_tour[] = { tour::slide_backup(vid.creature_scale, 1 / sca); tour::slide_backup(pconf.scale, sca); tour::slide_backup(texture_off, true); + tour::slide_backup(spacetime_step, spacetime_step / sca); + tour::slide_backup(spacetime_qty, spacetime_qty * 5); dynamicval fs(future_shown, -10); ds_restart_scaled(); tour::slide_backup(invincibility_pt, HUGE_VAL); rockgen.cshift = 0; + rogueviz::rv_hook(multi::hooks_handleInput, 100, [] { + if(tour_value == 0) return; + auto& act = multi::action_states[1]; + if(ticks >= 16000 && ticks < 18000) act[multi::pcMoveUp].held = true; + }); + if(1) { + + std::mt19937 gr; + gr.seed(617); + auto randd = [&] { return (gr() % 1000000 + .5) / 1000000; }; + dynamicval g(geometry, gSpace435); - for(int x=-10; x<=10; x++) - for(int y=-10; y<=10; y++) if(hypot(x+0.5, y) >= 2) { - rockgen.add(cspin(0, 2, (x + randd() - randd()) / sca) * cspin(1, 2, (y + randd() - randd()) / sca)); + for(int x=-6; x<=6; x++) + for(int y=-40; y<=10; y++) if(hypot(x+0.5, y) >= 2 && (x&1) == 1) { + rockgen.add(cspin(0, 2, (x + (randd() - randd())/3) / sca) * cspin(1, 2, (y + randd() - randd()) / sca)); + } + + for(int x=-6; x<=6; x++) + for(int y=60; y<=200; y++) if((x&3) == 2) { + rockgen.add(lorentz(1, 3, -2 * ds_simspeed * ds_accel) * cspin(0, 2, (x + randd() - randd()) / sca) * cspin(1, 2, (y/2 + randd() - randd()) / sca)); + } + + if(true) { + rockgen.add(lorentz(3, 2, 12.5 * ds_simspeed) * cspin(1, 2, 1 / sca) * cspin(0, 2, -0.5 / sca) * lorentz(1, 3, -1 * ds_simspeed * ds_accel)); } for(int x=0; x<=24; x++) for(int y=-10; y<=10; y++) if(y) { rockgen.cshift = (rand() % 1000) / 100. / sca; - rockgen.add(cspin(0, 1, x * 15._deg) * cspin(1, 2, y / sca) * lorentz(0, 3, 1 + randd() * 3)); + rockgen.add(lorentz(3, 2, 5 * ds_simspeed) * cspin(0, 1, x * 15._deg) * cspin(1, 2, y / sca) * lorentz(0, 3, 1 + randd() * 3)); } } @@ -205,17 +339,93 @@ slide relhell_tour[] = { tour::slide_backup(ds_missile_rapidity, 0.5); tour::slide_backup(ds_accel, ds_accel * 10); tour::slide_backup(vid.creature_scale, 5 / sca); - tour::slide_backup(pconf.scale, sca); + tour::slide_backup(pconf.scale, sca * 2); tour::slide_backup(texture_off, true); tour::slide_backup(view_proper_times, true); tour::slide_backup(time_scale, 0.15); tour::slide_backup(disable_ds_gen, true); + tour::slide_backup(spacetime_step, spacetime_step / sca * 3); + tour::slide_backup(spacetime_qty, spacetime_qty * 500); + tour::slide_backup(ship_history_period, spacetime_step); dynamicval fs(future_shown, -10); ds_restart_scaled(); tour::slide_backup(invincibility_pt, HUGE_VAL); + rogueviz::rv_hook(multi::hooks_handleInput, 100, [] { + if(tour_value == 0) return; + auto& act = multi::action_states[1]; + if(ticks >= 11000 && ticks < 13000) act[multi::pcMoveUp].held = true; + if(ticks >= 13000 && ticks < 17000) act[multi::pcMoveDown].held = true; + if(ticks >= 17000 && ticks < 19000) act[multi::pcMoveUp].held = true; + }); + rockgen.cshift = 10; }); + + static ld alpha = 0; + + add_temporary_hook(mode, hook_alter_replay, 100, [] { + if(tour_value == 0) return; + alpha = 0; + if(ticks >= 9000 && ticks <= 10000) { + ld t = (ticks - 9000) / 1000.; + t = t * t * (3 - 2 * t); + alpha = sin(t * TAU) * 0.5; + println(hlog, "alpha = ", alpha); + current.T = cspin(1, 0, alpha) * current.T; + } + + // if(ticks >= 11000 && ticks < 13000) act[multi::pcMoveUp].held = true; + }); + + add_temporary_hook(mode, hooks_prestats, 50, [] { + if(tour_value == 0) return false; + dynamicval g(geometry, gCubeTiling); dynamicval gv(variation, eVariation::pure); + dynamicval gm(pmodel, mdPerspective); dynamicval gs(sightranges[geometry], 50); + dynamicval gw(vid.linewidth, 3 * vid.linewidth); + initquickqueue(); + calcparam(); + for(int w: {0, 1}) { + shiftmatrix T = shiftless(MirrorY * rgpushxto0(hyperpoint(-7, -4, 2.2, 1))); + if(w == 1) { + T = T * cspin(1, 0, -alpha); + ld rapid_gained = 0; + if(ticks >= 11000) rapid_gained += min(ticks - 11000, 2000); + if(ticks >= 13000) rapid_gained -= min(ticks - 13000, 4000); + if(ticks >= 17000) rapid_gained += min(ticks - 17000, 2000); + rapid_gained /= 1000; + auto rg = rapid_gained; + rapid_gained *= ds_simspeed; + rapid_gained *= ds_accel; + println(hlog, "rapid_gained = ", rapid_gained, " from ", rg); + T = T * lorentz(1, 2, -rapid_gained); + } + color_t col = w == 1 ? 0xFFFFFFFF : 0x8000FF; + queueline(T * hyperpoint(-0.2, 0, 0, 1), T * hyperpoint(1.2, 0, 0, 1), col); + curvepoint(hyperpoint(1.2, 0, 0, 1)); + curvepoint(hyperpoint(1.1, 0.05, 0, 1)); + curvepoint(hyperpoint(1.1, -0.05, 0, 1)); + curvepoint(hyperpoint(1.2, 0, 0, 1)); + queuecurve(T, 0, col, PPR::LINE); + latex_in_space(T * eupush(hyperpoint(1.2, 0.2, 0, 1)) * MirrorY, 0.002, "$x$", col, 0); + queueline(T * hyperpoint(0,-0.2, 0, 1), T * hyperpoint(0, 1.2, 0, 1), col); + curvepoint(hyperpoint(0, 1.2, 0, 1)); + curvepoint(hyperpoint(+0.05, 1.1, 0, 1)); + curvepoint(hyperpoint(-0.05, 1.1, 0, 1)); + curvepoint(hyperpoint(0, 1.2, 0, 1)); + queuecurve(T, 0, col, PPR::LINE); + latex_in_space(T * eupush(hyperpoint(0.2, 1.2, 0, 1)) * MirrorY, 0.002, "$y$", col, 0); + queueline(T * hyperpoint(0,0,-0.2, 1), T * hyperpoint(0, 0, 1.2, 1), col); + curvepoint(hyperpoint(0, 0, 1.2, 1)); + curvepoint(hyperpoint(+0.05, -0.05, 1.1, 1)); + curvepoint(hyperpoint(-0.05, 0.05, 1.1, 1)); + curvepoint(hyperpoint(0, 0, 1.2, 1)); + queuecurve(T, 0, col, PPR::LINE); + latex_in_space(T * eupush(hyperpoint(0, -0.2, 1.2, 1)) * MirrorY, 0.002, "$t$", col, 0); + } + quickqueue(); + return true; + }); } }, @@ -224,6 +434,7 @@ slide relhell_tour[] = { "Here is Space Rocks played in spherical geometry. It uses " "stereographic projection so that a big part of the sphere can be seen. (You can press '5' to switch to and from the orthogonal projection.)", [] (presmode mode) { + kills[moAsteroid] = 0; setCanvas(mode, &ccolor::plain, [] { set_spacerocks_ship(); set_geometry(gSphere); @@ -234,6 +445,7 @@ slide relhell_tour[] = { tour::slide_backup(pconf.scale, 0.5); tour::slide_backup(pconf.alpha, 1); tour::slide_backup(vid.monmode, 2); + tour::slide_backup(vid.aurasmoothen, 90); }); if(mode == pmKey) { if(pconf.alpha == 1) pconf.alpha = 1000, pconf.scale = 950; @@ -242,7 +454,7 @@ slide relhell_tour[] = { } }, - {"Spherical symmetry", 10, LEGAL::ANY | QUICKGEO | NOTITLE, + {"Spherical symmetry: formation", 10, LEGAL::ANY | QUICKGEO | NOTITLE, "In the previous slide, time was implemented as in most games, and " "how Newton imagined it. It is assumed that objects move on geodesics " "(great circles) if no force is acting on them.\n\n" @@ -257,6 +469,44 @@ slide relhell_tour[] = { , [] (presmode mode) { + kills[moAsteroid] = 0; + setCanvas(mode, &ccolor::plain, [] { + set_spacerocks_ship(); + set_geometry(gSphere); + set_variation(eVariation::bitruncated); + tour::slide_backup(land_structure, lsSingle); + tour::slide_backup(specialland, laAsteroids); + tour::slide_backup(shmup::on, true); + tour::slide_backup(pconf.scale, 0.5); + tour::slide_backup(pconf.alpha, 1); + tour::slide_backup(vid.monmode, 2); + tour::slide_backup(vid.creature_scale, 0.5); + tour::slide_backup(dont_gen_asteroids, true); + // tour::slide_backup(stdgridcolor, 0x808080FF); + tour::slide_backup(stdgridcolor, 0xC0C0C0C0); + tour::slide_backup(vid.multiplier_grid, 3); + tour::slide_backup(gridbelow, true); + }); + straight_line_viz_rocks(mode); + } + }, + + {"Spherical symmetry: forces", 10, LEGAL::ANY | QUICKGEO | NOTITLE, + "In the previous slide, time was implemented as in most games, and " + "how Newton imagined it. It is assumed that objects move on geodesics " + "(great circles) if no force is acting on them.\n\n" + "Note that, in the world of Newton and Galileo, and also in the world of Einstein's special relativity, the spacetime is perfectly symmetric. " + "You cannot really tell that you are moving (except by looking at landmarks); you can create a frame of reference and a system of coordinates " + "in which the ship is not moving and the physics are the same.\n\n" + "While the spherical space is perfectly symmetric, the spacetime as shown in this slide is not. " + "The wings of our ship do not move in straight lines (instead they move in smaller circles, which are curved). " + "If we had unchained items there, they would move towards the center of the ship, allowing the " + "captain to tell that they are moving.\n\n" + "Press 5 to see a visualization of how various parts of the ships would move if they actually moved in straight lines." + , + + [] (presmode mode) { + kills[moAsteroid] = 0; setCanvas(mode, &ccolor::plain, [] { set_spacerocks_ship(); set_geometry(gSphere); @@ -274,7 +524,7 @@ slide relhell_tour[] = { } }, - {"de Sitter spacetime", 10, LEGAL::ANY | QUICKGEO, + {"empty de Sitter spacetime", 10, LEGAL::ANY | QUICKGEO, "The de Sitter spacetime is a way to add time to spherical geometry in a symmetric way. " "The space here feels to expand exponentially as the time passes, as in, nearby objects get farther and farther away. " "Still, the spacetime is symmetric -- if we are using an appropriate frame of reference, the 'totally geodesic' slice of spacetime at t=0 is " @@ -288,10 +538,12 @@ slide relhell_tour[] = { tour::slide_backup(ds_simspeed, M_PI / 10); // tour::slide_backup(ds_scale, 1); tour::slide_backup(pconf.scale, 1); - dynamicval fs(future_shown, -10); + tour::slide_backup(disable_ds_gen, true); + dynamicval fs(future_shown, -20); ds_restart(); - rockgen.cshift = 10; + rockgen.cshift = 20; + rsrcgen.cshift = 20; }); if(mode == pmStart) { add_ds_cleanup(); @@ -300,9 +552,8 @@ slide relhell_tour[] = { } }, - {"de Sitter game", 10, LEGAL::ANY | QUICKGEO, - "The de Sitter part of the Relative Hell game takes part in this spacetime. " - "Try to stay close to the yellow star as long as possible! If required, you can " + {"full de Sitter game", 10, LEGAL::ANY | QUICKGEO, + "And here is the full game. If required, you can " "shoot down stars with a limited number of missiles. For high score, you will also need to replenish your " "resources by capturing free-flying fuel, oxygen, health, and missiles.", @@ -321,6 +572,7 @@ slide relhell_tour[] = { "you can press 5 to switch to the Beltrami-Klein model.\n\n", [] (presmode mode) { + kills[moAsteroid] = 0; setCanvas(mode, &ccolor::plain, [] { set_spacerocks_ship(); set_geometry(gKleinQuartic); @@ -339,11 +591,40 @@ slide relhell_tour[] = { } }, - {"Hyperbolic symmetry", 10, LEGAL::ANY | QUICKGEO | NOTITLE, + {"Hyperbolic symmetry: formation", 10, LEGAL::ANY | QUICKGEO | NOTITLE, "Of course, just like in spherical space, this is not a symmetric spacetime.\n\n" "Press 5 to see a visualization of how various parts of the ships would move if they actually moved in straight lines.", [] (presmode mode) { + kills[moAsteroid] = 0; + setCanvas(mode, &ccolor::plain, [] { + set_spacerocks_ship(); + set_geometry(gKleinQuartic); + set_variation(eVariation::bitruncated); + tour::slide_backup(land_structure, lsSingle); + tour::slide_backup(specialland, laAsteroids); + tour::slide_backup(shmup::on, true); + tour::slide_backup(pconf.scale, 0.95); + tour::slide_backup(pconf.alpha, 1); + tour::slide_backup(vid.monmode, 2); + tour::slide_backup(dont_gen_asteroids, true); + tour::slide_backup(vid.linequality, 3); + tour::slide_backup(vid.creature_scale, 0.3); + // tour::slide_backup(stdgridcolor, 0x808080FF); + tour::slide_backup(stdgridcolor, 0xC0C0C0C0); + tour::slide_backup(vid.multiplier_grid, 3); + tour::slide_backup(gridbelow, true); + }); + straight_line_viz_rocks(mode); + } + }, + + {"Hyperbolic symmetry: forces", 10, LEGAL::ANY | QUICKGEO | NOTITLE, + "Of course, just like in spherical space, this is not a symmetric spacetime.\n\n" + "Press 5 to see a visualization of how various parts of the ships would move if they actually moved in straight lines.", + + [] (presmode mode) { + kills[moAsteroid] = 0; setCanvas(mode, &ccolor::plain, [] { set_spacerocks_ship(); set_geometry(gKleinQuartic); @@ -361,10 +642,81 @@ slide relhell_tour[] = { } }, - {"anti-de Sitter spacetime", 10, LEGAL::ANY | QUICKGEO | NOTITLE, + {"anti-de Sitter spacetime: rocks", 10, LEGAL::ANY | QUICKGEO | NOTITLE, "anti-de Sitter spacetime is a way to add time to this space in a symmetric way.\n\n" "Because of how the anti-de Sitter spacetime works, faraway objects are 'pulled' towards us. " - "You can see this effect by shooting a missile -- it will eventually return to us!\n\n" + "Here is an almost empty anti-de Sitter space, with some rocks. See how they are pulled towards " + "the center." + , + + [] (presmode mode) { + setCanvas(mode, &ccolor::plain, [] { + rogueviz::on_cleanup_or_next([] { lps_enable(nullptr); }); + ads_game::run_ads_game_std(); + stop_game(); + run_ads_game(); + tour::slide_backup(changed_structure, true); + tour::slide_backup(specialland, laAsteroids); + // tour::slide_backup(specialland, laCrossroads); + tour::slide_backup(land_structure, lsSingle); + run_ads_game(); + /* disable everything */ + tour::slide_backup(pconf.alpha, 1); + tour::slide_backup(keep_ship_angle, true); + + rogueviz::rv_hook(hooks_frame, 100, [] { + for(int i=0; i<360; i++) addaura(shiftless(xspinpush0(i*1._deg, 1)), 0xFFFFFF, 0); + }); + + for(int i=0; i<50; i++) hybrid::in_actual([&] { + add_rock(cwt.at, ci_at[cwt.at], + // ads_matrix(Id) * spin(rand() % 100) * twist::uxpush(0.5 + (rand() % 100)/50.) * spin(rand() % 2 ? -90._deg : 90._deg) * lorentz(0, 3, 0.2 + (rand() % 100) / 100.) + ads_matrix(Id) * spin(rand() % 100) * lorentz(0, 3, 0.5 + (rand() % 100)/40.) * spin(rand() % 2 ? -90._deg : 90._deg) * lorentz(0, 2, 0.2 + (rand() % 100) / 50.) + ); + }); + + }); + } + }, + + {"anti-de Sitter spacetime: missiles", 10, LEGAL::ANY | QUICKGEO | NOTITLE, + "You can also see this effect by shooting a missile -- it will eventually return to us!\n\n" + "Then, press 5 to see a replay from the missile's point of view." + , + + [] (presmode mode) { + setCanvas(mode, &ccolor::plain, [] { + rogueviz::on_cleanup_or_next([] { lps_enable(nullptr); }); + ads_game::run_ads_game_std(); + stop_game(); + run_ads_game(); + tour::slide_backup(changed_structure, true); + tour::slide_backup(specialland, laAsteroids); + // tour::slide_backup(specialland, laCrossroads); + tour::slide_backup(land_structure, lsSingle); + run_ads_game(); + /* disable everything */ + tour::slide_backup(pconf.alpha, 1); + tour::slide_backup(keep_ship_angle, true); + + rogueviz::rv_hook(hooks_frame, 100, [] { + for(int i=0; i<360; i++) addaura(shiftless(xspinpush0(i*1._deg, 1)), 0xFFFFFF, 0); + }); + + tour::slide_backup(time_shift, 0.2); + tour::slide_backup(ads_time_unit, 1); + tour::slide_backup(view_proper_times, true); + }); + if(mode == pmStart) tour::slide_backup(missile_replay, missile_replay); + if(mode == pmKey) { + switch_replay(); + missile_replay = !missile_replay; + } + if(mode == pmStop && in_replay) switch_replay(); + } + }, + + {"anti-de Sitter spacetime: world", 10, LEGAL::ANY | QUICKGEO | NOTITLE, "In the world of Relative Hell, this pull is countered by making the static objects rotate in a specific way -- this creates a centrifugal " "force which counterbalances this effect. As you can see, the heptagons further away are " "squashed -- this is again the Lorentz contraction\n\n." @@ -454,6 +806,7 @@ slide relhell_tour[] = { [] (presmode mode) { setCanvas(mode, &ccolor::plain, [] { rogueviz::on_cleanup_or_next([] { lps_enable(nullptr); }); + tour::slide_backup(turret_limit, 1); ads_game::run_ads_game_std(); tour::slide_backup(pconf.alpha, 1); rv_hook(hooks_pre_ads_start, 100, [] { @@ -512,14 +865,70 @@ slide relhell_tour[] = { {\color{remph}3-dimensional Euclidean space:} \begin{itemize} \item $\bbE^3 = \{(x,y,z): x,y,z \in \bbR\}$ - \item squared distance between \\ points $(x_1,y_1,z_1)$ and $(x_2, y_2, z_2)$ is \[(x_1-x_2)^2+(y_1-y_2)^2+(z_1-z_2)^2\] - \item {\color{remph} isometries} (rotations, etc.) preserve this squared distance + \item squared distance between \\ points $(x_1,y_1,z_1)$ and $(x_2, y_2, z_2)$ is \[(x_1-x_2)^2+(y_1-y_2)^2+(z_1-z_2)^2\rule{3cm}{0cm}\] + \item {\color{remph} isometries} (rotations, etc.) \\ preserve this squared distance \end{itemize} )=", sm::SIDE, 90); + static int start = -1; + static int anim_start = -1; + if(mode == pmKey) start = (start == -1) ? ticks : -1; + if(mode == pmKeyAlt) anim_start = ticks; if(mode == pmStart) { tour::slide_backup(mapeditor::drawplayer, false); tour::slide_backup(vid.axes, 0); + tour::slide_backup(pconf.scale, 0.5); + tour::slide_backup(vid.use_smart_range, 2); + tour::slide_backup(vid.smart_range_detail, 1); + tour::slide_backup(pconf.xposition, -0.4); rogueviz::rv_hook(hooks_latex_slide, 100, [] { dialog::dwidth += 500; menu_darkening++; dialog::draw_side_shade(); dialog::dwidth -= 500; menu_darkening --; }); + View = Id; + static ld t; + rogueviz::rv_hook(anims::hooks_anim, 101, [] { + + if(anim_start >= 0) { + ld t = (ticks - anim_start) / 4000.; + if(t >= 1) t = 1; + centerover = currentmap->gamestart(); + View = ypush(t * t * (3 - 2 * t)); + } + + if(start != -1) { + t = (ticks - start) / 5000.; + if(t < 1) t *= t; + else t = 2 * t - 1; + } + View = spin(t) * View; + anims::moved(); + }); + + rogueviz::rv_hook(hooks_frame, 101, [] { + + if(!nomap) for(int s: {0, 1}) { + color_t axecolor = s == 0 ? 0x80C080FF : 0x008000FF; + shiftmatrix S = shiftless(s == 0 ? View : Id); + vid.linewidth *= 3; + + if(s == 0 && (tour_value != 1 || ticks >= 13000)) { + vid.linewidth *= 3; + for(ld v=0; v<=TAU; v+=0.01) curvepoint(hyperpoint(sin(v), cos(v), 1, 1)); queuecurve(S, 0xFFC0C0FF, 0, PPR::LINE); + vid.linewidth /= 3; + } + + curvepoint(hyperpoint(2.1,0,1,1)); curvepoint(hyperpoint(-2.1,0,1,1)); queuecurve(S, axecolor, 0, PPR::LINE); + curvepoint(hyperpoint(0,2.1,1,1)); curvepoint(hyperpoint(0,-2.1,1,1)); queuecurve(S, axecolor, 0, PPR::LINE); + latex_in_space(S * eupush(hyperpoint(2.2, 0.2, 1, 1)), 0.002, "$x$", axecolor, 0); + latex_in_space(S * eupush(hyperpoint(0.2, -2.2, 1, 1)), 0.002, "$y$", axecolor, 0); + for(int x: {-2, -1, 1, 2}) { + curvepoint(hyperpoint(x,0.1,1,1)); curvepoint(hyperpoint(x,-0.1,1,1)); queuecurve(S, axecolor, 0, PPR::LINE); + curvepoint(hyperpoint(0.1,x,1,1)); curvepoint(hyperpoint(-0.1,x,1,1)); queuecurve(S, axecolor, 0, PPR::LINE); + } + vid.linewidth /= 3; + curvepoint(hyperpoint(2.1,0.1,1,1)); curvepoint(hyperpoint(2.3,0,1,1)); curvepoint(hyperpoint(2.1,-0.1,1,1)); + queuecurve(S, 0, axecolor, PPR::LINE); + curvepoint(hyperpoint(0.1,-2.1,1,1)); curvepoint(hyperpoint(0,-2.3,1,1)); curvepoint(hyperpoint(-0.1,-2.1,1,1)); + queuecurve(S, 0, axecolor, PPR::LINE); + } + }); } }}, @@ -533,17 +942,33 @@ slide relhell_tour[] = { "light-like (squared distance = 0) and time-like (squared distance < 0), but if we have a point and direction, we have an isometry that " "takes it into any other point and direction of the same type.", [] (presmode mode) { - latex_slide(mode, defs+R"=( + string s = ""; + if(!tour_value || ticks >= 9000) { + s = "\\definecolor{rcsl}{rgb}{0,0.75,0}\n\\definecolor{rtsl}{rgb}{0,0,1}\n\\definecolor{rsign}{rgb}{1,0.25,0.25}\n"; + if(ticks >= 19000 || !tour_value) + s += "\\def\\csl#1{{\\color{rcsl}#1}}\n\\def\\tsl#1{{\\color{rtsl}#1}}\n\\def\\hlsign#1{{\\color{rsign}#1}}\n"; + else if(ticks >= 11000) + s += "\\def\\csl#1{{\\color{rcsl}#1}}\n\\def\\tsl#1{{\\color{rtsl}#1}}\n\\def\\hlsign#1{{#1}}\n"; + else if(ticks >= 9000) + s += "\\def\\csl#1{{\\color{rcsl}#1}}\n\\def\\tsl#1{{#1}}\n\\def\\hlsign#1{{#1}}\n"; + } + else { + s = "\\def\\csl#1{{#1}}\n\\def\\tsl#1{{#1}}\n\\def\\hlsign#1{{#1}}\n"; + } + latex_slide(mode, defs+s+R"=( {\color{remph}Minkowski spacetime with 2 space and 1 time dimension:} \begin{itemize} - \item $\bbE^{2,1} = \{(x,y,t): x,y,t \in \bbR\}$ - \item spacetime interval between \\ points $(x_1,y_1,t_1)$ and $(x_2, y_2, t_2)$ is \[(x_1-x_2)^2+(y_1-y_2)^2-(t_1-t_2)^2\] + \item $\bbE^{2,1} = \{(\csl{x,y},\tsl{t}): \csl{x,y},\tsl{t} \in \bbR\}$ + \item spacetime interval (``squared distance'') between \\ points $(\csl{x_1,y_1},\tsl{t_1})$ and $(\csl{x_2, y_2}, \tsl{t_2})$ is \[\csl{(x_1-x_2)^2\hlsign{+}(y_1-y_2)^2}\tsl{\hlsign{-}(t_1-t_2)^2}\rule{3cm}{0cm}\] \item {\color{remph} Lorentz transformations} preserve this \end{itemize} + \rule{0cm}{3cm} )=", sm::SIDE, 90); setCanvas(mode, &ccolor::chessboard, [] { set_geometry(gEuclidSquare); set_variation(eVariation::pure); tour::slide_backup(vid.axes, 0); }); static int start = -1; + static int hilite = 0; if(mode == pmKey) start = (start == -1) ? ticks : -1; + if(mode == pmKeyAlt) hilite++; if(mode == pmStart) { tour::slide_backup(anims::ma, anims::maTranslation); tour::slide_backup(pconf.stretch, 1); @@ -553,21 +978,77 @@ slide relhell_tour[] = { tour::slide_backup(vid.axes, 0); tour::slide_backup(vid.use_smart_range, 2); tour::slide_backup(vid.smart_range_detail, 1); + static ld t; rogueviz::rv_hook(hooks_frame, 101, [] { - if(start == -1) { anims::cycle_length = 0; pconf.stretch = 1; return; } - ld t = asinh((ticks - start) / 5000.); - anims::cycle_length = sinh(t) * 10; + if(start == -1) { anims::cycle_length = 0; pconf.stretch = 1; t = 0; return; } + t = (ticks - start) / 5000.; + if(tour_value && t > 1) t = 1; + if(tour_value && ticks - start > 45000) + t = t - (ticks - start - 45000) / 5000.; + t = asinh(t); + anims::cycle_length = sinh(t) * 10 * anims::period / 10000; pconf.stretch = sqrt(1 - tanh(t) * tanh(t)); println(hlog, "t=", t, "sinh = ", anims::cycle_length, " stretch = ", pconf.stretch); }); rogueviz::rv_hook(hooks_latex_slide, 100, [] { initquickqueue(); dynamicval s(pconf.stretch, 1); - drawMonsterType(moRunDog, nullptr, shiftless(spin(90._deg)), 0xFFFFFFFF, start >= 0 ? (ticks-start) / 500. : 0, 0xFFFFFFFF); + drawMonsterType(moRunDog, nullptr, shiftless(spin(t >= 0 ? 90._deg : -90._deg)), 0xFFFFFFFF, start >= 0 ? (ticks-start) / 500. : 0, 0xFFFFFFFF); + sortquickqueue(); quickqueue(); dialog::dwidth += 500; menu_darkening++; dialog::draw_side_shade(); dialog::dwidth -= 500; menu_darkening --; }); + rogueviz::rv_hook(hooks_post_latex_slide, 100, [] { + dynamicval s(pconf.stretch, 1); + if(true) for(int s: {0, 1}) { + vid.linewidth *= 2; + initquickqueue(); + color_t axecolor = s == 0 ? 0x80C080FF : 0x00C000FF; + color_t axecolor2 = s == 0 ? 0x8080C0FF : 0x0000FFFF; + shiftmatrix S = shiftless(eupush(3, 1.1) * euscale(0.4, 0.4)); + + ld gs = 2.45; + if(s == 0 && (!tour_value || ticks >= 32000)) for(int a=0; a<4; a++) { + vid.linewidth *= 3; + for(ld v=-1.5; v<=1.5; v+=0.01) curvepoint(hyperpoint(sinh(v), cosh(v), 1, 1)); queuecurve(S * spin(90._deg*a), 0xFFC0C0FF, 0, PPR::LINE); + vid.linewidth /= 3; + } + if(s==0) if(hilite == 3 || hilite == 4 || !tour_value) { + curvepoint(hyperpoint(gs,gs,1,1)); curvepoint(hyperpoint(-gs,gs,1,1)); curvepoint(hyperpoint(0,0,1,1)); queuecurve(S, 0, axecolor2 & 0xFFFFFF80, PPR::LINE); + curvepoint(hyperpoint(gs,-gs,1,1)); curvepoint(hyperpoint(-gs,-gs,1,1)); curvepoint(hyperpoint(0,0,1,1)); queuecurve(S, 0, axecolor2 & 0xFFFFFF80, PPR::LINE); + } + if(s==0) if(hilite == 1 || hilite == 4 || !tour_value) { + curvepoint(hyperpoint(gs,gs,1,1)); curvepoint(hyperpoint(gs,-gs,1,1)); curvepoint(hyperpoint(0,0,1,1)); queuecurve(S, 0, axecolor & 0xFFFFFF80, PPR::LINE); + curvepoint(hyperpoint(-gs,-gs,1,1)); curvepoint(hyperpoint(-gs,gs,1,1)); curvepoint(hyperpoint(0,0,1,1)); queuecurve(S, 0, axecolor & 0xFFFFFF80, PPR::LINE); + } + if(s==0) if(hilite == 2 || hilite == 4 || !tour_value) { + vid.linewidth *= 3; + curvepoint(hyperpoint(gs,gs,1,1)); curvepoint(hyperpoint(-gs,-gs,1,1)); curvepoint(hyperpoint(0,0,1,1)); queuecurve(S, 0x00C0C0FF, 0, PPR::LINE); + curvepoint(hyperpoint(gs,-gs,1,1)); curvepoint(hyperpoint(-gs,gs,1,1)); curvepoint(hyperpoint(0,0,1,1)); queuecurve(S, 0x00C0C0FF, 0, PPR::LINE); + vid.linewidth /= 3; + } + + if(s == 0) S = S * lorentz(0, 1, t); + vid.linewidth *= 3; + curvepoint(hyperpoint(2.1,0,1,1)); curvepoint(hyperpoint(-2.1,0,1,1)); queuecurve(S, axecolor, 0, PPR::LINE); + curvepoint(hyperpoint(0,2.1,1,1)); curvepoint(hyperpoint(0,-2.1,1,1)); queuecurve(S, axecolor2, 0, PPR::LINE); + latex_in_space(S * eupush(hyperpoint(2.2, 0.2, 0, 1)), 0.002, "$y$", axecolor, 0); + latex_in_space(S * eupush(hyperpoint(0.2, -2.2, 0, 1)), 0.002, "$t$", axecolor2, 0); + for(int x: {-2, -1, 1, 2}) { + curvepoint(hyperpoint(x,0.1,1,1)); curvepoint(hyperpoint(x,-0.1,1,1)); queuecurve(S, axecolor, 0, PPR::LINE); + curvepoint(hyperpoint(0.1,x,1,1)); curvepoint(hyperpoint(-0.1,x,1,1)); queuecurve(S, axecolor2, 0, PPR::LINE); + } + vid.linewidth /= 3; + curvepoint(hyperpoint(2.1,0.1,1,1)); curvepoint(hyperpoint(2.3,0,1,1)); curvepoint(hyperpoint(2.1,-0.1,1,1)); + queuecurve(S, 0, axecolor, PPR::LINE); + curvepoint(hyperpoint(0.1,-2.1,1,1)); curvepoint(hyperpoint(0,-2.3,1,1)); curvepoint(hyperpoint(-0.1,-2.1,1,1)); + queuecurve(S, 0, axecolor2, PPR::LINE); + quickqueue(); + vid.linewidth /= 2; + } + + }); } }}, @@ -585,7 +1066,11 @@ slide relhell_tour[] = { tour::slide_backup(pconf.alpha, 1000); tour::slide_backup(mapeditor::drawplayer, false); tour::slide_backup(vid.axes, 0); + tour::slide_backup(pconf.xposition, -0.25); + tour::slide_backup(anims::ma, anims::maTranslation); + tour::slide_backup(anims::cycle_length, 0); } + if(mode == pmKey) anims::cycle_length = 10 - anims::cycle_length; latex_slide(mode, defs+R"=( {\color{remph}2-dimensional sphere:} \begin{itemize} @@ -594,6 +1079,19 @@ slide relhell_tour[] = { \item {\color{remph} isometries} (rotations, etc.) keep this distance \end{itemize} )=", sm::SIDE, 90); + static bool arcs = false; + if(mode == pmKeyAlt) arcs = !arcs; + if(mode == pmStart) rogueviz::rv_hook(hooks_post_latex_slide, 100, [] { + if(!arcs) return; + initquickqueue(); + vid.linewidth *= 15; + for(int a=0; a<=6; a++) { + for(ld v=-1; v<=1; v+=0.01) curvepoint(cspin(0, 2, 15._deg * a) * hyperpoint(-cos(v), sin(v), 0, 1)); + queuecurve(shiftless(Id), 0xFF8080FF, 0, PPR::LINE); + } + vid.linewidth /= 15; + quickqueue(); + }); }}, {"hyperbolic geometry", 999, LEGAL::NONE | QUICKGEO | USE_SLIDE_NAME | NOTITLE, @@ -606,10 +1104,18 @@ slide relhell_tour[] = { "also employ an extra coordinate, and it is straightforward to apply 3D engines to work with " "spherical and hyperbolic geometry too, using these models.", [] (presmode mode) { - latex_slide(mode, defs+R"=( - {\color{remph}2-dimensional hyperbolic space (Minkowski hyperboloid model):} + string s = ""; + if(!tour_value || ticks >= 13000) { + s = "\\definecolor{rcsl}{rgb}{0,0.75,0}\n\\definecolor{rtsl}{rgb}{0,0,1}\n\\definecolor{rsign}{rgb}{1,0.25,0.25}\n"; + s += "\\def\\csl#1{{\\color{rcsl}#1}}\n\\def\\tsl#1{{\\color{rtsl}#1}}\n\\def\\hlsign#1{{\\color{rsign}#1}}\n"; + } + else { + s = "\\def\\csl#1{{#1}}\n\\def\\tsl#1{{#1}}\n\\def\\hlsign#1{{#1}}\n"; + } + latex_slide(mode, defs+s+R"=( + {\color{remph}2-dimensional hyperbolic space \\ (Minkowski hyperboloid model):} \begin{itemize} - \item $\bbH^2 = \{(x,y,t) \in \bbE^{2,1}: x^2+y^2-t^2=-1, t>0\}$ + \item $\bbH^2 = \{(\csl{x,y},\tsl{t}) \in \bbE^{2,1}: \csl{x^2\hlsign{+}y^2}\hlsign{-}\tsl{t^2}=-1, t>0\}$ \item distances measured as \\ the lengths of curves in $\bbE^{2,1}$ \item {\color{remph} isometries} (rotations, etc.) keep this distance \item we get the Poincaré model by projecting \\ $(x,y,t) \mapsto (\frac{x}{t+1}, \frac{y}{t+1})$ @@ -617,15 +1123,19 @@ slide relhell_tour[] = { )=", sm::SIDE, 90); setCanvas(mode, &ccolor::football, [] { tour::slide_backup(pconf.model, mdHyperboloid); - tour::slide_backup(pconf.scale, pconf.scale * 0.5); + tour::slide_backup(pconf.scale, pconf.scale * 1); + tour::slide_backup(vid.multiplier_ring, 3); tour::slide_backup(pconf.ball(), cspin(1, 2, -20._deg)); tour::slide_backup(mapeditor::drawplayer, false); tour::slide_backup(vid.axes, 0); rogueviz::rv_hook(hooks_latex_slide, 100, [] { dialog::dwidth += 500; menu_darkening++; dialog::draw_side_shade(); dialog::dwidth -= 500; menu_darkening --; }); + tour::slide_backup(anims::ma, anims::maTranslation); + tour::slide_backup(anims::cycle_length, 0); }); + if(mode == pmKey) anims::cycle_length = 10 - anims::cycle_length; }}, - {"anti-de Sitter spacetime", 999, LEGAL::NONE | QUICKGEO | USE_SLIDE_NAME | NOTITLE, + {"anti-de Sitter geometry", 999, LEGAL::NONE | QUICKGEO | USE_SLIDE_NAME | NOTITLE, "Here is how we add a time coordinate to the hyperbolic plane, in order to get 2+1D anti-de Sitter spacetime. " "As you can see, the construction is quite similar, and again, we get a maximally symmetric spacetime.\n\n" "Press 5 for an animated visualization of this construction. Initially you see the hyperbolic plane at time 0 (u=0, t>0). " @@ -634,10 +1144,12 @@ slide relhell_tour[] = { "uses the RogueViz implementation of that space. However, the angular coordinate becomes time-like, making our spacetime to be " "much more symmetric, and the geodesics work in a much more intuitive way.", [] (presmode mode) { - latex_slide(mode, defs+R"=( + string s = "\\definecolor{rcsl}{rgb}{0,0.75,0}\n\\definecolor{rtsl}{rgb}{0,0,1}\n\\definecolor{rsign}{rgb}{1,0.25,0.25}\n"; + s += "\\def\\csl#1{{\\color{rcsl}#1}}\n\\def\\tsl#1{{\\color{rtsl}#1}}\n\\def\\hlsign#1{{\\color{rsign}#1}}\n"; + latex_slide(mode, defs+s+R"=( {\color{remph}anti-de Sitter spacetime:} \begin{itemize} - \item $\wadS{2} = \{(x,y,t,u) \in \bbE^{2,2}: \\ x^2+y^2-t^2-u^2=-1\}$ + \item $\wadS{2} = \{(\csl{x,y},\tsl{t,u}) \in \bbE^{2,2}: \\ \csl{x^2\hlsign{+}y^2}\hlsign{-}\tsl{t^2\hlsign{-}u^2}=-1\}$ \item take $u=0, t>0$ -- we get $\bbH^2$ \item rotation in the $(t,u)$ plane \\ corresponds to the pass of time \item $\uadS{2}$ -- the {\color{remph}universal cover}: \\ @@ -675,7 +1187,7 @@ slide relhell_tour[] = { }); }}, - {"de Sitter spacetime", 999, LEGAL::NONE | QUICKGEO | USE_SLIDE_NAME | NOTITLE, + {"de Sitter spacetime geometry", 999, LEGAL::NONE | QUICKGEO | USE_SLIDE_NAME | NOTITLE, "And here is how we add a time coordinate to 2D spherical geometry, to get 2+1D de Sitter spacetime. " "The construction is actually very similar to three-dimensional hyperbolic plane, but now the " "'squared radius' is space-like. So we get a maximally symmetric spacetime again.\n\n" @@ -683,12 +1195,14 @@ slide relhell_tour[] = { "it looks from the point of view of an inhabitant -- the whole 'sphere' does not expand.", [] (presmode mode) { - latex_slide(mode, defs+R"=( + string s = "\\definecolor{rcsl}{rgb}{0,0.75,0}\n\\definecolor{rtsl}{rgb}{0,0,1}\n\\definecolor{rsign}{rgb}{1,0.25,0.25}\n"; + s += "\\def\\csl#1{{\\color{rcsl}#1}}\n\\def\\tsl#1{{\\color{rtsl}#1}}\n\\def\\hlsign#1{{\\color{rsign}#1}}\n"; + latex_slide(mode, defs+s+R"=( {\color{remph}de Sitter spacetime:} \begin{itemize} - \item $\dS{2} = \{(x,y,z,t) \in \bbE^{3,1}: \\ x^2+y^2+z^2-t^2=1\}$ + \item $\dS{2} = \{(\csl{x,y,z},\tsl{t}) \in \bbE^{3,1}: \\ \csl{x^2\hlsign{+}y^2\hlsign{+}z^2}\hlsign{-}\tsl{t^2}=1\}$ \item take $t=0$ -- we get $\bbS^2$ - \item the universe is expanding with $t$ \\ (not if we apply Lorentz transformation) + \item the universe is expanding with $t$ \\ (not if we apply \\ the Lorentz transformation) \end{itemize} )=", sm::NOSCR | sm::SIDE, 90); static int phase = 0; @@ -755,18 +1269,76 @@ slide relhell_tour[] = { return true; }); } - } - }; + } + }; int pohooks = - 0 + - addHook_slideshows(100, [] (tour::ss::slideshow_callback cb) { + 0 + arg::add3("-contrep", [] { + cmode = sm::NORMAL; for(int a=0; a<3000; a++) println(hlog, a), paused = false, game_over = false, have_crashes = false, ds_turn(10), ticks += 10; + switch_replay(); + switch_spacetime_to(true); + pmodel = mdRelPerspective; use_duality = false; + }) + + arg::add3("-ads-missile-replay", [] { missile_replay = true; }) + + arg::add3("-stereo-transition", [] { + arg::shift(); int len = arg::argi(); + static int tstart = 999000; + + rogueviz::rv_hook(hooks_handleKey, 101, [] (int sym, int uni) { + println(hlog, "uni = ", uni); + if((cmode & sm::NORMAL) && uni == 'y') { + tstart = tstart > ticks ? ticks : 999000; + return true; + } + return false; + }); + rv_hook(anims::hooks_anim, 102, [len] { + ld t = (ticks - tstart) * 1. / len; flip_limit = 0.9; + if(t < 0) { pconf.alpha = 1000; pconf.scale = 950; vid.yshift = 0; pconf.stretch = 1; backbrightness = 0.25; } + else if(t > 1) { pconf.alpha = 1; pconf.scale = 0.95; pconf.stretch = 1; vid.yshift = M_PI; backbrightness = 1; } + else { + ld t1 = t; t1 = t1 * t1 * (3 - 2 * t1); + pconf.alpha = exp(log(1000) * (1 - t1)); + pconf.scale = 0.95 * pconf.alpha; + pconf.stretch = 1; + vid.yshift = M_PI * t1; + backbrightness = lerp(0.25, 1, t1); + } + }); + }) + + arg::add3("-ads-resource", [] { + static int howmany = -2; + if(howmany == -2) rogueviz::rv_hook(hooks_prestats, 101, [] { + if(howmany <= 0) return false; + vector res = {rtFuel, rtOxygen, rtHull, rtAmmo}; + flat_model_enabler fm; + dynamicval g(geometry, gEuclid); + initquickqueue(); + int index = 0; + for(auto which: res) { + auto sh = *rsrc_shape[which]; + for(int s: {0, 1}) for(int dx=-5; dx<=5; dx++) for(int dy=-5; dy<=5; dy++) { + if(s == 1 && (dx || dy)) continue; + if(s == 0 && (dx*dx+dy*dy >= 20)) continue; + for(int i=0; i