mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2024-11-15 17:54:48 +00:00
4908 lines
129 KiB
C++
4908 lines
129 KiB
C++
// This is the main header file of HyperRogue. Mostly everything is dumped here.
|
|
// It is quite chaotic.
|
|
|
|
// version numbers
|
|
#define VER "11.0j"
|
|
#define VERNUM 11010
|
|
#define VERNUM_HEX 0xA60A
|
|
|
|
#include <stdarg.h>
|
|
#include "hyper_function.h"
|
|
|
|
namespace hr {
|
|
|
|
struct always_false {
|
|
operator bool() const { return false; };
|
|
void operator = (bool b) const {};
|
|
};
|
|
|
|
template<class T>
|
|
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 || geometry == gHoroTris)
|
|
#define archimedean (geometry == gArchimedean)
|
|
#define eubinary (euclid || binarytiling || geometry == gCrystal || (DIM == 3 && hyperbolic))
|
|
|
|
#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 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<ld> cld;
|
|
|
|
#define DEBMEM(x) // { x fflush(stdout); }
|
|
|
|
#define DEBSM(x)
|
|
|
|
#if MAXMDIM == 3
|
|
#define DIM 2
|
|
#else
|
|
#define DIM ((geometry >= gBinary3) ? 3 : 2)
|
|
#endif
|
|
#define MDIM (DIM+1)
|
|
|
|
extern array<ld, gGUARD> sightranges;
|
|
|
|
struct hyperpoint : array<ld, MAXMDIM> {
|
|
hyperpoint() {}
|
|
|
|
hyperpoint(ld x, ld y, ld z, ld w) {
|
|
(*this)[0] = x; (*this)[1] = y; (*this)[2] = z;
|
|
if(MAXMDIM == 4) (*this)[3] = w;
|
|
}
|
|
};
|
|
|
|
struct transmatrix {
|
|
ld tab[MAXMDIM][MAXMDIM];
|
|
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<MDIM; i++) {
|
|
z[i] = 0;
|
|
for(int j=0; j<MDIM; j++) z[i] += T[i][j] * H[j];
|
|
}
|
|
return z;
|
|
}
|
|
|
|
inline transmatrix operator * (const transmatrix& T, const transmatrix& U) {
|
|
transmatrix R;
|
|
for(int i=0; i<MDIM; i++) for(int j=0; j<MDIM; j++) {
|
|
R[i][j] = 0;
|
|
for(int k=0; k<MDIM; k++)
|
|
R[i][j] += T[i][k] * U[k][j];
|
|
}
|
|
return R;
|
|
}
|
|
|
|
constexpr transmatrix diag(ld a, ld b, ld c, ld d) {
|
|
#if MAXMDIM==3
|
|
return transmatrix{{{a,0,0}, {0,b,0}, {0,0,c}}};
|
|
#else
|
|
return transmatrix{{{a,0,0,0}, {0,b,0,0}, {0,0,c,0}, {0,0,0,d}}};
|
|
#endif
|
|
}
|
|
|
|
|
|
// identity matrix
|
|
const static transmatrix Id = diag(1,1,1,1);
|
|
|
|
// zero matrix
|
|
const static transmatrix Zero = diag(0,0,0,0);
|
|
|
|
// mirror image
|
|
const static transmatrix Mirror = diag(1,-1,1,1);
|
|
|
|
// mirror image
|
|
const static transmatrix MirrorX = diag(-1,1,1,1);
|
|
|
|
// mirror image
|
|
const static transmatrix MirrorZ = diag(1,1,-1,1);
|
|
|
|
// rotate by PI
|
|
const static transmatrix pispin = diag(-1,-1,1,1);
|
|
|
|
// central symmetry
|
|
const static transmatrix centralsym = diag(-1,-1,-1,-1);
|
|
|
|
inline hyperpoint hpxyz(ld x, ld y, ld z) { return DIM == 2 ? hyperpoint(x,y,z,0) : hyperpoint(x,y,0,z); }
|
|
inline hyperpoint hpxyz3(ld x, ld y, ld z, ld w) { return DIM == 2 ? hyperpoint(x,y,w,0) : hyperpoint(x,y,z,w); }
|
|
inline hyperpoint point3(ld x, ld y, ld z) { return hyperpoint(x,y,z,0); }
|
|
inline hyperpoint point2(ld x, ld y) { return hyperpoint(x,y,0,0); }
|
|
|
|
namespace hyperpoint_vec {
|
|
|
|
inline hyperpoint& operator *= (hyperpoint& h, ld d) {
|
|
for(int i=0; i<MDIM; i++) h[i] *= d;
|
|
return h;
|
|
}
|
|
|
|
inline hyperpoint& operator /= (hyperpoint& h, ld d) {
|
|
for(int i=0; i<MDIM; i++) h[i] /= d;
|
|
return h;
|
|
}
|
|
|
|
inline hyperpoint operator += (hyperpoint& h, hyperpoint h2) {
|
|
for(int i=0; i<MDIM; i++) h[i] += h2[i];
|
|
return h;
|
|
}
|
|
|
|
inline hyperpoint operator -= (hyperpoint& h, hyperpoint h2) {
|
|
for(int i=0; i<MDIM; i++) h[i] -= h2[i];
|
|
return h;
|
|
}
|
|
|
|
inline hyperpoint operator * (ld d, hyperpoint h) { return h *= d; }
|
|
inline hyperpoint operator * (hyperpoint h, ld d) { return h *= d; }
|
|
inline hyperpoint operator / (hyperpoint h, ld d) { return h /= d; }
|
|
inline hyperpoint operator + (hyperpoint h, hyperpoint h2) { return h += h2; }
|
|
inline hyperpoint operator - (hyperpoint h, hyperpoint h2) { return h -= h2; }
|
|
|
|
// cross product
|
|
inline hyperpoint operator ^ (hyperpoint h1, hyperpoint h2) {
|
|
return hpxyz(
|
|
h1[1] * h2[2] - h1[2] * h2[1],
|
|
h1[2] * h2[0] - h1[0] * h2[2],
|
|
h1[0] * h2[1] - h1[1] * h2[0]
|
|
);
|
|
}
|
|
|
|
// inner product (in R^3)
|
|
inline ld operator | (hyperpoint h1, hyperpoint h2) {
|
|
ld sum = 0;
|
|
for(int i=0; i<MDIM; i++) sum += h1[i] * h2[i];
|
|
return sum;
|
|
}
|
|
}
|
|
|
|
|
|
extern int cellcount, heptacount;
|
|
|
|
// cell information for the game
|
|
|
|
struct gcell {
|
|
|
|
#if CAP_BITFIELD
|
|
// main fields
|
|
eLand land : 8;
|
|
eWall wall : 8;
|
|
eMonster monst : 8;
|
|
eItem item : 8;
|
|
|
|
// if this is a barrier, what lands on are on the sides?
|
|
eLand barleft : 8, barright : 8;
|
|
|
|
unsigned ligon : 1; // is it sparkling with lightning?
|
|
|
|
signed
|
|
mpdist : 7,
|
|
pathdist : 8, // player distance wrt usual movement
|
|
cpdist : 8; // current/minimum player distance
|
|
|
|
unsigned
|
|
mondir : 4, // monster direction, for multi-tile monsters and graphics
|
|
bardir : 4, // barrier direction
|
|
stuntime : 4, // stun time left (for Palace Guards and Skeletons)
|
|
hitpoints : 4; // hitpoints left (for Palace Guards, also reused as cpid for mirrors)
|
|
|
|
unsigned landflags : 8; // extra flags for land
|
|
#else
|
|
eLand land;
|
|
eWall wall;
|
|
eMonster monst;
|
|
eItem item;
|
|
eLand barleft, barright;
|
|
bool ligon;
|
|
signed char pathdist, cpdist, mpdist;
|
|
|
|
unsigned char mondir, bardir, stuntime, hitpoints;
|
|
unsigned char landflags;
|
|
#endif
|
|
|
|
// 'landparam' is used for:
|
|
// heat in Icy/Cocytus;
|
|
// heat in Dry (0..10);
|
|
// CR2 structure;
|
|
// hive Weird Rock color / pheromones;
|
|
// Ocean/coast depth;
|
|
// Bomberbird Egg hatch time / mine marking;
|
|
// number of Ancient Jewelry;
|
|
// improved tracking in Trollheim
|
|
union {
|
|
int32_t landpar;
|
|
unsigned int landpar_color;
|
|
float heat;
|
|
char bytes[4];
|
|
struct fieldinfo {
|
|
uint16_t fieldval;
|
|
unsigned rval : 4;
|
|
unsigned flowerdist : 4;
|
|
unsigned walldist : 4;
|
|
unsigned walldist2 : 4;
|
|
} fi;
|
|
|
|
} LHU;
|
|
|
|
#ifdef CELLID
|
|
int cellid;
|
|
#endif
|
|
|
|
gcell() { cellcount++;
|
|
#ifdef CELLID
|
|
cellid = cellcount;
|
|
#endif
|
|
}
|
|
~gcell() { cellcount--; }
|
|
};
|
|
|
|
#define landparam LHU.landpar
|
|
#define landparam_color LHU.landpar_color
|
|
|
|
#define fval LHU.fi.fieldval
|
|
|
|
#define NODIR 14
|
|
#define NOBARRIERS 15
|
|
#define MODFIXER 10090080
|
|
|
|
#define MAX_EDGE 14
|
|
|
|
template<class T> struct walker;
|
|
|
|
template<class T> struct connection_table {
|
|
|
|
// Assumption: class T has a field c of type connection_table<T>.
|
|
|
|
// NOTE: since aconnection_table may be allocated with
|
|
// less than MAX_EDGE neighbors (see tailored_alloc),
|
|
// the order of fields matters.
|
|
|
|
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; i<full()->degree(); i++) move_table[i] = NULL;
|
|
}
|
|
void connect(int d0, T* c1, int d1, bool m) {
|
|
move(d0) = c1;
|
|
c1->move(d1) = full();
|
|
setspin(d0, d1, m);
|
|
c1->c.setspin(d1, d0, m);
|
|
}
|
|
void connect(int d0, walker<T> hs) {
|
|
connect(d0, hs.at, hs.spin, hs.mirrored);
|
|
}
|
|
};
|
|
|
|
// Allocate a class T with a connection_table, but
|
|
// with only `degree` connections. Also set yet
|
|
// unknown connections to NULL.
|
|
|
|
// Generating the hyperbolic world consumes lots of
|
|
// RAM, so we really need to be careful on low memory devices.
|
|
|
|
template<class T> T* tailored_alloc(int degree) {
|
|
const T* sample = (T*) °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; i<degree; i++) result->c.move_table[i] = NULL;
|
|
return result;
|
|
}
|
|
|
|
template<class T> void tailored_delete(T* x) {
|
|
x->~T();
|
|
delete[] ((char*) (x));
|
|
}
|
|
|
|
static const struct wstep_t { wstep_t() {} } wstep;
|
|
static const struct wmirror_t { wmirror_t() {}} wmirror;
|
|
static const struct rev_t { rev_t() {} } rev;
|
|
static const struct revstep_t { revstep_t() {}} revstep;
|
|
|
|
int hrand(int x);
|
|
|
|
template<class T> struct walker {
|
|
T *at;
|
|
int spin;
|
|
bool mirrored;
|
|
walker<T> (T *at = NULL, int s = 0, bool m = false) : at(at), spin(s), mirrored(m) { }
|
|
walker<T>& operator += (int i) {
|
|
spin = at->c.fix(spin+(mirrored?-i:i));
|
|
return (*this);
|
|
}
|
|
walker<T>& operator -= (int i) {
|
|
spin = at->c.fix(spin-(mirrored?-i:i));
|
|
return (*this);
|
|
}
|
|
walker<T>& operator += (wmirror_t) {
|
|
mirrored = !mirrored;
|
|
return (*this);
|
|
}
|
|
walker<T>& operator += (wstep_t) {
|
|
at->cmove(spin);
|
|
int nspin = at->c.spin(spin);
|
|
if(at->c.mirror(spin)) mirrored = !mirrored;
|
|
at = at->move(spin);
|
|
spin = nspin;
|
|
return (*this);
|
|
}
|
|
walker<T>& operator += (rev_t) {
|
|
int d = at->degree();
|
|
if(DIM == 3 && binarytiling) {
|
|
if(spin < 4) spin = 8;
|
|
else if(spin >= 8) spin = 0;
|
|
else spin ^= 1;
|
|
}
|
|
return (*this) += d/2 + ((d&1)?hrand(2):0);
|
|
}
|
|
walker<T>& operator += (revstep_t) {
|
|
(*this) += rev; return (*this) += wstep;
|
|
}
|
|
bool operator != (const walker<T>& x) const {
|
|
return at != x.at || spin != x.spin || mirrored != x.mirrored;
|
|
}
|
|
bool operator == (const walker<T>& x) const {
|
|
return at == x.at && spin == x.spin && mirrored == x.mirrored;
|
|
}
|
|
|
|
bool operator < (const walker<T>& cw2) const {
|
|
return tie(at, spin, mirrored) < tie(cw2.at, cw2.spin, cw2.mirrored);
|
|
}
|
|
|
|
walker<T>& operator ++ (int) { return (*this) += 1; }
|
|
walker<T>& operator -- (int) { return (*this) -= 1; }
|
|
template<class U> walker operator + (U t) const { walker<T> w = *this; w += t; return w; }
|
|
template<class U> walker operator - (U t) const { walker<T> w = *this; w += (-t); return w; }
|
|
T*& peek() { return at->move(spin); }
|
|
T* cpeek() { return at->cmove(spin); }
|
|
bool creates() { return !peek(); }
|
|
walker<T> mirrorat(int d) { return walker<T> (at, at->c.fix(d+d - spin), !mirrored); }
|
|
};
|
|
|
|
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<heptagon> 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<cell> c;
|
|
cell*& move(int d) { return c.move(d); }
|
|
cell*& modmove(int d) { return c.modmove(d); }
|
|
cell* cmove(int d) { return createMov(this, d); }
|
|
cell* cmodmove(int d) { return createMov(this, c.fix(d)); }
|
|
cell() {}
|
|
|
|
// prevent accidental copying
|
|
cell(const cell&) = delete;
|
|
heptagon& operator=(const cell&) = delete;
|
|
// do not add any fields after connection_table (see tailored_alloc)
|
|
};
|
|
|
|
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<heptagon> heptspin;
|
|
typedef walker<cell> 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<class T> 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<string> 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<int> 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 T> class hookset : public map<int, function<T>> {};
|
|
typedef hookset<void()> *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<bool(int)> *hooks_turn;
|
|
extern hookset<bool(const transmatrix&, cell*, shmup::monster*)> *hooks_draw;
|
|
extern hookset<bool(shmup::monster*)> *hooks_kill;
|
|
extern hookset<bool(shmup::monster*, string&)> *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 drawParticleSpeed(cell *c, color_t col, int speed);
|
|
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 queuecircleat(cell *c, double rad, color_t col);
|
|
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<void()> 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<void()> reaction_t;
|
|
typedef function<bool()> bool_reaction_t;
|
|
|
|
extern reaction_t help_delegate;
|
|
|
|
#define HELPFUN(x) (help_delegate = x, "HELPFUN")
|
|
|
|
enum eStereo { sOFF, sAnaglyph, sLR, sODS };
|
|
|
|
struct radarpoint {
|
|
hyperpoint h;
|
|
char glyph;
|
|
color_t color;
|
|
color_t line;
|
|
};
|
|
|
|
extern vector<radarpoint> radarpoints;
|
|
|
|
struct videopar {
|
|
ld scale, alpha, sspeed, mspeed, yshift, camera_angle;
|
|
ld ballangle, ballproj, euclid_to_sphere, twopoint_param, stretch, binary_width, fixed_facing_dir;
|
|
int mobilecompasssize;
|
|
int radarsize; // radar for 3D geometries
|
|
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<void()> > screens;
|
|
|
|
template<class T> 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<cell*, transmatrix> 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<int(cell*)> 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<int, cell*> 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, sgWall };
|
|
static const int USERSHAPEGROUPS = 5;
|
|
|
|
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<edge> edges;
|
|
vector<edge> 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<rugpoint*> points;
|
|
extern vector<triangle> 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<pair<cell*, eMonster> > killhistory;
|
|
extern vector<pair<cell*, eItem> > findhistory;
|
|
extern vector<cell*> movehistory;
|
|
extern set<cell*> 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<class A>
|
|
void apply_orientation(A& x, A& y) { if(!model_straight) tie(x,y) = make_pair(x*ocos + y*osin, y*ocos - x*osin); }
|
|
template<class A>
|
|
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<shmup::monster*> 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<ld, ld> 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 && binarytiling) ? 2 : (DIM == 3 && hyperbolic) ? 3 : 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)?(getDistLimit()<4?8: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<int, ittypes> items;
|
|
extern array<int, motypes> kills;
|
|
|
|
extern int explore[10], exploreland[10][landtypes], landcount[landtypes];
|
|
|
|
typedef flagtype modecode_t;
|
|
extern map<modecode_t, array<int, ittypes> > 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<cell*> 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<class T> 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<stalemate1> 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();
|
|
}
|
|
|
|
#define sword_angles (S7*S3*2)
|
|
|
|
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 smooth_scrolling;
|
|
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<item> 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<pair<string, color_t> > 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<string(int, int)> 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<void()>& 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<void()>& 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<cell*, animation> 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,
|
|
// in depth tested models transparent surfaces need to be depth sorted by HyperRogue
|
|
// and set to PPR::TRANSPARENT to draw them after all the opaque ones
|
|
TRANSPARENT,
|
|
// no depth testing for SUPERLINE and above
|
|
SUPERLINE, 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<int> 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<ld,ld>* 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<eLand(eLand)> getNext;
|
|
extern function<bool(eLand)> quickfind;
|
|
extern function<bool(eLand)> showland;
|
|
|
|
void start();
|
|
|
|
struct slide {
|
|
const char *name; int unused_id; int flags; const char *help;
|
|
function<void(presmode mode)> action;
|
|
} ;
|
|
|
|
extern slide *slides;
|
|
extern slide default_slides[];
|
|
|
|
static const int LEGAL_NONE=0;
|
|
static const int LEGAL_UNLIMITED=1;
|
|
static const int LEGAL_HYPERBOLIC=2;
|
|
static const int LEGAL_ANY=3;
|
|
static const int LEGAL_NONEUC=4;
|
|
static const int QUICKSKIP=8;
|
|
static const int FINALSLIDE=16;
|
|
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<void(int)> *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<linepattern> 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<class T, class... U> T pick(T x, U... u) { std::initializer_list<T> i = {x,u...}; return *(i.begin() + hrand(1+sizeof...(u))); }
|
|
|
|
template<class T, class V, class... U> bool among(T x, V y) { return x == y; }
|
|
template<class T, class V, class... U> bool among(T x, V y, U... u) { return x==y || among(x,u...); }
|
|
|
|
eLand getNewSealand(eLand old);
|
|
bool createOnSea(eLand old);
|
|
|
|
namespace inv {
|
|
extern bool on;
|
|
extern bool usedForbidden;
|
|
extern bool activating;
|
|
extern array<int, ittypes> remaining;
|
|
extern array<int, ittypes> 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, color_t icol, int ticks, bool hidden);
|
|
|
|
void initquickqueue();
|
|
void quickqueue();
|
|
int darkenedby(int c, int lev);
|
|
extern int mousex, mousey;
|
|
extern ld mouseaim_x, mouseaim_y, mouseaim_sensitivity;
|
|
string generateHelpForItem(eItem it);
|
|
bool graphglyph();
|
|
extern bool hiliteclick;
|
|
extern int antialiaslines;
|
|
extern color_t ringcolor, periodcolor, modelcolor;
|
|
|
|
#include <functional>
|
|
|
|
template<class T, class U> int addHook(hookset<T>*& m, int prio, const U& hook) {
|
|
if(!m) m = new hookset<T> ();
|
|
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<class T, class... U> void callhooks(hookset<T> *h, U... args) {
|
|
if(h) for(auto& p: *h) p.second(args...);
|
|
}
|
|
|
|
template<class T, class V, class... U> V callhandlers(V zero, hookset<T> *h, U&... args) {
|
|
if(h) for(auto& p: *h) {
|
|
auto z = p.second(args...);
|
|
if(z != zero) return z;
|
|
}
|
|
return zero;
|
|
}
|
|
|
|
extern hookset<bool(int sym, int uni)> *hooks_handleKey;
|
|
extern hookset<bool(cell *c, const transmatrix& V)> *hooks_drawcell;
|
|
extern hookset<bool(int argc, char** argv)> *hooks_main;
|
|
extern hookset<int()> *hooks_args;
|
|
extern hookset<bool(cell*)> *hooks_mark;
|
|
extern hookset<eLand(eLand)> *hooks_nextland;
|
|
extern hookset<bool()> *hooks_welcome_message, *hooks_default_help;
|
|
extern hookset<void(cell*)> *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<msginfo> 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> {
|
|
color_t& operator [] (int i) { i %= size(); if(i<0) i += size(); return ((vector<color_t>&)(*this)) [i]; }
|
|
const color_t& operator [] (int i) const { i %= size(); if(i<0) i += size(); return ((vector<color_t>&)(*this)) [i]; }
|
|
colortable(std::initializer_list<color_t> v) : vector(v) {}
|
|
colortable() : vector({0}) {}
|
|
};
|
|
|
|
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 <void(int sym, int uni)> keyhandler;
|
|
#if CAP_SDL
|
|
extern function <bool(SDL_Event &ev)> 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<bool()> usable;
|
|
function<void()> display;
|
|
function<void()> 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<cell*> buggycells;
|
|
|
|
extern bool landUnlocked(eLand l);
|
|
|
|
extern void describeCell(cell*);
|
|
extern bool rlyehComplete();
|
|
|
|
extern int steplimit, cstep;
|
|
|
|
template<class... T>
|
|
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<GLfloat, 2> glvec2;
|
|
typedef array<GLfloat, 3> glvec3;
|
|
typedef array<GLfloat, 4> glvec4;
|
|
|
|
#if MAXMDIM == 4
|
|
#define SHDIM 4
|
|
typedef glvec4 glvertex;
|
|
#else
|
|
#define SHDIM 3
|
|
typedef glvec3 glvertex;
|
|
#endif
|
|
|
|
struct texture_triangle {
|
|
array<hyperpoint, 3> v;
|
|
array<hyperpoint, 3> tv;
|
|
texture_triangle(array<hyperpoint, 3> _v, array<hyperpoint, 3> _tv) : v(_v), tv(_tv) {}
|
|
};
|
|
|
|
struct textureinfo {
|
|
transmatrix M;
|
|
int texture_id;
|
|
vector<texture_triangle> triangles;
|
|
vector<glvertex> vertices;
|
|
vector<glvertex> tvertices;
|
|
cell *c;
|
|
vector<transmatrix> matrices;
|
|
|
|
// these are required to adjust to geometry changes
|
|
int current_type, symmetries;
|
|
};
|
|
|
|
struct drawqueueitem {
|
|
PPR prio;
|
|
color_t color;
|
|
int subprio;
|
|
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<glvertex> *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<heptagon*, clearingdata> 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<cell*>& 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<eVariation> 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<heptagon*, 3> 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<hrmap*> allmaps;
|
|
|
|
// list all cells in distance at most maxdist, or until when maxcount cells are reached
|
|
|
|
struct manual_celllister {
|
|
vector<cell*> lst;
|
|
vector<int> 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; i<isize(lst); i++) lst[i]->listindex = tmps[i];
|
|
}
|
|
};
|
|
|
|
|
|
struct celllister : manual_celllister {
|
|
vector<int> 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<isize(lst); i++) {
|
|
cell *c = lst[i];
|
|
if(maxdist) forCellCM(c2, c) {
|
|
add_at(c2, dists[i]+1);
|
|
if(c2 == breakon) return;
|
|
}
|
|
if(c == last) {
|
|
if(isize(lst) >= 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<eLand> landlist;
|
|
template<class T> 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 && DIM == 3; }
|
|
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<bool(eLand&)> *hooks_music;
|
|
extern hookset<bool()> *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<int, bool> 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<color_t> texture_pixels;
|
|
|
|
color_t& get_texture_pixel(int x, int y) {
|
|
return texture_pixels[(y&(twidth-1))*twidth+(x&(twidth-1))];
|
|
}
|
|
|
|
vector<pair<color_t*, color_t>> undos;
|
|
vector<tuple<cell*, hyperpoint, int> > 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<eGeometry, eVariation, char, int, eModel, ld, ld> texture_parameters;
|
|
texture_parameters orig_texture_parameters;
|
|
|
|
map<int, textureinfo> texture_map, texture_map_orig;
|
|
set<cell*> models;
|
|
|
|
bool texture_tuned;
|
|
string texture_tuner;
|
|
vector<hyperpoint*> 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<hyperpoint, 3>& v, const array<hyperpoint, 3>& tv, int splits);
|
|
void mapTextureTriangle(textureinfo &mi, const array<hyperpoint, 3>& v, const array<hyperpoint, 3>& 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<MDIM; i++) z[i] = T[i][DIM];
|
|
return z;
|
|
}
|
|
|
|
transmatrix actualV(const heptspin& hs, const transmatrix& V);
|
|
transmatrix applyspin(const heptspin& hs, const transmatrix& V);
|
|
transmatrix cview();
|
|
|
|
extern string bitruncnames[5];
|
|
extern bool need_mouseh;
|
|
|
|
extern int whateveri, whateveri2;
|
|
|
|
void clear_euland(eLand first);
|
|
|
|
extern eMonster passive_switch;
|
|
|
|
bool cannotPickupItem(cell *c, bool telekinesis);
|
|
bool canPickupItemWithMagnetism(cell *c, cell *from);
|
|
void pickupMovedItems(cell *c);
|
|
eMonster genRuinMonster(cell *c);
|
|
|
|
template<class T> void hrandom_shuffle(T* x, int n) {
|
|
for(int k=1; k<n; k++) swap(x[k], x[hrand(k+1)]);
|
|
}
|
|
|
|
void resetModes(char leave = 'c');
|
|
void activateSafety(eLand l);
|
|
void showMainMenu();
|
|
extern bool nomenukey;
|
|
void resetConfig();
|
|
void welcomeMessage();
|
|
void jumpTo(cell *dest, eItem byWhat, int bonuskill = 0, eMonster dashmon = moNone);
|
|
extern bool canmove;
|
|
|
|
void activateSafety(eLand l);
|
|
extern bool childbug;
|
|
|
|
void fullcenter();
|
|
void mainloop();
|
|
void clearAnimations();
|
|
|
|
transmatrix rotmatrix(double rotation, int c0, int c1);
|
|
|
|
void destroycellcontents(cell *c);
|
|
extern heptagon *last_cleared;
|
|
|
|
template<class T, class U> void eliminate_if(vector<T>& data, U pred) {
|
|
for(int i=0; i<isize(data); i++)
|
|
if(pred(data[i]))
|
|
data[i] = data.back(), data.pop_back(), i--;
|
|
}
|
|
|
|
bool is_cell_removed(cell *c);
|
|
void set_if_removed(cell*& c, cell *val);
|
|
|
|
struct renderbuffer {
|
|
bool valid;
|
|
int x, y;
|
|
|
|
#if CAP_GL
|
|
int tx, ty;
|
|
GLuint FramebufferName;
|
|
GLuint renderedTexture;
|
|
GLuint depth_stencil_rb;
|
|
Uint32 *expanded_data;
|
|
void use_as_texture();
|
|
#endif
|
|
#if CAP_SDL
|
|
SDL_Surface *srf;
|
|
void make_surface();
|
|
SDL_Surface *render();
|
|
#endif
|
|
|
|
renderbuffer(int x, int y, bool gl);
|
|
~renderbuffer();
|
|
void enable();
|
|
void clear(color_t col);
|
|
};
|
|
|
|
struct resetbuffer {
|
|
GLint drawFboId, readFboId;
|
|
SDL_Surface *sreset;
|
|
resetbuffer();
|
|
void reset();
|
|
};
|
|
|
|
double randd();
|
|
|
|
#if CAP_ORIENTATION
|
|
transmatrix getOrientation();
|
|
#endif
|
|
|
|
bool showHalloween();
|
|
extern bool havesave;
|
|
extern vector<msginfo> 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<cell*, int> 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<cell*> dcal; // queue for cpdist
|
|
extern vector<cell*> pathq; // queue for pathdist
|
|
extern vector<pair<cell*, int> > butterflies;
|
|
extern vector<cell*> 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<landtacinfo> land_tac;
|
|
string llts(long long i);
|
|
void clearMemoRPM();
|
|
extern int randompattern[landtypes];
|
|
extern int pair_to_vec(int x, int y);
|
|
typedef pair<cell**, bool> 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<void()> call_initgame;
|
|
extern void initializeCLI();
|
|
|
|
static const int max_vec = (1<<14);
|
|
|
|
string helptitle(string s, color_t col);
|
|
pair<int, int> cell_to_pair(cell *c);
|
|
extern bool nohud, nofps, nomap;
|
|
|
|
template<class T> array<T, 4> make_array(T a, T b, T c, T d) { array<T,4> x; x[0] = a; x[1] = b; x[2] = c; x[3] = d; return x; }
|
|
template<class T> array<T, 3> make_array(T a, T b, T c) { array<T,3> x; x[0] = a; x[1] = b; x[2] = c; return x; }
|
|
template<class T> array<T, 2> make_array(T a, T b) { array<T,2> x; x[0] = a; x[1] = b; return x; }
|
|
|
|
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(int d, const hyperpoint& h);
|
|
ld hypot_d(int d, const hyperpoint& h);
|
|
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<int, int> 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<heptagon*, 3> 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<shared_ptr<supersaver>> saverlist;
|
|
|
|
extern saverlist savers;
|
|
|
|
extern string ftssmart(ld x);
|
|
|
|
string itsh(int i);
|
|
|
|
#if CAP_CONFIG
|
|
|
|
template<class T> struct dsaver : supersaver {
|
|
T& val;
|
|
T dft;
|
|
bool dosave() { return val != dft; }
|
|
void reset() { val = dft; }
|
|
dsaver(T& val) : val(val) { }
|
|
};
|
|
|
|
template<class T> struct saver : dsaver<T> {};
|
|
|
|
template<class T, class U, class V> void addsaver(T& i, U name, V dft) {
|
|
auto s = make_shared<saver<T>> (i);
|
|
s->dft = dft;
|
|
s->name = name;
|
|
savers.push_back(s);
|
|
}
|
|
|
|
template<class T> void addsaver(T& i, string name) {
|
|
addsaver(i, name, i);
|
|
}
|
|
|
|
template<class T> struct saverenum : supersaver {
|
|
T& val;
|
|
T dft;
|
|
bool dosave() { return val != dft; }
|
|
void reset() { val = dft; }
|
|
saverenum<T>(T& v) : val(v) { }
|
|
string save() { return its(int(val)); }
|
|
void load(const string& s) { val = (T) atoi(s.c_str()); }
|
|
};
|
|
|
|
template<class T, class U> void addsaverenum(T& i, U name, T dft) {
|
|
auto s = make_shared<saverenum<T>> (i);
|
|
s->dft = dft;
|
|
s->name = name;
|
|
savers.push_back(s);
|
|
}
|
|
|
|
template<class T, class U> void addsaverenum(T& i, U name) {
|
|
addsaverenum(i, name, i);
|
|
}
|
|
|
|
template<> struct saver<int> : dsaver<int> {
|
|
saver<int>(int& val) : dsaver<int>(val) { }
|
|
string save() { return its(val); }
|
|
void load(const string& s) { val = atoi(s.c_str()); }
|
|
};
|
|
|
|
template<> struct saver<char> : dsaver<char> {
|
|
saver<char>(char& val) : dsaver<char>(val) { }
|
|
string save() { return its(val); }
|
|
void load(const string& s) { val = atoi(s.c_str()); }
|
|
};
|
|
|
|
template<> struct saver<bool> : dsaver<bool> {
|
|
saver<bool>(bool& val) : dsaver<bool>(val) { }
|
|
string save() { return val ? "yes" : "no"; }
|
|
void load(const string& s) { val = isize(s) && s[0] == 'y'; }
|
|
};
|
|
|
|
template<> struct saver<unsigned> : dsaver<unsigned> {
|
|
saver<unsigned>(unsigned& val) : dsaver<unsigned>(val) { }
|
|
string save() { return itsh(val); }
|
|
void load(const string& s) { val = (unsigned) strtoll(s.c_str(), NULL, 16); }
|
|
};
|
|
|
|
template<> struct saver<string> : dsaver<string> {
|
|
saver<string>(string& val) : dsaver<string>(val) { }
|
|
string save() { return val; }
|
|
void load(const string& s) { val = s; }
|
|
};
|
|
|
|
template<> struct saver<ld> : dsaver<ld> {
|
|
saver<ld>(ld& val) : dsaver<ld>(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<unique_ptr<drawqueueitem>> 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 make_array(x, y, z);
|
|
#else
|
|
return make_array<GLfloat>(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<textured_vertex>& v);
|
|
void prepare(vector<colored_vertex>& v);
|
|
void prepare(vector<ct_vertex>& v);
|
|
}
|
|
|
|
void prettypoly(const vector<hyperpoint>& 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<glvertex>& 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<torusmode_info> tmodes;
|
|
|
|
enum : flagtype {
|
|
TF_SINGLE = 1,
|
|
TF_SIMPLE = 2,
|
|
TF_WEIRD = 4,
|
|
TF_HEX = 16,
|
|
TF_SQUARE = 32,
|
|
TF_CYL = 64,
|
|
TF_KLEIN = 256,
|
|
};
|
|
|
|
flagtype tmflags();
|
|
}
|
|
|
|
#if CAP_FIELD
|
|
namespace fieldpattern {
|
|
extern int current_extra;
|
|
|
|
struct primeinfo {
|
|
int p;
|
|
int cells;
|
|
bool squared;
|
|
};
|
|
|
|
struct fgeomextra {
|
|
eGeometry base;
|
|
vector<primeinfo> primes;
|
|
int current_prime_id;
|
|
fgeomextra(eGeometry b, int i) : base(b), current_prime_id(i) {}
|
|
};
|
|
|
|
extern vector<fgeomextra> 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<cell*> arrowtraps;
|
|
extern map<cell*, blizzardcell> blizzardcells;
|
|
extern vector<blizzardcell*> 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<hpcshape> b, shadow, side[SIDEPARS], gpside[SIDEPARS][MAX_EDGE];
|
|
floorshape() { prio = PPR::FLOOR; }
|
|
};
|
|
|
|
extern vector<struct plain_floorshape*> all_plain_floorshapes;
|
|
extern vector<struct escher_floorshape*> 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<pair<cell*, int> > 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_extension> help_extensions;
|
|
|
|
namespace gamestack {
|
|
bool pushed();
|
|
}
|
|
|
|
namespace geom3 {
|
|
extern ld BODY;
|
|
extern ld depth, camera, wall_height, creature_scale, height_width;
|
|
}
|
|
|
|
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+=SD3 * pow(.5, vid.linequality))
|
|
#define REVRING(i) for(double i=S84; i>=-1e-6; i-=SD3 * 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 MAXMDIM == 4
|
|
heptagon *createStep3(heptagon *parent, int d);
|
|
#endif
|
|
transmatrix parabolic(ld u);
|
|
transmatrix parabolic3(ld u, ld v);
|
|
extern ld btrange, btrange_cosh;
|
|
transmatrix relative_matrix(heptagon *h2, heptagon *h1);
|
|
}
|
|
#endif
|
|
|
|
#if MAXMDIM == 4
|
|
namespace euclid3 {
|
|
heptagon *createStep(heptagon *parent, int d);
|
|
hrmap* new_map();
|
|
void draw();
|
|
}
|
|
|
|
namespace reg3 {
|
|
void generate();
|
|
hrmap* new_map();
|
|
heptagon *createStep(heptagon *parent, int d);
|
|
extern vector<hyperpoint> cellshape;
|
|
void draw();
|
|
transmatrix relative_matrix(heptagon *h2, heptagon *h1);
|
|
int dist_alt(cell *c);
|
|
int celldistance(cell *c1, cell *c2);
|
|
bool pseudohept(cell *c);
|
|
}
|
|
#endif
|
|
|
|
namespace arcm {
|
|
#if CAP_ARCM
|
|
|
|
struct archimedean_tiling {
|
|
|
|
int coloring;
|
|
|
|
string symbol;
|
|
|
|
vector<int> faces;
|
|
vector<int> adj;
|
|
vector<bool> invert;
|
|
vector<int> nflags;
|
|
|
|
bool have_ph, have_line, have_symmetry;
|
|
int real_faces;
|
|
int real_face_type;
|
|
|
|
int repetition;
|
|
int N;
|
|
|
|
ld euclidean_angle_sum;
|
|
|
|
vector<int> flags;
|
|
|
|
vector<vector<pair<int, int>>> adjacent;
|
|
vector<vector<pair<ld, ld>>> 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<ld> inradius, circumradius, alphas;
|
|
|
|
int matches[30][30];
|
|
int periods[30];
|
|
int tilegroup[30], groupoffset[30], tilegroups;
|
|
|
|
int errors;
|
|
string errormsg;
|
|
|
|
pair<int, int>& get_adj(heptagon *h, int cid);
|
|
pair<int, int>& get_adj(heptspin hs) { return get_adj(hs.at, hs.spin); }
|
|
pair<ld, ld>& get_triangle(heptagon *h, int cid);
|
|
pair<ld, ld>& get_triangle(heptspin hs) { return get_triangle(hs.at, hs.spin); }
|
|
pair<ld, ld>& get_triangle(const pair<int, int>& p, int delta = 0);
|
|
pair<int, int>& get_adj(const pair<int, int>& 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<heptagon*, pair<heptagon*, transmatrix>> 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<int, MAXDIM> coord;
|
|
static const coord c0 = {};
|
|
|
|
typedef array<ld, MAXDIM> 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<cell*> 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<class T> void write(const T& t) { hwrite(*this, t); }
|
|
template<class T> void read(T& t) { hread(*this, t); }
|
|
template<class T> T get() { T t; hread(*this, t); return t; }
|
|
template<class T> T get_raw() { T t; hread_raw(*this, t); return t; }
|
|
};
|
|
|
|
template<class T> void hwrite_raw(hstream& hs, const T& c) { hs.write_chars((char*) &c, sizeof(T)); }
|
|
template<class T> void hread_raw(hstream& hs, T& c) { hs.read_chars((char*) &c, sizeof(T)); }
|
|
|
|
template<class T, typename = typename std::enable_if<std::is_integral<T>::value || std::is_enum<T>::value>::type> void hwrite(hstream& hs, const T& c) { hwrite_raw(hs, c); }
|
|
template<class T, typename = typename std::enable_if<std::is_integral<T>::value || std::is_enum<T>::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<l; i++) s += hs.read_char(); }
|
|
inline void hwrite(hstream& hs, const ld& h) { double d = h; hs.write_chars((char*) &d, sizeof(double)); }
|
|
inline void hread(hstream& hs, ld& h) { double d; hs.read_chars((char*) &d, sizeof(double)); h = d; }
|
|
|
|
template<class T, size_t X> void hwrite(hstream& hs, const array<T, X>& a) { for(auto &ae: a) hwrite(hs, ae); }
|
|
template<class T, size_t X> void hread(hstream& hs, array<T, X>& a) { for(auto &ae: a) hread(hs, ae); }
|
|
|
|
template<class T> void hwrite(hstream& hs, const vector<T>& a) { hwrite<int>(hs, isize(a)); for(auto &ae: a) hwrite(hs, ae); }
|
|
template<class T> void hread(hstream& hs, vector<T>& a) { a.resize(hs.get<int>()); for(auto &ae: a) hread(hs, ae); }
|
|
|
|
template<class T, class U> void hwrite(hstream& hs, const map<T,U>& a) {
|
|
hwrite<int>(hs, isize(a)); for(auto &ae: a) hwrite(hs, ae.first, ae.second);
|
|
}
|
|
template<class T, class U> void hread(hstream& hs, map<T,U>& a) {
|
|
a.clear();
|
|
int N = hs.get<int>();
|
|
for(int i=0; i<N; i++) {
|
|
T key; hread(hs, key);
|
|
hread(hs, a[key]);
|
|
}
|
|
}
|
|
|
|
template<class C, class C1, class... CS> void hwrite(hstream& hs, const C& c, const C1& c1, const CS&... cs) { hwrite(hs, c); hwrite(hs, c1, cs...); }
|
|
template<class C, class C1, class... CS> 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<class... CS> string sprint(const CS&... cs) { shstream hs; print(hs, cs...); return hs.s; }
|
|
|
|
template<class C, class C1, class... CS> void print(hstream& hs, const C& c, const C1& c1, const CS&... cs) { print(hs, c); print(hs, c1, cs...); }
|
|
|
|
template<class... CS> 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<int... Is>
|
|
struct seq { };
|
|
|
|
template<int N, int... Is>
|
|
struct gen_seq : gen_seq<N - 1, N - 1, Is...> { };
|
|
|
|
template<int... Is>
|
|
struct gen_seq<0, Is...> : seq<Is...> { };
|
|
|
|
template<typename T, typename F, int... Is>
|
|
void for_each(T&& t, F f, seq<Is...>)
|
|
{
|
|
auto l = { (f(std::get<Is>(t)), 0)... }; ignore(l);
|
|
}
|
|
}
|
|
|
|
template<typename... Ts, typename F>
|
|
void for_each_in_tuple(std::tuple<Ts...> const& t, F f)
|
|
{
|
|
detail::for_each(t, f, detail::gen_seq<sizeof...(Ts)>());
|
|
}
|
|
|
|
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<class T> void print(hstream& hs, const walker<T>& w) { print(hs, "[", w.at, "/", w.spin, "/", w.mirrored, "]"); }
|
|
|
|
struct comma_printer {
|
|
bool first;
|
|
hstream& hs;
|
|
template<class T> void operator() (const T& t) { if(first) first = false; else print(hs, ","); print(hs, t); }
|
|
comma_printer(hstream& hs) : first(true), hs(hs) {}
|
|
};
|
|
|
|
template<class T, size_t X> void print(hstream& hs, const array<T, X>& a) { print(hs, "("); comma_printer c(hs); for(const T& t: a) c(t); print(hs, ")"); }
|
|
template<class T> void print(hstream& hs, const vector<T>& 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<ld, MAXMDIM>&)h); }
|
|
inline void print(hstream& hs, const transmatrix T) {
|
|
print(hs, "("); comma_printer c(hs);
|
|
for(int i=0; i<MDIM; i++)
|
|
for(int j=0; j<MDIM; j++) c(T[i][j]);
|
|
print(hs, ")"); }
|
|
|
|
template<class T, class U> void print(hstream& hs, const pair<T, U> & t) { print(hs, "(", t.first, ",", t.second, ")"); }
|
|
|
|
template<class... T> void print(hstream& hs, const tuple<T...> & 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; i<indentation; i++) special_log(' '); } special_log(c); if(c == 10) doindent = true; }
|
|
virtual char read_char() { throw hstream_exception(); }
|
|
};
|
|
|
|
extern logger hlog;
|
|
|
|
#ifdef __GNUC__
|
|
__attribute__((__format__ (__printf__, 1, 2)))
|
|
#endif
|
|
inline string format(const char *fmt, ...) {
|
|
char buf[1000];
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
vsnprintf(buf, 1000, fmt, ap);
|
|
va_end(ap);
|
|
return buf;
|
|
}
|
|
|
|
inline void print(hstream& hs, heptagon* h) { print(hs, format("H%p", h)); }
|
|
inline void print(hstream& hs, cell* h) { print(hs, format("C%p", h)); }
|
|
|
|
inline void print(hstream& hs, cellwalker cw) {
|
|
if(cw.at) print(hs, "[", cw.at, "/", cw.at->type, ":", cw.spin, ":", cw.mirrored, "]");
|
|
else print(hs, "[NULL]");
|
|
}
|
|
|
|
struct indenter {
|
|
dynamicval<int> 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<int, int> vec_to_pair(int vec);
|
|
|
|
struct bignum {
|
|
static const int BASE = 1000000000;
|
|
static const long long BASE2 = BASE * (long long)BASE;
|
|
vector<int> 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<int> gettype(cell *c);
|
|
int N;
|
|
vector<cell*> samples;
|
|
map<vector<int>, int> codeid;
|
|
vector<vector<int> > children;
|
|
int rootid, diskid;
|
|
int coefficients_known;
|
|
vector<int> coef;
|
|
int valid_from, tested_to;
|
|
ld growth;
|
|
|
|
int sample_id(cell *c);
|
|
void preliminary_grouping();
|
|
void reduce_grouping();
|
|
vector<vector<bignum>> 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<int(cell*)>& 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<string, cld> 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<ld> 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<string, ld&> params;
|
|
|
|
namespace dq {
|
|
extern set<heptagon*> visited;
|
|
extern queue<tuple<heptagon*, transmatrix, ld>> drawqueue;
|
|
|
|
void enqueue(heptagon *h, const transmatrix& T);
|
|
}
|
|
|
|
typedef pair<string, reaction_t> named_functionality;
|
|
inline named_functionality named_dialog(string x, reaction_t dialog) { return named_functionality(x, [dialog] () { pushScreen(dialog); }); }
|
|
|
|
extern hookset<named_functionality()> *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<cell*> track;
|
|
extern int current_player;
|
|
extern vector<eLand> 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);
|
|
}
|
|
|