hyperrogue/hyper.h

1742 lines
46 KiB
C
Raw Normal View History

2017-10-29 13:19:51 +00:00
// This is the main header file of HyperRogue. Mostly everything is dumped here.
// It is quite chaotic.
// version numbers
2019-08-07 22:49:30 +00:00
#define VER "11.1i"
#define VERNUM_HEX 0xA709
#include <stdarg.h>
#include "hyper_function.h"
namespace hr {
2019-02-17 17:50:56 +00:00
struct always_false {
operator bool() const { return false; };
void operator = (bool b) const {};
};
2018-07-14 06:45:14 +00:00
template<class T>
void ignore(T&&) {
// placate GCC's overzealous -Wunused-result
}
2019-03-30 16:52:51 +00:00
template<class T, class V, class... U> bool among(T x, V y) { return x == y; }
template<class T, class V, class... U> bool among(T x, V y, U... u) { return x==y || among(x,u...); }
2018-06-17 16:32:06 +00:00
// functions and types used from the standard library
using std::vector;
using std::map;
using std::array;
using std::unordered_map;
using std::sort;
using std::multimap;
using std::set;
using std::string;
using std::pair;
using std::tuple;
using std::shared_ptr;
using std::make_shared;
using std::min;
using std::max;
using std::make_pair;
using std::tie;
using std::queue;
using std::swap;
using std::complex;
using std::reverse;
using std::real;
using std::imag;
using std::stable_sort;
using std::out_of_range;
using std::get;
using std::move;
using std::make_tuple;
using std::unique_ptr;
2018-06-18 01:53:39 +00:00
2018-06-18 01:43:23 +00:00
using std::abs;
2018-06-18 01:53:39 +00:00
using std::isfinite;
using std::isnan;
2018-10-23 15:03:58 +00:00
using std::isinf;
2018-06-18 01:53:39 +00:00
using std::log;
using std::exp;
using std::sin;
using std::cos;
using std::sinh;
using std::asin;
using std::acos;
using std::tan;
using std::atan;
using std::atan2;
using std::tanh;
using std::sqrt;
using std::pow;
using std::floor;
using std::ceil;
#ifndef NO_STD_HYPOT
using std::hypot;
using std::asinh;
using std::acosh;
#endif
struct hr_exception: std::exception { hr_exception() {} };
struct hr_shortest_path_exception: hr_exception { };
// genus (in grammar)
#define GEN_M 0
#define GEN_F 1
#define GEN_N 2
#define GEN_O 3
2019-04-29 09:17:06 +00:00
// Add a message to the GUI.
// If multiple messages appear with the same spamtype != 0, the older ones disappear quickly
void addMessage(string s, char spamtype = 0);
// geometry-dependent constants
#define ALPHA (M_PI*2/S7)
#define S7 ginf[geometry].sides
#define S3 ginf[geometry].vertex
2018-08-30 14:08:05 +00:00
#define hyperbolic_37 (S7 == 7 && S3 == 3 && !binarytiling && !archimedean)
#define hyperbolic_not37 ((S7 > 7 || S3 > 3 || binarytiling || archimedean) && hyperbolic)
#define weirdhyperbolic ((S7 > 7 || S3 > 3 || !STDVAR || binarytiling || archimedean) && hyperbolic)
#define stdhyperbolic (S7 == 7 && S3 == 3 && STDVAR && !binarytiling && !archimedean)
2018-08-09 17:28:53 +00:00
2019-03-12 01:40:15 +00:00
#define binarytiling (ginf[geometry].flags & qBINARY)
#define archimedean (geometry == gArchimedean)
2019-07-25 10:24:02 +00:00
#define penrose (ginf[geometry].flags & qPENROSE)
2019-04-29 09:17:06 +00:00
// these geometries do not feature alternate structures for horocycles
2019-08-06 18:59:43 +00:00
#define eubinary (euclid || binarytiling || geometry == gCrystal || nil)
#define cgclass (ginf[geometry].cclass)
#define euclid (cgclass == gcEuclid)
#define sphere (cgclass == gcSphere)
#define sol (cgclass == gcSol)
2019-08-06 10:00:46 +00:00
#define nil (cgclass == gcNil)
#define hyperbolic (cgclass == gcHyperbolic)
2019-08-06 10:00:46 +00:00
#define nonisotropic (sol || nil)
#define translatable (euclid || nonisotropic)
2018-11-30 14:26:50 +00:00
#define nonorientable (ginf[geometry].flags & qNONORIENTABLE)
2019-02-25 17:13:09 +00:00
#define elliptic (ginf[geometry].flags & qELLIPTIC)
2018-11-30 14:26:50 +00:00
#define quotient (ginf[geometry].flags & qANYQ)
#define euwrap (quotient && euclid)
#define fulltorus (bounded && euclid)
#define smallbounded (ginf[geometry].flags & qSMALL)
#define bounded (ginf[geometry].flags & qBOUNDED)
2019-04-29 09:17:06 +00:00
// Dry Forest burning, heat transfer, etc. are performed on the whole universe
#define doall (bounded)
// These geometries are generated without the heptagon structure.
// 'master' holds the coordinates
#define masterless among(geometry, gEuclid, gEuclidSquare, gTorus)
2019-04-29 09:17:06 +00:00
#define sphere_narcm (sphere && !archimedean)
2018-08-17 11:29:00 +00:00
#define a4 (S3 == 4)
#define a45 (S3 == 4 && S7 == 5)
#define a46 (S3 == 4 && S7 == 6)
#define a47 (S3 == 4 && S7 == 7)
#define a457 (S3 == 4 && S7 != 6)
#define a467 (S3 == 4 && S7 >= 6)
2018-11-30 13:45:19 +00:00
#define a38 (S3 == 3 && S7 == 8)
#define sphere4 (sphere && S7 == 4)
#define stdeuc (geometry == gNormal || geometry == gEuclid || geometry == gEuclidSquare)
2018-11-30 14:26:50 +00:00
#define smallsphere (sphere_narcm && S7 < 5)
#define bigsphere (sphere_narcm && S7 == 5)
#define euclid4 (masterless && a4)
#define euclid6 (masterless && !a4)
#define S6 (S3*2)
#define MAX_S3 4
2018-11-27 15:17:20 +00:00
#define SG6 (S3==3?6:4)
#define SG3 (S3==3?3:2)
#define SG2 (S3==3?2:1)
#define GOLDBERG (variation == eVariation::goldberg)
#define IRREGULAR (variation == eVariation::irregular)
#define PURE (variation == eVariation::pure)
#define BITRUNCATED (variation == eVariation::bitruncated)
2018-08-30 00:11:43 +00:00
#define DUAL (variation == eVariation::dual)
2018-08-30 14:05:24 +00:00
#define DUALMUL (DUAL ? 2 : 1)
#define CHANGED_VARIATION (variation != ginf[geometry].default_variation)
#define STDVAR (PURE || BITRUNCATED)
#define NONSTDVAR (!STDVAR)
2019-02-17 17:28:20 +00:00
#if CAP_ARCM
2018-08-30 14:05:24 +00:00
#define VALENCE (BITRUNCATED ? 3 : archimedean ? arcm::valence() : S3)
2019-02-17 17:28:20 +00:00
#else
#define VALENCE (BITRUNCATED ? 3 : S3)
#endif
2016-08-26 09:58:03 +00:00
#define NUMWITCH 7
// achievements
#define LB_YENDOR_CHALLENGE 40
#define LB_PURE_TACTICS 41
#define NUMLEADER 82
2016-08-26 09:58:03 +00:00
#define LB_PURE_TACTICS_SHMUP 49
#define LB_PURE_TACTICS_COOP 50
2019-01-11 01:19:28 +00:00
#define LB_RACING 81
2016-08-26 09:58:03 +00:00
#if ISMOBILE || ISWEB || ISPANDORA || 1
typedef double ld;
#define LDF "%lf"
#define PLDF "lf"
#else
typedef long double ld;
#define LDF "%Lf"
#define PLDF "Lf"
#endif
typedef complex<ld> cld;
struct charstyle {
int charid;
color_t skincolor, haircolor, dresscolor, swordcolor, dresscolor2, uicolor, eyecolor;
bool lefthanded;
};
enum eStereo { sOFF, sAnaglyph, sLR, sODS };
struct videopar {
ld scale, alpha, sspeed, mspeed, yshift, camera_angle;
ld ballangle, ballproj, euclid_to_sphere, twopoint_param, stretch, binary_width, fixed_facing_dir;
int mobilecompasssize;
int radarsize; // radar for 3D geometries
2019-07-31 15:32:44 +00:00
ld radarrange;
int aurastr, aurasmoothen;
bool fixed_facing;
bool fixed_yz;
bool use_wall_radar;
int linequality;
bool full;
int graphglyph; // graphical glyphs
bool darkhepta;
int shifttarget;
int xres, yres, framelimit;
int xscr, yscr;
ld xposition, yposition;
bool grid;
int particles;
int fsize;
int flashtime;
int wallmode, monmode, axes;
bool axes3;
bool revcontrol;
int msgleft, msglimit;
bool usingGL;
int antialias;
#define AA_NOGL 1
#define AA_VERSION 2
#define AA_LINES 4
#define AA_POLY 8
#define AA_LINEWIDTH 16
#define AA_FONT 32
#define AA_MULTI 64
#define AA_MULTI16 128 // not configurable
ld linewidth;
ld multiplier_grid, multiplier_ring;
int joyvalue, joyvalue2, joypanthreshold;
ld joypanspeed;
charstyle cs;
bool samegender; // same gender for the Princess?
int language;
bool backeffects; // background particle effects
int killreduction, itemreduction, portreduction;
int steamscore;
bool drawmousecircle; // draw the circle around the mouse
bool skipstart; // skip the start menu
bool quickmouse; // quick mouse on the map
bool sloppy_3d; // make 3D faster but ugly
int timeformat; // time format used in the message log
int use_smart_range; // 0 = distance-based, 1 = model-based, 2 = model-based and generate
ld smart_range_detail;// minimum visible cell for modes 1 and 2
ld smart_range_detail_3;// minimum visible cell in 3D (for mode 2, there is no mode 1)
int cells_drawn_limit;
int cells_generated_limit; // limit on cells generated per frame
ld skiprope;
eStereo stereo_mode;
ld ipd;
ld lr_eyewidth, anaglyph_eyewidth;
ld fov;
bool consider_shader_projection;
int desaturate;
int texture_step;
bool always3; // always use the 3D engine
ld depth; // world level below the plane
ld camera; // camera level above the plane
ld wall_height, creature_scale, height_width;
eModel vpmodel;
ld lake_top, lake_bottom;
ld rock_wall_ratio;
ld human_wall_ratio;
int tc_alpha, tc_depth, tc_camera;
ld highdetail, middetail;
bool gp_autoscale_heights;
2019-06-01 17:58:07 +00:00
ld eye;
bool auto_eye;
};
extern videopar vid;
#if MAXMDIM == 3
2019-05-08 16:33:08 +00:00
#define WDIM 2
#else
2019-07-28 09:17:25 +00:00
#define WDIM ((geometry >= gBinary3 && geometry != gBinary4 && geometry != gKiteDart2 PROD(&& geometry != gProduct)) ? 3 : 2)
#endif
#define GDIM (vid.always3 ? 3 : WDIM)
2019-05-08 16:33:08 +00:00
#define DIM GDIM
2019-02-17 17:47:19 +00:00
#define MDIM (DIM+1)
2019-08-09 12:03:43 +00:00
#define self (*this)
2017-12-14 01:50:52 +00:00
extern int cellcount, heptacount;
2019-08-09 19:00:52 +00:00
extern color_t forecolor;
extern ld band_shift;
// cell information for the game
struct gcell {
#if CAP_BITFIELD
// main fields
eLand land : 8;
eWall wall : 8;
eMonster monst : 8;
eItem item : 8;
// if this is a barrier, what lands on are on the sides?
eLand barleft : 8, barright : 8;
unsigned ligon : 1; // is it sparkling with lightning?
signed
mpdist : 7,
pathdist : 8, // player distance wrt usual movement
cpdist : 8; // current/minimum player distance
unsigned
2019-04-29 01:36:28 +00:00
mondir : 8, // monster direction, for multi-tile monsters and graphics
bardir : 8, // barrier direction
stuntime : 8, // stun time left (for Palace Guards and Skeletons)
hitpoints : 7, // hitpoints left (for Palace Guards, also reused as cpid for mirrors)
monmirror : 1; // monster mirroring state for nonorientable geometries
unsigned landflags : 8; // extra flags for land
#else
eLand land;
eWall wall;
eMonster monst;
eItem item;
eLand barleft, barright;
2019-06-01 14:59:04 +00:00
bool ligon, monmirror;
signed char pathdist, cpdist, mpdist;
unsigned char mondir, bardir, stuntime, hitpoints;
unsigned char landflags;
#endif
// 'landparam' is used for:
// heat in Icy/Cocytus;
// heat in Dry (0..10);
// CR2 structure;
// hive Weird Rock color / pheromones;
// Ocean/coast depth;
// Bomberbird Egg hatch time / mine marking;
// number of Ancient Jewelry;
// improved tracking in Trollheim
union {
int32_t landpar;
unsigned int landpar_color;
float heat;
char bytes[4];
struct fieldinfo {
uint16_t fieldval;
unsigned rval : 4;
unsigned flowerdist : 4;
unsigned walldist : 4;
unsigned walldist2 : 4;
} fi;
} LHU;
2017-12-14 01:50:52 +00:00
#ifdef CELLID
int cellid;
#endif
gcell() { cellcount++;
#ifdef CELLID
cellid = cellcount;
#endif
}
2017-12-14 01:50:52 +00:00
~gcell() { cellcount--; }
};
#define landparam LHU.landpar
#define landparam_color LHU.landpar_color
#define fval LHU.fi.fieldval
2019-04-29 01:36:28 +00:00
#define NODIR 126
#define NOBARRIERS 127
#define MODFIXER (2*10090080*17)
2019-08-06 18:56:18 +00:00
#define MAX_EDGE 18
template<class T> struct walker;
2017-10-29 11:46:57 +00:00
template<class T> struct connection_table {
// Assumption: class T has a field c of type connection_table<T>.
// NOTE: since aconnection_table may be allocated with
// less than MAX_EDGE neighbors (see tailored_alloc),
// the order of fields matters.
2019-04-29 01:36:28 +00:00
T* move_table[MAX_EDGE + (MAX_EDGE + sizeof(char*) - 1) / sizeof(char*)];
2019-04-29 01:36:28 +00:00
unsigned char *spintable() { return (unsigned char*) (&move_table[full()->degree()]); }
2018-08-22 07:52:24 +00:00
T* full() { T* x = (T*) this; return (T*)((char*)this - ((char*)(&(x->c)) - (char*)x)); }
void setspin(int d, int spin, bool mirror) {
2019-04-29 01:36:28 +00:00
unsigned char& c = spintable() [d];
c = spin;
if(mirror) c |= 128;
}
// we are spin(i)-th neighbor of move[i]
2019-04-29 01:36:28 +00:00
int spin(int d) { return spintable() [d] & 127; }
bool mirror(int d) { return spintable() [d] & 128; }
int fix(int d) { return (d + MODFIXER) % full()->degree(); }
T*& modmove(int i) { return move(fix(i)); }
T*& move(int i) { return move_table[i]; }
unsigned char modspin(int i) { return spin(fix(i)); }
void fullclear() {
2019-01-28 20:41:53 +00:00
for(int i=0; i<full()->degree(); i++) move_table[i] = NULL;
}
void connect(int d0, T* c1, int d1, bool m) {
move(d0) = c1;
c1->move(d1) = full();
setspin(d0, d1, m);
c1->c.setspin(d1, d0, m);
}
void connect(int d0, walker<T> hs) {
connect(d0, hs.at, hs.spin, hs.mirrored);
}
};
// Allocate a class T with a connection_table, but
// with only `degree` connections. Also set yet
// unknown connections to NULL.
// Generating the hyperbolic world consumes lots of
// RAM, so we really need to be careful on low memory devices.
template<class T> T* tailored_alloc(int degree) {
const T* sample = (T*) &degree;
T* result;
#ifndef NO_TAILORED_ALLOC
2019-04-29 01:36:28 +00:00
int b = (char*)&sample->c.move_table[degree] + degree - (char*) sample;
result = (T*) new char[b];
new (result) T();
#else
result = new T;
#endif
2019-05-05 15:34:46 +00:00
result->type = degree;
for(int i=0; i<degree; i++) result->c.move_table[i] = NULL;
return result;
}
2019-01-18 20:04:39 +00:00
template<class T> void tailored_delete(T* x) {
x->~T();
delete[] ((char*) (x));
}
static const struct wstep_t { wstep_t() {} } wstep;
static const struct wmirror_t { wmirror_t() {}} wmirror;
static const struct rev_t { rev_t() {} } rev;
static const struct revstep_t { revstep_t() {}} revstep;
// unused for heptagons
2019-08-03 09:36:57 +00:00
inline vector<int> reverse_directions(struct heptagon *c, int i) { return {i}; }
2019-08-09 23:56:00 +00:00
int hrand(int);
template<class T> struct walker {
T *at;
int spin;
bool mirrored;
2019-08-09 12:38:55 +00:00
walker<T> (T *at = NULL, int s = 0, bool m = false) : at(at), spin(s), mirrored(m) { if(at) s = at->c.fix(s); }
walker<T>& operator += (int i) {
spin = at->c.fix(spin+(mirrored?-i:i));
return (*this);
}
walker<T>& operator -= (int i) {
spin = at->c.fix(spin-(mirrored?-i:i));
return (*this);
}
walker<T>& operator += (wmirror_t) {
mirrored = !mirrored;
return (*this);
}
walker<T>& operator += (wstep_t) {
at->cmove(spin);
int nspin = at->c.spin(spin);
if(at->c.mirror(spin)) mirrored = !mirrored;
at = at->move(spin);
spin = nspin;
return (*this);
}
walker<T>& operator += (rev_t) {
auto rd = reverse_directions(at, spin);
if(rd.size() == 1) spin = rd[0];
else spin = rd[hrand(rd.size())];
return (*this);
}
walker<T>& operator += (revstep_t) {
(*this) += rev; return (*this) += wstep;
}
bool operator != (const walker<T>& x) const {
return at != x.at || spin != x.spin || mirrored != x.mirrored;
}
bool operator == (const walker<T>& x) const {
return at == x.at && spin == x.spin && mirrored == x.mirrored;
}
bool operator < (const walker<T>& cw2) const {
return tie(at, spin, mirrored) < tie(cw2.at, cw2.spin, cw2.mirrored);
}
walker<T>& operator ++ (int) { return (*this) += 1; }
walker<T>& operator -- (int) { return (*this) -= 1; }
template<class U> walker operator + (U t) const { walker<T> w = *this; w += t; return w; }
template<class U> walker operator - (U t) const { walker<T> w = *this; w += (-t); return w; }
T*& peek() { return at->move(spin); }
T* cpeek() { return at->cmove(spin); }
bool creates() { return !peek(); }
walker<T> mirrorat(int d) { return walker<T> (at, at->c.fix(d+d - spin), !mirrored); }
};
2018-08-17 11:29:00 +00:00
2017-10-29 13:19:51 +00:00
struct cell;
// automaton state
enum hstate { hsOrigin, hsA, hsB, hsError, hsA0, hsA1, hsB0, hsB1, hsC };
struct cell *createMov(struct cell *c, int d);
struct heptagon *createStep(struct heptagon *c, int d);
2019-07-21 20:56:10 +00:00
struct cdata {
int val[4];
int bits;
};
2019-04-29 11:41:24 +00:00
// in bitruncated/irregular/Goldberg geometries, heptagons form the
// underlying regular tiling (not necessarily heptagonal); in pure
// geometries, they correspond 1-1 to tiles; in 'masterless' geometries
// heptagons are unused
2017-10-29 13:19:51 +00:00
struct heptagon {
// automaton state
hstate s : 6;
unsigned int dm4: 2;
2017-10-29 13:19:51 +00:00
// distance from the origin
short distance;
2019-04-29 11:41:24 +00:00
// note: all the 'val' values may have different meaning in other geometries
2017-10-29 13:19:51 +00:00
// emerald/wineyard generator
short emeraldval;
// fifty generator
short fiftyval;
// zebra generator (1B actually)
short zebraval;
// field id
2019-05-05 15:34:46 +00:00
int fieldval : 24;
// degree
unsigned char type : 8;
2019-04-29 11:41:24 +00:00
// data for fractal landscapes
2017-10-29 13:19:51 +00:00
short rval0, rval1;
2019-04-29 11:41:24 +00:00
// for alternate structures, cdata contains the pointer to the original
// for the main map, it contains the fractal landscape data
struct cdata *cdata;
// central cell of this underlying tiling
2017-10-29 13:19:51 +00:00
cell *c7;
// associated generator of alternate structure, for Camelot and horocycles
heptagon *alt;
// connection table
connection_table<heptagon> c;
heptagon*& move(int d) { return c.move(d); }
heptagon*& modmove(int d) { return c.modmove(d); }
2017-10-29 13:19:51 +00:00
// functions
2017-12-14 01:50:52 +00:00
heptagon () { heptacount++; }
~heptagon () { heptacount--; }
heptagon *cmove(int d) { return createStep(this, d); }
heptagon *cmodmove(int d) { return createStep(this, c.fix(d)); }
2019-05-05 15:34:46 +00:00
inline int degree() { return type; }
// prevent accidental copying
heptagon(const heptagon&) = delete;
heptagon& operator=(const heptagon&) = delete;
// do not add any fields after connection_table (see tailored_alloc)
};
2017-10-29 13:19:51 +00:00
2017-10-29 11:46:57 +00:00
struct cell : gcell {
2019-04-29 11:41:24 +00:00
char type; int degree() { return type; }
2017-10-29 11:46:57 +00:00
// wall parameter, used for remaining power of Bonfires and Thumpers
char wparam;
2019-04-29 11:41:24 +00:00
// used by celllister
int listindex;
2017-10-29 11:46:57 +00:00
2019-04-29 11:41:24 +00:00
// heptagon who owns us; for 'masterless' tilings it contains coordinates instead
2017-10-29 11:46:57 +00:00
heptagon *master;
connection_table<cell> c;
cell*& move(int d) { return c.move(d); }
cell*& modmove(int d) { return c.modmove(d); }
cell* cmove(int d) { return createMov(this, d); }
cell* cmodmove(int d) { return createMov(this, c.fix(d)); }
cell() {}
// prevent accidental copying
cell(const cell&) = delete;
heptagon& operator=(const cell&) = delete;
// do not add any fields after connection_table (see tailored_alloc)
2017-10-29 13:19:51 +00:00
};
2019-05-05 15:36:00 +00:00
/*
2018-09-27 19:52:23 +00:00
namespace arcm { int degree(heptagon *h); int valence(); }
2018-08-30 00:11:43 +00:00
2019-02-17 17:28:20 +00:00
int heptagon::degree() {
#if CAP_ARCM
if(archimedean) return arcm::degree(this); else
#endif
return S7;
2019-05-05 15:36:00 +00:00
} */
2018-08-22 09:52:35 +00:00
typedef walker<heptagon> heptspin;
typedef walker<cell> cellwalker;
static const struct cth_t { cth_t() {}} cth;
2018-09-01 11:50:56 +00:00
inline heptspin operator+ (cellwalker cw, cth_t) { return heptspin(cw.at->master, cw.spin * DUALMUL, cw.mirrored); }
inline cellwalker operator+ (heptspin hs, cth_t) { return cellwalker(hs.at->c7, hs.spin / DUALMUL, hs.mirrored); }
#define BUGCOLORS 3
2019-06-17 08:13:08 +00:00
#define big_unlock (inv::on && !chaosmode)
// land completion for shared unlocking
2019-06-17 08:13:08 +00:00
#define U5 (big_unlock ? 10 : 5)
// land completion for advanced unlocking
2019-06-17 08:13:08 +00:00
#define U10 (big_unlock ? 25 : 10)
// land completion
2019-06-17 08:13:08 +00:00
#define R10 (big_unlock ? 50 : 10)
// intermediate lands
2019-06-17 08:13:08 +00:00
#define R30 (big_unlock ? 100 : 30)
// advanced lands
2019-06-17 08:13:08 +00:00
#define R60 (big_unlock ? 200 : 60)
// advanced lands II
2019-06-17 08:13:08 +00:00
#define R90 (big_unlock ? 300 : 90)
// Crossroads IV
2019-06-17 08:13:08 +00:00
#define R200 (big_unlock ? 800 : 200)
// Crossroads V
2019-06-17 08:13:08 +00:00
#define R300 (big_unlock ? 1200 : 300)
// kill types for Dragon Chasms
2019-06-17 08:13:08 +00:00
#define R20 (big_unlock ? 30 : 20)
// kill count for Graveyard/Hive
2019-06-17 08:13:08 +00:00
#define R100 (big_unlock ? 500 : 100)
2019-04-29 11:41:24 +00:00
string XLAT(string x); // translate the sentence x
string XLATN(string x); // translate the sentence x
string cts(char c); // character to string
string its(int i); // int to string
string itsh8(int i); // int to string (8 hex digits)
2019-08-09 19:00:52 +00:00
string itsh(int i); // int to string
2018-06-22 12:47:24 +00:00
// size casted to int, to prevent warnings and actual errors caused by the unsignedness of x.size()
template<class T> int isize(const T& x) {return x.size(); }
2016-08-26 09:58:03 +00:00
// game forward declarations
namespace anticheat { extern bool tampered; }
#define HRANDMAX 0x7FFFFFFF
namespace rg {
// possible parameters e.g. for restart_game and wrongmode
static const char nothing = 0;
static const char peace = 'P';
static const char inv = 'i';
static const char chaos = 'C';
static const char tactic = 't';
static const char tour = 'T';
static const char yendor = 'y';
static const char shmup = 's';
static const char randpattern = 'r';
static const char princess = 'p';
2018-04-30 22:21:18 +00:00
static const char daily = 'd';
2018-05-15 21:26:04 +00:00
static const char daily_off = 'D';
static const char racing = 'R';
2019-05-29 00:44:30 +00:00
static const char dualmode = 'U';
// wrongmode only -- marks 'global' achievements not related to the current mode
static const char global = 'x';
// wrongmode only -- change vid.scfg.players then restart_game(rg::nothing) instead
static const char multi = 'm';
// wrongmode only -- mark achievements for special geometries/variations
static const char special_geometry = 'g';
}
2017-03-23 10:53:57 +00:00
enum orbAction { roMouse, roKeyboard, roCheck, roMouseForce, roMultiCheck, roMultiGo };
2016-08-26 09:58:03 +00:00
namespace hive { void createBugArmy(cell *c); }
namespace whirlpool { void generate(cell *wto); }
namespace whirlwind { void generate(cell *wto); }
namespace mirror {
2017-07-22 23:33:27 +00:00
static const int SPINSINGLE = 1;
static const int SPINMULTI = 2;
static const int GO = 4;
static const int ATTACK = 8;
void act(int dir, int flags);
2016-08-26 09:58:03 +00:00
}
2017-03-23 10:53:57 +00:00
struct movedir {
2019-04-29 11:41:24 +00:00
int d;
// non-negative numbers denote 'rotate +d steps and act in this direction
// negative numbers have the following meanings (warning: not used consistently):
2017-03-23 10:53:57 +00:00
#define MD_WAIT (-1)
#define MD_DROP (-2)
#define MD_UNDECIDED (-3)
#define MD_USE_ORB (-4)
2019-04-29 11:41:24 +00:00
int subdir; // for normal movement (0+): turn left or right
2017-03-23 10:53:57 +00:00
cell *tgt; // for MD_USE_ORB: target cell
};
2016-08-26 09:58:03 +00:00
void activateActiv(cell *c, bool msg);
// shmup
string csname(charstyle& cs);
void initcs(charstyle& cs);
2017-03-23 10:53:57 +00:00
2019-03-06 15:36:10 +00:00
extern bool flipplayer;
template<class T> class hookset : public map<int, function<T>> {};
typedef hookset<void()> *purehookset;
static const int NOHINT = -1;
2016-08-26 09:58:03 +00:00
2017-10-08 22:21:39 +00:00
typedef function<void()> reaction_t;
typedef function<bool()> bool_reaction_t;
2017-10-08 22:21:39 +00:00
#define HELPFUN(x) (help_delegate = x, "HELPFUN")
typedef function<int(cell*)> cellfunction;
2016-08-26 09:58:03 +00:00
// passable flags
#define SAGEMELT .1
2019-07-25 21:07:36 +00:00
#define TEMPLE_EACH (among(geometry, gHoroRec, gHoroHex, gKiteDart3) ? 3 : (sol && binarytiling) ? 6 : (WDIM == 3 && binarytiling) ? 2 : geometry == gSpace435 ? 4 : (WDIM == 3 && hyperbolic) ? 3 : 6)
2018-05-15 21:26:04 +00:00
#define PT(x, y) ((tactic::on || quotient == 2 || daily::on) ? (y) : inv::on ? min(2*(y),x) : (x))
2016-08-26 09:58:03 +00:00
#define ROCKSNAKELENGTH 50
2017-03-23 10:53:57 +00:00
#define WORMLENGTH 15
2016-08-26 09:58:03 +00:00
#define PUREHARDCORE_LEVEL 10
#define PRIZEMUL 7
#define INF 9999
#define INFD 60
2017-03-23 10:53:57 +00:00
#define PINFD 125
2018-01-25 22:52:57 +00:00
#ifndef BARLEV
2019-03-02 23:45:40 +00:00
#define BARLEV ((ISANDROID||ISIOS||ISFAKEMOBILE||getDistLimit()<7)?(getDistLimit()<4?8:9):10)
2018-01-25 22:52:57 +00:00
#endif
2016-08-26 09:58:03 +00:00
#define BUGLEV 15
// #define BARLEV 9
#define YDIST 101
2018-12-14 18:24:27 +00:00
#define MODECODES (1ll<<61)
2016-08-26 09:58:03 +00:00
2018-12-14 18:24:27 +00:00
typedef flagtype modecode_t;
2016-08-26 09:58:03 +00:00
#define GUNRANGE 3
2017-03-23 10:53:57 +00:00
// 0 = basic treasure, 1 = other item, 2 = power orb, 3 = not an item
2016-08-26 09:58:03 +00:00
#define IC_TREASURE 0
#define IC_OTHER 1
#define IC_ORB 2
2017-03-23 10:53:57 +00:00
#define IC_NAI 3
2016-08-26 09:58:03 +00:00
// loops
#define fakecellloop(ct) for(cell *ct = (cell*)1; ct; ct=NULL)
#define forCellIdAll(ct, i, cf) fakecellloop(ct) for(int i=0; i<(cf)->type && (ct=(cf)->move(i),true); i++)
2016-08-26 09:58:03 +00:00
#define forCellIdCM(ct, i, cf) fakecellloop(ct) for(int i=0; i<(cf)->type && (ct=createMov((cf),i),true); i++)
#define forCellIdEx(ct, i, cf) forCellIdAll(ct,i,cf) if(ct)
#define forCellEx(ct, cf) forCellIdEx(ct,forCellEx ## __LINE__,cf)
#define forCellCM(ct, cf) forCellIdCM(ct,forCellCM ## __LINE__,cf)
#define forCellAll(ct, cf) forCellIdCM(ct,forCellAll ## __LINE__,cf)
// canAttack/moveval flags
#define AF_NORMAL 0 // nothing special about this attack
2017-09-30 09:46:41 +00:00
#define AF_TOUGH Flag(0) // tough attacks: Hyperbugs
#define AF_MAGIC Flag(1) // magical attacks: Flash
#define AF_STAB Flag(2) // stabbing attacks (usually ignored except Hedgehogs)
#define AF_LANCE Flag(3) // lance attacks (used by Lancers)
#define AF_ONLY_ENEMY Flag(4) // only say YES if it is an enemy
#define AF_ONLY_FRIEND Flag(5) // only say YES if it is a friend
#define AF_ONLY_FBUG Flag(6) // only say YES if it is a bug_or friend
#define AF_BACK Flag(7) // backward attacks (ignored except Viziers and Flailers)
#define AF_APPROACH Flag(8) // approach attacks (ignored except Lancers)
#define AF_IGNORE_UNARMED Flag(9) // ignore the UNARMED flag
#define AF_NOSHIELD Flag(10) // ignore the shielded status
#define AF_GETPLAYER Flag(11) // check for player (replace m2 with moPlayer for player position)
#define AF_GUN Flag(12) // revolver attack
#define AF_FAST Flag(13) // fast attack
#define AF_EAT Flag(17) // eating attacks from Worm-likes
#define MF_NOATTACKS Flag(14) // don't do any attacks
#define MF_PATHDIST Flag(15) // consider pathdist for moveval
#define MF_ONLYEAGLE Flag(16) // do this only for Eagles
#define MF_MOUNT Flag(18) // don't do
#define MF_NOFRIEND Flag(19) // don't do it for friends
#define AF_SWORD Flag(20) // big sword
#define AF_SWORD_INTO Flag(21) // moving into big sword
#define AF_MSG Flag(22) // produce a message
#define AF_MUSTKILL Flag(23) // when TRUE, stunning attacks are not accepted by canAttack
2017-09-30 09:46:41 +00:00
#define AF_NEXTTURN Flag(24) // next turn -- don't count shield at power 1
#define AF_FALL Flag(25) // death by falling
#define MF_STUNNED Flag(26) // edgeunstable: ignore ladders (as stunned monsters do)
#define MF_IVY Flag(27) // edgeunstable: ignore ivy (ivy cannot climb ivy)
#define AF_HORNS Flag(28) // spear attack (always has APPROACH too)
#define AF_BULL Flag(29) // bull attack
#define AF_SIDE Flag(30) // side attack
2018-01-02 10:15:42 +00:00
#define AF_CRUSH Flag(31) // Crusher's delayed attack
2017-03-23 10:53:57 +00:00
2017-07-22 23:33:27 +00:00
#if CAP_SDL
2016-08-26 09:58:03 +00:00
2017-07-22 23:33:27 +00:00
#if CAP_PNG
2016-08-26 09:58:03 +00:00
#include "savepng.h"
#define IMAGEEXT ".png"
void IMAGESAVE(SDL_Surface *s, const char *fname);
2017-07-22 23:33:27 +00:00
#else
#define IMAGEEXT ".bmp"
#define IMAGESAVE SDL_SaveBMP
#endif
2016-08-26 09:58:03 +00:00
#endif
// for some reason I need this to compile under OSX
2017-07-22 23:33:27 +00:00
#if ISMAC
2016-08-26 09:58:03 +00:00
extern "C" { void *_Unwind_Resume = 0; }
#endif
template<class T> struct dynamicval {
T& where;
T backup;
dynamicval(T& wh, T val) : where(wh) { backup = wh; wh = val; }
2017-07-04 13:38:33 +00:00
dynamicval(T& wh) : where(wh) { backup = wh; }
2016-08-26 09:58:03 +00:00
~dynamicval() { where = backup; }
};
static const int MAXPLAYER = 7;
#define DEFAULTCONTROL (multi::players == 1 && !shmup::on && !multi::alwaysuse && !(rug::rugged && rug::renderonce))
2017-05-31 16:33:50 +00:00
#define DEFAULTNOR(sym) (DEFAULTCONTROL || multi::notremapped(sym))
2017-03-23 10:53:57 +00:00
2017-07-22 23:33:27 +00:00
#define CAP_MENUSCALING (ISPANDORA || ISMOBILE)
2017-03-23 10:53:57 +00:00
2017-07-22 23:33:27 +00:00
#if CAP_MENUSCALING
#define displayfrZ dialog::zoom::displayfr
#define displayfrZH dialog::zoom::displayfr_highlight
2017-03-23 10:53:57 +00:00
#else
#define displayfrZ displayfr
#define displayfrZH dialog::zoom::displayfr_highlight
2017-03-23 10:53:57 +00:00
#endif
// just in case if I change my mind about when Orbs lose their power
#define ORBBASE 0
#define mmscale(V, x) (mmspatial ? (ivoryz ? mzscale(V,x) : mscale(V, x)) : (V))
#define SHADOW_WALL 0x60
#define SHADOW_SL 0x18
#define SHADOW_MON 0x30
// ranks:
2018-08-28 12:27:23 +00:00
enum class PPR {
2019-05-28 23:06:01 +00:00
ZERO, EUCLIDEAN_SKY, OUTCIRCLE, MOVESTAR,
2018-08-28 12:27:23 +00:00
MINUSINF,
BELOWBOTTOMm,
BELOWBOTTOM,
BELOWBOTTOMp,
BELOWBOTTOM_FALLANIM,
LAKEBOTTOM, HELLSPIKE,
INLAKEWALLm, INLAKEWALL, INLAKEWALLp,
INLAKEWALL_FALLANIM,
SUBLAKELEV, LAKELEV, BOATLEV, BOATLEV2, BOATLEV3,
LAKEWALLm, LAKEWALL, LAKEWALLp,
LAKEWALL_FALLANIM,
FLOOR_TOWER,
FLOOR,
FLOOR_DRAGON,
FLOORa, FLOORb, FLOORc, FLOORd,
LIZEYE,
BFLOOR,
GFLOORa, GFLOORb, GFLOORc,
WALLSHADOW,
STRUCT0, STRUCT1, STRUCT2, STRUCT3,
THORNS, WALL,
REDWALLm, REDWALLs, REDWALLp, REDWALL,
REDWALLm2, REDWALLs2, REDWALLp2, REDWALLt2,
REDWALLm3, REDWALLs3, REDWALLp3, REDWALLt3,
HEPTAMARK,
ITEM_BELOW,
ITEM, ITEMa, ITEMb,
BIGSTATUE,
WALL3m, WALL3s, WALL3p, WALL3, WALL3A,
// WALL3m, WALL3s, WALL3p, WALL3, WALL3A,
HIDDEN, GIANTSHADOW,
TENTACLE0, TENTACLE1,
ONTENTACLE, ONTENTACLE_EYES, ONTENTACLE_EYES2,
MONSTER_SHADOW,
MONSTER_FOOT, MONSTER_LEG, MONSTER_GROIN,
MONSTER_SUBWPN, MONSTER_WPN,
MONSTER_BODY, MONSTER_ARMOR0, MONSTER_ARMOR1,
MONSTER_CLOAK, MONSTER_NECK,
MONSTER_HEAD, MONSTER_FACE, MONSTER_EYE0, MONSTER_EYE1,
MONSTER_HAIR, MONSTER_HAT0, MONSTER_HAT1,
MONSTER_HOODCLOAK1, MONSTER_HOODCLOAK2,
STUNSTARS,
CARRIED, CARRIEDa, CARRIEDb,
2019-05-20 11:40:56 +00:00
PARTICLE, SWORDMARK, MAGICSWORD, MISSILE, SKY,
2018-08-28 12:27:23 +00:00
MINEMARK, ARROW,
MOBILE_ARROW,
LINE,
// in depth tested models transparent surfaces need to be depth sorted by HyperRogue
// and set to PPR::TRANSPARENT_* to draw them after all the opaque ones
TRANSPARENT_LAKE, TRANSPARENT_SHADOW, TRANSPARENT_WALL,
// no depth testing for SUPERLINE and above
SUPERLINE, TEXT, CIRCLE,
2018-08-28 12:27:23 +00:00
MAX,
DEFAULT = -1
2017-03-23 10:53:57 +00:00
};
2018-09-01 11:50:56 +00:00
inline PPR operator + (PPR x, int y) { return PPR(int(x) + y); }
inline PPR operator - (PPR x, int y) { return PPR(int(x) - y); }
inline int operator - (PPR x, PPR y) { return int(x) - int(y); }
2018-08-28 12:27:23 +00:00
2017-03-23 10:53:57 +00:00
#define OUTLINE_NONE 0x000000FF
#define OUTLINE_FRIEND 0x00FF00FF
#define OUTLINE_ENEMY 0xFF0000FF
#define OUTLINE_TREASURE 0xFFFF00FF
#define OUTLINE_ORB 0xFF8000FF
#define OUTLINE_OTHER 0xFFFFFFFF
#define OUTLINE_DEAD 0x800000FF
#define OUTLINE_TRANS 0
2017-07-04 13:38:33 +00:00
#define OUTLINE_DEFAULT ((bordcolor << 8) + 0xFF)
#define OUTLINE_FORE ((forecolor << 8) + 0xFF)
#define OUTLINE_BACK ((backcolor << 8) + 0xFF)
2017-03-23 10:53:57 +00:00
inline string pick123() { return cts('1' + rand() % 3); }
inline string pick12() { return cts('1' + rand() % 2); }
extern int detaillevel;
extern bool quitmainloop;
enum eGravity { gsNormal, gsLevitation, gsAnti };
extern eGravity gravity_state, last_gravity_state;
2017-03-23 10:53:57 +00:00
#define IFM(x) (mousing?"":x)
extern bool viewdists;
void preventbarriers(cell *c);
bool passable_for(eMonster m, cell *w, cell *from, flagtype extra);
void beastcrash(cell *c, cell *beast);
int angledist(int t, int d1, int d2);
int angledist(cell *c, int d1, int d2);
void setcameraangle(bool b);
#define MODELCOUNT ((int) mdGUARD)
void drawShape(pair<ld,ld>* coords, int qty, color_t color);
2017-03-23 10:53:57 +00:00
#define pmodel (vid.vpmodel)
2019-04-04 15:23:53 +00:00
string current_proj_name();
2017-03-23 10:53:57 +00:00
2019-03-30 16:45:56 +00:00
inline bool mdAzimuthalEqui() { return among(pmodel, mdEquidistant, mdEquiarea, mdEquivolume); }
2018-03-26 17:06:47 +00:00
2019-03-30 16:45:56 +00:00
inline bool mdBandAny() { return among(pmodel, mdBand, mdBandEquidistant, mdBandEquiarea, mdSinusoidal); }
2017-11-13 10:26:21 +00:00
color_t darkena(color_t c, int lev, int a);
2017-03-23 10:53:57 +00:00
#define SHSIZE 16
2019-08-09 20:07:03 +00:00
namespace anims { void animate_parameter(ld &x, string f, const reaction_t& r); }
2017-03-23 10:53:57 +00:00
2019-08-09 19:00:52 +00:00
extern bool timerghost;
2019-08-09 21:08:42 +00:00
extern bool autocheat;
extern int cheater;
2019-08-09 19:00:52 +00:00
2017-03-23 10:53:57 +00:00
namespace arg {
2017-07-22 23:33:27 +00:00
#if CAP_COMMANDLINE
2017-03-23 10:53:57 +00:00
2018-02-26 12:14:20 +00:00
void lshift();
2019-04-23 10:02:58 +00:00
void unshift();
2017-03-23 10:53:57 +00:00
2018-02-26 12:14:20 +00:00
void shift();
2017-03-23 10:53:57 +00:00
2018-02-26 12:14:20 +00:00
const string& args();
const char* argcs();
2018-02-26 12:14:20 +00:00
int argi();
ld argf();
bool argis(const string& s);
2019-04-22 20:59:37 +00:00
bool nomore();
unsigned arghex();
2019-02-17 17:43:39 +00:00
inline void shift_arg_formula(ld& x, const reaction_t& r = reaction_t()) { shift(); x = argf();
#if CAP_ANIMATIONS
anims::animate_parameter(x, args(), r);
#endif
}
2017-03-23 10:53:57 +00:00
2018-02-26 12:14:20 +00:00
void init(int _argc, char **_argv);
2017-03-23 10:53:57 +00:00
void launch_dialog(const reaction_t& r = reaction_t());
2017-10-29 11:46:57 +00:00
extern int curphase;
2017-03-23 10:53:57 +00:00
2018-02-26 12:14:20 +00:00
void phaseerror(int x);
2017-03-23 10:53:57 +00:00
// returned values: 0 = ok, 1 = not recognized, 2 = shift phase
int readCommon();
int readLocal();
// an useful macro
#define PHASE(x) { if(arg::curphase > x) arg::phaseerror(x); else if(arg::curphase < x) return 2; }
#define PHASEFROM(x) { if(arg::curphase < x) return 2; }
2018-07-21 16:03:53 +00:00
inline void cheat() { autocheat = true; cheater++; timerghost = false; }
#define TOGGLE(x, param, act) \
else if(args()[0] == '-' && args()[1] == x && !args()[2]) { PHASEFROM(2); showstartmenu = false; act; } \
else if(args()[0] == '-' && args()[1] == x && args()[2] == '1') { PHASEFROM(2); showstartmenu = false; if(!param) act; } \
else if(args()[0] == '-' && args()[1] == x && args()[2] == '0') { PHASEFROM(2); showstartmenu = false; if(param) act; }
2017-03-23 10:53:57 +00:00
void read(int phase);
eLand readland(const string& ss);
eItem readItem(const string& ss);
eMonster readMonster(const string& ss);
2017-03-23 10:53:57 +00:00
#endif
}
2017-07-22 23:33:27 +00:00
#if CAP_TOUR
2017-04-08 15:18:29 +00:00
namespace tour {
extern bool on;
extern string tourhelp;
extern string slidecommand;
2017-07-04 13:38:33 +00:00
extern int currentslide;
2017-04-08 15:18:29 +00:00
enum presmode {
pmStartAll = 0,
pmStart = 1, pmFrame = 2, pmStop = 3, pmKey = 4, pmRestart = 5,
2017-07-10 18:47:38 +00:00
pmAfterFrame = 6,
pmGeometry = 11, pmGeometryReset = 13, pmGeometryStart = 15
};
2017-06-18 16:51:46 +00:00
void setCanvas(presmode mode, char canv);
void presentation(presmode mode);
void checkGoodLand(eLand l);
2017-04-08 15:18:29 +00:00
int getid();
extern function<eLand(eLand)> getNext;
extern function<bool(eLand)> quickfind;
extern function<bool(eLand)> showland;
2017-04-08 15:18:29 +00:00
void start();
2017-06-18 16:51:46 +00:00
struct slide {
const char *name; int unused_id; int flags; const char *help;
function<void(presmode mode)> action;
} ;
extern slide *slides;
extern slide default_slides[];
static const int LEGAL_NONE=0;
static const int LEGAL_UNLIMITED=1;
static const int LEGAL_HYPERBOLIC=2;
static const int LEGAL_ANY=3;
static const int LEGAL_NONEUC=4;
static const int QUICKSKIP=8;
static const int FINALSLIDE=16;
2017-07-04 13:38:33 +00:00
static const int QUICKGEO=32;
static const int SIDESCREEN = 64;
2018-04-22 09:10:19 +00:00
static const int USE_SLIDE_NAME = 128;
2017-06-18 16:51:46 +00:00
extern slide slideHypersian;
extern slide slideExpansion;
2017-07-04 13:38:33 +00:00
namespace ss {
void showMenu();
void list(slide*);
}
extern hookset<void(int)> *hooks_slide;
2017-04-08 15:18:29 +00:00
};
2019-02-17 17:50:56 +00:00
#else
namespace tour {
static const always_false on;
}
2017-04-08 15:18:29 +00:00
#endif
2017-07-12 17:50:39 +00:00
namespace sm {
static const int NORMAL = 1;
static const int MISSION = 2;
static const int HELP = 4;
static const int MAP = 8;
static const int DRAW = 16;
static const int NUMBER = 32;
static const int SHMUPCONFIG = 64;
static const int OVERVIEW = 128;
static const int SIDE = 256;
static const int DOTOUR = 512;
static const int CENTER = 1024;
2017-07-22 23:33:27 +00:00
static const int ZOOMABLE = 4096;
2017-11-06 20:18:40 +00:00
static const int TORUSCONFIG = 8192;
static const int MAYDARK = 16384;
2017-12-14 01:50:52 +00:00
static const int DIALOG_STRICT_X = 32768; // do not interpret dialog clicks outside of the X region
2018-09-13 18:38:06 +00:00
static const int EXPANSION = (1<<16);
static const int HEXEDIT = (1<<17);
2017-07-12 17:50:39 +00:00
};
2017-07-10 18:47:38 +00:00
namespace linepatterns {
enum ePattern {
patPalacelike,
patPalace,
patZebraTriangles,
patZebraLines,
2018-09-21 17:51:13 +00:00
patTriTree,
patTriRings,
patHepta,
patRhomb,
patTree,
patAltTree,
patVine,
patPower,
patNormal,
patTrihepta,
2017-07-04 13:38:33 +00:00
patBigTriangles,
patBigRings,
2018-09-21 17:51:13 +00:00
patHorocycles,
patTriOther,
patDual,
patMeridians,
patParallels,
patCircles,
patRadii
};
void clearAll();
void setColor(ePattern id, color_t col);
void drawAll();
2017-07-10 18:47:38 +00:00
void showMenu();
void switchAlpha(ePattern id, color_t col);
2018-09-21 17:51:13 +00:00
struct linepattern {
int id;
const char *lpname;
color_t color;
ld multiplier;
2018-09-21 17:51:13 +00:00
};
extern vector<linepattern> patterns;
2018-11-08 21:34:23 +00:00
extern ld width;
};
static const int DISTANCE_UNKNOWN = 127;
2017-06-18 16:51:46 +00:00
#define SETMOUSEKEY 5000
extern char mousekey;
extern char newmousekey;
void displaymm(char c, int x, int y, int rad, int size, const string& title, int align);
2017-07-10 18:47:38 +00:00
#include <functional>
template<class T, class U> int addHook(hookset<T>*& m, int prio, const U& hook) {
if(!m) m = new hookset<T> ();
2017-07-16 21:00:55 +00:00
while(m->count(prio)) {
prio++;
}
2017-07-10 18:47:38 +00:00
(*m)[prio] = hook;
return 0;
}
template<class T, class... U> void callhooks(hookset<T> *h, U... args) {
if(h) for(auto& p: *h) p.second(args...);
}
template<class T, class V, class... U> V callhandlers(V zero, hookset<T> *h, U&... args) {
2017-07-10 18:47:38 +00:00
if(h) for(auto& p: *h) {
auto z = p.second(args...);
if(z != zero) return z;
}
return zero;
}
struct msginfo {
int stamp;
time_t rtstamp;
int gtstamp;
int turnstamp;
2017-07-10 18:47:38 +00:00
char flashout;
char spamtype;
int quantity;
string msg;
};
int watercolor(int phase);
bool doHighlight();
void buildHelpText();
void buildCredits();
2017-07-10 18:47:38 +00:00
void setAppropriateOverview();
bool quitsaves();
2017-10-29 11:46:57 +00:00
extern const char* COLORBAR;
2017-07-10 18:47:38 +00:00
#define GLERR(call) glError(call, __FILE__, __LINE__)
2018-11-08 15:21:33 +00:00
struct colortable: vector<color_t> {
color_t& operator [] (int i) { i %= size(); if(i<0) i += size(); return ((vector<color_t>&)(*this)) [i]; }
const color_t& operator [] (int i) const { i %= size(); if(i<0) i += size(); return ((vector<color_t>&)(*this)) [i]; }
colortable(std::initializer_list<color_t> v) : vector(v) {}
colortable() : vector({0}) {}
};
2017-07-10 18:47:38 +00:00
#define SHMUPTITLE "shoot'em up mode"
// check for a plain number key
#define NUMBERKEY (interpret_as_direction(sym, uni) ? 0 : uni)
#define DKEY (get_direction_key(sym, uni))
#define DIRECTIONKEY (interpret_as_direction(sym, uni) ? uni : 0)
2017-07-12 16:03:53 +00:00
namespace scores { void load(); }
2017-07-22 23:33:27 +00:00
#if ISMOBILE==1
2017-07-12 16:03:53 +00:00
namespace leader { void showMenu(); void handleKey(int sym, int uni); }
#endif
2017-07-16 21:00:55 +00:00
namespace mirror {
2017-08-06 12:50:16 +00:00
cellwalker reflect(const cellwalker& cw);
2017-07-16 21:00:55 +00:00
}
struct hint {
time_t last;
function<bool()> usable;
function<void()> display;
function<void()> action;
};
extern hint hints[];
int counthints();
2017-07-22 23:33:27 +00:00
int textwidth(int siz, const string &str);
#if CAP_GL
int gl_width(int size, const char *s);
#endif
#ifdef ISMOBILE
extern int andmode;
extern bool longclick;
extern bool useRangedOrb;
2017-07-22 23:33:27 +00:00
#endif
2017-08-06 12:50:16 +00:00
2017-10-29 11:46:57 +00:00
static inline bool orbProtection(eItem it) { return false; } // not implemented
2019-02-17 17:33:15 +00:00
#if CAP_FIELD
namespace windmap {
void create();
2017-09-30 09:46:41 +00:00
static const int NOWINDBELOW = 8;
static const int NOWINDFROM = 120;
int getId(cell *c);
2017-09-30 09:46:41 +00:00
int at(cell *c);
}
2019-02-17 17:33:15 +00:00
#endif
int getgametime();
string getgametime_s(int timespent = getgametime());
extern int stampbase;
2017-10-09 09:46:49 +00:00
2017-10-29 11:46:57 +00:00
#ifndef GL
typedef float GLfloat;
#endif
2019-02-22 19:58:40 +00:00
typedef array<GLfloat, 2> glvec2;
2018-02-11 18:08:17 +00:00
typedef array<GLfloat, 3> glvec3;
typedef array<GLfloat, 4> glvec4;
#if MAXMDIM == 4
#define SHDIM 4
2019-02-22 19:58:40 +00:00
typedef glvec4 glvertex;
#else
#define SHDIM 3
typedef glvec3 glvertex;
#endif
2018-02-11 18:08:17 +00:00
2017-10-29 13:19:51 +00:00
extern int emeraldtable[100][7];
2018-03-24 11:59:01 +00:00
// extern cell *cwpeek(cellwalker cw, int dir);
2017-10-29 13:19:51 +00:00
const eLand NOWALLSEP = laNone;
const eLand NOWALLSEP_USED = laWhirlpool;
#define HAUNTED_RADIUS getDistLimit()
#define UNKNOWN 65535
#define GRAIL_FOUND 0x4000
#define GRAIL_RADIUS_MASK 0x3FFF
2019-08-09 21:24:33 +00:00
extern vector<cell*> dcal;
2017-10-29 13:19:51 +00:00
// list all cells in distance at most maxdist, or until when maxcount cells are reached
2018-06-28 11:35:03 +00:00
struct manual_celllister {
2017-10-29 13:19:51 +00:00
vector<cell*> lst;
vector<int> tmps;
2018-06-28 11:35:03 +00:00
bool listed(cell *c) {
return c->listindex >= 0 && c->listindex < isize(lst) && lst[c->listindex] == c;
}
bool add(cell *c) {
if(listed(c)) return false;
tmps.push_back(c->listindex);
c->listindex = isize(lst);
2018-06-28 11:35:03 +00:00
lst.push_back(c);
return true;
}
2018-06-28 11:35:03 +00:00
~manual_celllister() {
for(int i=0; i<isize(lst); i++) lst[i]->listindex = tmps[i];
2018-06-28 11:35:03 +00:00
}
};
2018-06-28 11:35:03 +00:00
struct celllister : manual_celllister {
vector<int> dists;
void add_at(cell *c, int d) {
if(add(c)) dists.push_back(d);
2017-10-29 13:19:51 +00:00
}
celllister(cell *orig, int maxdist, int maxcount, cell *breakon) {
2018-06-28 11:35:03 +00:00
add_at(orig, 0);
2017-10-29 13:19:51 +00:00
cell *last = orig;
2018-06-22 12:47:24 +00:00
for(int i=0; i<isize(lst); i++) {
2017-10-29 13:19:51 +00:00
cell *c = lst[i];
if(maxdist) forCellCM(c2, c) {
2018-06-28 11:35:03 +00:00
add_at(c2, dists[i]+1);
2017-10-29 13:19:51 +00:00
if(c2 == breakon) return;
}
if(c == last) {
2018-06-22 12:47:24 +00:00
if(isize(lst) >= maxcount || dists[i]+1 == maxdist) break;
last = lst[isize(lst)-1];
2017-10-29 13:19:51 +00:00
}
}
}
int getdist(cell *c) { return dists[c->listindex]; }
2017-10-29 13:19:51 +00:00
};
2019-02-17 17:33:15 +00:00
#if CAP_FIELD
2017-10-29 13:19:51 +00:00
#define currfp fieldpattern::getcurrfp()
namespace fieldpattern {
struct fpattern& getcurrfp();
}
int currfp_gmul(int a, int b);
int currfp_inverses(int i);
int currfp_distwall(int i);
2019-03-15 11:47:08 +00:00
int currfp_n();
int currfp_get_P();
int currfp_get_R();
int currfp_get_X();
2019-02-17 17:33:15 +00:00
#endif
2017-10-29 13:19:51 +00:00
2017-10-30 11:05:36 +00:00
void runGeometryExperiments();
// z to close to this limit => do not draw
#define BEHIND_LIMIT 1e-6
2017-11-03 18:31:42 +00:00
2018-04-13 11:08:41 +00:00
namespace lv {
static const flagtype appears_in_geom_exp = 1;
static const flagtype display_error_message = 2;
static const flagtype appears_in_full = 4;
static const flagtype appears_in_ptm = 8;
static const flagtype display_in_help = 16;
2018-05-01 17:34:57 +00:00
static const flagtype one_and_half = 32;
2018-04-13 11:08:41 +00:00
};
struct land_validity_t {
int quality_level; // 0 (dont show), 1 (1/2), 2 (ok), 3(1!)
flagtype flags;
string msg;
};
namespace fieldpattern {
pair<int, bool> fieldval(cell *c);
}
int emeraldval(cell *c);
2017-12-05 18:43:45 +00:00
int inpair(cell *c, int colorpair);
int snake_pair(cell *c);
2018-11-08 15:21:33 +00:00
extern colortable nestcolors;
2017-12-09 01:20:10 +00:00
unsigned char& part(color_t& col, int i);
2017-12-09 19:02:56 +00:00
int pattern_threecolor(cell *c);
int fiftyval200(cell *c);
2019-04-29 01:34:21 +00:00
bool isWall3(cell *c, color_t& wcol);
2017-12-17 23:24:56 +00:00
extern string bitruncnames[5];
2017-12-27 13:09:39 +00:00
extern bool need_mouseh;
void clear_euland(eLand first);
2017-12-30 14:12:15 +00:00
extern eMonster passive_switch;
bool cannotPickupItem(cell *c, bool telekinesis);
bool canPickupItemWithMagnetism(cell *c, cell *from);
void pickupMovedItems(cell *c);
2018-01-04 20:24:13 +00:00
eMonster genRuinMonster(cell *c);
2018-01-26 00:45:49 +00:00
template<class T, class U> void eliminate_if(vector<T>& data, U pred) {
2018-06-22 12:47:24 +00:00
for(int i=0; i<isize(data); i++)
2018-01-26 00:45:49 +00:00
if(pred(data[i]))
data[i] = data.back(), data.pop_back(), i--;
}
2018-02-03 19:04:47 +00:00
#if CAP_ORIENTATION
transmatrix getOrientation();
#endif
namespace elec { extern int lightningfast; }
2019-05-12 23:57:40 +00:00
#define DF_INIT 1 // always display these
#define DF_MSG 2 // always display these
#define DF_WARN 4 // always display these
#define DF_ERROR 8 // always display these
#define DF_STEAM 16
#define DF_GRAPH 32
#define DF_TURN 64
#define DF_FIELD 128
#define DF_GEOM 256
#define DF_MEMORY 512
#define DF_TIME 1024 // a flag to display timestamps
#define DF_GP 2048
#define DF_POLY 4096
2019-05-21 22:04:29 +00:00
#define DF_LOG 8192
#define DF_KEYS "imwesxufgbtopl"
#if ISANDROID
#define DEBB(r,x)
2019-05-12 23:57:40 +00:00
#define DEBB0(r,x)
#define DEBBI(r,x)
#else
2019-05-12 23:57:40 +00:00
#define DEBB(r,x) { if(debugflags & (r)) { println_log x; } }
#define DEBB0(r,x) { if(debugflags & (r)) { print_log x; } }
#define DEBBI(r,x) { if(debugflags & (r)) { println_log x; } } indenter_finish _debbi(debugflags & (r));
#endif
2019-03-01 17:53:32 +00:00
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; }
2018-02-11 18:08:17 +00:00
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; }
template<class T> array<T, 2> make_array(T a, T b) { array<T,2> x; x[0] = a; x[1] = b; return x; }
2018-04-05 22:31:25 +00:00
struct supersaver {
string name;
virtual string save() = 0;
virtual void load(const string& s) = 0;
virtual bool dosave() = 0;
virtual void reset() = 0;
virtual ~supersaver() {};
2018-04-05 22:31:25 +00:00
};
typedef vector<shared_ptr<supersaver>> saverlist;
extern saverlist savers;
#if CAP_CONFIG
template<class T> struct dsaver : supersaver {
T& val;
T dft;
bool dosave() { return val != dft; }
void reset() { val = dft; }
dsaver(T& val) : val(val) { }
};
template<class T> struct saver : dsaver<T> {};
template<class T, class U, class V> void addsaver(T& i, U name, V dft) {
auto s = make_shared<saver<T>> (i);
s->dft = dft;
s->name = name;
savers.push_back(s);
}
template<class T> void addsaver(T& i, string name) {
addsaver(i, name, i);
}
template<class T> struct saverenum : supersaver {
T& val;
T dft;
bool dosave() { return val != dft; }
void reset() { val = dft; }
saverenum<T>(T& v) : val(v) { }
string save() { return its(int(val)); }
2018-04-05 22:31:25 +00:00
void load(const string& s) { val = (T) atoi(s.c_str()); }
};
template<class T, class U> void addsaverenum(T& i, U name, T dft) {
auto s = make_shared<saverenum<T>> (i);
s->dft = dft;
s->name = name;
savers.push_back(s);
}
template<class T, class U> void addsaverenum(T& i, U name) {
addsaverenum(i, name, i);
}
template<> struct saver<int> : dsaver<int> {
saver<int>(int& val) : dsaver<int>(val) { }
string save() { return its(val); }
void load(const string& s) { val = atoi(s.c_str()); }
};
template<> struct saver<char> : dsaver<char> {
saver<char>(char& val) : dsaver<char>(val) { }
string save() { return its(val); }
void load(const string& s) { val = atoi(s.c_str()); }
};
template<> struct saver<bool> : dsaver<bool> {
saver<bool>(bool& val) : dsaver<bool>(val) { }
string save() { return val ? "yes" : "no"; }
2018-06-22 12:47:24 +00:00
void load(const string& s) { val = isize(s) && s[0] == 'y'; }
2018-04-05 22:31:25 +00:00
};
template<> struct saver<unsigned> : dsaver<unsigned> {
saver<unsigned>(unsigned& val) : dsaver<unsigned>(val) { }
string save() { return itsh(val); }
void load(const string& s) { val = (unsigned) strtoll(s.c_str(), NULL, 16); }
};
template<> struct saver<string> : dsaver<string> {
saver<string>(string& val) : dsaver<string>(val) { }
string save() { return val; }
void load(const string& s) { val = s; }
};
2019-08-09 19:00:52 +00:00
string fts(ld val, int prec);
string itsh(int x);
2018-04-05 22:31:25 +00:00
template<> struct saver<ld> : dsaver<ld> {
saver<ld>(ld& val) : dsaver<ld>(val) { }
string save() { return fts(val, 10); }
2018-04-05 22:31:25 +00:00
void load(const string& s) {
if(s == "0.0000000000e+000") ; // ignore!
else val = atof(s.c_str());
}
};
#endif
2018-04-30 22:21:18 +00:00
namespace daily {
extern bool on;
extern int daily_id;
void setup();
void split();
void gifts();
2018-05-15 21:26:04 +00:00
void turnoff();
void showMenu();
int find_daily_lbid(int id);
2018-05-20 13:16:21 +00:00
bool prevent_spawn_treasure_on(cell *c);
2018-05-26 23:06:12 +00:00
void handleQuit(int sev);
void uploadscore(bool really_final);
2018-04-30 22:21:18 +00:00
}
2018-05-04 00:40:46 +00:00
namespace torusconfig {
extern int sdx, sdy;
2018-12-14 18:24:27 +00:00
enum eTorusMode : char {
2018-05-04 00:40:46 +00:00
tmSingleHex,
tmSingle,
tmSlantedHex,
tmStraight,
tmStraightHex,
tmKlein,
tmKleinHex,
tmCylinder,
tmCylinderHex,
tmMobius,
tmMobiusHex,
2018-05-04 00:40:46 +00:00
};
extern eTorusMode torus_mode;
extern void activate();
struct torusmode_info {
string name;
flagtype flags;
};
extern vector<torusmode_info> tmodes;
enum : flagtype {
TF_SINGLE = 1,
TF_SIMPLE = 2,
TF_WEIRD = 4,
TF_HEX = 16,
TF_SQUARE = 32,
TF_CYL = 64,
TF_KLEIN = 256,
};
flagtype tmflags();
2018-05-04 00:40:46 +00:00
}
2018-05-04 10:20:50 +00:00
struct plainshape;
void clear_plainshape(plainshape& gsh);
namespace gp {
void clear_plainshapes();
plainshape& get_plainshape();
}
2018-05-07 18:13:56 +00:00
extern bool just_gmatrix;
2018-05-15 21:23:12 +00:00
bool haveLeaderboard(int id);
int get_currentscore(int id);
void set_priority_board(int id);
int get_sync_status();
bool score_loaded(int id);
int score_default(int id);
void handle_event(SDL_Event& ev);
void generate_floorshapes();
#define SIDE_SLEV 0
2019-05-08 16:33:08 +00:00
#define SIDE_WTS3 3
#define SIDE_WALL 4
#define SIDE_LAKE 5
#define SIDE_LTOB 6
#define SIDE_BTOI 7
2019-05-20 11:40:56 +00:00
#define SIDE_SKY 8
2019-05-24 23:36:49 +00:00
#define SIDE_HIGH 9
#define SIDE_HIGH2 10
#define SIDEPARS 11
void initShape(int sg, int id);
extern int usershape_changes;
2019-06-28 07:44:40 +00:00
#define BADMODEL 0
2019-07-25 10:18:13 +00:00
extern vector<ld> equal_weights;
#define RING(i) for(double i=0; i<=cgi.S84+1e-6; i+=SD3 * pow(.5, vid.linequality))
#define REVRING(i) for(double i=cgi.S84; i>=-1e-6; i-=SD3 * pow(.5, vid.linequality))
#define PRING(i) for(double i=0; i<=cgi.S84+1e-6; i+= pow(.5, vid.linequality))
#define REVPRING(i) for(double i=cgi.S84; i>=-1e-6; i-=pow(.5, vid.linequality))
2018-08-09 17:28:53 +00:00
2018-12-21 13:43:38 +00:00
#define ONEMPTY if(d == 7 && passable(c, NULL, 0) && !safety && !reptilecheat)
template <class T> void texture_order(const T& f) {
const int STEP = vid.texture_step;
const ld STEP2 = STEP;
for(int y=0; y<STEP; y++)
for(int x=0; x<STEP; x++) {
ld x0 = x / STEP2;
ld y0 = y / STEP2;
ld b = 1 / STEP2;
if(x+y < STEP) {
f(x0, y0); f(x0+b, y0); f(x0, y0+b);
}
if(x+y <= STEP && x && y) {
f(x0, y0); f(x0-b, y0); f(x0, y0-b);
}
}
}
2019-03-11 17:46:34 +00:00
static const color_t NOCOLOR = 0;
2019-08-09 19:00:52 +00:00
typedef pair<cell**, bool> euc_pointer;
static const int max_vec = (1<<14);
extern bool needConfirmationEvenIfSaved();
2019-07-31 11:21:41 +00:00
2019-08-09 13:07:43 +00:00
}
2019-08-09 19:00:52 +00:00
#define IS(z) = z
2019-08-09 13:07:43 +00:00
#include "autohdr.h"
2019-08-09 19:00:52 +00:00
#undef IS
#define IS(z)
2019-08-09 23:15:41 +00:00
#define EX
2019-08-09 19:00:52 +00:00
namespace hr {
inline bool movepcto(const movedir& md) { return movepcto(md.d, md.subdir); }
}