1 // Hyperbolic Rogue -- Locations
2 // Copyright (C) 2011-2018 Zeno Rogue, see 'hyper.cpp' for details
3 
4 /** \file locations.cpp
5  *  \brief definition of connection tables, walkers, cell and heptagon structures
6  *
7  *  The standard geometry uses 'heptagons' for the underlying heptagonal tessellation,
8  *  and 'cells' for the tessellation that the game is actually played on.
9  *  Other geometries also use the class 'heptagon' even if they are not heptagon-based;
10  *  there may be one 'heptagon' per each cell. Heptagons are not used in masterless
11  *  geometries, though. This file implements the basic types and functions for navigating both graphs.
12  */
13 
14 #include "hyper.h"
15 namespace hr {
16 
17 #if HDR
18 
19 extern int cellcount, heptacount;
20 
21 #define NODIR 126
22 #define NOBARRIERS 127
23 
24 /** \brief Cell information for the game. struct cell builds on this */
25 struct gcell {
26 
27 #if CAP_BITFIELD
28   /** \brief which land does this cell belong to */
29   eLand land : 8;
30   /** \brief wall type (waNone for no walls) */
31   eWall wall : 8;
32   /** \brief monster on this cell -- note that player characters are handled separately */
33   eMonster monst : 8;
34   /** \brief item on this cell */
35   eItem item : 8;
36 
37   /** \brief if this is a barrier, what lands on are on the sides? */
38   eLand barleft : 8, barright : 8;
39 
40   /** \brief is it currently sparkling with lightning? */
41   unsigned ligon : 1;
42 
43   signed
44     mpdist : 7,         ///< minimum player distance, the smaller value, the more generated it is */
45     pathdist : 8,       ///< distance from the target -- actual meaning may change
46     cpdist : 8;         ///< current distance to the player
47 
48   unsigned
49     mondir : 8,         ///< which direction the monster is facing (if relevant), also used for boats
50     bardir : 8,         ///< may equal NODIR (no barrier here), NOBARRIERS (barriers not allowed here), or the barrier direction
51     stuntime : 8,       ///< for stunned monsters, stun time left; also used for Mutant Ivy timing
52     hitpoints : 7,      ///< hitpoints left, for Palace monsters, Dragons, Krakens etc. Also reused as cpid for mirrors
53     monmirror : 1;      ///< monster mirroring state for nonorientable geometries
54 
55   unsigned landflags : 8; ///< some lands need additional flags
56 #else
57   eLand land;
58   eWall wall;
59   eMonster monst;
60   eItem item;
61   eLand barleft, barright;
62   bool ligon, monmirror;
63   signed char pathdist, cpdist, mpdist;
64 
65   unsigned char mondir, bardir, stuntime, hitpoints;
66   unsigned char landflags;
67 #endif
68 
69   /** 'landparam' is used for:
70    *  heat in Icy/Cocytus;
71    *  heat in Dry (0..10);
72    *  CR2 structure;
73    *  hive Weird Rock color / pheromones;
74    *  Ocean/coast depth;
75    *  Bomberbird Egg hatch time / mine marking;
76    *  number of Ancient Jewelry;
77    *  improved tracking in Trollheim
78    */
79   union {
80     int32_t landpar;
81     unsigned int landpar_color;
82     float heat;
83     char bytes[4];
84     struct fieldinfo {
85       uint16_t fieldval;
86       unsigned rval : 4;
87       unsigned flowerdist : 4;
88       unsigned walldist : 4;
89       unsigned walldist2 : 4;
90       } fi;
91 
92   } LHU;
93 
94   /** \brief wall parameter, used e.g. for remaining power of Bonfires and Thumpers */
95   char wparam;
96 
97   #ifdef CELLID
98   int cellid;
99   #endif
100 
gcellhr::gcell101   gcell() {
102     #ifdef CELLID
103     cellid = cellcount;
104     #endif
105     }
106   };
107 
108 #define landparam LHU.landpar
109 #define landparam_color LHU.landpar_color
110 #define fval LHU.fi.fieldval
111 
112 #define FULL_EDGE 120
113 
114 template<class T> struct walker;
115 
116 /** Connection tables are used by heptagon and cell structures. They basically
117  *  describe the structure of the graph on the given manifold. We assume that
118  *  the class T has a field c of type connection_table<T>,
119  *  as its last field. Edges are listed in the clockwise order (for 2D tilings,
120  *  for 3D tilings the order is more arbitrary). For each edge we remember which other T
121  *  we are connected to, as well as the index of this edge in the other T, and whether it is
122  *  mirrored (for graphs on non-orientable manifolds).
123  *  To conserve memory, these classes need to be allocated with tailored_alloc
124  *  and freed with tailored_free.
125  */
126 
127 int gmod(int i, int j);
128 
129 template<class T> struct connection_table {
130 
131   /** \brief Table of moves. This is the maximum size, but tailored_alloc allocates less. */
132   T* move_table[FULL_EDGE + (FULL_EDGE + sizeof(char*) - 1) / sizeof(char*)];
133 
spintablehr::connection_table134   unsigned char *spintable() { return (unsigned char*) (&move_table[full()->degree()]); }
135 
136   /** \brief get the full T from the pointer to this connection table */
fullhr::connection_table137   T* full() { return (T*)((char*)this - offsetof(T, c)); }
138   /** \brief for the edge d, set the `spin` and `mirror` attributes */
setspinhr::connection_table139   void setspin(int d, int spin, bool mirror) {
140     unsigned char& c = spintable() [d];
141     c = spin;
142     if(mirror) c |= 128;
143     }
144   /** \brief we are spin(i)-th neighbor of move[i] */
spinhr::connection_table145   int spin(int d) { return spintable() [d] & 127; }
146   /** \brief on non-orientable surfaces, the d-th edge may be mirrored */
mirrorhr::connection_table147   bool mirror(int d) { return spintable() [d] & 128; }
148   /** \brief 'fix' the edge number d to get the actual index in [0, degree()) */
fixhr::connection_table149   int fix(int d) { return gmod(d, full()->degree()); }
150   /** \brief T in the direction i */
movehr::connection_table151   T*& move(int i) { return move_table[i]; }
152   /** \brief T in the direction i, modulo degree() */
modmovehr::connection_table153   T*& modmove(int i) { return move(fix(i)); }
modspinhr::connection_table154   unsigned char modspin(int i) { return spin(fix(i)); }
155   /** \brief initialize the table */
fullclearhr::connection_table156   void fullclear() {
157     for(int i=0; i<full()->degree(); i++) move_table[i] = NULL;
158     }
159   /** \brief connect this in direction d0 to c1 in direction d1, possibly mirrored */
connecthr::connection_table160   void connect(int d0, T* c1, int d1, bool m) {
161     move(d0) = c1;
162     c1->move(d1) = full();
163     setspin(d0, d1, m);
164     c1->c.setspin(d1, d0, m);
165     }
166   /* like the other connect, but take the parameters of the other cell from a walker */
connecthr::connection_table167   void connect(int d0, walker<T> hs) {
168     connect(d0, hs.at, hs.spin, hs.mirrored);
169     }
170   };
171 
172 /** \brief Allocate a class T with a connection_table, but with only `degree` connections.
173  *
174  *  Also set yet unknown connections to NULL.
175  *
176  * Generating the hyperbolic world consumes lots of
177  * RAM, so we really need to be careful on low memory devices.
178  */
179 
tailored_alloc(int degree)180 template<class T> T* tailored_alloc(int degree) {
181   T* result;
182 #ifndef NO_TAILORED_ALLOC
183   int b = offsetof(T, c) + offsetof(connection_table<T>, move_table) + sizeof(T*) * degree + degree;
184   result = (T*) new char[b];
185   new (result) T();
186 #else
187   result = new T;
188 #endif
189   result->type = degree;
190   for(int i=0; i<degree; i++) result->c.move_table[i] = NULL;
191   return result;
192   }
193 
194 /** \brief Counterpart to hr::tailored_alloc(). */
tailored_delete(T * x)195 template<class T> void tailored_delete(T* x) {
196   x->~T();
197   delete[] ((char*) (x));
198   }
199 
wstep_thr::wstep_t200 static const struct wstep_t { wstep_t() {} } wstep;
wmirror_thr::wmirror_t201 static const struct wmirror_t { wmirror_t() {}} wmirror;
rev_thr::rev_t202 static const struct rev_t { rev_t() {} } rev;
revstep_thr::revstep_t203 static const struct revstep_t { revstep_t() {}} revstep;
204 
205 extern int hrand(int);
206 
207 /** \brief the walker structure is used for walking on surfaces defined via \ref connection_table. */
208 template<class T> struct walker {
209   /** \brief where we are at */
210   T *at;
211   /** \brief in which direction (edge) we are facing */
212   int spin;
213   /** \brief are we mirrored */
214   bool mirrored;
215   walker<T> (T *at = NULL, int s = 0, bool m = false) : at(at), spin(s), mirrored(m) { if(at) s = at->c.fix(s); }
216   /** \brief spin by i to the left (or right, when mirrored */
operator +=hr::walker217   walker<T>& operator += (int i) {
218     spin = at->c.fix(spin+(mirrored?-i:i));
219     return (*this);
220     }
221   /** \brief spin by i to the right (or left, when mirrored */
operator -=hr::walker222   walker<T>& operator -= (int i) {
223     spin = at->c.fix(spin-(mirrored?-i:i));
224     return (*this);
225     }
226   /** \brief add wmirror to mirror this walker */
operator +=hr::walker227   walker<T>& operator += (wmirror_t) {
228     mirrored = !mirrored;
229     return (*this);
230     }
231   /** \brief add wstep to make a single step, after which we are facing the T we were originally on */
operator +=hr::walker232   walker<T>& operator += (wstep_t) {
233     at->cmove(spin);
234     int nspin = at->c.spin(spin);
235     if(at->c.mirror(spin)) mirrored = !mirrored;
236     at = at->move(spin);
237     spin = nspin;
238     return (*this);
239     }
240   /** \brief add wrev to face the other direction, may be non-deterministic and use hrand */
operator +=hr::walker241   walker<T>& operator += (rev_t) {
242     auto rd = reverse_directions(at, spin);
243     if(rd.size() == 1) spin = rd[0];
244     else spin = rd[hrand(rd.size())];
245     return (*this);
246     }
247   /** \brief adding revstep is equivalent to adding rev and step */
operator +=hr::walker248   walker<T>& operator += (revstep_t) {
249     (*this) += rev; return (*this) += wstep;
250     }
operator !=hr::walker251   bool operator != (const walker<T>& x) const {
252     return at != x.at || spin != x.spin || mirrored != x.mirrored;
253     }
operator ==hr::walker254   bool operator == (const walker<T>& x) const {
255     return at == x.at && spin == x.spin && mirrored == x.mirrored;
256     }
257 
operator <hr::walker258   bool operator < (const walker<T>& cw2) const {
259     return tie(at, spin, mirrored) < tie(cw2.at, cw2.spin, cw2.mirrored);
260     }
261 
262   /** how much should we spin to face direction dir */
to_spinhr::walker263   int to_spin(int dir) {
264     return gmod(dir - spin, at->type) * (mirrored ? -1 : 1);
265     }
266 
operator ++hr::walker267   walker<T>& operator ++ (int) { return (*this) += 1; }
operator --hr::walker268   walker<T>& operator -- (int) { return (*this) -= 1; }
operator +hr::walker269   template<class U> walker operator + (U t) const { walker<T> w = *this; w += t; return w; }
operator -hr::walker270   template<class U> walker operator - (U t) const { walker<T> w = *this; w += (-t); return w; }
271   /** \brief what T are we facing, without creating it */
peekhr::walker272   T*& peek() { return at->move(spin); }
273   /** \brief what T are we facing, with creating it */
cpeekhr::walker274   T* cpeek() { return at->cmove(spin); }
275   /** \brief would we create a new T if we stepped forwards? */
createshr::walker276   bool creates() { return !peek(); }
277   /** \brief mirror this walker with respect to the d-th edge */
mirrorathr::walker278   walker<T> mirrorat(int d) { return walker<T> (at, at->c.fix(d+d - spin), !mirrored); }
279   };
280 
281 struct cell;
282 
283 // automaton state
284 enum hstate { hsOrigin, hsA, hsB, hsError, hsA0, hsA1, hsB0, hsB1, hsC };
285 
286 struct cell *createMov(struct cell *c, int d);
287 struct heptagon *createStep(struct heptagon *c, int d);
288 
~cdata_or_heptagonhr::cdata_or_heptagon289 struct cdata_or_heptagon { virtual ~cdata_or_heptagon() {} };
290 
291 struct cdata : cdata_or_heptagon {
292   int val[4];
293   int bits;
294   };
295 
296 /** \brief Limit on the 'distance' value in heptagon.
297  *
298  *  This value is signed (negative distances are used
299  *  in horocycle implementation. Distance is currently a short, and we need a bit of breathing room.
300  *  It would not be a technical problem to use a larger type, but 32000 is close to what fits in
301  *  the memory of a normal computer. Farlands appear close to this limit.
302  **/
303 
304 constexpr int global_distance_limit = 32000;
305 
306 /** This value is used in iterative algorithms to prevent infinite loops created by incorrect
307     data (e.g., circular dragon). It should be larger than global_distance_limit */
308 constexpr int iteration_limit = 10000000;
309 
310 /** \brief underlying tiling
311  *  in bitruncated/irregular/Goldberg geometries, heptagons form the
312  *  underlying regular tiling (not necessarily heptagonal); in pure
313  *  geometries, they correspond 1-1 to tiles; in 'masterless' geometries
314  *  heptagons are unused
315  */
316 
317 struct heptagon : cdata_or_heptagon {
318   /** \brief Automata are used to generate the standard maps. s is the state of this automaton */
319   hstate s : 6;
320   /** \brief distance modulo 4, in heptagons */
321   unsigned int dm4: 2;
322   /** \brief distance from the origin; based on the final geometry of cells, not heptagons themselves */
323   short distance;
324   /** \brief Emerald/wineyard generator. May have different meaning in other geometries. */
325   short emeraldval;
326   /** \brief Palace pattern generator. May have different meaning in other geometries. */
327   short fiftyval;
328   /** \brief Zebra pattern generator. May have different meaning in other geometries. */
329   short zebraval;
330   /** \brief Field quotient pattern ID. May have different meaning in other geometries. */
331   int fieldval : 24;
332   /** \brief the number of adjacent heptagons */
333   unsigned char type : 8;
334   /** \brief data for fractal landscapes */
335   short rval0, rval1;
336   /** for the main map, it contains the fractal landscape data
337    *
338    *  For alternate structures, cdata contains the pointer to the original.
339    */
340   struct cdata *cdata;
341   /** \brief which central cell does this heptagon correspond too
342    *
343    *  For alternate geometries, c7 is NULL
344    */
345   cell *c7;
346   /** \brief associated generator of alternate structure, for Camelot and horocycles */
347   heptagon *alt;
348   /** \brief connection table */
349   connection_table<heptagon> c;
350   // DO NOT add any fields after connection_table! (see tailored_alloc)
movehr::heptagon351   heptagon*& move(int d) { return c.move(d); }
modmovehr::heptagon352   heptagon*& modmove(int d) { return c.modmove(d); }
353   // functions
heptagonhr::heptagon354   heptagon () { heptacount++; }
~heptagonhr::heptagon355   ~heptagon () { heptacount--; }
cmovehr::heptagon356   heptagon *cmove(int d) { return createStep(this, d); }
cmodmovehr::heptagon357   heptagon *cmodmove(int d) { return createStep(this, c.fix(d)); }
degreehr::heptagon358   inline int degree() { return type; }
359 
360   // prevent accidental copying
361   heptagon(const heptagon&) = delete;
362   heptagon& operator=(const heptagon&) = delete;
363   };
364 
365 struct cell : gcell {
366   char type;        ///< our degree
degreehr::cell367   int degree() { return type; }
368 
369   int listindex;    ///< used by celllister
370   heptagon *master; ///< heptagon who owns us; for 'masterless' tilings it contains coordinates instead
371 
372   connection_table<cell> c;
373   // DO NOT add any fields after connection_table! (see tailored_alloc)
374 
movehr::cell375   cell*& move(int d) { return c.move(d); }
modmovehr::cell376   cell*& modmove(int d) { return c.modmove(d); }
cmovehr::cell377   cell* cmove(int d) { return createMov(this, d); }
cmodmovehr::cell378   cell* cmodmove(int d) { return createMov(this, c.fix(d)); }
cellhr::cell379   cell() {}
380 
381   // prevent accidental copying
382   cell(const cell&) = delete;
383   heptagon& operator=(const cell&) = delete;
384   };
385 
386 /** abbreviations */
387 typedef walker<heptagon> heptspin;
388 typedef walker<cell> cellwalker;
389 
390 /** \brief A structure useful when walking on the cell graph in arbitrary way, or listing cells in general.
391   *
392   * Only one celllister may be active at a time, using the stack semantics.
393   * Only the most recently created one works; the previous one will resume
394   * working when this one is destroyed.
395   */
396 struct manual_celllister {
397   /** \brief list of cells in this list */
398   vector<cell*> lst;
399   vector<int> tmps;
400 
401   /** \brief is the given cell on the list? */
listedhr::manual_celllister402   bool listed(cell *c) {
403     return c->listindex >= 0 && c->listindex < isize(lst) && lst[c->listindex] == c;
404     }
405 
406   /** \brief add a cell to the list */
addhr::manual_celllister407   bool add(cell *c) {
408     if(listed(c)) return false;
409     tmps.push_back(c->listindex);
410     c->listindex = isize(lst);
411     lst.push_back(c);
412     return true;
413     }
414 
~manual_celllisterhr::manual_celllister415   ~manual_celllister() {
416     for(int i=0; i<isize(lst); i++) lst[i]->listindex = tmps[i];
417     }
418   };
419 
420 /** \brief automatically generate a list of nearby cells */
421 struct celllister : manual_celllister {
422   vector<int> dists;
423 
add_athr::celllister424   void add_at(cell *c, int d) {
425     if(add(c)) dists.push_back(d);
426     }
427 
428   /** \brief automatically generate a list of nearby cells
429   @param orig where to start
430   @param maxdist maximum distance to cover
431   @param maxcount maximum number of cells to cover
432   @param breakon we are actually looking for this cell, so stop when reaching it
433   */
celllisterhr::celllister434   celllister(cell *orig, int maxdist, int maxcount, cell *breakon) {
435     add_at(orig, 0);
436     cell *last = orig;
437     for(int i=0; i<isize(lst); i++) {
438       cell *c = lst[i];
439       if(maxdist) forCellCM(c2, c) {
440         add_at(c2, dists[i]+1);
441         if(c2 == breakon) return;
442         }
443       if(c == last) {
444         if(isize(lst) >= maxcount || dists[i]+1 == maxdist) break;
445         last = lst[isize(lst)-1];
446         }
447       }
448     }
449 
450   /** \brief for a given cell c on the list, return its distance from orig */
getdisthr::celllister451   int getdist(cell *c) { return dists[c->listindex]; }
452   };
453 
454 /** \brief translate heptspins to cellwalkers and vice versa */
cth_thr::cth_t455 static const struct cth_t { cth_t() {}} cth;
operator +(cellwalker cw,cth_t)456 inline heptspin operator+ (cellwalker cw, cth_t) { return heptspin(cw.at->master, cw.spin * DUALMUL, cw.mirrored); }
operator +(heptspin hs,cth_t)457 inline cellwalker operator+ (heptspin hs, cth_t) { return cellwalker(hs.at->c7, hs.spin / DUALMUL, hs.mirrored); }
458 
459 #endif
460 
proper(cell * c,int d)461 EX bool proper(cell *c, int d) { return d >= 0 && d < c->type; }
462 
463 #if HDR
464 
465 constexpr int STRONGWIND = 99;
466 constexpr int FALL = 98;
467 constexpr int NO_SPACE = 97;
468 constexpr int TELEPORT = 96;
469 constexpr int JUMP = 95;
470 constexpr int STAY = 94;
471 
472 namespace whirlwind { cell *jumpDestination(cell*); }
473 
474 /** \brief a structure for representing movements
475  *
476  *  mostly for 'proper' moves where s->move(d) == t,
477  *  but also sometimes for other moves
478  */
479 
480 struct movei {
481   cell *s;
482   cell *t;
483   int d;
ophr::movei484   bool op() { return s != t; }
properhr::movei485   bool proper() const { return d >= 0 && d < s->type && s->move(d) == t; }
moveihr::movei486   movei(cell *_s, int _d) : s(_s), d(_d) {
487     if(d == STRONGWIND) t = whirlwind::jumpDestination(s);
488     else if(d < 0 || d >= s->type) t = s;
489     else t = s->move(d);
490     }
moveihr::movei491   movei(cell *_s, cell *_t, int _d) : s(_s), t(_t), d(_d) {}
moveihr::movei492   movei(cellwalker cw) : s(cw.at), t(cw.cpeek()), d(cw.spin) {}
revhr::movei493   movei rev() const { return movei(t, s, rev_dir_or(d)); }
dir_orhr::movei494   int dir_or(int x) const { return proper() ? d : x; }
rev_dir_orhr::movei495   int rev_dir_or(int x) const { return proper() ? s->c.spin(d) : x; }
rev_dir_mirrorhr::movei496   int rev_dir_mirror() const { return proper() ? s->c.spin(d) : d; }
rev_dir_forcehr::movei497   int rev_dir_force() const { hassert(proper()); return s->c.spin(d); }
dir_forcehr::movei498   int dir_force() const { hassert(proper()); return d; }
mirrorhr::movei499   bool mirror() { return s->c.mirror(d); }
500   };
501 #endif
502 
moveimon(cell * c)503 EX movei moveimon(cell *c) { return movei(c, c->mondir); }
504 
match(cell * f,cell * t)505 EX movei match(cell *f, cell *t) {
506   for(int i=0; i<f->type; i++) if(f->move(i) == t) return movei(f, t, i);
507   return movei(f, t, -1);
508   }
509 
510 }
511