1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2024-11-27 14:37:16 +00:00

Merge branch 'master' into fix_hyperroid

This commit is contained in:
Zeno Rogue 2020-11-06 15:40:59 +01:00 committed by GitHub
commit 28383c94e0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
79 changed files with 5882 additions and 3186 deletions

View File

@ -89,8 +89,6 @@ struct archimedean_tiling {
}; };
#endif #endif
#if CAP_ARCM
#if HDR #if HDR
static const int sfPH = 1; static const int sfPH = 1;
static const int sfLINE = 2; static const int sfLINE = 2;
@ -99,6 +97,8 @@ static const int sfTHREE = 8;
static const int sfSEMILINE = 16; static const int sfSEMILINE = 16;
#endif #endif
#if CAP_ARCM
EX archimedean_tiling current; EX archimedean_tiling current;
EX archimedean_tiling fake_current; EX archimedean_tiling fake_current;
@ -841,8 +841,8 @@ void connectHeptagons(heptspin hi, heptspin hs) {
/** T and X are supposed to be equal -- move T so that it is closer to X */ /** T and X are supposed to be equal -- move T so that it is closer to X */
void fixup_matrix(transmatrix& T, const transmatrix& X, ld step) { void fixup_matrix(transmatrix& T, const transmatrix& X, ld step) {
for(int i=0; i<MDIM; i++) for(int i=0; i<MXDIM; i++)
for(int j=0; j<MDIM; j++) for(int j=0; j<MXDIM; j++)
T[i][j] = (T[i][j] * (1-step) + X[i][j] * step); T[i][j] = (T[i][j] * (1-step) + X[i][j] * step);
/* /*
@ -1450,10 +1450,10 @@ EX int valence() {
return total / isize(current.faces); return total / isize(current.faces);
} }
#endif
EX map<gp::loc, cdata>& get_cdata() { return ((arcm::hrmap_archimedean*) (currentmap))->eucdata; } EX map<gp::loc, cdata>& get_cdata() { return ((arcm::hrmap_archimedean*) (currentmap))->eucdata; }
#endif
EX } EX }
} }

View File

@ -136,8 +136,8 @@ EX transmatrix adjmatrix(int i) {
} }
struct hrmap_asonov : hrmap { struct hrmap_asonov : hrmap {
unordered_map<coord, heptagon*> at; map<coord, heptagon*> at;
unordered_map<heptagon*, coord> coords; map<heptagon*, coord> coords;
heptagon *getOrigin() override { return get_at(coord(0,0,0)); } heptagon *getOrigin() override { return get_at(coord(0,0,0)); }

View File

@ -372,7 +372,7 @@ EX bool attackJustStuns(cell *c2, flagtype f, eMonster attacker) {
return true; return true;
else if((f & AF_SWORD) && c2->monst == moSkeleton) else if((f & AF_SWORD) && c2->monst == moSkeleton)
return false; return false;
else if(f & (AF_CRUSH | AF_MAGIC | AF_FALL | AF_EAT | AF_GUN)) else if(f & (AF_CRUSH | AF_MAGIC | AF_FALL | AF_EAT | AF_GUN | AF_PSI))
return false; return false;
else else
return isStunnable(c2->monst) && c2->hitpoints > 1; return isStunnable(c2->monst) && c2->hitpoints > 1;
@ -1183,19 +1183,19 @@ EX void killThePlayerAt(eMonster m, cell *c, flagtype flags) {
} }
#if HDR #if HDR
template<class T> void do_swords(cell *mf, cell *mt, eMonster who, const T& f) { template<class T> void do_swords(movei mi, eMonster who, const T& f) {
for(int bb=0; bb<2; bb++) if(who == moPlayer && sword::orbcount(bb)) { for(int bb=0; bb<2; bb++) if(who == moPlayer && sword::orbcount(bb)) {
cell *sf = sword::pos(mf, sword::dir[multi::cpid], bb); cell *sf = sword::pos(mi.s, sword::dir[multi::cpid], bb);
cell *st = sword::pos(mt, sword::shift(mf, mt, sword::dir[multi::cpid]), bb); cell *st = sword::pos(mi.t, sword::shift(mi, sword::dir[multi::cpid]), bb);
f(st, bb); f(st, bb);
if(sf != st && !isNeighbor(sf,st)) { if(sf != st && !isNeighbor(sf,st)) {
// also attack the in-transit cell // also attack the in-transit cell
if(S3 == 3) { if(S3 == 3) {
forCellEx(sb, sf) if(isNeighbor(sb, st) && sb != mf && sb != mt) f(sb, bb); forCellEx(sb, sf) if(isNeighbor(sb, st) && sb != mi.s && sb != mi.t) f(sb, bb);
} }
else { else {
forCellEx(sb, mf) if(isNeighbor(sb, st) && sb != mt) f(sb, bb); forCellEx(sb, mi.s) if(isNeighbor(sb, st) && sb != mi.t) f(sb, bb);
forCellEx(sb, mt) if(isNeighbor(sb, sf) && sb != mf) f(sb, bb); forCellEx(sb, mi.t) if(isNeighbor(sb, sf) && sb != mi.s) f(sb, bb);
} }
} }
} }
@ -1204,14 +1204,16 @@ template<class T> void do_swords(cell *mf, cell *mt, eMonster who, const T& f) {
int lastdouble = -3; int lastdouble = -3;
EX void stabbingAttack(cell *mf, cell *mt, eMonster who, int bonuskill IS(0)) { EX void stabbingAttack(movei mi, eMonster who, int bonuskill IS(0)) {
int numsh = 0, numflail = 0, numlance = 0, numslash = 0, numbb[2]; int numsh = 0, numflail = 0, numlance = 0, numslash = 0, numbb[2];
numbb[0] = numbb[1] = 0; numbb[0] = numbb[1] = 0;
int backdir = neighborId(mt, mf); cell *mf = mi.s;
cell *mt = mi.t;
int backdir = mi.rev_dir();
do_swords(mf, mt, who, [&] (cell *c, int bb) { if(swordAttack(mt, who, c, bb)) numbb[bb]++, numslash++; }); do_swords(mi, who, [&] (cell *c, int bb) { if(swordAttack(mt, who, c, bb)) numbb[bb]++, numslash++; });
for(int bb=0; bb<2; bb++) achievement_count("SLASH", numbb[bb], 0); for(int bb=0; bb<2; bb++) achievement_count("SLASH", numbb[bb], 0);

View File

@ -22,7 +22,7 @@ struct display_data {
/** The view relative to the player character. */ /** The view relative to the player character. */
shiftmatrix player_matrix; shiftmatrix player_matrix;
/** On-screen coordinates for all the visible cells. */ /** On-screen coordinates for all the visible cells. */
unordered_map<cell*, shiftmatrix> cellmatrices, old_cellmatrices; map<cell*, shiftmatrix> cellmatrices, old_cellmatrices;
/** Position of the current map view, relative to the screen (0 to 1). */ /** Position of the current map view, relative to the screen (0 to 1). */
ld xmin, ymin, xmax, ymax; ld xmin, ymin, xmax, ymax;
/** Position of the current map view, in pixels. */ /** Position of the current map view, in pixels. */
@ -50,7 +50,7 @@ struct display_data {
/** Which copy of the player cell? */ /** Which copy of the player cell? */
transmatrix which_copy; transmatrix which_copy;
/** On-screen coordinates for all the visible cells. */ /** On-screen coordinates for all the visible cells. */
unordered_map<cell*, vector<shiftmatrix>> all_drawn_copies; map<cell*, vector<shiftmatrix>> all_drawn_copies;
}; };
#define View (::hr::current_display->view_matrix) #define View (::hr::current_display->view_matrix)
@ -79,7 +79,14 @@ int utfsize(char c) {
} }
EX int get_sightrange() { return getDistLimit() + sightrange_bonus; } EX int get_sightrange() { return getDistLimit() + sightrange_bonus; }
EX int get_sightrange_ambush() { return max(get_sightrange(), ambush::distance); }
EX int get_sightrange_ambush() {
#if CAP_COMPLEX2
return max(get_sightrange(), ambush::distance);
#else
return get_sightrange();
#endif
}
bool display_data::in_anaglyph() { return vid.stereo_mode == sAnaglyph; } bool display_data::in_anaglyph() { return vid.stereo_mode == sAnaglyph; }
bool display_data::stereo_active() { return vid.stereo_mode != sOFF; } bool display_data::stereo_active() { return vid.stereo_mode != sOFF; }
@ -603,7 +610,9 @@ EX void resetGL() {
matched_programs.clear(); matched_programs.clear();
glhr::current_glprogram = nullptr; glhr::current_glprogram = nullptr;
ray::reset_raycaster(); ray::reset_raycaster();
#if CAP_RUG
if(rug::glbuf) rug::close_glbuf(); if(rug::glbuf) rug::close_glbuf();
#endif
} }
#endif #endif
@ -1142,8 +1151,7 @@ EX void initgraph() {
} }
#if ISWEB #if ISWEB
vid.xscr = vid.xres = 1280; get_canvas_size();
vid.yscr = vid.yres = 900;
#else #else
const SDL_VideoInfo *inf = SDL_GetVideoInfo(); const SDL_VideoInfo *inf = SDL_GetVideoInfo();
vid.xscr = vid.xres = inf->current_w; vid.xscr = vid.xres = inf->current_w;
@ -1161,7 +1169,9 @@ EX void initgraph() {
#if CAP_CONFIG #if CAP_CONFIG
loadConfig(); loadConfig();
#endif #endif
#if CAP_ARCM
arcm::current.parse(); arcm::current.parse();
#endif
if(hybri) geometry = hybrid::underlying; if(hybri) geometry = hybrid::underlying;
#if CAP_COMMANDLINE #if CAP_COMMANDLINE

View File

@ -21,6 +21,7 @@ EX int newRoundTableRadius() {
return 28 + 2 * items[itHolyGrail]; return 28 + 2 * items[itHolyGrail];
} }
#if CAP_COMPLEX2
EX int getAnthraxData(cell *c, bool b) { EX int getAnthraxData(cell *c, bool b) {
int d = celldistAlt(c); int d = celldistAlt(c);
int rad = 28 + 3 * camelot::anthraxBonus; int rad = 28 + 3 * camelot::anthraxBonus;
@ -36,10 +37,13 @@ EX int getAnthraxData(cell *c, bool b) {
if(b) return rad; if(b) return rad;
return d; return d;
} }
#endif
EX int roundTableRadius(cell *c) { EX int roundTableRadius(cell *c) {
if(eubinary) return 28; if(eubinary) return 28;
#if CAP_COMPLEX2
if(tactic::on) return getAnthraxData(c, true); if(tactic::on) return getAnthraxData(c, true);
#endif
if(!c->master->alt) return 28; if(!c->master->alt) return 28;
return c->master->alt->alt->emeraldval & GRAIL_RADIUS_MASK; return c->master->alt->alt->emeraldval & GRAIL_RADIUS_MASK;
} }
@ -55,7 +59,9 @@ EX int celldistAltRelative(cell *c) {
if(sphere || quotient) { if(sphere || quotient) {
return celldist(c) - 3; return celldist(c) - 3;
} }
#if CAP_COMPLEX2
if(tactic::on) return getAnthraxData(c, false); if(tactic::on) return getAnthraxData(c, false);
#endif
return celldistAlt(c) - roundTableRadius(c); return celldistAlt(c) - roundTableRadius(c);
} }
@ -1805,12 +1811,14 @@ EX void moreBigStuff(cell *c) {
if(c->master->emeraldval % 2) if(c->master->emeraldval % 2)
c->wall = waColumn; c->wall = waColumn;
} }
#if CAP_BT
else if(geometry == gHoroTris || geometry == gHoroRec) { else if(geometry == gHoroTris || geometry == gHoroRec) {
if(c->c.spin(bt::updir()) != 0) c->wall = waColumn; if(c->c.spin(bt::updir()) != 0) c->wall = waColumn;
} }
else if(geometry == gKiteDart3) { else if(geometry == gKiteDart3) {
if(kite::getshape(c->master) == kite::pKite) c->wall = waColumn; if(kite::getshape(c->master) == kite::pKite) c->wall = waColumn;
} }
#endif
else if(in_s2xe()) { else if(in_s2xe()) {
auto d = hybrid::get_where(c); auto d = hybrid::get_where(c);
if(!PIU(pseudohept(d.first))) c->wall = waColumn; if(!PIU(pseudohept(d.first))) c->wall = waColumn;

View File

@ -19,6 +19,10 @@ EX namespace bt {
#endif #endif
} }
#if !CAP_BT
EX int updir() { return 0; }
#endif
#if CAP_BT #if CAP_BT
#if HDR #if HDR
enum bindir { enum bindir {
@ -1031,7 +1035,6 @@ EX int celldistance3(heptagon *c1, heptagon *c2) {
} }
EX int celldistance3(cell *c1, cell *c2) { return celldistance3(c1->master, c2->master); } EX int celldistance3(cell *c1, cell *c2) { return celldistance3(c1->master, c2->master); }
#endif
EX hyperpoint get_horopoint(ld y, ld x) { EX hyperpoint get_horopoint(ld y, ld x) {
return xpush(-y) * bt::parabolic(x) * C0; return xpush(-y) * bt::parabolic(x) * C0;
@ -1091,6 +1094,7 @@ EX hyperpoint get_corner_horo_coordinates(cell *c, int i) {
auto hooksw = addHook(hooks_swapdim, 100, [] { auto hooksw = addHook(hooks_swapdim, 100, [] {
if(bt::in()) build_tmatrix(); if(bt::in()) build_tmatrix();
}); });
#endif
} }

View File

@ -179,8 +179,11 @@ EX heptagon* hyperbolic_origin() {
h.cdata = NULL; h.cdata = NULL;
h.alt = NULL; h.alt = NULL;
h.distance = 0; h.distance = 0;
#if CAP_IRR
if(IRREGULAR) irr::link_start(origin); if(IRREGULAR) irr::link_start(origin);
else h.c7 = newCell(odegree, origin); else
#endif
h.c7 = newCell(odegree, origin);
return origin; return origin;
} }
@ -292,10 +295,10 @@ EX void initcells() {
hrmap* res = callhandlers((hrmap*)nullptr, hooks_newmap); hrmap* res = callhandlers((hrmap*)nullptr, hooks_newmap);
if(res) currentmap = res; if(res) currentmap = res;
else if(INVERSE) currentmap = gp::new_inverse();
else if(fake::in()) currentmap = fake::new_map();
else if(asonov::in()) currentmap = asonov::new_map(); else if(asonov::in()) currentmap = asonov::new_map();
else if(nonisotropic || hybri) currentmap = nisot::new_map(); else if(nonisotropic || hybri) currentmap = nisot::new_map();
else if(INVERSE) currentmap = gp::new_inverse();
else if(fake::in()) currentmap = fake::new_map();
#if CAP_CRYSTAL #if CAP_CRYSTAL
else if(cryst) currentmap = crystal::new_map(); else if(cryst) currentmap = crystal::new_map();
#endif #endif
@ -405,7 +408,7 @@ EX void clearfrom(heptagon *at) {
} }
int edges = at->degree(); int edges = at->degree();
if(bt::in() && WDIM == 2) edges = at->c7->type; if(bt::in() && WDIM == 2) edges = at->c7->type;
for(int i=0; i<edges; i++) if(at->move(i)) { for(int i=0; i<edges; i++) if(at->move(i) && at->move(i) != at) {
if(at->move(i)->alt != &deletion_marker) if(at->move(i)->alt != &deletion_marker)
q.push(at->move(i)); q.push(at->move(i));
unlink_cdata(at->move(i)); unlink_cdata(at->move(i));
@ -554,7 +557,9 @@ EX int celldistAlt(cell *c) {
/** direction upwards in the tree */ /** direction upwards in the tree */
EX int updir(heptagon *h) { EX int updir(heptagon *h) {
#if CAP_BT
if(bt::in()) return bt::updir(); if(bt::in()) return bt::updir();
#endif
#if MAXMDIM >= 4 #if MAXMDIM >= 4
if(WDIM == 3 && reg3::in_rule()) { if(WDIM == 3 && reg3::in_rule()) {
for(int i=0; i<S7; i++) if(h->move(i) && h->move(i)->distance < h->distance) for(int i=0; i<S7; i++) if(h->move(i) && h->move(i)->distance < h->distance)
@ -815,10 +820,12 @@ cdata *getHeptagonCdata(heptagon *h) {
if(sphere || quotient) h = currentmap->gamestart()->master; if(sphere || quotient) h = currentmap->gamestart()->master;
bool starting = h->s == hsOrigin; bool starting = h->s == hsOrigin;
#if CAP_BT
if(bt::in()) { if(bt::in()) {
if(bt::mapside(h) == 0) starting = true; if(bt::mapside(h) == 0) starting = true;
for(int i=0; i<h->type; i++) if(bt::mapside(h->cmove(i)) == 0) starting = true; for(int i=0; i<h->type; i++) if(bt::mapside(h->cmove(i)) == 0) starting = true;
} }
#endif
if(starting) { if(starting) {
h->cdata = new cdata(orig_cdata); h->cdata = new cdata(orig_cdata);
@ -866,7 +873,12 @@ cdata *getHeptagonCdata(heptagon *h) {
cdata *getEuclidCdata(gp::loc h) { cdata *getEuclidCdata(gp::loc h) {
int x = h.first, y = h.second; int x = h.first, y = h.second;
#if CAP_ARCM
auto& data = arcm::in() ? arcm::get_cdata() : euc::get_cdata(); auto& data = arcm::in() ? arcm::get_cdata() : euc::get_cdata();
#else
auto& data = euc::get_cdata();
#endif
// hrmap_euclidean* euc = dynamic_cast<hrmap_euclidean*> (currentmap); // hrmap_euclidean* euc = dynamic_cast<hrmap_euclidean*> (currentmap);
if(data.count(h)) return &(data[h]); if(data.count(h)) return &(data[h]);
@ -918,6 +930,7 @@ int ld_to_int(ld x) {
return int(x + 1000000.5) - 1000000; return int(x + 1000000.5) - 1000000;
} }
#if CAP_ARCM
EX gp::loc pseudocoords(cell *c) { EX gp::loc pseudocoords(cell *c) {
transmatrix T = arcm::archimedean_gmatrix[c->master].second; transmatrix T = arcm::archimedean_gmatrix[c->master].second;
return {ld_to_int(T[0][LDIM]), ld_to_int((spin(60*degree) * T)[0][LDIM])}; return {ld_to_int(T[0][LDIM]), ld_to_int((spin(60*degree) * T)[0][LDIM])};
@ -935,19 +948,22 @@ EX cdata *arcmCdata(cell *c) {
dynamicval<hrmap*> cm(currentmap, arcm::current_altmap); dynamicval<hrmap*> cm(currentmap, arcm::current_altmap);
return getHeptagonCdata(h2); return getHeptagonCdata(h2);
} }
#endif
EX int getCdata(cell *c, int j) { EX int getCdata(cell *c, int j) {
if(fake::in()) return FPIU(getCdata(c, j)); if(fake::in()) return FPIU(getCdata(c, j));
if(INVERSE) { if(hybri) { c = hybrid::get_where(c).first; return PIU(getBits(c)); }
else if(INVERSE) {
cell *c1 = gp::get_mapped(c); cell *c1 = gp::get_mapped(c);
return UIU(getCdata(c1, j)); return UIU(getCdata(c1, j));
} }
if(hybri) { c = hybrid::get_where(c).first; return PIU(getBits(c)); }
else if(euc::in()) return getEuclidCdata(euc2_coordinates(c))->val[j]; else if(euc::in()) return getEuclidCdata(euc2_coordinates(c))->val[j];
#if CAP_ARCM
else if(arcm::in() && euclid) else if(arcm::in() && euclid)
return getEuclidCdata(pseudocoords(c))->val[j]; return getEuclidCdata(pseudocoords(c))->val[j];
else if(arcm::in() && hyperbolic) else if(arcm::in() && hyperbolic)
return arcmCdata(c)->val[j]*3; return arcmCdata(c)->val[j]*3;
#endif
else if(!geometry_supports_cdata()) return 0; else if(!geometry_supports_cdata()) return 0;
else if(ctof(c)) return getHeptagonCdata(c->master)->val[j]*3; else if(ctof(c)) return getHeptagonCdata(c->master)->val[j]*3;
else { else {
@ -961,16 +977,18 @@ EX int getCdata(cell *c, int j) {
EX int getBits(cell *c) { EX int getBits(cell *c) {
if(fake::in()) return FPIU(getBits(c)); if(fake::in()) return FPIU(getBits(c));
if(INVERSE) { if(hybri) { c = hybrid::get_where(c).first; return PIU(getBits(c)); }
else if(INVERSE) {
cell *c1 = gp::get_mapped(c); cell *c1 = gp::get_mapped(c);
return UIU(getBits(c1)); return UIU(getBits(c1));
} }
if(hybri) { c = hybrid::get_where(c).first; return PIU(getBits(c)); }
else if(euc::in()) return getEuclidCdata(euc2_coordinates(c))->bits; else if(euc::in()) return getEuclidCdata(euc2_coordinates(c))->bits;
#if CAP_ARCM
else if(arcm::in() && euclid) else if(arcm::in() && euclid)
return getEuclidCdata(pseudocoords(c))->bits; return getEuclidCdata(pseudocoords(c))->bits;
else if(arcm::in() && (hyperbolic || sl2)) else if(arcm::in() && (hyperbolic || sl2))
return arcmCdata(c)->bits; return arcmCdata(c)->bits;
#endif
else if(!geometry_supports_cdata()) return 0; else if(!geometry_supports_cdata()) return 0;
else if(c == c->master->c7) return getHeptagonCdata(c->master)->bits; else if(c == c->master->c7) return getHeptagonCdata(c->master)->bits;
else { else {
@ -1108,7 +1126,7 @@ EX int celldistance(cell *c1, cell *c2) {
if(hybri) return hybrid::celldistance(c1, c2); if(hybri) return hybrid::celldistance(c1, c2);
#if CAP_FIELD #if CAP_FIELD
if(geometry == gFieldQuotient) { if(geometry == gFieldQuotient && (PURE || BITRUNCATED)) {
int d = fieldpattern::field_celldistance(c1, c2); int d = fieldpattern::field_celldistance(c1, c2);
if(d != DISTANCE_UNKNOWN) return d; if(d != DISTANCE_UNKNOWN) return d;
} }

View File

@ -534,11 +534,13 @@ void celldrawer::setcolors() {
break; break;
case waMineUnknown: case waMineMine: case waMineUnknown: case waMineMine:
#if CAP_COMPLEX2
if(mine::marked_safe(c)) if(mine::marked_safe(c))
fcol = wcol = gradient(wcol, 0x40FF40, 0, 0.2, 1); fcol = wcol = gradient(wcol, 0x40FF40, 0, 0.2, 1);
else if(mine::marked_mine(c)) else if(mine::marked_mine(c))
fcol = wcol = gradient(wcol, 0xFF4040, -1, sintick(100), 1); fcol = wcol = gradient(wcol, 0xFF4040, -1, sintick(100), 1);
// fallthrough // fallthrough
#endif
case waMineOpen: case waMineOpen:
if(wmblack || wmascii) { if(wmblack || wmascii) {
@ -1352,7 +1354,9 @@ void celldrawer::draw_features() {
} }
case waTerraWarrior: case waTerraWarrior:
#if CAP_COMPLEX2
drawTerraWarrior(V, terracotta::randterra ? (c->landparam & 7) : (5 - (c->landparam & 7)), 7, 0); drawTerraWarrior(V, terracotta::randterra ? (c->landparam & 7) : (5 - (c->landparam & 7)), 7, 0);
#endif
break; break;
case waBoat: case waStrandedBoat: case waBoat: case waStrandedBoat:

View File

@ -4139,3 +4139,33 @@ graphics/UI bugfixes:
- fixed the issues with Orb of Yendor - fixed the issues with Orb of Yendor
- fixed a bug in S2xE, and choosing cells in sphere - fixed a bug in S2xE, and choosing cells in sphere
- fixed Friendly Ghosts - fixed Friendly Ghosts
2020-11-02 00:08 Update 11.4:
* Panini perspective projection (allows wider vision -- configurable in 3d config -> FOV)
* Changed the default texture_step to 4
* An option to hide the flat projection in hyperboloid
* improved plain floor shapes in arbitrary tessellations
* fixed the Asonov cat geometry
* Five new projections: Poor Man (hyperbolic only), Panini, retroazimuthal: Craig, Hammer, Littrow (retro-Hammer buggy on sphere)
* Various fixes related to product spaces, especially product+inverse
* Fixed the navigation keys in dialogs
* fixed duals for Euclidean tessellations
Also, improvements in the Web version -- Backspace not Esc to exit dialogs, auto-resizing, raytracer is available.
Not yet in HyperRogue online, but see: https://zenorogue.itch.io/bringris
2020-11-05 18:53 Update 11.4a:
- fixed the aura when camera angle changed
- fixed selecting large regions for copying with mouse
- messages at 30 treasures etc. should no longer appear in PTM
- fixed a bug which allowed changing the generation/game range outside of cheat mode
- fixed drawing of creatures in kill list (visible e.g. for dogs)
- the RGB/RGBA hex value color is now shown with leading 0s
- Orb of the Mind now actually kills reptiles
- Orb of Chaos is now forbidden in the Princess Quest
- highlight mode setting should be saved now
- improved the safe move checking (fixes some minor bugs especially in multiplayer)
- allies use the new safe move checking now (they now know whether attacking hedgehog warriors/pikemen is safe for them and do it if yes)
- golems and bomberbirds now pathfind correctly

View File

@ -39,28 +39,47 @@ EX bool hasSafeOrb(cell *c) {
} }
#if HDR #if HDR
struct stalemate1 { struct player_move_info {
eMonster who; movei mi;
cell *moveto;
cell *pushto;
cell *comefrom;
cell *swordlast[2], *swordtransit[2], *swordnext[2]; cell *swordlast[2], *swordtransit[2], *swordnext[2];
stalemate1(eMonster w, cell *mt, cell *pt, cell *cf) : who(w), moveto(mt), pushto(pt), comefrom(cf) {} player_move_info(movei mi);
}; };
#endif #endif
EX vector<player_move_info> pmi;
EX vector<cell*> pushes;
player_move_info::player_move_info(movei _mi) : mi(_mi) {
for(int b=0; b<2; b++) swordlast[b] = sword::pos(multi::cpid, b);
dynamicval<sword::sworddir> x7(sword::dir[multi::cpid], sword::shift(mi, sword::dir[multi::cpid]));
for(int b=0; b<2; b++) {
swordnext[b] = sword::pos(multi::cpid, b);
swordtransit[b] = NULL;
if(swordnext[b] && swordnext[b] != swordlast[b] && !isNeighbor(swordlast[b], swordnext[b])) {
forCellEx(c2, swordnext[b])
if(c2 != mi.t && c2 != mi.s && isNeighbor(c2, S3==3 ? swordlast[b] : mi.t))
swordtransit[b] = c2;
if(S3 == 4)
forCellEx(c2, mi.s)
if(c2 != mi.s && isNeighbor(c2, swordlast[b]))
swordtransit[b] = c2;
}
}
}
EX bool krakensafe(cell *c) { EX bool krakensafe(cell *c) {
return items[itOrbFish] || items[itOrbAether] || return items[itOrbFish] || items[itOrbAether] ||
(c->item == itOrbFish && c->wall == waBoat) || (c->item == itOrbFish && c->wall == waBoat) ||
(c->item == itOrbAether && c->wall == waBoat); (c->item == itOrbAether && c->wall == waBoat);
} }
EX bool monstersnear(stalemate1& sm) { EX bool monstersnear(cell *c, eMonster who) {
cell *c = sm.moveto;
bool eaten = false; bool eaten = false;
if(hardcore && sm.who == moPlayer) return false; if(hardcore && who == moPlayer) return false;
int res = 0; int res = 0;
bool fast = false; bool fast = false;
@ -76,9 +95,9 @@ EX bool monstersnear(stalemate1& sm) {
who_kills_me = moCrusher; res++; who_kills_me = moCrusher; res++;
} }
if(sm.who == moPlayer || items[itOrbEmpathy]) { if(who == moPlayer || items[itOrbEmpathy]) {
fast = (items[itOrbSpeed] && (items[itOrbSpeed] & 1)); fast = (items[itOrbSpeed] && (items[itOrbSpeed] & 1));
if(sm.who == moPlayer && sm.moveto->item == itOrbSpeed && !items[itOrbSpeed]) fast = true; if(who == moPlayer && c->item == itOrbSpeed && !items[itOrbSpeed]) fast = true;
} }
if(havewhat&HF_OUTLAW) { if(havewhat&HF_OUTLAW) {
@ -103,7 +122,7 @@ EX bool monstersnear(stalemate1& sm) {
if(!logical_adjacent(c3, c3->monst, c2) || !logical_adjacent(c2, c3->monst, c) || (c3->monst == moWitchSpeed && c2->land != laPower)) if(!logical_adjacent(c3, c3->monst, c2) || !logical_adjacent(c2, c3->monst, c) || (c3->monst == moWitchSpeed && c2->land != laPower))
continue; continue;
if(elec::affected(c3)) continue; if(elec::affected(c3)) continue;
if(c3->stuntime > (sm.who == moPlayer ? 0 : 1)) continue; if(c3->stuntime > (who == moPlayer ? 0 : 1)) continue;
// speedwitches can only attack not-fastened monsters, // speedwitches can only attack not-fastened monsters,
// others can only attack if the move is not fastened // others can only attack if the move is not fastened
if(c3->monst == moWitchSpeed && items[itOrbSpeed]) continue; if(c3->monst == moWitchSpeed && items[itOrbSpeed]) continue;
@ -120,19 +139,19 @@ EX bool monstersnear(stalemate1& sm) {
// consider normal monsters // consider normal monsters
if(c2 && if(c2 &&
isArmedEnemy(c2, sm.who) && isArmedEnemy(c2, who) &&
(c2->monst != moLancer || isUnarmed(sm.who) || !logical_adjacent(c, sm.who, c2))) { (c2->monst != moLancer || isUnarmed(who) || !logical_adjacent(c, who, c2))) {
eMonster m = c2->monst; eMonster m = c2->monst;
if(elec::affected(c2)) continue; if(elec::affected(c2)) continue;
if(fast && c2->monst != moWitchSpeed) continue; if(fast && c2->monst != moWitchSpeed) continue;
// Krakens just destroy boats // Krakens just destroy boats
if(c2->monst == moKrakenT && onboat(sm)) { if(c2->monst == moKrakenT && c->wall == waBoat) {
if(krakensafe(c)) continue; if(krakensafe(c)) continue;
else if(warningprotection(XLAT("This move appears dangerous -- are you sure?")) && res == 0) m = moWarning; else if(warningprotection(XLAT("This move appears dangerous -- are you sure?")) && res == 0) m = moWarning;
else continue; else continue;
} }
// they cannot attack through vines // they cannot attack through vines
if(!canAttack(c2, c2->monst, c, sm.who, AF_NEXTTURN)) continue; if(!canAttack(c2, c2->monst, c, who, AF_NEXTTURN)) continue;
if(c2->monst == moWorm || c2->monst == moTentacle || c2->monst == moHexSnake) { if(c2->monst == moWorm || c2->monst == moTentacle || c2->monst == moHexSnake) {
if(passable_for(c2->monst, c, c2, 0)) if(passable_for(c2->monst, c, c2, 0))
eaten = true; eaten = true;
@ -142,18 +161,16 @@ EX bool monstersnear(stalemate1& sm) {
} }
} }
if(sm.who == moPlayer && res && (markOrb2(itOrbShield) || markOrb2(itOrbShell)) && !eaten) if(who == moPlayer && res && (markOrb2(itOrbShield) || markOrb2(itOrbShell)) && !eaten)
res = 0; res = 0;
if(sm.who == moPlayer && res && markOrb2(itOrbDomination) && c->monst) if(who == moPlayer && res && markOrb2(itOrbDomination) && c->monst)
res = 0; res = 0;
return !!res; return !!res;
} }
EX bool monstersnear2(); EX bool monstersnear_aux() {
EX bool monstersnear2() {
changes.value_set(passive_switch, (gold() & 1) ? moSwitch1 : moSwitch2); changes.value_set(passive_switch, (gold() & 1) ? moSwitch1 : moSwitch2);
multi::cpid++; multi::cpid++;
bool b = false; bool b = false;
@ -162,22 +179,33 @@ EX bool monstersnear2() {
if(multi::cpid == multi::players || multi::players == 1 || multi::checkonly) { if(multi::cpid == multi::players || multi::players == 1 || multi::checkonly) {
if(shmup::delayed_safety) return false; if(shmup::delayed_safety) return false;
dynamicval<eMonster> sw(passive_switch, passive_switch);
for(int i=0; i<isize(stalemate::moves); i++) for(int i=0; i<isize(pmi); i++)
for(int j=0; j<isize(stalemate::moves); j++) if(i != j) { for(int j=0; j<isize(pmi); j++) if(i != j) {
if(swordConflict(stalemate::moves[i], stalemate::moves[j])) { if(swordConflict(pmi[i], pmi[j])) {
b = true; b = true;
who_kills_me = moEnergySword; who_kills_me = moEnergySword;
} }
if(multi::player[i].at == multi::player[j].at) if(pmi[i].mi.t == pmi[j].mi.t)
{ b = true; who_kills_me = moFireball; } { b = true; who_kills_me = moFireball; }
if(celldistance(multi::player[i].at, multi::player[j].at) > 8) if(celldistance(pmi[i].mi.t, pmi[j].mi.t) > 8)
{ b = true; who_kills_me = moAirball; } { b = true; who_kills_me = moAirball; }
} }
for(int i=0; !b && i<isize(stalemate::moves); i++) for(auto& pushto: pushes)
b = monstersnear(stalemate::moves[i]); for(auto& mi: pmi)
if(pushto == mi.mi.t) {
b = true; who_kills_me = moTongue;
}
for(int i=0; i<isize(pushes); i++)
for(int j=0; j<i; j++)
if(pushes[i] == pushes[j]) {
b = true; who_kills_me = moCrushball;
}
for(int i=0; !b && i<isize(pmi); i++)
b = monstersnear(pmi[i].mi.t, moPlayer);
} }
else b = !multimove(); else b = !multimove();
multi::cpid--; multi::cpid--;
@ -185,94 +213,17 @@ EX bool monstersnear2() {
return b; return b;
} }
EX bool monstersnear(cell *c, eMonster who, cell *pushto, cell *comefrom) { /** like monstersnear but add the potential moves of other players into account */
EX bool monstersnear_add_pmi(player_move_info pmi0) {
if(peace::on) return 0; // you are safe pmi.push_back(pmi0);
bool b = monstersnear_aux();
stalemate1 sm(who, c, pushto, comefrom); pmi.pop_back();
if(who == moPlayer) for(int b=0; b<2; b++) sm.swordlast[b] = sword::pos(multi::cpid, b);
cell *none = NULL;
cell **wcw = &cwt.at;
if(who != moPlayer) wcw = &none;
else if(multi::players > 1) wcw = &multi::player[multi::cpid].at;
dynamicval<cell*> x5(*wcw, c);
dynamicval<bool> x6(stalemate::nextturn, true);
dynamicval<sword::sworddir> x7(sword::dir[multi::cpid],
who == moPlayer ? sword::shift(comefrom, c, sword::dir[multi::cpid]) :
sword::dir[multi::cpid]);
for(int b=0; b<2; b++) {
if(who == moPlayer) {
sm.swordnext[b] = sword::pos(multi::cpid, b);
sm.swordtransit[b] = NULL;
if(sm.swordnext[b] && sm.swordnext[b] != sm.swordlast[b] && !isNeighbor(sm.swordlast[b], sm.swordnext[b])) {
forCellEx(c2, sm.swordnext[b])
if(c2 != c && c2 != comefrom && isNeighbor(c2, S3==3 ? sm.swordlast[b] : *wcw))
sm.swordtransit[b] = c2;
if(S3 == 4)
forCellEx(c2, c)
if(c2 != comefrom && isNeighbor(c2, sm.swordlast[b]))
sm.swordtransit[b] = c2;
}
}
else {
sm.swordnext[b] = sm.swordtransit[b] = NULL;
}
}
stalemate::moves.push_back(sm);
// dynamicval<eMonster> x7(stalemate::who, who);
bool b;
if(who == moPlayer && c->wall == waBigStatue) {
eWall w = comefrom->wall;
c->wall = waNone;
if(doesnotFall(comefrom)) comefrom->wall = waBigStatue;
b = monstersnear2();
comefrom->wall = w;
c->wall = waBigStatue;
}
else if(who == moPlayer && isPushable(c->wall)) {
eWall w = c->wall;
c->wall = waNone;
b = monstersnear2();
c->wall = w;
}
else {
b = monstersnear2();
}
stalemate::moves.pop_back();
return b; return b;
} }
EX namespace stalemate {
EX vector<stalemate1> moves;
EX bool nextturn;
EX bool isMoveto(cell *c) {
for(int i=0; i<isize(moves); i++) if(moves[i].moveto == c) return true;
return false;
}
EX bool isPushto(cell *c) {
for(int i=0; i<isize(moves); i++) if(moves[i].pushto == c) return true;
return false;
}
EX }
EX bool onboat(stalemate1& sm) {
cell *c = sm.moveto;
cell *cf = sm.comefrom;
return (c->wall == waBoat) || (cf->wall == waBoat && c->wall == waSea);
}
EX bool multimove() { EX bool multimove() {
if(multi::cpid == 0) lastkills = tkills(); if(multi::cpid == 0) lastkills = tkills();
if(!multi::playerActive(multi::cpid)) return !monstersnear2(); if(!multi::playerActive(multi::cpid)) return !monstersnear_aux();
cellwalker bcwt = cwt; cellwalker bcwt = cwt;
cwt = multi::player[multi::cpid]; cwt = multi::player[multi::cpid];
bool b = movepcto(multi::whereto[multi::cpid]); bool b = movepcto(multi::whereto[multi::cpid]);
@ -293,11 +244,11 @@ EX namespace multi {
EX bool aftermove; EX bool aftermove;
EX } EX }
EX bool swordConflict(const stalemate1& sm1, const stalemate1& sm2) { EX bool swordConflict(const player_move_info& sm1, const player_move_info& sm2) {
if(items[itOrbSword] || items[itOrbSword2]) if(items[itOrbSword] || items[itOrbSword2])
for(int b=0; b<2; b++) for(int b=0; b<2; b++)
if(sm1.comefrom == sm2.swordlast[b] || sm1.comefrom == sm2.swordtransit[b] || sm1.comefrom == sm2.swordnext[b]) if(sm1.mi.s == sm2.swordlast[b] || sm1.mi.s == sm2.swordtransit[b] || sm1.mi.s == sm2.swordnext[b])
if(sm1.moveto == sm2.swordlast[b] || sm1.moveto == sm2.swordtransit[b] || sm1.moveto == sm2.swordnext[b]) if(sm1.mi.t == sm2.swordlast[b] || sm1.mi.t == sm2.swordtransit[b] || sm1.mi.t == sm2.swordnext[b])
return true; return true;
return false; return false;
} }

View File

@ -980,6 +980,8 @@ enum eModel : int {
// 32..38 // 32..38
mdWerner, mdAitoff, mdHammer, mdLoximuthal, mdMiller, mdGallStereographic, mdWinkelTripel, mdWerner, mdAitoff, mdHammer, mdLoximuthal, mdMiller, mdGallStereographic, mdWinkelTripel,
// 39.. // 39..
mdPoorMan, mdPanini, mdRetroCraig, mdRetroLittrow, mdRetroHammer,
// 44..
mdGUARD, mdPixel, mdHyperboloidFlat, mdPolynomial, mdManual mdGUARD, mdPixel, mdHyperboloidFlat, mdPolynomial, mdManual
}; };
#endif #endif
@ -1031,6 +1033,11 @@ EX vector<modelinfo> mdinf = {
{X3("Miller projection"), mf::euc_boring | mf::band, DEFAULTS}, // scale latitude 4/5 -> Mercator -> 5/4 {X3("Miller projection"), mf::euc_boring | mf::band, DEFAULTS}, // scale latitude 4/5 -> Mercator -> 5/4
{X3("Gall stereographic"), mf::euc_boring | mf::band, DEFAULTS}, // like central cylindrical but stereographic {X3("Gall stereographic"), mf::euc_boring | mf::band, DEFAULTS}, // like central cylindrical but stereographic
{X3("Winkel tripel"), mf::euc_boring | mf::broken, DEFAULTS}, // mean of equirec and Aitoff {X3("Winkel tripel"), mf::euc_boring | mf::broken, DEFAULTS}, // mean of equirec and Aitoff
{X3("Poor man's square"), mf::euc_boring, DEFAULTS}, //
{X3("Panini projection"), mf::euc_boring, DEFAULTS}, //
{X3("Craig retroazimuthal"), mf::euc_boring | mf::broken, DEFAULTS}, // retroazimuthal cylindrical
{X3("Littrow retroazimuthal"), mf::euc_boring | mf::broken, DEFAULTS}, // retroazimuthal conformal
{X3("Hammer retroazimuthal"), mf::euc_boring, DEFAULTS}, // retroazimuthal equidistant
{X3("guard"), 0, DEFAULTS}, {X3("guard"), 0, DEFAULTS},
{X3("polynomial"), mf::conformal, DEFAULTS}, {X3("polynomial"), mf::conformal, DEFAULTS},
}; };

View File

@ -2800,12 +2800,18 @@ EX namespace sword {
EX void determine_sword_angles() { EX void determine_sword_angles() {
sword_angles = 2; sword_angles = 2;
if(SWORDDIM == 3) sword_angles = 1; if(SWORDDIM == 3) sword_angles = 1;
#if CAP_IRR
else if(IRREGULAR) sword_angles = 840; else if(IRREGULAR) sword_angles = 840;
#endif
#if CAP_BT
else if(bt::in()) sword_angles = 42; else if(bt::in()) sword_angles = 42;
#endif
#if CAP_ARCM
else if(arcm::in()) { else if(arcm::in()) {
if(!PURE) possible_divisor((BITRUNCATED ? 2 : 1) * isize(arcm::current.faces)); if(!PURE) possible_divisor((BITRUNCATED ? 2 : 1) * isize(arcm::current.faces));
if(!DUAL) for(int f: arcm::current.faces) possible_divisor(f); if(!DUAL) for(int f: arcm::current.faces) possible_divisor(f);
} }
#endif
else { else {
possible_divisor(S7); possible_divisor(S7);
if(BITRUNCATED) possible_divisor(S3); if(BITRUNCATED) possible_divisor(S3);
@ -2861,10 +2867,13 @@ EX namespace sword {
} }
// from c1 to c2 // from c1 to c2
EX sworddir shift(cell *c1, cell *c2, sworddir d) { EX sworddir shift(movei mi, sworddir d) {
if(!c1 || !c2) return d; cell *c1 = mi.s;
int s1 = neighborId(c1, c2); cell *c2 = mi.t;
int s2 = neighborId(c2, c1); if(!mi.proper()) return d;
int s1 = mi.d;
int s2 = mi.rev_dir();
neighborId(c2, c1);
if(s1 < 0 || s2 < 0) return d; if(s1 < 0 || s2 < 0) return d;
if(SWORDDIM == 2) { if(SWORDDIM == 2) {
int sub = (hybri) ? 2 : 0; int sub = (hybri) ? 2 : 0;
@ -3347,7 +3356,7 @@ EX namespace ca {
EX eWall wlive = waFloorA; EX eWall wlive = waFloorA;
EX unordered_set<cell*> changed; EX set<cell*> changed;
EX void list_adj(cell *c) { EX void list_adj(cell *c) {
changed.insert(c); changed.insert(c);

View File

@ -22,6 +22,8 @@ struct supersaver {
virtual bool dosave() = 0; virtual bool dosave() = 0;
virtual void reset() = 0; virtual void reset() = 0;
virtual ~supersaver() {}; virtual ~supersaver() {};
virtual bool affects(void* v) { return false; }
virtual void set_default() = 0;
}; };
typedef vector<shared_ptr<supersaver>> saverlist; typedef vector<shared_ptr<supersaver>> saverlist;
@ -36,6 +38,8 @@ template<class T> struct dsaver : supersaver {
bool dosave() { return val != dft; } bool dosave() { return val != dft; }
void reset() { val = dft; } void reset() { val = dft; }
dsaver(T& val) : val(val) { } dsaver(T& val) : val(val) { }
bool affects(void* v) { return v == &val; }
void set_default() { dft = val; }
}; };
template<class T> struct saver : dsaver<T> {}; template<class T> struct saver : dsaver<T> {};
@ -51,6 +55,18 @@ template<class T> void addsaver(T& i, string name) {
addsaver(i, name, i); addsaver(i, name, i);
} }
template<class T> void removesaver(T& val) {
for(int i=0; i<isize(savers); i++)
if(savers[i]->affects(&val))
savers.erase(savers.begin() + i);
}
template<class T> void set_saver_default(T& val) {
for(auto sav: savers)
if(sav->affects(&val))
sav->set_default();
}
template<class T> struct saverenum : supersaver { template<class T> struct saverenum : supersaver {
T& val; T& val;
T dft; T dft;
@ -59,6 +75,8 @@ template<class T> struct saverenum : supersaver {
saverenum<T>(T& v) : val(v) { } saverenum<T>(T& v) : val(v) { }
string save() { return its(int(val)); } string save() { return its(int(val)); }
void load(const string& s) { val = (T) atoi(s.c_str()); } void load(const string& s) { val = (T) atoi(s.c_str()); }
virtual bool affects(void* v) { return v == &val; }
virtual void set_default() { dft = val; }
}; };
template<class T, class U> void addsaverenum(T& i, U name, T dft) { template<class T, class U> void addsaverenum(T& i, U name, T dft) {
@ -344,6 +362,7 @@ EX void initConfig() {
addsaver(pconf.ballproj, "ballproj", 1); addsaver(pconf.ballproj, "ballproj", 1);
addsaver(vid.monmode, "monster display mode", DEFAULT_MONMODE); addsaver(vid.monmode, "monster display mode", DEFAULT_MONMODE);
addsaver(vid.wallmode, "wall display mode", DEFAULT_WALLMODE); addsaver(vid.wallmode, "wall display mode", DEFAULT_WALLMODE);
addsaver(vid.highlightmode, "highlightmode");
addsaver(vid.depth, "3D depth", 1); addsaver(vid.depth, "3D depth", 1);
addsaver(vid.camera, "3D camera level", 1); addsaver(vid.camera, "3D camera level", 1);
@ -473,7 +492,9 @@ EX void initConfig() {
addsaver(shmup::on, "mode-shmup", false); addsaver(shmup::on, "mode-shmup", false);
addsaver(hardcore, "mode-hardcore", false); addsaver(hardcore, "mode-hardcore", false);
addsaver(chaosmode, "mode-chaos"); addsaver(chaosmode, "mode-chaos");
#if CAP_INV
addsaver(inv::on, "mode-Orb Strategy"); addsaver(inv::on, "mode-Orb Strategy");
#endif
addsaverenum(variation, "mode-variation", eVariation::bitruncated); addsaverenum(variation, "mode-variation", eVariation::bitruncated);
addsaver(peace::on, "mode-peace"); addsaver(peace::on, "mode-peace");
addsaver(peace::otherpuzzles, "mode-peace-submode"); addsaver(peace::otherpuzzles, "mode-peace-submode");
@ -495,6 +516,7 @@ EX void initConfig() {
addsaver(vid.binary_width, "binary-tiling-width", 1); addsaver(vid.binary_width, "binary-tiling-width", 1);
addsaver(pconf.collignon_parameter, "collignon-parameter", 1); addsaver(pconf.collignon_parameter, "collignon-parameter", 1);
addsaver(pconf.collignon_reflected, "collignon-reflect", false); addsaver(pconf.collignon_reflected, "collignon-reflect", false);
addsaver(pconf.show_hyperboloid_flat, "hyperboloid-flat", true);
addsaver(pconf.aitoff_parameter, "aitoff-parameter"); addsaver(pconf.aitoff_parameter, "aitoff-parameter");
addsaver(pconf.miller_parameter, "miller-parameter"); addsaver(pconf.miller_parameter, "miller-parameter");
@ -577,7 +599,9 @@ EX void initConfig() {
addsaverenum(pconf.basic_model, "basic model"); addsaverenum(pconf.basic_model, "basic model");
addsaver(pconf.use_atan, "use_atan"); addsaver(pconf.use_atan, "use_atan");
#if CAP_ARCM
addsaver(arcm::current.symbol, "arcm-symbol", "4^5"); addsaver(arcm::current.symbol, "arcm-symbol", "4^5");
#endif
addsaverenum(hybrid::underlying, "product-underlying"); addsaverenum(hybrid::underlying, "product-underlying");
for(int i=0; i<isize(ginf); i++) { for(int i=0; i<isize(ginf); i++) {
@ -637,7 +661,7 @@ EX void initConfig() {
addsaver(vid.sloppy_3d, "sloppy3d", true); addsaver(vid.sloppy_3d, "sloppy3d", true);
addsaver(vid.texture_step, "wall-quality", 1); addsaver(vid.texture_step, "wall-quality", 4);
addsaver(smooth_scrolling, "smooth-scrolling", false); addsaver(smooth_scrolling, "smooth-scrolling", false);
addsaver(mouseaim_sensitivity, "mouseaim_sensitivity", 0.01); addsaver(mouseaim_sensitivity, "mouseaim_sensitivity", 0.01);
@ -690,6 +714,8 @@ EX void initConfig() {
addsaver(camera_speed, "camera-speed", 1); addsaver(camera_speed, "camera-speed", 1);
addsaver(camera_rot_speed, "camera-rot-speed", 1); addsaver(camera_rot_speed, "camera-rot-speed", 1);
addsaver(panini_alpha, "panini_alpha", 0);
callhooks(hooks_configfile); callhooks(hooks_configfile);
#if CAP_CONFIG #if CAP_CONFIG
@ -1061,6 +1087,43 @@ EX void menuitem_sightrange(char c IS('c')) {
dialog::add_action(edit_sightrange); dialog::add_action(edit_sightrange);
} }
EX void menuitem_sfx_volume() {
dialog::addSelItem(XLAT("sound effects volume"), its(effvolume), 'e');
dialog::add_action([] {
dialog::editNumber(effvolume, 0, 128, 10, 60, XLAT("sound effects volume"), "");
dialog::numberdark = dialog::DONT_SHOW;
dialog::reaction = [] () {
#if ISANDROID
settingsChanged = true;
#endif
};
dialog::bound_low(0);
dialog::bound_up(MIX_MAX_VOLUME);
});
}
EX void menuitem_music_volume() {
if (!audio) return;
dialog::addSelItem(XLAT("background music volume"), its(musicvolume), 'b');
dialog::add_action([] {
dialog::editNumber(musicvolume, 0, 128, 10, 60, XLAT("background music volume"), "");
dialog::numberdark = dialog::DONT_SHOW;
dialog::reaction = [] () {
#if CAP_SDLAUDIO
Mix_VolumeMusic(musicvolume);
#endif
#if ISANDROID
settingsChanged = true;
#endif
};
dialog::bound_low(0);
dialog::bound_up(MIX_MAX_VOLUME);
dialog::extra_options = [] {
dialog::addBoolItem_action(XLAT("play music when out of focus"), music_out_of_focus, 'A');
};
});
}
EX void showSpecialEffects() { EX void showSpecialEffects() {
cmode = vid.xres > vid.yres * 1.4 ? sm::SIDE : sm::MAYDARK; cmode = vid.xres > vid.yres * 1.4 ? sm::SIDE : sm::MAYDARK;
gamescreen(0); gamescreen(0);
@ -1312,37 +1375,8 @@ EX void configureOther() {
// dialog::addBoolItem_action(XLAT("forget faraway cells"), memory_saving_mode, 'y'); // dialog::addBoolItem_action(XLAT("forget faraway cells"), memory_saving_mode, 'y');
#if CAP_AUDIO #if CAP_AUDIO
dialog::addSelItem(XLAT("background music volume"), its(musicvolume), 'b'); menuitem_music_volume();
dialog::add_action([] { menuitem_sfx_volume();
dialog::editNumber(musicvolume, 0, 128, 10, 60, XLAT("background music volume"), "");
dialog::reaction = [] () {
#if CAP_SDLAUDIO
Mix_VolumeMusic(musicvolume);
#endif
#if ISANDROID
settingsChanged = true;
#endif
};
dialog::bound_low(0);
dialog::bound_up(MIX_MAX_VOLUME);
dialog::extra_options = [] {
#if CAP_SDLAUDIO
dialog::addBoolItem_action(XLAT("play music when out of focus"), music_out_of_focus, 'A');
#endif
};
});
dialog::addSelItem(XLAT("sound effects volume"), its(effvolume), 'e');
dialog::add_action([] {
dialog::editNumber(effvolume, 0, 128, 10, 60, XLAT("sound effects volume"), "");
dialog::reaction = [] () {
#if ISANDROID
settingsChanged = true;
#endif
};
dialog::bound_low(0);
dialog::bound_up(MIX_MAX_VOLUME);
});
#endif #endif
menuitem_sightrange('r'); menuitem_sightrange('r');
@ -1530,17 +1564,49 @@ EX void explain_detail() {
)); ));
} }
EX void add_edit_fov(char key IS('f')) { EX ld max_fov_angle() {
dialog::addSelItem(XLAT("field of view"), fts(vid.fov) + "°", key); if(panini_alpha >= 1 || panini_alpha <= -1) return 360;
dialog::add_action([] { return acos(-panini_alpha) * 2 / degree;
dialog::editNumber(vid.fov, 1, 170, 1, 45, "field of view", }
EX void add_edit_fov(char key IS('f'), bool pop IS(false)) {
string sfov = fts(vid.fov) + "°";
if(panini_alpha) {
sfov += " / " + fts(max_fov_angle()) + "°";
}
dialog::addSelItem(XLAT("field of view"), sfov, key);
dialog::add_action([=] {
if(pop) popScreen();
dialog::editNumber(vid.fov, 1, max_fov_angle(), 1, 45, "field of view",
XLAT( XLAT(
"Horizontal field of view, in angles. " "Horizontal field of view, in angles. "
"This affects the Hypersian Rug mode (even when stereo is OFF) " "This affects the Hypersian Rug mode (even when stereo is OFF) "
"and non-disk models.") "and non-disk models.") + "\n\n" +
XLAT(
"Must be less than %1°. Panini projection can be used to get higher values.",
fts(max_fov_angle())
)
); );
dialog::bound_low(1e-8); dialog::bound_low(1e-8);
dialog::bound_up(179); dialog::bound_up(max_fov_angle() - 0.01);
dialog::extra_options = [] {
dialog::addSelItem(XLAT("Panini projection"), fts(panini_alpha), 'P');
dialog::add_action([] {
popScreen();
dialog::editNumber(panini_alpha, 0, 1, 0.1, 0, "Panini parameter",
XLAT(
"The Panini projection is an alternative perspective projection "
"which allows very wide field-of-view values. HyperRogue uses "
"a quick implementation, so parameter values too close to 1 may "
"be buggy; try e.g. 0.9 instead.")
);
dialog::reaction = ray::reset_raycaster;
dialog::extra_options = [] {
add_edit_fov('F', true);
};
});
};
}); });
} }
@ -2654,7 +2720,7 @@ EX int read_gamemode_args() {
auto ah_config = addHook(hooks_args, 0, read_config_args) + addHook(hooks_args, 0, read_gamemode_args) + addHook(hooks_args, 0, read_color_args); auto ah_config = addHook(hooks_args, 0, read_config_args) + addHook(hooks_args, 0, read_gamemode_args) + addHook(hooks_args, 0, read_color_args);
#endif #endif
EX unordered_map<string, ld&> params = { EX map<string, ld&> params = {
{"linewidth", vid.linewidth}, {"linewidth", vid.linewidth},
{"patternlinewidth", linepatterns::width}, {"patternlinewidth", linepatterns::width},
{"scale", pconf.scale}, {"scale", pconf.scale},

View File

@ -480,11 +480,13 @@ EX void handleKeyNormal(int sym, int uni) {
} }
#endif #endif
#if CAP_COMPLEX2
if(DEFAULTNOR(sym)) { if(DEFAULTNOR(sym)) {
gmodekeys(sym, uni); gmodekeys(sym, uni);
if(uni == 'm' && canmove && (centerover == cwt.at ? mouseover : centerover)) if(uni == 'm' && canmove && (centerover == cwt.at ? mouseover : centerover))
mine::performMarkCommand(mouseover); mine::performMarkCommand(mouseover);
} }
#endif
if(DEFAULTCONTROL) { if(DEFAULTCONTROL) {
if(sym == '.' || sym == 's') movepcto(-1, 1); if(sym == '.' || sym == 's') movepcto(-1, 1);

View File

@ -9,7 +9,6 @@
namespace hr { namespace hr {
EX namespace crystal { EX namespace crystal {
#if CAP_CRYSTAL
#if HDR #if HDR
static const int MAXDIM = 7; static const int MAXDIM = 7;
@ -34,6 +33,8 @@ struct ldcoord : public array<ld, MAXDIM> {
static const ldcoord ldc0 = {}; static const ldcoord ldc0 = {};
#endif #endif
#if CAP_CRYSTAL
/** Crystal can be bitruncated either by changing variation to bitruncated. /** Crystal can be bitruncated either by changing variation to bitruncated.
* In case of the 4D Crystal, the standard HyperRogue bitruncation becomes * In case of the 4D Crystal, the standard HyperRogue bitruncation becomes
* confused by having both the original and new vertices of degree 8. * confused by having both the original and new vertices of degree 8.
@ -470,7 +471,7 @@ struct hrmap_crystal : hrmap_standard {
map<coord, heptagon*> heptagon_at; map<coord, heptagon*> heptagon_at;
map<int, eLand> landmemo; map<int, eLand> landmemo;
map<coord, eLand> landmemo4; map<coord, eLand> landmemo4;
unordered_map<cell*, unordered_map<cell*, int>> distmemo; map<cell*, map<cell*, int>> distmemo;
map<cell*, ldcoord> sgc; map<cell*, ldcoord> sgc;
cell *camelot_center; cell *camelot_center;
ldcoord camelot_coord; ldcoord camelot_coord;

View File

@ -721,12 +721,14 @@ int read_cheat_args() {
inv::compute(); inv::compute();
} }
#endif #endif
#if CAP_COMPLEX2
else if(argis("-ambush")) { else if(argis("-ambush")) {
// make all ambushes use the given number of dogs // make all ambushes use the given number of dogs
// example: hyper -W Hunt -IP Shield 1 -ambush 60 // example: hyper -W Hunt -IP Shield 1 -ambush 60
PHASE(3) cheat(); PHASE(3) cheat();
shift(); ambush::fixed_size = argi(); shift(); ambush::fixed_size = argi();
} }
#endif
else if(argis("-testdistances")) { else if(argis("-testdistances")) {
PHASE(3); shift(); test_distances(argi()); PHASE(3); shift(); test_distances(argi());
} }
@ -875,6 +877,11 @@ int read_cheat_args() {
cheat(); cheat();
gen_wandering = false; gen_wandering = false;
} }
else if(argis("-hroll")) {
shift();
int i = argi();
while(i>0) i--, hrand(10);
}
else if(argis("-W")) { else if(argis("-W")) {
PHASEFROM(2); PHASEFROM(2);
shift(); shift();

View File

@ -64,7 +64,10 @@ EX namespace dialog {
EX color_t dialogcolor = 0xC0C0C0; EX color_t dialogcolor = 0xC0C0C0;
EX void addBack() { EX void addBack() {
addItem(XLAT("go back"), ISWEB ? SDLK_BACKSPACE : SDLK_ESCAPE); addItem(XLAT("go back"),
(cmode & sm::NUMBER) ? SDLK_RETURN :
ISWEB ? SDLK_BACKSPACE :
SDLK_ESCAPE);
} }
EX void addHelp() { EX void addHelp() {
@ -523,20 +526,37 @@ EX namespace dialog {
return it.type == diItem || it.type == diBigItem; return it.type == diItem || it.type == diBigItem;
} }
EX void handle_actions(int &sym, int &uni) {
if(key_actions.count(uni)) {
key_actions[uni]();
sym = uni = 0;
return;
}
if(key_actions.count(sym)) {
key_actions[sym]();
sym = uni = 0;
return;
}
}
EX void handleNavigation(int &sym, int &uni) { EX void handleNavigation(int &sym, int &uni) {
if(uni == '\n' || uni == '\r' || DIRECTIONKEY == SDLK_KP5) if(uni == '\n' || uni == '\r' || DIRECTIONKEY == SDLK_KP5) {
for(int i=0; i<isize(items); i++) for(int i=0; i<isize(items); i++)
if(isitem(items[i])) if(isitem(items[i]))
if(items[i].body == highlight_text) { if(items[i].body == highlight_text) {
uni = sym = items[i].key; uni = sym = items[i].key;
handle_actions(sym, uni);
return; return;
} }
}
if(DKEY == SDLK_PAGEDOWN) { if(DKEY == SDLK_PAGEDOWN) {
uni = sym = 0;
for(int i=0; i<isize(items); i++) for(int i=0; i<isize(items); i++)
if(isitem(items[i])) if(isitem(items[i]))
highlight_text = items[i].body; highlight_text = items[i].body;
} }
if(DKEY == SDLK_PAGEUP) { if(DKEY == SDLK_PAGEUP) {
uni = sym = 0;
for(int i=0; i<isize(items); i++) for(int i=0; i<isize(items); i++)
if(isitem(items[i])) { if(isitem(items[i])) {
highlight_text = items[i].body; highlight_text = items[i].body;
@ -544,11 +564,11 @@ EX namespace dialog {
} }
} }
if(DKEY == SDLK_UP) { if(DKEY == SDLK_UP) {
uni = sym = 0;
string last = ""; string last = "";
for(int i=0; i<isize(items); i++) for(int i=0; i<isize(items); i++)
if(isitem(items[i])) if(isitem(items[i]))
last = items[i].body; last = items[i].body;
uni = sym = 0;
for(int i=0; i<isize(items); i++) for(int i=0; i<isize(items); i++)
if(isitem(items[i])) { if(isitem(items[i])) {
if(items[i].body == highlight_text) { if(items[i].body == highlight_text) {
@ -559,6 +579,7 @@ EX namespace dialog {
highlight_text = last; highlight_text = last;
} }
if(DKEY == SDLK_DOWN) { if(DKEY == SDLK_DOWN) {
uni = sym = 0;
int state = 0; int state = 0;
for(int i=0; i<isize(items); i++) for(int i=0; i<isize(items); i++)
if(isitem(items[i])) { if(isitem(items[i])) {
@ -570,18 +591,8 @@ EX namespace dialog {
highlight_text = items[i].body; highlight_text = items[i].body;
break; break;
} }
uni = sym = 0;
}
if(key_actions.count(uni)) {
key_actions[uni]();
sym = uni = 0;
return;
}
if(key_actions.count(sym)) {
key_actions[sym]();
sym = uni = 0;
return;
} }
handle_actions(sym, uni);
} }
color_t colorhistory[10] = { color_t colorhistory[10] = {
@ -697,7 +708,7 @@ EX namespace dialog {
getcstat = 'A' + i, inslider = true; getcstat = 'A' + i, inslider = true;
} }
displayColorButton(dcenter, vid.yres/2+vid.fsize * 6, XLAT("select this color") + " : " + itsh(color), ' ', 8, 0, color >> (colorAlpha ? ash : 0)); displayColorButton(dcenter, vid.yres/2+vid.fsize * 6, XLAT("select this color") + " : " + format(colorAlpha ? "%08X" : "%06X", color), ' ', 8, 0, color >> (colorAlpha ? ash : 0));
if(extra_options) extra_options(); if(extra_options) extra_options();

View File

@ -93,9 +93,11 @@ void launch(int seed, int elimit, int hlimit) {
cl1 = cl.lst; cl1 = cl.lst;
for(cell *c: cl.lst) { for(cell *c: cl.lst) {
c->wall = waNone, c->land = laCanvas; c->wall = waNone, c->land = laCanvas;
#if CAP_ARCM
int id = arcm::current.tilegroup[arcm::id_of(c->master)]; int id = arcm::current.tilegroup[arcm::id_of(c->master)];
color_t yellows[5] = { 0x80C080, 0x80C0C0, 0x8080C0, 0xC080C0, 0xC0C080 }; color_t yellows[5] = { 0x80C080, 0x80C0C0, 0x8080C0, 0xC080C0, 0xC0C080 };
c->landparam = yellows[id]; c->landparam = yellows[id];
#endif
} }
println(hlog, "c1 size = ", isize(cl.lst)); println(hlog, "c1 size = ", isize(cl.lst));
} }

View File

@ -293,6 +293,8 @@ EX bool two_sided_model() {
if(pmodel == mdHyperboloid) return !euclid; if(pmodel == mdHyperboloid) return !euclid;
// if(pmodel == mdHemisphere) return true; // if(pmodel == mdHemisphere) return true;
if(pmodel == mdDisk) return sphere; if(pmodel == mdDisk) return sphere;
if(pmodel == mdRetroLittrow) return sphere;
if(pmodel == mdRetroHammer) return sphere;
if(pmodel == mdHemisphere) return true; if(pmodel == mdHemisphere) return true;
if(pmodel == mdRotatedHyperboles) return true; if(pmodel == mdRotatedHyperboles) return true;
if(pmodel == mdSpiral && pconf.spiral_cone < 360) return true; if(pmodel == mdSpiral && pconf.spiral_cone < 360) return true;
@ -305,6 +307,12 @@ EX int get_side(const hyperpoint& H) {
double horizon = curnorm / pconf.alpha; double horizon = curnorm / pconf.alpha;
return (H[2] <= -horizon) ? -1 : 1; return (H[2] <= -horizon) ? -1 : 1;
} }
if(pmodel == mdRetroLittrow && sphere) {
return H[2] >= 0 ? 1 : -1;
}
if(pmodel == mdRetroHammer && sphere) {
return H[2] >= 0 ? 1 : -1;
}
if(pmodel == mdRotatedHyperboles) if(pmodel == mdRotatedHyperboles)
return H[1] > 0 ? -1 : 1; return H[1] > 0 ? -1 : 1;
if(pmodel == mdHyperboloid && hyperbolic) if(pmodel == mdHyperboloid && hyperbolic)
@ -2111,7 +2119,7 @@ EX void sort_drawqueue() {
int siz = isize(ptds); int siz = isize(ptds);
#if MINIMIZE_GL_CALLS #if MINIMIZE_GL_CALLS
unordered_map<color_t, vector<unique_ptr<drawqueueitem>>> subqueue; map<color_t, vector<unique_ptr<drawqueueitem>>> subqueue;
for(auto& p: ptds) subqueue[(p->prio == PPR::CIRCLE || p->prio == PPR::OUTCIRCLE) ? 0 : p->outline_group()].push_back(move(p)); for(auto& p: ptds) subqueue[(p->prio == PPR::CIRCLE || p->prio == PPR::OUTCIRCLE) ? 0 : p->outline_group()].push_back(move(p));
ptds.clear(); ptds.clear();
for(auto& p: subqueue) for(auto& r: p.second) ptds.push_back(move(r)); for(auto& p: subqueue) for(auto& r: p.second) ptds.push_back(move(r));
@ -2156,7 +2164,7 @@ EX void reverse_side_priorities() {
// on the sphere, parts on the back are drawn first // on the sphere, parts on the back are drawn first
EX void draw_backside() { EX void draw_backside() {
DEBBI(DF_GRAPH, ("draw_backside")); DEBBI(DF_GRAPH, ("draw_backside"));
if(pmodel == mdHyperboloid && hyperbolic) { if(pmodel == mdHyperboloid && hyperbolic && pconf.show_hyperboloid_flat) {
dynamicval<eModel> dv (pmodel, mdHyperboloidFlat); dynamicval<eModel> dv (pmodel, mdHyperboloidFlat);
for(auto& ptd: ptds) for(auto& ptd: ptds)
if(!among(ptd->prio, PPR::MOBILE_ARROW, PPR::OUTCIRCLE, PPR::CIRCLE)) if(!among(ptd->prio, PPR::MOBILE_ARROW, PPR::OUTCIRCLE, PPR::CIRCLE))

View File

@ -129,9 +129,10 @@ EX void compute_graphical_distance() {
} }
} }
EX void computePathdist(eMonster param) { EX void computePathdist(eMonster param, bool include_allies IS(true)) {
for(cell *c: targets) for(cell *c: targets)
if(include_allies || isPlayerOn(c))
onpath(c, isPlayerOn(c) ? 0 : 1, hrand(c->type)); onpath(c, isPlayerOn(c) ? 0 : 1, hrand(c->type));
int qtarg = isize(targets); int qtarg = isize(targets);
@ -158,8 +159,11 @@ EX void computePathdist(eMonster param) {
// printf("i=%d cd=%d\n", i, c->move(i)->cpdist); // printf("i=%d cd=%d\n", i, c->move(i)->cpdist);
cell *c2 = c->move(i); cell *c2 = c->move(i);
flagtype f = P_MONSTER | P_REVDIR;
if(param == moTameBomberbird) f |= P_FLYING;
if(c2 && c2->pathdist == PINFD && if(c2 && c2->pathdist == PINFD &&
passable(c2, (qb<qtarg) && !nonAdjacent(c,c2) && !thruVine(c,c2) ?NULL:c, P_MONSTER | P_REVDIR)) { passable(c2, (qb<qtarg) && !nonAdjacent(c,c2) && !thruVine(c,c2) ?NULL:c, f)) {
if(qb >= qtarg) { if(qb >= qtarg) {
if(param == moTortoise && nogoSlow(c, c2)) continue; if(param == moTortoise && nogoSlow(c, c2)) continue;
@ -186,9 +190,9 @@ struct pathdata {
pathlock--; pathlock--;
clear_pathdata(); clear_pathdata();
} }
pathdata(eMonster m) { pathdata(eMonster m, bool include_allies IS(true)) {
checklock(); checklock();
computePathdist(m); computePathdist(m, include_allies);
} }
pathdata(int i) { pathdata(int i) {
checklock(); checklock();

View File

@ -100,7 +100,7 @@ EX namespace euc {
/** ? */ /** ? */
intmatrix inverse_axes; intmatrix inverse_axes;
/** for canonicalization on tori */ /** for canonicalization on tori */
unordered_map<coord, int> hash; map<coord, int> hash;
vector<coord> seq; vector<coord> seq;
int index; int index;
@ -150,11 +150,13 @@ EX namespace euc {
tmatrix[i] = eumove(shifttable[i]); tmatrix[i] = eumove(shifttable[i]);
camelot_center = NULL; camelot_center = NULL;
build_torus3(geometry); build_torus3(geometry);
#if CAP_IRR
if(!valid_irr_torus()) { if(!valid_irr_torus()) {
addMessage(XLAT("Error: period mismatch")); addMessage(XLAT("Error: period mismatch"));
eu_input = irr::base_config; eu_input = irr::base_config;
build_torus3(geometry); build_torus3(geometry);
} }
#endif
} }
heptagon *getOrigin() override { heptagon *getOrigin() override {
@ -168,6 +170,7 @@ EX namespace euc {
auto h = tailored_alloc<heptagon> (S7); auto h = tailored_alloc<heptagon> (S7);
if(!IRREGULAR) if(!IRREGULAR)
h->c7 = newCell(S7, h); h->c7 = newCell(S7, h);
#if CAP_IRR
else { else {
coord m0 = shifttable[0]; coord m0 = shifttable[0];
transmatrix dummy; transmatrix dummy;
@ -180,6 +183,7 @@ EX namespace euc {
break; break;
} }
} }
#endif
h->distance = 0; h->distance = 0;
h->cdata = NULL; h->cdata = NULL;
h->alt = NULL; h->alt = NULL;
@ -534,6 +538,7 @@ EX namespace euc {
} }
EX bool valid_irr_torus() { EX bool valid_irr_torus() {
#if CAP_IRR
if(!IRREGULAR) return true; if(!IRREGULAR) return true;
if(eu.twisted) return false; if(eu.twisted) return false;
for(int i=0; i<2; i++) { for(int i=0; i<2; i++) {
@ -547,6 +552,7 @@ EX namespace euc {
eu.canonicalize(x0, dm0, dummy, mirr); eu.canonicalize(x0, dm0, dummy, mirr);
if(x0 != euzero || dm0 != eutester) return false; if(x0 != euzero || dm0 != eutester) return false;
} }
#endif
return true; return true;
} }

View File

@ -81,7 +81,9 @@ EX namespace fake {
transmatrix S1, S2; transmatrix S1, S2;
ld dist; ld dist;
in_underlying([c, d, &S1, &S2, &dist] { in_underlying([c, d, &S1, &S2, &dist] {
#if CAP_ARCM
dynamicval<bool> u(arcm::use_gmatrix, false); dynamicval<bool> u(arcm::use_gmatrix, false);
#endif
transmatrix T = currentmap->adj(c, d); transmatrix T = currentmap->adj(c, d);
S1 = rspintox(tC0(T)); S1 = rspintox(tC0(T));
transmatrix T1 = spintox(tC0(T)) * T; transmatrix T1 = spintox(tC0(T)) * T;
@ -89,12 +91,16 @@ EX namespace fake {
S2 = xpush(-dist) * T1; S2 = xpush(-dist) * T1;
}); });
#if CAP_ARCM
if(arcm::in()) { if(arcm::in()) {
int t = arcm::id_of(c->master); int t = arcm::id_of(c->master);
int t2 = arcm::id_of(c->move(d)->master); int t2 = arcm::id_of(c->move(d)->master);
auto& cof = arcm::current_or_fake(); auto& cof = arcm::current_or_fake();
cgi.adjcheck = cof.inradius[t/2] + cof.inradius[t2/2]; cgi.adjcheck = cof.inradius[t/2] + cof.inradius[t2/2];
} }
#else
if(0) ;
#endif
else if(WDIM == 2) { else if(WDIM == 2) {
@ -400,7 +406,9 @@ EX ld around;
/** @brief the value of 'around' which makes the tiling Euclidean */ /** @brief the value of 'around' which makes the tiling Euclidean */
EX ld compute_euclidean() { EX ld compute_euclidean() {
#if CAP_ARCM
if(arcm::in()) return arcm::current.N * 2 / arcm::current.euclidean_angle_sum; if(arcm::in()) return arcm::current.N * 2 / arcm::current.euclidean_angle_sum;
#endif
if(WDIM == 2) return 4 / (S7-2.) + 2; if(WDIM == 2) return 4 / (S7-2.) + 2;
if(underlying == gRhombic3) return 3; if(underlying == gRhombic3) return 3;
@ -411,8 +419,10 @@ EX ld compute_euclidean() {
} }
EX ld around_orig() { EX ld around_orig() {
#if CAP_ARCM
if(arcm::in()) if(arcm::in())
return arcm::current.N; return arcm::current.N;
#endif
if(WDIM == 2) if(WDIM == 2)
return S3; return S3;
if(underlying == gRhombic3) if(underlying == gRhombic3)

View File

@ -424,6 +424,48 @@ void geometry_information::generate_floorshapes_for(int id, cell *c, int siid, i
} }
} }
else if(arb::in()) {
vector<hyperpoint> actual;
for(int j=0; j<cor; j++)
actual.push_back(get_corner_position(c, j));
ld min_dist = 1e3;
for(int j=0; j<cor; j++)
for(int k=0; k<j; k++) {
ld dist = hdist(actual[j], actual[k]);
if(dist > 1e-6 && dist < min_dist)
min_dist = dist;
}
ld dist = min_dist * (1 - 3 / sca);
ld area = 0;
for(int j=0; j<cor; j++) {
hyperpoint current = kleinize(actual[j]);
hyperpoint last = kleinize(actual[j?j-1:cor-1]);
area += current[0] * last[1] - last[0] * current[1];
}
if(area < 0) dist = -dist;
for(int j=0; j<cor; j++) {
hyperpoint last = actual[j?j-1:cor-1];
hyperpoint current = actual[j];
hyperpoint next = actual[j<cor-1?j+1:0];
auto T = gpushxto0(current);
last = T * last;
next = T * next;
hyperpoint a = rspintox(last) * ypush0(dist);
hyperpoint b = rspintox(last) * xpush(hdist0(last)) * ypush0(dist);
hyperpoint c = rspintox(next) * ypush0(-dist);
hyperpoint d = rspintox(next) * xpush(hdist0(next)) * ypush0(-dist);
hyperpoint h = linecross(a, b, c, d);
cornerlist.push_back(rgpushxto0(current) * h);
}
}
else { else {
for(int j=0; j<cor; j++) for(int j=0; j<cor; j++)
cornerlist.push_back(get_corner_position(c, j, sca)); cornerlist.push_back(get_corner_position(c, j, sca));
@ -771,7 +813,9 @@ void geometry_information::generate_floorshapes() {
} }
else { else {
cell model; static hrmap_standard stdmap;
dynamicval<hrmap*> c(currentmap, &stdmap);
// cell model;
model.type = S6; generate_floorshapes_for(0, &model, 0, 0); model.type = S6; generate_floorshapes_for(0, &model, 0, 0);
model.type = S7; generate_floorshapes_for(1, &model, bt::in() ? 0 : 1, 0); model.type = S7; generate_floorshapes_for(1, &model, bt::in() ? 0 : 1, 0);
} }
@ -886,24 +930,30 @@ EX int shvid(cell *c) {
} }
else if(GOLDBERG_INV) else if(GOLDBERG_INV)
return gp::get_plainshape_id(c); return gp::get_plainshape_id(c);
#if CAP_IRR
else if(IRREGULAR) else if(IRREGULAR)
return irr::cellindex[c]; return irr::cellindex[c];
#endif
#if CAP_ARCM
else if(arcm::in()) { else if(arcm::in()) {
auto& ac = arcm::current; auto& ac = arcm::current;
int id = arcm::id_of(c->master); int id = arcm::id_of(c->master);
if(ac.regular && id>=2 && id < 2*ac.N) id &= 1; if(ac.regular && id>=2 && id < 2*ac.N) id &= 1;
return id; return id;
} }
#endif
else if(arb::in()) else if(arb::in())
return arb::id_of(c->master); return arb::id_of(c->master);
else if(geosupport_football() == 2) else if(geosupport_football() == 2)
return pseudohept(c); return pseudohept(c);
#if CAP_BT
else if(geometry == gBinaryTiling) else if(geometry == gBinaryTiling)
return c->type-6; return c->type-6;
else if(kite::in()) else if(kite::in())
return kite::getshape(c->master); return kite::getshape(c->master);
else if(geometry == gBinary4 || geometry == gTernary) else if(geometry == gBinary4 || geometry == gTernary)
return c->master->zebraval; return c->master->zebraval;
#endif
else if(inforder::mixed()) { else if(inforder::mixed()) {
int t = c->type; int t = c->type;
static vector<bool> computed; static vector<bool> computed;

View File

@ -182,7 +182,7 @@ EX bool activateRecall() {
killFriendlyIvy(); killFriendlyIvy();
movecost(cwt.at, recallCell.at, 3); movecost(cwt.at, recallCell.at, 3);
playerMoveEffects(cwt.at, recallCell.at); playerMoveEffects(movei(cwt.at, recallCell.at, TELEPORT));
mirror::destroyAll(); mirror::destroyAll();
sword::reset(); sword::reset();

View File

@ -300,6 +300,7 @@ void set_or_configure_geometry(eGeometry g) {
addMessage(XLAT("Only works with (semi-)regular tilings")); addMessage(XLAT("Only works with (semi-)regular tilings"));
return; return;
} }
#if CAP_ARCM
if(arcm::in()) { if(arcm::in()) {
int steps, single_step; int steps, single_step;
if(!arcm::current.get_step_values(steps, single_step)) { if(!arcm::current.get_step_values(steps, single_step)) {
@ -307,6 +308,7 @@ void set_or_configure_geometry(eGeometry g) {
return; return;
} }
} }
#endif
} }
} }
dual::may_split_or_do([g] { set_geometry(g); }); dual::may_split_or_do([g] { set_geometry(g); });
@ -384,7 +386,9 @@ void ge_select_tiling() {
EX string current_proj_name() { EX string current_proj_name() {
bool h = hyperbolic || sn::in(); bool h = hyperbolic || sn::in();
if(vpconf.model != mdDisk) if(vpconf.model == mdPanini && vpconf.alpha == 1)
return XLAT("stereographic Panini");
else if(vpconf.model != mdDisk)
return models::get_model_name(vpconf.model); return models::get_model_name(vpconf.model);
else if(h && vpconf.alpha == 1) else if(h && vpconf.alpha == 1)
return XLAT("Poincaré model"); return XLAT("Poincaré model");
@ -540,8 +544,10 @@ EX void select_quotient_screen() {
} }
else if(g == gFieldQuotient) else if(g == gFieldQuotient)
pushScreen(showQuotientConfig); pushScreen(showQuotientConfig);
#if CAP_CRYSTAL
else if(g == gCrystal) else if(g == gCrystal)
pushScreen(crystal::show); pushScreen(crystal::show);
#endif
else { else {
dual::may_split_or_do([g] { set_geometry(g); }); dual::may_split_or_do([g] { set_geometry(g); });
start_game(); start_game();
@ -707,7 +713,9 @@ EX void showEuclideanMenu() {
worldsize = euc::eu.det; worldsize = euc::eu.det;
if(BITRUNCATED) worldsize *= (a4 ? 2 : 3); if(BITRUNCATED) worldsize *= (a4 ? 2 : 3);
if(GOLDBERG) worldsize *= cgi.gpdata->area; if(GOLDBERG) worldsize *= cgi.gpdata->area;
#if CAP_IRR
if(IRREGULAR) worldsize *= isize(irr::cells) / isize(irr::cells_of_heptagon); if(IRREGULAR) worldsize *= isize(irr::cells) / isize(irr::cells_of_heptagon);
#endif
} }
else else
worldsize = denom ? nom / denom : 0; worldsize = denom ? nom / denom : 0;
@ -794,15 +802,19 @@ EX void showEuclideanMenu() {
dialog::add_action(select_quotient); dialog::add_action(select_quotient);
#if CAP_ARCM
if(arcm::in()) { if(arcm::in()) {
dialog::addItem(XLAT("advanced parameters"), '4'); dialog::addItem(XLAT("advanced parameters"), '4');
dialog::add_action_push(arcm::show); dialog::add_action_push(arcm::show);
} }
#endif
#if CAP_CRYSTAL
if(cryst) { if(cryst) {
dialog::addItem(XLAT("advanced parameters"), '4'); dialog::addItem(XLAT("advanced parameters"), '4');
dialog::add_action_push(crystal::show); dialog::add_action_push(crystal::show);
} }
#endif
if(fake::available()) { if(fake::available()) {
dialog::addItem(XLAT("fake curvature"), '4'); dialog::addItem(XLAT("fake curvature"), '4');

View File

@ -673,12 +673,17 @@ void geometry_information::prepare_basics() {
plevel = vid.plevel_factor * scalefactor; plevel = vid.plevel_factor * scalefactor;
single_step = 1; single_step = 1;
if(hybri && !prod) { if(hybri && !prod) {
#if CAP_ARCM
if(hybrid::underlying == gArchimedean) if(hybrid::underlying == gArchimedean)
arcm::current.get_step_values(psl_steps, single_step); arcm::current.get_step_values(psl_steps, single_step);
#else
if(0) ;
#endif
else { else {
single_step = S3 * S7 - 2 * S7 - 2 * S3; single_step = S3 * S7 - 2 * S7 - 2 * S3;
psl_steps = 2 * S7; psl_steps = 2 * S7;
if(BITRUNCATED) psl_steps *= S3; if(BITRUNCATED) psl_steps *= S3;
if(inv) psl_steps = 2 * S3;
if(single_step < 0) single_step = -single_step; if(single_step < 0) single_step = -single_step;
} }
DEBB(DF_GEOM | DF_POLY, ("steps = ", psl_steps, " / ", single_step)); DEBB(DF_GEOM | DF_POLY, ("steps = ", psl_steps, " / ", single_step));
@ -913,7 +918,7 @@ EX void apply_always3() {
#if MAXMDIM >= 4 #if MAXMDIM >= 4
EX void switch_always3() { EX void switch_always3() {
if(dual::split(switch_always3)) return; if(dual::split(switch_always3)) return;
#if CAP_GL #if CAP_GL && CAP_RUG
if(rug::rugged) rug::close(); if(rug::rugged) rug::close();
#endif #endif
vid.always3 = !vid.always3; vid.always3 = !vid.always3;
@ -946,7 +951,7 @@ EX void switch_always3() {
EX void switch_fpp() { EX void switch_fpp() {
#if MAXMDIM >= 4 #if MAXMDIM >= 4
#if CAP_GL #if CAP_GL && CAP_RUG
if(rug::rugged) rug::close(); if(rug::rugged) rug::close();
#endif #endif
if(dual::split(switch_fpp)) return; if(dual::split(switch_fpp)) return;
@ -1026,7 +1031,9 @@ EX string cgi_string() {
if(GOLDBERG_INV) V("GP", its(gp::param.first) + "," + its(gp::param.second)); if(GOLDBERG_INV) V("GP", its(gp::param.first) + "," + its(gp::param.second));
if(IRREGULAR) V("IRR", its(irr::irrid)); if(IRREGULAR) V("IRR", its(irr::irrid));
#if CAP_ARCM
if(arcm::in()) V("ARCM", arcm::current.symbol); if(arcm::in()) V("ARCM", arcm::current.symbol);
#endif
if(arb::in()) V("ARB", its(arb::current.order)); if(arb::in()) V("ARB", its(arb::current.order));
@ -1034,7 +1041,10 @@ EX string cgi_string() {
if(bt::in() || GDIM == 3) V("WQ", its(vid.texture_step)); if(bt::in() || GDIM == 3) V("WQ", its(vid.texture_step));
if(hybri) V("U", its(int(hybrid::underlying))); if(hybri) {
V("U", PIU(cgi_string()));
// its(int(hybrid::underlying)));
}
if(prod) V("PL", fts(vid.plevel_factor)); if(prod) V("PL", fts(vid.plevel_factor));

View File

@ -12,14 +12,14 @@ shiftmatrix &ggmatrix(cell *c);
EX void fixelliptic(transmatrix& at) { EX void fixelliptic(transmatrix& at) {
if(elliptic && at[LDIM][LDIM] < 0) { if(elliptic && at[LDIM][LDIM] < 0) {
for(int i=0; i<MDIM; i++) for(int j=0; j<MDIM; j++) for(int i=0; i<MXDIM; i++) for(int j=0; j<MXDIM; j++)
at[i][j] = -at[i][j]; at[i][j] = -at[i][j];
} }
} }
EX void fixelliptic(hyperpoint& h) { EX void fixelliptic(hyperpoint& h) {
if(elliptic && h[LDIM] < 0) if(elliptic && h[LDIM] < 0)
for(int i=0; i<MDIM; i++) h[i] = -h[i]; for(int i=0; i<MXDIM; i++) h[i] = -h[i];
} }
/** find relative_matrix via recursing the tree structure */ /** find relative_matrix via recursing the tree structure */
@ -398,6 +398,7 @@ ld hrmap_standard::spin_angle(cell *c, int d) {
ld hexshift = 0; ld hexshift = 0;
if(c == c->master->c7 && (S7 % 2 == 0) && BITRUNCATED) hexshift = cgi.hexshift + 2*M_PI/c->type; if(c == c->master->c7 && (S7 % 2 == 0) && BITRUNCATED) hexshift = cgi.hexshift + 2*M_PI/c->type;
else if(cgi.hexshift && c == c->master->c7) hexshift = cgi.hexshift; else if(cgi.hexshift && c == c->master->c7) hexshift = cgi.hexshift;
#if CAP_IRR
if(IRREGULAR) { if(IRREGULAR) {
auto id = irr::cellindex[c]; auto id = irr::cellindex[c];
auto& vs = irr::cells[id]; auto& vs = irr::cells[id];
@ -405,7 +406,7 @@ ld hrmap_standard::spin_angle(cell *c, int d) {
auto& p = vs.jpoints[vs.neid[d]]; auto& p = vs.jpoints[vs.neid[d]];
return -atan2(p[1], p[0]) - hexshift; return -atan2(p[1], p[0]) - hexshift;
} }
else #endif
return M_PI - d * 2 * M_PI / c->type - hexshift; return M_PI - d * 2 * M_PI / c->type - hexshift;
} }
@ -594,6 +595,7 @@ EX bool approx_nearcorner = false;
EX hyperpoint nearcorner(cell *c, int i) { EX hyperpoint nearcorner(cell *c, int i) {
if(GOLDBERG_INV) { if(GOLDBERG_INV) {
i = gmod(i, c->type);
cellwalker cw(c, i); cellwalker cw(c, i);
cw += wstep; cw += wstep;
transmatrix cwm = currentmap->adj(c, i); transmatrix cwm = currentmap->adj(c, i);

View File

@ -154,7 +154,7 @@ void display(const glmatrix& m) {
printf("\n"); printf("\n");
} }
glmatrix operator * (glmatrix m1, glmatrix m2) { EX glmatrix operator * (glmatrix m1, glmatrix m2) {
glmatrix res; glmatrix res;
for(int i=0; i<4; i++) for(int i=0; i<4; i++)
for(int j=0; j<4; j++) { for(int j=0; j<4; j++) {
@ -694,6 +694,10 @@ template<class T> void bindbuffer(T& v) {
#define PTR(attrib, q, field) \ #define PTR(attrib, q, field) \
glVertexAttribPointer(attrib, q, GL_FLOAT, GL_FALSE, sizeof(v[0]), (void*) ((char*) &v[0].field - (char*) &v[0])); glVertexAttribPointer(attrib, q, GL_FLOAT, GL_FALSE, sizeof(v[0]), (void*) ((char*) &v[0].field - (char*) &v[0]));
EX void bindbuffer_vertex(vector<glvertex>& v) {
bindbuffer(v);
}
#endif #endif
EX void vertices(const vector<glvertex>& v, int vshift IS(0)) { EX void vertices(const vector<glvertex>& v, int vshift IS(0)) {

View File

@ -806,6 +806,7 @@ EX namespace gp {
dialog::addBreak(100); dialog::addBreak(100);
#if CAP_IRR
if(irr::supports(geometry)) { if(irr::supports(geometry)) {
dialog::addBoolItem(XLAT("irregular"), IRREGULAR, 'i'); dialog::addBoolItem(XLAT("irregular"), IRREGULAR, 'i');
dialog::add_action(dialog::add_confirmation([=] () { dialog::add_action(dialog::add_confirmation([=] () {
@ -817,6 +818,7 @@ EX namespace gp {
if(!IRREGULAR) irr::visual_creator(); if(!IRREGULAR) irr::visual_creator();
})); }));
} }
#endif
dialog::addBreak(100); dialog::addBreak(100);
int style = 0; int style = 0;
@ -1126,6 +1128,8 @@ EX namespace gp {
} }
transmatrix relative_matrix(cell *c2, cell *c1, const hyperpoint& hint) override { transmatrix relative_matrix(cell *c2, cell *c1, const hyperpoint& hint) override {
c1 = mapping[c1];
c2 = mapping[c2];
return in_underlying([&] { return currentmap->relative_matrix(c2, c1, hint); }); return in_underlying([&] { return currentmap->relative_matrix(c2, c1, hint); });
} }

View File

@ -22,6 +22,8 @@ EX bool spatial_graphics;
EX bool wmspatial, wmescher, wmplain, wmblack, wmascii, wmascii3; EX bool wmspatial, wmescher, wmplain, wmblack, wmascii, wmascii3;
EX bool mmspatial, mmhigh, mmmon, mmitem; EX bool mmspatial, mmhigh, mmmon, mmitem;
EX ld panini_alpha = 0;
EX int detaillevel = 0; EX int detaillevel = 0;
EX bool first_cell_to_draw = true; EX bool first_cell_to_draw = true;
@ -1020,7 +1022,11 @@ EX void drawTerraWarrior(const shiftmatrix& V, int t, int hp, double footphase)
EX void drawPlayer(eMonster m, cell *where, const shiftmatrix& V, color_t col, double footphase, bool stop IS(false)) { EX void drawPlayer(eMonster m, cell *where, const shiftmatrix& V, color_t col, double footphase, bool stop IS(false)) {
charstyle& cs = getcs(); charstyle& cs = getcs();
#if CAP_COMPLEX2
auto& knighted = camelot::knighted; auto& knighted = camelot::knighted;
#else
const bool knighted = false;
#endif
if(mapeditor::drawplayer && !mapeditor::drawUserShape(V, mapeditor::sgPlayer, cs.charid, cs.skincolor, where)) { if(mapeditor::drawplayer && !mapeditor::drawUserShape(V, mapeditor::sgPlayer, cs.charid, cs.skincolor, where)) {
@ -1264,8 +1270,10 @@ void drawMimic(eMonster m, cell *where, const shiftmatrix& V, color_t col, doubl
else if(!where || shmup::curtime >= shmup::getPlayer()->nextshot) else if(!where || shmup::curtime >= shmup::getPlayer()->nextshot)
queuepoly(VBODY * VBS, cgi.shPKnife, darkena(col, 0, 0XC0)); queuepoly(VBODY * VBS, cgi.shPKnife, darkena(col, 0, 0XC0));
#if CAP_COMPLEX2
if(camelot::knighted) if(camelot::knighted)
queuepoly(VBODY3 * VBS, cgi.shKnightCloak, darkena(col, 1, 0xC0)); queuepoly(VBODY3 * VBS, cgi.shKnightCloak, darkena(col, 1, 0xC0));
#endif
queuepoly(VHEAD1, (cs.charid&1) ? cgi.shFemaleHair : cgi.shPHead, darkena(col, 1, 0XC0)); queuepoly(VHEAD1, (cs.charid&1) ? cgi.shFemaleHair : cgi.shPHead, darkena(col, 1, 0XC0));
queuepoly(VHEAD, cgi.shPFace, darkena(col, 0, 0XC0)); queuepoly(VHEAD, cgi.shPFace, darkena(col, 0, 0XC0));
@ -3070,8 +3078,22 @@ EX void drawaura() {
else rad0 *= m; else rad0 *= m;
} }
cx[r][z][0] = rad0 * c; ld x = rad0 * c;
cx[r][z][1] = rad0 * s * pconf.stretch; ld y = rad0 * s;
if(pconf.camera_angle) {
ld z = rad0;
ld cam = pconf.camera_angle * degree;
GLfloat cc = cos(cam);
GLfloat ss = sin(cam);
tie(y, z) = make_pair(y * cc - z * ss, z * cc + y * ss);
x *= rad0 / z;
y *= rad0 / z;
}
cx[r][z][0] = x;
cx[r][z][1] = y * pconf.stretch;
for(int u=0; u<3; u++) for(int u=0; u<3; u++)
cx[r][z][u+2] = bak[u] + (aurac[rm][u] / (aurac[rm][3]+.1) - bak[u]) * cmul[z]; cx[r][z][u+2] = bak[u] + (aurac[rm][u] / (aurac[rm][3]+.1) - bak[u]) * cmul[z];
@ -3410,7 +3432,11 @@ EX bool placeSidewall(cell *c, int i, int sidepar, const shiftmatrix& V, color_t
#endif #endif
bool openorsafe(cell *c) { bool openorsafe(cell *c) {
#if CAP_COMPLEX2
return c->wall == waMineOpen || mine::marked_safe(c); return c->wall == waMineOpen || mine::marked_safe(c);
#else
return false;
#endif
} }
#define Dark(x) darkena(x,0,0xFF) #define Dark(x) darkena(x,0,0xFF)
@ -3693,7 +3719,7 @@ EX bool frustum_culling = true;
void make_clipping_planes() { void make_clipping_planes() {
#if MAXMDIM >= 4 #if MAXMDIM >= 4
clipping_planes.clear(); clipping_planes.clear();
if(!frustum_culling || PIU(sphere) || experimental || vid.stereo_mode == sODS) return; if(!frustum_culling || PIU(sphere) || experimental || vid.stereo_mode == sODS || panini_alpha) return;
auto add_clipping_plane = [] (ld x1, ld y1, ld x2, ld y2) { auto add_clipping_plane = [] (ld x1, ld y1, ld x2, ld y2) {
ld z1 = 1, z2 = 1; ld z1 = 1, z2 = 1;
hyperpoint sx = point3(y1 * z2 - y2 * z1, z1 * x2 - z2 * x1, x1 * y2 - x2 * y1); hyperpoint sx = point3(y1 * z2 - y2 * z1, z1 * x2 - z2 * x1, x1 * y2 - x2 * y1);
@ -3788,7 +3814,9 @@ EX void gridline(const shiftmatrix& V, const hyperpoint h1, const hyperpoint h2,
EX int wall_offset(cell *c) { EX int wall_offset(cell *c) {
if(hybri || WDIM == 2) return hybrid::wall_offset(c); if(hybri || WDIM == 2) return hybrid::wall_offset(c);
#if CAP_BT
if(kite::in() && kite::getshape(c->master) == kite::pKite) return 10; if(kite::in() && kite::getshape(c->master) == kite::pKite) return 10;
#endif
return 0; return 0;
} }
@ -4455,7 +4483,6 @@ EX bool allowChangeRange() {
if(tour::on) return true; if(tour::on) return true;
#endif #endif
if(racing::on) return true; if(racing::on) return true;
if(sightrange_bonus >= 0) return true;
if(arcm::in() || arb::in()) return true; if(arcm::in() || arb::in()) return true;
if(WDIM == 3) return true; if(WDIM == 3) return true;
return false; return false;
@ -4866,7 +4893,8 @@ EX void calcparam() {
cd->xcenter += cd->scrsize * pconf.xposition; cd->xcenter += cd->scrsize * pconf.xposition;
cd->ycenter += cd->scrsize * pconf.yposition; cd->ycenter += cd->scrsize * pconf.yposition;
cd->tanfov = tan(vid.fov * degree / 2); ld fov = vid.fov * degree / 2;
cd->tanfov = sin(fov) / (cos(fov) + panini_alpha);
callhooks(hooks_calcparam); callhooks(hooks_calcparam);
reset_projection(); reset_projection();
@ -4966,13 +4994,22 @@ EX void gamescreen(int _darken) {
return; return;
} }
auto cdc = *current_display;
auto gx = vid.xres;
auto gy = vid.yres;
if(dual::split([=] () { if(dual::split([=] () {
*current_display = cdc;
vid.xres = gx;
vid.yres = gy;
dual::in_subscreen([=] () { gamescreen(_darken); }); dual::in_subscreen([=] () { gamescreen(_darken); });
})) { })) {
calcparam(); calcparam();
return; return;
} }
calcparam();
if((cmode & sm::MAYDARK) && !current_display->sidescreen) { if((cmode & sm::MAYDARK) && !current_display->sidescreen) {
_darken += 2; _darken += 2;
} }

View File

@ -232,7 +232,7 @@ EX void buildCredits() {
"Kojiguchi Kazuki, baconcow, Alan, SurelyYouJest, hotdogPi, DivisionByZero, xXxWeedGokuxXx, jpystynen, Dmitry Marakasov, Alexandre Moine, Arthur O'Dwyer, " "Kojiguchi Kazuki, baconcow, Alan, SurelyYouJest, hotdogPi, DivisionByZero, xXxWeedGokuxXx, jpystynen, Dmitry Marakasov, Alexandre Moine, Arthur O'Dwyer, "
"Triple_Agent_AAA, bluetailedgnat, Allalinor, Shitford, KittyTac, Christopher King, KosGD, TravelDemon, Bubbles, rdococ, frozenlake, MagmaMcFry, " "Triple_Agent_AAA, bluetailedgnat, Allalinor, Shitford, KittyTac, Christopher King, KosGD, TravelDemon, Bubbles, rdococ, frozenlake, MagmaMcFry, "
"Snakebird Priestess, roaringdragon2, Stopping Dog, bengineer8, Sir Light IJIJ, ShadeBlade, Saplou, shnourok, Ralith, madasa, 6% remaining, Chimera245, Remik Pi, alien foxcat thing, " "Snakebird Priestess, roaringdragon2, Stopping Dog, bengineer8, Sir Light IJIJ, ShadeBlade, Saplou, shnourok, Ralith, madasa, 6% remaining, Chimera245, Remik Pi, alien foxcat thing, "
"Piotr Grochowski" "Piotr Grochowski, Ann, still-flow"
); );
#ifdef EXTRALICENSE #ifdef EXTRALICENSE
help += EXTRALICENSE; help += EXTRALICENSE;
@ -928,8 +928,12 @@ EX void describeMouseover() {
if(isReptile(c->wall)) if(isReptile(c->wall))
out += " [" + turnstring((unsigned char) c->wparam) + "]"; out += " [" + turnstring((unsigned char) c->wparam) + "]";
#if CAP_COMPLEX2
if(c->monst == moKnight) if(c->monst == moKnight)
out += XLAT(", %1 the Knight", camelot::knight_name(c)); out += XLAT(", %1 the Knight", camelot::knight_name(c));
#else
if(0) ;
#endif
else if(c->monst) { else if(c->monst) {
out += ", "; out += XLAT1(minf[c->monst].name); out += ", "; out += XLAT1(minf[c->monst].name);
@ -950,10 +954,12 @@ EX void describeMouseover() {
out += ", "; out += ", ";
out += XLAT1(iinf[c->item].name); out += XLAT1(iinf[c->item].name);
if(c->item == itBarrow) out += " (x" + its(c->landparam) + ")"; if(c->item == itBarrow) out += " (x" + its(c->landparam) + ")";
#if CAP_COMPLEX2
if(c->land == laHunting) { if(c->land == laHunting) {
int i = ambush::size(c, c->item); int i = ambush::size(c, c->item);
if(i) out += " (" + XLAT("ambush:") + " " + its(i) + ")"; if(i) out += " (" + XLAT("ambush:") + " " + its(i) + ")";
} }
#endif
if(c->item == itBabyTortoise && tortoise::seek()) if(c->item == itBabyTortoise && tortoise::seek())
out += " " + tortoise::measure(tortoise::babymap[c]); out += " " + tortoise::measure(tortoise::babymap[c]);
if(!c->monst) set_help_to(c->item); if(!c->monst) set_help_to(c->item);
@ -1000,12 +1006,14 @@ EX void describeMouseover() {
callhooks(hooks_mouseover, c); callhooks(hooks_mouseover, c);
if(mousey < vid.fsize * 3/2 && getcstat == '-' && !instat) getcstat = SDLK_F1; if(mousey < vid.fsize * 3/2 && getcstat == '-' && !instat) getcstat = SDLK_F1;
#if CAP_TOUR
if(tour::on && !tour::texts) { if(tour::on && !tour::texts) {
if(tour::slides[tour::currentslide].flags & tour::NOTITLE) if(tour::slides[tour::currentslide].flags & tour::NOTITLE)
mouseovers = ""; mouseovers = "";
else else
mouseovers = XLAT(tour::slides[tour::currentslide].name); mouseovers = XLAT(tour::slides[tour::currentslide].name);
} }
#endif
} }
EX void showHelp() { EX void showHelp() {

View File

@ -279,6 +279,12 @@ heptagon *hrmap_standard::create_step(heptagon *h, int d) {
else else
buildHeptagon(h, d, transition(h->s, d)); buildHeptagon(h, d, transition(h->s, d));
} }
else if(S3 > 4 && quotient) {
/* this branch may be used for some >4-valent quotient spaces outside of standard HyperRogue */
/* this is wrong, but we don't care in quotient */
h->move(d) = h;
// buildHeptagon(h, d, transition(h->s, d));
}
else if(d == 1) { else if(d == 1) {
addSpin(h, d, h->move(0), h->c.spin(0)-1, -1); addSpin(h, d, h->move(0), h->c.spin(0)-1, -1);
} }

View File

@ -228,6 +228,7 @@ bool displayglyph(int cx, int cy, int buttonsize, char glyph, color_t color, int
glyphphase[id] * 2; glyphphase[id] * 2;
drawItemType(it, NULL, shiftless(V), icol, t, false); drawItemType(it, NULL, shiftless(V), icol, t, false);
} }
sortquickqueue();
quickqueue(); quickqueue();
} }
else if(glyph == '*') else if(glyph == '*')

18
hyper.h
View File

@ -13,8 +13,8 @@
#define _HYPER_H_ #define _HYPER_H_
// version numbers // version numbers
#define VER "11." #define VER "11.4a"
#define VERNUM_HEX 0xA83B #define VERNUM_HEX 0xA841
#include "sysconfig.h" #include "sysconfig.h"
@ -48,7 +48,6 @@ template<class T, class V, class... U> bool among(T x, V y, U... u) { return x==
using std::vector; using std::vector;
using std::map; using std::map;
using std::array; using std::array;
using std::unordered_map;
using std::sort; using std::sort;
using std::multimap; using std::multimap;
using std::set; using std::set;
@ -242,6 +241,7 @@ struct projection_configuration {
ld model_orientation, halfplane_scale, model_orientation_yz; ld model_orientation, halfplane_scale, model_orientation_yz;
ld collignon_parameter; ld collignon_parameter;
ld aitoff_parameter, miller_parameter, loximuthal_parameter, winkel_parameter; ld aitoff_parameter, miller_parameter, loximuthal_parameter, winkel_parameter;
bool show_hyperboloid_flat;
bool collignon_reflected; bool collignon_reflected;
string formula; string formula;
eModel basic_model; eModel basic_model;
@ -272,6 +272,7 @@ struct projection_configuration {
miller_parameter = .8; miller_parameter = .8;
loximuthal_parameter = 0; loximuthal_parameter = 0;
winkel_parameter = .5; winkel_parameter = .5;
show_hyperboloid_flat = true;
} }
}; };
@ -383,16 +384,23 @@ struct videopar {
extern videopar vid; extern videopar vid;
/** \brief How many dimensional is the gameplay. In the FPP mode of a 2D geometry, WDIM is 2 */
#define WDIM cginf.g.gameplay_dimension #define WDIM cginf.g.gameplay_dimension
/** \brief How many dimensional is the graphical representation. In the FPP mode of a 2D geometry, MDIM is 3 */
#define GDIM cginf.g.graphical_dimension #define GDIM cginf.g.graphical_dimension
/** \brief How many dimensions of the matrix representation are used. It is usually 3 in 2D geometries (not FPP) and in product geometries, 4 in 3D geometries */
#define MDIM (MAXMDIM == 3 ? 3 : cginf.g.homogeneous_dimension) #define MDIM (MAXMDIM == 3 ? 3 : cginf.g.homogeneous_dimension)
/** \brief What dimension of matrices is used in loops (the 'extra' dimensions have values 0 or 1 as in Id)
* Even if MDIM==3, it may be faster to keep 4x4 matrices and perform computations using them (rather than having another condition due to the variable loop size).
* The experiments on my computer show it to be the case, but the effect is not significant, and it may be different on another computer.
*/
#define MXDIM (CAP_MDIM_FIXED ? MAXMDIM : MDIM)
/** \brief The 'homogeneous' dimension index */
#define LDIM (MDIM-1) #define LDIM (MDIM-1)
#define cclass g.kind #define cclass g.kind
#define self (*this) #define self (*this)
// #define MODFIXER (2*10090080*17)
#define BUGCOLORS 3 #define BUGCOLORS 3
#define big_unlock (inv::on && !chaosmode) #define big_unlock (inv::on && !chaosmode)

View File

@ -59,22 +59,22 @@ struct hyperpoint : array<ld, MAXMDIM> {
#endif #endif
inline hyperpoint& operator *= (ld d) { inline hyperpoint& operator *= (ld d) {
for(int i=0; i<MDIM; i++) self[i] *= d; for(int i=0; i<MXDIM; i++) self[i] *= d;
return self; return self;
} }
inline hyperpoint& operator /= (ld d) { inline hyperpoint& operator /= (ld d) {
for(int i=0; i<MDIM; i++) self[i] /= d; for(int i=0; i<MXDIM; i++) self[i] /= d;
return self; return self;
} }
inline hyperpoint& operator += (const hyperpoint h2) { inline hyperpoint& operator += (const hyperpoint h2) {
for(int i=0; i<MDIM; i++) self[i] += h2[i]; for(int i=0; i<MXDIM; i++) self[i] += h2[i];
return self; return self;
} }
inline hyperpoint& operator -= (const hyperpoint h2) { inline hyperpoint& operator -= (const hyperpoint h2) {
for(int i=0; i<MDIM; i++) self[i] -= h2[i]; for(int i=0; i<MXDIM; i++) self[i] -= h2[i];
return self; return self;
} }
@ -99,7 +99,7 @@ struct hyperpoint : array<ld, MAXMDIM> {
// inner product // inner product
inline friend ld operator | (hyperpoint h1, hyperpoint h2) { inline friend ld operator | (hyperpoint h1, hyperpoint h2) {
ld sum = 0; ld sum = 0;
for(int i=0; i<MDIM; i++) sum += h1[i] * h2[i]; for(int i=0; i<MXDIM; i++) sum += h1[i] * h2[i];
return sum; return sum;
} }
}; };
@ -118,18 +118,18 @@ struct transmatrix {
inline friend hyperpoint operator * (const transmatrix& T, const hyperpoint& H) { inline friend hyperpoint operator * (const transmatrix& T, const hyperpoint& H) {
hyperpoint z; hyperpoint z;
for(int i=0; i<MDIM; i++) { for(int i=0; i<MXDIM; i++) {
z[i] = 0; z[i] = 0;
for(int j=0; j<MDIM; j++) z[i] += T[i][j] * H[j]; for(int j=0; j<MXDIM; j++) z[i] += T[i][j] * H[j];
} }
return z; return z;
} }
inline friend transmatrix operator * (const transmatrix& T, const transmatrix& U) { inline friend transmatrix operator * (const transmatrix& T, const transmatrix& U) {
transmatrix R; transmatrix R;
for(int i=0; i<MDIM; i++) for(int j=0; j<MDIM; j++) { for(int i=0; i<MXDIM; i++) for(int j=0; j<MXDIM; j++) {
R[i][j] = 0; R[i][j] = 0;
for(int k=0; k<MDIM; k++) for(int k=0; k<MXDIM; k++)
R[i][j] += T[i][k] * U[k][j]; R[i][j] += T[i][k] * U[k][j];
} }
return R; return R;
@ -490,14 +490,14 @@ EX ld hypot_auto(ld x, ld y) {
EX hyperpoint normalize(hyperpoint H) { EX hyperpoint normalize(hyperpoint H) {
if(prod) return H; if(prod) return H;
ld Z = zlevel(H); ld Z = zlevel(H);
for(int c=0; c<MDIM; c++) H[c] /= Z; for(int c=0; c<MXDIM; c++) H[c] /= Z;
return H; return H;
} }
/** like normalize but makes (ultra)ideal points material */ /** like normalize but makes (ultra)ideal points material */
EX hyperpoint ultra_normalize(hyperpoint H) { EX hyperpoint ultra_normalize(hyperpoint H) {
if(material(H) <= 0) { if(material(H) <= 0) {
H[MDIM-1] = hypot_d(MDIM-1, H) + 1e-6; H[LDIM] = hypot_d(LDIM, H) + 1e-6;
} }
return normalize(H); return normalize(H);
} }
@ -531,7 +531,7 @@ EX hyperpoint midz(const hyperpoint& H1, const hyperpoint& H2) {
ld Z = 2; ld Z = 2;
if(!euclid) Z = zlevel(H3) * 2 / (zlevel(H1) + zlevel(H2)); if(!euclid) Z = zlevel(H3) * 2 / (zlevel(H1) + zlevel(H2));
for(int c=0; c<MDIM; c++) H3[c] /= Z; for(int c=0; c<MXDIM; c++) H3[c] /= Z;
return H3; return H3;
} }
@ -611,8 +611,8 @@ EX transmatrix cpush(int cid, ld alpha) {
EX transmatrix xpush(ld alpha) { return cpush(0, alpha); } EX transmatrix xpush(ld alpha) { return cpush(0, alpha); }
EX bool eqmatrix(transmatrix A, transmatrix B, ld eps IS(.01)) { EX bool eqmatrix(transmatrix A, transmatrix B, ld eps IS(.01)) {
for(int i=0; i<MDIM; i++) for(int i=0; i<MXDIM; i++)
for(int j=0; j<MDIM; j++) for(int j=0; j<MXDIM; j++)
if(std::abs(A[i][j] - B[i][j]) > eps) if(std::abs(A[i][j] - B[i][j]) > eps)
return false; return false;
return true; return true;
@ -702,7 +702,7 @@ EX transmatrix parabolic13(ld u, ld v) {
} }
EX hyperpoint parabolic10(hyperpoint h) { EX hyperpoint parabolic10(hyperpoint h) {
if(euclid) { h[MDIM] = 1; return h; } if(euclid) { h[LDIM] = 1; return h; }
else if(MDIM == 4) return hyperpoint(sinh(h[0]), h[1]/exp(h[0]), h[2]/exp(h[0]), cosh(h[0])); else if(MDIM == 4) return hyperpoint(sinh(h[0]), h[1]/exp(h[0]), h[2]/exp(h[0]), cosh(h[0]));
else return hyperpoint(sinh(h[0]), h[1]/exp(h[0]), cosh(h[0]), 0); else return hyperpoint(sinh(h[0]), h[1]/exp(h[0]), cosh(h[0]), 0);
} }
@ -768,18 +768,19 @@ EX transmatrix pushxto0(const hyperpoint& H) {
/** set the i-th column of T to H */ /** set the i-th column of T to H */
EX void set_column(transmatrix& T, int i, const hyperpoint& H) { EX void set_column(transmatrix& T, int i, const hyperpoint& H) {
for(int j=0; j<MDIM; j++) for(int j=0; j<MXDIM; j++)
T[j][i] = H[j]; T[j][i] = H[j];
} }
/** build a matrix using the given vectors as columns */ /** build a matrix using the given vectors as columns */
EX transmatrix build_matrix(hyperpoint h1, hyperpoint h2, hyperpoint h3, hyperpoint h4) { EX transmatrix build_matrix(hyperpoint h1, hyperpoint h2, hyperpoint h3, hyperpoint h4) {
transmatrix T; transmatrix T;
for(int i=0; i<MDIM; i++) for(int i=0; i<MXDIM; i++) {
T[i][0] = h1[i], T[i][0] = h1[i],
T[i][1] = h2[i], T[i][1] = h2[i],
T[i][2] = h3[i]; T[i][2] = h3[i];
if(MAXMDIM == 4) for(int i=0; i<MDIM; i++) T[i][3] = h4[i]; if(MAXMDIM == 4) T[i][3] = h4[i];
}
return T; return T;
} }
@ -868,11 +869,11 @@ EX void fixmatrix_euclid(transmatrix& T) {
EX void orthonormalize(transmatrix& T) { EX void orthonormalize(transmatrix& T) {
for(int x=0; x<MDIM; x++) for(int y=0; y<=x; y++) { for(int x=0; x<MDIM; x++) for(int y=0; y<=x; y++) {
ld dp = 0; ld dp = 0;
for(int z=0; z<MDIM; z++) dp += T[z][x] * T[z][y] * sig(z); for(int z=0; z<MXDIM; z++) dp += T[z][x] * T[z][y] * sig(z);
if(y == x) dp = 1 - sqrt(sig(x)/dp); if(y == x) dp = 1 - sqrt(sig(x)/dp);
for(int z=0; z<MDIM; z++) T[z][x] -= dp * T[z][y]; for(int z=0; z<MXDIM; z++) T[z][x] -= dp * T[z][y];
} }
} }
@ -893,20 +894,20 @@ EX ld det3(const transmatrix& T) {
/** determinant */ /** determinant */
EX ld det(const transmatrix& T) { EX ld det(const transmatrix& T) {
if(GDIM == 2) if(MDIM == 3)
return det3(T); return det3(T);
else { else {
ld det = 1; ld det = 1;
transmatrix M = T; transmatrix M = T;
for(int a=0; a<MDIM; a++) { for(int a=0; a<MDIM; a++) {
for(int b=a; b<=GDIM; b++) for(int b=a; b<MDIM; b++)
if(M[b][a]) { if(M[b][a]) {
if(b != a) if(b != a)
for(int c=a; c<MDIM; c++) tie(M[b][c], M[a][c]) = make_pair(-M[a][c], M[b][c]); for(int c=a; c<MDIM; c++) tie(M[b][c], M[a][c]) = make_pair(-M[a][c], M[b][c]);
break; break;
} }
if(!M[a][a]) return 0; if(!M[a][a]) return 0;
for(int b=a+1; b<=GDIM; b++) { for(int b=a+1; b<MDIM; b++) {
ld co = -M[b][a] / M[a][a]; ld co = -M[b][a] / M[a][a];
for(int c=a; c<MDIM; c++) M[b][c] += M[a][c] * co; for(int c=a; c<MDIM; c++) M[b][c] += M[a][c] * co;
} }
@ -986,7 +987,7 @@ EX transmatrix ortho_inverse(transmatrix T) {
/** \brief inverse of an orthogonal matrix in Minkowski space */ /** \brief inverse of an orthogonal matrix in Minkowski space */
EX transmatrix pseudo_ortho_inverse(transmatrix T) { EX transmatrix pseudo_ortho_inverse(transmatrix T) {
for(int i=1; i<MDIM; i++) for(int i=1; i<MXDIM; i++)
for(int j=0; j<i; j++) for(int j=0; j<i; j++)
swap(T[i][j], T[j][i]); swap(T[i][j], T[j][i]);
for(int i=0; i<MDIM-1; i++) for(int i=0; i<MDIM-1; i++)
@ -1127,7 +1128,7 @@ EX hyperpoint mscale(const hyperpoint& t, double fac) {
if(GDIM == 3 && !prod) return cpush(2, fac) * t; if(GDIM == 3 && !prod) return cpush(2, fac) * t;
if(prod) fac = exp(fac); if(prod) fac = exp(fac);
hyperpoint res; hyperpoint res;
for(int i=0; i<MDIM; i++) for(int i=0; i<MXDIM; i++)
res[i] = t[i] * fac; res[i] = t[i] * fac;
return res; return res;
} }
@ -1143,8 +1144,12 @@ EX transmatrix mscale(const transmatrix& t, double fac) {
} }
if(prod) fac = exp(fac); if(prod) fac = exp(fac);
transmatrix res; transmatrix res;
for(int i=0; i<MDIM; i++) for(int j=0; j<MDIM; j++) for(int i=0; i<MXDIM; i++) {
for(int j=0; j<MDIM; j++)
res[i][j] = t[i][j] * fac; res[i][j] = t[i][j] * fac;
for(int j=MDIM; j<MXDIM; j++)
res[i][j] = t[i][j];
}
return res; return res;
} }
@ -1154,17 +1159,25 @@ EX shiftmatrix mscale(const shiftmatrix& t, double fac) {
EX transmatrix xyscale(const transmatrix& t, double fac) { EX transmatrix xyscale(const transmatrix& t, double fac) {
transmatrix res; transmatrix res;
for(int i=0; i<MDIM; i++) for(int j=0; j<GDIM; j++) for(int i=0; i<MXDIM; i++) {
for(int j=0; j<GDIM; j++)
res[i][j] = t[i][j] * fac; res[i][j] = t[i][j] * fac;
for(int j=GDIM; j<MXDIM; j++)
res[i][j] = t[i][j];
}
return res; return res;
} }
EX transmatrix xyzscale(const transmatrix& t, double fac, double facz) { EX transmatrix xyzscale(const transmatrix& t, double fac, double facz) {
transmatrix res; transmatrix res;
for(int i=0; i<MDIM; i++) for(int j=0; j<GDIM; j++) for(int i=0; i<MXDIM; i++) {
for(int j=0; j<GDIM; j++)
res[i][j] = t[i][j] * fac; res[i][j] = t[i][j] * fac;
for(int i=0; i<MDIM; i++) res[i][LDIM] =
res[i][LDIM] = t[i][LDIM] * facz; t[i][LDIM] * facz;
for(int j=LDIM+1; j<MXDIM; j++)
res[i][j] = t[i][j];
}
return res; return res;
} }
@ -1181,7 +1194,7 @@ EX transmatrix mzscale(const transmatrix& t, double fac) {
transmatrix res = t * inverse(tcentered) * ypush(-fac) * tcentered; transmatrix res = t * inverse(tcentered) * ypush(-fac) * tcentered;
fac *= .2; fac *= .2;
fac += 1; fac += 1;
for(int i=0; i<MDIM; i++) for(int j=0; j<MDIM; j++) for(int i=0; i<MXDIM; i++) for(int j=0; j<MXDIM; j++)
res[i][j] = res[i][j] * fac; res[i][j] = res[i][j] * fac;
return res; return res;
} }
@ -1300,8 +1313,8 @@ EX ld ortho_error(transmatrix T) {
EX transmatrix transpose(transmatrix T) { EX transmatrix transpose(transmatrix T) {
transmatrix result; transmatrix result;
for(int i=0; i<MDIM; i++) for(int i=0; i<MXDIM; i++)
for(int j=0; j<MDIM; j++) for(int j=0; j<MXDIM; j++)
result[j][i] = T[i][j]; result[j][i] = T[i][j];
return result; return result;
} }
@ -1340,7 +1353,7 @@ inline hyperpoint zpush0(ld x) { return cpush0(2, x); }
/** T * C0, optimized */ /** T * C0, optimized */
inline hyperpoint tC0(const transmatrix &T) { inline hyperpoint tC0(const transmatrix &T) {
hyperpoint z; hyperpoint z;
for(int i=0; i<MDIM; i++) z[i] = T[i][LDIM]; for(int i=0; i<MXDIM; i++) z[i] = T[i][LDIM];
return z; return z;
} }
@ -1485,4 +1498,24 @@ EX hyperpoint lerp(hyperpoint a0, hyperpoint a1, ld x) {
return a0 + (a1-a0) * x; return a0 + (a1-a0) * x;
} }
EX hyperpoint linecross(hyperpoint a, hyperpoint b, hyperpoint c, hyperpoint d) {
a /= a[LDIM];
b /= b[LDIM];
c /= c[LDIM];
d /= d[LDIM];
ld bax = b[0] - a[0];
ld dcx = d[0] - c[0];
ld cax = c[0] - a[0];
ld bay = b[1] - a[1];
ld dcy = d[1] - c[1];
ld cay = c[1] - a[1];
hyperpoint res;
res[0] = (cay * dcx * bax + a[0] * bay * dcx - c[0] * dcy * bax) / (bay * dcx - dcy * bax);
res[1] = (cax * dcy * bay + a[1] * bax * dcy - c[1] * dcx * bay) / (bax * dcy - dcx * bay);
res[2] = 1;
return normalize(res);
}
} }

View File

@ -2,21 +2,16 @@
// This is the main file when the online version of HyperRogue is compiled with Emscripten. // This is the main file when the online version of HyperRogue is compiled with Emscripten.
// Copyright (C) 2011-2018 Zeno Rogue, see 'hyper.cpp' for details // Copyright (C) 2011-2018 Zeno Rogue, see 'hyper.cpp' for details
#ifndef ISWEB
#define ISWEB 1 #define ISWEB 1
#define ISMINI 0 #define ISMINI 0
#define CAP_AUDIO 0
#define CAP_SDLGFX 0
#define CAP_PNG 0
#define CAP_TOUR 1
#define CAP_SDLTTF 0
#define CAP_SHMUP 0
#define CAP_RUG 1
#define CAP_INV 0 #define CAP_INV 0
#define CAP_URL 1 #define CAP_URL 1
#define GLES_ONLY #define GLES_ONLY
#define CAP_COMPLEX2 1 #define SCU
#endif
#if CAP_ROGUEVIZ #if CAP_ROGUEVIZ || defined(MAXMDIM)
#define MAXMDIM 4 #define MAXMDIM 4
#else #else
#define MAXMDIM 3 #define MAXMDIM 3
@ -45,6 +40,7 @@ namespace hr {
void emscripten_get_commandline(); void emscripten_get_commandline();
void loadCompressedChar(int &otwidth, int &otheight, int *tpix); void loadCompressedChar(int &otwidth, int &otheight, int *tpix);
void get_canvas_size();
const char *wheresounds; const char *wheresounds;
@ -53,7 +49,11 @@ namespace hr {
void offer_download(std::string sfilename, std::string smimetype); void offer_download(std::string sfilename, std::string smimetype);
} }
#ifdef SCU
#include "hyper.cpp" #include "hyper.cpp"
#else
#include "hyper.h"
#endif
namespace hr { namespace hr {
@ -72,7 +72,7 @@ string get_value(string name) {
return res; return res;
} }
void offer_download(string sfilename, string smimetype) { EX void offer_download(string sfilename, string smimetype) {
EM_ASM({ EM_ASM({
var name = UTF8ToString($0, $1); var name = UTF8ToString($0, $1);
@ -105,7 +105,7 @@ extern "C" {
} }
} }
void offer_choose_file(reaction_t r) { EX void offer_choose_file(reaction_t r) {
on_use_file = r; on_use_file = r;
EM_ASM({ EM_ASM({
fileElem.click(); fileElem.click();
@ -221,9 +221,39 @@ EM_BOOL fsc_callback(int eventType, const EmscriptenFullscreenChangeEvent *fulls
return true; return true;
} }
void initweb() { EX void get_canvas_size() {
vid.xscr = vid.xres = EM_ASM_INT({
var d = document.getElementById("this_wide");
if(!d) return window.innerWidth;
return d.clientWidth;
});
if(vid.full) vid.yscr = vid.yres = EM_ASM_INT({
var d = document.getElementById("this_wide");
if(!d) return window.innerWidth;
return d.clientHeight;
});
else {
vid.xscr = vid.xres = vid.xres - 32;
vid.yscr = vid.yres = EM_ASM_INT({
return window.innerHeight;
}) - 32;
vid.yscr = vid.yres = min(vid.yscr, vid.xscr * 9 / 16);
vid.xscr = vid.xres = min(vid.xscr, vid.yscr * 16 / 9);
}
println(hlog, "X = ", vid.xscr, " Y = ", vid.yscr);
}
EM_BOOL resize_callback(int eventType, const EmscriptenUiEvent *resizeEvent, void *userData) {
if(vid.full) return true;
get_canvas_size();
setvideomode();
return true;
}
EX void initweb() {
// toggleanim(false); // toggleanim(false);
emscripten_set_fullscreenchange_callback(0, NULL, false, fsc_callback); emscripten_set_fullscreenchange_callback(0, NULL, false, fsc_callback);
emscripten_set_resize_callback(0, NULL, false, resize_callback);
printf("showstartmenu = %d\n", showstartmenu); printf("showstartmenu = %d\n", showstartmenu);
if(showstartmenu) pushScreen(showDemo); if(showstartmenu) pushScreen(showDemo);
} }
@ -241,7 +271,7 @@ transmatrix getOrientation() {
} }
#endif #endif
void emscripten_get_commandline() { EX void emscripten_get_commandline() {
#ifdef EMSCRIPTEN_FIXED_ARG #ifdef EMSCRIPTEN_FIXED_ARG
string s = EMSCRIPTEN_FIXED_ARG; string s = EMSCRIPTEN_FIXED_ARG;
#else #else

View File

@ -1074,6 +1074,76 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) {
} }
} }
case mdRetroCraig: {
makeband(H_orig, ret, [] (ld& x, ld& y) {
if(x)
y = x / sin_auto(x) * (sin_auto(y) * cos_auto(x) - tan_auto(pconf.loximuthal_parameter) * cos_auto(y));
else
y = sin_auto(y) - tan_auto(pconf.loximuthal_parameter) * cos_auto(y);
});
break;
}
case mdRetroLittrow: {
makeband(H_orig, ret, [] (ld& x, ld& y) {
tie(x, y) = make_pair(
sin_auto(x) / cos_auto(y),
cos_auto(x) * tan_auto(y)
);
});
break;
}
case mdRetroHammer: {
ld d = hdist(H, ypush0(pconf.loximuthal_parameter));
makeband(H_orig, ret, [d,H] (ld& x, ld& y) {
if(x == 0 && y == 0) return;
if(x)
y = x / sin_auto(x) * (sin_auto(y) * cos_auto(x) - tan_auto(pconf.loximuthal_parameter) * cos_auto(y));
else
y = sin_auto(y) - tan_auto(pconf.loximuthal_parameter) * cos_auto(y);
ld scale = d / hypot(x, y);
if(H[2] < 0) scale = -scale;
x *= scale;
y *= scale;
});
break;
}
case mdPanini: {
ld proh = sqrt(H[2]*H[2] + curvature() * H[0] * H[0]);
H /= proh;
H /= (H[2] + pconf.alpha);
ret = H;
ret[2] = 0; ret[3] = 1;
break;
}
case mdPoorMan: {
find_zlev(H);
H = space_to_perspective(H);
models::apply_orientation_yz(H[1], H[2]);
models::apply_orientation(H[0], H[1]);
ld u = H[0], v = H[1];
if(abs(u) > 1e-3 && abs(v) > 1e-3) {
ld r2 = u*u+v*v;
ld scale = sqrt((-r2+sqrt(r2*(r2+4*u*u*v*v*(r2-2))))/(2*(r2-2))) / u / v;
if(u*v<0) scale = -scale;
H = scale * H;
}
ret = H;
ret[2] = 0;
ret[3] = 1;
models::apply_orientation(ret[1], ret[0]);
models::apply_orientation_yz(ret[2], ret[1]);
break;
}
case mdGUARD: case mdManual: break; case mdGUARD: case mdManual: break;
} }
@ -1462,6 +1532,10 @@ void hrmap::draw_at(cell *at, const shiftmatrix& where) {
} }
void hrmap_standard::draw_at(cell *at, const shiftmatrix& where) { void hrmap_standard::draw_at(cell *at, const shiftmatrix& where) {
if(S3 > 4) {
hrmap::draw_at(at, where);
return;
}
drawn_cells.clear(); drawn_cells.clear();
drawn_cells.emplace_back(at->master, hsOrigin, where * master_relative(at, true)); drawn_cells.emplace_back(at->master, hsOrigin, where * master_relative(at, true));
for(int i=0; i<isize(drawn_cells); i++) { for(int i=0; i<isize(drawn_cells); i++) {
@ -1926,6 +2000,7 @@ EX void draw_model_elements() {
} }
case mdHyperboloid: { case mdHyperboloid: {
if(!pconf.show_hyperboloid_flat) return;
if(hyperbolic) { if(hyperbolic) {
#if CAP_QUEUE #if CAP_QUEUE
curvepoint(point3(0,0,1)); curvepoint(point3(0,0,1));

View File

@ -313,6 +313,8 @@ EX void dropGreenStone(cell *c) {
return; return;
} }
if(items[itGreenStone] && c->item == itNone) { if(items[itGreenStone] && c->item == itNone) {
changes.ccell(c);
changes.value_keep(items[itGreenStone]);
items[itGreenStone]--; items[itGreenStone]--;
if(false) { if(false) {
c->item = itNone; c->item = itNone;
@ -484,6 +486,7 @@ EX void gainItem(eItem it) {
#define IF(x) if(g < (x) && g2 >= x && !peace::on) #define IF(x) if(g < (x) && g2 >= x && !peace::on)
if(in_full_game()) {
IF(R60/4) IF(R60/4)
addMessage(XLAT("Collect treasure to access more different lands...")); addMessage(XLAT("Collect treasure to access more different lands..."));
IF(R30) IF(R30)
@ -501,6 +504,7 @@ EX void gainItem(eItem it) {
addMessage(XLAT("And the Orbs of Yendor await!")); addMessage(XLAT("And the Orbs of Yendor await!"));
} }
} }
}
EX string itemcounter(int qty) { EX string itemcounter(int qty) {
string s = ""; s += " ("; s += its(qty); s += ")"; return s; string s = ""; s += " ("; s += its(qty); s += ")"; return s;

View File

@ -2431,7 +2431,9 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
break; break;
case laBrownian: case laBrownian:
#if CAP_COMPLEX2
brownian::build(c, d); brownian::build(c, d);
#endif
break; break;
case laMirrored: case laMirrored:
@ -2807,6 +2809,7 @@ EX void setdist(cell *c, int d, cell *from) {
if(d >= BARLEV) { if(d >= BARLEV) {
#if CAP_BT
if(bt::in() && WDIM == 3 && !c->land && !sn::in()) { if(bt::in() && WDIM == 3 && !c->land && !sn::in()) {
ld z = vid.binary_width; ld z = vid.binary_width;
cell *cseek = c; cell *cseek = c;
@ -2816,6 +2819,7 @@ EX void setdist(cell *c, int d, cell *from) {
while(z < 3.999 && step < 10) cseek = cseek->cmove(bt::updir()), z *= scale; while(z < 3.999 && step < 10) cseek = cseek->cmove(bt::updir()), z *= scale;
if(cseek->master->emeraldval) setland(c, eLand(cseek->master->emeraldval)); if(cseek->master->emeraldval) setland(c, eLand(cseek->master->emeraldval));
} }
#endif
if(!c->land && from && (WDIM == 3 || !among(from->land, laBarrier, laElementalWall, laHauntedWall, laOceanWall)) && !quotient && !(chaosmode > 1)) { if(!c->land && from && (WDIM == 3 || !among(from->land, laBarrier, laElementalWall, laHauntedWall, laOceanWall)) && !quotient && !(chaosmode > 1)) {
if(!hasbardir(c)) setland(c, from->land); if(!hasbardir(c)) setland(c, from->land);

View File

@ -62,8 +62,11 @@ struct fullnoun {
}; };
#if !CAP_TRANS #if !CAP_TRANS
#define NUMEXTRA 11 #if HDR
const char* natchars[NUMEXTRA] = {"°","é","á", "²", "½", "Θ", "δ", "π", "ϕ", "", ""}; #define NUMEXTRA 12
extern const char* natchars[NUMEXTRA];
#endif
const char* natchars[NUMEXTRA] = {"°","é","á", "²", "½", "Θ", "δ", "π", "ϕ", "", "", ""};
#endif #endif
#if CAP_TRANS #if CAP_TRANS

View File

@ -459,6 +459,7 @@ constexpr int FALL = 98;
constexpr int NO_SPACE = 97; constexpr int NO_SPACE = 97;
constexpr int TELEPORT = 96; constexpr int TELEPORT = 96;
constexpr int JUMP = 95; constexpr int JUMP = 95;
constexpr int STAY = 94;
namespace whirlwind { cell *jumpDestination(cell*); } namespace whirlwind { cell *jumpDestination(cell*); }

View File

@ -1095,8 +1095,8 @@ EX namespace mapeditor {
displayButton(8, vid.yres-8-fs*2, XLAT("ESC = return to the game"), SDLK_ESCAPE, 0); displayButton(8, vid.yres-8-fs*2, XLAT("ESC = return to the game"), SDLK_ESCAPE, 0);
} }
EX unordered_set<cell*> affected; EX set<cell*> affected;
EX unordered_set<int> affected_id; EX set<int> affected_id;
EX void showMapEditor() { EX void showMapEditor() {
cmode = sm::MAP; cmode = sm::MAP;
@ -1276,6 +1276,7 @@ EX namespace mapeditor {
void list_spill(cellwalker tgt, cellwalker src, manual_celllister& cl) { void list_spill(cellwalker tgt, cellwalker src, manual_celllister& cl) {
spill_list.clear(); spill_list.clear();
spill_list.emplace_back(tgt, src); spill_list.emplace_back(tgt, src);
if(painttype == 7) return;
int crad = 0, nextstepat = 0; int crad = 0, nextstepat = 0;
for(int i=0; i<isize(spill_list); i++) { for(int i=0; i<isize(spill_list); i++) {
if(i == nextstepat) { if(i == nextstepat) {

View File

@ -200,12 +200,15 @@ EX namespace models {
if(GDIM == 2 && pm == mdEquivolume) return false; if(GDIM == 2 && pm == mdEquivolume) return false;
if(GDIM == 3 && among(pm, mdBall, mdHyperboloid, mdFormula, mdPolygonal, mdRotatedHyperboles, mdSpiral, mdHemisphere)) return false; if(GDIM == 3 && among(pm, mdBall, mdHyperboloid, mdFormula, mdPolygonal, mdRotatedHyperboles, mdSpiral, mdHemisphere)) return false;
if(pm == mdCentralInversion && !euclid) return false; if(pm == mdCentralInversion && !euclid) return false;
if(pm == mdPoorMan) return hyperbolic;
if(pm == mdRetroHammer) return hyperbolic;
return true; return true;
} }
EX bool has_orientation(eModel m) { EX bool has_orientation(eModel m) {
if(m == mdHorocyclic) if(m == mdHorocyclic)
return hyperbolic; return hyperbolic;
if((m == mdPerspective || m == mdGeodesic) && panini_alpha) return true;
return return
among(m, mdHalfplane, mdPolynomial, mdPolygonal, mdTwoPoint, mdJoukowsky, mdJoukowskyInverted, mdSpiral, mdSimulatedPerspective, mdTwoHybrid, mdHorocyclic, mdAxial, mdAntiAxial, mdQuadrant, among(m, mdHalfplane, mdPolynomial, mdPolygonal, mdTwoPoint, mdJoukowsky, mdJoukowskyInverted, mdSpiral, mdSimulatedPerspective, mdTwoHybrid, mdHorocyclic, mdAxial, mdAntiAxial, mdQuadrant,
mdWerner, mdAitoff, mdHammer, mdLoximuthal, mdWinkelTripel) || mdBandAny(); mdWerner, mdAitoff, mdHammer, mdLoximuthal, mdWinkelTripel) || mdBandAny();
@ -442,7 +445,9 @@ EX namespace models {
dialog::addBreak(50); dialog::addBreak(50);
} }
if(among(vpmodel, mdDisk, mdBall, mdHyperboloid, mdRotatedHyperboles)) { if(among(vpmodel, mdDisk, mdBall, mdHyperboloid, mdRotatedHyperboles, mdPanini)) {
dynamicval<eModel> v(vpconf.model, vpconf.model);
if(vpmodel == mdHyperboloid) vpconf.model = mdDisk;
dialog::addSelItem(XLAT("projection distance"), fts(vpconf.alpha) + " (" + current_proj_name() + ")", 'p'); dialog::addSelItem(XLAT("projection distance"), fts(vpconf.alpha) + " (" + current_proj_name() + ")", 'p');
dialog::add_action(projectionDialog); dialog::add_action(projectionDialog);
} }
@ -614,6 +619,10 @@ EX namespace models {
}); });
} }
if(vpmodel == mdHyperboloid) {
dialog::addBoolItem_action(XLAT("show flat"), pconf.show_hyperboloid_flat, 'b');
}
if(vpmodel == mdCollignon) { if(vpmodel == mdCollignon) {
dialog::addSelItem(XLAT("parameter"), fts(vpconf.collignon_parameter) + (vpconf.collignon_reflected ? " (r)" : ""), 'b'); dialog::addSelItem(XLAT("parameter"), fts(vpconf.collignon_parameter) + (vpconf.collignon_reflected ? " (r)" : ""), 'b');
dialog::add_action([](){ dialog::add_action([](){
@ -636,13 +645,17 @@ EX namespace models {
}); });
} }
if(vpmodel == mdLoximuthal) { if(among(vpmodel, mdLoximuthal, mdRetroHammer, mdRetroCraig)) {
dialog::addSelItem(XLAT("parameter"), fts(vpconf.loximuthal_parameter), 'b'); dialog::addSelItem(XLAT("parameter"), fts(vpconf.loximuthal_parameter), 'b');
dialog::add_action([](){ dialog::add_action([vpmodel](){
dialog::editNumber(vpconf.loximuthal_parameter, -M_PI/2, M_PI/2, .1, 0, XLAT("parameter"), dialog::editNumber(vpconf.loximuthal_parameter, -M_PI/2, M_PI/2, .1, 0, XLAT("parameter"),
(vpmodel == mdLoximuthal ?
"This model is similar to azimuthal equidistant, but based on loxodromes (lines of constant geographic direction) rather than geodesics. " "This model is similar to azimuthal equidistant, but based on loxodromes (lines of constant geographic direction) rather than geodesics. "
"The loximuthal projection maps (the shortest) loxodromes to straight lines of the same length, going through the starting point. " "The loximuthal projection maps (the shortest) loxodromes to straight lines of the same length, going through the starting point. "
"This setting changes the latitude of the starting point." "This setting changes the latitude of the starting point." :
"In retroazimuthal projections, a point is drawn at such a point that the azimuth *from* that point to the chosen central point is correct. "
"For example, if you should move east, the point is drawn to the right. This parameter is the latitude of the central point.")
+ string(hyperbolic ? "\n\n(In hyperbolic geometry directions are assigned according to the Lobachevsky coordinates.)" : "")
); );
}); });
} }
@ -827,7 +840,7 @@ EX namespace models {
PHASEFROM(2); PHASEFROM(2);
if(pmodel == mdCollignon) shift_arg_formula(vpconf.collignon_parameter); if(pmodel == mdCollignon) shift_arg_formula(vpconf.collignon_parameter);
else if(pmodel == mdMiller) shift_arg_formula(vpconf.miller_parameter); else if(pmodel == mdMiller) shift_arg_formula(vpconf.miller_parameter);
else if(pmodel == mdLoximuthal) shift_arg_formula(vpconf.loximuthal_parameter); else if(among(pmodel, mdLoximuthal, mdRetroCraig, mdRetroHammer)) shift_arg_formula(vpconf.loximuthal_parameter);
else if(among(pmodel, mdAitoff, mdHammer, mdWinkelTripel)) shift_arg_formula(vpconf.aitoff_parameter); else if(among(pmodel, mdAitoff, mdHammer, mdWinkelTripel)) shift_arg_formula(vpconf.aitoff_parameter);
if(pmodel == mdWinkelTripel) shift_arg_formula(vpconf.winkel_parameter); if(pmodel == mdWinkelTripel) shift_arg_formula(vpconf.winkel_parameter);
} }
@ -856,6 +869,10 @@ EX namespace models {
PHASEFROM(2); PHASEFROM(2);
shift_arg_formula(vpconf.skiprope); shift_arg_formula(vpconf.skiprope);
} }
else if(argis("-palpha")) {
PHASEFROM(2);
shift_arg_formula(panini_alpha, reset_all_shaders);
}
else if(argis("-zoom")) { else if(argis("-zoom")) {
PHASEFROM(2); shift_arg_formula(vpconf.scale); PHASEFROM(2); shift_arg_formula(vpconf.scale);
} }

View File

@ -318,10 +318,12 @@ EX eItem wanderingTreasure(cell *c) {
/** generate the wandering monsters */ /** generate the wandering monsters */
EX void wandering() { EX void wandering() {
#if CAP_COMPLEX2
if(mine::in_minesweeper()) { if(mine::in_minesweeper()) {
mine::count_status(); mine::count_status();
return; return;
} }
#endif
if(!canmove) return; if(!canmove) return;
if(!gen_wandering) return; if(!gen_wandering) return;
if(racing::on) return; if(racing::on) return;

View File

@ -108,6 +108,8 @@ EX void moveMonster(const movei& mi) {
auto& cf = mi.s; auto& cf = mi.s;
auto& ct = mi.t; auto& ct = mi.t;
eMonster m = cf->monst; eMonster m = cf->monst;
changes.ccell(cf);
changes.ccell(ct);
bool fri = isFriendly(cf); bool fri = isFriendly(cf);
if(isDragon(m)) { if(isDragon(m)) {
printf("called for Dragon\n"); printf("called for Dragon\n");
@ -117,6 +119,7 @@ EX void moveMonster(const movei& mi) {
// the following line is necessary because otherwise plates disappear only inside the sight range // the following line is necessary because otherwise plates disappear only inside the sight range
if(cellUnstable(cf) && !ignoresPlates(m)) { if(cellUnstable(cf) && !ignoresPlates(m)) {
fallingFloorAnimation(cf); fallingFloorAnimation(cf);
changes.ccell(cf);
cf->wall = waChasm; cf->wall = waChasm;
} }
moveEffect(mi, m); moveEffect(mi, m);
@ -124,6 +127,7 @@ EX void moveMonster(const movei& mi) {
(m == moShark || m == moCShark || m == moGreaterShark)) (m == moShark || m == moCShark || m == moGreaterShark))
achievement_gain_once("MOATSHARK"); achievement_gain_once("MOATSHARK");
if(m == moTentacleGhost) { if(m == moTentacleGhost) {
changes.ccell(cf);
cf->monst = moTentacletail; cf->monst = moTentacletail;
m = moGhost; m = moGhost;
} }
@ -156,10 +160,11 @@ EX void moveMonster(const movei& mi) {
} }
} }
if(fri || isBug(m) || items[itOrbDiscord]) stabbingAttack(cf, ct, m); if(fri || isBug(m) || items[itOrbDiscord]) stabbingAttack(mi, m);
if(mi.d == JUMP && m == moVaulter) { if(mi.d == JUMP && m == moVaulter) {
cell *cm = common_neighbor(cf, ct); cell *cm = common_neighbor(cf, ct);
changes.ccell(cm);
if(cm->wall == waShrub) cm->wall = waNone; if(cm->wall == waShrub) cm->wall = waNone;
if(cm->wall == waSmallTree) cm->wall = waNone; if(cm->wall == waSmallTree) cm->wall = waNone;
if(cm->wall == waBigTree) cm->wall = waSmallTree; if(cm->wall == waBigTree) cm->wall = waSmallTree;
@ -1518,7 +1523,10 @@ EX int stayvalue(eMonster m, cell *c) {
} }
/** for an ally m at c, evaluate moving to c2 */ /** for an ally m at c, evaluate moving to c2 */
EX int movevalue(eMonster m, cell *c, cell *c2, flagtype flags) { EX int movevalue(eMonster m, cell *c, int dir, flagtype flags) {
auto mi = movei(c, dir);
auto& c2 = mi.t;
int val = 0; int val = 0;
if(isPlayerOn(c2)) val = -3000; if(isPlayerOn(c2)) val = -3000;
@ -1537,7 +1545,6 @@ EX int movevalue(eMonster m, cell *c, cell *c2, flagtype flags) {
isInactiveEnemy(c2,m) ? 1000 : isInactiveEnemy(c2,m) ? 1000 :
-500; -500;
else if(monstersnear(c2, m, NULL, c)) val = 50; // linked with mouse suicide!
else if(passable_for(m, c2, c, 0)) { else if(passable_for(m, c2, c, 0)) {
#if CAP_COMPLEX2 #if CAP_COMPLEX2
if(mine::marked_mine(c2) && !ignoresPlates(m)) if(mine::marked_mine(c2) && !ignoresPlates(m))
@ -1545,12 +1552,22 @@ EX int movevalue(eMonster m, cell *c, cell *c2, flagtype flags) {
else else
#endif #endif
val = 4000; val = 4000;
int tk = tkills();
changes.init(true);
moveMonster(mi);
int tk2 = tkills();
bool b = monstersnear(mi.t, m);
changes.rollback();
if(b) val = 50;
else if(tk2 > tk) val += 1000 + 200 * (tk2 - tk);
} }
else if(passable_for(m, c2, c, P_DEADLY)) val = -1100; else if(passable_for(m, c2, c, P_DEADLY)) val = -1100;
else val = -1750; else val = -1750;
if(c->monst == moGolem ) if(c->monst == moGolem ) {
val -= c2->cpdist; val -= c2->pathdist;
}
else if(c->monst == moFriendlyGhost ) else if(c->monst == moFriendlyGhost )
val += c2->cpdist - 40; val += c2->cpdist - 40;
else if(c->monst == moMouse) { else if(c->monst == moMouse) {
@ -1599,9 +1616,9 @@ EX int movevalue(eMonster m, cell *c, cell *c2, flagtype flags) {
val -= 5; val -= 5;
} }
if(c->monst == moTameBomberbird) { if(c->monst == moTameBomberbird) {
int d = c2->cpdist; int d = c2->pathdist;
if(d == 1 && c->cpdist > 1) d = 5; if(d == 1 && c->pathdist > 1) d = 5;
if(d == 2 && c->cpdist > 2) d = 4; if(d == 2 && c->pathdist > 2) d = 4;
val -= d; val -= d;
} }
if(c->monst == moKnight && (eubinary || c2->master->alt)) { if(c->monst == moKnight && (eubinary || c2->master->alt)) {
@ -1616,11 +1633,11 @@ EX int movevalue(eMonster m, cell *c, cell *c2, flagtype flags) {
EX void movegolems(flagtype flags) { EX void movegolems(flagtype flags) {
if(items[itOrbEmpathy] && items[itOrbSlaying]) if(items[itOrbEmpathy] && items[itOrbSlaying])
flags |= AF_CRUSH; flags |= AF_CRUSH;
pathdata pd(moMouse);
int qg = 0; int qg = 0;
for(int i=0; i<isize(golems); i++) { for(int i=0; i<isize(golems); i++) {
cell *c = golems[i]; cell *c = golems[i];
eMonster m = c->monst; eMonster m = c->monst;
pathdata pd(m, false);
if(c->stuntime) continue; if(c->stuntime) continue;
if(m == moGolem || m == moKnight || m == moTameBomberbird || m == moPrincess || if(m == moGolem || m == moKnight || m == moTameBomberbird || m == moPrincess ||
m == moPrincessArmed || m == moMouse || m == moFriendlyGhost) { m == moPrincessArmed || m == moMouse || m == moFriendlyGhost) {
@ -1636,8 +1653,7 @@ EX void movegolems(flagtype flags) {
DEBB(DF_TURN, ("moveval")); DEBB(DF_TURN, ("moveval"));
for(int k=0; k<c->type; k++) if(c->move(k)) { for(int k=0; k<c->type; k++) if(c->move(k)) {
cell *c2 = c->move(k); int val = movevalue(m, c, k, flags);
int val = movevalue(m, c, c2, flags);
if(val > bestv) bestv = val, bdirs.clear(); if(val > bestv) bestv = val, bdirs.clear();
if(val == bestv) bdirs.push_back(k); if(val == bestv) bdirs.push_back(k);
@ -1646,7 +1662,7 @@ EX void movegolems(flagtype flags) {
if(m == moTameBomberbird) { if(m == moTameBomberbird) {
cell *c2 = whirlwind::jumpDestination(c); cell *c2 = whirlwind::jumpDestination(c);
if(c2 && !c2->monst) { if(c2 && !c2->monst) {
int val = movevalue(m, c, c2, flags); int val = movevalue(m, c, STRONGWIND, flags);
// printf("val = %d bestv = %d\n", // printf("val = %d bestv = %d\n",
if(val > bestv) bestv = val, bdirs.clear(); if(val > bestv) bestv = val, bdirs.clear();
if(val == bestv) bdirs.push_back(STRONGWIND); if(val == bestv) bdirs.push_back(STRONGWIND);

View File

@ -221,22 +221,15 @@ struct key_configurer {
int sc; int sc;
vector<string>& shmupcmdtable; vector<string>& shmupcmdtable;
string caption;
int setwhat; int setwhat;
key_configurer(int sc, vector<string>& sct) : sc(sc), shmupcmdtable(sct), setwhat(0) {} key_configurer(int sc, vector<string>& sct, const string& caption) : sc(sc), shmupcmdtable(sct), caption(caption), setwhat(0) {
}
void operator() () { void operator() () {
dialog::init( dialog::init(caption);
XLAT(sc == 1 ? "configure player 1" :
sc == 2 ? "configure player 2" :
sc == 3 ? "configure panning" :
sc == 4 ? "configure player 3" :
sc == 5 ? "configure player 4" :
sc == 6 ? "configure player 5" :
sc == 7 ? "configure player 6" :
sc == 8 ? "configure player 7" : ""
));
getcstat = ' '; getcstat = ' ';
@ -302,7 +295,21 @@ struct key_configurer {
} }
}; };
EX reaction_t get_key_configurer(int sc, vector<string>& sct) { return key_configurer(sc, sct); } EX reaction_t get_key_configurer(int sc, vector<string>& sct, string caption) {
return key_configurer(sc, sct, caption);
}
EX reaction_t get_key_configurer(int sc, vector<string>& sct) {
return key_configurer(sc, sct, XLAT(sc == 1 ? "configure player 1" :
sc == 2 ? "configure player 2" :
sc == 3 ? "configure panning" :
sc == 4 ? "configure player 3" :
sc == 5 ? "configure player 4" :
sc == 6 ? "configure player 5" :
sc == 7 ? "configure player 6" :
sc == 8 ? "configure player 7" : ""
));
}
#if CAP_SDLJOY #if CAP_SDLJOY
struct joy_configurer { struct joy_configurer {
@ -456,14 +463,14 @@ struct shmup_configurer {
if(0) ; if(0) ;
#if CAP_SDL #if CAP_SDL
else if(uni == '1') pushScreen(key_configurer(1, cmdlist)); else if(uni == '1') pushScreen(get_key_configurer(1, cmdlist));
else if(uni == '2') pushScreen(key_configurer(2, cmdlist)); else if(uni == '2') pushScreen(get_key_configurer(2, cmdlist));
else if(uni == 'p') pushScreen(key_configurer(3, GDIM == 3 ? pancmds3 : pancmds)); else if(uni == 'p') pushScreen(get_key_configurer(3, GDIM == 3 ? pancmds3 : pancmds));
else if(uni == '3') pushScreen(key_configurer(4, cmdlist)); else if(uni == '3') pushScreen(get_key_configurer(4, cmdlist));
else if(uni == '4') pushScreen(key_configurer(5, cmdlist)); else if(uni == '4') pushScreen(get_key_configurer(5, cmdlist));
else if(uni == '5') pushScreen(key_configurer(6, cmdlist)); else if(uni == '5') pushScreen(get_key_configurer(6, cmdlist));
else if(uni == '6') pushScreen(key_configurer(7, cmdlist)); else if(uni == '6') pushScreen(get_key_configurer(7, cmdlist));
else if(uni == '7') pushScreen(key_configurer(8, cmdlist)); else if(uni == '7') pushScreen(get_key_configurer(8, cmdlist));
#if CAP_SDLJOY #if CAP_SDLJOY
else if(uni == 'j') pushScreen(joy_configurer(players)); else if(uni == 'j') pushScreen(joy_configurer(players));
#endif #endif
@ -638,6 +645,7 @@ EX void initConfig() {
multi::scs[5].uicolor = 0x00C0C0FF; multi::scs[5].uicolor = 0x00C0C0FF;
multi::scs[6].uicolor = 0xC0C0C0FF; multi::scs[6].uicolor = 0xC0C0C0FF;
#if CAP_CONFIG
addsaver(multi::players, "mode-number of players"); addsaver(multi::players, "mode-number of players");
addsaver(alwaysuse, "use configured keys"); addsaver(alwaysuse, "use configured keys");
// unfortunately we cannot use key names here because SDL is not yet initialized // unfortunately we cannot use key names here because SDL is not yet initialized
@ -656,6 +664,7 @@ EX void initConfig() {
} }
} }
for(int i=0; i<7; i++) addsaver(multi::scs[i], "player"+its(i)); for(int i=0; i<7; i++) addsaver(multi::scs[i], "player"+its(i));
#endif
} }
EX void handleInput(int delta) { EX void handleInput(int delta) {

View File

@ -295,11 +295,17 @@ EX namespace dual {
} }
else { else {
variation = eVariation::pure; variation = eVariation::pure;
#if CAP_ARCM
geometry = s == 0 ? gEuclidSquare : gArchimedean; geometry = s == 0 ? gEuclidSquare : gArchimedean;
#else
geometry = gEuclidSquare;
#endif
} }
firstland = specialland = laCrossroads4; firstland = specialland = laCrossroads4;
#if CAP_ARCM
if(geometry == gArchimedean) if(geometry == gArchimedean)
arcm::current.parse("4,4,4,4,4"); arcm::current.parse("4,4,4,4,4");
#endif
check_cgi(); check_cgi();
cgi.require_basics(); cgi.require_basics();
dgd[s].storegame(); dgd[s].storegame();

View File

@ -60,6 +60,19 @@ void set_mingw64() {
setvbuf(stdout, NULL, _IONBF, 0); // MinGW is quirky with output buffering setvbuf(stdout, NULL, _IONBF, 0); // MinGW is quirky with output buffering
} }
void set_web() {
preprocessor = "/usr/lib/emscripten/em++ -E";
compiler = "/usr/lib/emscripten/em++ -c";
default_standard = standard = " -std=c++17";
opts = "-DISWEB=1";
linker =
"/usr/lib/emscripten/em++ -s USE_ZLIB=1 -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=0 -s TOTAL_MEMORY=512MB "
"-s EXTRA_EXPORTED_RUNTIME_METHODS='[\"FS\",\"ccall\"]' "
"-s EXPORTED_FUNCTIONS=\"['_main', '_use_file']\" "
"-s DISABLE_EXCEPTION_CATCHING=0 -o mhyper.html";
libs = "";
}
vector<string> modules; vector<string> modules;
time_t get_file_time(const string s) { time_t get_file_time(const string s) {
@ -123,6 +136,12 @@ int main(int argc, char **argv) {
obj_dir += "/linux"; obj_dir += "/linux";
setdir += "../"; setdir += "../";
} }
else if(s == "-web") {
set_web();
modules.push_back("hyperweb");
obj_dir += "/web";
setdir += "../";
}
else if(s.substr(0, 2) == "-f") { else if(s.substr(0, 2) == "-f") {
opts += " " + s; opts += " " + s;
obj_dir += "/"; obj_dir += "/";

View File

@ -127,11 +127,11 @@ unsigned char fonttable[] = {
unsigned char *ftv = fonttable; unsigned char *ftv = fonttable;
void resetTabFont() { EX void resetTabFont() {
ftv = fonttable; ftv = fonttable;
} }
void loadCompressedChar(int &otwidth, int &otheight, unsigned char *tpix) { EX void loadCompressedChar(int &otwidth, int &otheight, unsigned char *tpix) {
if(*ftv == 255) { if(*ftv == 255) {
fprintf(stderr, "There is something wrong with the font table\n"); fprintf(stderr, "There is something wrong with the font table\n");
exit(1); exit(1);

View File

@ -236,8 +236,8 @@ EX namespace sn {
struct hrmap_solnih : hrmap { struct hrmap_solnih : hrmap {
hrmap *binary_map; hrmap *binary_map;
hrmap *ternary_map; /* nih only */ hrmap *ternary_map; /* nih only */
unordered_map<pair<heptagon*, heptagon*>, heptagon*> at; map<pair<heptagon*, heptagon*>, heptagon*> at;
unordered_map<heptagon*, pair<heptagon*, heptagon*>> coords; map<heptagon*, pair<heptagon*, heptagon*>> coords;
heptagon *origin; heptagon *origin;
@ -872,8 +872,8 @@ EX namespace nilv {
} }
struct hrmap_nil : hrmap { struct hrmap_nil : hrmap {
unordered_map<mvec, heptagon*> at; map<mvec, heptagon*> at;
unordered_map<heptagon*, mvec> coords; map<heptagon*, mvec> coords;
heptagon *getOrigin() override { return get_at(mvec_zero); } heptagon *getOrigin() override { return get_at(mvec_zero); }
@ -1231,6 +1231,8 @@ EX namespace hybrid {
dynamicval<hrmap*> gpm(pmap, this); dynamicval<hrmap*> gpm(pmap, this);
dynamicval<eGeometry> gag(actual_geometry, geometry); dynamicval<eGeometry> gag(actual_geometry, geometry);
dynamicval<eGeometry> g(geometry, underlying); dynamicval<eGeometry> g(geometry, underlying);
dynamicval<int> gss(underlying_cgip->single_step, cgi.single_step);
dynamicval<int> gsp(underlying_cgip->psl_steps, cgi.psl_steps);
dynamicval<geometry_information*> gc(cgip, underlying_cgip); dynamicval<geometry_information*> gc(cgip, underlying_cgip);
dynamicval<hrmap*> gu(currentmap, underlying_map); dynamicval<hrmap*> gu(currentmap, underlying_map);
return t(); return t();
@ -1308,6 +1310,8 @@ EX namespace hybrid {
if(!hybri) return f(); if(!hybri) return f();
dynamicval<eGeometry> g(geometry, underlying); dynamicval<eGeometry> g(geometry, underlying);
dynamicval<eGeometry> gag(actual_geometry, geometry); dynamicval<eGeometry> gag(actual_geometry, geometry);
dynamicval<int> gss(underlying_cgip->single_step, cgi.single_step);
dynamicval<int> gsp(underlying_cgip->psl_steps, cgi.psl_steps);
dynamicval<geometry_information*> gc(cgip, underlying_cgip); dynamicval<geometry_information*> gc(cgip, underlying_cgip);
dynamicval<hrmap*> gpm(pmap, currentmap); dynamicval<hrmap*> gpm(pmap, currentmap);
dynamicval<hrmap*> gm(currentmap, get_umap()); dynamicval<hrmap*> gm(currentmap, get_umap());
@ -1345,13 +1349,17 @@ EX namespace hybrid {
} }
EX int wall_offset(cell *c) { EX int wall_offset(cell *c) {
if(GOLDBERG) { if(GOLDBERG || INVERSE) {
/* a bit slow... */ /* a bit slow... */
cell *c1 = WDIM == 2 ? c : get_where(c).first; cell *c1 = WDIM == 2 ? c : get_where(c).first;
gp::draw_li = WDIM == 2 ? gp::get_local_info(c1) : PIU(gp::get_local_info(c1)); gp::draw_li = WDIM == 2 ? gp::get_local_info(c1) : PIU(gp::get_local_info(c1));
} }
auto ugeometry = hybri ? hybrid::underlying : geometry; auto ugeometry = hybri ? hybrid::underlying : geometry;
#if CAP_ARCM
int id = ugeometry == gArchimedean ? arcm::id_of(c->master) + 20 * arcm::parent_index_of(c->master) : shvid(c); int id = ugeometry == gArchimedean ? arcm::id_of(c->master) + 20 * arcm::parent_index_of(c->master) : shvid(c);
#else
int id = shvid(c);
#endif
if(isize(cgi.walloffsets) <= id) cgi.walloffsets.resize(id+1, {-1, nullptr}); if(isize(cgi.walloffsets) <= id) cgi.walloffsets.resize(id+1, {-1, nullptr});
auto &wop = cgi.walloffsets[id]; auto &wop = cgi.walloffsets[id];
int &wo = wop.first; int &wo = wop.first;
@ -2057,14 +2065,19 @@ EX namespace rots {
return spin(beta) * uxpush(distance/2) * spin(-beta+alpha); return spin(beta) * uxpush(distance/2) * spin(-beta+alpha);
} }
std::unordered_map<int, transmatrix> saved_matrices_ray; std::map<int, transmatrix> saved_matrices_ray;
EX transmatrix ray_iadj(cell *c1, int i) { EX transmatrix ray_iadj(cell *c1, int i) {
if(i == c1->type-1) return uzpush(-cgi.plevel) * spin(-2*cgi.plevel); if(i == c1->type-1) return uzpush(-cgi.plevel) * spin(-2*cgi.plevel);
if(i == c1->type-2) return uzpush(+cgi.plevel) * spin(+2*cgi.plevel); if(i == c1->type-2) return uzpush(+cgi.plevel) * spin(+2*cgi.plevel);
cell *c2 = c1->cmove(i); cell *c2 = c1->cmove(i);
#if CAP_ARCM
int id1 = hybrid::underlying == gArchimedean ? arcm::id_of(c1->master) + 20 * arcm::parent_index_of(c1->master) : shvid(c1); int id1 = hybrid::underlying == gArchimedean ? arcm::id_of(c1->master) + 20 * arcm::parent_index_of(c1->master) : shvid(c1);
int id2 = hybrid::underlying == gArchimedean ? arcm::id_of(c2->master) + 20 * arcm::parent_index_of(c2->master) : shvid(c2); int id2 = hybrid::underlying == gArchimedean ? arcm::id_of(c2->master) + 20 * arcm::parent_index_of(c2->master) : shvid(c2);
#else
int id1 = shvid(c1);
int id2 = shvid(c2);
#endif
int j = c1->c.spin(i); int j = c1->c.spin(i);
int id = id1 + (id2 << 10) + (i << 20) + (j << 26); int id = id1 + (id2 << 10) + (i << 20) + (j << 26);
auto &M = saved_matrices_ray[id]; auto &M = saved_matrices_ray[id];
@ -2084,14 +2097,19 @@ EX namespace rots {
struct hrmap_rotation_space : hybrid::hrmap_hybrid { struct hrmap_rotation_space : hybrid::hrmap_hybrid {
std::unordered_map<int, transmatrix> saved_matrices; std::map<int, transmatrix> saved_matrices;
transmatrix adj(cell *c1, int i) override { transmatrix adj(cell *c1, int i) override {
if(i == c1->type-2) return uzpush(-cgi.plevel) * spin(-2*cgi.plevel); if(i == c1->type-2) return uzpush(-cgi.plevel) * spin(-2*cgi.plevel);
if(i == c1->type-1) return uzpush(+cgi.plevel) * spin(+2*cgi.plevel); if(i == c1->type-1) return uzpush(+cgi.plevel) * spin(+2*cgi.plevel);
cell *c2 = c1->cmove(i); cell *c2 = c1->cmove(i);
#if CAP_ARCM
int id1 = hybrid::underlying == gArchimedean ? arcm::id_of(c1->master) + 20 * arcm::parent_index_of(c1->master) : shvid(c1); int id1 = hybrid::underlying == gArchimedean ? arcm::id_of(c1->master) + 20 * arcm::parent_index_of(c1->master) : shvid(c1);
int id2 = hybrid::underlying == gArchimedean ? arcm::id_of(c2->master) + 20 * arcm::parent_index_of(c2->master) : shvid(c2); int id2 = hybrid::underlying == gArchimedean ? arcm::id_of(c2->master) + 20 * arcm::parent_index_of(c2->master) : shvid(c2);
#else
int id1 = shvid(c1);
int id2 = shvid(c2);
#endif
int j = c1->c.spin(i); int j = c1->c.spin(i);
int id = id1 + (id2 << 10) + (i << 20) + (j << 26); int id = id1 + (id2 << 10) + (i << 20) + (j << 26);
auto &M = saved_matrices[id]; auto &M = saved_matrices[id];

View File

@ -309,7 +309,7 @@ EX eOrbLandRelation getOLR(eItem it, eLand l) {
return olrUseless; return olrUseless;
if(l == laPrincessQuest) if(l == laPrincessQuest)
if(among(it, itOrbAether, itOrbFlash, itOrbTeleport, itOrbSummon, itOrbFreedom, itOrbFriend, itOrbPhasing)) if(among(it, itOrbAether, itOrbFlash, itOrbTeleport, itOrbSummon, itOrbFreedom, itOrbFriend, itOrbPhasing, itOrbChaos))
return olrForbidden; return olrForbidden;
if(l == laTemple) if(l == laTemple)

View File

@ -88,7 +88,9 @@ EX bool reduceOrbPower(eItem it, int cap) {
return true; return true;
} }
if(items[it] > cap && timerghost) items[it] = cap; if(items[it] > cap && timerghost) items[it] = cap;
#if CAP_COMPLEX2
mine::auto_teleport_charges(); mine::auto_teleport_charges();
#endif
return false; return false;
} }
@ -566,7 +568,7 @@ EX void teleportTo(cell *dest) {
killFriendlyIvy(); killFriendlyIvy();
drainOrb(itOrbTeleport); drainOrb(itOrbTeleport);
movecost(cwt.at, dest, 3); movecost(cwt.at, dest, 3);
playerMoveEffects(cwt.at, dest); playerMoveEffects(movei(cwt.at, dest, TELEPORT));
afterplayermoved(); afterplayermoved();
bfs(); bfs();
} }
@ -578,7 +580,7 @@ EX void teleportTo(cell *dest) {
killFriendlyIvy(); killFriendlyIvy();
cell *from = cwt.at; cell *from = cwt.at;
movecost(from, dest, 1); movecost(from, dest, 1);
playerMoveEffects(cwt.at, dest); playerMoveEffects(movei(cwt.at, dest, TELEPORT));
current_display->which_copy = unshift(ggmatrix(dest)); current_display->which_copy = unshift(ggmatrix(dest));
cwt.at = dest; cwt.spin = hrand(dest->type); flipplayer = !!(hrand(2)); cwt.at = dest; cwt.spin = hrand(dest->type); flipplayer = !!(hrand(2));
drainOrb(itOrbTeleport); drainOrb(itOrbTeleport);
@ -596,7 +598,9 @@ EX void teleportTo(cell *dest) {
checkmoveO(); checkmoveO();
movecost(from, dest, 2); movecost(from, dest, 2);
#if CAP_COMPLEX2
mine::auto_teleport_charges(); mine::auto_teleport_charges();
#endif
} }
EX bool jumpTo(orbAction a, cell *dest, eItem byWhat, int bonuskill IS(0), eMonster dashmon IS(moNone)) { EX bool jumpTo(orbAction a, cell *dest, eItem byWhat, int bonuskill IS(0), eMonster dashmon IS(moNone)) {
@ -634,8 +638,9 @@ EX bool jumpTo(orbAction a, cell *dest, eItem byWhat, int bonuskill IS(0), eMons
} }
sword::reset(); sword::reset();
stabbingAttack(c1, dest, moPlayer, bonuskill); auto mi = movei(c1, dest, JUMP);
playerMoveEffects(c1, dest); stabbingAttack(mi, moPlayer, bonuskill);
playerMoveEffects(mi);
if(itemclass(byWhat) == IC_ORB) if(itemclass(byWhat) == IC_ORB)
apply_impact(dest); apply_impact(dest);
@ -654,7 +659,7 @@ EX bool jumpTo(orbAction a, cell *dest, eItem byWhat, int bonuskill IS(0), eMons
mirror::destroyAll(); mirror::destroyAll();
if(monstersnearO(a, dest, moPlayer, NULL, c1)) { if(monstersnearO(a, dest)) {
changes.rollback(); changes.rollback();
return false; return false;
} }
@ -935,7 +940,7 @@ bool gun_attack(orbAction a, cell *dest) {
attackMonster(dest, AF_GUN, moNone); attackMonster(dest, AF_GUN, moNone);
apply_impact(dest); apply_impact(dest);
if(monstersnearO(a, cwt.at, moPlayer, NULL, cwt.at)) { if(monstersnearO(a, cwt.at)) {
changes.rollback(); changes.rollback();
return false; return false;
} }
@ -1064,13 +1069,13 @@ void useOrbOfDragon(cell *c) {
checkmoveO(); checkmoveO();
} }
EX bool monstersnearO(orbAction a, cell *c, eMonster who, cell *pushto, cell *comefrom) { EX bool monstersnearO(orbAction a, cell *c) {
// printf("[a = %d] ", a); // printf("[a = %d] ", a);
if(shmup::on) return false; if(shmup::on) return false;
if(a == roCheck && multi::players > 1) if(a == roCheck && multi::players > 1)
return true; return true;
else if(a == roMultiCheck) return false; else if(a == roMultiCheck) return false;
else return monstersnear(c, who, pushto, comefrom); else return monstersnear(c, moPlayer);
} }
EX bool isCheck(orbAction a) { return a == roCheck || a == roMultiCheck; } EX bool isCheck(orbAction a) { return a == roCheck || a == roMultiCheck; }
@ -1237,12 +1242,12 @@ EX eItem targetRangedOrb(cell *c, orbAction a) {
if(c->monst) { if(c->monst) {
if(!canAttack(cf, moFriendlyIvy, c, c->monst, 0)) continue; if(!canAttack(cf, moFriendlyIvy, c, c->monst, 0)) continue;
if(monstersnear(cwt.at, moPlayer, NULL, cwt.at)) continue; if(monstersnear(cwt.at, moPlayer)) continue;
} }
else { else {
if(!passable(c, cf, P_ISPLAYER | P_MONSTER)) continue; if(!passable(c, cf, P_ISPLAYER | P_MONSTER)) continue;
if(strictlyAgainstGravity(c, cf, false, MF_IVY)) continue; if(strictlyAgainstGravity(c, cf, false, MF_IVY)) continue;
if(monstersnear(cwt.at, moPlayer, c, cwt.at)) continue; if(monstersnear(cwt.at, moPlayer)) continue;
} }
dirs.push_back(d); dirs.push_back(d);
} }

View File

@ -422,7 +422,7 @@ EX int fieldval_uniq(cell *c) {
} }
else if(euc::in(2)) { else if(euc::in(2)) {
auto p = euc2_coordinates(c); auto p = euc2_coordinates(c);
if(bounded) return p.first + (p.second << 16); if(bounded) return p.first + p.second * (1 << 16);
return gmod(p.first - 22 * p.second, 3*127); return gmod(p.first - 22 * p.second, 3*127);
} }
else if(euc::in(3)) { else if(euc::in(3)) {
@ -1682,11 +1682,13 @@ EX namespace patterns {
ep.extra_params["ey"] = y; ep.extra_params["ey"] = y;
if(S7 == 6) ep.extra_params["ez"] = -x-y; if(S7 == 6) ep.extra_params["ez"] = -x-y;
} }
#if CAP_CRYSTAL
if(cryst) { if(cryst) {
crystal::ldcoord co = crystal::get_ldcoord(c); crystal::ldcoord co = crystal::get_ldcoord(c);
for(int i=0; i<crystal::MAXDIM; i++) for(int i=0; i<crystal::MAXDIM; i++)
ep.extra_params["x"+its(i)] = co[i]; ep.extra_params["x"+its(i)] = co[i];
} }
#endif
if(asonov::in()) { if(asonov::in()) {
auto co = asonov::get_coord(c->master); auto co = asonov::get_coord(c->master);
ep.extra_params["ax"] = szgmod(co[0], asonov::period_xy); ep.extra_params["ax"] = szgmod(co[0], asonov::period_xy);

View File

@ -358,7 +358,7 @@ bool pcmove::swing() {
mirror::act(origd, mirror::SPINMULTI | mirror::ATTACK); mirror::act(origd, mirror::SPINMULTI | mirror::ATTACK);
if(monstersnear(cwt.at, moPlayer, nullptr, cwt.at)) { if(monstersnear_add_pmi(movei(cwt.at, STAY))) {
if(vmsg()) if(vmsg())
wouldkill("You would be killed by %the1!"); wouldkill("You would be killed by %the1!");
return false; return false;
@ -510,6 +510,13 @@ struct changes_t {
void at_rollback(reaction_t act) { void at_rollback(reaction_t act) {
if(on) rollbacks.emplace_back(act); if(on) rollbacks.emplace_back(act);
} }
void push_push(cell *tgt) {
pushes.push_back(tgt);
auto v = [] { pushes.pop_back(); };
rollbacks.push_back(v);
commits.push_back(v);
}
}; };
#endif #endif
@ -601,7 +608,7 @@ bool pcmove::actual_move() {
return false; return false;
} }
if(items[itOrbDomination] > ORBBASE && isMountable(c2->monst) && !monstersnear2() && fmsMove) { if(items[itOrbDomination] > ORBBASE && isMountable(c2->monst) && fmsMove) {
if(checkonly) { nextmovetype = lmMove; return true; } if(checkonly) { nextmovetype = lmMove; return true; }
if(!isMountable(cwt.at->monst)) dragon::target = NULL; if(!isMountable(cwt.at->monst)) dragon::target = NULL;
movecost(cwt.at, c2, 3); movecost(cwt.at, c2, 3);
@ -629,6 +636,7 @@ bool pcmove::actual_move() {
addMessage(XLAT("You push %the1.", c2->wall)); addMessage(XLAT("You push %the1.", c2->wall));
lastmovetype = lmPush; lastmove = cwt.at; lastmovetype = lmPush; lastmove = cwt.at;
pushThumper(mip); pushThumper(mip);
changes.push_push(mip.t);
return perform_actual_move(); return perform_actual_move();
} }
@ -646,8 +654,6 @@ bool pcmove::actual_move() {
if(!c2->monst && cwt.at->wall == waBoat && cwt.at->item != itOrbYendor && boatGoesThrough(c2) && markOrb(itOrbWater) && !nonAdjacentPlayer(c2, cwt.at) && fmsMove) { if(!c2->monst && cwt.at->wall == waBoat && cwt.at->item != itOrbYendor && boatGoesThrough(c2) && markOrb(itOrbWater) && !nonAdjacentPlayer(c2, cwt.at) && fmsMove) {
if(havePushConflict(cwt.at, checkonly)) return false;
if(c2->item && !cwt.at->item) moveItem(c2, cwt.at, false), boatmove = true; if(c2->item && !cwt.at->item) moveItem(c2, cwt.at, false), boatmove = true;
placeWater(c2, cwt.at); placeWater(c2, cwt.at);
moveBoat(mi); moveBoat(mi);
@ -663,7 +669,6 @@ bool pcmove::actual_move() {
bool pcmove::boat_move() { bool pcmove::boat_move() {
cell *& c2 = mi.t; cell *& c2 = mi.t;
if(havePushConflict(cwt.at, checkonly)) return false;
if(againstWind(c2, cwt.at)) { if(againstWind(c2, cwt.at)) {
if(vmsg()) addMessage(XLAT(airdist(c2) < 3 ? "The Air Elemental blows you away!" : "You cannot go against the wind!")); if(vmsg()) addMessage(XLAT(airdist(c2) < 3 ? "The Air Elemental blows you away!" : "You cannot go against the wind!"));
@ -744,8 +749,6 @@ bool pcmove::after_escape() {
return false; return false;
} }
if(havePushConflict(cwt.at, checkonly)) return false;
changes.ccell(c2); changes.ccell(c2);
changes.ccell(cwt.at); changes.ccell(cwt.at);
@ -756,6 +759,7 @@ bool pcmove::after_escape() {
nextmovetype = lmMove; nextmovetype = lmMove;
addMessage(XLAT("You push %the1 behind you!", waBigStatue)); addMessage(XLAT("You push %the1 behind you!", waBigStatue));
animateMovement(mi.rev(), LAYER_BOAT); animateMovement(mi.rev(), LAYER_BOAT);
changes.push_push(cwt.at);
return perform_actual_move(); return perform_actual_move();
} }
@ -849,7 +853,7 @@ bool pcmove::move_if_okay() {
if(switchplace_prevent(cwt.at, c2, checkonly)) if(switchplace_prevent(cwt.at, c2, checkonly))
return false; return false;
if(!checkonly && warningprotection_hit(do_we_stab_a_friend(cwt.at, c2, moPlayer))) if(!checkonly && warningprotection_hit(do_we_stab_a_friend(mi, moPlayer)))
return false; return false;
nextmovetype = lmMove; nextmovetype = lmMove;
@ -899,7 +903,7 @@ bool pcmove::attack() {
if(!ca) { if(!ca) {
if(forcedmovetype == fmAttack) { if(forcedmovetype == fmAttack) {
if(monstersnear(cwt.at,moPlayer,NULL,cwt.at)) { if(monstersnear_add_pmi(movei(cwt.at, STAY))) {
if(vmsg()) wouldkill("%The1 would get you!"); if(vmsg()) wouldkill("%The1 would get you!");
return false; return false;
} }
@ -922,10 +926,9 @@ bool pcmove::attack() {
else else
mip.t = c2; mip.t = c2;
if(mip.t) changes.ccell(mip.t); if(mip.t) changes.ccell(mip.t);
changes.push_push(mip.t);
} }
if(havePushConflict(mip.t, checkonly)) return false;
if(!(isWatery(cwt.at) && c2->monst == moWaterElemental) && checkNeedMove(checkonly, true)) if(!(isWatery(cwt.at) && c2->monst == moWaterElemental) && checkNeedMove(checkonly, true))
return false; return false;
@ -982,7 +985,7 @@ bool pcmove::attack() {
lastmovetype = lmAttack; lastmove = c2; lastmovetype = lmAttack; lastmove = c2;
swordAttackStatic(); swordAttackStatic();
if(monstersnear(cwt.at, moPlayer, nullptr, cwt.at)) { if(monstersnear_add_pmi(movei(cwt.at, STAY))) {
if(vmsg()) wouldkill("You would be killed by %the1!"); if(vmsg()) wouldkill("You would be killed by %the1!");
return false; return false;
} }
@ -1090,18 +1093,18 @@ bool pcmove::perform_move_or_jump() {
lastmovetype = lmMove; lastmove = cwt.at; lastmovetype = lmMove; lastmove = cwt.at;
apply_chaos(); apply_chaos();
stabbingAttack(cwt.at, mi.t, moPlayer); stabbingAttack(mi, moPlayer);
cell *c1 = cwt.at;
changes.value_keep(cwt); changes.value_keep(cwt);
cwt += wstep; cwt += wstep;
mirror::act(origd, mirror::SPINMULTI | mirror::ATTACK | mirror::GO); mirror::act(origd, mirror::SPINMULTI | mirror::ATTACK | mirror::GO);
playerMoveEffects(c1, mi.t); auto pmi = player_move_info(mi);
playerMoveEffects(mi);
if(mi.t->monst == moFriendlyIvy) changes.ccell(mi.t), mi.t->monst = moNone; if(mi.t->monst == moFriendlyIvy) changes.ccell(mi.t), mi.t->monst = moNone;
if(monstersnear(cwt.at, moPlayer, nullptr, c1)) { if(monstersnear_add_pmi(pmi)) {
if(vmsg()) wouldkill("%The1 would kill you there!"); if(vmsg()) wouldkill("%The1 would kill you there!");
return false; return false;
} }
@ -1135,20 +1138,22 @@ bool pcmove::stay() {
return false; return false;
swordAttackStatic(); swordAttackStatic();
nextmovetype = lmSkip; nextmovetype = lmSkip;
if(monstersnear(cwt.at, moPlayer, nullptr, cwt.at)) {
mi = movei(cwt.at, STAY);
if(last_gravity_state && !gravity_state)
playerMoveEffects(mi);
if(d == -2)
dropGreenStone(cwt.at);
if(monstersnear_add_pmi(mi)) {
if(vmsg()) wouldkill("%The1 would get you!"); if(vmsg()) wouldkill("%The1 would get you!");
return false; return false;
} }
if(checkonly) return true; if(checkonly) return true;
if(changes.on) changes.commit(); if(changes.on) changes.commit();
if(d == -2)
dropGreenStone(cwt.at);
if(cellUnstable(cwt.at) && !markOrb(itOrbAether)) if(cellUnstable(cwt.at) && !markOrb(itOrbAether))
doesFallSound(cwt.at); doesFallSound(cwt.at);
if(last_gravity_state && !gravity_state)
playerMoveEffects(cwt.at, cwt.at);
return after_move(); return after_move();
} }
@ -1246,12 +1251,14 @@ EX bool playerInPower() {
return false; return false;
} }
EX void playerMoveEffects(cell *c1, cell *c2) { EX void playerMoveEffects(movei mi) {
cell *c1 = mi.s;
cell *c2 = mi.t;
if(peace::on) items[itOrbSword] = c2->land == laBurial ? 100 : 0; if(peace::on) items[itOrbSword] = c2->land == laBurial ? 100 : 0;
changes.value_keep(sword::dir[multi::cpid]); changes.value_keep(sword::dir[multi::cpid]);
sword::dir[multi::cpid] = sword::shift(c1, c2, sword::dir[multi::cpid]); sword::dir[multi::cpid] = sword::shift(mi, sword::dir[multi::cpid]);
destroyWeakBranch(c1, c2, moPlayer); destroyWeakBranch(c1, c2, moPlayer);
@ -1457,20 +1464,20 @@ EX void sideAttack(cell *mf, int dir, eMonster who, int bonuskill) {
} }
} }
EX eMonster do_we_stab_a_friend(cell *mf, cell *mt, eMonster who) { EX eMonster do_we_stab_a_friend(movei mi, eMonster who) {
eMonster m = moNone; eMonster m = moNone;
do_swords(mf, mt, who, [&] (cell *c, int bb) { do_swords(mi, who, [&] (cell *c, int bb) {
if(!peace::on && canAttack(mt, who, c, c->monst, AF_SWORD) && c->monst && isFriendly(c)) m = c->monst; if(!peace::on && canAttack(mi.t, who, c, c->monst, AF_SWORD) && c->monst && isFriendly(c)) m = c->monst;
}); });
for(int t=0; t<mf->type; t++) { for(int t=0; t<mi.s->type; t++) {
cell *c = mf->move(t); cell *c = mi.s->move(t);
if(!c) continue; if(!c) continue;
bool stabthere = false; bool stabthere = false;
if(logical_adjacent(mt, who, c)) stabthere = true; if(logical_adjacent(mi.t, who, c)) stabthere = true;
if(stabthere && canAttack(mt,who,c,c->monst,AF_STAB) && isFriendly(c)) if(stabthere && canAttack(mi.t,who,c,c->monst,AF_STAB) && isFriendly(c))
return c->monst; return c->monst;
} }
@ -1484,27 +1491,14 @@ EX void wouldkill(const char *msg) {
addMessage(XLAT("Cannot move into the current location of another player!")); addMessage(XLAT("Cannot move into the current location of another player!"));
else if(who_kills_me == moAirball) else if(who_kills_me == moAirball)
addMessage(XLAT("Players cannot get that far away!")); addMessage(XLAT("Players cannot get that far away!"));
else if(who_kills_me == moTongue)
addMessage(XLAT("Cannot push into another player!"));
else if(who_kills_me == moCrushball)
addMessage(XLAT("Cannot push into the same location!"));
else else
addMessage(XLAT(msg, who_kills_me)); addMessage(XLAT(msg, who_kills_me));
} }
EX bool havePushConflict(cell *pushto, bool checkonly) {
if(pushto && multi::activePlayers() > 1) {
for(int i=0; i<multi::players; i++) if(i != multi::cpid && multi::playerActive(i))
if(multi::origpos[i] == pushto || multi::origtarget[i] == pushto) {
addMessage(XLAT("Cannot push into another player!"));
return true;
}
for(int i=0; i<isize(stalemate::moves); i++) {
if(pushto == stalemate::moves[i].pushto) {
addMessage(XLAT("Cannot push into the same location!"));
return true;
}
}
}
return false;
}
EX void movecost(cell* from, cell *to, int phase) { EX void movecost(cell* from, cell *to, int phase) {
if(from->land == laPower && to->land != laPower && (phase & 1)) { if(from->land == laPower && to->land != laPower && (phase & 1)) {
int n=0; int n=0;

View File

@ -718,24 +718,26 @@ void geometry_information::procedural_shapes() {
vector<ld> equal_weights(1000, 1); vector<ld> equal_weights(1000, 1);
#if !(CAP_BT && MAXMDIM >= 4) #if MAXMDIM < 4
void geometry_information::make_wall(int id, vector<hyperpoint> vertices, vector<ld> weights) { } void geometry_information::make_wall(int id, vector<hyperpoint> vertices, vector<ld> weights) { }
void geometry_information::reserve_wall3d(int i) { } void geometry_information::reserve_wall3d(int i) { }
void geometry_information::create_wall3d() { } void geometry_information::create_wall3d() { }
void geometry_information::compute_cornerbonus() { } void geometry_information::compute_cornerbonus() { }
#endif #endif
#if CAP_BT && MAXMDIM >= 4 #if MAXMDIM >= 4
// Make a wall // Make a wall
hyperpoint ray_kleinize(hyperpoint h, int id, ld pz) { hyperpoint ray_kleinize(hyperpoint h, int id, ld pz) {
if(geometry == gNil && among(id, 2, 5)) h[2] = 0; if(geometry == gNil && among(id, 2, 5)) h[2] = 0;
#if CAP_BT
if(hyperbolic && bt::in()) { if(hyperbolic && bt::in()) {
// ld co = vid.binary_width / log(2) / 4; // ld co = vid.binary_width / log(2) / 4;
// hyperpoint res = point31(h[2]*log(2)/2, h[0]*co, h[1]*co); // hyperpoint res = point31(h[2]*log(2)/2, h[0]*co, h[1]*co);
return deparabolic10(bt::parabolic3(h[0], h[1]) * xpush0(log(2)/2*h[2])); return deparabolic10(bt::parabolic3(h[0], h[1]) * xpush0(log(2)/2*h[2]));
} }
#endif
if(prod) { if(prod) {
return point3(h[0]/h[2], h[1]/h[2], pz); return point3(h[0]/h[2], h[1]/h[2], pz);
} }
@ -756,7 +758,9 @@ void geometry_information::make_wall(int id, vector<hyperpoint> vertices, vector
reverse(vertices.begin(), vertices.end()), reverse(vertices.begin(), vertices.end()),
reverse(weights.begin(), weights.end()); reverse(weights.begin(), weights.end());
#if CAP_BT
ld yy = log(2) / 2; ld yy = log(2) / 2;
#endif
bshape(shWall3D[id], PPR::WALL); bshape(shWall3D[id], PPR::WALL);
last->flags |= POLY_TRIANGLES | POLY_PRINTABLE; last->flags |= POLY_TRIANGLES | POLY_PRINTABLE;
@ -815,8 +819,13 @@ void geometry_information::make_wall(int id, vector<hyperpoint> vertices, vector
hpcpush(h); return; hpcpush(h); return;
} }
if(sn::in() || !bt::in()) { hpcpush(ultra_normalize(h)); return; } if(sn::in() || !bt::in()) { hpcpush(ultra_normalize(h)); return; }
#if CAP_BT
if(bt::in()) {
hyperpoint res = bt::parabolic3(h[0], h[1]) * xpush0(yy*h[2]); hyperpoint res = bt::parabolic3(h[0], h[1]) * xpush0(yy*h[2]);
hpcpush(res); hpcpush(res);
}
#endif
hpcpush(h);
}); });
} }
@ -833,9 +842,14 @@ void geometry_information::make_wall(int id, vector<hyperpoint> vertices, vector
if(nil) if(nil)
h = nilv::on_geodesic(vertices[a], vertices[(a+1)%n], y * 1. / STEP); h = nilv::on_geodesic(vertices[a], vertices[(a+1)%n], y * 1. / STEP);
if(sn::in() || !bt::in()) { hpcpush(ultra_normalize(h)); continue; } if(sn::in() || !bt::in()) { hpcpush(ultra_normalize(h)); continue; }
#if CAP_BT
if(bt::in()) {
hyperpoint res = bt::parabolic3(h[0], h[1]) * xpush0(yy*h[2]); hyperpoint res = bt::parabolic3(h[0], h[1]) * xpush0(yy*h[2]);
hpcpush(res); hpcpush(res);
} }
#endif
hpcpush(h);
}
hpcpush(hpc[last->s]); hpcpush(hpc[last->s]);
} }
@ -875,6 +889,8 @@ void geometry_information::reserve_wall3d(int i) {
void geometry_information::create_wall3d() { void geometry_information::create_wall3d() {
if(WDIM == 2) return; if(WDIM == 2) return;
reserve_wall3d(kite::in() ? 22 : hybri ? 0 : S7); reserve_wall3d(kite::in() ? 22 : hybri ? 0 : S7);
#if CAP_BT
if(GDIM == 3 && bt::in() && geometry == gBinary3) { if(GDIM == 3 && bt::in() && geometry == gBinary3) {
hyperpoint h00 = point3(-1,-1,-1); hyperpoint h00 = point3(-1,-1,-1);
hyperpoint h01 = point3(-1,0,-1); hyperpoint h01 = point3(-1,0,-1);
@ -970,6 +986,7 @@ void geometry_information::create_wall3d() {
make_wall(12, {point3(3*h,r3,z), point3(0,2*r3,z), point3(-3*h,r3,z)}); make_wall(12, {point3(3*h,r3,z), point3(0,2*r3,z), point3(-3*h,r3,z)});
make_wall(13, {point3(3*h,r3,z), point3(3*h,-r3,z), point3(0,-2*r3,z), point3(-3*h,-r3,z), point3(-3*h,r3,z)}); make_wall(13, {point3(3*h,r3,z), point3(3*h,-r3,z), point3(0,-2*r3,z), point3(-3*h,-r3,z), point3(-3*h,r3,z)});
} }
#endif
if(prod) { if(prod) {
walloffsets.clear(); walloffsets.clear();
@ -1060,6 +1077,7 @@ void geometry_information::create_wall3d() {
} }
} }
#if CAP_BT
if(kite::in()) { if(kite::in()) {
auto kv = kite::make_walls(); auto kv = kite::make_walls();
for(auto& v: kv.first) for(auto& h: v) { for(auto& v: kv.first) for(auto& h: v) {
@ -1068,6 +1086,7 @@ void geometry_information::create_wall3d() {
} }
for(int i=0; i<isize(kv.first); i++) make_wall(i, kv.first[i], kv.second[i]); for(int i=0; i<isize(kv.first); i++) make_wall(i, kv.first[i], kv.second[i]);
} }
#endif
wallstart.push_back(isize(raywall)); wallstart.push_back(isize(raywall));
compute_cornerbonus(); compute_cornerbonus();

View File

@ -321,7 +321,11 @@ EX void showMission() {
); );
keyhandler = handleKeyQuit; keyhandler = handleKeyQuit;
#if CAP_COMPLEX2
bool sweeper = mine::in_minesweeper(); bool sweeper = mine::in_minesweeper();
#else
const bool sweeper = false;
#endif
if(!peace::on && !racing::on && !sweeper) if(!peace::on && !racing::on && !sweeper)
dialog::addInfo(XLAT("Your score: %1", its(gold()))); dialog::addInfo(XLAT("Your score: %1", its(gold())));
@ -335,6 +339,7 @@ EX void showMission() {
dialog::addInfo(XLAT("Orbs of Yendor found: %1", its(items[itOrbYendor])), iinf[itOrbYendor].color); dialog::addInfo(XLAT("Orbs of Yendor found: %1", its(items[itOrbYendor])), iinf[itOrbYendor].color);
dialog::addInfo(XLAT("CONGRATULATIONS!"), iinf[itOrbYendor].color); dialog::addInfo(XLAT("CONGRATULATIONS!"), iinf[itOrbYendor].color);
} }
#if CAP_COMPLEX2
else if(mine::in_minesweeper()) { else if(mine::in_minesweeper()) {
int to_uncover = kills[moBomberbird]; int to_uncover = kills[moBomberbird];
if(to_uncover) { if(to_uncover) {
@ -346,6 +351,7 @@ EX void showMission() {
dialog::addInfo(XLAT("You won in %1", getgametime_s(mine::victory_time))); dialog::addInfo(XLAT("You won in %1", getgametime_s(mine::victory_time)));
} }
} }
#endif
else { else {
if(0) if(0)
; ;

View File

@ -32,9 +32,9 @@ EX namespace quotientspace {
int rv(int x) { return (rvadd+x*rvdir) % S7; } int rv(int x) { return (rvadd+x*rvdir) % S7; }
#if HDR
constexpr int symmask = (1<<30); constexpr int symmask = (1<<30);
#if HDR
struct code { struct code {
vector<int> connections; vector<int> connections;

View File

@ -755,7 +755,7 @@ EX transmatrix track_matrix(int at, int dir) {
transmatrix res = unshift(ggmatrix(racing::track[at])); transmatrix res = unshift(ggmatrix(racing::track[at]));
while(true) { while(true) {
if(at+dir < 0 || at+dir >= isize(racing::track)) return res; if(at+dir < 0 || at+dir >= isize(racing::track)) return res;
for(int x=0; x<MDIM; x++) for(int y=0; y<MDIM; y++) for(int x=0; x<MXDIM; x++) for(int y=0; y<MXDIM; y++)
if(abs(res[y][x]) > 10000) return res; if(abs(res[y][x]) > 10000) return res;
cell *cur = racing::track[at]; cell *cur = racing::track[at];
at += dir; at += dir;

View File

@ -27,7 +27,11 @@ EX ld exp_start = 1;
EX ld exp_decay_exp = 4; EX ld exp_decay_exp = 4;
EX ld exp_decay_poly = 10; EX ld exp_decay_poly = 10;
#ifdef GLES_ONLY
const int gms_limit = 16; /* enough for Bringris -- need to do better */
#else
const int gms_limit = 110; const int gms_limit = 110;
#endif
EX ld maxstep_sol = .05; EX ld maxstep_sol = .05;
EX ld maxstep_nil = .1; EX ld maxstep_nil = .1;
@ -39,7 +43,8 @@ static const int NO_LIMIT = 999999;
EX ld hard_limit = NO_LIMIT; EX ld hard_limit = NO_LIMIT;
EX int max_iter_sol = 600, max_iter_iso = 60; EX int max_iter_sol = 600;
EX int max_iter_iso = 60;
EX int max_cells = 2048; EX int max_cells = 2048;
EX bool rays_generate = true; EX bool rays_generate = true;
@ -170,6 +175,8 @@ int deg, irays;
#ifdef GLES_ONLY #ifdef GLES_ONLY
void add(string& tgt, string type, string name, int min_index, int max_index) { void add(string& tgt, string type, string name, int min_index, int max_index) {
if(min_index >= max_index) ;
else
if(min_index + 1 == max_index) if(min_index + 1 == max_index)
tgt += "{ return " + name + "[" + its(min_index) + "]; }"; tgt += "{ return " + name + "[" + its(min_index) + "]; }";
else { else {
@ -193,6 +200,11 @@ string build_getter(string type, string name, int index) {
#define GET(array, index) array "[" index "]" #define GET(array, index) array "[" index "]"
#endif #endif
void replace_str(string& s, string a, string b) {
while(s.find(a) != string::npos)
s.replace(s.find(a), isize(a), b);
}
EX hookset<void(string&, string&)> hooks_rayshader; EX hookset<void(string&, string&)> hooks_rayshader;
EX hookset<bool(shared_ptr<raycaster>)> hooks_rayset; EX hookset<bool(shared_ptr<raycaster>)> hooks_rayset;
@ -216,6 +228,7 @@ void enable_raycaster() {
bool use_reflect = reflect_val && !nil && !levellines; bool use_reflect = reflect_val && !nil && !levellines;
bool bi = arcm::in() || kite::in() || arb::in() || !PURE; bool bi = arcm::in() || kite::in() || arb::in() || !PURE;
bi = false;
string vsh = string vsh =
"attribute mediump vec4 aPosition;\n" "attribute mediump vec4 aPosition;\n"
@ -269,11 +282,13 @@ void enable_raycaster() {
int flat1 = 0, flat2 = deg; int flat1 = 0, flat2 = deg;
if(prod || rotspace) flat2 -= 2; if(prod || rotspace) flat2 -= 2;
#if CAP_BT
if(hyperbolic && bt::in()) { if(hyperbolic && bt::in()) {
fsh += "uniform mediump float uBLevel;\n"; fsh += "uniform mediump float uBLevel;\n";
flat1 = bt::dirs_outer(); flat1 = bt::dirs_outer();
flat2 -= bt::dirs_inner(); flat2 -= bt::dirs_inner();
} }
#endif
if(hyperbolic) fsh += if(hyperbolic) fsh +=
@ -355,14 +370,34 @@ void enable_raycaster() {
" mediump mat4 vw = uStart * xzspin(-lambda) * xpush(eye) * yzspin(phi);\n" " mediump mat4 vw = uStart * xzspin(-lambda) * xpush(eye) * yzspin(phi);\n"
" mediump vec4 at0 = vec4(0., 0., 1., 0.);\n"; " mediump vec4 at0 = vec4(0., 0., 1., 0.);\n";
else fmain += else {
fmain +=
" mediump mat4 vw = uStart;\n" " mediump mat4 vw = uStart;\n"
" mediump vec4 at0 = at;\n" " mediump vec4 at0 = at;\n"
" gl_FragColor = vec4(0,0,0,1);\n" " gl_FragColor = vec4(0,0,0,1);\n"
" mediump float left = 1.;\n" " mediump float left = 1.;\n"
" at0.y = -at.y;\n" " at0.y = -at.y;\n"
" at0.w = 0.;\n" " at0.w = 0.;\n";
if(panini_alpha) fmain +=
"mediump float hr = at0.x*at0.x;\n"
"mediump float alpha = " + to_glsl(panini_alpha) + ";\n"
"mediump float A = 1. + hr;\n"
"mediump float B = -2.*hr*alpha;\n"
"mediump float C = 1. - hr*alpha*alpha;\n"
"B /= A; C /= A;\n"
"mediump float hz = B / 2. + sqrt(C + B*B/4.);\n"
"if(abs(hz) > 1e-3) {"
"at0.xyz *= hz+alpha;\n"
"at0.z = hz;\n}"
" else at0.z = 0.;\n"
"\n"
;
fmain +=
" at0.xyz = at0.xyz / length(at0.xyz);\n"; " at0.xyz = at0.xyz / length(at0.xyz);\n";
}
if(hyperbolic) fsh += " mediump float len(mediump vec4 x) { return x[3]; }\n"; if(hyperbolic) fsh += " mediump float len(mediump vec4 x) { return x[3]; }\n";
else if(sphere && rotspace) fsh += " mediump float len(mediump vec4 x) { return 1.+x.x*x.x+x.y*x.y-x.z*x.z-x.w*x.w; }\n"; else if(sphere && rotspace) fsh += " mediump float len(mediump vec4 x) { return 1.+x.x*x.x+x.y*x.y-x.z*x.z-x.w*x.w; }\n";
@ -454,7 +489,7 @@ void enable_raycaster() {
fmain += "for(int i="+its(flat1)+"; i<"+(prod ? "sides-2" : WDIM == 2 ? "sides" : its(flat2))+"; i++) {\n"; fmain += "for(int i="+its(flat1)+"; i<"+(prod ? "sides-2" : WDIM == 2 ? "sides" : its(flat2))+"; i++) {\n";
fmain += "int woi = walloffset+i;\n"; // fmain += "int woi = walloffset+i;\n";
if(in_h2xe()) fmain += if(in_h2xe()) fmain +=
" mediump float v = ((position - uM[woi] * position)[2] / (uM[woi] * tangent - tangent)[2]);\n" " mediump float v = ((position - uM[woi] * position)[2] / (uM[woi] * tangent - tangent)[2]);\n"
@ -496,6 +531,8 @@ void enable_raycaster() {
" mediump vec4 next_position = position + d * tangent;\n" " mediump vec4 next_position = position + d * tangent;\n"
" if(dot(next_position, tangent) < dot(uM[woi]*next_position, uM[woi]*tangent)) continue;\n"; " if(dot(next_position, tangent) < dot(uM[woi]*next_position, uM[woi]*tangent)) continue;\n";
replace_str(fmain, "[woi]", "[walloffset+i]");
fmain += fmain +=
" if(d < dist) { dist = d; which = i; }\n" " if(d < dist) { dist = d; which = i; }\n"
"}\n"; "}\n";
@ -964,6 +1001,11 @@ void enable_raycaster() {
"tangent -= dot(vec4(-position.xyz, position.w), tangent) * position;\n" "tangent -= dot(vec4(-position.xyz, position.w), tangent) * position;\n"
"tangent /= sqrt(dot(tangent.xyz, tangent.xyz) - tangent.w*tangent.w);\n"; "tangent /= sqrt(dot(tangent.xyz, tangent.xyz) - tangent.w*tangent.w);\n";
if(in_h2xe()) fmain +=
"position /= sqrt(position.z*position.z - dot(position.xy, position.xy));\n"
"tangent -= dot(vec3(-position.xy, position.z), tangent.xyz) * position;\n"
"tangent /= sqrt(dot(tangent.xy, tangent.xy) - tangent.z*tangent.z);\n";
if(hyperbolic && bt::in()) { if(hyperbolic && bt::in()) {
fmain += fmain +=
"if(which == 20) {\n" "if(which == 20) {\n"
@ -1054,11 +1096,12 @@ void enable_raycaster() {
" if(col.w == 1.) {\n"; " if(col.w == 1.) {\n";
if(hyperbolic) fmain += if(hyperbolic) fmain +=
" mediump float z = at0.z * sinh(go);\n" " mediump vec4 t = at0 * sinh(go);\n";
" mediump float w = 1.;\n";
else fmain += else fmain +=
" mediump float z = at0.z * go;\n" " mediump vec4 t = at0 * go;\n";
" mediump float w = 1.;\n";
fmain +=
" t.w = 1.;\n";
if(levellines) { if(levellines) {
if(hyperbolic) if(hyperbolic)
@ -1068,9 +1111,12 @@ void enable_raycaster() {
fsh += "uniform mediump float uLevelLines;\n"; fsh += "uniform mediump float uLevelLines;\n";
} }
if(panini_alpha)
fmain += panini_shader();
#ifndef GLES_ONLY #ifndef GLES_ONLY
fmain += fmain +=
" gl_FragDepth = (" + to_glsl(-vnear-vfar)+"+w*" + to_glsl(2*vnear*vfar)+"/z)/" + to_glsl(vnear-vfar)+";\n" " gl_FragDepth = (" + to_glsl(-vnear-vfar)+"+t.w*" + to_glsl(2*vnear*vfar)+"/t.z)/" + to_glsl(vnear-vfar)+";\n"
" gl_FragDepth = (gl_FragDepth + 1.) / 2.;\n"; " gl_FragDepth = (gl_FragDepth + 1.) / 2.;\n";
#endif #endif
@ -1195,12 +1241,20 @@ void bind_array(vector<array<float, 4>>& v, GLint t, GLuint& tx, int id) {
if(tx == 0) glGenTextures(1, &tx); if(tx == 0) glGenTextures(1, &tx);
glActiveTexture(GL_TEXTURE0 + id); glActiveTexture(GL_TEXTURE0 + id);
GLERR("activeTexture");
glBindTexture(GL_TEXTURE_2D, tx); glBindTexture(GL_TEXTURE_2D, tx);
GLERR("bindTexture");
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
GLERR("texParameteri");
#ifdef GLES_ONLY
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, length, isize(v)/length, 0, GL_RGBA, GL_FLOAT, &v[0]);
#else
glTexImage2D(GL_TEXTURE_2D, 0, 0x8814 /* GL_RGBA32F */, length, isize(v)/length, 0, GL_RGBA, GL_FLOAT, &v[0]); glTexImage2D(GL_TEXTURE_2D, 0, 0x8814 /* GL_RGBA32F */, length, isize(v)/length, 0, GL_RGBA, GL_FLOAT, &v[0]);
#endif
GLERR("bind_array"); GLERR("bind_array");
} }
@ -1533,8 +1587,11 @@ EX void cast() {
} }
if(o->uPLevel != -1) if(o->uPLevel != -1)
glUniform1f(o->uPLevel, cgi.plevel / 2); glUniform1f(o->uPLevel, cgi.plevel / 2);
#if CAP_BT
if(o->uBLevel != -1) if(o->uBLevel != -1)
glUniform1f(o->uBLevel, log(bt::expansion()) / 2); glUniform1f(o->uBLevel, log(bt::expansion()) / 2);
#endif
if(o->uLinearSightRange != -1) if(o->uLinearSightRange != -1)
glUniform1f(o->uLinearSightRange, sightranges[geometry]); glUniform1f(o->uLinearSightRange, sightranges[geometry]);
@ -1560,7 +1617,13 @@ EX void cast() {
} }
#if CAP_VERTEXBUFFER
glhr::bindbuffer_vertex(screen);
glVertexAttribPointer(hr::aPosition, 4, GL_FLOAT, GL_FALSE, sizeof(glvertex), 0);
#else
glVertexAttribPointer(hr::aPosition, 4, GL_FLOAT, GL_FALSE, sizeof(glvertex), &screen[0]); glVertexAttribPointer(hr::aPosition, 4, GL_FLOAT, GL_FALSE, sizeof(glvertex), &screen[0]);
#endif
if(ray::comparison_mode) if(ray::comparison_mode)
glhr::set_depthtest(false); glhr::set_depthtest(false);
else { else {
@ -1572,6 +1635,7 @@ EX void cast() {
glActiveTexture(GL_TEXTURE0 + 0); glActiveTexture(GL_TEXTURE0 + 0);
glBindTexture(GL_TEXTURE_2D, floor_textures->renderedTexture); glBindTexture(GL_TEXTURE_2D, floor_textures->renderedTexture);
GLERR("bind");
glDrawArrays(GL_TRIANGLES, 0, 6); glDrawArrays(GL_TRIANGLES, 0, 6);
GLERR("finish"); GLERR("finish");
} }

View File

@ -13,13 +13,6 @@
namespace hr { namespace hr {
#if MAXMDIM >= 4 #if MAXMDIM >= 4
namespace binary {
void build_tmatrix();
void virtualRebaseSimple(heptagon*& base, transmatrix& at);
int celldistance3(heptagon *c1, heptagon *c2);
hyperpoint deparabolic3(hyperpoint h);
}
/** \brief regular three-dimensional tessellations */ /** \brief regular three-dimensional tessellations */
EX namespace reg3 { EX namespace reg3 {
@ -608,8 +601,8 @@ EX namespace reg3 {
hrmap *binary_map; hrmap *binary_map;
hrmap_quotient3 *quotient_map; hrmap_quotient3 *quotient_map;
unordered_map<heptagon*, pair<heptagon*, transmatrix>> reg_gmatrix; map<heptagon*, pair<heptagon*, transmatrix>> reg_gmatrix;
unordered_map<heptagon*, vector<pair<heptagon*, transmatrix> > > altmap; map<heptagon*, vector<pair<heptagon*, transmatrix> > > altmap;
vector<cell*> spherecells; vector<cell*> spherecells;
@ -641,10 +634,13 @@ EX namespace reg3 {
quotient_map = nullptr; quotient_map = nullptr;
#if CAP_FIELD #if CAP_FIELD
#if CAP_CRYSTAL
if(geometry == gSpace344) { if(geometry == gSpace344) {
quotient_map = new hrmap_from_crystal; quotient_map = new hrmap_from_crystal;
} }
else if(geometry == gSpace535) { else
#endif
if(geometry == gSpace535) {
quotient_map = new seifert_weber::hrmap_seifert_cover; quotient_map = new seifert_weber::hrmap_seifert_cover;
} }
else if(hyperbolic) { else if(hyperbolic) {
@ -653,6 +649,7 @@ EX namespace reg3 {
#endif #endif
h.zebraval = quotient_map ? quotient_map->allh[0]->zebraval : 0; h.zebraval = quotient_map ? quotient_map->allh[0]->zebraval : 0;
#if CAP_BT
if(hyperbolic) { if(hyperbolic) {
dynamicval<eGeometry> g(geometry, gBinary3); dynamicval<eGeometry> g(geometry, gBinary3);
bt::build_tmatrix(); bt::build_tmatrix();
@ -667,6 +664,7 @@ EX namespace reg3 {
binary_map = bt::new_alt_map(alt); binary_map = bt::new_alt_map(alt);
T = xpush(.01241) * spin(1.4117) * xpush(0.1241) * cspin(0, 2, 1.1249) * xpush(0.07) * Id; T = xpush(.01241) * spin(1.4117) * xpush(0.1241) * cspin(0, 2, 1.1249) * xpush(0.07) * Id;
} }
#endif
reg_gmatrix[origin] = make_pair(alt, T); reg_gmatrix[origin] = make_pair(alt, T);
altmap[alt].emplace_back(origin, T); altmap[alt].emplace_back(origin, T);
@ -730,12 +728,14 @@ EX namespace reg3 {
println(hlog, "FAIL"); println(hlog, "FAIL");
exit(3); exit(3);
} }
#if CAP_BT
if(steps) { if(steps) {
dynamicval<eGeometry> g(geometry, gBinary3); dynamicval<eGeometry> g(geometry, gBinary3);
dynamicval<hrmap*> cm(currentmap, binary_map); dynamicval<hrmap*> cm(currentmap, binary_map);
for(int i=0; i<alt->type; i++) for(int i=0; i<alt->type; i++)
verify_neighbors(alt->cmove(i), steps-1, currentmap->iadj(alt, i) * hT); verify_neighbors(alt->cmove(i), steps-1, currentmap->iadj(alt, i) * hT);
} }
#endif
} }
heptagon *create_step(heptagon *parent, int d) override { heptagon *create_step(heptagon *parent, int d) override {
@ -748,11 +748,13 @@ EX namespace reg3 {
transmatrix T = p1.second * cgi.adjmoves[d]; transmatrix T = p1.second * cgi.adjmoves[d];
#endif #endif
transmatrix T1 = T; transmatrix T1 = T;
#if CAP_BT
if(hyperbolic) { if(hyperbolic) {
dynamicval<eGeometry> g(geometry, gBinary3); dynamicval<eGeometry> g(geometry, gBinary3);
dynamicval<hrmap*> cm(currentmap, binary_map); dynamicval<hrmap*> cm(currentmap, binary_map);
binary_map->virtualRebase(alt, T); binary_map->virtualRebase(alt, T);
} }
#endif
fixmatrix(T); fixmatrix(T);
auto hT = tC0(T); auto hT = tC0(T);
@ -852,10 +854,12 @@ EX namespace reg3 {
} }
~hrmap_reg3() { ~hrmap_reg3() {
#if CAP_BT
if(binary_map) { if(binary_map) {
dynamicval<eGeometry> g(geometry, gBinary3); dynamicval<eGeometry> g(geometry, gBinary3);
delete binary_map; delete binary_map;
} }
#endif
if(quotient_map) delete quotient_map; if(quotient_map) delete quotient_map;
clearfrom(origin); clearfrom(origin);
} }
@ -901,11 +905,13 @@ EX namespace reg3 {
auto p1 = reg_gmatrix[h1]; auto p1 = reg_gmatrix[h1];
auto p2 = reg_gmatrix[h2]; auto p2 = reg_gmatrix[h2];
transmatrix T = Id; transmatrix T = Id;
#if CAP_BT
if(hyperbolic) { if(hyperbolic) {
dynamicval<eGeometry> g(geometry, gBinary3); dynamicval<eGeometry> g(geometry, gBinary3);
dynamicval<hrmap*> cm(currentmap, binary_map); dynamicval<hrmap*> cm(currentmap, binary_map);
T = binary_map->relative_matrix(p2.first, p1.first, hint); T = binary_map->relative_matrix(p2.first, p1.first, hint);
} }
#endif
T = inverse(p1.second) * T * p2.second; T = inverse(p1.second) * T * p2.second;
if(elliptic && T[LDIM][LDIM] < 0) T = centralsym * T; if(elliptic && T[LDIM][LDIM] < 0) T = centralsym * T;
return T; return T;
@ -1343,7 +1349,11 @@ EX int celldistance(cell *c1, cell *c2) {
return clueless_celldistance(c1, c2); return clueless_celldistance(c1, c2);
dynamicval<eGeometry> g(geometry, gBinary3); dynamicval<eGeometry> g(geometry, gBinary3);
#if CAP_BT
return 20 + bt::celldistance3(r->reg_gmatrix[c1->master].first, r->reg_gmatrix[c2->master].first); return 20 + bt::celldistance3(r->reg_gmatrix[c1->master].first, r->reg_gmatrix[c2->master].first);
#else
return 20;
#endif
} }
EX bool pseudohept(cell *c) { EX bool pseudohept(cell *c) {
@ -1429,7 +1439,7 @@ ld adistance(cell *c) {
return regmap()->reg_gmatrix[c->master].first->distance * log(2) - h[0]; return regmap()->reg_gmatrix[c->master].first->distance * log(2) - h[0];
} }
unordered_map<pair<cell*, cell*>, int> memo; map<pair<cell*, cell*>, int> memo;
bool cdd; bool cdd;

View File

@ -85,7 +85,9 @@ renderbuffer::renderbuffer(int x, int y, bool gl) : x(x), y(y) {
# if CAP_GL # if CAP_GL
if(gl) { if(gl) {
GLERR("renderbuffer init");
resetbuffer rb; resetbuffer rb;
GLERR("after resetbuffer");
tx = next_p2(x); tx = next_p2(x);
ty = next_p2(y); ty = next_p2(y);
@ -119,7 +121,7 @@ renderbuffer::renderbuffer(int x, int y, bool gl) : x(x), y(y) {
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, tx, ty); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, tx, ty);
bool has_depth = true; bool has_depth = true;
if(glGetError() != GL_NO_ERROR) { if(glGetError() != GL_NO_ERROR) {
printf("Could not create: GL_DEPTH24_STENCIL8"); println(hlog, "Could not create: GL_DEPTH24_STENCIL8");
glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, tx, ty); glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, tx, ty);
has_depth = false; has_depth = false;
} }
@ -243,7 +245,9 @@ resetbuffer::resetbuffer() {
#if CAP_GL #if CAP_GL
drawFboId = 0, readFboId = 0; drawFboId = 0, readFboId = 0;
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &drawFboId); glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &drawFboId);
GLERR("getInteger a");
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &readFboId); glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &readFboId);
GLERR("getInteger b");
#endif #endif
#if CAP_SDL #if CAP_SDL
sreset = s; sreset = s;

1802
rogueviz/bringris.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -29,7 +29,7 @@ struct jmatrix : array<array<int, 7>, 7> {
}; };
vector<jmatrix> jms; vector<jmatrix> jms;
std::unordered_map<jmatrix, int> ids; std::map<jmatrix, int> ids;
jmatrix J, Z, id; jmatrix J, Z, id;

View File

@ -74,7 +74,7 @@ void make() {
for(int i=0; i<magmav; i++) vertices.push_back(vertices[i]); for(int i=0; i<magmav; i++) vertices.push_back(vertices[i]);
for(int i=0; i<magmav; i++) vertices.push_back(vertices[i]); for(int i=0; i<magmav; i++) vertices.push_back(vertices[i]);
unordered_map<pair<int, int>, int> counts; map<pair<int, int>, int> counts;
int big = v - 2; int big = v - 2;

View File

@ -11,7 +11,7 @@
#endif #endif
#define main nconf_main #define main nconf_main
#undef unordered_map #undef map
#undef self #undef self
#include "nconf.cpp" #include "nconf.cpp"
#undef main #undef main

View File

@ -546,7 +546,7 @@ void queuedisk(const shiftmatrix& V, const colorpair& cp, bool legend, const str
} }
} }
unordered_map<pair<edgeinfo*, int>, int> drawn_edges; map<pair<edgeinfo*, int>, int> drawn_edges;
map<pair<cell*, cell*>, transmatrix> relmatrices; map<pair<cell*, cell*>, transmatrix> relmatrices;

View File

@ -360,7 +360,7 @@ void starbattle_puzzle() {
} }
keyhandler = [] (int sym, int uni) { keyhandler = [] (int sym, int uni) {
handlePanning(sym, uni); if(!dialog_shown) handlePanning(sym, uni);
dialog::handleNavigation(sym, uni); dialog::handleNavigation(sym, uni);
if(among(sym, '-', SDLK_F1) && !holdmouse) push_stop(); if(among(sym, '-', SDLK_F1) && !holdmouse) push_stop();

179
rogueviz/subquotient.cpp Normal file
View File

@ -0,0 +1,179 @@
#include "../hyper.h"
#include <iostream>
#include <fstream>
#include <thread>
namespace hr {
namespace subquotient {
eGeometry gSubquotient(eGeometry(-1));
vector<int> connections;
void create_subquotient(int qty = -1, int id = 0) {
start_game();
auto ac = currentmap->allcells();
auto ca = currentmap->gamestart();
for(auto cb: ac) for(int i=0; i<cb->type; i++) for(int m=0; m<2; m++) {
vector<cell*> visited;
map<cell*, cellwalker> vmap;
auto visit = [&] (cell *da, cellwalker db) {
if(vmap.count(da)) {
// println(hlog, da, " -> ", db, " [old]");
return;
}
// println(hlog, da, " -> ", db, " [new]");
vmap[da] = db;
visited.emplace_back(da);
};
visit(ca, cellwalker(cb, i, m));
for(int i=0; i<isize(visited); i++) {
for(int j=0; j<visited[i]->type; j++) {
cellwalker wa(visited[i], 0);
cellwalker wb(vmap[visited[i]]);
wa += j;
wb += j;
wa += wstep;
wb += wstep;
int r = wa.spin;
wa -= r;
wb -= r;
// println(hlog, wa, " -> ", wb);
setdist(wa.at, 7, nullptr);
wa.at->item = itGold;
visit(wa.at, wb);
}
}
int vertex = 0, edge = 0, badcycle = 0;
map<int, int> by_cycle;
for(auto swb: vmap) {
auto& s = swb.first;
auto& wb = swb.second;
if(s == wb.at) { vertex++; continue; }
bool is_edge = false;
for(int j=0; j<s->type; j++) if(s->move(j) == wb.at && (wb+j).peek() == s)
is_edge = true;
if(is_edge) { edge++; continue; }
int cs = 0;
cell *sx = s;
auto cw = cellwalker(s, 0);
vector<cell*> lst;
do {
int sp = cw.spin;
bool mirr = cw.mirrored;
if(cw.mirrored) sp = -sp;
cw -= sp;
lst.push_back(sx);
cw = vmap[sx];
if(mirr) cw += wmirror;
sx = cw.at;
cw += sp;
cs++;
if(cs >= 100) break;
}
while(sx != s);
if(cw.spin) badcycle++;
by_cycle[cs]++;
}
if(vertex || edge || badcycle || m == 0) continue;
vector<pair<int, int>> bcp;
for(auto b: by_cycle) bcp.push_back(b);
if(qty == -1)
println(hlog, "m=", m, " vertex/edge = ", tie(vertex, edge), " badcycle = ", badcycle, " by_cycle = ", bcp);
if(by_cycle[qty] == isize(vmap)) {
if(id > 0) {id--; continue; }
map<cell*, int> ids;
int next_id = 0;
vector<cell*> by_id;
set<cell*> visited;
for(auto s: ac) if(!visited.count(s)) {
by_id.push_back(s);
ids[s] = next_id;
auto sx = s;
do {
visited.insert(sx);
sx = vmap[sx].at;
}
while(sx != s);
next_id++;
}
println(hlog, "ids = ", next_id);
connections.clear();
if(int(gSubquotient) == -1) {
ginf.push_back(ginf[geometry]);
gSubquotient = eGeometry(isize(ginf) - 1);
}
ginf[gSubquotient] = ginf[geometry];
/* we need to be 'pure', unrectified may not work */
if(UNRECTIFIED) swap(ginf[gSubquotient].sides, ginf[gSubquotient].vertex);
for(int i=0; i<next_id; i++) {
cell *s = by_id[i];
for(int j=0; j<s->type; j++) {
cellwalker cw(s, j);
cw += wstep;
int res;
while(!ids.count(cw.at)) {
int sp = cw.spin;
bool flip = cw.mirrored;
if(flip) sp = -sp;
cw -= sp;
if(cw.spin) println(hlog, "bad spin");
cw = vmap[cw.at];
if(flip) cw += wmirror;
cw += sp;
}
res = ids[cw.at] * s->type + cw.spin;
if(cw.mirrored) res |= quotientspace::symmask;
connections.push_back(res);
}
}
stop_game();
set_geometry(gSubquotient);
variation = eVariation::pure;
println(hlog, "variation = ", int(variation));
start_game();
println(hlog, "started");
return;
}
}
}
int readArgs() {
using namespace arg;
if(0) ;
else if(argis("-subquotient")) { start_game(); shift(); create_subquotient(argi()); }
else return 1;
return 0;
}
auto fundamentalhook = addHook(hooks_args, 100, readArgs)
+ addHook(hooks_newmap, 0, [] {
if(geometry == gSubquotient)
return (hrmap*) new quotientspace::hrmap_quotient(connections);
return (hrmap*) nullptr;
});
}
}

View File

@ -631,7 +631,7 @@ bool force(rugpoint& m1, rugpoint& m2, double rd, bool is_anticusp=false, double
transmatrix iT = rgpushxto0(m1.native); transmatrix iT = rgpushxto0(m1.native);
for(int i=0; i<MDIM; i++) if(std::isnan(m1.native[i])) { for(int i=0; i<MXDIM; i++) if(std::isnan(m1.native[i])) {
addMessage("Failed!"); addMessage("Failed!");
println(hlog, "m1 = ", m1.native); println(hlog, "m1 = ", m1.native);
throw rug_exception(); throw rug_exception();
@ -1850,11 +1850,15 @@ EX namespace rug {
EX bool rugged = false; EX bool rugged = false;
EX bool renderonce = false; EX bool renderonce = false;
EX bool rendernogl = true; EX bool rendernogl = true;
EX bool mouse_control_rug = false;
EX int texturesize = 512; EX int texturesize = 512;
EX ld scale = 1.0f; EX ld scale = 1.0f;
EX bool rug_control() { return false; } EX bool rug_control() { return false; }
EX bool in_crystal() { return false; } EX bool in_crystal() { return false; }
EX void reset_view() { } EX void reset_view() { }
#if HDR
struct using_rugview {};
#endif
EX } EX }
#endif #endif

View File

@ -1815,6 +1815,7 @@ void no_init() { }
startanim null_animation { "", no_init, [] { gamescreen(2); }}; startanim null_animation { "", no_init, [] { gamescreen(2); }};
#if CAP_STARTANIM
startanim joukowsky { "Joukowsky transform", no_init, [] { startanim joukowsky { "Joukowsky transform", no_init, [] {
dynamicval<eModel> dm(pmodel, mdJoukowskyInverted); dynamicval<eModel> dm(pmodel, mdJoukowskyInverted);
dynamicval<ld> dt(pconf.model_orientation, ticks / 25.); dynamicval<ld> dt(pconf.model_orientation, ticks / 25.);
@ -1874,6 +1875,7 @@ startanim spin_around { "spinning around", no_init, [] {
dynamicval<transmatrix> dv(View, spin(-cos_auto(circle_radius)*alpha) * xpush(circle_radius) * spin(alpha) * View); dynamicval<transmatrix> dv(View, spin(-cos_auto(circle_radius)*alpha) * xpush(circle_radius) * spin(alpha) * View);
gamescreen(2); gamescreen(2);
}}; }};
#endif
reaction_t add_to_frame; reaction_t add_to_frame;

View File

@ -60,6 +60,23 @@ glhr::glmatrix model_orientation_gl() {
return s; return s;
} }
EX void reset_all_shaders() {
ray::reset_raycaster();
compiled_programs.clear();
matched_programs.clear();
}
EX string panini_shader() {
return
"t.w += 1.; t *= 2. / t.w; t.w -= 1.;\n"
"float s = t.z;\n"
"float l = length(t.xyz);\n"
"t /= max(length(t.xz), 1e-2);\n"
"t.z += " + glhr::to_glsl(panini_alpha) + ";\n"
"t *= l;\n"
"t.w = 1.;\n";
}
shared_ptr<glhr::GLprogram> write_shader(flagtype shader_flags) { shared_ptr<glhr::GLprogram> write_shader(flagtype shader_flags) {
string varying, vsh, fsh, vmain = "void main() {\n", fmain = "void main() {\n"; string varying, vsh, fsh, vmain = "void main() {\n", fmain = "void main() {\n";
@ -332,6 +349,14 @@ shared_ptr<glhr::GLprogram> write_shader(flagtype shader_flags) {
} }
if(shader_flags & GF_LEVELS) vmain += "vPos = t;\n"; if(shader_flags & GF_LEVELS) vmain += "vPos = t;\n";
if(treset) vmain += "t[3] = 1.0;\n"; if(treset) vmain += "t[3] = 1.0;\n";
if(WDIM == 3 && panini_alpha) {
vmain += "t = uPP * t;", vsh += "uniform mediump mat4 uPP;";
/* panini */
vmain += panini_shader();
shader_flags |= SF_ORIENT;
}
vmain += "gl_Position = uP * t;\n"; vmain += "gl_Position = uP * t;\n";
} }
@ -485,6 +510,7 @@ void display_data::set_projection(int ed, ld shift) {
for(int i=0; i<3; i++) NLP[3][i] = NLP[i][3] = 0; for(int i=0; i<3; i++) NLP[3][i] = NLP[i][3] = 0;
NLP[3][3] = 1; NLP[3][3] = 1;
} }
if(!(shader_flags & SF_ORIENT))
glhr::projection_multiply(glhr::tmtogl_transpose(NLP)); glhr::projection_multiply(glhr::tmtogl_transpose(NLP));
} }
if(ed) { if(ed) {
@ -520,6 +546,9 @@ void display_data::set_projection(int ed, ld shift) {
if(get_shader_flags() & SF_USE_ALPHA) if(get_shader_flags() & SF_USE_ALPHA)
pp[3][2] = GLfloat(pconf.alpha); pp[3][2] = GLfloat(pconf.alpha);
if(nisot::local_perspective_used())
pp = glhr::tmtogl_transpose(NLP) * pp;
if(get_shader_flags() & SF_ORIENT) { if(get_shader_flags() & SF_ORIENT) {
if(GDIM == 3) for(int a=0; a<4; a++) if(GDIM == 3) for(int a=0; a<4; a++)
models::apply_orientation_yz(pp[a][1], pp[a][2]); models::apply_orientation_yz(pp[a][1], pp[a][2]);
@ -547,6 +576,10 @@ void display_data::set_projection(int ed, ld shift) {
glhr::projection_multiply(glhr::translate(shift, 0, 0)); glhr::projection_multiply(glhr::translate(shift, 0, 0));
} }
if(in_h2xe() || in_s2xe()) {
glhr::projection_multiply(glhr::translate(0, 0, shift));
}
if(selected->shader_flags & SF_HALFPLANE) { if(selected->shader_flags & SF_HALFPLANE) {
glhr::projection_multiply(glhr::translate(0, 1, 0)); glhr::projection_multiply(glhr::translate(0, 1, 0));
glhr::projection_multiply(glhr::scale(-1, 1, 1)); glhr::projection_multiply(glhr::scale(-1, 1, 1));
@ -608,7 +641,7 @@ EX void glapplymatrix(const transmatrix& V) {
GLfloat mat[16]; GLfloat mat[16];
int id = 0; int id = 0;
if(MDIM == 3) { if(MXDIM == 3) {
for(int y=0; y<3; y++) { for(int y=0; y<3; y++) {
for(int x=0; x<3; x++) mat[id++] = V[x][y]; for(int x=0; x<3; x++) mat[id++] = V[x][y];
mat[id++] = 0; mat[id++] = 0;

View File

@ -1167,8 +1167,10 @@ void movePlayer(monster *m, int delta) {
cwt.at = c2; afterplayermoved(); cwt.at = c2; afterplayermoved();
if(c2->item && c2->land == laAlchemist) c2->wall = m->base->wall; if(c2->item && c2->land == laAlchemist) c2->wall = m->base->wall;
#if CAP_COMPLEX2
if(m->base->wall == waRoundTable) if(m->base->wall == waRoundTable)
camelot::roundTableMessage(c2); camelot::roundTableMessage(c2);
#endif
if(c2->wall == waCloud || c2->wall == waMirror) { if(c2->wall == waCloud || c2->wall == waMirror) {
visibleFor(500); visibleFor(500);
cellwalker cw(c2, 0, false); cellwalker cw(c2, 0, false);
@ -1189,7 +1191,9 @@ void movePlayer(monster *m, int delta) {
items[itOrbLife] = 0; items[itOrbLife] = 0;
m->dead = true; m->dead = true;
} }
#if CAP_COMPLEX2
mine::uncover_full(c2); mine::uncover_full(c2);
#endif
if(isWatery(c2) && isWatery(m->base) && m->inBoat) if(isWatery(c2) && isWatery(m->base) && m->inBoat)
moveItem(m->base, c2, true); moveItem(m->base, c2, true);
@ -2523,7 +2527,7 @@ EX void turn(int delta) {
if(doall) if(doall)
for(cell *c: currentmap->allcells()) activateMonstersAt(c); for(cell *c: currentmap->allcells()) activateMonstersAt(c);
else else
for(unordered_map<cell*, shiftmatrix>::iterator it = gmatrix.begin(); it != gmatrix.end(); it++) for(map<cell*, shiftmatrix>::iterator it = gmatrix.begin(); it != gmatrix.end(); it++)
activateMonstersAt(it->first); activateMonstersAt(it->first);
/* printf("size: gmatrix = %ld, active = %ld, monstersAt = %ld, delta = %d\n", /* printf("size: gmatrix = %ld, active = %ld, monstersAt = %ld, delta = %d\n",
@ -2635,7 +2639,9 @@ EX void turn(int delta) {
#if CAP_INV #if CAP_INV
if(inv::on) inv::compute(); if(inv::on) inv::compute();
#endif #endif
#if CAP_COMPLEX2
terracotta::check(); terracotta::check();
#endif
heat::processfires(); heat::processfires();
if(havewhat&HF_WHIRLPOOL) whirlpool::move(); if(havewhat&HF_WHIRLPOOL) whirlpool::move();
if(havewhat&HF_WHIRLWIND) whirlwind::move(); if(havewhat&HF_WHIRLWIND) whirlwind::move();

View File

@ -55,10 +55,7 @@ void dqi_sky::draw() {
int sk = get_skybrightness(); int sk = get_skybrightness();
unordered_map<cell*, pair<color_t, color_t>> colors; map<cell*, pair<color_t, color_t>> colors;
#ifdef USE_UNORDERED_MAP
colors.reserve(isize(sky));
#endif
for(sky_item& si: sky) colors[si.c] = for(sky_item& si: sky) colors[si.c] =
make_pair(darkena(gradient(0, si.color, 0, sk, 255), 0, 0xFF), make_pair(darkena(gradient(0, si.color, 0, sk, 255), 0, 0xFF),
darkena(si.skycolor, 0, 0xFF) darkena(si.skycolor, 0, 0xFF)
@ -238,6 +235,7 @@ void celldrawer::draw_ceiling() {
break; break;
case laVariant: { case laVariant: {
#if CAP_COMPLEX2
int b = getBits(c); int b = getBits(c);
col = 0x404040; col = 0x404040;
for(int a=0; a<21; a++) for(int a=0; a<21; a++)
@ -245,6 +243,7 @@ void celldrawer::draw_ceiling() {
col += variant::features[a].color_change; col += variant::features[a].color_change;
col = col & 0x00FF00; col = col & 0x00FF00;
skycol = col; skycol = col;
#endif
break; break;
} }

View File

@ -161,7 +161,9 @@ struct hrmap_spherical : hrmap_standard {
transmatrix relative_matrix(cell *c2, cell *c1, const hyperpoint& hint) { transmatrix relative_matrix(cell *c2, cell *c1, const hyperpoint& hint) {
if(!gmatrix0.count(c2) || !gmatrix0.count(c1)) { if(!gmatrix0.count(c2) || !gmatrix0.count(c1)) {
#if !ISWEB
printf("building gmatrix0 (size=%d)\n", isize(gmatrix0)); printf("building gmatrix0 (size=%d)\n", isize(gmatrix0));
#endif
#if CAP_GP #if CAP_GP
auto bak = gp::draw_li; auto bak = gp::draw_li;
#endif #endif

View File

@ -185,6 +185,10 @@
#define MAXMDIM 4 #define MAXMDIM 4
#endif #endif
#ifndef CAP_MDIM_FIXED
#define CAP_MDIM_FIXED 0
#endif
#ifndef CAP_TEXTURE #ifndef CAP_TEXTURE
#define CAP_TEXTURE (CAP_GL && (CAP_PNG || CAP_SDL_IMG) && !ISMINI) #define CAP_TEXTURE (CAP_GL && (CAP_PNG || CAP_SDL_IMG) && !ISMINI)
#endif #endif
@ -206,7 +210,7 @@
#endif #endif
#ifndef CAP_TOUR #ifndef CAP_TOUR
#define CAP_TOUR (!ISWEB && !ISMINI) #define CAP_TOUR (!ISMINI)
#endif #endif
#ifndef CAP_ROGUEVIZ #ifndef CAP_ROGUEVIZ
@ -285,7 +289,7 @@
#endif #endif
#ifndef CAP_SHMUP #ifndef CAP_SHMUP
#define CAP_SHMUP 1 #define CAP_SHMUP (!ISWEB)
#endif #endif
#ifndef CAP_BITFIELD #ifndef CAP_BITFIELD
@ -403,6 +407,10 @@ extern "C" {
#define CAP_GLEW (CAP_GL && !ISMOBILE && !ISMAC && !ISLINUX && !ISWEB) #define CAP_GLEW (CAP_GL && !ISMOBILE && !ISMAC && !ISLINUX && !ISWEB)
#endif #endif
#if ISWEB
#define GLES_ONLY
#endif
#if CAP_GL #if CAP_GL
#if CAP_GLEW #if CAP_GLEW
#include <GL/glew.h> #include <GL/glew.h>
@ -462,6 +470,11 @@ typedef unsigned GLuint;
#include <zlib.h> #include <zlib.h>
#endif #endif
#if ISWEB
#include <emscripten.h>
#include <emscripten/html5.h>
#endif
#if CAP_GMP #if CAP_GMP
#include <gmpxx.h> #include <gmpxx.h>
#endif #endif
@ -478,14 +491,6 @@ typedef unsigned GLuint;
#endif #endif
#endif #endif
#ifdef USE_UNORDERED_MAP
#include <unordered_map>
#include <unordered_set>
#else
#define unordered_map map
#define unordered_set set
#endif
#include <stdint.h> #include <stdint.h>
#if ISWINDOWS #if ISWINDOWS
@ -573,7 +578,7 @@ union SDL_Event;
#endif #endif
#ifndef CAP_RAY #ifndef CAP_RAY
#define CAP_RAY (MAXMDIM >= 4 && !ISWEB && !ISMOBILE && CAP_GL) #define CAP_RAY (MAXMDIM >= 4 && CAP_GL)
#endif #endif
#ifndef CAP_MEMORY_RESERVE #ifndef CAP_MEMORY_RESERVE

View File

@ -194,7 +194,9 @@ EX void initgame() {
cwt.at = currentmap->gamestart(); cwt.spin = 0; cwt.mirrored = false; cwt.at = currentmap->gamestart(); cwt.spin = 0; cwt.mirrored = false;
cwt.at->land = firstland; cwt.at->land = firstland;
#if CAP_COMPLEX2
if(firstland == laBrownian) brownian::init(cwt.at); if(firstland == laBrownian) brownian::init(cwt.at);
#endif
chaosAchieved = false; chaosAchieved = false;
@ -214,7 +216,9 @@ EX void initgame() {
} }
if((tactic::on || yendor::on || peace::on) && isCyclic(firstland)) { if((tactic::on || yendor::on || peace::on) && isCyclic(firstland)) {
#if CAP_COMPLEX2
camelot::anthraxBonus = items[itHolyGrail]; camelot::anthraxBonus = items[itHolyGrail];
#endif
cwt.at->move(0)->land = firstland; cwt.at->move(0)->land = firstland;
if(firstland == laWhirlpool) cwt.at->move(0)->wall = waSea; if(firstland == laWhirlpool) cwt.at->move(0)->wall = waSea;
@ -366,7 +370,9 @@ EX void initgame() {
#if CAP_INV #if CAP_INV
if(inv::on) inv::init(); if(inv::on) inv::init();
#endif #endif
#if CAP_COMPLEX2
mine::auto_teleport_charges(); mine::auto_teleport_charges();
#endif
if(!use_special_land) { if(!use_special_land) {
if(firstland != (princess::challenge ? laPalace : laIce)) cheater++; if(firstland != (princess::challenge ? laPalace : laIce)) cheater++;
} }
@ -1265,7 +1271,9 @@ EX void stop_game() {
princess::reviveAt = 0; princess::reviveAt = 0;
princess::forceVizier = false; princess::forceVizier = false;
princess::forceMouse = false; princess::forceMouse = false;
#if CAP_COMPLEX2
camelot::knighted = 0; camelot::knighted = 0;
#endif
// items[itGreenStone] = 100; // items[itGreenStone] = 100;
clearMemory(); clearMemory();
game_active = false; game_active = false;
@ -1287,7 +1295,6 @@ EX void set_geometry(eGeometry target) {
bool was_default = pmodel == default_model(); bool was_default = pmodel == default_model();
callhooks(hooks_on_geometry_change); callhooks(hooks_on_geometry_change);
if(geometry != target) { if(geometry != target) {
int old_DIM = GDIM;
stop_game(); stop_game();
ors::reset(); ors::reset();
if(among(target, gProduct, gRotSpace)) { if(among(target, gProduct, gRotSpace)) {
@ -1318,14 +1325,11 @@ EX void set_geometry(eGeometry target) {
if(bt::in() || WDIM == 3 || kite::in() || arb::in()) if(!hybri) variation = eVariation::pure; if(bt::in() || WDIM == 3 || kite::in() || arb::in()) if(!hybri) variation = eVariation::pure;
#endif #endif
if(S3 >= OINF) variation = eVariation::pure; if(S3 >= OINF) variation = eVariation::pure;
if(INVERSE) variation = gp::variation_for(gp::param); if(INVERSE && !hybri) variation = gp::variation_for(gp::param);
if(ginf[target].default_variation == eVariation::pure && geometry != gArchimedean) if(ginf[target].default_variation == eVariation::pure && geometry != gArchimedean)
variation = eVariation::pure; variation = eVariation::pure;
if(was_default) pmodel = default_model(); if(was_default) pmodel = default_model();
if(nonisotropic && old_DIM == 2 && vid.texture_step < 4) vid.texture_step = 4;
if(WDIM == 2 && (cgflags & qIDEAL) && vid.always3 && vid.texture_step < 32) vid.texture_step = 32; if(WDIM == 2 && (cgflags & qIDEAL) && vid.always3 && vid.texture_step < 32) vid.texture_step = 32;
if(prod) { pmodel = mdPerspective; if(vid.texture_step < 4) vid.texture_step = 4; }
if(WDIM == 3 && (cgflags & qIDEAL) && vid.texture_step < 4) vid.texture_step = 4;
if(sl2) nisot::geodesic_movement = true; if(sl2) nisot::geodesic_movement = true;
if(rotspace) { if(rotspace) {
@ -1495,7 +1499,9 @@ EX void start_game() {
ignored_memory_warning = false; ignored_memory_warning = false;
check_cgi(); check_cgi();
cgi.require_basics(); cgi.require_basics();
#if CAP_ARCM
arcm::current.compute_geometry(); arcm::current.compute_geometry();
#endif
initcells(); initcells();
expansion.reset(); expansion.reset();

View File

@ -7,6 +7,13 @@
#include "hyper.h" #include "hyper.h"
namespace hr { namespace hr {
#if !CAP_TOUR
EX namespace tour {
EX always_false on;
EX }
#endif
#if CAP_TOUR #if CAP_TOUR
/** \brief Variables and function related to Guided Tour and other presentations. */ /** \brief Variables and function related to Guided Tour and other presentations. */

View File

@ -263,6 +263,7 @@ cld exp_parser::parse(int prio) {
force_eat(")"); force_eat(")");
res = edge_of_triangle_with_angles(M_PI/2, M_PI/a, M_PI/b); res = edge_of_triangle_with_angles(M_PI/2, M_PI/a, M_PI/b);
} }
#if CAP_ARCM
else if(eat("arcmedge(")) { else if(eat("arcmedge(")) {
vector<int> vals; vector<int> vals;
vals.push_back(iparse(0)); vals.push_back(iparse(0));
@ -280,6 +281,7 @@ cld exp_parser::parse(int prio) {
if(extra_params.count("distunit")) if(extra_params.count("distunit"))
res /= extra_params["distunit"]; res /= extra_params["distunit"];
} }
#endif
else if(eat("regangle(")) { else if(eat("regangle(")) {
cld edgelen = parse(0); cld edgelen = parse(0);
if(extra_params.count("distunit")) { if(extra_params.count("distunit")) {
@ -373,6 +375,7 @@ cld exp_parser::parse(int prio) {
else if(number == "psl_steps") res = cgi.psl_steps; else if(number == "psl_steps") res = cgi.psl_steps;
else if(number == "single_step") res = cgi.single_step; else if(number == "single_step") res = cgi.single_step;
else if(number == "step") res = hdist0(tC0(currentmap->adj(cwt.at, 0))); else if(number == "step") res = hdist0(tC0(currentmap->adj(cwt.at, 0)));
else if(number == "edgelen") res = hdist(get_corner_position(cwt.at, 0), get_corner_position(cwt.at, 1));
else if(number == "mousey") res = mousey; else if(number == "mousey") res = mousey;
else if(number == "random") res = randd(); else if(number == "random") res = randd();
else if(number == "mousez") res = cld(mousex - current_display->xcenter, mousey - current_display->ycenter) / cld(current_display->radius, 0); else if(number == "mousez") res = cld(mousex - current_display->xcenter, mousey - current_display->ycenter) / cld(current_display->radius, 0);

View File

@ -1063,7 +1063,11 @@ void save_mode_data(hstream& f) {
f.write<char>(chaosmode); f.write<char>(chaosmode);
f.write<char>(shmup::on); f.write<char>(shmup::on);
f.write<char>(inv::on); f.write<char>(inv::on);
#if CAP_TOUR
f.write<char>(tour::on); f.write<char>(tour::on);
#else
f.write<char>(false);
#endif
f.write<char>(peace::on); f.write<char>(peace::on);
f.write<char>(peace::otherpuzzles); f.write<char>(peace::otherpuzzles);
f.write<char>(peace::explore_other); f.write<char>(peace::explore_other);