1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2024-06-18 03:09:59 +00:00

implemented new geometries: cylinder and (only one for now) Mobius band

This commit is contained in:
Zeno Rogue 2018-11-27 02:32:11 +01:00
parent 449dd5adaf
commit 460eb19881
21 changed files with 185 additions and 83 deletions

View File

@ -729,7 +729,7 @@ void setLandSphere(cell *c) {
if(c->land == laElementalWall && (c->type != 6 || GOLDBERG))
c->wall = getElementalWall(hrand(2) ? c->barleft : c->barright);
}
if(!torus)
if(!euwrap)
if(specialland == laCrossroads || specialland == laCrossroads2 || specialland == laCrossroads3 || specialland == laTerracotta) {
int x = getHemisphere(c, 1);
if(x == 0 && specialland == laTerracotta)
@ -782,6 +782,10 @@ eLand switchable(eLand nearland, eLand farland, int c) {
}
eLand getEuclidLand(int c) {
if(nonorientable) {
c = -c;
if(c < 5) return laCrossroads;
}
auto& la = get_euland(c);
if(la) return la;
if(get_euland(c-2) && !get_euland(c-1)) getEuclidLand(c-1);

106
cell.cpp
View File

@ -253,7 +253,11 @@ namespace torusconfig {
{"rectangle (hex)", TF_WEIRD | TF_HEX},
{"Klein bottle (squares)", TF_SIMPLE | TF_KLEIN | TF_SQUARE},
{"Klein bottle (hex)", TF_WEIRD | TF_KLEIN | TF_HEX},
};
{"cylinder (squares)", TF_SIMPLE | TF_CYL },
{"cylinder (hex)", TF_SIMPLE | TF_CYL | TF_HEX},
{"Möbius band (squares)", TF_SIMPLE | TF_CYL | TF_KLEIN},
{"Möbius band (hex)", TF_SIMPLE | TF_CYL | TF_HEX | TF_KLEIN},
};
eTorusMode torus_mode, newmode;
flagtype tmflags() { return tmodes[torus_mode].flags; }
@ -342,11 +346,19 @@ namespace torusconfig {
ginf[gTorus].vertex = 3, ginf[gTorus].sides = 6;
else
ginf[gTorus].vertex = 4, ginf[gTorus].sides = 4;
if(tmflags() & TF_KLEIN)
ginf[gTorus].quotientstyle |= qNONOR;
else
ginf[gTorus].quotientstyle &= ~qNONOR;
if(tmflags() & TF_CYL)
ginf[gTorus].quotientstyle &= ~qFULLTORUS;
else
ginf[gTorus].quotientstyle |= qFULLTORUS;
}
}
int euclid_getvec(int dx, int dy) {
if(torus) return torusconfig::getvec(dx, dy);
if(euwrap) return torusconfig::getvec(dx, dy);
else return pair_to_vec(dx, dy);
}
@ -438,7 +450,7 @@ hrmap_torus *torusmap() {
struct hrmap_euclidean : hrmap {
cell *gamestart() {
return euclideanAtCreate(0);
return *(euclideanAtCreate(0).first);
}
struct euclideanSlab {
@ -462,12 +474,25 @@ struct hrmap_euclidean : hrmap {
euclidean[y][x] = NULL;
}
cell*& at(int vec) {
euc_pointer at(int vec) {
auto p = vec_to_pair(vec);
int x = p.first, y = p.second;
bool mobius = false;
if(euwrap) {
int zx = torusconfig::sdx;
int zy = torusconfig::sdy;
int periods = gdiv(x * zx + y * zy, zx * zx + zy * zy);
if(nonorientable) mobius = (periods&1) ? S6 : 0, periods &=~ 1;
y -= zy * periods;
x -= zx * periods;
if(mobius) x -= zx, y -= zy, y = -y;
}
euclideanSlab*& slab = euclidean[(y>>8)&(slabs-1)][(x>>8)&(slabs-1)];
if(!slab) slab = new hrmap_euclidean::euclideanSlab;
return slab->a[y&255][x&255];
return make_pair(&(slab->a[y&255][x&255]), mobius);
}
map<int, struct cdata> eucdata;
@ -483,8 +508,10 @@ struct hrmap_euclidean : hrmap {
};
cellwalker vec_to_cellwalker(int vec) {
if(!torus)
return cellwalker(euclideanAtCreate(vec), 0, false);
if(!fulltorus) {
auto p = euclideanAtCreate(vec);
return cellwalker(*p.first, 0, p.second);
}
else {
hrmap_torus *cur = torusmap();
if(!cur) return cellwalker(NULL, 0);
@ -495,13 +522,23 @@ cellwalker vec_to_cellwalker(int vec) {
int cellwalker_to_vec(cellwalker cw) {
int id = decodeId(cw.at->master);
if(!torus) return id;
if(!fulltorus) {
if(nonorientable) {
auto ep = euclideanAt(id);
if(ep.second != cw.mirrored) {
int x, y;
tie(x, y) = vec_to_pair(id);
return pair_to_vec(x + torusconfig::sdx, torusconfig::sdy - y);
}
}
return id;
}
return torusconfig::id_to_vec(id, cw.mirrored);
}
int cell_to_vec(cell *c) {
int id = decodeId(c->master);
if(!torus) return id;
if(!fulltorus) return id;
return torusconfig::id_to_vec(id, false);
}
@ -919,7 +956,10 @@ cell *createMov(cell *c, int d) {
for(int dx=-1; dx<=1; dx++)
for(int dy=-1; dy<=1; dy++)
euclideanAtCreate(id + pair_to_vec(dx, dy));
if(!c->move(d)) { printf("fail!\n"); }
if(!c->move(d)) {
println(hlog, "id = ", id, " vec_to_pair(id) = ", vec_to_pair(id), ": failed to create move ", d, " in Euclidean\n");
exit(0);
}
}
if(c->move(d)) return c->move(d);
@ -992,28 +1032,36 @@ cell *getMovR(cell *c, int d) {
return c->move(d);
}
void eumerge(cell* c1, cell *c2, int s1, int s2) {
void eumerge(cell* c1, int s1, cell *c2, int s2, bool mirror) {
if(!c2) return;
c1->move(s1) = c2; c1->c.setspin(s1, s2, false);
c2->move(s2) = c1; c2->c.setspin(s2, s1, false);
c1->move(s1) = c2; c1->c.setspin(s1, s2, mirror);
c2->move(s2) = c1; c2->c.setspin(s2, s1, mirror);
}
// map<pair<eucoord, eucoord>, cell*> euclidean;
cell*& euclideanAt(int vec) {
if(torus) { printf("euclideanAt called\n"); exit(1); }
euc_pointer euclideanAt(int vec) {
if(fulltorus) { printf("euclideanAt called\n"); exit(1); }
hrmap_euclidean* euc = dynamic_cast<hrmap_euclidean*> (currentmap);
return euc->at(vec);
}
cell*& euclideanAtCreate(int vec) {
cell*& c = euclideanAt(vec);
euc_pointer euclideanAtCreate(int vec) {
euc_pointer ep = euclideanAt(vec);
cell*& c = *ep.first;
if(!c) {
c = newCell(8, encodeId(vec));
euclideanAt(vec) = c;
build_euclidean_moves(c, vec, [c,vec] (int delta, int d, int d2) { eumerge(c, euclideanAt(vec + delta), d, d2); });
// euclideanAt(vec) = c;
build_euclidean_moves(c, vec, [ep, c,vec] (int delta, int d, int d2) {
euc_pointer ep2 = euclideanAt(vec + delta);
cell* c2 = *ep2.first;
if(!c2) return;
if(ep.second) d = c->c.fix(-d);
if(ep2.second) d2 = c2->c.fix(-d2);
eumerge(c, d, c2, d2, ep.second != ep2.second);
});
}
return c;
return ep;
}
// initializer (also inits origin from heptagon.cpp)
@ -1021,7 +1069,7 @@ void initcells() {
DEBB(DF_INIT, (debugfile,"initcells\n"));
if(archimedean) currentmap = arcm::new_map();
else if(torus) currentmap = new hrmap_torus;
else if(fulltorus) currentmap = new hrmap_torus;
else if(euclid) currentmap = new hrmap_euclidean;
else if(sphere) currentmap = new hrmap_spherical;
else if(quotient) currentmap = new quotientspace::hrmap_quotient;
@ -1181,10 +1229,10 @@ int compdist(int dx[]) {
}
int celldist(cell *c) {
if(torus)
if(fulltorus)
return torusmap()->dists[decodeId(c->master)];
if(masterless)
return eudist(decodeId(c->master));
return eudist(decodeId(c->master)); // fix cylinder
if(sphere || binarytiling) return celldistance(c, currentmap->gamestart());
if(IRREGULAR) return irr::celldist(c, false);
if(archimedean || ctof(c)) return c->master->distance;
@ -1202,7 +1250,7 @@ int celldist(cell *c) {
int celldistAlt(cell *c) {
if(masterless) {
if(torus) return celldist(c);
if(fulltorus) return celldist(c); // fix cylinder
int x, y;
tie(x,y) = vec_to_pair(decodeId(c->master));
return euclidAlt(x, y);
@ -1460,7 +1508,7 @@ cdata *getHeptagonCdata(heptagon *h) {
cdata *getEuclidCdata(int h) {
if(torus) {
if(euwrap) { // fix cylinder?
static cdata xx;
return &xx;
}
@ -1572,16 +1620,16 @@ map<pair<cell*, cell*>, int> saved_distances;
int celldistance(cell *c1, cell *c2) {
if((masterless) && (euclid6 || (euclid4 && PURE))) {
if(!torus)
return eudist(decodeId(c1->master) - decodeId(c2->master));
else if(torus && torusconfig::torus_mode == 0)
if(!euwrap)
return eudist(decodeId(c1->master) - decodeId(c2->master)); // fix cylinder
else if(euwrap && torusconfig::torus_mode == 0)
return torusmap()->dists[torusconfig::vec_to_id(decodeId(c1->master)-decodeId(c2->master))];
}
if(geometry == gFieldQuotient && !GOLDBERG)
return currfp.getdist(fieldpattern::fieldval(c1), fieldpattern::fieldval(c2));
if(sphere || quotient || torus) {
if(sphere || quotient || fulltorus) {
if(saved_distances.count(make_pair(c1,c2)))
return saved_distances[make_pair(c1,c2)];

View File

@ -1667,7 +1667,7 @@ geometryinfo ginf[gGUARD] = {
{"elliptic", "elliptic", 5, 3, qNONOR, gcSphere, 0, {{SEE_ALL, SEE_ALL}}, eVariation::bitruncated},
{"Zebra quotient", "Zebra", 7, 3, qSMALL | qZEBRA, gcHyperbolic, 0x00400, {{7, 5}}, eVariation::bitruncated},
{"field quotient", "field", 7, 3, qFIELD, gcHyperbolic, 0x00200, {{7, 5}}, eVariation::bitruncated},
{"torus/Klein bottle", "torus", 6, 3, qTORUS, gcEuclid, 0x00600, {{7, 7}}, eVariation::bitruncated},
{"torus/Klein bottle", "torus", 6, 3, qEUWRAP | qFULLTORUS, gcEuclid, 0x00600, {{7, 7}}, eVariation::bitruncated},
{"octagons", "oct", 8, 3, 0, gcHyperbolic, 0x08000, {{6, 4}}, eVariation::bitruncated},
{"four pentagons", "4x5", 5, 4, 0, gcHyperbolic, 0x08200, {{6, 4}}, eVariation::bitruncated},
{"four hexagons", "4x6", 6, 4, 0, gcHyperbolic, 0x08400, {{5, 3}}, eVariation::bitruncated},

View File

@ -201,7 +201,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, gBinaryTiling, gArchimedean,
gMacbeath, gBring, gSchmutzM2, gSchmutzM3,
gMacbeath, gBring, gSchmutzM2, gSchmutzM3,
gGUARD};
enum eGeometryClass { gcHyperbolic, gcEuclid, gcSphere };
@ -223,9 +223,10 @@ struct geometryinfo {
static const int qSMALL = 1;
static const int qFIELD = 2;
static const int qNONORIENTABLE = 4;
static const int qTORUS = 8;
static const int qEUWRAP = 8;
static const int qDOCKS = 16;
static const int qZEBRA = 32;
static const int qFULLTORUS = 64;
// note: dnext assumes that x&7 equals 7
static const int SEE_ALL = 50;

View File

@ -12,7 +12,7 @@ namespace whirlwind {
int fzebra3(cell *c) {
if(archimedean) return 0;
if(euclid) {
if(torus) return 0;
if(fulltorus) return 0;
int x, y;
tie(x,y) = cell_to_pair(c);
return 1+((((signed short)(y)+int(50000))/3)%3);
@ -543,7 +543,7 @@ namespace princess {
int dist(cell *c) {
if(c->land != laPalace && c->land != laDungeon) return OUT_OF_PALACE;
else if(quotient || sphere || torus) return OUT_OF_PRISON;
else if(quotient || sphere || fulltorus) return OUT_OF_PRISON;
else if(euclid) return celldistAlt(c);
else if(!c->master->alt) return OUT_OF_PRISON;
else return celldistAlt(c);
@ -826,7 +826,7 @@ namespace clearing {
if(quotient) return;
if(euclid) {
if(torus) return;
if(euwrap) return; // fix cylinder
if(pseudohept(c)) return;
c->monst = moMutant;
@ -2795,7 +2795,7 @@ namespace prairie {
c->LHU.fi.walldist = 8;
c->LHU.fi.walldist2 = 8;
if(torus) {
if(euwrap) { // fix cylinder
c->LHU.fi.rval = 0;
}
else if(euclid) {
@ -3540,7 +3540,7 @@ namespace dungeon {
*/
if(euclid) {
if(torus) return;
if(euwrap) return;
int x, y;
tie(x, y) = cell_to_pair(c);
string tab6[] = {

View File

@ -596,7 +596,7 @@ namespace conformal {
vector<pair<int, int> > torus_zeros;
void match_torus_period() {
void match_torus_period() { // fix cylinder
torus_zeros.clear();
for(int y=0; y<=200; y++)
for(int x=-200; x<=200; x++) {
@ -821,7 +821,7 @@ namespace conformal {
dialog::add_action([](){
dialog::editNumber(spiral_y, -20, 20, 1, 10, XLAT("spiral period: y"), "");
});
if(torus) {
if(euwrap) {
dialog::addSelItem(XLAT("match the period of the torus"), its(spiral_id), 'n');
dialog::add_action(match_torus_period);
}

View File

@ -116,6 +116,8 @@ void showTorusConfig() {
bool single = (mode.flags & torusconfig::TF_SINGLE);
bool square = (mode.flags & torusconfig::TF_SQUARE);
bool simple = (mode.flags & torusconfig::TF_SIMPLE);
bool cyl = (mode.flags & torusconfig::TF_CYL);
bool klein = (mode.flags & torusconfig::TF_KLEIN);
if(single) {
dialog::addSelItem(XLAT("number of cells (n)"), its(torusconfig::newqty), 'n');
@ -124,6 +126,10 @@ void showTorusConfig() {
else
dialog::addSelItem(XLAT("cell below 0 (d)"), its(torusconfig::newdy), 'd');
}
else if(cyl) {
dialog::addSelItem(XLAT("period (x)"), its(torusconfig::newsdx), 'x');
dialog::addSelItem(XLAT("period (y)"), its(torusconfig::newsdy), 'y');
}
else {
if(torusconfig::newsdx < 1) torusconfig::newsdx = 1;
if(torusconfig::newsdy < 1) torusconfig::newsdy = 1;
@ -136,6 +142,7 @@ void showTorusConfig() {
int valid = 2;
int adx = torusconfig::newsdx, ady = torusconfig::newsdy;
if(single) {
if(square) {
dialog::addInfo("this mode has bad patterns", 0x808080), valid = 1;
@ -149,6 +156,33 @@ void showTorusConfig() {
dialog::addInfo(XLAT("best if %1 is divisible by %2", "d+1", "3"), 0x808080), valid = 1;
}
}
else if(cyl) {
if(torusconfig::sdx == 0 && torusconfig::sdy == 0)
dialog::addInfo(XLAT("period cannot be 0"), 0x800000), valid = 0;
else if(square) {
if(torusconfig::newsdy & 1)
dialog::addInfo(XLAT("best if %1 is divisible by %2", "y", "2"), 0x808080), valid = 1;
if(torusconfig::newsdx & 1)
dialog::addInfo(XLAT("best if %1 is divisible by %2", "x", "2"), 0x808080), valid = 1;
if(!torus_bitrunc && valid == 1)
dialog::addInfo("incompatible with bitruncating", 0x808080), valid = 0;
if(klein && abs(adx) != abs(ady) && adx != 0 && ady != 0)
dialog::addInfo("Möbius band requires a symmetric period", 0x800000), valid = 0;
if(klein && ady)
dialog::addInfo("not implemented", 0x800000), valid = 0;
}
else {
if(torusconfig::newsdy % 3)
dialog::addInfo(XLAT("best if %1 is divisible by %2", "y", "3"), 0x808080), valid = 1;
if(torusconfig::newsdx % 3)
dialog::addInfo(XLAT("best if %1 is divisible by %2", "x", "3"), 0x808080), valid = 1;
if(klein && adx != 0 && ady != 0 && adx != -ady)
dialog::addInfo("Möbius band requires a symmetric period", 0x800000), valid = 0;
if(klein)
dialog::addInfo("not implemented", 0x800000), valid = 0;
}
}
else {
if(square) {
if(torusconfig::newsdx & 1)
@ -286,7 +320,7 @@ void showEuclideanMenu() {
for(int i=0; i<gGUARD; i++) {
bool on = geometry == i;
dynamicval<eGeometry> cg(geometry, eGeometry(i));
if(!!(quotient || elliptic || torus) != showquotients) continue;
if(!!(quotient || elliptic || euwrap) != showquotients) continue;
dialog::addBoolItem(XLAT(ginf[i].name), on, letter++);
dialog::lastItem().value += validclasses[land_validity(specialland).quality_level];
dialog::add_action([i] {
@ -397,7 +431,9 @@ void showEuclideanMenu() {
else if((tq & qNONORIENTABLE) && sphere) qstring = "elliptic";
else if(tq & qTORUS) qstring = "torus";
else if(tq & qFULLTORUS) qstring = "torus";
else if(tq & qEUWRAP) qstring = "cylinder";
else if(tq & qSMALL) qstring = ginf[geometry].shortname;
@ -437,7 +473,7 @@ void showEuclideanMenu() {
dialog::addBoolItem(XLAT("stereographic/orthogonal"), vid.alpha>10, '1');
else
dialog::addBoolItem(XLAT("Poincaré/Klein"), vid.alpha>.5, '1');
if(torus || geometry == gFieldQuotient)
if(euwrap || geometry == gFieldQuotient)
dialog::addItem(XLAT("advanced parameters"), '4');
dialog::addHelp();
dialog::addBack();
@ -482,7 +518,7 @@ void showEuclideanMenu() {
else if(uni == '5')
ewhichscreen ^= 3;
else if(uni == '4') {
if(torus)
if(euwrap)
prepare_torusconfig(),
pushScreen(showTorusConfig);
else if(geometry == gFieldQuotient)

View File

@ -81,7 +81,7 @@ transmatrix calc_relative_matrix(cell *c2, cell *c1, const hyperpoint& point_hin
if(binarytiling) return binary::relative_matrix(c2->master, c1->master);
if(archimedean) return arcm::relative_matrix(c2->master, c1->master);
if(torus) {
if(euwrap) {
transmatrix t = Id;
if(whateveri) printf("[%p,%d] ", c2, celldistance(c2, c1));
int mirrors = 0;
@ -182,7 +182,7 @@ transmatrix calc_relative_matrix(cell *c2, cell *c1, const hyperpoint& point_hin
transmatrix &ggmatrix(cell *c) {
transmatrix& t = gmatrix[c];
if(t[2][2] == 0) {
if(torus && centerover.at)
if(euwrap && centerover.at)
t = calc_relative_matrix(c, centerover.at, C0);
else if(euclid) {
if(!centerover.at) centerover = cwt;
@ -229,7 +229,7 @@ template<class T, class U>
void virtualRebase(cell*& base, T& at, bool tohex, const U& check) {
if(euclid || sphere) {
again:
if(torus) for(int i=0; i<6; i++) {
if(euwrap) for(int i=0; i<6; i++) {
auto newat = eumovedir(3+i) * at;
if(hdist0(check(newat)) < hdist0(check(at))) {
at = newat;

View File

@ -2156,7 +2156,7 @@ bool drawMonster(const transmatrix& Vparam, int ct, cell *c, color_t col) {
// also whatever in the lineview mode, and whatever in the quotient geometry
else if(isFriendly(c) || isBug(c) || (c->monst && conformal::on) || c->monst == moKrakenH || (isBull(c->monst) && c->mondir != NODIR) || c->monst == moButterfly || isMagneticPole(c->monst) ||
isSwitch(c->monst) || c->monst == moPair || (c->monst && (quotient || torus || dont_face_pc))) {
isSwitch(c->monst) || c->monst == moPair || (c->monst && (quotient || euwrap || dont_face_pc))) {
if(c->monst == moKrakenH) Vs = Vb, nospins = nospinb;
if(!nospins) Vs = Vs * ddspin(c, c->mondir, M_PI);
if(c->monst == moPair) Vs = Vs * xpush(-.12);
@ -3577,7 +3577,7 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
transmatrix& gm = gmatrix[c];
orig =
gm[2][2] == 0 ? true :
torus ? hypot(gm[0][2], gm[1][2]) >= hypot(V[0][2], V[1][2]) :
euwrap ? hypot(gm[0][2], gm[1][2]) >= hypot(V[0][2], V[1][2]) :
sphereflipped() ? fabs(gm[2][2]-1) <= fabs(V[2][2]-1) :
fabs(gm[2][2]-1) >= fabs(V[2][2]-1) - 1e-8;

View File

@ -816,7 +816,7 @@ void describeMouseover() {
if(euclid && cheater) {
out += " ("+its(cell_to_vec(c))+")";
if(!torus || torusconfig::torus_mode != torusconfig::tmSingle) {
if(!fulltorus || torusconfig::torus_mode != torusconfig::tmSingle) {
int x, y;
tie(x,y) = cell_to_pair(c);
out += " ("+its(short(x))+","+its(short(y))+")";

20
hyper.h
View File

@ -100,10 +100,11 @@ void addMessage(string s, char spamtype = 0);
#define nonorientable (ginf[geometry].quotientstyle & qNONORIENTABLE)
#define elliptic (sphere && nonorientable)
#define quotient (ginf[geometry].quotientstyle & (qSMALL | qFIELD | qDOCKS | qZEBRA))
#define torus (ginf[geometry].quotientstyle & qTORUS)
#define euwrap (ginf[geometry].quotientstyle & qEUWRAP)
#define fulltorus (ginf[geometry].quotientstyle & qFULLTORUS)
#define doall (ginf[geometry].quotientstyle)
#define smallbounded (sphere || (quotient & qSMALL) || torus)
#define bounded (sphere || quotient || torus)
#define smallbounded (sphere || (quotient & qSMALL) || fulltorus)
#define bounded (sphere || quotient || fulltorus)
#define masterless among(geometry, gEuclid, gEuclidSquare, gTorus)
#define sphere_narcm (sphere && !archimedean)
@ -3393,7 +3394,9 @@ string llts(long long i);
void clearMemoRPM();
extern int randompattern[landtypes];
extern int pair_to_vec(int x, int y);
cell*& euclideanAtCreate(int vec);
typedef pair<cell**, bool> euc_pointer;
euc_pointer euclideanAt(int vec);
euc_pointer euclideanAtCreate(int vec);
bool isCyclic(eLand l);
bool generateAll(eLand l);
void extendcheck(cell *c);
@ -3791,7 +3794,11 @@ namespace torusconfig {
tmStraight,
tmStraightHex,
tmKlein,
tmKleinHex
tmKleinHex,
tmCylinder,
tmCylinderHex,
tmMobius,
tmMobiusHex,
};
extern eTorusMode torus_mode;
@ -3810,7 +3817,8 @@ namespace torusconfig {
TF_WEIRD = 4,
TF_HEX = 16,
TF_SQUARE = 32,
TF_KLEIN = 256
TF_CYL = 64,
TF_KLEIN = 256,
};
flagtype tmflags();

View File

@ -665,7 +665,7 @@ ld spherity(const transmatrix& V) {
}
bool confusingGeometry() {
return elliptic || quotient || torus;
return elliptic || quotient || euwrap;
}
ld master_to_c7_angle() {
@ -1476,7 +1476,7 @@ bool do_draw(cell *c, const transmatrix& T) {
if(iz < -M_PI || iz >= M_PI) return false;
}
if(cells_drawn > vid.cells_drawn_limit) return false;
bool usr = vid.use_smart_range || quotient || torus;
bool usr = vid.use_smart_range || quotient || euwrap;
if(usr && cells_drawn >= 50 && !in_smart_range(T)) return false;
if(vid.use_smart_range == 2) setdist(c, 7, c);
return true;

View File

@ -190,7 +190,7 @@ void giantLandSwitch(cell *c, int d, cell *from) {
case laPalace: // -------------------------------------------------------------
if(hyperbolic_not37 || torus || S7 < 5 || archimedean) {
if(hyperbolic_not37 || fulltorus || S7 < 5 || archimedean) {
if(d == 9) {
int i = hrand(100);
if(i < 10)
@ -391,7 +391,7 @@ void giantLandSwitch(cell *c, int d, cell *from) {
if(d==8) {
if(randomPatternsMode)
c->wall = RANDPAT3(0) ? waCavewall : waCavefloor;
else if(torus) {
else if(fulltorus) {
c->wall = waCavefloor;
}
else if(euclid) {
@ -482,7 +482,7 @@ void giantLandSwitch(cell *c, int d, cell *from) {
}
else if(archimedean && arcm::current.have_line)
v = arcm::linespattern(c) ? 24 : 16;
else if(torus || hyperbolic_not37 || quotient || archimedean) {
else if(fulltorus || hyperbolic_not37 || quotient || archimedean) {
v = hrand(100) < 25 ? 24 : 16;
}
else if(euclid) {
@ -541,7 +541,7 @@ void giantLandSwitch(cell *c, int d, cell *from) {
case laZebra:
if(d==8) {
if(torus) ;
if(fulltorus) ;
else if(archimedean && arcm::current.have_line)
c->wall = arcm::linespattern(c) ? waTrapdoor : waNone;
else if(euclid && !archimedean) {
@ -565,7 +565,7 @@ void giantLandSwitch(cell *c, int d, cell *from) {
case laWineyard:
if(d==8) {
if(torus) ;
if(fulltorus) ;
else if(archimedean && arcm::current.have_line)
c->wall = arcm::linespattern(c) ? waVinePlant : waNone;
else if(euclid && !archimedean) {
@ -1099,7 +1099,7 @@ void giantLandSwitch(cell *c, int d, cell *from) {
if(quotient && zebra40(c) == 5) {
c->wall = waChasm;
}
if(torus) {
if(fulltorus) {
int i = hrand(100);
if(i == 0) c->item = itTreat;
else if(i < 5) c->wall = waChasm;
@ -1152,7 +1152,7 @@ void giantLandSwitch(cell *c, int d, cell *from) {
bool randstorm = hyperbolic_not37 || NONSTDVAR || (quotient && geometry != gZebraQuotient);
if(d == 9) {
if(torus) {
if(fulltorus) {
int pid = decodeId(c->master);
if(pid == torusconfig::qty/3) c->wall = waCharged;
if(pid == torusconfig::qty*2/3) c->wall = waGrounded;
@ -2413,7 +2413,7 @@ void setdist(cell *c, int d, cell *from) {
#else
if(true) {
#endif
if(sphere || torus) setLandSphere(c);
if(sphere || fulltorus) setLandSphere(c);
else if(euclid) setLandEuclid(c);
if(weirdhyperbolic) setLandWeird(c);
if(quotient) { setland(c, specialland); setLandQuotient(c); }

View File

@ -1207,7 +1207,7 @@ land_validity_t& land_validity(eLand l) {
if(archimedean && DUAL)
return not_implemented;
// no equidistants supported in these geometries (big sphere is OK though)
if(quotient || elliptic || smallsphere || torus)
if(quotient || elliptic || smallsphere || euwrap)
return unbounded_only_except_bigsphere;
// Yendorian only implemented in standard
if(l == laEndorian && geometry)
@ -1390,7 +1390,7 @@ land_validity_t& land_validity(eLand l) {
return great_walls_missing;
// highlight Crossroads on Euclidean
if(euclid && !torus && (l == laCrossroads || l == laCrossroads4))
if(euclid && !euwrap && (l == laCrossroads || l == laCrossroads4)) // fix cylinder
return full_game;
// highlight Zebra-based lands on Zebra Quotient!
@ -1427,7 +1427,7 @@ land_validity_t& land_validity(eLand l) {
return pattern_not_implemented_exclude;
}
if(l == laStorms && torus)
if(l == laStorms && fulltorus)
return interesting;
if(l == laMagnetic || l == laBrownian)

View File

@ -80,7 +80,7 @@ unsigned bitmajority(unsigned a, unsigned b, unsigned c) {
}
int eufifty(cell *c) {
if(torus) {
if(fulltorus) {
if(c->land == laWildWest) return cell_to_vec(c) % 37;
else return cell_to_vec(c) % 27;
}
@ -347,7 +347,7 @@ int fieldval_uniq(cell *c) {
if(ctof(c)) return c->master->fieldval;
else return createMov(c, 0)->master->fieldval + 256 * createMov(c,2)->master->fieldval + (1<<16) * createMov(c,4)->master->fieldval;
}
else if(torus) {
else if(fulltorus) {
return decodeId(c->master);
}
else if(euclid) {
@ -365,7 +365,7 @@ int fieldval_uniq(cell *c) {
}
int fieldval_uniq_rand(cell *c, int randval) {
if(sphere || torus || euclid || NONSTDVAR)
if(sphere || euclid || NONSTDVAR)
// we do not care in these cases
return fieldval_uniq(c);
if(ctof(c)) return currfp.gmul(c->master->fieldval, randval)/7;
@ -433,7 +433,7 @@ int getHemisphere(heptagon *h, int which) {
}
int getHemisphere(cell *c, int which) {
if(torus) return 0;
if(euwrap) return 0;
if(which == 0 && GOLDBERG && has_nice_dual()) {
set<cell*> visited;
vector<cell*> q;

View File

@ -57,7 +57,7 @@ ld widthfactor = 5;
ld label_scale = 1;
void fundamental_marker() {
if(!funmode || !(quotient || torus || elliptic)) return;
if(!funmode || !(quotient || euwrap || elliptic)) return;
same.clear();
gm.clear();

View File

@ -411,13 +411,14 @@ void buildcellcrawler(cell *c, cellcrawler& cr, int dir) {
map<int, cellcrawler> scc;
pair<int, int> get_cellcrawler_id(cell *c) {
if(among(geometry, gZebraQuotient, gMinimal)) {
if(among(geometry, gZebraQuotient, gMinimal) || (euwrap && !fulltorus)) {
// Zebra Quotient does exhibit some symmetries,
// but these are so small anyway that it is safer to just build
// a crawler for every neuron
return make_pair(neuronId(*getNeuronSlow(c)), 0);
// not yet implemented for cylinder
}
if(torus && (torusconfig::tmflags() & torusconfig::TF_KLEIN))
if(fulltorus && (torusconfig::tmflags() & torusconfig::TF_KLEIN))
return make_pair(cell_to_pair(c).second * 2 + ctof(c), 0);
int id = 0, dir = 0;
if(GOLDBERG) {

View File

@ -166,7 +166,7 @@ void notimpl() {
hyperpoint where(int i, cell *base) {
auto m = vdata[i].m;
if(m->base == base) return tC0(m->at);
else if(quotient || elliptic || torus) {
else if(confusingGeometry()) {
return calc_relative_matrix(m->base, base, C0) * tC0(m->at);
}
else {
@ -177,7 +177,7 @@ hyperpoint where(int i, cell *base) {
void addedge(int i, int j, edgeinfo *ei) {
cell *base =
(quotient || elliptic || torus) ? vdata[i].m->base : currentmap->gamestart();
confusingGeometry() ? vdata[i].m->base : currentmap->gamestart();
hyperpoint hi = where(i, base);
hyperpoint hj = where(j, base);
double d = hdist(hi, hj);
@ -1172,7 +1172,7 @@ bool drawVertex(const transmatrix &V, cell *c, shmup::monster *m) {
if(hilite) ghilite = true;
bool multidraw = quotient || torus;
bool multidraw = quotient || euwrap;
if(ei->lastdraw < frameid || multidraw) {
ei->lastdraw = frameid;

View File

@ -575,7 +575,7 @@ void buildRug() {
need_mouseh = true;
good_shape = false;
if(torus) {
if(euwrap) {
good_shape = true;
buildTorusRug();
return;
@ -812,7 +812,7 @@ int divides = 0;
bool stop = false;
bool subdivide_further() {
if(torus) return false;
if(euwrap) return false;
return isize(points) * 4 < vertex_limit;
}
@ -991,7 +991,7 @@ void addNewPoints() {
if(anticusp_factor && detect_cusps())
return;
if(torus || qvalid == isize(points)) {
if(euwrap || qvalid == isize(points)) {
subdivide();
return;
}

View File

@ -172,7 +172,7 @@ void initgame() {
clear_euland(specialland);
if(euclid && specialland == laPrincessQuest) {
cell *c = euclideanAtCreate(pair_to_vec(EPX, EPY));
cell *c = *euclideanAtCreate(pair_to_vec(EPX, EPY)).first;
princess::generating = true;
c->land = laPalace;
setdist(c, 7 - getDistLimit() - genrange_bonus, NULL);

View File

@ -82,6 +82,10 @@ int gmod(int i, int j) {
return i;
}
int gdiv(int i, int j) {
return (i - gmod(i, j)) / j;
}
ld frac(ld x) {
x -= int(x);
if(x < 0) x++;