1 // Hyperbolic Rogue -- main header file
2 // Copyright (C) 2011-2019 Zeno Rogue, see 'hyper.cpp' for details
3 
4 /** \file hyper.h
5  *  \brief The main header file of HyperRogue
6  *
7  *  Contains general utility macros, various value macros, using clauses for standard library functions,
8  *  implementation of the basic connection_table, walker, cell and heptagon classes,
9  *  and general routines which did not fit elsewhere
10  */
11 
12 #ifndef _HYPER_H_
13 #define _HYPER_H_
14 
15 // version numbers
16 #define VER "12.0f"
17 #define VERNUM_HEX 0xA906
18 
19 #include "sysconfig.h"
20 
21 #include <stdarg.h>
22 #include "hyper_function.h"
23 
24 /** \brief the main namespace of HyperRogue */
25 namespace hr {
26 
27 /** \brief A helper structure that acts as a boolean which is always false. Helpful when disabling stuff with compiler flags. */
28 struct always_false {
29   operator bool() const { return false; }
30   bool operator = (bool b) const { return b; }
31   };
32 
33 /** \brief placate GCC's overzealous -Wunused-result */
34 template<class T>
ignore(T &&)35 void ignore(T&&) {
36   }
37 
38 /** \brief a simple static_cast<void*> for use with printf("%p") */
voidp(const void * p)39 inline const void *voidp(const void *p) {
40   return p;
41   }
42 
43 /** \brief Is the value of first parameter equal to one of the remaining parameters? */
among(T x,V y)44 template<class T, class V, class... U> bool among(T x, V y) { return x == y; }
among(T x,V y,U...u)45 template<class T, class V, class... U> bool among(T x, V y, U... u) { return x==y || among(x,u...); }
46 
47 // functions and types used from the standard library
48 using std::vector;
49 using std::map;
50 using std::array;
51 using std::sort;
52 using std::multimap;
53 using std::set;
54 using std::string;
55 using std::pair;
56 using std::tuple;
57 using std::shared_ptr;
58 using std::make_shared;
59 using std::min;
60 using std::max;
61 using std::make_pair;
62 using std::tie;
63 using std::queue;
64 using std::swap;
65 using std::complex;
66 using std::reverse;
67 using std::real;
68 using std::imag;
69 using std::stable_sort;
70 using std::out_of_range;
71 using std::get;
72 using std::move;
73 using std::make_tuple;
74 using std::unique_ptr;
75 
76 using std::abs;
77 using std::isfinite;
78 using std::isnan;
79 using std::isinf;
80 using std::log;
81 using std::exp;
82 using std::sin;
83 using std::cos;
84 using std::sinh;
85 using std::asin;
86 using std::acos;
87 using std::tan;
88 using std::atan;
89 using std::atan2;
90 using std::tanh;
91 using std::sqrt;
92 using std::pow;
93 using std::floor;
94 using std::ceil;
95 #ifndef NO_STD_HYPOT
96 using std::hypot;
97 using std::asinh;
98 using std::acosh;
99 #endif
100 
101 struct hr_exception : std::runtime_error {
hr_exceptionhr_exception102     explicit hr_exception() : std::runtime_error("hr_exception") {}
hr_exceptionhr_exception103     explicit hr_exception(const std::string& s) : std::runtime_error(s.c_str()) {}
104 };
105 
106 struct hr_shortest_path_exception { };
107 
108 // genus (in grammar)
109 #define GEN_M 0
110 #define GEN_F 1
111 #define GEN_N 2
112 #define GEN_O 3
113 
114 // Add a message to the GUI.
115 // If multiple messages appear with the same spamtype != 0, the older ones disappear quickly
116 void addMessage(string s, char spamtype = 0);
117 
118 // geometry-dependent constants
119 
120 #define cginf ginf[geometry]
121 
122 #define S7 cginf.sides
123 #define S3 cginf.vertex
124 #define hyperbolic_37 (S7 == 7 && S3 == 3 && !bt::in() && !arcm::in())
125 #define hyperbolic_not37 ((S7 > 7 || S3 > 3 || bt::in() || arcm::in()) && hyperbolic)
126 #define weirdhyperbolic ((S7 > 7 || S3 > 3 || !STDVAR || bt::in() || arcm::in() || arb::in()) && hyperbolic)
127 #define stdhyperbolic (S7 == 7 && S3 == 3 && STDVAR && !bt::in() && !arcm::in())
128 
129 #define cgflags cginf.flags
130 
131 #define cryst (cgflags & qCRYSTAL)
132 
133 /** convenience flag for geometries with major aspects missing */
134 #define experimental (cgflags & qEXPERIMENTAL)
135 
136 // these geometries do not feature alternate structures for horocycles
137 #define eubinary (euclid || bt::in() || cryst || nil)
138 
139 #define cgclass (cginf.cclass)
140 #define euclid (cgclass == gcEuclid)
141 #define sphere (cgclass == gcSphere)
142 #define sol (cgflags & qSOL)
143 #define nih (cgflags & qNIH)
144 #define nil (cgclass == gcNil)
145 #define sl2 (cgclass == gcSL2)
146 #define prod (cgclass == gcProduct)
147 #define hybri (cgflags & qHYBRID)
148 #define rotspace (geometry == gRotSpace)
149 #define hyperbolic (cgclass == gcHyperbolic)
150 #define nonisotropic (among(cgclass, gcSolNIH, gcNil, gcSL2))
151 #define translatable (euclid || nonisotropic)
152 #define nonorientable (cgflags & qNONORIENTABLE)
153 #define elliptic (cgflags & qELLIPTIC)
154 #define quotient (cgflags & qANYQ)
155 #define smallbounded (cgflags & qSMALL)
156 #define bounded (cgflags & qBOUNDED)
157 
158 // Dry Forest burning, heat transfer, etc. are performed on the whole universe
159 #define doall (bounded)
160 
161 #define sphere_narcm (sphere && !arcm::in())
162 
163 #define a4 (S3 == 4)
164 #define a45 (S3 == 4 && S7 == 5)
165 #define a46 (S3 == 4 && S7 == 6)
166 #define a47 (S3 == 4 && S7 == 7)
167 #define a457 (S3 == 4 && S7 != 6)
168 #define a467 (S3 == 4 && S7 >= 6)
169 #define a38 (S3 == 3 && S7 == 8)
170 #define sphere4 (sphere && S7 == 4)
171 #define stdeuc (geometry == gNormal || geometry == gEuclid || geometry == gEuclidSquare)
172 #define smallsphere (sphere_narcm && S7 < 5)
173 #define bigsphere (sphere_narcm && S7 == 5)
174 
175 #define S6 (S3*2)
176 #define MAX_S3 4
177 
178 #define SG6 (S3==3?6:4)
179 #define SG3 (S3==3?3:2)
180 #define SG2 (S3==3?2:1)
181 
182 #define GOLDBERG_INV (GOLDBERG || INVERSE)
183 
184 #define INVERSE among(variation, eVariation::unrectified, eVariation::warped, eVariation::untruncated )
185 
186 #define UNRECTIFIED (variation == eVariation::unrectified)
187 #define WARPED (variation == eVariation::warped)
188 #define UNTRUNCATED (variation == eVariation::untruncated)
189 
190 #define GOLDBERG (variation == eVariation::goldberg)
191 #define IRREGULAR (variation == eVariation::irregular)
192 #define PURE (variation == eVariation::pure)
193 #define BITRUNCATED (variation == eVariation::bitruncated)
194 #define DUAL (variation == eVariation::dual)
195 #define DUALMUL (DUAL ? 2 : 1)
196 
197 #define CHANGED_VARIATION (variation != cginf.default_variation)
198 
199 #define STDVAR (PURE || BITRUNCATED)
200 #define NONSTDVAR (!STDVAR)
201 
202 #define VALENCE current_valence()
203 
204 #define NUMWITCH 7
205 
206 // achievements
207 
208 #define LB_YENDOR_CHALLENGE 40
209 #define LB_PURE_TACTICS 41
210 #define NUMLEADER 87
211 #define LB_PURE_TACTICS_SHMUP 49
212 #define LB_PURE_TACTICS_COOP 50
213 #define LB_RACING 81
214 
215 #if ISMOBILE || ISWEB || ISPANDORA || 1
216 typedef double ld;
217 #define LDF "%lf"
218 #define PLDF "lf"
219 #else
220 typedef long double ld;
221 #define LDF "%Lf"
222 #define PLDF "Lf"
223 #endif
224 
225 typedef complex<ld> cld;
226 
227 typedef unsigned color_t;
228 
229 struct charstyle {
230   int charid;
231   color_t skincolor, haircolor, dresscolor, swordcolor, dresscolor2, uicolor, eyecolor;
232   bool lefthanded;
233   };
234 
235 enum eStereo { sOFF, sAnaglyph, sLR, sODS };
236 
237 enum eModel : int;
238 
239 /** configuration of the projection */
240 struct projection_configuration {
241   eModel model;            /**< which projection, see classes.cpp */
242   ld xposition, yposition; /**< move the center to another position */
243   ld scale, alpha, camera_angle, fisheye_param, twopoint_param, stretch, ballangle, ballproj, euclid_to_sphere;
244   ld clip_min, clip_max;
245   ld model_orientation, halfplane_scale, model_orientation_yz;
246   ld collignon_parameter;
247   ld aitoff_parameter, miller_parameter, loximuthal_parameter, winkel_parameter;
248   bool show_hyperboloid_flat;
249   bool collignon_reflected;
250   string formula;
251   eModel basic_model;
252   ld top_z;
253   ld model_transition;
254   ld spiral_angle;
255   ld spiral_x;
256   ld spiral_y;
257   bool use_atan;
258   ld right_spiral_multiplier;
259   ld any_spiral_multiplier;
260   ld sphere_spiral_multiplier;
261   ld spiral_cone;
262   ld skiprope;
263   ld product_z_scale;
264   ld rotational_nil;
265 
266   ld depth_scaling;
267   ld hyperboloid_scaling;
268   ld vr_angle, vr_zshift, vr_scale_factor;
269 
projection_configurationprojection_configuration270   projection_configuration() {
271     formula = "z^2"; top_z = 5; model_transition = 1; spiral_angle = 70; spiral_x = 10; spiral_y = 7;
272     rotational_nil = 1;
273     right_spiral_multiplier = 1;
274     any_spiral_multiplier = 1;
275     sphere_spiral_multiplier = 2;
276     spiral_cone = 360;
277     use_atan = false;
278     product_z_scale = 1;
279     aitoff_parameter = .5;
280     miller_parameter = .8;
281     loximuthal_parameter = 0;
282     winkel_parameter = .5;
283     show_hyperboloid_flat = true;
284     depth_scaling = 1;
285     vr_angle = 0;
286     hyperboloid_scaling = 1;
287     vr_zshift = 0;
288     vr_scale_factor = 1;
289     }
290   };
291 
292 enum eThreatLevel { tlNoThreat, tlSpam, tlNormal, tlHighThreat };
293 
294 struct videopar {
295   projection_configuration projection_config, rug_config;
296   ld yshift;
297   ld sspeed, mspeed;
298   ld binary_width, fixed_facing_dir;
299   int mobilecompasssize;
300   int radarsize; // radar for 3D geometries
301   ld radarrange;
302   int aurastr, aurasmoothen;
303   bool fixed_facing;
304   bool fixed_yz;
305   bool use_wall_radar;
306 
307   int linequality;
308 
309   bool want_fullscreen;
310   bool full;
311   bool change_fullscr;
312   bool relative_window_size;
313   bool want_vsync;
314   bool current_vsync;
315 
316   int graphglyph; // graphical glyphs
317   bool darkhepta;
318   int shifttarget;
319 
320   int xres, yres, framelimit;
321 
322   int xscr, yscr;
323 
324   int fullscreen_x, fullscreen_y;
325   int window_x, window_y;
326   ld window_rel_x, window_rel_y;
327 
328   bool grid;
329   bool particles;
330 
331   bool relative_font;
332   int fsize, abs_fsize, fontscale;
333   int flashtime;
334 
335   int wallmode, monmode, axes, highlightmode;
336   bool axes3;
337   bool revcontrol;
338 
339   int msgleft, msglimit;
340 
341   bool wantGL;
342   int want_antialias;
343   bool fineline;
344 
345   bool usingGL;
346   int antialias;
347   #define AA_NOGL      1
348   #define AA_VERSION   2
349   #define AA_LINES     4
350   #define AA_POLY      8
351   #define AA_FONT      32
352   #define AA_MULTI     64
353   #define AA_MULTI16   128 // not configurable
354   ld linewidth;
355 
356   ld multiplier_grid, multiplier_ring;
357 
358   int joyvalue, joyvalue2, joypanthreshold;
359   ld joypanspeed;
360 
361   charstyle cs;
362 
363   bool samegender; // same gender for the Princess?
364   int language;
365 
366   bool backeffects; // background particle effects
367 
368   int killreduction, itemreduction, portreduction;
369 
370   int steamscore;
371   bool drawmousecircle; // draw the circle around the mouse
372   bool skipstart;       // skip the start menu
373   bool quickmouse;      // quick mouse on the map
374   bool sloppy_3d;       // make 3D faster but ugly
375   int timeformat;       // time format used in the message log
376 
377   int use_smart_range;  // 0 = distance-based, 1 = model-based, 2 = model-based and generate
378   ld smart_range_detail;// minimum visible cell for modes 1 and 2
379   ld smart_range_detail_3;// minimum visible cell in 3D (for mode 2, there is no mode 1)
380   bool smart_area_based;// based on area or length?
381   int cells_drawn_limit;
382   int cells_generated_limit; // limit on cells generated per frame
383 
384   eStereo stereo_mode;
385   ld ipd;
386   ld lr_eyewidth, anaglyph_eyewidth;
387   ld fov;
388   bool consider_shader_projection;
389   int desaturate;
390   int texture_step;
391 
392 
393   bool always3;  // always use the 3D engine
394   ld depth;      // world level below the plane
395   ld camera;     // camera level above the plane
396   ld wall_height, creature_scale, height_width;
397   ld lake_top, lake_bottom;
398   ld rock_wall_ratio;
399   ld human_wall_ratio;
400 
401   int tc_alpha, tc_depth, tc_camera;
402   ld highdetail, middetail;
403   bool gp_autoscale_heights;
404 
405   ld eye;
406   bool auto_eye;
407 
408   ld plevel_factor;
409   bool bubbles_special, bubbles_threshold, bubbles_all;
410   int joysmooth;
411 
412   eThreatLevel faraway_highlight; // draw attention to monsters on the horizon
413   int faraway_highlight_color; // 0 = monster color, 100 = red-green oscillation
414   };
415 
416 extern videopar vid;
417 
418 /** \brief How many dimensional is the gameplay. In the FPP mode of a 2D geometry, WDIM is 2 */
419 #define WDIM cginf.g.gameplay_dimension
420 /** \brief How many dimensional is the graphical representation. In the FPP mode of a 2D geometry, MDIM is 3 */
421 #define GDIM cginf.g.graphical_dimension
422 /** \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 */
423 #define MDIM (MAXMDIM == 3 ? 3 : cginf.g.homogeneous_dimension)
424 /** \brief What dimension of matrices is used in loops (the 'extra' dimensions have values 0 or 1 as in Id)
425  *  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).
426  *  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.
427  */
428 #define MXDIM (CAP_MDIM_FIXED ? MAXMDIM : MDIM)
429 /** \brief The 'homogeneous' dimension index */
430 #define LDIM (MDIM-1)
431 #define cclass g.kind
432 
433 #define self (*this)
434 
435 #define BUGCOLORS 3
436 
437 #define big_unlock (inv::on && !ls::any_chaos())
438 
439 // land completion for shared unlocking
440 #define U5 (big_unlock ? 10 : 5)
441 // land completion for advanced unlocking
442 #define U10 (big_unlock ? 25 : 10)
443 
444 // land completion
445 #define R10 (big_unlock ? 50 : 10)
446 // intermediate lands
447 #define R30 (big_unlock ? 100 : 30)
448 // advanced lands
449 #define R60 (big_unlock ? 200 : 60)
450 // advanced lands II
451 #define R90 (big_unlock ? 300 : 90)
452 // Crossroads IV
453 #define R200 (big_unlock ? 800 : 200)
454 // Crossroads V
455 #define R300 (big_unlock ? 1200 : 300)
456 // kill types for Dragon Chasms
457 #define R20 (big_unlock ? 30 : 20)
458 // kill count for Graveyard/Hive
459 #define R100 (big_unlock ? 500 : 100)
460 
461 // size casted to int, to prevent warnings and actual errors caused by the unsignedness of x.size()
isize(const T & x)462 template<class T> int isize(const T& x) {return x.size(); }
463 
464 // automatically growing vector
465 template<class T> struct grow_vector : public vector<T> {
growgrow_vector466   T& grow(size_t index) {
467     if(index >= this->size()) {
468       this->resize(index + 1);
469       }
470     return (vector<T>::operator[]) (index);
471     }
472   };
473 
474 // game forward declarations
475 
476 namespace anticheat { extern bool tampered; }
477 #define HRANDMAX 0x7FFFFFFF
478 
479 struct movedir {
480   int d;
481   // non-negative numbers denote 'rotate +d steps and act in this direction
482   // negative numbers have the following meanings (warning: not used consistently):
483   #define MD_WAIT (-1)
484   #define MD_DROP (-2)
485   #define MD_UNDECIDED (-3)
486   #define MD_USE_ORB (-4)
487   int subdir; // for normal movement (0+): turn left or right
488   struct cell *tgt;  // for MD_USE_ORB: target cell
489   };
490 
491 // shmup
492 
493 template<class T>
494 class hookset {
495     std::map<int, std::function<T>> *map_ = nullptr;
496 
497 public:
498     template<class U>
add(int prio,U && hook)499     int add(int prio, U&& hook) {
500         if (map_ == nullptr) map_ = new std::map<int, std::function<T>>();
501         while (map_->count(prio)) {
502             prio++;
503         }
504         map_->emplace(prio, static_cast<U&&>(hook));
505         return prio;
506     }
507 
del(int prio)508     void del(int prio) {
509         map_->erase(prio);
510         }
511 
512     template<class... U>
callhooks(U &&...args)513     void callhooks(U&&... args) const {
514         if (map_ == nullptr) return;
515         for (const auto& p : *map_) {
516             p.second(static_cast<U&&>(args)...);
517         }
518     }
519 
520     template<class V, class... U>
callhandlers(V zero,U &&...args)521     V callhandlers(V zero, U&&... args) const {
522         if (map_ == nullptr) return zero;
523         for (const auto& p : *map_) {
524             auto z = p.second(static_cast<U&&>(args)...);
525             if (z != zero) return z;
526         }
527         return zero;
528     }
529 };
530 
531 using purehookset = hookset<void()>;
532 
533 static const int NOHINT = -1;
534 
535 typedef function<void()> reaction_t;
536 typedef function<bool()> bool_reaction_t;
537 
538 void offer_choose_file(reaction_t r);
539 
540 #define HELPFUN(x) (help_delegate = x, "HELPFUN")
541 
542 typedef function<int(struct cell*)> cellfunction;
543 
544 // passable flags
545 
546 #define SAGEMELT .1
547 #define PT(x, y) ((tactic::on || quotient == 2 || daily::on) ? (y) : inv::on ? min(2*(y),x) : (x))
548 #define ROCKSNAKELENGTH 50
549 #define WORMLENGTH 15
550 #define PRIZEMUL 7
551 
552 #define INF  9999
553 #define INFD 60
554 #define PINFD 125
555 #ifndef BARLEV
556 #define BARLEV ((ISANDROID||ISIOS||ISFAKEMOBILE||getDistLimit()<7)?(getDistLimit()<4?8:9):10)
557 #endif
558 #define BUGLEV 15
559 // #define BARLEV 9
560 
561 #define YDIST 101
562 #define MODECODES (1ll<<61)
563 
564 #define GUNRANGE 3
565 
566 // loops
567 
568 #define fakecellloop(ct) for(cell *ct = (cell*)1; ct; ct=NULL)
569 
570 #define forCellIdAll(ct, i, cf) fakecellloop(ct) for(int i=0; i<(cf)->type && (ct=(cf)->move(i),true); i++)
571 #define forCellIdCM(ct, i, cf)  fakecellloop(ct) for(int i=0; i<(cf)->type && (ct=createMov((cf),i),true); i++)
572 #define forCellIdEx(ct, i, cf)  forCellIdAll(ct,i,cf) if(ct)
573 
574 #define forCellEx(ct, cf) forCellIdEx(ct,forCellEx ## __LINE__,cf)
575 #define forCellCM(ct, cf) forCellIdCM(ct,forCellCM ## __LINE__,cf)
576 #define forCellAll(ct, cf) forCellIdCM(ct,forCellAll ## __LINE__,cf)
577 
578 // canAttack/moveval flags
579 
580 #define AF_NORMAL            0          // nothing special about this attack
581 
582 #define AF_TOUGH             Flag(0)    // tough attacks: Hyperbugs
583 #define AF_MAGIC             Flag(1)    // magical attacks: Flash
584 #define AF_STAB              Flag(2)    // stabbing attacks (usually ignored except Hedgehogs)
585 #define AF_LANCE             Flag(3)    // lance attacks (used by Lancers)
586 #define AF_ONLY_ENEMY        Flag(4)    // only say YES if it is an enemy
587 #define AF_ONLY_FRIEND       Flag(5)    // only say YES if it is a friend
588 #define AF_ONLY_FBUG         Flag(6)    // only say YES if it is a bug_or friend
589 #define AF_BACK              Flag(7)    // backward attacks (ignored except Viziers and Flailers)
590 #define AF_APPROACH          Flag(8)    // approach attacks (ignored except Lancers)
591 #define AF_IGNORE_UNARMED    Flag(9)    // ignore the UNARMED flag
592 #define AF_NOSHIELD          Flag(10)   // ignore the shielded status
593 #define AF_GETPLAYER         Flag(11)   // check for player (replace m2 with moPlayer for player position)
594 #define AF_GUN               Flag(12)   // revolver attack
595 #define AF_FAST              Flag(13)   // fast attack
596 #define AF_EAT               Flag(17)   // eating attacks from Worm-likes
597 
598 #define MF_NOATTACKS         Flag(14)   // don't do any attacks
599 #define MF_PATHDIST          Flag(15)   // consider pathdist for moveval
600 #define MF_ONLYEAGLE         Flag(16)   // do this only for Eagles
601 #define MF_MOUNT             Flag(18)   // don't do
602 #define MF_NOFRIEND          Flag(19)   // don't do it for friends
603 
604 #define AF_SWORD             Flag(20)   // big sword
605 #define AF_SWORD_INTO        Flag(21)   // moving into big sword
606 #define AF_MSG               Flag(22)   // produce a message
607 #define AF_MUSTKILL          Flag(23)   // when TRUE, stunning attacks are not accepted by canAttack
608 #define AF_NEXTTURN          Flag(24)   // next turn -- don't count shield at power 1
609 #define AF_FALL              Flag(25)   // death by falling
610 #define MF_STUNNED           Flag(26)   // edgeunstable: ignore ladders (as stunned monsters do)
611 #define MF_IVY               Flag(27)   // edgeunstable: ignore ivy (ivy cannot climb ivy)
612 #define AF_HORNS             Flag(28)   // spear attack (always has APPROACH too)
613 #define AF_BULL              Flag(29)   // bull attack
614 #define AF_SIDE              Flag(30)   // side attack
615 #define AF_CRUSH             Flag(31)   // Crusher's delayed attack
616 #define AF_PLAGUE            Flag(32)   // Orb of Plague (do not check adjacency)
617 #define AF_PSI               Flag(33)   // Orb of the Mind
618 #define AF_WEAK              Flag(34)   // Curse of Weakness
619 
620 #if CAP_SDL
621 
622 #if CAP_PNG
623 #include "savepng.h"
624 #define IMAGEEXT ".png"
625 void IMAGESAVE(SDL_Surface *s, const char *fname);
626 #else
627 #define IMAGEEXT ".bmp"
628 #define IMAGESAVE SDL_SaveBMP
629 #endif
630 
631 #endif
632 
633 template<class T> struct dynamicval {
634   T& where;
635   T backup;
dynamicvaldynamicval636   dynamicval(T& wh, T val) : where(wh) { backup = wh; wh = val; }
dynamicvaldynamicval637   dynamicval(T& wh) : where(wh) { backup = wh; }
~dynamicvaldynamicval638   ~dynamicval() { where = backup; }
639   };
640 
641 struct finalizer {
642   reaction_t f;
finalizerfinalizer643   finalizer(reaction_t r) : f(r) {}
~finalizerfinalizer644   ~finalizer() { f(); }
645   };
646 
647 static const int MAXPLAYER = 7;
648 
649 #define DEFAULTCONTROL (multi::players == 1 && !shmup::on && !multi::alwaysuse)
650 #define DEFAULTNOR(sym) (DEFAULTCONTROL || multi::notremapped(sym))
651 
652 #define CAP_MENUSCALING (ISPANDORA || ISMOBILE)
653 
654 #if CAP_MENUSCALING
655 #define displayfrZ dialog::zoom::displayfr
656 #define displayfrZH dialog::zoom::displayfr_highlight
657 #else
658 #define displayfrZ displayfr
659 #define displayfrZH dialog::zoom::displayfr_highlight
660 #endif
661 
662 // just in case if I change my mind about when Orbs lose their power
663 #define ORBBASE 0
664 
665 #define mmscale(V, x) (mmspatial ? (ivoryz ? mzscale(V,x) : mscale(V, x)) : (V))
666 
667 #define SHADOW_WALL 0x60
668 #define SHADOW_SL   0x18
669 #define SHADOW_MON  0x30
670 
671 // ranks:
672 enum class PPR {
673   ZERO, EUCLIDEAN_SKY, OUTCIRCLE, MOVESTAR,
674   MINUSINF,
675   BELOWBOTTOMm,
676   BELOWBOTTOM,
677   BELOWBOTTOMp,
678   BELOWBOTTOM_FALLANIM,
679   LAKEBOTTOM, HELLSPIKE,
680   INLAKEWALLm, INLAKEWALL, INLAKEWALLp,
681   INLAKEWALL_FALLANIM,
682   BSHALLOW, SHALLOW, ASHALLOW,
683   SUBLAKELEV, LAKELEV, BOATLEV, BOATLEV2, BOATLEV3,
684   LAKEWALLm, LAKEWALL, LAKEWALLp,
685   LAKEWALL_FALLANIM,
686   FLOOR_TOWER,
687   FLOOR,
688   FLOOR_DRAGON,
689   FLOORa, FLOORb, FLOORc, FLOORd,
690   LIZEYE,
691   BFLOOR,
692   GFLOORa, GFLOORb, GFLOORc,
693   WALLSHADOW,
694   STRUCT0, STRUCT1, STRUCT2, STRUCT3,
695   THORNS, WALL,
696   REDWALLm, REDWALLs, REDWALLp, REDWALL,
697   REDWALLm2, REDWALLs2, REDWALLp2, REDWALLt2,
698   REDWALLm3, REDWALLs3, REDWALLp3, REDWALLt3,
699   HEPTAMARK,
700   ITEM_BELOW,
701   ITEM, ITEMa, ITEMb,
702   BIGSTATUE,
703 
704   WALL3m, WALL3s, WALL3p, WALL3, WALL3A,
705 
706 // WALL3m, WALL3s, WALL3p, WALL3, WALL3A,
707   HIDDEN, GIANTSHADOW,
708   TENTACLE0, TENTACLE1,
709   ONTENTACLE, ONTENTACLE_EYES, ONTENTACLE_EYES2,
710   MONSTER_SHADOW,
711   MONSTER_FOOT, MONSTER_LEG, MONSTER_GROIN,
712   MONSTER_SUBWPN, MONSTER_WPN,
713   MONSTER_BODY, MONSTER_ARMOR0, MONSTER_ARMOR1,
714   MONSTER_CLOAK, MONSTER_NECK,
715   MONSTER_HEAD, MONSTER_FACE, MONSTER_EYE0, MONSTER_EYE1,
716   MONSTER_HAIR, MONSTER_HAT0, MONSTER_HAT1,
717   MONSTER_HOODCLOAK1, MONSTER_HOODCLOAK2,
718   STUNSTARS,
719   CARRIED, CARRIEDa, CARRIEDb,
720   PARTICLE, SWORDMARK, MAGICSWORD, MISSILE, SKY,
721   MINEMARK, ARROW,
722   MOBILE_ARROW,
723   LINE,
724   // in depth tested models transparent surfaces need to be depth sorted by HyperRogue
725   // and set to PPR::TRANSPARENT_* to draw them after all the opaque ones
726   TRANSPARENT_LAKE, TRANSPARENT_SHADOW, TRANSPARENT_WALL,
727   // no depth testing for SUPERLINE and above
728   SUPERLINE, TEXT, CIRCLE,
729   MAX,
730   DEFAULT = -1
731   };
732 
733 inline PPR operator + (PPR x, int y) { return PPR(int(x) + y); }
734 inline PPR operator - (PPR x, int y) { return PPR(int(x) - y); }
735 inline int operator - (PPR x, PPR y) { return int(x) - int(y); }
736 
737 #define OUTLINE_NONE     0x000000FF
738 #define OUTLINE_FRIEND   0x00FF00FF
739 #define OUTLINE_ENEMY    0xFF0000FF
740 #define OUTLINE_TREASURE 0xFFFF00FF
741 #define OUTLINE_ORB      0xFF8000FF
742 #define OUTLINE_OTHER    0xFFFFFFFF
743 #define OUTLINE_DEAD     0x800000FF
744 #define OUTLINE_TRANS    0
745 #define OUTLINE_DEFAULT  ((bordcolor << 8) + 0xFF)
746 #define OUTLINE_FORE     ((forecolor << 8) + 0xFF)
747 #define OUTLINE_BACK     ((backcolor << 8) + 0xFF)
748 
749 enum orbAction { roMouse, roKeyboard, roCheck, roMouseForce, roMultiCheck, roMultiGo };
750 
751 #define MODELCOUNT ((int) mdGUARD)
752 
753 #define pconf vid.projection_config
754 #if CAP_RUG
755 #define vpconf (rug::rugged ? vid.rug_config : vid.projection_config)
756 #else
757 #define vpconf pconf
758 #endif
759 #define pmodel (pconf.model)
760 
761 static const int DISTANCE_UNKNOWN = 127;
762 
addHook(hookset<T> & m,int prio,U && hook)763 template<class T, class U> int addHook(hookset<T>& m, int prio, U&& hook) {
764   return m.add(prio, static_cast<U&&>(hook));
765   }
766 
delHook(hookset<T> & m,int prio)767 template<class T> void delHook(hookset<T>& m, int prio) {
768   m.del(prio);
769   }
770 
callhooks(const hookset<T> & h,U &&...args)771 template<class T, class... U> void callhooks(const hookset<T>& h, U&&... args) {
772   return h.callhooks(static_cast<U&&>(args)...);
773   }
774 
callhandlers(V zero,const hookset<T> & h,U &&...args)775 template<class T, class V, class... U> V callhandlers(V zero, const hookset<T>& h, U&&... args) {
776   return h.callhandlers(zero, static_cast<U&&>(args)...);
777   }
778 
779 string XLAT(string);
780 
781 #define GLERR(call) glError(call, __FILE__, __LINE__)
782 
783 #define SHMUPTITLE "shoot'em up mode"
784 
785 // check for a plain number key
786 #define NUMBERKEY (interpret_as_direction(sym, uni) ? 0 : uni)
787 #define DKEY (get_direction_key(sym, uni))
788 #define DIRECTIONKEY (interpret_as_direction(sym, uni) ? uni : 0)
789 
790 namespace scores { void load(); }
791 
792 #if ISMOBILE
793 namespace leader { void showMenu(); void handleKey(int sym, int uni); }
794 #endif
795 
796 int textwidth(int siz, const string &str);
797 #if CAP_GL
798 int gl_width(int size, const char *s);
799 #endif
800 
801 #if ISMOBILE
802 extern int andmode;
803 extern bool longclick;
804 extern bool useRangedOrb;
805 #endif
806 
807 #ifndef GL
808 typedef float GLfloat;
809 #endif
810 
811 typedef array<GLfloat, 2> glvec2;
812 typedef array<GLfloat, 3> glvec3;
813 typedef array<GLfloat, 4> glvec4;
814 
815 #if MAXMDIM == 4
816 #define SHDIM 4
817 typedef glvec4 glvertex;
818 #else
819 #define SHDIM 3
820 typedef glvec3 glvertex;
821 #endif
822 
823 extern int emeraldtable[100][7];
824 
825 // extern cell *cwpeek(cellwalker cw, int dir);
826 
827 #define HAUNTED_RADIUS getDistLimit()
828 #define UNKNOWN 65535
829 
830 #define GRAIL_FOUND 0x4000
831 #define GRAIL_RADIUS_MASK 0x3FFF
832 
833 extern vector<cell*> dcal;
834 
835 // z to close to this limit => do not draw
836 
837 #define BEHIND_LIMIT 1e-6
838 
eliminate_if(vector<T> & data,U pred)839 template<class T, class U> void eliminate_if(vector<T>& data, U pred) {
840   for(int i=0; i<isize(data); i++)
841     if(pred(data[i]))
842       data[i] = data.back(), data.pop_back(), i--;
843   }
844 
make_array(T a,T b,T c,T d)845 template<class T> array<T, 4> make_array(T a, T b, T c, T d) { array<T,4> x; x[0] = a; x[1] = b; x[2] = c; x[3] = d; return x; }
make_array(T a,T b,T c)846 template<class T> array<T, 3> make_array(T a, T b, T c) { array<T,3> x; x[0] = a; x[1] = b; x[2] = c; return x; }
make_array(T a,T b)847 template<class T> array<T, 2> make_array(T a, T b) { array<T,2> x; x[0] = a; x[1] = b; return x; }
848 
849 // Find in a std::map or std::unordered_map, or return null.
850 template<class Map, class Key>
at_or_null(const Map & map,const Key & key)851 const typename Map::mapped_type *at_or_null(const Map& map, const Key& key) {
852   auto it = map.find(key);
853   return (it == map.end()) ? nullptr : &it->second;
854   }
855 
856 namespace daily {
857   extern bool on;
858   extern int daily_id;
859   void setup();
860   void split();
861   void gifts();
862   void turnoff();
863   void showMenu();
864   int find_daily_lbid(int id);
865   bool prevent_spawn_treasure_on(cell *c);
866   void handleQuit(int sev);
867   void uploadscore(bool really_final);
868   }
869 
870 #define RING(i) for(double i=0; i<=cgi.S84+1e-6; i+=SD3 * pow(.5, vid.linequality))
871 #define REVRING(i) for(double i=cgi.S84; i>=-1e-6; i-=SD3 * pow(.5, vid.linequality))
872 #define PRING(i) for(double i=0; i<=cgi.S84+1e-6; i+= pow(.5, vid.linequality))
873 #define REVPRING(i) for(double i=cgi.S84; i>=-1e-6; i-=pow(.5, vid.linequality))
874 
875 #define ONEMPTY if(d == 7 && passable(c, NULL, 0) && !safety && !reptilecheat)
876 
texture_order(const T & f)877 template <class T> void texture_order(const T& f) {
878   const int STEP = vid.texture_step;
879   const ld STEP2 = STEP;
880   for(int y=0; y<STEP; y++)
881   for(int x=0; x<STEP; x++) {
882     ld x0 = x / STEP2;
883     ld y0 = y / STEP2;
884     ld b = 1 / STEP2;
885 
886      if(x+y < STEP) {
887        f(x0, y0); f(x0+b, y0); f(x0, y0+b);
888        }
889      if(x+y <= STEP && x && y) {
890        f(x0, y0); f(x0-b, y0); f(x0, y0-b);
891        }
892     }
893   }
894 
895 /** find the smallest value of x in range [dmin..dmax] such that f(x) returns true */
896 
binsearch(ld dmin,ld dmax,const T & f)897 template<class T> ld binsearch(ld dmin, ld dmax, const T& f) {
898   for(int i=0; i<200; i++) {
899     ld d = (dmin + dmax) / 2;
900     if(dmin == d || dmax == d) break;
901     if(f(d)) dmax = d;
902     else dmin = d;
903     }
904   return dmin;
905   }
906 
907   static const int max_vec = (1<<14);
908   extern bool needConfirmationEvenIfSaved();
909 
910 typedef unsigned long long flagtype;
911 #define Flag(i) (flagtype(1ull<<i))
set_flag(flagtype & f,flagtype which,bool b)912 static inline void set_flag(flagtype& f, flagtype which, bool b) {
913   if(b) f |= which;
914   else f &= ~which;
915   }
916 
917 }
918 
919 /** this macro is used to delay performing the action in case if everything is rolled back */
920 #define LATE(x) \
921   if(changes.on) { changes.at_commit([=] { x; }); return; }
922 
923 // assert macro
924 #ifdef NDEBUG
925 #define hassert(condition) if(!(condition)) __builtin_unreachable()
926 #else
927 #define hassert(condition) if(!(condition)) printf("%s:%d:%s: assertion failed: %s\n", __FILE__, __LINE__, __func__, #condition)
928 #endif
929 
930 #define IS(z) = z
931 #include "autohdr.h"
932 #undef IS
933 #define IS(z)
934 #define EX
935 
936 #endif
937