diff --git a/classes.h b/classes.h index 626de7ca..fc6f72ca 100644 --- a/classes.h +++ b/classes.h @@ -216,3 +216,8 @@ extern monstertype minf[motypes]; extern itemtype iinf[ittypes]; extern const landtype linf[landtypes]; + +enum cpatterntype { + cpFootball, cpThree, cpChess, cpSingle, cpLarge, cpUnknown + }; + diff --git a/geom-exp.cpp b/geom-exp.cpp index 5c020efe..0b41db04 100644 --- a/geom-exp.cpp +++ b/geom-exp.cpp @@ -136,6 +136,8 @@ void showTorusConfig() { dialog::display(); } +string truncatenames[2] = {" (t)", " (n)"}; + void showEuclideanMenu() { cmode = sm::SIDE; gamescreen(0); @@ -270,7 +272,6 @@ void showEuclideanMenu() { } else { dialog::init(XLAT("experiment with geometry")); - string truncatenames[2] = {" (t)", " (n)"}; dialog::addSelItem(XLAT("geometry"), XLAT(ginf[geometry].name) + XLAT(truncatenames[nontruncated]), '5'); dialog::addBreak(50); diff --git a/graph.cpp b/graph.cpp index 6d645e56..69f06776 100644 --- a/graph.cpp +++ b/graph.cpp @@ -3895,9 +3895,7 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) { if(patterns::displaycodes) { - int pf = patterns::displaycodes == 2 ? patterns::subpattern_flags : 0; - - auto si = patterns::getpatterninfo(c, patterns::whichPattern, pf); + auto si = patterns::getpatterninfo0(c); for(int i=0; itype; i += si.symmetries) { queuepoly(V * applyPatterndir(c,si), shAsymmetric, darkena(0x000000, 0, 0xC0)); diff --git a/hyper.h b/hyper.h index efae7a43..50bfdb32 100644 --- a/hyper.h +++ b/hyper.h @@ -295,7 +295,7 @@ typedef int cellfunction(cell*); int towerval(cell *c, cellfunction* cf = &coastvalEdge); #define HRANDMAX 0x7FFFFFFF int hrandpos(); // 0 to HRANDMAX -void restartGame(char switchWhat = 0, bool push = false); +void restartGame(char switchWhat = 0, bool push = false, bool keep_screens = true); int landMultiplier(eLand l); eItem treasureType(eLand l); void buildBarrier(cell *c, int d, eLand l = laNone); @@ -674,6 +674,7 @@ namespace patterns { static const char PAT_DOWN = 'H'; static const char PAT_COLORING = 'C'; static const char PAT_SIBLING = 'S'; + static const char PAT_CHESS = 'c'; extern int subpattern_flags; @@ -684,12 +685,14 @@ namespace patterns { static const int SPF_CHANGEROT = 16; static const int SPF_TWOCOL = 32; static const int SPF_EXTRASYM = 64; + static const int SPF_ALTERNATE = 128; + static const int SPF_FOOTBALL = 256; - static const int SPF_SYM0123 = 14; + static const int SPF_SYM0123 = SPF_SYM01 | SPF_SYM02 | SPF_SYM03; extern char whichCanvas; - extern int displaycodes; + extern bool displaycodes; int generateCanvas(cell *c); @@ -2384,9 +2387,11 @@ namespace texture { extern vector texture_pixels; void showMenu(); - + void update(); void drawPixel(cell *c, hyperpoint h, int col); + + extern cpatterntype cgroup; } void queueline(const hyperpoint& H1, const hyperpoint& H2, int col, int prf = 0, int prio = PPR_LINE); @@ -2410,3 +2415,4 @@ inline hyperpoint tC0(const transmatrix &T) { transmatrix actualV(const heptspin& hs, const transmatrix& V); transmatrix cview(); +extern string truncatenames[2]; diff --git a/init.cpp b/init.cpp index df2d7ca5..e53f2d57 100644 --- a/init.cpp +++ b/init.cpp @@ -364,6 +364,8 @@ void addMessage(string s, char spamtype = 0); #define smallsphere (S7 < 5) #define bigsphere (S7 == 5) #define ap4 (a4 && nontruncated) +#define euclid4 (euclid && a4) +#define euclid6 (euclid && !a4) #define S6 (S3*2) #define S42 (S7*S6) diff --git a/pattern2.cpp b/pattern2.cpp index ae72b224..9e2427ea 100644 --- a/pattern2.cpp +++ b/pattern2.cpp @@ -471,12 +471,27 @@ namespace patterns { if(sym03 && (i&2)) i ^= 3; } + void applyAlt(patterninfo& si, int sub, int pat) { + if(sub & SPF_ALTERNATE) { + si.id += 4; + si.id %= 12; + } + if(pat == PAT_COLORING && (sub & SPF_FOOTBALL)) { + if(si.id == 4) si.dir++; + si.id = !si.id; + if(si.id && (sub & SPF_EXTRASYM)) + si.symmetries = si.id ? 1 : 2; + return; + } + } + void val46(cell *c, patterninfo &si, int sub, int pat) { if(ctof(c)) { si.id = c->master->emeraldval >> 1; applySym0123(si.id, sub); si.dir = (c->master->emeraldval&1) ^ (c->master->emeraldval>>1); si.symmetries = 2; + applyAlt(si, sub, pat); /* printf("[%3d] ", c->master->emeraldval); for(int i=0; i<6; i++) printf("%2d", val46(createMov(c, i))); printf("\n"); */ @@ -488,11 +503,13 @@ namespace patterns { si.dir += 4; if((sub & SPF_TWOCOL) && (pat == PAT_COLORING)) si.id = 4; - else if(si.id == 4) si.dir++; + else if(pat == PAT_COLORING && si.id == 4) si.dir++; if(sub & SPF_SYM01) si.symmetries = 2; else if(sub & SPF_SYM03) si.symmetries = 2; else if(sub & SPF_SYM02) si.symmetries = 4; + + applyAlt(si, sub, pat); } } @@ -519,7 +536,7 @@ namespace patterns { else si.dir = (zebra40(createMov(c, 0)) & 4) ? 2 : 0; } } - + void val38(cell *c, patterninfo &si, int sub, int pat) { bool symRotation = sub & SPF_ROT; @@ -534,6 +551,9 @@ namespace patterns { si.id += 4; si.dir = (pat == PAT_COLORING ? 1 : 0) + (c->master->fiftyval | (c->master->fiftyval & 8 ? 0 : 2)); si.symmetries = 2; + si.id += 8; + si.id %= 12; + applyAlt(si, sub, pat); } else { si.id = 8 * ((c->master->fiftyval & 1) ^ (c->spin(0) & 1)); @@ -542,11 +562,13 @@ namespace patterns { if(fv == 0) si.dir = (si.id == 8 && pat == PAT_COLORING ? 1 : 0) + i; } if(symRotation) si.symmetries = 2; + si.id += 8; + si.id %= 12; + applyAlt(si, sub, pat); } - } - void valEuclid(cell *c, patterninfo &si, int sub) { + void valEuclid6(cell *c, patterninfo &si, int sub) { bool symRotation = sub & SPF_ROT; si.id = ishept(c) ? 4 : ishex1(c) ? 8 : 0; if(sub & SPF_CHANGEROT) { @@ -555,11 +577,28 @@ namespace patterns { if(symRotation) si.id = 0; } + void valEuclid4(cell *c, patterninfo &si, int sub) { + si.id = eupattern4(c); + applySym0123(si.id, sub); + if(sub & SPF_CHANGEROT) { + int dirt[] = {0,1,3,2}; + si.dir = dirt[si.id]; + if(c->type == 8) si.dir *= 2; + } + if(sub & SPF_SYM03) { + si.id *= 4; + applyAlt(si, sub, PAT_COLORING); + } + else + si.symmetries = (sub & SPF_EXTRASYM) ? c->type/4 : c->type; + } + void val_all(cell *c, patterninfo &si, int sub, int pat) { if(a46) val46(c, si, sub, pat); else if(a38) val38(c, si, sub, pat); else if(sphere) valSibling(c, si, sub); - else if(euclid) valEuclid(c, si, sub); + else if(euclid4) valEuclid4(c, si, sub); + else if(euclid) valEuclid6(c, si, sub); else if(a4) val457(c, si, sub); else si.symmetries = ctof(c) ? 1 : 2; } @@ -643,6 +682,9 @@ namespace patterns { } if(sphere && !(nontruncated) && !(S7 == 3)) si.symmetries = ctof(c) ? 1 : 2; + if(sphere && (sub & SPF_EXTRASYM)) { + si.symmetries = ctof(c) ? 1 : 2; + } if(a38) si.symmetries = (ctof(c) && !nontruncated) ? 1 : 2; if(a457) { @@ -659,7 +701,6 @@ namespace patterns { int subpattern_flags; - // also works with 38 void val_threecolors(cell *c, patterninfo& si, int sub) { int pcol = pattern_threecolor(c); si.id = pcol * 4; @@ -673,11 +714,13 @@ namespace patterns { break; } } - if(euclid && (sub & SPF_CHANGEROT)) si.dir = 0; + if(euclid6 && (sub & SPF_CHANGEROT)) si.dir = 0; if(sub & SPF_ROT) si.id = 0; - if(!(sub & SPF_EXTRASYM)) { - if(euclid) si.symmetries = 6; + if(euclid6 && !(sub & SPF_EXTRASYM)) { + si.symmetries = 6; } + if(S7 == 4) + applyAlt(si, sub, PAT_COLORING); } patterninfo getpatterninfo(cell *c, char pat, int sub) { @@ -815,6 +858,11 @@ namespace patterns { else if(pat == PAT_COLORING && (a46 || a38)) { val_all(c, si, sub, pat); } + + else if(pat == PAT_CHESS) { + val_nopattern(c, si, sub); + si.id = celldist(c) & 1; + } else val_nopattern(c, si, sub); @@ -882,6 +930,11 @@ int pattern_threecolor(cell *c) { if(z == 14 || z == 11) return 4; return 1; } + if(a46 && nontruncated) { + patterns::patterninfo si; + patterns::val46(c, si, 0, patterns::PAT_COLORING); + return si.id; + } if(S7 == 5 && nontruncated) { const int codes[12] = {1, 2, 0, 3, 2, 0, 0, 1, 3, 1, 2, 3}; return codes[c->master->fiftyval]; @@ -911,7 +964,7 @@ bool warptype(cell *c) { namespace patterns { int canvasback = linf[laCanvas].color >> 2; int subcanvas; - int displaycodes; + bool displaycodes; char whichShape = 0; char whichCanvas = 0; @@ -1033,7 +1086,10 @@ namespace patterns { col[2] /= 4; return (0x202020 + col[0] + (col[1] << 8) + (col[2] << 16)) >> (err?2:0); } - if(whichCanvas == PAT_FIELD) { + if(whichPattern == 'c') { + return (c->master->distance&1) ? 0xC0C0C0 : 0x202020; + } + if(whichCanvas == 'F') { return pseudohept(c) ? 0x202020 : 0xC0C0C0; } if(whichCanvas == 'T') { @@ -1045,18 +1101,25 @@ namespace patterns { void showPrePattern() { dialog::init("predesigned patterns"); - dialog::addItem(XLAT("Gameboard"), 'g'); + dialog::addItem(XLAT("single color"), 'g'); dialog::addItem(XLAT("random colors"), 'r'); - dialog::addItem(XLAT("rainbow landscape"), 'l'); - dialog::addItem(XLAT("dark rainbow landscape"), 'd'); + + if(stdeuc) { + dialog::addItem(XLAT("rainbow landscape"), 'l'); + dialog::addItem(XLAT("dark rainbow landscape"), 'd'); + } + dialog::addItem(XLAT("football"), 'F'); + if(S3 == 4 && nontruncated) + dialog::addItem(XLAT("chessboard"), 'c'); dialog::addItem(XLAT("nice coloring"), 'T'); - dialog::addSelItem(XLAT("emerald pattern"), "emerald", 'e'); - - dialog::addSelItem(XLAT("four elements"), "palace", 'b'); - dialog::addSelItem(XLAT("eight domains"), "palace", 'a'); + if(stdhyperbolic) { + dialog::addSelItem(XLAT("emerald pattern"), "emerald", 'e'); + dialog::addSelItem(XLAT("four elements"), "palace", 'b'); + dialog::addSelItem(XLAT("eight domains"), "palace", 'a'); + } dialog::addSelItem(XLAT("zebra pattern"), "zebra", 'z'); dialog::addSelItem(XLAT("four triangles"), "zebra", 't'); @@ -1064,21 +1127,37 @@ namespace patterns { dialog::addSelItem(XLAT("random black-and-white"), "current", 'w'); - dialog::addSelItem(XLAT("field pattern C"), "field", 'C'); - dialog::addSelItem(XLAT("field pattern D"), "field", 'D'); - dialog::addSelItem(XLAT("field pattern N"), "field", 'N'); - dialog::addSelItem(XLAT("field pattern S"), "field", 'S'); + if(!sphere) { + dialog::addSelItem(XLAT("field pattern C"), "field", 'C'); + dialog::addSelItem(XLAT("field pattern D"), "field", 'D'); + dialog::addSelItem(XLAT("field pattern N"), "field", 'N'); + dialog::addSelItem(XLAT("field pattern S"), "field", 'S'); + } dialog::display(); keyhandler = [] (int sym, int uni) { dialog::handleNavigation(sym, uni); - if((uni >= 'a' && uni <= 'z') || (uni >= 'A' && uni <= 'Z')) { + if(uni == 'g') { + static unsigned c = (canvasback << 8) | 0xFF; + unsigned canvasbacks[] = { + 5, 0xFFFFFFFF, 0x101010FF, 0x404040FF, 0x808080FF, 0x800000FF + }; + dialog::openColorDialog(c, canvasbacks); + dialog::reaction = [] () { + whichCanvas = 'g'; + canvasback = c >> 8; + firstland = specialland = laCanvas; + randomPatternsMode = false; + restartGame(0, false, true); + }; + } + else if((uni >= 'a' && uni <= 'z') || (uni >= 'A' && uni <= 'Z')) { whichCanvas = uni; subcanvas = rand(); firstland = specialland = laCanvas; randomPatternsMode = false; - restartGame(); + restartGame(0, false, true); } else if(doexiton(sym, uni)) popScreen(); }; @@ -1087,7 +1166,7 @@ namespace patterns { void showPattern() { cmode = sm::SIDE | sm::MAYDARK; { - dynamicval dc(displaycodes, displaycodes ? displaycodes : 2); + dynamicval dc(displaycodes, true); gamescreen(0); } dialog::init(); @@ -1102,6 +1181,9 @@ namespace patterns { if(stdhyperbolic || euclid) dialog::addBoolItem(XLAT("Palace Pattern"), (whichPattern == PAT_PALACE), PAT_PALACE); + + if(nontruncated && S3 == 4) + dialog::addBoolItem(XLAT("chessboard"), (whichPattern == PAT_CHESS), PAT_CHESS); if(a38 || a46 || euclid || S3 == 4) dialog::addBoolItem(XLAT("coloring"), (whichPattern == PAT_COLORING), PAT_COLORING); @@ -1149,9 +1231,21 @@ namespace patterns { } if(euclid && among(whichPattern, PAT_COLORING, 0)) dialog::addBoolItem(XLAT("extra symmetries"), subpattern_flags & SPF_EXTRASYM, '='); + + if(a38 && nontruncated && whichPattern == 0) { + dialog::addBoolItem(XLAT("extra symmetries"), subpattern_flags & SPF_EXTRASYM, '='); + } + + if(a46 && nontruncated && whichPattern == PAT_COLORING) { + dialog::addBoolItem(XLAT("extra symmetries"), subpattern_flags & SPF_EXTRASYM, '='); + } + + if((a38 || (sphere && S7 == 4) || euclid4 || a46) && !nontruncated) { + dialog::addBoolItem(XLAT("alternate coloring"), subpattern_flags & SPF_ALTERNATE, '\''); + dialog::addBoolItem(XLAT("football pattern"), subpattern_flags & SPF_FOOTBALL, '*'); + } - dialog::addBoolItem(XLAT("display pattern codes (full)"), (displaycodes == 1), 'd'); - dialog::addBoolItem(XLAT("display pattern codes (simplified)"), (displaycodes == 2), 's'); + dialog::addBoolItem(XLAT("display pattern codes (full)"), displaycodes, 'd'); dialog::addBoolItem(XLAT("display only hexagons"), (whichShape == '6'), '6'); dialog::addBoolItem(XLAT("display only heptagons"), (whichShape == '7'), '7'); @@ -1166,28 +1260,34 @@ namespace patterns { keyhandler = [] (int sym, int uni) { dialog::handleNavigation(sym, uni); - printf("uni = %c\n", uni); - if(among(uni, PAT_EMERALD, PAT_PALACE, PAT_ZEBRA, PAT_DOWN, PAT_FIELD, PAT_COLORING, PAT_SIBLING)) { + if(among(uni, PAT_EMERALD, PAT_PALACE, PAT_ZEBRA, PAT_DOWN, PAT_FIELD, PAT_COLORING, PAT_SIBLING, PAT_CHESS)) { if(whichPattern == uni) whichPattern = 0; else whichPattern = uni; mapeditor::modelcell.clear(); } - else if(printf("not among\n"), 0) ; - else if(uni >= '0' && uni <= '5') subpattern_flags ^= (1 << (uni - '0')); else if(uni == '=') subpattern_flags ^= SPF_EXTRASYM; + else if(uni == '\'') { + subpattern_flags ^= SPF_ALTERNATE; + subpattern_flags &= ~SPF_FOOTBALL; + } + + else if(uni == '*') { + subpattern_flags ^= SPF_FOOTBALL; + subpattern_flags &= ~SPF_ALTERNATE; + } + else if(uni == '6' || uni == '7' || uni == '8') { if(whichShape == uni) whichShape = 0; else whichShape = uni; } - else if(uni == 'd') displaycodes = displaycodes == 1 ? 0 : 1; - else if(uni == 's') displaycodes = displaycodes == 2 ? 0 : 2; + else if(uni == 'd') displaycodes = !displaycodes; else if(uni == 'l' && (cheater || autocheat)) pushScreen(linepatterns::showMenu); @@ -1198,6 +1298,145 @@ namespace patterns { }; } + bool compatible(cpatterntype oldp, cpatterntype newp) { + // larges are not incompatible between themselves + if(newp == cpLarge) + return false; + // other cps are compatible with themselves + if(newp == oldp) return true; + // Single can be upgraded to everything + if(oldp == cpSingle) return true; + // Football can be upgraded to Three colors + if(oldp == cpFootball) return newp == cpThree; + // incompatible otherwise + return false; + } + + struct changeable_pattern_geometry { + eGeometry geo; + bool nontrunc; + char whichPattern; + int subpattern_flags; + }; + + struct changeable_pattern { + string name; + vector geometries; + }; + + vector cpatterns = { + {"football", { + {gNormal, false, 0, 0}, + {gSphere, false, 0, 0}, + {gEuclid, false, 0, SPF_EXTRASYM}, + {gOctagon, false, 0, 0}, + {gOctagon, true, PAT_COLORING, SPF_FOOTBALL | SPF_EXTRASYM}, + {g45, false, 0, 0}, + {g46, false, 0, SPF_EXTRASYM}, + {g47, false, 0, 0}, + {gSmallSphere, false, 0, 0}, + {gSmallSphere, true, PAT_COLORING, SPF_FOOTBALL | SPF_EXTRASYM}, + {gTinySphere, false, 0, SPF_EXTRASYM}, + {gEuclidSquare, false, 0, SPF_EXTRASYM}, + }}, + {"three colors", { + {gEuclid, false, PAT_COLORING, SPF_SYM0123 | SPF_EXTRASYM}, + {gSmallSphere, false, PAT_COLORING, 0}, + {gSmallSphere, false, PAT_COLORING, SPF_ALTERNATE}, + {gSmallSphere, true, PAT_COLORING}, + {gOctagon, false, PAT_COLORING, SPF_ROT | SPF_EXTRASYM}, + {gOctagon, false, PAT_COLORING, SPF_ROT | SPF_EXTRASYM | SPF_ALTERNATE}, + {gOctagon, true, PAT_COLORING, 0}, + {gEuclidSquare, false, PAT_COLORING, SPF_SYM03 | SPF_EXTRASYM}, + {gEuclidSquare, false, PAT_COLORING, SPF_SYM03 | SPF_EXTRASYM | SPF_ALTERNATE}, + {g46, false, PAT_COLORING, SPF_SYM0123}, + {g46, false, PAT_COLORING, SPF_SYM0123 | SPF_EXTRASYM | SPF_ALTERNATE} + }}, + {"chessboard", { + {gEuclidSquare, true, PAT_CHESS, SPF_EXTRASYM}, + {g45, true, PAT_CHESS, 0}, + {g46, true, PAT_CHESS, 0}, + {g47, true, PAT_CHESS, 0} + }}, + {"single type", { + {gNormal, true, 0, 0}, + {gSphere, true, 0, SPF_EXTRASYM}, + {gEuclid, false, 0, SPF_EXTRASYM}, + {gOctagon, true, 0, SPF_EXTRASYM}, + {g45, true, 0, 0}, + {g46, true, 0, 0}, + {g47, true, 0, 0}, + {gSmallSphere, true, 0, SPF_EXTRASYM}, + {gTinySphere, true, 0, SPF_EXTRASYM}, + {gEuclidSquare, true, 0, SPF_EXTRASYM}, + }}, + {"large picture", { + {gNormal, false, PAT_PALACE, SPF_SYM0123}, + {gNormal, true, PAT_PALACE, SPF_SYM0123}, + {gElliptic, false, PAT_FIELD, 0}, + {gElliptic, true, PAT_FIELD, 0}, + {gEuclid, false, PAT_PALACE, 0} + }} + }; + + cpatterntype cgroup, old_cgroup; + + void showChangeablePatterns() { + cmode = sm::SIDE | sm::MAYDARK; + { + dynamicval dc(displaycodes, true); + gamescreen(0); + } + dialog::init(); + for(int i=0; i= '0' && uni < '0' + size(cpatterns)) + cgroup = cpatterntype(uni - '0'); + else if(cgroup != cpUnknown && uni >= 'a' && uni < 'a' + size(cpatterns[cgroup].geometries)) { + auto &g = cpatterns[cgroup].geometries[uni - 'a']; + if(g.geo != geometry) { targetgeometry = g.geo; restartGame('g', false, true); } + if(g.nontrunc != nontruncated) restartGame('7', false, true); + whichPattern = g.whichPattern; + subpattern_flags = g.subpattern_flags; + } + else if(doexiton(sym, uni)) + popScreen(); + }; + } + + void computeCgroup() { + cgroup = cpUnknown; + for(int i=0; i