diff --git a/README.md b/README.md index 0906a856..feb82c90 100644 --- a/README.md +++ b/README.md @@ -48,8 +48,12 @@ You can aim for the Orb of Yendor, or you can simply aim for as high score as po ## Modifications OK, now lots of the above can be changed. You can change the geometry and topology (to Euclidean, spherical, or even to nonisotropic 3D geometries). You can play challenges based on -various in-game quests, and even try some other game genres in non-Euclidean spaces (roguelite aka shmup, racing, peaceful puzzles). Or use the engine for non-Euclidean computations -and visualizations (see [RogueViz](http://roguetemple.com/z/hyper/rogueviz.php)). Have fun! +various in-game quests, and even try some other game genres in non-Euclidean spaces (roguelite aka shmup, racing, peaceful puzzles). + +## RogueViz + +HyperRogue uses [RogueViz](http://roguetemple.com/z/hyper/rogueviz.php), which is our engine for non-Euclidean games, computations and visualizations. This repo includes the source code of RogueViz demos in subdirectory `rogueviz`, but +not the data, which is available on [itch.io](https://zenorogue.itch.io/rogueviz). RogueViz is funded by the National Science Centre, Poland, grant UMO-2019/35/B/ST6/04456. ## Development ## @@ -74,6 +78,7 @@ make The `mymake` program builds HyperRogue in parts. It takes longer than the method shown above, but it uses significantly less memory during compilation, and when you change something, `mymake` will only recompile the changed file. Additionally, it can be easily configured, e.g., to produce an optimized build, or to include addons (see `mymake.cpp` for some example invocations, and `devmods` for some example addons). +Most useful parameters include `-O3` (optimized build), `-rv` (include the RogueViz demos), `-vr` (build the VR version). ``` make mymake && ./mymake diff --git a/changelog.txt b/changelog.txt index 33040b3c..d3a9fb76 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4575,3 +4575,21 @@ Geometry: - Goldberg-Coxeter improvements (larger limits supported, warn if outside of the supported limits, some are fixed) - fixed fat edges in some H3 honeycombs - fixed some bugs with Multi-dimensional Crystal quotient space + +2022-03-01 09:39 Update 12.0l: +Orb-related fixes: +- Curse of Repulsion now correctly marked when used +- when having Orb of Freedom + Orb of Time, other orbs are no longer drained by Freedom checks +- Valentine's Easter Egg: Add +1 extra charge to Orb of Love + +Geometry: +- fixed VR in product geometries +- portals between geometries: fixed some formulas, walking mode +- fixed dark lines in binary tiling x R raycasting which happened when we got a=0 in quadratic equation +- made Yendor/Haunted sight radius consistent when the tiling is changed +- infinite generation for single-land Camelot now only happens in hyperbolic geometry (also fixes the missing Grail in Crystal) +- additions and fixes to RogueViz + +Other: +- fixed Crossroads wiki links +- fixed some settings incorrectly showing a warning on editing (this also brings back the 'play music when out of focus' option) diff --git a/graph.cpp b/graph.cpp index 6f96e274..e7d0ea1f 100644 --- a/graph.cpp +++ b/graph.cpp @@ -3075,7 +3075,7 @@ EX void addaura(shiftpoint h, color_t col, int fd) { if(!haveaura_cached) return; apply_joukowsky_aura(h); - int r = int(2*AURA + atan2(h[1], h[0]) * AURA / 2 / M_PI) % AURA; + int r = gmod(atan2(h[1], h[0]) * AURA / 2 / M_PI, AURA); aurac[r][3] += auramemo << fd; col = darkened(col); aurac[r][0] += (col>>16)&255; diff --git a/help.cpp b/help.cpp index 3f0ef0ca..2fb1550b 100644 --- a/help.cpp +++ b/help.cpp @@ -232,7 +232,7 @@ EX void buildCredits() { "Kojiguchi Kazuki, baconcow, Alan, SurelyYouJest, hotdogPi, DivisionByZero, xXxWeedGokuxXx, jpystynen, Dmitry Marakasov, Alexandre Moine, Arthur O'Dwyer, " "Triple_Agent_AAA, bluetailedgnat, Allalinor, Shitford, KittyTac, Christopher King, KosGD, TravelDemon, Bubbles, rdococ, frozenlake, MagmaMcFry, " "Snakebird Priestess, roaringdragon2, Stopping Dog, bengineer8, Sir Light IJIJ, ShadeBlade, Saplou, shnourok, Ralith, madasa, 6% remaining, Chimera245, Remik Pi, alien foxcat thing, " - "Piotr Grochowski, Ann, still-flow, tyzone, Paradoxica, LottieRatWorld" + "Piotr Grochowski, Ann, still-flow, tyzone, Paradoxica, LottieRatWorld, aismallard" ); #ifdef EXTRALICENSE help += EXTRALICENSE; diff --git a/hyper.h b/hyper.h index c303b878..a307313e 100644 --- a/hyper.h +++ b/hyper.h @@ -13,8 +13,8 @@ #define _HYPER_H_ // version numbers -#define VER "12.0k" -#define VERNUM_HEX 0xA90B +#define VER "12.0l" +#define VERNUM_HEX 0xA90C #include "sysconfig.h" diff --git a/items.cpp b/items.cpp index 7d63e4f4..4d2bd610 100644 --- a/items.cpp +++ b/items.cpp @@ -42,6 +42,7 @@ EX bool doPickupItemsWithMagnetism(cell *c) { c4->item = c3->item; moveEffect(movei(c3, c4, (cw+j).spin), moDeadBird); c3->item = itNone; + markOrb(itCurseRepulsion); } } } diff --git a/rogueviz/embeddings.cpp b/rogueviz/embeddings.cpp index 7dce3b94..a7e48f93 100644 --- a/rogueviz/embeddings.cpp +++ b/rogueviz/embeddings.cpp @@ -11,15 +11,43 @@ embedding_type etype = eNatural; map landscape_at; map delta_at; +map delta_id; + +int qdelta; void init_landscape(int dimensions) { etype = eLandscape; landscape_at.clear(); delta_at.clear(); + delta_id.clear(); + qdelta = 0; landscape_at[currentmap->gamestart()].resize(dimensions, 0); println(hlog, "initialized for ", currentmap->gamestart()); } +kohvec& get_landscape_at(cell *h); + +void init_landscape_det(const vector& ac) { + etype = eLandscape; + landscape_at.clear(); + delta_at.clear(); + delta_id.clear(); + qdelta = 0; + landscape_at[currentmap->gamestart()].resize(0, 0); + for(cell *c: ac) get_landscape_at(c); + int dimensions = isize(delta_at); + landscape_at.clear(); + landscape_at[currentmap->gamestart()].resize(dimensions, 0); + println(hlog, "qdelta = ", qdelta, " size of delta_at = ", isize(delta_at)); + for(auto& d: delta_at) { + d.second.resize(dimensions, 0); + // d.second[id++] = 1; + d.second[delta_id[d.first]] = 1; + } + + println(hlog, "initialized for ", currentmap->gamestart(), ", dimensions = ", dimensions); + } + void normalize(cellwalker& cw) { int d = celldist(cw.at); back: @@ -55,17 +83,25 @@ void normalize(cellwalker& cw) { } } +ld hrandd() { + return ((hrngen() & HRANDMAX) + .5) / HRANDMAX; + } + ld gaussian_random() { - return (hrand(1000) + hrand(1000) - hrand(1000) - hrand(1000)) / 1000.; + ld u1 = hrandd(); + ld u2 = hrandd(); + return sqrt(-2*log(u1)) * cos(2*M_PI*u2); } void apply_delta(cellwalker cw, kohvec& v) { normalize(cw); auto& da = delta_at[cw]; - if(da.empty()) { + if(!delta_id.count(cw)) { + delta_id[cw] = qdelta++; da.resize(isize(v)); - for(auto& x: da) x = gaussian_random(); + for(int i=0; i ", kz(alpha)); + // println(hlog, kz(x), " -> ", kz(alpha)); v[2*i] = cos(alpha); v[2*i+1] = sin(alpha); } - println(hlog, kz(h), " -> ", v); + // println(hlog, kz(h), " -> ", v); } else if(euclid && bounded && WDIM == 2) { columns = 4; diff --git a/rogueviz/fifteen.cpp b/rogueviz/fifteen.cpp index 89284763..61ef447b 100644 --- a/rogueviz/fifteen.cpp +++ b/rogueviz/fifteen.cpp @@ -452,7 +452,8 @@ auto fifteen_hook = if(fifteen_slides.empty()) { fifteen_slides.emplace_back( slide{"Introduction", 999, LEGAL::NONE, - "This is a collection of some geometric and topological variants of the Fifteen puzzle." + "This is a collection of some geometric and topological variants of the Fifteen puzzle. Most of these " + "are digital implementations of the mechanical designs by Henry Segerman." , [] (presmode mode) {} }); @@ -490,11 +491,16 @@ auto fifteen_hook = add("coiled", "coiled", "Coiled fifteen puzzle by Henry Segerman.", "https://www.youtube.com/watch?v=rfAEgxNEOrQ"); add("Möbius band", "mobiusband", "Fifteen puzzle on a Möbius band."); add("Kite-and-dart", "kitedart", "Kite-and-dart puzzle."); + add("29", "29", "The 29 puzzle by Henry Segerman.", "https://www.youtube.com/watch?v=EitWHthBY30"); + add("12", "12", "The 12 puzzle mentioned in the same video by Henry Segerman.", "https://www.youtube.com/watch?v=EitWHthBY30"); + add("124", "124", "The 124 puzzle mentioned in the same video by Henry Segerman.", "https://www.youtube.com/watch?v=EitWHthBY30"); + add("60", "60", "The 124 puzzle mentioned in the same video by Henry Segerman.", "https://www.youtube.com/watch?v=EitWHthBY30"); + add("Continental drift", "sphere19", "Based on the Continental Drift puzzle by Henry Segerman.", "https://www.youtube.com/watch?v=0uQx33KFMO0"); add_end(fifteen_slides); } - cb(XLAT("variants of the fifteen puzzle"), &fifteen_slides[0], 'h'); + cb(XLAT("variants of the fifteen puzzle"), &fifteen_slides[0], 'f'); }); #endif diff --git a/rogueviz/hyperbolic-analogs.cpp b/rogueviz/hyperbolic-analogs.cpp index 330e4c23..681a3206 100644 --- a/rogueviz/hyperbolic-analogs.cpp +++ b/rogueviz/hyperbolic-analogs.cpp @@ -440,6 +440,10 @@ auto msc = arg::add3("-analogs", enable) slide_url(mode, 'm', "HyperRogue page about projections", "http://www.roguetemple.com/z/hyper/models.php"); setCanvas(mode, '0'); if(mode == pmStart) { + slide_backup(mapeditor::drawplayer); + slide_backup(vid.use_smart_range); + slide_backup(vid.smart_range_detail); + slide_backup(vid.linequality); enable(); start_game(); slide_backup(cycle_models); diff --git a/rogueviz/intra-demos.cpp b/rogueviz/intra-demos.cpp index e9e4a695..69cb6459 100644 --- a/rogueviz/intra-demos.cpp +++ b/rogueviz/intra-demos.cpp @@ -496,6 +496,7 @@ auto hooks = mapstream::loadMap(s); slide_backup(ray::fixed_map, true); slide_backup(ray::max_iter_intra, y); + slide_backup(mapeditor::drawplayer, false); }; }; @@ -509,6 +510,7 @@ auto hooks = if(twitter != "") slide_url(mode, 't', "Twitter link", twitter); slide_action(mode, 'r', "run this visualization", loader); + slidecommand = "portal options"; if(mode == tour::pmKey) pushScreen(intra::show_portals); } }); diff --git a/rogueviz/kohonen.cpp b/rogueviz/kohonen.cpp index 2b42ccd6..e309015b 100644 --- a/rogueviz/kohonen.cpp +++ b/rogueviz/kohonen.cpp @@ -264,10 +264,7 @@ bool triangulate(kohvec d, neuron& w, map& find, transmatrix& re } if(diff < bdiff) bdiff = diff, candidate = w2, cdir = i; } - if(cdir == -1) { - println(hlog, "not enough directions"); - return false; - } + if(cdir == -1) break; dirs.push_back(cdir); other.push_back(candidate); kv.push_back(candidate->net); @@ -291,6 +288,7 @@ bool triangulate(kohvec d, neuron& w, map& find, transmatrix& re for(int i=0; i& v) { vector res; for(int i=0; i<10; i++) res.push_back(v[i]); return res; }; println(hlog, "dot too small, i=", i,", dirs=", dirs); println(hlog, "a = ", head(a)); @@ -299,6 +297,7 @@ bool triangulate(kohvec d, neuron& w, map& find, transmatrix& re println(hlog, "orig kv: ", head(z->net), " @ ", z->where); for(auto z: kv) println(hlog, "curr kv: ", head(z)); + */ return false; } for(int j=i+1; j> dispersion; + vector> dispersion; }; double dispersion_end_at = 1.6; +bool dispersion_long; + double dispersion_precision = .0001; int dispersion_each = 1; @@ -476,10 +477,10 @@ void buildcellcrawler(cell *c, cellcrawler& cr, int dir) { cr.build(cellwalker(c,dir)); if(!gaussian) { - vector curtemp; - vector newtemp; + vector curtemp; + vector newtemp; vector qty; - vector > pairs; + vector > pairs; int N = isize(net); curtemp.resize(N, 0); @@ -503,8 +504,8 @@ void buildcellcrawler(cell *c, cellcrawler& cr, int dir) { auto &d = cr.dispersion; d.clear(); - - DEBBI(DF_LOG, ("Building dispersion, precision = ", dispersion_precision, " end_at = ", dispersion_end_at, "...\n")); + + // DEBBI(DF_LOG, ("Building dispersion, precision = ", dispersion_precision, " end_at = ", dispersion_end_at, "...\n")); for(iter=0; dispersion_count ? true : vmax > vmin * dispersion_end_at; iter++) { if(iter % dispersion_each == 0) { @@ -527,10 +528,13 @@ void buildcellcrawler(cell *c, cellcrawler& cr, int dir) { for(int i=0; i vmax) vmax = curtemp[i]; + // if(iter % 50 == 0) println(hlog, "iter=", iter, " vmin=", vmin, " vmax=", vmax, " pairs=", isize(pairs)); } - dispersion_count = isize(d); - DEBB(DF_LOG, ("Dispersion count = ", dispersion_count)); + if(!dispersion_count) { + if(!dispersion_long) dispersion_count = isize(d); + DEBB(DF_LOG, ("Dispersion count = ", isize(d), " celldist = ", celldist(c))); + } /* println(hlog, "dlast = ", d.back()); println(hlog, "dlast2 = ", d[d.size()-2]); @@ -542,7 +546,9 @@ void buildcellcrawler(cell *c, cellcrawler& cr, int dir) { map scc; pair get_cellcrawler_id(cell *c) { - if(among(geometry, gZebraQuotient, gMinimal, gArnoldCat, gField435, gField534) || (euclid && quotient && !bounded) || IRREGULAR || (GDIM == 3 && sphere) || (hyperbolic && GDIM == 3 && quotient) + if(!bounded) + return make_pair(neuronId(*getNeuronSlow(c)), 0); + if(among(geometry, gZebraQuotient, gMinimal, gArnoldCat, gField435, gField534) || (euclid && quotient && !bounded) || IRREGULAR || (GDIM == 3 && sphere) || (hyperbolic && GDIM == 3) || (euclid && nonorientable)) { // Zebra Quotient does exhibit some symmetries, // but these are so small anyway that it is safer to just build @@ -644,20 +650,20 @@ void step() { tt = pow(tt, ttpower); double sigma = maxdist * tt; - int dispid = int(dispersion_count * tt); if(qpct) { int pct = (int) ((qpct * (t+.0)) / tmax); if(pct != lpct) { lpct = pct; analyze(); +} - if(gaussian) - println(hlog, format("t = %6d/%6d %3d%% sigma=%10.7lf maxudist=%10.7lf\n", t, tmax, pct, sigma, maxudist)); - else - println(hlog, format("t = %6d/%6d %3d%% dispid=%5d maxudist=%10.7lf\n", t, tmax, pct, dispid, maxudist)); - } - } +// if(gaussian) +// println(hlog, format("t = %6d/%6d %3d%% sigma=%10.7lf maxudist=%10.7lf\n", t, tmax, pct, sigma, maxudist)); +// else +// println(hlog, format("t = %6d/%6d %3d%% dispid=%5d maxudist=%10.7lf\n", t, tmax, pct, dispid, maxudist)); +// } + } // int id = hrand(samples); neuron& n = winner(id); whowon.resize(samples); @@ -678,12 +684,18 @@ void step() { cellcrawler& s = scc[cid.first]; s.sprawl(cellwalker(n.where, cid.second)); - vector fake(1,1); + vector fake(0,0); + /* for(auto& sd: s.data) + fake.push_back(exp(-sqr(sd.dist/sigma))); */ + + int dispersion_count = isize(s.dispersion); + int dispid = int(dispersion_count * tt); + auto it = gaussian ? fake.begin() : s.dispersion[dispid].begin(); for(auto& sd: s.data) { neuron *n2 = getNeuron(sd.target.at); - if(!n2) continue; + if(!n2) { it++; continue; } n2->debug++; double nu = learning_factor; @@ -697,15 +709,15 @@ void step() { for(int k=0; knet[k] += nu * (data[id].val[k] - n2->net[k]); - if(isnan(n2->net[k])) - throw hr_exception("obtained nan somehow, nu = " + lalign(0, nu)); + /* if(isnan(n2->net[k])) + throw hr_exception("obtained nan somehow, nu = " + lalign(0, nu)); */ } } - for(auto& n2: net) { + /* for(auto& n2: net) { if(n2.debug > 1) throw hr_exception("sprawler error"); n2.debug = 0; - } + } */ t--; if(t == 0) analyze(); @@ -893,7 +905,7 @@ void initialize_dispersion() { DEBBI(DF_LOG, ("Initializing dispersion")); - if(gaussian) { + if(gaussian || true) { DEBB(DF_LOG, ("dist = ", fts(mydistance(net[0].where, net[1].where)))); cell *c1 = net[cells/2].where; vector mapdist; @@ -902,19 +914,26 @@ void initialize_dispersion() { maxdist = mapdist[isize(mapdist)*5/6] * distmul; DEBB(DF_LOG, ("maxdist = ", fts(maxdist))); } - + dispersion_count = 0; - + + if(!gaussian) + DEBB(DF_LOG, ("dispersion precision = ", dispersion_precision, " end_at = ", dispersion_end_at, "...\n")); + + DEBB(DF_LOG, ("building crawlers...\n")); + scc.clear(); for(int i=0; i(); + scan(fsm, mtlname); } if(s == "map_Kd") { scan(fsm, texname); @@ -93,8 +94,12 @@ void model::load_obj(model_data& md) { next_object: object *co = nullptr; bool textured = false; + fs.get(); string oname = scanline(fs); println(hlog, "reading object: ", oname); + md.objindex.push_back(isize(md.objs)); + hyperpoint ctr = Hypc; + int cqty = 0; while(true) { if(feof(fs.f)) { if(co) cgi.finishshape(); @@ -117,6 +122,7 @@ void model::load_obj(model_data& md) { h[1] /= 100; h[2] /= 100; vertices.push_back(h); + ctr += h; cqty++; } else if(s == "vt") { ld u, v; @@ -134,7 +140,10 @@ void model::load_obj(model_data& md) { else if(s == "usemtl") { if(co) cgi.finishshape(); if(co) println(hlog, "vertices = ", co->sh.e-co->sh.s, " tvertices = ", isize(co->tv.tvertices)); - string mtlname = scanline(fs); + fs.get(); + string mtlname; + scan(fs, mtlname); + //string mtlname = scanline(fs); co = nullptr; if(mtlname.find("Layer_Layer0") != string::npos) continue; objects.push_back(make_shared()); @@ -196,6 +205,14 @@ void model::load_obj(model_data& md) { tot.push_back(textured ? tvertices[vis[i].t] : point3(0,0,0)); } if(!co) continue; + + if(shift_to_ctr) { + hyperpoint ctr1 = ctr / cqty; + ctr1[3] = 0; + println(hlog, "ctr1 = ", ctr1, "hys = ", hys[0]); + for(auto& h: hys) + h -= ctr1; + } hyperpoint norm = (hys[1] - hys[0]) ^ (hys[2] - hys[0]); norm /= hypot_d(3, norm); @@ -255,7 +272,8 @@ void model::load_obj(model_data& md) { println(hlog, "reading finished"); - cgi.extra_vertices(); + md.objindex.push_back(isize(md.objs)); + cgi.extra_vertices(); } model_data& model::get() { @@ -277,8 +295,8 @@ model_data& model::get() { } void model_data::render(const shiftmatrix& V) { - for(auto& obj: objs) { - queuepoly(V, obj->sh, obj->color); + for(auto& obj: objs) if(obj->color) { + queuepoly(V, obj->sh, obj->color); } } @@ -303,6 +321,7 @@ auto cf = addHook(hooks_configfile, 100, [] { ->editable(1, 100, 1, "3D model precision", "higher-precision models take more time to load and to render.", 'p') ->set_sets([] { dialog::numberdark = dialog::DONT_SHOW; }) ; + param_b(shift_to_ctr, "shift_to_ctr"); }); } diff --git a/rogueviz/planets.cpp b/rogueviz/planets.cpp index 4e0ad571..d99d4f3f 100644 --- a/rogueviz/planets.cpp +++ b/rogueviz/planets.cpp @@ -435,6 +435,7 @@ void choose_projection() { cmode = sm::SIDE | sm::MAYDARK; gamescreen(0); dialog::init(XLAT("choose projection"), 0xFFFFFFFF, 150, 0); + dynamicval di(index); for(int i=0; i<8; i++) { index = i; dynamicval md(pmodel, pmodel); @@ -520,7 +521,7 @@ auto msc = "We can also project a sphere to a sphere of different curvature. For example, what about the azimuthal equidistant projection from Earth to Moon? " "This projection correctly maps the angles and distances from a chosen point at Earth. " - "Press 'o' to use the place on Earth you are in as the chosen point, try other projections, or change the other settings!" + "Press '5' to use the place on Earth you are in as the chosen point, try other projections, or change the other settings!" , [] (presmode mode) { slide_url(mode, 't', "Twitter link (with description)", "https://twitter.com/ZenoRogue/status/1339946298460483589"); @@ -533,9 +534,12 @@ auto msc = slide_backup(pmodel, mdDisk); slide_backup(pconf.scale, 1000); slide_backup(pconf.alpha, 1000); + slide_backup(mapeditor::drawplayer, false); start_game(); slide_backup(max_alpha, 192); } + slidecommand = "options"; + if(mode == tour::pmKey) pushScreen(show); }}); }); diff --git a/rogueviz/playing-with-impossibility.cpp b/rogueviz/playing-with-impossibility.cpp index 14fb2e3c..571e0117 100644 --- a/rogueviz/playing-with-impossibility.cpp +++ b/rogueviz/playing-with-impossibility.cpp @@ -169,7 +169,13 @@ void geodesic_screen(presmode mode, int id) { use_angledir(mode, id == 0); setCanvas(mode, '0'); - if(mode == pmStart) stop_game(), pmodel = mdHorocyclic, geometry = gCubeTiling, pconf.clip_min = -10000, pconf.clip_max = +100, start_game(); + if(mode == pmStart) { + slide_backup(pmodel); + slide_backup(pconf.clip_min); + slide_backup(pconf.clip_max); + slide_backup(vid.cells_drawn_limit); + stop_game(), pmodel = mdHorocyclic, geometry = gCubeTiling, pconf.clip_min = -10000, pconf.clip_max = +100, start_game(); + } add_stat(mode, [id] { cmode |= sm::SIDE; @@ -540,6 +546,7 @@ slide dmv_slides[] = { [] (presmode mode) { setCanvas(mode, '0'); if(mode == pmStart) { + tour::slide_backup(mapeditor::drawplayer, false); enable_earth(); View = Id; @@ -653,6 +660,7 @@ slide dmv_slides[] = { set_geometry(gFieldQuotient); */ start_game(); + tour::slide_backup(mapeditor::drawplayer, false); pentaroll::create_pentaroll(true); tour::slide_backup(anims::period, 30000.); tour::slide_backup(sightranges[geometry], 4); @@ -1132,7 +1140,7 @@ slide dmv_slides[] = { int phooks = 0 + addHook_slideshows(100, [] (tour::ss::slideshow_callback cb) { - cb(XLAT("Playing with Impossibility"), &dmv_slides[0], 'p'); + cb(XLAT("Playing with Impossibility"), &dmv_slides[0], 'i'); }); } diff --git a/rogueviz/presentation.cpp b/rogueviz/presentation.cpp index aeef6e30..7f993dab 100644 --- a/rogueviz/presentation.cpp +++ b/rogueviz/presentation.cpp @@ -235,6 +235,7 @@ void choose_presentation() { if(!tour::texts) nomenukey = true; popScreenAll(); tour::start(); + if(!tour::on) tour::start(); }); }); @@ -250,7 +251,7 @@ int phooks = + addHook(dialog::hooks_display_dialog, 100, [] () { if(current_screen_cfunction() == showStartMenu) { dialog::addBreak(100); - dialog::addBigItem(XLAT("RogueViz demos"), 'p'); + dialog::addBigItem(XLAT("RogueViz demos"), 'd'); dialog::add_action([] () { pushScreen(choose_presentation); }); } }); diff --git a/rogueviz/snow.cpp b/rogueviz/snow.cpp index 35d6dc65..5471c028 100644 --- a/rogueviz/snow.cpp +++ b/rogueviz/snow.cpp @@ -40,11 +40,15 @@ bool snow_glitch = false; /* disable textures */ bool snow_texture = true; +/* draw single objects? */ +bool single_objects = true; + int snow_shape = 0; struct snowball { transmatrix T; int model_id; + int object_id; }; map> snowballs_at; @@ -134,14 +138,29 @@ bool draw_snow(cell *c, const shiftmatrix& V) { } } - for(int t=0; tcolor) queuepoly(V*T.T, obj->sh, obj->color); + } + } } else { auto& p = queuepoly(V * T.T, shapeid(snow_shape), snow_color);