mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2025-01-11 18:00:34 +00:00
torus config editing
This commit is contained in:
parent
a90b7cc86d
commit
b28320b141
7
cell.cpp
7
cell.cpp
@ -221,7 +221,12 @@ namespace torusconfig {
|
|||||||
// values as the default -- otherwise the three-color
|
// values as the default -- otherwise the three-color
|
||||||
// pattern breaks. Also, they should have no common
|
// pattern breaks. Also, they should have no common
|
||||||
// prime divisor.
|
// prime divisor.
|
||||||
int qty = 127*3, dx = 1, dy = -11*2;
|
int def_qty = 127*3, dx = 1, def_dy = -11*2;
|
||||||
|
int qty = def_qty, dy = def_dy;
|
||||||
|
|
||||||
|
// new values to change
|
||||||
|
int newqty, newdy;
|
||||||
|
int torus_cx, torus_cy;
|
||||||
}
|
}
|
||||||
|
|
||||||
int decodeId(heptagon* h);
|
int decodeId(heptagon* h);
|
||||||
|
@ -59,6 +59,7 @@ bool inv::on;
|
|||||||
#include "config.cpp"
|
#include "config.cpp"
|
||||||
#include "scores.cpp"
|
#include "scores.cpp"
|
||||||
#include "menus.cpp"
|
#include "menus.cpp"
|
||||||
|
#include "geom-exp.cpp"
|
||||||
#include "quit.cpp"
|
#include "quit.cpp"
|
||||||
#include "shmup.cpp"
|
#include "shmup.cpp"
|
||||||
#if CAP_ROGUEVIZ
|
#if CAP_ROGUEVIZ
|
||||||
|
297
geom-exp.cpp
Normal file
297
geom-exp.cpp
Normal file
@ -0,0 +1,297 @@
|
|||||||
|
// -- geometry menu --
|
||||||
|
|
||||||
|
int eupage = 0;
|
||||||
|
int euperpage = 21;
|
||||||
|
|
||||||
|
const char *curvenames[8] = {
|
||||||
|
"0", "1", "2", "extremely hyperbolic", "strongly hyperbolic", "strongly hyperbolic", "moderately hyperbolic", "weakly hyperbolic"
|
||||||
|
};
|
||||||
|
|
||||||
|
string euchelp =
|
||||||
|
"If you want to know how much the gameplay is affected by the "
|
||||||
|
"hyperbolic geometry in HyperRogue, this mode is for you!\n\n"
|
||||||
|
|
||||||
|
"You can try many different geometries here. We start by gluing "
|
||||||
|
"n-gons in such a way that k of them meet in every vertex. "
|
||||||
|
"Depending on n and k, this either folds into a sphere, unfolds into a plane, "
|
||||||
|
"or requires a hyperbolic space. The result may be then 'truncated' by "
|
||||||
|
"replacing each vertex by a 2k-gon. Furthermore, you can play "
|
||||||
|
"with quotient geometries. For example, the elliptic geometry is "
|
||||||
|
"obtained from the sphere by making the antipodes be the same point, "
|
||||||
|
"so you return to the same spot (but as a mirror image) after going there. "
|
||||||
|
"Have fun experimenting! "
|
||||||
|
"Achievements and leaderboards do not work in geometry experiments, "
|
||||||
|
"except some specific ones.\n\n"
|
||||||
|
"In standard geometry (truncated or not), you can play the full game, but in other geometries "
|
||||||
|
"you select a particular land. Lands are unlocked by visiting them in this "
|
||||||
|
"session, or permanently by collecting 25 treasure. Try Crossroads in Euclidean "
|
||||||
|
"or chaos mode in non-standard non-quotient hyperbolic to visit many lands. "
|
||||||
|
"Highlights:\n"
|
||||||
|
"* Crystal World and Warped Coast can be understood as extra geometries.\n"
|
||||||
|
"* Halloween is specially designed for spherical geometry.\n"
|
||||||
|
"* To see the difference, try Hunting Grounds in Euclidean -- it is impossible.\n";
|
||||||
|
|
||||||
|
int ewhichscreen = 2;
|
||||||
|
|
||||||
|
void showQuotientConfig() {}
|
||||||
|
|
||||||
|
void showTorusConfig() {
|
||||||
|
cmode = sm::SIDE | sm::TORUSCONFIG;
|
||||||
|
gamescreen(2);
|
||||||
|
|
||||||
|
dialog::init(XLAT("advanced concfiguration"));
|
||||||
|
|
||||||
|
dialog::addSelItem(XLAT("number of cells (n)"), its(torusconfig::newqty), 'n');
|
||||||
|
dialog::addSelItem(XLAT("cell bottom-right from 0 (d)"), its(torusconfig::newdy), 'd');
|
||||||
|
|
||||||
|
if(torusconfig::newqty % 3)
|
||||||
|
dialog::addInfo("best if n is divisible by 3", 0x808080);
|
||||||
|
|
||||||
|
if((torusconfig::newdy + 999999) % 3 != 2)
|
||||||
|
dialog::addInfo("best if d+1 is divisible by 3", 0x808080);
|
||||||
|
|
||||||
|
dialog::addSelItem(XLAT("scale factor"), fts(vid.scale), 'z');
|
||||||
|
|
||||||
|
#if CAP_RUG
|
||||||
|
dialog::addBoolItem(XLAT("hypersian rug mode"), (rug::rugged), 'u');
|
||||||
|
#endif
|
||||||
|
|
||||||
|
dialog::addItem("activate", 'a');
|
||||||
|
dialog::addItem("default", 'c');
|
||||||
|
|
||||||
|
keyhandler = [] (int sym, int uni) {
|
||||||
|
if(uni == 'n')
|
||||||
|
dialog::editNumber(torusconfig::newqty, 0, 1000, 3, torusconfig::def_qty, XLAT("number of cells (n)"), "");
|
||||||
|
else if(uni == 'd')
|
||||||
|
dialog::editNumber(torusconfig::newdy, -1000, 1000, 3, -torusconfig::def_dy, XLAT("cell bottom-right from 0 (d)"), "");
|
||||||
|
else if((uni == 'a' || uni == '\n') && torusconfig::newqty >= 3 && abs(torusconfig::newdy) < torusconfig::newqty ) {
|
||||||
|
targetgeometry = gEuclid; restartGame('g');
|
||||||
|
torusconfig::qty = torusconfig::newqty;
|
||||||
|
torusconfig::dy = torusconfig::newdy;
|
||||||
|
targetgeometry = gTorus; restartGame('g');
|
||||||
|
}
|
||||||
|
else if(uni == 'c') {
|
||||||
|
targetgeometry = gEuclid; restartGame('g');
|
||||||
|
torusconfig::qty = torusconfig::def_qty;
|
||||||
|
torusconfig::dy = torusconfig::def_dy;
|
||||||
|
targetgeometry = gTorus; restartGame('g');
|
||||||
|
}
|
||||||
|
else if(uni == 'z') editScale();
|
||||||
|
else if(uni == 'u') rug::select();
|
||||||
|
else if(doexiton(sym, uni))
|
||||||
|
popScreen();
|
||||||
|
};
|
||||||
|
|
||||||
|
dialog::display();
|
||||||
|
}
|
||||||
|
|
||||||
|
void showEuclideanMenu() {
|
||||||
|
cmode = sm::SIDE;
|
||||||
|
gamescreen(0);
|
||||||
|
if(cheater) for(int i=0; i<landtypes; i++) landvisited[i] = true;
|
||||||
|
for(int i=0; i<landtypes; i++)
|
||||||
|
if(hiitemsMax(treasureType(eLand(i))) >= 25) landvisited[i] = true;
|
||||||
|
landvisited[laCrossroads] = true;
|
||||||
|
landvisited[laIce] = true;
|
||||||
|
landvisited[laHunting] = true;
|
||||||
|
landvisited[laMirrorOld] = true;
|
||||||
|
landvisited[laPrincessQuest] = cheater || princess::everSaved;
|
||||||
|
landvisited[laWildWest] = true;
|
||||||
|
landvisited[laHalloween] = true;
|
||||||
|
landvisited[laWarpCoast] = true;
|
||||||
|
landvisited[laGraveyard] = true;
|
||||||
|
landvisited[laDual] = true;
|
||||||
|
landvisited[laCA] = true;
|
||||||
|
// for(int i=2; i<lt; i++) landvisited[i] = true;
|
||||||
|
|
||||||
|
if(geometry == gNormal || ewhichscreen == 2) {
|
||||||
|
dialog::init(XLAT("experiment with geometry"));
|
||||||
|
int ts = ginf[geometry].sides;
|
||||||
|
int tv = ginf[geometry].vertex;
|
||||||
|
int tq = ginf[geometry].quotientstyle;
|
||||||
|
int nom = (nontruncated ? tv : tv+ts) * ((tq & qELLIP) ? 2 : 4);
|
||||||
|
int denom = (2*ts + 2*tv - ts * tv);
|
||||||
|
|
||||||
|
dialog::addSelItem(XLAT("land"), XLAT1(linf[specialland].name), '5');
|
||||||
|
dialog::addBreak(50);
|
||||||
|
|
||||||
|
for(int i=0; i<gGUARD; i++)
|
||||||
|
dialog::addBoolItem(XLAT(ginf[i].name), geometry == i, 'a'+i);
|
||||||
|
|
||||||
|
dialog::addBreak(50);
|
||||||
|
|
||||||
|
if(ts == 6 && tv == 3)
|
||||||
|
dialog::addSelItem(XLAT("truncated"), XLAT("does not matter"), 't');
|
||||||
|
else
|
||||||
|
dialog::addBoolItem(XLAT("truncated"), !nontruncated, 't');
|
||||||
|
|
||||||
|
dialog::addBreak(50);
|
||||||
|
|
||||||
|
int worldsize = denom ? nom/denom : 0;
|
||||||
|
if(tq & qTORUS) worldsize = torusconfig::qty;
|
||||||
|
if(tq & qZEBRA) worldsize = nontruncated ? 12 : 40;
|
||||||
|
if(tq & qFIELD) {
|
||||||
|
worldsize = size(currfp.matrices) / ts;
|
||||||
|
if(!nontruncated) worldsize = ((ts+tv)*worldsize) / tv;
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog::addSelItem(XLAT("sides per face"), its(ts), 0);
|
||||||
|
dialog::addSelItem(XLAT("faces per vertex"), its(tv), 0);
|
||||||
|
|
||||||
|
string qstring = "none";
|
||||||
|
if(tq & qZEBRA) qstring = "zebra";
|
||||||
|
|
||||||
|
else if(tq & qFIELD) qstring = "field";
|
||||||
|
|
||||||
|
else if(tq & qELLIP) qstring = "torus";
|
||||||
|
|
||||||
|
else if(tq & qTORUS) qstring = "torus";
|
||||||
|
|
||||||
|
dialog::addSelItem(XLAT("quotient space"), XLAT(qstring), 0);
|
||||||
|
|
||||||
|
dialog::addSelItem(XLAT("size of the world"),
|
||||||
|
worldsize < 0 ? "exp(∞)*" + (nom%denom ? its(nom)+"/"+its(-denom) : its(-worldsize)):
|
||||||
|
worldsize == 0 ? "∞" :
|
||||||
|
its(worldsize),
|
||||||
|
'3');
|
||||||
|
|
||||||
|
switch(ginf[geometry].cclass) {
|
||||||
|
case 0:
|
||||||
|
dialog::addSelItem(XLAT("Curvature"), XLAT("hyperbolic"), 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
dialog::addSelItem(XLAT("Curvature"), XLAT("flat"), 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
dialog::addSelItem(XLAT("Curvature"), XLAT("spherical"), 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(sphere)
|
||||||
|
dialog::addBoolItem(XLAT("stereographic/orthogonal"), vid.alpha>10, '1');
|
||||||
|
else
|
||||||
|
dialog::addBoolItem(XLAT("Poincaré/Klein"), vid.alpha>.5, '1');
|
||||||
|
if(torus || quotient == 2)
|
||||||
|
dialog::addItem(XLAT("advanced parameters"), '4');
|
||||||
|
dialog::addItem(XLAT("help"), SDLK_F1);
|
||||||
|
dialog::addItem(XLAT("back"), '0');
|
||||||
|
dialog::display();
|
||||||
|
|
||||||
|
keyhandler = [] (int sym, int uni) {
|
||||||
|
dialog::handleNavigation(sym, uni);
|
||||||
|
if(uni >= 'a' && uni < 'a'+gGUARD) {
|
||||||
|
targetgeometry = eGeometry(uni - 'a');
|
||||||
|
restartGame(geometry == targetgeometry ? 0 : 'g');
|
||||||
|
pushScreen(showEuclideanMenu);
|
||||||
|
}
|
||||||
|
else if(uni == 't') {
|
||||||
|
if(!euclid) {
|
||||||
|
restartGame('7');
|
||||||
|
pushScreen(showEuclideanMenu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(uni == '2' || sym == SDLK_F1) gotoHelp(euchelp);
|
||||||
|
else if(uni == '3') { viewdists = !viewdists; if(viewdists) popScreenAll(); }
|
||||||
|
else if(uni == '1' && !euclid) {
|
||||||
|
if(sphere) {
|
||||||
|
if(vid.alpha < 10) { vid.alpha = 999; vid.scale = 998; }
|
||||||
|
else {vid.alpha = 1; vid.scale = .4; }
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(vid.alpha > .5) { vid.alpha = 0; vid.scale = 1; }
|
||||||
|
else {vid.alpha = 1; vid.scale = 1; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(uni == '5')
|
||||||
|
ewhichscreen ^= 3;
|
||||||
|
else if(uni == '4') {
|
||||||
|
if(torus)
|
||||||
|
torusconfig::newdy = torusconfig::dy,
|
||||||
|
torusconfig::newqty = torusconfig::qty,
|
||||||
|
pushScreen(showTorusConfig);
|
||||||
|
if(quotient==2) pushScreen(showQuotientConfig);
|
||||||
|
}
|
||||||
|
else if(doexiton(sym, uni))
|
||||||
|
popScreen();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
|
||||||
|
generateLandList(isLandValid);
|
||||||
|
|
||||||
|
for(int i=0; i<euperpage; i++) {
|
||||||
|
if(euperpage * eupage + i >= size(landlist)) { dialog::addBreak(100); break; }
|
||||||
|
eLand l = landlist[euperpage * eupage + i];
|
||||||
|
char ch;
|
||||||
|
if(i < 26) ch = 'a' + i;
|
||||||
|
else ch = 'A' + (i-26);
|
||||||
|
string validclasses[4] = {"", " (½)", "", " (!)"};
|
||||||
|
string s = XLAT1(linf[l].name);
|
||||||
|
|
||||||
|
if(landvisited[l]) {
|
||||||
|
dialog::addBoolItem(s, l == specialland, ch);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dialog::addSelItem(s, XLAT("(locked)"), ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog::lastItem().color = linf[l].color;
|
||||||
|
dialog::lastItem().value += validclasses[isLandValid(l)];
|
||||||
|
}
|
||||||
|
dialog::addBreak(50);
|
||||||
|
if(chaosUnlocked && !quotient && !euclid && !sphere)
|
||||||
|
dialog::addItem(XLAT("Chaos mode"), '1');
|
||||||
|
dialog::addItem(XLAT("next page"), '-');
|
||||||
|
|
||||||
|
dialog::addItem(XLAT("help"), SDLK_F1);
|
||||||
|
dialog::addItem(XLAT("back"), '0');
|
||||||
|
dialog::display();
|
||||||
|
|
||||||
|
keyhandler = [] (int sym, int uni) {
|
||||||
|
dialog::handleNavigation(sym, uni);
|
||||||
|
int lid;
|
||||||
|
if(uni >= 'a' && uni <= 'z') lid = uni - 'a';
|
||||||
|
else if(uni >= 'A' && uni <= 'Z') lid = 26 + uni - 'A';
|
||||||
|
else lid = -1;
|
||||||
|
|
||||||
|
if(lid >= 0) lid += euperpage * eupage;
|
||||||
|
|
||||||
|
if(uni == '5')
|
||||||
|
ewhichscreen ^= 3;
|
||||||
|
else if(uni == '-' || uni == PSEUDOKEY_WHEELUP || uni == PSEUDOKEY_WHEELDOWN) {
|
||||||
|
eupage++;
|
||||||
|
if(eupage * euperpage >= size(landlist)) eupage = 0;
|
||||||
|
}
|
||||||
|
else if(uni == '1') {
|
||||||
|
if(chaosUnlocked) {
|
||||||
|
restartGame('C');
|
||||||
|
pushScreen(showEuclideanMenu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(lid >= 0 && lid < size(landlist)) {
|
||||||
|
eLand nland = landlist[lid];
|
||||||
|
if(landvisited[nland]) {
|
||||||
|
specialland = nland;
|
||||||
|
restartGame(tactic::on ? 't' : 0);
|
||||||
|
pushScreen(showEuclideanMenu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(uni == '2' || sym == SDLK_F1) gotoHelp(euchelp);
|
||||||
|
else if(doexiton(sym, uni)) popScreen();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void runGeometryExperiments() {
|
||||||
|
specialland = getLandForList(cwt.c);
|
||||||
|
pushScreen(showEuclideanMenu);
|
||||||
|
}
|
||||||
|
|
@ -3067,6 +3067,7 @@ bool dodrawcell(cell *c) {
|
|||||||
if(c->mpdist > 7 && !cheater) return false;
|
if(c->mpdist > 7 && !cheater) return false;
|
||||||
// always show on the torus rug
|
// always show on the torus rug
|
||||||
if(rug::rugged && torus) return true;
|
if(rug::rugged && torus) return true;
|
||||||
|
if(cmode & sm::TORUSCONFIG) return true;
|
||||||
// in the Yendor Challenge, scrolling back is forbidden
|
// in the Yendor Challenge, scrolling back is forbidden
|
||||||
if(c->cpdist > 7 && (yendor::on && !cheater)) return false;
|
if(c->cpdist > 7 && (yendor::on && !cheater)) return false;
|
||||||
// (incorrect comment) too far, no bugs nearby
|
// (incorrect comment) too far, no bugs nearby
|
||||||
@ -3343,6 +3344,14 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
|
|||||||
PPR_TEXT); */
|
PPR_TEXT); */
|
||||||
queuestr(V, (cd > 9 ? .6 : 1) * .2, label, 0xFF000000 + distcolors[cd&7], 1);
|
queuestr(V, (cd > 9 ? .6 : 1) * .2, label, 0xFF000000 + distcolors[cd&7], 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(cmode & sm::TORUSCONFIG) {
|
||||||
|
using namespace torusconfig;
|
||||||
|
int cd = torus_cx * dx + torus_cy * newdy;
|
||||||
|
cd %= newqty; if(cd<0) cd += newqty;
|
||||||
|
string label = its(cd);
|
||||||
|
queuestr(V, cd ? .2 : .6, label, cd == 0 ? 0xFFFF0040 : 0xFFFFFFD0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
asciicol = wcol;
|
asciicol = wcol;
|
||||||
|
|
||||||
|
1
hyper.h
1
hyper.h
@ -1443,6 +1443,7 @@ namespace sm {
|
|||||||
static const int CENTER = 1024;
|
static const int CENTER = 1024;
|
||||||
static const int A3 = 2048; // affects poly
|
static const int A3 = 2048; // affects poly
|
||||||
static const int ZOOMABLE = 4096;
|
static const int ZOOMABLE = 4096;
|
||||||
|
static const int TORUSCONFIG = 8192;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace linepatterns {
|
namespace linepatterns {
|
||||||
|
17
hypgraph.cpp
17
hypgraph.cpp
@ -390,6 +390,10 @@ transmatrix eumovedir(int d) {
|
|||||||
return eumove(0,0);
|
return eumove(0,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ld matrixnorm(const transmatrix& Mat) {
|
||||||
|
return Mat[0][2] * Mat[0][2] + Mat[1][2] * Mat[1][2];
|
||||||
|
}
|
||||||
|
|
||||||
void drawEuclidean() {
|
void drawEuclidean() {
|
||||||
DEBB(DF_GRAPH, (debugfile,"drawEuclidean\n"));
|
DEBB(DF_GRAPH, (debugfile,"drawEuclidean\n"));
|
||||||
eucoord px=0, py=0;
|
eucoord px=0, py=0;
|
||||||
@ -402,18 +406,20 @@ void drawEuclidean() {
|
|||||||
pid = decodeId(centerover->master);
|
pid = decodeId(centerover->master);
|
||||||
else
|
else
|
||||||
decodeMaster(centerover->master, px, py);
|
decodeMaster(centerover->master, px, py);
|
||||||
|
|
||||||
int minsx = mindx-1, maxsx=maxdx+1, minsy=mindy-1, maxsy=maxdy+1;
|
int minsx = mindx-1, maxsx=maxdx+1, minsy=mindy-1, maxsy=maxdy+1;
|
||||||
mindx=maxdx=mindy=maxdy=0;
|
mindx=maxdx=mindy=maxdy=0;
|
||||||
|
|
||||||
static ld centerd;
|
|
||||||
|
|
||||||
transmatrix View0 = View;
|
transmatrix View0 = View;
|
||||||
|
|
||||||
ld cellrad = vid.radius / (EUCSCALE + vid.alphax);
|
ld cellrad = vid.radius / (EUCSCALE + vid.alphax);
|
||||||
|
|
||||||
|
ld centerd = matrixnorm(View0);
|
||||||
|
|
||||||
for(int dx=minsx; dx<=maxsx; dx++)
|
for(int dx=minsx; dx<=maxsx; dx++)
|
||||||
for(int dy=minsy; dy<=maxsy; dy++) {
|
for(int dy=minsy; dy<=maxsy; dy++) {
|
||||||
|
torusconfig::torus_cx = dx;
|
||||||
|
torusconfig::torus_cy = dy;
|
||||||
reclevel = eudist(dx, dy);
|
reclevel = eudist(dx, dy);
|
||||||
cell *c;
|
cell *c;
|
||||||
transmatrix Mat;
|
transmatrix Mat;
|
||||||
@ -432,9 +438,8 @@ void drawEuclidean() {
|
|||||||
Mat = View0 * Mat;
|
Mat = View0 * Mat;
|
||||||
|
|
||||||
if(torus) {
|
if(torus) {
|
||||||
ld locald = (Mat[0][2] * Mat[0][2] + Mat[1][2] * Mat[1][2]);
|
ld locald = matrixnorm(Mat);
|
||||||
if(c == centerover) centerd = locald;
|
if(locald < centerd) centerd = locald, centerover = c, View = View0 * eumove(dx, dy);
|
||||||
else if(locald < centerd) centerd = locald, centerover = c, View = View0 * eumove(dx, dy);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mat[0][0] = -1;
|
// Mat[0][0] = -1;
|
||||||
|
250
menus.cpp
250
menus.cpp
@ -305,6 +305,12 @@ void showMainMenu() {
|
|||||||
|
|
||||||
// -- display modes --
|
// -- display modes --
|
||||||
|
|
||||||
|
void editScale() {
|
||||||
|
dialog::editNumber(vid.scale, .001, 1000, .1, 1, XLAT("scale factor"),
|
||||||
|
XLAT("Scale the displayed model."));
|
||||||
|
dialog::scaleLog();
|
||||||
|
}
|
||||||
|
|
||||||
void showDisplayMode() {
|
void showDisplayMode() {
|
||||||
cmode = sm::SIDE;
|
cmode = sm::SIDE;
|
||||||
gamescreen(0);
|
gamescreen(0);
|
||||||
@ -355,11 +361,7 @@ void showDisplayMode() {
|
|||||||
|
|
||||||
if(xuni == 'p') projectionDialog();
|
if(xuni == 'p') projectionDialog();
|
||||||
|
|
||||||
if(xuni == 'z') {
|
if(xuni == 'z') editScale();
|
||||||
dialog::editNumber(vid.scale, .001, 1000, .1, 1, XLAT("scale factor"),
|
|
||||||
XLAT("Scale the displayed model."));
|
|
||||||
dialog::scaleLog();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(xuni == 'm') { vid.monmode += 60 + (shiftmul > 0 ? 1 : -1); vid.monmode %= 6; }
|
if(xuni == 'm') { vid.monmode += 60 + (shiftmul > 0 ? 1 : -1); vid.monmode %= 6; }
|
||||||
|
|
||||||
@ -543,244 +545,6 @@ void showChangeMode() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- geometry menu --
|
|
||||||
|
|
||||||
int eupage = 0;
|
|
||||||
int euperpage = 21;
|
|
||||||
|
|
||||||
const char *curvenames[8] = {
|
|
||||||
"0", "1", "2", "extremely hyperbolic", "strongly hyperbolic", "strongly hyperbolic", "moderately hyperbolic", "weakly hyperbolic"
|
|
||||||
};
|
|
||||||
|
|
||||||
string euchelp =
|
|
||||||
"If you want to know how much the gameplay is affected by the "
|
|
||||||
"hyperbolic geometry in HyperRogue, this mode is for you!\n\n"
|
|
||||||
|
|
||||||
"You can try many different geometries here. We start by gluing "
|
|
||||||
"n-gons in such a way that k of them meet in every vertex. "
|
|
||||||
"Depending on n and k, this either folds into a sphere, unfolds into a plane, "
|
|
||||||
"or requires a hyperbolic space. The result may be then 'truncated' by "
|
|
||||||
"replacing each vertex by a 2k-gon. Furthermore, you can play "
|
|
||||||
"with quotient geometries. For example, the elliptic geometry is "
|
|
||||||
"obtained from the sphere by making the antipodes be the same point, "
|
|
||||||
"so you return to the same spot (but as a mirror image) after going there. "
|
|
||||||
"Have fun experimenting! "
|
|
||||||
"Achievements and leaderboards do not work in geometry experiments, "
|
|
||||||
"except some specific ones.\n\n"
|
|
||||||
"In standard geometry (truncated or not), you can play the full game, but in other geometries "
|
|
||||||
"you select a particular land. Lands are unlocked by visiting them in this "
|
|
||||||
"session, or permanently by collecting 25 treasure. Try Crossroads in Euclidean "
|
|
||||||
"or chaos mode in non-standard non-quotient hyperbolic to visit many lands. "
|
|
||||||
"Highlights:\n"
|
|
||||||
"* Crystal World and Warped Coast can be understood as extra geometries.\n"
|
|
||||||
"* Halloween is specially designed for spherical geometry.\n"
|
|
||||||
"* To see the difference, try Hunting Grounds in Euclidean -- it is impossible.\n";
|
|
||||||
|
|
||||||
int ewhichscreen = 2;
|
|
||||||
|
|
||||||
void showEuclideanMenu() {
|
|
||||||
cmode = sm::SIDE;
|
|
||||||
gamescreen(0);
|
|
||||||
int s = vid.fsize;
|
|
||||||
if(cheater) for(int i=0; i<landtypes; i++) landvisited[i] = true;
|
|
||||||
for(int i=0; i<landtypes; i++)
|
|
||||||
if(hiitemsMax(treasureType(eLand(i))) >= 25) landvisited[i] = true;
|
|
||||||
landvisited[laCrossroads] = true;
|
|
||||||
landvisited[laIce] = true;
|
|
||||||
landvisited[laHunting] = true;
|
|
||||||
landvisited[laMirrorOld] = true;
|
|
||||||
landvisited[laPrincessQuest] = cheater || princess::everSaved;
|
|
||||||
landvisited[laWildWest] = true;
|
|
||||||
landvisited[laHalloween] = true;
|
|
||||||
landvisited[laWarpCoast] = true;
|
|
||||||
landvisited[laGraveyard] = true;
|
|
||||||
landvisited[laDual] = true;
|
|
||||||
landvisited[laCA] = true;
|
|
||||||
// for(int i=2; i<lt; i++) landvisited[i] = true;
|
|
||||||
|
|
||||||
if(geometry == gNormal || ewhichscreen == 2) {
|
|
||||||
dialog::init(XLAT("experiment with geometry"));
|
|
||||||
int ts = ginf[geometry].sides;
|
|
||||||
int tv = ginf[geometry].vertex;
|
|
||||||
int tq = ginf[geometry].quotientstyle;
|
|
||||||
int nom = (nontruncated ? tv : tv+ts) * ((tq & qELLIP) ? 2 : 4);
|
|
||||||
int denom = (2*ts + 2*tv - ts * tv);
|
|
||||||
|
|
||||||
dialog::addSelItem(XLAT("land"), XLAT1(linf[specialland].name), '5');
|
|
||||||
dialog::addBreak(50);
|
|
||||||
|
|
||||||
for(int i=0; i<gGUARD; i++)
|
|
||||||
dialog::addBoolItem(XLAT(ginf[i].name), geometry == i, 'a'+i);
|
|
||||||
|
|
||||||
dialog::addBreak(50);
|
|
||||||
|
|
||||||
if(ts == 6 && tv == 3)
|
|
||||||
dialog::addSelItem(XLAT("truncated"), XLAT("does not matter"), 't');
|
|
||||||
else
|
|
||||||
dialog::addBoolItem(XLAT("truncated"), !nontruncated, 't');
|
|
||||||
|
|
||||||
dialog::addBreak(50);
|
|
||||||
|
|
||||||
int worldsize = denom ? nom/denom : 0;
|
|
||||||
if(tq & qTORUS) worldsize = torusconfig::qty;
|
|
||||||
if(tq & qZEBRA) worldsize = nontruncated ? 12 : 40;
|
|
||||||
if(tq & qFIELD) {
|
|
||||||
worldsize = size(currfp.matrices) / ts;
|
|
||||||
if(!nontruncated) worldsize = ((ts+tv)*worldsize) / tv;
|
|
||||||
}
|
|
||||||
|
|
||||||
dialog::addSelItem(XLAT("sides per face"), its(ts), 0);
|
|
||||||
dialog::addSelItem(XLAT("faces per vertex"), its(tv), 0);
|
|
||||||
|
|
||||||
string qstring = "none";
|
|
||||||
if(tq & qZEBRA) qstring = "zebra";
|
|
||||||
|
|
||||||
else if(tq & qFIELD) qstring = "field";
|
|
||||||
|
|
||||||
else if(tq & qELLIP) qstring = "torus";
|
|
||||||
|
|
||||||
else if(tq & qTORUS) qstring = "torus";
|
|
||||||
|
|
||||||
dialog::addSelItem(XLAT("quotient space"), XLAT(qstring), 0);
|
|
||||||
|
|
||||||
dialog::addSelItem(XLAT("size of the world"),
|
|
||||||
worldsize < 0 ? "exp(∞)*" + (nom%denom ? its(nom)+"/"+its(-denom) : its(-worldsize)):
|
|
||||||
worldsize == 0 ? "∞" :
|
|
||||||
its(worldsize),
|
|
||||||
'3');
|
|
||||||
|
|
||||||
switch(ginf[geometry].cclass) {
|
|
||||||
case 0:
|
|
||||||
dialog::addSelItem(XLAT("Curvature"), XLAT("hyperbolic"), 0);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
dialog::addSelItem(XLAT("Curvature"), XLAT("flat"), 0);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
dialog::addSelItem(XLAT("Curvature"), XLAT("spherical"), 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(sphere)
|
|
||||||
dialog::addBoolItem(XLAT("stereographic/orthogonal"), vid.alpha>10, '1');
|
|
||||||
else
|
|
||||||
dialog::addBoolItem(XLAT("Poincaré/Klein"), vid.alpha>.5, '1');
|
|
||||||
dialog::addItem(XLAT("help"), SDLK_F1);
|
|
||||||
dialog::addItem(XLAT("back"), '0');
|
|
||||||
dialog::display();
|
|
||||||
|
|
||||||
keyhandler = [] (int sym, int uni) {
|
|
||||||
dialog::handleNavigation(sym, uni);
|
|
||||||
if(uni >= 'a' && uni < 'a'+gGUARD) {
|
|
||||||
targetgeometry = eGeometry(uni - 'a');
|
|
||||||
restartGame(geometry == targetgeometry ? 0 : 'g');
|
|
||||||
pushScreen(showEuclideanMenu);
|
|
||||||
}
|
|
||||||
else if(uni == 't') {
|
|
||||||
if(!euclid) {
|
|
||||||
restartGame('7');
|
|
||||||
pushScreen(showEuclideanMenu);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(uni == '2' || sym == SDLK_F1) gotoHelp(euchelp);
|
|
||||||
else if(uni == '3') { viewdists = !viewdists; if(viewdists) popScreenAll(); }
|
|
||||||
else if(uni == '1' && !euclid) {
|
|
||||||
if(sphere) {
|
|
||||||
if(vid.alpha < 10) { vid.alpha = 999; vid.scale = 998; }
|
|
||||||
else {vid.alpha = 1; vid.scale = .4; }
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(vid.alpha > .5) { vid.alpha = 0; vid.scale = 1; }
|
|
||||||
else {vid.alpha = 1; vid.scale = 1; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(uni == '5')
|
|
||||||
ewhichscreen ^= 3;
|
|
||||||
else if(doexiton(sym, uni))
|
|
||||||
popScreen();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
|
|
||||||
generateLandList(isLandValid);
|
|
||||||
|
|
||||||
for(int i=0; i<euperpage; i++) {
|
|
||||||
if(euperpage * eupage + i >= size(landlist)) { dialog::addBreak(100); break; }
|
|
||||||
eLand l = landlist[euperpage * eupage + i];
|
|
||||||
char ch;
|
|
||||||
if(i < 26) ch = 'a' + i;
|
|
||||||
else ch = 'A' + (i-26);
|
|
||||||
string validclasses[4] = {"", " (½)", "", " (!)"};
|
|
||||||
string s = XLAT1(linf[l].name);
|
|
||||||
|
|
||||||
if(landvisited[l]) {
|
|
||||||
dialog::addBoolItem(s, l == specialland, ch);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
dialog::addSelItem(s, XLAT("(locked)"), ch);
|
|
||||||
}
|
|
||||||
|
|
||||||
dialog::lastItem().color = linf[l].color;
|
|
||||||
dialog::lastItem().value += validclasses[isLandValid(l)];
|
|
||||||
}
|
|
||||||
dialog::addBreak(50);
|
|
||||||
if(chaosUnlocked && !quotient && !euclid && !sphere)
|
|
||||||
dialog::addItem(XLAT("Chaos mode"), '1');
|
|
||||||
dialog::addItem(XLAT("next page"), '-');
|
|
||||||
|
|
||||||
dialog::addItem(XLAT("help"), SDLK_F1);
|
|
||||||
dialog::addItem(XLAT("back"), '0');
|
|
||||||
dialog::display();
|
|
||||||
|
|
||||||
vid.fsize = s;
|
|
||||||
keyhandler = [] (int sym, int uni) {
|
|
||||||
dialog::handleNavigation(sym, uni);
|
|
||||||
int lid;
|
|
||||||
if(uni >= 'a' && uni <= 'z') lid = uni - 'a';
|
|
||||||
else if(uni >= 'A' && uni <= 'Z') lid = 26 + uni - 'A';
|
|
||||||
else lid = -1;
|
|
||||||
|
|
||||||
if(lid >= 0) lid += euperpage * eupage;
|
|
||||||
|
|
||||||
if(uni == '5')
|
|
||||||
ewhichscreen ^= 3;
|
|
||||||
else if(uni == '-' || uni == PSEUDOKEY_WHEELUP || uni == PSEUDOKEY_WHEELDOWN) {
|
|
||||||
eupage++;
|
|
||||||
if(eupage * euperpage >= size(landlist)) eupage = 0;
|
|
||||||
}
|
|
||||||
else if(uni == '1') {
|
|
||||||
if(chaosUnlocked) {
|
|
||||||
restartGame('C');
|
|
||||||
pushScreen(showEuclideanMenu);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(lid >= 0 && lid < size(landlist)) {
|
|
||||||
eLand nland = landlist[lid];
|
|
||||||
if(landvisited[nland]) {
|
|
||||||
specialland = nland;
|
|
||||||
restartGame(tactic::on ? 't' : 0);
|
|
||||||
pushScreen(showEuclideanMenu);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(uni == '2' || sym == SDLK_F1) gotoHelp(euchelp);
|
|
||||||
else if(doexiton(sym, uni)) popScreen();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void runGeometryExperiments() {
|
|
||||||
specialland = getLandForList(cwt.c);
|
|
||||||
pushScreen(showEuclideanMenu);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool showstartmenu;
|
bool showstartmenu;
|
||||||
|
|
||||||
bool showHalloween() {
|
bool showHalloween() {
|
||||||
|
Loading…
Reference in New Issue
Block a user