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