diff --git a/bigstuff.cpp b/bigstuff.cpp index 8ee12dc3..cbc64ca6 100644 --- a/bigstuff.cpp +++ b/bigstuff.cpp @@ -30,7 +30,7 @@ int getAnthraxData(cell *c, bool b) { } int roundTableRadius(cell *c) { - if(euclid) return 28; + if(eubinary) return 28; if(tactic::on) return getAnthraxData(c, true); return c->master->alt->alt->emeraldval & GRAIL_RADIUS_MASK; } @@ -74,7 +74,7 @@ const int NOCOMPASS = 1000000; int compassDist(cell *c) { if(sphere || quotient) return 0; - if(euclid || c->master->alt) return celldistAlt(c); + if(eubinary || c->master->alt) return celldistAlt(c); if(isHaunted(c->land) || c->land == laGraveyard) return getHauntedDepth(c); return NOCOMPASS; } @@ -84,7 +84,7 @@ cell *findcompass(cell *c) { if(d == NOCOMPASS) return NULL; while(inscreenrange(c)) { - if(!euclid && !sphere && !quotient) + if(!eubinary && !sphere && !quotient) generateAlts(c->master); forCellEx(c2, c) if(compassDist(c2) < d) { c = c2; @@ -99,7 +99,7 @@ cell *findcompass(cell *c) { } bool grailWasFound(cell *c) { - if(euclid || quotient || sphere) return items[itHolyGrail]; + if(eubinary || quotient || sphere) return items[itHolyGrail]; return c->master->alt->alt->emeraldval & GRAIL_FOUND; } @@ -249,7 +249,7 @@ void beCIsland(cell *c) { } void generateTreasureIsland(cell *c) { - if(!euclid) generateAlts(c->master); + if(!eubinary) generateAlts(c->master); if(isOnCIsland(c)) return; bool src = hrand(100) < 10; @@ -261,21 +261,21 @@ void generateTreasureIsland(cell *c) { int qc = 0, qlo, qhi; for(int i=0; itype; i++) { cell *c2 = createMov(c, i); - if(!euclid) generateAlts(c2->master); - if((euclid || (c->master->alt && c2->master->alt)) && celldistAlt(c2) < celldistAlt(c)) { + if(!eubinary) generateAlts(c2->master); + if((eubinary || (c->master->alt && c2->master->alt)) && celldistAlt(c2) < celldistAlt(c)) { ctab[qc++] = c2; qlo = i; qhi = i; while(true && qc < MAX_EDGE) { qlo--; c2 = createMovR(c, qlo); - if(!euclid && !c2->master->alt) break; + if(!eubinary && !c2->master->alt) break; if(celldistAlt(c2) >= celldistAlt(c)) break; ctab[qc++] = c2; } while(true && qc < MAX_EDGE) { qhi++; c2 = createMovR(c, qhi); - if(!euclid && !c2->master->alt) break; + if(!eubinary && !c2->master->alt) break; if(celldistAlt(c2) >= celldistAlt(c)) break; ctab[qc++] = c2; } @@ -295,7 +295,7 @@ void generateTreasureIsland(cell *c) { if(c->wall != waCTree && hrand(100) < 15) c->wall = (c->wall == waCIsland ? waCIsland2 : waCIsland); } - if(src && c2->wall == waCTree && (euclid||c->master->alt) && celldistAlt(c) <= -10) { + if(src && c2->wall == waCTree && (eubinary||c->master->alt) && celldistAlt(c) <= -10) { bool end = true; for(int i=0; iland), c->land); */ } - if((!chaosmode) && bearsCamelot(c->land) && is_master(c) && + if((!chaosmode) && bearsCamelot(c->land) && is_master(c) && !binarytiling && (quickfind(laCamelot) || peace::on || (hrand(I2000) < 200 && horo_ok() && items[itEmerald] >= U5 && !tactic::on))) { int rtr = newRoundTableRadius(); @@ -1177,7 +1176,7 @@ void buildCamelotWall(cell *c) { c->wall = waCamelot; for(int i=0; itype; i++) { cell *c2 = createMov(c, i); - if(c2->wall == waNone && (euclid || (c2->master->alt && c->master->alt)) && celldistAlt(c2) > celldistAlt(c) && c2->monst == moNone) + if(c2->wall == waNone && (eubinary || (c2->master->alt && c->master->alt)) && celldistAlt(c2) > celldistAlt(c) && c2->monst == moNone) c2->wall = waCamelotMoat; } } @@ -1185,14 +1184,14 @@ void buildCamelotWall(cell *c) { void moreBigStuff(cell *c) { if(quotient) return; - - if(c->land == laPalace && !euclid && c->master->alt) { + + if(c->land == laPalace && !eubinary && c->master->alt) { int d = celldistAlt(c); if(d <= PRADIUS1) generateAlts(c->master); } if(c->land == laStorms) - if(!euclid && !quotient && !sphere) { + if(!eubinary && !quotient && !sphere) { if(c->master->alt && c->master->alt->distance <= 2) { generateAlts(c->master); preventbarriers(c); @@ -1210,15 +1209,15 @@ void moreBigStuff(cell *c) { } if((bearsCamelot(c->land) && !euclid && !quotient) || c->land == laCamelot) - if(euclid || c->master->alt) { + if(eubinary || binarytiling || c->master->alt) if(!(binarytiling && specialland != laCamelot)) { int d = celldistAltRelative(c); if(tactic::on || (d <= 14 && roundTableRadius(c) > 20)) { - if(!euclid) generateAlts(c->master); + if(!eubinary) generateAlts(c->master); preventbarriers(c); if(d == 10) { if(weirdhyperbolic ? hrand(100) < 50 : pseudohept(c)) buildCamelotWall(c); else { - if(!euclid) for(int i=0; imaster->move[i]); + if(!eubinary) for(int i=0; imaster->move[i]); int q = 0; if(weirdhyperbolic) { for(int t=0; ttype; t++) createMov(c, t); @@ -1261,7 +1260,7 @@ void moreBigStuff(cell *c) { // roughly as many knights as table cells if(hrand(nonbitrunc ? 2618 : 1720) < 1000) c->monst = moKnight; - if(!euclid) for(int i=0; imaster->move[i]); + if(!eubinary) for(int i=0; imaster->move[i]); for(int i=0; itype; i++) if(c->mov[i] && celldistAltRelative(c->mov[i]) < d) c->mondir = (i+3) % 6; @@ -1271,7 +1270,7 @@ void moreBigStuff(cell *c) { if(d == 5 && tactic::on) c->item = itGreenStone; if(d <= 10) c->land = laCamelot; - if(d > 10 && !euclid && !tactic::on) { + if(d > 10 && !eubinary && !tactic::on) { setland(c, eLand(c->master->alt->alt->fiftyval)); if(c->land == laNone) printf("Camelot\n"); // NONEDEBUG } @@ -1284,9 +1283,9 @@ void moreBigStuff(cell *c) { c->wall = waColumn; } - else if((c->land == laRlyeh && !euclid) || c->land == laTemple) { - if(euclid || (c->master->alt && (tactic::on || c->master->alt->distance <= 2))) { - if(!euclid && !chaosmode) generateAlts(c->master); + else if((c->land == laRlyeh && !euclid) || c->land == laTemple) if(!(binarytiling && specialland != laTemple)) { + if(eubinary || (c->master->alt && (tactic::on || c->master->alt->distance <= 2))) { + if(!eubinary && !chaosmode) generateAlts(c->master); preventbarriers(c); int d = celldistAlt(c); if(d <= 0) { @@ -1299,7 +1298,7 @@ void moreBigStuff(cell *c) { else if(pseudohept(c)) c->wall = waColumn; else { - if(!euclid) for(int i=0; imaster->move[i]); + if(!eubinary) for(int i=0; imaster->move[i]); int q = 0; for(int t=0; ttype; t++) { createMov(c, t); @@ -1311,22 +1310,22 @@ void moreBigStuff(cell *c) { } } - if((c->land == laOvergrown && !euclid) || c->land == laClearing) { - if(euclid || (c->master->alt && (tactic::on || c->master->alt->distance <= 2))) { - if(!euclid) generateAlts(c->master); + if((c->land == laOvergrown && !euclid) || c->land == laClearing) if(!(binarytiling && specialland != laClearing)) { + if(eubinary || (c->master->alt && (tactic::on || c->master->alt->distance <= 2))) { + if(!eubinary) generateAlts(c->master); preventbarriers(c); int d = celldistAlt(c); if(d <= 0) { c->land = laClearing, c->wall = waNone; // , c->monst = moNone, c->item = itNone; } - else if(d == 1 && !tactic::on && !euclid) + else if(d == 1 && !tactic::on && !eubinary) c->wall = waSmallTree, c->monst = moNone, c->item = itNone; } } - if((c->land == laJungle && !euclid) || c->land == laMountain) { - if(euclid || (c->master->alt && (tactic::on || c->master->alt->distance <= 2))) { - if(!euclid) generateAlts(c->master); + if((c->land == laJungle && !euclid) || c->land == laMountain) if(!(binarytiling && specialland != laMountain)) { + if(eubinary || (c->master->alt && (tactic::on || c->master->alt->distance <= 2))) { + if(!eubinary) generateAlts(c->master); preventbarriers(c); int d = celldistAlt(c); if(d <= 0 || (firstland == laMountain && tactic::on)) { @@ -1335,14 +1334,14 @@ void moreBigStuff(cell *c) { } } - if(c->land == laOcean || c->land == laWhirlpool) { + if(c->land == laOcean || c->land == laWhirlpool) if(!(binarytiling && specialland != laWhirlpool)) { bool fullwhirlpool = false; if(tactic::on && specialland == laWhirlpool) fullwhirlpool = true; if(yendor::on && yendor::clev().l == laWhirlpool) fullwhirlpool = true; - if(euclid || (c->master->alt && (fullwhirlpool || c->master->alt->distance <= 2))) { - if(!euclid) generateAlts(c->master); + if(eubinary || (c->master->alt && (fullwhirlpool || c->master->alt->distance <= 2))) { + if(!eubinary) generateAlts(c->master); preventbarriers(c); int dd = celldistAlt(c); if(dd <= 0 || fullwhirlpool) { diff --git a/binary-tiling.cpp b/binary-tiling.cpp new file mode 100644 index 00000000..522c05ad --- /dev/null +++ b/binary-tiling.cpp @@ -0,0 +1,207 @@ + +namespace hr { + +namespace binary { + + enum bindir { + bd_right = 0, + bd_up_right = 1, + bd_up = 2, + bd_up_left = 3, + bd_left = 4, + bd_down = 5, /* for cells of degree 6 */ + bd_down_left = 5, /* for cells of degree 7 */ + bd_down_right = 6 /* for cells of degree 7 */ + }; + + int typeof(heptagon *h) { + return h->c7->type; + } + + // 0 - central, -1 - left, +1 - right + int mapside(heptagon *h) { + return h->zebraval; + } + + #if DEBUG_BINARY_TILING + map xcode; + map rxcode; + + long long expected_xcode(heptagon *h, int d) { + auto r =xcode[h]; + if(d == 0) return r + 1; + if(d == 1) return 2*r + 1; + if(d == 2) return 2*r; + if(d == 3) return 2*r - 1; + if(d == 4) return r-1; + if(d == 5 && typeof(h) == 6) return r / 2; + if(d == 5 && typeof(h) == 7) return (r-1) / 2; + if(d == 6 && typeof(h) == 7) return (r+1) / 2; + breakhere(); + } + #endif + + void breakhere() { + exit(1); + } + + heptagon *path(heptagon *h, int d, int d1, std::initializer_list p) { + static int rec = 0; + rec++; if(rec>100) exit(1); + // printf("{generating path from %p (%d/%d) dir %d:", h, typeof(h), mapside(h), d); + heptagon *h1 = h; + for(int d0: p) { + // printf(" [%d]", d0); + h1 = hr::createStep(h1, d0); + // printf(" %p", h1); + } + + #if DEBUG_BINARY_TILING + if(xcode[h1] != expected_xcode(h, d)) { + printf("expected_xcode mismatch\n"); + breakhere(); + } + #endif + // printf("}\n"); + if(h->move[d] && h->move[d] != h1) { + printf("already connected to something else (1)\n"); + breakhere(); + } + if(h1->move[d1] && h1->move[d1] != h) { + printf("already connected to something else (2)\n"); + breakhere(); + } + connectHeptagons(h, d, h1, d1); + rec--; + return h1; + } + + heptagon *build(heptagon *parent, int d, int d1, int t, int side, int delta) { + auto h = buildHeptagon(parent, d, hsOrigin, d1); + h->distance = parent->distance + delta; + h->c7 = newCell(t, h); + h->cdata = NULL; + h->zebraval = side; + #if DEBUG_BINARY_TILING + xcode[h] = expected_xcode(parent, d); + if(rxcode.count(xcode[h])) { + printf("xcode clash\n"); + breakhere(); + } + rxcode[xcode[h]] = h; + #endif + return h; + } + + heptagon *createStep(heptagon *parent, int d) { + auto h = parent; + switch(d) { + case bd_right: { + if(mapside(h) > 0 && typeof(h) == 7) + return path(h, d, bd_left, {bd_left, bd_down, bd_right, bd_up}); + else if(mapside(h) >= 0) + return build(parent, bd_right, bd_left, typeof(parent) ^ 1, 1, 0); + else if(typeof(h) == 6) + return path(h, d, bd_left, {bd_down, bd_right, bd_up, bd_left}); + else + return path(h, d, bd_left, {bd_down_right, bd_up}); + } + case bd_left: { + if(mapside(h) < 0 && typeof(h) == 7) + return path(h, d, bd_right, {bd_right, bd_down, bd_left, bd_up}); + else if(mapside(h) <= 0) + return build(parent, bd_left, bd_right, typeof(parent) ^ 1, -1, 0); + else if(typeof(h) == 6) + return path(h, d, bd_right, {bd_down, bd_left, bd_up, bd_right}); + else + return path(h, d, bd_right, {bd_down_left, bd_up}); + } + case bd_up_right: { + return path(h, d, bd_down_left, {bd_up, bd_right}); + } + case bd_up_left: { + return path(h, d, bd_down_right, {bd_up, bd_left}); + } + case bd_up: + return build(parent, bd_up, bd_down, 6, mapside(parent), 1); + default: + /* bd_down */ + if(typeof(h) == 6) { + if(mapside(h) == 0) + return build(parent, bd_down, bd_up, 6, 0, -1); + else if(mapside(h) == 1) + return path(h, d, bd_up, {bd_left, bd_left, bd_down, bd_right}); + else if(mapside(h) == -1) + return path(h, d, bd_up, {bd_right, bd_right, bd_down, bd_left}); + } + /* bd_down_left */ + else if(d == bd_down_left) { + return path(h, d, bd_up_right, {bd_left, bd_down}); + } + else if(d == bd_down_right) { + return path(h, d, bd_up_left, {bd_right, bd_down}); + } + } + printf("error: case not handled in binary tiling\n"); + breakhere(); + return NULL; + } + + transmatrix parabolic(ld u) { + u = u / log(2); + return transmatrix {{{-u*u/8+1, u/2, u*u/8}, {-u/2, 1, u/2}, {-u*u/8, u/2, u*u/8+1}}}; + } + + void draw_rec(cell *c, int dirs, const transmatrix& V) { + if(!dodrawcell(c)) return; + drawcell(c, V, 0, false); + // 1: up + if(dirs & 1) + draw_rec(createMov(c, bd_up), 7, V * xpush(-log(2))); + // right + if(dirs & 2) + draw_rec(createMov(c, bd_right), 2, V * parabolic(1)); + // left + if(dirs & 4) + draw_rec(createMov(c, bd_left), 4, V * parabolic(-1)); + // down + if((dirs & 8) && c->type == 6) + draw_rec(createMov(c, bd_down), dirs & 62, V * xpush(log(2))); + // down_left + if((dirs & 16) && c->type == 7) + draw_rec(createMov(c, bd_down_left), dirs & 28, V * parabolic(-1) * xpush(log(2))); + // down_right + if((dirs & 32) && c->type == 7) + draw_rec(createMov(c, bd_down_right), dirs & 42, V * parabolic(1) * xpush(log(2))); + } + + void draw() { + draw_rec(viewctr.h->c7, 63, cview()); + } + + transmatrix relative_matrix(heptagon *h2, heptagon *h1) { + if(gmatrix0.count(h2->c7) && gmatrix0.count(h1->c7)) + return inverse(gmatrix0[h1->c7]) * gmatrix0[h2->c7]; + transmatrix gm = Id, where = Id; + while(h1 != h2) { + if(h1->distance <= h2->distance) { + if(typeof(h2) == 6) + h2 = hr::createStep(h2, bd_down), where = xpush(log(2)) * where; + else if(mapside(h2) == 1) + h2 = hr::createStep(h2, bd_left), where = parabolic(-1) * where; + else if(mapside(h2) == -1) + h2 = hr::createStep(h2, bd_right), where = parabolic(1) * where; + } + else { + if(typeof(h1) == 6) + h1 = hr::createStep(h1, bd_down), gm = gm * xpush(-log(2)); + else if(mapside(h1) == 1) + h1 = hr::createStep(h1, bd_left), gm = gm * parabolic(1); + else if(mapside(h1) == -1) + h1 = hr::createStep(h1, bd_right), gm = gm * parabolic(-1); + } + } + return gm * where; + } + } +} diff --git a/cell.cpp b/cell.cpp index f1a46ebd..c73a737d 100644 --- a/cell.cpp +++ b/cell.cpp @@ -73,7 +73,17 @@ hrmap_hyperbolic::hrmap_hyperbolic() { h.alt = NULL; h.distance = 0; isnonbitrunc = nonbitrunc; - if(irr::on) + if(binarytiling) { + #if DEBUG_BINARY_TILING + binary::xcode.clear(); + binary::rxcode.clear(); + binary::xcode[&h] = (1 << 16); + binary::rxcode[1<<16] = &h; + #endif + h.zebraval = 0, + h.c7 = newCell(6, origin); + } + else if(irr::on) irr::link_start(origin); else h.c7 = newCell(S7, origin); @@ -972,7 +982,7 @@ void clearHexes(heptagon *at) { at->cdata = NULL; } if(irr::on) irr::clear_links(at); - else if(at->c7) subcell(at->c7, clearcell); + else if(at->c7 && !binarytiling) subcell(at->c7, clearcell); } void unlink_cdata(heptagon *h) { @@ -1003,7 +1013,9 @@ void clearfrom(heptagon *at) { at->cdata = NULL; } } - for(int i=0; imove[i]) { + int edges = S7; + if(binarytiling) edges = at->c7->type; + for(int i=0; imove[i]) { if(at->move[i]->alt != &deletion_marker) q.push(at->move[i]); unlink_cdata(at->move[i]); @@ -1109,6 +1121,7 @@ int celldistAlt(cell *c) { tie(x,y) = vec_to_pair(decodeId(c->master)); return euclidAlt(x, y); } + if(binarytiling) return celldist(c) + (specialland == laCamelot && !tactic::on? 30 : 0); if(sphere || quotient) { return celldist(c) - 3; } @@ -1458,8 +1471,8 @@ int heptdistance(heptagon *h1, heptagon *h2) { if(h1 == h2) return d; for(int i=0; imove[i] == h2) return d + 1; int d1 = h1->distance, d2 = h2->distance; - if(d1 >= d2) d++, h1 = h1->move[0]; - if(d2 > d1) d++, h2 = h2->move[0]; + if(d1 >= d2) d++, h1 = createStep(h1, binarytiling ? 5 : 0); + if(d2 > d1) d++, h2 = createStep(h2, binarytiling ? 5 : 0); } } diff --git a/classes.cpp b/classes.cpp index 9b892823..8f61b3a5 100644 --- a/classes.cpp +++ b/classes.cpp @@ -1680,6 +1680,7 @@ geometryinfo ginf[gGUARD] = { {"Bolza Surface", "Bolza", 8, 3, qSMALL | qDOCKS, gcHyperbolic, 0x18200, {{6, 4}}}, {"Bolza Surface x2", "Bolza2", 8, 3, qSMALL | qDOCKS, gcHyperbolic, 0x18400, {{6, 4}}}, {"minimal quotient", "minimal", 7, 3, qSMALL | qNONOR, gcHyperbolic, 0x18600, {{7, 5}}}, + {"binary tiling", "binary", 7, 3, 0, gcHyperbolic, 0, {{7, 5}}} }; } diff --git a/classes.h b/classes.h index fd18a569..bfb7d77e 100644 --- a/classes.h +++ b/classes.h @@ -198,7 +198,7 @@ enum eLand { laNone, laBarrier, laCrossroads, laDesert, laIce, laCaves, laJungle enum eGeometry { gNormal, gEuclid, gSphere, gElliptic, gZebraQuotient, gFieldQuotient, gTorus, gOctagon, g45, g46, g47, gSmallSphere, gTinySphere, gEuclidSquare, gSmallElliptic, - gKleinQuartic, gBolza, gBolza2, gMinimal, + gKleinQuartic, gBolza, gBolza2, gMinimal, gBinaryTiling, gGUARD}; enum eGeometryClass { gcHyperbolic, gcEuclid, gcSphere }; diff --git a/compileunits.h b/compileunits.h index 69fb2b5d..8d0a8237 100644 --- a/compileunits.h +++ b/compileunits.h @@ -29,6 +29,7 @@ #include "patterns.cpp" #include "fieldpattern.cpp" #include "heptagon.cpp" +#include "binary-tiling.cpp" #include "language.cpp" #include "cell.cpp" #include "goldberg.cpp" diff --git a/complex.cpp b/complex.cpp index a2dc7b58..fd2f4441 100644 --- a/complex.cpp +++ b/complex.cpp @@ -926,7 +926,7 @@ namespace whirlpool { // next == -1 -> prev cell *get(cell *c, int next) { int i = 0; - if(!euclid && !c->master->alt) return NULL; + if(!eubinary && !c->master->alt) return NULL; int d = celldistAlt(c); int d2; while(true) { @@ -949,7 +949,7 @@ namespace whirlpool { cell *at = whirlline[isize(whirlline)-1]; cell *prev = whirlline[isize(whirlline)-2]; for(int i=0; itype; i++) - if(at->mov[i] && (euclid || at->mov[i]->master->alt) && celldistAlt(at->mov[i]) == d && at->mov[i] != prev) { + if(at->mov[i] && (eubinary || at->mov[i]->master->alt) && celldistAlt(at->mov[i]) == d && at->mov[i] != prev) { if(at->mov[i] == whirlline[0]) return; // loops in weird geometries? if(at->mov[i] == whirlline[isize(whirlline)/2]) return; // even weirder geometry? whirlline.push_back(at->mov[i]); @@ -968,7 +968,7 @@ namespace whirlpool { else if(hrand(5000) < 500) wto->wall = waBoat; - if(wto->wall == waBoat && (euclid || wto->master->alt)) { + if(wto->wall == waBoat && (eubinary || wto->master->alt)) { int d = celldistAlt(wto); if(yendor::on) d -= 200; // 250 : hard @@ -1016,7 +1016,7 @@ namespace whirlpool { void moveAt(cell *c, manual_celllister& cl) { if(c->land != laWhirlpool) return; if(cl.listed(c)) return; - if(!(euclid || c->master->alt)) return; + if(!(eubinary || c->master->alt)) return; cell *c2 = get(c, 1); if(!c2) return; int d = celldistAlt(c); diff --git a/floorshapes.cpp b/floorshapes.cpp index c77f55a9..0a14c9da 100644 --- a/floorshapes.cpp +++ b/floorshapes.cpp @@ -199,8 +199,63 @@ void bshape2(hpcshape& sh, int p, int shapeid, matrixlist& m) { hpcpush(hpc[last->s]); } +hyperpoint get_horopoint(ld y, ld x) { + return xpush(-y) * binary::parabolic(x) * C0; + } + +void horopoint(ld y, ld x) { + hpcpush(get_horopoint(y, x)); + } + +void horopoint(ld y, ld x, cell &fc, int c) { + hpcpush(iddspin(&fc, c) * get_horopoint(y, x)); + } + +void horoline(ld y, ld x1, ld x2) { + for(int a=0; a<=16; a++) + horopoint(y, x1 + (x2-x1) * a / 16.); + } + +void horoline(ld y, ld x1, ld x2, cell &fc, int c) { + for(int a=0; a<=16; a++) + horopoint(y, x1 + (x2-x1) * a / 16., fc, c); + } void bshape_regular(floorshape &fsh, int id, int sides, int shift, ld size) { + + if(binarytiling) { + bshape(fsh.b[id], fsh.prio); + + ld yx = size * log(2) / 2; + ld yy = yx; + ld xx = size / sqrt(2)/2; + horoline(-yx, -xx, xx); horoline(yx, xx*2, -xx*2); horopoint(-yx, -xx); + + bshape(fsh.shadow[id], fsh.prio); + horoline(-yx*SHADMUL, -xx*SHADMUL, xx*SHADMUL); horoline(yx*SHADMUL, xx*SHADMUL*2, -xx*SHADMUL*2); horopoint(-yx*SHADMUL, -xx*SHADMUL); + + cell fc; + fc.type = 6+id; + + for(int k=0; k &shv, i } else if(geosupport_threecolor() == 2) queuepolyat(V, shv[pseudohept(c)], col, prio); + else if(binarytiling) + queuepolyat(V, shv[c->type-6], col, prio); else queuepolyat(V, shv[ctof(c)], col, prio); } diff --git a/game.cpp b/game.cpp index f80a1d94..dfa683f6 100644 --- a/game.cpp +++ b/game.cpp @@ -413,7 +413,7 @@ bool thruVine(cell *c, cell *c2) { bool againstCurrent(cell *w, cell *from) { if(from->land != laWhirlpool) return false; if(againstWind(from, w)) return false; // wind is stronger than current - if(!euclid && (!from->master->alt || !w->master->alt)) return false; + if(!eubinary && (!from->master->alt || !w->master->alt)) return false; int dfrom = celldistAlt(from); int dw = celldistAlt(w); if(dw < dfrom) return false; @@ -2176,7 +2176,7 @@ void killMonster(cell *c, eMonster who, flagtype deathflags) { c->item = itOrbWater; if(m == moPirate && isOnCIsland(c) && c->item == itNone && ( - euclid || + eubinary || (c->master->alt && celldistAlt(c) <= 2-getDistLimit()) || isHaunted(c->land))) { bool toomany = false; @@ -6740,7 +6740,7 @@ bool collectItem(cell *c2, bool telekinesis) { items[itOrbSpeed] += v; items[itHolyGrail]++; addMessage(XLAT("Congratulations! You have found the Holy Grail!")); - if(!euclid) c2->master->alt->emeraldval |= GRAIL_FOUND; + if(!eubinary) c2->master->alt->emeraldval |= GRAIL_FOUND; achievement_collection(c2->item, pg, gold()); } else if(c2->item == itKey) { diff --git a/geom-exp.cpp b/geom-exp.cpp index 59f603b4..e437c902 100644 --- a/geom-exp.cpp +++ b/geom-exp.cpp @@ -285,9 +285,11 @@ void showEuclideanMenu() { dialog::addBreak(50); if(ts == 6 && tv == 3) - dialog::addSelItem(XLAT("variations"), XLAT("does not matter"), 't'); + dialog::addSelItem(XLAT("variations"), XLAT("does not matter"), 'v'); + else if(binarytiling) + dialog::addSelItem(XLAT("variations"), XLAT("not implemented"), 'v'); else { - dialog::addBoolItem(XLAT("variations"), nonbitrunc, 't'); + dialog::addBoolItem(XLAT("variations"), nonbitrunc, 'v'); dialog::lastItem().value = gp::operation_name(); } @@ -389,8 +391,8 @@ void showEuclideanMenu() { } else if(uni == 'u') showquotients = !showquotients; - else if(uni == 't') { - if(euclid6) ; + else if(uni == 'v') { + if(euclid6 || binarytiling) ; else // if(S3 == 3) gp::configure(); /* else { diff --git a/graph.cpp b/graph.cpp index ca5954e5..5d914509 100644 --- a/graph.cpp +++ b/graph.cpp @@ -162,6 +162,7 @@ int ctof(cell *c) { if(nonbitrunc && !gp::on) return 1; // if(euclid) return 0; if(!c) return 1; + if(binarytiling) return c->type == 7; return ishept(c) ? 1 : 0; // c->type == 6 ? 0 : 1; } @@ -241,6 +242,12 @@ int displaydir(cell *c, int d) { auto& p = vs.jpoints[vs.neid[d]]; return -int(atan2(p[1], p[0]) * S84 / 2 / M_PI + MODFIXER + .5); } + else if(binarytiling) { + if(d == NODIR) return 0; + if(d == c->type-1) d++; + int dirs[8] = {0, 11, 21, 31, 42, 53, 63, 73}; + return -21-dirs[d]; + } else if(euclid) return - d * S84 / c->type; else @@ -248,6 +255,7 @@ int displaydir(cell *c, int d) { } double hexshiftat(cell *c) { + if(binarytiling) return 0; if(ctof(c) && S7==6 && S3 == 4 && !nonbitrunc) return hexshift + 2*M_PI/S7; if(ctof(c) && (S7==8 || S7 == 4) && S3 == 3 && !nonbitrunc) return hexshift + 2*M_PI/S7; if(hexshift && ctof(c)) return hexshift; @@ -2642,7 +2650,7 @@ void setcolors(cell *c, int& wcol, int &fcol) { else if(c->land == laAlchemist) fcol = 0x900090; else if(c->land == laWhirlpool) - fcol = 0x0000C0 + int(32 * sin(ticks / 200. + ((euclid||c->master->alt) ? celldistAlt(c) : 0)*1.5)); + fcol = 0x0000C0 + int(32 * sin(ticks / 200. + ((eubinary||c->master->alt) ? celldistAlt(c) : 0)*1.5)); else if(c->land == laLivefjord) fcol = 0x000080; else if(isWarped(c->land)) @@ -2788,7 +2796,7 @@ void setcolors(cell *c, int& wcol, int &fcol) { else if(c->wall == waBigTree) wcol = 0x0080C0; break; case laTemple: { - int d = showoff ? 0 : (euclid||c->master->alt) ? celldistAlt(c) : 99; + int d = showoff ? 0 : (eubinary||c->master->alt) ? celldistAlt(c) : 99; if(chaosmode) fcol = 0x405090; else if(d % TEMPLE_EACH == 0) @@ -3182,7 +3190,7 @@ bool placeSidewall(cell *c, int i, int sidepar, const transmatrix& V, int col) { transmatrix V2 = V * ddspin(c, i); - if(gp::on || irr::on) { + if(gp::on || irr::on || binarytiling) { draw_shapevec(c, V2, qfi.fshape->gpside[sidepar][i], col, prio); return false; } @@ -4779,7 +4787,14 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) { double spd = 1; bool rev = false; - if(isGravityLand(cwt.c->land)) { + if(binarytiling && conformal::do_rotate >= 2) { + if(!straightDownSeek || c->master->distance < straightDownSeek->master->distance) { + usethis = true; + spd = 1; + } + } + + else if(isGravityLand(cwt.c->land)) { if(cwt.c->land == laDungeon) rev = true; if(conformal::do_rotate >= 1) if(!straightDownSeek || edgeDepth(c) < edgeDepth(straightDownSeek)) { @@ -4788,7 +4803,7 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) { } } - if(c->master->alt && cwt.c->master->alt && + else if(c->master->alt && cwt.c->master->alt && (cwt.c->land == laMountain || (conformal::do_rotate >= 2 && (cwt.c->land == laTemple || cwt.c->land == laWhirlpool || @@ -4803,7 +4818,7 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) { } } - if(conformal::do_rotate >= 2 && cwt.c->land == laOcean && cwt.c->landparam < 25) { + else if(conformal::do_rotate >= 2 && cwt.c->land == laOcean && cwt.c->landparam < 25) { if(!straightDownSeek || coastval(c, laOcean) < coastval(straightDownSeek, laOcean)) { usethis = true; spd = cwt.c->landparam / 10; @@ -5209,6 +5224,8 @@ void drawthemap() { profile_start(1); if(euclid) drawEuclidean(); + else if(binarytiling) + binary::draw(); else drawrec(viewctr, hsOrigin, cview()); drawWormSegments(); diff --git a/heptagon.cpp b/heptagon.cpp index 55284bdd..6b63e189 100644 --- a/heptagon.cpp +++ b/heptagon.cpp @@ -74,6 +74,7 @@ heptagon *buildHeptagon(heptagon *parent, int d, hstate s, int pard = 0, int fix h->spintable = 0; h->move[pard] = parent; tsetspin(h->spintable, pard, d); parent->move[d] = h; tsetspin(parent->spintable, d, pard); + if(binarytiling) return h; if(parent->c7) { if(irr::on) irr::link_next(parent, d); @@ -238,7 +239,9 @@ heptspin& operator += (heptspin& h, wstep_t) { h = h + wstep; return h; } heptagon *createStep(heptagon *h, int d) { d = fixrot(d); - if(!h->move[0] && h->s != hsOrigin) { + if(!h->move[d] && binarytiling) + return binary::createStep(h, d); + if(!h->move[0] && h->s != hsOrigin && !binarytiling) { // cheating: int pard=0; if(S3 == 3) diff --git a/hyper.h b/hyper.h index ed52ce72..56aba74e 100644 --- a/hyper.h +++ b/hyper.h @@ -82,10 +82,13 @@ void addMessage(string s, char spamtype = 0); #define ALPHA (M_PI*2/S7) #define S7 ginf[geometry].sides #define S3 ginf[geometry].vertex -#define hyperbolic_37 (S7 == 7 && S3 == 3) -#define hyperbolic_not37 ((S7 > 7 || S3 > 3) && hyperbolic) -#define weirdhyperbolic ((S7 > 7 || S3 > 3 || gp::on || irr::on) && hyperbolic) -#define stdhyperbolic (S7 == 7 && S3 == 3 && !gp::on) +#define hyperbolic_37 (S7 == 7 && S3 == 3 && !binarytiling) +#define hyperbolic_not37 ((S7 > 7 || S3 > 3 || binarytiling) && hyperbolic) +#define weirdhyperbolic ((S7 > 7 || S3 > 3 || gp::on || irr::on || binarytiling) && hyperbolic) +#define stdhyperbolic (S7 == 7 && S3 == 3 && !gp::on && !irr::on && !binarytiling) + +#define binarytiling (geometry == gBinaryTiling) +#define eubinary (euclid || binarytiling) #define cgclass (ginf[geometry].cclass) #define euclid (cgclass == gcEuclid) @@ -3755,4 +3758,10 @@ bool saved_tortoise_on(cell *c); #define PRING(i) for(double i=0; i<=S84+1e-6; i+= pow(.5, vid.linequality)) #define REVPRING(i) for(double i=S84; i>=-1e-6; i-=pow(.5, vid.linequality)) +void horopoint(ld y, ld x); + +namespace binary { + heptagon *createStep(heptagon *parent, int d); + } + } diff --git a/hypgraph.cpp b/hypgraph.cpp index 8ab5f863..4d55ea39 100644 --- a/hypgraph.cpp +++ b/hypgraph.cpp @@ -800,18 +800,36 @@ void optimizeview() { transmatrix TB = Id; - for(int i=-1; ic7->type; i++) { + heptagon *h2 = createStep(viewctr.h, i); + transmatrix T = binary::relative_matrix(h2, viewctr.h); + hyperpoint H = View * tC0(T); + if(H[2] < best) best = H[2], turn = i, TB = T; + } + if(turn >= 0) { + View = View * TB; + fixmatrix(View); + viewctr.h = createStep(viewctr.h, turn); + } } - - if(turn >= 0) { - View = View * TB; - fixmatrix(View); - viewctr = viewctr + turn + wstep; + + else { + + for(int i=-1; i= 0) { + View = View * TB; + fixmatrix(View); + viewctr = viewctr + turn + wstep; + } } } diff --git a/landgen.cpp b/landgen.cpp index 22669f9b..3dec8b13 100644 --- a/landgen.cpp +++ b/landgen.cpp @@ -352,9 +352,9 @@ void giantLandSwitch(cell *c, int d, cell *from) { if(hrand(5000) < 20*PRIZEMUL && c->wall != waOpenGate) placePrizeOrb(c); if(c->wall == waNone) buildPrizeMirror(c, 250); - if(c->land == laPalace && (euclid || c->master->alt) && celldistAlt(c) <= 150 && !(havewhat&HF_MOUSE) && !princess::generating && + if(c->land == laPalace && (eubinary || c->master->alt) && celldistAlt(c) <= 150 && !(havewhat&HF_MOUSE) && !princess::generating && princess::getPrisonInfo(c) && - (euclid || (princess::getPrisonInfo(c)->bestdist < 6 && princess::getPrisonInfo(c)->princess))) { + (eubinary || (princess::getPrisonInfo(c)->bestdist < 6 && princess::getPrisonInfo(c)->princess))) { c->monst = moMouse; if(!princess::squeaked) { addMessage(XLAT("You hear a distant squeak!")); @@ -1329,7 +1329,7 @@ void giantLandSwitch(cell *c, int d, cell *from) { // depth! int d = chaosmode ? -15 * items[itGrimoire]: - (euclid || c->master->alt) ? celldistAlt(c) : 10; + (eubinary || c->master->alt) ? celldistAlt(c) : 10; // remember: d is negative if(chaosmode ? hrand(100) < 25 : d % TEMPLE_EACH == 0) { if(hrand(5000) < 20 - 2*d && !c->monst && !peace::on) @@ -1469,9 +1469,9 @@ void giantLandSwitch(cell *c, int d, cell *from) { case laCaribbean: if(d == 9) { - if(!euclid) { + if(!eubinary) { if(c->master->alt && c->master->alt->distance <= 2) { - if(!euclid) generateAlts(c->master); + if(!eubinary) generateAlts(c->master); preventbarriers(c); int d = celldistAlt(c); if(d <= 0) @@ -1490,11 +1490,11 @@ void giantLandSwitch(cell *c, int d, cell *from) { c->wall = waSea; } } - if(d == 8 && !euclid) { + if(d == 8 && !eubinary) { int mindist = 9; for(int i=0; itype; i++) { cell *c2 = c->mov[i]; - if((euclid || c2->master->alt) && celldistAlt(c2) < mindist) + if((eubinary || c2->master->alt) && celldistAlt(c2) < mindist) mindist = celldistAlt(c2); } if(mindist == 0) beCIsland(c); @@ -2372,7 +2372,7 @@ void setdist(cell *c, int d, cell *from) { // this fixes the following problem: // http://steamcommunity.com/app/342610/discussions/0/1470840994970724215/ - if(!generatingEquidistant && from && d >= 7 && c->land) { + if(!generatingEquidistant && from && d >= 7 && c->land && !binarytiling) { int cdi = celldist(c); if(celldist(from) > cdi) { forCellCM(c2, c) if(celldist(c2) < cdi) { diff --git a/pattern2.cpp b/pattern2.cpp index 60ce789f..0c690851 100644 --- a/pattern2.cpp +++ b/pattern2.cpp @@ -343,6 +343,7 @@ int fieldval_uniq(cell *c) { auto p = cell_to_pair(c); return gmod(p.first * torusconfig::dx + p.second * torusconfig::dy, torusconfig::qty); } + else if(binarytiling) return 0; if(ctof(c) || gp::on || irr::on) return c->master->fieldval/S7; else { int z = 0; @@ -734,7 +735,7 @@ namespace patterns { void val_warped(cell *c, patterninfo& si) { int u = ishept(c)?1:0; - if(S3 != 3 || S7 != 7) { + if(S3 != 3 || S7 != 7 || gp::on || irr::on) { si.id = u; si.dir = 1; return; @@ -871,6 +872,12 @@ namespace patterns { patterninfo si; si.dir = 0; si.reflect = false; si.id = ctof(c); si.symmetries = c->type; + + if(binarytiling) { + if(pat == PAT_SINGLETYPE) si.id = 0; + si.dir = 2; + return si; + } if(pat == PAT_SINGLETYPE) { si.id = 0; si.symmetries = 1; @@ -1160,6 +1167,7 @@ int pattern_threecolor(cell *c) { // which roughly corresponds to the heptagons in the normal tiling bool pseudohept(cell *c) { if(irr::on) return irr::pseudohept(c); + if(binarytiling) return c->type & c->master->distance & 1; if(gp::on && gp_threecolor() == 2) return gp::pseudohept_val(c) == 0; if(gp::on && gp_threecolor() == 1 && (S7&1) && (S3 == 3)) @@ -2010,7 +2018,7 @@ namespace linepatterns { case patTree: if(is_master(c)) { - cell *c2 = c->master->move[0]->c7; + cell *c2 = c->master->move[binarytiling ? 5 : 0]->c7; if(gmatrix.count(c2)) queuelinef(tC0(V), gmatrix[c2]*C0, col, 2 + vid.linequality); } break; diff --git a/polygons.cpp b/polygons.cpp index 68995e50..812fac81 100644 --- a/polygons.cpp +++ b/polygons.cpp @@ -791,7 +791,7 @@ void drawpolyline(polytodraw& p) { } } else poly_flags &=~ POLY_INVERSE; - + if(spherespecial) { if(!hiliteclick && !(poly_flags & POLY_INFRONT)) return; } @@ -1622,6 +1622,8 @@ void buildpolys() { last->flags |= POLY_HASWALLS | POLY_FULL | POLY_HASSHADOW | POLY_ISSIDE; } + if(binarytiling) hexvdist = rhexf = 1, tessf = 1, gp::scale = 1, scalef = 1, crossf *= .8; + double floorrad0 = hexvdist*0.92; double floorrad1 = rhexf / gp::scale *0.94; @@ -1629,7 +1631,7 @@ void buildpolys() { if(gp::on) goldbf = gp::scale * 1.6; if(irr::on) goldbf = irr::scale * 1.6; if(gp::on) floorrad1 /= 1.6; - + double triangleside = hcrossf*.94; if(nonbitrunc) triangleside = tessf * .94; @@ -1722,21 +1724,32 @@ void buildpolys() { for(int t=0; t<=6; t++) hpcpush(ddi(S7 + t*S14, floorrad0*7/8 * gp::scale) * C0); } - bshape(shWall[0], PPR_WALL); - for(int t=0; t<=S6; t++) { - hpcpush(ddi(S7 + t*S14, floorrad0 * goldbf) * C0); - if(t != S6) hpcpush(ddi(S14 + t*S14, floorrad0 * goldbf/4) * C0); - } - - bshape(shWall[1], PPR_WALL); - if(S7 == 6 || S7 == 4) { - for(int t=0; t<=S6; t++) { - hpcpush(ddi(S7 + t*S14, floorrad1 * goldbf) * C0); - if(t != S6) hpcpush(ddi(S14 + t*S14, floorrad1 * goldbf/4) * C0); + if(binarytiling) { + for(int i=0; i<2; i++) { + bshape(shWall[i], PPR_WALL); + horopoint(log(2)/8, .1); + horopoint(log(2)/8, -.1); + horopoint(-log(2)/8, 0); } } - else - for(int t=0; t<=S7; t++) hpcpush(ddi(t*S36+td, floorrad1 * goldbf) * C0); + + else { + bshape(shWall[0], PPR_WALL); + for(int t=0; t<=S6; t++) { + hpcpush(ddi(S7 + t*S14, floorrad0 * goldbf) * C0); + if(t != S6) hpcpush(ddi(S14 + t*S14, floorrad0 * goldbf/4) * C0); + } + + bshape(shWall[1], PPR_WALL); + if(S7 == 6 || S7 == 4) { + for(int t=0; t<=S6; t++) { + hpcpush(ddi(S7 + t*S14, floorrad1 * goldbf) * C0); + if(t != S6) hpcpush(ddi(S14 + t*S14, floorrad1 * goldbf/4) * C0); + } + } + else + for(int t=0; t<=S7; t++) hpcpush(ddi(t*S36+td, floorrad1 * goldbf) * C0); + } bshape(shCross, PPR_WALL); for(int i=0; i<=84; i+=7) diff --git a/screenshot.cpp b/screenshot.cpp index b00a7dd4..bc6b0934 100644 --- a/screenshot.cpp +++ b/screenshot.cpp @@ -268,7 +268,7 @@ void saveHighQualityShot(const char *fname, const char *caption, int fade) { vid.xres = vid.yres * 22/16; while(vid.xres & 15) vid.xres++; } - + // if(vid.pmodel == 0) vid.scale = 0.99; calcparam(); diff --git a/shmup.cpp b/shmup.cpp index 6553f4ae..ec0952ab 100644 --- a/shmup.cpp +++ b/shmup.cpp @@ -3374,6 +3374,8 @@ transmatrix calc_relative_matrix(cell *c2, cell *c1, const hyperpoint& point_hin } } + if(binarytiling) return binary::relative_matrix(c2->master, c1->master); + if(torus) { transmatrix t = Id; if(whateveri) printf("[%p,%d] ", c2, celldistance(c2, c1)); diff --git a/system.cpp b/system.cpp index f19dab09..d1d874c0 100644 --- a/system.cpp +++ b/system.cpp @@ -1165,7 +1165,7 @@ void switch_game_mode(char switchWhat) { case rg::bitrunc: case rg::gp: - if(euclid6) geometry = gNormal; + if(euclid6 || binarytiling) geometry = gNormal; nonbitrunc = !nonbitrunc; irr::on = false; gp::on = (switchWhat == rg::gp && !gp::on); need_reset_geometry = true; @@ -1191,6 +1191,7 @@ void switch_game_mode(char switchWhat) { if(gp::param.second && gp::param.second != gp::param.first) gp::param.second = 0; } + if(geometry == gBinaryTiling) nonbitrunc = true, gp::on = irr::on = false; need_reset_geometry = true; #if CAP_TEXTURE diff --git a/textures.cpp b/textures.cpp index 03a6dc03..40c292e6 100644 --- a/textures.cpp +++ b/textures.cpp @@ -313,6 +313,31 @@ void mapTexture(cell *c, textureinfo& mi, patterns::patterninfo &si, const trans } } + else if(binarytiling) { + mi.M = T; + mi.triangles.clear(); + + ld yx = log(2) / 2; + ld yy = yx; + ld xx = 1 / sqrt(2)/2; + + hyperpoint vertices[8]; + vertices[0] = get_horopoint(-yy, xx); + vertices[1] = get_horopoint(yy, 2*xx); + vertices[2] = get_horopoint(yy, xx); + vertices[3] = get_horopoint(yy, 0); + vertices[4] = get_horopoint(yy, -xx); + vertices[5] = get_horopoint(yy, -2*xx); + vertices[6] = get_horopoint(-yy, -xx); + vertices[7] = get_horopoint(-yy, 0); + + for(int i=0; i<8; i++) { + hyperpoint h1 = vertices[i]; + hyperpoint h2 = vertices[(i+1)%8]; + mi.triangles.emplace_back(make_array(C0, h1, h2), make_array(mi.M*C0, mi.M*h1, mi.M*h2)); + } + } + else { mi.M = T * applyPatterndir(c, si);