expansion, ctrl+E cheat, fix with distance calculation

This commit is contained in:
Zeno Rogue 2017-04-04 11:13:15 +02:00
parent 0d7d2cf825
commit 645a64e8c9
15 changed files with 684 additions and 442 deletions

757
cell.cpp
View File

@ -1,9 +1,10 @@
// Hyperbolic Rogue -- cells
// Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details
// cells the game is played on
#define DEBMEM(x) // { x fflush(stdout); }
int fix6(int a) { return (a+96)% 6; }
int fix7(int a) { return (a+420)%S7; }
@ -61,8 +62,260 @@ typedef unsigned short eucoord;
#include <map>
struct cdata {
int val[4];
int bits;
};
// list all cells in distance at most maxdist, or until when maxcount cells are reached
struct celllister {
vector<cell*> lst;
vector<int> tmps;
vector<int> dists;
bool listed(cell *c) {
return c->aitmp >= 0 && c->aitmp < size(lst) && lst[c->aitmp] == c;
}
void add(cell *c, int d) {
if(listed(c)) return;
c->aitmp = size(lst);
tmps.push_back(c->aitmp);
lst.push_back(c);
dists.push_back(d);
}
int getdist(cell *c) { return dists[c->aitmp]; }
~celllister() {
for(int i=0; i<size(lst); i++) lst[i]->aitmp = tmps[i];
}
celllister(cell *orig, int maxdist, int maxcount, cell *breakon) {
lst.clear();
tmps.clear();
dists.clear();
add(orig, 0);
cell *last = orig;
for(int i=0; i<size(lst); i++) {
cell *c = lst[i];
if(maxdist) forCellCM(c2, c) {
add(c2, dists[i]+1);
if(c2 == breakon) return;
}
if(c == last) {
if(size(lst) >= maxcount || dists[i]+1 == maxdist) break;
last = lst[size(lst)-1];
maxdist--;
}
}
}
};
// -- hrmap ---
#include <typeinfo>
struct hrmap {
virtual heptagon *getOrigin() { return NULL; }
virtual cell *gamestart() { return getOrigin()->c7; }
virtual ~hrmap() { printf("removing %s\n", typeid(this).name()); };
virtual vector<cell*>& allcells() { return dcal; }
virtual void verify() { }
};
hrmap *currentmap;
vector<hrmap*> allmaps;
// --- auxiliary hyperbolic map for horocycles ---
struct hrmap_alternate : hrmap {
heptagon *origin;
hrmap_alternate(heptagon *o) { origin = o; }
~hrmap_alternate() { clearfrom(origin); }
};
// --- hyperbolic geometry ---
struct hrmap_hyperbolic : hrmap {
heptagon *origin;
hrmap_hyperbolic() {
origin = new heptagon;
heptagon& h = *origin;
h.s = hsOrigin;
h.emeraldval = 98;
h.zebraval = 40;
h.fiftyval = 0;
h.fieldval = 0;
h.rval0 = h.rval1 = 0;
h.cdata = NULL;
for(int i=0; i<7; i++) h.move[i] = NULL;
h.spintable = 0;
h.alt = NULL;
h.distance = 0;
h.c7 = newCell(7, origin);
}
heptagon *getOrigin() { return origin; }
~hrmap_hyperbolic() {
DEBMEM ( verifycells(origin); )
clearfrom(origin);
}
void verify() { verifycells(origin); }
};
// --- spherical geometry ---
int spherecells() {
if(S7 == 5) return (elliptic?6:12);
if(S7 == 4) return (elliptic?3:6);
if(S7 == 3) return 4;
if(S7 == 2) return (elliptic?1:2);
if(S7 == 1) return 1;
return 12;
}
struct hrmap_spherical : hrmap {
heptagon *dodecahedron[12];
hrmap_spherical() {
for(int i=0; i<spherecells(); i++) {
heptagon& h = *(dodecahedron[i] = new heptagon);
h.s = hsOrigin;
h.emeraldval = i;
h.zebraval = i;
h.fiftyval = i;
h.rval0 = h.rval1 = 0;
h.alt = NULL;
h.cdata = NULL;
h.spintable = 0;
for(int i=0; i<S7; i++) h.move[i] = NULL;
h.c7 = newCell(S7, &h);
}
for(int i=0; i<S7; i++) {
dodecahedron[0]->move[i] = dodecahedron[i+1];
dodecahedron[0]->setspin(i, 0);
dodecahedron[i+1]->move[0] = dodecahedron[0];
dodecahedron[i+1]->setspin(0, i);
dodecahedron[i+1]->move[1] = dodecahedron[(i+S7-1)%S7+1];
dodecahedron[i+1]->setspin(1, S7-1);
dodecahedron[i+1]->move[S7-1] = dodecahedron[(i+1)%S7+1];
dodecahedron[i+1]->setspin(S7-1, 1);
if(S7 == 5 && elliptic) {
dodecahedron[i+1]->move[2] = dodecahedron[(i+2)%S7+1];
dodecahedron[i+1]->setspin(2, 3 + 8);
dodecahedron[i+1]->move[3] = dodecahedron[(i+3)%S7+1];
dodecahedron[i+1]->setspin(3, 2 + 8);
}
else if(S7 == 5) {
dodecahedron[6]->move[i] = dodecahedron[7+i];
dodecahedron[6]->setspin(i, 0);
dodecahedron[7+i]->move[0] = dodecahedron[6];
dodecahedron[7+i]->setspin(0, i);
dodecahedron[i+7]->move[1] = dodecahedron[(i+4)%5+7];
dodecahedron[i+7]->setspin(1, 4);
dodecahedron[i+7]->move[4] = dodecahedron[(i+1)%5+7];
dodecahedron[i+7]->setspin(4, 1);
dodecahedron[i+1]->move[2] = dodecahedron[7+(10-i)%5];
dodecahedron[i+1]->setspin(2, 2);
dodecahedron[7+(10-i)%5]->move[2] = dodecahedron[1+i];
dodecahedron[7+(10-i)%5]->setspin(2, 2);
dodecahedron[i+1]->move[3] = dodecahedron[7+(9-i)%5];
dodecahedron[i+1]->setspin(3, 3);
dodecahedron[7+(9-i)%5]->move[3] = dodecahedron[i+1];
dodecahedron[7+(9-i)%5]->setspin(3, 3);
}
if(S7 == 4) {
dodecahedron[5]->move[3-i] = dodecahedron[i+1];
dodecahedron[5]->setspin(3-i, 2);
dodecahedron[i+1]->move[2] = dodecahedron[5];
dodecahedron[i+1]->setspin(2, 3-i);
}
}
}
heptagon *getOrigin() { return dodecahedron[0]; }
~hrmap_spherical() {
for(int i=0; i<spherecells(); i++) clearHexes(dodecahedron[i]);
for(int i=0; i<spherecells(); i++) delete dodecahedron[i];
}
void verify() {
for(int i=0; i<spherecells(); i++) for(int k=0; k<S7; k++) {
heptspin hs;
hs.h = dodecahedron[i];
hs.spin = k;
hs = hsstep(hs, 0);
hs = hsspin(hs, S7-1);
hs = hsstep(hs, 0);
hs = hsspin(hs, S7-1);
hs = hsstep(hs, 0);
hs = hsspin(hs, S7-1);
if(hs.h != dodecahedron[i]) printf("error %d,%d\n", i, k);
}
for(int i=0; i<spherecells(); i++) verifycells(dodecahedron[i]);
}
};
heptagon *getDodecahedron(int i) {
hrmap_spherical *s = dynamic_cast<hrmap_spherical*> (currentmap);
if(!s) return NULL;
return s->dodecahedron[i];
}
// --- euclidean geometry ---
cell*& euclideanAtCreate(eucoord x, eucoord y);
struct hrmap_euclidean : hrmap {
cell *gamestart() {
return euclideanAtCreate(0,0);
}
struct euclideanSlab {
cell* a[256][256];
euclideanSlab() {
for(int y=0; y<256; y++) for(int x=0; x<256; x++)
a[y][x] = NULL;
}
~euclideanSlab() {
for(int y=0; y<256; y++) for(int x=0; x<256; x++)
if(a[y][x]) delete a[y][x];
}
};
euclideanSlab* euclidean[256][256];
hrmap_euclidean() {
for(int y=0; y<256; y++) for(int x=0; x<256; x++)
euclidean[y][x] = NULL;
}
cell*& at(eucoord x, eucoord y) {
euclideanSlab*& slab = euclidean[y>>8][x>>8];
if(!slab) slab = new hrmap_euclidean::euclideanSlab;
return slab->a[y&255][x&255];
}
map<heptagon*, struct cdata> eucdata;
~hrmap_euclidean() {
for(int y=0; y<256; y++) for(int x=0; x<256; x++)
if(euclidean[y][x]) {
delete euclidean[y][x];
euclidean[y][x] = NULL;
}
eucdata.clear();
}
};
union heptacoder {
heptagon *h;
struct { eucoord x; eucoord y; } c;
@ -79,6 +332,145 @@ heptagon* encodeMaster(eucoord x, eucoord y) {
return u.h;
}
// --- quotient geometry ---
namespace quotientspace {
struct code {
int c[8];
};
bool operator == (const code& c1, const code &c2) {
for(int i=0; i<8; i++) if(c1.c[i] != c2.c[i]) return false;
return true;
}
bool operator < (const code& c1, const code &c2) {
for(int i=0; i<8; i++) if(c1.c[i] != c2.c[i]) return c1.c[i] < c2.c[i];
return false;
}
int cod(heptagon *h) {
return zebra40(h->c7);
}
code get(heptspin hs) {
code res;
res.c[0] = cod(hs.h);
for(int i=1; i<8; i++) {
res.c[i] = cod(hsstep(hs, 0).h);
hs = hsspin(hs, 1);
}
return res;
}
int rvadd = 0, rvdir = 1;
int rv(int x) { return (rvadd+x*rvdir) % 7; }
struct hrmap_quotient : hrmap {
hrmap_hyperbolic base;
vector<cell*> celllist;
cell *origin;
map<quotientspace::code, int> reachable;
vector<heptspin> bfsq;
vector<int> connections;
void add(const heptspin& hs) {
code g = get(hs);
if(!reachable.count(g)) {
reachable[g] = bfsq.size();
bfsq.push_back(hs);
add(hsspin(hs, 1));
}
}
vector<heptagon*> allh;
hrmap_quotient() {
if(quotient == 2) {
connections = fp43.connections;
}
else {
heptspin hs; hs.h = base.origin; hs.spin = 0;
reachable.clear();
bfsq.clear();
connections.clear();
add(hs);
for(int i=0; i<(int)bfsq.size(); i++) {
hs = hsstep(bfsq[i], 0);
add(hs);
connections.push_back(reachable[get(hs)]);
}
}
int TOT = connections.size() / 7;
printf("heptagons = %d\n", TOT);
printf("all cells = %d\n", TOT*10/3);
if(!TOT) exit(1);
allh.resize(TOT);
for(int i=0; i<TOT; i++) allh[i] = new heptagon;
// heptagon *oldorigin = origin;
allh[0]->alt = base.origin;
for(int i=0; i<TOT; i++) {
heptagon *h = allh[i];
if(i) {
h->alt = NULL;
}
if(true) {
h->s = hsOrigin;
h->emeraldval = 0;
h->zebraval = 0;
h->fiftyval = 0;
h->fieldval = 7*i;
h->rval0 = h->rval1 = 0; h->cdata = NULL;
h->distance = 0;
h->c7 = newCell(7, h);
}
for(int j=0; j<7; j++) {
h->move[rv(j)] = allh[connections[i*7+j]/7];
h->setspin(rv(j), rv(connections[i*7+j]%7));
}
}
for(int i=0; i<TOT; i++) {
generateAlts(allh[i]);
allh[i]->emeraldval = allh[i]->alt->emeraldval;
allh[i]->zebraval = allh[i]->alt->zebraval;
allh[i]->fiftyval = allh[i]->alt->fiftyval;
allh[i]->distance = allh[i]->alt->distance;
/* for(int j=0; j<7; j++)
allh[i]->move[j]->alt = createStep(allh[i]->alt, j); */
}
celllister cl(gamestart(), 100, 100000000, NULL);
celllist = cl.lst;
}
heptagon *getOrigin() { return allh[0]; }
~hrmap_quotient() {
for(int i=0; i<size(allh); i++) {
clearHexes(allh[i]);
delete allh[i];
}
}
vector<cell*>& allcells() { return celllist; }
};
};
// --- general ---
// very similar to createMove in heptagon.cpp
cell *createMov(cell *c, int d) {
@ -193,32 +585,17 @@ void eumerge(cell* c1, cell *c2, int s1, int s2) {
c2->mov[s2] = c1; tsetspin(c2->spintable, s2, s1);
}
struct euclideanSlab {
cell* a[256][256];
euclideanSlab() {
for(int y=0; y<256; y++) for(int x=0; x<256; x++)
a[y][x] = NULL;
}
~euclideanSlab() {
for(int y=0; y<256; y++) for(int x=0; x<256; x++)
if(a[y][x]) delete a[y][x];
}
};
euclideanSlab* euclidean[256][256];
// map<pair<eucoord, eucoord>, cell*> euclidean;
cell*& euclideanAt(eucoord x, eucoord y) {
euclideanSlab*& slab(euclidean[y>>8][x>>8]);
if(!slab) slab = new euclideanSlab;
return slab->a[y&255][x&255];
hrmap_euclidean* euc = dynamic_cast<hrmap_euclidean*> (currentmap);
return euc->at(x, y);
}
cell*& euclideanAtCreate(eucoord x, eucoord y) {
cell*& c ( euclideanAt(x,y) );
cell*& c = euclideanAt(x,y);
if(!c) {
c = newCell(6, &origin);
c = newCell(6, NULL);
c->master = encodeMaster(x,y);
euclideanAt(x,y) = c;
eumerge(c, euclideanAt(x+1,y), 0, 3);
@ -231,104 +608,20 @@ cell*& euclideanAtCreate(eucoord x, eucoord y) {
return c;
}
int spherecells() {
if(S7 == 5) return (elliptic?6:12);
if(S7 == 4) return (elliptic?3:6);
if(S7 == 3) return 4;
if(S7 == 2) return (elliptic?1:2);
if(S7 == 1) return 1;
return 12;
}
// initializer (also inits origin from heptagon.cpp)
void initcells() {
DEBB(DF_INIT, (debugfile,"initcells\n"));
if(sphere) {
for(int i=0; i<spherecells(); i++) {
heptagon& h = dodecahedron[i];
h.s = hsOrigin;
h.emeraldval = i;
h.zebraval = i;
h.fiftyval = i;
h.rval0 = h.rval1 = 0;
h.alt = NULL;
h.cdata = NULL;
h.spintable = 0;
for(int i=0; i<S7; i++) h.move[i] = NULL;
h.c7 = newCell(S7, &h);
}
for(int i=0; i<S7; i++) {
dodecahedron[0].move[i] = &dodecahedron[i+1];
dodecahedron[0].setspin(i, 0);
dodecahedron[i+1].move[0] = &dodecahedron[0];
dodecahedron[i+1].setspin(0, i);
dodecahedron[i+1].move[1] = &dodecahedron[(i+S7-1)%S7+1];
dodecahedron[i+1].setspin(1, S7-1);
dodecahedron[i+1].move[S7-1] = &dodecahedron[(i+1)%S7+1];
dodecahedron[i+1].setspin(S7-1, 1);
if(S7 == 5 && elliptic) {
dodecahedron[i+1].move[2] = &dodecahedron[(i+2)%S7+1];
dodecahedron[i+1].setspin(2, 3 + 8);
dodecahedron[i+1].move[3] = &dodecahedron[(i+3)%S7+1];
dodecahedron[i+1].setspin(3, 2 + 8);
}
else if(S7 == 5) {
dodecahedron[6].move[i] = &dodecahedron[7+i];
dodecahedron[6].setspin(i, 0);
dodecahedron[7+i].move[0] = &dodecahedron[6];
dodecahedron[7+i].setspin(0, i);
if(euclid) currentmap = new hrmap_euclidean;
else if(sphere) currentmap = new hrmap_spherical;
else if(quotient) currentmap = new quotientspace::hrmap_quotient;
else currentmap = new hrmap_hyperbolic;
dodecahedron[i+7].move[1] = &dodecahedron[(i+4)%5+7];
dodecahedron[i+7].setspin(1, 4);
dodecahedron[i+7].move[4] = &dodecahedron[(i+1)%5+7];
dodecahedron[i+7].setspin(4, 1);
dodecahedron[i+1].move[2] = &dodecahedron[7+(10-i)%5];
dodecahedron[i+1].setspin(2, 2);
dodecahedron[7+(10-i)%5].move[2] = &dodecahedron[1+i];
dodecahedron[7+(10-i)%5].setspin(2, 2);
allmaps.push_back(currentmap);
dodecahedron[i+1].move[3] = &dodecahedron[7+(9-i)%5];
dodecahedron[i+1].setspin(3, 3);
dodecahedron[7+(9-i)%5].move[3] = &dodecahedron[i+1];
dodecahedron[7+(9-i)%5].setspin(3, 3);
}
if(S7 == 4) {
dodecahedron[5].move[3-i] = &dodecahedron[i+1];
dodecahedron[5].setspin(3-i, 2);
dodecahedron[i+1].move[2] = &dodecahedron[5];
dodecahedron[i+1].setspin(2, 3-i);
}
}
}
else {
origin.s = hsOrigin;
origin.emeraldval = 98;
origin.zebraval = 40;
origin.fiftyval = 0;
origin.fieldval = 0;
origin.rval0 = origin.rval1 = 0;
origin.cdata = NULL;
for(int i=0; i<7; i++) origin.move[i] = NULL;
origin.spintable = 0;
origin.alt = NULL;
origin.distance = 0;
if(euclid)
origin.c7 = euclideanAtCreate(0,0);
else
origin.c7 = newCell(7, &origin);
}
if(quotient) quotientspace::build();
// origin.emeraldval =
// origin->emeraldval =
}
#define DEBMEM(x) // { x fflush(stdout); }
void clearcell(cell *c) {
if(!c) return;
DEBMEM ( printf("c%d %p\n", c->type, c); )
@ -380,7 +673,7 @@ void clearfrom(heptagon *at) {
at->move[i] = NULL;
}
clearHexes(at);
if(at != &origin) delete at;
delete at;
}
//printf("maxq = %d\n", maxq);
}
@ -400,11 +693,12 @@ void verifycell(cell *c) {
}
void verifycells(heptagon *at) {
for(int i=0; i<7; i++) if(at->move[i] && at->move[i]->move[at->spin(i)] && at->move[i]->move[at->spin(i)] != at) {
for(int i=0; i<S7; i++) if(at->move[i] && at->move[i]->move[at->spin(i)] && at->move[i]->move[at->spin(i)] != at) {
printf("hexmix error %p [%d s=%d] %p %p\n", at, i, at->spin(i), at->move[i], at->move[i]->move[at->spin(i)]);
}
if(!sphere && !quotient) for(int i=0; i<7; i++) if(at->move[i] && at->spin(i) == 0 && at->move[i] != &origin)
verifycells(at->move[i]);
if(!sphere && !quotient)
for(int i=0; i<7; i++) if(at->move[i] && at->spin(i) == 0 && at->s != hsOrigin)
verifycells(at->move[i]);
verifycell(at->c7);
}
@ -807,12 +1101,6 @@ map<heptagon*, int> spins;
#define RVAL_MASK 0x10000000
#define DATA_MASK 0x20000000
struct cdata {
int val[4];
int bits;
};
map<heptagon*, struct cdata> eucdata;
cdata orig_cdata;
void affect(cdata& d, short rv, signed char signum) {
@ -835,9 +1123,9 @@ void setHeptagonRval(heptagon *h) {
cdata *getHeptagonCdata(heptagon *h) {
if(h->cdata) return h->cdata;
if(sphere || quotient) h = &origin;
if(sphere || quotient) h = currentmap->gamestart()->master;
if(h == &origin) {
if(h == currentmap->gamestart()->master) {
return h->cdata = new cdata(orig_cdata);
}
@ -907,14 +1195,15 @@ cdata *getHeptagonCdata(heptagon *h) {
cdata *getEuclidCdata(heptagon *h) {
eucoord x, y;
if(eucdata.count(h)) return &(eucdata[h]);
hrmap_euclidean* euc = dynamic_cast<hrmap_euclidean*> (currentmap);
if(euc->eucdata.count(h)) return &(euc->eucdata[h]);
decodeMaster(h, x, y);
if(x == 0 && y == 0) {
cdata xx;
for(int i=0; i<4; i++) xx.val[i] = 0;
xx.bits = 0;
return &(eucdata[h] = xx);
return &(euc->eucdata[h] = xx);
}
int ord = 1, bid = 0;
while(!((x|y)&ord)) ord <<= 1, bid++;
@ -946,7 +1235,7 @@ cdata *getEuclidCdata(heptagon *h) {
if(gbit) xx.bits |= (1<<b);
}
return &(eucdata[h] = xx);
return &(euc->eucdata[h] = xx);
}
// impossible!
@ -981,52 +1270,6 @@ eLand getCLand(cell *c) {
return land_scape[b & 31];
}
// list all cells in distance at most maxdist, or until when maxcount cells are reached
struct celllister {
vector<cell*> lst;
vector<int> tmps;
vector<int> dists;
bool listed(cell *c) {
return c->aitmp >= 0 && c->aitmp < size(lst) && lst[c->aitmp] == c;
}
void add(cell *c, int d) {
if(listed(c)) return;
c->aitmp = size(lst);
tmps.push_back(c->aitmp);
lst.push_back(c);
dists.push_back(d);
}
int getdist(cell *c) { return dists[c->aitmp]; }
~celllister() {
for(int i=0; i<size(lst); i++) lst[i]->aitmp = tmps[i];
}
celllister(cell *orig, int maxdist, int maxcount, cell *breakon) {
lst.clear();
tmps.clear();
dists.clear();
add(orig, 0);
cell *last = orig;
for(int i=0; i<size(lst); i++) {
cell *c = lst[i];
if(maxdist) forCellCM(c2, c) {
add(c2, dists[i]+1);
if(c2 == breakon) return;
}
if(c == last) {
if(size(lst) >= maxcount || dists[i]+1 == maxdist) break;
last = lst[size(lst)-1];
maxdist--;
}
}
}
};
cell *heptatdir(cell *c, int d) {
if(d&1) {
cell *c2 = createMov(c, d);
@ -1098,6 +1341,9 @@ int celldistance(cell *c1, cell *c2) {
forCellEx(c, cl2) if(isNeighbor(c, cr1)) return d+2;
forCellEx(c, cl1) if(isNeighbor(c, cr2)) return d+2;
forCellEx(ca, cl2) forCellEx(cb, cr1) if(isNeighbor(ca, cb)) return d+3;
forCellEx(ca, cl1) forCellEx(cb, cr2) if(isNeighbor(ca, cb)) return d+3;
int d1 = celldist(cl1), d2 = celldist(cl2);
if(d1 >= d2) {
@ -1117,28 +1363,9 @@ int celldistance(cell *c1, cell *c2) {
}
}
void clearHyperbolicMemory() {
DEBMEM ( verifycells(&origin); )
clearfrom(&origin);
for(int i=0; i<size(allAlts); i++) clearfrom(allAlts[i]);
allAlts.clear();
}
void clearCellMemory() {
// EUCLIDEAN
if(sphere) {
for(int i=0; i<spherecells(); i++) clearHexes(&dodecahedron[i]);
}
else if(quotient) quotientspace::clear();
else if(euclid) {
for(int y=0; y<256; y++) for(int x=0; x<256; x++)
if(euclidean[y][x]) {
delete euclidean[y][x];
euclidean[y][x] = NULL;
}
eucdata.clear();
}
else clearHyperbolicMemory();
for(int i=0; i<size(allmaps); i++) delete allmaps[i];
allmaps.clear();
}
void clearMemory() {
@ -1153,22 +1380,6 @@ void clearMemory() {
DEBMEM ( printf("ok\n"); )
}
void verifyDodecahedron() {
for(int i=0; i<spherecells(); i++) for(int k=0; k<S7; k++) {
heptspin hs;
hs.h = &dodecahedron[i];
hs.spin = k;
hs = hsstep(hs, 0);
hs = hsspin(hs, S7-1);
hs = hsstep(hs, 0);
hs = hsspin(hs, S7-1);
hs = hsstep(hs, 0);
hs = hsspin(hs, S7-1);
if(hs.h != &dodecahedron[i]) printf("error %d,%d\n", i, k);
}
for(int i=0; i<spherecells(); i++) verifycells(&dodecahedron[i]);
}
int getHemisphere(cell *c, int which) {
if(c->type != 6) {
int id = c->master->fiftyval;
@ -1187,133 +1398,3 @@ int getHemisphere(cell *c, int which) {
}
}
namespace quotientspace {
vector<cell*> allcells;
struct code {
int c[8];
};
bool operator == (const code& c1, const code &c2) {
for(int i=0; i<8; i++) if(c1.c[i] != c2.c[i]) return false;
return true;
}
bool operator < (const code& c1, const code &c2) {
for(int i=0; i<8; i++) if(c1.c[i] != c2.c[i]) return c1.c[i] < c2.c[i];
return false;
}
map<code, int> reachable;
vector<heptspin> bfsq;
int cod(heptagon *h) {
return zebra40(h->c7);
}
code get(heptspin hs) {
code res;
res.c[0] = cod(hs.h);
for(int i=1; i<8; i++) {
res.c[i] = cod(hsstep(hs, 0).h);
hs = hsspin(hs, 1);
}
return res;
}
vector<int> connections;
int rvadd = 0, rvdir = 1;
int rv(int x) { return (rvadd+x*rvdir) % 7; } // if(x) return 7-x; else return x; }
void add(const heptspin& hs) {
code g = get(hs);
if(!reachable.count(g)) {
reachable[g] = bfsq.size();
bfsq.push_back(hs);
add(hsspin(hs, 1));
}
}
vector<heptagon*> allh;
void clear() {
clearfrom(origin.alt);
for(int i=0; i<size(allh); i++) {
clearHexes(allh[i]);
if(i) delete allh[i];
}
allh.clear();
allcells.clear();
}
void build() {
if(quotient == 2) {
connections = fp43.connections;
}
else {
heptspin hs; hs.h = &origin; hs.spin = 0;
reachable.clear();
bfsq.clear();
connections.clear();
add(hs);
for(int i=0; i<(int)bfsq.size(); i++) {
hs = hsstep(bfsq[i], 0);
add(hs);
connections.push_back(reachable[get(hs)]);
}
}
clearHyperbolicMemory();
origin.c7 = newCell(7, &origin);
int TOT = connections.size() / 7;
printf("heptagons = %d\n", TOT);
printf("all cells = %d\n", TOT*10/3);
if(!TOT) exit(1);
allh.resize(TOT);
for(int i=0; i<TOT; i++) allh[i] = i==0 ? &origin : new heptagon;
origin.alt = new heptagon;
*origin.alt = origin;
for(int i=0; i<7; i++) origin.alt->move[i] = NULL;
origin.alt->c7 = newCell(7, origin.alt);
for(int i=0; i<TOT; i++) {
heptagon *h = allh[i];
if(i) {
h->alt = NULL;
h->s = hsOrigin;
h->emeraldval = 0;
h->zebraval = 0;
h->fiftyval = 0;
h->fieldval = 7*i;
h->rval0 = h->rval1 = 0; h->cdata = NULL;
h->distance = 0;
h->c7 = newCell(7, h);
}
for(int j=0; j<7; j++) {
h->move[rv(j)] = allh[connections[i*7+j]/7];
h->setspin(rv(j), rv(connections[i*7+j]%7));
}
}
for(int i=0; i<TOT; i++) {
generateAlts(allh[i]);
allh[i]->emeraldval = allh[i]->alt->emeraldval;
allh[i]->zebraval = allh[i]->alt->zebraval;
allh[i]->fiftyval = allh[i]->alt->fiftyval;
allh[i]->distance = allh[i]->alt->distance;
/* for(int j=0; j<7; j++)
allh[i]->move[j]->alt = createStep(allh[i]->alt, j); */
}
celllister cl(origin.c7, 100, 100000000, NULL);
allcells = cl.lst;
}
}

View File

@ -1600,7 +1600,7 @@ namespace heat {
vinefires.clear();
rosefires.clear();
vector<cell*>& allcells = quotient ? quotientspace::allcells : dcal;
vector<cell*>& allcells = currentmap->allcells();
int dcs = size(allcells);
@ -1760,7 +1760,7 @@ namespace heat {
}
void dryforest() {
vector<cell*>& allcells = quotient ? quotientspace::allcells : dcal;
vector<cell*>& allcells = currentmap->allcells();
int dcs = size(allcells);
for(int i=0; i<dcs; i++) {
cell *c = allcells[i];
@ -1789,7 +1789,7 @@ bool gardener = false;
bool lifebrought = false; // was Life brought to the Dead Caves?
void livecaves() {
vector<cell*>& allcells = quotient ? quotientspace::allcells : dcal;
vector<cell*>& allcells = currentmap->allcells();
int dcs = size(allcells);
vector<cell*> bringlife;
@ -2708,7 +2708,7 @@ namespace ca {
void simulate() {
if(cwt.c->land != laCA) return;
vector<cell*>& allcells = quotient ? quotientspace::allcells : dcal;
vector<cell*>& allcells = currentmap->allcells();
int dcs = size(allcells);
bool willlive[dcs];
for(int i=0; i<dcs; i++) {

View File

@ -276,7 +276,7 @@ namespace conformal {
m->at = Id;
m->base = c;
v.push_back(m);
if(c == origin.c7) break;
if(c == currentmap->gamestart()) break;
for(int i=0; i<c->type; i++)
if(celldist(c->mov[i]) < celldist(c)) {
c = c->mov[i];
@ -586,12 +586,18 @@ namespace conformal {
setvideomode();
} */
}
else if(sym == 'x' && pmodel == mdPolygonal)
else if(sym == 'x' && pmodel == mdPolygonal) {
dialog::editNumber(polygonal::SI, 3, 10, 1, 4, XLAT("polygon sides"), "");
else if(sym == 'y' && pmodel == mdPolygonal)
dialog::sidedialog = true;
}
else if(sym == 'y' && pmodel == mdPolygonal) {
dialog::editNumber(polygonal::STAR, -1, 1, .1, 0, XLAT("star factor"), "");
else if(sym == 'n' && pmodel == mdPolygonal)
dialog::sidedialog = true;
}
else if(sym == 'n' && pmodel == mdPolygonal) {
dialog::editNumber(polygonal::deg, 2, MSI-1, 1, 2, XLAT("degree of the approximation"), "");
dialog::sidedialog = true;
}
else if(sym == 'x' && pmodel == mdPolynomial) {
polygonal::maxcoef = max(polygonal::maxcoef, polygonal::coefid);
int ci = polygonal::coefid + 1;

View File

@ -167,13 +167,20 @@ namespace dialog {
addBreak(brk);
}
int dcenter, dwidth;
bool sidedialog;
int displayLong(string str, int siz, int y, bool measure) {
int last = 0;
int lastspace = 0;
int xs = vid.xres * 618/1000;
int xo = vid.xres * 186/1000;
int xs, xo;
if(sidescreen)
xs = dwidth - vid.fsize, xo = vid.xres + vid.fsize;
else
xs = vid.xres * 618/1000, xo = vid.xres * 186/1000;
for(int i=0; i<=size(str); i++) {
int ls = 0;
@ -196,7 +203,7 @@ namespace dialog {
y += siz/2;
return y;
}
int tothei, dialogwidth, dfsize, dfspace, leftwidth, rightwidth, innerwidth, itemx, keyx, valuex;
string highlight_text;
@ -223,9 +230,9 @@ namespace dialog {
int fwidth = innerwidth + leftwidth + rightwidth;
dialogwidth = max(dialogwidth, fwidth);
itemx = (vid.xres - fwidth) / 2 + leftwidth;
keyx = (vid.xres - fwidth) / 2 + leftwidth - dfsize/2;
valuex = (vid.xres - fwidth) / 2 + leftwidth + innerwidth + dfsize/2;
itemx = dcenter - fwidth / 2 + leftwidth;
keyx = dcenter - fwidth / 2 + leftwidth - dfsize/2;
valuex = dcenter - fwidth / 2 + leftwidth + innerwidth + dfsize/2;
}
void display() {
@ -238,7 +245,16 @@ namespace dialog {
dfsize *= 3;
#endif
dfspace = dfsize * 5/4;
dcenter = vid.xres/2;
dwidth = vid.xres;
measure();
if(sidescreen) {
dwidth = vid.xres - vid.yres;
dcenter = (vid.xres + dwidth) / 2;
}
while(tothei > vid.yres - 5 * vid.fsize) {
int adfsize = int(dfsize * sqrt((vid.yres - 5. * vid.fsize) / tothei));
if(adfsize < dfsize-1) dfsize = adfsize + 1;
@ -246,7 +262,7 @@ namespace dialog {
dfspace = dfsize * 5/4;
measure();
}
while(dialogwidth > vid.xres) {
while(dialogwidth > dwidth) {
int adfsize = int(dfsize * sqrt(vid.xres * 1. / dialogwidth));
if(adfsize < dfsize-1) dfsize = adfsize + 1;
else dfsize--; // keep dfspace
@ -267,7 +283,7 @@ namespace dialog {
tothei += dfspace * I.scale / 100;
int mid = (top + tothei) / 2;
if(I.type == diTitle || I.type == diInfo) {
displayfr(vid.xres/2, mid, 2, dfsize * I.scale/100, I.body, I.color, 8);
displayfr(dcenter, mid, 2, dfsize * I.scale/100, I.body, I.color, 8);
}
else if(I.type == diItem) {
bool xthis = (mousey >= top && mousey < tothei);
@ -291,9 +307,15 @@ namespace dialog {
}
else if(I.type == diSlider) {
bool xthis = (mousey >= top && mousey < tothei);
displayfr(vid.xres*1/4, mid, 2, dfsize * I.scale/100, "(", I.color, 16);
displayfr(vid.xres*1/4 + double(vid.xres/2 * I.param), mid, 2, dfsize * I.scale/100, "#", I.color, 8);
displayfr(vid.xres*3/4, mid, 2, dfsize * I.scale/100, ")", I.color, 0);
int sl, sr;
if(sidescreen)
sl = vid.yres + vid.fsize*2, sr = vid.xres - vid.fsize*2;
else
sl = vid.xres/4, sr = vid.xres*3/4;
int sw = sr-sl;
displayfr(sl, mid, 2, dfsize * I.scale/100, "(", I.color, 16);
displayfr(sl + double(sw * I.param), mid, 2, dfsize * I.scale/100, "#", I.color, 8);
displayfr(sr, mid, 2, dfsize * I.scale/100, ")", I.color, 0);
if(xthis) getcstat = I.key, inslider = true;
}
}
@ -480,11 +502,13 @@ namespace dialog {
ne.scale = ne.inverse_scale = identity;
ne.intval = NULL;
ne.positive = false;
sidedialog = false;
}
void editNumber(int& x, int vmin, int vmax, int step, int dft, string title, string help) {
editNumber(ne.intbuf, vmin, vmax, step, dft, title, help);
ne.intbuf = x; ne.intval = &x; ne.s = its(x);
sidedialog = true;
}
string disp(ld x) { if(ne.intval) return its((int) (x+.5)); else return fts(x); }

View File

@ -348,9 +348,9 @@ bool pseudohept(cell *c) {
if(purehepta) {
if(sphere)
return
c->master == &dodecahedron[3] ||
c->master == &dodecahedron[5] ||
c->master == &dodecahedron[6];
c->master == getDodecahedron(3) ||
c->master == getDodecahedron(5) ||
c->master == getDodecahedron(6);
int z = zebra40(c);
return z == 5 || z == 8 || z == 15;
}

108
graph.cpp
View File

@ -2821,7 +2821,12 @@ bool bugsNearby(cell *c, int dist = 2) {
int minecolors[8] = {
0xFFFFFF, 0xF0, 0xF060, 0xF00000,
0x60, 0x600000, 0x00C0C0, 0
0x60, 0x600000, 0x00C0C0, 0x000000
};
int distcolors[8] = {
0xFFFFFF, 0xF0, 0xF060, 0xF00000,
0xA0A000, 0xA000A0, 0x00A0A0, 0xFFD500
};
const char* minetexts[8] = {
@ -3012,6 +3017,8 @@ transmatrix pushone() { return euclid ? eupush(1, 0) : xpush(sphere?.5 : 1); }
void drawMovementArrows(cell *c, transmatrix V) {
if(viewdists) return;
for(int d=0; d<8; d++) {
movedir md = vectodir(spin(-d * M_PI/4) * tC0(pushone()));
@ -3725,7 +3732,7 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
ivoryz = isGravityLand(c->land);
transmatrix& gm = gmatrix[c];
bool orig = (gm[2][2] == 0 || fabs(gm[2][2]-1) >= fabs(V[2][2]-1)) - 1e-8;
bool orig = (gm[2][2] == 0 || fabs(gm[2][2]-1) >= fabs(V[2][2]-1) - 1e-8);
if(sphere && vid.alpha > 1) {
long double d = V[2][2];
@ -3735,7 +3742,7 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
if(sphere && vid.alpha <= 1) {
if(V[2][2] < -.8) return;
}
if(orig) gm = V;
ld dist0 = hdist0(tC0(V)) - 1e-6;
@ -3859,6 +3866,19 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
int wcol, fcol, asciicol;
setcolors(c, wcol, fcol);
if(viewdists) {
int cd = celldistance(c, cwt.c);
string label = its(cd);
// string label = its(fieldpattern::getriverdistleft(c)) + its(fieldpattern::getriverdistright(c));
int dc = distcolors[cd&7];
wcol = gradient(wcol, dc, 0, .4, 1);
fcol = gradient(fcol, dc, 0, .4, 1);
/* queuepolyat(V, shFloor[ct6], darkena(gradient(0, distcolors[cd&7], 0, .25, 1), fd, 0xC0),
PPR_TEXT); */
queuestr(V, (cd > 9 ? .6 : 1) * .2, label, 0xFF000000 + distcolors[cd&7], 1);
}
asciicol = wcol;
if(c->land == laNone && c->wall == waNone)
@ -4316,12 +4336,6 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
#ifndef NOEDIT
if(viewdists) {
string label = its(celldistance(c, cwt.c));
// string label = its(fieldpattern::getriverdistleft(c)) + its(fieldpattern::getriverdistright(c));
queuestr(V, .5, label, 0xFFFFFFFF);
}
if(cmode == emMapEditor && mapeditor::displaycodes) {
int labeli = mapeditor::displaycodes == 1 ? mapeditor::realpattern(c) : mapeditor::subpattern(c);
@ -4353,7 +4367,7 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
queuestr(V, .6, buf, col);
#endif
}
if(realred(c->wall) && !wmspatial) {
int s = snakelevel(c);
if(s >= 1)
@ -5859,6 +5873,8 @@ void describeMouseover() {
if(webdisplay & 8) {
out += " LP:" + itsh(c->landparam)+"/"+its(turncount);
out += " CD:" + its(celldist(c));
out += " D:" + its(c->mpdist);
@ -6375,6 +6391,8 @@ void centerpc(ld aspd) {
void drawmovestar(double dx, double dy) {
if(viewdists) return;
DEBB(DF_GRAPH, (debugfile,"draw movestar\n"));
if(!playerfound) return;
@ -6574,6 +6592,8 @@ void checkpanjoy(double t) {
int realradius;
bool sidescreen;
void calcparam() {
DEBB(DF_GRAPH, (debugfile,"calc param\n"));
vid.xcenter = vid.xres / 2;
@ -6585,10 +6605,18 @@ void calcparam() {
realradius = min(realradius, vid.radius);
sidescreen = false;
if(vid.xres < vid.yres) {
vid.radius = int(vid.scale * vid.xcenter) - (ISIOS ? 10 : 2);
vid.ycenter = vid.yres - realradius - vid.fsize - (ISIOS ? 10 : 0);
}
else {
if(vid.xres >= vid.yres * 4/3 && dialog::sidedialog && cmode == emNumber)
sidescreen = true;
if(viewdists && cmode == emNormal && vid.xres >= vid.yres * 4/3) sidescreen = true;
if(sidescreen) vid.xcenter = vid.yres/2;
}
ld eye = vid.eye; if(pmodel || rug::rugged) eye = 0;
vid.beta = 1 + vid.alpha + eye;
@ -7069,6 +7097,42 @@ void drawStats() {
#ifdef ROGUEVIZ
if(rogueviz::on) return;
#endif
if(viewdists && sidescreen) {
dialog::init("");
int qty[64];
vector<cell*>& ac = currentmap->allcells();
for(int i=0; i<64; i++) qty[i] = 0;
for(int i=0; i<size(ac); i++) {
int d = celldistance(ac[i], cwt.c);
if(d >= 0 && d < 64) qty[d]++;
}
if(geometry == gNormal)
for(int i=purehepta?6:8; i<=15; i++)
qty[i] =
purehepta ?
3*qty[i-1] - qty[i-2]
: qty[i-1] + qty[i-2] + qty[i-3] - qty[i-4];
if(geometry == gEuclid)
for(int i=8; i<=15; i++) qty[i] = 6*i;
for(int i=0; i<64; i++) if(qty[i])
dialog::addInfo(its(qty[i]), distcolors[i&7]);
if(geometry == gNormal && !purehepta) {
dialog::addBreak(200);
dialog::addInfo("a(d+4) = a(d+3) + a(d+2) + a(d+1) - a(d)", 0xFFFFFF);
dialog::addInfo("a(d) ~ 1.72208^d", 0xFFFFFF);
}
if(geometry == gNormal && purehepta) {
dialog::addBreak(200);
dialog::addInfo("a(d+2) = 3a(d+1) - a(d+2)", 0xFFFFFF);
dialog::addInfo("a(d) ~ 2.61803^d", 0xFFFFFF);
}
if(geometry == gEuclid) {
dialog::addBreak(300);
dialog::addInfo("a(n) = 6n", 0xFFFFFF);
}
dialog::display();
}
if(sidescreen) return;
instat = false;
bool portrait = vid.xres < vid.yres;
int colspace = portrait ? (vid.yres - vid.xres - vid.fsize*3) : (vid.xres - vid.yres - 16) / 2;
@ -7402,7 +7466,8 @@ void drawscreen() {
if(cmode != emNormal && cmode != emDraw && cmode != emCustomizeChar) darken = 2;
if(cmode == emQuit && !canmove) darken = 0;
if(cmode == emOverview) darken = 16;
if(cmode == emNumber && dialog::lastmode == em3D) darken = 0;
if(sidescreen) darken = 0;
#ifndef NOEDIT
if(cmode == emMapEditor && !mapeditor::subscreen && !mapeditor::choosefile) darken = 0;
@ -7581,17 +7646,20 @@ void setvideomode() {
void restartGraph() {
DEBB(DF_INIT, (debugfile,"restartGraph\n"));
if(euclid) {
centerover = euclideanAtCreate(0,0);
}
else {
viewctr.h = &origin;
viewctr.spin = 0;
viewctr.mirrored = false;
}
View = Id;
webdisplay = 0;
if(sphere) View = spin(-M_PI/2);
if(currentmap) {
if(euclid) {
centerover = euclideanAtCreate(0,0);
}
else {
viewctr.h = currentmap->getOrigin();
viewctr.spin = 0;
viewctr.mirrored = false;
}
if(sphere) View = spin(-M_PI/2);
}
}
void resetview() {

View File

@ -95,11 +95,6 @@ hstate transition(hstate s, int dir) {
return hsError;
}
heptagon dodecahedron[12];
#define origin (dodecahedron[0])
vector<heptagon*> allAlts;
// create h->move[d] if not created yet
heptagon *createStep(heptagon *h, int d);
@ -118,7 +113,7 @@ heptagon *buildHeptagon(heptagon *parent, int d, hstate s, int pard = 0) {
h->zebraval = zebra_heptagon(parent->zebraval, d);
h->fieldval = fp43.connections[fieldpattern::btspin(parent->fieldval, d)];
h->rval0 = h->rval1 = 0; h->cdata = NULL;
if(parent == &origin || parent == origin.alt)
if(parent->s == hsOrigin)
h->fiftyval = fiftytable[0][d];
else
h->fiftyval = nextfiftyval(parent->fiftyval, parent->move[0]->fiftyval, d);
@ -211,7 +206,7 @@ heptspin hsspin(const heptspin &hs, int val) {
// display the coordinates of the heptagon
void backtrace(heptagon *pos) {
if(pos == &origin) return;
if(pos->s == hsOrigin) return;
backtrace(pos->move[0]);
printf(" %d", pos->spin(0));
}

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.roguetemple.hyperroid"
android:versionCode="9403" android:versionName="9.4c"
android:versionCode="9404" android:versionName="9.4d"
android:installLocation="auto">
<!-- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> -->
<!-- <uses-sdk android:minSdkVersion="9" android:targetSdkVersion="9" /> -->

View File

@ -1,6 +1,6 @@
#define VER "9.4d"
#define VERNUM 9404
#define VERNUM_HEX 0x9404
#define VER "9.4e"
#define VERNUM 9405
#define VERNUM_HEX 0x9405
#define GEN_M 0
#define GEN_F 1

View File

@ -4895,7 +4895,7 @@ void setdist(cell *c, int d, cell *from) {
c->monst = moMonkey;
else if(hrand(80000) < 5 + items[itRuby] + hard)
c->monst = moEagle;
else if(ishept(c) && c != origin.c7 && hrand(4000) < 300 + items[itRuby] && !c->monst) {
else if(ishept(c) && c != currentmap->gamestart() && hrand(4000) < 300 + items[itRuby] && !c->monst) {
int hardchance = items[itRuby] + hard;
if(hardchance > 25) hardchance = 25;
bool hardivy = hrand(100) < hardchance;
@ -5224,7 +5224,7 @@ bool haveOrbPower() {
if(itemclass(c->item) == IC_ORB) return true;
}
else if(sphere) for(int i=0; i<spherecells(); i++) {
cell *c = dodecahedron[i].c7;
cell *c = getDodecahedron(i)->c7;
if(itemclass(c->item) == IC_ORB) return true;
forCellEx(c2, c) if(itemclass(c2->item) == IC_ORB) return true;
}
@ -5233,7 +5233,7 @@ bool haveOrbPower() {
bool haveKraken() {
for(int i=0; i<spherecells(); i++) {
cell *c = dodecahedron[i].c7;
cell *c = getDodecahedron(i)->c7;
if(c->monst == moKrakenH || c->monst == moKrakenT) return true;
}
return false;
@ -5617,7 +5617,7 @@ heptagon *createAlternateMap(cell *c, int rad, hstate firststate, int special) {
}
heptagon *alt = new heptagon;
allAlts.push_back(alt);
allmaps.push_back(new hrmap_alternate(alt));
//printf("new alt {%p}\n", alt);
alt->s = firststate;
alt->emeraldval = 0;

View File

@ -155,7 +155,7 @@ namespace mapstream {
int rspin;
if(size(cellbyid) == 0) {
c = origin.c7;
c = currentmap->gamestart();
rspin = 0;
}
else {
@ -202,7 +202,7 @@ namespace mapstream {
int32_t whereami = loadInt();
if(whereami >= 0 && whereami < size(cellbyid))
cwt.c = cellbyid[whereami];
else cwt.c = origin.c7;
else cwt.c = currentmap->gamestart();
for(int i=0; i<size(cellbyid); i++) {
cell *c = cellbyid[i];

View File

@ -374,6 +374,7 @@ void projectionDialog() {
// "to the eye. "
"See also the conformal mode (in the special modes menu) "
"for more models."));
dialog::sidedialog = true;
}
void handleVisual1(int sym, int uni) {
@ -392,6 +393,7 @@ void handleVisual1(int sym, int uni) {
dialog::editNumber(vid.scale, .001, 1000, .1, 1, XLAT("scale factor"),
XLAT("Scale the displayed model."));
dialog::scaleLog();
dialog::sidedialog = true;
}
if(xuni == 'a') dialog::editNumber(vid.sspeed, -5, 5, 1, 0,
@ -671,6 +673,8 @@ void handle3D(int sym, int uni) {
pmodel = (pmodel == mdHyperboloid ? mdDisk : mdHyperboloid);
else if(uni) cmode = emVisual2;
if(cmode == emNumber) dialog::sidedialog = true;
}
void showVisual2() {
@ -777,11 +781,13 @@ void handleVisual2(int sym, int uni) {
if(xuni == 'f')
dialog::editNumber(vid.framelimit, 5, 300, 10, 300, XLAT("framerate limit"), "");
if(xuni == 'a')
if(xuni == 'a') {
dialog::editNumber(sightrange, 4, cheater ? 10 : 7, 1, 7, XLAT("sight range"),
XLAT("Roughly 42% cells are on the edge of your sight range. Reducing "
"the sight range makes HyperRogue work faster, but also makes "
"the game effectively harder."));
dialog::sidedialog = true;
}
if(xuni == 'r') revcontrol = !revcontrol;
if(xuni == 'd') vid.drawmousecircle = !vid.drawmousecircle;
@ -791,10 +797,12 @@ void handleVisual2(int sym, int uni) {
dialog::editNumber(fontscale, 0, 400, 10, 100, XLAT("font scale"), "");
#endif
if(xuni == 'e')
if(xuni == 'e') {
dialog::editNumber(vid.eye, -10, 10, 0.01, 0, XLAT("distance between eyes"),
XLAT("Watch the Minkowski hyperboloid or the hypersian rug mode with the "
"red/cyan 3D glasses."));
dialog::sidedialog = true;
}
#ifdef STEAM
if(xuni == 'l') vid.steamscore = vid.steamscore^1;
@ -843,6 +851,7 @@ void showChangeMode() {
dialog::addBoolItem(XLAT("paper model creator"), (false), 'n');
#endif
dialog::addBoolItem(XLAT("conformal/history mode"), (conformal::on), 'a');
dialog::addBoolItem(XLAT("expansion"), viewdists, 'x');
dialog::addBreak(50);
@ -886,6 +895,10 @@ void handleChangeMode(int sym, int uni) {
else if(xuni == 'e') {
cmode = emPickEuclidean;
}
else if(xuni == 'x') {
viewdists = !viewdists;
cmode = emNormal;
}
else if(xuni == 't') {
clearMessages();
cmode = emTactic;

View File

@ -1961,8 +1961,8 @@ void queuechr(const hyperpoint& h, int size, char chr, int col, int frame = 0) {
void queuechr(const transmatrix& V, double size, char chr, int col, int frame = 0) {
int xc, yc, sc; getcoord0(tC0(V), xc, yc, sc);
int xs, ys, ss; getcoord0(V * xpush0(.5), xs, ys, ss);
queuechr(xc, yc, sc, int(sqrt(squar(xc-xs)+squar(yc-ys)) * size), chr, col, frame);
int xs, ys, ss; getcoord0(V * xpush0(.5), xs, ys, ss);
queuechr(xc, yc, sc, int(sqrt(squar(xc-xs)+squar(yc-ys)) * scalef * size), chr, col, frame);
}
void queuestr(const hyperpoint& h, int size, const string& chr, int col, int frame = 0) {

View File

@ -1399,8 +1399,10 @@ void handleMenu(int sym, int uni) {
else if(uni == 'l') showlabels = !showlabels;
else if(uni == 'x') specialmark = !specialmark;
else if(uni == 'b') backcolor ^= 0xFFFFFF;
else if(uni == 'g')
else if(uni == 'g') {
dialog::editNumber(ggamma, 0, 5, .01, 0.5, XLAT("gamma value for edges"), "");
dialog::sidedialog = true;
}
else if(uni) cmode = emNormal;
}

View File

@ -37,7 +37,7 @@ void initgame() {
if(firstland == laMountain && !tactic::on) firstland = laJungle;
if(isGravityLand(firstland) && !tactic::on) firstland = laCrossroads;
cwt.c = origin.c7; cwt.spin = 0; cwt.mirrored = false;
cwt.c = currentmap->gamestart(); cwt.spin = 0; cwt.mirrored = false;
cwt.c->land = (euclid || sphere) ? euclidland : firstland;
chaosAchieved = false;
@ -113,13 +113,12 @@ void initgame() {
setdist(cwt.c, i, NULL);
if(tactic::trailer) safety = false;
if(sphere) verifyDodecahedron();
else verifycells(&origin);
currentmap->verify();
}
if(quotient && generateAll(firstland)) {
for(int i=0; i<size(quotientspace::allcells); i++)
setdist(quotientspace::allcells[i], 8, NULL);
for(int i=0; i<size(currentmap->allcells()); i++)
setdist(currentmap->allcells()[i], 8, NULL);
}
@ -844,34 +843,85 @@ void loadsave() {
}
#endif
void restartGame(char switchWhat) {
namespace gamestack {
struct gamedata {
hrmap *hmap;
cellwalker cwt;
heptspin viewctr;
transmatrix View;
eGeometry geometry;
};
vector<gamedata> gd;
bool pushed() { return size(gd); }
void push() {
if(geometry) {
printf("ERROR: push implemented only in non-hyperbolic geometry\n");
exit(1);
}
gamedata gdn;
gdn.hmap = currentmap;
gdn.cwt = cwt;
gdn.viewctr = viewctr;
gdn.View = View;
gdn.geometry = geometry;
gd.push_back(gdn);
}
void pop() {
gamedata& gdn = gd[size(gd)-1];
currentmap = gdn.hmap;
cwt = gdn.cwt;
viewctr = gdn.viewctr;
View = gdn.View;
geometry = gdn.geometry;
resetGeometry();
gd.pop_back();
bfs();
}
};
void restartGame(char switchWhat, bool push) {
DEBB(DF_INIT, (debugfile,"restartGame\n"));
achievement_final(true);
#ifndef NOSAVE
saveStats();
#endif
for(int i=0; i<ittypes; i++) items[i] = 0;
lastkills = 0; for(int i=0; i<motypes; i++) kills[i] = 0;
for(int i=0; i<10; i++) explore[i] = 0;
for(int i=0; i<10; i++) for(int l=0; l<landtypes; l++)
exploreland[i][l] = 0;
for(int i=0; i<numplayers(); i++)
if(multi::playerActive(i))
multi::deaths[i]++;
#ifndef NOSAVE
anticheat::tampered = false;
#endif
achievementsReceived.clear();
princess::saved = false;
princess::reviveAt = 0;
princess::forceVizier = false;
princess::forceMouse = false;
knighted = 0;
// items[itGreenStone] = 100;
cellcount = 0;
clearMemory();
if(push)
gamestack::push();
else if(gamestack::pushed()) {
gamestack::pop();
return;
}
else {
achievement_final(true);
#ifndef NOSAVE
saveStats();
#endif
for(int i=0; i<ittypes; i++) items[i] = 0;
lastkills = 0; for(int i=0; i<motypes; i++) kills[i] = 0;
for(int i=0; i<10; i++) explore[i] = 0;
for(int i=0; i<10; i++) for(int l=0; l<landtypes; l++)
exploreland[i][l] = 0;
for(int i=0; i<numplayers(); i++)
if(multi::playerActive(i))
multi::deaths[i]++;
#ifndef NOSAVE
anticheat::tampered = false;
#endif
achievementsReceived.clear();
princess::saved = false;
princess::reviveAt = 0;
princess::forceVizier = false;
princess::forceMouse = false;
knighted = 0;
// items[itGreenStone] = 100;
cellcount = 0;
clearMemory();
}
if(switchWhat == 'C') {
geometry = gNormal;
yendor::on = tactic::on = princess::challenge = false;
@ -1187,14 +1237,13 @@ bool applyCheat(char u, cell *c = NULL) {
return true;
}
if(u == 'E'-64) {
addMessage(XLAT("You summon many monsters!"));
cheater++;
for(int i=0; i<cwt.c->type; i++) {
cell *c2 = cwt.c->mov[i];
if(passable(c2, NULL, P_MONSTER)) {
eMonster mo[2] = { moRedTroll, moDarkTroll };
c2->monst = mo[hrand(2)];
}
if(geometry) {
restartGame(0, false);
}
else {
euclidland = cwt.c->land;
printf("target geometry = %d\n", targetgeometry);
restartGame('g', true);
}
return true;
}
@ -1299,6 +1348,10 @@ bool applyCheat(char u, cell *c = NULL) {
return true;
}
#ifdef LOCAL
if(u == 'K'-64) {
printf("viewctr = %p.%d\n", viewctr.h, viewctr.spin);
display(View);
}
if(u == 'D'-64) {
cheater = 0; autocheat = 0;
return true;