// This is the main header file of HyperRogue. Mostly everything is dumped here. // It is quite chaotic. // version numbers #define VER "11.0g" #define VERNUM 11007 #define VERNUM_HEX 0xA607 #include #include "hyper_function.h" namespace hr { struct always_false { operator bool() const { return false; }; void operator = (bool b) const {}; }; template void ignore(T&&) { // placate GCC's overzealous -Wunused-result } // 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; using std::abs; using std::isfinite; using std::isnan; using std::isinf; 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 // genus (in grammar) #define GEN_M 0 #define GEN_F 1 #define GEN_N 2 #define GEN_O 3 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 #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) #define binarytiling (geometry == gBinaryTiling || geometry == gBinary3) #define archimedean (geometry == gArchimedean) #define eubinary (euclid || binarytiling || geometry == gCrystal) #define cgclass (ginf[geometry].cclass) #define euclid (cgclass == gcEuclid) #define sphere (cgclass == gcSphere) #define hyperbolic (cgclass == gcHyperbolic) #define nonorientable (ginf[geometry].flags & qNONORIENTABLE) #define elliptic (ginf[geometry].flags & qELLIPTIC) #define quotient (ginf[geometry].flags & qANYQ) #define euwrap (quotient && euclid) #define fulltorus (bounded && euclid) #define doall (bounded) #define smallbounded (ginf[geometry].flags & qSMALL) #define bounded (ginf[geometry].flags & qBOUNDED) #define masterless among(geometry, gEuclid, gEuclidSquare, gTorus) #define sphere_narcm (sphere && !archimedean) #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) #define a38 (S3 == 3 && S7 == 8) #define sphere4 (sphere && S7 == 4) #define stdeuc (geometry == gNormal || geometry == gEuclid || geometry == gEuclidSquare) #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 S42 (S7*S6) #define S12 (S6*2) #define S14 (S7*2) #define S21 (S7*S3) #define S28 (S7*4) #define S36 (S6*6) #define S84 (S7*S6*2) #define MAX_S3 4 #define eurad crossf #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) #define DUAL (variation == eVariation::dual) #define DUALMUL (DUAL ? 2 : 1) #define CHANGED_VARIATION (variation != ginf[geometry].default_variation) #define STDVAR (PURE || BITRUNCATED) #define NONSTDVAR (!STDVAR) #if CAP_ARCM #define VALENCE (BITRUNCATED ? 3 : archimedean ? arcm::valence() : S3) #else #define VALENCE (BITRUNCATED ? 3 : S3) #endif #define NUMWITCH 7 // achievements #define LB_YENDOR_CHALLENGE 40 #define LB_PURE_TACTICS 41 #define NUMLEADER 82 #define LB_PURE_TACTICS_SHMUP 49 #define LB_PURE_TACTICS_COOP 50 #define LB_RACING 81 #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 cld; #define DEBMEM(x) // { x fflush(stdout); } #define DEBSM(x) #if MAXDIM == 3 #define DIM 2 #else #define DIM ((geometry == gBinary3 || geometry == gCubeTiling || geometry == gCell120 || geometry == gECell120) ? 3 : 2) #endif #define MDIM (DIM+1) extern array sightranges; struct hyperpoint : array { hyperpoint() {} hyperpoint(ld x, ld y, ld z, ld w) { (*this)[0] = x; (*this)[1] = y; (*this)[2] = z; if(MAXDIM == 4) (*this)[3] = w; } }; struct transmatrix { ld tab[MAXDIM][MAXDIM]; ld * operator [] (int i) { return tab[i]; } const ld * operator [] (int i) const { return tab[i]; } }; inline hyperpoint operator * (const transmatrix& T, const hyperpoint& H) { hyperpoint z; for(int i=0; i struct walker; template struct connection_table { // Assumption: class T has a field c of type connection_table. // NOTE: since aconnection_table may be allocated with // less than MAX_EDGE neighbors (see tailored_alloc), // the order of fields matters. unsigned char spintable[6]; unsigned short mirrortable; T* move_table[MAX_EDGE]; unsigned char spintable_extra[2]; T* full() { T* x = (T*) this; return (T*)((char*)this - ((char*)(&(x->c)) - (char*)x)); } unsigned char& get_spinchar(int d) { if(d < 12) return spintable[d>>1]; else return spintable_extra[(d-12)>>1]; } void setspin(int d, int spin, bool mirror) { unsigned char& c = get_spinchar(d); c &= ~(15 << ((d&1) << 2)); c |= spin << ((d&1) << 2); if(mirror) mirrortable |= (1 << d); else mirrortable &=~ (1 << d); } // we are spin(i)-th neighbor of move[i] int spin(int d) { return (get_spinchar(d) >> ((d&1)<<2)) & 15; } bool mirror(int d) { return (mirrortable >> d) & 1; } 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() { for(int i=0; idegree(); 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 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 T* tailored_alloc(int degree) { const T* sample = (T*) °ree; T* result; #ifndef NO_TAILORED_ALLOC if(degree <= 12) { int b = (char*)&sample->c.move_table[degree] - (char*) sample; result = (T*) new char[b]; new (result) T(); } else #endif result = new T; for(int i=0; ic.move_table[i] = NULL; return result; } template 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; int hrand(int x); template struct walker { T *at; int spin; bool mirrored; walker (T *at = NULL, int s = 0, bool m = false) : at(at), spin(s), mirrored(m) { } walker& operator += (int i) { spin = at->c.fix(spin+(mirrored?-i:i)); return (*this); } walker& operator -= (int i) { spin = at->c.fix(spin-(mirrored?-i:i)); return (*this); } walker& operator += (wmirror_t) { mirrored = !mirrored; return (*this); } walker& 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& operator += (rev_t) { int d = at->degree(); return (*this) += d/2 + ((d&1)?hrand(2):0); } walker& operator += (revstep_t) { (*this) += rev; return (*this) += wstep; } bool operator != (const walker& x) const { return at != x.at || spin != x.spin || mirrored != x.mirrored; } bool operator == (const walker& x) const { return at == x.at && spin == x.spin && mirrored == x.mirrored; } bool operator < (const walker& cw2) const { return tie(at, spin, mirrored) < tie(cw2.at, cw2.spin, cw2.mirrored); } walker& operator ++ (int) { return (*this) += 1; } walker& operator -- (int) { return (*this) -= 1; } template walker operator + (U t) const { walker w = *this; w += t; return w; } template walker operator - (U t) const { walker w = *this; w += (-t); return w; } T*& peek() { return at->move(spin); } T* cpeek() { return at->cmove(spin); } bool creates() { return !peek(); } walker mirrorat(int d) { return walker (at, at->c.fix(d+d - spin), !mirrored); } }; 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); struct heptagon { // automaton state hstate s : 6; unsigned int dm4: 2; // distance from the origin short distance; // emerald/wineyard generator short emeraldval; // fifty generator short fiftyval; // zebra generator (1B actually) short zebraval; // field id int fieldval; // evolution data short rval0, rval1; struct cdata *cdata; // for alts, this contains the pointer to the original // central cell cell *c7; // associated generator of alternate structure, for Camelot and horocycles heptagon *alt; // connection table connection_table c; heptagon*& move(int d) { return c.move(d); } heptagon*& modmove(int d) { return c.modmove(d); } // functions heptagon () { heptacount++; } ~heptagon () { heptacount--; } heptagon *cmove(int d) { return createStep(this, d); } heptagon *cmodmove(int d) { return createStep(this, c.fix(d)); } inline int degree(); // prevent accidental copying heptagon(const heptagon&) = delete; heptagon& operator=(const heptagon&) = delete; // do not add any fields after connection_table (see tailored_alloc) }; struct cell : gcell { char type; // 6 for hexagons, 7 for heptagons int degree() { return type; } // wall parameter, used for remaining power of Bonfires and Thumpers char wparam; int listindex; heptagon *master; connection_table 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) }; namespace arcm { int degree(heptagon *h); int valence(); } int heptagon::degree() { #if CAP_ARCM if(archimedean) return arcm::degree(this); else #endif return S7; } typedef walker heptspin; typedef walker cellwalker; static const struct cth_t { cth_t() {}} cth; 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 // land completion for shared unlocking #define U5 (inv::on ? 10 : 5) // land completion for advanced unlocking #define U10 (inv::on ? 25 : 10) // land completion #define R10 (inv::on ? 50 : 10) // intermediate lands #define R30 (inv::on ? 100 : 30) // advanced lands #define R60 (inv::on ? 200 : 60) // advanced lands II #define R90 (inv::on ? 300 : 90) // Crossroads IV #define R200 (inv::on ? 800 : 200) // Crossroads V #define R300 (inv::on ? 1200 : 300) // kill types for Dragon Chasms #define R20 (inv::on ? 30 : 20) // kill count for Graveyard/Hive #define R100 (inv::on ? 500 : 100) string XLAT(string x); string XLATN(string x); string cts(char c); string its(int i); int hrand(int i); // size casted to int, to prevent warnings and actual errors caused by the unsignedness of x.size() template int isize(const T& x) {return x.size(); } // initialize the achievement system. void achievement_init(); // close the achievement system. void achievement_close(); // get the user name string myname(); // gain the achievement with the given name. // flags: 'e' - for Euclidean, 's' - for Shmup, '7' - for heptagonal // Only awarded if special modes are matched exactly. void achievement_gain(const char*, char flags = 0); // gain the achievement for collecting a number of 'it'. void achievement_collection(eItem it, int prevgold, int newgold); // this is used for 'counting' achievements, such as kill 10 // monsters at the same time. void achievement_count(const string& s, int current, int prev); // scores for special challenges void achievement_score(int cat, int score); // gain the victory achievements. Set 'hyper' to true for // the Hyperstone victory, and false for the Orb of Yendor victory. void achievement_victory(bool hyper); // gain the final achievements. Called with really=false whenever the user // looks at their score, and really=true when the game really ends. void achievement_final(bool really); // display the last achievement gained. void achievement_display(); // call the achievement callbacks void achievement_pump(); // achievements received this game extern vector achievementsReceived; // game forward declarations bool mirrorkill(cell *c); bool isNeighbor(cell *c1, cell *c2); void checkTide(cell *c); namespace anticheat { extern bool tampered; } int numplayers(); void removeIvy(cell *c); bool cellEdgeUnstable(cell *c, flagtype flags = 0); int coastvalEdge(cell *c); #define HRANDMAX 0x7FFFFFFF int hrandpos(); // 0 to HRANDMAX 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'; static const char daily = 'd'; static const char daily_off = 'D'; static const char racing = 'R'; // 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'; } int landMultiplier(eLand l); eItem treasureType(eLand l); void buildBarrier(cell *c, int d, eLand l = laNone); void extendBarrier(cell *c); bool buildBarrier4(cell *c, int d, int mode, eLand ll, eLand lr); bool buildBarrier6(cellwalker cw, int type); bool makeEmpty(cell *c); bool isCrossroads(eLand l); enum orbAction { roMouse, roKeyboard, roCheck, roMouseForce, roMultiCheck, roMultiGo }; void moveItem (cell *from, cell *to, bool activateYendor); bool uncoverMines(cell *c, int lev, int dist, bool just_checking); void killMonster(cell *c, eMonster who_killed, flagtype flags = 0); void toggleGates(cell *ct, eWall type, int rad); bool destroyHalfvine(cell *c, eWall newwall = waNone, int tval = 6); void buildCrossroads2(cell *c); bool isHaunted(eLand l); heptagon *createAlternateMap(cell *c, int rad, hstate firststate, int special=0); void setdist(cell *c, int d, cell *from); void checkOnYendorPath(); void killThePlayerAt(eMonster m, cell *c, flagtype flags); bool notDippingFor(eItem i); bool collectItem(cell *c2, bool telekinesis = false); void castLightningBolt(cellwalker lig); bool movepcto(int d, int subdir = 1, bool checkonly = false); void stabbingAttack(cell *mf, cell *mt, eMonster who, int bonuskill = 0); bool earthMove(cell *from, int dir); void messageKill(eMonster killer, eMonster victim); void moveMonster(cell *ct, cell *cf, int direction_hint); int palaceHP(); void placeLocalOrbs(cell *c); int elementalKills(); bool elementalUnlocked(); bool trollUnlocked(); bool isMultitile(eMonster m); void checkFreedom(cell *cf); int rosedist(cell *c); bool canPushStatueOn(cell *c); namespace hive { void createBugArmy(cell *c); } namespace whirlpool { void generate(cell *wto); } namespace whirlwind { void generate(cell *wto); } namespace mirror { 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); } int neighborId(cell *c1, cell *c2); struct movedir { int d; // 0 to 6, or one of the following -- warning: not used consistently #define MD_WAIT (-1) #define MD_DROP (-2) #define MD_UNDECIDED (-3) #define MD_USE_ORB (-4) int subdir; // for normal movement (0-6): turn left or right cell *tgt; // for MD_USE_ORB: target cell }; inline bool movepcto(const movedir& md) { return movepcto(md.d, md.subdir); } void activateActiv(cell *c, bool msg); // shmup struct charstyle { int charid; color_t skincolor, haircolor, dresscolor, swordcolor, dresscolor2, uicolor; bool lefthanded; }; string csname(charstyle& cs); void initcs(charstyle& cs); void savecs(FILE *f, charstyle& cs, int vernum); void loadcs(FILE *f, charstyle& cs, int vernum); #define MAXPLAYER 7 #define MAXJOY 8 #define MAXBUTTON 64 #define MAXAXE 16 #define MAXHAT 4 namespace multi { extern bool alwaysuse; void recall(); extern cell *origpos[MAXPLAYER], *origtarget[MAXPLAYER]; extern int players; extern cellwalker player[MAXPLAYER]; extern bool flipped[MAXPLAYER]; cell *mplayerpos(int i); extern vector revive_queue; // queue for revival extern movedir whereto[MAXPLAYER]; // player's target cell extern int cpid; // player id -- an extra parameter for player-related functions extern int cpid_edit; // cpid currently being edited // treasure collection, kill, and death statistics extern int treasures[MAXPLAYER], kills[MAXPLAYER], deaths[MAXPLAYER]; struct config { char keyaction[512]; char joyaction[MAXJOY][MAXBUTTON]; char axeaction[MAXJOY][MAXAXE]; char hataction[MAXJOY][MAXHAT][4]; int deadzoneval[MAXJOY][MAXAXE]; }; void saveConfig(FILE *f); void loadConfig(FILE *f); void initConfig(); extern charstyle scs[MAXPLAYER]; bool playerActive(int p); int activePlayers(); cell *multiPlayerTarget(int i); void checklastmove(); void leaveGame(int i); void configure(); } template class hookset : public map> {}; typedef hookset *purehookset; namespace shmup { using namespace multi; void recall(); extern bool on; extern bool safety; extern int curtime; void clearMonsters(); void clearMemory(); void init(); void teleported(); struct monster { eMonster type; cell *base; cell *torigin; // tortoises: origin // butterflies: last position transmatrix at; transmatrix pat; eMonster stk; bool dead; bool notpushed; bool inBoat; bool no_targetting; monster *parent; // who shot this missile eMonster parenttype; // type of the parent int nextshot; // when will it be able to shot (players/flailers) int pid; // player ID char hitpoints; int stunoff; int blowoff; double swordangle; // sword angle wrt at double vel; // velocity, for flail balls double footphase; bool isVirtual; // off the screen: gmatrix is unknown, and pat equals at monster() { dead = false; inBoat = false; parent = NULL; nextshot = 0; stunoff = 0; blowoff = 0; footphase = 0; no_targetting = false; swordangle = 0; } void store(); void findpat(); cell *findbase(const transmatrix& T); void rebasePat(const transmatrix& new_pat); }; extern struct monster* mousetarget; extern monster *pc[MAXPLAYER]; extern eItem targetRangedOrb(orbAction a); void degradeDemons(); void killThePlayer(eMonster m); void killThePlayer(eMonster m, int i); void visibleFor(int t); bool verifyTeleport(); bool dragonbreath(cell *dragon); void shmupDrownPlayers(cell *c); cell *playerpos(int i); bool playerInBoat(int i); void destroyBoats(cell *c); bool boatAt(cell *c); void fixStorage(); void addShmupHelp(string& out); void activateArrow(cell *c); void pushmonsters(); void popmonsters(); extern hookset *hooks_turn; extern hookset *hooks_draw; extern hookset *hooks_kill; extern hookset *hooks_describe; void turn(int); extern monster *lmousetarget; void virtualRebase(shmup::monster *m, bool tohex); extern monster *pc[MAXPLAYER]; int reflect(cell*& c2, cell*& mbase, transmatrix& nat); } transmatrix& ggmatrix(cell *c); transmatrix master_relative(cell *c, bool get_inverse = false); void virtualRebase(cell*& base, transmatrix& at, bool tohex); void virtualRebase(cell*& base, hyperpoint& h, bool tohex); transmatrix calc_relative_matrix(cell *c, cell *c1, const hyperpoint& point_hint); transmatrix calc_relative_matrix(cell *c, cell *c1, int direction_hint); static const int NOHINT = -1; // graph void showMissionScreen(); void restartGraph(); void resetmusic(); void drawFlash(cell* c); void drawBigFlash(cell* c); void drawParticle(cell *c, color_t col, int maxspeed = 100); void drawParticles(cell *c, color_t col, int qty, int maxspeed = 100); void drawFireParticles(cell *c, int qty, int maxspeed = 100); int firecolor(int phase = 0, int mul = 1); void drawLightning(); void drawSafety(); void restartGraph(); void movepckeydir(int); void centerpc(ld aspd); typedef color_t color_t; void displayButton(int x, int y, const string& name, int key, int align, int rad = 0); void displayColorButton(int x, int y, const string& name, int key, int align, int rad, color_t color, color_t color2 = 0); inline string ONOFF(bool b) { return XLAT(b ? "ON" : "OFF"); } int darkened(int c); extern int getcstat; bool displaychr(int x, int y, int shift, int size, char chr, color_t col); bool displayfr(int x, int y, int b, int size, const string &s, color_t color, int align); bool displayfrSP(int x, int y, int sh, int b, int size, const string &s, color_t color, int align, int p); bool outofmap(hyperpoint h); void applymodel(hyperpoint H, hyperpoint& Hscr); void drawCircle(int x, int y, int size, color_t color, color_t fillcolor = 0); void fixcolor(int& col); ld displayspin(cell *c, int d); bool non_spatial_model(); hyperpoint gethyper(ld x, ld y); void resetview(); void drawthemap(); void drawfullmap(); extern function wrap_drawfullmap; bool displaystr(int x, int y, int shift, int size, const char *str, color_t color, int align); bool displaystr(int x, int y, int shift, int size, const string& str, color_t color, int align); extern int darken, inmirrorcount; void calcparam(); #if CAP_SDL color_t& qpixel(SDL_Surface *surf, int x, int y); void setvideomode(); #endif #if CAP_CONFIG void saveConfig(); #endif extern hyperpoint mouseh; extern hyperpoint ccenter; extern ld crad; extern bool mousepressed, anyshiftclick, numlock_on; extern string help; typedef function reaction_t; typedef function bool_reaction_t; extern reaction_t help_delegate; #define HELPFUN(x) (help_delegate = x, "HELPFUN") 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 aurastr, aurasmoothen; bool fixed_facing; 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 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; 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; multi::config scfg; int steamscore; bool drawmousecircle; // draw the circle around the mouse bool skipstart; // skip the start menu int quickmouse; // quick mouse on the map 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 int cells_drawn_limit; ld skiprope; eStereo stereo_mode; ld ipd; ld lr_eyewidth, anaglyph_eyewidth; ld fov; bool consider_shader_projection; }; extern videopar vid; extern vector< function > screens; template void pushScreen(const T& x) { screens.push_back(x); } inline void popScreen() { screens.pop_back(); } inline void popScreenAll() { while(isize(screens)>1) popScreen(); } struct display_data { transmatrix view_matrix; // current rotation, relative to viewctr transmatrix player_matrix; // player-relative view heptspin view_center; cellwalker precise_center; unordered_map cellmatrices, old_cellmatrices; ld xmin, ymin, xmax, ymax; // relative ld xtop, ytop, xsize, ysize; // in pixels display_data() { xmin = ymin = 0; xmax = ymax = 1; } // paramaters calculated from the above int xcenter, ycenter; ld radius; int scrsize; bool sidescreen; ld tanfov; GLfloat scrdist, scrdist_text; ld eyewidth(); bool stereo_active(); bool in_anaglyph(); void set_viewport(int ed); void set_projection(int ed, bool apply_models); void set_mask(int ed); }; extern display_data default_display; extern display_data *current_display; #define View (current_display->view_matrix) #define cwtV (current_display->player_matrix) #define viewctr (current_display->view_center) #define centerover (current_display->precise_center) #define gmatrix (current_display->cellmatrices) #define gmatrix0 (current_display->old_cellmatrices) extern cell *mouseover, *mouseover2, *lmouseover; extern string mouseovers; extern struct SDL_Surface *s; typedef function cellfunction; namespace patterns { extern char whichShape; extern int canvasback; extern cpatterntype cgroup, old_cgroup; enum ePattern : char { PAT_NONE = 0, PAT_TYPES = 'T', PAT_ZEBRA = 'z', PAT_EMERALD = 'f', PAT_PALACE = 'p', PAT_FIELD = 'F', PAT_DOWN = 'H', PAT_COLORING = 'C', PAT_SIBLING = 'S', PAT_CHESS = 'c', PAT_SINGLETYPE = 't' }; extern ePattern whichPattern; extern int subpattern_flags; static const int SPF_ROT = 1; static const int SPF_SYM01 = 2; static const int SPF_SYM02 = 4; static const int SPF_SYM03 = 8; static const int SPF_CHANGEROT = 16; static const int SPF_TWOCOL = 32; static const int SPF_EXTRASYM = 64; static const int SPF_ALTERNATE = 128; static const int SPF_FOOTBALL = 256; static const int SPF_FULLSYM = 512; static const int SPF_DOCKS = 1024; static const int SPF_NO_SUBCODES = 2048; static const int SPF_SYM0123 = SPF_SYM01 | SPF_SYM02 | SPF_SYM03; extern char whichCanvas; extern bool displaycodes; int generateCanvas(cell *c); struct patterninfo { int id; int dir; bool reflect; int symmetries; }; patterninfo getpatterninfo(cell *c, ePattern pat, int sub); inline patterninfo getpatterninfo0(cell *c) { return getpatterninfo(c, whichPattern, subpattern_flags); } bool compatible(cpatterntype oldp, cpatterntype newp); extern void pushChangeablePatterns(); void computeCgroup(); void showPattern(); void val38(cell *c, patterninfo &si, int sub, int pat); int downdir(cell *c, const cellfunction& cf = coastvalEdge); } namespace mapeditor { #if CAP_EDIT extern map modelcell; #endif extern bool drawplayer; void applyModelcell(cell *c); extern cell *drawcell; void initdraw(cell *c); void showMapEditor(); void showDrawEditor(); enum eShapegroup { sgPlayer, sgMonster, sgItem, sgFloor }; static const int USERSHAPEGROUPS = 4; bool haveUserShape(eShapegroup group, int id); void draw_texture_ghosts(cell *c, const transmatrix& V); void map_settings(); } struct renderbuffer; namespace rug { extern bool rugged; extern bool spatial_rug; extern bool computed; extern bool renderonce; extern bool rendernogl; extern int texturesize; extern ld model_distance; extern transmatrix currentrot; #if CAP_RUG void show(); // initialize both the texture and the model void init(); // initialize only the texture (assume model already initialized) void reopen(); // close the rug mode, remove the texture void close(); // clear the model void clear_model(); void actDraw(); void select(); void buildVertexInfo(cell *c, transmatrix V); void drawRugScene(); void prepareTexture(); void drawRugScene(); void push_all_points(int coord, ld val); void apply_rotation(const transmatrix& t); string makehelp(); struct edge { struct rugpoint *target; double len; }; struct dexp_data { hyperpoint params; hyperpoint cont; ld remaining_distance; }; struct rugpoint { double x1, y1; bool valid; bool inqueue; double dist; hyperpoint h; // point in the represented space hyperpoint flat; // point in the native space, in azeq hyperpoint precompute; vector edges; vector anticusp_edges; // Find-Union algorithm rugpoint *glue; rugpoint *getglue() { return glue ? (glue = glue->getglue()) : this; } hyperpoint& glueflat() { return glue->flat; } rugpoint() { glue = NULL; } void glueto(rugpoint *x) { x = x->getglue(); auto y = getglue(); if(x != y) y->glue = x; } int dexp_id; dexp_data surface_point; }; struct triangle { rugpoint *m[3]; triangle(rugpoint *m1, rugpoint *m2, rugpoint *m3) { m[0] = m1; m[1] = m2; m[2] = m3; } }; extern vector points; extern vector triangles; extern int qvalid; extern bool subdivide_further(); extern void subdivide(); extern bool good_shape; extern int vertex_limit; extern void enqueue(rugpoint *p); void sort_rug_points(); extern bool rug_perspective; bool handlekeys(int sym, int uni); void addTriangle(rugpoint *t1, rugpoint *t2, rugpoint *t3, ld len = 1); rugpoint *addRugpoint(hyperpoint h, double dist); void buildRug(); bool in_crystal(); void physics(); extern renderbuffer *glbuf; extern eGeometry gwhere; extern bool no_fog; extern ld lowrug, hirug, ruggospeed; extern GLuint alternate_texture; extern bool invert_depth; extern ld ruggo; #endif } #define HASLINEVIEW namespace conformal { extern bool on; extern vector > killhistory; extern vector > findhistory; extern vector movehistory; extern set inmovehistory, inkillhistory, infindhistory; extern bool includeHistory; extern bool use_atan; extern ld rotation; extern int do_rotate; extern ld model_orientation; extern ld halfplane_scale; extern ld ocos, osin; extern ld cos_ball, sin_ball; extern bool model_straight; extern ld model_transition; extern ld top_z; extern ld spiral_angle, spiral_x, spiral_y; extern ld spiral_cone; // screen coordinates to logical coordinates: apply_orientation(x,y) // logical coordinates back to screen coordinates: apply_orientation(y,x) template void apply_orientation(A& x, A& y) { if(!model_straight) tie(x,y) = make_pair(x*ocos + y*osin, y*ocos - x*osin); } template void apply_ball(A& x, A& y) { tie(x,y) = make_pair(x*cos_ball + y*sin_ball, y*cos_ball - x*sin_ball); } void configure(); extern bool autoband; extern bool autobandhistory; extern bool dospiral; extern ld lvspeed; extern int bandsegment; extern int bandhalf; extern ld extra_line_steps; void create(); void clear(); void model_menu(); void history_menu(); string get_model_name(eModel); void apply(); void movetophase(); void renderAutoband(); extern vector v; extern double phase; void applyIB(); void progress_screen(); void progress(string str); bool model_has_orientation(); extern string formula; extern eModel basic_model; } namespace polygonal { static const int MSI = 120; extern int SI; extern ld STAR; extern int deg; extern ld coefr[MSI], coefi[MSI]; extern int maxcoef, coefid; void solve(); pair compute(ld x, ld y); } void selectEyeGL(int ed); void selectEyeMask(int ed); extern int ticks; extern color_t backcolor, bordcolor, forecolor; void setGLProjection(color_t col = backcolor); // passable flags #define P_MONSTER Flag(0) // can move through monsters #define P_MIRROR Flag(1) // can move through mirrors #define P_REVDIR Flag(2) // reverse direction movement #define P_WIND Flag(3) // can move against the wind #define P_GRAVITY Flag(4) // can move against the gravity #define P_ISPLAYER Flag(5) // player-only moves (like the Round Table jump) #define P_ONPLAYER Flag(6) // always can step on the player #define P_FLYING Flag(7) // is flying #define P_BULLET Flag(8) // bullet can fly through more things #define P_MIRRORWALL Flag(9) // mirror images go through mirror walls #define P_JUMP1 Flag(10) // first part of a jump #define P_JUMP2 Flag(11) // second part of a jump #define P_TELE Flag(12) // teleport onto #define P_BLOW Flag(13) // Orb of Air -- blow, or push #define P_AETHER Flag(14) // aethereal #define P_FISH Flag(15) // swimming #define P_WINTER Flag(16) // fire resistant #define P_USEBOAT Flag(17) // can use boat #define P_NOAETHER Flag(18) // disable AETHER #define P_FRIENDSWAP Flag(19) // can move on friends (to swap with tem) #define P_ISFRIEND Flag(20) // is a friend (can use Empathy + Winter/Aether/Fish combo) #define P_LEADER Flag(21) // can push statues and use boats #define P_MARKWATER Flag(22) // mark Orb of Water as used #define P_EARTHELEM Flag(23) // Earth Elemental #define P_WATERELEM Flag(24) // Water Elemental #define P_IGNORE37 Flag(25) // ignore the triheptagonal board #define P_CHAIN Flag(26) // for chaining moves with boats #define P_DEADLY Flag(27) // suicide moves allowed #define P_ROSE Flag(28) // rose smell #define P_CLIMBUP Flag(29) // allow climbing up #define P_CLIMBDOWN Flag(30) // allow climbing down #define P_REPTILE Flag(31) // is reptile #define P_VOID Flag(32) // void beast #define P_PHASE Flag(33) // phasing movement #define P_PULLMAGNET Flag(34) // pull the other part of the magnet bool passable(cell *w, cell *from, flagtype flags); bool anti_alchemy(cell *w, cell *from); bool isElemental(eLand l); int coastval(cell *c, eLand base); int getHauntedDepth(cell *c); eLand randomElementalLand(); bool notDippingForExtra(eItem i, eItem x); void placePrizeOrb(cell *c); void wandering(); bool isSealand(eLand l); int newRoundTableRadius(); bool grailWasFound(cell *c); extern bool buggyGeneration; int buildIvy(cell *c, int children, int minleaf); int celldistAltRelative(cell *c); int roundTableRadius(cell *c); eLand pickLandRPM(eLand old); bool bearsCamelot(eLand l); extern bool safety; #define SAGEMELT .1 #define TEMPLE_EACH (DIM == 3 ? 2 : 6) #define PT(x, y) ((tactic::on || quotient == 2 || daily::on) ? (y) : inv::on ? min(2*(y),x) : (x)) #define ROCKSNAKELENGTH 50 #define WORMLENGTH 15 #define PUREHARDCORE_LEVEL 10 #define PRIZEMUL 7 #define INF 9999 #define INFD 60 #define PINFD 125 #ifndef BARLEV #define BARLEV ((ISANDROID||ISIOS||ISFAKEMOBILE||getDistLimit()<7)?9:10) #endif #define BUGLEV 15 // #define BARLEV 9 bool isKillable(cell *c); bool isKillableSomehow(cell *c); bool isAlchAny(eWall w); bool isAlchAny(cell *c); #define YDIST 101 #define MODECODES (1ll<<61) extern cellwalker cwt; // player character position extern array items; extern array kills; extern int explore[10], exploreland[10][landtypes], landcount[landtypes]; typedef flagtype modecode_t; extern map > hiitems; extern eLand firstland, specialland; bool pseudohept(cell *c); bool pureHardcore(); extern int cheater; int airdist(cell *c); bool eq(short a, short b); extern vector dcal; // queue for cpdist bool isPlayerOn(cell *c); bool isFriendly(eMonster m); bool isFriendly(cell *c); bool isChild(cell *w, cell *killed); // is w killed if killed is killed? static const int NO_TREASURE = 1; static const int NO_YENDOR = 2; static const int NO_GRAIL = 4; static const int NO_LOVE = 8; int gold(int no = 0); int tkills(); bool hellUnlocked(); bool markOrb(eItem it); // mark the orb as 'used', return true if exists bool markEmpathy(eItem it); // mark both the given orb and Empathy as 'used', return true if exists bool markEmpathy2(eItem it); // as above, but next turn bool isMimic(eMonster m); bool isMimic(cell *c); void fallMonster(cell *c, flagtype flags = 0); // kill monster due to terrain bool attackMonster(cell *c, flagtype flags, eMonster killer); bool isWorm(eMonster m); bool isWorm(cell *c); void empathyMove(cell *c, cell *cto, int dir); bool isIvy(eMonster m); bool isIvy(cell *c); #define GUNRANGE 3 // 0 = basic treasure, 1 = other item, 2 = power orb, 3 = not an item #define IC_TREASURE 0 #define IC_OTHER 1 #define IC_ORB 2 #define IC_NAI 3 bool playerInPower(); void activateFlash(); void activateLightning(); bool markOrb(eItem it); bool markOrb2(eItem it); void drainOrb(eItem it, int target = 0); void useupOrb(eItem it, int qty); void initgame(); bool haveRangedTarget(); eItem targetRangedOrb(cell *c, orbAction a); void reduceOrbPowers(); int realstuntime(cell *c); extern bool invismove, invisfish; bool attackingForbidden(cell *c, cell *c2); void killOrStunMonster(cell *c2, eMonster who_killed); void useup(cell *c); // useup thumpers/bonfires cell *playerpos(int i); bool makeflame(cell *c, int timeout, bool checkonly); void bfs(); bool isPlayerInBoatOn(cell *c); bool isPlayerInBoatOn(cell *c, int i); void destroyBoats(cell *c, cell *cf, bool strandedToo); extern bool showoff; extern int lastexplore; extern int truelotus; extern eLand lastland; extern time_t timerstart; extern bool timerstopped; bool againstRose(cell *cfrom, cell *cto); bool withRose(cell *cfrom, cell *cto); // 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++) #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 #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 #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 #define AF_CRUSH Flag(31) // Crusher's delayed attack bool canAttack(cell *c1, eMonster m1, cell *c2, eMonster m2, flagtype flags); extern bool chaosmode; extern bool chaosUnlocked; extern bool chaosAchieved; bool isTechnicalLand(eLand l); int getGhostcount(); void raiseBuggyGeneration(cell *c, const char *s); void verifyMutantAround(cell *c); #if CAP_SDL #if CAP_PNG #include "savepng.h" #define IMAGEEXT ".png" void IMAGESAVE(SDL_Surface *s, const char *fname); #else #define IMAGEEXT ".bmp" #define IMAGESAVE SDL_SaveBMP #endif #endif void drawscreen(); void buildAirmap(); // currently works for worms only bool sameMonster(cell *c1, cell *c2); cell *wormhead(cell *c); eMonster getMount(int player_id); eMonster haveMount(); bool isDragon(eMonster m); // for some reason I need this to compile under OSX #if ISMAC extern "C" { void *_Unwind_Resume = 0; } #endif extern bool autocheat; extern bool inHighQual; void mountmove(cell *c, int spin, bool fp); void mountmove(cell *c, int spin, bool fp, cell *ppos); void mountswap(cell *c1, int spin1, bool fp1, cell *c2, int spin2, bool fp2); template struct dynamicval { T& where; T backup; dynamicval(T& wh, T val) : where(wh) { backup = wh; wh = val; } dynamicval(T& wh) : where(wh) { backup = wh; } ~dynamicval() { where = backup; } }; struct stalemate1 { eMonster who; cell *moveto; cell *killed; cell *pushto; cell *comefrom; cell *swordlast[2], *swordtransit[2], *swordnext[2]; bool isKilled(cell *c); stalemate1(eMonster w, cell *mt, cell *ki, cell *pt, cell *cf) : who(w), moveto(mt), killed(ki), pushto(pt), comefrom(cf) {} }; namespace stalemate { extern vector moves; extern bool nextturn; bool isKilled(cell *c); bool isMoveto(cell *c); bool isKilledDirectlyAt(cell *c); bool isPushto(cell *c); }; extern int turncount; bool reduceOrbPower(eItem it, int cap); bool checkOrb(eMonster m1, eItem orb); movedir vectodir(const hyperpoint& P); namespace tortoise { extern int seekbits; int getRandomBits(); } namespace sword { extern int angle[MAXPLAYER]; cell *pos(cell *c, int s); cell *pos(int id); bool at(cell *where, bool noplayer = false); int shift(cell *c1, cell *c2); } void killThePlayer(eMonster m, int id, flagtype flags); bool attackJustStuns(cell *c2, flagtype flags, eMonster attacker); bool isTargetOrAdjacent(cell *c); bool warningprotection(const string& s); bool mineMarked(cell *c); bool minesafe(); bool hasSafeOrb(cell *c); void placeWater(cell *c, cell *c2); bool againstCurrent(cell *w, cell *from); bool needConfirmation(); bool needConfirmationEvenIfSaved(); #define DEFAULTCONTROL (multi::players == 1 && !shmup::on && !multi::alwaysuse && !(rug::rugged && rug::renderonce)) #define DEFAULTNOR(sym) (DEFAULTCONTROL || multi::notremapped(sym)) extern bool timerghost; extern bool gen_wandering; #define CAP_MENUSCALING (ISPANDORA || ISMOBILE) #if CAP_MENUSCALING #define displayfrZ dialog::zoom::displayfr #define displayfrZH dialog::zoom::displayfr_highlight #else #define displayfrZ displayfr #define displayfrZH dialog::zoom::displayfr_highlight #endif namespace dialog { extern string highlight_text; extern color_t dialogcolor; enum tDialogItem {diTitle, diItem, diBreak, diHelp, diInfo, diSlider, diBigItem}; struct item { tDialogItem type; string body; string value; string keycaption; int key; color_t color, colorv, colork, colors, colorc; int scale; double param; int position; }; struct scaler { ld (*direct) (ld); ld (*inverse) (ld); bool positive; }; static inline ld identity_f(ld x) { return x; }; const static scaler identity = {identity_f, identity_f, false}; const static scaler logarithmic = {log, exp, true}; const static scaler asinhic = {asinh, sinh, false}; struct numberEditor { ld *editwhat; string s; ld vmin, vmax, step, dft; string title, help; scaler sc; int *intval; ld intbuf; bool animatable; }; extern numberEditor ne; extern vector items; extern reaction_t reaction, extra_options, reaction_final; item& lastItem(); extern color_t *palette; string keyname(int k); string disp(ld x); void addSelItem(string body, string value, int key); void addBoolItem(string body, bool value, int key); void addBigItem(string body, int key); void addColorItem(string body, int value, int key); void openColorDialog(color_t& col, color_t *pal = palette); extern bool colorAlpha; void addHelp(string body); void addInfo(string body, color_t color = dialogcolor); void addItem(string body, int key); int addBreak(int val); void addTitle(string body, color_t color, int scale); void init(); void init(string title, color_t color = 0xE8E8E8, int scale = 150, int brk = 60); void display(); void editNumber(ld& x, ld vmin, ld vmax, ld step, ld dft, string title, string help); void editNumber(int& x, int vmin, int vmax, int step, int dft, string title, string help); void use_hexeditor(); inline void scaleLog() { ne.sc = logarithmic; } inline void scaleSinh() { ne.sc = asinhic; } void bound_low(ld val); void bound_up(ld val); void handleNavigation(int &sym, int &uni); namespace zoom { bool displayfr(int x, int y, int b, int size, const string &s, color_t color, int align); bool displayfr_highlight(int x, int y, int b, int size, const string &s, color_t color, int align, int hicolor = 0xFFFF00); } bool editingDetail(); int handlePage(int& nl, int& nlm, int perpage); void displayPageButtons(int i, bool pages); bool handlePageButtons(int uni); extern bool sidedialog; extern int dialogflags; extern int dcenter; int displaycolor(color_t col); void openFileDialog(string& filename, string fcap, string ext, bool_reaction_t action); extern string infix; bool hasInfix(const string &s); bool editInfix(int uni); void vpush(color_t, const char *name); extern vector > v; void addHelp(); void addBack(); void add_action(const reaction_t& action); void add_key_action(int key, const reaction_t& action); string view_edited_string(); void start_editing(string& s); string editchecker(int sym, int uni); bool handle_edit_string(int sym, int uni, function checker = editchecker); void edit_string(string& s, string title, string help); void confirm_dialog(const string& text, const reaction_t& act); inline void cheat_if_confirmed(const reaction_t& act) { if(needConfirmationEvenIfSaved()) pushScreen([act] () { confirm_dialog(XLAT("This will enable the cheat mode, making this game ineligible for scoring. Are you sure?"), act); }); else act(); } inline void do_if_confirmed(const reaction_t& act) { if(needConfirmationEvenIfSaved()) pushScreen([act] () { confirm_dialog(XLAT("This will end your current game and start a new one. Are you sure?"), act); }); else act(); } inline reaction_t add_confirmation(const reaction_t& act) { return [act] { do_if_confirmed(act); }; } } void checkStunKill(cell *dest); void clearMessages(); void resetGeometry(); namespace shot { #if CAP_SHOT extern int shotx, shoty, shotformat; extern bool make_svg; extern ld gamma, fade; extern string caption; extern bool transparent; void menu(); void default_screenshot_content(); void take(string fname, const function& what = default_screenshot_content); #endif } #if CAP_SVG namespace svg { void circle(int x, int y, int size, color_t col, color_t fillcolor, double linewidth); void polygon(int *polyx, int *polyy, int polyi, color_t col, color_t outline, double linewidth); void text(int x, int y, int size, const string& str, bool frame, color_t col, int align); extern bool in; extern string link; #if CAP_SHOT void render(const string& fname, const function& what = shot::default_screenshot_content); #endif } #else namespace svg { static const always_false in; } #endif extern int sightrange_bonus, genrange_bonus, gamerange_bonus; namespace halloween { void getTreat(cell *where); } // just in case if I change my mind about when Orbs lose their power #define ORBBASE 0 transmatrix mscale(const transmatrix& t, double fac); transmatrix mzscale(const transmatrix& t, double fac); extern bool ivoryz; #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 bool drawMonsterType(eMonster m, cell *where, const transmatrix& V, color_t col, double footphase); void drawPlayerEffects(const transmatrix& V, cell *c, bool onPlayer); // monster movement animations struct animation { int ltick; double footphase; transmatrix wherenow; int attacking; transmatrix attackat; }; // we need separate animation layers for Orb of Domination and Tentacle+Ghost, // and also to mark Boats #define ANIMLAYERS 3 #define LAYER_BIG 0 // for worms and krakens #define LAYER_SMALL 1 // for others #define LAYER_BOAT 2 // mark that a boat has moved extern map animations[ANIMLAYERS]; void animateAttack(cell *src, cell *tgt, int layer, int direction_hint); void animateMovement(cell *src, cell *tgt, int layer, int direction_hint); // for animations which might use the same locations, // such as replacements or multi-tile monsters void indAnimateMovement(cell *src, cell *tgt, int layer, int direction_hint); void commitAnimations(int layer); void animateReplacement(cell *a, cell *b, int layer, int direction_hinta, int direction_hintb); void fallingFloorAnimation(cell *c, eWall w = waNone, eMonster m = moNone); void fallingMonsterAnimation(cell *c, eMonster m, int id = multi::cpid); // ranks: enum class PPR { ZERO, OUTCIRCLE, MOVESTAR, 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, PARTICLE, SWORDMARK, MAGICSWORD, MISSILE, MINEMARK, ARROW, MOBILE_ARROW, LINE, TEXT, CIRCLE, MAX, DEFAULT = -1 }; 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); } namespace mapeditor { bool drawUserShape(const transmatrix& V, eShapegroup group, int id, color_t color, cell *c, PPR prio = PPR::DEFAULT); } #if CAP_SHAPES void ShadowV(const transmatrix& V, const struct hpcshape& bp, PPR prio = PPR::MONSTER_SHADOW); #endif #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 #define OUTLINE_DEFAULT ((bordcolor << 8) + 0xFF) #define OUTLINE_FORE ((forecolor << 8) + 0xFF) #define OUTLINE_BACK ((backcolor << 8) + 0xFF) extern bool audio; extern string musiclicense; extern string musfname[landtypes]; extern int musicvolume, effvolume; void initAudio(); bool loadMusicInfo(); void handlemusic(); void playSeenSound(cell *c); void playSound(cell *c, const string& fname, int vol = 100); inline string pick123() { return cts('1' + rand() % 3); } inline string pick12() { return cts('1' + rand() % 2); } bool playerInBoat(int i); extern int lowfar; extern bool wmspatial, wmescher, wmplain, wmblack, wmascii; extern bool mmspatial, mmhigh, mmmon, mmitem; extern bool spatial_graphics; extern int maxreclevel, reclevel; string explain3D(ld *param); extern int detaillevel; extern bool quitmainloop; enum eGlyphsortorder { gsoFirstTop, gsoFirstBottom, gsoLastTop, gsoLastBottom, gsoLand, gsoValue, gsoMAX }; extern eGlyphsortorder glyphsortorder; void explodeMine(cell *c); bool mayExplodeMine(cell *c, eMonster who); void explosion(cell *c, int power, int central); void explodeBarrel(cell *c); enum eGravity { gsNormal, gsLevitation, gsAnti }; extern eGravity gravity_state, last_gravity_state; int gravityLevel(cell *c); int gravityLevelDiff(cell *c, cell *f); void fullcenter(); void movecost(cell* from, cell *to, int phase); // 1 = pre-collect, 2 = post-collect, 3 = both void checkmove(); transmatrix eumove(ld x, ld y); transmatrix eumove(int vec); transmatrix eumovedir(int d); int reptilemax(); extern bool mousing; #define IFM(x) (mousing?"":x) extern cell *recallCell; extern eLand cheatdest; void cheatMoveTo(eLand l); void doOvergenerate(); void collectMessage(cell *c2, eItem which); namespace quotientspace { void build(); void clear(); extern vector connections; } void killFriendlyIvy(); #if CAP_SHAPES void pushdown(cell *c, int& q, const transmatrix &V, double down, bool rezoom, bool repriority); #endif 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* coords, int qty, color_t color); extern eModel pmodel; inline bool mdAzimuthalEqui() { return pmodel == mdEquidistant || pmodel == mdEquiarea; } inline bool mdBandAny() { return pmodel == mdBand || pmodel == mdBandEquidistant || pmodel == mdBandEquiarea || pmodel == mdSinusoidal; } int darkena(int c, int lev, int a); #define SHSIZE 16 extern cell *shpos[MAXPLAYER][SHSIZE]; extern int cshpos; #if CAP_ANIMATIONS namespace anims { void animate_parameter(ld &x, string f, const reaction_t& r); void deanimate(ld &x); void get_parameter_animation(ld &x, string& f); extern ld a, b; } #endif namespace arg { #if CAP_COMMANDLINE void lshift(); void shift(); const string& args(); const char* argcs(); int argi(); ld argf(); bool argis(const string& s); unsigned arghex(); 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 } void init(int _argc, char **_argv); void launch_dialog(const reaction_t& r = reaction_t()); extern int curphase; void phaseerror(int x); // 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; } 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; } void read(int phase); eLand readland(const string& ss); eItem readItem(const string& ss); eMonster readMonster(const string& ss); #endif } extern bool generatingEquidistant; void clearfrom(heptagon *at); void clearHexes(heptagon *at); void verifycells(heptagon *at); int zebra40(cell *c); cell *createMov(cell *c, int d); #if CAP_TOUR namespace tour { extern bool on; extern string tourhelp; extern string slidecommand; extern int currentslide; enum presmode { pmStartAll = 0, pmStart = 1, pmFrame = 2, pmStop = 3, pmKey = 4, pmRestart = 5, pmAfterFrame = 6, pmGeometry = 11, pmGeometryReset = 13, pmGeometryStart = 15 }; void setCanvas(presmode mode, char canv); void presentation(presmode mode); void checkGoodLand(eLand l); int getid(); extern function getNext; extern function quickfind; extern function showland; void start(); struct slide { const char *name; int unused_id; int flags; const char *help; function 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; static const int QUICKGEO=32; static const int SIDESCREEN = 64; static const int USE_SLIDE_NAME = 128; extern slide slideHypersian; extern slide slideExpansion; namespace ss { void showMenu(); void list(slide*); } extern hookset *hooks_slide; }; #else namespace tour { static const always_false on; } #endif extern bool doCross; void optimizeview(); extern bool noGUI; extern bool dronemode; extern ld whatever; 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; static const int A3 = 2048; // affects poly static const int ZOOMABLE = 4096; static const int TORUSCONFIG = 8192; static const int MAYDARK = 16384; static const int DIALOG_STRICT_X = 32768; // do not interpret dialog clicks outside of the X region static const int EXPANSION = (1<<16); static const int HEXEDIT = (1<<17); }; namespace linepatterns { enum ePattern { patPalacelike, patPalace, patZebraTriangles, patZebraLines, patTriTree, patTriRings, patHepta, patRhomb, patTree, patAltTree, patVine, patPower, patNormal, patTrihepta, patBigTriangles, patBigRings, patHorocycles, patTriOther, patDual, patMeridians, patParallels, patCircles, patRadii }; void clearAll(); void setColor(ePattern id, color_t col); void drawAll(); void showMenu(); void switchAlpha(ePattern id, color_t col); struct linepattern { int id; const char *lpname; color_t color; }; extern vector patterns; extern ld width; }; transmatrix ddspin(cell *c, int d, ld bonus = 0); transmatrix iddspin(cell *c, int d, ld bonus = 0); bool doexiton(int sym, int uni); void switchFullscreen(); string turnstring(int i); int celldistance(cell *c1, cell *c2); int hyperbolic_celldistance(cell *c1, cell *c2); bool behindsphere(const transmatrix& V); extern hyperpoint pirateCoords; bool mouseout(); bool againstWind(cell *c2, cell *c1); // to, from transmatrix atscreenpos(ld x, ld y, ld size); hyperpoint mirrorif(const hyperpoint& V, bool b); #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); bool canPushThumperOn(cell *tgt, cell *thumper, cell *player); void pushThumper(cell *th, cell *cto); template T pick(T x, U... u) { std::initializer_list i = {x,u...}; return *(i.begin() + hrand(1+sizeof...(u))); } template bool among(T x, V y) { return x == y; } template bool among(T x, V y, U... u) { return x==y || among(x,u...); } eLand getNewSealand(eLand old); bool createOnSea(eLand old); namespace inv { extern bool on; extern bool usedForbidden; extern bool activating; extern array remaining; extern array usedup; void compute(); void applyBox(eItem it); extern int incheck; void check(int delta); void show(); } bool drawItemType(eItem it, cell *c, const transmatrix& V, int icol, int ticks, bool hidden); void initquickqueue(); void quickqueue(); int darkenedby(int c, int lev); extern int mousex, mousey; string generateHelpForItem(eItem it); bool graphglyph(); extern bool hiliteclick; extern int antialiaslines; extern color_t ringcolor, periodcolor, modelcolor; #include template int addHook(hookset*& m, int prio, const U& hook) { if(!m) m = new hookset (); while(m->count(prio)) { prio++; } (*m)[prio] = hook; return 0; } extern purehookset hooks_frame, hooks_stats, clearmemory, hooks_config, hooks_tests, hooks_removecells, hooks_initgame, hooks_calcparam, hooks_mainmenu, hooks_startmenu, hooks_markers; template void callhooks(hookset *h, U... args) { if(h) for(auto& p: *h) p.second(args...); } template V callhandlers(V zero, hookset *h, U&... args) { if(h) for(auto& p: *h) { auto z = p.second(args...); if(z != zero) return z; } return zero; } extern hookset *hooks_handleKey; extern hookset *hooks_drawcell; extern hookset *hooks_main; extern hookset *hooks_args; extern hookset *hooks_mark; extern hookset *hooks_nextland; extern hookset *hooks_welcome_message, *hooks_default_help; extern hookset *hooks_mouseover; extern ld shiftmul; void initcs(charstyle &cs); charstyle& getcs(int id = multi::cpid); struct msginfo { int stamp; time_t rtstamp; int gtstamp; int turnstamp; char flashout; char spamtype; int quantity; string msg; }; extern vector msgs; void flashMessages(); extern int lightat, safetyat; int watercolor(int phase); bool doHighlight(); void buildHelpText(); void buildCredits(); void setAppropriateOverview(); bool quitsaves(); extern const char* COLORBAR; int textwidth(int siz, const string &str); #define GLERR(call) glError(call, __FILE__, __LINE__) extern bool gtouched, mousepressed, mousemoved, actonrelease; extern bool inslider; struct colortable: vector { color_t& operator [] (int i) { i %= size(); if(i<0) i += size(); return ((vector&)(*this)) [i]; } const color_t& operator [] (int i) const { i %= size(); if(i<0) i += size(); return ((vector&)(*this)) [i]; } colortable(std::initializer_list v) : vector(v) {} colortable() : vector({0}) {} }; extern bool outoffocus; extern int frames; extern transmatrix playerV; extern bool didsomething; extern void drawStats(); extern int calcfps(); extern colortable distcolors, minecolors; extern eItem orbToTarget; extern eMonster monsterToSummon; void panning(hyperpoint hf, hyperpoint ht); extern transmatrix sphereflip; void initConfig(); void loadConfig(); extern bool auraNOGL; #if CAP_SDLJOY extern void initJoysticks(); extern bool autojoy; extern int joyx, joyy, panjoyx, panjoyy; extern movedir joydir; extern SDL_Joystick* sticks[8]; extern int numsticks; void closeJoysticks(); #endif void preparesort(); #if ISMOBILE==1 #define SHMUPTITLE "shoot'em up mode" #else #define SHMUPTITLE "shoot'em up / multiplayer / input" #endif bool dodrawcell(cell *c); void drawcell(cell *c, transmatrix V, int spinv, bool mirrored); extern double downspin; extern int frameid; extern bool leftclick; void clearMemory(); extern function keyhandler; #if CAP_SDL extern function joyhandler; #endif void gmodekeys(int sym, int uni); // 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) bool interpret_as_direction(int sym, int uni); int get_direction_key(int sym, int uni); void switchGL(); void switchFullscreen(); extern int cmode; namespace scores { void load(); } void gotoHelp(const string& h); void showCustomizeChar(); void showCheatMenu(); void showDisplayMode(); void showChangeMode(); void showEuclideanMenu(); void show3D(); void gameoverscreen(); void showJoyConfig(); void gamescreen(int darken); void showMission(); void handleKeyQuit(int sym, int uni); void handlePanning(int sym, int uni); #if ISMOBILE==1 namespace leader { void showMenu(); void handleKey(int sym, int uni); } #endif namespace mirror { cellwalker reflect(const cellwalker& cw); } bool inmirror(eLand l); bool inmirror(cell *c); bool inmirror(const cellwalker& cw); void queuemarkerat(const transmatrix& V, color_t col); void check_total_victory(); void applyBoxNum(int& i, string name = ""); extern int hinttoshow; bool isShmupLifeOrb(eItem it); int orbcharges(eItem it); color_t gradient(color_t c0, color_t c1, ld v0, ld v, ld v1); struct hint { time_t last; function usable; function display; function action; }; extern hint hints[]; int counthints(); void gainShard(cell *c2, const char *msg); 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; #endif void addaura(hyperpoint h, color_t col, int fd); void addauraspecial(hyperpoint h, color_t col, int dir); void drawaura(); void clearaura(); void drawBug(const cellwalker& cw, color_t col); void mainloop(); void mainloopiter(); extern bool showstartmenu; void selectLanguageScreen(); bool inscreenrange(cell *c); bool allowIncreasedSight(); bool allowChangeRange(); static inline bool orbProtection(eItem it) { return false; } // not implemented #if CAP_FIELD namespace windmap { void create(); static const int NOWINDBELOW = 8; static const int NOWINDFROM = 120; int getId(cell *c); int at(cell *c); } #endif extern int wavephase; void buildEquidistant(cell *c); void produceGhost(cell *c, eMonster victim, eMonster who); void sideAttack(cell *mf, int dir, eMonster who, int bonus, eItem orb); void sideAttack(cell *mf, int dir, eMonster who, int bonuskill); void orboflava(int i); void setland(cell *c, eLand l); eLand getNewLand(eLand old); extern bool randomPatternsMode; extern int isRandland(eLand l); extern vector buggycells; extern bool landUnlocked(eLand l); extern void describeCell(cell*); extern bool rlyehComplete(); extern int steplimit, cstep; template void limitgen(T... args) { if(steplimit) { cstep++; printf("%6d ", cstep); printf(args...); if(cstep == steplimit) buggyGeneration = true; } } eLand oppositeElement(eLand l, eLand l2); extern int hardness_empty(); extern eWall getElementalWall(eLand l); void gainItem(eItem it); void destroyTrapsOn(cell *c); void destroyTrapsAround(cell *c); extern int messagelogpos; void showMessageLog(); int getgametime(); string getgametime_s(int timespent = getgametime()); extern int stampbase; transmatrix cellrelmatrix(cell *c, int i); void terracottaAround(cell *c); double cellgfxdist(cell *c, int i); int ctof(cell *c); void modalDebug(cell *c); void push_debug_screen(); int getDistLimit(); void drawqueue(); #ifndef GL typedef float GLfloat; #endif typedef array glvec2; typedef array glvec3; typedef array glvec4; #if MAXDIM == 4 #define SHDIM 4 typedef glvec4 glvertex; #else #define SHDIM 3 typedef glvec3 glvertex; #endif struct texture_triangle { array v; array tv; texture_triangle(array _v, array _tv) : v(_v), tv(_tv) {} }; struct textureinfo { transmatrix M; int texture_id; vector triangles; vector vertices; vector tvertices; cell *c; vector matrices; // these are required to adjust to geometry changes int current_type, symmetries; }; struct drawqueueitem { PPR prio; color_t color; virtual void draw() = 0; virtual void draw_back() {} virtual void draw_pre() {} virtual ~drawqueueitem() {} void draw_darker(); virtual color_t outline_group() = 0; }; struct dqi_poly : drawqueueitem { ld band_shift; transmatrix V; const vector *tab; int offset, cnt; color_t outline; double linewidth; int flags; textureinfo *tinf; hyperpoint intester; void draw(); void gldraw(); void draw_back(); virtual color_t outline_group() { return outline; } }; struct dqi_line : drawqueueitem { ld band_shift; hyperpoint H1, H2; int prf; double width; void draw(); void draw_back(); virtual color_t outline_group() { return color; } }; struct dqi_string : drawqueueitem { string str; int x, y, shift, size, frame; int align; void draw(); virtual color_t outline_group() { return 1; } }; struct dqi_circle : drawqueueitem { int x, y, size, fillcolor; double linewidth; void draw(); virtual color_t outline_group() { return 2; } }; struct dqi_action : drawqueueitem { reaction_t action; dqi_action(const reaction_t& a) : action(a) {} void draw() { action(); } virtual color_t outline_group() { return 2; } }; extern int emeraldtable[100][7]; // extern cell *cwpeek(cellwalker cw, int dir); const eLand NOWALLSEP = laNone; const eLand NOWALLSEP_USED = laWhirlpool; bool hasbardir(cell *c); bool buildBarrierNowall(cell *c, eLand l2, int forced_dir = NODIR); bool checkBarriersBack(cellwalker bb, int q=5, bool cross = false); bool checkBarriersFront(cellwalker bb, int q=5, bool cross = false); bool quickfind(eLand l); void beCIsland(cell *c); bool isOnCIsland(cell *c); void generateTreasureIsland(cell *c); bool openplains(cell *c); void buildBigStuff(cell *c, cell *from); void setLandQuotient(cell *c); void setLandSphere(cell *c); void setLandWeird(cell *c); void moreBigStuff(cell *c); void setLandEuclid(cell *c); bool checkInTree(cell *c, int maxv); cell *findcompass(cell *c); int edgeDepth(cell *c); int compassDist(cell *c); void buildCamelot(cell *c); #define HAUNTED_RADIUS getDistLimit() #define UNKNOWN 65535 #if CAP_COMMANDLINE extern const char *scorefile; extern string levelfile; extern string picfile; extern const char *conffile; extern const char *musicfile; #endif extern string s0; extern int anthraxBonus; int celldistAlt(cell *c); int celldist(cell *c); int getHemisphere(cell *c, int which); namespace tactic { extern bool on; extern bool trailer; } namespace yendor { extern bool on; extern bool generating; extern eLand nexttostart; #define YF_DEAD 1 #define YF_WALLS 2 #define YF_END 4 #define YF_DEAD5 8 #define YF_NEAR_IVY 16 #define YF_NEAR_ELEM 32 #define YF_NEAR_OVER 64 #define YF_NEAR_RED 128 #define YF_REPEAT 512 #define YF_NEAR_TENT 1024 #define YF_START_AL 2048 #define YF_START_CR 4096 #define YF_CHAOS 8192 #define YF_RECALL 16384 #define YF_NEAR_FJORD 32768 #define YF_START_ANY (YF_START_AL|YF_START_CR) struct yendorlevel { eLand l; int flags; }; yendorlevel& clev(); } namespace clearing { struct clearingdata { cell *root; int dist; }; extern bool buggyplant; extern std::map bpdata; } namespace peace { extern bool on; } namespace princess { #define EPX 39 #define EPY 21 #define OUT_OF_PRISON 200 #define OUT_OF_PALACE 250 #define PRADIUS0 (141) #define PRADIUS1 (150) extern bool generating; extern bool gotoPrincess; extern bool forceMouse; extern bool challenge; extern bool squeaked; extern bool saved; extern bool nodungeon; extern int reviveAt; extern bool forceVizier; struct info { int id; // id of this info cell *prison; // where was the Princess locked heptagon *alt; // alt of the prison int bestdist; // best dist achieved int bestnear; // best dist achieved, by the player int value; // number of Rugs at 120 cell *princess; // where is the Princess currently }; int newInfo(cell *c); } #define GRAIL_FOUND 0x4000 #define GRAIL_RADIUS_MASK 0x3FFF int eudist(int sx, int sy); heptagon *createStep(heptagon *h, int d); cell *createMovR(cell *c, int d); bool ishept(cell *c); int cdist50(cell *c); bool polarb50(cell *c); bool isGravityLand(eLand l); bool isWarped(eLand l); bool isWarped(cell *c); struct hrmap { virtual heptagon *getOrigin() { return NULL; } virtual cell *gamestart() { return getOrigin()->c7; } virtual ~hrmap() { }; virtual vector& allcells() { return dcal; } virtual void verify() { } }; struct hrmap_hyperbolic : hrmap { heptagon *origin; eVariation mvar; hrmap_hyperbolic(); heptagon *getOrigin() { return origin; } ~hrmap_hyperbolic() { DEBMEM ( verifycells(origin); ) // printf("Deleting hyperbolic map: %p\n", this); dynamicval ph(variation, mvar); clearfrom(origin); } void verify() { verifycells(origin); } }; namespace irr { #if CAP_IRR extern ld density; extern ld quality; extern int cellcount; extern int place_attempts; extern int rearrange_max_attempts; extern int rearrange_less; void link_to_base(heptagon *h, heptspin base); void link_start(heptagon *h); void link_next(heptagon *h, int d); void may_link_next(heptagon *h, int d); void link_cell(cell *c, int d); void clear_links(heptagon *h); bool pseudohept(cell*); array get_masters(cell *c); bool ctof(cell* c); bool supports(eGeometry g); void visual_creator(); unsigned char density_code(); int celldist(cell *c, bool alts); extern int bitruncations_requested, bitruncations_performed; #endif } extern hrmap *currentmap; extern vector allmaps; // list all cells in distance at most maxdist, or until when maxcount cells are reached struct manual_celllister { vector lst; vector tmps; 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); lst.push_back(c); return true; } ~manual_celllister() { for(int i=0; ilistindex = tmps[i]; } }; struct celllister : manual_celllister { vector dists; void add_at(cell *c, int d) { if(add(c)) dists.push_back(d); } celllister(cell *orig, int maxdist, int maxcount, cell *breakon) { add_at(orig, 0); cell *last = orig; for(int i=0; i= maxcount || dists[i]+1 == maxdist) break; last = lst[isize(lst)-1]; } } } int getdist(cell *c) { return dists[c->listindex]; } }; hrmap *newAltMap(heptagon *o); #if CAP_FIELD #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); #endif const char *dnameof(eMonster m); const char *dnameof(eLand l); const char *dnameof(eWall w); const char *dnameof(eItem i); void runGeometryExperiments(); // z to close to this limit => do not draw #define BEHIND_LIMIT 1e-6 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; static const flagtype one_and_half = 32; }; struct land_validity_t { int quality_level; // 0 (dont show), 1 (1/2), 2 (ok), 3(1!) flagtype flags; string msg; }; extern vector landlist; template void generateLandList(T t); land_validity_t& land_validity(eLand l); bool isLandIngame(eLand l); bool inmirrororwall(eLand l); extern bool holdmouse; // what part of the compass does 'skip turn' static const auto SKIPFAC = .4; bool haveMobileCompass(); bool handleCompass(); inline bool sphereflipped() { return sphere && vid.alpha > 1.1; } int cellcolor(cell *c); transmatrix screenpos(ld x, ld y); extern ld backbrightness; void initcells(); void precalc(); extern const hyperpoint C02, C03; #define C0 (DIM == 2 ? C02 : C03) extern long long circlesize[100], disksize[100]; extern ld circlesizeD[10000]; void computeSizes(); #if CAP_FILES extern const char *scorefile; extern const char *conffile; extern string levelfile; extern string picfile; extern const char *musicfile; extern const char *loadlevel; #endif transmatrix spin(ld alpha); transmatrix xpush(ld alpha); transmatrix inverse(const transmatrix&); ld hdist(const hyperpoint& h1, const hyperpoint& h2); extern bool fixseed; extern eLand firstland0; extern int startseed; extern transmatrix heptmove[MAX_EDGE], hexmove[MAX_EDGE]; extern transmatrix invheptmove[MAX_EDGE], invhexmove[MAX_EDGE]; // heptspin hsstep(const heptspin &hs, int spin); extern void fixmatrix(transmatrix&); transmatrix rgpushxto0(const hyperpoint& H); string its(int i); double hdist0(const hyperpoint& mh); extern bool fading; extern ld fadeout; int itemclass(eItem i); int monsterclass(eMonster m); extern purehookset hooks_drawmap; extern hookset *hooks_music; extern hookset *hooks_prestats; extern purehookset hooks_fixticks; ld realradius(); void sdltogl(SDL_Surface *txt, struct glfont_t& f, int ch); void showStartMenu(); bool polara50(int x); bool polara50(cell *c); int fiftyval049(cell *c); namespace fieldpattern { pair fieldval(cell *c); } int emeraldval(cell *c); int inpair(cell *c, int colorpair); int snake_pair(cell *c); extern colortable nestcolors; #if CAP_TEXTURE namespace texture { enum eTextureState { tsOff, tsAdjusting, tsActive }; struct texture_data { GLuint textureid; int twidth; texture_data() { textureid = 0; twidth = 2048; } vector texture_pixels; color_t& get_texture_pixel(int x, int y) { return texture_pixels[(y&(twidth-1))*twidth+(x&(twidth-1))]; } vector> undos; vector > pixels_to_draw; bool loadTextureGL(); bool whitetexture(); bool readtexture(string tn); void saveRawTexture(string tn); void undo(); void undoLock(); void update(); }; struct texture_config { string texturename; string configname; color_t paint_color; eTextureState tstate; eTextureState tstate_max; transmatrix itt; color_t grid_color; color_t mesh_color; color_t master_color; color_t slave_color; int color_alpha; int gsplits; int recolor(color_t col); typedef tuple texture_parameters; texture_parameters orig_texture_parameters; map texture_map, texture_map_orig; set models; bool texture_tuned; string texture_tuner; vector tuned_vertices; bool apply(cell *c, const transmatrix &V, color_t col); void mark_triangles(); void clear_texture_map(); void perform_mapping(); void mapTextureTriangle(textureinfo &mi, const array& v, const array& tv, int splits); void mapTextureTriangle(textureinfo &mi, const array& v, const array& tv) { mapTextureTriangle(mi, v, tv, gsplits); } void mapTexture2(textureinfo& mi); void finish_mapping(); void true_remap(); void remap(); bool correctly_mapped; hyperpoint texture_coordinates(hyperpoint); void drawRawTexture(); void saveFullTexture(string tn); bool save(); bool load(); texture_data data; texture_config() { // argh, no member initialization in some of my compilers texturename = "textures/hyperrogue-texture.png"; configname = "textures/hyperrogue.txc"; itt = Id; paint_color = 0x000000FF; grid_color = 0; mesh_color = 0; master_color = 0xFFFFFF30; slave_color = 0xFF000008; color_alpha = 128; gsplits = 1; texture_tuned = false; } }; extern texture_config config; extern ld penwidth; extern bool saving; void showMenu(); void drawPixel(cell *c, hyperpoint h, color_t col); extern cell *where; // compute 'c' automatically, based on the hint in 'where' void drawPixel(hyperpoint h, color_t col); void drawLine(hyperpoint h1, hyperpoint h2, color_t col, int steps = 10); extern bool texturesym; extern cpatterntype cgroup; extern bool texture_aura; bool using_aura(); void start_editor(); } #endif dqi_line& queueline(const hyperpoint& H1, const hyperpoint& H2, color_t col, int prf = 0, PPR prio = PPR::LINE); dqi_action& queueaction(PPR prio, const reaction_t& action); void queuereset(eModel m, PPR prio); extern ld tessf, crossf, hexf, hcrossf, hexhexdist, hexvdist, hepvdist, rhexf; extern ld scalefactor, orbsize, floorrad0, floorrad1, zhexf; unsigned char& part(color_t& col, int i); transmatrix applyPatterndir(cell *c, const patterns::patterninfo& si); int pattern_threecolor(cell *c); int fiftyval200(cell *c); // T * C0, optimized inline hyperpoint tC0(const transmatrix &T) { hyperpoint z; for(int i=0; i void hrandom_shuffle(T* x, int n) { for(int k=1; k void eliminate_if(vector& data, U pred) { for(int i=0; i gamelog; extern time_t savetime; extern bool cblind; extern void save_memory(); namespace inv { void init(); } extern bool survivalist; extern bool hauntedWarning; extern bool usedSafety; namespace elec { extern int lightningfast; } extern int lastkills; extern map rosemap; extern int hardcoreAt; extern flagtype havewhat, hadwhat; extern int safetyseed; extern int lastsafety; extern int knighted; extern int rosephase; extern int rosewave; extern eItem localTreasureType(); extern void clearshadow(); extern bool seenSevenMines; extern vector dcal; // queue for cpdist extern vector pathq; // queue for pathdist extern vector > butterflies; extern vector crush_now, crush_next; extern void shrand(int seed); extern eLand safetyland; extern int sagephase; extern int lastsize; extern int noiseuntil; hyperpoint xpush0(ld x); hyperpoint ypush0(ld x); transmatrix xspinpush(ld alpha, ld x); hyperpoint xspinpush0(ld alpha, ld x); #define DF_INIT 0 // always display these #define DF_MSG 0 // always display these #define DF_STEAM 1 #define DF_GRAPH 2 #define DF_TURN 4 #define DF_FIELD 8 #if ISANDROID #define DEBB(r,x) #else #define DEBB(r,x) { if(debugfile && (!(r) || (debugflags & (r)))) { fprintf x; fflush(debugfile); } } #endif extern FILE *debugfile; extern int debugflags; int gmod(int i, int j); int gdiv(int i, int j); extern walltype winf[walltypes]; extern vector land_tac; string llts(long long i); void clearMemoRPM(); extern int randompattern[landtypes]; extern int pair_to_vec(int x, int y); typedef pair euc_pointer; euc_pointer euclideanAt(int vec); euc_pointer euclideanAtCreate(int vec); bool isCyclic(eLand l); bool generateAll(eLand l); void extendcheck(cell *c); void extendNowall(cell *c); bool isbar4(cell *c); void extendBarrierFront(cell *c); void extendBarrierBack(cell *c); void extendCR5(cell *c); bool mirrorwall(cell *c); extern void setbarrier(cell *c); extern function call_initgame; extern void initializeCLI(); static const int max_vec = (1<<14); string helptitle(string s, color_t col); pair cell_to_pair(cell *c); extern bool nohud, nofps, nomap; template array make_array(T a, T b, T c) { array x; x[0] = a; x[1] = b; x[2] = c; return x; } template array make_array(T a, T b) { array x; x[0] = a; x[1] = b; return x; } extern cell *lastmountpos[MAXPLAYER]; extern const hyperpoint Hypc; ld det(const transmatrix& T); void queuechr(const hyperpoint& h, int size, char chr, color_t col, int frame = 0); string fts(float x); bool model_needs_depth(); hyperpoint hpxy(ld x, ld y); hyperpoint hpxy3(ld x, ld y, ld z); ld sqhypot_d(const hyperpoint& h, int d); ld hypot_d(const hyperpoint& h, int d); transmatrix pushxto0(const hyperpoint& H); transmatrix rpushxto0(const hyperpoint& H); transmatrix spintox(const hyperpoint& H); transmatrix ypush(ld alpha); #if CAP_SURFACE namespace surface { enum eShape { dsNone, dsTractricoid, dsDini, dsKuen, dsHyperlike, dsHyperboloid, dsHemisphere, dsCrystal }; extern eShape sh; void show_surfaces(); void run_shape(eShape); extern ld hyper_b, dini_b; } #endif struct stringpar { string v; stringpar(string s) : v(s) { } stringpar(const char* s) : v(s) { } stringpar(eMonster m) { v= minf[m].name; } stringpar(eLand l) { v= linf[l].name; } stringpar(eWall w) { v= winf[w].name; } stringpar(eItem i) { v= iinf[i].name; } }; string XLAT(string x); string XLAT(string x, stringpar p1); string XLAT(string x, stringpar p1, stringpar p2); string XLAT(string x, stringpar p1, stringpar p2, stringpar p3); string XLAT(string x, stringpar p1, stringpar p2, stringpar p3, stringpar p4); string XLAT(string x, stringpar p1, stringpar p2, stringpar p3, stringpar p4, stringpar p5); namespace gp { typedef pair loc; loc operator+(loc e1, loc e2); loc operator-(loc e1, loc e2); loc operator*(loc e1, loc e2); extern loc eudir(int dir); #if CAP_GP void compute_geometry(); void extend_map(cell *c, int d); extern loc param; extern int area; extern int pseudohept_val(cell *); extern int last_dir(cell *c); extern void configure(); extern ld alpha; extern transmatrix Tf[MAX_EDGE][32][32][6]; struct local_info { int last_dir; loc relative; int first_dir; int total_dir; }; local_info get_local_info(cell *c); const char *disp(loc at); void be_in_triangle(local_info& li); int compute_dist(cell *c, int master_function(cell*)); int solve_triangle(int dmain, int d0, int d1, loc at); hyperpoint get_master_coordinates(cell *c); loc univ_param(); #endif int dist_1(), dist_2(), dist_3(); array get_masters(cell *c); extern string operation_name(); } int get_sightrange(); int get_sightrange_ambush(); int gamerange(); int numplayers(); extern int base_distlimit; bool has_nice_dual(); extern hyperpoint mid(const hyperpoint &h1, const hyperpoint &h2); void loadNewConfig(FILE *f); 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() {}; }; typedef vector> saverlist; extern saverlist savers; extern string ftssmart(ld x); string itsh(int i); #if CAP_CONFIG template struct dsaver : supersaver { T& val; T dft; bool dosave() { return val != dft; } void reset() { val = dft; } dsaver(T& val) : val(val) { } }; template struct saver : dsaver {}; template void addsaver(T& i, U name, V dft) { auto s = make_shared> (i); s->dft = dft; s->name = name; savers.push_back(s); } template void addsaver(T& i, string name) { addsaver(i, name, i); } template struct saverenum : supersaver { T& val; T dft; bool dosave() { return val != dft; } void reset() { val = dft; } saverenum(T& v) : val(v) { } string save() { return its(int(val)); } void load(const string& s) { val = (T) atoi(s.c_str()); } }; template void addsaverenum(T& i, U name, T dft) { auto s = make_shared> (i); s->dft = dft; s->name = name; savers.push_back(s); } template void addsaverenum(T& i, U name) { addsaverenum(i, name, i); } template<> struct saver : dsaver { saver(int& val) : dsaver(val) { } string save() { return its(val); } void load(const string& s) { val = atoi(s.c_str()); } }; template<> struct saver : dsaver { saver(char& val) : dsaver(val) { } string save() { return its(val); } void load(const string& s) { val = atoi(s.c_str()); } }; template<> struct saver : dsaver { saver(bool& val) : dsaver(val) { } string save() { return val ? "yes" : "no"; } void load(const string& s) { val = isize(s) && s[0] == 'y'; } }; template<> struct saver : dsaver { saver(unsigned& val) : dsaver(val) { } string save() { return itsh(val); } void load(const string& s) { val = (unsigned) strtoll(s.c_str(), NULL, 16); } }; template<> struct saver : dsaver { saver(string& val) : dsaver(val) { } string save() { return val; } void load(const string& s) { val = s; } }; template<> struct saver : dsaver { saver(ld& val) : dsaver(val) { } string save() { return ftssmart(val); } void load(const string& s) { if(s == "0.0000000000e+000") ; // ignore! else val = atof(s.c_str()); } }; #endif extern vector> ptds; extern ld intval(const hyperpoint &h1, const hyperpoint &h2); transmatrix euscalezoom(hyperpoint h); transmatrix euaffine(hyperpoint h); transmatrix eupush(ld x, ld y); transmatrix eupush3(ld x, ld y, ld z); transmatrix eupush(hyperpoint h); transmatrix rspintox(const hyperpoint& H); transmatrix gpushxto0(const hyperpoint& H); transmatrix build_matrix(hyperpoint h1, hyperpoint h2, hyperpoint h3); hyperpoint normalize(hyperpoint H); extern ld hrandf(); namespace glhr { struct glmatrix { GLfloat a[4][4]; GLfloat* operator[] (int i) { return a[i]; } const GLfloat* operator[] (int i) const { return a[i]; } GLfloat* as_array() { return a[0]; } const GLfloat* as_array() const { return a[0]; } }; enum class shader_projection { standard, band, halfplane, standardH3, standardR3, standardS30, standardS31, standardS32, standardS33, MAX }; extern shader_projection new_shader_projection; void set_depthtest(bool b); glmatrix translate(ld x, ld y, ld z); void color2(color_t color, ld scale = 1); void be_nontextured(shader_projection sp = new_shader_projection); void be_textured(shader_projection sp = new_shader_projection); void set_modelview(const glmatrix& m); hyperpoint gltopoint(const glvertex& t); glvertex pointtogl(const hyperpoint& t); inline glvertex makevertex(GLfloat x, GLfloat y, GLfloat z) { #if SHDIM == 3 return glvertex({x,y,z}); #else return glvertex({x,y,z,1}); #endif } struct colored_vertex { glvertex coords; glvec4 color; colored_vertex(GLfloat x, GLfloat y, GLfloat r, GLfloat g, GLfloat b) { coords[0] = x; coords[1] = y; coords[2] = current_display->scrdist; color[0] = r; color[1] = g; color[2] = b; color[3] = 1; } }; struct textured_vertex { glvertex coords; glvec2 texture; }; struct ct_vertex { glvertex coords; glvec4 color; glvec2 texture; ct_vertex(const hyperpoint& h, ld x1, ld y1, ld col) { coords = pointtogl(h); texture[0] = x1; texture[1] = y1; color[0] = color[1] = color[2] = col; color[3] = 1; } }; void prepare(vector& v); void prepare(vector& v); void prepare(vector& v); } void prettypoly(const vector& t, color_t fillcol, color_t linecol, int lev); #if CAP_SHAPES dqi_poly& queuepolyat(const transmatrix& V, const hpcshape& h, color_t col, PPR prio); #endif dqi_poly& queuetable(const transmatrix& V, const vector& f, int cnt, color_t linecol, color_t fillcol, PPR prio); #if CAP_SHAPES struct floorshape; struct qfloorinfo { transmatrix spin; const hpcshape *shape; const floorshape *fshape; textureinfo *tinf; int usershape; }; extern qfloorinfo qfi; struct hpcshape { int s, e; PPR prio; int flags; hyperpoint intester; }; extern hpcshape shFullCross[2]; #endif int fix6(int a); int fix7(int a); int fixdir(int a, cell *c); cell *newCell(int type, heptagon *master); extern color_t qpixel_pixel_outside; void queuechr(int x, int y, int shift, int size, char chr, color_t col, int frame = 0, int align = 8); int zebra3(cell *c); int geosupport_threecolor(); int geosupport_football(); bool geosupport_chessboard(); bool ishex1(cell *c); namespace fieldpattern { int fieldval_uniq(cell *c); int fieldval_uniq_rand(cell *c, int d); } bool warptype(cell *c); bool horo_ok(); ld master_to_c7_angle(); extern int mutantphase; void resize_screen_to(int x, int y); extern bool canvas_invisible; extern cell *pd_from; namespace daily { extern bool on; extern int daily_id; void setup(); void split(); void gifts(); void turnoff(); void showMenu(); int find_daily_lbid(int id); bool prevent_spawn_treasure_on(cell *c); void handleQuit(int sev); void uploadscore(bool really_final); } enum eOrbLandRelation { olrForbidden, // never appears: forbidden olrDangerous, // never appears: would be dangerous olrUseless, // never appears: useless here olrNoPrizes, // no prizes in this land olrNoPrizeOrb,// orb not allowed as a prize olrPrize25, // prize for collecting 25 olrPrize3, // prize for collecting 3 olrNative, // native orb in this land olrNative1, // native orb in this land (1) olrGuest, // extra orb in this land olrPNative, // Land of Power: native olrPBasic, // Land of Power: basic orbs olrPPrized, // Land of Power: prized orbs olrPNever, // Land of Power: foreign orbs olrHub, // hub lands olrMonster, // available from a monster olrAlways, // always available olrBurns // burns }; namespace torusconfig { extern int sdx, sdy; enum eTorusMode : char { tmSingleHex, tmSingle, tmSlantedHex, tmStraight, tmStraightHex, tmKlein, tmKleinHex, tmCylinder, tmCylinderHex, tmMobius, tmMobiusHex, }; extern eTorusMode torus_mode; extern void activate(); struct torusmode_info { string name; flagtype flags; }; extern vector 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(); } #if CAP_FIELD namespace fieldpattern { extern int current_extra; struct primeinfo { int p; int cells; bool squared; }; struct fgeomextra { eGeometry base; vector primes; int current_prime_id; fgeomextra(eGeometry b, int i) : base(b), current_prime_id(i) {} }; extern vector fgeomextras; extern void enableFieldChange(); } #endif bool incompatible(eLand l1, eLand l2); eOrbLandRelation getOLR(eItem it, eLand l); struct plainshape; void clear_plainshape(plainshape& gsh); #if CAP_GP void build_plainshape(plainshape& gsh, gp::local_info& li); #endif namespace gp { void clear_plainshapes(); plainshape& get_plainshape(); } extern bool debug_geometry; #if CAP_SHAPES dqi_poly& queuepoly(const transmatrix& V, const hpcshape& h, color_t col); dqi_poly& queuepolyat(const transmatrix& V, const hpcshape& h, color_t col, PPR prio); #endif void queuestr(const hyperpoint& h, int size, const string& chr, color_t col, int frame = 0); void queuechr(const transmatrix& V, double size, char chr, color_t col, int frame = 0); extern bool just_gmatrix; void drawStandard(); 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 pop_game(); void push_game(); void start_game(); void stop_game(); void switch_game_mode(char switchWhat); void stop_game_and_switch_mode(char switchWhat = rg::nothing); // stop_game + switch_game_mode void restart_game(char switchWhat = rg::nothing); // popAllScreens + popAllGames + stop_game + switch_game_mode + start_game // these work as stop_game_and_switch_mode void set_variation(eVariation); void set_geometry(eGeometry); void generate_floorshapes(); void drawArrowTraps(); void drawBlizzards(); struct blizzardcell; extern vector arrowtraps; extern map blizzardcells; extern vector bcells; void set_blizzard_frame(cell *c, int frameid); #define SIDE_SLEV 0 #define SIDE_WALL 3 #define SIDE_LAKE 4 #define SIDE_LTOB 5 #define SIDE_BTOI 6 #define SIDE_WTS3 7 #define SIDEPARS 8 #if CAP_SHAPES struct floorshape { bool is_plain; int shapeid; PPR prio; vector b, shadow, side[SIDEPARS], gpside[SIDEPARS][MAX_EDGE]; floorshape() { prio = PPR::FLOOR; } }; extern vector all_plain_floorshapes; extern vector all_escher_floorshapes; struct plain_floorshape : floorshape { ld rad0, rad1; plain_floorshape() { is_plain = true; all_plain_floorshapes.push_back(this); } void configure(ld r0, ld r1) { rad0 = r0; rad1 = r1; } }; // noftype: 0 (shapeid2 is heptagonal or just use shapeid1), 1 (shapeid2 is pure heptagonal), 2 (shapeid2 is Euclidean), 3 (shapeid2 is hexagonal) struct escher_floorshape : floorshape { int shapeid0, shapeid1, noftype, shapeid2; ld scale; escher_floorshape(int s0, int s1, int noft=0, int s2=0) : shapeid0(s0), shapeid1(s1), noftype(noft), shapeid2(s2) { all_escher_floorshapes.push_back(this); scale = 1; is_plain = false; } }; extern plain_floorshape shFloor, shMFloor, shMFloor2, shMFloor3, shMFloor4, shFullFloor, shBigTriangle, shTriheptaFloor, shBigHepta; extern escher_floorshape shDragonFloor, shPowerFloor, shRedRockFloor[3]; #endif #if ISMOBILE bool buttonclicked; void gdpush(int t); #endif extern int fontscale; bool confusingGeometry(); int revhint(cell *c, int hint); extern int pathlock; extern void computePathdist(eMonster m); extern void onpath(cell *c, int d); extern void clear_pathdata(); struct pathdata { void checklock() { if(pd_from) pd_from = NULL, clear_pathdata(); if(pathlock) printf("path error\n"); pathlock++; } ~pathdata() { pathlock--; clear_pathdata(); } pathdata(eMonster m) { checklock(); computePathdist(m); } pathdata(int i) { checklock(); } }; extern int timetowait; extern vector > airmap; extern void compute_graphical_distance(); extern ld scalef; struct help_extension { char key; string text; string subtext; color_t color; reaction_t action; help_extension() { color = forecolor; } help_extension(char k, string t, reaction_t a) : key(k), text(t), action(a) { color = forecolor; } }; extern vector help_extensions; namespace gamestack { bool pushed(); } namespace geom3 { extern ld BODY; extern ld depth, camera, wall_height; } void queuestr(const transmatrix& V, double size, const string& chr, color_t col, int frame = 0, int align = 8); void queuestr(int x, int y, int shift, int size, string str, color_t col, int frame = 0, int align = 8); ld frac(ld x); extern color_t poly_outline; #if CAP_SHAPES extern hpcshape shDisk, shTriangle, shHeptaMarker, shSnowball, shDiskT, shDiskS, shDiskSq, shDiskM, shTinyBird, shTinyShark, shAsymmetric; #endif extern std::mt19937 hrngen; bool anglestraight(cell *c, int d1, int d2); hyperpoint randomPointIn(int t); void buildpolys(); bool compute_relamatrix(cell *src, cell *tgt, int direction_hint, transmatrix& T); extern bool need_reset_geometry; extern ld hexshift; extern bool noshadow, bright, nohelp, dont_face_pc; extern void switchHardcore(); extern bool shaderside_projection; void generateAlts(heptagon *h, int levs = IRREGULAR ? 1 : S3-3, bool link_cdata = true); namespace ors { extern int mode; extern string choices[]; void show(); void apply(); void check_orientation(); void unrotate(transmatrix& T); void rerotate(transmatrix& T); void reset(); } bool saved_tortoise_on(cell *c); #define RING(i) for(double i=0; i<=S84+1e-6; i+=S3 * pow(.5, vid.linequality)) #define REVRING(i) for(double i=S84; i>=-1e-6; i-=S3 * pow(.5, vid.linequality)) #define PRING(i) for(double i=0; i<=S84+1e-6; i+= pow(.5, vid.linequality)) #define REVPRING(i) for(double i=S84; i>=-1e-6; i-=pow(.5, vid.linequality)) #if CAP_BT void horopoint(ld y, ld x); hyperpoint get_horopoint(ld y, ld x); hyperpoint get_horopoint3(ld y, ld x, ld z); namespace binary { heptagon *createStep(heptagon *parent, int d); #if MAXDIM == 4 heptagon *createStep3(heptagon *parent, int d); #endif transmatrix parabolic(ld u); transmatrix parabolic3(ld u, ld v); extern ld btrange, btrange_cosh; } #endif #if MAXDIM == 4 namespace euclid3 { heptagon *createStep(heptagon *parent, int d); hrmap* new_map(); void draw(); } #endif namespace arcm { #if CAP_ARCM struct archimedean_tiling { int coloring; string symbol; vector faces; vector adj; vector invert; vector nflags; bool have_ph, have_line, have_symmetry; int real_faces; int real_face_type; int repetition; int N; ld euclidean_angle_sum; vector flags; vector>> adjacent; vector>> triangles; void make_match(int a, int i, int b, int j); void prepare(); void compute_geometry(); void parse(); void parse(string s) { symbol = s; parse(); } ld edgelength; vector inradius, circumradius, alphas; int matches[30][30]; int periods[30]; int tilegroup[30], groupoffset[30], tilegroups; int errors; string errormsg; pair& get_adj(heptagon *h, int cid); pair& get_adj(heptspin hs) { return get_adj(hs.at, hs.spin); } pair& get_triangle(heptagon *h, int cid); pair& get_triangle(heptspin hs) { return get_triangle(hs.at, hs.spin); } pair& get_triangle(const pair& p, int delta = 0); pair& get_adj(const pair& p, int delta = 0); int support_threecolor(); int support_threecolor_bitruncated(); int support_football(); bool support_chessboard(); void regroup(); string world_size(); eGeometryClass get_class(); ld scale(); }; extern archimedean_tiling current; extern map> archimedean_gmatrix; void initialize(heptagon *root); transmatrix relative_matrix(heptagon *h1, heptagon *h2); short& id_of(heptagon *); void draw(); void create_adjacent(heptagon*, int); int fix(heptagon *h, int spin); #endif } namespace crystal { #if CAP_CRYSTAL static const int MAXDIM = 7; typedef array coord; static const coord c0 = {}; typedef array ldcoord; static const ldcoord ldc0 = {}; heptagon *get_heptagon_at(coord c); coord get_coord(heptagon *h); ldcoord get_ldcoord(cell *c); extern colortable coordcolors; extern ld compass_probability; extern bool view_coordinates; color_t colorize(cell *c); int precise_distance(cell *c1, cell *c2); ld space_distance(cell *c1, cell *c2); hrmap *new_map(); void create_step(heptagon *h, int d); void build_rugdata(); void apply_rotation(const transmatrix t); void switch_z_coordinate(); void next_home_orientation(); void flip_z(); void set_land(cell *c); int dist_alt(cell *c); int dist_relative(cell *c); void show(); void init_rotation(); string get_table_volume(); string get_table_boundary(); bool pure(); ld compass_angle(); string compass_help(); void may_place_compass(cell *c); void centerrug(ld aspd); vector build_shortest_path(cell *c1, cell *c2); #endif } hyperpoint get_warp_corner(cell *c, int cid); hyperpoint get_corner_position(cell *c, int cid, ld cf = 3); int decodeId(heptagon* h); heptagon* encodeId(int id); void virtualRebaseSimple(heptagon*& base, transmatrix& at); extern bool game_active, playerfound; string bygen(reaction_t h); #if CAP_URL void open_url(string s); #endif // HyperRogue streams struct hstream { virtual void write_char(char c) = 0; virtual void write_chars(const char* c, size_t q) { while(q--) write_char(*(c++)); } virtual char read_char() = 0; virtual void read_chars(char* c, size_t q) { while(q--) *(c++) = read_char(); } template void write(const T& t) { hwrite(*this, t); } template void read(T& t) { hread(*this, t); } template T get() { T t; hread(*this, t); return t; } template T get_raw() { T t; hread_raw(*this, t); return t; } }; template void hwrite_raw(hstream& hs, const T& c) { hs.write_chars((char*) &c, sizeof(T)); } template void hread_raw(hstream& hs, T& c) { hs.read_chars((char*) &c, sizeof(T)); } template::value || std::is_enum::value>::type> void hwrite(hstream& hs, const T& c) { hwrite_raw(hs, c); } template::value || std::is_enum::value>::type> void hread(hstream& hs, T& c) { hread_raw(hs, c); } inline void hwrite(hstream& hs, const string& s) { hs.write_char(isize(s)); for(char c: s) hs.write_char(c); } inline void hread(hstream& hs, string& s) { s = ""; int l = (unsigned char) hs.read_char(); for(int i=0; i void hwrite(hstream& hs, const array& a) { for(auto &ae: a) hwrite(hs, ae); } template void hread(hstream& hs, array& a) { for(auto &ae: a) hread(hs, ae); } template void hwrite(hstream& hs, const vector& a) { hwrite(hs, isize(a)); for(auto &ae: a) hwrite(hs, ae); } template void hread(hstream& hs, vector& a) { a.resize(hs.get()); for(auto &ae: a) hread(hs, ae); } template void hwrite(hstream& hs, const map& a) { hwrite(hs, isize(a)); for(auto &ae: a) hwrite(hs, ae.first, ae.second); } template void hread(hstream& hs, map& a) { a.clear(); int N = hs.get(); for(int i=0; i void hwrite(hstream& hs, const C& c, const C1& c1, const CS&... cs) { hwrite(hs, c); hwrite(hs, c1, cs...); } template void hread(hstream& hs, C& c, C1& c1, CS&... cs) { hread(hs, c); hread(hs, c1, cs...); } struct hstream_exception : std::exception { hstream_exception() {} }; struct fhstream : hstream { FILE *f; virtual void write_char(char c) { write_chars(&c, 1); } virtual void write_chars(const char* c, size_t i) { if(fwrite(c, i, 1, f) != 1) throw hstream_exception(); } virtual void read_chars(char* c, size_t i) { if(fread(c, i, 1, f) != 1) throw hstream_exception(); } virtual char read_char() { char c; read_chars(&c, 1); return c; } fhstream() { f = NULL; } fhstream(const string pathname, const char *mode) { f = fopen(pathname.c_str(), mode); } ~fhstream() { if(f) fclose(f); } }; struct shstream : hstream { string s; int pos; shstream() { pos = 0; } virtual void write_char(char c) { s += c; } virtual char read_char() { if(pos == isize(s)) throw hstream_exception(); return s[pos++]; } }; inline void print(hstream& hs) {} template string sprint(const CS&... cs) { shstream hs; print(hs, cs...); return hs.s; } template void print(hstream& hs, const C& c, const C1& c1, const CS&... cs) { print(hs, c); print(hs, c1, cs...); } template void println(hstream& hs, const CS&... cs) { print(hs, cs...); hs.write_char('\n'); } // copied from: https://stackoverflow.com/questions/16387354/template-tuple-calling-a-function-on-each-element namespace detail { template struct seq { }; template struct gen_seq : gen_seq { }; template struct gen_seq<0, Is...> : seq { }; template void for_each(T&& t, F f, seq) { auto l = { (f(std::get(t)), 0)... }; ignore(l); } } template void for_each_in_tuple(std::tuple const& t, F f) { detail::for_each(t, f, detail::gen_seq()); } inline void print(hstream& hs, const string& s) { hs.write_chars(s.c_str(), isize(s)); } inline void print(hstream& hs, int i) { print(hs, its(i)); } inline void print(hstream& hs, ld x) { print(hs, fts(x)); } template void print(hstream& hs, const walker& w) { print(hs, "[", w.at, "/", w.spin, "/", w.mirrored, "]"); } struct comma_printer { bool first; hstream& hs; template void operator() (const T& t) { if(first) first = false; else print(hs, ","); print(hs, t); } comma_printer(hstream& hs) : first(true), hs(hs) {} }; template void print(hstream& hs, const array& a) { print(hs, "("); comma_printer c(hs); for(const T& t: a) c(t); print(hs, ")"); } template void print(hstream& hs, const vector& a) { print(hs, "("); comma_printer c(hs); for(const T& t: a) c(t); print(hs, ")"); } inline void print(hstream& hs, const hyperpoint h) { print(hs, (const array&)h); } inline void print(hstream& hs, const transmatrix T) { print(hs, "("); comma_printer c(hs); for(int i=0; i void print(hstream& hs, const pair & t) { print(hs, "(", t.first, ",", t.second, ")"); } template void print(hstream& hs, const tuple & t) { print(hs, "("); comma_printer p(hs); for_each_in_tuple(t, p); print(hs, ")"); } #ifndef SPECIAL_LOGGER inline void special_log(char c) { putchar(c); } #endif struct logger : hstream { int indentation; bool doindent; logger() { doindent = false; } virtual void write_char(char c) { if(doindent) { doindent = false; for(int i=0; itype, ":", cw.spin, ":", cw.mirrored, "]"); else print(hs, "[NULL]"); } struct indenter { dynamicval ind; indenter(int i = 2) : ind(hlog.indentation, hlog.indentation + (i)) {} }; void appendHelp(string s); transmatrix rspintox(const hyperpoint& H); extern bool playermoved; extern int tidalsize; extern void calcTidalPhase(); void curvepoint(const hyperpoint& H1); dqi_poly& queuecurve(color_t linecol, color_t fillcol, PPR prio); ld cos_auto(ld x); ld sin_auto(ld x); ld tan_auto(ld x); ld asin_auto(ld x); ld atan_auto(ld x); ld atan2_auto(ld x); ld atan2(hyperpoint h); namespace anims { #if CAP_ANIMATIONS void apply(); void rollback(); void show(); bool any_on(); bool any_animation(); bool center_music(); extern string animfile; extern int noframes; extern ld period, cycle_length, parabolic_length, rug_angle, circle_radius, circle_spins; #else static bool any_on() { return false; } static void rollback() { } static bool center_music() { return false; } static bool any_animation() { return false; } static void apply() { } #endif } #if CAP_STARTANIM namespace startanims { extern reaction_t current; void pick(); } #endif extern int animation_lcm; extern ld animation_factor; ld parseld(const string& s); pair vec_to_pair(int vec); struct bignum { static const int BASE = 1000000000; static const long long BASE2 = BASE * (long long)BASE; vector digits; bignum() {} bignum(int i) : digits() { digits.push_back(i); } void be(int i) { digits.resize(1); digits[0] = i; } bignum& operator +=(const bignum& b); void addmul(const bignum& b, int factor); string get_str(int max_length); bool operator < (const bignum&) const; ld leading() const { switch(isize(digits)) { case 0: return 0; case 1: return digits.back(); default: return digits.back() + ld(digits[isize(digits)-2]) / BASE; } } ld approx() const { return leading() * pow(BASE, isize(digits) - 1); } ld log_approx() const { return log(leading()) * log(BASE) * (isize(digits) - 1); } ld operator / (const bignum& b) const { return leading() / b.leading() * pow(BASE, isize(digits) - isize(b.digits)); } int approx_int() const { if(isize(digits) > 1) return BASE; if(digits.empty()) return 0; return digits[0]; } long long approx_ll() const { if(isize(digits) > 2) return BASE2; if(digits.empty()) return 0; if(isize(digits) == 1) return digits[0]; return digits[0] + digits[1] * (long long) BASE; } friend inline bignum operator +(bignum a, const bignum& b) { a.addmul(b, 1); return a; } friend inline bignum operator -(bignum a, const bignum& b) { a.addmul(b, -1); return a; } }; struct expansion_analyzer { vector gettype(cell *c); int N; vector samples; map, int> codeid; vector > children; int rootid, diskid; int coefficients_known; vector coef; int valid_from, tested_to; ld growth; int sample_id(cell *c); void preliminary_grouping(); void reduce_grouping(); vector> descendants; bignum& get_descendants(int level); bignum& get_descendants(int level, int type); void find_coefficients(); void reset(); expansion_analyzer() { reset(); } string approximate_descendants(int d, int max_length); void view_distances_dialog(); ld get_growth(); private: bool verify(int id); int valid(int v, int step); }; extern expansion_analyzer expansion; int towerval(cell *c, const cellfunction& cf); int parent_id(cell *c, int which, const cellfunction& cf); extern int sibling_limit; extern void set_sibling_limit(); int type_in_reduced(expansion_analyzer& ea, cell *c, const function& f); namespace ts { cell *verified_add(cell *c, int which, int bonus, const cellfunction& cf); cell *add(cell *c, int which, int bonus, const cellfunction& cf); inline cell *left_parent(cell *c, const cellfunction& cf) { return verified_add(c, 1, 0, cf); } inline cell *right_parent(cell *c, const cellfunction& cf) { return verified_add(c, -1, 0, cf); } cell *left_of(cell *c, const cellfunction& cf); cell *right_of(cell *c, const cellfunction& cf); cell *child_number(cell *c, int id, const cellfunction& cf); } void generate_around(cell *c); int euclidAlt(short x, short y); int cylinder_alt(cell *c); struct exp_parser { string s; int at; exp_parser() { at = 0; } map extra_params; bool ok() { return at == isize(s); } char next(int step=0) { if(at >= isize(s)-step || at == -1) return 0; else return s[at+step]; } bool eat(const char *c) { int orig_at = at; while(*c && *c == next()) at++, c++; if(*c == 0) return true; else at = orig_at; return false; } cld parse(int prio = 0); cld parsepar() { cld res = parse(); if(next() != ')') { at = -1; return res; } at++; return res; } }; #if CAP_COMPLEX2 namespace brownian { const int level = 5; void init(cell *c); void build(cell *c, int d); void explosion(cell *c, int x); }; #else namespace brownian { inline void dissolve_brownian(cell*, int) {}; inline void build(cell *c, int d) {} inline void init(cell *c) {} } #endif #define ONEMPTY if(d == 7 && passable(c, NULL, 0) && !safety && !reptilecheat) extern bool reptilecheat; void enable_cheat(); extern int cells_drawn; void menuitem_sightrange(char c = 'r'); bool invis_point(const hyperpoint h); bool invalid_point(const hyperpoint h); bool invalid_point(const transmatrix T); bool in_smart_range(const transmatrix& T); void curvepoint(const hyperpoint& H1); dqi_poly& queuecurve(color_t linecol, color_t fillcol, PPR prio); bool haveaura(); string parser_help(); static const ld degree = M_PI / 180; void show_color_dialog(); extern ld band_shift; int cone_side(const hyperpoint H); void fix_the_band(transmatrix& T); struct bandfixer { dynamicval bw; bandfixer(transmatrix& T) : bw(band_shift, band_shift) { fix_the_band(T); } }; inline void delayed_geo_reset() { need_reset_geometry = true; } extern unordered_map params; namespace dq { extern set visited; extern queue> drawqueue; void enqueue(heptagon *h, const transmatrix& T); } typedef pair named_functionality; inline named_functionality named_dialog(string x, reaction_t dialog) { return named_functionality(x, [dialog] () { pushScreen(dialog); }); } extern hookset *hooks_o_key; named_functionality get_o_key(); hyperpoint nearcorner(cell *c, int i); extern bool showquotients; bool do_draw(cell *c, const transmatrix& T); ld sintick(int period, ld phase = 0); #if CAP_RACING namespace racing { extern bool on, player_relative, track_ready, guiding, standard_centering; extern ld race_advance, race_angle; extern int ghosts_to_show, ghosts_to_save; void generate_track(); void configure_race(); void prepare_subscreens(); extern vector track; extern int current_player; extern vector race_lands; extern string track_code; extern int race_start_tick, race_finish_tick[MAXPLAYER]; void race_won(); void apply_seed(); string racetimeformat(int t); void add_debug(cell *c); void displayScore(eLand l); } bool subscreen_split(reaction_t for_each_subscreen); #else // static bool on = false: emits a warning // static const bool on = false: no warning, but does not allow assignment namespace racing { static const always_false on; } inline bool subscreen_split(reaction_t for_each_subscreen) { return false; } #endif bool in_gravity_zone(cell *c); bool normal_gravity_at(cell *c); void build_pool(cell *c, bool with_boat); void createArrowTrapAt(cell *c, eLand land); bool no_barriers_in_radius(cell *c, int rad); }