mirror of
				https://github.com/zenorogue/hyperrogue.git
				synced 2025-10-31 05:52:59 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			606 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			606 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Banach-Tarski animation in RogueViz.
 | |
| // Copyright (C) 2011-2018 Zeno Rogue, see 'hyper.cpp' for details
 | |
| 
 | |
| // good parameters: -fixx 10 -W Cros -bantar_anim
 | |
| // use -bantar_map to see how it works
 | |
| 
 | |
| #include "rogueviz.h"
 | |
| 
 | |
| namespace rogueviz { namespace banachtarski {
 | |
| 
 | |
| bool on;
 | |
| 
 | |
| typedef vector<int> cwpath;
 | |
| 
 | |
| cwpath invertpath(cwpath p) {
 | |
|   cwpath res;
 | |
|   for(int i=0; i<isize(p); i++)
 | |
|     res.push_back(-p[isize(p)-1-i]);
 | |
|   return res;
 | |
|   }
 | |
| 
 | |
| array<cwpath, 4> gens;
 | |
| 
 | |
| cellwalker bttargets[4];
 | |
| 
 | |
| cellwalker trace(cellwalker cw, cwpath& p) {
 | |
|   for(int i: p) if(i == 0) cw += wstep; else cw += i;
 | |
|   return cw;
 | |
|   }
 | |
| 
 | |
| set<cell*> testlist;
 | |
| 
 | |
| map<cell*, cell*> parent;
 | |
| 
 | |
| bool test_uniq(cellwalker cw, int z, int lev, cell *par) {
 | |
|   if(testlist.count(cw.at)) return false;
 | |
|   testlist.insert(cw.at);
 | |
|   if(par) parent[cw.at] = par;
 | |
|   if(celldist(cw.at) > 9) return true;
 | |
| 
 | |
|   /* if(cw.at->wall == waSea) {
 | |
|     printf("test_uniq failed\n");
 | |
|     cw.at->wall = waEternalFire;
 | |
|     }
 | |
|   cw.at->wall = waSea; */
 | |
|   if(lev) for(int y=0; y<4; y++) if(y != z)
 | |
|     if(!test_uniq(trace(cw, gens[y]), y^2, lev-1, cw.at))
 | |
|       return false;
 | |
|   
 | |
|   return true;
 | |
|   }
 | |
| 
 | |
| template<class T> void recursively(cell *c, cell *c1, const T& t) {
 | |
|   t(c);
 | |
|   for(int i=0; i<c->type; i++) 
 | |
|     if(c->move(i) && c->c.spin(i) == 0 && c->move(i) != c1)
 | |
|       recursively(c->move(i), c, t);
 | |
|   }
 | |
| 
 | |
| vector<cell*> allcells;
 | |
| 
 | |
| set<cell*> seen;
 | |
| 
 | |
| struct cellinfo {
 | |
|   cell *c;
 | |
|   int gid;
 | |
|   int spdist;
 | |
|   eWall w;
 | |
|   eItem it;
 | |
|   eLand land;
 | |
|   eMonster mo;
 | |
|   vector<int> way;
 | |
|   cwpath pinv;
 | |
|   };
 | |
| 
 | |
| map<cell*, cellinfo> infos;
 | |
| 
 | |
| int cidd = 0;
 | |
| 
 | |
| int more = 5;
 | |
| 
 | |
| void debugpath(vector<int>& way, cwpath& pinv) {
 | |
|   printf("pinv:"); for(int i: pinv) printf(" %d", i); printf("\n");
 | |
| 
 | |
|   cellwalker cw = cwt;
 | |
|   
 | |
|   cellwalker last_cw = cw;
 | |
|   int lastd = 0;
 | |
| 
 | |
|   printf("way:"); for(int i: way) {
 | |
|     cellwalker cw2 = trace(cw, pinv);
 | |
|     printf(" [%d]", lastd = celldist(cw2.at));
 | |
|     printf(" %d", i);
 | |
|     last_cw = cw;
 | |
|     cw = trace(cw, gens[i]);
 | |
|     }
 | |
| 
 | |
|   cellwalker cw2 = trace(cw, pinv);
 | |
|   int curd;
 | |
|   printf(" [%d]", curd = celldist(cw2.at));
 | |
|   printf("\n"); 
 | |
| 
 | |
|   if(lastd == 10 && curd == 2) {
 | |
|     int b = way.back();
 | |
|     way.pop_back();
 | |
|     printf("CW:"); for(int w: way) for(int wp: gens[w]) printf(" %d", wp);
 | |
|     printf(" {");
 | |
|     for(int wp: gens[b]) printf(" %d", wp);
 | |
|     printf(" }");
 | |
|     for(int i: pinv) printf(" %d", i);
 | |
|     way.push_back(b);
 | |
|     printf("\n");
 | |
|     }
 | |
|   }
 | |
| 
 | |
| 
 | |
| void recursive_paint(cwpath& pinv, vector<int>& way, int noway) {
 | |
|   cellwalker cw = cwt;
 | |
|   for(int i: way) cw = trace(cw, gens[i]);
 | |
|   cw = trace(cw, pinv);
 | |
|   cell *c = cw.at;
 | |
| 
 | |
|   /* if(cidd == 1 && way == vector<int>{1,2,3})
 | |
|     c->item = itPirate; */
 | |
| 
 | |
|   if(seen.count(c)) { 
 | |
|     printf("seen error [%d]\n", celldist(c)); 
 | |
|     debugpath(way, pinv);
 | |
|     debugpath(infos[c].way, infos[c].pinv);
 | |
|     return; 
 | |
|     }
 | |
|   seen.insert(c);
 | |
| 
 | |
|   int hsh = 7;
 | |
|   for(int w: way) hsh = 11301 * hsh + w * 37121;
 | |
|   
 | |
|   bool all0 = true;
 | |
|   for(int w: way) if(w) all0 = false;
 | |
|   
 | |
|   int gid;
 | |
|   
 | |
|   /* if(d)
 | |
|     c->landparam = 0x202020;
 | |
|   else */
 | |
|   if(all0 || way[0] == 2)
 | |
|     gid = 0;
 | |
|   else if(way[0] == 0)
 | |
|     gid = 1;
 | |
|   else if(way[0] == 1)
 | |
|     gid = 2;
 | |
|   else if(way[0] == 3)
 | |
|     gid = 3;
 | |
|   else
 | |
|     gid = 3;
 | |
|   
 | |
|   infos[c] = cellinfo{c, gid, 0, waNone, itNone, laNone, moNone, way, pinv};
 | |
| 
 | |
|   // c->landparam ^= ((isize(way)&1) * 0x3F3F3F);
 | |
|   // c->landparam = hsh; // d * 5 + 256 * (hsh&0xFFFF) + 0x400000;
 | |
|   if(cidd>112899) c->landparam = 0x101010;
 | |
|   // c->landparam = cidd * 0x1241C3;
 | |
| 
 | |
|   if(celldist(c) <= 11+more) for(int i=0; i<4; i++) if(i != noway) {
 | |
|     vector<int> newway = {i};
 | |
|     for(int ii: way) newway.push_back(ii);
 | |
|     recursive_paint(pinv, newway, i^2);
 | |
|     }
 | |
|   }
 | |
| 
 | |
| bool once = true;
 | |
| 
 | |
| cwpath path_to(cell *c, int dir = 0) {
 | |
|   cwpath p;
 | |
|   cellwalker cw(c, dir);
 | |
|   while(cw != cwt) {
 | |
|     if(celldist((cw+wstep).at) < celldist(cw.at))
 | |
|       p.push_back(0), cw += wstep;
 | |
|     else {
 | |
|       if(p.size() && p.back()) p.back()++;
 | |
|       else p.push_back(1);
 | |
|       cw += 1;
 | |
|       }
 | |
|     }
 | |
|   return p;
 | |
|   }
 | |
| 
 | |
| void bantar_note(cell *c) {
 | |
|   if(seen.count(c)) return;
 | |
|   
 | |
|   cwpath pinv = invertpath(path_to(c));
 | |
|   
 | |
|   vector<int> way;
 | |
|   recursive_paint(pinv, way, 4);
 | |
|   cidd++;
 | |
|   }
 | |
| 
 | |
| using bantar_config = pair<cell*, cell*>;
 | |
| 
 | |
| tuple<ld,bool,ld> quality(bantar_config cp) {
 | |
|   shiftpoint h1 = tC0(ggmatrix(cp.first));
 | |
|   shiftpoint h2 = tC0(ggmatrix(cp.second));
 | |
|   return make_tuple(hdist0(h1) * hdist0(h2), h2[1] > 0, abs(h2[0] / h2[1]));
 | |
|   }
 | |
| 
 | |
| int notry = 0;
 | |
| 
 | |
| void bantar() {
 | |
|   if(!on) return;
 | |
|   cwt = cellwalker(currentmap->gamestart(), 0);
 | |
|   centerover = cwt.at;
 | |
|   infos.clear();
 | |
|   
 | |
|   vector<bantar_config> genchoices;
 | |
|   
 | |
|   int lnotry = notry;
 | |
|   
 | |
|   {
 | |
|   celllister clgen(cwt.at, 4, 1000000, NULL);
 | |
|   for(cell *c1: clgen.lst) if(c1->type == S7)
 | |
|   for(cell *c2: clgen.lst) if(c2->type == S7) 
 | |
|     genchoices.emplace_back(c1, c2);
 | |
|   stable_sort(genchoices.begin(), genchoices.end(), [] (const bantar_config b1, const bantar_config b2) { return quality(b1) < quality(b2); });
 | |
|   
 | |
|   for(bantar_config bc: genchoices) {
 | |
|       if(get<0>(quality(bc)) >= 4) exit(1);
 | |
|     for(int i=0; i<S7; i++)
 | |
|     for(int j=0; j<S7; j++) {
 | |
|       gens[0] = path_to(bc.first, i);
 | |
|       gens[1] = path_to(bc.second, j);
 | |
|       gens[2] = invertpath(gens[0]);
 | |
|       gens[3] = invertpath(gens[1]);
 | |
|       testlist.clear();
 | |
|       parent.clear();
 | |
|       bool tres = test_uniq(cwt, -1, 15, NULL);
 | |
|       auto q = quality(bc);
 | |
|       if(tres) {
 | |
|         DEBB(DF_LOG, ("gens = ", gens));
 | |
|         DEBB(DF_LOG, ("testing quality ", q, " ", make_pair(celldist(bc.first), celldist(bc.second)), ", result = ", tres));
 | |
|         lnotry--; if(lnotry <= 0) goto picked;
 | |
|         }
 | |
|       // if(tres) goto picked;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   picked:
 | |
| 
 | |
|   /*
 | |
|   if(S7 == 8) {
 | |
|     gens[1] = {0,4,0,4};
 | |
|     gens[0] = {2,0,2};
 | |
|     }
 | |
|   else {
 | |
|     gens[0] = {0,4,0,4};
 | |
|     gens[1] = {2,0,4,0,2};
 | |
|     }
 | |
|   gens[2] = invertpath(gens[0]);
 | |
|   gens[3] = invertpath(gens[1]);
 | |
|   */
 | |
|   
 | |
|   for(int i=0; i<4; i++) bttargets[i] = trace(cwt, gens[i]);
 | |
|   
 | |
|   celllister cl(cwt.at, 8+more, 1000000, NULL);
 | |
|   // recursively(cwt.at, NULL, [] (cell *c) { allcells.push_back(c); } );
 | |
|   for(cell* c: cl.lst) bantar_note(c);
 | |
|   
 | |
|   for(cell *c: cl.lst) if(infos.count(c) && infos[c].gid == 0) 
 | |
|     forCellEx(c2, c) if(infos.count(c2) && infos[c2].gid != 0)
 | |
|       c->bardir = NOBARRIERS;
 | |
|     
 | |
|   for(int it=0; it<ittypes; it++) if(itemclass(eItem(it)) == IC_TREASURE)
 | |
|     items[it] = 200;
 | |
|   }
 | |
| 
 | |
| vector<int> spdist;
 | |
| 
 | |
| int curpart;
 | |
| 
 | |
| /* bool hidebad(cell *c, const transmatrix& V) {
 | |
|   if(c->wparam != curpart && curpart < 4) return true;
 | |
|   return false;
 | |
|   } */
 | |
| 
 | |
| heptspin cth(cellwalker cw) {
 | |
|   return heptspin(cw.at->master, cw.spin, cw.mirrored);
 | |
|   }
 | |
| 
 | |
| ld alphaof(hyperpoint h) {
 | |
|   return atan2(h[1], h[0]);
 | |
|   }
 | |
| 
 | |
| #define ForInfos for(auto& cci: infos) 
 | |
| 
 | |
| void bantar_frame() {
 | |
|   
 | |
|   ForInfos
 | |
|     cci.second.w = cci.second.c->wall,
 | |
|     cci.second.it = cci.second.c->item,
 | |
|     cci.second.mo = cci.second.c->monst,
 | |
|     cci.second.land = cci.second.c->land,
 | |
|     cci.second.c->wparam = cci.second.gid;
 | |
| 
 | |
|   calcparam();
 | |
|   
 | |
|   vector<unique_ptr<drawqueueitem>> subscr[4];
 | |
|   
 | |
|   compute_graphical_distance();
 | |
| 
 | |
|   const int tmax = 2000;
 | |
|   int t = ticks % (5*tmax);
 | |
|   int tphase = t / tmax, tsub = t % tmax;
 | |
|   ld xdst, ydst;
 | |
| 
 | |
|   for(int i=0; i<4; i++) {
 | |
| 
 | |
|     ptds.clear();    
 | |
| 
 | |
|     cellwalker xcw;
 | |
|     ld part = 1;
 | |
|     if(i == 1) xcw = bttargets[0];
 | |
|     else if(i == 2) xcw = bttargets[1], part = .5;
 | |
|     else if(i == 3) xcw = bttargets[3], part = .5;
 | |
|     else xcw = cwt;
 | |
|     
 | |
|     View = Id;
 | |
|     
 | |
|     transmatrix tView = actualV(cth(xcw), Id) * calc_relative_matrix(cwt.at, xcw.at, C0) * inverse(actualV(cth(cwt), Id));
 | |
|     
 | |
|     if(tphase < 2) part = 0;
 | |
|     else if(tphase == 2)
 | |
|       part = part * tsub / tmax;
 | |
| 
 | |
|     transmatrix itView = inverse(tView);
 | |
|     transmatrix z = rspintox(itView*C0) * xpush(hdist0(itView*C0) * part) * spintox(itView*C0);
 | |
|     transmatrix ful = rspintox(itView*C0) * xpush(hdist0(itView*C0) * tmax / tmax) * spintox(itView*C0); // rgpushxto0(itView*C0);
 | |
|     hyperpoint C1 = xpush0(1);
 | |
|     ld bof = alphaof(tView * ful * C1);
 | |
|     z = z * spin(bof * part);
 | |
|     View = inverse(z);
 | |
|     
 | |
|     if(tphase == 0 && tsub > tmax/2) {
 | |
|       ld alpha = rand() % 10;
 | |
|       ld d = (rand() % 1000) / 20000. * (tsub-tmax/2) / (tmax/2);
 | |
|       View = spin(alpha) * xpush(d) * spin(-alpha);
 | |
|       }
 | |
|     
 | |
|     /* int phasemask = 3;
 | |
|     if(tphase == 0) phasemask = 0;
 | |
|     if(tphase == 4) phasemask = 2; */
 | |
| 
 | |
|     ForInfos if(cci.second.gid == i)
 | |
|       cci.second.c->wall = cci.second.w,
 | |
|       cci.second.c->item = cci.second.it,
 | |
|       cci.second.c->monst = cci.second.mo,
 | |
|       cci.second.c->land = cci.second.land;
 | |
|     else
 | |
|       cci.second.c->wall = waInvisibleFloor,
 | |
|       cci.second.c->item = itNone,
 | |
|       cci.second.c->monst = moNone,
 | |
|       cci.second.c->land = laNone;
 | |
|     
 | |
|     mapeditor::drawplayer = cwt.at->wparam == i;
 | |
|     
 | |
|     switch(tphase) {
 | |
|       case 0:
 | |
|         xdst = ydst = 0;
 | |
|         curpart = 4;
 | |
|         break;
 | |
|       case 1: 
 | |
|         xdst = ydst = .5 * tsub / tmax;
 | |
|         break;
 | |
|       case 2:
 | |
|         xdst = ydst = .5;
 | |
|         break;
 | |
|       case 3:
 | |
|         xdst = .5, ydst = .5 * (tmax-tsub) / tmax;
 | |
|         break;
 | |
|       case 4:
 | |
|         xdst = .5, ydst = 0;
 | |
|         break;
 | |
|       default:
 | |
|         xdst = ydst = 0;
 | |
|       }
 | |
|     
 | |
|     /* ld xpos = (!(i&2)) ? xdst : -xdst;
 | |
|     ld ypos = (!(i&1)) ? ydst : -ydst; */
 | |
|     
 | |
|     gmatrix.clear();
 | |
|     
 | |
|     drawthemap();
 | |
|     if(0) for(auto p: parent) if(gmatrix.count(p.first) && gmatrix.count(p.second) && infos[p.first].gid == i && infos[p.second].gid == i)
 | |
|       queueline(tC0(gmatrix[p.first]), tC0(gmatrix[p.second]), 0xFFFFFFFF, 2);
 | |
|     subscr[i] = std::move(ptds);
 | |
|     }
 | |
|   
 | |
|   map<int, map<int, vector<unique_ptr<drawqueueitem>>>> xptds;
 | |
|   for(int i=0; i<4; i++) for(auto& p: subscr[i])
 | |
|     xptds[int(p->prio)][i].push_back(std::move(p));
 | |
| 
 | |
|   for(auto& sm: xptds) for(auto& sm2: sm.second) {
 | |
|     int i = sm2.first;
 | |
|     ptds.clear();
 | |
|     for(auto& p: sm2.second) ptds.push_back(std::move(p));
 | |
| 
 | |
|     pconf.scale = .5;
 | |
|     pconf.xposition = (!(i&2)) ? xdst : -xdst;
 | |
|     pconf.yposition = (!(i&1)) ? ydst : -ydst;
 | |
|     calcparam();
 | |
|     drawqueue();
 | |
|     }
 | |
| 
 | |
|   ForInfos
 | |
|     cci.second.c->wall = cci.second.w,
 | |
|     cci.second.c->item = cci.second.it,
 | |
|     cci.second.c->monst = cci.second.mo,
 | |
|     cci.second.c->land = cci.second.land;
 | |
|   
 | |
|   ptds.clear();
 | |
|   }
 | |
| 
 | |
| void bantar_anim() {
 | |
| 
 | |
|   vid.aurastr = 0;
 | |
|   bool breakanim = false;
 | |
|   int t = SDL_GetTicks();
 | |
|   drawthemap();
 | |
|   while(!breakanim) {
 | |
|     ticks = SDL_GetTicks() - t;
 | |
|     
 | |
|     pushScreen(bantar_frame);
 | |
|     drawscreen();
 | |
|     popScreen();
 | |
|     
 | |
|     SDL_Event ev;
 | |
|     while(SDL_PollEvent(&ev)) 
 | |
|       if(ev.type == SDL_EVENT_KEY_DOWN || ev.type == SDL_EVENT_MOUSE_BUTTON_DOWN)
 | |
|         breakanim = true;      
 | |
|     }
 | |
|   mapeditor::drawplayer = true;
 | |
|   pconf.xposition = pconf.yposition = 0;
 | |
|   pconf.scale = 1;
 | |
|   }
 | |
| 
 | |
| bool bmap;
 | |
| 
 | |
| void bantar_stats() {
 | |
|   if(bmap) {
 | |
|     vid.linewidth *= (inHighQual ? 10 : 2);
 | |
|     for(auto p: parent) if(gmatrix.count(p.first) && gmatrix.count(p.second))
 | |
|       queueline(tC0(gmatrix[p.first]), tC0(gmatrix[p.second]), 0x00FF00FF, 4);
 | |
| 
 | |
|     double x = cgi.hexvdist;
 | |
|     for(auto gm: gmatrix) for(cell *c: {gm.first})
 | |
|     if(euclid || !pseudohept(c)) for(int t=0; t<c->type; t++) if(infos.count(c) && infos.count(c->move(t)) && c->move(t) && infos[c].gid != infos[c->move(t)].gid)
 | |
|       if(euclid ? c->move(t)<c : (((t^1)&1) || c->move(t) < c))
 | |
|         queueline(gm.second * ddspin(c,t,-M_PI/S6) * xpush(x) * C0, 
 | |
|           gm.second * ddspin(c,t,+M_PI/S6) * xpush(x) * C0, 
 | |
|           0xFF0000FF, 1);
 | |
|     vid.linewidth /= (inHighQual ? 10 : 2);
 | |
|     drawqueue();
 | |
|     }
 | |
|   }
 | |
| 
 | |
| void init_bantar() {
 | |
|   if(!on) {
 | |
|     stop_game();
 | |
|     on = true;
 | |
|     start_game();
 | |
|     }
 | |
|   }
 | |
| 
 | |
| void init_bantar_map() {
 | |
|   bmap = true;
 | |
|   ForInfos {
 | |
|     int hsh = 0x202047;
 | |
|     for(int w: cci.second.way) hsh = (11301 * hsh + w * 37121) & 0x7F7F7F;
 | |
|     cci.second.c->landparam = hsh;
 | |
|     cci.second.c->land = laCanvas;
 | |
|     cci.second.c->wall = waNone;
 | |
|     cci.second.c->item = itNone;
 | |
|     cci.second.c->monst = moNone;
 | |
|     }
 | |
|   }
 | |
|   
 | |
| // see: https://twitter.com/ZenoRogue/status/1001127253747658752
 | |
| // see also: https://twitter.com/ZenoRogue/status/1000043540985057280 (older version)
 | |
| 
 | |
| void bantar_record() {
 | |
|   int TSIZE = rug::texturesize; // recommended 2048
 | |
|   resetbuffer rb;
 | |
|   renderbuffer rbuf(TSIZE, TSIZE, true);
 | |
| 
 | |
|   int fr = 0;
 | |
|   
 | |
|   for(int i=0; i < 10000; i += 33) {
 | |
|     if(i % 1000 == 999) i++;
 | |
|     ticks = i;
 | |
| 
 | |
|     rbuf.enable();
 | |
|     vid.xres = vid.yres = TSIZE;
 | |
|     banachtarski::bantar_frame();
 | |
|     
 | |
|     IMAGESAVE(rbuf.render(), ("bantar/" + hr::format("%05d", fr) + IMAGEEXT).c_str());
 | |
|     printf("GL %5d/%5d\n", i, 10000);
 | |
|     fr++;
 | |
|     }
 | |
|   
 | |
|   rb.reset();
 | |
|   }
 | |
| 
 | |
| int readArgs() {
 | |
|   using namespace arg;
 | |
|            
 | |
|   if(0) ;
 | |
|   else if(argis("-bantar_anim")) {
 | |
|     PHASE(3);
 | |
|     init_bantar();
 | |
|     peace::on = true;
 | |
|     airmap.clear();
 | |
|     ForInfos if(cci.second.c->monst == moAirElemental)
 | |
|       cci.second.c->monst = moFireElemental;
 | |
|     bantar_anim();
 | |
|     }
 | |
|   else if(argis("-bantar_test")) {
 | |
|     PHASE(3);
 | |
|     init_bantar();
 | |
|     peace::on = true;
 | |
|     airmap.clear();
 | |
|     ForInfos if(cci.second.c->monst == moAirElemental)
 | |
|       cci.second.c->monst = moFireElemental;
 | |
|     ForInfos if(cci.second.gid != 2)
 | |
|       cci.second.c->wall = waInvisibleFloor,
 | |
|       cci.second.c->item = itNone,
 | |
|       cci.second.c->monst = moNone,
 | |
|       cci.second.c->land = laNone;
 | |
|     airmap.clear();
 | |
|     havewhat = 0;
 | |
|     }
 | |
|   else if(argis("-bantar_map")) {
 | |
|     init_bantar();
 | |
|     init_bantar_map();
 | |
|     }
 | |
|   else if(argis("-btry")) {
 | |
|     shift(); notry = argi();
 | |
|     }
 | |
|   else if(argis("-bantar_record")) {
 | |
|     using namespace banachtarski;
 | |
|     PHASE(3);
 | |
|     peace::on = true;
 | |
|     airmap.clear();
 | |
|     ForInfos if(cci.second.c->monst == moAirElemental)
 | |
|       cci.second.c->monst = moFireElemental;
 | |
|     bantar_record();
 | |
|     }
 | |
|   else return 1;
 | |
|   return 0;
 | |
|   }
 | |
| 
 | |
| auto hook = addHook(hooks_args, 100, readArgs)
 | |
|   + addHook(hooks_initgame, 100, bantar)
 | |
|   + addHook(hooks_frame, 100, bantar_stats)
 | |
|   + addHook_rvslides(140, [] (string s, vector<tour::slide>& v) {
 | |
|     if(s != "mixed") return;
 | |
|     using namespace pres;
 | |
|     v.push_back(
 | |
|       tour::slide{"Banach-Tarski-like", 62, LEGAL::NONE,
 | |
|      "Banach-Tarski-like decomposition. Break a hyperbolic plane into two hyperbolic planes.\n\n"
 | |
|      "Press '5' to show the decomposition. Press any key to stop.\n\n"
 | |
|      "You will see a map of the decomposition. Press '5' again to return.",
 | |
|      
 | |
|     [] (presmode mode) {
 | |
|       slidecommand = "Banach-Tarski switch";
 | |
|       slide_url(mode, 't', "Twitter link", "https://twitter.com/ZenoRogue/status/1001127253747658752");
 | |
| 
 | |
|       if(mode == 3) {
 | |
|         while(gamestack::pushed()) stop_game(), gamestack::pop();
 | |
|         banachtarski::bmap = false;
 | |
|         banachtarski::on = false;
 | |
|         }
 | |
|       if(mode == 4) {
 | |
|         if(!banachtarski::on) {
 | |
|           bool b = mapeditor::drawplayer;
 | |
|           specialland = cwt.at->land;
 | |
|           gamestack::push();
 | |
|           banachtarski::init_bantar();
 | |
|           airmap.clear();
 | |
|           dynamicval<int> vs(sightrange_bonus, 3);
 | |
|           dynamicval<int> vg(genrange_bonus, 3);
 | |
|           doOvergenerate();
 | |
|           banachtarski::bantar_anim();
 | |
|           quitmainloop = false;
 | |
|           mapeditor::drawplayer = b;
 | |
|           banachtarski::init_bantar_map();
 | |
|           resetview();
 | |
|           }
 | |
|         else if(banachtarski::on && banachtarski::bmap) {
 | |
|           banachtarski::bmap = false;
 | |
|           banachtarski::on = false;
 | |
|           gamestack::pop();
 | |
|           }
 | |
|         }
 | |
|       }}
 | |
|       );
 | |
|     });
 | |
| 
 | |
| }}
 | 
