Updated the source files to 9.4c

This commit is contained in:
Zeno Rogue 2017-03-23 11:53:57 +01:00
parent 1e3612939c
commit 58e053f183
39 changed files with 44729 additions and 30565 deletions

View File

@ -1,7 +1,7 @@
// Hyperbolic Rogue -- achievements // Hyperbolic Rogue -- achievements
// Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details // Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details
#define NUMLEADER 57 #define NUMLEADER 69
#define SCORE_UNKNOWN (-1) #define SCORE_UNKNOWN (-1)
#define NO_SCORE_YET (-2) #define NO_SCORE_YET (-2)
@ -16,7 +16,7 @@ const char* leadernames[NUMLEADER] = {
"Score", "Diamonds", "Gold", "Spice", "Rubies", "Elixirs", "Score", "Diamonds", "Gold", "Spice", "Rubies", "Elixirs",
"Shards", "Totems", "Daisies", "Statues", "Feathers", "Sapphires", "Shards", "Totems", "Daisies", "Statues", "Feathers", "Sapphires",
"Hyperstones", "Time to Win-71", "Turns to Win-71", "Hyperstones", "Time to Win-71", "Turns to Win-71",
"Time to 10 Hyperstones-83", "Turns to 10 Hyperstones-83", "Orbs of Yendor", "Time to 10 Hyperstones-94", "Turns to 10 Hyperstones-94", "Orbs of Yendor",
"Fern Flowers", "Fern Flowers",
"Royal Jellies", "Powerstones", "Silver", "Wine", "Emeralds", "Grimoires", "Royal Jellies", "Powerstones", "Silver", "Wine", "Emeralds", "Grimoires",
"Holy Grails", "Red Gems", "Pirate Treasures", "Holy Grails", "Red Gems", "Pirate Treasures",
@ -47,8 +47,23 @@ const char* leadernames[NUMLEADER] = {
"Tortoise points", // 54 "Tortoise points", // 54
"Dragon Scales", // 55 "Dragon Scales", // 55
"Apples", // 56 "Apples", // 56
"Heptagonal Mode", // 57
"Sunken Treasures", // 58
"Ancient Jewelry", // 59
"Golden Eggs", // 60
"Multiplayer Score", // 61
"Statistics", // 62
"Halloween", // 63
"Amethysts", // 64
"Slime Molds", // 65
"Dodecahedra", // 66
"Green Grass", // 67
"Spinel" // 68
}; };
#define LB_STATISTICS 62
#define LB_HALLOWEEN 63
bool haveLeaderboard(int id); bool haveLeaderboard(int id);
void upload_score(int id, int v); void upload_score(int id, int v);
@ -59,13 +74,18 @@ int achievementTimer;
bool wrongMode(char flags) { bool wrongMode(char flags) {
if(cheater) return true; if(cheater) return true;
if(flags == 'x') return false;
if(purehepta != (flags == '7')) return true; if(purehepta != (flags == '7')) return true;
if(euclid != (flags == 'e')) return true; if(euclid != (flags == 'e')) return true;
if(sphere != (flags == 'E')) return true;
if((quotient == 1) != (flags == 'q')) return true;
if((quotient == 2) != (flags == 'Q')) return true;
if(shmup::on != (flags == 's')) return true; if(shmup::on != (flags == 's')) return true;
if(randomPatternsMode) return true; if(randomPatternsMode) return true;
if(yendor::on) return true; if(yendor::on) return true;
if(tactic::on) return true; if(tactic::on) return true;
if(chaosmode != (flags == 'C')) return true; if(chaosmode != (flags == 'C')) return true;
if((numplayers() > 1) != (flags == 'm')) return true;
return false; return false;
} }
@ -80,10 +100,13 @@ void achievement_log(const char* s, char flags) {
for(int i=0; i<size(achievementsReceived); i++) for(int i=0; i<size(achievementsReceived); i++)
if(achievementsReceived[i] == s) return; if(achievementsReceived[i] == s) return;
achievementsReceived.push_back(s); achievementsReceived.push_back(s);
#ifndef NOSAVE
remove_emergency_save();
#ifndef ANDROID
FILE *f = fopen(scorefile, "at"); FILE *f = fopen(scorefile, "at");
if(!f) return; if(!f) return;
int t = (int) (time(NULL) - timerstart); int t = (int) (time(NULL) - timerstart);
time_t timer = time(NULL); time_t timer = time(NULL);
@ -101,6 +124,7 @@ void improveItemScores();
#include "hypersteam.cpp" #include "hypersteam.cpp"
#else #else
#ifndef ANDROID #ifndef ANDROID
#ifndef IOS
void achievement_init() {} void achievement_init() {}
void achievement_close() {} void achievement_close() {}
void achievement_gain(const char* s, char flags) { void achievement_gain(const char* s, char flags) {
@ -108,11 +132,18 @@ void achievement_gain(const char* s, char flags) {
} }
#endif #endif
#endif #endif
#endif
void achievement_collection(eItem it, int prevgold, int newgold) { void achievement_collection(eItem it, int prevgold, int newgold) {
if(cheater) return; if(cheater) return;
if(randomPatternsMode) return; if(randomPatternsMode) return;
int q = items[it]; int q = items[it];
if(it == itTreat && q == 50)
achievement_gain("HALLOWEEN1", 'E');
if(it == itTreat && q == 100)
achievement_gain("HALLOWEEN2", 'E');
if(q == 1) { if(q == 1) {
if(it == itDiamond) achievement_gain("DIAMOND1"); if(it == itDiamond) achievement_gain("DIAMOND1");
@ -142,7 +173,7 @@ void achievement_collection(eItem it, int prevgold, int newgold) {
if(it == itPalace) achievement_gain("RUG1"); if(it == itPalace) achievement_gain("RUG1");
if(it == itFjord) achievement_gain("GARNET1"); if(it == itFjord) achievement_gain("GARNET1");
if(it == itEdge) achievement_gain("TOWER1"); if(it == itIvory) achievement_gain("TOWER1");
if(it == itElemental) achievement_gain("ELEMENT1"); if(it == itElemental) achievement_gain("ELEMENT1");
if(it == itZebra) achievement_gain("ZEBRA1"); if(it == itZebra) achievement_gain("ZEBRA1");
@ -157,6 +188,17 @@ void achievement_collection(eItem it, int prevgold, int newgold) {
if(it == itBabyTortoise) achievement_gain("TORTOISE1"); if(it == itBabyTortoise) achievement_gain("TORTOISE1");
if(it == itDragon) achievement_gain("DRAGON1"); if(it == itDragon) achievement_gain("DRAGON1");
if(it == itApple) achievement_gain("APPLE1"); if(it == itApple) achievement_gain("APPLE1");
if(it == itKraken) achievement_gain("KRAKEN1");
if(it == itBarrow) achievement_gain("BARROW1");
if(it == itTrollEgg) achievement_gain("TROLL1");
if(it == itAmethyst) achievement_gain("MOUNT1");
if(it == itSlime) achievement_gain("DUNG1");
if(it == itDodeca) achievement_gain("DOD1");
if(it == itGreenGrass) achievement_gain("PRAIR1");
if(it == itBull) achievement_gain("BULL1");
} }
// 32 // 32
@ -194,7 +236,7 @@ void achievement_collection(eItem it, int prevgold, int newgold) {
if(it == itPalace) achievement_gain("RUG2"); if(it == itPalace) achievement_gain("RUG2");
if(it == itFjord) achievement_gain("GARNET2"); if(it == itFjord) achievement_gain("GARNET2");
if(it == itEdge) achievement_gain("TOWER2"); if(it == itIvory) achievement_gain("TOWER2");
if(it == itElemental) achievement_gain("ELEMENT2"); if(it == itElemental) achievement_gain("ELEMENT2");
if(it == itZebra) achievement_gain("ZEBRA2"); if(it == itZebra) achievement_gain("ZEBRA2");
@ -209,6 +251,17 @@ void achievement_collection(eItem it, int prevgold, int newgold) {
if(it == itBabyTortoise) achievement_gain("TORTOISE2"); if(it == itBabyTortoise) achievement_gain("TORTOISE2");
if(it == itDragon) achievement_gain("DRAGON2"); if(it == itDragon) achievement_gain("DRAGON2");
if(it == itApple) achievement_gain("APPLE2"); if(it == itApple) achievement_gain("APPLE2");
if(it == itKraken) achievement_gain("KRAKEN2");
if(it == itBarrow) achievement_gain("BARROW2");
if(it == itTrollEgg) achievement_gain("TROLL2");
if(it == itAmethyst) achievement_gain("MOUNT2");
if(it == itSlime) achievement_gain("DUNG2");
if(it == itDodeca) achievement_gain("DOD2");
if(it == itGreenGrass) achievement_gain("PRAIR2");
if(it == itBull) achievement_gain("BULL2");
} }
if(q == 25) { if(q == 25) {
@ -239,7 +292,7 @@ void achievement_collection(eItem it, int prevgold, int newgold) {
if(it == itPalace) achievement_gain("RUG3"); if(it == itPalace) achievement_gain("RUG3");
if(it == itFjord) achievement_gain("GARNET3"); if(it == itFjord) achievement_gain("GARNET3");
if(it == itEdge) achievement_gain("TOWER3"); if(it == itIvory) achievement_gain("TOWER3");
if(it == itElemental) achievement_gain("ELEMENT3"); if(it == itElemental) achievement_gain("ELEMENT3");
if(it == itZebra) achievement_gain("ZEBRA3"); if(it == itZebra) achievement_gain("ZEBRA3");
@ -257,6 +310,17 @@ void achievement_collection(eItem it, int prevgold, int newgold) {
if(it == itBabyTortoise) achievement_gain("TORTOISE3"); if(it == itBabyTortoise) achievement_gain("TORTOISE3");
if(it == itDragon) achievement_gain("DRAGON3"); if(it == itDragon) achievement_gain("DRAGON3");
if(it == itApple) achievement_gain("APPLE3"); if(it == itApple) achievement_gain("APPLE3");
if(it == itKraken) achievement_gain("KRAKEN3");
if(it == itBarrow) achievement_gain("BARROW3");
if(it == itTrollEgg) achievement_gain("TROLL3");
if(it == itAmethyst) achievement_gain("MOUNT3");
if(it == itSlime) achievement_gain("DUNG3");
if(it == itDodeca) achievement_gain("DOD3");
if(it == itGreenGrass) achievement_gain("PRAIR3");
if(it == itBull) achievement_gain("BULL3");
} }
if(q == 50) { if(q == 50) {
@ -287,7 +351,7 @@ void achievement_collection(eItem it, int prevgold, int newgold) {
if(it == itPalace) achievement_gain("RUG4"); if(it == itPalace) achievement_gain("RUG4");
if(it == itFjord) achievement_gain("GARNET4"); if(it == itFjord) achievement_gain("GARNET4");
if(it == itEdge) achievement_gain("TOWER4"); if(it == itIvory) achievement_gain("TOWER4");
if(it == itElemental) achievement_gain("ELEMENT4"); if(it == itElemental) achievement_gain("ELEMENT4");
if(it == itZebra) achievement_gain("ZEBRA4"); if(it == itZebra) achievement_gain("ZEBRA4");
@ -302,6 +366,17 @@ void achievement_collection(eItem it, int prevgold, int newgold) {
if(it == itBabyTortoise) achievement_gain("TORTOISE4"); if(it == itBabyTortoise) achievement_gain("TORTOISE4");
if(it == itDragon) achievement_gain("DRAGON4"); if(it == itDragon) achievement_gain("DRAGON4");
if(it == itApple) achievement_gain("APPLE4"); if(it == itApple) achievement_gain("APPLE4");
if(it == itKraken) achievement_gain("KRAKEN4");
if(it == itBarrow) achievement_gain("BARROW4");
if(it == itTrollEgg) achievement_gain("TROLL4");
if(it == itAmethyst) achievement_gain("MOUNT4");
if(it == itSlime) achievement_gain("DUNG4");
if(it == itDodeca) achievement_gain("DOD4");
if(it == itGreenGrass) achievement_gain("PRAIR4");
if(it == itBull) achievement_gain("BULL4");
} }
if(it == itOrbYendor) { if(it == itOrbYendor) {
@ -323,6 +398,8 @@ void achievement_count(const string& s, int current, int prev) {
achievement_gain("STABBER1"); achievement_gain("STABBER1");
if(s == "STAB" && current >= 2) if(s == "STAB" && current >= 2)
achievement_gain("STABBER2"); achievement_gain("STABBER2");
if(s == "SLASH" && current >= 2)
achievement_gain("SLASH2");
if(s == "STAB" && current >= 4) if(s == "STAB" && current >= 4)
achievement_gain("STABBER3"); achievement_gain("STABBER3");
if(s == "MIRRORKILL" && current-prev >= 1) if(s == "MIRRORKILL" && current-prev >= 1)
@ -374,6 +451,9 @@ void achievement_score(int cat, int number) {
#ifdef HAVE_ACHIEVEMENTS #ifdef HAVE_ACHIEVEMENTS
if(cheater) return; if(cheater) return;
if(euclid) return; if(euclid) return;
if(sphere && cat != LB_HALLOWEEN) return;
if(quotient) return;
if(elliptic && cat != LB_HALLOWEEN) return;
if(purehepta) return; if(purehepta) return;
if(randomPatternsMode) return; if(randomPatternsMode) return;
if(shmup::on && cat != LB_PURE_TACTICS_SHMUP && cat != LB_PURE_TACTICS_COOP) return; if(shmup::on && cat != LB_PURE_TACTICS_SHMUP && cat != LB_PURE_TACTICS_COOP) return;
@ -403,7 +483,7 @@ void improveItemScores() {
improve_score(34, itPalace); improve_score(34, itPalace);
improve_score(35, itFjord); improve_score(35, itFjord);
improve_score(37, itEdge); improve_score(37, itIvory);
improve_score(38, itElemental); improve_score(38, itElemental);
improve_score(39, itZebra); improve_score(39, itZebra);
@ -420,14 +500,34 @@ void improveItemScores() {
improve_score(54, itBabyTortoise); improve_score(54, itBabyTortoise);
improve_score(55, itDragon); improve_score(55, itDragon);
improve_score(56, itApple); improve_score(56, itApple);
improve_score(58, itKraken);
improve_score(59, itBarrow);
improve_score(60, itTrollEgg);
improve_score(64, itAmethyst);
improve_score(65, itSlime);
improve_score(66, itDodeca);
improve_score(67, itGreenGrass);
improve_score(68, itBull);
} }
void achievement_final(bool really_final) { void achievement_final(bool really_final) {
if(offlineMode) return; if(offlineMode) return;
#ifdef HAVE_ACHIEVEMENTS #ifdef HAVE_ACHIEVEMENTS
upload_score(LB_STATISTICS, time(NULL));
if(cheater) return; if(cheater) return;
if(sphere && euclidland == laHalloween) {
if(shmup::on || chaosmode || purehepta || numplayers() > 1 || tactic::on || randomPatternsMode)
return;
achievement_score(LB_HALLOWEEN, items[itTreat]);
}
if(euclid) return; if(euclid) return;
if(purehepta) return; if(sphere) return;
if(elliptic) return;
if(randomPatternsMode) return; if(randomPatternsMode) return;
if(tactic::on) { if(tactic::on) {
@ -439,15 +539,24 @@ void achievement_final(bool really_final) {
if(yendor::on) return; if(yendor::on) return;
if(shmup::on && chaosmode) return; // no leaderboards for two special modes at once
int specials = 0;
if(shmup::on) specials++;
if(chaosmode) specials++;
if(purehepta) specials++;
if(specials > 1) return;
if(numplayers() > 1 && chaosmode) return;
if(numplayers() > 1 && purehepta) return;
int total_improved = 0; int total_improved = 0;
specific_improved = 0; specific_improved = 0;
specific_what = 0; specific_what = 0;
if(!shmup::on && !chaosmode) improveItemScores(); if(!shmup::on && !chaosmode && !purehepta && numplayers() == 1) improveItemScores();
int sid = chaosmode ? 53 : shmup::on ? (numplayers() > 1 ? 44 : 28) : 0; int sid = purehepta ? 57 : chaosmode ? 53 : shmup::on ? (numplayers() > 1 ? 44 : 28) :
(numplayers() > 1 ? 61 : 0);
int tg = gold(); int tg = gold();
if(tg && haveLeaderboard(sid)) { if(tg && haveLeaderboard(sid)) {
@ -488,6 +597,8 @@ void achievement_victory(bool hyper) {
#ifdef HAVE_ACHIEVEMENTS #ifdef HAVE_ACHIEVEMENTS
if(cheater) return; if(cheater) return;
if(euclid) return; if(euclid) return;
if(sphere) return;
if(quotient) return;
if(purehepta) return; if(purehepta) return;
if(randomPatternsMode) return; if(randomPatternsMode) return;
if(hyper && shmup::on) return; if(hyper && shmup::on) return;
@ -572,3 +683,7 @@ void achievement_display() {
#endif #endif
} }
bool isAscending(int i) {
return i == 13 || i == 14 || i == 15 || i == 16 || i == 29 || i == 30 || i == 45;
};

650
cell.cpp
View File

@ -1,10 +1,11 @@
// Hyperbolic Rogue -- cells // Hyperbolic Rogue -- cells
// Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details // Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details
// cells the game is played on // cells the game is played on
int fix6(int a) { return (a+96)% 6; } int fix6(int a) { return (a+96)% 6; }
int fix7(int a) { return (a+84)% 7; } int fix7(int a) { return (a+420)%S7; }
int dirdiff(int dd, int t) { int dirdiff(int dd, int t) {
dd %= t; dd %= t;
@ -15,7 +16,20 @@ int dirdiff(int dd, int t) {
struct cell : gcell { struct cell : gcell {
char type; // 6 for hexagons, 7 for heptagons char type; // 6 for hexagons, 7 for heptagons
unsigned char spn[7];
// wall parameter, used for remaining power of Bonfires and Thumpers
char wparam;
// 'tmp' is used for:
// pathfinding algorithm used by monsters with atypical movement (which do not use pathdist)
// bugs' pathfinding algorithm
short aitmp;
uint32_t spintable;
int spin(int d) { return tspin(spintable, d); }
int spn(int d) { return tspin(spintable, d); }
int mirror(int d) { return tmirror(spintable, d); }
heptagon *master; heptagon *master;
cell *mov[7]; // meaning very similar to heptagon::move cell *mov[7]; // meaning very similar to heptagon::move
}; };
@ -36,11 +50,11 @@ cell *newCell(int type, heptagon *master) {
return c; return c;
} }
void merge(cell *c, int d, cell *c2, int d2) { void merge(cell *c, int d, cell *c2, int d2, bool mirrored = false) {
c->mov[d] = c2; c->mov[d] = c2;
c->spn[d] = d2; tsetspin(c->spintable, d, d2 + (mirrored?8:0));
c2->mov[d2] = c; c2->mov[d2] = c;
c2->spn[d2] = d; tsetspin(c2->spintable, d2, d + (mirrored?8:0));
} }
typedef unsigned short eucoord; typedef unsigned short eucoord;
@ -80,55 +94,54 @@ cell *createMov(cell *c, int d) {
if(c->mov[d]) return c->mov[d]; if(c->mov[d]) return c->mov[d];
else if(purehepta) { else if(purehepta) {
heptagon *h2 = createStep(c->master, d); heptagon *h2 = createStep(c->master, d);
c->mov[d] = h2->c7; merge(c,d,h2->c7,c->master->spin(d),false);
c->spn[d] = c->master->spin[d];
h2->c7->mov[c->spn[d]] = c;
h2->c7->spn[c->spn[d]] = d;
} }
else if(c->type == 7) { else if(c->type != 6) {
cell *n = newCell(6, c->master); cell *n = newCell(6, c->master);
c->mov[d] = n; n->mov[0] = c; merge(c,d,n,0,false);
c->spn[d] = 0; n->spn[0] = d;
heptspin hs; hs.h = c->master; hs.spin = d; heptspin hs; hs.h = c->master; hs.spin = d; hs.mirrored = false;
heptspin hs2 = hsstep(hsspin(hs, 3), 3); int a3 = c->type/2;
int a4 = a3+1;
// merge(hs2.h->c7, hs2.spin, n, 2); heptspin hs2 = hsstep(hsspin(hs, a3), a3);
merge(hs2.h->c7, hs2.spin, n, 2, hs2.mirrored);
hs2.h->c7->mov[hs2.spin] = n; n->mov[2] = hs2.h->c7; heptspin hs3 = hsstep(hsspin(hs, a4), a4);
hs2.h->c7->spn[hs2.spin] = 2; n->spn[2] = hs2.spin; merge(hs3.h->c7, hs3.spin, n, 4, hs3.mirrored);
hs2 = hsstep(hsspin(hs, 4), 4);
// merge(hs2.h->c7, hs2.spin, n, 4);
hs2.h->c7->mov[hs2.spin] = n; n->mov[4] = hs2.h->c7;
hs2.h->c7->spn[hs2.spin] = 4; n->spn[4] = hs2.spin;
extern void verifycell(cell *c);
verifycell(n);
} }
else if(d == 5) { else if(d == 5) {
int di = fixrot(c->spn[0]+1); int di = fixrot(c->spin(0)+1);
cell *c2 = createMov(c->mov[0], di); cell *c2 = createMov(c->mov[0], di);
merge(c, 5, c2, fix6(c->mov[0]->spn[di] + 1)); bool mirr = c->mov[0]->mirror(di);
merge(c, 5, c2, fix6(c->mov[0]->spn(di) + (mirr?-1:1)), mirr);
// c->mov[5] = c->mov[0]->mov[fixrot(c->spn[0]+1)]; // c->mov[5] = c->mov[0]->mov[fixrot(c->spn[0]+1)];
// c->spn[5] = fix6(c->mov[0]->spn[fixrot(c->spn[0]+1)] + 1); // c->spn[5] = fix6(c->mov[0]->spn[fixrot(c->spn[0]+1)] + 1);
} }
else if(d == 1) { else if(d == 1) {
int di = fixrot(c->spn[0]-1); int di = fixrot(c->spn(0)-1);
cell *c2 = createMov(c->mov[0], di); cell *c2 = createMov(c->mov[0], di);
merge(c, 1, c2, fix6(c->mov[0]->spn[di] - 1)); bool mirr = c->mov[0]->mirror(di);
merge(c, 1, c2, fix6(c->mov[0]->spn(di) - (mirr?-1:1)), mirr);
// c->mov[1] = c->mov[0]->mov[fixrot(c->spn[0]-1)]; // c->mov[1] = c->mov[0]->mov[fixrot(c->spn[0]-1)];
// c->spn[1] = fix6(c->mov[0]->spn[fixrot(c->spn[0]-1)] - 1); // c->spn[1] = fix6(c->mov[0]->spn[fixrot(c->spn[0]-1)] - 1);
} }
else if(d == 3) { else if(d == 3) {
int di = fixrot(c->spn[2]-1); bool mirr = c->mirror(2);
int di = fixrot(c->spn(2)-(mirr?-1:1));
cell *c2 = createMov(c->mov[2], di); cell *c2 = createMov(c->mov[2], di);
merge(c, 3, c2, fix6(c->mov[2]->spn[di] - 1)); bool nmirr = mirr ^ c->mov[2]->mirror(di);
merge(c, 3, c2, fix6(c->mov[2]->spn(di) - (nmirr?-1:1)), nmirr);
// c->mov[3] = c->mov[2]->mov[fixrot(c->spn[2]-1)]; // c->mov[3] = c->mov[2]->mov[fixrot(c->spn[2]-1)];
// c->spn[3] = fix6(c->mov[2]->spn[fixrot(c->spn[2]-1)] - 1); // c->spn[3] = fix6(c->mov[2]->spn[fixrot(c->spn[2]-1)] - 1);
} }
@ -136,12 +149,12 @@ cell *createMov(cell *c, int d) {
} }
cell *createMovR(cell *c, int d) { cell *createMovR(cell *c, int d) {
d %= 42; d += 42; d %= c->type; d %= 420; d += 420; d %= c->type;
return createMov(c, d); return createMov(c, d);
} }
cell *getMovR(cell *c, int d) { cell *getMovR(cell *c, int d) {
d %= 42; d += 42; d %= c->type; d %= 420; d += 420; d %= c->type;
return c->mov[d]; return c->mov[d];
} }
@ -149,12 +162,13 @@ cell *getMovR(cell *c, int d) {
struct cellwalker { struct cellwalker {
cell *c; cell *c;
int spin; int spin;
cellwalker(cell *c, int spin) : c(c), spin(spin) {} bool mirrored;
cellwalker() {} cellwalker(cell *c, int spin) : c(c), spin(spin) { mirrored = false; }
cellwalker() { mirrored = false; }
}; };
void cwspin(cellwalker& cw, int d) { void cwspin(cellwalker& cw, int d) {
cw.spin = (cw.spin+d + 42) % cw.c->type; cw.spin = (cw.spin+(MIRR(cw)?-d:d) + 420) % cw.c->type;
} }
bool cwstepcreates(cellwalker& cw) { bool cwstepcreates(cellwalker& cw) {
@ -162,20 +176,21 @@ bool cwstepcreates(cellwalker& cw) {
} }
cell *cwpeek(cellwalker cw, int dir) { cell *cwpeek(cellwalker cw, int dir) {
return createMov(cw.c, (cw.spin+42+dir) % cw.c->type); return createMov(cw.c, (cw.spin+420+dir) % cw.c->type);
} }
void cwstep(cellwalker& cw) { void cwstep(cellwalker& cw) {
createMov(cw.c, cw.spin); createMov(cw.c, cw.spin);
int nspin = cw.c->spn[cw.spin]; int nspin = cw.c->spn(cw.spin);
if(cw.c->mirror(cw.spin)) cw.mirrored = !cw.mirrored;
cw.c = cw.c->mov[cw.spin]; cw.c = cw.c->mov[cw.spin];
cw.spin = nspin; cw.spin = nspin;
} }
void eumerge(cell* c1, cell *c2, int s1, int s2) { void eumerge(cell* c1, cell *c2, int s1, int s2) {
if(!c2) return; if(!c2) return;
c1->mov[s1] = c2; c1->spn[s1] = s2; c1->mov[s1] = c2; tsetspin(c1->spintable, s1, s2);
c2->mov[s2] = c1; c2->spn[s2] = s1; c2->mov[s2] = c1; tsetspin(c2->spintable, s2, s1);
} }
struct euclideanSlab { struct euclideanSlab {
@ -216,28 +231,99 @@ cell*& euclideanAtCreate(eucoord x, eucoord y) {
return c; return c;
} }
int spherecells() {
if(S7 == 5) return (elliptic?6:12);
if(S7 == 4) return (elliptic?3:6);
if(S7 == 3) return 4;
if(S7 == 2) return (elliptic?1:2);
if(S7 == 1) return 1;
return 12;
}
// initializer (also inits origin from heptagon.cpp) // initializer (also inits origin from heptagon.cpp)
void initcells() { void initcells() {
DEBB(DF_INIT, (debugfile,"initcells\n")); DEBB(DF_INIT, (debugfile,"initcells\n"));
origin.s = hsOrigin;
origin.emeraldval = 98;
origin.zebraval = 40;
origin.fiftyval = 0;
#ifdef CDATA
origin.rval0 = origin.rval1 = 0;
origin.cdata = NULL;
#endif
for(int i=0; i<7; i++) origin.move[i] = NULL;
origin.alt = NULL;
origin.distance = 0;
if(euclid)
origin.c7 = euclideanAtCreate(0,0);
else
origin.c7 = newCell(7, &origin);
if(sphere) {
for(int i=0; i<spherecells(); i++) {
heptagon& h = dodecahedron[i];
h.s = hsOrigin;
h.emeraldval = i;
h.zebraval = i;
h.fiftyval = i;
h.rval0 = h.rval1 = 0;
h.alt = NULL;
h.cdata = NULL;
h.spintable = 0;
for(int i=0; i<S7; i++) h.move[i] = NULL;
h.c7 = newCell(S7, &h);
}
for(int i=0; i<S7; i++) {
dodecahedron[0].move[i] = &dodecahedron[i+1];
dodecahedron[0].setspin(i, 0);
dodecahedron[i+1].move[0] = &dodecahedron[0];
dodecahedron[i+1].setspin(0, i);
dodecahedron[i+1].move[1] = &dodecahedron[(i+S7-1)%S7+1];
dodecahedron[i+1].setspin(1, S7-1);
dodecahedron[i+1].move[S7-1] = &dodecahedron[(i+1)%S7+1];
dodecahedron[i+1].setspin(S7-1, 1);
if(S7 == 5 && elliptic) {
dodecahedron[i+1].move[2] = &dodecahedron[(i+2)%S7+1];
dodecahedron[i+1].setspin(2, 3 + 8);
dodecahedron[i+1].move[3] = &dodecahedron[(i+3)%S7+1];
dodecahedron[i+1].setspin(3, 2 + 8);
}
else if(S7 == 5) {
dodecahedron[6].move[i] = &dodecahedron[7+i];
dodecahedron[6].setspin(i, 0);
dodecahedron[7+i].move[0] = &dodecahedron[6];
dodecahedron[7+i].setspin(0, i);
dodecahedron[i+7].move[1] = &dodecahedron[(i+4)%5+7];
dodecahedron[i+7].setspin(1, 4);
dodecahedron[i+7].move[4] = &dodecahedron[(i+1)%5+7];
dodecahedron[i+7].setspin(4, 1);
dodecahedron[i+1].move[2] = &dodecahedron[7+(10-i)%5];
dodecahedron[i+1].setspin(2, 2);
dodecahedron[7+(10-i)%5].move[2] = &dodecahedron[1+i];
dodecahedron[7+(10-i)%5].setspin(2, 2);
dodecahedron[i+1].move[3] = &dodecahedron[7+(9-i)%5];
dodecahedron[i+1].setspin(3, 3);
dodecahedron[7+(9-i)%5].move[3] = &dodecahedron[i+1];
dodecahedron[7+(9-i)%5].setspin(3, 3);
}
if(S7 == 4) {
dodecahedron[5].move[3-i] = &dodecahedron[i+1];
dodecahedron[5].setspin(3-i, 2);
dodecahedron[i+1].move[2] = &dodecahedron[5];
dodecahedron[i+1].setspin(2, 3-i);
}
}
}
else {
origin.s = hsOrigin;
origin.emeraldval = 98;
origin.zebraval = 40;
origin.fiftyval = 0;
origin.fieldval = 0;
origin.rval0 = origin.rval1 = 0;
origin.cdata = NULL;
for(int i=0; i<7; i++) origin.move[i] = NULL;
origin.spintable = 0;
origin.alt = NULL;
origin.distance = 0;
if(euclid)
origin.c7 = euclideanAtCreate(0,0);
else
origin.c7 = newCell(7, &origin);
}
if(quotient) quotientspace::build();
// origin.emeraldval = // origin.emeraldval =
} }
@ -247,13 +333,13 @@ void clearcell(cell *c) {
if(!c) return; if(!c) return;
DEBMEM ( printf("c%d %p\n", c->type, c); ) DEBMEM ( printf("c%d %p\n", c->type, c); )
for(int t=0; t<c->type; t++) if(c->mov[t]) { for(int t=0; t<c->type; t++) if(c->mov[t]) {
DEBMEM ( printf("mov %p [%p] S%d\n", c->mov[t], c->mov[t]->mov[c->spn[t]], c->spn[t]); ) DEBMEM ( printf("mov %p [%p] S%d\n", c->mov[t], c->mov[t]->mov[c->spn(t)], c->spn(t)); )
if(c->mov[t]->mov[c->spn[t]] != NULL && if(c->mov[t]->mov[c->spn(t)] != NULL &&
c->mov[t]->mov[c->spn[t]] != c) { c->mov[t]->mov[c->spn(t)] != c) {
printf("cell error\n"); printf("cell error\n");
exit(1); exit(1);
} }
c->mov[t]->mov[c->spn[t]] = NULL; c->mov[t]->mov[c->spn(t)] = NULL;
} }
DEBMEM ( printf("DEL %p\n", c); ) DEBMEM ( printf("DEL %p\n", c); )
delete c; delete c;
@ -261,6 +347,14 @@ void clearcell(cell *c) {
heptagon deletion_marker; heptagon deletion_marker;
void clearHexes(heptagon *at) {
if(at->c7) {
if(!purehepta) for(int i=0; i<7; i++)
clearcell(at->c7->mov[i]);
clearcell(at->c7);
}
}
#include <queue> #include <queue>
void clearfrom(heptagon *at) { void clearfrom(heptagon *at) {
queue<heptagon*> q; queue<heptagon*> q;
@ -276,22 +370,16 @@ void clearfrom(heptagon *at) {
if(at->move[i]->alt != &deletion_marker) if(at->move[i]->alt != &deletion_marker)
q.push(at->move[i]); q.push(at->move[i]);
at->move[i]->alt = &deletion_marker; at->move[i]->alt = &deletion_marker;
DEBMEM ( printf("!mov %p [%p]\n", at->move[i], at->move[i]->move[at->spin[i]]); ) DEBMEM ( printf("!mov %p [%p]\n", at->move[i], at->move[i]->move[at->spin(i)]); )
if(at->move[i]->move[at->spin[i]] != NULL && if(at->move[i]->move[at->spin(i)] != NULL &&
at->move[i]->move[at->spin[i]] != at) { at->move[i]->move[at->spin(i)] != at) {
printf("hept error\n"); printf("hept error\n");
exit(1); exit(1);
} }
at->move[i]->move[at->spin[i]] = NULL; at->move[i]->move[at->spin(i)] = NULL;
at->move[i] = NULL; at->move[i] = NULL;
} }
DEBMEM ( printf("at %p\n", at); ) clearHexes(at);
if(at->c7) {
if(!purehepta) for(int i=0; i<7; i++)
clearcell(at->c7->mov[i]);
clearcell(at->c7);
}
DEBMEM ( printf("!DEL %p\n", at); )
if(at != &origin) delete at; if(at != &origin) delete at;
} }
//printf("maxq = %d\n", maxq); //printf("maxq = %d\n", maxq);
@ -302,46 +390,49 @@ void verifycell(cell *c) {
for(int i=0; i<t; i++) { for(int i=0; i<t; i++) {
cell *c2 = c->mov[i]; cell *c2 = c->mov[i];
if(c2) { if(c2) {
if(t == 7 && !purehepta) verifycell(c2); if(t != 6 && !purehepta) verifycell(c2);
if(c2->mov[c->spn[i]] && c2->mov[c->spn[i]] != c) if(c2->mov[c->spn(i)] && c2->mov[c->spn(i)] != c) {
printf("cell error %p %p\n", c, c2); printf("cell error %p:%d [%d] %p:%d [%d]\n", c, i, c->type, c2, c->spn(i), c2->type);
exit(1);
}
} }
} }
} }
void verifycells(heptagon *at) { void verifycells(heptagon *at) {
for(int i=0; i<7; i++) if(at->move[i] && at->spin[i] == 0 && at->move[i] != &origin) for(int i=0; i<7; i++) if(at->move[i] && at->move[i]->move[at->spin(i)] && at->move[i]->move[at->spin(i)] != at) {
verifycells(at->move[i]); printf("hexmix error %p [%d s=%d] %p %p\n", at, i, at->spin(i), at->move[i], at->move[i]->move[at->spin(i)]);
for(int i=0; i<7; i++) if(at->move[i] && at->move[i]->move[at->spin[i]] && at->move[i]->move[at->spin[i]] != at) {
printf("hexmix error %p %p %p\n", at, at->move[i], at->move[i]->move[at->spin[i]]);
} }
if(!sphere && !quotient) for(int i=0; i<7; i++) if(at->move[i] && at->spin(i) == 0 && at->move[i] != &origin)
verifycells(at->move[i]);
verifycell(at->c7); verifycell(at->c7);
} }
int eupattern(cell *c) {
eucoord x, y;
decodeMaster(c->master, x, y);
short z = (short(y+2*x))%3;
z %= 3;
if(z<0) z += 3;
return z;
}
bool ishept(cell *c) { bool ishept(cell *c) {
// EUCLIDEAN // EUCLIDEAN
if(euclid) { if(euclid) return eupattern(c) == 0;
eucoord x, y; else return c->type != 6;
decodeMaster(c->master, x, y);
return (short(y+2*x))%3 == 0;
}
else return c->type == 7;
} }
bool ishex1(cell *c) { bool ishex1(cell *c) {
// EUCLIDEAN // EUCLIDEAN
if(euclid) { if(euclid) return eupattern(c) == 1;
eucoord x, y;
decodeMaster(c->master, x, y);
short z = (short(y+2*x))%3;
if(z<0) z += 3;
return z == 1;
}
else return c->type == 7; else return c->type == 7;
} }
int emeraldval(cell *c) { int emeraldval(cell *c) {
if(euclid) return 0; if(euclid) return eupattern(c);
if(sphere) return 0;
if(c->type == 7) if(c->type == 7)
return c->master->emeraldval >> 3; return c->master->emeraldval >> 3;
else { else {
@ -360,6 +451,17 @@ int eudist(short sx, short sy) {
return max(max(z0,z1), z2); return max(max(z0,z1), z2);
} }
int compdist(int dx[3]) {
int mi = min(min(dx[0], dx[1]), dx[2]);
if(dx[0] > mi+2 || dx[1] > mi+2 || dx[2] > mi+2)
return -1; // { printf("cycle error!\n"); exit(1); }
if(dx[0] == mi+2 || dx[1] == mi+2 || dx[2] == mi+2)
return mi+1;
if((dx[0] == mi+1) + (dx[1] == mi+1) + (dx[2] == mi+1) >= 2)
return mi+1;
return mi;
}
int celldist(cell *c) { int celldist(cell *c) {
if(euclid) { if(euclid) {
eucoord x, y; eucoord x, y;
@ -370,12 +472,7 @@ int celldist(cell *c) {
int dx[3]; int dx[3];
for(int u=0; u<3; u++) for(int u=0; u<3; u++)
dx[u] = createMov(c, u+u)->master->distance; dx[u] = createMov(c, u+u)->master->distance;
int mi = min(min(dx[0], dx[1]), dx[2]); return compdist(dx);
if(dx[0] > mi+2 || dx[1] > mi+2 || dx[2] > mi+2)
return -1; // { printf("cycle error!\n"); exit(1); }
if(dx[0] == mi+2 || dx[1] == mi+2 || dx[2] == mi+2)
return mi+1;
return mi;
} }
#define ALTDIST_BOUNDARY 99999 #define ALTDIST_BOUNDARY 99999
@ -392,6 +489,7 @@ int celldistAlt(cell *c) {
decodeMaster(c->master, x, y); decodeMaster(c->master, x, y);
return euclidAlt(x, y); return euclidAlt(x, y);
} }
if(!c->master->alt) return 0;
if(c->type == 7) return c->master->alt->distance; if(c->type == 7) return c->master->alt->distance;
int dx[3]; int dx[3];
for(int u=0; u<3; u++) if(createMov(c, u+u)->master->alt == NULL) for(int u=0; u<3; u++) if(createMov(c, u+u)->master->alt == NULL)
@ -420,8 +518,23 @@ unsigned bitmajority(unsigned a, unsigned b, unsigned c) {
return (a&b) | ((a^b)&c); return (a&b) | ((a^b)&c);
} }
int eufifty(cell *c) {
eucoord x, y;
decodeMaster(c->master, x, y);
int ix = short(x) + 99999 + short(y);
int iy = short(y) + 99999;
if(c->land == laWildWest)
return (ix + iy * 26 + 28) % 37;
else {
ix += (iy/3) * 3;
iy %= 3; ix %= 9;
return iy * 9 + ix;
}
}
int fiftyval(cell *c) { int fiftyval(cell *c) {
if(euclid) return 0; if(euclid) return eufifty(c) * 32;
if(sphere) return 0;
if(c->type == 7) if(c->type == 7)
return c->master->fiftyval; return c->master->fiftyval;
else { else {
@ -433,26 +546,11 @@ int fiftyval(cell *c) {
} }
int cdist50(cell *c) { int cdist50(cell *c) {
if(sphere) return 0;
if(euclid) { if(euclid) {
eucoord x, y; if(c->land == laWildWest)
decodeMaster(c->master, x, y); return "0123333332112332223322233211233333322"[eufifty(c)] - '0';
int ix = short(x) + 99999 + short(y); else return "012333321112322232222321123"[eufifty(c)] - '0';
int iy = short(y) + 99999;
if(c->land == laPalace) {
char palacemap[3][10] = {
"012333321",
"112322232",
"222321123"
};
ix += (iy/3) * 3;
iy %= 3; ix %= 9;
return palacemap[iy][ix] - '0';
}
else {
const char *westmap = "0123333332112332223322233211233333322";
int id = ix + iy * 26 + 28;
return westmap[id % 37] - '0';
}
} }
if(c->type == 7) return cdist50(fiftyval(c)); if(c->type == 7) return cdist50(fiftyval(c));
int a0 = cdist50(createMov(c,0)); int a0 = cdist50(createMov(c,0));
@ -464,6 +562,7 @@ int cdist50(cell *c) {
int land50(cell *c) { int land50(cell *c) {
if(c->type == 7) return land50(fiftyval(c)); if(c->type == 7) return land50(fiftyval(c));
else if(sphere || euclid) return 0;
else { else {
if(cdist50(createMov(c,0)) < 3) return land50(createMov(c,0)); if(cdist50(createMov(c,0)) < 3) return land50(createMov(c,0));
if(cdist50(createMov(c,2)) < 3) return land50(createMov(c,2)); if(cdist50(createMov(c,2)) < 3) return land50(createMov(c,2));
@ -474,6 +573,7 @@ int land50(cell *c) {
int polara50(cell *c) { int polara50(cell *c) {
if(c->type == 7) return polara50(fiftyval(c)); if(c->type == 7) return polara50(fiftyval(c));
else if(sphere || euclid) return 0;
else { else {
if(cdist50(createMov(c,0)) < 3) return polara50(createMov(c,0)); if(cdist50(createMov(c,0)) < 3) return polara50(createMov(c,0));
if(cdist50(createMov(c,2)) < 3) return polara50(createMov(c,2)); if(cdist50(createMov(c,2)) < 3) return polara50(createMov(c,2));
@ -485,6 +585,7 @@ int polara50(cell *c) {
int polarb50(cell *c) { int polarb50(cell *c) {
if(euclid) return true; if(euclid) return true;
if(c->type == 7) return polarb50(fiftyval(c)); if(c->type == 7) return polarb50(fiftyval(c));
else if(sphere || euclid) return true;
else { else {
if(cdist50(createMov(c,0)) < 3) return polarb50(createMov(c,0)); if(cdist50(createMov(c,0)) < 3) return polarb50(createMov(c,0));
if(cdist50(createMov(c,2)) < 3) return polarb50(createMov(c,2)); if(cdist50(createMov(c,2)) < 3) return polarb50(createMov(c,2));
@ -498,7 +599,8 @@ int elhextable[28][3] = {
}; };
int fiftyval049(cell *c) { int fiftyval049(cell *c) {
if(c->type == 7) return fiftyval(c) / 32; if(c->type == 7 || euclid) return fiftyval(c) / 32;
else if(sphere) return 0;
else { else {
int a[3], qa=0; int a[3], qa=0;
int pa = polara50(c), pb = polarb50(c); int pa = polara50(c), pb = polarb50(c);
@ -536,7 +638,9 @@ int fiftyval049(cell *c) {
int zebra40(cell *c) { int zebra40(cell *c) {
if(c->type == 7) return (c->master->zebraval/10); if(c->type == 7) return (c->master->zebraval/10);
else { else if(sphere) return 0;
else if(euclid) return eupattern(c);
else {
int ii[3], z; int ii[3], z;
ii[0] = (c->mov[0]->master->zebraval/10); ii[0] = (c->mov[0]->master->zebraval/10);
ii[1] = (c->mov[2]->master->zebraval/10); ii[1] = (c->mov[2]->master->zebraval/10);
@ -558,6 +662,7 @@ int zebra40(cell *c) {
int zebra3(cell *c) { int zebra3(cell *c) {
if(c->type == 7) return (c->master->zebraval/10)/4; if(c->type == 7) return (c->master->zebraval/10)/4;
else if(sphere) return 0;
else { else {
int ii[3]; int ii[3];
ii[0] = (c->mov[0]->master->zebraval/10)/4; ii[0] = (c->mov[0]->master->zebraval/10)/4;
@ -696,8 +801,6 @@ bool randpatternMajority(cell *c, int ival, int iterations) {
return memo; return memo;
} }
#ifdef CDATA
#include <map> #include <map>
map<heptagon*, int> spins; map<heptagon*, int> spins;
@ -732,6 +835,8 @@ void setHeptagonRval(heptagon *h) {
cdata *getHeptagonCdata(heptagon *h) { cdata *getHeptagonCdata(heptagon *h) {
if(h->cdata) return h->cdata; if(h->cdata) return h->cdata;
if(sphere || quotient) h = &origin;
if(h == &origin) { if(h == &origin) {
return h->cdata = new cdata(orig_cdata); return h->cdata = new cdata(orig_cdata);
} }
@ -876,8 +981,108 @@ eLand getCLand(cell *c) {
return land_scape[b & 31]; return land_scape[b & 31];
} }
// list all cells in distance at most maxdist, or until when maxcount cells are reached
struct celllister {
vector<cell*> lst;
vector<int> tmps;
vector<int> dists;
bool listed(cell *c) {
return c->aitmp >= 0 && c->aitmp < size(lst) && lst[c->aitmp] == c;
}
void add(cell *c, int d) {
if(listed(c)) return;
c->aitmp = size(lst);
tmps.push_back(c->aitmp);
lst.push_back(c);
dists.push_back(d);
}
int getdist(cell *c) { return dists[c->aitmp]; }
~celllister() {
for(int i=0; i<size(lst); i++) lst[i]->aitmp = tmps[i];
}
celllister(cell *orig, int maxdist, int maxcount, cell *breakon) {
lst.clear();
tmps.clear();
dists.clear();
add(orig, 0);
cell *last = orig;
for(int i=0; i<size(lst); i++) {
cell *c = lst[i];
if(maxdist) forCellCM(c2, c) {
add(c2, dists[i]+1);
if(c2 == breakon) return;
}
if(c == last) {
if(size(lst) >= maxcount || dists[i]+1 == maxdist) break;
last = lst[size(lst)-1];
maxdist--;
}
}
}
};
cell *heptatdir(cell *c, int d) {
if(d&1) {
cell *c2 = createMov(c, d);
int s = c->spin(d);
s += 3; s %= 6;
return createMov(c2, s);
}
else return createMov(c, d);
}
namespace fieldpattern {
pair<int, bool> fieldval(cell *c) {
if(c->type == 7) return make_pair(c->master->fieldval, false);
else return make_pair(btspin(c->master->fieldval, c->spin(0)), true);
}
int subpathid = fp43.matcode[fp43.strtomatrix("RRRPRRRRRPRRRP")];
int subpathorder = fp43.order(fp43.matrices[subpathid]);
pair<int, int> subval(cell *c, int _subpathid = subpathid, int _subpathorder = subpathorder) {
if(c->type == 6)
return min(min(subval(createMov(c, 0)),subval(createMov(c, 2))), subval(createMov(c, 4)));
else {
pair<int, int> pbest, pcur;
pcur.first = c->master->fieldval;
pcur.second = 0;
pbest = pcur;
for(int i=0; i<_subpathorder; i++) {
pcur.first = fp43.gmul(pcur.first, _subpathid);
pcur.second++;
if(pcur < pbest) pbest = pcur;
}
return pbest;
}
}
}
int celldistance(cell *c1, cell *c2) { int celldistance(cell *c1, cell *c2) {
int d = 0; int d = 0;
if(euclid) {
eucoord x1, y1, x2, y2;
decodeMaster(c1->master, x1, y1);
decodeMaster(c2->master, x2, y2);
return eudist(x1-x2, y1-y2);
}
if(sphere || quotient == 1) {
celllister cl(c1, 64, 1000, c2);
return cl.getdist(c2);
}
if(quotient == 2)
return fp43.getdist(fieldpattern::fieldval(c1), fieldpattern::fieldval(c2));
cell *cl1=c1, *cr1=c1, *cl2=c2, *cr2=c2; cell *cl1=c1, *cr1=c1, *cl2=c2, *cr2=c2;
while(true) { while(true) {
if(cl1 == cl2) return d; if(cl1 == cl2) return d;
@ -912,16 +1117,20 @@ int celldistance(cell *c1, cell *c2) {
} }
} }
void clearMemory() { void clearHyperbolicMemory() {
extern void clearGameMemory(); DEBMEM ( verifycells(&origin); )
clearGameMemory(); clearfrom(&origin);
if(shmup::on) shmup::clearMemory(); for(int i=0; i<size(allAlts); i++) clearfrom(allAlts[i]);
cleargraphmemory(); allAlts.clear();
#ifndef MOBILE }
mapeditor::clearModelCells();
#endif void clearCellMemory() {
// EUCLIDEAN // EUCLIDEAN
if(euclid) { if(sphere) {
for(int i=0; i<spherecells(); i++) clearHexes(&dodecahedron[i]);
}
else if(quotient) quotientspace::clear();
else if(euclid) {
for(int y=0; y<256; y++) for(int x=0; x<256; x++) for(int y=0; y<256; y++) for(int x=0; x<256; x++)
if(euclidean[y][x]) { if(euclidean[y][x]) {
delete euclidean[y][x]; delete euclidean[y][x];
@ -929,13 +1138,182 @@ void clearMemory() {
} }
eucdata.clear(); eucdata.clear();
} }
else { else clearHyperbolicMemory();
DEBMEM ( verifycells(&origin); ) }
clearfrom(&origin);
for(int i=0; i<size(allAlts); i++) clearfrom(allAlts[i]); void clearMemory() {
allAlts.clear(); extern void clearGameMemory();
} clearGameMemory();
shmup::clearMemory();
cleargraphmemory();
#ifndef NOEDIT
mapeditor::clearModelCells();
#endif
clearCellMemory();
DEBMEM ( printf("ok\n"); ) DEBMEM ( printf("ok\n"); )
} }
#endif void verifyDodecahedron() {
for(int i=0; i<spherecells(); i++) for(int k=0; k<S7; k++) {
heptspin hs;
hs.h = &dodecahedron[i];
hs.spin = k;
hs = hsstep(hs, 0);
hs = hsspin(hs, S7-1);
hs = hsstep(hs, 0);
hs = hsspin(hs, S7-1);
hs = hsstep(hs, 0);
hs = hsspin(hs, S7-1);
if(hs.h != &dodecahedron[i]) printf("error %d,%d\n", i, k);
}
for(int i=0; i<spherecells(); i++) verifycells(&dodecahedron[i]);
}
int getHemisphere(cell *c, int which) {
if(c->type != 6) {
int id = c->master->fiftyval;
int hemitable[3][12] = {
{ 6, 3, 3, 3, 3, 3,-6,-3,-3,-3,-3,-3},
{ 6, 3, 6, 3, 0, 0,-6,-3,-6,-3, 0, 0},
{-3, 0, 3, 0,-6,-6, 3, 0,-3, 0, 6, 6}
};
return hemitable[which][id];
}
else {
int score = 0;
for(int i=0; i<6; i+=2)
score += getHemisphere(c->mov[i], which);
return score/3;
}
}
namespace quotientspace {
vector<cell*> allcells;
struct code {
int c[8];
};
bool operator == (const code& c1, const code &c2) {
for(int i=0; i<8; i++) if(c1.c[i] != c2.c[i]) return false;
return true;
}
bool operator < (const code& c1, const code &c2) {
for(int i=0; i<8; i++) if(c1.c[i] != c2.c[i]) return c1.c[i] < c2.c[i];
return false;
}
map<code, int> reachable;
vector<heptspin> bfsq;
int cod(heptagon *h) {
return zebra40(h->c7);
}
code get(heptspin hs) {
code res;
res.c[0] = cod(hs.h);
for(int i=1; i<8; i++) {
res.c[i] = cod(hsstep(hs, 0).h);
hs = hsspin(hs, 1);
}
return res;
}
vector<int> connections;
int rvadd = 0, rvdir = 1;
int rv(int x) { return (rvadd+x*rvdir) % 7; } // if(x) return 7-x; else return x; }
void add(const heptspin& hs) {
code g = get(hs);
if(!reachable.count(g)) {
reachable[g] = bfsq.size();
bfsq.push_back(hs);
add(hsspin(hs, 1));
}
}
vector<heptagon*> allh;
void clear() {
clearfrom(origin.alt);
for(int i=0; i<size(allh); i++) {
clearHexes(allh[i]);
if(i) delete allh[i];
}
allh.clear();
allcells.clear();
}
void build() {
if(quotient == 2) {
connections = fp43.connections;
}
else {
heptspin hs; hs.h = &origin; hs.spin = 0;
reachable.clear();
bfsq.clear();
connections.clear();
add(hs);
for(int i=0; i<(int)bfsq.size(); i++) {
hs = hsstep(bfsq[i], 0);
add(hs);
connections.push_back(reachable[get(hs)]);
}
}
clearHyperbolicMemory();
origin.c7 = newCell(7, &origin);
int TOT = connections.size() / 7;
printf("heptagons = %d\n", TOT);
printf("all cells = %d\n", TOT*10/3);
if(!TOT) exit(1);
allh.resize(TOT);
for(int i=0; i<TOT; i++) allh[i] = i==0 ? &origin : new heptagon;
origin.alt = new heptagon;
*origin.alt = origin;
for(int i=0; i<7; i++) origin.alt->move[i] = NULL;
origin.alt->c7 = newCell(7, origin.alt);
for(int i=0; i<TOT; i++) {
heptagon *h = allh[i];
if(i) {
h->alt = NULL;
h->s = hsOrigin;
h->emeraldval = 0;
h->zebraval = 0;
h->fiftyval = 0;
h->fieldval = 7*i;
h->rval0 = h->rval1 = 0; h->cdata = NULL;
h->distance = 0;
h->c7 = newCell(7, h);
}
for(int j=0; j<7; j++) {
h->move[rv(j)] = allh[connections[i*7+j]/7];
h->setspin(rv(j), rv(connections[i*7+j]%7));
}
}
for(int i=0; i<TOT; i++) {
generateAlts(allh[i]);
allh[i]->emeraldval = allh[i]->alt->emeraldval;
allh[i]->zebraval = allh[i]->alt->zebraval;
allh[i]->fiftyval = allh[i]->alt->fiftyval;
allh[i]->distance = allh[i]->alt->distance;
/* for(int j=0; j<7; j++)
allh[i]->move[j]->alt = createStep(allh[i]->alt, j); */
}
celllister cl(origin.c7, 100, 100000000, NULL);
allcells = cl.lst;
}
}

View File

@ -1,11 +1,6 @@
// Hyperbolic Rogue -- items, monsters, walls, lands, descriptions, etc. // Hyperbolic Rogue -- items, monsters, walls, lands, descriptions, etc.
// Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details // Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details
#define GEN_M 0
#define GEN_F 1
#define GEN_N 2
#define GEN_O 3
// --- help --- // --- help ---
const char *wormdes = const char *wormdes =
@ -110,7 +105,7 @@ const char *foresthelp =
"Trees catch fire on the next turn. The temperature of the grass cells " "Trees catch fire on the next turn. The temperature of the grass cells "
"rises once per turn for each fire nearby, and becomes fire itself " "rises once per turn for each fire nearby, and becomes fire itself "
"when its temperature has risen 10 times.\n" "when its temperature has risen 10 times.\n"
"You can also cut down the trees. Big trees take two turns to cut down."; "You can also chop down the trees. Big trees take two turns to chop down.";
const char *hivehelp = const char *hivehelp =
"The Hive is filled with Hyperbugs. They are huge insects which look a bit like " "The Hive is filled with Hyperbugs. They are huge insects which look a bit like "
@ -216,13 +211,36 @@ const char *winddesc =
"outcoming wind. However, you can move two cells with the wind in a single turn, " "outcoming wind. However, you can move two cells with the wind in a single turn, "
"and so can the birds."; "and so can the birds.";
const char *warningdesc =
"Warnings are issued when you try to do something that appears dangerous, "
"like stepping on a known mine, or getting your boat destroyed by "
"a Kraken without having Orb of the Fish. In some cases the action "
"might actually be safe -- so you can ignore the warning and do it anyway, "
"simply by repeating the action.";
const char *hauntdesc = const char *hauntdesc =
"A dark forest filled with ghosts and graves. But there is also treasure hidden " "A dark forest filled with ghosts and graves. But there is also treasure hidden "
"deep within... But don't let greed make you stray from your path, as " "deep within... But don't let greed make you stray from your path, as "
"you can get lost!\n\n" "you can get lost!\n\n"
"The Haunted Woods are bounded by a single equidistant curve. It is not a circle or horocycle.\n\n"; "The Haunted Woods are bounded by a single equidistant curve. It is not a circle or horocycle.\n\n";
const char *bulldashdesc =
"Butterflies don't pursue you -- unless you get next to them, they just spin around the obstacles. "
"They cannot be killed conventionally, but you get treasure when a Raging Bull crashes into a Butterfly. ";
const char *prairiedesc =
"You can find safety in some places in the Prairie, but if you want treasures, "
"they can be found only on the other side of a giant herd of bulls.";
const char *cadesc =
"A land for people wanting to experiment with cellular automata in the HyperRogue grid. "
"Rules can be given on the command line; the default rules are:\n"
"-c07 00100000 -c06 0010000 -c17 00011000 -c16 0001100 -caprob 0.3\n"
"(-c0 or -c1 can be given if the same rule is to be used for hexagonal "
"and heptagonal cells).";
const char *NODESC = "No description yet."; const char *NODESC = "No description yet.";
const char *NODESCYET = "No description yet.";
const char *GENDERSWITCH = NODESC; const char *GENDERSWITCH = NODESC;
// --- monsters --- // --- monsters ---
@ -259,8 +277,8 @@ const char *dragondesc =
"The head will regenerate on the " "The head will regenerate on the "
"turns the Dragon is not moving, so you will usually have to hit it with " "turns the Dragon is not moving, so you will usually have to hit it with "
"your last attack; otherwise, if the head is healthy, it may breathe " "your last attack; otherwise, if the head is healthy, it may breathe "
"fire (at range 3), losing the hitpoint. Killing the Dragon gives you " "fire (at range 3), losing the hitpoint. Killing the Dragon "
"treasure."; "while still in the Dragon Chasms gives you treasure.";
const char *tortoisedesc = const char *tortoisedesc =
"Galápagos is the land of Tortoises. " "Galápagos is the land of Tortoises. "
@ -275,8 +293,49 @@ const char *tortoisedesc =
"Bringing back a Baby Tortoise counts as 5 $$$. The more factors agree in " "Bringing back a Baby Tortoise counts as 5 $$$. The more factors agree in "
"the given location of Galápagos, the brighter it is shown on your screen."; "the given location of Galápagos, the brighter it is shown on your screen.";
const char *krakendesc =
"There are Krakens in your homeland too... huge sea monsters which "
"could easily destroy ships. The geometry of this strange world "
"prevents quick movement of huge objects, "
"so there are no large ships, only small boats, and "
"hyperbolic Krakens are relatively small too. Still, you suppose they might be "
"the widest creatures which could still move at considerable speed...\n\n"
"Kraken heads can move only on hexagons. You need to attack all the tentacles to "
"kill the Kraken. A tentacle cannot attack if it has been attacked on the "
"same turn. When a Kraken attacks you while you are in a boat, it "
"destroys the boat, but does not kill you.";
const int motypes = 125; const char *halloweendesc =
"Halloween is a special land, that is available only in the spherical "
"or elliptic geometry (press 'o' to switch). You play on the surface of "
"a jack-o'-lantern, "
"and have to collect as many Treats as possible. Each Treat you collect "
"brings new monsters to fight, and new magical powers for you. You "
"have to fight the monsters while effectively managing your limited "
"resources.";
const char *reptiledesc =
"These reptiles are quite strange creatures. They "
"spend most of their lives sleeping as floors "
"that other creatures can walk on. "
"Sometimes they wake up to hunt their prey, "
"but they will happily go back to sleep if they "
"happen to move into a hole on their way. "
"Your attacks do not kill the Reptiles, but "
"you can push and stun them.";
const char *naturedesc =
"This Orb allows you to grow like an Ivy. "
"The Ivy is always rooted in your current location; "
"moving among the Ivy cells will move the root. "
"Moving to a new location will cause the Ivy to grow "
", if an Ivy could make that movement "
"(otherwise it breaks). "
"You can also target one of the cells adjacent to your ivy "
"(not to you) to grow or attack there.";
const int motypes = 139;
struct monstertype { struct monstertype {
char glyph; char glyph;
@ -474,7 +533,7 @@ monstertype minf[motypes] = {
{ 'B', 0x909000, "Slime Beast", slimehelp}, { 'B', 0x909000, "Slime Beast", slimehelp},
{ '@', 0x8080FF, "Knight", camelothelp }, // knight moved { '@', 0x8080FF, "Knight", camelothelp }, // knight moved
{ '@', 0x8B4513, "Illusion", { '@', 0x8B4513, "Illusion",
"Illusions are targetted " "Illusions are targeted "
"by most monsters, just like yourself, Thumpers, and your friends." "by most monsters, just like yourself, Thumpers, and your friends."
}, },
{ 'P', 0xD00000, "Pirate", { 'P', 0xD00000, "Pirate",
@ -526,7 +585,7 @@ monstertype minf[motypes] = {
{ 'P', 0xFF80FF, "Princess", princessdesc}, { 'P', 0xFF80FF, "Princess", princessdesc},
{ 'P', 0xFF80FF, "Prince", princessdesc}, { 'P', 0xFF80FF, "Prince", princessdesc},
{ 'P', 0xFF80FF, "Princess", princessdesc}, { 'P', 0xFF80FF, "Princess", princessdesc},
{ 'S', 0xC0C0C0, "Servant", "A simple servant of the master of the Ivory Tower."}, { 'F', 0xD03000, "Familiar", "A simple servant of the master of the Ivory Tower."},
{ 'B', 0x707070, "Gargoyle", gargdesc}, { 'B', 0x707070, "Gargoyle", gargdesc},
{ 'E', 0xFF0000, "Fire Elemental", { 'E', 0xFF0000, "Fire Elemental",
"This monster leaves a trail of fire behind."}, "This monster leaves a trail of fire behind."},
@ -573,7 +632,7 @@ monstertype minf[motypes] = {
{ 'T', 0x487830, "Tortoise", tortoisedesc}, { 'T', 0x487830, "Tortoise", tortoisedesc},
{ 'D', 0xC03000, "Dragon", dragondesc}, { 'D', 0xC03000, "Dragon", dragondesc},
{ 'd', 0xC03000, "Dragon", dragondesc}, { 'd', 0xC03000, "Dragon", dragondesc},
{ 'N', 0x303030, "Nighthawk", NODESC}, { 'F', 0x909090, "Gadfly", "Annoying insects. They can awaken Sleeping Bulls."},
{ 'Y', 0xFF8000, "Yendorian Researcher", { 'Y', 0xFF8000, "Yendorian Researcher",
"These people study gravity and infinite trees. " "These people study gravity and infinite trees. "
"They have no special features, other than wearing a strange hat." "They have no special features, other than wearing a strange hat."
@ -581,6 +640,39 @@ monstertype minf[motypes] = {
{ 'K', 0xA8A8A8, "Sparrowhawk", { 'K', 0xA8A8A8, "Sparrowhawk",
"A bird who hunts in the treetops of Yendorian Forest." "A bird who hunts in the treetops of Yendorian Forest."
}, },
{ 'K', 0xD0A0A0, "Kraken", krakendesc},
{ 'K', 0xC07070, "Kraken Tentacle", krakendesc},
{ 'D', 0xF09090, "Draugr",
"Animated corpses of ancient Viking warriors. They are immune to mundane weapons, "
"but they can be destroyed by your Orb of the Sword."
},
{ 'C', 0xC08000, "Friendly Ivy", naturedesc },
{ 'V', 0xC000C0, "Vampire Bat",
"Vampire Bats don't attack normally, but they drain your magical powers if "
"they are at distance at most 2 from you."
},
{ 'B', 0x404040, "Bat",
"Someone has told you that one can get battle experience safely by "
"killing tons of essentially harmless creatures, such as Bats. But "
"does this make any sense?...\n\n"
"It does not. Bats cannot hurt you, but may block your movement, or "
"toggle switches if they fall on them." },
{ 'R', 0x8080C0, "Reptile", reptiledesc },
{ 'B', 0x606020, "Herd Bull",
"Herds of these Bulls are running long distances for some reason. They become Raging Bulls if something stops them." },
{ 'B', 0xA03000, "Raging Bull",
"Raging Bulls charge in a straight line: on heptagons, when they can choose one of two possible directions, "
"they choose one closer to your current location. In the case of a tie, the cell where more neighbors is "
"closer to your current location is chosen; if still a tie, past locations are considered. "
"They can attack you in any direction, and monsters on their way are attacked even if friendly. "
"When they crash into something, the obstacle is usually destroyed, and they are stunned for three turns, after "
"which they charge at you again (in any direction). "
"Raging Bulls cannot be killed or stunned conventionally."
},
{ 'B', 0xB07000, "Sleeping Bull",
"Sleeping bulls wake up when you get into distance of two cells from them."
},
{ 'S', 0xFFD500, "Butterfly", bulldashdesc},
// shmup specials // shmup specials
{ '@', 0xC0C0C0, "Rogue", "In the Shoot'em Up mode, you are armed with thrown Knives."}, { '@', 0xC0C0C0, "Rogue", "In the Shoot'em Up mode, you are armed with thrown Knives."},
@ -593,6 +685,9 @@ monstertype minf[motypes] = {
{ '?', 0x00C000, "dead bug", NODESC}, { '?', 0x00C000, "dead bug", NODESC},
{ '?', 0xFFFF00, "electric discharge", NODESC}, // appears as 'killed by electrocution' { '?', 0xFFFF00, "electric discharge", NODESC}, // appears as 'killed by electrocution'
{ '?', 0xE06000, "dead bird", NODESC}, { '?', 0xE06000, "dead bird", NODESC},
{ '?', 0xE06000, "Energy Sword", NODESC},
{ '!', 0xFF0000, "Warning", warningdesc},
{ '*', 0, "vertex", "A vertex from rogueviz."}
}; };
enum eMonster { enum eMonster {
@ -626,18 +721,23 @@ enum eMonster {
moMouse, moMouseMoved, moMouse, moMouseMoved,
moPrincess, moPrincessMoved, moPrincess, moPrincessMoved,
moPrincessArmed, moPrincessArmedMoved, moPrincessArmed, moPrincessArmedMoved,
moEdgeMonkey, moGargoyle, moFireElemental, moAirElemental, moFamiliar, moGargoyle, moFireElemental, moAirElemental,
moOrangeDog, moTentacleGhost, moOrangeDog, moTentacleGhost,
moMetalBeast, moMetalBeast2, moOutlaw, moMutant, moMetalBeast, moMetalBeast2, moOutlaw, moMutant,
moStormTroll, moForestTroll, moStormTroll, moForestTroll,
moRedFox, moWindCrow, moFriendlyGhost, moRatling, moFalsePrincess, moRoseLady, moRedFox, moWindCrow, moFriendlyGhost, moRatling, moFalsePrincess, moRoseLady,
moRoseBeauty, moRatlingAvenger, moRoseBeauty, moRatlingAvenger,
moTortoise, moDragonHead, moDragonTail, moTortoise, moDragonHead, moDragonTail,
moNighthawk, moLemur, moKestrel, moGadfly, moResearcher, moSparrowhawk,
moKrakenH, moKrakenT, moDraugr, moFriendlyIvy,
moVampire, moBat, moReptile,
moHerdBull, moRagingBull, moSleepBull,
moButterfly,
// shmup specials // shmup specials
moPlayer, moBullet, moFlailBullet, moFireball, moTongue, moAirball, moPlayer, moBullet, moFlailBullet, moFireball, moTongue, moAirball,
// temporary // temporary
moDeadBug, moLightningBolt, moDeadBird moDeadBug, moLightningBolt, moDeadBird, moEnergySword, moWarning,
moRogueviz
}; };
struct genderswitch_t { struct genderswitch_t {
@ -667,7 +767,7 @@ genderswitch_t genderswitch[NUM_GS] = {
// --- items --- // --- items ---
const int ittypes = 92; const int ittypes = 110;
struct itemtype { struct itemtype {
char glyph; char glyph;
@ -694,7 +794,7 @@ itemtype iinf[ittypes] = {
}, },
{ '!', 0xFFFF00, "Elixir of Life", { '!', 0xFFFF00, "Elixir of Life",
"A wonderful beverage, apparently obtained by mixing red and blue slime. You definitely feel more " "A wonderful beverage, apparently obtained by mixing red and blue slime. You definitely feel more "
"healthy after drinking it, but you still fell that one hit of a monster is enough to kill you."}, "healthy after drinking it, but you still feel that one hit of a monster is enough to kill you."},
{ '%', 0xFF00FF, "Shard", { '%', 0xFF00FF, "Shard",
"A piece of a magic mirror, or a mirage cloud, that can be used for magical purposes. Only mirrors and clouds " "A piece of a magic mirror, or a mirage cloud, that can be used for magical purposes. Only mirrors and clouds "
"in the Land of Mirrors leave these."}, "in the Land of Mirrors leave these."},
@ -798,7 +898,7 @@ itemtype iinf[ittypes] = {
"Each fire drains 5 charges. You are not allowed to throw fire into adjacent cells." "Each fire drains 5 charges. You are not allowed to throw fire into adjacent cells."
}, },
{ 'o', 0x8B4513, "Orb of Trickery", { 'o', 0x8B4513, "Orb of Trickery",
"This Orb allows you to create illusions of yourself. Illusions are targetted " "This Orb allows you to create illusions of yourself. Illusions are targeted "
"by most monsters, just like yourself, Thumpers, and your friends.\n\n" "by most monsters, just like yourself, Thumpers, and your friends.\n\n"
"Each illusion takes 5 charges to create, and one extra charge " "Each illusion takes 5 charges to create, and one extra charge "
"per turn. You can also click your illusion to take it away, restoring 4 charges.\n\n" "per turn. You can also click your illusion to take it away, restoring 4 charges.\n\n"
@ -991,7 +1091,67 @@ itemtype iinf[ittypes] = {
"you have to dismount this turn -- be very careful to make this possible, " "you have to dismount this turn -- be very careful to make this possible, "
"as your mount could attack you immediately!\n\n" "While riding, " "as your mount could attack you immediately!\n\n" "While riding, "
"click on a location to order your mount to move or attack there.", "click on a location to order your mount to move or attack there.",
} },
{ 'o', 0xFFFF80, "Orb of the Sword",
"This Orb gives you a weapon made of pure magical energy. You do not hold "
"it, it simply floats in the air next to you. When you go, the energy sword moves "
"with you, pointing at the same relative angle it pointed before -- you cannot "
"move or rotate it otherwise. Most monsters can be killed by moving the sword into them, "
"and won't move into the spot with the sword."
},
{ 'x', 0x4040FF, "Sunken Treasure",
"Cargo of a ship which was once destroyed by a Kraken." },
{ 'o', 0xFF8040, "Orb of the Sword II",
"An alternative version of Orb of the Sword. If you have both of them, "
"you have two energy swords, facing in opposite directions."
},
{ '*', 0xFFFF80, "Ancient Jewelry",
"Precious belongings of ancient Viking heroes. Your Orb of the Sword can be "
"used to dig these treasures out of the barrows."
},
{ '!', 0xFFD700, "Golden Egg",
"Trolls of Trollheim are descendants of a bridge Troll, who collected "
"payments from people crossing the bridge. One of them paid with "
"golden eggs. The bridge Troll found the eggs beautiful, but he quickly lost them. "
"Golden eggs are still revered by Trolls, and you can find them in their "
"caves."
},
{ '!', 0xFF0000, "Warning", warningdesc
},
{ 'o', 0x808080, "Orb of the Stone",
"Trolls turn into stone walls when they die. When you have this Orb, "
"this happens to every monster you defeat. Statues created from this Orb "
"have slightly different properties than Trolls who petrify naturally."
},
{ 'o', 0xC08000, "Orb of Nature", naturedesc },
{ '%', 0x800080, "Treat", halloweendesc },
{ '%', 0x30A030, "Slime Mold",
"A very interesting species of slime mold."
},
{ '*', 0xFF00FF, "Amethyst", "A beatiful purple gem from the Lost Mountain." },
{ 'o', 0xC00040, "Orb of Recall",
"When the charges on this Orb expire, "
"you will be automatically returned to the place where you have found it. "
"Extra Orbs of Recall delay this without changing the recall location. "
"Pick up an Orb of Safety causes an immediate recall."},
{ ']', 0x8080FF, "Dodecahedron",
"These dodecahedra made of a mysterious material are the Reptiles' favorite toy."
},
{ 'o', 0x8080FF, "Orb of Vaulting",
"This Orb allows you to jump over an adjacent monster, killing or stunning it. "
"You can only vault in a roughly straight line. "
"Target a cell on the other side to use it."
},
{ '$', 0x80FF80, "Green Grass", prairiedesc },
{ 'o', 0x8080FF, "Orb of Horns",
"After you move while having this Orb, you immediately attack the next cell in the straight line "
"(or two cells, when moving on a heptagon). This attack is slightly stronger than your normal "
"attack: it can stun some of the monsters which cannot be killed or stunned normally."
},
{ 'o', 0x8080FF, "Orb of the Bull",
"You get the powers of Shield, Horns, and Thorns after you move two moves in a straight line "
"with this Orb." },
{ '$', 0xC060C0, "Spinel", bulldashdesc },
}; };
enum eItem { itNone, itDiamond, itGold, itSpice, itRuby, itElixir, itShard, itBone, itHell, itStatue, enum eItem { itNone, itDiamond, itGold, itSpice, itRuby, itElixir, itShard, itBone, itHell, itStatue,
@ -1000,32 +1160,43 @@ enum eItem { itNone, itDiamond, itGold, itSpice, itRuby, itElixir, itShard, itBo
itOrbLightning, itOrbFlash, itOrbWinter, itOrbSpeed, itOrbLife, itOrbShield, itOrbDigging, itOrbLightning, itOrbFlash, itOrbWinter, itOrbSpeed, itOrbLife, itOrbShield, itOrbDigging,
itOrbTeleport, itOrbSafety, itOrbTeleport, itOrbSafety,
itOrbThorns, itFernFlower, itOrbThorns, itFernFlower,
itWine, itOrbGhost, itSilver, itOrbPsi, itWine, itOrbAether, itSilver, itOrbPsi,
itRoyalJelly, itEmerald, itOrbInvis, itPower, itOrbFire, itRoyalJelly, itEmerald, itOrbInvis, itPower, itOrbFire,
itHolyGrail, itGrimoire, itHolyGrail, itGrimoire,
itOrbDragon, itOrbIllusion, itOrbDragon, itOrbIllusion,
itPirate, itCompass, itPirate, itCompass,
itRedGem, itOrbPreserve, itOrbTelekinesis, itRedGem, itOrbTime, itOrbSpace,
itBombEgg, itCoast, itWhirlpool, itBombEgg, itCoast, itWhirlpool,
itOrbFriend, itOrbWater, itOrbAir, itOrbFriend, itOrbWater, itOrbAir,
itPalace, itOrbFrog, itPalace, itOrbFrog,
itFjord, itOrbFish, itFjord, itOrbFish,
itOrbDiscord, itOrbDiscord,
itSavedPrincess, itOrbLove, itSavedPrincess, itOrbLove,
itEdge, itZebra, itIvory, itZebra,
itFireShard, itAirShard, itEarthShard, itWaterShard, itFireShard, itAirShard, itEarthShard, itWaterShard,
itElemental, itOrbSummon, itOrbMatter, itElemental, itOrbSummon, itOrbMatter,
itBounty, itRevolver, itFulgurite, itMutant, itBounty, itRevolver, itFulgurite, itMutant,
itOrbStunning, itOrbLuck, itOrbStunning, itOrbLuck,
itMutant2, itOrbFreedom, itLotus, itOrbUndeath, itMutant2, itOrbFreedom, itLotus, itOrbUndeath,
itWindstone, itOrbEmpathy, itStrongWind, itBuggy, itBuggy2, itWindstone, itOrbEmpathy, itStrongWind, itBuggy, itBuggy2,
itRose, itCoral, itOrbSkunk, itOrb37, itOrbEnergy, itRose, itCoral, itOrbBeauty, itOrb37, itOrbEnergy,
itBabyTortoise, itOrbShell, itApple, itDragon, itOrbDomination itBabyTortoise, itOrbShell, itApple, itDragon, itOrbDomination,
itOrbSword,
itKraken, itOrbSword2, itBarrow,
itTrollEgg, itWarning,
itOrbStone, itOrbNature, itTreat,
itSlime, itAmethyst,
itOrbRecall, itDodeca,
itOrbDash,
itGreenGrass,
itOrbHorns,
itOrbBull,
itBull
}; };
// --- wall types --- // --- wall types ---
const int walltypes = 88; const int walltypes = 96;
struct walltype { struct walltype {
char glyph; char glyph;
@ -1105,7 +1276,7 @@ walltype winf[walltypes] = {
"using an Orb of Aether, your Aether power will be completely drained." "using an Orb of Aether, your Aether power will be completely drained."
}, },
{ '#', 0xC0C0C0, "wall of Camelot", camelothelp }, { '#', 0xC0C0C0, "wall of Camelot", camelothelp },
{ '#', 0xA06000, "Round Table", camelothelp }, { '+', 0xA06000, "Round Table", camelothelp },
{ '=', 0x0000A0, "moat of Camelot", camelothelp}, { '=', 0x0000A0, "moat of Camelot", camelothelp},
{ '+', 0x606060, "big statue of Cthulhu", { '+', 0x606060, "big statue of Cthulhu",
"These statues of Cthulhu are too large to carry, and they don't look too " "These statues of Cthulhu are too large to carry, and they don't look too "
@ -1168,7 +1339,7 @@ walltype winf[walltypes] = {
{ '#', 0x3030FF, "charged wall", elecdesc}, { '#', 0x3030FF, "charged wall", elecdesc},
{ '#', 0xFF3030, "grounded wall", elecdesc}, { '#', 0xFF3030, "grounded wall", elecdesc},
{ '#', 0xA0A060, "sandstone wall", elecdesc}, { '#', 0xA0A060, "sandstone wall", elecdesc},
{ '+', 0x704000, "saloon wall", wildwestdesc}, { '#', 0x704000, "saloon wall", wildwestdesc},
{ '#', 0x90C0C0, "metal wall", elecdesc}, { '#', 0x90C0C0, "metal wall", elecdesc},
{ '#', 0x607030, "dead troll", trollhelpX}, { '#', 0x607030, "dead troll", trollhelpX},
{ '+', 0xC0C0FF, "fan", winddesc}, { '+', 0xC0C0FF, "fan", winddesc},
@ -1182,13 +1353,28 @@ walltype winf[walltypes] = {
{ '#', 0xC0C000, "warp gate", { '#', 0xC0C000, "warp gate",
"This gate separates the warped area from the normal land."}, "This gate separates the warped area from the normal land."},
{ '+', 0x804000, "trunk", "The skeleton of a tree."}, { '+', 0x804000, "trunk", "The skeleton of a tree."},
{ '+', 0x804000, "solid branch", "Branches here could bear your weight easily."}, { '-', 0x402000, "solid branch", "Branches here could bear your weight easily."},
{ '+', 0x804000, "weak branch", { ':', 0x804000, "weak branch",
"Branches here will bear you weight, but if you use them to move (not fall) to an unstable place, they will break."}, "Branches here will bear you weight, but if you use them to move (not fall) to an unstable place, they will break."},
{ '+', 0x60C060, "canopy", { '+', 0x60C060, "canopy",
"Only thin twigs and leaves here. They may bear fruits, but for you, these cells count " "Only thin twigs and leaves here. They may bear fruits, but for you, these cells count "
"as unstable." "as unstable."
} },
{ '#', 0xD0C060, "barrow wall", "This wall is quite strong. You will need another way in."},
{ '#', 0x90A060, "barrow", "Your Orb of the Sword can be used to dig here."},
{ '#', 0xE0E0E0, "stone statue", "A petrified creature."},
{ '.', 0xE8E8E8, "tower of Camelot", camelothelp},
{ '-', 0x402000, "big bush",
"You can hold this bush to climb the Lost Mountain. "
"Bushes block the movement of birds."
},
{ ':', 0x804000, "small bush",
"You can hold this bush to climb the Lost Mountain, "
"but it is not very strong -- it will get destroyed "
"if you climb from it into an unstable location. "
"Bushes block the movement of birds."},
{ '.', 0xFFFF00, "Reptile floor", reptiledesc},
{ '.', 0xFFFF00, "Reptile bridge", reptiledesc},
}; };
enum eWall { waNone, waIcewall, waBarrier, waFloorA, waFloorB, waCavewall, waCavefloor, waDeadTroll, waDune, enum eWall { waNone, waIcewall, waBarrier, waFloorA, waFloorB, waCavewall, waCavefloor, waDeadTroll, waDune,
@ -1212,12 +1398,16 @@ enum eWall { waNone, waIcewall, waBarrier, waFloorA, waFloorB, waCavewall, waCav
waDeadTroll2, waFan, waDeadTroll2, waFan,
waTemporary, waEarthD, waElementalTmp, waElementalD, waTemporary, waEarthD, waElementalTmp, waElementalD,
waFloorC, waFloorD, waRose, waWarpGate, waFloorC, waFloorD, waRose, waWarpGate,
waTrunk, waSolidBranch, waWeakBranch, waCanopy waTrunk, waSolidBranch, waWeakBranch, waCanopy,
waBarrowWall, waBarrowDig,
waPetrified, waTower,
waBigBush, waSmallBush,
waReptile, waReptileBridge
}; };
// --- land types --- // --- land types ---
const int landtypes = 56; const int landtypes = 67;
struct landtype { struct landtype {
int color; int color;
@ -1355,6 +1545,42 @@ landtype linf[landtypes] = {
}, },
{ 0x487830, "Galápagos", tortoisedesc}, { 0x487830, "Galápagos", tortoisedesc},
{ 0xD04000, "Dragon Chasms", dragondesc}, { 0xD04000, "Dragon Chasms", dragondesc},
{ 0xD04000, "Kraken Depths",
"A long time ago, this was a trade route. But then, Krakens have risen out of the "
"depths. Many trading ships sank here. Legend says that you can uncover the secret "
"of a magical weapon spell somewhere in the depths...\n\n"
"You can find Sunken Treasures here, but they won't appear until you have killed "
"a Kraken. You will also need Orb of the Fish to get the treasures, luckily you can "
"steal one from the Viking treasure hunters."
},
{ 0x804020, "Burial Grounds",
"Ancient Viking heroes were buried here. Their graves have barrows raised over "
"them, and are guarded by Draugar, animated corpses who are immune to mundane weapons. "
"You will need to use a magical weapon spell to defeat them, and to rob the "
"ancient jewelry buried in the graves."
},
{ 0x90A548, "Trollheim",
"Many clans of Trolls spend their lives in this kingdom. You can find many "
"statues of Trolls here. You suppose that they are not actually statues, but simply "
"elderly Trolls, who have petrified upon death. Or maybe you have killed "
"these Trolls yourself?"
},
{ 0xFF7518, "Halloween", halloweendesc},
{ 0x605040, "Dungeon",
"The result of a collaboration of the Great Vizier and the Wizard of the Ivory Tower."
},
{ 0x603000, "Lost Mountain",
"Gravitational anomalies in the Jungle create mountains "
"overgrown with ivies and bushes. "
"Will you dare to climb the ivies to get the amethysts hidden above?\n\n"
"Cells adjacent to Ivies count as stable (but Ivies "
"cannot climb themselves or other Ivies)."},
{ 0xFFFF00, "Reptiles", reptiledesc},
{ 0x0000D0, "Prairie", prairiedesc},
{ 0x800080, "Bull Dash", bulldashdesc},
{ 0xC000C0, "Crossroads V", "Extremely narrow Crossroads layout.\n"},
{ 0xC0C0C0, "Cellular Automaton", cadesc}
}; };
enum eLand { laNone, laBarrier, laCrossroads, laDesert, laIce, laCaves, laJungle, laAlchemist, laMirror, laGraveyard, enum eLand { laNone, laBarrier, laCrossroads, laDesert, laIce, laCaves, laJungle, laAlchemist, laMirror, laGraveyard,
@ -1367,8 +1593,11 @@ enum eLand { laNone, laBarrier, laCrossroads, laDesert, laIce, laCaves, laJungle
laCanvas, laPrincessQuest, laCanvas, laPrincessQuest,
laWildWest, laStorms, laOvergrown, laClearing, laWildWest, laStorms, laOvergrown, laClearing,
laHaunted, laHauntedWall, laHauntedBorder, laHaunted, laHauntedWall, laHauntedBorder,
laWhirlwind, laRose, laGridCoast, laGridSea, laCrossroads4, laWhirlwind, laRose, laWarpCoast, laWarpSea, laCrossroads4,
laEndorian, laTortoise, laDragon laEndorian, laTortoise, laDragon,
laKraken, laBurial, laTrollheim,
laHalloween, laDungeon, laMountain, laReptile,
laPrairie, laBull, laCrossroads5, laCA
}; };
// cell information for the game // cell information for the game
@ -1387,69 +1616,104 @@ struct gcell {
unsigned ligon : 1; // is it sparkling with lightning? unsigned ligon : 1; // is it sparkling with lightning?
unsigned unsigned
pathdist : 5, // player distance wrt usual movement pathdist : 7, // player distance wrt usual movement
cpdist : 5, mpdist : 5; // current/minimum player distance cpdist : 5, mpdist : 5; // current/minimum player distance
unsigned mondir : 3, // monster direction, for multi-tile monsters and graphics unsigned mondir : 3, // monster direction, for multi-tile monsters and graphics
bardir : 4, // barrier direction bardir : 4, // barrier direction
stuntime : 4, // stun time left (for Palace Guards and Skeletons) stuntime : 4, // stun time left (for Palace Guards and Skeletons)
hitpoints : 3, // hitpoints left (for Palace Guards) hitpoints : 3; // hitpoints left (for Palace Guards, also reused as cpid for mirrors)
landflags : 2; // extra flags for land
unsigned landflags : 8; // extra flags for land
char wparam; // wall parameter, used for remaining power of Bonfires and Thumpers
// 'tmp' is used for:
// pathfinding algorithm used by monsters with atypical movement (which do not use pathdist)
// bugs' pathfinding algorithm
short aitmp;
// 'landparam' is used for: // 'landparam' is used for:
// heat in Icy/Cocytus; // heat in Icy/Cocytus;
// heat in Dry (0..10); // heat in Dry (0..10);
// CR2 structure; // CR2 structure;
// hive Weird Rock color / pheromones; // hive Weird Rock color / pheromones;
// Ocean/coast depth // Ocean/coast depth;
union { int32_t landpar; float heat; char bytes[4]; } LHU; // Bomberbird Egg hatch time / mine marking;
// number of Ancient Jewelry;
// improved tracking in Trollheim
union {
int32_t landpar;
float heat;
char bytes[4];
struct fieldinfo {
uint16_t fieldval;
unsigned rval : 4;
unsigned flowerdist : 4;
unsigned walldist : 4;
unsigned walldist2 : 4;
} fi;
} LHU;
}; };
#define landparam LHU.landpar #define landparam LHU.landpar
#define fval LHU.fi.fieldval
#define NODIR 7 #define NODIR 7
#define NOBARRIERS 8 #define NOBARRIERS 8
#define LAND_OVER 44 #define LAND_OVER 53
eLand land_over[LAND_OVER] = { #define LAND_OVERX 55
eLand land_over[LAND_OVERX] = {
laIce, laCaves, laDesert, laMotion, laJungle, laAlchemist, laIce, laCaves, laDesert, laMotion, laJungle, laAlchemist,
laCrossroads, laCrossroads,
laMirror, laMinefield, laZebra, laPalace, laPrincessQuest, laMirror, laMinefield, laPalace, laPrincessQuest, laZebra, laReptile,
laOcean, laLivefjord, laGridCoast, laCaribbean, laWhirlpool, laRlyeh, laTemple, laOcean, laWarpCoast, laLivefjord, laKraken, laCaribbean, laWhirlpool, laRlyeh, laTemple,
laIvoryTower, laEndorian, laDungeon, laMountain,
laCrossroads2, laCrossroads2,
laDryForest, laWineyard, laDeadCaves, laGraveyard, laHaunted, laHive, laDryForest, laWineyard, laDeadCaves, laGraveyard, laHaunted, laHive,
laRedRock, laRedRock,
laIvoryTower, laEndorian,
laDragon, laTortoise, laDragon, laTortoise,
laOvergrown, laClearing, laStorms, laWhirlwind, laRose, laOvergrown, laClearing, laStorms, laWhirlwind, laRose, laBurial,
laEmerald, laCamelot, laElementalWall, laEmerald, laCamelot,
laHell, laCrossroads3, laCocytus, laPower, laCrossroads4 laPrairie, laBull,
laElementalWall, laTrollheim,
laHell, laCrossroads3, laCocytus, laPower, laCrossroads4,
laCrossroads5,
// EXTRA
laWildWest, laHalloween
}; };
#define LAND_EUC 42 #define LAND_EUC 49
eLand land_euc[LAND_EUC] = { eLand land_euc[LAND_EUC] = {
laIce, laCaves, laDesert, laMotion, laJungle, laIce, laCaves, laDesert, laMotion, laJungle,
laCrossroads, laCrossroads,
laMirror, laMinefield, laAlchemist, laZebra, laPalace, laPrincessQuest, laMirror, laMinefield, laAlchemist, laZebra, laPalace, laPrincessQuest,
laOcean, laLivefjord, laGridCoast, laCaribbean, laWhirlpool, laRlyeh, laTemple, laOcean, laLivefjord, laWarpCoast, laCaribbean, laKraken, laWhirlpool, laRlyeh, laTemple,
laElementalWall, laElementalWall, laTrollheim,
laDryForest, laWineyard, laDeadCaves, laGraveyard, laHive, laRedRock, laIvoryTower, laDryForest, laWineyard, laDeadCaves, laGraveyard, laHive, laRedRock, laIvoryTower,
laOvergrown, laClearing, laStorms, laWhirlwind, laRose, laOvergrown, laClearing, laStorms, laWhirlwind, laRose, laBurial,
laEmerald, laCamelot, laDragon, laTortoise, laEmerald, laCamelot, laDragon, laTortoise,
laHell, laCrossroads3, laCocytus, laPower, laHell, laCrossroads3, laCocytus, laPower,
laCrossroads4, laCrossroads4,
laWildWest laWildWest,
laReptile, laMountain, laBull, laPrairie
}; };
// MISSING: laCrossroads2 // MISSING: laCrossroads2
#define LAND_HYP 39 #define LAND_SPH 39
eLand land_sph[LAND_SPH] = {
laHalloween,
laIce, laCaves, laDesert, laMotion, laJungle,
laCrossroads,
laMirror, laMinefield, laAlchemist,
laLivefjord, laWarpCoast, laKraken, laRlyeh,
laTrollheim,
laDryForest, laDeadCaves, laGraveyard, laHive, laRedRock,
laOvergrown, laStorms, laWhirlwind, laRose, laBurial,
laEmerald, laDragon, laTortoise,
laHell, laCrossroads3, laCocytus, laPower, laElementalWall,
laCrossroads4,
laWildWest, laPalace, laBull, laPrairie, laCA
};
#define LAND_HYP 47
eLand land_hyp[LAND_HYP] = { eLand land_hyp[LAND_HYP] = {
laHell, laCocytus, laGraveyard, laHell, laCocytus, laGraveyard,
laWineyard, laDryForest, laCaves, laWineyard, laDryForest, laCaves,
@ -1458,8 +1722,14 @@ eLand land_hyp[LAND_HYP] = {
laDesert, laRedRock, laDesert, laRedRock,
laWhirlpool, laOvergrown, laClearing, laStorms, laWhirlpool, laOvergrown, laClearing, laStorms,
laCaribbean, laJungle, laAlchemist, laMotion, laMirror, laMinefield, laCaribbean, laJungle, laAlchemist, laMotion, laMirror, laMinefield,
laZebra, laElementalWall, laIvoryTower, laHaunted, laWhirlwind, laCrossroads, laZebra, laElementalWall, laIvoryTower, laHaunted, laWhirlwind,
laGridCoast, laRose, laDragon, laEndorian, laTortoise laWarpCoast, laRose, laDragon, laEndorian,
laReptile, laDungeon, laMountain,
laTortoise,
laKraken, laBurial, laTrollheim,
laPrairie, laBull,
// always must be last
laCrossroads
}; };
#define LAND_SCAPE 32 #define LAND_SCAPE 32
@ -1472,29 +1742,32 @@ eLand land_scape[LAND_SCAPE] = {
laOvergrown, laStorms, laOvergrown, laStorms,
laJungle, laAlchemist, laMotion, laMirror, laMinefield, laJungle, laAlchemist, laMotion, laMirror, laMinefield,
laZebra, laWhirlwind, laCrossroads, laZebra, laWhirlwind, laCrossroads,
laGridCoast, laRose, laWarpCoast, laRose,
laCrossroads, laCrossroads2, laCrossroads3 laCrossroads, laCrossroads2, laCrossroads3
}; };
#define LAND_TAC 44 #define LAND_TAC 50
struct landtacinfo { eLand l; int tries, multiplier; }; struct landtacinfo { eLand l; int tries, multiplier; };
landtacinfo land_tac[LAND_TAC] = { landtacinfo land_tac[LAND_TAC] = {
{laIce, 10, 1}, {laDesert, 10, 1}, {laMotion, 10, 1}, {laCaves, 10, 1}, {laAlchemist, 10, 1}, {laIce, 10, 1}, {laDesert, 10, 1}, {laMotion, 10, 1}, {laCaves, 10, 1}, {laAlchemist, 10, 1},
{laJungle, 10, 1}, {laMirror, 10, 1}, {laZebra, 10, 1}, {laPalace, 10, 1}, {laJungle, 10, 1}, {laMirror, 10, 1}, {laZebra, 10, 1}, {laPalace, 10, 1},
{laOcean, 10, 1}, {laLivefjord, 10, 1}, {laGridCoast, 10, 1}, {laRlyeh, 10, 1}, {laHell, 10, 1}, {laOcean, 10, 1}, {laLivefjord, 10, 1}, {laWarpCoast, 10, 1}, {laRlyeh, 10, 1}, {laHell, 10, 1},
{laElementalWall, 10, 1}, {laDryForest, 10, 1}, {laWineyard, 10, 1}, {laDryForest, 10, 1}, {laWineyard, 10, 1}, {laReptile, 10, 1},
{laDeadCaves, 10, 1}, {laGraveyard, 10, 1}, {laDeadCaves, 10, 1}, {laGraveyard, 10, 1},
{laHaunted, 10, 1}, {laHaunted, 10, 1},
{laIvoryTower, 10, 1}, {laEndorian, 10, 1}, {laIvoryTower, 10, 1}, {laEndorian, 10, 1}, {laMountain, 5, 2}, {laDungeon, 5, 2},
{laEmerald, 10, 1}, {laEmerald, 10, 1},
{laCocytus, 10, 1}, {laCocytus, 10, 1},
{laCaribbean, 5, 2}, {laWhirlpool, 5, 2}, {laTemple, 5, 2}, {laMinefield, 5, 2}, {laCaribbean, 5, 2}, {laWhirlpool, 5, 2}, {laKraken, 5, 2},
{laTemple, 5, 2}, {laMinefield, 5, 2},
{laPower, 5, 2}, {laHive, 5, 2}, {laRedRock, 5, 2}, {laStorms, 5, 2}, {laOvergrown, 5, 2}, {laPower, 5, 2}, {laHive, 5, 2}, {laRedRock, 5, 2}, {laStorms, 5, 2}, {laOvergrown, 5, 2},
{laClearing, 5, 2}, {laClearing, 5, 2},
{laWhirlwind, 5, 2}, {laRose, 5, 2}, {laDragon, 2, 5}, {laTortoise, 1, 10}, {laWhirlwind, 5, 2}, {laRose, 5, 2}, {laDragon, 2, 5}, {laTortoise, 1, 10},
{laBurial, 5, 2},
{laElementalWall, 10, 1}, {laTrollheim, 5, 2},
{laCrossroads, 10, 1}, {laCrossroads2, 10, 1}, {laCrossroads3, 10, 1}, {laCrossroads4, 10, 1}, {laCrossroads, 10, 1}, {laCrossroads2, 10, 1}, {laCrossroads3, 10, 1}, {laCrossroads4, 10, 1},
@ -1506,6 +1779,6 @@ landtacinfo land_tac[LAND_TAC] = {
eLand randlands[RANDLANDS] = { eLand randlands[RANDLANDS] = {
laIce, laDesert, laCaves, laAlchemist, laGraveyard, laPower, laLivefjord, laZebra, laIce, laDesert, laCaves, laAlchemist, laGraveyard, laPower, laLivefjord, laZebra,
laRlyeh, laDryForest, laEmerald, laWineyard, laDeadCaves, laRedRock, laRlyeh, laDryForest, laEmerald, laWineyard, laDeadCaves, laRedRock,
laOvergrown, laWildWest, laGridCoast laOvergrown, laWildWest, laWarpCoast
}; };

File diff suppressed because it is too large Load Diff

View File

@ -4,11 +4,10 @@
namespace polygonal { namespace polygonal {
typedef long double ld; typedef complex<ld> cld;
typedef complex<long double> cld;
int SI = 4; int SI = 4;
double STAR = 0; ld STAR = 0;
int deg = 20; int deg = 20;
@ -55,7 +54,7 @@ namespace polygonal {
} }
pair<ld, ld> compute(ld x, ld y, int prec) { pair<ld, ld> compute(ld x, ld y, int prec) {
if(pmodel == 4) { if(pmodel == mdPolynomial) {
cld z(x,y); cld z(x,y);
cld res (0,0); cld res (0,0);
for(int i=maxcoef; i>=0; i--) { res += coef[i]; if(i) res *= z; } for(int i=maxcoef; i>=0; i--) { res += coef[i]; if(i) res *= z; }
@ -77,28 +76,21 @@ namespace polygonal {
pair<ld, ld> compute(ld x, ld y) { return compute(x,y,deg); } pair<ld, ld> compute(ld x, ld y) { return compute(x,y,deg); }
void drawBoundary(int color) { void drawBoundary(int color) {
#ifdef GL queuereset(mdDisk, PPR_CIRCLE);
if(vid.usingGL) {
qglcoords = 0; for(int r=0; r<=2000; r++) {
glcolor(color); cld z = exp(cld(0, 2*M_PI * r / 2000.0));
int pts = 0; pair<ld,ld> z2 = compute(real(z), imag(z), deg);
for(int r=0; r<2000; r++) { hyperpoint h;
cld z = exp(cld(0, 2*M_PI * r / 2000.0)); h[0] = z2.first * vid.radius;
pair<ld,ld> z2 = compute(real(z), imag(z), deg); h[1] = z2.second * vid.radius;
glcoords[pts][0] = vid.radius * z2.first; h[2] = vid.scrdist;
glcoords[pts][1] = vid.radius * z2.second; curvepoint(h);
glcoords[pts][2] = vid.scrdist;
pts++;
}
glVertexPointer(3, GL_FLOAT, 0, glcoords);
glEnableClientState(GL_VERTEX_ARRAY);
glDrawArrays(GL_LINE_LOOP, 0, pts);
return;
} }
#endif
queuecurve(color, 0, PPR_CIRCLE);
queuereset(pmodel, PPR_CIRCLE);
} }
} }
@ -247,7 +239,7 @@ namespace conformal {
vector<cell*> movehistory; vector<cell*> movehistory;
bool includeHistory; bool includeHistory;
double lvspeed = 1; ld lvspeed = 1;
int bandhalf = 200; int bandhalf = 200;
int bandsegment = 16000; int bandsegment = 16000;
int rotation = 0; int rotation = 0;
@ -368,10 +360,9 @@ namespace conformal {
shmup::calc_relative_matrix(v[j+1]->base, v[j]->base->master) * shmup::calc_relative_matrix(v[j+1]->base, v[j]->base->master) *
v[j+1]->at * C0; v[j+1]->at * C0;
int x, y, shift; hyperpoint nextscr;
getcoord(next, x, y, shift); applymodel(next, nextscr);
tpixels += nextscr[0] * vid.radius;
tpixels += x-vid.xcenter;
} }
vid.radius = rad; vid.radius = rad;
@ -447,7 +438,7 @@ namespace conformal {
v[j+1]->at * C0; v[j+1]->at * C0;
int x, y, shift; int x, y, shift;
getcoord(next, x, y, shift); getcoord0(next, x, y, shift);
int bwidth = x-bandhalf; int bwidth = x-bandhalf;
@ -489,62 +480,83 @@ namespace conformal {
} }
#endif #endif
const char* directions[5][4] = { const char* directions[MODELCOUNT][4] = {
{ "right", "up", "left", "down" }, { "right", "up", "left", "down" },
{ "counterclockwise", "zoom out", "clockwise", "zoom in" }, { "counterclockwise", "zoom out", "clockwise", "zoom in" },
{ "left to right", "spin down", "right to left", "spin up" }, { "left to right", "spin down", "right to left", "spin up" },
{ "right", "up", "left", "down" }, { "right", "up", "left", "down" },
{ "right", "up", "left", "down" },
{ "right", "up", "left", "down" },
{ "right", "up", "left", "down" },
{ "right", "up", "left", "down" },
{ "right", "up", "left", "down" } { "right", "up", "left", "down" }
}; };
const char *modelnames[5] = { const char *modelnames[MODELCOUNT] = {
"disk", "half-plane", "band", "polygonal", "polynomial" "disk", "half-plane", "band", "polygonal", "polynomial",
"azimuthal equidistant", "azimuthal equi-area",
"ball model", "hyperboloid"
}; };
void show() { void show() {
displayStat( 0, XLAT("conformal/history mode"), "", ' '); dialog::init(XLAT("conformal/history mode"));
displayStat( 2, XLAT("include history"), ONOFF(includeHistory), 'i'); dialog::addBoolItem(XLAT("include history"), (includeHistory), 'i');
bool notconformal = (pmodel >= 5 && pmodel <= 6) || abs(vid.alpha-1) > 1e-3;
displayStat( 4, XLAT("model used"), modelnames[pmodel], 'm'); dialog::addSelItem(notconformal ? XLAT("model used (not conformal!)") : XLAT("model used"), XLAT(modelnames[pmodel]), 'm');
displayStat( 5, XLAT("rotation"), directions[pmodel][rotation&3], 'r'); dialog::addSelItem(XLAT("rotation"), directions[pmodel][rotation&3], 'r');
if(pmodel == 4) { if(pmodel == 4) {
displayStat( 6, XLAT("coefficient"), dialog::addSelItem(XLAT("coefficient"),
fts4(real(polygonal::coef[polygonal::coefid]))+"+"+ fts4(real(polygonal::coef[polygonal::coefid])), 'x');
fts4(imag(polygonal::coef[polygonal::coefid]))+"i", 'x'); dialog::addSelItem(XLAT("coefficient (imaginary)"),
displayStat( 7, XLAT("which coefficient"), its(polygonal::coefid), 'n'); fts4(imag(polygonal::coef[polygonal::coefid])), 'y');
dialog::addSelItem(XLAT("which coefficient"), its(polygonal::coefid), 'n');
} }
if(pmodel == 3) { if(pmodel == 3) {
displayStat( 6, XLAT("polygon sides"), its(polygonal::SI), 'x'); dialog::addSelItem(XLAT("polygon sides"), its(polygonal::SI), 'x');
displayStat( 7, XLAT("star factor"), fts(polygonal::STAR), 'y'); dialog::addSelItem(XLAT("star factor"), fts(polygonal::STAR), 'y');
displayStat( 8, XLAT("degree of the approximation"), its(polygonal::deg), 'n'); dialog::addSelItem(XLAT("degree of the approximation"), its(polygonal::deg), 'n');
} }
displayStat(10, XLAT("prepare the line animation"), ONOFF(on), 'e'); dialog::addBoolItem(XLAT("prepare the line animation"), (on), 'e');
if(on) displayStat(11, XLAT("animation speed"), fts(lvspeed), 'a'); if(on) dialog::addSelItem(XLAT("animation speed"), fts(lvspeed), 'a');
#ifndef MOBILE #ifndef MOBILE
displayStat(13, XLAT("render bands automatically"), ONOFF(autoband), 'o'); dialog::addBoolItem(XLAT("render bands automatically"), (autoband), 'o');
if(autoband) if(autoband)
displayStat(14, XLAT("include history when auto-rendering"), ONOFF(autobandhistory), 'j'); dialog::addBoolItem(XLAT("include history when auto-rendering"), (autobandhistory), 'j');
bool renderable = on && pmodel == 2; bool renderable = on && pmodel == 2;
if(renderable || autoband) { if(renderable || autoband) {
displayStat(15, XLAT("band width"), its(bandhalf*2), 'd'); dialog::addSelItem(XLAT("band width"), "2*"+its(bandhalf), 'd');
displayStat(16, XLAT("length of a segment"), its(bandsegment), 's'); dialog::addSelItem(XLAT("length of a segment"), its(bandsegment), 's');
displayStat(17, XLAT("spiral on rendering"), ONOFF(dospiral), 'g'); dialog::addBoolItem(XLAT("spiral on rendering"), (dospiral), 'g');
if(renderable) if(renderable)
displayStat(18, XLAT("render now (length: %1)", its(measureLength())), "", 'f'); dialog::addItem(XLAT("render now (length: %1)", its(measureLength())), 'f');
} }
#endif #endif
displayStat(20, XLAT("exit this menu"), "", 'q'); dialog::addItem(XLAT("exit this menu"), 'q');
dialog::display();
mouseovers = XLAT("see http://www.roguetemple.com/z/hyper/conformal.php"); mouseovers = XLAT("see http://www.roguetemple.com/z/hyper/conformal.php");
} }
void handleKey(int uni, int sym) { int ib = 0;
ld compbuf;
void applyIB() {
using namespace polygonal;
cld& tgt = coef[coefid];
if(ib == 1) tgt = cld(compbuf, imag(tgt));
if(ib == 2) tgt = cld(real(tgt), compbuf);
}
void handleKey(int sym, int uni) {
dialog::handleNavigation(sym, uni);
ib = 0;
if(uni == 'e') { if(uni == 'e') {
if(on) clear(); if(on) clear();
@ -559,38 +571,53 @@ namespace conformal {
} }
else if(uni == 'o') else if(uni == 'o')
autoband = !autoband; autoband = !autoband;
else if(uni == 'm') { else if(uni == 'm' || uni == 'M') {
pmodel++;
pmodel %= 5; switchagain: {
if(pmodel == 3) polygonal::solve(); pmodel = eModel((pmodel + (shiftmul > 0 ? 1 : -1) + MODELCOUNT) % MODELCOUNT);
if(sphere)
if(pmodel == mdHalfplane || pmodel == mdBand || pmodel == mdEquidistant || pmodel == mdEquiarea)
goto switchagain;
}
if(pmodel == mdPolygonal) polygonal::solve();
/* if(pmodel && vid.usingGL) { /* if(pmodel && vid.usingGL) {
addMessage(XLAT("openGL mode disabled")); addMessage(XLAT("openGL mode disabled"));
vid.usingGL = false; vid.usingGL = false;
setvideomode(); setvideomode();
} */ } */
} }
else if(sym == 'x' && pmodel == 3) { polygonal::SI += (shiftmul > 0 ? 1:-1); polygonal::solve(); } else if(sym == 'x' && pmodel == mdPolygonal)
else if(sym == 'y' && pmodel == 3) { polygonal::STAR += shiftmul/10; polygonal::solve(); } dialog::editNumber(polygonal::SI, 3, 10, 1, 4, XLAT("polygon sides"), "");
else if(sym == 'n' && pmodel == 3) { polygonal::deg += (shiftmul>0?1:-1); else if(sym == 'y' && pmodel == mdPolygonal)
if(polygonal::deg < 2) polygonal::deg = 2; dialog::editNumber(polygonal::STAR, -1, 1, .1, 0, XLAT("star factor"), "");
if(polygonal::deg > MSI-1) polygonal::deg = MSI-1; else if(sym == 'n' && pmodel == mdPolygonal)
dialog::editNumber(polygonal::deg, 2, MSI-1, 1, 2, XLAT("degree of the approximation"), "");
else if(sym == 'x' && pmodel == mdPolynomial) {
polygonal::maxcoef = max(polygonal::maxcoef, polygonal::coefid);
int ci = polygonal::coefid + 1;
compbuf = real(polygonal::coef[polygonal::coefid]);
dialog::editNumber(compbuf, -10, 10, .01/ci/ci, 0, XLAT("coefficient"), "");
ib = 1;
} }
else if(sym == 'x' && pmodel == 4) { else if(sym == 'y' && pmodel == mdPolynomial) {
int ci = polygonal::coefid; polygonal::maxcoef = max(polygonal::maxcoef, polygonal::coefid);
polygonal::coef[polygonal::coefid] += polygonal::cld(shiftmul/100/ci/ci, 0); int ci = polygonal::coefid + 1;
compbuf = imag(polygonal::coef[polygonal::coefid]);
dialog::editNumber(compbuf, -10, 10, .01/ci/ci, 0, XLAT("coefficient (imaginary)"), "");
ib = 2;
} }
else if(sym == 'y' && pmodel == 4) { else if(sym == 'n' && pmodel == mdPolynomial)
int ci = polygonal::coefid; dialog::editNumber(polygonal::coefid, 0, MSI-1, 1, 0, XLAT("which coefficient"), "");
polygonal::coef[polygonal::coefid] += polygonal::cld(0, shiftmul/100/ci/ci);
}
else if(sym == 'n' && pmodel == 4) { polygonal::coefid += (shiftmul>0?1:-1); polygonal::maxcoef = max(polygonal::maxcoef, polygonal::coefid); }
else if(sym == 'r') rotation += (shiftmul > 0 ? 1:3); else if(sym == 'r') rotation += (shiftmul > 0 ? 1:3);
else if(sym == 'a') { lvspeed += shiftmul/10; } else if(sym == 'a')
else if(sym == 'd') { bandhalf += int(5 * shiftmul); if(bandhalf < 5) bandhalf = 5; } dialog::editNumber(lvspeed, -5, 5, .1, 1, XLAT("animation speed"), "");
else if(sym == 's') { bandsegment += int(500 * shiftmul); if(bandsegment < 500) bandsegment = 500; } else if(sym == 'd')
dialog::editNumber(bandhalf, 5, 1000, 5, 200, XLAT("band width"), "");
else if(sym == 's')
dialog::editNumber(bandsegment, 500, 32000, 500, 16000, XLAT("band segment"), "");
else if(sym == 'g') { dospiral = !dospiral; } else if(sym == 'g') { dospiral = !dospiral; }
#ifndef MOBILE #ifndef MOBILE
else if(uni == 'f' && pmodel == 2 && on) createImage(dospiral); else if(uni == 'f' && pmodel == mdBand && on) createImage(dospiral);
#endif #endif
else if(sym == 'q' || sym == SDLK_ESCAPE || sym == '0') { cmode = emNormal; } else if(sym == 'q' || sym == SDLK_ESCAPE || sym == '0') { cmode = emNormal; }
else if(sym == 'i') { else if(sym == 'i') {
@ -646,10 +673,10 @@ namespace conformal {
#ifndef MOBILE #ifndef MOBILE
if(celldist(cwt.c) <= 7) return; if(celldist(cwt.c) <= 7) return;
if(!autoband) return; if(!autoband) return;
int spm = pmodel; eModel spm = pmodel;
bool ih = includeHistory; bool ih = includeHistory;
includeHistory = autobandhistory; includeHistory = autobandhistory;
pmodel = 2; pmodel = mdBand;
create(); create();
createImage(dospiral); createImage(dospiral);
clear(); clear();

727
dialogs.cpp Normal file
View File

@ -0,0 +1,727 @@
/* Missing.
#ifndef MOBILE
dialog::addItemHelp(16, XLAT("use Shift to decrease and Ctrl to fine tune "));
dialog::addItemHelp(17, XLAT("(e.g. Shift+Ctrl+Z)"));
#endif
if(xuni == 'i') {
}
*/
namespace dialog {
namespace zoom {
int zoomf = 1, shiftx, shifty;
bool zoomoff = false;
};
#ifdef MENU_SCALING
#ifndef MOBILE
void handleZooming(SDL_Event &ev) {
using namespace zoom;
if(zoomoff || (cmode != emOverview && cmode != emTactic)) {
zoomf = 1; shiftx = shifty = 0; zoomoff = false; return;
}
if(ev.type == SDL_MOUSEBUTTONDOWN) {
zoomf = 3;
}
if(zoomf == 3) {
shiftx = -2*mousex;
shifty = -2*mousey;
}
if(ev.type == SDL_MOUSEBUTTONUP && zoomf > 1) {
zoomoff = true;
}
}
#endif
#else
inline void handleZooming(SDL_Event &ev) {}
#endif
bool displayzoom(int x, int y, int b, int size, const string &s, int color, int align) {
using namespace zoom;
return displayfr(x * zoomf + shiftx, y * zoomf + shifty, b, size * zoomf, s, color, align);
}
vector<item> items;
item& lastItem() { return items[items.size() - 1]; }
void init() { items.clear(); }
string keyname(int k) {
if(k == 0) return "";
if(k == SDLK_ESCAPE) return "Esc";
if(k == SDLK_F5) return "F5";
if(k == SDLK_F10) return "F10";
if(k == SDLK_HOME) return "Home";
if(k == 32) return "space";
if(k >= 1 && k <= 26) { string s = "Ctrl+"; s += (k+64); return s; }
if(k < 128) { string s; s += k; return s; }
return "?";
}
void addSlider(double d1, double d2, double d3, int key) {
item it;
it.type = diSlider;
it.color = 0xC0C0C0;
it.scale = 100;
it.key = key;
it.param = (d2-d1) / (d3-d1);
items.push_back(it);
}
void addSelItem(string body, string value, int key) {
item it;
it.type = diItem;
it.body = body;
it.value = value;
it.keycaption = keyname(key);
it.key = key;
it.color = 0xC0C0C0;
it.colork = 0x808080;
it.colorv = 0x80A040;
it.colors = 0xFFD500;
it.colorc = 0xFFD500;
it.colors = 0xFF8000;
if(value == ONOFF(true)) it.colorv = 0x40FF40;
if(value == ONOFF(false)) it.colorv = 0xC04040;
it.scale = 100;
items.push_back(it);
}
void addBoolItem(string body, bool value, int key) {
addSelItem(body, ONOFF(value), key);
}
void addColorItem(string body, int value, int key) {
item it;
it.type = diItem;
it.body = body;
it.value = COLORBAR;
it.keycaption = keyname(key);
it.key = key;
it.color = it.colorv = value >> 8;
it.colors = it.color ^ 0x404040;
it.colorc = it.color ^ 0x808080;
it.scale = 100;
items.push_back(it);
}
void addHelp(string body) {
item it;
it.type = diHelp;
it.body = body;
it.scale = 100;
if(size(body) >= 500) it.scale = 70;
items.push_back(it);
}
void addInfo(string body, int color) {
item it;
it.type = diInfo;
it.body = body;
it.color = color;
it.scale = 100;
items.push_back(it);
}
void addItem(string body, int key) {
item it;
it.type = diItem;
it.body = body;
it.keycaption = keyname(key);
it.key = key;
it.color = 0xC0C0C0;
it.colork = 0x808080;
it.colors = 0xFFD500;
it.colorc = 0xFF8000;
it.scale = 100;
items.push_back(it);
}
void addBreak(int val) {
item it;
it.type = diBreak;
it.scale = val;
items.push_back(it);
}
void addTitle(string body, int color, int scale) {
item it;
it.type = diTitle;
it.body = body;
it.color = color;
it.scale = scale;
items.push_back(it);
}
void init(string title, int color, int scale, int brk) {
init();
addTitle(title, color, scale);
addBreak(brk);
}
int displayLong(string str, int siz, int y, bool measure) {
int last = 0;
int lastspace = 0;
int xs = vid.xres * 618/1000;
int xo = vid.xres * 186/1000;
for(int i=0; i<=size(str); i++) {
int ls = 0;
int prev = last;
if(str[i] == ' ') lastspace = i;
if(textwidth(siz, str.substr(last, i-last)) > xs) {
if(lastspace == last) ls = i-1, last = i-1;
else ls = lastspace, last = ls+1;
}
if(str[i] == 10 || i == size(str)) ls = i, last = i+1;
if(ls) {
if(!measure) displayfr(xo, y, 2, siz, str.substr(prev, ls-prev), 0xC0C0C0, 0);
if(ls == prev) y += siz/2;
else y += siz;
lastspace = last;
}
}
y += siz/2;
return y;
}
int tothei, dialogwidth, dfsize, dfspace, leftwidth, rightwidth, innerwidth, itemx, keyx, valuex;
string highlight_text;
void measure() {
tothei = 0;
dialogwidth = 0;
innerwidth = 0;
int N = items.size();
for(int i=0; i<N; i++) {
if(items[i].type == diHelp)
tothei += displayLong(items[i].body, dfsize * items[i].scale / 100, 0, true);
else {
tothei += dfspace * items[i].scale / 100;
if(items[i].type == diItem)
innerwidth = max(innerwidth, textwidth(dfsize * items[i].scale / 100, items[i].body));
if(items[i].type == diTitle || items[i].type == diInfo)
dialogwidth = max(dialogwidth, textwidth(dfsize * items[i].scale / 100, items[i].body) * 10/9);
}
}
leftwidth = ISMOBILE ? 0 : textwidth(dfsize, "MMMMM") + dfsize/2;
rightwidth = textwidth(dfsize, "MMMMMMMM") + dfsize/2;
int fwidth = innerwidth + leftwidth + rightwidth;
dialogwidth = max(dialogwidth, fwidth);
itemx = (vid.xres - fwidth) / 2 + leftwidth;
keyx = (vid.xres - fwidth) / 2 + leftwidth - dfsize/2;
valuex = (vid.xres - fwidth) / 2 + leftwidth + innerwidth + dfsize/2;
}
void display() {
int N = items.size();
dfsize = vid.fsize;
#ifdef MOBILE
dfsize *= 3;
#endif
#ifdef PANDORA
dfsize *= 3;
#endif
dfspace = dfsize * 5/4;
measure();
while(tothei > vid.yres - 5 * vid.fsize) {
int adfsize = int(dfsize * sqrt((vid.yres - 5. * vid.fsize) / tothei));
if(adfsize < dfsize-1) dfsize = adfsize + 1;
else dfsize--;
dfspace = dfsize * 5/4;
measure();
}
while(dialogwidth > vid.xres) {
int adfsize = int(dfsize * sqrt(vid.xres * 1. / dialogwidth));
if(adfsize < dfsize-1) dfsize = adfsize + 1;
else dfsize--; // keep dfspace
measure();
}
tothei = (vid.yres - tothei) / 2;
for(int i=0; i<N; i++) {
item& I = items[i];
if(I.type == diHelp) {
tothei = displayLong(items[i].body, dfsize * items[i].scale / 100, tothei, false);
continue;
}
int top = tothei;
tothei += dfspace * I.scale / 100;
int mid = (top + tothei) / 2;
if(I.type == diTitle || I.type == diInfo) {
displayfr(vid.xres/2, mid, 2, dfsize * I.scale/100, I.body, I.color, 8);
}
else if(I.type == diItem) {
bool xthis = (mousey >= top && mousey < tothei);
#ifdef MOBILE
if(xthis && mousepressed)
I.color = I.colorc;
#else
if(xthis && mousemoved) {
highlight_text = I.body;
mousemoved = false;
}
if(highlight_text == I.body) {
I.color = (xthis&&mousepressed&&actonrelease) ? I.colorc : I.colors;
}
#endif
if(!mousing)
displayfr(keyx, mid, 2, dfsize * I.scale/100, I.keycaption, I.colork, 16);
displayfr(itemx, mid, 2, dfsize * I.scale/100, I.body, I.color, 0);
displayfr(valuex, mid, 2, dfsize * I.scale/100, I.value, I.colorv, 0);
if(xthis) getcstat = I.key;
}
else if(I.type == diSlider) {
bool xthis = (mousey >= top && mousey < tothei);
displayfr(vid.xres*1/4, mid, 2, dfsize * I.scale/100, "(", I.color, 16);
displayfr(vid.xres*1/4 + double(vid.xres/2 * I.param), mid, 2, dfsize * I.scale/100, "#", I.color, 8);
displayfr(vid.xres*3/4, mid, 2, dfsize * I.scale/100, ")", I.color, 0);
if(xthis) getcstat = I.key, inslider = true;
}
}
}
void handleNavigation(int &sym, int &uni) {
#ifndef MOBILE
if(uni == '\n' || uni == '\r' || sym == SDLK_KP5)
for(int i=0; i<size(items); i++)
if(items[i].type == diItem)
if(items[i].body == highlight_text) {
uni = sym = items[i].key;
return;
}
if(sym == SDLK_PAGEDOWN || sym == SDLK_KP3) {
for(int i=0; i<size(items); i++)
if(items[i].type == diItem)
highlight_text = items[i].body;
}
if(sym == SDLK_PAGEUP || sym == SDLK_KP9) {
for(int i=0; i<size(items); i++)
if(items[i].type == diItem) {
highlight_text = items[i].body;
break;
}
}
if(sym == SDLK_UP || sym == SDLK_KP8) {
string last = "";
for(int i=0; i<size(items); i++)
if(items[i].type == diItem)
last = items[i].body;
uni = sym = 0;
for(int i=0; i<size(items); i++)
if(items[i].type == diItem) {
if(items[i].body == highlight_text) {
highlight_text = last; return;
}
else last = items[i].body;
}
highlight_text = last;
}
if(sym == SDLK_DOWN || sym == SDLK_KP2) {
int state = 0;
for(int i=0; i<size(items); i++)
if(items[i].type == diItem) {
if(state) { highlight_text = items[i].body; return; }
else if(items[i].body == highlight_text) state = 1;
}
for(int i=0; i<size(items); i++)
if(items[i].type == diItem)
highlight_text = items[i].body;
uni = sym = 0;
}
#endif
}
unsigned int colorhistory[10] = {
0x202020FF, 0x800000FF, 0x008000FF, 0x000080FF,
0x404040FF, 0xC0C0C0FF, 0x804000FF, 0xC0C000FF,
0x408040FF, 0xFFD500FF
}, lch;
unsigned int *palette;
void drawColorDialog(int color) {
int ash = 8;
for(int j=0; j<10; j++) {
int x = vid.xres / 2 + vid.fsize * 2 * (j-5);
int y = vid.yres / 2- 5 * vid.fsize;
string s0 = ""; s0 += ('0'+j);
vid.fsize *= 2;
displayColorButton(x, y, s0, '0'+j, 0, 0, colorhistory[j] >> ash);
vid.fsize /= 2;
}
if(palette) {
int q = palette[0];
for(int i=0; i<q; i++) {
int x = vid.xres / 2 + vid.fsize * (2 * i-q);
int y = vid.yres / 2- 7 * vid.fsize;
string s0 = ""; s0 += ('a'+i);
vid.fsize *= 2;
displayColorButton(x, y, s0, 'a'+i, 0, 0, palette[i+1] >> ash);
vid.fsize /= 2;
}
}
for(int i=0; i<4; i++) {
int y = vid.yres / 2 + (2-i) * vid.fsize * 2;
displayColorButton(vid.xres / 4, y, "(", 0, 16, 0, 0xFFFFFF);
string rgt = ") "; rgt += "ABGR" [i];
displayColorButton(vid.xres * 3/4, y, rgt, 0, 0, 0, 0xFFFFFF);
displayColorButton(vid.xres /4 + vid.xres * ((color >> (8*i)) & 0xFF) / 510, y, "#", 0, 8, 0, 0xFFFFFF);
if(mousey >= y - vid.fsize && mousey < y + vid.fsize)
getcstat = 'A' + i, inslider = true;
}
displayColorButton(vid.xres/2, vid.yres/2+vid.fsize * 6, XLAT("select this color") + " : " + itsh(color), ' ', 8, 0, color >> ash);
}
// 0: nothing happened, 1: color accepted, 2: break
int handleKeyColor(int sym, int uni, int& color) {
if(uni >= 'A' && uni <= 'D') {
int x = (mousex - vid.xres/4) * 510 / vid.xres;
if(x < 0) x = 0;
if(x > 255) x = 255;
unsigned char* pts = (unsigned char*) &color;
pts[uni - 'A'] = x;
}
else if(uni == ' ') {
bool inHistory = false;
for(int i=0; i<10; i++) if(colorhistory[i] == (unsigned) color)
inHistory = true;
if(!inHistory) { colorhistory[lch] = color; lch++; lch %= 10; }
return 1;
}
else if(uni >= '0' && uni <= '9') {
color = colorhistory[uni - '0'];
}
else if(palette && uni >= 'a' && uni < 'a'+(int) palette[0]) {
color = palette[1 + uni - 'a'];
}
else if(uni || sym == SDLK_F10) return 2;
return 0;
}
int *colorPointer;
emtype lastmode;
void openColorDialog(int& col, unsigned int *pal) {
colorPointer = &col; palette = pal;
lastmode = cmode; cmode = emColor;
}
void handleColor(int sym, int uni) {
int ret = handleKeyColor(sym, uni, *colorPointer);
if(ret) cmode = lastmode;
}
struct numberEditor {
ld *editwhat;
string s;
ld vmin, vmax, step, dft;
string title, help;
ld (*scale) (ld);
ld (*inverse_scale) (ld);
int *intval; ld intbuf;
bool positive;
} ne;
bool editingDetail() {
return ne.editwhat == &geom3::highdetail || ne.editwhat == &geom3::middetail;
}
ld identity(ld x) { return x; }
void scaleSinh() {
ne.scale = ASINH;
ne.inverse_scale = sinh;
}
void scaleLog() {
ne.scale = log;
ne.inverse_scale = exp;
ne.positive = true;
}
void editNumber(ld& x, ld vmin, ld vmax, ld step, ld dft, string title, string help) {
ne.editwhat = &x;
ne.s = fts(x);
ne.vmin = vmin;
ne.vmax = vmax;
ne.step = step;
ne.dft = dft;
ne.title = title;
ne.help = help;
lastmode = cmode; cmode = emNumber;
ne.scale = ne.inverse_scale = identity;
ne.intval = NULL;
ne.positive = false;
}
void editNumber(int& x, int vmin, int vmax, int step, int dft, string title, string help) {
editNumber(ne.intbuf, vmin, vmax, step, dft, title, help);
ne.intbuf = x; ne.intval = &x; ne.s = its(x);
}
string disp(ld x) { if(ne.intval) return its((int) (x+.5)); else return fts(x); }
void affect(char kind) {
if(ne.intval) {
if(kind == 's') sscanf(ne.s.c_str(), "%d", ne.intval), *ne.editwhat = *ne.intval;
if(kind == 'v') *ne.intval = (int) (*ne.editwhat + .5), ne.s = its(*ne.intval);
}
else {
if(kind == 's') {
ld x;
sscanf(ne.s.c_str(), LDF, &x);
if(ne.positive && x <= 0) return;
*ne.editwhat = x;
}
if(kind == 'v') ne.s = fts(*ne.editwhat);
}
#ifndef NOAUDIO
if(ne.intval == &musicvolume) {
if(musicvolume < 0)
*ne.editwhat = musicvolume = 0, affect('v');
else if(musicvolume > MIX_MAX_VOLUME)
*ne.editwhat = musicvolume = MIX_MAX_VOLUME, affect('v');
#ifdef SDLAUDIO
else Mix_VolumeMusic(musicvolume);
#endif
#ifdef ANDROID
settingsChanged = true;
#endif
}
if(ne.intval == &effvolume) {
if(effvolume < 0)
*ne.editwhat = effvolume = 0, affect('v');
else if(effvolume > MIX_MAX_VOLUME)
*ne.editwhat = effvolume = MIX_MAX_VOLUME, affect('v');
#ifdef ANDROID
settingsChanged = true;
#endif
}
#endif
if(ne.intval == &vid.framelimit && vid.framelimit < 5)
*ne.editwhat = vid.framelimit = 5, affect('v');
#ifdef MOBILE
if(ne.intval == &fontscale && fontscale < 50)
*ne.editwhat = fontscale = 50, affect('v');
#endif
if(ne.intval == &sightrange && sightrange < 4)
*ne.editwhat = sightrange = 4, affect('v');
int msr = cheater ? 15 : 7;
if(ne.intval == &sightrange && sightrange > msr)
*ne.editwhat = sightrange = msr, affect('v');
if(ne.intval == &conformal::bandhalf && conformal::bandhalf < 5)
*ne.editwhat = *ne.intval = 5, affect('v');
if(ne.intval == &conformal::bandsegment && conformal::bandsegment < 500)
*ne.editwhat = *ne.intval = 500, affect('v');
if(ne.intval == &polygonal::coefid && polygonal::coefid < 0)
*ne.editwhat = *ne.intval = 0, affect('v');
if(ne.intval == &polygonal::coefid && polygonal::coefid >= MSI)
*ne.editwhat = *ne.intval = MSI-1, affect('v');
if(ne.intval == &polygonal::deg && polygonal::deg < 0)
*ne.editwhat = *ne.intval = MSI-1, affect('v');
if(ne.intval == &polygonal::deg && polygonal::deg >= MSI)
*ne.editwhat = *ne.intval = MSI-1, affect('v');
if(ne.intval == &polygonal::SI) polygonal::solve();
if(ne.editwhat == &polygonal::STAR) polygonal::solve();
conformal::applyIB();
if(ne.editwhat == &geom3::highdetail && geom3::highdetail > geom3::middetail)
geom3::middetail = geom3::highdetail;
if(ne.editwhat == &geom3::middetail && geom3::highdetail > geom3::middetail)
geom3::highdetail = geom3::middetail;
if(lastmode == em3D) buildpolys(), resetGL();
}
void drawNumberDialog() {
init(ne.title);
addInfo(ne.s);
addSlider(ne.scale(ne.vmin), ne.scale(*ne.editwhat), ne.scale(ne.vmax), 500);
addBreak(100);
#ifndef MOBILE
addHelp("You can scroll with arrow keys -- Ctrl to fine-tune");
addBreak(100);
#endif
addItem("return", ' ');
addSelItem("default value", disp(ne.dft), SDLK_HOME);
addBreak(100);
if(lastmode == em3D) ne.help = explain3D(ne.editwhat);
if(ne.help != "") {
addHelp(ne.help);
bool scal = size(ne.help) > 160;
#ifndef MOBILE
#ifndef PANDORA
scal = false;
#endif
#endif
if(scal) lastItem().scale = 30;
}
if(ne.editwhat == &vid.alpha) {
addBreak(100);
addSelItem(sphere ? "stereographic" : "Poincaré model", "1", 'p');
addSelItem(sphere ? "gnomonic" : "Klein model", "0", 'k');
addItem(sphere ? "towards orthographic" : "towards Gans model", 'o');
}
if(ne.editwhat == &ne.intbuf && ne.intval == &sightrange && cheater)
addBoolItem("overgenerate", overgenerate, 'o');
display();
}
void handleNumber(int sym, int uni) {
handleNavigation(sym, uni);
if((uni >= '0' && uni <= '9') || (uni == '.' && !ne.intval) || (uni == '-' && !ne.positive)) {
ne.s += uni;
affect('s');
}
else if(uni == '\b' || uni == '\t') {
ne.s = ne.s. substr(0, size(ne.s)-1);
sscanf(ne.s.c_str(), LDF, ne.editwhat);
affect('s');
}
#ifndef MOBILE
else if(sym == SDLK_RIGHT || sym == SDLK_KP6) {
if(ne.intval && abs(shiftmul) < .6)
(*ne.editwhat)++;
else
*ne.editwhat = ne.inverse_scale(ne.scale(*ne.editwhat) + shiftmul * ne.step);
affect('v');
}
else if(sym == SDLK_LEFT || sym == SDLK_KP4) {
if(ne.intval && abs(shiftmul) < .6)
(*ne.editwhat)--;
else
*ne.editwhat = ne.inverse_scale(ne.scale(*ne.editwhat) - shiftmul * ne.step);
affect('v');
}
#endif
else if(sym == SDLK_HOME) {
*ne.editwhat = ne.dft;
affect('v');
}
else if(uni == 500) {
ld d = (mousex - vid.xres/4 + .0) / (vid.xres/2);
*ne.editwhat =
ne.inverse_scale(d * (ne.scale(ne.vmax) - ne.scale(ne.vmin)) + ne.scale(ne.vmin));
affect('v');
}
else if(uni == 'o' && ne.editwhat == &ne.intbuf && ne.intval == &sightrange && cheater)
overgenerate = !overgenerate;
else if(uni == 'p' && ne.editwhat == &vid.alpha) {
*ne.editwhat = 1; vid.scale = 1; ne.s = "1";
}
else if(uni == 'k' && ne.editwhat == &vid.alpha) {
*ne.editwhat = 0; vid.scale = 1; ne.s = "0";
}
else if((uni == 'i' || uni == 'I' || uni == 'o' || uni == 'O') && ne.editwhat == &vid.alpha) {
double d = exp(shiftmul/10);
vid.alpha *= d;
vid.scale *= d;
ne.s = fts(vid.alpha);
}
else if(uni) {
cmode = lastmode;
}
}
int nlpage = 1;
int wheelshift = 0;
int handlePage(int& nl, int& nlm, int perpage) {
nlm = nl;
int onl = nl;
int ret = 0;
if(nlpage) {
nl = nlm = perpage;
if(nlpage == 2) ret = nlm;
int w = wheelshift;
int realw = 0;
while(w<0 && ret) {
ret--; w++; realw--;
}
while(w>0 && ret+perpage < onl) {
ret++; w--; realw++;
}
wheelshift = realw;
if(ret+nl > onl) nl = onl-ret;
}
return ret;
}
void displayPageButtons(int i, bool pages) {
int i0 = vid.yres - vid.fsize;
int xr = vid.xres / 80;
if(pages) if(displayfrZ(xr*8, i0, 1, vid.fsize, IFM("1 - ") + XLAT("page") + " 1", nlpage == 1 ? 0xD8D8C0 : 0xC0C0C0, 8))
getcstat = '1';
if(pages) if(displayfrZ(xr*24, i0, 1, vid.fsize, IFM("2 - ") + XLAT("page") + " 2", nlpage == 1 ? 0xD8D8C0 : 0xC0C0C0, 8))
getcstat = '2';
if(pages) if(displayfrZ(xr*40, i0, 1, vid.fsize, IFM("3 - ") + XLAT("all"), nlpage == 1 ? 0xD8D8C0 : 0xC0C0C0, 8))
getcstat = '3';
if(i&1) if(displayfrZ(xr*56, i0, 1, vid.fsize, IFM("0 - ") + XLAT("return"), 0xC0C0C0, 8))
getcstat = '0';
if(i&2) if(displayfrZ(xr*72, i0, 1, vid.fsize, IFM("F1 - ") + XLAT("help"), 0xC0C0C0, 8))
getcstat = SDLK_F1;
}
bool handlePageButtons(int uni) {
if(uni == '1') nlpage = 1, wheelshift = 0;
else if(uni == '2') nlpage = 2, wheelshift = 0;
else if(uni == '3') nlpage = 0, wheelshift = 0;
else if(uni == PSEUDOKEY_WHEELUP) wheelshift--;
else if(uni == PSEUDOKEY_WHEELDOWN) wheelshift++;
else return false;
return true;
}
};

234
fake-mobile.cpp Normal file
View File

@ -0,0 +1,234 @@
#define ISANDROID 0
#define ISMOBILE 1
#define ISIOS 0
#define MOBILE
#define MOBPAR_FORMAL int
#define MOBPAR_ACTUAL 0
#define FAKEMOBILE
#define MIX_MAX_VOLUME 128
const char *scorefile = "fakemobile_score.txt";
const char *conffile = "fakemobile_config.txt";
#include <SDL/SDL.h>
#include <GL/gl.h>
#include "init.cpp"
#include <SDL/SDL_ttf.h>
#include <SDL/SDL_gfxPrimitives.h>
#undef main
void playSound(cell *, const string &s, int vol) {
printf("play sound: %s vol %d\n", s.c_str(), vol);
}
SDL_Surface *s;
int gdpos = 0;
int gdpop() { return graphdata[gdpos++]; }
TTF_Font *font[256];
bool rawdisplaystr(int x, int y, int shift, int size, const char *str, int color, int align) {
if(strlen(str) == 0) return false;
if(size <= 0 || size > 255) {
return false;
}
SDL_Color col;
col.r = (color >> 16) & 255;
col.g = (color >> 8 ) & 255;
col.b = (color >> 0 ) & 255;
col.r >>= darken; col.g >>= darken; col.b >>= darken;
if(!font[size])
font[size] = TTF_OpenFont("VeraBd.ttf", size);
SDL_Surface *txt = TTF_RenderText_Solid(font[size], str, col);
if(txt == NULL) return false;
SDL_Rect rect;
rect.w = txt->w;
rect.h = txt->h;
rect.x = x - rect.w * align / 16;
rect.y = y - rect.h/2;
bool clicked = (mousex >= rect.x && mousey >= rect.y && mousex <= rect.x+rect.w && mousey <= rect.y+rect.h);
SDL_BlitSurface(txt, NULL, s,&rect);
SDL_FreeSurface(txt);
return clicked;
}
int textwidth(int siz, const string &str) {
if(size(str) == 0) return 0;
if(!font[siz]) font[siz] = TTF_OpenFont("VeraBd.ttf", siz);
int w, h;
TTF_SizeUTF8(font[siz], str.c_str(), &w, &h);
// printf("width = %d [%d]\n", w, size(str));
return w;
}
char action;
int getticks() { return SDL_GetTicks(); }
bool currentlyConnecting() { return false; }
bool currentlyConnected() { return false; }
void viewAchievements() { printf("view Achievements\n"); }
void viewLeaderboard(string id) { printf("view Leaderboard :: %s\n", id.c_str()); }
void switchGoogleConnection() { printf("sgc\n"); }
int main(int argc, char **argv) {
initAll();
vid.xres = 800; vid.yres = 450;
vid.usingGL = false;
// 450; vid.yres = 600;
s= SDL_SetVideoMode(vid.xres, vid.yres, 32, 0);
if(TTF_Init() != 0) {
printf("Failed to initialize TTF.\n");
exit(2);
}
int mx = 0; int my = 0; bool _clicked = false;
int action = 0;
firstland = laMinefield;
items[itGreenStone] = 100;
items[itDiamond] = 50;
for(int i=1; i<10; i++) kills[i] = 5;
while(true) {
SDL_LockSurface(s);
memset(s->pixels, 0, vid.xres * vid.yres * 4);
SDL_UnlockSurface(s);
mousex = mx;
mousey = my;
clicked = _clicked;
mobile_draw(MOBPAR_ACTUAL);
action = 0;
gdpos = 0;
while(gdpos < graphdata.size()) {
switch(gdpop()) {
case 2: {
int x = gdpop(), y = gdpop(), al = gdpop();
int color = gdpop();
int size = gdpop();
int b = gdpop();
int n = gdpop();
string s;
for(int i=0; i<n; i++) s += char(gdpop());
rawdisplaystr(x, y, 0, size, s.c_str(), color, al);
break;
}
case 1: {
int col = gdpop();
int otl = gdpop();
int num = gdpop();
Sint16 xpox[6000], xpoy[6000];
// printf("%4d polygon %d\n", gdpos, num);
for(int i=0; i<num; i++) xpox[i] = gdpop(), xpoy[i] = gdpop();
filledPolygonColor(s, xpox, xpoy, num, col);
aapolygonColor(s, xpox, xpoy, num, otl);
break;
}
case 3: {
int col = gdpop();
int num = gdpop();
for(int i=0; i<num; i++) polyx[i] = gdpop(), polyy[i] = gdpop();
for(int i=0; i<num-1; i++)
aalineColor(s, polyx[i], polyy[i], polyx[i+1], polyy[i+1], col);
}
case 4: {
int col = gdpop();
int x = gdpop(), y = gdpop(), rad = gdpop();
aacircleColor(s, x, y, rad, (col << 8) + 0xFF);
}
}
}
SDL_UpdateRect(s, 0, 0, vid.xres, vid.yres);
SDL_Event ev;
while(SDL_PollEvent(&ev)) {
if(ev.type == SDL_MOUSEBUTTONDOWN) {
mx = ev.button.x;
my = ev.button.y;
_clicked = true;
}
if(ev.type == SDL_MOUSEBUTTONUP) {
_clicked = false;
}
if(ev.type == SDL_MOUSEMOTION) {
mx = ev.motion.x;
my = ev.motion.y;
}
if(ev.type == SDL_KEYDOWN) {
int sym = ev.key.keysym.sym;
/* if(sym == '1') {
printf("Number of cells explored, by distance from the player:\n");
for(int i=0; i<10; i++) printf(" %d", explore[i]); printf("\n");
return 0;
}
else if(sym == '2') {
items[rand() % ittypes] += 3;
kills[rand() % motypes] += 3;
}
else if(sym == '3') {
items[itHell] = 0;
items[itGreenStone] = 100;
}
action = sym; */
extra ex;
mousing = false;
handlekey(sym, sym, ex);
}
if(ev.type == SDL_QUIT) {
SDL_Quit();
return 0;
}
}
}
SDL_Quit();
clearMemory();
}
void openURL() {
printf("< openURL > \n");
}

684
fieldpattern.cpp Normal file
View File

@ -0,0 +1,684 @@
namespace fieldpattern {
extern int subpathid;
extern int subpathorder;
bool isprime(int n) {
for(int k=2; k<n; k++) if(n%k == 0) return false;
return true;
}
struct matrix {
int a[3][3];
int* operator [] (int k) { return a[k]; }
const int* operator [] (int k) const { return a[k]; }
};
bool operator == (const matrix& A, const matrix& B) {
for(int i=0; i<3; i++) for(int j=0; j<3; j++)
if(A[i][j] != B[i][j]) return false;
return true;
}
bool operator != (const matrix& A, const matrix& B) {
for(int i=0; i<3; i++) for(int j=0; j<3; j++)
if(A[i][j] != B[i][j]) return true;
return false;
}
bool operator < (const matrix& A, const matrix& B) {
for(int i=0; i<3; i++) for(int j=0; j<3; j++)
if(A[i][j] != B[i][j]) return A[i][j] < B[i][j];
return false;
}
int btspin(int id, int d) {
return 7*(id/7) + (id + d) % 7;
}
struct fpattern {
int Prime, wsquare, Field;
// we perform our computations in the field Z_Prime[w] where w^2 equals wsquare
// (or simply Z_Prime for wsquare == 0)
#define EASY
// 'easy' assumes that all elements of the field actually used
// are of form n or mw (not n+mw), and cs and ch are both of form n
// by experimentation, such cs and ch always exist
// many computations are much simpler under that assumption
#ifndef EASY
static int neasy;
int m(int x) { x %= Prime; if(x<0) x+= Prime; return x; }
#endif
int sub(int a, int b) {
#ifdef EASY
return (a + b * (Prime-1)) % Prime;
#else
return m(a%Prime-b%Prime) + Prime * m(a/Prime-b/Prime);
#endif
}
int add(int a, int b) {
#ifdef EASY
return (a+b)%Prime;
#else
return m(a%Prime+b%Prime) + Prime * m(a/Prime+b/Prime);
#endif
}
int mul(int tx, int ty) {
#ifdef EASY
return (tx*ty*((tx<0&&ty<0)?wsquare:1)) % Prime;
#else
if(tx >= Prime && tx % Prime) neasy++;
if(ty >= Prime && ty % Prime) neasy++;
int x[2], y[2], z[3];
for(int i=0; i<3; i++) z[i] = 0;
for(int i=0; i<2; i++)
x[i] = tx%Prime, tx /= Prime;
for(int i=0; i<2; i++)
y[i] = ty%Prime, ty /= Prime;
for(int i=0; i<2; i++)
for(int j=0; j<2; j++)
z[i+j] = (z[i+j] + x[i] * y[j]) % Prime;
z[0] += z[2] * wsquare;
return m(z[0]) + Prime * m(z[1]);
#endif
}
int sqr(int x) { return mul(x,x); }
matrix mmul(const matrix& A, const matrix& B) {
matrix res;
for(int i=0; i<3; i++) for(int k=0; k<3; k++) {
#ifdef EASY
res[i][k] =
(mul(A[i][0], B[0][k]) + mul(A[i][1], B[1][k]) + mul(A[i][2], B[2][k])) % Prime;
#else
int t=0;
for(int j=0; j<3; j++) t = add(t, mul(A[i][j], B[j][k]));
res[i][k] = t;
#endif
}
return res;
}
map<matrix, int> matcode;
vector<matrix> matrices;
vector<string> qpaths;
vector<matrix> qcoords;
matrix Id, R, P;
matrix strtomatrix(string s) {
matrix res = Id;
matrix m = Id;
for(int i=size(s)-1; i>=0; i--)
if(s[i] == 'R') res = mmul(R, res);
else if (s[i] == 'P') res = mmul(P, res);
else if (s[i] == 'x') { m[0][0] = -1; res = mmul(m, res); m[0][0] = +1; }
else if (s[i] == 'y') { m[1][1] = -1; res = mmul(m, res); m[1][1] = +1; }
else if (s[i] == 'z') { m[2][2] = -1; res = mmul(m, res); m[2][2] = +1; }
return res;
}
void addas(const matrix& M, int i) {
if(!matcode.count(M)) {
matcode[M] = i;
for(int j=0; j<size(qcoords); j++)
addas(mmul(M, qcoords[j]), i);
}
}
void add(const matrix& M) {
if(!matcode.count(M)) {
int i = matrices.size();
matcode[M] = i, matrices.push_back(M);
for(int j=0; j<size(qcoords); j++)
addas(mmul(M, qcoords[j]), i);
add(mmul(R, M));
}
}
#define MXF 1000000
vector<int> connections;
vector<int> inverses;
vector<int> rrf; // rrf[i] equals gmul(i, 6)
vector<int> rpf; // rpf[i] equals gmul(i, 7)
matrix mpow(matrix M, int N) {
while((N&1) == 0) N >>= 1, M = mmul(M, M);
matrix res = M;
N >>= 1;
while(N) {
M = mmul(M,M); if(N&1) res = mmul(res, M);
N >>= 1;
}
return res;
}
int gmul(int a, int b) { return matcode[mmul(matrices[a], matrices[b])]; }
int gpow(int a, int N) { return matcode[mpow(matrices[a], N)]; }
pair<int,bool> gmul(pair<int, bool> a, int b) {
return make_pair(gmul(a.first,b), a.second);
}
int order(const matrix& M) {
int cnt = 1;
matrix Po = M;
while(Po != Id) Po = mmul(Po, M), cnt++;
return cnt;
}
string decodepath(int i) {
string s;
while(i) {
if(i % 7) i--, s += 'R';
else i = connections[i], s += 'P';
}
return s;
}
int orderstats();
int cs, sn, ch, sh;
int solve() {
for(int a=0; a<3; a++) for(int b=0; b<3; b++) Id[a][b] = a==b?1:0;
if(!isprime(Prime)) {
return 1;
}
for(int pw=1; pw<3; pw++) {
if(pw>3) break;
Field = pw==1? Prime : Prime*Prime;
if(pw == 2) {
for(wsquare=1; wsquare<Prime; wsquare++) {
int roots = 0;
for(int a=0; a<Prime; a++) if((a*a)%Prime == wsquare) roots++;
if(!roots) break;
}
} else wsquare = 0;
#ifdef EASY
int sqrts[Prime];
for(int k=0; k<Prime; k++) sqrts[k] = 0;
for(int k=1-Prime; k<Prime; k++) sqrts[sqr(k)] = k;
int fmax = Prime;
#else
int sqrts[Field];
for(int k=0; k<Field; k++) sqrts[sqr(k)] = k;
int fmax = Field;
#endif
if(Prime == 13 && wsquare) {
for(int i=0; i<Prime; i++) printf("%3d", sqrts[i]);
printf("\n");
}
for(int i=0; i<3; i++) for(int j=0; j<3; j++)
R[i][j] = P[i][j] = i==j ? 1 : 0;
for(cs=0; cs<fmax; cs++) {
int sb = sub(1, sqr(cs));
sn = sqrts[sb];
R[0][0] = cs; R[1][1] = cs;
R[0][1] = sn; R[1][0] = sub(0, sn);
matrix Z = R;
for(int i=0; i<6; i++) Z = mmul(Z, R);
if(Z != Id) continue;
if(R[0][0] == 1) continue;
for(ch=2; ch<fmax; ch++) {
int chx = sub(mul(ch,ch), 1);
sh = sqrts[chx];
P[0][0] = sub(0, ch);
P[0][2] = sub(0, sh);
P[1][1] = Prime-1;
P[2][0] = sh;
P[2][2] = ch;
matrix Z = mmul(P, R);
Z = mmul(Z, mmul(Z, Z));
if(Z == Id) return 0;
}
}
}
return 2;
}
void build() {
for(int i=0; i<size(qpaths); i++) {
matrix M = strtomatrix(qpaths[i]);
qcoords.push_back(M);
printf("Solved %s as matrix of order %d\n", qpaths[i].c_str(), order(M));
}
matcode.clear(); matrices.clear();
add(Id);
if(matrices.size() != 7) { printf("Error: rotation crash\n"); exit(1); }
connections.clear();
for(int i=0; i<(int)matrices.size(); i++) {
matrix M = matrices[i];
matrix PM = mmul(P, M);
add(PM);
if(matrices.size() % 7) { printf("Error: rotation crash\n"); exit(1); }
if(!matcode.count(PM)) { printf("Error: not marked\n"); exit(1); }
connections.push_back(matcode[PM]);
}
DEBB(DF_FIELD, (debugfile, "Computing inverses...\n"));
int N = size(matrices);
DEBB(DF_FIELD, (debugfile, "Number of heptagons: %d\n", N));
rrf.resize(N); rrf[0] = 6;
for(int i=0; i<N; i++)
rrf[btspin(i,1)] = btspin(rrf[i], 1),
rrf[connections[i]] = connections[rrf[i]];
rpf.resize(N); rpf[0] = 7;
for(int i=0; i<N; i++)
rpf[btspin(i,1)] = btspin(rpf[i], 1),
rpf[connections[i]] = connections[rpf[i]];
inverses.resize(N);
inverses[0] = 0;
for(int i=0; i<N; i++) // inverses[i] = gpow(i, N-1);
inverses[btspin(i,1)] = rrf[inverses[i]], // btspin(inverses[i],6),
inverses[connections[i]] = rpf[inverses[i]];
int errs = 0;
for(int i=0; i<N; i++) if(gmul(i, inverses[i])) errs++;
if(errs) printf("errs = %d\n", errs);
if(0) for(int i=0; i<size(matrices); i++) {
printf("%5d/%4d", connections[i], inverses[i]);
if(i%7 == 6) printf("\n");
}
DEBB(DF_FIELD, (debugfile, "Built.\n"));
}
vector<char> disthep;
vector<char> disthex;
vector<char> distwall, distriver, distwall2, distriverleft, distriverright, distflower;
vector<eItem> markers;
int getdist(pair<int,bool> a, vector<char>& dists) {
if(!a.second) return dists[a.first];
int m = 60;
int ma = dists[a.first];
int mb = dists[connections[btspin(a.first, 3)]];
int mc = dists[connections[btspin(a.first, 4)]];
m = min(m, 1 + ma);
m = min(m, 1 + mb);
m = min(m, 1 + mc);
if(m <= 2 && ma+mb+mc <= m*3-2) return m-1; // special case
m = min(m, 2 + dists[connections[btspin(a.first, 2)]]);
m = min(m, 2 + dists[connections[btspin(a.first, 5)]]);
m = min(m, 2 + dists[connections[btspin(connections[btspin(a.first, 3)], 5)]]);
return m;
}
int getdist(pair<int,bool> a, pair<int,bool> b) {
if(a.first == b.first) return a.second == b.second ? 0 : 1;
if(b.first) a.first = gmul(a.first, inverses[b.first]), b.first = 0;
return getdist(a, b.second ? disthex : disthep);
}
int maxdist, otherpole, circrad, wallid, wallorder, riverid;
int dijkstra(vector<char>& dists, vector<int> indist[64]) {
int N = connections.size();
dists.resize(N);
for(int i=0; i<N; i++) dists[i] = 60;
int maxd = 0;
for(int i=0; i<64; i++) while(!indist[i].empty()) {
int at = indist[i].back();
indist[i].pop_back();
if(dists[at] <= i) continue;
maxd = i;
dists[at] = i;
for(int q=0; q<7; q++) {
dists[at] = i;
if(purehepta)
indist[i+1].push_back(connections[at]);
else {
indist[i+2].push_back(connections[at]);
indist[i+3].push_back(connections[btspin(connections[at], 2)]);
}
at = btspin(at, 1);
}
}
return maxd;
}
void analyze() {
DEBB(DF_FIELD, (debugfile, "purehepta = %d\n", purehepta));
int N = connections.size();
markers.resize(N);
vector<int> indist[64];
indist[0].push_back(0);
int md0 = dijkstra(disthep, indist);
indist[1].push_back(0);
indist[1].push_back(connections[3]);
indist[1].push_back(connections[4]);
indist[2].push_back(connections[btspin(connections[3], 5)]);
indist[2].push_back(connections[2]);
indist[2].push_back(connections[5]);
int md1 = dijkstra(disthex, indist);
maxdist = max(md0, md1);
otherpole = 0;
for(int i=0; i<N; i+=7) {
int mp = 0;
for(int q=0; q<7; q++) if(disthep[connections[i+q]] < disthep[i]) mp++;
if(mp == 7) {
bool eq = true;
for(int q=0; q<7; q++) if(disthep[connections[i+q]] != disthep[connections[i]]) eq = false;
if(eq) {
// for(int q=0; q<7; q++) printf("%3d", disthep[connections[i+q]]);
// printf(" (%2d) at %d\n", disthep[i], i);
if(disthep[i] > disthep[otherpole]) otherpole = i;
// for(int r=0; r<7; r++) {
// printf("Matrix: "); for(int a=0; a<3; a++) for(int b=0; b<3; b++)
// printf("%4d", matrices[i+r][a][b]); printf("\n");
// }
}
}
}
circrad = 99;
for(int i=0; i<N; i++) for(int u=2; u<4; u++) if(disthep[i] < circrad)
if(disthep[connections[i]] < disthep[i] && disthep[connections[btspin(i,u)]] < disthep[i])
circrad = disthep[i];
DEBB(DF_FIELD, (debugfile, "maxdist = %d otherpole = %d circrad = %d\n", maxdist, otherpole, circrad));
matrix PRRR = strtomatrix("PRRR");
matrix PRRPRRRRR = strtomatrix("PRRPRRRRR");
matrix PRRRP = strtomatrix("PRRRP");
matrix PRP = strtomatrix("PRP");
matrix PR = strtomatrix("PR");
matrix Wall = strtomatrix("RRRPRRRRRPRRRP");
wallorder = order(Wall);
wallid = matcode[Wall];
DEBB(DF_FIELD, (debugfile, "wall order = %d\n", wallorder));
#define SETDIST(X, d, it) {int c = matcode[X]; indist[d].push_back(c); if(!it) ; else if(markers[c] && markers[c] != it) markers[c] = itBuggy; else markers[c] = it; }
matrix W = Id;
for(int i=0; i<wallorder; i++) {
SETDIST(W, 0, itAmethyst)
W = mmul(W, Wall);
}
W = P;
for(int i=0; i<wallorder; i++) {
SETDIST(W, 0, itEmerald)
W = mmul(W, Wall);
}
int walldist = dijkstra(distwall, indist);
DEBB(DF_FIELD, (debugfile, "wall dist = %d\n", walldist));
W = strtomatrix("RRRRPR");
for(int j=0; j<wallorder; j++) {
W = mmul(W, Wall);
for(int i=0; i<wallorder; i++) {
SETDIST(W, 0, itNone)
SETDIST(mmul(PRRR, W), 1, itNone)
W = mmul(Wall, W);
}
}
dijkstra(distwall2, indist);
int rpushid = matcode[PRRPRRRRR];
riverid = 0;
for(int i=0; i<N; i++) {
int j = i;
int ipush = gmul(rpushid, i);
for(int k=0; k<wallorder; k++) {
if(ipush == j) {
DEBB(DF_FIELD, (debugfile, "River found at %d:%d\n", i, k));
riverid = i;
goto riveridfound;
}
j = gmul(j, wallid);
}
}
riveridfound: ;
W = strtomatrix("RRRRPR");
for(int j=0; j<wallorder; j++) {
W = mmul(W, Wall);
for(int i=0; i<wallorder; i++) {
if(i == 7) SETDIST(W, 0, itCoast)
if(i == 3) SETDIST(mmul(PRRRP, W), 0, itWhirlpool)
W = mmul(Wall, W);
}
}
dijkstra(purehepta ? distriver : distflower, indist);
W = matrices[riverid];
for(int i=0; i<wallorder; i++) {
SETDIST(W, 0, itStatue)
W = mmul(W, Wall);
}
W = mmul(P, W);
for(int i=0; i<wallorder; i++) {
SETDIST(W, 0, itSapphire)
W = mmul(W, Wall);
}
W = mmul(PRP, matrices[riverid]);
for(int i=0; i<wallorder; i++) {
SETDIST(W, 1, itShard)
W = mmul(W, Wall);
}
W = mmul(PR, matrices[riverid]);
for(int i=0; i<wallorder; i++) {
SETDIST(W, 1, itGold)
W = mmul(W, Wall);
}
int riverdist = dijkstra(purehepta ? distflower : distriver, indist);
DEBB(DF_FIELD, (debugfile, "river dist = %d\n", riverdist));
if(!purehepta) {
W = matrices[riverid];
for(int i=0; i<wallorder; i++) {
SETDIST(W, 0, itStatue)
W = mmul(W, Wall);
}
W = mmul(PR, matrices[riverid]);
for(int i=0; i<wallorder; i++) {
SETDIST(W, 0, itGold)
W = mmul(W, Wall);
}
W = mmul(P, matrices[riverid]);
for(int i=0; i<wallorder; i++) {
SETDIST(W, 1, itSapphire)
W = mmul(W, Wall);
}
dijkstra(distriverleft, indist);
W = mmul(PRP, matrices[riverid]);
for(int i=0; i<wallorder; i++) {
SETDIST(W, 0, itShard)
W = mmul(W, Wall);
}
W = mmul(P, matrices[riverid]);
for(int i=0; i<wallorder; i++) {
SETDIST(W, 0, itSapphire)
W = mmul(W, Wall);
}
W = matrices[riverid];
for(int i=0; i<wallorder; i++) {
SETDIST(W, 1, itStatue)
W = mmul(W, Wall);
}
dijkstra(distriverright, indist);
}
else {
W = strtomatrix("RRRRPR");
for(int j=0; j<wallorder; j++) {
W = mmul(W, Wall);
for(int i=0; i<wallorder; i++) {
if(i == 7) SETDIST(W, 0, itCoast)
W = mmul(Wall, W);
}
}
dijkstra(distriverleft, indist);
W = strtomatrix("RRRRPR");
for(int j=0; j<wallorder; j++) {
W = mmul(W, Wall);
for(int i=0; i<wallorder; i++) {
if(i == 3) SETDIST(mmul(PRRRP, W), 0, itWhirlpool)
W = mmul(Wall, W);
}
}
dijkstra(distriverright, indist);
}
DEBB(DF_FIELD, (debugfile, "wall-river distance = %d\n", distwall[riverid]));
DEBB(DF_FIELD, (debugfile, "river-wall distance = %d\n", distriver[0]));
}
bool easy(int i) {
return i < Prime || !(i % Prime);
}
// 11 * 25
// (1+z+z^3) * (1+z^3+z^4) ==
// 1+z+z^7 == 1+z+z^2(z^5) == 1+z+z^2(1+z^2) = 1+z+z^2+z^4
void init(int p) {
Prime = p;
if(solve()) {
printf("error: could not solve the fieldpattern\n");
exit(1);
}
build();
}
fpattern(int p) {
if(!p) return;
init(p);
}
void findsubpath() {
int N = size(matrices);
for(int i=1; i<N; i++)
if(gpow(i, Prime) == 0) {
subpathid = i;
subpathorder = Prime;
DEBB(DF_FIELD, (debugfile, "Subpath found: %s\n", decodepath(i).c_str()));
return;
}
}
};
int fpattern::orderstats() {
int N = size(matrices);
#define MAXORD 10000
int ordcount[MAXORD];
int ordsample[MAXORD];
for(int i=0; i<MAXORD; i++) ordcount[i] = 0;
for(int i=0; i<N; i++) {
int cnt = order(matrices[i]);
if(cnt < MAXORD) {
if(!ordcount[cnt]) ordsample[cnt] = i;
ordcount[cnt]++;
}
}
printf("Listing:\n");
for(int i=0; i<MAXORD; i++) if(ordcount[i])
printf("Found %4d matrices of order %3d: %s\n", ordcount[i], i, decodepath(ordsample[i]).c_str());
return ordsample[Prime];
}
fpattern fp43(43);
void info() {
fpattern fp(0);
int cases = 0, hard = 0;
for(int p=0; p<500; p++) {
fp.Prime = p;
if(fp.solve() == 0) {
printf("%4d: wsquare=%d cs=%d sn=%d ch=%d sh=%d\n",
p, fp.wsquare, fp.cs, fp.sn, fp.ch, fp.sh);
cases++;
if(!fp.easy(fp.cs) || !fp.easy(fp.sn) || !fp.easy(fp.ch) || !fp.easy(fp.sn))
hard++;
#ifndef EASY
neasy = 0;
#endif
fp.build();
#ifndef EASY
printf("Not easy: %d\n", neasy);
#endif
int N = size(fp.matrices);
int left = N / fp.Prime;
printf("Prime decomposition: %d = %d", N, fp.Prime);
for(int p=2; p<=left; p++) while(left%p == 0) printf("*%d", p), left /= p;
printf("\n");
printf("Order of RRP is: %d\n", fp.order(fp.strtomatrix("RRP")));
printf("Order of RRRP is: %d\n", fp.order(fp.strtomatrix("RRRP")));
printf("Order of RRRPRRRRRPRRRP is: %d\n", fp.order(fp.strtomatrix("RRRPRRRRRPRRRP")));
}
}
printf("cases found = %d (%d hard)\n", cases, hard);
}
}
using fieldpattern::fp43;

224
flags.cpp
View File

@ -12,7 +12,9 @@ bool isIcyLand(cell *c) {
} }
bool isGravityLand(eLand l) { bool isGravityLand(eLand l) {
return l == laIvoryTower || l == laEndorian; return
l == laIvoryTower || l == laEndorian ||
l == laMountain || l == laDungeon;
} }
// watery // watery
@ -32,7 +34,8 @@ bool isWateryOrBoat(cell *c) {
bool isNoFlight(cell *c) { bool isNoFlight(cell *c) {
return return
c->wall == waBoat || c->wall == waVineHalfA || c->wall == waVineHalfB || c->wall == waBoat || c->wall == waVineHalfA || c->wall == waVineHalfB ||
c->wall == waStrandedBoat || c->wall == waTrunk; c->wall == waStrandedBoat || c->wall == waTrunk ||
c->wall == waBigBush || c->wall == waSmallBush;
} }
bool boatStrandable(cell *c) { bool boatStrandable(cell *c) {
@ -93,7 +96,7 @@ bool isNonliving(eMonster m) {
m == moMirage || m == moMirror || m == moGolem || m == moGolemMoved || m == moMirage || m == moMirror || m == moGolem || m == moGolemMoved ||
m == moZombie || m == moGhost || m == moShadow || m == moSkeleton || m == moZombie || m == moGhost || m == moShadow || m == moSkeleton ||
m == moEvilGolem || m == moIllusion || m == moEarthElemental || m == moEvilGolem || m == moIllusion || m == moEarthElemental ||
m == moWaterElemental; m == moWaterElemental || m == moDraugr;
} }
bool isMetalBeast(eMonster m) { bool isMetalBeast(eMonster m) {
@ -102,7 +105,8 @@ bool isMetalBeast(eMonster m) {
bool isStunnable(eMonster m) { bool isStunnable(eMonster m) {
return m == moPalace || m == moFatGuard || m == moSkeleton || isPrincess(m) || return m == moPalace || m == moFatGuard || m == moSkeleton || isPrincess(m) ||
isMetalBeast(m) || m == moTortoise || isDragon(m); isMetalBeast(m) || m == moTortoise || isDragon(m) ||
m == moReptile;
} }
bool hasHitpoints(eMonster m) { bool hasHitpoints(eMonster m) {
@ -110,15 +114,23 @@ bool hasHitpoints(eMonster m) {
} }
bool isMountable(eMonster m) { bool isMountable(eMonster m) {
return isWorm(m); return isWorm(m) && m != moTentacleGhost;
} }
bool isFriendly(eMonster m) { bool isFriendly(eMonster m) {
return isMimic(m) || isGolemOrKnight(m) || m == moIllusion; return isMimic(m) || isGolemOrKnight(m) || m == moIllusion || m == moFriendlyIvy;
}
bool isFriendlyOrPlayer(eMonster m) {
return isFriendly(m) || m == moPlayer;
} }
bool isFriendly(cell *c) { bool isFriendly(cell *c) {
if(items[itOrbDomination] && c->monst && sameMonster(c, cwt.c)) return true; if(items[itOrbDomination] && c->monst && c->monst != moTentacleGhost) {
for(int i=0; i<numplayers(); i++)
if(sameMonster(c, playerpos(i)))
return true;
}
return isFriendly(c->monst); return isFriendly(c->monst);
} }
@ -146,13 +158,18 @@ bool isIvy(cell *c) {
} }
bool isMonsterPart(eMonster m) { bool isMonsterPart(eMonster m) {
return m == moMutant || (isIvy(m) && m != moIvyRoot); return m == moMutant || (isIvy(m) && m != moIvyRoot) ||
m == moDragonTail || m == moKrakenT;
} }
bool isMutantIvy(eMonster m) { bool isMutantIvy(eMonster m) {
return m == moMutant; return m == moMutant;
} }
bool isAnyIvy(eMonster m) {
return isIvy(m) || isMutantIvy(m) || m == moFriendlyIvy;
}
bool isBulletType(eMonster m) { bool isBulletType(eMonster m) {
return return
m == moBullet || m == moFlailBullet || m == moBullet || m == moFlailBullet ||
@ -213,7 +230,7 @@ bool cellHalfvine(cell *c) {
} }
bool isWarped(eLand l) { bool isWarped(eLand l) {
return l == laGridCoast || l == laGridSea; return l == laWarpCoast || l == laWarpSea;
} }
bool isElementalShard(eItem i) { bool isElementalShard(eItem i) {
@ -229,19 +246,28 @@ eMonster elementalOf(eLand l) {
return moNone; return moNone;
} }
eItem localshardof(eLand l) {
return eItem(itFireShard + (l - laEFire));
}
int itemclass(eItem i) { int itemclass(eItem i) {
if(i == 0) return -1; if(i == 0) return -1;
if(i < itKey || i == itFernFlower || if(i < itKey || i == itFernFlower ||
i == itWine || i == itSilver || i == itEmerald || i == itRoyalJelly || i == itPower || i == itWine || i == itSilver || i == itEmerald || i == itRoyalJelly || i == itPower ||
i == itGrimoire || i == itPirate || i == itRedGem || i == itBombEgg || i == itGrimoire || i == itPirate || i == itRedGem || i == itBombEgg ||
i == itCoast || i == itWhirlpool || i == itPalace || i == itFjord || i == itCoast || i == itWhirlpool || i == itPalace || i == itFjord ||
i == itElemental || i == itZebra || i == itEdge || i == itElemental || i == itZebra || i == itIvory ||
i == itBounty || i == itFulgurite || i == itMutant || i == itLotus || i == itMutant2 || i == itBounty || i == itFulgurite || i == itMutant || i == itLotus || i == itMutant2 ||
i == itWindstone || i == itCoral || i == itRose || i == itWindstone || i == itCoral || i == itRose ||
i == itBabyTortoise || i == itDragon || i == itApple) i == itBabyTortoise || i == itDragon || i == itApple ||
i == itKraken || i == itBarrow || i == itTrollEgg || i == itTreat ||
i == itSlime || i == itAmethyst || i == itDodeca ||
i == itGreenGrass || i == itBull)
return IC_TREASURE; return IC_TREASURE;
if(i == itSavedPrincess || i == itStrongWind || i == itWarning)
return IC_NAI;
if(i == itKey || i == itOrbYendor || i == itGreenStone || i == itHolyGrail || i == itCompass || if(i == itKey || i == itOrbYendor || i == itGreenStone || i == itHolyGrail || i == itCompass ||
i == itSavedPrincess || isElementalShard(i) || i == itRevolver || i == itStrongWind) isElementalShard(i) || i == itRevolver)
return IC_OTHER; return IC_OTHER;
return IC_ORB; return IC_ORB;
} }
@ -264,10 +290,11 @@ bool realred(eWall w) {
int snakelevel(eWall w) { int snakelevel(eWall w) {
if(w == waRed1 || w == waDeadfloor2 || w == waRubble || w == waGargoyleFloor || if(w == waRed1 || w == waDeadfloor2 || w == waRubble || w == waGargoyleFloor ||
w == waGargoyleBridge || w == waTempFloor || w == waTempBridge) w == waGargoyleBridge || w == waTempFloor || w == waTempBridge || w == waRoundTable)
return 1; return 1;
if(w == waRed2) return 2; if(w == waRed2) return 2;
if(w == waRed3) return 3; if(w == waRed3) return 3;
if(w == waTower) return 3;
return 0; return 0;
} }
@ -285,7 +312,9 @@ bool isWall(cell *w) {
w->wall == waStrandedBoat || w->wall == waOpenGate || w->wall == waClosePlate || w->wall == waStrandedBoat || w->wall == waOpenGate || w->wall == waClosePlate ||
w->wall == waOpenPlate || w->wall == waTrapdoor || w->wall == waGiantRug || w->wall == waOpenPlate || w->wall == waTrapdoor || w->wall == waGiantRug ||
w->wall == waLadder || w->wall == waTrunk || w->wall == waSolidBranch || w->wall == waLadder || w->wall == waTrunk || w->wall == waSolidBranch ||
w->wall == waWeakBranch || w->wall == waCanopy) w->wall == waWeakBranch || w->wall == waCanopy || w->wall == waTower ||
w->wall == waSmallBush || w->wall == waBigBush ||
w->wall == waReptile || w->wall == waReptileBridge)
return false; return false;
if(isWatery(w) || isChasmy(w) || isFire(w)) return false; if(isWatery(w) || isChasmy(w) || isFire(w)) return false;
return true; return true;
@ -293,18 +322,25 @@ bool isWall(cell *w) {
bool isAngryBird(eMonster m) { bool isAngryBird(eMonster m) {
return m == moEagle || m == moAlbatross || m == moBomberbird || m == moGargoyle || return m == moEagle || m == moAlbatross || m == moBomberbird || m == moGargoyle ||
m == moWindCrow || m == moKestrel || m == moNighthawk; m == moWindCrow || m == moSparrowhawk ||
m == moVampire || m == moBat || m == moButterfly || m == moGadfly;
} }
bool isBird(eMonster m) { bool isBird(eMonster m) {
return isAngryBird(m) || m == moTameBomberbird || m == moTameBomberbirdMoved; return isAngryBird(m) || m == moTameBomberbird || m == moTameBomberbirdMoved;
}
bool slowMover(eMonster m) {
return
m == moLesser || m == moGreater || isMetalBeast(m) ||
m == moTortoise || m == moDraugr;
} }
bool normalMover(eMonster m) { bool normalMover(eMonster m) {
return return
m == moYeti || m == moRanger || m == moGoblin || m == moTroll || m == moDesertman || m == moYeti || m == moRanger || m == moGoblin || m == moTroll || m == moDesertman ||
m == moMonkey || m == moZombie || m == moNecromancer || m == moCultist || m == moMonkey || m == moZombie || m == moNecromancer || m == moCultist ||
m == moLesser || m == moGreater || m == moRunDog || m == moPyroCultist || m == moRunDog || m == moPyroCultist ||
m == moFireFairy || m == moCrystalSage || m == moHedge || m == moFireFairy || m == moCrystalSage || m == moHedge ||
m == moVineBeast || m == moLancer || m == moFlailer || m == moVineBeast || m == moLancer || m == moFlailer ||
m == moMiner || m == moDarkTroll || m == moMiner || m == moDarkTroll ||
@ -314,12 +350,12 @@ bool normalMover(eMonster m) {
m == moRedTroll || m == moRedTroll ||
m == moPalace || m == moFatGuard || m == moSkeleton || m == moVizier || m == moPalace || m == moFatGuard || m == moSkeleton || m == moVizier ||
m == moFjordTroll || m == moStormTroll || m == moForestTroll || m == moFjordTroll || m == moStormTroll || m == moForestTroll ||
m == moEdgeMonkey || m == moFamiliar ||
m == moFireElemental || m == moOrangeDog || m == moFireElemental || m == moOrangeDog ||
isMetalBeast(m) ||
m == moOutlaw || m == moRedFox || m == moFalsePrincess || m == moRoseLady || m == moOutlaw || m == moRedFox || m == moFalsePrincess || m == moRoseLady ||
m == moRoseBeauty || m == moWolf || m == moRoseBeauty || m == moWolf ||
m == moTortoise || m == moLemur; m == moResearcher || m == moRagingBull ||
slowMover(m);
} }
// from-to // from-to
@ -339,20 +375,24 @@ bool isShark(eMonster m) {
bool isSlimeMover(eMonster m) { bool isSlimeMover(eMonster m) {
return return
m == moSlime || m == moSeep || m == moShark || m == moSlime || m == moSeep || m == moVineSpirit || m == moParrot;
m == moVineSpirit || m == moCShark || m == moParrot;
} }
bool isDragon(eMonster m) { return m == moDragonHead || m == moDragonTail; }
bool isKraken(eMonster m) { return m == moKrakenH || m == moKrakenT; }
bool isBlowableMonster(eMonster m) { bool isBlowableMonster(eMonster m) {
return m && !( return m && !(
isWorm(m) || isIvy(m) || isMutantIvy(m) || isSlimeMover(m) || isWorm(m) || isIvy(m) || isMutantIvy(m) || isSlimeMover(m) ||
m == moGhost || m == moGreaterShark || m == moGhost || m == moGreaterShark ||
m == moWaterElemental || m == moWitchGhost || isMimic(m) m == moWaterElemental || m == moWitchGhost || isMimic(m) ||
isKraken(m)
); );
} }
bool isMultitile(eMonster m) { bool isMultitile(eMonster m) {
return isWorm(m) || isIvy(m) || isMutantIvy(m); return isWorm(m) || isIvy(m) || isMutantIvy(m) || isKraken(m);
} }
bool isSlimeMover(cell *c) { bool isSlimeMover(cell *c) {
@ -380,8 +420,7 @@ bool isLeader(eMonster m) {
} }
bool isFlying(eMonster m) { bool isFlying(eMonster m) {
return isBird(m) || isGhost(m) || m == moAirElemental || isDragon(m) || return isBird(m) || isGhost(m) || m == moAirElemental || isDragon(m) || checkOrb(m, itOrbAether);
(isFriendly(m) && checkOrb(m, itOrbGhost));
} }
bool survivesChasm(eMonster m) { bool survivesChasm(eMonster m) {
@ -393,7 +432,7 @@ bool ignoresPlates(eMonster m) {
} }
bool itemBurns(eItem it) { bool itemBurns(eItem it) {
return it && it != itOrbDragon && it != itOrbFire && it != itDragon; return it && it != itOrbDragon && it != itOrbFire && it != itDragon && it != itTreat;
} }
bool attackThruVine(eMonster m) { bool attackThruVine(eMonster m) {
@ -404,6 +443,11 @@ bool attackNonAdjacent(eMonster m) {
return m == moGhost || m == moFriendlyGhost || m == moTentacleGhost; return m == moGhost || m == moFriendlyGhost || m == moTentacleGhost;
} }
bool noHighlight(eMonster m) {
return
(m == moIvyWait || m == moIvyNext || m == moIvyDead);
}
bool isInactiveEnemy(cell *w, eMonster forwho) { bool isInactiveEnemy(cell *w, eMonster forwho) {
if(w->monst == moWormtail || w->monst == moWormwait || w->monst == moTentacletail || w->monst == moTentaclewait || w->monst == moHexSnakeTail) if(w->monst == moWormtail || w->monst == moWormwait || w->monst == moTentacletail || w->monst == moTentaclewait || w->monst == moHexSnakeTail)
return true; return true;
@ -429,7 +473,7 @@ bool isActiveEnemy(cell *w, eMonster forwho) {
bool isUnarmed(eMonster m) { bool isUnarmed(eMonster m) {
return return
m == moMouse || m == moMouseMoved || m == moPrincess || m == moPrincessMoved || m == moMouse || m == moMouseMoved || m == moPrincess || m == moPrincessMoved ||
m == moCrystalSage; m == moCrystalSage || m == moVampire || m == moBat;
} }
bool isArmedEnemy(cell *w, eMonster forwho) { bool isArmedEnemy(cell *w, eMonster forwho) {
@ -451,16 +495,17 @@ bool eternalFire(cell *c) {
bool isCyclic(eLand l) { bool isCyclic(eLand l) {
return return
l == laWhirlpool || l == laTemple || l == laCamelot || l == laClearing; l == laWhirlpool || l == laTemple || l == laCamelot || l == laClearing ||
l == laMountain;
} }
bool haveRangedOrb() { bool haveRangedOrb() {
return return
items[itOrbPsi] || items[itOrbDragon] || items[itOrbTeleport] || items[itOrbPsi] || items[itOrbDragon] || items[itOrbTeleport] ||
items[itOrbIllusion] || items[itOrbTelekinesis] || items[itOrbAir] || items[itOrbIllusion] || items[itOrbSpace] || items[itOrbAir] ||
items[itOrbFrog] || items[itOrbSummon] || items[itOrbMatter] || items[itOrbFrog] || items[itOrbSummon] || items[itOrbMatter] ||
items[itRevolver] || items[itOrbStunning] || items[itStrongWind] || items[itRevolver] || items[itOrbStunning] || items[itStrongWind] ||
items[itOrbDomination]; items[itOrbDomination] || items[itOrbNature] || items[itOrbDash];
} }
bool isOffensiveOrb(eItem it) { bool isOffensiveOrb(eItem it) {
@ -471,9 +516,9 @@ bool isOffensiveOrb(eItem it) {
bool isRangedOrb(eItem i) { bool isRangedOrb(eItem i) {
return i == itOrbPsi || i == itOrbDragon || i == itOrbTeleport || i == itOrbIllusion || return i == itOrbPsi || i == itOrbDragon || i == itOrbTeleport || i == itOrbIllusion ||
i == itOrbTelekinesis || i == itOrbAir || i == itOrbFrog || i == itOrbSpace || i == itOrbAir || i == itOrbFrog ||
i == itOrbSummon || i == itOrbMatter || i == itRevolver || i == itOrbStunning || i == itOrbSummon || i == itOrbMatter || i == itRevolver || i == itOrbStunning ||
i == itOrbDomination; i == itOrbDomination || i == itOrbNature || i == itOrbDash;
} }
bool isProtectionOrb(eItem i) { bool isProtectionOrb(eItem i) {
@ -484,59 +529,72 @@ bool isEmpathyOrb(eItem i) {
return return
i == itOrbFire || i == itOrbDigging || i == itOrbWinter || i == itOrbFire || i == itOrbDigging || i == itOrbWinter ||
i == itOrbUndeath || i == itOrbSpeed || i == itOrbShield || i == itOrbUndeath || i == itOrbSpeed || i == itOrbShield ||
i == itOrbGhost || i == itOrbInvis || i == itOrbThorns || i == itOrbAether || i == itOrbInvis || i == itOrbThorns ||
i == itOrbWater; i == itOrbWater || i == itOrbStone;
} }
bool isUtilityOrb(eItem i) { bool isUtilityOrb(eItem i) {
return i == itOrbSpeed || i == itOrbDigging || return i == itOrbSpeed || i == itOrbDigging ||
i == itOrbSafety || i == itOrbTeleport || i == itOrbGhost || i == itOrbSafety || i == itOrbTeleport || i == itOrbAether ||
i == itOrbPreserve || i == itOrbTelekinesis || i == itOrbTime || i == itOrbSpace ||
i == itOrbSummon || i == itOrbLuck || i == itOrbEnergy; i == itOrbSummon || i == itOrbLuck || i == itOrbEnergy;
} }
bool isDirectionalOrb(eItem i) {
return i == itOrbHorns || i == itOrbBull;
}
bool isRevivalOrb(eItem i) {
return i == itOrbLife || i == itOrbFriend || i == itOrbUndeath;
}
bool isFriendOrb(eItem i) { bool isFriendOrb(eItem i) {
return i == itOrbLife || i == itOrbFriend || i == itOrbDiscord || i == itOrbLove || return i == itOrbLife || i == itOrbFriend || i == itOrbDiscord || i == itOrbLove ||
i == itOrbEmpathy || i == itOrbUndeath; i == itOrbEmpathy || i == itOrbUndeath;
} }
bool isFriendlyGhost(eMonster m) { bool isFriendlyGhost(eMonster m) {
return m == moFriendlyGhost || (markEmpathy(itOrbGhost) && isFriendly(m)); return m == moFriendlyGhost || (markEmpathy(itOrbAether) && isFriendly(m));
} }
bool isDragon(eMonster m) { return m == moDragonHead || m == moDragonTail; }
bool survivesWater(eMonster m) { bool survivesWater(eMonster m) {
return return
m == moShark || m == moGreaterShark || m == moCShark || m == moShark || m == moGreaterShark || m == moCShark ||
isGhost(m) || m == moWitchGhost || isGhost(m) || m == moWitchGhost || m == moShadow ||
isBird(m) || m == moWaterElemental || m == moAirElemental || isBird(m) || m == moWaterElemental || m == moAirElemental ||
isWorm(m) || isIvy(m) || isDragon(m) || isWorm(m) || isIvy(m) || isDragon(m) || isKraken(m) ||
m == moMutant || m == moFriendlyIvy ||
m == moTortoise; // Tortoises and Ivies survive, but don't go through water m == moTortoise; // Tortoises and Ivies survive, but don't go through water
} }
// flying even if stunned
bool isPermanentFlying(eMonster m) {
return m == moAirElemental || isGhost(m);
}
bool survivesFire(eMonster m) { bool survivesFire(eMonster m) {
return return
isGhost(m) || m == moWitchWinter || m == moWitchGhost || isGhost(m) || m == moWitchWinter || m == moWitchGhost ||
m == moBomberbird || m == moTameBomberbird || m == moTameBomberbirdMoved || m == moBomberbird || m == moTameBomberbird || m == moTameBomberbirdMoved ||
(isFriendly(m) && markOrb(itOrbWinter)) || isWorm(m) || m == moFireElemental || (isFriendly(m) && markOrb(itOrbWinter)) || isWorm(m) || m == moFireElemental ||
isDragon(m); isDragon(m) || m == moShadow;
} }
bool survivesMine(eMonster m) { /* bool survivesMine(eMonster m) {
return isFlying(m); return ignoresPlates(m) || isFlying(m);
} } */
bool survivesWall(eMonster m) { bool survivesWall(eMonster m) {
return isGhost(m); return isGhost(m);
} }
bool survivesThorns(eMonster m) { bool survivesThorns(eMonster m) {
return isGhost(m) || m == moSkeleton; return isGhost(m) || m == moSkeleton || m == moDraugr;
} }
bool survivesFall(eMonster m) { bool survivesFall(eMonster m) {
return isBird(m) || m == moAirElemental || m == moSkeleton || isDragon(m); return isBird(m) || m == moAirElemental || m == moSkeleton || isDragon(m) || m == moShadow ||
isGhost(m);
} }
bool isThorny(eWall w) { return w == waRose; } bool isThorny(eWall w) { return w == waRose; }
@ -547,9 +605,75 @@ bool checkOrb(eMonster m1, eItem orb) {
return false; return false;
} }
bool checkOrb2(eMonster m1, eItem orb) {
if(m1 == moPlayer) return markOrb2(orb);
if(isFriendly(m1)) return markEmpathy2(orb);
return false;
}
bool ignoresSmell(eMonster m) { bool ignoresSmell(eMonster m) {
return return
m == moHexSnake || isIvy(m) || isMutantIvy(m) || isGhostMover(m) || isSlimeMover(m) || m == moHexSnake || isIvy(m) || isMutantIvy(m) || isGhostMover(m) || isSlimeMover(m) ||
m == moRoseLady || checkOrb(m, itOrbSkunk) || checkOrb(m, itOrbGhost) || checkOrb(m, itOrbShield); m == moRoseLady || checkOrb(m, itOrbBeauty) || checkOrb(m, itOrbAether) || checkOrb(m, itOrbShield);
}
bool isTroll(eMonster m) {
return
m == moTroll || m == moRedTroll || m == moDarkTroll ||
m == moForestTroll || m == moStormTroll || m == moFjordTroll;
}
bool isGrave(eWall w) {
return w == waFreshGrave || w == waAncientGrave;
}
bool isTree(cell *c) {
return false; // c->wall == waBigTree || c->wall == waSmallTree;
}
bool highwall(cell *c) {
if(c->wall == waGlass) return false;
if(wmescher && wmspatial && c->wall == waBarrier && c->land == laOceanWall)
return false;
// if(wmspatial && isTree(c)) return false;
if(isGrave(c->wall)) return true;
return winf[c->wall].glyph == '#' || c->wall == waClosedGate;
}
int chasmgraph(cell *c) {
if(c->wall == waChasm) return 2;
if(isChasmy(c)) return 1;
if(isWateryOrBoat(c)) return 1;
if(wmescher && c->wall == waBarrier && c->land == laOceanWall) return 1;
if(c->wall == waReptileBridge) return 1;
return 0;
}
bool conegraph(cell *c) {
return wmescher && wmspatial && (c->wall == waDune || c->wall == waBigTree || c->wall == waSmallTree || c->wall == waCTree || (c->wall == waBarrier && c->land == laOceanWall));
}
bool isReptile(eWall w) {
return w == waReptile || w == waReptileBridge;
}
bool isBull(eMonster m) {
return m == moRagingBull || m == moHerdBull || m == moSleepBull;
}
bool hornStuns(cell *c) {
eMonster m = c->monst;
return
m == moRagingBull || m == moSleepBull || m == moHerdBull ||
m == moButterfly || m == moGreater || m == moGreaterM || m == moDraugr ||
m == moHedge || m == moFlailer || m == moVizier ||
attackJustStuns(c);
}
// generate all the world first in the quotient geometry
bool generateAll(eLand l) {
return
l == laIce || l == laDryForest || l == laCocytus || l == laLivefjord ||
l == laCaves || l == laCA;
} }

3780
game.cpp

File diff suppressed because it is too large Load Diff

View File

@ -4,21 +4,33 @@
// Copyright (C) 2011-2012 Zeno Rogue, see 'hyper.cpp' for details // Copyright (C) 2011-2012 Zeno Rogue, see 'hyper.cpp' for details
ld tessf, crossf, hexf, hcrossf; ld tessf, crossf, hexf, hcrossf, hexhexdist;
// tessf: distance from heptagon center to another heptagon center // tessf: distance from heptagon center to another heptagon center
// hexf: distance from heptagon center to heptagon vertex // hexf: distance from heptagon center to heptagon vertex
// crossf: distance from heptagon center to adjacent hexagon center // crossf: distance from heptagon center to adjacent hexagon center
// hexhexdist: distance between adjacent hexagon vertices
#define ALPHA (M_PI*2/7) #define ALPHA (M_PI*2/S7)
hyperpoint Crad[42]; hyperpoint Crad[42];
transmatrix heptmove[7], hexmove[7]; transmatrix heptmove[7], hexmove[7];
transmatrix invheptmove[7], invhexmove[7]; transmatrix invheptmove[7], invhexmove[7];
transmatrix spinmatrix[84];
const transmatrix& getspinmatrix(int id) {
while(id>=S84) id -= S84;
while(id<0) id += S84;
return spinmatrix[id];
}
// the results are: // the results are:
// hexf = 0.378077 hcrossf = 0.620672 tessf = 1.090550 // hexf = 0.378077 hcrossf = 0.620672 tessf = 1.090550
// hexhexdist = 0.566256
// the distance between two hexagon centers
void precalc() { void precalc() {
@ -31,15 +43,15 @@ void precalc() {
for(int p=0; p<100; p++) { for(int p=0; p<100; p++) {
ld f = (fmin+fmax) / 2; ld f = (fmin+fmax) / 2;
hyperpoint H = xpush(f) * C0; hyperpoint H = xpush(f) * C0;
ld v1 = intval(H, C0), v2 = intval(H, spin(2*M_PI/7)*H); ld v1 = intval(H, C0), v2 = intval(H, spin(2*M_PI/S7)*H);
if(v1 > v2) fmin = f; else fmax = f; if(sphere ? v1 < v2 : v1 > v2) fmin = f; else fmax = f;
} }
tessf = fmin; tessf = fmin;
fmin = 0, fmax = 2; fmin = 0, fmax = sphere ? M_PI / 2 : 2;
for(int p=0; p<100; p++) { for(int p=0; p<100; p++) {
ld f = (fmin+fmax) / 2; ld f = (fmin+fmax) / 2;
hyperpoint H = spin(M_PI/7) * xpush(f) * C0; hyperpoint H = spin(M_PI/S7) * xpush(f) * C0;
ld v1 = intval(H, C0), v2 = intval(H, xpush(tessf) * C0); ld v1 = intval(H, C0), v2 = intval(H, xpush(tessf) * C0);
if(v1 < v2) fmin = f; else fmax = f; if(v1 < v2) fmin = f; else fmax = f;
} }
@ -50,7 +62,7 @@ void precalc() {
for(int p=0; p<100; p++) { for(int p=0; p<100; p++) {
ld f = (fmin+fmax) / 2; ld f = (fmin+fmax) / 2;
hyperpoint H = xpush(f) * C0; hyperpoint H = xpush(f) * C0;
hyperpoint H1 = spin(2*M_PI/7) * H; hyperpoint H1 = spin(2*M_PI/S7) * H;
hyperpoint H2 = xpush(tessf-f) * C0; hyperpoint H2 = xpush(tessf-f) * C0;
ld v1 = intval(H, H1), v2 = intval(H, H2); ld v1 = intval(H, H1), v2 = intval(H, H2);
if(v1 < v2) fmin = f; else fmax = f; if(v1 < v2) fmin = f; else fmax = f;
@ -59,84 +71,180 @@ void precalc() {
// printf("hexf = %.6Lf cross = %.6Lf tessf = %.6Lf\n", hexf, crossf, tessf); // printf("hexf = %.6Lf cross = %.6Lf tessf = %.6Lf\n", hexf, crossf, tessf);
for(int i=0; i<42; i++) for(int i=0; i<S42; i++)
Crad[i] = spin(2*M_PI*i/42) * xpush(.4) * C0; Crad[i] = spin(2*M_PI*i/S42) * xpush(.4) * C0;
for(int d=0; d<7; d++) for(int d=0; d<S7; d++)
heptmove[d] = spin(-d * ALPHA) * xpush(tessf) * spin(M_PI); heptmove[d] = spin(-d * ALPHA) * xpush(tessf) * spin(M_PI);
for(int d=0; d<7; d++) for(int d=0; d<S7; d++)
hexmove[d] = spin(-d * ALPHA) * xpush(-crossf)* spin(M_PI); hexmove[d] = spin(-d * ALPHA) * xpush(-crossf)* spin(M_PI);
for(int d=0; d<7; d++) invheptmove[d] = inverse(heptmove[d]); for(int d=0; d<S7; d++) invheptmove[d] = inverse(heptmove[d]);
for(int d=0; d<7; d++) invhexmove[d] = inverse(hexmove[d]); for(int d=0; d<S7; d++) invhexmove[d] = inverse(hexmove[d]);
hexhexdist = hdist(xpush(crossf) * C0, spin(M_PI*2/S7) * xpush(crossf) * C0);
for(int i=0; i<S84; i++) spinmatrix[i] = spin(i * M_PI / S42);
} }
transmatrix ddi(ld dir, ld dist) { transmatrix ddi(ld dir, ld dist) {
// EUCLIDEAN
if(euclid) if(euclid)
return eupush(cos(M_PI*dir/42) * dist, -sin(M_PI*dir/42) * dist); return eupush(cos(M_PI*dir/S42) * dist, -sin(M_PI*dir/S42) * dist);
else else
return spin(M_PI*dir/42) * xpush(dist) * spin(-M_PI*dir/42); return spin(M_PI*dir/S42) * xpush(dist) * spin(-M_PI*dir/S42);
} }
// tesselation drawing hyperpoint ddi0(ld dir, ld dist) {
if(euclid)
return hpxy(cos(M_PI*dir/S42) * dist, -sin(M_PI*dir/S42) * dist);
else
return xspinpush0(M_PI*dir/S42, dist);
}
#define NUMFACE 500 namespace geom3 {
transmatrix tess[NUMFACE];
void genTesselation() { int tc_alpha=3, tc_depth=1, tc_camera=2;
int N = 1;
tess[0] = Id; ld depth = 1; // world below the plane
for(int i=0; i<N; i++) { ld camera = 1; // camera above the plane
for(int t=0; t<7; t++) { ld wall_height = .3;
ld trot = (t % 8) * M_PI * 2 / 7.0; ld slev = .08;
transmatrix T = spin(trot) * xpush(tessf) * /*spin(-trot) */ spin(M_PI) * tess[i]; ld lake_top = .25, lake_bottom = .9;
for(int j=0; j<N; j++) if(intval(T*C0, tess[j]*C0) < 0.1) goto nextt; ld rock_wall_ratio = .9;
// printf("%d:%d -> %d\n", i,t, N); ld human_wall_ratio = .7;
tess[N] = T; N++; ld human_height;
if(N == NUMFACE) return;
nextt: ; ld highdetail = 8, middetail = 8;
// Here we convert between the following parameters:
// abslev: level below the plane
// lev: level above the world (abslev = depth-lev)
// projection: projection parameter
// factor: zoom factor
ld abslev_to_projection(ld abslev) {
if(sphere || euclid) return camera+abslev;
return tanh(abslev) / tanh(camera);
}
ld projection_to_abslev(ld proj) {
if(sphere || euclid) return proj-camera;
// tanh(abslev) / tanh(camera) = proj
return atanh(proj * tanh(camera));
}
ld lev_to_projection(ld lev) {
return abslev_to_projection(depth - lev);
}
ld projection_to_factor(ld proj) {
return lev_to_projection(0) / proj;
}
ld factor_to_projection(ld fac) {
return lev_to_projection(0) / fac;
}
ld lev_to_factor(ld lev) {
return projection_to_factor(lev_to_projection(lev));
}
ld factor_to_lev(ld fac) {
return depth - projection_to_abslev(factor_to_projection(fac));
}
// how should we scale at level lev
ld scale_at_lev(ld lev) {
if(sphere || euclid) return 1;
return cosh(depth - lev);
}
ld INFDEEP, BOTTOM, HELLSPIKE, LAKE, WALL,
SLEV[4], FLATEYE,
LEG1, LEG, LEG3, GROIN, GROIN1, GHOST,
BODY, NECK1, NECK, NECK3, HEAD,
ABODY, AHEAD, BIRD;
string invalid;
void compute() {
// tanh(depth) / tanh(camera) == vid.alpha
invalid = "";
if(tc_alpha < tc_depth && tc_alpha < tc_camera)
vid.alpha = tanh(depth) / tanh(camera);
else if(tc_depth < tc_alpha && tc_depth < tc_camera) {
ld v = vid.alpha * tanh(camera);
if(v<-1 || v>1) invalid = "cannot adjust depth", depth = camera;
else depth = atanh(v);
} }
} else {
} ld v = tanh(depth) / vid.alpha;
if(v<-1 || v>1) invalid = "cannot adjust camera", camera = depth;
struct ltd { else camera = atanh(v);
hyperpoint P1; }
hyperpoint P2;
int col; if(fabs(vid.alpha) < 1e-6) invalid = "does not work with perfect Klein";
};
vector<ltd> lines;
void addline(hyperpoint P1, hyperpoint P2, int col) {
ltd L;
L.P1 = P1; L.P2 = P2; L.col = col;
lines.push_back(L);
}
void addlines() {
// change the if(0) conditions to see the underlying structure
if(0) for(int t =0; t<NUMFACE; t++) for(int u=1; u<8; u++) { if(invalid != "") {
addline(View * tess[t] * C0, View * tess[t] * tess[u] * C0, u==1 ? 0xA000 : 0x4000); INFDEEP = .7;
} BOTTOM = .8;
HELLSPIKE = .85;
if(0) for(int t =0; t<NUMFACE; t++) for(int r=0; r<7; r++) { LAKE = .9;
addline( WALL = 1.25;
View * tess[t] * spin((2*r+1)*M_PI/7) * xpush(crossf) * C0, SLEV[0] = 1;
View * tess[t] * spin((2*r+3)*M_PI/7) * xpush(crossf) * C0, SLEV[1] = 1.08;
0x808080); SLEV[2] = 1.16;
} SLEV[3] = 1.24;
FLATEYE = 1.03;
if(1) for(int t =0; t<NUMFACE; t++) for(int r=0; r<7; r++) { LEG1 = 1.025;
addline(tess[t] * spin(M_PI*2*(r+1)/7) * xpush(hexf) * C0, tess[t] * spin(M_PI*2*r/7) * xpush(hexf) * C0, 0x404040); LEG = 1.05;
addline(tess[t] * spin(M_PI*2*r/7) * xpush(hexf) * C0, tess[t] * spin(M_PI*2*r/7) * xpush(tessf/2) * C0, 0x404040); LEG3 = 1.075;
} GROIN = 1.09;
GROIN1 = 1.105;
GHOST = 1.1;
BODY = 1.15;
NECK1 = 1.16;
NECK = 1.17;
NECK3 = 1.18;
HEAD = 1.19;
ABODY = 1.08;
AHEAD = 1.12;
BIRD = 1.20;
}
else {
INFDEEP = (euclid || sphere) ? 0.01 : lev_to_projection(0) * tanh(camera);
WALL = lev_to_factor(wall_height);
human_height = human_wall_ratio * wall_height;
LEG1 = lev_to_factor(human_height * .1);
LEG = lev_to_factor(human_height * .2);
LEG3 = lev_to_factor(human_height * .3);
GROIN = lev_to_factor(human_height * .4);
GROIN1= lev_to_factor(human_height * .5);
BODY = lev_to_factor(human_height * .6);
NECK1 = lev_to_factor(human_height * .7);
NECK = lev_to_factor(human_height * .8);
NECK3 = lev_to_factor(human_height * .9);
HEAD = lev_to_factor(human_height);
ABODY = lev_to_factor(human_height * .4);
AHEAD = lev_to_factor(human_height * .6);
BIRD = lev_to_factor((human_wall_ratio+1)/2 * wall_height * .8);
GHOST = lev_to_factor(human_height * .5);
FLATEYE = lev_to_factor(human_height * .15);
slev = rock_wall_ratio * wall_height / 3;
for(int s=0; s<=3; s++)
SLEV[s] = lev_to_factor(rock_wall_ratio * wall_height * s/3);
LAKE = lev_to_factor(-lake_top);
HELLSPIKE = lev_to_factor(-(lake_top+lake_bottom)/2);
BOTTOM = lev_to_factor(-lake_bottom);
}
}
} }
void initgeo() { void initgeo() {
// printf("%Lf\n", (ld) hdist0(xpush(-1)*ypush(0.01)*xpush(1)*C0));
precalc(); precalc();
genTesselation();
addlines();
} }

7916
graph.cpp

File diff suppressed because it is too large Load Diff

View File

@ -4,24 +4,42 @@
// heptagon here refers to underlying heptagonal tesselation // heptagon here refers to underlying heptagonal tesselation
// (which you can see by changing the conditions in graph.cpp) // (which you can see by changing the conditions in graph.cpp)
// automaton state #define MIRR(x) x.mirrored
enum hstate { hsOrigin, hsA, hsB, hsError };
int fixrot(int a) { return (a+98)% 7; } // automaton state
int fix42(int a) { return (a+420)% 42; } enum hstate { hsOrigin, hsA, hsB, hsError, hsA0, hsA1, hsB0, hsB1, hsC };
int fixrot(int a) { return (a+490)% S7; }
int fix42(int a) { return (a+420)% S42; }
struct heptagon; struct heptagon;
struct cell; struct cell;
cell *newCell(int type, heptagon *master); cell *newCell(int type, heptagon *master);
#define CDATA // spintable functions
int tspin(uint32_t& t, int d) {
return (t >> (d<<2)) & 7;
}
int tmirror(uint32_t& t, int d) {
return (t >> ((d<<2)+3)) & 1;
}
void tsetspin(uint32_t& t, int d, int spin) {
t &= ~(15 << (d<<2));
t |= spin << (d<<2);
}
struct heptagon { struct heptagon {
// automaton state // automaton state
hstate s : 8; hstate s : 8;
// we are spin[i]-th neighbor of move[i] // we are spin[i]-th neighbor of move[i]
unsigned char spin[7]; uint32_t spintable;
int spin(int d) { return tspin(spintable, d); }
int mirror(int d) { return tmirror(spintable, d); }
void setspin(int d, int sp) { tsetspin(spintable, d, sp); }
// neighbors; move[0] always goes towards origin, // neighbors; move[0] always goes towards origin,
// and then we go clockwise // and then we go clockwise
heptagon* move[7]; heptagon* move[7];
@ -33,18 +51,18 @@ struct heptagon {
short fiftyval; short fiftyval;
// zebra generator (1B actually) // zebra generator (1B actually)
short zebraval; short zebraval;
#ifdef CDATA // field id
int fieldval;
// evolution data // evolution data
short rval0, rval1; short rval0, rval1;
struct cdata *cdata; struct cdata *cdata;
#endif
// central cell // central cell
cell *c7; cell *c7;
// associated generator of alternate structure, for Camelot and horocycles // associated generator of alternate structure, for Camelot and horocycles
heptagon *alt; heptagon *alt;
// functions // functions
heptagon*& modmove(int i) { return move[fixrot(i)]; } heptagon*& modmove(int i) { return move[fixrot(i)]; }
unsigned char& gspin(int i) { return spin[fixrot(i)]; } unsigned char gspin(int i) { return spin(fixrot(i)); }
}; };
// the automaton is used to generate each heptagon in an unique way // the automaton is used to generate each heptagon in an unique way
@ -54,15 +72,32 @@ struct heptagon {
// and sometimes in direction 5 // and sometimes in direction 5
hstate transition(hstate s, int dir) { hstate transition(hstate s, int dir) {
if(s == hsOrigin) return hsA; if(sphere) {
if(s == hsA && dir >= 3 && dir <= 4) return hsA; if(S7 == 4) {
if(s == hsA && dir == 5) return hsB; if(s == hsOrigin) return dir == 0 ? hsB0 : hsB1;
if(s == hsB && dir == 4) return hsB; }
if(s == hsB && dir == 3) return hsA; if(S7 == 3) {
if(s == hsOrigin) return hsB1;
}
if(s == hsOrigin) return dir == 0 ? hsA0 : hsA1;
if(s == hsA0 && dir == 2) return hsB0;
if(s == hsA1 && dir == 2) return hsB1;
if(s == hsB0 && dir == S7-2) return hsC;
return hsError;
}
else {
if(s == hsOrigin) return hsA;
if(s == hsA && dir >= 3 && dir <= 4) return hsA;
if(s == hsA && dir == 5) return hsB;
if(s == hsB && dir == 4) return hsB;
if(s == hsB && dir == 3) return hsA;
}
return hsError; return hsError;
} }
heptagon origin; heptagon dodecahedron[12];
#define origin (dodecahedron[0])
vector<heptagon*> allAlts; vector<heptagon*> allAlts;
// create h->move[d] if not created yet // create h->move[d] if not created yet
@ -74,16 +109,16 @@ heptagon *buildHeptagon(heptagon *parent, int d, hstate s, int pard = 0) {
h->alt = NULL; h->alt = NULL;
h->s = s; h->s = s;
for(int i=0; i<7; i++) h->move[i] = NULL; for(int i=0; i<7; i++) h->move[i] = NULL;
h->move[pard] = parent; h->spin[pard] = d; h->spintable = 0;
parent->move[d] = h; parent->spin[d] = pard; h->move[pard] = parent; tsetspin(h->spintable, pard, d);
parent->move[d] = h; tsetspin(parent->spintable, d, pard);
if(parent->c7) { if(parent->c7) {
h->c7 = newCell(7, h); h->c7 = newCell(7, h);
h->emeraldval = emerald_heptagon(parent->emeraldval, d); h->emeraldval = emerald_heptagon(parent->emeraldval, d);
h->zebraval = zebra_heptagon(parent->zebraval, d); h->zebraval = zebra_heptagon(parent->zebraval, d);
#ifdef CDATA h->fieldval = fp43.connections[fieldpattern::btspin(parent->fieldval, d)];
h->rval0 = h->rval1 = 0; h->cdata = NULL; h->rval0 = h->rval1 = 0; h->cdata = NULL;
#endif if(parent == &origin || parent == origin.alt)
if(parent == &origin)
h->fiftyval = fiftytable[0][d]; h->fiftyval = fiftytable[0][d];
else else
h->fiftyval = nextfiftyval(parent->fiftyval, parent->move[0]->fiftyval, d); h->fiftyval = nextfiftyval(parent->fiftyval, parent->move[0]->fiftyval, d);
@ -98,10 +133,10 @@ heptagon *buildHeptagon(heptagon *parent, int d, hstate s, int pard = 0) {
if(pard == 0) { if(pard == 0) {
if(purehepta) h->distance = parent->distance + 1; if(purehepta) h->distance = parent->distance + 1;
else if(parent->s == hsOrigin) h->distance = 2; else if(parent->s == hsOrigin) h->distance = 2;
else if(h->spin[0] == 5) else if(h->spin(0) == 5)
h->distance = parent->distance + 1; h->distance = parent->distance + 1;
else if(h->spin[0] == 4 && h->move[0]->s == hsB) else if(h->spin(0) == 4 && h->move[0]->s == hsB)
h->distance = createStep(h->move[0], (h->spin[0]+2)%7)->distance + 3; h->distance = createStep(h->move[0], (h->spin(0)+2)%7)->distance + 3;
else h->distance = parent->distance + 2; else h->distance = parent->distance + 2;
} }
else h->distance = parent->distance - (purehepta?1:2); else h->distance = parent->distance - (purehepta?1:2);
@ -112,9 +147,9 @@ void addSpin(heptagon *h, int d, heptagon *from, int rot, int spin) {
rot = fixrot(rot); rot = fixrot(rot);
createStep(from, rot); createStep(from, rot);
h->move[d] = from->move[rot]; h->move[d] = from->move[rot];
h->spin[d] = fixrot(from->spin[rot] + spin); h->setspin(d, fixrot(from->spin(rot) + spin));
h->move[d]->move[fixrot(from->spin[rot] + spin)] = h; h->move[d]->move[fixrot(from->spin(rot) + spin)] = h;
h->move[d]->spin[fixrot(from->spin[rot] + spin)] = d; h->move[d]->setspin(fixrot(from->spin(rot) + spin), d);
//generateEmeraldval(h->move[d]); generateEmeraldval(h); //generateEmeraldval(h->move[d]); generateEmeraldval(h);
} }
@ -122,7 +157,7 @@ extern int hrand(int);
heptagon *createStep(heptagon *h, int d) { heptagon *createStep(heptagon *h, int d) {
d = fixrot(d); d = fixrot(d);
if(h->s != hsOrigin && !h->move[0]) { if(!h->move[0] && h->s != hsOrigin) {
buildHeptagon(h, 0, hsA, 3 + hrand(2)); buildHeptagon(h, 0, hsA, 3 + hrand(2));
} }
if(h->move[d]) return h->move[d]; if(h->move[d]) return h->move[d];
@ -130,18 +165,18 @@ heptagon *createStep(heptagon *h, int d) {
buildHeptagon(h, d, hsA); buildHeptagon(h, d, hsA);
} }
else if(d == 1) { else if(d == 1) {
addSpin(h, d, h->move[0], h->spin[0]-1, -1); addSpin(h, d, h->move[0], h->spin(0)-1, -1);
} }
else if(d == 6) { else if(d == 6) {
addSpin(h, d, h->move[0], h->spin[0]+1, +1); addSpin(h, d, h->move[0], h->spin(0)+1, +1);
} }
else if(d == 2) { else if(d == 2) {
createStep(h->move[0], h->spin[0]-1); createStep(h->move[0], h->spin(0)-1);
addSpin(h, d, h->move[0]->modmove(h->spin[0]-1), 5 + h->move[0]->gspin(h->spin[0]-1), -1); addSpin(h, d, h->move[0]->modmove(h->spin(0)-1), 5 + h->move[0]->gspin(h->spin(0)-1), -1);
} }
else if(d == 5 && h->s == hsB) { else if(d == 5 && h->s == hsB) {
createStep(h->move[0], h->spin[0]+1); createStep(h->move[0], h->spin(0)+1);
addSpin(h, d, h->move[0]->modmove(h->spin[0]+1), 2 + h->move[0]->gspin(h->spin[0]+1), +1); addSpin(h, d, h->move[0]->modmove(h->spin(0)+1), 2 + h->move[0]->gspin(h->spin(0)+1), +1);
} }
else else
buildHeptagon(h, d, (d == 5 || (h->s == hsB && d == 4)) ? hsB : hsA); buildHeptagon(h, d, (d == 5 || (h->s == hsB && d == 4)) ? hsB : hsA);
@ -153,20 +188,24 @@ heptagon *createStep(heptagon *h, int d) {
struct heptspin { struct heptspin {
heptagon *h; heptagon *h;
int spin; int spin;
bool mirrored;
heptspin() { mirrored = false; }
}; };
heptspin hsstep(const heptspin &hs, int spin) { heptspin hsstep(const heptspin &hs, int spin) {
createStep(hs.h, hs.spin); createStep(hs.h, hs.spin);
heptspin res; heptspin res;
res.h = hs.h->move[hs.spin]; res.h = hs.h->move[hs.spin];
res.spin = fixrot(hs.h->spin[hs.spin] + spin); res.mirrored = hs.mirrored ^ hs.h->mirror(hs.spin);
res.spin = fixrot(hs.h->spin(hs.spin) + (MIRR(res)?-spin:spin));
return res; return res;
} }
heptspin hsspin(const heptspin &hs, int val) { heptspin hsspin(const heptspin &hs, int val) {
heptspin res; heptspin res;
res.h = hs.h; res.h = hs.h;
res.spin = fixrot(hs.spin + val); res.spin = fixrot(hs.spin + (MIRR(hs)?-val:val));
res.mirrored = hs.mirrored;
return res; return res;
} }
@ -174,7 +213,7 @@ heptspin hsspin(const heptspin &hs, int val) {
void backtrace(heptagon *pos) { void backtrace(heptagon *pos) {
if(pos == &origin) return; if(pos == &origin) return;
backtrace(pos->move[0]); backtrace(pos->move[0]);
printf(" %d", pos->spin[0]); printf(" %d", pos->spin(0));
} }
void hsshow(const heptspin& t) { void hsshow(const heptspin& t) {

582
hyper.cpp
View File

@ -15,46 +15,17 @@
// along with this program; if not, write to the Free Software // along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifdef LOCAL
#define CDATA
#endif
#define VER "8.3j"
#define VERNUM 8310
#define VERNUM_HEX 0x8310
#define ISANDROID 0 #define ISANDROID 0
#define ISMOBILE 0 #define ISMOBILE 0
#define ISIOS 0 #define ISIOS 0
#define USE_SDL
#define USE_COMMANDLINE
#include <stdio.h> #ifdef STEAM
#define NOLICENSE
#include <SDL/SDL.h>
#ifndef MAC
#undef main
#endif #endif
#include <SDL/SDL_ttf.h> #include "init.cpp"
#include <math.h>
#include <time.h>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
FILE *debugfile;
int debugflags;
const char *scorefile = "hyperrogue.log";
const char *conffile = "hyperrogue.ini";
string levelfile = "hyperrogue.lev";
string picfile = "hyperrogue.pic";
const char *loadlevel = NULL;
const char *musicfile = "";
#ifdef LINUX #ifdef LINUX
#include <sys/resource.h> #include <sys/resource.h>
@ -77,58 +48,29 @@ void moreStack() {
} }
#endif #endif
string s0; eLand readland(const char *s) {
void addMessage(string s, char spamtype = 0); string ss = s;
if(ss == "II") return laCrossroads2;
if(ss == "III") return laCrossroads3;
if(ss == "IV") return laCrossroads4;
if(ss == "V") return laCrossroads5;
for(int l=0; l<landtypes; l++) if(strstr(linf[l].name, s) != NULL) {
return eLand(l);
break;
}
return laNone;
}
int clWidth, clHeight, clFont; eItem readItem(const char *s) {
string commandline; string ss = s;
for(int i=0; i<ittypes; i++) if(strstr(iinf[i].name, s) != NULL) {
#include "hyperpoint.cpp" return eItem(i);
#include "patterns.cpp" break;
#include "heptagon.cpp" }
#include "classes.cpp" return itNone;
#include "language.cpp" }
#ifdef STEAM
#define NOLICENSE
#endif
#include "hyper.h"
#include "cell.cpp"
#include "flags.cpp"
#include "yendor.cpp"
#include "complex.cpp"
#include "game.cpp"
#include "landgen.cpp"
#include "orbs.cpp"
#include "system.cpp"
// #include "patterngen.cpp"
#include "geometry.cpp"
#include "polygons.cpp"
#ifndef MOBILE
#include "mapeditor.cpp"
#endif
#include "netgen.cpp"
#include "graph.cpp"
#include "achievement.cpp"
#include <unistd.h>
int main(int argc, char **argv) {
#ifdef LINUX
moreStack();
#endif
void initializeCLI() {
printf("HyperRogue by Zeno Rogue <zeno@attnam.com>, version " VER "\n"); printf("HyperRogue by Zeno Rogue <zeno@attnam.com>, version " VER "\n");
#ifndef NOLICENSE #ifndef NOLICENSE
@ -136,208 +78,290 @@ int main(int argc, char **argv) {
printf("comes with absolutely no warranty; see COPYING for details\n"); printf("comes with absolutely no warranty; see COPYING for details\n");
#endif #endif
// printf("cell size = %d\n", int(sizeof(cell)));
srand(time(NULL));
shrand(time(NULL));
#ifdef FHS #ifdef FHS
char sbuf[640], cbuf[640]; static string sbuf, cbuf;
if(getenv("HOME")) { if(getenv("HOME")) {
snprintf(sbuf, 640, "%s/.%s", getenv("HOME"), scorefile); scorefile = sbuf; sbuf = getenv("HOME"); sbuf += "/."; sbuf += scorefile;
snprintf(cbuf, 640, "%s/.%s", getenv("HOME"), conffile); conffile = cbuf; cbuf = getenv("HOME"); cbuf += "/."; cbuf += conffile;
scorefile = sbuf.c_str();
conffile = cbuf.c_str();
} }
#endif #endif
}
for(int i=1; i<argc; i++) { int arg::readCommon() {
if(strcmp(argv[i], "-c") == 0 && i != argc-1) {conffile = argv[i+1]; i++;} if(argis("-c")) { PHASE(1); shift(); conffile = args(); }
else if(strcmp(argv[i], "-s") == 0 && i != argc-1) {scorefile = argv[i+1]; i++;} else if(argis("-s")) { PHASE(1); shift(); scorefile = args(); }
else if(strcmp(argv[i], "-m") == 0 && i != argc-1) {musicfile = argv[i+1]; i++;} else if(argis("-m")) { PHASE(1); shift(); musicfile = args(); }
else if(strcmp(argv[i], "-lev") == 0 && i != argc-1) {levelfile = argv[i+1]; i++;} else if(argis("-se")) { PHASE(1); shift(); wheresounds = args(); }
else if(strcmp(argv[i], "-pic") == 0 && i != argc-1) {picfile = argv[i+1]; i++;} #ifndef NOEDIT
else if(strcmp(argv[i], "-load") == 0 && i != argc-1) {loadlevel = argv[i+1]; i++;} else if(argis("-lev")) { shift(); levelfile = args(); }
// else if(strcmp(argv[i], "-P") == 0 && i != argc-1) {par = atoi(argv[i+1]); i++;} else if(argis("-pic")) { shift(); picfile = args(); }
else if(strcmp(argv[i], "-W") == 0 && i != argc-1) { else if(argis("-load")) { PHASE(3); shift(); mapstream::loadMap(loadlevel); }
for(int l=0; l<landtypes; l++) if(strstr(linf[l].name, argv[i+1]) != NULL) {
firstland = euclidland = eLand(l);
break;
}
i++;
}
else if(strcmp(argv[i], "-L") == 0) {
printf("Treasures:\n");
for(int i=1; i<ittypes; i++)
if(itemclass(eItem(i)) == IC_TREASURE)
printf(" %s\n", iinf[i].name);
printf("\n");
printf("Orbs:\n");
for(int i=1; i<ittypes; i++)
if(itemclass(eItem(i)) == IC_ORB)
printf(" %s\n", iinf[i].name);
printf("\n");
printf("Other items:\n");
for(int i=1; i<ittypes; i++)
if(itemclass(eItem(i)) == IC_OTHER)
printf(" %s\n", iinf[i].name);
printf("\n");
printf("Monsters:\n");
for(int i=1; i<motypes; i++)
printf(" %s\n", minf[i].name);
printf("\n");
printf("Lands:\n");
for(int i=1; i<landtypes; i++)
printf(" %s\n", linf[i].name);
printf("\n");
printf("Walls:\n");
for(int i=0; i<walltypes; i++)
printf(" %s\n", winf[i].name);
printf("\n");
exit(0);
}
else if(strcmp(argv[i], "-f") == 0) { commandline += "f"; }
else if(strcmp(argv[i], "-w") == 0) { commandline += "w"; }
else if(strcmp(argv[i], "-e") == 0) { commandline += "e"; }
else if(strcmp(argv[i], "-a") == 0) { commandline += "a"; }
else if(strcmp(argv[i], "-p") == 0) { commandline += "p"; }
else if(strcmp(argv[i], "-7") == 0) { commandline += "7"; }
else if(strcmp(argv[i], "-C") == 0) { commandline += "C"; }
else if(strcmp(argv[i], "-o") == 0) { commandline += "o"; }
else if(strcmp(argv[i], "-o0") == 0) { commandline += char(200); }
else if(strcmp(argv[i], "-o1") == 0) { commandline += char(201); }
else if(strcmp(argv[i], "-E") == 0) { commandline += "E"; }
else if(strcmp(argv[i], "-S") == 0) { commandline += "S"; }
else if(strcmp(argv[i], "-H") == 0) { commandline += "H"; }
else if(strcmp(argv[i], "-P1") == 0) { commandline += "P1"; }
else if(strcmp(argv[i], "-P2") == 0) { commandline += "P2"; }
else if(strcmp(argv[i], "-P3") == 0) { commandline += "P3"; }
else if(strcmp(argv[i], "-P4") == 0) { commandline += "P4"; }
else if(strcmp(argv[i], "-T") == 0) { commandline += "T"; }
else if(strcmp(argv[i], "-R") == 0) { commandline += "R"; }
else if(strcmp(argv[i], "-D") == 0) { commandline += "D"; }
else if(strcmp(argv[i], "-PM1") == 0) { pmodel = 1; }
else if(strcmp(argv[i], "-PM2") == 0) { pmodel = 2; }
else if(strcmp(argv[i], "-offline") == 0) offlineMode = true;
else if(strcmp(argv[i], "-debugf") == 0) {
debugfile = fopen("hyperrogue-debug.txt", "w");
debugflags = atoi(argv[i+1]);
i++;
}
else if(strcmp(argv[i], "-debuge") == 0) {
debugfile = stderr;
debugflags = atoi(argv[i+1]);
i++;
}
#ifdef LOCAL
else if(strcmp(argv[i], "-auto") == 0) doAutoplay = true;
#endif #endif
else if(strcmp(argv[i], "-ch") == 0) { autocheat = true; } else if(argis("-canvas")) {
else if(strcmp(argv[i], "-Y") == 0) { firstland = euclidland = laCanvas;
yendor::on = true; shift();
yendor::challenge = atoi(argv[i+1]); if(args()[1] == 0) mapeditor::whichCanvas = args()[0];
i++; else mapeditor::canvasback = strtol(args(), NULL, 16);
} }
else if(strcmp(argv[i], "-r") == 0) { else if(argis("-back")) {
i++; shift(); backcolor = strtol(args(), NULL, 16);
sscanf(argv[i], "%dx%dx%d", &clWidth, &clHeight, &clFont); }
} else if(argis("-W2")) {
else if(strcmp(argv[i], "--version") == 0 || strcmp(argv[i], "-v") == 0) { shift(); cheatdest = readland(args()); autocheat = true;
printf("HyperRogue version " VER "\n"); }
exit(0); else if(argis("-W")) {
} shift(); firstland = euclidland = readland(args());
else if(strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) { }
printf("Press F1 while playing to get ingame options.\n\n"); else if(argis("-I")) {
printf("HyperRogue accepts the following command line options:\n"); PHASE(3) cheater++; timerghost = false;
printf(" -c FILE - use the specified configuration file\n"); shift(); eItem i = readItem(args());
printf(" -s FILE - use the specified highscore file\n"); shift(); items[i] = argi();
printf(" -m FILE - use the specified soundtrack (music)\n"); }
printf(" -lev FILE - use the specified filename for the map editor (without loading)\n"); else if(argis("-L")) {
printf(" -load FILE - use the specified filename for the map editor\n"); printf("Treasures:\n");
printf(" --version, -v - show the version number\n"); for(int i=1; i<ittypes; i++)
printf(" --help, -h - show the commandline options\n"); if(itemclass(eItem(i)) == IC_TREASURE)
printf(" -f, -w - start in the fullscreen or windowed mode\n"); printf(" %s\n", iinf[i].name);
printf(" -e, -a, -p - start in the Escher, ASCII, or Plain mode\n"); printf("\n");
printf(" -r WxHxF - use the given resolution and font size\n"); printf("Orbs:\n");
printf(" -o - switch the OpenGL mode\n"); for(int i=1; i<ittypes; i++)
printf(" -o0 - switch the OpenGL mode off\n"); if(itemclass(eItem(i)) == IC_ORB)
printf(" -o1 - switch the OpenGL mode on\n"); printf(" %s\n", iinf[i].name);
printf(" -W LAND - start in the given land (cheat)\n"); printf("\n");
printf(" -ch - auto-enable cheat mode\n"); printf("Other items:\n");
printf(" -E - switch Euclidean\n"); for(int i=1; i<ittypes; i++)
printf(" -S - switch Shmup\n"); if(itemclass(eItem(i)) == IC_OTHER)
printf(" -Pn - switch Shmup number of players (n=1..4)\n"); printf(" %s\n", iinf[i].name);
printf(" -H - switch Hardcore\n"); printf("\n");
printf(" -T - switch Tactical\n"); printf("Monsters:\n");
printf(" -7 - switch heptagonal mode\n"); for(int i=1; i<motypes; i++)
printf(" -C - switch Chaos mode\n"); printf(" %s\n", minf[i].name);
printf(" -R - switch Random Pattern\n"); printf("\n");
printf(" -Y id - switch Yendor, level id\n"); printf("Lands:\n");
printf(" -D - disable all the special game modes\n"); for(int i=1; i<landtypes; i++)
printf(" -L - list of features\n"); printf(" %s\n", linf[i].name);
printf(" -debugf 7 - output debugging information to hyperrogue-debug.txt\n"); printf("\n");
printf(" -debuge 7 - output debugging information to stderr\n"); printf("Walls:\n");
printf(" -offline - don't connect to Steam (for Steam versions)\n"); for(int i=0; i<walltypes; i++)
exit(0); printf(" %s\n", winf[i].name);
} printf("\n");
else { exit(0);
printf("Unknown option: %s\n", argv[i]); }
else if(argis("-wm")) { PHASE(2); vid.wallmode = argi(); }
else if(argis("-mm")) { PHASE(2); vid.monmode = argi(); }
#define TOGGLE(x, param) \
else if(args()[0] == '-' && args()[1] == x && !args()[2]) { PHASE(2); param = !param; } \
else if(args()[0] == '-' && args()[1] == x && args()[2] == '1') { PHASE(2); param = true; } \
else if(args()[0] == '-' && args()[1] == x && args()[2] == '0') { PHASE(2); param = false; }
TOGGLE('o', vid.usingGL)
TOGGLE('C', chaosmode)
TOGGLE('7', purehepta)
TOGGLE('f', vid.full)
TOGGLE('T', tactic::on)
TOGGLE('S', shmup::on)
TOGGLE('H', hardcore)
TOGGLE('R', randomPatternsMode)
else if(argis("-geo")) { PHASE(2); shift(); geometry = targetgeometry = (eGeometry) argi(); }
else if(argis("-qs")) {
autocheat = true;
shift(); fp43.qpaths.push_back(args());
}
else if(argis("-fix")) {
fixseed = true; autocheat = true;
}
else if(argis("-qpar")) {
int p;
shift(); sscanf(args(), "%d,%d,%d",
&p, &quotientspace::rvadd, &quotientspace::rvdir
);
autocheat = true;
fp43.init(p);
}
else if(argis("-cs")) {
shift();
fieldpattern::matrix M = fp43.strtomatrix(args());
fieldpattern::subpathid = fp43.matcode[M];
fieldpattern::subpathorder = fp43.order(M);
autocheat = true;
}
else if(argis("-csp")) {
autocheat = true;
fp43.findsubpath();
}
else if(argis("-fi")) {
fieldpattern::info();
exit(0);
}
else if(argis("-P")) {
PHASE(2); shift();
vid.scfg.players = argi();
}
else if(argis("-PM")) {
PHASE(2); shift(); pmodel = eModel(argi());
}
else if(argis("-offline")) offlineMode = true;
else if(argis("-debugf")) {
debugfile = fopen("hyperrogue-debug.txt", "w");
shift(); debugflags = argi();
}
else if(argis("-debuge")) {
debugfile = stderr;
shift(); debugflags = argi();
}
else if(argis("-ch")) { autocheat = true; }
else if(argis("-zoom") && curphase == 2) {
PHASE(2); shift(); vid.scale = argf();
}
else if(argis("-zoom") && curphase == 3) {
PHASE(3); shift(); vid.scale = argf();
}
else if(argis("-Y")) {
yendor::on = true;
shift(); yendor::challenge = argi();
}
else if(argis("-r")) {
PHASE(2);
shift();
int clWidth=0, clHeight=0, clFont=0;
sscanf(args(), "%dx%dx%d", &clWidth, &clHeight, &clFont);
if(clWidth) vid.xres = clWidth;
if(clHeight) vid.yres = clHeight;
if(clFont) vid.fsize = clFont;
}
else if(argis("--version") || argis("-v")) {
printf("HyperRogue version " VER "\n");
exit(0);
}
else if(argis("--run")) {
PHASE(3); mainloop(); quitmainloop = false;
}
else if(argis("--draw")) {
PHASE(3); drawscreen();
}
else if(argis("--exit")) {
PHASE(3); printf("Success.\n");
exit(0);
}
else if(argis("-gencells")) {
PHASE(3); shift();
printf("Generating %d cells...\n", argi());
celllister cl(cwt.c, 50, argi(), NULL);
printf("Cells generated: %d\n", size(cl.lst));
for(int i=0; i<size(cl.lst); i++)
setdist(cl.lst[i], 7, NULL);
}
else if(argis("-sr")) {
if(curphase == 1) PHASE(2);
shift(); sightrange = argi();
}
else if(argis("-pngshot")) {
PHASE(3); shift();
printf("saving PNG screenshot to %s\n", args());
saveHighQualityShot(args());
}
else if(argis("-svgsize")) {
shift(); sscanf(args(), "%d/%d", &svg::svgsize, &svg::divby);
}
else if(argis("-pngsize")) {
shift(); sscanf(args(), "%d", &pngres);
}
else if(argis("-svggamma")) {
shift(); svg::gamma = argf();
}
else if(argis("-svgshot")) {
PHASE(3); shift();
printf("saving SVG screenshot to %s\n", args());
svg::render(args());
}
else if(argis("--help") || argis("-h")) {
printf("Press F1 while playing to get ingame options.\n\n");
printf("HyperRogue accepts the following command line options:\n");
printf(" -c FILE - use the specified configuration file\n");
printf(" -s FILE - use the specified highscore file\n");
printf(" -m FILE - use the specified soundtrack (music)\n");
printf(" -se DIR - the directory containing sound effects\n");
printf(" -lev FILE - use the specified filename for the map editor (without loading)\n");
printf(" -load FILE - use the specified filename for the map editor\n");
printf(" -canvas COLOR - set background color or pattern code for the canvas\n");
printf(" --version, -v - show the version number\n");
printf(" --help, -h - show the commandline options\n");
printf(" -f* - toggle fullscreen mode\n");
printf(" -wm n, -mm n - start in the given wallmode or monmode\n");
printf(" -r WxHxF - use the given resolution and font size\n");
printf(" -o* - toggle the OpenGL mode\n");
printf(" -W LAND - start in the given land (cheat)\n");
printf(" -W2 LAND - make the given land easy to find (also turns on autocheat)\n");
printf(" -ch - auto-enable cheat mode\n");
printf(" -geo n - switch geometry (1=Euclidean, 2=spherical, 3=elliptic, 4/5=quotient)\n");
printf(" -qs <desc> - fieldpattern: quotient by the given <desc> (must be followed by qpar)\n");
printf(" -qpar <prime> - fieldpattern: use the given prime instead of 43\n");
printf(" -cs <desc> - fieldpattern: set subpath to the given <desc> (cannot be followed by qpar)\n");
printf(" -csp - fieldpattern: find the subpath of order <prime> (cannot be followed by qpar)\n");
printf(" -S* - toggle Shmup\n");
printf(" -P n - switch Shmup number of players (n=1..7)\n");
printf(" -PM - switch the model index\n");
printf(" -H* - toggle Hardcore\n");
printf(" -T* - toggle Tactical\n");
printf(" -7* - toggle heptagonal mode\n");
printf(" -C* - toggle Chaos mode\n");
printf(" -R* - toggle Random Pattern\n");
printf(" -Y id - enable Yendor, level id\n");
printf(" -D - disable all the special game modes\n");
printf(" -L - list of features\n");
printf(" -debugf 7 - output debugging information to hyperrogue-debug.txt\n");
printf(" -debuge 7 - output debugging information to stderr\n");
printf(" -offline - don't connect to Steam (for Steam versions)\n");
printf(" -I ITEM n - start with n of ITEM (activates cheat and disables ghosts)\n");
printf(" -fix - fix the seed\n");
printf("Toggles: -o0 disables, -o1 enables, -o switches");
printf("Not all options are documented, see hyper.cpp");
exit(0);
}
else if(ca::readArg()) ;
else return 1;
return 0;
}
int main(int argc, char **argv) {
#ifndef WEB
#ifdef LINUX
moreStack();
#endif
arg::init(argc, argv);
initializeCLI();
#endif
initAll();
arg::read(3);
mainloop();
finishAll();
profile_info();
return 0;
}
#ifdef USE_COMMANDLINE
namespace arg {
int argc; char **argv;
void read(int phase) {
curphase = phase;
while(argc) {
int r;
r = readCommon(); if(r == 2) return; if(r == 0) { lshift(); continue; }
#ifdef LOCAL
r = readLocal(); if(r == 2) return; if(r == 0) { lshift(); continue; }
#endif
#ifdef ROGUEVIZ
r = rogueviz::readArgs(); if(r == 2) return; if(r == 0) { lshift(); continue; }
#endif
printf("Unknown option: %s\n", args());
exit(3); exit(3);
} }
} }
achievement_init();
eLand f = firstland;
// initlanguage();
initgraph();
loadsave();
precalc();
resetGL();
initcells();
#ifdef BUILDZEBRA
firstland = laCanvas;
shmup::on = false;
#endif
shmup::safety = safety;
initgame();
#ifdef BUILDZEBRA
zebraPattern();
#endif
if(!shmup::on) {
restoreGolems(items[itOrbLife], moGolem); items[itOrbLife] = 0;
restoreGolems(items[itOrbFriend], moTameBomberbird); items[itOrbFriend] = 0;
restoreGolems(kills[moPrincessMoved], moPrincess, princess::saveHP); kills[moPrincessMoved] = 0;
restoreGolems(kills[moPrincessArmedMoved], moPrincessArmed, princess::saveArmedHP); kills[moPrincessArmedMoved] = 0;
}
firstland = f;
// verifyHell();
// exit(1);
int t1 = SDL_GetTicks();
// if(switchEuclid) restartGame('e');
if(loadlevel) mapstream::loadMap(loadlevel);
#ifdef LOCAL
// river();
autoplay();
#endif
mainloop();
achievement_final(!items[itOrbSafety]);
saveStats();
int msec = SDL_GetTicks() - t1;
DEBB(DF_INIT, (debugfile, "frame : %f ms (%f fps)\n", 1.*msec/frames, 1000.*frames/msec));
offscreen.clear();
clearMemory();
cleargraph();
achievement_close();
return 0;
} }
#endif

604
hyper.h
View File

@ -7,6 +7,9 @@
#define GL #define GL
#define PSEUDOKEY_WHEELDOWN 2501
#define PSEUDOKEY_WHEELUP 2502
#ifdef NOGFX #ifdef NOGFX
#undef GFX #undef GFX
#endif #endif
@ -18,9 +21,10 @@
// scale the Euclidean // scale the Euclidean
#define EUCSCALE 2.3 #define EUCSCALE 2.3
// disable this if you have no access to SDL_mixer
#ifndef MOBILE #ifndef MOBILE
#define AUDIO #ifndef NOAUDIO
#define SDLAUDIO
#endif
#endif #endif
#define NUMWITCH 7 #define NUMWITCH 7
@ -29,7 +33,7 @@
#define LB_YENDOR_CHALLENGE 40 #define LB_YENDOR_CHALLENGE 40
#define LB_PURE_TACTICS 41 #define LB_PURE_TACTICS 41
#define NUMLEADER 57 #define NUMLEADER 69
#define LB_PURE_TACTICS_SHMUP 49 #define LB_PURE_TACTICS_SHMUP 49
#define LB_PURE_TACTICS_COOP 50 #define LB_PURE_TACTICS_COOP 50
@ -75,6 +79,7 @@ void achievement_pump();
vector<string> achievementsReceived; vector<string> achievementsReceived;
// game forward declarations // game forward declarations
typedef int flagtype;
bool mirrorkill(cell *c); bool mirrorkill(cell *c);
bool isNeighbor(cell *c1, cell *c2); bool isNeighbor(cell *c1, cell *c2);
@ -82,7 +87,7 @@ void checkTide(cell *c);
namespace anticheat { extern bool tampered; } namespace anticheat { extern bool tampered; }
int numplayers(); int numplayers();
void removeIvy(cell *c); void removeIvy(cell *c);
bool cellEdgeUnstable(cell *c); bool cellEdgeUnstable(cell *c, flagtype flags = 0);
int coastvalEdge(cell *c); int coastvalEdge(cell *c);
typedef int cellfunction(cell*); typedef int cellfunction(cell*);
int towerval(cell *c, cellfunction* cf = &coastvalEdge); int towerval(cell *c, cellfunction* cf = &coastvalEdge);
@ -94,13 +99,13 @@ eItem treasureType(eLand l);
void buildBarrier(cell *c, int d, eLand l = laNone); void buildBarrier(cell *c, int d, eLand l = laNone);
void extendBarrier(cell *c); void extendBarrier(cell *c);
bool buildBarrier4(cell *c, int d, int mode, eLand ll, eLand lr); bool buildBarrier4(cell *c, int d, int mode, eLand ll, eLand lr);
void makeEmpty(cell *c); bool makeEmpty(cell *c);
bool isCrossroads(eLand l); bool isCrossroads(eLand l);
enum orbAction { roMouse, roKeyboard, roCheck, roMouseForce }; enum orbAction { roMouse, roKeyboard, roCheck, roMouseForce, roMultiCheck, roMultiGo };
void moveItem (cell *from, cell *to, bool activateYendor); void moveItem (cell *from, cell *to, bool activateYendor);
void uncoverMines(cell *c, int lev); void uncoverMines(cell *c, int lev, int dist);
bool survivesMine(eMonster m); bool survivesMine(eMonster m);
void killMonster(cell *c); void killMonster(cell *c, eMonster who_killed, flagtype flags = 0);
void toggleGates(cell *ct, eWall type, int rad); void toggleGates(cell *ct, eWall type, int rad);
bool destroyHalfvine(cell *c, eWall newwall = waNone, int tval = 6); bool destroyHalfvine(cell *c, eWall newwall = waNone, int tval = 6);
void buildCrossroads2(cell *c); void buildCrossroads2(cell *c);
@ -109,12 +114,12 @@ heptagon *createAlternateMap(cell *c, int rad, hstate firststate, int special=0)
void generateAlts(heptagon *h); void generateAlts(heptagon *h);
void setdist(cell *c, int d, cell *from); void setdist(cell *c, int d, cell *from);
void checkOnYendorPath(); void checkOnYendorPath();
void killThePlayerAt(eMonster m, cell *c, int flags); void killThePlayerAt(eMonster m, cell *c, flagtype flags);
bool notDippingFor(eItem i); bool notDippingFor(eItem i);
bool collectItem(cell *c2, bool telekinesis = false); bool collectItem(cell *c2, bool telekinesis = false);
void castLightningBolt(struct cellwalker lig); void castLightningBolt(struct cellwalker lig);
bool movepcto(int d, int subdir = 1, bool checkonly = false); bool movepcto(int d, int subdir = 1, bool checkonly = false);
void stabbingAttack(cell *mf, cell *mt, eMonster who); void stabbingAttack(cell *mf, cell *mt, eMonster who, int bonuskill = 0);
bool earthMove(cell *from, int dir); bool earthMove(cell *from, int dir);
void messageKill(eMonster killer, eMonster victim); void messageKill(eMonster killer, eMonster victim);
void moveMonster(cell *ct, cell *cf); void moveMonster(cell *ct, cell *cf);
@ -122,6 +127,7 @@ int palaceHP();
void placeLocalOrbs(cell *c); void placeLocalOrbs(cell *c);
int elementalKills(); int elementalKills();
bool elementalUnlocked(); bool elementalUnlocked();
bool trollUnlocked();
bool isMultitile(eMonster m); bool isMultitile(eMonster m);
void checkFreedom(cell *cf); void checkFreedom(cell *cf);
int rosedist(cell *c); int rosedist(cell *c);
@ -137,7 +143,16 @@ namespace mirror {
int neighborId(cell *c1, cell *c2); int neighborId(cell *c1, cell *c2);
struct movedir { int d; int subdir; }; 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); } inline bool movepcto(const movedir& md) { return movepcto(md.d, md.subdir); }
void activateActiv(cell *c, bool msg); void activateActiv(cell *c, bool msg);
@ -145,19 +160,65 @@ void activateActiv(cell *c, bool msg);
// shmup // shmup
struct charstyle { struct charstyle {
int charid, skincolor, haircolor, dresscolor, swordcolor, dresscolor2; int charid, skincolor, haircolor, dresscolor, swordcolor, dresscolor2, uicolor;
}; };
string csname(charstyle& cs); string csname(charstyle& cs);
void initcs(charstyle& cs); void initcs(charstyle& cs);
void savecs(FILE *f, charstyle& cs); void savecs(FILE *f, charstyle& cs, int vernum);
void loadcs(FILE *f, charstyle& cs); 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 {
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 {
int players;
int subconfig;
int setwhat;
char keyaction[512];
char joyaction[MAXJOY][MAXBUTTON];
char axeaction[MAXJOY][MAXAXE];
char hataction[MAXJOY][MAXHAT][4];
int deadzoneval[MAXJOY][MAXAXE];
};
charstyle scs[MAXPLAYER];
bool playerActive(int p);
int activePlayers();
cell *multiPlayerTarget(int i);
void checklastmove();
void leaveGame(int i);
}
namespace shmup { namespace shmup {
void recall();
extern bool on; extern bool on;
extern bool safety; extern bool safety;
extern int curtime; extern int curtime;
extern int players, cpid;
void clearMemory(); void clearMemory();
void init(); void init();
void teleported(); void teleported();
@ -175,22 +236,8 @@ namespace shmup {
cell *playerpos(int i); cell *playerpos(int i);
bool playerInBoat(int i); bool playerInBoat(int i);
void destroyBoats(cell *c);
#define MAXBUTTON 64 bool boatAt(cell *c);
#define MAXAXE 16
#define MAXHAT 4
struct config {
int players;
int subconfig;
int setwhat;
char keyaction[512];
char joyaction[8][MAXBUTTON];
char axeaction[8][MAXAXE];
char hataction[8][MAXHAT][4];
};
charstyle scs[4];
} }
// graph // graph
@ -206,6 +253,10 @@ void cleargraphmemory();
void drawFlash(cell* c); void drawFlash(cell* c);
void drawBigFlash(cell* c); void drawBigFlash(cell* c);
void drawParticle(cell *c, int col, int maxspeed = 100);
void drawParticles(cell *c, int col, int qty, int maxspeed = 100);
void drawFireParticles(cell *c, int qty, int maxspeed = 100);
int firecolor(int phase);
void drawLightning(); void drawLightning();
void drawSafety(); void drawSafety();
@ -214,8 +265,6 @@ void movepckeydir(int);
void centerpc(ld aspd); void centerpc(ld aspd);
void displayStatHelp(int y, string name);
void displayStat(int y, const string& name, const string& val, char mkey);
void displayButton(int x, int y, const string& name, int key, int align, int rad = 0); 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, int color, int color2 = 0); void displayColorButton(int x, int y, const string& name, int key, int align, int rad, int color, int color2 = 0);
inline string ONOFF(bool b) { return XLAT(b ? "ON" : "OFF"); } inline string ONOFF(bool b) { return XLAT(b ? "ON" : "OFF"); }
@ -223,17 +272,15 @@ int darkened(int c);
extern int getcstat; extern int getcstat;
bool displaychr(int x, int y, int shift, int size, char chr, int col); bool displaychr(int x, int y, int shift, int size, char chr, int col);
bool displayfr(int x, int y, int b, int size, const string &s, int color, int align); bool displayfr(int x, int y, int b, int size, const string &s, int color, int align);
void saveHighQualityShot(); void saveHighQualityShot(const char *fname = NULL);
bool outofmap(hyperpoint h); bool outofmap(hyperpoint h);
void getcoord(const hyperpoint& H, int& x, int& y, int &shift); void applymodel(hyperpoint H, hyperpoint& Hscr);
void drawline(const hyperpoint& H1, int x1, int y1, int s1, const hyperpoint& H2, int x2, int y2, int col);
void drawline(const hyperpoint& H1, const hyperpoint& H2, int col);
void drawCircle(int x, int y, int size, int color); void drawCircle(int x, int y, int size, int color);
void fixcolor(int& col); void fixcolor(int& col);
int displaydir(cell *c, int d); int displaydir(cell *c, int d);
hyperpoint gethyper(ld x, ld y); hyperpoint gethyper(ld x, ld y);
void resetview(); extern cell *lcenterover; extern heptspin viewctr; void resetview(); extern heptspin viewctr; extern cell *centerover;
#ifndef MOBILE #ifndef MOBILE
int& qpixel(SDL_Surface *surf, int x, int y); int& qpixel(SDL_Surface *surf, int x, int y);
#endif #endif
@ -245,31 +292,30 @@ extern int darken;
void setvideomode(); void setvideomode();
void calcparam(); void calcparam();
string ifMousing(string key, string s); #ifndef NOCONFIG
void saveConfig(); void saveConfig();
#endif
extern hyperpoint mouseh; extern hyperpoint mouseh;
extern int webdisplay; extern int webdisplay;
extern bool GL_initialized;
extern hyperpoint ccenter; extern hyperpoint ccenter;
extern ld crad; extern ld crad;
extern bool mousepressed, anyshiftclick; extern bool mousepressed, anyshiftclick;
extern string help; extern string help;
extern int lalpha;
struct videopar { struct videopar {
ld scale, eye, alpha, aspeed; ld scale, eye, alpha, sspeed, mspeed, yshift, camera_angle;
ld ballangle, ballproj;
int mobilecompasssize;
bool full; bool full;
bool goteyes; // for rendering bool goteyes; // for rendering
bool goteyes2; // for choosing colors bool goteyes2; // for choosing colors
bool quick;
bool darkhepta; bool darkhepta;
bool shifttarget; int shifttarget;
int xres, yres, framelimit; int xres, yres, framelimit;
@ -280,6 +326,9 @@ struct videopar {
int radius; int radius;
ld alphax, beta; ld alphax, beta;
bool grid;
int particles;
int fsize; int fsize;
int flashtime; int flashtime;
@ -292,7 +341,7 @@ struct videopar {
bool usingAA; bool usingAA;
int joyvalue, joyvalue2, joypanthreshold; int joyvalue, joyvalue2, joypanthreshold;
float joypanspeed; ld joypanspeed;
charstyle cs; charstyle cs;
@ -301,9 +350,10 @@ struct videopar {
int killreduction, itemreduction, portreduction; int killreduction, itemreduction, portreduction;
shmup::config scfg; multi::config scfg;
bool steamscore; int steamscore;
bool drawmousecircle; // draw the circle around the mouse
}; };
extern videopar vid; extern videopar vid;
@ -322,7 +372,10 @@ enum emtype {emNormal, emHelp,
emYendor, emTactic, emRugConfig, emYendor, emTactic, emRugConfig,
emConformal, emConformal,
emProgress, emProgress,
emCheatMenu emCheatMenu, emLeader,
emJoyConfig,
emColor, emNumber,
em3D, emRogueviz
}; };
extern emtype cmode, lastmode; extern emtype cmode, lastmode;
@ -338,14 +391,18 @@ extern struct SDL_Surface *s;
namespace mapeditor { namespace mapeditor {
extern bool drawplayer; extern bool drawplayer;
extern char whichPattern, whichShape; extern char whichPattern, whichShape;
extern char whichCanvas;
extern int displaycodes;
int generateCanvas(cell *c); int generateCanvas(cell *c);
void clearModelCells(); void clearModelCells();
void applyModelcell(cell *c); void applyModelcell(cell *c);
int realpattern(cell *c); int realpattern(cell *c);
int patterndir(cell *c, char w = whichPattern); int patterndir(cell *c, char w = whichPattern);
int subpattern(cell *c);
extern cell *drawcell; extern cell *drawcell;
} }
#ifndef NORUG
namespace rug { namespace rug {
extern bool rugged; extern bool rugged;
void init(); void init();
@ -353,6 +410,7 @@ namespace rug {
void actDraw(); void actDraw();
void buildVertexInfo(cell *c, transmatrix V); void buildVertexInfo(cell *c, transmatrix V);
} }
#endif
#define HASLINEVIEW #define HASLINEVIEW
namespace conformal { namespace conformal {
@ -372,9 +430,8 @@ namespace conformal {
namespace polygonal { namespace polygonal {
extern int SI; extern int SI;
extern double STAR; extern ld STAR;
void solve(); void solve();
typedef long double ld;
pair<ld, ld> compute(ld x, ld y); pair<ld, ld> compute(ld x, ld y);
} }
@ -422,8 +479,9 @@ extern bool localKill(shmup::monster *m);
#define P_ROSE (1<<28) // rose smell #define P_ROSE (1<<28) // rose smell
#define P_CLIMBUP (1<<29) // allow climbing up #define P_CLIMBUP (1<<29) // allow climbing up
#define P_CLIMBDOWN (1<<30) // allow climbing down #define P_CLIMBDOWN (1<<30) // allow climbing down
#define P_REPTILE (1<<31) // is reptile
bool passable(cell *w, cell *from, int flags); bool passable(cell *w, cell *from, flagtype flags);
bool isElemental(eLand l); bool isElemental(eLand l);
int coastval(cell *c, eLand base); int coastval(cell *c, eLand base);
@ -450,13 +508,15 @@ extern bool safety;
#define SAGEMELT .1 #define SAGEMELT .1
#define TEMPLE_EACH 6 #define TEMPLE_EACH 6
#define PT(x, y) (tactic::on ? (y) : (x)) #define PT(x, y) ((tactic::on || quotient == 2) ? (y) : (x))
#define ROCKSNAKELENGTH 50 #define ROCKSNAKELENGTH 50
#define WORMLENGTH 15
#define PUREHARDCORE_LEVEL 10 #define PUREHARDCORE_LEVEL 10
#define PRIZEMUL 7 #define PRIZEMUL 7
#define INF 9999 #define INF 9999
#define INFD 20 #define INFD 20
#define PINFD 125
#define BARLEV ((ISANDROID||ISIOS||purehepta)?9:10) #define BARLEV ((ISANDROID||ISIOS||purehepta)?9:10)
#define BUGLEV 15 #define BUGLEV 15
// #define BARLEV 9 // #define BARLEV 9
@ -469,7 +529,7 @@ bool isAlchAny(eWall w);
bool isAlchAny(cell *c); bool isAlchAny(cell *c);
#define YDIST 101 #define YDIST 101
#define MODECODES 38 #define MODECODES 254
extern cellwalker cwt; // player character position extern cellwalker cwt; // player character position
extern int sval; extern int sval;
@ -494,10 +554,14 @@ bool hellUnlocked();
bool markOrb(eItem it); // mark the orb as 'used', return true if exists 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 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(eMonster m);
bool isMimic(cell *c); bool isMimic(cell *c);
void killWithMessage(cell *c, bool orStun = false, eMonster killer = moNone);
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(eMonster m);
bool isWorm(cell *c); bool isWorm(cell *c);
@ -507,10 +571,11 @@ bool isIvy(cell *c);
#define GUNRANGE 3 #define GUNRANGE 3
// 0 = basic treasure, 1 = something else, 2 = power orb // 0 = basic treasure, 1 = other item, 2 = power orb, 3 = not an item
#define IC_TREASURE 0 #define IC_TREASURE 0
#define IC_OTHER 1 #define IC_OTHER 1
#define IC_ORB 2 #define IC_ORB 2
#define IC_NAI 3
bool playerInPower(); bool playerInPower();
void activateFlash(); void activateFlash();
@ -528,7 +593,7 @@ int realstuntime(cell *c);
extern bool invismove, invisfish; extern bool invismove, invisfish;
bool attackingForbidden(cell *c, cell *c2); bool attackingForbidden(cell *c, cell *c2);
void killOrStunMonster(cell *c2); void killOrStunMonster(cell *c2, eMonster who_killed);
extern vector<cell*> offscreen; // offscreen cells to take care off extern vector<cell*> offscreen; // offscreen cells to take care off
@ -538,6 +603,8 @@ cell *playerpos(int i);
bool makeflame(cell *c, int timeout, bool checkonly); bool makeflame(cell *c, int timeout, bool checkonly);
void bfs(); void bfs();
bool isPlayerInBoatOn(cell *c); bool isPlayerInBoatOn(cell *c);
bool isPlayerInBoatOn(cell *c, int i);
void destroyBoats(cell *c, cell *cf, bool strandedToo);
extern bool showoff; extern bool showoff;
extern int lastexplore; extern int lastexplore;
extern int truelotus; extern int truelotus;
@ -583,7 +650,18 @@ bool withRose(cell *cfrom, cell *cto);
#define MF_MOUNT (1<<18) // don't do #define MF_MOUNT (1<<18) // don't do
#define MF_NOFRIEND (1<<19) // don't do it for friends #define MF_NOFRIEND (1<<19) // don't do it for friends
bool canAttack(cell *c1, eMonster m1, cell *c2, eMonster m2, int flags); #define AF_SWORD (1<<20) // big sword
#define AF_SWORD_INTO (1<<21) // moving into big sword
#define AF_MSG (1<<22) // produce a message
#define AF_ORSTUN (1<<23) // attackMonster: allow stunning
#define AF_NEXTTURN (1<<24) // next turn -- don't count shield at power 1
#define AF_FALL (1<<25) // death by falling
#define MF_STUNNED (1<<26) // edgeunstable: ignore ladders (as stunned monsters do)
#define MF_IVY (1<<27) // edgeunstable: ignore ivy (ivy cannot climb ivy)
#define AF_HORNS (1<<28) // spear attack (always has APPROACH too)
#define AF_BULL (1<<29) // bull attack
bool canAttack(cell *c1, eMonster m1, cell *c2, eMonster m2, flagtype flags);
extern bool chaosmode; extern bool chaosmode;
extern bool chaosUnlocked; extern bool chaosUnlocked;
@ -594,22 +672,6 @@ int getGhostcount();
void raiseBuggyGeneration(cell *c, const char *s); void raiseBuggyGeneration(cell *c, const char *s);
void verifyMutantAround(cell *c); void verifyMutantAround(cell *c);
extern FILE *debugfile;
extern int debugflags;
extern bool offline;
#ifdef ANDROID
#define DEBB(r,x)
#else
#define DEBB(r,x) { if(debugfile && (!(r) || (debugflags & (r)))) { fprintf x; fflush(debugfile); } }
#endif
#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
#ifdef MOBILE #ifdef MOBILE
#define NOPNG #define NOPNG
#endif #endif
@ -633,7 +695,8 @@ void buildAirmap();
// currently works for worms only // currently works for worms only
bool sameMonster(cell *c1, cell *c2); bool sameMonster(cell *c1, cell *c2);
cell *wormhead(cell *c); cell *wormhead(cell *c);
eMonster getMount(); eMonster getMount(int player_id);
eMonster haveMount();
bool isDragon(eMonster m); bool isDragon(eMonster m);
@ -647,6 +710,8 @@ extern bool autocheat;
extern bool inHighQual; extern bool inHighQual;
void mountmove(cell *c, int spin, bool fp); 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 { template<class T> struct dynamicval {
T& where; T& where;
@ -655,18 +720,403 @@ template<class T> struct dynamicval {
~dynamicval() { where = backup; } ~dynamicval() { where = backup; }
}; };
namespace stalemate { struct stalemate1 {
eMonster who; eMonster who;
cell *moveto; cell *moveto;
cell *killed; cell *killed;
cell *pushto; cell *pushto;
cell *comefrom; 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 {
vector<stalemate1> moves;
bool nextturn; bool nextturn;
bool isKilled(cell *c); bool isKilled(cell *c);
bool anyKilled();
bool isMoveto(cell *c);
bool isKilledDirectlyAt(cell *c);
bool isPushto(cell *c);
}; };
extern int turncount; extern int turncount;
bool reduceOrbPower(eItem it, int cap); bool reduceOrbPower(eItem it, int cap);
bool checkOrb(eMonster m1, eItem orb); bool checkOrb(eMonster m1, eItem orb);
movedir vectodir(const hyperpoint& P);
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);
bool isTargetOrAdjacent(cell *c);
bool warningprotection();
bool mineMarked(cell *c);
bool minesafe();
bool hasSafeOrb(cell *c);
void placeWater(cell *c, cell *c2);
bool againstCurrent(cell *w, cell *from);
#define DEFAULTCONTROL (multi::players == 1 && !shmup::on && !multi::alwaysuse)
extern bool timerghost;
#ifdef PANDORA
#define MENU_SCALING
#endif
#ifdef MOBILE
#define MENU_SCALING
#endif
#ifdef MENU_SCALING
#define displayfrZ dialog::displayzoom
#else
#define displayfrZ displayfr
#endif
namespace dialog {
enum tDialogItem {diTitle, diItem, diBreak, diHelp, diInfo, diSlider};
struct item {
tDialogItem type;
string body;
string value;
string keycaption;
int key;
int color, colorv, colork, colors, colorc;
int scale;
double param;
};
item& lastItem();
void addSelItem(string body, string value, int key);
void addBoolItem(string body, bool value, int key);
void addColorItem(string body, int value, int key);
void addHelp(string body);
void addInfo(string body, int color = 0xC0C0C0);
void addItem(string body, int key);
void addBreak(int val);
void addTitle(string body, int color, int scale);
void init();
void init(string title, int color = 0xE8E8E8, int scale = 150, int brk = 60);
void display();
void drawColorDialog(int color);
int handleKeyColor(int sym, int uni, int& color);
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 scaleLog();
void scaleSinh();
void handleNavigation(int &sym, int &uni);
bool displayzoom(int x, int y, int b, int size, const string &s, int color, int align);
bool editingDetail();
int handlePage(int& nl, int& nlm, int perpage);
void displayPageButtons(int i, bool pages);
bool handlePageButtons(int uni);
}
void checkStunKill(cell *dest);
void clearMessages();
void resetGeometry();
namespace svg {
void circle(int x, int y, int size, int col);
void polygon(int *polyx, int *polyy, int polyi, int col, int outline);
void text(int x, int y, int size, const string& str, bool frame, int col, int align);
extern bool in;
extern string *info;
void render(const char *fname = NULL);
}
extern int sightrange;
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, int col, double footphase);
void drawPlayerEffects(const transmatrix& V, cell *c, bool onPlayer);
// monster movement animations
struct animation {
int ltick;
double footphase;
transmatrix wherenow;
};
// 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];
extern unordered_map<cell*, transmatrix> gmatrix, gmatrix0;
void animateMovement(cell *src, cell *tgt, int layer);
// for animations which might use the same locations,
// such as replacements or multi-tile monsters
void indAnimateMovement(cell *src, cell *tgt, int layer);
void commitAnimations(int layer);
void animateReplacement(cell *a, cell *b, int layer);
void fallingFloorAnimation(cell *c, eWall w = waNone, eMonster m = moNone);
void fallingMonsterAnimation(cell *c, eMonster m);
// ranks:
enum PPR {
PPR_ZERO, PPR_OUTCIRCLE, PPR_MOVESTAR,
PPR_MINUSINF,
PPR_BELOWBOTTOMm,
PPR_BELOWBOTTOM,
PPR_BELOWBOTTOMp,
PPR_LAKEBOTTOM, PPR_HELLSPIKE,
PPR_INLAKEWALLm, PPR_INLAKEWALL, PPR_INLAKEWALLp,
PPR_SUBLAKELEV, PPR_LAKELEV, PPR_BOATLEV, PPR_BOATLEV2, PPR_BOATLEV3,
PPR_LAKEWALLm, PPR_LAKEWALL, PPR_LAKEWALLp,
PPR_FLOOR_TOWER,
PPR_FLOOR,
PPR_FLOOR_DRAGON,
PPR_FLOORa, PPR_FLOORb, PPR_FLOORc, PPR_FLOORd,
PPR_LIZEYE,
PPR_BFLOOR,
PPR_GFLOORa, PPR_GFLOORb, PPR_GFLOORc,
PPR_WALLSHADOW,
PPR_STRUCT0, PPR_STRUCT1, PPR_STRUCT2, PPR_STRUCT3,
PPR_THORNS, PPR_WALL,
PPR_REDWALLm, PPR_REDWALLs, PPR_REDWALLp, PPR_REDWALL,
PPR_REDWALLm2, PPR_REDWALLs2, PPR_REDWALLp2, PPR_REDWALLt2,
PPR_REDWALLm3, PPR_REDWALLs3, PPR_REDWALLp3, PPR_REDWALLt3,
PPR_HEPTAMARK,
PPR_ITEM, PPR_ITEMa, PPR_ITEMb,
PPR_BIGSTATUE,
PPR_GLASSm, PPR_GLASSs, PPR_GLASSp, PPR_GLASS,
PPR_WALL3m, PPR_WALL3s, PPR_WALL3p, PPR_WALL3, PPR_WALL3A,
PPR_HIDDEN, PPR_GIANTSHADOW,
PPR_TENTACLE0, PPR_TENTACLE1,
PPR_ONTENTACLE, PPR_ONTENTACLE_EYES, PPR_ONTENTACLE_EYES2,
PPR_MONSTER_SHADOW,
PPR_MONSTER_FOOT, PPR_MONSTER_LEG, PPR_MONSTER_GROIN,
PPR_MONSTER_BODY, PPR_MONSTER_SUBWPN, PPR_MONSTER_WPN, PPR_MONSTER_ARMOR0, PPR_MONSTER_ARMOR1,
PPR_MONSTER_CLOAK, PPR_MONSTER_NECK,
PPR_MONSTER_HEAD, PPR_MONSTER_FACE, PPR_MONSTER_EYE0, PPR_MONSTER_EYE1,
PPR_MONSTER_HAIR, PPR_MONSTER_HAT0, PPR_MONSTER_HAT1,
PPR_MONSTER_HOODCLOAK1, PPR_MONSTER_HOODCLOAK2,
PPR_STUNSTARS,
PPR_CARRIED, PPR_CARRIEDa, PPR_CARRIEDb,
PPR_PARTICLE, PPR_SWORDMARK, PPR_MAGICSWORD, PPR_MISSILE,
PPR_MINEMARK, PPR_ARROW,
PPR_LINE, PPR_TEXT, PPR_CIRCLE,
PPR_MAX
};
void ShadowV(const transmatrix& V, const struct hpcshape& bp, int prio = PPR_MONSTER_SHADOW);
#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
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 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;
#ifdef ROGUEVIZ
namespace rogueviz {
extern bool on;
string describe(shmup::monster *m);
void activate(shmup::monster *m);
void drawVertex(const transmatrix &V, cell *c, shmup::monster *m);
bool virt(shmup::monster *m);
void turn(int delta);
void drawExtra();
void fixparam();
int readArgs();
void close();
}
#endif
void explodeMine(cell *c);
bool mayExplodeMine(cell *c, eMonster who);
int gravityLevel(cell *c);
void fullcenter();
void movecost(cell* from, cell *to);
void checkmove();
transmatrix eumove(int x, int y);
#ifndef NOSAVE
void loadScores();
#endif
int reptilemax();
extern bool mousing;
#define IFM(x) (mousing?"":x)
extern cell *recallCell;
extern eLand cheatdest;
void cheatMoveTo(eLand l);
extern int backcolor;
extern bool overgenerate;
void doOvergenerate();
void collectMessage(cell *c2, eItem which);
namespace quotientspace {
void build();
void clear();
extern vector<int> connections;
}
void killFriendlyIvy();
void pushdown(cell *c, int& q, const transmatrix &V, double down, bool rezoom, bool repriority);
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);
enum eModel {
mdDisk, mdHalfplane, mdBand, mdPolygonal, mdPolynomial,
mdEquidistant, mdEquiarea, mdBall, mdHyperboloid, mdGUARD, mdUnchanged };
#define MODELCOUNT ((int) mdGUARD)
void drawShape(pair<ld,ld>* coords, int qty, int color);
extern eModel pmodel;
int darkena(int c, int lev, int a);
#define SHSIZE 16
extern cell *shpos[MAXPLAYER][SHSIZE];
extern int cshpos;
namespace arg {
#ifdef USE_COMMANDLINE
extern int argc; extern char **argv;
inline void lshift() {
argc--; argv++;
}
inline void shift() {
lshift(); if(!argc) { printf("Missing parameter\n"); exit(1); }
}
inline char* args() { return *argv; }
inline int argi() { return atoi(*argv); }
inline ld argf() { return atof(*argv); }
inline bool argis(const char *s) { return strcmp(*argv, s) == 0; }
inline void init(int _argc, char **_argv) { argc=_argc-1; argv=_argv+1; }
int curphase;
inline void phaseerror(int x) {
printf("Command line error: cannot read command '%s' from phase %d in phase %d\n", args(), x, curphase);
exit(1);
}
// returned values: 0 = ok, 1 = not recognized, 2 = shift phase
int readCommon();
int readLocal();
// an useful macro
#define PHASE(x) { if(arg::curphase > x) phaseerror(x); else if(arg::curphase < x) return 2; }
void read(int phase);
#else
inline void read(int phase) { }
#endif
}
extern bool generatingEquidistant;

View File

@ -1,29 +1,12 @@
// Hyperbolic Rogue // Hyperbolic Rogue
// Copyright (C) 2011-2012 Zeno Rogue, see 'hyper.cpp' for details // Copyright (C) 2011-2012 Zeno Rogue, see 'hyper.cpp' for details
// basic utility functions enum eGeometry {gNormal, gEuclid, gSphere, gElliptic, gQuotient, gQuotient2, gGUARD};
eGeometry geometry, targetgeometry = gEuclid;
#ifdef MOBILE #define euclid (geometry == gEuclid)
typedef double ld; #define sphere (geometry == gSphere || geometry == gElliptic)
#else #define elliptic (geometry == gElliptic)
typedef long double ld; #define quotient (geometry == gQuotient ? 1 : geometry == gQuotient2 ? 2 : 0)
#endif
template<class T> int size(const T& x) {return int(x.size()); }
string its(int i) { char buf[64]; sprintf(buf, "%d", i); return buf; }
string fts(float x) { char buf[64]; sprintf(buf, "%4.2f", x); return buf; }
string fts4(float x) { char buf[64]; sprintf(buf, "%6.4f", x); return buf; }
string cts(char c) { char buf[8]; buf[0] = c; buf[1] = 0; return buf; }
string llts(long long i) {
// sprintf does not work on Windows IIRC
if(i < 0) return "-" + llts(-i);
if(i < 10) return its((int) i);
return llts(i/10) + its(i%10);
}
string itsh(int i) {static char buf[16]; sprintf(buf, "%03X", i); return buf; }
// for the Euclidean mode...
bool euclid = false;
// for the pure heptagonal grid // for the pure heptagonal grid
bool purehepta = false; bool purehepta = false;
@ -34,13 +17,31 @@ bool purehepta = false;
//=========================== //===========================
#ifdef SINHCOSH #ifdef SINHCOSH
ld sinh(ld alpha) { return (exp(alpha) - exp(-alpha)) / 2; } // ld sinh(ld alpha) { return (exp(alpha) - exp(-alpha)) / 2; }
ld cosh(ld alpha) { return (exp(alpha) + exp(-alpha)) / 2; } // ld cosh(ld alpha) { return (exp(alpha) + exp(-alpha)) / 2; }
/* ld inverse_sinh(ld z) {
return log(z+sqrt(1+z*z));
}
double inverse_cos(double c) {
double s = sqrt(1-c*c);
double r = atan(s/c);
if(r < 0) r = -r;
return r;
}
// ld tanh(ld x) { return sinh(x) / cosh(x); }
ld inverse_tanh(ld x) { return log((1+x)/(1-x)) / 2; } */
#endif
#ifndef M_PI
#define M_PI 3.14159265358979
#endif #endif
ld squar(ld x) { return x*x; } ld squar(ld x) { return x*x; }
int sig(int z) { return z<2?1:-1; } int sig(int z) { return (sphere || z<2)?1:-1; }
// hyperbolic point: // hyperbolic point:
//=================== //===================
@ -62,17 +63,17 @@ hyperpoint hpxyz(ld x, ld y, ld z) {
hyperpoint hpxy(ld x, ld y) { hyperpoint hpxy(ld x, ld y) {
// EUCLIDEAN // EUCLIDEAN
return hpxyz(x,y, euclid ? 1 : sqrt(1+x*x+y*y)); return hpxyz(x,y, euclid ? 1 : sphere ? sqrt(1-x*x-y*y) : sqrt(1+x*x+y*y));
} }
// center of the pseudosphere // center of the pseudosphere
hyperpoint Hypc = { {0,0,0} }; const hyperpoint Hypc = { {0,0,0} };
// origin of the hyperbolic plane // origin of the hyperbolic plane
hyperpoint C0 = { {0,0,1} }; const hyperpoint C0 = { {0,0,1} };
// a point (I hope this number needs no comments ;) ) // a point (I hope this number needs no comments ;) )
hyperpoint Cx1 = { {1,0,1.41421356237} }; const hyperpoint Cx1 = { {1,0,1.41421356237} };
// this function returns approximate square of distance between two points // this function returns approximate square of distance between two points
// (in the spherical analogy, this would be the distance in the 3D space, // (in the spherical analogy, this would be the distance in the 3D space,
@ -80,7 +81,17 @@ hyperpoint Cx1 = { {1,0,1.41421356237} };
// also used to verify whether a point h1 is on the hyperbolic plane by using Hypc for h2 // also used to verify whether a point h1 is on the hyperbolic plane by using Hypc for h2
ld intval(const hyperpoint &h1, const hyperpoint &h2) { ld intval(const hyperpoint &h1, const hyperpoint &h2) {
return squar(h1[0]-h2[0]) + squar(h1[1]-h2[1]) - squar(h1[2]-h2[2]); return squar(h1[0]-h2[0]) + squar(h1[1]-h2[1]) + (sphere?1:euclid?0:-1) * squar(h1[2]-h2[2]);
}
ld intvalxy(const hyperpoint &h1, const hyperpoint &h2) {
return squar(h1[0]-h2[0]) + squar(h1[1]-h2[1]);
}
ld zlevel(const hyperpoint &h) {
if(euclid) return h[2];
else if(sphere) return sqrt(intval(h, Hypc));
else return sqrt(-intval(h, Hypc));
} }
// display a hyperbolic point // display a hyperbolic point
@ -100,7 +111,8 @@ hyperpoint mid(const hyperpoint& H1, const hyperpoint& H2) {
ld Z = 2; ld Z = 2;
if(!euclid) { if(sphere) Z = sqrt(intval(H3, Hypc));
else if(!euclid) {
Z = intval(H3, Hypc); Z = intval(H3, Hypc);
Z = sqrt(-Z); Z = sqrt(-Z);
} }
@ -110,42 +122,20 @@ hyperpoint mid(const hyperpoint& H1, const hyperpoint& H2) {
return H3; return H3;
} }
hyperpoint mid3(const hyperpoint& H1, const hyperpoint& H2, const hyperpoint& H3) { // like mid, but take 3D into account
hyperpoint midz(const hyperpoint& H1, const hyperpoint& H2) {
hyperpoint Hx; hyperpoint H3;
Hx[0] = H1[0] + H2[0] + H3[0]; H3[0] = H1[0] + H2[0];
Hx[1] = H1[1] + H2[1] + H3[1]; H3[1] = H1[1] + H2[1];
Hx[2] = H1[2] + H2[2] + H3[2]; H3[2] = H1[2] + H2[2];
ld Z = 2; ld Z = 2;
if(!euclid) { if(sphere || !euclid) Z = zlevel(H3) * 2 / (zlevel(H1) + zlevel(H2));
Z = intval(Hx, Hypc); for(int c=0; c<3; c++) H3[c] /= Z;
Z = sqrt(-Z);
}
for(int c=0; c<3; c++) Hx[c] /= Z; return H3;
return Hx;
}
hyperpoint mid4(const hyperpoint& H1, const hyperpoint& H2, const hyperpoint& H3, const hyperpoint& H4) {
hyperpoint Hx;
Hx[0] = H1[0] + H2[0] + H3[0] + H4[0];
Hx[1] = H1[1] + H2[1] + H3[1] + H4[1];
Hx[2] = H1[2] + H2[2] + H3[2] + H4[2];
ld Z = 2;
if(!euclid) {
Z = intval(Hx, Hypc);
Z = sqrt(-Z);
}
for(int c=0; c<3; c++) Hx[c] /= Z;
return Hx;
} }
// matrices // matrices
@ -161,9 +151,13 @@ struct transmatrix {
}; };
// identity matrix // identity matrix
transmatrix Id = {{{1,0,0}, {0,1,0}, {0,0,1}}}; const transmatrix Id = {{{1,0,0}, {0,1,0}, {0,0,1}}};
transmatrix Mirror = {{{1,0,0}, {0,-1,0}, {0,0,1}}}; // mirror image
const transmatrix Mirror = {{{1,0,0}, {0,-1,0}, {0,0,1}}};
// rotate by PI
const transmatrix pispin = {{{-1,0,0}, {0,-1,0}, {0,0,1}}};
hyperpoint operator * (const transmatrix& T, const hyperpoint& H) { hyperpoint operator * (const transmatrix& T, const hyperpoint& H) {
hyperpoint z; hyperpoint z;
@ -174,11 +168,18 @@ hyperpoint operator * (const transmatrix& T, const hyperpoint& H) {
return z; return z;
} }
transmatrix operator * (const transmatrix& T, const transmatrix& U) { // T * C0, optimized
inline hyperpoint tC0(const transmatrix &T) {
hyperpoint z;
z[0] = T[0][2]; z[1] = T[1][2]; z[2] = T[2][2];
return z;
}
inline transmatrix operator * (const transmatrix& T, const transmatrix& U) {
transmatrix R; transmatrix R;
for(int i=0; i<3; i++) for(int j=0; j<3; j++) R[i][j] = 0; // for(int i=0; i<3; i++) for(int j=0; j<3; j++) R[i][j] = 0;
for(int i=0; i<3; i++) for(int j=0; j<3; j++) for(int k=0; k<3; k++) for(int i=0; i<3; i++) for(int j=0; j<3; j++) // for(int k=0; k<3; k++)
R[i][j] += T[i][k] * U[k][j]; R[i][j] = T[i][0] * U[0][j] + T[i][1] * U[1][j] + T[i][2] * U[2][j];
return R; return R;
} }
@ -202,26 +203,52 @@ transmatrix eupush(ld x, ld y) {
transmatrix xpush(ld alpha) { transmatrix xpush(ld alpha) {
if(euclid) return eupush(alpha, 0); if(euclid) return eupush(alpha, 0);
transmatrix T = Id; transmatrix T = Id;
T[0][0] = +cosh(alpha); T[0][2] = +sinh(alpha); if(sphere) {
T[2][0] = +sinh(alpha); T[2][2] = +cosh(alpha); T[0][0] = +cos(alpha); T[0][2] = +sin(alpha);
T[2][0] = -sin(alpha); T[2][2] = +cos(alpha);
}
else {
T[0][0] = +cosh(alpha); T[0][2] = +sinh(alpha);
T[2][0] = +sinh(alpha); T[2][2] = +cosh(alpha);
}
return T; return T;
} }
double inverse_sinh(ld z) { inline hyperpoint xpush0(ld x) {
return log(z+sqrt(1+z*z)); hyperpoint h;
if(euclid) return hpxy(x, 0);
else if(sphere) h[0] = sin(x), h[1] = 0, h[2] = cos(x);
else h[0] = sinh(x), h[1] = 0, h[2] = cosh(x);
return h;
} }
inline hyperpoint xspinpush0(ld alpha, ld x) {
// return spin(alpha)*xpush0(x);
ld s;
hyperpoint h;
if(euclid) return hpxy(x*cos(alpha), -x*sin(alpha));
else if(sphere) s=sin(x), h[0] = s*cos(alpha), h[1] = -s*sin(alpha), h[2] = cos(x);
else s=sinh(x), h[0] = s*cos(alpha), h[1] = -s*sin(alpha), h[2] = cosh(x);
return h;
}
// push alpha units vertically // push alpha units vertically
transmatrix ypush(ld alpha) { transmatrix ypush(ld alpha) {
if(euclid) return eupush(0, alpha); if(euclid) return eupush(0, alpha);
transmatrix T = Id; transmatrix T = Id;
T[1][1] = +cosh(alpha); T[1][2] = +sinh(alpha); if(sphere) {
T[2][1] = +sinh(alpha); T[2][2] = +cosh(alpha); T[1][1] = +cos(alpha); T[1][2] = +sin(alpha);
T[2][1] = -sin(alpha); T[2][2] = +cos(alpha);
}
else {
T[1][1] = +cosh(alpha); T[1][2] = +sinh(alpha);
T[2][1] = +sinh(alpha); T[2][2] = +cosh(alpha);
}
return T; return T;
} }
// rotate the hyperplane around C0 such that H[1] == 0 and H[0] >= 0 // rotate the hyperplane around C0 such that H[1] == 0 and H[0] >= 0
transmatrix spintox(hyperpoint H) { transmatrix spintox(const hyperpoint& H) {
transmatrix T = Id; transmatrix T = Id;
ld R = sqrt(H[0] * H[0] + H[1] * H[1]); ld R = sqrt(H[0] * H[0] + H[1] * H[1]);
if(R >= 1e-12) { if(R >= 1e-12) {
@ -232,7 +259,7 @@ transmatrix spintox(hyperpoint H) {
} }
// reverse of spintox(H) // reverse of spintox(H)
transmatrix rspintox(hyperpoint H) { transmatrix rspintox(const hyperpoint& H) {
transmatrix T = Id; transmatrix T = Id;
ld R = sqrt(H[0] * H[0] + H[1] * H[1]); ld R = sqrt(H[0] * H[0] + H[1] * H[1]);
if(R >= 1e-12) { if(R >= 1e-12) {
@ -243,30 +270,42 @@ transmatrix rspintox(hyperpoint H) {
} }
// for H such that H[1] == 0, this matrix pushes H to C0 // for H such that H[1] == 0, this matrix pushes H to C0
transmatrix pushxto0(hyperpoint H) { transmatrix pushxto0(const hyperpoint& H) {
if(euclid) return eupush(-H[0], -H[1]); if(euclid) return eupush(-H[0], -H[1]);
transmatrix T = Id; transmatrix T = Id;
T[0][0] = +H[2]; T[0][2] = -H[0]; if(sphere) {
T[2][0] = -H[0]; T[2][2] = +H[2]; T[0][0] = +H[2]; T[0][2] = -H[0];
T[2][0] = +H[0]; T[2][2] = +H[2];
}
else {
T[0][0] = +H[2]; T[0][2] = -H[0];
T[2][0] = -H[0]; T[2][2] = +H[2];
}
return T; return T;
} }
// reverse of pushxto0(H) // reverse of pushxto0(H)
transmatrix rpushxto0(hyperpoint H) { transmatrix rpushxto0(const hyperpoint& H) {
if(euclid) return eupush(H[0], H[1]); if(euclid) return eupush(H[0], H[1]);
transmatrix T = Id; transmatrix T = Id;
T[0][0] = +H[2]; T[0][2] = +H[0]; if(sphere) {
T[2][0] = +H[0]; T[2][2] = +H[2]; T[0][0] = +H[2]; T[0][2] = +H[0];
T[2][0] = -H[0]; T[2][2] = +H[2];
}
else {
T[0][0] = +H[2]; T[0][2] = +H[0];
T[2][0] = +H[0]; T[2][2] = +H[2];
}
return T; return T;
} }
// generalization: H[1] can be non-zero // generalization: H[1] can be non-zero
transmatrix gpushxto0(hyperpoint H) { transmatrix gpushxto0(const hyperpoint& H) {
hyperpoint H2 = spintox(H) * H; hyperpoint H2 = spintox(H) * H;
return rspintox(H) * pushxto0(H2) * spintox(H); return rspintox(H) * pushxto0(H2) * spintox(H);
} }
transmatrix rgpushxto0(hyperpoint H) { transmatrix rgpushxto0(const hyperpoint& H) {
hyperpoint H2 = spintox(H) * H; hyperpoint H2 = spintox(H) * H;
return rspintox(H) * rpushxto0(H2) * spintox(H); return rspintox(H) * rpushxto0(H2) * spintox(H);
} }
@ -305,18 +344,22 @@ void fixmatrix(transmatrix& T) {
void display(const transmatrix& T) { void display(const transmatrix& T) {
for(int y=0; y<3; y++) { for(int y=0; y<3; y++) {
for(int x=0; x<3; x++) printf("%10.7f", double(T[y][x])); for(int x=0; x<3; x++) printf("%10.7f", double(T[y][x]));
printf(" -> %10.7f\n", double(squar(T[y][0]) + squar(T[y][1]) - squar(T[y][2]))); printf(" -> %10.7f\n", double(squar(T[y][0]) + squar(T[y][1]) + sig(2) * squar(T[y][2])));
// printf("\n"); // printf("\n");
} }
for(int x=0; x<3; x++) printf("%10.7f", double(squar(T[0][x]) + squar(T[1][x]) - squar(T[2][x]))); printf("\n");
for(int x=0; x<3; x++) printf("%10.7f", double(squar(T[0][x]) + squar(T[1][x]) + sig(2) * squar(T[2][x])));
printf("\n");
for(int x=0; x<3; x++) { for(int x=0; x<3; x++) {
int y = (x+1) % 3; int y = (x+1) % 3;
printf("%10.7f", double(T[0][x]*T[0][y] + T[1][x]*T[1][y] - T[2][x]*T[2][y])); printf("%10.7f", double(T[0][x]*T[0][y] + T[1][x]*T[1][y] + sig(2) * T[2][x]*T[2][y]));
} }
printf("\n\n"); printf("\n\n");
} }
transmatrix inverse(transmatrix T) { transmatrix inverse(transmatrix T) {
profile_start(7);
ld det = 0; ld det = 0;
for(int i=0; i<3; i++) for(int i=0; i<3; i++)
det += T[0][i] * T[1][(i+1)%3] * T[2][(i+2)%3]; det += T[0][i] * T[1][(i+1)%3] * T[2][(i+2)%3];
@ -330,12 +373,22 @@ transmatrix inverse(transmatrix T) {
for(int j=0; j<3; j++) for(int j=0; j<3; j++)
T2[j][i] = (T[(i+1)%3][(j+1)%3] * T[(i+2)%3][(j+2)%3] - T[(i+1)%3][(j+2)%3] * T[(i+2)%3][(j+1)%3]) / det; T2[j][i] = (T[(i+1)%3][(j+1)%3] * T[(i+2)%3][(j+2)%3] - T[(i+1)%3][(j+2)%3] * T[(i+2)%3][(j+1)%3]) / det;
profile_stop(7);
return T2; return T2;
} }
double hdist(hyperpoint h1, hyperpoint h2) { // distance between mh and 0
hyperpoint mh = gpushxto0(h1) * h2; double hdist0(const hyperpoint& mh) {
return inverse_sinh(sqrt(mh[0]*mh[0]+mh[1]*mh[1])); if(sphere) return mh[2] >= 1 ? 0 : mh[2] <= -1 ? M_PI : acos(mh[2]);
if(!euclid && mh[2] > 1.5) return acosh(mh[2]);
ld d = sqrt(mh[0]*mh[0]+mh[1]*mh[1]);
if(euclid) return d;
return asinh(d);
}
// distance between two points
double hdist(const hyperpoint& h1, const hyperpoint& h2) {
return hdist0(gpushxto0(h1) * h2);
} }
namespace hyperpoint_vec { namespace hyperpoint_vec {
@ -361,3 +414,49 @@ namespace hyperpoint_vec {
} }
} }
hyperpoint mscale(const hyperpoint& t, double fac) {
hyperpoint res;
for(int i=0; i<3; i++)
res[i] = t[i] * fac;
return res;
}
transmatrix mscale(const transmatrix& t, double fac) {
transmatrix res;
for(int i=0; i<3; i++) for(int j=0; j<3; j++)
res[i][j] = t[i][j] * fac;
return res;
}
transmatrix xyscale(const transmatrix& t, double fac) {
transmatrix res;
for(int i=0; i<3; i++) for(int j=0; j<2; j++)
res[i][j] = t[i][j] * fac;
return res;
}
transmatrix xyzscale(const transmatrix& t, double fac, double facz) {
transmatrix res;
for(int i=0; i<3; i++) for(int j=0; j<2; j++)
res[i][j] = t[i][j] * fac;
for(int i=0; i<3; i++)
res[i][2] = t[i][2] * facz;
return res;
}
// double downspin_zivory;
transmatrix mzscale(const transmatrix& t, double fac) {
// take only the spin
transmatrix tcentered = gpushxto0(tC0(t)) * t;
// tcentered = tcentered * spin(downspin_zivory);
fac -= 1;
transmatrix res = t * inverse(tcentered) * ypush(-fac) * tcentered;
fac *= .2;
fac += 1;
for(int i=0; i<3; i++) for(int j=0; j<3; j++)
res[i][j] = res[i][j] * fac;
return res;
}

173
hyperweb.cpp Normal file
View File

@ -0,0 +1,173 @@
#define WEB
#define MOBWEB
#define MINI
#define NOAUDIO
#define NOGFX
#define NOPNG
#define DEMO
#ifdef FAKEWEB
void mainloopiter();
template<class A, class B, class C> void emscripten_set_main_loop(A a, B b, C c) { while(true) mainloopiter(); }
#else
#include <emscripten.h>
#endif
void initweb();
void loadCompressedChar(int &otwidth, int &otheight, int *tpix);
#include "hyper.cpp"
void playSound(cell *c, const string& fname, int vol) { }
void initweb() {
toggleanim(false);
cmode = emMenu;
}
unsigned char fonttable[] = {
43,13,0,255,0,255,0,49,
43,16,0,133,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,236,255,4,235,0,10,206,255,4,205,0,10,176,255,4,175,0,10,146,255,4,145,0,10,116,255,4,115,0,10,86,255,4,85,0,10,55,255,4,55,0,58,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,149,
43,19,0,155,255,4,0,4,255,4,0,7,255,4,0,4,255,4,0,7,255,4,0,4,255,4,0,7,255,4,0,4,255,4,0,7,255,4,0,4,255,4,0,7,255,4,0,4,255,4,0,7,255,4,0,4,255,4,0,7,255,4,0,4,255,4,0,7,255,4,0,4,255,4,0,7,255,4,0,4,255,4,0,255,0,224,
43,30,0,251,152,255,3,72,0,3,28,255,3,188,0,17,223,255,2,247,9,0,3,100,255,3,116,0,16,38,255,3,185,0,4,172,255,3,44,0,16,110,255,3,114,0,3,3,239,255,2,227,0,17,181,255,3,42,0,3,60,255,3,156,0,16,7,245,255,2,227,0,4,132,255,3,84,0,11,255,23,0,7,255,23,0,7,255,23,0,7,255,23,0,11,51,255,3,172,0,4,187,255,3,37,0,16,114,255,3,110,0,3,5,244,255,2,230,0,17,176,255,3,47,0,3,56,255,3,169,0,16,1,237,255,2,239,2,0,3,119,255,3,108,0,16,45,255,3,179,0,4,181,255,3,46,0,11,255,23,0,7,255,23,0,7,255,23,0,7,255,23,0,11,70,255,3,157,0,4,207,255,2,252,12,0,16,131,255,3,95,0,3,15,253,255,2,203,0,17,192,255,3,34,0,3,73,255,3,142,0,16,5,246,255,2,229,0,4,134,255,3,81,0,16,57,255,3,168,0,4,195,255,3,21,0,16,117,255,3,107,0,3,7,248,255,2,215,0,17,178,255,3,46,0,3,61,255,3,154,0,255,0,27,
43,25,0,186,252,255,2,0,22,253,255,2,0,22,254,255,2,0,22,255,3,0,17,24,102,157,193,216,255,3,233,188,130,64,3,0,10,29,169,252,255,11,236,153,51,0,7,58,240,255,16,0,6,21,236,255,17,0,6,137,255,5,238,111,39,255,3,15,46,97,159,238,255,2,0,6,214,255,5,71,0,2,255,3,0,4,5,83,198,0,6,245,255,5,13,0,2,255,3,0,13,244,255,5,85,0,2,255,3,0,13,209,255,5,244,133,59,255,3,0,13,130,255,11,166,119,71,12,0,9,16,227,255,13,249,186,81,2,0,7,38,213,255,15,196,28,0,7,7,106,212,255,14,215,9,0,9,36,105,157,204,255,11,116,0,13,255,3,121,185,255,6,199,0,13,255,3,0,2,106,255,5,238,0,13,255,3,0,2,15,255,5,248,0,4,206,106,18,0,6,255,3,0,2,40,255,5,224,0,4,255,2,252,196,127,79,35,9,0,1,255,3,14,62,204,255,5,158,0,4,255,8,245,255,10,250,44,0,4,255,18,253,97,0,5,255,17,204,60,0,6,21,62,103,145,181,199,215,232,248,255,3,240,215,178,124,49,0,16,4,255,3,0,21,3,255,3,0,21,2,255,3,0,21,1,255,3,0,22,255,3,0,111,
43,36,0,255,0,37,62,163,221,246,246,221,162,62,0,11,11,224,255,2,159,0,10,8,162,255,8,159,7,0,9,141,255,2,235,19,0,10,163,255,10,159,0,8,49,252,255,2,94,0,10,65,255,3,251,109,16,15,109,252,255,3,61,0,6,2,203,255,2,189,0,11,164,255,3,145,0,4,145,255,3,163,0,6,111,255,2,247,37,0,11,223,255,3,47,0,4,48,255,3,222,0,5,28,243,255,2,125,0,12,247,255,3,14,0,4,14,255,3,246,0,5,176,255,2,214,6,0,12,246,255,3,14,0,4,15,255,3,245,0,4,81,255,2,254,61,0,13,222,255,3,48,0,4,49,255,3,221,0,3,13,227,255,2,155,0,14,163,255,3,146,0,4,146,255,3,161,0,3,146,255,2,233,17,0,14,63,255,3,251,108,15,14,107,251,255,3,60,0,2,53,253,255,2,90,0,16,163,255,10,159,0,2,4,207,255,2,185,0,17,8,162,255,8,160,7,0,2,116,255,2,246,35,0,3,60,161,221,245,246,222,163,63,0,8,63,163,222,246,246,222,162,62,0,3,31,244,255,2,121,0,2,7,159,255,8,162,8,0,17,181,255,2,211,5,0,2,160,255,10,162,0,16,86,255,2,254,58,0,2,63,255,3,251,110,16,15,109,252,255,3,64,0,14,15,230,255,2,152,0,3,164,255,3,145,0,4,145,255,3,164,0,14,151,255,2,231,16,0,3,223,255,3,47,0,4,48,255,3,222,0,13,57,254,255,2,87,0,4,247,255,3,14,0,4,14,255,3,246,0,12,5,211,255,2,182,0,5,246,255,3,14,0,4,15,255,3,245,0,12,121,255,2,245,32,0,5,221,255,3,47,0,4,47,255,3,220,0,11,34,246,255,2,117,0,6,161,255,3,144,0,4,141,255,3,161,0,11,185,255,2,208,4,0,6,60,255,3,251,107,15,14,103,250,255,3,59,0,10,91,255,2,253,55,0,8,159,255,10,158,0,10,17,233,255,2,148,0,9,7,159,255,8,160,7,0,10,156,255,2,229,14,0,11,60,161,221,246,246,222,163,62,0,255,0,73,
43,31,0,255,0,2,32,124,187,229,246,251,241,218,186,142,91,30,0,17,6,143,251,255,11,0,16,3,187,255,13,0,16,112,255,14,0,16,209,255,5,186,52,10,14,44,107,197,255,2,0,16,246,255,5,22,0,6,50,187,0,16,239,255,5,43,0,24,179,255,5,184,1,0,23,59,254,255,5,147,0,23,36,228,255,6,146,0,21,86,244,255,8,150,1,0,6,20,255,4,237,0,6,109,254,255,10,155,1,0,5,63,255,4,201,0,5,81,255,13,159,2,0,4,145,255,4,164,0,4,15,235,255,4,241,84,209,255,7,164,3,0,2,21,238,255,4,102,0,4,115,255,5,105,0,1,19,206,255,7,168,4,1,172,255,5,28,0,4,194,255,5,24,0,2,17,204,255,7,172,155,255,5,199,0,5,238,255,5,5,0,3,15,201,255,13,78,0,5,251,255,5,38,0,4,14,198,255,11,202,1,0,5,231,255,5,136,0,5,12,194,255,9,242,37,0,6,190,255,5,250,72,0,5,11,191,255,8,142,0,7,108,255,6,251,131,22,0,2,1,65,200,255,8,244,37,0,6,11,226,255,7,253,224,215,242,255,11,202,4,0,6,67,249,255,22,133,0,7,76,242,255,15,229,227,255,4,253,61,0,7,31,178,254,255,10,249,186,87,4,53,251,255,4,224,15,0,8,36,124,183,224,242,251,238,220,182,137,81,13,0,4,123,255,5,165,0,255,0,25,
43,11,0,91,255,4,0,7,255,4,0,7,255,4,0,7,255,4,0,7,255,4,0,7,255,4,0,7,255,4,0,7,255,4,0,7,255,4,0,7,255,4,0,255,0,24,
43,16,0,119,20,238,255,4,183,0,9,155,255,4,252,42,0,8,45,253,255,4,157,0,9,177,255,4,251,34,0,8,48,255,5,165,0,9,163,255,5,57,0,8,21,250,255,4,211,0,9,111,255,5,121,0,9,199,255,5,38,0,8,20,253,255,4,223,0,9,85,255,5,160,0,9,139,255,5,109,0,9,184,255,5,66,0,9,217,255,5,36,0,9,240,255,5,15,0,9,251,255,5,4,0,9,251,255,5,4,0,9,240,255,5,14,0,9,219,255,5,36,0,9,186,255,5,66,0,9,141,255,5,109,0,9,88,255,5,159,0,9,23,254,255,4,221,0,10,203,255,5,35,0,9,114,255,5,118,0,9,23,251,255,4,208,0,10,165,255,5,54,0,9,50,255,5,163,0,10,178,255,4,250,33,0,9,46,254,255,4,155,0,10,156,255,4,251,41,0,9,21,238,255,4,183,0,66,
43,16,0,114,184,255,4,238,20,0,9,43,252,255,4,153,0,10,157,255,4,253,44,0,9,34,251,255,4,176,0,10,166,255,5,48,0,9,58,255,5,162,0,10,211,255,4,249,20,0,9,122,255,5,109,0,9,39,255,5,198,0,10,224,255,4,253,19,0,9,161,255,5,84,0,9,110,255,5,138,0,9,67,255,5,183,0,9,37,255,5,216,0,9,15,255,5,238,0,9,5,255,5,249,0,9,6,255,5,250,0,9,15,255,5,239,0,9,38,255,5,217,0,9,68,255,5,184,0,9,111,255,5,139,0,9,162,255,5,85,0,9,225,255,4,253,20,0,8,40,255,5,198,0,9,123,255,5,110,0,9,212,255,4,250,21,0,8,59,255,5,162,0,9,167,255,5,48,0,8,35,251,255,4,176,0,9,158,255,4,253,45,0,8,43,252,255,4,154,0,9,184,255,4,238,20,0,71,
43,19,0,160,255,3,0,16,255,3,0,16,255,3,0,9,12,198,83,0,4,255,3,0,4,83,198,12,0,2,126,255,2,196,54,0,2,255,3,0,2,54,196,255,2,125,0,2,173,255,3,254,166,31,255,3,31,166,254,255,3,173,0,3,67,201,255,3,247,255,3,248,255,3,204,69,0,6,82,214,255,7,218,87,1,0,8,8,189,255,5,199,11,0,8,1,86,218,255,7,223,91,1,0,5,69,204,255,3,245,255,3,245,255,3,207,71,0,3,173,255,3,254,161,27,255,3,27,161,254,255,3,174,0,2,126,255,2,193,51,0,2,255,3,0,2,51,193,255,2,125,0,2,12,199,82,0,4,255,3,0,4,83,198,12,0,9,255,3,0,16,255,3,0,16,255,3,0,255,0,95,
43,30,0,255,0,118,255,4,0,26,255,4,0,26,255,4,0,26,255,4,0,26,255,4,0,26,255,4,0,26,255,4,0,26,255,4,0,26,255,4,0,17,255,22,0,8,255,22,0,8,255,22,0,8,255,22,0,17,255,4,0,26,255,4,0,26,255,4,0,26,255,4,0,26,255,4,0,26,255,4,0,26,255,4,0,26,255,4,0,26,255,4,0,255,0,28,
43,14,0,255,0,127,255,6,0,8,255,6,0,8,255,6,0,8,255,6,0,8,255,6,0,7,14,255,5,227,0,7,86,255,5,83,0,7,164,255,4,184,0,7,3,237,255,3,248,36,0,7,63,255,4,130,0,8,140,255,3,222,9,0,8,217,255,3,77,0,63,
43,15,0,255,0,62,255,11,0,4,255,11,0,4,255,11,0,4,255,11,0,4,255,11,0,255,0,2,
43,14,0,255,0,127,255,6,0,8,255,6,0,8,255,6,0,8,255,6,0,8,255,6,0,8,255,6,0,8,255,6,0,130,
43,13,0,112,11,247,255,2,216,0,8,81,255,3,138,0,8,159,255,3,60,0,7,2,234,255,2,235,2,0,7,59,255,3,160,0,8,137,255,3,82,0,8,215,255,2,248,11,0,7,36,255,3,181,0,8,115,255,3,103,0,8,193,255,2,254,26,0,7,18,252,255,2,203,0,8,93,255,3,125,0,8,171,255,3,47,0,7,6,242,255,2,224,0,8,71,255,3,147,0,8,149,255,3,68,0,8,226,255,2,240,5,0,7,49,255,3,168,0,8,127,255,3,90,0,8,205,255,2,251,16,0,7,27,255,3,190,0,8,105,255,3,112,0,8,183,255,3,33,0,7,12,248,255,2,211,0,8,83,255,3,133,0,8,161,255,3,55,0,7,3,235,255,2,231,1,0,7,61,255,3,155,0,8,139,255,3,77,0,8,217,255,2,245,9,0,73,
43,25,0,208,47,125,193,222,244,245,222,193,125,47,0,13,35,174,255,10,173,34,0,10,62,241,255,12,240,59,0,8,56,246,255,14,245,53,0,6,9,217,255,16,214,8,0,5,123,255,5,254,151,51,12,11,50,148,253,255,5,120,0,4,2,225,255,5,106,0,6,102,255,5,223,2,0,3,68,255,5,208,0,8,207,255,5,66,0,3,127,255,5,122,0,8,122,255,5,125,0,3,181,255,5,65,0,8,65,255,5,179,0,3,217,255,5,31,0,8,32,255,5,216,0,3,233,255,5,12,0,8,14,255,5,232,0,3,248,255,5,3,0,8,4,255,5,247,0,3,248,255,5,4,0,8,5,255,5,248,0,3,233,255,5,13,0,8,14,255,5,232,0,3,218,255,5,33,0,8,34,255,5,216,0,3,182,255,5,67,0,8,68,255,5,180,0,3,128,255,5,125,0,8,126,255,5,126,0,3,69,255,5,211,1,0,6,1,212,255,5,67,0,3,3,226,255,5,109,0,6,109,255,5,224,2,0,4,125,255,5,254,152,51,11,11,50,152,254,255,5,121,0,5,10,219,255,16,216,8,0,6,58,247,255,14,246,55,0,8,64,242,255,12,241,62,0,10,38,177,255,10,177,36,0,13,48,127,194,223,245,245,224,194,127,48,0,232,
43,25,0,204,21,63,106,149,191,234,255,6,0,13,255,12,0,13,255,12,0,13,255,12,0,13,255,12,0,13,235,192,149,107,64,21,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,13,255,18,0,7,255,18,0,7,255,18,0,7,255,18,0,7,255,18,0,228,
43,25,0,205,1,49,116,165,209,233,248,248,233,208,159,95,12,0,10,48,144,232,255,11,244,123,6,0,8,255,16,196,14,0,7,255,17,183,0,7,255,18,78,0,6,255,3,254,186,109,45,16,7,37,113,233,255,6,170,0,6,255,1,250,150,37,0,7,25,220,255,5,224,0,6,182,39,0,10,78,255,5,248,0,18,12,255,5,241,0,18,21,255,5,222,0,18,90,255,5,183,0,17,14,218,255,5,130,0,16,10,184,255,6,61,0,15,27,199,255,6,207,0,15,75,236,255,6,253,60,0,13,5,141,254,255,7,129,0,13,33,202,255,8,172,2,0,12,84,240,255,8,181,7,0,11,8,151,255,8,251,120,1,0,11,40,209,255,8,225,57,0,12,94,244,255,8,175,17,0,13,255,19,0,6,255,19,0,6,255,19,0,6,255,19,0,6,255,19,0,228,
43,25,0,203,28,84,132,172,204,229,244,252,248,237,218,183,138,66,4,0,10,255,14,222,92,0,9,255,16,140,0,8,255,17,76,0,7,255,17,183,0,7,224,161,111,67,38,15,5,4,22,64,149,251,255,5,233,0,18,85,255,5,246,0,18,9,255,5,217,0,18,81,255,5,162,0,14,4,21,60,139,247,255,4,253,46,0,11,255,11,251,89,0,12,255,10,175,39,0,13,255,10,252,171,34,0,12,255,12,240,60,0,11,255,13,236,20,0,13,7,22,54,113,211,255,6,128,0,17,3,158,255,5,205,0,18,23,255,5,242,0,18,21,255,5,248,0,5,201,92,8,0,9,2,155,255,5,222,0,5,255,2,244,172,106,58,24,8,3,17,49,107,207,255,6,165,0,5,255,19,65,0,5,255,18,154,0,6,255,17,150,4,0,6,55,166,248,255,12,198,69,0,10,12,84,148,195,229,246,252,241,229,201,161,110,34,0,233,
43,25,0,211,7,212,255,7,0,16,139,255,8,0,15,60,253,255,8,0,14,12,221,255,9,0,14,152,255,3,254,255,6,0,13,72,255,4,143,255,6,0,12,17,229,255,3,215,8,255,6,0,12,165,255,3,251,52,0,1,255,6,0,11,84,255,4,129,0,2,255,6,0,10,23,235,255,3,205,5,0,2,255,6,0,10,179,255,3,248,43,0,3,255,6,0,9,98,255,4,116,0,4,255,6,0,8,31,241,255,3,194,2,0,4,255,6,0,7,1,190,255,3,243,34,0,5,255,6,0,7,111,255,4,102,0,6,255,6,0,7,246,255,3,182,0,7,255,6,0,7,255,22,0,3,255,22,0,3,255,22,0,3,255,22,0,3,255,22,0,15,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,230,
43,25,0,204,255,17,0,8,255,17,0,8,255,17,0,8,255,17,0,8,255,17,0,8,255,5,0,20,255,5,0,20,255,5,0,20,255,5,163,214,239,251,237,219,175,120,35,0,11,255,13,254,181,34,0,9,255,15,244,79,0,8,255,16,248,64,0,7,255,17,219,6,0,6,255,2,238,158,93,40,15,4,21,66,150,249,255,6,94,0,6,199,86,5,0,8,45,232,255,5,172,0,18,89,255,5,221,0,18,14,255,5,244,0,18,14,255,5,244,0,18,89,255,5,220,0,5,206,106,17,0,9,43,232,255,5,168,0,5,255,2,251,193,123,74,32,12,3,19,63,146,248,255,6,86,0,5,255,18,206,2,0,5,255,17,239,47,0,6,255,16,230,54,0,7,52,155,242,255,11,246,150,16,0,10,6,66,133,178,217,237,250,247,231,207,158,100,15,0,232,
43,25,0,209,55,128,193,220,241,249,231,192,134,47,0,13,64,200,255,10,199,67,0,9,1,137,255,14,0,9,163,255,15,0,8,112,255,16,0,7,41,249,255,5,232,131,60,20,5,15,47,110,201,255,2,0,7,158,255,5,177,13,0,8,53,188,0,6,22,248,255,4,212,7,0,17,92,255,5,92,14,111,185,232,250,240,218,165,92,6,0,8,151,255,5,119,239,255,8,228,81,0,7,202,255,17,128,0,6,224,255,18,99,0,5,242,255,18,239,18,0,4,251,255,7,179,58,18,9,51,164,255,6,118,0,4,238,255,6,179,0,6,179,255,5,192,0,4,222,255,6,58,0,6,58,255,5,230,0,4,193,255,6,18,0,6,18,255,5,249,0,4,141,255,6,18,0,6,18,255,5,236,0,4,84,255,6,58,0,6,58,255,5,210,0,4,10,239,255,5,179,0,6,179,255,5,147,0,5,145,255,6,178,57,17,8,51,164,255,6,63,0,5,21,234,255,16,187,0,7,80,254,255,14,232,33,0,8,90,250,255,12,228,50,0,10,55,198,255,9,252,165,20,0,13,64,141,203,229,249,243,224,184,121,33,0,232,
43,25,0,202,255,20,0,5,255,20,0,5,255,20,0,5,255,19,253,0,5,255,19,169,0,17,108,255,6,50,0,16,3,223,255,5,187,0,17,90,255,6,68,0,17,208,255,5,205,0,17,73,255,6,86,0,17,192,255,5,219,2,0,16,55,255,6,103,0,17,174,255,5,232,8,0,16,40,253,255,5,121,0,17,157,255,5,242,16,0,16,26,249,255,5,138,0,17,139,255,5,249,26,0,16,16,242,255,5,156,0,17,122,255,5,253,39,0,16,8,232,255,5,174,0,17,104,255,6,55,0,16,3,220,255,5,191,0,17,87,255,6,72,0,17,205,255,5,208,0,17,69,255,6,90,0,17,188,255,5,223,4,0,237,
43,25,0,206,6,73,149,194,229,243,252,243,229,194,149,73,5,0,11,86,225,255,11,223,83,0,9,121,255,15,119,0,7,58,253,255,15,253,57,0,6,167,255,17,166,0,6,228,255,5,234,101,28,7,27,97,232,255,5,227,0,6,250,255,5,70,0,5,69,255,5,249,0,6,239,255,5,13,0,5,13,255,5,238,0,6,191,255,5,69,0,5,70,255,5,189,0,6,94,255,5,232,98,27,6,27,97,232,255,5,91,0,6,2,181,255,15,165,1,0,7,6,143,251,255,11,245,133,2,0,9,18,136,254,255,9,253,129,18,0,9,113,242,255,13,242,113,0,7,142,255,17,142,0,5,68,255,6,158,61,16,4,26,64,164,254,255,5,67,0,4,176,255,5,122,0,7,120,255,5,175,0,4,233,255,5,16,0,7,17,255,5,232,0,4,251,255,5,16,0,7,17,255,5,250,0,4,234,255,5,119,0,7,118,255,5,232,0,4,193,255,5,254,154,59,15,4,24,62,161,254,255,5,192,0,4,109,255,19,109,0,4,8,217,255,17,217,8,0,5,40,225,255,15,226,40,0,7,21,151,251,255,11,252,154,22,0,10,19,98,159,202,231,244,253,244,231,203,161,101,21,0,231,
43,25,0,207,34,121,184,223,242,248,227,201,137,61,0,13,20,165,252,255,9,193,50,0,10,50,228,255,12,248,81,0,8,32,232,255,14,252,74,0,7,187,255,16,230,17,0,5,63,255,6,167,52,9,9,53,170,255,6,140,0,5,147,255,5,181,0,6,170,255,5,237,8,0,4,210,255,5,58,0,6,53,255,6,82,0,4,237,255,5,18,0,6,9,255,6,138,0,4,250,255,5,18,0,6,9,255,6,191,0,4,232,255,5,58,0,6,52,255,6,220,0,4,194,255,5,179,0,6,167,255,6,237,0,4,121,255,6,179,58,18,18,58,181,255,7,251,0,4,21,242,255,18,241,0,5,106,255,18,223,0,6,136,255,17,201,0,7,88,231,255,8,236,115,255,5,150,0,8,7,95,167,220,241,250,232,185,108,11,99,255,5,90,0,17,10,218,255,4,248,21,0,6,186,50,0,8,17,185,255,5,156,0,7,255,2,195,106,44,13,4,20,61,134,235,255,5,248,40,0,7,255,16,110,0,8,255,15,162,0,9,255,14,135,1,0,9,69,203,255,10,198,63,0,13,53,138,196,234,250,241,220,192,127,54,0,234,
43,14,0,200,255,6,0,8,255,6,0,8,255,6,0,8,255,6,0,8,255,6,0,8,255,6,0,8,255,6,0,92,255,6,0,8,255,6,0,8,255,6,0,8,255,6,0,8,255,6,0,8,255,6,0,8,255,6,0,130,
43,14,0,200,255,6,0,8,255,6,0,8,255,6,0,8,255,6,0,8,255,6,0,8,255,6,0,8,255,6,0,92,255,6,0,8,255,6,0,8,255,6,0,8,255,6,0,8,255,6,0,7,14,255,5,227,0,7,86,255,5,83,0,7,164,255,4,184,0,7,3,237,255,3,248,36,0,7,63,255,4,130,0,8,140,255,3,222,9,0,8,217,255,3,77,0,63,
43,30,0,255,0,129,34,122,211,0,24,26,112,201,255,3,0,21,19,102,191,253,255,5,0,18,13,92,181,250,255,8,0,15,8,82,171,246,255,9,203,118,0,12,4,72,161,241,255,9,201,116,32,0,11,1,62,151,235,255,8,254,199,114,30,0,12,52,140,227,255,8,254,197,112,28,0,15,255,8,253,195,110,27,0,18,255,5,253,193,108,25,0,21,255,5,251,184,100,20,0,21,255,8,252,188,103,22,0,18,52,141,228,255,8,252,191,107,25,0,17,1,63,152,235,255,8,253,195,111,28,0,17,4,73,162,241,255,8,254,198,114,30,0,17,8,83,172,246,255,9,202,118,0,18,13,93,182,250,255,8,0,21,19,103,192,253,255,5,0,24,26,113,202,255,3,0,27,35,123,212,0,255,0,78,
43,30,0,255,0,255,0,4,255,23,0,7,255,23,0,7,255,23,0,7,255,23,0,127,255,23,0,7,255,23,0,7,255,23,0,7,255,23,0,255,0,168,
43,30,0,255,0,109,211,122,34,0,27,255,3,200,112,26,0,24,255,5,253,190,102,19,0,21,255,8,250,180,92,13,0,18,118,203,255,9,246,170,82,8,0,17,32,116,201,255,9,241,160,72,4,0,17,30,114,199,254,255,8,235,150,62,1,0,17,28,112,196,254,255,8,227,140,52,0,18,26,110,194,253,255,8,0,21,24,107,192,253,255,5,0,21,19,99,183,250,255,5,0,18,22,103,187,251,255,8,0,15,25,107,191,252,255,8,228,141,52,0,12,27,110,194,253,255,8,235,151,63,1,0,11,31,114,198,254,255,8,241,161,73,4,0,12,118,202,255,9,246,171,83,8,0,15,255,8,250,181,93,13,0,18,255,5,253,191,103,19,0,21,255,3,201,113,26,0,24,212,123,34,0,255,0,98,
43,21,0,170,28,84,133,175,209,235,248,251,238,216,171,103,18,0,8,255,12,242,114,0,7,255,14,145,0,6,255,15,67,0,5,255,15,171,0,5,255,2,223,136,72,26,6,23,88,227,255,5,229,0,5,194,71,1,0,6,59,255,5,249,0,14,12,255,5,231,0,14,85,255,5,181,0,13,36,233,255,5,82,0,12,53,232,255,5,180,0,12,80,246,255,5,209,17,0,11,87,252,255,5,206,23,0,11,51,249,255,5,179,10,0,12,174,255,5,183,4,0,13,236,255,5,38,0,14,255,6,1,0,77,255,6,0,15,255,6,0,15,255,6,0,15,255,6,0,15,255,6,0,15,255,6,0,198,
43,36,0,255,0,45,19,97,161,207,238,251,246,233,201,159,94,22,0,22,37,166,250,255,10,250,171,50,0,18,18,154,251,255,14,254,158,14,0,15,43,220,255,4,204,123,68,28,11,5,21,58,116,195,255,4,221,40,0,13,70,242,255,3,179,46,0,10,44,176,255,3,235,46,0,11,42,242,255,2,237,77,0,14,86,243,255,2,226,24,0,9,17,220,255,2,224,34,0,16,52,239,255,2,181,0,9,154,255,2,236,33,0,18,67,253,255,2,88,0,7,37,251,255,2,73,0,5,41,155,224,248,231,173,57,0,1,255,4,0,3,143,255,2,210,0,7,167,255,2,170,0,5,101,250,255,5,252,93,255,4,0,3,14,243,255,2,62,0,5,20,251,255,2,43,0,4,81,254,255,7,243,255,4,0,4,153,255,2,135,0,5,97,255,2,195,0,4,12,234,255,3,188,45,7,49,194,255,5,0,4,83,255,2,195,0,5,160,255,2,117,0,4,104,255,3,220,8,0,3,11,225,255,4,0,4,31,255,2,227,0,5,205,255,2,61,0,4,179,255,3,107,0,5,111,255,4,0,4,11,255,2,246,0,5,237,255,2,22,0,4,228,255,3,42,0,5,45,255,4,0,4,7,255,2,244,0,5,250,255,2,6,0,4,247,255,3,13,0,5,14,255,4,0,4,28,255,2,222,0,5,250,255,2,11,0,4,248,255,3,14,0,5,16,255,4,0,4,78,255,2,187,0,5,238,255,2,34,0,4,229,255,3,43,0,5,45,255,4,0,4,164,255,2,118,0,5,208,255,2,61,0,4,181,255,3,109,0,5,113,255,4,0,3,46,252,255,1,250,33,0,5,164,255,2,125,0,4,107,255,3,220,8,0,3,10,224,255,4,0,2,29,220,255,2,149,0,6,105,255,2,198,0,4,13,237,255,3,187,45,6,47,192,255,5,30,115,236,255,2,208,13,0,6,27,253,255,1,253,41,0,4,87,255,8,240,255,8,206,26,0,8,184,255,2,171,0,5,107,251,255,5,251,89,255,6,242,133,6,0,9,66,255,2,254,64,0,5,44,158,225,249,232,174,56,0,1,255,2,250,223,168,103,14,0,12,178,255,2,234,30,0,12,23,12,0,17,27,235,255,2,210,28,0,31,67,249,255,2,231,57,0,13,15,165,91,0,15,81,248,255,2,252,158,29,0,9,10,107,227,255,1,241,32,0,15,64,234,255,3,249,185,109,52,28,6,18,41,91,161,236,255,4,188,0,16,25,174,255,16,176,32,0,18,63,184,253,255,10,248,165,59,0,22,27,105,166,209,239,251,245,225,201,147,86,18,0,120,
43,28,0,233,77,255,8,76,0,18,174,255,8,173,0,17,21,250,255,8,250,20,0,16,113,255,10,112,0,16,210,255,10,209,0,15,52,255,12,51,0,14,149,255,5,214,214,255,5,148,0,13,8,238,255,5,117,118,255,5,238,7,0,12,88,255,5,252,24,25,252,255,5,87,0,12,185,255,5,179,0,2,180,255,5,184,0,11,29,253,255,5,81,0,2,82,255,5,253,28,0,10,124,255,5,235,5,0,2,5,235,255,5,123,0,10,220,255,5,143,0,4,144,255,5,219,0,9,63,255,6,46,0,4,47,255,6,62,0,8,160,255,5,205,0,6,206,255,5,159,0,7,13,244,255,5,108,0,6,109,255,5,244,12,0,6,99,255,20,98,0,6,196,255,20,195,0,5,38,255,22,37,0,4,135,255,22,134,0,3,3,229,255,22,228,3,0,2,74,255,6,36,0,10,36,255,6,73,0,2,171,255,5,193,0,12,194,255,5,170,0,1,19,249,255,5,95,0,12,96,255,5,248,18,110,255,5,242,11,0,12,11,243,255,5,109,207,255,5,156,0,14,157,255,5,207,0,252,
43,27,0,219,255,10,253,244,233,209,174,126,55,1,0,9,255,17,211,74,0,8,255,18,254,108,0,7,255,19,250,46,0,6,255,20,151,0,6,255,6,0,5,16,43,123,240,255,5,218,0,6,255,6,0,8,69,255,5,244,0,6,255,6,0,8,7,255,5,239,0,6,255,6,0,8,67,255,5,208,0,6,255,6,0,5,15,42,120,238,255,5,125,0,6,255,19,226,20,0,6,255,18,213,44,0,7,255,18,143,17,0,7,255,19,228,41,0,6,255,20,218,7,0,5,255,6,0,5,4,21,67,159,255,6,104,0,5,255,6,0,9,119,255,5,189,0,5,255,6,0,9,16,255,5,235,0,5,255,6,0,9,17,255,5,251,0,5,255,6,0,9,122,255,5,235,0,5,255,6,0,5,4,21,67,161,255,6,200,0,5,255,21,122,0,5,255,20,231,16,0,5,255,19,240,60,0,6,255,18,180,38,0,7,255,12,248,236,213,171,117,36,0,249,
43,26,0,218,47,110,171,209,228,246,248,233,205,158,99,21,0,11,3,86,203,255,11,253,179,62,0,8,30,197,255,16,0,7,62,237,255,17,0,6,41,239,255,18,0,5,9,221,255,6,252,167,88,33,12,6,21,47,95,155,234,255,2,0,5,118,255,6,211,41,0,9,3,80,197,0,4,11,237,255,5,209,12,0,17,77,255,5,251,37,0,18,149,255,5,162,0,19,202,255,5,83,0,19,224,255,5,30,0,19,245,255,5,9,0,19,246,255,5,8,0,19,225,255,5,29,0,19,203,255,5,81,0,19,150,255,5,161,0,19,78,255,5,251,36,0,18,11,238,255,5,207,11,0,18,119,255,6,208,38,0,9,3,79,197,0,5,9,222,255,6,252,166,86,32,11,5,20,46,94,155,234,255,2,0,6,42,239,255,18,0,7,63,237,255,17,0,8,30,198,255,16,0,9,3,87,204,255,11,253,180,63,0,12,48,111,172,210,229,247,249,234,206,159,99,22,0,238,
43,30,0,243,255,7,250,245,239,224,208,184,152,111,57,4,0,13,255,16,235,147,34,0,11,255,18,251,136,7,0,9,255,20,202,25,0,8,255,21,216,21,0,7,255,6,0,3,9,23,48,96,157,241,255,7,192,2,0,6,255,6,0,8,9,124,247,255,6,104,0,6,255,6,0,10,52,239,255,5,228,5,0,5,255,6,0,11,71,255,6,66,0,5,255,6,0,12,180,255,5,141,0,5,255,6,0,12,92,255,5,199,0,5,255,6,0,12,34,255,5,223,0,5,255,6,0,12,11,255,5,245,0,5,255,6,0,12,12,255,5,244,0,5,255,6,0,12,36,255,5,222,0,5,255,6,0,12,95,255,5,198,0,5,255,6,0,12,184,255,5,140,0,5,255,6,0,11,75,255,6,66,0,5,255,6,0,10,55,241,255,5,228,5,0,5,255,6,0,8,10,126,248,255,6,104,0,6,255,6,0,3,8,22,47,95,158,242,255,7,192,2,0,6,255,21,217,22,0,7,255,20,202,25,0,8,255,18,250,135,7,0,9,255,16,234,145,32,0,11,255,7,252,247,240,225,208,183,152,110,55,3,0,255,0,25,
43,25,0,203,255,19,0,6,255,19,0,6,255,19,0,6,255,19,0,6,255,19,0,6,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,18,0,7,255,18,0,7,255,18,0,7,255,18,0,7,255,18,0,7,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,19,0,6,255,19,0,6,255,19,0,6,255,19,0,6,255,19,0,228,
43,25,0,203,255,18,0,7,255,18,0,7,255,18,0,7,255,18,0,7,255,18,0,7,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,17,0,8,255,17,0,8,255,17,0,8,255,17,0,8,255,17,0,8,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,241,
43,30,0,250,29,92,151,200,220,237,251,243,230,206,166,124,59,4,0,14,66,178,254,255,12,241,155,54,0,10,18,174,255,18,0,9,48,228,255,19,0,8,32,231,255,20,0,7,5,214,255,7,198,110,53,23,6,10,24,48,90,137,205,254,255,2,0,7,110,255,6,223,63,0,11,21,110,207,0,6,9,235,255,5,217,19,0,21,74,255,5,252,43,0,22,147,255,5,165,0,23,201,255,5,84,0,23,224,255,5,30,0,8,255,10,0,5,245,255,5,10,0,8,255,10,0,5,245,255,5,9,0,8,255,10,0,5,224,255,5,31,0,8,255,10,0,5,202,255,5,85,0,8,255,10,0,5,148,255,5,168,0,12,255,6,0,5,76,255,5,253,48,0,11,255,6,0,5,10,236,255,5,222,24,0,10,255,6,0,6,114,255,6,228,72,0,9,255,6,0,6,7,218,255,7,205,115,59,24,8,5,18,45,97,255,6,0,7,37,235,255,21,0,8,55,233,255,20,0,9,24,187,255,17,253,179,0,10,1,79,194,255,13,221,140,35,0,14,40,104,165,207,226,245,251,238,224,194,151,107,41,0,255,0,22,
43,30,0,243,255,6,0,12,255,6,0,6,255,6,0,12,255,6,0,6,255,6,0,12,255,6,0,6,255,6,0,12,255,6,0,6,255,6,0,12,255,6,0,6,255,6,0,12,255,6,0,6,255,6,0,12,255,6,0,6,255,6,0,12,255,6,0,6,255,6,0,12,255,6,0,6,255,6,0,12,255,6,0,6,255,24,0,6,255,24,0,6,255,24,0,6,255,24,0,6,255,24,0,6,255,6,0,12,255,6,0,6,255,6,0,12,255,6,0,6,255,6,0,12,255,6,0,6,255,6,0,12,255,6,0,6,255,6,0,12,255,6,0,6,255,6,0,12,255,6,0,6,255,6,0,12,255,6,0,6,255,6,0,12,255,6,0,6,255,6,0,12,255,6,0,6,255,6,0,12,255,6,0,6,255,6,0,12,255,6,0,255,0,18,
43,13,0,107,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,121,
43,15,0,125,255,6,0,9,255,6,0,9,255,6,0,9,255,6,0,9,255,6,0,9,255,6,0,9,255,6,0,9,255,6,0,9,255,6,0,9,255,6,0,9,255,6,0,9,255,6,0,9,255,6,0,9,255,6,0,9,255,6,0,9,255,6,0,9,255,6,0,9,255,6,0,9,255,6,0,9,255,6,0,9,255,6,0,9,255,6,0,9,255,6,0,8,2,255,5,253,0,8,22,255,5,237,0,8,79,255,5,217,0,7,4,198,255,5,167,0,5,9,60,189,255,6,104,0,4,255,9,240,13,0,4,255,9,115,0,5,255,8,162,0,6,255,6,239,112,0,7,255,1,252,236,215,165,101,12,0,38,
43,29,0,235,255,6,0,9,38,223,255,6,254,115,0,4,255,6,0,8,54,235,255,6,250,91,0,5,255,6,0,7,73,244,255,6,243,70,0,6,255,6,0,6,95,251,255,6,234,52,0,7,255,6,0,5,120,255,7,222,37,0,8,255,6,0,3,1,145,255,7,207,24,0,9,255,6,0,2,6,168,255,7,190,14,0,10,255,6,0,1,14,189,255,7,170,6,0,11,255,6,24,207,255,7,147,2,0,12,255,6,222,255,7,122,0,14,255,12,251,97,0,15,255,11,245,76,0,16,255,11,169,1,0,16,255,12,157,3,0,15,255,13,171,6,0,14,255,6,248,255,7,184,10,0,13,255,6,66,243,255,7,197,16,0,12,255,6,0,1,53,236,255,7,208,23,0,11,255,6,0,2,41,227,255,7,218,31,0,10,255,6,0,3,31,217,255,7,227,40,0,9,255,6,0,4,22,206,255,7,234,50,0,8,255,6,0,5,14,193,255,7,241,61,0,7,255,6,0,6,8,178,255,7,246,74,0,6,255,6,0,7,4,162,255,7,250,88,0,5,255,6,0,8,1,145,255,7,253,103,0,4,255,6,0,10,127,255,8,119,0,255,0,6,
43,23,0,187,255,6,0,17,255,6,0,17,255,6,0,17,255,6,0,17,255,6,0,17,255,6,0,17,255,6,0,17,255,6,0,17,255,6,0,17,255,6,0,17,255,6,0,17,255,6,0,17,255,6,0,17,255,6,0,17,255,6,0,17,255,6,0,17,255,6,0,17,255,6,0,17,255,6,0,17,255,6,0,17,255,6,0,17,255,19,0,4,255,19,0,4,255,19,0,4,255,19,0,4,255,19,0,208,
43,36,0,255,0,36,255,7,121,0,13,121,255,7,0,7,255,7,229,5,0,11,6,230,255,7,0,7,255,8,94,0,11,95,255,8,0,7,255,8,208,0,11,209,255,8,0,7,255,9,68,0,9,69,255,9,0,7,255,9,183,0,9,184,255,9,0,7,255,10,43,0,7,44,255,10,0,7,255,6,197,255,3,157,0,7,158,255,3,196,255,6,0,7,255,6,82,255,3,248,23,0,5,23,248,255,3,81,255,6,0,7,255,6,2,221,255,3,130,0,5,131,255,3,220,2,255,6,0,7,255,6,0,1,109,255,3,235,9,0,3,9,236,255,3,108,0,1,255,6,0,7,255,6,0,1,11,238,255,3,104,0,3,105,255,3,238,11,0,1,255,6,0,7,255,6,0,2,135,255,3,217,1,0,1,2,218,255,3,134,0,2,255,6,0,7,255,6,0,2,26,250,255,3,78,0,1,79,255,3,250,26,0,2,255,6,0,7,255,6,0,3,162,255,3,193,0,1,194,255,3,161,0,3,255,6,0,7,255,6,0,3,47,255,4,105,255,4,47,0,3,255,6,0,7,255,6,0,4,188,255,3,253,255,3,187,0,4,255,6,0,7,255,6,0,4,74,255,7,73,0,4,255,6,0,7,255,6,0,4,1,214,255,5,213,1,0,4,255,6,0,7,255,6,0,5,100,255,5,99,0,5,255,6,0,7,255,6,0,5,8,233,255,3,233,7,0,5,255,6,0,7,255,6,0,17,255,6,0,7,255,6,0,17,255,6,0,7,255,6,0,17,255,6,0,7,255,6,0,17,255,6,0,7,255,6,0,17,255,6,0,255,0,73,
43,30,0,243,255,7,139,0,10,255,6,0,6,255,7,246,26,0,9,255,6,0,6,255,8,152,0,9,255,6,0,6,255,8,251,35,0,8,255,6,0,6,255,9,165,0,8,255,6,0,6,255,9,254,46,0,7,255,6,0,6,255,6,207,255,3,179,0,7,255,6,0,6,255,6,71,255,4,57,0,6,255,6,0,6,255,6,0,1,188,255,3,192,0,6,255,6,0,6,255,6,0,1,51,254,255,3,71,0,5,255,6,0,6,255,6,0,2,168,255,3,204,1,0,4,255,6,0,6,255,6,0,2,35,250,255,3,84,0,4,255,6,0,6,255,6,0,3,147,255,3,215,3,0,3,255,6,0,6,255,6,0,3,22,242,255,3,97,0,3,255,6,0,6,255,6,0,4,127,255,3,225,7,0,2,255,6,0,6,255,6,0,4,12,232,255,3,111,0,2,255,6,0,6,255,6,0,5,106,255,3,233,12,0,1,255,6,0,6,255,6,0,5,4,219,255,3,124,0,1,255,6,0,6,255,6,0,6,85,255,3,240,18,255,6,0,6,255,6,0,7,202,255,3,137,255,6,0,6,255,6,0,7,65,255,3,246,255,6,0,6,255,6,0,8,183,255,9,0,6,255,6,0,8,46,253,255,8,0,6,255,6,0,9,162,255,8,0,6,255,6,0,9,31,248,255,7,0,6,255,6,0,10,141,255,7,0,255,0,18,
43,31,0,255,0,2,9,73,136,193,218,236,251,236,218,194,136,73,10,0,16,17,125,235,255,11,235,125,17,0,13,63,231,255,15,231,62,0,11,101,252,255,17,251,101,0,9,71,252,255,19,252,69,0,7,23,240,255,6,232,126,55,20,5,21,56,127,233,255,6,239,22,0,6,142,255,6,163,10,0,7,11,167,255,6,141,0,5,19,246,255,5,169,0,10,1,173,255,5,246,19,0,4,89,255,5,240,16,0,11,17,242,255,5,87,0,4,156,255,5,143,0,13,145,255,5,154,0,4,206,255,5,73,0,13,75,255,5,204,0,4,226,255,5,26,0,13,28,255,5,225,0,4,246,255,5,8,0,13,10,255,5,245,0,4,246,255,5,8,0,13,8,255,5,246,0,4,227,255,5,26,0,13,27,255,5,225,0,4,206,255,5,72,0,13,74,255,5,205,0,4,158,255,5,142,0,13,144,255,5,156,0,4,90,255,5,239,14,0,11,16,241,255,5,88,0,4,20,247,255,5,166,0,11,170,255,5,247,20,0,5,144,255,6,160,9,0,7,10,164,255,6,143,0,6,24,241,255,6,230,124,54,19,4,19,55,125,232,255,6,240,23,0,7,74,253,255,19,252,73,0,9,105,252,255,17,252,104,0,11,66,233,255,15,233,66,0,13,18,128,236,255,11,236,128,19,0,16,10,75,138,195,219,238,251,238,220,195,138,75,10,0,255,0,33,
43,26,0,211,255,12,243,227,195,144,73,2,0,8,255,17,225,85,0,7,255,19,152,1,0,5,255,20,129,0,5,255,20,249,35,0,4,255,6,0,5,9,38,101,213,255,6,132,0,4,255,6,0,8,7,184,255,5,202,0,4,255,6,0,9,44,255,5,233,0,4,255,6,0,9,7,255,5,250,0,4,255,6,0,9,45,255,5,233,0,4,255,6,0,8,7,185,255,5,202,0,4,255,6,0,5,8,37,100,213,255,6,131,0,4,255,20,249,35,0,4,255,20,129,0,5,255,19,152,1,0,5,255,17,226,87,0,7,255,12,244,229,197,146,73,2,0,8,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,251,
43,31,0,255,0,2,9,73,136,193,218,236,251,237,219,195,139,78,12,0,16,17,125,235,255,11,239,134,23,0,13,63,231,255,15,238,75,0,11,101,252,255,17,254,118,0,9,71,252,255,19,254,85,0,7,23,240,255,6,232,126,55,20,5,21,56,127,233,255,6,246,30,0,6,142,255,6,163,10,0,7,11,167,255,6,153,0,5,19,246,255,5,169,0,10,1,173,255,5,250,24,0,4,88,255,5,240,16,0,11,17,242,255,5,93,0,4,156,255,5,143,0,13,145,255,5,160,0,4,205,255,5,73,0,13,75,255,5,207,0,4,226,255,5,26,0,13,28,255,5,226,0,4,246,255,5,8,0,13,10,255,5,246,0,4,246,255,5,7,0,13,8,255,5,248,0,4,227,255,5,24,0,13,27,255,5,235,0,4,207,255,5,68,0,13,74,255,5,208,0,4,160,255,5,134,0,13,144,255,5,166,0,4,92,255,5,233,9,0,11,16,241,255,5,104,0,4,22,248,255,5,150,0,11,170,255,5,253,28,0,5,148,255,6,142,5,0,7,10,164,255,6,175,0,6,27,243,255,6,223,117,50,18,4,19,55,125,232,255,6,252,49,0,7,79,253,255,20,136,0,9,108,253,255,18,177,3,0,10,67,233,255,16,156,6,0,12,18,126,233,255,12,229,78,0,16,8,71,132,190,217,235,251,255,6,241,36,0,23,78,253,255,5,207,8,0,23,108,255,6,154,0,24,140,255,6,91,0,23,1,170,255,5,244,40,0,23,8,196,255,5,212,10,0,127,
43,28,0,227,255,10,251,240,226,191,147,74,7,0,11,255,16,227,90,0,10,255,18,121,0,9,255,18,252,50,0,8,255,19,154,0,8,255,6,0,3,2,14,49,127,247,255,5,219,0,8,255,6,0,7,93,255,5,244,0,8,255,6,0,7,12,255,5,248,0,8,255,6,0,7,14,255,5,222,0,8,255,6,0,7,97,255,5,162,0,8,255,6,0,3,1,13,49,129,248,255,5,58,0,8,255,18,143,0,9,255,16,248,123,1,0,9,255,15,231,51,0,11,255,16,242,66,0,10,255,17,244,38,0,9,255,6,0,2,7,33,95,208,255,6,186,0,9,255,6,0,5,6,183,255,6,62,0,8,255,6,0,6,19,234,255,5,179,0,8,255,6,0,7,112,255,5,254,37,0,7,255,6,0,7,12,240,255,5,148,0,7,255,6,0,8,140,255,5,244,16,0,6,255,6,0,8,31,252,255,5,117,0,6,255,6,0,9,170,255,5,225,3,0,5,255,6,0,9,57,255,6,86,0,5,255,6,0,10,200,255,5,199,0,254,
43,26,0,215,27,115,172,217,237,250,249,239,221,193,160,115,68,13,0,10,21,159,253,255,12,252,203,0,8,34,224,255,16,0,7,5,212,255,17,0,7,101,255,18,0,7,186,255,5,243,127,51,15,3,12,30,72,121,190,250,255,2,0,7,231,255,5,73,0,9,15,103,205,0,7,250,255,5,11,0,19,236,255,5,97,0,19,188,255,5,253,172,91,34,1,0,15,96,255,9,244,206,166,120,59,6,0,10,3,192,255,13,239,155,42,0,9,16,182,255,14,253,143,5,0,8,1,84,204,255,14,164,0,11,40,111,171,219,253,255,10,71,0,14,9,51,106,174,248,255,6,170,0,18,22,195,255,5,226,0,19,40,255,5,248,0,5,193,67,0,12,12,255,5,241,0,5,255,2,199,97,13,0,9,110,255,5,217,0,5,255,4,245,176,117,61,31,11,3,21,67,159,254,255,5,158,0,5,255,20,70,0,5,255,19,181,0,6,255,18,201,15,0,6,62,145,225,255,13,243,126,8,0,10,33,93,144,181,216,235,247,252,241,227,195,151,85,9,0,240,
43,25,0,200,255,24,0,1,255,24,0,1,255,24,0,1,255,24,0,1,255,24,0,10,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,235,
43,29,0,235,255,6,0,11,255,6,0,6,255,6,0,11,255,6,0,6,255,6,0,11,255,6,0,6,255,6,0,11,255,6,0,6,255,6,0,11,255,6,0,6,255,6,0,11,255,6,0,6,255,6,0,11,255,6,0,6,255,6,0,11,255,6,0,6,255,6,0,11,255,6,0,6,255,6,0,11,255,6,0,6,255,6,0,11,255,6,0,6,255,6,0,11,255,6,0,6,255,6,0,11,255,6,0,6,255,6,0,11,255,6,0,6,255,6,0,11,255,6,0,6,250,255,5,4,0,9,4,255,5,249,0,6,233,255,5,20,0,9,21,255,5,232,0,6,213,255,5,63,0,9,65,255,5,212,0,6,164,255,5,146,0,9,149,255,5,162,0,6,101,255,5,249,57,0,7,60,250,255,5,101,0,6,18,244,255,5,247,139,56,15,3,15,57,141,248,255,5,243,18,0,7,139,255,19,138,0,8,9,205,255,17,203,9,0,9,26,201,255,15,201,26,0,11,5,125,234,255,11,233,125,5,0,14,7,84,144,198,226,241,252,241,225,197,144,84,6,0,255,0,14,
43,28,0,224,207,255,5,156,0,14,157,255,5,207,110,255,5,242,10,0,12,11,243,255,5,109,19,249,255,5,94,0,12,95,255,5,249,19,0,1,171,255,5,192,0,12,193,255,5,170,0,2,74,255,5,254,34,0,10,35,254,255,5,73,0,2,3,229,255,5,130,0,10,131,255,5,228,3,0,3,135,255,5,225,2,0,8,2,226,255,5,134,0,4,38,255,6,69,0,8,70,255,6,37,0,5,196,255,5,166,0,8,167,255,5,195,0,6,99,255,5,247,16,0,6,17,247,255,5,98,0,6,13,244,255,5,105,0,6,106,255,5,244,12,0,7,160,255,5,202,0,6,203,255,5,159,0,8,63,255,6,43,0,4,44,255,6,62,0,8,1,220,255,5,141,0,4,142,255,5,220,1,0,9,124,255,5,233,4,0,2,5,234,255,5,123,0,10,29,253,255,5,79,0,2,80,255,5,253,28,0,11,185,255,5,177,0,2,178,255,5,184,0,12,88,255,5,251,23,23,251,255,5,87,0,12,8,238,255,5,115,116,255,5,238,7,0,13,149,255,5,212,213,255,5,148,0,14,52,255,12,51,0,15,210,255,10,209,0,16,113,255,10,112,0,16,21,250,255,8,250,21,0,17,174,255,8,173,0,18,77,255,8,76,0,255,0,6,
43,40,0,255,0,66,225,255,5,75,0,8,103,255,6,114,0,8,75,255,5,225,0,2,163,255,5,137,0,8,165,255,6,176,0,8,137,255,5,163,0,2,101,255,5,199,0,8,226,255,6,236,1,0,7,199,255,5,101,0,2,38,255,5,250,10,0,6,32,255,3,245,240,255,3,44,0,6,10,250,255,5,39,0,3,231,255,5,68,0,6,94,255,3,188,181,255,3,105,0,6,66,255,5,233,0,4,170,255,5,130,0,6,156,255,3,127,119,255,3,167,0,6,128,255,5,172,0,4,107,255,5,192,0,6,217,255,3,65,57,255,3,228,0,6,190,255,5,110,0,4,45,255,5,247,7,0,4,23,255,3,250,9,5,246,255,3,35,0,4,5,246,255,5,49,0,4,1,237,255,5,61,0,4,85,255,3,198,0,2,190,255,3,96,0,4,57,255,5,240,2,0,5,176,255,5,123,0,4,146,255,3,137,0,2,128,255,3,158,0,4,119,255,5,181,0,6,114,255,5,185,0,4,208,255,3,76,0,2,66,255,3,220,0,4,181,255,5,120,0,6,52,255,5,243,4,0,2,16,253,255,2,253,16,0,2,10,250,255,3,26,0,2,2,240,255,5,58,0,6,3,242,255,5,54,0,2,75,255,3,209,0,4,199,255,3,87,0,2,48,255,5,246,6,0,7,183,255,5,116,0,2,137,255,3,147,0,4,137,255,3,149,0,2,110,255,5,191,0,8,121,255,5,178,0,2,199,255,3,86,0,4,75,255,3,211,0,2,172,255,5,129,0,8,59,255,5,238,2,9,250,255,3,24,0,4,15,253,255,2,254,18,0,1,233,255,5,67,0,8,6,246,255,5,47,66,255,3,219,0,6,207,255,3,79,40,255,5,250,10,0,9,190,255,5,109,128,255,3,157,0,6,146,255,3,140,101,255,5,200,0,10,128,255,5,171,189,255,3,96,0,6,84,255,3,202,163,255,5,138,0,10,65,255,5,234,245,255,3,35,0,6,22,255,3,251,230,255,5,76,0,10,9,249,255,8,229,0,8,216,255,8,253,17,0,11,197,255,8,168,0,8,154,255,8,209,0,12,134,255,8,106,0,8,93,255,8,147,0,12,72,255,8,45,0,8,31,255,8,86,0,12,13,252,255,6,237,1,0,9,225,255,7,24,0,13,203,255,6,178,0,10,163,255,6,218,0,255,0,112,
43,28,0,225,167,255,6,168,0,10,169,255,6,166,0,2,17,228,255,6,91,0,8,92,255,6,227,16,0,3,68,254,255,5,240,29,0,6,30,240,255,5,254,67,0,5,144,255,6,190,1,0,4,2,191,255,6,143,0,6,8,213,255,6,115,0,4,116,255,6,212,8,0,7,48,250,255,5,248,44,0,2,45,248,255,5,249,48,0,9,121,255,6,209,6,6,209,255,6,120,0,10,2,195,255,6,138,139,255,6,195,2,0,11,33,242,255,5,253,253,255,5,242,32,0,13,97,255,12,96,0,15,174,255,10,174,0,16,20,232,255,8,231,20,0,17,86,255,8,86,0,18,163,255,8,162,0,17,78,255,10,78,0,15,18,231,255,10,231,18,0,14,165,255,12,164,0,13,80,255,6,218,219,255,6,79,0,11,19,232,255,5,253,60,60,253,255,5,231,18,0,10,167,255,6,142,0,2,143,255,6,166,0,9,82,255,6,217,9,0,2,9,218,255,6,81,0,7,20,233,255,5,253,57,0,4,60,253,255,5,232,19,0,6,169,255,6,139,0,6,142,255,6,168,0,5,84,255,6,215,8,0,6,9,218,255,6,83,0,3,21,234,255,5,252,55,0,8,59,253,255,5,233,20,0,2,170,255,6,137,0,10,141,255,6,170,0,253,
43,26,0,208,171,255,6,136,0,10,137,255,6,170,21,235,255,5,252,53,0,8,54,252,255,5,234,21,0,1,87,255,6,212,6,0,6,7,213,255,6,86,0,3,173,255,6,134,0,6,135,255,6,172,0,4,22,236,255,5,251,51,0,4,52,252,255,5,235,22,0,5,89,255,6,211,6,0,2,6,212,255,6,88,0,7,175,255,6,132,0,2,133,255,6,174,0,8,23,236,255,5,251,50,51,251,255,5,236,23,0,9,90,255,6,210,210,255,6,89,0,11,176,255,12,175,0,12,24,237,255,10,237,23,0,13,92,255,10,91,0,15,178,255,8,177,0,16,25,238,255,6,238,24,0,17,93,255,6,92,0,19,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,244,
43,26,0,210,255,23,0,3,255,23,0,3,255,23,0,3,255,23,0,3,255,22,163,0,16,50,245,255,6,195,6,0,15,27,229,255,6,221,20,0,15,10,205,255,6,239,40,0,15,1,174,255,6,251,67,0,16,136,255,7,101,0,16,95,255,7,140,0,16,61,249,255,6,177,2,0,15,34,235,255,6,206,11,0,15,15,214,255,6,229,27,0,15,4,186,255,6,245,50,0,16,150,255,6,253,80,0,16,110,255,7,117,0,16,73,252,255,6,155,0,16,43,241,255,6,189,5,0,15,22,223,255,6,216,17,0,15,7,197,255,6,236,36,0,16,164,255,22,0,3,255,23,0,3,255,23,0,3,255,23,0,3,255,23,0,235,
43,16,0,115,255,11,0,5,255,11,0,5,255,11,0,5,255,11,0,5,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,11,0,5,255,11,0,5,255,11,0,5,255,11,0,66,
43,13,0,104,217,255,2,245,9,0,8,139,255,3,77,0,8,61,255,3,155,0,8,3,235,255,2,231,1,0,8,161,255,3,55,0,8,83,255,3,133,0,8,12,248,255,2,211,0,9,183,255,3,33,0,8,105,255,3,112,0,8,27,255,3,190,0,9,205,255,2,251,16,0,8,127,255,3,90,0,8,49,255,3,168,0,9,226,255,2,240,5,0,8,149,255,3,68,0,8,71,255,3,147,0,8,6,242,255,2,224,0,9,171,255,3,47,0,8,93,255,3,125,0,8,18,252,255,2,203,0,9,193,255,2,254,26,0,8,115,255,3,103,0,8,37,255,3,181,0,9,215,255,2,248,11,0,8,137,255,3,82,0,8,59,255,3,160,0,8,2,234,255,2,235,2,0,8,159,255,3,60,0,8,81,255,3,138,0,8,11,247,255,2,216,0,65,
43,16,0,114,255,11,0,5,255,11,0,5,255,11,0,5,255,11,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,5,255,11,0,5,255,11,0,5,255,11,0,5,255,11,0,67,
43,30,0,252,50,241,255,3,241,49,0,22,39,234,255,5,234,39,0,20,30,226,255,7,226,30,0,18,22,217,255,9,217,22,0,16,15,207,255,5,200,255,5,206,15,0,14,9,195,255,4,242,88,0,1,87,242,255,4,195,9,0,12,5,182,255,4,207,37,0,3,36,205,255,4,181,5,0,10,2,168,255,4,151,7,0,5,7,148,255,4,167,2,0,9,153,255,3,241,86,0,9,83,240,255,3,152,0,8,137,255,3,206,36,0,11,33,202,255,3,136,0,255,0,255,0,243,
43,18,0,255,0,255,0,192,255,54,0,18,
43,18,0,92,137,255,4,95,0,13,154,255,3,242,34,0,12,2,169,255,3,198,3,0,12,5,182,255,3,129,0,13,9,195,255,2,252,59,0,13,15,207,255,2,223,14,0,13,22,217,255,2,164,0,255,0,255,0,54,
43,24,0,255,0,85,23,71,119,167,202,228,243,252,247,234,216,173,122,36,0,10,255,14,180,31,0,8,255,15,235,39,0,7,255,16,211,2,0,6,255,2,201,117,64,26,10,4,19,57,138,249,255,5,84,0,6,185,47,0,9,90,255,5,161,0,17,8,255,5,216,0,7,10,80,150,192,226,240,251,255,9,238,0,6,107,234,255,15,253,0,5,147,255,18,0,4,71,255,19,0,4,173,255,5,241,119,44,11,0,3,1,255,6,0,4,228,255,5,72,0,6,25,255,6,0,4,249,255,5,9,0,6,108,255,6,0,4,236,255,5,67,0,5,46,239,255,6,0,4,185,255,5,231,93,25,5,35,122,244,255,7,0,4,85,255,19,0,5,174,255,11,124,255,6,0,5,8,160,255,8,238,99,0,1,255,6,0,7,57,158,219,245,247,226,189,115,21,0,2,255,6,0,218,
43,26,0,185,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,2,21,116,194,229,249,232,194,113,14,0,9,255,6,0,1,98,238,255,7,229,73,0,8,255,6,124,255,10,251,84,0,7,255,18,245,38,0,6,255,19,189,0,6,255,7,229,99,26,5,25,96,227,255,6,48,0,5,255,6,234,29,0,5,27,233,255,5,134,0,5,255,6,113,0,7,113,255,5,193,0,5,255,6,38,0,7,38,255,5,228,0,5,255,6,7,0,7,8,255,5,246,0,5,255,6,7,0,7,8,255,5,246,0,5,255,6,38,0,7,38,255,5,228,0,5,255,6,112,0,7,113,255,5,193,0,5,255,6,233,27,0,5,27,233,255,5,134,0,5,255,7,227,98,25,4,24,95,226,255,6,48,0,5,255,19,189,0,6,255,18,245,38,0,6,255,6,125,255,10,251,84,0,7,255,6,0,1,100,240,255,7,230,74,0,8,255,6,0,2,23,120,195,231,250,233,195,114,14,0,240,
43,21,0,255,0,46,6,84,147,202,227,245,246,221,164,79,2,0,8,2,114,231,255,9,219,76,0,6,20,192,255,13,0,5,10,200,255,14,0,5,144,255,15,0,4,31,249,255,6,173,74,23,5,19,64,145,243,255,1,0,4,118,255,5,253,93,0,7,20,169,0,4,188,255,5,151,0,14,224,255,5,51,0,14,245,255,5,10,0,14,245,255,5,10,0,14,224,255,5,51,0,14,188,255,5,150,0,14,118,255,5,253,89,0,7,14,163,0,4,31,249,255,6,170,73,21,4,18,58,134,238,255,1,0,5,144,255,15,0,5,10,201,255,14,0,6,20,193,255,13,0,7,2,116,231,255,9,221,77,0,9,6,85,149,204,229,246,247,222,165,80,3,0,192,
43,26,0,199,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,9,14,113,193,232,249,230,194,116,21,0,2,255,6,0,8,75,230,255,7,238,98,0,1,255,6,0,7,87,251,255,10,123,255,6,0,6,41,247,255,18,0,6,192,255,19,0,5,50,255,6,227,97,25,5,26,98,228,255,7,0,5,136,255,5,233,27,0,5,27,233,255,6,0,5,195,255,5,112,0,7,113,255,6,0,5,230,255,5,37,0,7,38,255,6,0,5,247,255,5,7,0,7,8,255,6,0,5,247,255,5,7,0,7,8,255,6,0,5,230,255,5,37,0,7,38,255,6,0,5,195,255,5,112,0,7,113,255,6,0,5,136,255,5,233,27,0,5,27,233,255,6,0,5,50,255,6,227,96,24,4,24,97,227,255,7,0,6,193,255,19,0,6,41,247,255,18,0,7,87,251,255,10,125,255,6,0,8,76,231,255,7,240,101,0,1,255,6,0,9,14,114,195,233,250,231,196,120,23,0,2,255,6,0,237,
43,24,0,255,0,88,9,92,155,209,231,248,242,221,179,112,24,0,11,3,122,236,255,9,246,140,8,0,8,22,195,255,13,202,25,0,6,10,201,255,15,202,8,0,5,145,255,5,246,129,41,7,14,74,206,255,5,140,0,4,31,249,255,4,252,67,0,5,9,203,255,4,246,24,0,3,118,255,5,146,0,7,69,255,5,112,0,3,188,255,5,60,0,7,11,255,5,179,0,3,225,255,19,221,0,3,246,255,19,242,0,3,246,255,20,0,3,225,255,20,0,3,190,255,5,25,0,17,120,255,5,109,0,17,34,251,255,4,238,45,0,9,15,103,205,0,5,150,255,5,245,137,55,15,3,15,33,75,123,191,251,255,2,0,5,13,206,255,17,0,6,24,198,255,16,0,7,3,120,233,255,14,0,9,6,85,148,202,228,245,253,246,236,216,192,159,122,76,25,0,218,
43,16,0,118,29,129,194,233,249,255,5,0,5,90,245,255,9,0,4,49,252,255,10,0,4,163,255,11,0,4,225,255,5,133,19,0,8,249,255,5,12,0,9,255,6,0,7,255,14,0,2,255,14,0,2,255,14,0,2,255,14,0,2,255,14,0,5,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,10,255,6,0,150,
43,26,0,255,0,115,11,110,192,232,249,230,196,119,23,0,2,255,6,0,8,67,226,255,7,240,101,0,1,255,6,0,7,78,249,255,10,125,255,6,0,6,35,243,255,18,0,6,186,255,19,0,5,46,255,6,233,103,26,5,27,104,233,255,7,0,5,133,255,5,238,35,0,5,35,239,255,6,0,5,193,255,5,119,0,7,119,255,6,0,5,229,255,5,40,0,7,41,255,6,0,5,247,255,5,8,0,7,9,255,6,0,5,247,255,5,7,0,7,8,255,6,0,5,229,255,5,36,0,7,40,255,6,0,5,192,255,5,108,0,7,118,255,6,0,5,132,255,5,229,23,0,5,33,237,255,6,0,5,45,255,6,224,94,23,4,26,102,232,255,7,0,6,185,255,19,0,6,35,243,255,18,0,7,78,249,255,10,124,255,6,0,8,68,226,255,7,240,100,5,255,5,248,0,9,12,110,193,233,250,231,196,120,23,0,1,26,255,5,227,0,19,79,255,5,198,0,19,183,255,5,129,0,7,189,58,0,9,120,255,5,254,45,0,7,255,2,209,120,61,22,5,10,36,92,193,255,6,160,0,8,255,16,212,19,0,8,255,15,200,24,0,9,255,13,225,110,2,0,10,32,95,146,189,219,241,251,250,236,221,184,133,68,2,0,34,
43,26,0,185,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,2,7,96,177,223,247,240,212,147,40,0,9,255,6,0,1,74,222,255,7,252,119,0,8,255,6,112,253,255,10,104,0,7,255,18,244,18,0,6,255,19,111,0,6,255,7,249,133,40,7,26,121,251,255,5,178,0,6,255,6,254,74,0,5,121,255,5,224,0,6,255,6,160,0,6,42,255,5,242,0,6,255,6,67,0,6,14,255,6,0,6,255,6,19,0,6,4,255,6,0,6,255,6,2,0,6,1,255,6,0,6,255,6,0,8,255,6,0,6,255,6,0,8,255,6,0,6,255,6,0,8,255,6,0,6,255,6,0,8,255,6,0,6,255,6,0,8,255,6,0,6,255,6,0,8,255,6,0,6,255,6,0,8,255,6,0,6,255,6,0,8,255,6,0,6,255,6,0,8,255,6,0,237,
43,12,0,87,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,30,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,111,
43,13,0,95,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,33,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,7,255,6,0,6,6,255,5,246,0,6,27,255,5,229,0,6,86,255,5,186,0,4,8,64,222,255,5,123,0,3,255,8,249,26,0,3,255,8,121,0,4,255,6,254,137,1,0,4,255,3,245,219,157,52,0,19,
43,25,0,178,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,6,38,228,255,6,118,0,4,255,6,0,5,40,230,255,5,252,100,0,5,255,6,0,4,43,232,255,5,249,83,0,6,255,6,0,3,45,234,255,5,243,68,0,7,255,6,0,2,47,235,255,5,236,54,0,8,255,6,0,1,50,237,255,5,228,42,0,9,255,6,53,239,255,5,218,31,0,10,255,6,240,255,5,207,22,0,11,255,11,194,15,0,12,255,11,116,0,13,255,12,110,0,12,255,6,241,255,6,112,0,11,255,6,60,244,255,6,114,0,10,255,6,0,1,66,247,255,6,115,0,9,255,6,0,2,74,249,255,6,117,0,8,255,6,0,3,82,251,255,6,119,0,7,255,6,0,4,89,253,255,6,121,0,6,255,6,0,5,98,254,255,6,123,0,5,255,6,0,6,106,255,7,125,0,4,255,6,0,7,115,255,7,127,0,225,
43,12,0,87,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,6,255,6,0,111,
43,38,0,255,0,255,0,25,255,6,0,2,30,128,206,237,244,214,156,52,0,5,48,149,212,243,242,216,151,45,0,9,255,6,0,1,109,244,255,7,142,4,0,1,8,147,255,7,253,124,0,8,255,6,130,255,10,149,5,189,255,10,108,0,7,255,17,254,193,255,11,245,19,0,6,255,31,112,0,6,255,7,228,90,18,15,77,233,255,7,229,91,18,16,83,236,255,5,179,0,6,255,6,242,35,0,4,99,255,6,245,37,0,4,93,255,5,224,0,6,255,6,134,0,5,40,255,6,139,0,5,20,255,5,243,0,6,255,6,55,0,5,13,255,6,60,0,6,252,255,5,0,6,255,6,15,0,5,4,255,6,18,0,6,252,255,5,0,6,255,6,2,0,6,255,6,2,0,6,255,6,0,6,255,6,0,7,255,6,0,7,255,6,0,6,255,6,0,7,255,6,0,7,255,6,0,6,255,6,0,7,255,6,0,7,255,6,0,6,255,6,0,7,255,6,0,7,255,6,0,6,255,6,0,7,255,6,0,7,255,6,0,6,255,6,0,7,255,6,0,7,255,6,0,6,255,6,0,7,255,6,0,7,255,6,0,6,255,6,0,7,255,6,0,7,255,6,0,6,255,6,0,7,255,6,0,7,255,6,0,255,0,90,
43,26,0,255,0,112,255,6,0,2,7,96,177,223,247,240,212,147,40,0,9,255,6,0,1,74,222,255,7,252,119,0,8,255,6,112,253,255,10,104,0,7,255,18,244,18,0,6,255,19,111,0,6,255,7,249,133,40,7,26,121,251,255,5,178,0,6,255,6,254,74,0,5,121,255,5,224,0,6,255,6,160,0,6,42,255,5,242,0,6,255,6,67,0,6,14,255,6,0,6,255,6,19,0,6,4,255,6,0,6,255,6,2,0,6,1,255,6,0,6,255,6,0,8,255,6,0,6,255,6,0,8,255,6,0,6,255,6,0,8,255,6,0,6,255,6,0,8,255,6,0,6,255,6,0,8,255,6,0,6,255,6,0,8,255,6,0,6,255,6,0,8,255,6,0,6,255,6,0,8,255,6,0,6,255,6,0,8,255,6,0,237,
43,25,0,255,0,102,6,86,149,204,228,246,247,229,206,151,89,8,0,11,2,116,232,255,10,233,119,3,0,8,20,192,255,14,194,22,0,6,9,200,255,16,201,9,0,5,144,255,18,145,0,4,31,249,255,5,244,127,44,10,8,42,126,243,255,5,249,31,0,3,118,255,5,243,48,0,6,48,244,255,5,117,0,3,188,255,5,126,0,8,126,255,5,187,0,3,225,255,5,42,0,8,43,255,5,223,0,3,246,255,5,8,0,8,9,255,5,245,0,3,246,255,5,8,0,8,9,255,5,245,0,3,225,255,5,42,0,8,43,255,5,223,0,3,188,255,5,125,0,8,125,255,5,187,0,3,118,255,5,243,46,0,6,45,243,255,5,117,0,3,31,249,255,5,243,125,43,8,8,41,123,242,255,5,249,31,0,4,145,255,18,145,0,5,10,201,255,16,201,10,0,6,20,192,255,14,195,22,0,8,2,117,232,255,10,234,120,3,0,11,7,86,150,205,230,247,248,231,207,153,90,8,0,231,
43,26,0,255,0,112,255,6,0,2,21,116,194,229,249,232,194,113,14,0,9,255,6,0,1,98,238,255,7,229,73,0,8,255,6,124,255,10,251,84,0,7,255,18,245,38,0,6,255,19,189,0,6,255,7,229,99,26,5,25,96,227,255,6,48,0,5,255,6,234,29,0,5,27,233,255,5,134,0,5,255,6,113,0,7,113,255,5,193,0,5,255,6,38,0,7,38,255,5,228,0,5,255,6,7,0,7,8,255,5,246,0,5,255,6,7,0,7,8,255,5,246,0,5,255,6,38,0,7,38,255,5,228,0,5,255,6,112,0,7,113,255,5,193,0,5,255,6,233,27,0,5,27,233,255,5,134,0,5,255,7,227,98,25,4,24,95,226,255,6,48,0,5,255,19,189,0,6,255,18,245,38,0,6,255,6,125,255,10,251,84,0,7,255,6,0,1,100,240,255,7,230,74,0,8,255,6,0,2,23,120,195,231,250,233,195,114,14,0,9,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,43,
43,26,0,255,0,115,14,113,193,232,249,230,196,119,23,0,2,255,6,0,8,75,230,255,7,240,101,0,1,255,6,0,7,87,251,255,10,125,255,6,0,6,41,247,255,18,0,6,193,255,19,0,5,51,255,6,227,97,25,5,26,98,228,255,7,0,5,136,255,5,233,27,0,5,27,233,255,6,0,5,195,255,5,112,0,7,113,255,6,0,5,230,255,5,37,0,7,38,255,6,0,5,247,255,5,7,0,7,8,255,6,0,5,247,255,5,7,0,7,8,255,6,0,5,230,255,5,37,0,7,38,255,6,0,5,194,255,5,112,0,7,113,255,6,0,5,134,255,5,233,27,0,5,27,233,255,6,0,5,50,255,6,227,96,24,4,24,97,227,255,7,0,6,192,255,19,0,6,41,247,255,18,0,7,87,251,255,10,125,255,6,0,8,76,231,255,7,240,101,0,1,255,6,0,9,14,114,195,233,250,231,196,120,23,0,2,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,20,255,6,0,29,
43,18,0,255,255,6,0,3,57,156,211,239,255,1,252,0,3,255,6,0,1,15,177,255,5,252,0,3,255,6,12,204,255,6,253,0,3,255,6,166,255,7,254,0,3,255,14,254,0,3,255,8,188,77,21,5,27,89,191,0,3,255,7,139,0,10,255,6,204,2,0,10,255,6,97,0,11,255,6,36,0,11,255,6,9,0,11,255,6,0,12,255,6,0,12,255,6,0,12,255,6,0,12,255,6,0,12,255,6,0,12,255,6,0,12,255,6,0,12,255,6,0,171,
43,21,0,255,0,44,44,125,181,218,239,250,250,241,221,196,162,123,76,25,0,5,20,176,255,14,0,4,11,216,255,15,0,4,129,255,16,0,4,212,255,5,212,80,25,5,18,46,98,163,240,255,2,0,4,245,255,5,35,0,7,6,87,200,0,4,244,255,4,254,14,0,14,206,255,5,178,53,6,0,12,118,255,7,251,223,187,148,99,39,0,7,8,198,255,12,215,108,4,0,5,11,136,241,255,12,189,7,0,6,10,81,144,193,231,255,9,117,0,11,10,45,100,211,255,5,206,0,14,31,255,5,244,0,3,199,85,5,0,8,38,255,5,242,0,3,255,2,240,167,104,57,25,9,6,26,85,215,255,5,202,0,3,255,17,108,0,3,255,16,186,3,0,3,255,14,246,138,5,0,4,25,76,122,160,194,218,238,248,253,245,233,204,164,98,21,0,193,
43,17,0,157,255,6,0,11,255,6,0,11,255,6,0,11,255,6,0,11,255,6,0,8,255,15,0,2,255,15,0,2,255,15,0,2,255,15,0,2,255,15,0,5,255,6,0,11,255,6,0,11,255,6,0,11,255,6,0,11,255,6,0,11,255,6,0,11,255,6,0,11,255,6,0,11,247,255,5,23,0,10,232,255,5,153,26,2,0,8,192,255,11,0,5,129,255,11,0,5,31,246,255,10,0,6,89,249,255,9,0,7,38,144,207,240,253,255,5,0,154,
43,26,0,255,0,112,255,6,0,8,255,6,0,6,255,6,0,8,255,6,0,6,255,6,0,8,255,6,0,6,255,5,254,0,8,255,6,0,6,255,5,253,0,8,255,6,0,6,255,5,252,0,8,255,6,0,6,255,5,250,0,8,255,6,0,6,255,5,248,0,8,255,6,0,6,255,5,248,0,8,255,6,0,6,255,5,248,0,7,2,255,6,0,6,255,5,253,0,7,19,255,6,0,6,255,6,9,0,6,66,255,6,0,6,244,255,5,40,0,6,158,255,6,0,6,225,255,5,122,0,5,71,253,255,6,0,6,179,255,5,250,118,25,6,38,130,248,255,7,0,6,112,255,19,0,6,19,244,255,18,0,7,105,255,10,254,113,255,6,0,8,119,252,255,7,225,77,0,1,255,6,0,9,39,146,212,241,248,226,180,101,9,0,2,255,6,0,237,
43,23,0,255,0,68,207,255,5,156,0,8,157,255,5,207,0,1,110,255,5,242,10,0,6,11,243,255,5,109,0,1,19,249,255,5,94,0,6,95,255,5,249,19,0,2,172,255,5,191,0,6,192,255,5,170,0,3,75,255,5,254,33,0,4,34,254,255,5,73,0,3,3,230,255,5,129,0,4,130,255,5,228,3,0,4,136,255,5,224,2,0,2,2,225,255,5,134,0,5,40,255,6,68,0,2,69,255,6,37,0,6,198,255,5,165,0,2,166,255,5,195,0,7,101,255,5,246,15,16,247,255,5,98,0,7,14,245,255,5,103,104,255,5,244,12,0,8,162,255,5,200,201,255,5,159,0,9,65,255,12,62,0,9,1,223,255,10,219,0,11,127,255,10,123,0,11,31,254,255,8,253,28,0,12,188,255,8,184,0,13,91,255,8,87,0,13,9,241,255,6,238,7,0,14,153,255,6,148,0,214,
43,33,0,255,0,208,222,255,5,85,0,5,71,255,5,71,0,5,86,255,5,222,0,2,155,255,5,151,0,5,134,255,5,133,0,5,153,255,5,155,0,2,88,255,5,218,0,5,196,255,5,195,0,5,220,255,5,88,0,2,22,254,255,5,29,0,3,9,249,255,5,249,8,0,3,31,255,5,254,22,0,3,210,255,5,96,0,3,65,255,7,64,0,3,98,255,5,210,0,4,143,255,5,163,0,3,127,255,7,127,0,3,165,255,5,143,0,4,76,255,5,229,0,3,189,255,3,192,255,3,189,0,3,231,255,5,76,0,4,13,251,255,5,40,0,1,5,245,255,3,67,255,3,246,5,0,1,43,255,5,251,13,0,5,198,255,5,107,0,1,58,255,3,227,0,1,227,255,3,58,0,1,110,255,5,198,0,6,131,255,5,174,0,1,120,255,3,165,0,1,165,255,3,121,0,1,177,255,5,131,0,6,64,255,5,238,2,182,255,3,102,0,1,102,255,3,183,3,240,255,5,64,0,6,7,246,255,5,54,241,255,3,40,0,1,40,255,3,242,59,255,5,246,7,0,7,186,255,5,169,255,3,233,0,3,232,255,3,175,255,5,186,0,8,119,255,5,254,255,3,172,0,3,171,255,9,119,0,8,52,255,9,110,0,3,108,255,9,52,0,8,2,238,255,8,47,0,3,46,255,8,238,2,0,9,174,255,7,239,2,0,3,1,237,255,7,174,0,10,107,255,7,179,0,5,177,255,7,107,0,10,40,255,7,117,0,5,114,255,7,40,0,11,229,255,6,55,0,5,51,255,6,229,0,255,0,48,
43,23,0,255,0,68,160,255,6,210,9,0,4,10,213,255,6,160,0,1,11,214,255,6,154,0,4,160,255,6,213,10,0,2,44,246,255,6,89,0,2,96,255,6,245,42,0,4,99,255,6,242,37,42,245,255,6,96,0,6,163,255,6,207,213,255,6,160,0,7,12,216,255,12,213,10,0,8,46,247,255,10,245,42,0,10,102,255,10,96,0,12,166,255,8,160,0,13,13,228,255,6,227,10,0,13,61,252,255,6,253,64,0,12,15,224,255,8,227,17,0,11,167,255,10,170,0,10,94,255,12,97,0,8,34,242,255,6,254,255,5,243,35,0,6,3,198,255,6,150,144,255,6,200,4,0,5,129,255,6,214,9,7,210,255,6,131,0,4,59,252,255,5,248,47,0,2,44,247,255,5,252,60,0,2,14,223,255,6,113,0,4,110,255,6,223,15,0,1,165,255,6,185,1,0,4,1,182,255,6,165,0,207,
43,23,0,255,0,67,203,255,5,176,0,8,147,255,5,209,0,1,98,255,5,252,29,0,6,5,236,255,5,115,0,1,9,238,255,5,132,0,6,80,255,5,252,24,0,2,142,255,5,232,5,0,5,174,255,5,183,0,3,37,254,255,5,88,0,4,18,249,255,5,89,0,4,186,255,5,194,0,4,107,255,5,241,9,0,4,81,255,6,44,0,3,201,255,5,157,0,5,3,227,255,5,150,0,2,39,255,6,63,0,6,125,255,5,242,13,0,1,133,255,5,223,1,0,6,24,250,255,5,105,1,225,255,5,131,0,8,169,255,5,210,66,255,6,37,0,8,64,255,6,210,255,5,199,0,10,213,255,11,105,0,10,108,255,10,249,17,0,10,14,243,255,9,173,0,12,152,255,9,79,0,12,47,255,8,235,5,0,13,197,255,7,147,0,14,91,255,7,53,0,14,6,234,255,5,214,0,15,3,231,255,5,121,0,15,77,255,5,253,29,0,14,2,193,255,5,183,0,13,14,51,169,255,6,72,0,12,228,255,8,194,0,13,228,255,7,244,39,0,13,228,255,6,238,65,0,14,228,255,3,243,207,133,23,0,35,
43,21,0,255,0,41,255,18,0,3,255,18,0,3,255,18,0,3,255,18,0,3,255,17,209,0,11,12,203,255,6,232,30,0,10,5,184,255,6,247,55,0,10,1,163,255,7,88,0,11,140,255,7,128,0,11,115,255,7,167,0,11,91,254,255,6,200,8,0,10,70,250,255,6,225,23,0,10,51,243,255,6,243,46,0,10,36,233,255,6,253,77,0,10,23,221,255,7,115,0,11,206,255,17,0,3,255,18,0,3,255,18,0,3,255,18,0,3,255,18,0,190,
43,26,0,194,13,104,179,225,244,255,4,0,16,54,227,255,8,0,15,20,234,255,9,0,15,127,255,10,0,15,199,255,5,228,85,23,4,0,16,238,255,5,89,0,19,253,255,5,27,0,19,255,6,5,0,19,255,6,0,20,255,6,0,19,3,255,6,0,19,18,255,5,251,0,19,61,255,5,237,0,19,155,255,5,200,0,16,7,42,143,255,6,128,0,15,255,9,217,17,0,15,255,7,234,136,17,0,16,255,7,254,193,52,0,16,255,9,245,41,0,16,8,40,133,252,255,5,156,0,19,138,255,5,217,0,19,47,255,5,245,0,19,11,255,5,254,0,20,255,6,0,20,255,6,0,20,255,6,3,0,19,254,255,5,21,0,19,240,255,5,77,0,19,206,255,5,221,77,21,3,0,16,136,255,10,0,15,25,240,255,9,0,16,62,232,255,8,0,17,16,110,182,226,245,255,4,0,83,
43,13,0,83,255,4,0,9,255,4,0,9,255,4,0,9,255,4,0,9,255,4,0,9,255,4,0,9,255,4,0,9,255,4,0,9,255,4,0,9,255,4,0,9,255,4,0,9,255,4,0,9,255,4,0,9,255,4,0,9,255,4,0,9,255,4,0,9,255,4,0,9,255,4,0,9,255,4,0,9,255,4,0,9,255,4,0,9,255,4,0,9,255,4,0,9,255,4,0,9,255,4,0,9,255,4,0,9,255,4,0,9,255,4,0,9,255,4,0,9,255,4,0,9,255,4,0,9,255,4,0,9,255,4,0,9,255,4,0,9,255,4,0,9,255,4,0,17,
43,26,0,187,255,4,244,224,179,104,13,0,17,255,8,226,54,0,16,255,9,234,19,0,15,255,10,126,0,16,4,23,85,229,255,5,199,0,19,90,255,5,237,0,19,28,255,5,253,0,19,7,255,6,0,20,255,6,0,20,255,6,0,20,255,6,3,0,19,252,255,5,17,0,19,238,255,5,59,0,19,201,255,5,151,0,19,129,255,5,254,141,42,7,0,16,17,218,255,9,0,16,17,135,234,255,7,0,16,51,192,254,255,7,0,15,41,244,255,9,0,15,157,255,5,252,132,39,8,0,16,218,255,5,135,0,19,246,255,5,46,0,19,255,6,9,0,19,255,6,0,20,255,6,0,19,3,255,6,0,19,22,255,5,254,0,19,78,255,5,239,0,16,3,21,77,221,255,5,206,0,15,255,10,135,0,15,255,9,240,25,0,15,255,8,232,62,0,16,255,4,245,226,182,110,16,0,90,
43,30,0,255,0,255,0,56,33,0,9,20,113,181,228,248,238,212,162,95,25,0,8,10,121,246,0,7,21,150,248,255,8,253,198,124,65,21,4,21,63,136,235,255,2,0,7,241,255,22,0,7,255,22,241,0,7,255,2,249,157,72,25,5,23,65,126,199,253,255,8,249,152,22,0,7,255,1,179,34,0,8,25,96,163,212,239,249,229,184,117,22,0,9,113,0,255,0,255,0,25,
43,22,0,200,255,18,0,4,255,18,0,4,255,2,0,14,255,2,0,4,255,2,0,14,255,2,0,4,255,2,0,14,255,2,0,4,255,2,0,14,255,2,0,4,255,2,0,14,255,2,0,4,255,2,0,14,255,2,0,4,255,2,0,14,255,2,0,4,255,2,0,14,255,2,0,4,255,2,0,14,255,2,0,4,255,2,0,14,255,2,0,4,255,2,0,14,255,2,0,4,255,2,0,14,255,2,0,4,255,2,0,14,255,2,0,4,255,2,0,14,255,2,0,4,255,2,0,14,255,2,0,4,255,2,0,14,255,2,0,4,255,2,0,14,255,2,0,4,255,2,0,14,255,2,0,4,255,2,0,14,255,2,0,4,255,2,0,14,255,2,0,4,255,2,0,14,255,2,0,4,255,2,0,14,255,2,0,4,255,2,0,14,255,2,0,4,255,2,0,14,255,2,0,4,255,2,0,14,255,2,0,4,255,2,0,14,255,2,0,4,255,2,0,14,255,2,0,4,255,2,0,14,255,2,0,4,255,18,0,4,255,18,0,46,
43,18,0,131,9,116,204,243,243,198,106,6,0,9,31,212,255,6,207,28,0,7,10,213,255,8,208,7,0,6,117,255,2,249,117,24,24,119,250,255,2,108,0,6,205,255,2,117,0,4,120,255,2,199,0,6,245,255,2,24,0,4,25,255,2,243,0,6,245,255,2,22,0,4,23,255,2,243,0,6,208,255,2,111,0,4,114,255,2,201,0,6,123,255,2,247,112,23,23,114,248,255,2,112,0,6,12,219,255,8,213,9,0,7,37,219,255,6,212,32,0,9,12,123,208,245,244,201,111,7,0,255,0,182,
43,24,0,134,95,255,4,136,0,17,34,242,255,3,153,0,17,4,199,255,3,168,2,0,17,130,255,3,182,5,0,17,60,252,255,2,194,9,0,17,15,223,255,2,206,15,0,18,165,255,2,217,21,0,64,9,92,155,209,231,248,242,221,179,112,24,0,11,3,122,236,255,9,246,140,8,0,8,22,195,255,13,202,25,0,6,10,201,255,15,202,8,0,5,145,255,5,246,129,41,7,14,74,206,255,5,140,0,4,31,249,255,4,252,67,0,5,9,203,255,4,246,24,0,3,118,255,5,146,0,7,69,255,5,112,0,3,188,255,5,60,0,7,11,255,5,179,0,3,225,255,19,221,0,3,246,255,19,242,0,3,246,255,20,0,3,225,255,20,0,3,190,255,5,25,0,17,120,255,5,109,0,17,34,251,255,4,238,45,0,9,15,103,205,0,5,150,255,5,245,137,55,15,3,15,33,75,123,191,251,255,2,0,5,13,206,255,17,0,6,24,198,255,16,0,7,3,120,233,255,14,0,9,6,85,148,202,228,245,253,246,236,216,192,159,122,76,25,0,218,
43,24,0,133,95,255,4,136,0,17,34,242,255,3,153,0,17,4,199,255,3,168,2,0,17,130,255,3,182,5,0,17,60,252,255,2,194,9,0,17,15,223,255,2,206,15,0,18,165,255,2,217,21,0,62,23,71,119,167,202,228,243,252,247,234,216,173,122,36,0,10,255,14,180,31,0,8,255,15,235,39,0,7,255,16,211,2,0,6,255,2,201,117,64,26,10,4,19,57,138,249,255,5,84,0,6,185,47,0,9,90,255,5,161,0,17,8,255,5,216,0,7,10,80,150,192,226,240,251,255,9,238,0,6,107,234,255,15,253,0,5,147,255,18,0,4,71,255,19,0,4,173,255,5,241,119,44,11,0,3,1,255,6,0,4,228,255,5,72,0,6,25,255,6,0,4,249,255,5,9,0,6,108,255,6,0,4,236,255,5,67,0,5,46,239,255,6,0,4,185,255,5,231,93,25,5,35,122,244,255,7,0,4,85,255,19,0,5,174,255,11,124,255,6,0,5,8,160,255,8,238,99,0,1,255,6,0,7,57,158,219,245,247,226,189,115,21,0,2,255,6,0,218,
};
unsigned char *ftv = fonttable;
/* fonttable is obtained with:
if(ch >= 32) {
printf("%d,%d,", txt->h, txt->w);
int rle_last = -1, rle_q = 0;
for(int j=0; j <txt->h;j++) {
for(int i=0; i < txt->w; i++) {
int c = (unsigned char) (qpixel(txt, i, j) >> 24);
if(c == rle_last && rle_q < 255) rle_q++;
else {
if(rle_last != -1) printf("%d,%d,", rle_last, rle_q);
if(c == 0 || c == 255) rle_last = c, rle_q = 1;
else { rle_last = -1; printf("%d,", c); }
}
}
}
if(rle_last != -1) printf("%d,%d,", rle_last, rle_q);
printf("\n");
}
*/
void loadCompressedChar(int &otwidth, int &otheight, int *tpix) {
otheight = *(ftv++);
otwidth = *(ftv++);
int left = otwidth * otheight;
while(left) {
int x = *(ftv++);
if(x == 0 || x == 255) {
x = x * 0x1010101;
int q = *(ftv++);
left -= q;
while(q--) *(tpix++) = x;
}
else {
*(tpix++) = (x << 24) | 0xFFFFFF;
left--;
}
}
}

541
init.cpp Normal file
View File

@ -0,0 +1,541 @@
#define VER "9.4c"
#define VERNUM 9403
#define VERNUM_HEX 0x9403
#define GEN_M 0
#define GEN_F 1
#define GEN_N 2
#define GEN_O 3
#ifdef MOBILE
#define MOBWEB
#endif
#ifdef WEB
#define MOBWEB
#define ONEGRAPH
#endif
#ifdef IOS
#define ONEGRAPH
#endif
#ifdef MOBWEB
#define NORUG
#define NOEDIT
#define NOMODEL
#endif
#ifdef MINI
#define NORUG
#define NOEDIT
#define NOMODEL
#define NOSAVE
#define NOCONFIG
#define NOTRANS
#endif
#ifdef MOBILE
#define EXTRALICENSE "\n\nHyperRogue soundtrack by Shawn Parrotte (http://www.shawnparrotte.com), under the Creative Commons BY-SA 3.0 license, http://creativecommons.org/licenses/by-sa/3.0/"
#undef XEXTRALICENSE
#ifndef FAKEMOBILE
#define SDLK_F1 (123001)
#define SDLK_F2 (123002)
#define SDLK_F3 (123003)
#define SDLK_F4 (123004)
#define SDLK_F5 (123005)
#define SDLK_F6 (123006)
#define SDLK_F7 (123007)
#define SDLK_F10 (123010)
#define SDLK_ESCAPE (123099)
#define SDLK_F12 (123012)
#define SDLK_HOME (123013)
#define SDLK_LEFT (123014)
#define SDLK_RIGHT (123015)
#define MIX_MAX_VOLUME 128
#define SDLK_UP (123021)
#define SDLK_DOWN (123022)
#define SDLK_PAGEUP (123023)
#define SDLK_PAGEDOWN (123024)
#define SDLK_RETURN (123025)
#define SDLK_KP1 (123031)
#define SDLK_KP2 (123032)
#define SDLK_KP3 (123033)
#define SDLK_KP4 (123034)
#define SDLK_KP5 (123035)
#define SDLK_KP6 (123036)
#define SDLK_KP7 (123037)
#define SDLK_KP8 (123038)
#define SDLK_KP9 (123039)
#define SDLK_KP_PERIOD (123051)
#define SDLK_DELETE (123052)
#define SDLK_DELETE (123052)
#endif
int fontscale = 100;
bool buttonclicked;
void gdpush(int t);
#endif
// desktop
#include <stdio.h>
#ifdef USE_SDL
#include <SDL/SDL.h>
#ifndef MAC
#undef main
#endif
#include <SDL/SDL_ttf.h>
#endif
#include <cmath>
#include <time.h>
#include <vector>
#include <string>
#include <algorithm>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <map>
#ifdef USE_UNORDERED_MAP
#include <unordered_map>
#else
#define unordered_map map
#endif
using namespace std;
string s0;
void addMessage(string s, char spamtype = 0);
#ifdef ANDROID
FILE *debfile;
#endif
FILE *debugfile;
int debugflags;
#ifdef USE_COMMANDLINE
const char *scorefile = "hyperrogue.log";
const char *conffile = "hyperrogue.ini";
string levelfile = "hyperrogue.lev";
string picfile = "hyperrogue.pic";
const char *musicfile = "";
const char *loadlevel = NULL;
#endif
#define S7 (sphere?5:7)
#define S42 (S7*6)
#define S14 (S7*2)
#define S21 (S7*3)
#define S28 (S7*4)
#define S84 (S7*12)
#include "util.cpp"
#include "hyperpoint.cpp"
#include "patterns.cpp"
#include "classes.cpp"
#include "fieldpattern.cpp"
#include "heptagon.cpp"
#include "language.cpp"
#include "hyper.h"
#include "cell.cpp"
#include "flags.cpp"
#include "yendor.cpp"
#include "complex.cpp"
#include "game.cpp"
#include "landgen.cpp"
#include "orbs.cpp"
#include "system.cpp"
#include "geometry.cpp"
#include "polygons.cpp"
#include "mapeditor.cpp"
#ifndef MOBILE
#include "netgen.cpp"
#endif
#include "graph.cpp"
#include "sound.cpp"
#include "achievement.cpp"
#ifndef MOBILE
#include <unistd.h>
#endif
bool fixseed = false;
void initAll() {
ca::init();
arg::read(1);
srand(time(NULL));
shrand(fixseed ? 0 : time(NULL));
achievement_init(); // not in ANDROID
eLand f = firstland;
// initlanguage();
initgraph();
#ifndef NOSAVE
loadsave();
#endif
resetGeometry();
initcells();
shmup::safety = safety;
initgame();
restartGraph();
if(!shmup::on) {
restoreGolems(items[itOrbLife], moGolem); items[itOrbLife] = 0;
restoreGolems(items[itOrbFriend], moTameBomberbird); items[itOrbFriend] = 0;
restoreGolems(kills[moPrincessMoved], moPrincess, princess::saveHP); kills[moPrincessMoved] = 0;
restoreGolems(kills[moPrincessArmedMoved], moPrincessArmed, princess::saveArmedHP); kills[moPrincessArmedMoved] = 0;
}
firstland = f;
}
void finishAll() {
achievement_final(!items[itOrbSafety]);
#ifndef NOSAVE
saveStats();
#endif
offscreen.clear();
clearMemory();
#ifndef MOBILE
cleargraph();
#endif
achievement_close();
}
#ifdef ANDROID
string buildScoreDescription() {
string s;
time_t timer;
timer = time(NULL);
char buf[128]; strftime(buf, 128, "%c", localtime(&timer));
char buf2[128];
s += XLAT("HyperRogue for Android");
s += " ("VER"), http://www.roguetemple.com/z/hyper.php\n";
s += XLAT("Date: %1 time: %2 s ", buf, its(savetime + time(NULL) - timerstart));
s += XLAT("distance: %1\n", its(celldist(cwt.c)));
// s += buf2;
if(cheater) s += XLAT("Cheats: ") + its(cheater) + "\n";
s += XLAT("Score: ") + its(gold());
for(int i=0; i<ittypes; i++) if(items[i]) {
string t = XLATN(iinf[i].name);
sprintf(buf2, " %s (%d)", t.c_str(), items[i]);
s += buf2;
}
s += "\n";
s += XLAT("Kills: ") + its(tkills());
for(int i=1; i<motypes; i++) if(kills[i]) {
string t = XLATN(minf[i].name);
sprintf(buf2, " %s (%d)", t.c_str(), kills[i]);
s += buf2;
}
s += "\n";
for(int i=0; i<gamelog.size(); i++) if(gamelog[i].msg != "") s += gamelog[i].msg + "\n";
return s;
}
#endif
#ifdef MOBILE
bool lclicked = false, clicked = false;
string lmouseovers;
bool inmenu = false;
bool longclick;
void handleScoreClick();
void openURL();
void displayTexts();
void controlMusic(int ticks);
void showHelp(MOBPAR_FORMAL, string nhelp) {
help = nhelp;
// helptext = help;
lastmode = cmode;
cmode = emHelp;
}
bool useRangedOrb;
void handleclick(MOBPAR_FORMAL) {
if(!shmup::on && andmode == 0 && cmode == emNormal && canmove && !useRangedOrb && vid.mobilecompasssize > 0) {
using namespace shmupballs;
int dx = mousex - xmove;
int dy = mousey - yb;
int h = hypot(dx, dy);
if(h < rad) {
if(h < rad*SKIPFAC) movepcto(MD_WAIT);
else {
double d = revcontrol ? -1 : 1;
mouseh = hpxy(dx * d / rad, dy * d / rad);
mousemovement();
}
getcstat = 0;
return;
}
}
if(buttonclicked || outofmap(mouseh)) {
if(andmode == 0 && getcstat == 'g' && !shmup::on) {
movepcto(MD_DROP);
getcstat = 0;
}
else if(getcstat != SDLK_F1) {
int px = mousex < vid.xcenter ? 0 : 1;
int py = mousey < vid.ycenter ? 0 : 1;
if(cmode == (canmove ? emNormal : emQuit)) {
if(px == 0 && py == 1) {
if(andmode == 0 && shmup::on) ;
else andmode = 10;
}
if(px == 1 && py == 1) {
if(andmode == 0 && shmup::on) ; // just fire, do not change modes
else {
if(andmode == 1) {
centerpc(INF);
View = Id;
viewctr.h = cwt.c->master;
}
andmode = 11;
}
}
if(px == 0 && py == 0) andmode = 22;
if(px == 1 && py == 0) andmode = 13;
}
}
else {
if(andmode == 0 && help != "@") {
addMessage(mouseovers);
showHelp(MOBPAR_ACTUAL, help);
andmode = 10;
getcstat = 0;
return;
}
}
}
if(andmode == 0 && cmode == (canmove ? emNormal : emQuit) && !outofmap(mouseh)) {
bool forcetarget = longclick;
if(mouseover && targetclick && targetRangedOrb(mouseover, forcetarget ? roMouseForce : roMouse)) {
;
}
else if(!forcetarget) movepcto(mousedest);
}
if(andmode == 10) {
if(!playerfound) {
centerpc(INF);
View = Id;
viewctr.h = cwt.c->master;
}
playermoved = true;
}
if(andmode >= 10) andmode -= 10;
if(andmode == 3) cmode = emMenu, andmode = 0;
}
int touchedAt;
int getticks();
void mobile_draw(MOBPAR_FORMAL) {
optimizeview();
int lastt = ticks; ticks = getticks();
if(lastt > ticks) lastt = ticks;
int tdiff = ticks - lastt;
if(playermoved && vid.sspeed > -4.99)
centerpc(tdiff / 1000.0 * exp(vid.sspeed));
if(shmup::on && (andmode == 0 || andmode == 10) && cmode == emNormal)
shmup::turn(tdiff);
safety = false;
vid.fsize = (min(vid.xres, vid.yres) * fontscale + 50) / 3200;
hyperpoint mouseoh = mouseh;
gtouched = mousepressed = clicked;
longclick = lclicked && ticks > touchedAt + 500;
useRangedOrb =
longclick || (!(vid.shifttarget & 2) && haveRangedOrb() && lmouseover && lmouseover->cpdist > 1);
targetclick = ((vid.shifttarget & 2) && !shmup::on) ? longclick : true;
if(shmup::on) {
using namespace shmupballs;
if(hypot(mousex - xfire, mousey - yb) < rad) targetclick = false;
if(hypot(mousex - xmove, mousey - yb) < rad) targetclick = false;
}
if(cmode == emNormal) {
lmouseover = (gtouched && lclicked) ? mouseover : NULL;
if(!shmup::on && !useRangedOrb && vid.mobilecompasssize) {
using namespace shmupballs;
int dx = mousex - xmove;
int dy = mousey - yb;
int h = hypot(dx, dy);
if(h < rad) {
if(h < rad*SKIPFAC) { lmouseover = cwt.c; mousedest.d = -1; }
else {
double d = revcontrol ? -1 : 1;
mouseh = hpxy(dx * d / rad, dy * d / rad);
calcMousedest();
}
}
}
if(andmode == 0 && !useRangedOrb && gtouched && lclicked) {
lmouseover = mousedest.d >= 0 ? cwt.c->mov[(cwt.spin + mousedest.d) % cwt.c->type] : cwt.c;
}
}
mouseh = gethyper(mousex, mousey);
// if(debfile) fprintf(debfile, "d1\n"), fflush(debfile);
frames++;
if(conformal::on) conformal::apply();
if(ticks > lastt) tortoise::updateVals(ticks - lastt);
if(clicked && !lclicked) touchedAt = ticks;
graphdata.clear();
getcstat = 0; shiftmul = 1; getcshift = 1;
drawscreen();
shiftmul = getcshift;
calcMousedest();
if(lclicked && !clicked && !inmenu) handleclick(MOBPAR_ACTUAL);
if(inmenu && !clicked && !lclicked) inmenu = false;
bool keyreact = lclicked && !clicked;
if(cmode == emOverview || cmode == emTactic) {
using namespace dialog::zoom;
if(zoomoff || (cmode != emOverview && cmode != emTactic)) {
zoomf = 1; shiftx = shifty = 0; zoomoff = false; return;
}
if(clicked && !lclicked) {
zoomf = 3;
}
if(zoomf == 3) {
shiftx = -2*mousex;
shifty = -2*mousey;
}
if(!clicked && zoomf > 1) { zoomoff = true; }
}
if(inslider) keyreact = true;
#ifdef ANDROID
if(getcstat == 's'-96) {
cmode = canmove ? emQuit : emNormal;
shareScore(MOBPAR_ACTUAL);
cmode = emNormal;
}
#endif
if(andmode == 2 && cmode != emNormal) andmode = 12;
if((cmode == emQuit && !canmove && keyreact && lclicked && !clicked) && !buttonclicked) {
cmode = emNormal; printf("back to quit\n");
}
else if(cmode == emScores) handleScoreKeys(0);
else if(getcstat && keyreact) {
if(cmode == (canmove ? emQuit : emNormal))
handleQuit(getcstat, getcstat);
else {
if(cmode != emNormal && cmode != emQuit) inmenu = true;
if(cmode == emMenu && getcstat == 'q') openURL();
else { extra ex; handlekey(getcstat, getcstat, ex); }
}
}
#ifdef IOS
displayTexts();
#endif
if((cmode != emVisual1 && cmode != emScores)) {
if(clicked && lclicked && andmode == 1 && !inmenu) {
if(!outofmap(mouseoh) && !outofmap(mouseh) && mouseoh[2] < 50 && mouseh[2] < 50) {
panning(mouseoh, mouseh);
}
}
if(andmode == 1 && lclicked && !clicked && !inmenu && mouseover)
performMarkCommand(mouseover);
if(clicked && andmode == 2 && (mouseover != lmouseover || mouseovers != lmouseovers) && cmode == emNormal) {
addMessage(mouseovers);
lmouseovers = mouseovers;
}
if(andmode == 10 && clicked != lclicked) andmode = 0;
if(andmode == 20 && clicked != lclicked) andmode = 10;
if(andmode == 2 && lclicked && !clicked) {
if(cmode == emNormal)
showHelp(MOBPAR_ACTUAL, help);
else if(cmode != emScores && cmode != emPickScores)
cmode = emNormal;
}
else if(andmode == 4) {
achievement_final(false);
}
if(clicked && andmode == 2 && (mouseover != lmouseover || mouseovers != lmouseovers)) {
addMessage(mouseovers);
showHelp(MOBPAR_ACTUAL, help);
lmouseovers = mouseovers;
}
}
if(clicked != lclicked)
flashMessages();
// END
lclicked = clicked;
#ifdef IOS
controlMusic(ticks - lastt);
#endif
}
#ifdef MOBILE
#include "google-games.cpp"
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -136,10 +136,13 @@ void setstats(set<string>& s, const char* bn) {
int main() { int main() {
nothe.insert("R'Lyeh"); nothe.insert("R'Lyeh");
nothe.insert("Camelot");
plural.insert("Crossroads"); plural.insert("Crossroads");
plural.insert("Crossroads II"); plural.insert("Crossroads II");
plural.insert("Crossroads III"); plural.insert("Crossroads III");
plural.insert("Elemental Planes"); plural.insert("Elemental Planes");
plural.insert("Crossroads IV");
plural.insert("Kraken Depths");
#define S(a,b) d[1].add(a,b); #define S(a,b) d[1].add(a,b);
#define N(a,b,c,d,e,f) \ #define N(a,b,c,d,e,f) \
@ -188,8 +191,8 @@ int main() {
string mis = ""; string mis = "";
for(int i=1; i<NUMLAN; i++) if(d[i].count(*x) == 0) for(int i=1; i<NUMLAN; i++) if(d[i].count(*x) == 0)
mis += d[i]["EN"]; mis += d[i]["EN"];
if(mis != "" && mis != "TR" && mis != "TRDE" && mis != "DE") if(mis != "")
printf("#warning Missing [%s]: %s\n", mis.c_str(), escape(*x, "?")); printf("// #warning Missing [%s]: %s\n", mis.c_str(), escape(*x, "?"));
} }
s.clear(); s.clear();
@ -202,8 +205,8 @@ int main() {
string mis = ""; string mis = "";
for(int i=1; i<NUMLAN; i++) if(nouns[i].count(*x) == 0) for(int i=1; i<NUMLAN; i++) if(nouns[i].count(*x) == 0)
mis += d[i]["EN"]; mis += d[i]["EN"];
if(mis != "" && mis != "TR" && mis != "TRDE" && mis != "DE") if(mis != "")
printf("#warning Missing [%s]: %s\n", mis.c_str(), escape(*x, "?")); printf("// #warning Missing [%s]: %s\n", mis.c_str(), escape(*x, "?"));
} }
#ifdef CHECKALL #ifdef CHECKALL

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -52,6 +52,12 @@ struct fullnoun {
noun n[NUMLAN-1]; noun n[NUMLAN-1];
}; };
#ifdef NOTRANS
#define NUMEXTRA 3
const char* natchars[NUMEXTRA] = {"°","é","á"};
#endif
#ifndef NOTRANS
#include "language-data.cpp" #include "language-data.cpp"
hashcode langhash(const string& s) { hashcode langhash(const string& s) {
@ -75,6 +81,7 @@ template<class T> const T* findInHashTableS(string s, const T *table, int size)
} }
#define findInHashTable(s,t) findInHashTableS(s, t, sizeof(t) / sizeof(t[0])) #define findInHashTable(s,t) findInHashTableS(s, t, sizeof(t) / sizeof(t[0]))
#endif
string choose3(int g, string a, string b, string c) { string choose3(int g, string a, string b, string c) {
if(g == GEN_M || g == GEN_O) return a; if(g == GEN_M || g == GEN_O) return a;
@ -100,11 +107,12 @@ set<string> warnshown;
void basicrep(string& x) { void basicrep(string& x) {
const sentence *s = findInHashTable(x, all_sentences); #ifndef NOTRANS
if(!s && !warnshown.count(x)) { const sentence *s = findInHashTable(x, all_sentences);
printf("WARNING: no translations for '%s'\n", x.c_str()); if(!s && !warnshown.count(x)) {
warnshown.insert(x); printf("WARNING: no translations for '%s'\n", x.c_str());
} warnshown.insert(x);
}
int l = lang(); int l = lang();
if(l) { if(l) {
@ -122,9 +130,11 @@ void basicrep(string& x) {
rep(x, "%l0", choose3(playergender(), "l", "la", "lo")); rep(x, "%l0", choose3(playergender(), "l", "la", "lo"));
rep(x, "%d0", choose3(playergender(), "", "a", "o")); rep(x, "%d0", choose3(playergender(), "", "a", "o"));
} }
#endif
} }
void parrep(string& x, string w, stringpar p) { void parrep(string& x, string w, stringpar p) {
#ifndef NOTRANS
int l = lang(); int l = lang();
const fullnoun *N = findInHashTable(p.v, all_nouns); const fullnoun *N = findInHashTable(p.v, all_nouns);
if(l == 1) { if(l == 1) {
@ -176,6 +186,7 @@ void parrep(string& x, string w, stringpar p) {
rep(x, "%ůj"+w, choose4(N->n[2].genus, "ého", "ou", "é", "ůj")); rep(x, "%ůj"+w, choose4(N->n[2].genus, "ého", "ou", "é", "ůj"));
rep(x, "%ým"+w, choose3(N->n[2].genus, "ým", "ou", "ým")); rep(x, "%ým"+w, choose3(N->n[2].genus, "ým", "ou", "ým"));
rep(x, "%ho"+w, choose3(N->n[2].genus, "ho", "ji", "ho")); rep(x, "%ho"+w, choose3(N->n[2].genus, "ho", "ji", "ho"));
rep(x, "%ého"+w, choose3(N->n[2].genus, "ého", "ou", "ého"));
if(p.v == "Mirror Image") if(p.v == "Mirror Image")
rep(x, "%s"+w, "se"); rep(x, "%s"+w, "se");
@ -198,6 +209,7 @@ void parrep(string& x, string w, stringpar p) {
rep(x, "%E"+w, choose3(N->n[3].genus, "", "а", "о")); rep(x, "%E"+w, choose3(N->n[3].genus, "", "а", "о"));
rep(x, "%A"+w, choose3(N->n[3].genus, "ый", "ая", "ое")); rep(x, "%A"+w, choose3(N->n[3].genus, "ый", "ая", "ое"));
rep(x, "%c"+w, choose3(N->n[3].genus, "ся", "ась", "")); rep(x, "%c"+w, choose3(N->n[3].genus, "ся", "ась", ""));
rep(x, "%y"+w, choose3(N->n[3].genus, "ый", "ая", "ое"));
} }
else { else {
rep(x,"%"+w,p.v); rep(x,"%"+w,p.v);
@ -228,10 +240,21 @@ void parrep(string& x, string w, stringpar p) {
rep(x, "%den"+w, "the"); rep(x, "%den"+w, "the");
} }
} }
#endif
if(true) { if(true) {
// proper names (R'Lyeh) // proper names (R'Lyeh)
rep(x,"%"+w,p.v); rep(x,"%"+w,p.v);
if(N && (N->english_grammar_flags & 1)) { #ifdef NOTRANS
int flags = 0;
if(p.v == "R'Lyeh" || p.v == "Camelot") flags = 1;
if(p.v == "Crossroads" || p.v == "Crossroads II" ||
p.v == "Crossroads III" || p.v == "Crossroads IV" ||
p.v == "Kraken Depths" || p.v == "Elemental Planes")
flags = 2;
#else
int flags = N ? N->english_grammar_flags : 0;
#endif
if(flags & 1) {
rep(x,"%the"+w, p.v); rep(x,"%the"+w, p.v);
rep(x,"%The"+w, p.v); rep(x,"%The"+w, p.v);
} }
@ -242,7 +265,7 @@ void parrep(string& x, string w, stringpar p) {
rep(x,"%his"+w, princessgender() ? "her" : "his"); rep(x,"%his"+w, princessgender() ? "her" : "his");
} }
// plural names (Crossroads) // plural names (Crossroads)
if(N && (N->english_grammar_flags & 2)) if(flags & 2)
rep(x,"%s"+w, ""); rep(x,"%s"+w, "");
else else
rep(x,"%s"+w, "s"); rep(x,"%s"+w, "s");
@ -288,20 +311,35 @@ string XLAT(string x, stringpar p1, stringpar p2, stringpar p3, stringpar p4) {
postrep(x); postrep(x);
return x; return x;
} }
string XLAT(string x, stringpar p1, stringpar p2, stringpar p3, stringpar p4, stringpar p5) {
basicrep(x);
parrep(x,"1",p1.v);
parrep(x,"2",p2.v);
parrep(x,"3",p3.v);
parrep(x,"4",p4.v);
parrep(x,"5",p5.v);
postrep(x);
return x;
}
string XLATN(string x) { string XLATN(string x) {
#ifndef NOTRANS
if(lang()) { if(lang()) {
const fullnoun *N = findInHashTable(x, all_nouns); const fullnoun *N = findInHashTable(x, all_nouns);
if(N) return N->n[lang()-1].nomp; if(N) return N->n[lang()-1].nomp;
} }
#endif
return x; return x;
} }
string XLAT1(string x) { string XLAT1(string x) {
#ifndef NOTRANS
if(lang()) { if(lang()) {
const fullnoun *N = findInHashTable(x, all_nouns); const fullnoun *N = findInHashTable(x, all_nouns);
if(N) return N->n[lang()-1].nom; if(N) return N->n[lang()-1].nom;
} }
#endif
return x; return x;
} }

View File

@ -12,14 +12,16 @@
#endif #endif
namespace mapeditor { namespace mapeditor {
#ifndef MOBILE int subcanvas;
cell *modelcell[200]; #ifndef NOEDIT
map<int, cell*> modelcell;
void clearModelCells() { void clearModelCells() {
for(int i=0; i<200; i++) modelcell[i] = NULL; modelcell.clear();
} }
void applyModelcell(cell *c) { void applyModelcell(cell *c) {
if(mapeditor::whichPattern == 'H') return;
if(mapeditor::whichPattern == 'H') return; if(mapeditor::whichPattern == 'H') return;
int i = realpattern(c); int i = realpattern(c);
cell *c2 = modelcell[i]; cell *c2 = modelcell[i];
@ -38,7 +40,7 @@ namespace mapeditor {
#endif #endif
} }
#ifndef MOBILE #ifndef NOEDIT
namespace mapstream { namespace mapstream {
std::map<cell*, int> cellids; std::map<cell*, int> cellids;
vector<cell*> cellbyid; vector<cell*> cellbyid;
@ -83,7 +85,7 @@ namespace mapstream {
cellids[c->mov[j]] < i) { cellids[c->mov[j]] < i) {
int32_t i = cellids[c->mov[j]]; int32_t i = cellids[c->mov[j]];
save(i); save(i);
saveChar(c->spn[j]); saveChar(c->spn(j));
saveChar(j); saveChar(j);
break; break;
} }
@ -167,7 +169,7 @@ namespace mapstream {
// printf("%p:%d,%d -> %p\n", c2, dir, c); // printf("%p:%d,%d -> %p\n", c2, dir, c);
// spinval becomes xspinval // spinval becomes xspinval
rspin = (c2->spn[dir] - loadChar() + 42) % c->type; rspin = (c2->spn(dir) - loadChar() + 42) % c->type;
} }
cellbyid.push_back(c); cellbyid.push_back(c);
@ -251,7 +253,7 @@ namespace mapstream {
ds.list.push_back(loadPoint()); ds.list.push_back(loadPoint());
} }
saveImages(); buildpolys();
bfs(); bfs();
restartGraph(); restartGraph();
return true; return true;
@ -302,6 +304,8 @@ namespace mapeditor {
case 'z': { case 'z': {
int t = zebra40(c); int t = zebra40(c);
if(euclid) return (t*4) % 6;
int t4 = t>>2, tcdir = 0; int t4 = t>>2, tcdir = 0;
if(purehepta) tcdir = t^1; if(purehepta) tcdir = t^1;
@ -321,6 +325,7 @@ namespace mapeditor {
case 'f': { case 'f': {
int t = emeraldval(c); int t = emeraldval(c);
if(euclid) return 0;
int tcdir = 0, tbest = (t&3); int tcdir = 0, tbest = (t&3);
for(int i=0; i<c->type; i++) { for(int i=0; i<c->type; i++) {
cell *c2 = c->mov[i]; cell *c2 = c->mov[i];
@ -386,7 +391,31 @@ namespace mapeditor {
return 0; return 0;
} }
#ifndef MOBILE string infix;
bool hasInfix(const string &s) {
if(infix == "") return true;
string t = "";
for(int i=0; i<size(s); i++) {
char c = s[i];
char tt = 0;
if(c >= 'a' && c <= 'z') tt += c - 32;
else if(c >= 'A' && c <= 'Z') tt += c;
if(tt) t += tt;
}
return t.find(infix) != string::npos;
}
bool editInfix(int uni) {
if(uni >= 'A' && uni <= 'Z') infix += uni;
else if(uni >= 'a' && uni <= 'z') infix += uni-32;
else if(infix != "" && uni == 8) infix = infix.substr(0, size(infix)-1);
else if(infix != "" && uni != 0) infix = "";
else return false;
return true;
}
#ifndef NOEDIT
int paintwhat = 0; int paintwhat = 0;
int painttype = 0; int painttype = 0;
int radius = 0; int radius = 0;
@ -397,11 +426,8 @@ namespace mapeditor {
bool symRotation, sym01, sym02, sym03; bool symRotation, sym01, sym02, sym03;
int displaycodes; int displaycodes;
int subcanvas;
int whichpart; int whichpart;
string infix;
cell *drawcell; cell *drawcell;
const char *mapeditorhelp = const char *mapeditorhelp =
@ -508,12 +534,6 @@ namespace mapeditor {
return 0x20; return 0x20;
} }
int colorhistory[10] = {
0x202020, 0x800000, 0x008000, 0x000080,
0x404040, 0xC0C0C0, 0x804000, 0xC0C000,
0x408040, 0xFFD500
}, lch;
bool choosefile = false; bool choosefile = false;
bool editext = false; bool editext = false;
@ -581,89 +601,23 @@ namespace mapeditor {
} }
} }
void drawColorDialog(int color) {
for(int j=0; j<10; j++) {
int x = vid.xres / 2 + vid.fsize * 2 * (j-5);
int y = vid.yres / 2- 5 * vid.fsize;
string s0 = ""; s0 += ('q'+j);
displayColorButton(x, y, s0, 'q'+j, 0, 0, colorhistory[j]);
}
for(int i=0; i<3; i++) for(int j=0; j<16; j++) {
int x = vid.xres / 2 + vid.fsize * 2 * (j-8);
int y = vid.yres / 2 + (i-1) * vid.fsize * 2;
int p = color;
p &= ~ (0xFF << (8*i));
p |= (17*j) << (8*i);
char c0 = "0aA" [i]+j;
string s0 = ""; s0 += c0;
displayColorButton(x, y, s0, c0, 0, 0, p);
}
displayColorButton(vid.xres/2, vid.yres/2+vid.fsize * 4, "select this color", ' ', 8, 0, color);
}
// 0: nothing happened, 1: color accepted, 2: break
int handleKeyColor(int uni, int& color) {
int i = 3;
int j = 0;
if(uni >= '0' && uni <= '0'+15)
i=0, j=uni-'0';
if(uni >= 'a' && uni <= 'a'+15)
i=1, j=uni-'a';
if(uni >= 'A' && uni <= 'A'+15)
i=2, j=uni-'A';
if(i<3) {
color &= ~ (0xFF << (8*i));
color |= (17*j) << (8*i);
}
else if(uni == ' ') {
bool inHistory = false;
for(int i=0; i<10; i++) if(colorhistory[i] == paintwhat)
inHistory = true;
if(!inHistory) { colorhistory[lch] = paintwhat; lch++; lch %= 10; }
return 1;
}
else if(uni >= 'q' && uni <= 'z') {
color = colorhistory[uni - 'q'];
return 1;
}
else if(uni) return 2;
return 0;
}
void displayFunctionKeys() { void displayFunctionKeys() {
int fs = vid.fsize + 5; int fs = vid.fsize + 5;
displayButton(8, vid.yres-8-fs*10, XLAT("F1 = help"), SDLK_F1, 0); displayButton(8, vid.yres-8-fs*11, XLAT("F1 = help"), SDLK_F1, 0);
displayButton(8, vid.yres-8-fs*9, XLAT("F2 = save"), SDLK_F2, 0); displayButton(8, vid.yres-8-fs*10, XLAT("F2 = save"), SDLK_F2, 0);
displayButton(8, vid.yres-8-fs*8, XLAT("F3 = load"), SDLK_F3, 0); displayButton(8, vid.yres-8-fs*9, XLAT("F3 = load"), SDLK_F3, 0);
displayButton(8, vid.yres-8-fs*7, XLAT("F4 = file"), SDLK_F3, 0); displayButton(8, vid.yres-8-fs*8, XLAT("F4 = file"), SDLK_F3, 0);
displayButton(8, vid.yres-8-fs*6, XLAT("F5 = restart"), SDLK_F5, 0); displayButton(8, vid.yres-8-fs*7, XLAT("F5 = restart"), SDLK_F5, 0);
displayButton(8, vid.yres-8-fs*5, XLAT("F6 = HQ shot"), SDLK_F6, 0); displayButton(8, vid.yres-8-fs*6, XLAT("F6 = HQ shot"), SDLK_F6, 0);
displayButton(8, vid.yres-8-fs*4, XLAT("F7 = player on/off"), SDLK_F7, 0); displayButton(8, vid.yres-8-fs*5, XLAT("F7 = player on/off"), SDLK_F7, 0);
displayButton(8, vid.yres-8-fs*4, XLAT("F8 = SVG shot"), SDLK_F8, 0);
displayButton(8, vid.yres-8-fs*3, XLAT("SPACE = map/graphics"), ' ', 0); displayButton(8, vid.yres-8-fs*3, XLAT("SPACE = map/graphics"), ' ', 0);
displayButton(8, vid.yres-8-fs*2, XLAT("ESC = return to the game"), SDLK_ESCAPE, 0); displayButton(8, vid.yres-8-fs*2, XLAT("ESC = return to the game"), SDLK_ESCAPE, 0);
} }
void vpush(int i, const char *name) { void vpush(int i, const char *name) {
string s = XLATN(name); string s = XLATN(name);
if(infix != "") { if(!hasInfix(s)) return;
string t = "";
for(int i=0; i<size(s); i++) {
char c = s[i];
char tt = 0;
if(c >= 'a' && c <= 'z') tt += c - 32;
else if(c >= 'A' && c <= 'Z') tt += c;
if(tt) t += tt;
}
if(t.find(infix) == string::npos) return;
}
v.push_back(make_pair(s, i)); v.push_back(make_pair(s, i));
} }
@ -672,42 +626,59 @@ namespace mapeditor {
if(choosefile) { drawFileDialog(); return; } if(choosefile) { drawFileDialog(); return; }
if(subscreen == 2) { if(subscreen == 2) {
displayStat(2, XLAT("Emerald Pattern"), ONOFF(whichPattern == 'f'), 'f'); dialog::init();
displayStat(3, XLAT("Palace Pattern"), ONOFF(whichPattern == 'p'), 'p');
displayStat(4, XLAT("Zebra Pattern"), ONOFF(whichPattern == 'z'), 'z'); dialog::addBoolItem(XLAT(euclid ? "three colors" : "Emerald Pattern"), (whichPattern == 'f'), 'f');
dialog::addBoolItem(XLAT("Palace Pattern"), (whichPattern == 'p'), 'p');
dialog::addBoolItem(XLAT(euclid ? "three colors rotated" : "Zebra Pattern"), (whichPattern == 'z'), 'z');
dialog::addBoolItem(XLAT("field pattern"), (whichPattern == 'F'), 'F');
if(whichPattern == 'f') symRotation = true; if(whichPattern == 'f') symRotation = true;
displayStat(6, XLAT("rotational symmetry"), ONOFF(symRotation), '0'); if(whichPattern == 'F') ;
displayStat(7, XLAT("symmetry 0-1"), ONOFF(sym01), '1'); else if(!euclid) {
displayStat(8, XLAT("symmetry 0-2"), ONOFF(sym02), '2'); dialog::addBoolItem(XLAT("rotational symmetry"), (symRotation), '0');
displayStat(9, XLAT("symmetry 0-3"), ONOFF(sym03), '3'); dialog::addBoolItem(XLAT("symmetry 0-1"), (sym01), '1');
dialog::addBoolItem(XLAT("symmetry 0-2"), (sym02), '2');
dialog::addBoolItem(XLAT("symmetry 0-3"), (sym03), '3');
}
else
dialog::addBoolItem(XLAT("edit all three colors"), (symRotation), '0');
displayStat(11, XLAT("display pattern codes (full)"), ONOFF(displaycodes), 'd'); dialog::addBoolItem(XLAT("display pattern codes (full)"), (displaycodes == 1), 'd');
displayStat(12, XLAT("display pattern codes (simplified)"), ONOFF(displaycodes), 's'); dialog::addBoolItem(XLAT("display pattern codes (simplified)"), (displaycodes == 2), 's');
displayStat(14, XLAT("display only hexagons"), ONOFF(whichShape == '6'), '6'); dialog::addBoolItem(XLAT("display only hexagons"), (whichShape == '6'), '6');
displayStat(15, XLAT("display only heptagons"), ONOFF(whichShape == '7'), '7'); dialog::addBoolItem(XLAT("display only heptagons"), (whichShape == '7'), '7');
displayStat(16, XLAT("display the triheptagonal grid"), ONOFF(whichShape == '8'), '8'); dialog::addBoolItem(XLAT("display the triheptagonal grid"), (whichShape == '8'), '8');
displayStat(18, XLAT("predesigned patterns"), "", 'r'); dialog::addItem(XLAT("predesigned patterns"), 'r');
dialog::display();
} }
else if(subscreen == 3) { else if(subscreen == 3) {
displayStat(2, XLAT("Gameboard"), "", 'g'); dialog::init("predesigned patterns");
displayStat(3, XLAT("random colors"), "", 'r'); dialog::addItem(XLAT("Gameboard"), 'g');
displayStat(4, XLAT("rainbow landscape"), "", 'l'); dialog::addItem(XLAT("random colors"), 'r');
dialog::addItem(XLAT("rainbow landscape"), 'l');
displayStat(6, XLAT("emerald pattern"), "emerald", 'e'); dialog::addSelItem(XLAT("emerald pattern"), "emerald", 'e');
displayStat(8, XLAT("four elements"), "palace", 'b'); dialog::addSelItem(XLAT("four elements"), "palace", 'b');
displayStat(9, XLAT("eight domains"), "palace", 'a'); dialog::addSelItem(XLAT("eight domains"), "palace", 'a');
displayStat(11, XLAT("zebra pattern"), "zebra", 'z'); dialog::addSelItem(XLAT("zebra pattern"), "zebra", 'z');
displayStat(12, XLAT("three stripes"), "zebra", 'x'); dialog::addSelItem(XLAT("four triangles"), "zebra", 't');
dialog::addSelItem(XLAT("three stripes"), "zebra", 'x');
displayStat(15, XLAT("random black-and-white"), "current", 'w'); dialog::addSelItem(XLAT("random black-and-white"), "current", 'w');
dialog::addSelItem(XLAT("field pattern C"), "field", 'C');
dialog::addSelItem(XLAT("field pattern D"), "field", 'D');
dialog::addSelItem(XLAT("field pattern N"), "field", 'N');
dialog::addSelItem(XLAT("field pattern S"), "field", 'S');
dialog::display();
} }
else if(subscreen == 1 && painttype == 6) else if(subscreen == 1 && painttype == 6)
drawColorDialog(paintwhat); dialog::drawColorDialog(paintwhat);
else if(subscreen == 1) { else if(subscreen == 1) {
v.clear(); v.clear();
if(painttype == 4) painttype = 0; if(painttype == 4) painttype = 0;
@ -810,11 +781,12 @@ namespace mapeditor {
createMov(c1, i); createMov(c1, i);
int i0 = (42+cf*i+d1) % c1->type; int i0 = (42+cf*i+d1) % c1->type;
int i1 = (i + d2) % c2->type; int i1 = (i + d2) % c2->type;
spillCopy(c1->mov[i0], c1->spn[i0], c2->mov[i1], c2->spn[i1], r-1); spillCopy(c1->mov[i0], c1->spn(i0), c2->mov[i1], c2->spn(i1), r-1);
} }
} }
int subpatternEmerald(int i) { int subpatternEmerald(int i) {
if(euclid) return (symRotation && (i<3)) ? 0 : i;
if((sym01?1:0)+(sym02?1:0)+(sym03?1:0) >= 2) i &= ~3; if((sym01?1:0)+(sym02?1:0)+(sym03?1:0) >= 2) i &= ~3;
if(sym01 && (i&1)) i ^= 1; if(sym01 && (i&1)) i ^= 1;
if(sym02 && (i&2)) i ^= 2; if(sym02 && (i&2)) i ^= 2;
@ -823,6 +795,7 @@ namespace mapeditor {
} }
int subpatternZebra(int i) { int subpatternZebra(int i) {
if(euclid) return (symRotation && (i<3)) ? 0 : i;
i = subpatternEmerald(i); i = subpatternEmerald(i);
if(symRotation) { if(symRotation) {
if(i >= 8 && i < 12) i -= 4; if(i >= 8 && i < 12) i -= 4;
@ -836,6 +809,7 @@ namespace mapeditor {
} }
int subpatternPalace(int i) { int subpatternPalace(int i) {
if(euclid) return i;
i = subpatternEmerald(i); i = subpatternEmerald(i);
if(symRotation && i >= 3) i -= ((i/4-1) % 7) * 4; if(symRotation && i >= 3) i -= ((i/4-1) % 7) * 4;
return i; return i;
@ -854,8 +828,12 @@ namespace mapeditor {
if(polarb50(c)) i|=2; if(polarb50(c)) i|=2;
return subpatternPalace(i); return subpatternPalace(i);
} }
case 'P':
return fiftyval(c);
case 'H': case 'H':
return realpattern(c); return realpattern(c);
case 'F':
return realpattern(c);
} }
return nopattern(c); return nopattern(c);
} }
@ -875,10 +853,19 @@ namespace mapeditor {
} }
case 'H': case 'H':
return towerval(c); return towerval(c);
case 'F': {
pair<int, bool> p = fieldpattern::fieldval(c);
return 10*p.first + (p.second?6:7);
}
} }
return nopattern(c); return nopattern(c);
} }
int realpatternsh(cell *c) {
if(whichPattern == 'F') return nopattern(c);
else return realpattern(c);
}
int cellShapeGroup() { int cellShapeGroup() {
if(whichPattern == 'f') return 4; if(whichPattern == 'f') return 4;
if(whichPattern == 'p') return 5; if(whichPattern == 'p') return 5;
@ -939,6 +926,8 @@ namespace mapeditor {
break; break;
case 1: case 1:
c->item = eItem(paintwhat); c->item = eItem(paintwhat);
if(c->item == itBabyTortoise)
tortoise::babymap[c] = getBits(c) ^ tortoise::getRandomBits();
break; break;
case 2: { case 2: {
eLand last = c->land; eLand last = c->land;
@ -980,7 +969,7 @@ namespace mapeditor {
case 6: case 6:
c->land = laCanvas; c->land = laCanvas;
c->wall = waNone; c->wall = waNone;
c->landparam = paintwhat; c->landparam = paintwhat >> 8;
break; break;
case 4: case 4:
c->wall = copywhat->wall; c->wall = copywhat->wall;
@ -995,7 +984,7 @@ namespace mapeditor {
break; break;
} }
checkUndo(); checkUndo();
if(r) for(int i=0; i<c->type; i++) spill(createMov(c, i), r-1, c->spn[i]); if(r) for(int i=0; i<c->type; i++) spill(createMov(c, i), r-1, c->spn(i));
} }
void allInPattern(cell *c, int r, int cdir) { void allInPattern(cell *c, int r, int cdir) {
@ -1073,11 +1062,11 @@ namespace mapeditor {
return true; return true;
} }
void handleKey(int uni, int sym) { void handleKey(int sym, int uni) {
if(choosefile && handleKeyFile(uni, sym)) ; if(choosefile && handleKeyFile(sym, uni)) ;
else if(subscreen == 1 && painttype == 6) { else if(subscreen == 1 && painttype == 6) {
paintwhat_str = "paint"; paintwhat_str = "paint";
int v = handleKeyColor(uni, paintwhat); int v = dialog::handleKeyColor(sym, uni, paintwhat);
if(v == 1) subscreen = 0; if(v == 1) subscreen = 0;
if(v == 2) cmode = emNormal; if(v == 2) cmode = emNormal;
} }
@ -1090,14 +1079,12 @@ namespace mapeditor {
subscreen = 0; subscreen = 0;
mousepressed = false; mousepressed = false;
} }
if(uni >= 'A' && uni <= 'Z') infix += uni; if(editInfix(uni)) ;
else if(uni >= 'a' && uni <= 'z') infix += uni-32; else if(subscreen == 1 && uni != 0) cmode = emNormal;
else if(infix != "" && uni == 8) infix = infix.substr(0, size(infix)-1);
else if(infix != "" && uni != 0) infix = "";
else if(subscreen == 1 && uni != 0) cmode = emNormal;
} }
else if(subscreen == 3) { else if(subscreen == 3) {
if(uni >= 'a' && uni <= 'z') { dialog::handleNavigation(sym, uni);
if((uni >= 'a' && uni <= 'z') || (uni >= 'A' && uni <= 'Z')) {
whichCanvas = uni; whichCanvas = uni;
subcanvas = rand(); subcanvas = rand();
firstland = laCanvas; randomPatternsMode = false; firstland = laCanvas; randomPatternsMode = false;
@ -1106,7 +1093,8 @@ namespace mapeditor {
else if(uni != 0) subscreen = 0; else if(uni != 0) subscreen = 0;
} }
else if(subscreen == 2) { else if(subscreen == 2) {
if(uni == 'f' || uni == 'p' || uni == 'z' || uni == 'H') { dialog::handleNavigation(sym, uni);
if(uni == 'f' || uni == 'p' || uni == 'z' || uni == 'H' || uni == 'F') {
if(whichPattern == uni) whichPattern = 0; if(whichPattern == uni) whichPattern = 0;
else whichPattern = uni; else whichPattern = uni;
clearModelCells(); clearModelCells();
@ -1171,6 +1159,9 @@ namespace mapeditor {
else if(sym == SDLK_F6) { else if(sym == SDLK_F6) {
saveHighQualityShot(); saveHighQualityShot();
} }
else if(sym == SDLK_F8) {
svg::render();
}
else if(sym == SDLK_F7) { else if(sym == SDLK_F7) {
drawplayer = !drawplayer; drawplayer = !drawplayer;
} }
@ -1214,7 +1205,7 @@ namespace mapeditor {
int dslayer; int dslayer;
bool coloring; bool coloring;
int colortouse = 0xC0C0C0; int colortouse = 0xC0C0C0FF;
transmatrix drawtrans; transmatrix drawtrans;
@ -1255,27 +1246,27 @@ namespace mapeditor {
void drawGrid() { void drawGrid() {
if(cmode == emDraw && !inHighQual) { if(cmode == emDraw && !inHighQual) {
lalpha = 0x20;
for(int d=0; d<84; d++) { for(int d=0; d<84; d++) {
transmatrix d2 = drawtrans * rgpushxto0(ccenter); transmatrix d2 = drawtrans * rgpushxto0(ccenter);
int lalpha;
if(d % (84/drawcell->type) == 0) if(d % (84/drawcell->type) == 0)
lalpha = 0x40; lalpha = 0x40;
else else
lalpha = 0x20; lalpha = 0x20;
queueline(d2 * C0, d2 * spin(M_PI*d/42)* xpush(1) * C0, 0xC0C0C0); int col = darkena(0xC0C0C0, 0, lalpha);
queueline(d2 * C0, d2 * spin(M_PI*d/42)* xpush(1) * C0, col);
for(int u=2; u<=20; u++) { for(int u=2; u<=20; u++) {
if(u % 5 == 0) lalpha = 0x40; if(u % 5 == 0) lalpha = 0x40;
else lalpha = 0x20; else lalpha = 0x20;
queueline( queueline(
d2 * spin(M_PI*d/42)* xpush(u/20.) * C0, d2 * spin(M_PI*d/42)* xpush(u/20.) * C0,
d2 * spin(M_PI*(d+1)/42)* xpush(u/20.) * C0, d2 * spin(M_PI*(d+1)/42)* xpush(u/20.) * C0,
0xC0C0C0); darkena(0xC0C0C0, 0, lalpha));
} }
} }
queueline(drawtrans*ccenter, drawtrans*coldcenter, 0xC0C0C0); queueline(drawtrans*ccenter, drawtrans*coldcenter, darkena(0xC0C0C0, 0, 0x20));
lalpha = 0xFF;
int sg = drawcellShapeGroup(); int sg = drawcellShapeGroup();
for(int i=0; i<USERSHAPEIDS; i++) if(editingShape(sg, i) && usershapes[sg][i]) { for(int i=0; i<USERSHAPEIDS; i++) if(editingShape(sg, i) && usershapes[sg][i]) {
@ -1285,12 +1276,10 @@ namespace mapeditor {
for(int a=0; a<size(ds.list); a++) { for(int a=0; a<size(ds.list); a++) {
hyperpoint P2 = drawtrans * ds.list[a]; hyperpoint P2 = drawtrans * ds.list[a];
int xc, yc, sc; queuechr(P2, 10, 'x',
getcoord(P2, xc, yc, sc); darkena(a == 0 ? 0x00FF00 :
queuechr(xc, yc, sc, 10, 'x',
a == 0 ? 0x00FF00 :
a == size(ds.list)-1 ? 0xFF0000 : a == size(ds.list)-1 ? 0xFF0000 :
0xFFFF00); 0xFFFF00, 0, 0xFF));
} }
} }
} }
@ -1299,7 +1288,7 @@ namespace mapeditor {
void showDrawEditor() { void showDrawEditor() {
if(coloring) { if(coloring) {
drawColorDialog(colortouse); dialog::drawColorDialog(colortouse);
return; return;
} }
@ -1376,14 +1365,15 @@ namespace mapeditor {
displayfr(vid.xres-8, vid.yres-8-fs*6, 2, vid.fsize, XLAT("x: %1", fts4(mh[0])), 0xC0C0C0, 16); displayfr(vid.xres-8, vid.yres-8-fs*6, 2, vid.fsize, XLAT("x: %1", fts4(mh[0])), 0xC0C0C0, 16);
displayfr(vid.xres-8, vid.yres-8-fs*5, 2, vid.fsize, XLAT("y: %1", fts4(mh[1])), 0xC0C0C0, 16); displayfr(vid.xres-8, vid.yres-8-fs*5, 2, vid.fsize, XLAT("y: %1", fts4(mh[1])), 0xC0C0C0, 16);
displayfr(vid.xres-8, vid.yres-8-fs*4, 2, vid.fsize, XLAT("z: %1", fts4(mh[2])), 0xC0C0C0, 16); displayfr(vid.xres-8, vid.yres-8-fs*4, 2, vid.fsize, XLAT("z: %1", fts4(mh[2])), 0xC0C0C0, 16);
displayfr(vid.xres-8, vid.yres-8-fs*2, 2, vid.fsize, XLAT("r: %1", fts4(hdist0(mh))), 0xC0C0C0, 16);
displayfr(vid.xres-8, vid.yres-8-fs*2, 2, vid.fsize, XLAT("r: %1", fts4(inverse_sinh(sqrt(mh[0]*mh[0]+mh[1]*mh[1])))), 0xC0C0C0, 16);
displayfr(vid.xres-8, vid.yres-8-fs, 2, vid.fsize, XLAT("ϕ: %1°", fts4(-atan2(mh[1], mh[0]) * 360 / 2 / M_PI)), 0xC0C0C0, 16); displayfr(vid.xres-8, vid.yres-8-fs, 2, vid.fsize, XLAT("ϕ: %1°", fts4(-atan2(mh[1], mh[0]) * 360 / 2 / M_PI)), 0xC0C0C0, 16);
} }
displayFunctionKeys(); displayFunctionKeys();
} }
bool rebuildPolys = false;
void applyToShape(int sg, int id, int uni, hyperpoint mh) { void applyToShape(int sg, int id, int uni, hyperpoint mh) {
bool haveshape = usershapes[sg][id]; bool haveshape = usershapes[sg][id];
bool xnew = false; bool xnew = false;
@ -1402,12 +1392,12 @@ namespace mapeditor {
if(uni == 'n' || xnew) { if(uni == 'n' || xnew) {
dsCur->list.clear(); dsCur->list.clear();
dsCur->list.push_back(mh); dsCur->list.push_back(mh);
saveImages(); rebuildPolys = true;
} }
if(uni == 'a' && haveshape) { if(uni == 'a' && haveshape) {
dsCur->list.push_back(mh); dsCur->list.push_back(mh);
saveImages(); rebuildPolys = true;
} }
if(uni == 'D') { if(uni == 'D') {
@ -1434,7 +1424,7 @@ namespace mapeditor {
i--; i--;
} }
} }
saveImages(); rebuildPolys = true;
} }
if(uni == 'T') { if(uni == 'T') {
@ -1446,6 +1436,22 @@ namespace mapeditor {
loadShape(sg, id, shPFace, 1, 6); loadShape(sg, id, shPFace, 1, 6);
loadShape(sg, id, shFlowerHair, 1, 7); */ loadShape(sg, id, shFlowerHair, 1, 7); */
// loadShape(sg, id, shPBody, 1, 0);
// loadShape(sg, id, shPHead, 1, 1);
/* loadShape(sg, id, shReptileFrontFoot, 1, 0);
loadShape(sg, id, shReptileRearFoot, 1, 1);
loadShape(sg, id, shReptileFrontLeg, 1, 2);
loadShape(sg, id, shReptileRearLeg, 1, 3);
loadShape(sg, id, shReptileBody, 2, 4);
loadShape(sg, id, shReptileHead, 2, 5);
loadShape(sg, id, shReptileTail, 2, 6); */
loadShape(sg, id, shTrylobite, 2, 0);
/* loadShape(sg, id, shYeti, 2, 0);
loadShape(sg, id, shHumanFoot, 1, 1); */
/* loadShape(sg, id, shYeti, 1, 2); /* loadShape(sg, id, shYeti, 1, 2);
loadShape(sg, id, shRatHead, 1, 3); loadShape(sg, id, shRatHead, 1, 3);
loadShape(sg, id, shRatTail, 1, 1); loadShape(sg, id, shRatTail, 1, 1);
@ -1463,10 +1469,10 @@ namespace mapeditor {
loadShape(3, 1, shTurtleFloor[1], 14, 0); */ loadShape(3, 1, shTurtleFloor[1], 14, 0); */
// loadShape(sg, id, shDragonSegment, 2, 0); // loadShape(sg, id, shDragonSegment, 2, 0);
loadShape(sg, id, shDragonSegment, 2, 1);
// loadShape(sg, id, shEyes, 2, 2); // loadShape(sg, id, shEyes, 2, 2);
saveImages(); // loadShape(sg, id, shFamiliarHead, 2, 0);
rebuildPolys = true;
} }
if(uni == 'K') { if(uni == 'K') {
@ -1483,10 +1489,12 @@ namespace mapeditor {
if(vid.cs.charid&1) if(vid.cs.charid&1)
loadShape(sg, id, shFemaleDress, 2, 2); loadShape(sg, id, shFemaleDress, 2, 2);
if(vid.cs.charid&1) /* if(vid.cs.charid&1)
loadShape(sg, id, shPrincessDress, 1, 3); loadShape(sg, id, shPrincessDress, 1, 3);
else else
loadShape(sg, id, shPrinceDress, 2, 3); loadShape(sg, id, shPrinceDress, 2, 3); */
loadShape(sg, id, shRatCape2, 1, 3);
if(vid.cs.charid&1) if(vid.cs.charid&1)
loadShape(sg, id, shFemaleHair, 2, 4); loadShape(sg, id, shFemaleHair, 2, 4);
@ -1498,7 +1506,7 @@ namespace mapeditor {
// loadShape(sg, id, shWolf, 2, dslayer); // loadShape(sg, id, shWolf, 2, dslayer);
saveImages(); rebuildPolys = true;
} }
if(uni == '+') dsCur->rots++; if(uni == '+') dsCur->rots++;
@ -1506,20 +1514,20 @@ namespace mapeditor {
if(uni >= '1' && uni <= '9') { if(uni >= '1' && uni <= '9') {
dsCur->rots = uni - '0'; dsCur->rots = uni - '0';
if(dsCur->rots == 9) dsCur->rots = 21; if(dsCur->rots == 9) dsCur->rots = 21;
saveImages(); rebuildPolys = true;
} }
if(uni == '0') { if(uni == '0') {
dsCur->sym = !dsCur->sym; dsCur->sym = !dsCur->sym;
saveImages(); rebuildPolys = true;
} }
if(uni == 't') { if(uni == 't') {
dsCur->shift = mh; dsCur->shift = mh;
saveImages(); rebuildPolys = true;
} }
if(uni == 'y') { if(uni == 'y') {
dsCur->spin = mh; dsCur->spin = mh;
saveImages(); rebuildPolys = true;
} }
#define COLORKEY (-10000) #define COLORKEY (-10000)
@ -1546,12 +1554,12 @@ namespace mapeditor {
return XLAT("vector graphics editor"); return XLAT("vector graphics editor");
} }
void drawHandleKey(int uni, int sym, double shiftmul) { void drawHandleKey(int sym, int uni) {
if(choosefile && handleKeyFile(uni, sym)) return; if(choosefile && handleKeyFile(sym, uni)) return;
if(coloring) { if(coloring) {
int v = handleKeyColor(uni, colortouse); int v = dialog::handleKeyColor(sym, uni, colortouse);
if(v == 2) { coloring = false; return; } if(v == 2) { coloring = false; return; }
else if(v == 1) { coloring = false; uni = COLORKEY; } else if(v == 1) { coloring = false; uni = COLORKEY; }
else return; else return;
@ -1581,9 +1589,9 @@ namespace mapeditor {
for(int l=0; l<USERLAYERS; l++) if(size(us->d[l].list)) { for(int l=0; l<USERLAYERS; l++) if(size(us->d[l].list)) {
usershapelayer& ds(us->d[l]); usershapelayer& ds(us->d[l]);
printf("// %d %d %d [%06X]\n", i, j, l, ds.color); printf("// %d %d %d [%06X]\n", i, j, l, ds.color);
for(int i=ds.sh.s; i < ds.sh.e; i++) { printf(" ID, %d, %d, ", us->d[l].rots, us->d[l].sym?2:1);
printf(" hpcpush(hpxyz(%f,%f,%f));\n", double(hpc[i][0]), double(hpc[i][1]), double(hpc[i][2])); for(int i=0; i<size(us->d[l].list); i++)
} printf("%lf,%lf, ", double(us->d[l].list[i][0]), double(us->d[l].list[i][1]));
printf("\n"); printf("\n");
} }
} }
@ -1661,7 +1669,7 @@ namespace mapeditor {
fclose(f); fclose(f);
addMessage(XLAT("Pictures loaded from %1", picfile)); addMessage(XLAT("Pictures loaded from %1", picfile));
saveImages(); buildpolys();
} }
if(sym == SDLK_F7) { if(sym == SDLK_F7) {
@ -1672,6 +1680,10 @@ namespace mapeditor {
saveHighQualityShot(); saveHighQualityShot();
} }
if(sym == SDLK_F8) {
svg::render();
}
if(sym == SDLK_F5) { if(sym == SDLK_F5) {
for(int i=0; i<USERSHAPEGROUPS; i++) for(int i=0; i<USERSHAPEGROUPS; i++)
for(int j=0; j<USERSHAPEIDS; j++) for(int j=0; j<USERSHAPEIDS; j++)
@ -1688,11 +1700,42 @@ namespace mapeditor {
} }
if(sym == SDLK_F10) cmode = emNormal; if(sym == SDLK_F10) cmode = emNormal;
if(rebuildPolys)
buildpolys(), rebuildPolys = false;
} }
#endif
int canvasback = linf[laCanvas].color >> 2;
int generateCanvas(cell *c) { int generateCanvas(cell *c) {
if(whichCanvas == 'C') {
using namespace fieldpattern;
int z = fp43.getdist(fieldval(c), make_pair(0,false));
if(z < fp43.circrad) return 0x00C000;
int z2 = fp43.getdist(fieldval(c), make_pair(fp43.otherpole,false));
if(z2 < fp43.disthep[fp43.otherpole] - fp43.circrad)
return 0x3000;
return 0x6000;
}
if(whichCanvas == 'D') {
using namespace fieldpattern;
int z = fp43.getdist(fieldval(c), make_pair(0,false));
return 255 * (fp43.maxdist+1-z) / fp43.maxdist;
}
if(whichCanvas == 'N') {
using namespace fieldpattern;
int z = fp43.getdist(fieldval(c), make_pair(0,false));
int z2 = fp43.getdist(fieldval(c), make_pair(fp43.otherpole,false));
if(z < z2) return 0x00C000;
if(z > z2) return 0xC00000;
return 0xCCCC00;
}
if(whichCanvas == 'S') {
return 0x3F1F0F * fieldpattern::subval(c).second + 0x000080;
}
if(whichCanvas == 'g') if(whichCanvas == 'g')
return linf[laCanvas].color >> 2; return canvasback;
if(whichCanvas == 'r') if(whichCanvas == 'r')
return hrand(0xFFFFFF + 1); return hrand(0xFFFFFF + 1);
if(whichCanvas == 'e') { if(whichCanvas == 'e') {
@ -1727,6 +1770,12 @@ namespace mapeditor {
int fv = zebra40(c); int fv = zebra40(c);
return fcol[fv&3]; return fcol[fv&3];
} }
if(whichCanvas == 't') {
static unsigned int fcol[4] = { 0x804040, 0x408040, 0x404080, 0x808040 };
int fv = zebra40(c);
if(fv/4 == 4 || fv/4 == 6 || fv/4 == 5 || fv/4 == 10) fv ^= 2;
return fcol[fv&3];
}
if(whichCanvas == 'x') { if(whichCanvas == 'x') {
static unsigned int fcol[4] = { 0xC0C0C0, 0x800000, 0x008000, 0x000080 }; static unsigned int fcol[4] = { 0xC0C0C0, 0x800000, 0x008000, 0x000080 };
return fcol[zebra3(c)]; return fcol[zebra3(c)];
@ -1736,20 +1785,17 @@ namespace mapeditor {
return fcol[randpattern(c, subcanvas) ? 1 : 0]; return fcol[randpattern(c, subcanvas) ? 1 : 0];
} }
if(whichCanvas == 'l') { if(whichCanvas == 'l') {
#ifdef CDATA int col[4];
int col[4]; bool err = false;
bool err = false; for(int j=0; j<4; j++) {
for(int j=0; j<4; j++) { col[j] = getCdata(c, j);
col[j] = getCdata(c, j); col[j] *= 3;
col[j] *= 3; col[j] %= 240;
col[j] %= 240; if(col[j] > 120) col[j] = 240 - col[j];
if(col[j] > 120) col[j] = 240 - col[j]; if(col[j] < -120) col[j] = -240 - col[j];
if(col[j] < -120) col[j] = -240 - col[j]; }
} return (0x808080 + col[0] + (col[1] << 8) + (col[2] << 16)) >> (err?2:0);
return (0x808080 + col[0] + (col[1] << 8) + (col[2] << 16)) >> (err?2:0);
#endif
} }
return linf[laCanvas].color >> 2; return canvasback;
} }
#endif
} }

1445
menus.cpp

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
// HyperRogue paper model generator // HyperRogue paper model generator
// Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details // Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details
#ifndef MOBILE #ifndef NOMODEL
namespace netgen { namespace netgen {
// We need a two-dimensional vector class for this. // We need a two-dimensional vector class for this.
@ -143,7 +143,7 @@ namespace netgen {
loaded = true; loaded = true;
if(!created) return; if(!created) { fclose(f); return; }
for(int i=0; i<CELLS; i++) err = fscanf(f, "%d", &ct[i]); for(int i=0; i<CELLS; i++) err = fscanf(f, "%d", &ct[i]);
@ -227,7 +227,7 @@ namespace netgen {
polyy[0] = int(v1.y); polyy[0] = int(v1.y);
polyy[1] = int(v2.y); polyy[1] = int(v2.y);
polyy[2] = int(v3.y); polyy[2] = int(v3.y);
filledPolygonColor(s, polyx, polyy, 3, col); filledPolygonColorI(s, polyx, polyy, 3, col);
#endif #endif
} }
@ -259,7 +259,7 @@ namespace netgen {
int& hqpixel(hyperpoint h) { int& hqpixel(hyperpoint h) {
int hx, hy, hs; int hx, hy, hs;
getcoord(h, hx, hy, hs); getcoord0(h, hx, hy, hs);
return qpixel(hqsurface, hx, hy); return qpixel(hqsurface, hx, hy);
} }
@ -644,20 +644,25 @@ namespace netgen {
nei[i][e] >= 0 ? 0x808080 : nei[i][e] >= 0 ? 0x808080 :
0xC0C0C0; 0xC0C0C0;
drawline(hvec(i, (e+ofs)%t), hvec(i, (e+1+ofs)%t), (col << 8) + 0xFF); prettyline(hvec(i, (e+ofs)%t), hvec(i, (e+1+ofs)%t), (col << 8) + 0xFF, 3);
} }
} }
} }
if(mode != 2) { if(mode != 2) {
displayStat( 2, XLAT("synchronize net and map"), "", 's'); dialog::init("paper model creator");
displayStat( 3, XLAT("display the scope"), "", 't');
displayStat( 5, XLAT("create the model"), "", 'c'); dialog::addItem(XLAT("synchronize net and map"), 's');
displayStat( 7, XLAT("back to HyperRogue"), "", 'q'); dialog::addItem(XLAT("display the scope"), 't');
displayStat( 9, XLAT("design the net"), "", 'd'); dialog::addItem(XLAT("create the model"), 'c');
dialog::addItem(XLAT("back to HyperRogue"), 'q');
dialog::addItem(XLAT("design the net"), 'd');
dialog::display();
} }
} }
void handleKey(int uni, int sym) { void handleKey(int sym, int uni) {
dialog::handleNavigation(sym, uni);
if(!loaded) { if(!loaded) {
loadData(); loadData();
@ -668,7 +673,7 @@ namespace netgen {
} }
if(!created) { if(!created) {
View = Id; View = Id;
if(lcenterover) viewctr.h = lcenterover->master; if(centerover) viewctr.h = centerover->master;
else viewctr.h = cwt.c->master; else viewctr.h = cwt.c->master;
playermoved = false; playermoved = false;
dataFromHR(); dataFromHR();
@ -684,17 +689,17 @@ namespace netgen {
} }
if(uni == 's') { if(uni == 's') {
View = Id; View = Id;
if(lcenterover) viewctr.h = lcenterover->master; if(centerover) viewctr.h = centerover->master;
else viewctr.h = cwt.c->master; else viewctr.h = cwt.c->master;
playermoved = false; playermoved = false;
} }
if(uni == 'c') { else if(uni == 'c') {
createPapermodel(); createPapermodel();
addMessage(XLAT("The paper model created as papermodel-*.bmp")); addMessage(XLAT("The paper model created as papermodel-*.bmp"));
} }
if(uni == 'd') designNet(); else if(uni == 'd') designNet();
if(uni == 't') mode = 2; else if(uni == 't') mode = 2;
if(uni == 'q' || sym == SDLK_ESCAPE) else if(uni || sym == SDLK_F10)
cmode = emNormal; cmode = emNormal;
} }

467
orbs.cpp
View File

@ -17,10 +17,18 @@ bool markEmpathy(eItem it) {
return true; return true;
} }
bool markEmpathy2(eItem it) {
if(items[itOrbEmpathy] < 2) return false;
if(!markOrb2(it)) return false;
markOrb2(itOrbEmpathy);
return true;
}
bool markOrb2(eItem it) { bool markOrb2(eItem it) {
if(!items[it]) return false; return markOrb(it);
/* if(!items[it]) return false;
orbused[it] = true; orbused[it] = true;
return items[it] > 1; return items[it] > 1; */
} }
int fixpower(int qty) { int fixpower(int qty) {
@ -58,32 +66,32 @@ void empathyMove(cell *c, cell *cto, int dir) {
} }
bool reduceOrbPower(eItem it, int cap) { bool reduceOrbPower(eItem it, int cap) {
if(items[it] && (lastorbused[it] || (it == itOrbShield && items[it]>3) || !markOrb(itOrbPreserve))) { if(items[it] && (lastorbused[it] || (it == itOrbShield && items[it]>3) || !markOrb(itOrbTime))) {
items[it] -= numplayers(); items[it] -= multi::activePlayers();
if(isHaunted(cwt.c->land)) survivalist = false; if(isHaunted(cwt.c->land)) survivalist = false;
if(items[it] < 0) items[it] = 0; if(items[it] < 0) items[it] = 0;
if(items[it] > cap) items[it] = cap; if(items[it] > cap && timerghost) items[it] = cap;
if(items[it] == 0 && it == itOrbLove) if(items[it] == 0 && it == itOrbLove)
princess::bringBack(); princess::bringBack();
return true; return true;
} }
if(items[it] > cap) items[it] = cap; if(items[it] > cap && timerghost) items[it] = cap;
return false; return false;
} }
void reduceOrbPowerAlways(eItem it) { void reduceOrbPowerAlways(eItem it) {
if(items[it]) { if(items[it]) {
items[it] -= numplayers(); items[it] -= multi::activePlayers();
if(items[it] < 0) items[it] = 0; if(items[it] < 0) items[it] = 0;
} }
} }
void reduceOrbPowers() { void reduceOrbPowers() {
if(getMount()) markOrb(itOrbDomination); if(haveMount()) markOrb(itOrbDomination);
for(int i=0; i<ittypes; i++) for(int i=0; i<ittypes; i++)
lastorbused[i] = orbused[i], orbused[i] = false; lastorbused[i] = orbused[i], orbused[i] = false;
if(items[itOrbShield]) orbused[itOrbShield] = lastorbused[itOrbShield]; if(items[itOrbShield]) orbused[itOrbShield] = lastorbused[itOrbShield];
reduceOrbPower(itOrbPreserve, cwt.c->land == laCaribbean ? 777 : 150); reduceOrbPower(itOrbTime, cwt.c->land == laCaribbean ? 777 : 150);
if(invismove && !invisfish) markOrb(itOrbInvis); if(invismove && !invisfish) markOrb(itOrbInvis);
reduceOrbPower(itOrbLightning, 777); reduceOrbPower(itOrbLightning, 777);
reduceOrbPower(itOrbSpeed, 67); reduceOrbPower(itOrbSpeed, 67);
@ -96,19 +104,20 @@ void reduceOrbPowers() {
reduceOrbPower(itOrbDragon, 111); reduceOrbPower(itOrbDragon, 111);
reduceOrbPower(itOrbPsi, 111); reduceOrbPower(itOrbPsi, 111);
reduceOrbPower(itOrbInvis, 77); reduceOrbPower(itOrbInvis, 77);
reduceOrbPower(itOrbGhost, 77); reduceOrbPower(itOrbAether, 77);
reduceOrbPower(itOrbDigging, 100); reduceOrbPower(itOrbDigging, 100);
reduceOrbPower(itOrbTeleport, 200); reduceOrbPower(itOrbTeleport, 200);
reduceOrbPower(itOrbTelekinesis, 150); reduceOrbPower(itOrbSpace, 150);
reduceOrbPowerAlways(itOrbSafety); reduceOrbPowerAlways(itOrbSafety);
reduceOrbPower(itOrbThorns, 150); reduceOrbPower(itOrbThorns, 150);
reduceOrbPower(itOrbWater, 150); reduceOrbPower(itOrbWater, 150);
reduceOrbPower(itOrbAir, 150); reduceOrbPower(itOrbAir, 150);
reduceOrbPower(itOrbFrog, 77); reduceOrbPower(itOrbFrog, 77);
reduceOrbPower(itOrbDash, 77);
reduceOrbPower(itOrbDiscord, 67); reduceOrbPower(itOrbDiscord, 67);
reduceOrbPower(itOrbSummon, 333); reduceOrbPower(itOrbSummon, 333);
reduceOrbPower(itOrbMatter, 333); reduceOrbPower(itOrbMatter, 333);
reduceOrbPower(itOrbFish, 77); reduceOrbPower(itOrbFish, 57 + 20 * multi::activePlayers());
if(!items[itSavedPrincess]) items[itOrbLove] = 0; if(!items[itSavedPrincess]) items[itOrbLove] = 0;
reduceOrbPower(itOrbLove, 777); reduceOrbPower(itOrbLove, 777);
reduceOrbPower(itOrbStunning, 100); reduceOrbPower(itOrbStunning, 100);
@ -117,13 +126,21 @@ void reduceOrbPowers() {
reduceOrbPower(itOrbFreedom, 77); reduceOrbPower(itOrbFreedom, 77);
reduceOrbPower(itOrbEmpathy, 77); reduceOrbPower(itOrbEmpathy, 77);
markOrb(itOrb37); reduceOrbPower(itOrb37, 333); markOrb(itOrb37); reduceOrbPower(itOrb37, 333);
reduceOrbPower(itOrbSkunk, 77); reduceOrbPower(itOrbBeauty, 77);
reduceOrbPower(itOrbEnergy, 77); reduceOrbPower(itOrbEnergy, 77);
reduceOrbPower(itOrbDomination, 120); reduceOrbPower(itOrbDomination, 120);
reduceOrbPower(itOrbSword, 100 + 20 * multi::activePlayers());
reduceOrbPower(itOrbSword2, 100 + 20 * multi::activePlayers());
reduceOrbPower(itOrbStone, 120);
reduceOrbPower(itOrbNature, 120);
reduceOrbPower(itOrbRecall, 77);
reduceOrbPower(itOrbBull, 120);
reduceOrbPower(itOrbHorns, 77);
if(cwt.c->land != laWildWest) if(cwt.c->land != laWildWest)
reduceOrbPower(itRevolver, 6); reduceOrbPower(itRevolver, 6);
whirlwind::calcdirs(cwt.c); whirlwind::calcdirs(cwt.c);
items[itStrongWind] = !items[itOrbGhost] && whirlwind::qdirs == 1 && !euclid; items[itStrongWind] = !items[itOrbAether] && whirlwind::qdirs == 1 && !euclid;
items[itWarning] = 0;
} }
void flashAlchemist(cell *c) { void flashAlchemist(cell *c) {
@ -135,11 +152,12 @@ void flashAlchemist(cell *c) {
} }
} }
void flashCell(cell *c, bool msg) { void flashCell(cell *c, eMonster killer, flagtype flags) {
eWall ow = c->wall;
flashAlchemist(c); flashAlchemist(c);
if(msg && c->monst && !isWorm(c) && c->monst != moShadow) if((flags & AF_MSG) && c->monst && !isWorm(c) && c->monst != moShadow)
addMessage(XLAT("%The1 is destroyed by the Flash.", c->monst)); addMessage(XLAT("%The1 is destroyed by the Flash.", c->monst));
killWithMessage(c, false); if(c->monst || isPlayerOn(c)) attackMonster(c, flags, killer);
if(isIcyLand(c)) if(isIcyLand(c))
HEAT(c) += 2; HEAT(c) += 2;
if(c->land == laDryForest) if(c->land == laDryForest)
@ -147,6 +165,7 @@ void flashCell(cell *c, bool msg) {
if(c->wall == waCavewall) c->wall = waCavefloor; if(c->wall == waCavewall) c->wall = waCavefloor;
if(c->wall == waDeadTroll) c->wall = waCavefloor; if(c->wall == waDeadTroll) c->wall = waCavefloor;
if(c->wall == waDeadTroll2) c->wall = waNone; if(c->wall == waDeadTroll2) c->wall = waNone;
if(c->wall == waPetrified) c->wall = waNone;
if(c->wall == waDeadfloor2) c->wall = waDeadfloor; if(c->wall == waDeadfloor2) c->wall = waDeadfloor;
if(c->wall == waGargoyleFloor) c->wall = waChasm; if(c->wall == waGargoyleFloor) c->wall = waChasm;
if(c->wall == waGargoyleBridge) placeWater(c, c); if(c->wall == waGargoyleBridge) placeWater(c, c);
@ -174,26 +193,35 @@ void flashCell(cell *c, bool msg) {
eWall w = c->wall; eWall w = c->wall;
c->wall = waNone; c->wall = waNone;
for(int i=0; i<c->type; i++) if(c->mov[i] && c->mov[i]->wall == w) for(int i=0; i<c->type; i++) if(c->mov[i] && c->mov[i]->wall == w)
flashCell(c->mov[i], msg); flashCell(c->mov[i], killer, flags);
} }
if(c->wall == waRed1) c->wall = waNone; if(c->wall == waRed1) c->wall = waNone;
else if(c->wall == waRed2) c->wall = waRed1; else if(c->wall == waRed2) c->wall = waRed1;
else if(c->wall == waRed3) c->wall = waRed2; else if(c->wall == waRed3) c->wall = waRed2;
if(c->wall == waBarrowWall) c->wall = waBarrowDig;
else if(c->wall == waBarrowDig) c->wall = waNone;
if(c->wall != ow && ow) drawParticles(c, winf[ow].color, 16);
if(hasTimeout(c) && c->wparam < 77) c->wparam = 77; if(hasTimeout(c) && c->wparam < 77) c->wparam = 77;
if(isActivable(c)) if(isActivable(c))
activateActiv(c, false); activateActiv(c, false);
} }
void activateFlashFrom(cell *cf) { void activateFlashFrom(cell *cf, eMonster who, flagtype flags) {
drawFlash(cf); drawFlash(cf);
playSound(cf, "storm");
for(int i=0; i<size(dcal); i++) { for(int i=0; i<size(dcal); i++) {
cell *c = dcal[i]; cell *c = dcal[i];
if(c == cf) continue; if(c == cf) continue;
for(int t=0; t<c->type; t++) for(int t=0; t<c->type; t++)
for(int u=0; u<cf->type; u++) for(int u=0; u<cf->type; u++)
if(c->mov[t] == cf->mov[u] && c->mov[t] != NULL) { if(c->mov[t] == cf->mov[u] && c->mov[t] != NULL) {
flashCell(c, true); flashCell(c, who, flags);
goto nexti;
} }
nexti: ;
} }
} }
@ -233,50 +261,75 @@ void checkFreedom(cell *cf) {
} }
addMessage(XLAT("Your %1 activates!", itOrbFreedom)); addMessage(XLAT("Your %1 activates!", itOrbFreedom));
drainOrb(itOrbFreedom); drainOrb(itOrbFreedom);
drawBigFlash(cf); for(int i=0; i<numplayers(); i++)
drawBigFlash(playerpos(i));
for(int i=0; i<size(dcal); i++) { for(int i=0; i<size(dcal); i++) {
cell *c = dcal[i]; cell *c = dcal[i];
if(c == cf) continue; if(c == cf && !shmup::on) continue;
if(c->cpdist > 5) break; if(c->cpdist > 5) break;
flashCell(c, true); flashCell(c, moPlayer, AF_MAGIC);
} }
} }
void activateFlash() { void activateFlash() {
int tk = tkills(); int tk = tkills();
drawFlash(cwt.c);
for(int i=0; i<numplayers(); i++)
drawFlash(playerpos(i));
addMessage(XLAT("You activate the Flash spell!")); addMessage(XLAT("You activate the Flash spell!"));
playSound(cwt.c, "storm");
drainOrb(itOrbFlash); drainOrb(itOrbFlash);
for(int i=0; i<size(dcal); i++) { for(int i=0; i<size(dcal); i++) {
cell *c = dcal[i]; cell *c = dcal[i];
if(c->cpdist > 2) break; if(c->cpdist > 2) break;
flashCell(c, false); flashCell(c, moPlayer, AF_MAGIC);
} }
achievement_count("FLASH", tkills(), tk); achievement_count("FLASH", tkills(), tk);
} }
bool barrierAt(cellwalker& c, int d) { bool reflectingBarrierAt(cell *c) {
if(d >= 7) return true; return
if(d <= -7) return true; c->wall == waBarrier || c->wall == waCamelot ||
c->wall == waPalace || c->wall == waPlatform ||
c->wall == waTempWall || c->wall == waWarpGate || c->wall == waBarrowDig || c->wall == waBarrowWall;
}
bool reflectingBarrierAt(cellwalker& c, int d) {
if(d >= 3) return true;
if(d <= -3) return true;
d = c.spin + d + 42; d = c.spin + d + 42;
d%=c.c->type; d%=c.c->type;
if(!c.c->mov[d]) return true; if(!c.c->mov[d]) return true;
return reflectingBarrierAt(c.c->mov[d]);
// WAS: // WAS:
// if(c.c->mov[d]->wall == waBarrier) return true; // if(c.c->mov[d]->wall == waBarrier) return true;
if(c.c->mov[d]->land == laBarrier || c.c->mov[d]->land == laOceanWall || // THEN:
c.c->mov[d]->land == laHauntedWall || // if(c.c->mov[d]->land == laBarrier || c.c->mov[d]->land == laOceanWall ||
c.c->mov[d]->land == laElementalWall) return true; // c.c->mov[d]->land == laHauntedWall ||
return false; // c.c->mov[d]->land == laElementalWall) ;
// return false;
} }
void killAdjacentSharks(cell *c) { void killAdjacentSharks(cell *c) {
for(int i=0; i<c->type; i++) { for(int i=0; i<c->type; i++) {
cell *c2 = c->mov[i]; cell *c2 = c->mov[i];
if(c2 && isShark(c2->monst)) { if(!c2) continue;
if(isShark(c2->monst)) {
c2->ligon = true; c2->ligon = true;
killMonster(c2); killMonster(c2, moLightningBolt);
killAdjacentSharks(c2); killAdjacentSharks(c2);
} }
if(isKraken(c2->monst) && isWatery(c2)) {
cell *c3 = kraken::head(c2);
c3->ligon = true;
forCellEx(c4, c3) killMonster(c4, moLightningBolt); // kill-all
forCellEx(c4, c3) if(isWatery(c4)) {
c4->ligon = true;
killAdjacentSharks(c4);
}
}
} }
} }
@ -293,20 +346,23 @@ void castLightningBolt(cellwalker lig) {
cell *c = lig.c; cell *c = lig.c;
eWall ow = c->wall;
flashAlchemist(c); flashAlchemist(c);
if(c->monst == moMetalBeast2 && !c->item) c->item = itFulgurite; if(c->monst == moMetalBeast2 && !c->item) c->item = itFulgurite;
killWithMessage(c, false); if(c->monst) attackMonster(c, AF_MAGIC, moLightningBolt);
if(isIcyLand(c)) HEAT(c) += 2; if(isIcyLand(c)) HEAT(c) += 2;
if(c->land == laDryForest) c->landparam += 2; if(c->land == laDryForest) c->landparam += 2;
bool first = !c->ligon; bool first = !c->ligon;
c->ligon = 1; c->ligon = 1;
bool brk = false, spin = false; bool brk = false, spin = false;
if(c->wall == waGargoyle) brk = true; if(c->wall == waGargoyle) brk = true;
if(c->wall == waCavewall) c->wall = waCavefloor, brk = true; if(c->wall == waCavewall) c->wall = waCavefloor, brk = true;
if(c->wall == waDeadTroll) c->wall = waCavefloor, brk = true; if(c->wall == waDeadTroll) c->wall = waCavefloor, brk = true;
if(c->wall == waDeadTroll2)c->wall = waNone, brk = true; if(c->wall == waDeadTroll2)c->wall = waNone, brk = true;
if(c->wall == waPetrified) c->wall = waNone, brk = true;
if(c->wall == waDeadfloor2)c->wall = waDeadfloor; if(c->wall == waDeadfloor2)c->wall = waDeadfloor;
if(c->wall == waRubble) c->wall = waNone; if(c->wall == waRubble) c->wall = waNone;
if(c->wall == waDeadwall) c->wall = waDeadfloor2, brk = true; if(c->wall == waDeadwall) c->wall = waDeadfloor2, brk = true;
@ -315,10 +371,17 @@ void castLightningBolt(cellwalker lig) {
if(c->wall == waIcewall) c->wall = waNone, brk = true; if(c->wall == waIcewall) c->wall = waNone, brk = true;
if(c->wall == waAncientGrave) c->wall = waNone, spin = true; if(c->wall == waAncientGrave) c->wall = waNone, spin = true;
if(c->wall == waFreshGrave) c->wall = waNone, spin = true; if(c->wall == waFreshGrave) c->wall = waNone, spin = true;
if(c->wall == waFreshGrave) c->wall = waNone, spin = true;
if(c->wall == waBigStatue) c->wall = waNone, spin = true; if(c->wall == waBigStatue) c->wall = waNone, spin = true;
if(c->wall == waColumn) c->wall = waNone, spin = true; if(c->wall == waColumn) c->wall = waNone, spin = true;
if(c->wall == waStone) c->wall = waNone, brk = true; if(c->wall == waStone) c->wall = waNone, brk = true;
if(c->wall == waCanopy || c->wall == waTrunk || c->wall == waBigBush || c->wall == waSmallBush) {
makeflame(c, 12, false); brk = true;
}
if(c->wall == waGrounded) brk = true; if(c->wall == waGrounded) brk = true;
if(c->wall == waFan) spin = true; if(c->wall == waFan) spin = true;
if(c->wall == waMetal) c->wall = waCharged, brk = true; if(c->wall == waMetal) c->wall = waCharged, brk = true;
@ -357,18 +420,22 @@ void castLightningBolt(cellwalker lig) {
brk = true; brk = true;
} }
if(c->wall != ow && ow)
drawParticles(c, winf[ow].color, 16);
if(c == cwt.c) {bnc++; if(bnc > 10) break; } if(c == cwt.c) {bnc++; if(bnc > 10) break; }
if(spin) cwspin(lig, hrand(lig.c->type)); if(spin) cwspin(lig, hrand(lig.c->type));
if(brk) break; if(brk) break;
if(c->wall == waBarrier || c->wall == waCamelot || c->wall == waPalace || c->wall == waPlatform || if(reflectingBarrierAt(c)) {
c->wall == waTempWall || c->wall == waWarpGate) {
int left = -1; int left = -1;
int right = 1; int right = 1;
while(barrierAt(lig, left)) left--; while(!reflectingBarrierAt(lig, left)) left--;
while(barrierAt(lig, right)) right++; while(!reflectingBarrierAt(lig, right)) right++;
cwspin(lig, -(right + left)); cwspin(lig, right + left);
if(c->wall == waBarrowWall) c->wall = waBarrowDig;
else if(c->wall == waBarrowDig) c->wall = waNone;
bnc++; if(bnc > 10) break; bnc++; if(bnc > 10) break;
} }
else { else {
@ -377,11 +444,13 @@ void castLightningBolt(cellwalker lig) {
} }
if(c->wall == waCloud) { if(c->wall == waCloud) {
drawParticles(c, winf[ow].color, 16);
c->wall = waNone; c->wall = waNone;
mirror::createMirages(c, lig.spin, moLightningBolt); mirror::createMirages(c, lig.spin, moLightningBolt);
} }
if(c->wall == waMirror) { if(c->wall == waMirror) {
drawParticles(c, winf[ow].color, 16);
c->wall = waNone; c->wall = waNone;
mirror::createMirrors(c, lig.spin, moLightningBolt); mirror::createMirrors(c, lig.spin, moLightningBolt);
break; break;
@ -389,6 +458,10 @@ void castLightningBolt(cellwalker lig) {
} }
} }
void castLightningBoltFrom(cell *c) {
for(int i=0; i<c->type; i++) castLightningBolt(cellwalker(c, i));
}
void activateLightning() { void activateLightning() {
int tk = tkills(); int tk = tkills();
drawLightning(); drawLightning();
@ -397,14 +470,16 @@ void activateLightning() {
for(int i=0; i<size(dcal); i++) if(dcal[i]) dcal[i]->ligon = 0; for(int i=0; i<size(dcal); i++) if(dcal[i]) dcal[i]->ligon = 0;
drainOrb(itOrbLightning); drainOrb(itOrbLightning);
for(int i=0; i<cwt.c->type; i++)
castLightningBolt(cellwalker(cwt.c, i)); for(int i=0; i<numplayers(); i++)
castLightningBoltFrom(playerpos(i));
elec::afterOrb = true; elec::afterOrb = true;
elec::act(); elec::act();
elec::afterOrb = false; elec::afterOrb = false;
achievement_count("LIGHTNING", tkills(), tk); achievement_count("LIGHTNING", tkills(), tk);
playSound(cwt.c, "storm");
} }
// roCheck: return orb type if successful, 0 otherwise // roCheck: return orb type if successful, 0 otherwise
@ -423,11 +498,43 @@ bool haveRangedTarget() {
return false; return false;
} }
void checkmoveO() {
if(multi::players > 1 && multi::activePlayers() == 1)
multi::checklastmove();
if(multi::players == 1) checkmove();
}
int teleportAction() {
// normal teleport
if(shmup::on || numplayers() == 1) return 1;
// multi-player, but all in -- do nothing
else if(numplayers() == multi::activePlayers()) return 0;
// otherwise teleport to the game
else return 2;
}
void teleportTo(cell *dest) { void teleportTo(cell *dest) {
playSound(dest, "other-teleport");
if(dest->monst) { if(dest->monst) {
cwt.c->monst = dest->monst; cwt.c->monst = dest->monst;
dest->monst = moNone; dest->monst = moNone;
} }
if(teleportAction() == 2) {
bool b = multiRevival(dest, NULL);
if(b) {
killFriendlyIvy();
drainOrb(itOrbTeleport);
movecost(cwt.c, dest);
playerMoveEffects(cwt.c, dest);
for(int i=9; i>=0; i--)
setdist(dest, i, NULL);
bfs();
}
return;
}
killFriendlyIvy();
movecost(cwt.c, dest); movecost(cwt.c, dest);
playerMoveEffects(cwt.c, dest); playerMoveEffects(cwt.c, dest);
cwt.c = dest; cwt.spin = hrand(dest->type); flipplayer = !!(hrand(2)); cwt.c = dest; cwt.spin = hrand(dest->type); flipplayer = !!(hrand(2));
@ -441,19 +548,32 @@ void teleportTo(cell *dest) {
bfs(); bfs();
items[itOrbSword] = 0;
items[itOrbSword2] = 0;
if(shmup::on) if(shmup::on)
shmup::teleported(); shmup::teleported();
else else
checkmove(); checkmoveO();
} }
void jumpTo(cell *dest, eItem byWhat) { void jumpTo(cell *dest, eItem byWhat, int bonuskill = 0, eMonster dashmon = moNone) {
if(byWhat != itStrongWind) playSound(dest, "orb-frog");
movecost(cwt.c, dest); movecost(cwt.c, dest);
killFriendlyIvy();
cell *c1 = cwt.c; cell *c1 = cwt.c;
animateMovement(cwt.c, dest, LAYER_SMALL);
cwt.c = dest; cwt.c = dest;
forCellIdEx(c2, i, dest) if(c2->cpdist < dest->cpdist) {
cwt.spin = i;
flipplayer = true;
}
countLocalTreasure(); countLocalTreasure();
items[itOrbSword] = 0;
items[itOrbSword2] = 0;
stabbingAttack(c1, dest, moPlayer, bonuskill);
playerMoveEffects(c1, dest); playerMoveEffects(c1, dest);
if(cwt.c->item != itOrbYendor && cwt.c->item != itHolyGrail) if(cwt.c->item != itOrbYendor && cwt.c->item != itHolyGrail)
collectItem(cwt.c, true); collectItem(cwt.c, true);
@ -463,6 +583,11 @@ void jumpTo(cell *dest, eItem byWhat) {
addMessage(XLAT("You jump!")); addMessage(XLAT("You jump!"));
} }
if(byWhat == itOrbDash) {
useupOrb(itOrbDash, 5);
addMessage(XLAT("You vault over %the1!", dashmon));
}
mirror::destroy(); mirror::destroy();
for(int i=9; i>=0; i--) for(int i=9; i>=0; i--)
@ -476,6 +601,19 @@ void jumpTo(cell *dest, eItem byWhat) {
monstersTurn(); monstersTurn();
} }
void growIvyTo(cell *dest, cell *src) {
if(dest->monst)
attackMonster(dest, AF_MSG | AF_ORSTUN, moFriendlyIvy);
else {
dest->monst = moFriendlyIvy;
dest->mondir = neighborId(dest, src);
moveEffect(dest, src, moFriendlyIvy);
empathyMove(src, dest, neighborId(src, dest));
}
createNoise(1);
monstersTurn();
}
void telekinesis(cell *dest) { void telekinesis(cell *dest) {
int cost = dest->cpdist * dest->cpdist; int cost = dest->cpdist * dest->cpdist;
@ -493,17 +631,17 @@ void telekinesis(cell *dest) {
} }
if(dest->wall == waGlass) { if(dest->wall == waGlass) {
drainOrb(itOrbTelekinesis); drainOrb(itOrbSpace);
addMessage(XLAT("Your power is drained by %the1!", dest->wall)); addMessage(XLAT("Your power is drained by %the1!", dest->wall));
} }
moveItem(dest, cwt.c, true); moveItem(dest, cwt.c, true);
collectItem(cwt.c, true); collectItem(cwt.c, true);
useupOrb(itOrbTelekinesis, cost); useupOrb(itOrbSpace, cost);
createNoise(3); createNoise(3);
bfs(); bfs();
if(!shmup::on) checkmove(); if(!shmup::on) checkmoveO();
} }
eMonster summonedAt(cell *dest) { eMonster summonedAt(cell *dest) {
@ -517,7 +655,7 @@ eMonster summonedAt(cell *dest) {
if(dest->wall == waAncientGrave || dest->wall == waFreshGrave) if(dest->wall == waAncientGrave || dest->wall == waFreshGrave)
return moGhost; return moGhost;
if(dest->wall == waClosePlate || dest->wall == waOpenPlate) if(dest->wall == waClosePlate || dest->wall == waOpenPlate)
return moPalace; return dest->land == laPalace ? moPalace : moBat;
if(dest->wall == waFloorA || dest->wall == waFloorB) if(dest->wall == waFloorA || dest->wall == waFloorB)
return moSlime; return moSlime;
if(dest->wall == waFloorC || dest->wall == waFloorD) if(dest->wall == waFloorC || dest->wall == waFloorD)
@ -536,8 +674,11 @@ eMonster summonedAt(cell *dest) {
return return
isElemental(dest->land) ? moWaterElemental : isElemental(dest->land) ? moWaterElemental :
dest->land == laLivefjord ? moViking : dest->land == laLivefjord ? moViking :
dest->land == laGridCoast ? moRatling : dest->land == laKraken ? moViking :
dest->land == laWarpCoast ? moRatling :
moPirate; moPirate;
if(isReptile(dest->wall))
return moReptile;
if(dest->wall == waChasm) if(dest->wall == waChasm)
return moAirElemental; return moAirElemental;
if(isFire(dest)) if(isFire(dest))
@ -561,6 +702,12 @@ eMonster summonedAt(cell *dest) {
if(dest->wall == waGiantRug) if(dest->wall == waGiantRug)
return moVizier; return moVizier;
if(dest->wall == waNone) { if(dest->wall == waNone) {
if(dest->land == laBull) return moRagingBull;
if(dest->land == laPrairie) return moAirElemental;
if(dest->land == laZebra) return moAirElemental;
if(dest->land == laMirror) return moAirElemental;
if(dest->land == laMountain) return moAirElemental; // unfortunately Ivies are too large
if(dest->land == laDungeon) return moBat;
if(dest->land == laIce) return moFireElemental; if(dest->land == laIce) return moFireElemental;
if(dest->land == laDesert) return moEarthElemental; if(dest->land == laDesert) return moEarthElemental;
if(dest->land == laJungle) return moWaterElemental; if(dest->land == laJungle) return moWaterElemental;
@ -587,20 +734,24 @@ eMonster summonedAt(cell *dest) {
if(dest->land == laWildWest) return moOutlaw; if(dest->land == laWildWest) return moOutlaw;
if(dest->land == laClearing) return moForestTroll; if(dest->land == laClearing) return moForestTroll;
if(dest->land == laWhirlwind) return moAirElemental; if(dest->land == laWhirlwind) return moAirElemental;
if(dest->land == laGridCoast) return moRatling; if(dest->land == laWarpCoast) return moRatling;
if(dest->land == laRose) return moRoseLady; if(dest->land == laRose) return moRoseLady;
if(dest->land == laDragon) return moFireElemental; if(dest->land == laDragon) return moFireElemental;
if(dest->land == laTortoise) return moTortoise; if(dest->land == laTortoise) return moTortoise;
if(dest->land == laBurial) return moEarthElemental;
if(isHaunted(dest->land)) return moGhost; if(isHaunted(dest->land)) return moGhost;
} }
return moNone; return moNone;
} }
void summonAt(cell *dest) { void summonAt(cell *dest) {
playSound(dest, "orb-ranged");
dest->monst = summonedAt(dest); dest->monst = summonedAt(dest);
dest->stuntime = 3; dest->stuntime = 3;
if(dest->monst == moPirate || dest->monst == moViking || (dest->monst == moRatling && dest->wall == waSea)) if(dest->monst == moPirate || dest->monst == moViking || (dest->monst == moRatling && dest->wall == waSea))
dest->wall = waBoat; dest->wall = waBoat, dest->item = itNone;
if(dest->monst == moViking && dest->land == laKraken)
dest->item = itOrbFish;
if(dest->wall == waStrandedBoat) if(dest->wall == waStrandedBoat)
dest->wall = waBoat; dest->wall = waBoat;
else if(dest->monst == moWaterElemental) else if(dest->monst == moWaterElemental)
@ -620,7 +771,7 @@ void summonAt(cell *dest) {
useupOrb(itOrbSummon, 20); useupOrb(itOrbSummon, 20);
createNoise(2); createNoise(2);
bfs(); bfs();
checkmove(); checkmoveO();
} }
bool tempWallPossibleAt(cell *dest) { bool tempWallPossibleAt(cell *dest) {
@ -641,46 +792,61 @@ void tempWallAt(cell *dest) {
dest->item = itNone; // underwater items are destroyed by this dest->item = itNone; // underwater items are destroyed by this
createNoise(2); createNoise(2);
bfs(); bfs();
checkmove(); checkmoveO();
} }
void psi_attack(cell *dest) { void psi_attack(cell *dest) {
playSound(dest, "other-mind");
if(isNonliving(dest->monst)) if(isNonliving(dest->monst))
addMessage(XLAT("You destroy %the1 with a mental blast!", dest->monst)); addMessage(XLAT("You destroy %the1 with a mental blast!", dest->monst));
else if(isDragon(dest->monst)) else if(isDragon(dest->monst) || isKraken(dest->monst))
addMessage(XLAT("You damage %the1 with a mental blast!", dest->monst)); addMessage(XLAT("You damage %the1 with a mental blast!", dest->monst));
else else
addMessage(XLAT("You kill %the1 with a mental blast!", dest->monst)); addMessage(XLAT("You kill %the1 with a mental blast!", dest->monst));
killWithMessage(dest, false); // note: psi attack works with Petrify!
attackMonster(dest, AF_MAGIC, moPlayer);
useupOrb(itOrbPsi, 30); useupOrb(itOrbPsi, 30);
createNoise(2); createNoise(2);
bfs(); bfs();
checkmove(); checkmoveO();
} }
void gun_attack(cell *dest) { void gun_attack(cell *dest) {
playSound(dest, "orb-ranged");
addMessage(XLAT("You shoot %the1!", dest->monst)); addMessage(XLAT("You shoot %the1!", dest->monst));
killWithMessage(dest, false); attackMonster(dest, AF_GUN, moNone);
items[itRevolver] --; items[itRevolver] --;
bfs(); bfs();
checkmove(); checkmoveO();
createNoise(5); createNoise(5);
monstersTurn(); monstersTurn();
} }
void stun_attack(cell *dest) { void checkStunKill(cell *dest) {
addMessage(XLAT("You stun %the1!", dest->monst));
dest->stuntime += 5;
if(isBird(dest->monst)) { if(isBird(dest->monst)) {
moveEffect(dest, dest, moDeadBird); moveEffect(dest, dest, moDeadBird);
if(cellUnstableOrChasm(dest)) dest->wall = waChasm; doesFall(dest);
if(isWatery(dest) || dest->wall == waChasm || isFire(dest)) if(isWatery(dest) || dest->wall == waChasm || isFire(dest)) {
killMonster(dest); addMessage(XLAT("%The1 falls!", dest->monst));
fallMonster(dest);
return;
}
} }
/* if(!isPermanentFlying(dest->monst) && cellEdgeUnstable(dest)) {
addMessage(XLAT("%The1 falls!", dest->monst));
fallMonster(dest);
} */
}
void stun_attack(cell *dest) {
playSound(dest, "orb-ranged");
addMessage(XLAT("You stun %the1!", dest->monst));
dest->stuntime += 5;
checkStunKill(dest);
useupOrb(itOrbStunning, 10); useupOrb(itOrbStunning, 10);
createNoise(3); createNoise(3);
bfs(); bfs();
checkmove(); checkmoveO();
} }
void placeIllusion(cell *c) { void placeIllusion(cell *c) {
@ -688,38 +854,48 @@ void placeIllusion(cell *c) {
useupOrb(itOrbIllusion, 5); useupOrb(itOrbIllusion, 5);
addMessage(XLAT("You create an Illusion!")); addMessage(XLAT("You create an Illusion!"));
bfs(); bfs();
checkmove(); checkmoveO();
} }
void blowoff(cell *cf, cell *ct) { void blowoff(cell *cf, cell *ct) {
playSound(ct, "orb-ranged");
addMessage(XLAT("You blow %the1 away!", cf->monst)); addMessage(XLAT("You blow %the1 away!", cf->monst));
pushMonster(ct, cf); pushMonster(ct, cf);
if(cf->item == itBabyTortoise) { if(cf->item == itBabyTortoise && !ct->item)
if(!ct->item) { moveItem(cf, ct, true);
ct->item = itBabyTortoise;
tortoise::babymap[ct] = tortoise::babymap[cf];
}
tortoise::babymap.erase(cf);
cf->item = itNone;
}
items[itOrbAir]--; items[itOrbAir]--;
createNoise(2); createNoise(2);
bfs(); bfs();
checkmove(); checkmoveO();
} }
void useOrbOfDragon(cell *c) { void useOrbOfDragon(cell *c) {
makeflame(c, 20, false); makeflame(c, 20, false);
playSound(c, "fire");
addMessage(XLAT("You throw fire!")); addMessage(XLAT("You throw fire!"));
useupOrb(itOrbDragon, 5); useupOrb(itOrbDragon, 5);
createNoise(3); createNoise(3);
bfs(); bfs();
checkmove(); checkmoveO();
} }
int monstersnearO(orbAction a, cell *c, cell *nocount, eMonster who, cell *pushto, cell *comefrom) {
// printf("[a = %d] ", a);
if(shmup::on) return 0;
if(a == roCheck && multi::players > 1)
return 1;
else if(a == roMultiCheck) return 0;
else return monstersnear(c, nocount, who, pushto, comefrom);
}
bool isCheck(orbAction a) { return a == roCheck || a == roMultiCheck; }
bool isWeakCheck(orbAction a) { return a == roCheck || a == roMultiCheck || a == roMouse; }
eItem targetRangedOrb(cell *c, orbAction a) { eItem targetRangedOrb(cell *c, orbAction a) {
if(!haveRangedOrb()) return itNone; if(!haveRangedOrb()) {
return itNone;
}
if(rosedist(cwt.c) == 1) { if(rosedist(cwt.c) == 1) {
int r = rosemap[cwt.c]; int r = rosemap[cwt.c];
@ -739,37 +915,38 @@ eItem targetRangedOrb(cell *c, orbAction a) {
// (-1) distance // (-1) distance
if(c == cwt.c || isNeighbor(cwt.c, c)) { if(c == cwt.c || isNeighbor(cwt.c, c)) {
if(a == roKeyboard || a == roMouseForce ) if(!isWeakCheck(a))
addMessage(XLAT("You cannot target that close!")); addMessage(XLAT("You cannot target that close!"));
return itNone; return itNone;
} }
if(c->cpdist > 7) { if(c->cpdist > 7) {
if(a != roCheck) if(!isWeakCheck(a))
addMessage(XLAT("You cannot target that far away!")); addMessage(XLAT("You cannot target that far away!"));
return itNone; return itNone;
} }
// (0-) strong wind // (0-) strong wind
if(items[itStrongWind] && c->cpdist == 2 && cwt.c == whirlwind::jumpFromWhereTo(c, true) && !monstersnear(c, NULL, moPlayer, NULL, cwt.c)) { if(items[itStrongWind] && c->cpdist == 2 && cwt.c == whirlwind::jumpFromWhereTo(c, true) && !monstersnearO(a, c, NULL, moPlayer, NULL, cwt.c)) {
if(a != roCheck) jumpTo(c, itStrongWind); if(!isCheck(a)) jumpTo(c, itStrongWind);
return itStrongWind; return itStrongWind;
} }
// (0x) control // (0x) control
if(getMount() && items[itOrbDomination] && dragon::whichturn != turncount) { if(haveMount() && items[itOrbDomination] && dragon::whichturn != turncount) {
if(a != roCheck) { if(!isCheck(a)) {
dragon::target = c; dragon::target = c;
dragon::whichturn = turncount; dragon::whichturn = turncount;
addMessage(XLAT("Commanded %the1!", getMount())); addMessage(XLAT("Commanded %the1!", haveMount()));
checkmove(); checkmoveO();
} }
return itOrbDomination; return itOrbDomination;
} }
// (0) telekinesis // (0) telekinesis
if(c->item && !itemHidden(c) && !cwt.c->item && items[itOrbTelekinesis] >= fixpower(c->cpdist * c->cpdist) && !cantGetGrimoire(c, a != roCheck)) { if(c->item && !itemHiddenFromSight(c) && !cwt.c->item && items[itOrbSpace] >= fixpower(c->cpdist * c->cpdist) && !cantGetGrimoire(c, !isCheck(a))
if(a != roCheck) telekinesis(c); && c->item != itBarrow) {
return itOrbTelekinesis; if(!isCheck(a)) telekinesis(c);
return itOrbSpace;
} }
// (0') air blow // (0') air blow
@ -781,20 +958,77 @@ eItem targetRangedOrb(cell *c, orbAction a) {
nowhereToBlow = true; nowhereToBlow = true;
cell *c2 = c->mov[e % c->type]; cell *c2 = c->mov[e % c->type];
if(c2 && c2->cpdist > c->cpdist && passable(c2, c, P_BLOW)) { if(c2 && c2->cpdist > c->cpdist && passable(c2, c, P_BLOW)) {
if(a != roCheck) blowoff(c, c2); if(!isCheck(a)) blowoff(c, c2);
return itOrbAir; return itOrbAir;
} }
} }
} }
// nature
if(items[itOrbNature] && numplayers() == 1 && c->monst != moFriendlyIvy) {
cell *sides[8];
int qsides = 0;
forCellCM(cf, c)
if(cf->monst == moFriendlyIvy) {
if(c->monst) {
if(!canAttack(c, c->monst, cf, moFriendlyIvy, 0)) continue;
if(monstersnear(cwt.c, c, moPlayer, NULL, cwt.c)) continue;
}
else {
if(!passable(c, cf, P_ISPLAYER | P_MONSTER)) continue;
if(strictlyAgainstGravity(c, cf, false, MF_IVY)) continue;
if(monstersnear(cwt.c, NULL, moPlayer, c, cwt.c)) continue;
}
sides[qsides++] = cf;
}
if(qsides > 0) {
if(!isCheck(a)) growIvyTo(c, sides[hrand(qsides)]);
return itOrbNature;
}
}
// (0'') jump // (0'') jump
int jumpstate = 0; int jumpstate = 0;
cell *jumpthru = NULL; cell *jumpthru = NULL;
// orb of vaulting
if(!shmup::on && items[itOrbDash] && c->cpdist == 2) {
int i = items[itOrbAether];
if(i) items[itOrbAether] = i-1;
cell *c2 = NULL, *c3 = NULL;
for(int i=0; i<cwt.c->type; i++) {
cell *cc = cwt.c->mov[i];
if(isNeighbor(cc, c)) c3 = c2, c2 = cc;
}
jumpthru = c2;
jumpstate = 10;
if(jumpstate == 10 && c2) jumpstate = 11;
if(jumpstate == 11 && c2->monst) jumpstate = 12;
if(jumpstate == 12 && !c3) jumpstate = 13;
if(jumpstate == 13 && passable(c2, cwt.c, P_ISPLAYER | P_JUMP1 | P_MONSTER)) jumpstate = 14;
if(jumpstate == 14 && passable(c, c2, P_ISPLAYER | P_JUMP2)) jumpstate = 15;
if(jumpstate == 15 && canAttack(cwt.c, moPlayer, c2, c2->monst, 0)) jumpstate = 16;
if(jumpstate == 16 && !monstersnearO(a, c, c2, moPlayer, NULL, cwt.c)) jumpstate = 17;
items[itOrbAether] = i;
if(jumpstate == 17) {
if(!isCheck(a)) {
int k = tkills();
eMonster m = c2->monst;
attackMonster(c2, AF_ORSTUN | AF_MSG, moPlayer);
k = tkills() - k;
jumpTo(c, itOrbDash, k, m);
}
return itOrbDash;
}
}
if(items[itOrbFrog] && c->cpdist == 2) { if(items[itOrbFrog] && c->cpdist == 2) {
jumpstate = 1; jumpstate = 1;
int i = items[itOrbGhost]; int i = items[itOrbAether];
if(i) items[itOrbGhost] = i-1; if(i) items[itOrbAether] = i-1;
for(int i=0; i<cwt.c->type; i++) { for(int i=0; i<cwt.c->type; i++) {
cell *c2 = cwt.c->mov[i]; cell *c2 = cwt.c->mov[i];
if(isNeighbor(c2, c)) { if(isNeighbor(c2, c)) {
@ -808,36 +1042,36 @@ eItem targetRangedOrb(cell *c, orbAction a) {
} }
} }
} }
items[itOrbGhost] = i; items[itOrbAether] = i;
if(jumpstate == 3 && !monstersnear(c, NULL, moPlayer, NULL, c)) { if(jumpstate == 3 && !monstersnearO(a, c, NULL, moPlayer, NULL, cwt.c)) {
jumpstate = 4; jumpstate = 4;
if(a != roCheck) jumpTo(c, itOrbFrog); if(!isCheck(a)) jumpTo(c, itOrbFrog);
return itOrbFrog; return itOrbFrog;
} }
} }
// (1) switch with an illusion // (1) switch with an illusion
if(items[itOrbTeleport] && c->monst == moIllusion && !cwt.c->monst) { if(items[itOrbTeleport] && c->monst == moIllusion && !cwt.c->monst && teleportAction() == 1) {
if(a != roCheck) teleportTo(c); if(!isCheck(a)) teleportTo(c);
return itOrbTeleport; return itOrbTeleport;
} }
// (2) place illusion // (2) place illusion
if(!shmup::on && items[itOrbIllusion] && c->monst == moNone && c->item == itNone && passable(c, NULL, P_MIRROR)) { if(!shmup::on && items[itOrbIllusion] && c->monst == moNone && c->item == itNone && passable(c, NULL, P_MIRROR)) {
if(a != roCheck) placeIllusion(c); if(!isCheck(a)) placeIllusion(c);
return itOrbIllusion; return itOrbIllusion;
} }
// (3) teleport // (3) teleport
if(items[itOrbTeleport] && c->monst == moNone && (c->item == itNone || itemHidden(c)) && if(items[itOrbTeleport] && c->monst == moNone && (c->item == itNone || itemHidden(c)) &&
passable(c, NULL, P_ISPLAYER | P_TELE) && shmup::verifyTeleport()) { passable(c, NULL, P_ISPLAYER | P_TELE) && teleportAction() && shmup::verifyTeleport()) {
if(a != roCheck) teleportTo(c); if(!isCheck(a)) teleportTo(c);
return itOrbTeleport; return itOrbTeleport;
} }
// (4) remove an illusion // (4) remove an illusion
if(!shmup::on && items[itOrbIllusion] && c->monst == moIllusion) { if(!shmup::on && items[itOrbIllusion] && c->monst == moIllusion) {
if(a != roCheck) { if(!isCheck(a)) {
addMessage(XLAT("You take the Illusion away.")); addMessage(XLAT("You take the Illusion away."));
items[itOrbIllusion] += 3; // 100% effective with the Orb of Energy! items[itOrbIllusion] += 3; // 100% effective with the Orb of Energy!
c->monst = moNone; c->monst = moNone;
@ -846,43 +1080,43 @@ eItem targetRangedOrb(cell *c, orbAction a) {
} }
// (4a) colt // (4a) colt
if(!shmup::on && items[itRevolver] && c->monst && canAttack(cwt.c, moPlayer, c, c->monst, AF_GUN) && !monstersnear(cwt.c, c, moPlayer, NULL, cwt.c) if(!shmup::on && items[itRevolver] && c->monst && canAttack(cwt.c, moPlayer, c, c->monst, AF_GUN)
&& c->pathdist <= GUNRANGE) { && c->pathdist <= GUNRANGE && !monstersnearO(a, cwt.c, c, moPlayer, NULL, cwt.c)) {
if(a != roCheck) gun_attack(c); if(!isCheck(a)) gun_attack(c);
return itRevolver; return itRevolver;
} }
// (5) psi blast (non-shmup variant) // (5) psi blast (non-shmup variant)
if(!shmup::on && items[itOrbPsi] && c->monst && (isDragon(c->monst) || !isWorm(c)) && c->monst != moShadow) { if(!shmup::on && items[itOrbPsi] && c->monst && (isDragon(c->monst) || !isWorm(c)) && c->monst != moShadow && c->monst != moKrakenH) {
if(a != roCheck) psi_attack(c); if(!isCheck(a)) psi_attack(c);
return itOrbPsi; return itOrbPsi;
} }
// (5a) summoning // (5a) summoning
if(items[itOrbSummon] && summonedAt(c)) { if(items[itOrbSummon] && summonedAt(c)) {
if(a != roCheck) summonAt(c); if(!isCheck(a)) summonAt(c);
return itOrbSummon; return itOrbSummon;
} }
// (5b) matter // (5b) matter
if(items[itOrbMatter] && tempWallPossibleAt(c)) { if(items[itOrbMatter] && tempWallPossibleAt(c)) {
if(a != roCheck) tempWallAt(c); if(!isCheck(a)) tempWallAt(c);
return itOrbMatter; return itOrbMatter;
} }
// (5c) stun // (5c) stun
if(items[itOrbStunning] && c->monst && !isMultitile(c->monst) && c->stuntime < 3 && !shmup::on) { if(items[itOrbStunning] && c->monst && !isMultitile(c->monst) && c->stuntime < 3 && !shmup::on) {
if(a != roCheck) stun_attack(c); if(!isCheck(a)) stun_attack(c);
return itOrbStunning; return itOrbStunning;
} }
// (6) place fire (non-shmup variant) // (6) place fire (non-shmup variant)
if(!shmup::on && items[itOrbDragon] && makeflame(c, 20, true)) { if(!shmup::on && items[itOrbDragon] && makeflame(c, 20, true)) {
if(a != roCheck) useOrbOfDragon(c); if(!isCheck(a)) useOrbOfDragon(c);
return itOrbDragon; return itOrbDragon;
} }
if(a == roCheck) return itNone; if(isWeakCheck(a)) return itNone;
if(nowhereToBlow) { if(nowhereToBlow) {
addMessage(XLAT("Nowhere to blow %the1!", c->monst)); addMessage(XLAT("Nowhere to blow %the1!", c->monst));
@ -911,7 +1145,11 @@ eItem targetRangedOrb(cell *c, orbAction a) {
else if(items[itOrbTeleport] && c->monst) { else if(items[itOrbTeleport] && c->monst) {
addMessage(XLAT("Cannot teleport on a monster!")); addMessage(XLAT("Cannot teleport on a monster!"));
} }
else if(c->item && items[itOrbTelekinesis]) { else if(items[itOrbSpace] && c->item == itBarrow)
addMessage(XLAT("%The1 is protected from this kind of magic!", c->item));
else if(c->item && items[itOrbSpace] && !itemHiddenFromSight(c)) {
if(cwt.c->item)
addMessage(XLAT("Cannot use %the1 here!", itOrbSpace));
addMessage(XLAT("Not enough power for telekinesis!")); addMessage(XLAT("Not enough power for telekinesis!"));
} }
else if(items[itOrbIllusion] && c->item) else if(items[itOrbIllusion] && c->item)
@ -920,6 +1158,9 @@ eItem targetRangedOrb(cell *c, orbAction a) {
addMessage(XLAT("Cannot cast illusion on a monster!")); addMessage(XLAT("Cannot cast illusion on a monster!"));
else if(items[itOrbIllusion] && !passable(c, NULL, P_MIRROR)) else if(items[itOrbIllusion] && !passable(c, NULL, P_MIRROR))
addMessage(XLAT("Cannot cast illusion here!")); addMessage(XLAT("Cannot cast illusion here!"));
else if(items[itOrbTeleport] && teleportAction() == 0) {
addMessage(XLAT("All players are in the game!"));
}
else if(items[itOrbTeleport] && !passable(c, NULL, P_TELE | P_ISPLAYER)) { else if(items[itOrbTeleport] && !passable(c, NULL, P_TELE | P_ISPLAYER)) {
addMessage(XLAT("Cannot teleport here!")); addMessage(XLAT("Cannot teleport here!"));
} }

11854
polygons.cpp

File diff suppressed because it is too large Load Diff

1260
rogueviz.cpp Normal file

File diff suppressed because it is too large Load Diff

74
rug.cpp
View File

@ -3,7 +3,7 @@
// implementation of the Hypersian Rug mode // implementation of the Hypersian Rug mode
#ifndef MOBILE #ifndef NORUG
#define TEXTURESIZE (texturesize) #define TEXTURESIZE (texturesize)
#define HTEXTURESIZE (texturesize/2) #define HTEXTURESIZE (texturesize/2)
@ -54,6 +54,7 @@ struct rugpoint {
double x1, y1; double x1, y1;
bool valid; bool valid;
bool inqueue; bool inqueue;
double dist;
hyperpoint h; hyperpoint h;
hyperpoint flat; hyperpoint flat;
vector<edge> edges; vector<edge> edges;
@ -72,13 +73,9 @@ vector<triangle> triangles;
// construct the graph // construct the graph
//--------------------- //---------------------
map<cell*, hyperpoint> gmatrix;
void buildVertexInfo(cell *c, transmatrix V) { if(genrug) gmatrix[c] = V*C0; }
int hyprand; int hyprand;
rugpoint *addRugpoint(hyperpoint h) { rugpoint *addRugpoint(hyperpoint h, double dist) {
rugpoint *m = new rugpoint; rugpoint *m = new rugpoint;
m->h = h; m->h = h;
@ -89,14 +86,15 @@ rugpoint *addRugpoint(hyperpoint h) {
hpxyz(h[0], h[1], (h[2]-1) * (rand() % 1000 - rand() % 1000) / 1000); hpxyz(h[0], h[1], (h[2]-1) * (rand() % 1000 - rand() % 1000) / 1000);
m->valid = false; m->valid = false;
m->inqueue = false; m->inqueue = false;
m->dist = dist;
points.push_back(m); points.push_back(m);
return m; return m;
} }
rugpoint *findRugpoint(hyperpoint h) { rugpoint *findRugpoint(hyperpoint h, double dist) {
for(int i=0; i<size(points); i++) for(int i=0; i<size(points); i++)
if(intval(points[i]->h, h) < 1e-5) return points[i]; if(intval(points[i]->h, h) < 1e-5) return points[i];
return addRugpoint(h); return addRugpoint(h, dist);
} }
void addNewEdge(rugpoint *e1, rugpoint *e2) { void addNewEdge(rugpoint *e1, rugpoint *e2) {
@ -116,9 +114,9 @@ void addTriangle(rugpoint *t1, rugpoint *t2, rugpoint *t3) {
} }
void addTriangle1(rugpoint *t1, rugpoint *t2, rugpoint *t3) { void addTriangle1(rugpoint *t1, rugpoint *t2, rugpoint *t3) {
rugpoint *t12 = findRugpoint(mid(t1->h, t2->h)); rugpoint *t12 = findRugpoint(mid(t1->h, t2->h), (t1->dist+ t2->dist)/2);
rugpoint *t23 = findRugpoint(mid(t2->h, t3->h)); rugpoint *t23 = findRugpoint(mid(t2->h, t3->h), (t1->dist+ t2->dist)/2);
rugpoint *t31 = findRugpoint(mid(t3->h, t1->h)); rugpoint *t31 = findRugpoint(mid(t3->h, t1->h), (t1->dist+ t2->dist)/2);
addTriangle(t1, t12, t31); addTriangle(t1, t12, t31);
addTriangle(t12, t2, t23); addTriangle(t12, t2, t23);
addTriangle(t23, t3, t31); addTriangle(t23, t3, t31);
@ -140,7 +138,7 @@ void buildRug() {
for(int i=0; i<size(dcal); i++) for(int i=0; i<size(dcal); i++)
if(gmatrix.count(dcal[i])) if(gmatrix.count(dcal[i]))
vptr[dcal[i]] = addRugpoint(gmatrix[dcal[i]]); vptr[dcal[i]] = addRugpoint(gmatrix[dcal[i]]*C0, dcal[i]->cpdist);
for(int i=0; i<size(dcal); i++) { for(int i=0; i<size(dcal); i++) {
cell *c = dcal[i]; cell *c = dcal[i];
@ -232,7 +230,9 @@ void preset(rugpoint *m) {
// m->h = a->h + (b->h-a->h) * az - ah * ort // m->h = a->h + (b->h-a->h) * az - ah * ort
hyperpoint res = a->flat + (b->flat-a->flat) * az - ah * ort; hyperpoint res = a->flat + (b->flat-a->flat) * az - ah * ort;
for(int i=0; i<3; i++) h[i] += res[i]; q++; for(int i=0; i<3; i++) h[i] += res[i];
q++;
} }
} }
@ -255,7 +255,7 @@ void subdivide() {
rugpoint *m = points[i]; rugpoint *m = points[i];
for(int j=0; j<size(m->edges); j++) { for(int j=0; j<size(m->edges); j++) {
rugpoint *m2 = m->edges[j].target; rugpoint *m2 = m->edges[j].target;
rugpoint *mm = addRugpoint(mid(m->h, m2->h)); rugpoint *mm = addRugpoint(mid(m->h, m2->h), (m->dist+m2->dist)/2);
using namespace hyperpoint_vec; using namespace hyperpoint_vec;
mm->flat = (m->flat + m2->flat) / 2; mm->flat = (m->flat + m2->flat) / 2;
mm->valid = true; qvalid++; mm->valid = true; qvalid++;
@ -334,6 +334,8 @@ void drawTriangle(triangle& t) {
rugpoint& m2 = *t.m[1]; rugpoint& m2 = *t.m[1];
rugpoint& m3 = *t.m[2]; rugpoint& m3 = *t.m[2];
if(!m1.valid || !m2.valid || !m3.valid) return; if(!m1.valid || !m2.valid || !m3.valid) return;
if(m1.dist >= sightrange+.51 || m2.dist >= sightrange+.51 || m3.dist >= sightrange+.51)
return;
dt++; dt++;
double x1, y1, z1; double x1, y1, z1;
double x2, y2, z2; double x2, y2, z2;
@ -376,6 +378,7 @@ Uint32 *expanded_data;
void initTexture() { void initTexture() {
if(!rendernogl) { if(!rendernogl) {
#ifndef PANDORA
FramebufferName = 0; FramebufferName = 0;
glGenFramebuffers(1, &FramebufferName); glGenFramebuffers(1, &FramebufferName);
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName); glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
@ -400,6 +403,7 @@ void initTexture() {
addMessage("Failed to initialize the framebuffer"); addMessage("Failed to initialize the framebuffer");
rugged = false; rugged = false;
} }
#endif
} }
else { else {
texture = SDL_CreateRGBSurface(SDL_SWSURFACE,TEXTURESIZE,TEXTURESIZE,32,0,0,0,0); texture = SDL_CreateRGBSurface(SDL_SWSURFACE,TEXTURESIZE,TEXTURESIZE,32,0,0,0,0);
@ -430,6 +434,7 @@ void prepareTexture() {
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, TEXTURESIZE, TEXTURESIZE, 0, GL_BGRA, GL_UNSIGNED_BYTE, expanded_data ); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, TEXTURESIZE, TEXTURESIZE, 0, GL_BGRA, GL_UNSIGNED_BYTE, expanded_data );
} }
else { else {
#ifndef PANDORA
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName); glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
glViewport(0,0,TEXTURESIZE,TEXTURESIZE); glViewport(0,0,TEXTURESIZE,TEXTURESIZE);
@ -438,7 +443,8 @@ void prepareTexture() {
drawthemap(); drawthemap();
if(!renderonce) queueline(C0, mouseh, 0xFF00FF); if(!renderonce) queueline(C0, mouseh, 0xFF00FF);
drawqueue(); drawqueue();
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
#endif
} }
vid = svid; vid = svid;
if(!rendernogl) glViewport(0,0,vid.xres,vid.yres); if(!rendernogl) glViewport(0,0,vid.xres,vid.yres);
@ -451,9 +457,11 @@ void closeTexture() {
delete[] expanded_data; delete[] expanded_data;
} }
else { else {
#ifndef PANDORA
glDeleteTextures(1, &renderedTexture); glDeleteTextures(1, &renderedTexture);
glDeleteRenderbuffers(1, &depth_stencil_rb); glDeleteRenderbuffers(1, &depth_stencil_rb);
glDeleteFramebuffers(1, &FramebufferName); glDeleteFramebuffers(1, &FramebufferName);
#endif
} }
} }
@ -489,6 +497,7 @@ void drawRugScene() {
glDisable(GL_BLEND); glDisable(GL_BLEND);
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
xview = vid.xres/(vid.radius*scale); xview = vid.xres/(vid.radius*scale);
yview = vid.yres/(vid.radius*scale); yview = vid.yres/(vid.radius*scale);
@ -563,7 +572,6 @@ void init() {
if(renderonce) prepareTexture(); if(renderonce) prepareTexture();
if(!rugged) return; if(!rugged) return;
gmatrix.clear();
genrug = true; genrug = true;
drawthemap(); drawthemap();
genrug = false; genrug = false;
@ -581,7 +589,6 @@ void close() {
triangles.clear(); triangles.clear();
for(int i=0; i<size(points); i++) delete points[i]; for(int i=0; i<size(points); i++) delete points[i];
points.clear(); points.clear();
gmatrix.clear();
pqueue = queue<rugpoint*> (); pqueue = queue<rugpoint*> ();
} }
@ -637,16 +644,22 @@ hyperpoint gethyper(ld x, ld y) {
} }
void show() { void show() {
displayStat( 0, XLAT("hypersian rug mode"), "", ' '); dialog::init(XLAT("hypersian rug mode"), iinf[itPalace].color, 150, 100);
displayStat( 2, XLAT("what's this?"), "", 'h');
displayStat( 3, XLAT("take me back"), "", 'q'); dialog::addItem(XLAT("what's this?"), 'h');
displayStat( 4, XLAT("enable the Hypersian Rug mode"), "", 'u'); dialog::addItem(XLAT("take me back"), 'q');
displayStat( 6, XLAT("render the texture only once"), ONOFF(renderonce), 'o'); dialog::addItem(XLAT("enable the Hypersian Rug mode"), 'u');
displayStat( 7, XLAT("render texture without OpenGL"), ONOFF(rendernogl), 'g'); dialog::addBoolItem(XLAT("render the texture only once"), (renderonce), 'o');
displayStat( 8, XLAT("texture size"), its(texturesize)+"x"+its(texturesize), 's'); dialog::addBoolItem(XLAT("render texture without OpenGL"), (rendernogl), 'g');
dialog::addSelItem(XLAT("texture size"), its(texturesize)+"x"+its(texturesize), 's');
dialog::display();
} }
void handleKey(int uni, int sym) { void handleKey(int sym, int uni) {
#ifdef PANDORA
rendernogl = true;
#endif
dialog::handleNavigation(sym, uni);
if(uni == 'h') { if(uni == 'h') {
lastmode = cmode; lastmode = cmode;
@ -661,19 +674,24 @@ void handleKey(int uni, int sym) {
"Use arrow keys to rotate, Page Up/Down to zoom."; "Use arrow keys to rotate, Page Up/Down to zoom.";
} }
else if(uni == 'u') { else if(uni == 'u') {
if(sphere) restartGame('E');
if(euclid) restartGame('e');
rug::init(); rug::init();
cmode = emNormal; cmode = emNormal;
} }
else if(uni == 'q')
cmode = emChangeMode;
else if(uni == 'o') else if(uni == 'o')
renderonce = !renderonce; renderonce = !renderonce;
#ifndef PANDORA
else if(uni == 'g') else if(uni == 'g')
rendernogl = !rendernogl; rendernogl = !rendernogl;
#endif
else if(uni == 's') { else if(uni == 's') {
texturesize = 2*texturesize; texturesize *= 2;
if(texturesize == 8192) texturesize = 128; if(texturesize == 8192) texturesize = 128;
dialog::scaleLog();
} }
else if(uni || sym == SDLK_F10)
cmode = emChangeMode;
} }
void select() { void select() {

2146
shmup.cpp

File diff suppressed because it is too large Load Diff

207
sound.cpp Normal file
View File

@ -0,0 +1,207 @@
bool audio;
string musiclicense;
string musfname[landtypes];
int musicvolume = 60, effvolume = 60;
eLand getCurrentLandForMusic() {
eLand id = cwt.c->land;
if(isHaunted(id)) id = laHaunted;
if(id == laWarpSea) id = laWarpCoast;
return id;
}
void playSeenSound(cell *c) {
if(!c->monst) return;
bool nearme = c->cpdist <= 7;
forCellEx(c2, c) if(c2->cpdist <= 7) nearme = true;
if(!nearme) return;
if(c->monst == moEagle)
playSound(c, "seen-eagle");
else if(c->monst == moEarthElemental)
playSound(c, "seen-earth");
else if(c->monst == moAirElemental)
playSound(c, "seen-air");
else if(c->monst == moWaterElemental)
playSound(c, "seen-water");
else if(c->monst == moFireElemental)
playSound(c, "fire");
else if(c->monst == moDragonHead)
playSound(c, "seen-dragon");
else if(c->monst == moWorm)
playSound(c, "seen-sandworm");
else if(c->monst == moSkeleton && c->land != laDungeon)
playSound(c, "seen-skeleton");
else if(c->monst == moHexSnake)
playSound(c, "seen-snake");
else if(c->monst == moWolf || c->monst == moRedFox)
playSound(c, "seen-woof");
else if(isTroll(c->monst))
playSound(c, "seen-troll");
else if(c->monst == moNecromancer)
playSound(c, "seen-necromancer");
else if(c->monst == moGhost)
playSound(c, "seen-ghost");
else if(c->monst == moRoseBeauty)
playSound(c, princessgender() ? "seen-rosebeauty" : "seen-gardener");
else if(c->monst == moVizier)
playSound(c, "seen-vizier");
else if(c->monst == moFireFairy)
playSound(c, "seen-fairy");
else if(c->monst == moCultist)
playSound(c, "seen-cultist");
else if(c->monst == moPyroCultist)
playSound(c, "seen-cultistfire");
else if(c->monst == moCultistLeader)
playSound(c, "seen-cultistleader");
}
#ifdef SDLAUDIO
bool loaded[landtypes];
Mix_Music* music[landtypes];
int musicpos[landtypes];
int musstart;
int musfadeval = 2000;
eLand cid = laNone;
void handlemusic() {
DEBB(DF_GRAPH, (debugfile,"handle music\n"));
if(audio && musicvolume) {
eLand id = getCurrentLandForMusic();
#ifdef LOCAL
extern bool local_changemusic(eLand& id);
if(local_changemusic(id)) return;
#endif
if(outoffocus) id = eLand(0);
if(musfname[id] == "LAST") id = cid;
if(!loaded[id]) {
loaded[id] = true;
// printf("loading (%d)> %s\n", id, musfname[id].c_str());
if(musfname[id] != "") {
music[id] = Mix_LoadMUS(musfname[id].c_str());
if(!music[id]) {
printf("Mix_LoadMUS: %s\n", Mix_GetError());
}
}
}
if(cid != id && !musfadeval) {
musicpos[cid] = SDL_GetTicks() - musstart;
musfadeval = musicpos[id] ? 500 : 2000;
Mix_FadeOutMusic(musfadeval);
// printf("fadeout %d, pos %d\n", musfadeval, musicpos[cid]);
}
if(music[id] && !Mix_PlayingMusic()) {
cid = id;
Mix_VolumeMusic(musicvolume);
Mix_FadeInMusicPos(music[id], -1, musfadeval, musicpos[id] / 1000.0);
// printf("fadein %d, pos %d\n", musfadeval, musicpos[cid]);
musstart = SDL_GetTicks() - musicpos[id];
musicpos[id] = 0;
musfadeval = 0;
}
}
}
void resetmusic() {
if(audio && musicvolume) {
Mix_FadeOutMusic(3000);
cid = laNone;
for(int i=0; i<landtypes; i++) musicpos[i] = 0;
musfadeval = 2000;
}
}
bool loadMusicInfo(string dir) {
DEBB(DF_INIT, (debugfile,"load music info\n"));
if(dir == "") return false;
FILE *f = fopen(dir.c_str(), "rt");
if(f) {
string dir2;
for(int i=0; i<size(dir); i++) if(dir[i] == '/' || dir[i] == '\\')
dir2 = dir.substr(0, i+1);
char buf[1000];
while(fgets(buf, 800, f) > 0) {
for(int i=0; buf[i]; i++) if(buf[i] == 10 || buf[i] == 13) buf[i] = 0;
if(buf[0] == '[' && buf[3] == ']') {
int id = (buf[1] - '0') * 10 + buf[2] - '0';
if(id >= 0 && id < landtypes) {
if(buf[5] == '*' && buf[6] == '/') musfname[id] = dir2 + (buf+7);
else musfname[id] = buf+5;
}
else {
fprintf(stderr, "warning: bad soundtrack id, use the following format:\n");
fprintf(stderr, "[##] */filename\n");
fprintf(stderr, "where ## are two digits, and */ is optional and replaced by path to the music\n");
fprintf(stderr, "alternatively LAST = reuse the last track instead of having a special one");
}
// printf("[%2d] %s\n", id, buf);
}
else if(buf[0] == '#') {
}
else {
musiclicense += buf;
musiclicense += "\n";
}
}
fclose(f);
return true;
}
return false;
}
bool loadMusicInfo() {
return
loadMusicInfo(musicfile)
|| loadMusicInfo("./hyperrogue-music.txt")
|| loadMusicInfo("music/hyperrogue-music.txt")
// Destination set by ./configure (in the GitHub repository)
#ifdef MUSICDESTDIR
|| loadMusicInfo(MUSICDESTDIR)
#endif
#ifdef FHS
|| loadMusicInfo("/usr/share/hyperrogue/hyperrogue-music.txt")
|| loadMusicInfo(s0 + getenv("HOME") + "/.hyperrogue-music.txt")
#endif
;
}
void initAudio() {
audio = loadMusicInfo();
if(audio) {
if(Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, 2, 2048) != 0) {
fprintf(stderr, "Unable to initialize audio: %s\n", Mix_GetError());
audio = false;
}
else {
audio = true;
Mix_AllocateChannels(16);
}
}
}
map<string, Mix_Chunk*> chunks;
string wheresounds = "sounds/";
void playSound(cell *c, const string& fname, int vol) {
if(effvolume == 0) return;
// printf("Play sound: %s\n", fname.c_str());
if(!chunks.count(fname)) {
string s = wheresounds+fname+".ogg";
chunks[fname] = Mix_LoadWAV(s.c_str());
// printf("Loading, as %p\n", chunks[fname]);
}
Mix_Chunk *chunk = chunks[fname];
if(chunk) {
Mix_VolumeChunk(chunk, effvolume * vol / 100);
Mix_PlayChannel(-1, chunk, 0);
}
}
#else
void resetmusic() {}
#endif

View File

@ -8,6 +8,7 @@ bool cblind;
bool autocheat; bool autocheat;
int truelotus; int truelotus;
int gamecount;
time_t timerstart, savetime; time_t timerstart, savetime;
bool timerstopped; bool timerstopped;
@ -25,26 +26,28 @@ void initgame() {
firstland = safetyland; firstland = safetyland;
} }
if(tactic::on && euclid) euclidland = firstland; if(tactic::on && (euclid || sphere)) euclidland = firstland;
if(firstland == laNone || firstland == laBarrier) if(firstland == laNone || firstland == laBarrier)
firstland = laCrossroads; firstland = laCrossroads;
if(firstland == laCrossroads5 && !tactic::on) firstland = laCrossroads2; // could not fit!
if(firstland == laOceanWall) firstland = laOcean; if(firstland == laOceanWall) firstland = laOcean;
if(firstland == laHauntedWall) firstland = laGraveyard; if(firstland == laHauntedWall) firstland = laGraveyard;
if(firstland == laMountain && !tactic::on) firstland = laJungle;
if(isGravityLand(firstland) && !tactic::on) firstland = laCrossroads; if(isGravityLand(firstland) && !tactic::on) firstland = laCrossroads;
cwt.c = origin.c7; cwt.spin = 0; cwt.c = origin.c7; cwt.spin = 0; cwt.mirrored = false;
cwt.c->land = euclid ? euclidland : firstland; cwt.c->land = (euclid || sphere) ? euclidland : firstland;
chaosAchieved = false; chaosAchieved = false;
if(firstland == laElementalWall) cwt.c->land = randomElementalLand(); if(firstland == laElementalWall) cwt.c->land = randomElementalLand();
if(tactic::on && (isGravityLand(firstland) || firstland == laOcean)) if(tactic::on && (isGravityLand(firstland) || firstland == laOcean) && firstland != laMountain)
cwt.c->land = purehepta ? laCrossroads : laCrossroads2; cwt.c->land = purehepta ? laCrossroads : laCrossroads2;
createMov(cwt.c, 0); createMov(cwt.c, 0);
setdist(cwt.c, BARLEV, NULL); setdist(cwt.c, BARLEV, NULL);
if((tactic::on || yendor::on) && isCyclic(firstland)) { if((tactic::on || yendor::on) && isCyclic(firstland)) {
@ -64,9 +67,9 @@ void initgame() {
} }
if(tactic::on && firstland == laCaribbean) { if(tactic::on && firstland == laCaribbean) {
if(hiitemsMax(itRedGem) >= 25) items[itRedGem] = 25; if(hiitemsMax(itRedGem) >= 25) items[itRedGem] = min(hiitemsMax(itRedGem), 50);
if(hiitemsMax(itFernFlower) >= 25) items[itFernFlower] = 25; if(hiitemsMax(itFernFlower) >= 25) items[itFernFlower] = min(hiitemsMax(itFernFlower), 50);
if(hiitemsMax(itWine) >= 25) items[itWine] = 25; if(hiitemsMax(itWine) >= 25) items[itWine] = min(hiitemsMax(itWine), 50);
} }
if(tactic::on && tactic::trailer) if(tactic::on && tactic::trailer)
@ -90,29 +93,69 @@ void initgame() {
if(cwt.c->land == laCrossroads2) { if(cwt.c->land == laCrossroads2) {
cwt.c->landparam = 12; cwt.c->landparam = 12;
createMov(cwt.c, 0)->landparam = 44; createMov(cwt.c, 0)->landparam = 44;
createMov(cwt.c, 0)->land = laCrossroads2;
} }
for(int i=0; i<numplayers(); i++) sword::angle[i] = 11;
if(!safety) multi::players = vid.scfg.players;
if(multi::players < 1 || multi::players > MAXPLAYER)
multi::players = 1;
multi::whereto[0].d = MD_UNDECIDED;
multi::cpid = 0;
if(shmup::on) shmup::init();
// extern int sightrange; sightrange = 9; // extern int sightrange; sightrange = 9;
// cwt.c->land = laHell; items[itHell] = 10; // cwt.c->land = laHell; items[itHell] = 10;
for(int i=BARLEV; i>=0; i--) { for(int i=BARLEV; i>=0; i--) {
if(tactic::trailer) safety = true; if(tactic::trailer && cwt.c->land != laClearing) safety = true;
setdist(cwt.c, i, NULL); setdist(cwt.c, i, NULL);
if(tactic::trailer) safety = false; if(tactic::trailer) safety = false;
verifycells(&origin);
if(sphere) verifyDodecahedron();
else verifycells(&origin);
}
if(quotient && generateAll(firstland)) {
for(int i=0; i<size(quotientspace::allcells); i++)
setdist(quotientspace::allcells[i], 8, NULL);
}
if(multi::players > 1 && !shmup::on) for(int i=0; i<numplayers(); i++) {
int idir = (3 * i) % cwt.c->type;
multi::player[i].c = cwt.c->mov[idir];
// special case -- otherwise they land on a wall
if(firstland == laCrossroads2 && i == 1)
multi::player[1].c = cwt.c;
if(firstland == laCrossroads2 && i == 6)
multi::player[6].c = createMov(createMov(cwt.c, 0), 3);
setdist(cwt.c->mov[idir], 0, cwt.c);
multi::player[i].spin = 0;
multi::flipped[i] = true;
multi::whereto[i].d = MD_UNDECIDED;
} }
if(tactic::on && tactic::trailer) if(tactic::on && tactic::trailer)
items[treasureType(firstland)] = 15; items[treasureType(firstland)] = 15;
yendor::init(3); yendor::init(3);
makeEmpty(cwt.c); multi::revive_queue.clear();
if(shmup::on) shmup::init(); if(multi::players > 1 && !shmup::on) {
for(int i=0; i<numplayers(); i++)
makeEmpty(playerpos(i));
}
else {
for(int i=0; i<numplayers(); i++)
makeEmpty(cwt.c);
}
if(!safety) { if(!safety) {
usedSafety = false; usedSafety = false;
timerstart = time(NULL); turncount = 0; rosewave = 0; rosephase = 0; timerstart = time(NULL); turncount = 0; rosewave = 0; rosephase = 0;
mapeditor::whichPattern = 0; if(!quotient) mapeditor::whichPattern = 0;
mapeditor::whichShape = 0; mapeditor::whichShape = 0;
noiseuntil = 0; noiseuntil = 0;
sagephase = 0; hardcoreAt = 0; sagephase = 0; hardcoreAt = 0;
@ -127,7 +170,8 @@ void initgame() {
if(!randomPatternsMode && !tactic::on && !yendor::on) { if(!randomPatternsMode && !tactic::on && !yendor::on) {
if(firstland != (princess::challenge ? laPalace : laIce)) cheater++; if(firstland != (princess::challenge ? laPalace : laIce)) cheater++;
} }
if(princess::challenge) { if(tactic::trailer) ;
else if(princess::challenge) {
kills[moVizier] = 1; kills[moVizier] = 1;
princess::forceMouse = true; princess::forceMouse = true;
if(yendor::everwon) if(yendor::everwon)
@ -141,25 +185,55 @@ void initgame() {
items[i] = 10; items[i] = 10;
kills[moYeti] = 1000; kills[moYeti] = 1000;
} */ } */
if(ISANDROID && yendor::on && modecode() != 0)
addMessage(XLAT("Note: currently scores are saved only in the normal mode on Android")); else if(randomPatternsMode)
if(ISANDROID && tactic::on) addMessage(XLAT("Welcome to the Random Pattern mode!"));
addMessage(XLAT("Note: you can play, but scores won't be saved on Android")); else if(tactic::on)
addMessage(XLAT("You are playing %the1 in the Pure Tactics mode.", firstland));
else if(yendor::on)
addMessage(XLAT("Welcome to the Yendor Challenge %1!", its(yendor::challenge)));
else if(shmup::on) ; // welcome message given elsewhere
else if(euclid)
addMessage(XLAT("Welcome to the Euclidean mode!"));
else if(sphere && euclidland == laHalloween)
addMessage(XLAT("Welcome to Halloween!"));
else if(elliptic)
addMessage(XLAT("Good luck in the elliptic plane!"));
else if(sphere)
addMessage(XLAT("Welcome to Spherogue!"));
#ifdef ROGUEVIZ
else if(rogueviz::on)
addMessage(XLAT("Welcome to RogueViz!"));
#endif
else {
addMessage(XLAT("Welcome to HyperRogue!"));
#ifndef MOBILE
#ifdef IOS
addMessage(XLAT("Press F1 or right-shift-click things for help."));
#else
addMessage(XLAT("Press F1 or right-click things for help."));
#endif
#endif
}
} }
else { else {
usedSafety = true; usedSafety = true;
safety = false; safety = false;
} }
haverose = false; hadrose = false; rosemap.clear(); havewhat = hadwhat = 0; rosemap.clear();
elec::lightningfast = 0; elec::lightningfast = 0;
lastsafety = gold();
bfs(); bfs();
} }
#define MAXBOX 250 bool havesave = true;
#define POSSCORE 210 // update this when new boxes are added!
#ifndef NOSAVE
#define MAXBOX 300
#define POSSCORE 258 // update this when new boxes are added!
struct score { struct score {
string ver; string ver;
@ -171,6 +245,7 @@ bool saving, loading, loadingHi;
string boxname[MAXBOX]; string boxname[MAXBOX];
bool fakebox[MAXBOX]; bool fakebox[MAXBOX];
bool monsbox[MAXBOX];
void applyBox(int& t) { void applyBox(int& t) {
if(saving) savebox[boxid++] = t; if(saving) savebox[boxid++] = t;
@ -181,12 +256,14 @@ void applyBox(int& t) {
void applyBoxNum(int& i, string name = "") { void applyBoxNum(int& i, string name = "") {
fakebox[boxid] = (name == ""); fakebox[boxid] = (name == "");
boxname[boxid] = name; boxname[boxid] = name;
monsbox[boxid] = false;
applyBox(i); applyBox(i);
} }
void applyBoxBool(bool& b, string name = "") { void applyBoxBool(bool& b, string name = "") {
int i = b; int i = b;
applyBoxNum(i, name); applyBoxNum(i, name);
monsbox[boxid] = false;
b = i; b = i;
} }
@ -207,6 +284,7 @@ int applyBoxLoad(string name = "") {
void applyBoxI(eItem it, bool f = false) { void applyBoxI(eItem it, bool f = false) {
boxname[boxid] = iinf[it].name; boxname[boxid] = iinf[it].name;
fakebox[boxid] = f; fakebox[boxid] = f;
monsbox[boxid] = false;
if(loadingHi) { if(loadingHi) {
updateHi(it, savebox[boxid++]); updateHi(it, savebox[boxid++]);
} }
@ -216,6 +294,7 @@ void applyBoxI(eItem it, bool f = false) {
void applyBoxM(eMonster m, bool f = false) { void applyBoxM(eMonster m, bool f = false) {
fakebox[boxid] = f; fakebox[boxid] = f;
boxname[boxid] = minf[m].name; boxname[boxid] = minf[m].name;
monsbox[boxid] = true;
applyBox(kills[m]); applyBox(kills[m]);
} }
@ -231,7 +310,7 @@ void applyBoxes() {
applyBoxNum(turncount, "turn count"); applyBoxNum(turncount, "turn count");
applyBoxNum(cellcount, "cells generated"); applyBoxNum(cellcount, "cells generated");
if(!saving) timerstart = time(NULL); if(loading) timerstart = time(NULL);
for(int i=0; i<itOrbLightning; i++) for(int i=0; i<itOrbLightning; i++)
if(i == 0) items[i] = 0, applyBoxI(itFernFlower); if(i == 0) items[i] = 0, applyBoxI(itFernFlower);
@ -240,7 +319,8 @@ void applyBoxes() {
for(int i=0; i<43; i++) { for(int i=0; i<43; i++) {
if(loading) kills[i] = 0; if(loading) kills[i] = 0;
bool fake = bool fake =
i == moLesserM || i == moNone || i == moWolfMoved || i == moTentacletail; i == moLesserM || i == moNone || i == moWolfMoved || i == moTentacletail ||
i == moIvyNext;
if(i == moWormtail) applyBoxM(moCrystalSage); if(i == moWormtail) applyBoxM(moCrystalSage);
else if(i == moWormwait) applyBoxM(moFireFairy); else if(i == moWormwait) applyBoxM(moFireFairy);
else if(i == moTentacleEscaping) applyBoxM(moMiner); else if(i == moTentacleEscaping) applyBoxM(moMiner);
@ -252,17 +332,20 @@ void applyBoxes() {
} }
if(saving) { if(saving) {
applyBoxSave((int) (savetime + timer - timerstart), "time played"); int totaltime = savetime;
if(!timerstopped) totaltime += timer - timerstart;
applyBoxSave((int) totaltime, "time played");
} }
else if(loading) savetime = applyBoxLoad("time played"); else if(loading) savetime = applyBoxLoad("time played");
else boxid++; else boxname[boxid] = "time played", boxid++;
if(saving) savecount++; if(saving) savecount++;
applyBoxNum(savecount, "number of saves"); applyBoxNum(savecount, "number of saves");
if(saving) savecount--; if(saving) savecount--;
applyBoxNum(cheater, "number of cheats"); applyBoxNum(cheater, "number of cheats");
if(saving) applyBoxSave(items[itOrbSafety] ? safetyland : cwt.c->land, "current land"); fakebox[boxid] = true;
if(saving) applyBoxSave(items[itOrbSafety] ? safetyland : cwt.c->land, "");
else if(loading) firstland = safetyland = eLand(applyBoxLoad()); else if(loading) firstland = safetyland = eLand(applyBoxLoad());
else lostin = eLand(savebox[boxid++]); else lostin = eLand(savebox[boxid++]);
@ -275,7 +358,7 @@ void applyBoxes() {
applyBoxI(itPower); applyBoxI(itPower);
applyBoxI(itOrbFire, true); applyBoxI(itOrbFire, true);
applyBoxI(itOrbInvis, true); applyBoxI(itOrbInvis, true);
applyBoxI(itOrbGhost, true); applyBoxI(itOrbAether, true);
applyBoxI(itOrbPsi, true); applyBoxI(itOrbPsi, true);
applyBoxM(moBug0); applyBoxM(moBug0);
applyBoxM(moBug1); applyBoxM(moBug1);
@ -302,20 +385,21 @@ void applyBoxes() {
applyBoxM(moCShark); applyBoxM(moCShark);
applyBoxM(moParrot); applyBoxM(moParrot);
applyBoxI(itPirate); applyBoxI(itPirate);
applyBoxI(itOrbPreserve, true); applyBoxI(itOrbTime, true);
applyBoxM(moHexSnake); applyBoxM(moHexSnake);
applyBoxM(moRedTroll); applyBoxM(moRedTroll);
applyBoxI(itRedGem); applyBoxI(itRedGem);
applyBoxI(itOrbTelekinesis, true); applyBoxI(itOrbSpace, true);
applyBoxBool(euclid, "Euclidean"); int geo = geometry;
applyBoxNum(geo, ""); geometry = eGeometry(geo);
applyBoxBool(hardcore, "hardcore"); applyBoxBool(hardcore, "hardcore");
applyBoxNum(hardcoreAt, "hardcoreAt"); applyBoxNum(hardcoreAt, "");
applyBoxBool(shmup::on, "shmup"); applyBoxBool(shmup::on, "shmup");
if(saving) applyBoxSave(euclidland, "euclid land"); if(saving) applyBoxSave(euclidland, "euclid land");
else if(loading) euclidland = eLand(applyBoxLoad("euclid land")); else if(loading) euclidland = eLand(applyBoxLoad("euclid land"));
else boxid++; else fakebox[boxid++] = true;
applyBoxI(itCoast); applyBoxI(itCoast);
applyBoxI(itWhirlpool); applyBoxI(itWhirlpool);
@ -329,8 +413,8 @@ void applyBoxes() {
applyBoxI(itPalace); applyBoxI(itPalace);
applyBoxI(itFjord); applyBoxI(itFjord);
applyBoxI(itOrbFrog); applyBoxI(itOrbFrog, true);
applyBoxI(itOrbDiscord); applyBoxI(itOrbDiscord, true);
applyBoxM(moPalace); applyBoxM(moPalace);
applyBoxM(moFatGuard); applyBoxM(moFatGuard);
applyBoxM(moSkeleton); applyBoxM(moSkeleton);
@ -340,15 +424,15 @@ void applyBoxes() {
applyBoxM(moWaterElemental); applyBoxM(moWaterElemental);
applyBoxI(itSavedPrincess); applyBoxI(itSavedPrincess);
applyBoxI(itOrbLove); applyBoxI(itOrbLove, true);
applyBoxM(moPrincess); applyBoxM(moPrincess);
applyBoxM(moPrincessMoved); // live Princess for Safety applyBoxM(moPrincessMoved, false); // live Princess for Safety
applyBoxM(moPrincessArmedMoved); // live Princess for Safety applyBoxM(moPrincessArmedMoved, false); // live Princess for Safety
applyBoxM(moMouse); applyBoxM(moMouse);
applyBoxNum(princess::saveArmedHP, "save armed HP"); applyBoxNum(princess::saveArmedHP, "");
applyBoxNum(princess::saveHP, "save HP"); applyBoxNum(princess::saveHP, "");
applyBoxI(itEdge); applyBoxI(itIvory);
applyBoxI(itElemental); applyBoxI(itElemental);
applyBoxI(itZebra); applyBoxI(itZebra);
applyBoxI(itFireShard); applyBoxI(itFireShard);
@ -358,11 +442,11 @@ void applyBoxes() {
applyBoxM(moAirElemental); applyBoxM(moAirElemental);
applyBoxM(moFireElemental); applyBoxM(moFireElemental);
applyBoxM(moEdgeMonkey); applyBoxM(moFamiliar);
applyBoxM(moGargoyle); applyBoxM(moGargoyle);
applyBoxM(moOrangeDog); applyBoxM(moOrangeDog);
applyBoxI(itOrbSummon); applyBoxI(itOrbSummon, true);
applyBoxI(itOrbMatter); applyBoxI(itOrbMatter, true);
applyBoxM(moForestTroll); applyBoxM(moForestTroll);
applyBoxM(moStormTroll); applyBoxM(moStormTroll);
@ -373,11 +457,11 @@ void applyBoxes() {
applyBoxI(itMutant); applyBoxI(itMutant);
applyBoxI(itFulgurite); applyBoxI(itFulgurite);
applyBoxI(itBounty); applyBoxI(itBounty);
applyBoxI(itOrbLuck); applyBoxI(itOrbLuck, true);
applyBoxI(itOrbStunning, true); applyBoxI(itOrbStunning, true);
applyBoxBool(tactic::on, "tactic ON"); applyBoxBool(tactic::on, "");
applyBoxNum(elec::lightningfast, "lightningfast"); applyBoxNum(elec::lightningfast, "");
// if(savebox[boxid]) printf("lotus = %d (lost = %d)\n", savebox[boxid], isHaunted(lostin)); // if(savebox[boxid]) printf("lotus = %d (lost = %d)\n", savebox[boxid], isHaunted(lostin));
if(loadingHi && isHaunted(lostin)) boxid++; if(loadingHi && isHaunted(lostin)) boxid++;
@ -394,7 +478,7 @@ void applyBoxes() {
else applyBoxNum(truelotus, "lotus/escape"); else applyBoxNum(truelotus, "lotus/escape");
applyBoxBool(purehepta, "heptagons only"); applyBoxBool(purehepta, "heptagons only");
applyBoxI(itRose); applyBoxI(itRose);
applyBoxI(itOrbSkunk, true); applyBoxI(itOrbBeauty, true);
applyBoxI(itCoral); applyBoxI(itCoral);
applyBoxI(itOrb37, true); applyBoxI(itOrb37, true);
applyBoxI(itOrbEnergy, true); applyBoxI(itOrbEnergy, true);
@ -403,22 +487,69 @@ void applyBoxes() {
applyBoxM(moRoseLady); applyBoxM(moRoseLady);
applyBoxM(moRoseBeauty); applyBoxM(moRoseBeauty);
applyBoxBool(chaosmode, "Chaos mode"); applyBoxBool(chaosmode, "Chaos mode");
applyBoxNum(shmup::players, "shmup players"); applyBoxNum(multi::players, "shmup players");
if(multi::players < 1 || multi::players > MAXPLAYER)
multi::players = 1;
applyBoxM(moRatlingAvenger); applyBoxM(moRatlingAvenger);
// printf("applybox %d\n", shmup::players); // printf("applybox %d\n", shmup::players);
applyBoxI(itApple); applyBoxI(itApple);
applyBoxM(moKestrel); applyBoxM(moSparrowhawk);
applyBoxM(moLemur); applyBoxM(moResearcher);
applyBoxI(itDragon); applyBoxI(itDragon);
applyBoxM(moDragonHead); applyBoxM(moDragonHead);
applyBoxI(itOrbDomination, true); applyBoxI(itOrbDomination, true);
applyBoxI(itBabyTortoise); applyBoxI(itBabyTortoise);
applyBoxNum(tortoise::seekbits, "tortoise bits"); applyBoxNum(tortoise::seekbits, "");
applyBoxM(moTortoise); applyBoxM(moTortoise);
applyBoxI(itOrbShell, true); applyBoxI(itOrbShell, true);
applyBoxNum(safetyseed); applyBoxNum(safetyseed);
// (+18)
for(int i=0; i<6; i++) {
applyBoxNum(multi::treasures[i]);
applyBoxNum(multi::kills[i]);
applyBoxNum(multi::deaths[i]);
}
// (+8)
applyBoxM(moDragonTail);
applyBoxI(itKraken);
applyBoxM(moKrakenH);
applyBoxM(moKrakenT);
applyBoxI(itOrbSword, true);
applyBoxI(itBarrow);
applyBoxM(moDraugr);
applyBoxI(itOrbSword2, true);
applyBoxI(itTrollEgg);
applyBoxI(itOrbStone, true);
bool sph;
sph = false; applyBoxBool(sph, "sphere"); if(sph) geometry = gSphere;
sph = false; applyBoxBool(sph, "elliptic"); if(sph) geometry = gElliptic;
applyBox(princess::reviveAt);
applyBoxI(itDodeca);
applyBoxI(itAmethyst);
applyBoxI(itSlime);
applyBoxI(itOrbNature, true);
applyBoxI(itOrbDash, true);
// itOrbRecall should not be here
applyBoxM(moBat);
applyBoxM(moReptile);
applyBoxM(moFriendlyIvy);
applyBoxI(itGreenGrass);
applyBoxI(itBull);
applyBoxI(itOrbHorns, true);
applyBoxI(itOrbBull, true);
applyBoxM(moSleepBull);
applyBoxM(moRagingBull);
applyBoxM(moHerdBull);
applyBoxM(moButterfly);
applyBoxM(moGadfly);
if(POSSCORE != boxid) printf("ERROR: %d boxes\n", boxid);
} }
void saveBox() { void saveBox() {
@ -432,26 +563,22 @@ void loadBox() {
void loadBoxHigh() { void loadBoxHigh() {
int sp = shmup::players; dynamicval<int> sp1(multi::players, savebox[197]);
int son = shmup::on; dynamicval<eGeometry> sp2(geometry, (eGeometry) savebox[116]);
bool euc = euclid; dynamicval<bool> sp3(shmup::on, savebox[119]);
bool cha = chaosmode; dynamicval<bool> sp4(chaosmode, savebox[196]);
bool ph = purehepta; dynamicval<bool> sp5(purehepta, savebox[186]);
if(savebox[238]) geometry = gSphere;
euclid = savebox[116]; if(savebox[239]) geometry = gElliptic;
shmup::on = savebox[119];
purehepta = savebox[186];
chaosmode = savebox[196];
shmup::players = savebox[197];
if(shmup::on && !shmup::players) ; if(multi::players < 1 || multi::players > MAXPLAYER)
multi::players = 1;
if(shmup::on && multi::players == 1) ;
else { else {
// have boxid // have boxid
boxid = 0; loadingHi = true; applyBoxes(); loadingHi = false; boxid = 0; loadingHi = true; applyBoxes(); loadingHi = false;
} }
purehepta = ph; chaosmode = cha; euclid = euc; shmup::on = son; shmup::players = sp;
} }
// certify that saves and achievements were received // certify that saves and achievements were received
@ -473,11 +600,27 @@ namespace anticheat {
long long saveposition = -1; long long saveposition = -1;
#include <unistd.h>
#include <sys/types.h>
void remove_emergency_save() {
#ifndef WINDOWS
if(saveposition >= 0) {
/* if(!timerghost)
addMessage(XLAT("Emergency truncate to ") + its(saveposition)); */
if(truncate(scorefile, saveposition)) {}
saveposition = -1;
}
#endif
}
void saveStats(bool emergency = false) { void saveStats(bool emergency = false) {
DEBB(DF_INIT, (debugfile,"saveStats [%s]\n", scorefile)); DEBB(DF_INIT, (debugfile,"saveStats [%s]\n", scorefile));
#ifndef ANDROID
if(autocheat) return;
if(randomPatternsMode) return; if(randomPatternsMode) return;
remove_emergency_save();
FILE *f = fopen(scorefile, "at"); FILE *f = fopen(scorefile, "at");
@ -487,16 +630,12 @@ void saveStats(bool emergency = false) {
return; return;
} }
if(saveposition >= 0) {
// addMessage(XLAT("Emergency seek to ") + its(saveposition));
fseek(f, saveposition, SEEK_SET); saveposition = -1;
}
if(emergency) { if(emergency) {
saveposition = ftell(f); saveposition = ftell(f);
// addMessage(XLAT("Emergency save at ") + its(saveposition)); // if(!timerghost) addMessage(XLAT("Emergency save at ") + its(saveposition));
} }
if(showoff) return; if(showoff) { fclose(f); return; }
time_t timer; time_t timer;
timer = time(NULL); timer = time(NULL);
@ -558,11 +697,13 @@ void saveStats(bool emergency = false) {
fprintf(f, "Total wealth: %d\n", gold()); fprintf(f, "Total wealth: %d\n", gold());
fprintf(f, "Total enemies killed: %d\n", tkills()); fprintf(f, "Total enemies killed: %d\n", tkills());
fprintf(f, "cells generated: %d\n", cellcount); fprintf(f, "cells generated: %d\n", cellcount);
if(pureHardcore()) fprintf(f, "Pure hardcore mode\n");
if(purehepta) fprintf(f, "Heptagons only mode\n"); if(purehepta) fprintf(f, "Heptagons only mode\n");
if(chaosmode) fprintf(f, "Chaos mode\n"); if(chaosmode) fprintf(f, "Chaos mode\n");
if(shmup::on) fprintf(f, "Shoot-em up mode (%d players)\n", shmup::players); if(shmup::on) fprintf(f, "Shoot-em up mode\n");
if(multi::players > 1) fprintf(f, "Multi-player (%d players)\n", multi::players);
fprintf(f, "Number of cells explored, by distance from the player:\n"); fprintf(f, "Number of cells explored, by distance from the player:\n");
for(int i=0; i<10; i++) fprintf(f, " %d", explore[i]); fprintf(f, "\n"); {for(int i=0; i<10; i++) fprintf(f, " %d", explore[i]);} fprintf(f, "\n");
/*for(int j=0; j<landtypes; j++) { /*for(int j=0; j<landtypes; j++) {
bool haveland = false; bool haveland = false;
for(int i=0; i<10; i++) for(int i=0; i<10; i++)
@ -590,15 +731,12 @@ void saveStats(bool emergency = false) {
#ifndef MOBILE #ifndef MOBILE
DEBB(DF_INIT, (debugfile, "Game statistics saved to %s\n", scorefile)); DEBB(DF_INIT, (debugfile, "Game statistics saved to %s\n", scorefile));
addMessage(XLAT("Game statistics saved to %1", scorefile)); if(!tactic::trailer)
addMessage(XLAT("Game statistics saved to %1", scorefile));
#endif #endif
fclose(f); fclose(f);
#endif
} }
bool havesave = true;
#ifndef ANDROID
// load the save // load the save
void loadsave() { void loadsave() {
DEBB(DF_INIT, (debugfile,"loadSave\n")); DEBB(DF_INIT, (debugfile,"loadSave\n"));
@ -606,6 +744,8 @@ void loadsave() {
for(int xc=0; xc<MODECODES; xc++) for(int xc=0; xc<MODECODES; xc++)
for(int i=0; i<landtypes; i++) for(int j=0; j<MAXTAC; j++) for(int i=0; i<landtypes; i++) for(int j=0; j<MAXTAC; j++)
tactic::lsc[xc][i][j] = -1; tactic::lsc[xc][i][j] = -1;
gamecount = 0;
FILE *f = fopen(scorefile, "rt"); FILE *f = fopen(scorefile, "rt");
havesave = f; havesave = f;
@ -617,7 +757,9 @@ void loadsave() {
char buf[120]; char buf[120];
if(fgets(buf, 120, f) == NULL) break; if(fgets(buf, 120, f) == NULL) break;
if(buf[0] == 'H' && buf[1] == 'y') { if(buf[0] == 'H' && buf[1] == 'y') {
if(fscanf(f, "%s", buf) <= 0) break; sc.ver = buf; gamecount++;
if(fscanf(f, "%s", buf) <= 0) break;
sc.ver = buf;
if(sc.ver < "4.4" || sc.ver == "CHEATER!") { ok = false; continue; } if(sc.ver < "4.4" || sc.ver == "CHEATER!") { ok = false; continue; }
ok = true; ok = true;
for(int i=0; i<MAXBOX; i++) { for(int i=0; i<MAXBOX; i++) {
@ -661,16 +803,20 @@ void loadsave() {
if(buf[0] == 'Y' && buf[1] == 'E' && buf[2] == 'N') { if(buf[0] == 'Y' && buf[1] == 'E' && buf[2] == 'N') {
char buf1[80], ver[10]; char buf1[80], ver[10];
int cid, oy, won, tc, t, ts, cert; int cid, oy, won, tc, t, ts, cert=0;
sscanf(buf, "%70s%10s%d%d%d%d%d%d%d", sscanf(buf, "%70s%10s%d%d%d%d%d%d%d",
buf1, ver, &cid, &oy, &won, &tc, &t, &ts, &cert); buf1, ver, &cid, &oy, &won, &tc, &t, &ts, &cert);
if(won) for(int xc=0; xc<MODECODES; xc++) if(won) for(int xc=0; xc<MODECODES; xc++)
if(anticheat::check(cert, ver, won ? "WON" : "LOST", tc, t, ts, xc*999 + cid + 256 * oy)) { if(anticheat::check(cert, ver, won ? "WON" : "LOST", tc, t, ts, xc*999 + cid + 256 * oy)) {
if(xc == 19 && cid == 25) xc = 0;
if(cid > 0 && cid < YENDORLEVELS) if(cid > 0 && cid < YENDORLEVELS)
if(!(ver < string("8.0f") && oy > 1 && cid == 15)) { if(!(ver < string("8.0f") && oy > 1 && cid == 15))
if(!(ver < string("9.3b") && oy > 1 && (cid == 27 || cid == 28)))
{
yendor::bestscore[xc][cid] = max(yendor::bestscore[xc][cid], oy); yendor::bestscore[xc][cid] = max(yendor::bestscore[xc][cid], oy);
} }
break;
} }
} }
@ -701,14 +847,25 @@ void loadsave() {
void restartGame(char switchWhat) { void restartGame(char switchWhat) {
DEBB(DF_INIT, (debugfile,"restartGame\n")); DEBB(DF_INIT, (debugfile,"restartGame\n"));
achievement_final(true); achievement_final(true);
#ifndef NOSAVE
saveStats(); saveStats();
#endif
for(int i=0; i<ittypes; i++) items[i] = 0; for(int i=0; i<ittypes; i++) items[i] = 0;
for(int i=0; i<motypes; i++) kills[i] = 0; lastkills = 0; for(int i=0; i<motypes; i++) kills[i] = 0;
for(int i=0; i<10; i++) explore[i] = 0; for(int i=0; i<10; i++) explore[i] = 0;
for(int i=0; i<10; i++) for(int l=0; l<landtypes; l++) for(int i=0; i<10; i++) for(int l=0; l<landtypes; l++)
exploreland[i][l] = 0; exploreland[i][l] = 0;
anticheat::tampered = false; achievementsReceived.clear();
for(int i=0; i<numplayers(); i++)
if(multi::playerActive(i))
multi::deaths[i]++;
#ifndef NOSAVE
anticheat::tampered = false;
#endif
achievementsReceived.clear();
princess::saved = false; princess::saved = false;
princess::reviveAt = 0;
princess::forceVizier = false; princess::forceVizier = false;
princess::forceMouse = false; princess::forceMouse = false;
knighted = 0; knighted = 0;
@ -716,20 +873,22 @@ void restartGame(char switchWhat) {
cellcount = 0; cellcount = 0;
clearMemory(); clearMemory();
if(switchWhat == 'C') { if(switchWhat == 'C') {
euclid = yendor::on = tactic::on = princess::challenge = false; geometry = gNormal;
yendor::on = tactic::on = princess::challenge = false;
resetGeometry();
chaosmode = !chaosmode; chaosmode = !chaosmode;
} }
if(switchWhat == '7') { if(switchWhat == '7') {
if(euclid) euclid = false; if(euclid) geometry = gNormal;
purehepta = !purehepta; purehepta = !purehepta;
extern void precalc(); extern void resetGL(); resetGeometry();
precalc(); resetGL();
} }
if(switchWhat == 'e') { if(switchWhat == 'g') {
extern void precalc(); extern void resetGL(); if(geometry == targetgeometry) geometry = gNormal;
if(chaosmode) chaosmode = false; else geometry = targetgeometry;
if(purehepta) { purehepta = false; precalc(); resetGL(); } if(chaosmode && geometry != gNormal) chaosmode = false;
euclid = !euclid; if(purehepta && euclid) purehepta = false;
resetGeometry();
} }
if(switchWhat == 'y') { if(switchWhat == 'y') {
yendor::on = !yendor::on; yendor::on = !yendor::on;
@ -794,11 +953,12 @@ void clearGameMemory() {
DEBB(DF_INIT, (debugfile,"clearGameMemory\n")); DEBB(DF_INIT, (debugfile,"clearGameMemory\n"));
pathq.clear(); pathq.clear();
dcal.clear(); dcal.clear();
yendor::yii = 0; yendor::yi.clear(); yendor::yii = NOYENDOR; yendor::yi.clear();
clearshadow(); clearshadow();
offscreen.clear(); offscreen.clear();
princess::clear(); princess::clear();
buggycells.clear(); buggycells.clear();
mirrors.clear();
clearing::bpdata.clear(); clearing::bpdata.clear();
tortoise::emap.clear(); tortoise::emap.clear();
tortoise::babymap.clear(); tortoise::babymap.clear();
@ -809,6 +969,15 @@ void clearGameMemory() {
conformal::movehistory.clear(); conformal::movehistory.clear();
conformal::includeHistory = false; conformal::includeHistory = false;
#endif #endif
recallCell = NULL;
prairie::lasttreasure = NULL;
prairie::enter = NULL;
prairie::tchoices.clear();
prairie::beaststogen.clear();
butterflies.clear();
#ifdef ROGUEVIZ
rogueviz::close();
#endif
} }
static int orbid = 0; static int orbid = 0;
@ -835,7 +1004,12 @@ eItem randomTreasure2(int cv) {
if(itemclass(i) != IC_TREASURE) continue; if(itemclass(i) != IC_TREASURE) continue;
int q = 2*items[i]; int q = 2*items[i];
if(a == lt) q -= (2*cv-1); if(a == lt) q -= (2*cv-1);
if(a == itEmerald && bearsCamelot(cwt.c->land)) q -= 5; if(a == itEmerald && bearsCamelot(cwt.c->land)) q -= 8;
if(a == itElixir && isCrossroads(cwt.c->land)) q -= 7;
if(a == itIvory && isCrossroads(cwt.c->land)) q -= 6;
if(a == itPalace && isCrossroads(cwt.c->land)) q -= 5;
if(a == itIvory && cwt.c->land == laJungle) q -= 5;
if(a == itIvory && cwt.c->land == laPalace) q -= 5;
if(q < bq) bq = q, cq = 0; if(q < bq) bq = q, cq = 0;
if(q == bq) { cq++; if(hrand(cq) == 0) best = i; } if(q == bq) { cq++; if(hrand(cq) == 0) best = i; }
} }
@ -844,10 +1018,20 @@ eItem randomTreasure2(int cv) {
bool isTechnicalLand(eLand l) { bool isTechnicalLand(eLand l) {
return l == laNone || l == laOceanWall || l == laBarrier || l == laCanvas || return l == laNone || l == laOceanWall || l == laBarrier || l == laCanvas ||
l == laHauntedWall || l == laHauntedBorder; l == laHauntedWall || l == laHauntedBorder || l == laCA;
}
eLand cheatdest;
void cheatMoveTo(eLand l) {
cheatdest = l;
if(l == laCrossroads5) l = laCrossroads;
activateSafety(l);
cheatdest = laNone;
} }
bool applyCheat(char u, cell *c = NULL) { bool applyCheat(char u, cell *c = NULL) {
if(u == 'M' && cwt.c->type == 6) { if(u == 'M' && cwt.c->type == 6) {
addMessage(XLAT("You summon some Mirages!")); addMessage(XLAT("You summon some Mirages!"));
cheater++; cheater++;
@ -877,7 +1061,7 @@ bool applyCheat(char u, cell *c = NULL) {
} }
if(u == 'C') { if(u == 'C') {
cheater++; cheater++;
activateSafety(laCrossroads); cheatMoveTo(laCrossroads);
addMessage(XLAT("Activated the Hyperstone Quest!")); addMessage(XLAT("Activated the Hyperstone Quest!"));
for(int t=1; t<ittypes; t++) for(int t=1; t<ittypes; t++)
@ -932,11 +1116,7 @@ bool applyCheat(char u, cell *c = NULL) {
return true; return true;
} }
if(u == 'R'-64) buildRosemap(); if(u == 'R'-64) buildRosemap();
if(u == 'D'-64) { #ifndef NOEDIT
mapeditor::drawplayer = !mapeditor::drawplayer;
return true;
}
#ifndef MOBILE
if(u == 'A') { if(u == 'A') {
lastexplore = turncount; lastexplore = turncount;
cmode = emMapEditor; cmode = emMapEditor;
@ -986,7 +1166,7 @@ bool applyCheat(char u, cell *c = NULL) {
addMessage(XLAT("You summon an Ivy!")); addMessage(XLAT("You summon an Ivy!"));
cheater++; cheater++;
int i = cwt.spin; int i = cwt.spin;
int j = cwt.c->spn[i]; int j = cwt.c->spn(i);
cell* c = cwt.c->mov[i]->mov[(j+3)%cwt.c->mov[i]->type]; cell* c = cwt.c->mov[i]->mov[(j+3)%cwt.c->mov[i]->type];
if(passable(c, NULL, 0)) buildIvy(c, 0, 1); if(passable(c, NULL, 0)) buildIvy(c, 0, 1);
return true; return true;
@ -1037,8 +1217,9 @@ bool applyCheat(char u, cell *c = NULL) {
return true; return true;
} }
if(u == 'Z') { if(u == 'Z') {
cwt.spin++; flipplayer = false; flipplayer = false;
cwt.spin %= cwt.c->type; mirror::spin(1);
cwspin(cwt, 1);
return true; return true;
} }
if(u == 'J') { if(u == 'J') {
@ -1058,14 +1239,14 @@ bool applyCheat(char u, cell *c = NULL) {
} }
if(u == 'S') { if(u == 'S') {
canmove = true; canmove = true;
activateSafety(cwt.c->land); cheatMoveTo(cwt.c->land);
items[itOrbSafety] += 3; items[itOrbSafety] += 3;
cheater++; addMessage(XLAT("Activated Orb of Safety!")); cheater++; addMessage(XLAT("Activated Orb of Safety!"));
return true; return true;
} }
if(u == 'U') { if(u == 'U') {
canmove = true; canmove = true;
activateSafety(firstland); cheatMoveTo(firstland);
cheater++; addMessage(XLAT("Teleported to %1!", firstland)); cheater++; addMessage(XLAT("Teleported to %1!", firstland));
return true; return true;
} }
@ -1090,15 +1271,39 @@ bool applyCheat(char u, cell *c = NULL) {
cwt.c->mov[i]->item = itOrbYendor; cwt.c->mov[i]->item = itOrbYendor;
return true; return true;
} }
if(u == 'B'-64) {
int i = cwt.spin;
sword::angle[0]++;
cwt.c->mov[i]->item = hrand(2) ? itOrbSword2 : itOrbSword;
return true;
}
if(u == 'X'-64) { if(u == 'X'-64) {
items[itEdge] = 12345; items[itOrbNature] += 50;
cheater++; cheater++;
return true; return true;
} }
if(u == 'V'-64) {
viewdists = !viewdists;
return true;
}
if(u == 'L'-64) {
cell *c = mouseover;
describeCell(c);
printf("Neighbors:"); for(int i=0; i<c->type; i++) printf("%p ", c->mov[i]);
printf("Barrier: dir=%d left=%d right=%d\n",
c->bardir, c->barleft, c->barright);
return true;
}
if(u == 'C'-64) { if(u == 'C'-64) {
cblind = !cblind; cblind = !cblind;
return true; return true;
} }
#ifdef LOCAL
if(u == 'D'-64) {
cheater = 0; autocheat = 0;
return true;
}
#endif
return false; return false;
} }

92
util.cpp Normal file
View File

@ -0,0 +1,92 @@
// Hyperbolic Rogue
// Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details
// basic utility functions
#ifdef MOBWEB
typedef double ld;
#define LDF "%lf"
#define PLDF "lf"
#define ASINH asinh
#else
typedef long double ld;
#define LDF "%Lf"
#define PLDF "Lf"
#define ASINH asinhl
#endif
template<class T> int size(const T& x) {return int(x.size()); }
string its(int i) { char buf[64]; sprintf(buf, "%d", i); return buf; }
string fts(float x) { char buf[64]; sprintf(buf, "%4.2f", x); return buf; }
string fts3(float x) { char buf[64]; sprintf(buf, "%5.3f", x); return buf; }
string fts4(float x) { char buf[64]; sprintf(buf, "%6.4f", x); return buf; }
string cts(char c) { char buf[8]; buf[0] = c; buf[1] = 0; return buf; }
string llts(long long i) {
// sprintf does not work on Windows IIRC
if(i < 0) return "-" + llts(-i);
if(i < 10) return its((int) i);
return llts(i/10) + its(i%10);
}
string itsh(int i) {static char buf[16]; sprintf(buf, "%03X", i); return buf; }
// debug utilities
extern FILE *debugfile;
extern int debugflags;
#ifdef ANDROID
#define DEBB(r,x)
#else
#define DEBB(r,x) { if(debugfile && (!(r) || (debugflags & (r)))) { fprintf x; fflush(debugfile); } }
#endif
#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
#ifdef PROFILING
#include <sys/time.h>
long long getms() {
struct timeval tval;
gettimeofday(&tval, NULL);
return tval.tv_sec * 1000000 + tval.tv_usec;
}
#define FRAMES 64
#define CATS 16
long long proftable[16][FRAMES];
int pframeid;
void profile_frame() {
pframeid++; pframeid %= FRAMES;
for(int t=0; t<16; t++) proftable[t][pframeid] = 0;
}
void profile_start(int t) { proftable[t][pframeid] -= getms(); }
void profile_stop(int t) { proftable[t][pframeid] += getms(); }
void profile_info() {
for(int t=0; t<16; t++) {
sort(proftable[t], proftable[t]+FRAMES);
if(proftable[t][FRAMES-1] == 0) continue;
long long sum = 0;
for(int f=0; f<FRAMES; f++) sum += proftable[t][f];
printf("Category %d: avg = %Ld, %Ld..%Ld..%Ld..%Ld..%Ld\n",
t, sum / FRAMES, proftable[t][0], proftable[t][16], proftable[t][32],
proftable[t][48], proftable[t][63]);
}
}
#else
#define profile_frame()
#define profile_start(t)
#define profile_stop(t)
#define profile_info()
#endif

View File

@ -5,7 +5,7 @@
// Yendor Quest, together with the Yendor Challenge // Yendor Quest, together with the Yendor Challenge
// also, the Pure Tactics Mode // also, the Pure Tactics Mode
#define MODECODES 38 #define MODECODES 254
int hiitemsMax(eItem it) { int hiitemsMax(eItem it) {
int mx = 0; int mx = 0;
@ -50,7 +50,7 @@ namespace yendor {
int challenge; // id of the challenge int challenge; // id of the challenge
int lastchallenge; int lastchallenge;
#define YENDORLEVELS 27 #define YENDORLEVELS 29
int bestscore[MODECODES][YENDORLEVELS]; int bestscore[MODECODES][YENDORLEVELS];
@ -69,6 +69,7 @@ namespace yendor {
#define YF_START_AL 2048 #define YF_START_AL 2048
#define YF_START_CR 4096 #define YF_START_CR 4096
#define YF_CHAOS 8192 #define YF_CHAOS 8192
#define YF_RECALL 16384
#define YF_START_ANY (YF_START_AL|YF_START_CR) #define YF_START_ANY (YF_START_AL|YF_START_CR)
@ -103,14 +104,26 @@ namespace yendor {
{laWildWest, 0}, {laWildWest, 0},
{laWhirlwind, YF_NEAR_TENT}, {laWhirlwind, YF_NEAR_TENT},
{laHell, YF_CHAOS | YF_DEAD}, {laHell, YF_CHAOS | YF_DEAD},
{laDragon, YF_DEAD} {laDragon, YF_DEAD},
{laReptile, 0},
{laTortoise, YF_RECALL},
}; };
int tscorelast;
void uploadScore() { void uploadScore() {
int tscore = 0; int tscore = 0;
for(int i=1; i<YENDORLEVELS; i++) for(int i=1; i<YENDORLEVELS; i++)
if(bestscore[0][i]) tscore += 999 + bestscore[0][i]; if(bestscore[0][i]) tscore += 999 + bestscore[0][i];
// printf("Yendor score = %d\n", tscore); // printf("Yendor score = %d\n", tscore);
if(tscore > tscorelast) {
tscorelast = tscore;
if(tscore >= 1000) achievement_gain("YENDC1", 'x');
if(tscore >= 5000) achievement_gain("YENDC2", 'x');
if(tscore >= 15000) achievement_gain("YENDC3", 'x');
}
achievement_score(LB_YENDOR_CHALLENGE, tscore); achievement_score(LB_YENDOR_CHALLENGE, tscore);
} }
@ -134,7 +147,8 @@ namespace yendor {
vector<yendorinfo> yi; vector<yendorinfo> yi;
int yii = 0; #define NOYENDOR 999999
int yii = NOYENDOR;
int hardness() { int hardness() {
int thf = 0; int thf = 0;
@ -156,11 +170,10 @@ namespace yendor {
return ysUntouched; return ysUntouched;
} }
bool check(cell *yendor, bool checkonly) { bool check(cell *yendor) {
int byi = size(yi); int byi = size(yi);
for(int i=0; i<size(yi); i++) if(yi[i].path[0] == yendor) byi = i; for(int i=0; i<size(yi); i++) if(yi[i].path[0] == yendor) byi = i;
if(byi < size(yi) && yi[byi].found) return true; if(byi < size(yi) && yi[byi].found) return false;
if(checkonly) return false;
if(byi == size(yi)) { if(byi == size(yi)) {
yendorinfo nyi; yendorinfo nyi;
nyi.path[0] = yendor; nyi.path[0] = yendor;
@ -241,7 +254,7 @@ namespace yendor {
generating = false; generating = false;
for(int b=10; b>=5; b--) setdist(key, b, nyi.path[YDIST-2]); for(int b=10; b>=5; b--) setdist(key, b, nyi.path[YDIST-2]);
for(int i=-1; i<key->type; i++) { for(int i=-1; i<key->type; i++) {
cell *c2 = i >= 0 ? key->mov[i] : key; cell *c2 = i >= 0 ? key->mov[i] : key;
checkTide(c2); checkTide(c2);
@ -257,6 +270,7 @@ namespace yendor {
c2->wall = waBoat, c2->monst = moPirate, c2->item = itOrbWater; c2->wall = waBoat, c2->monst = moPirate, c2->item = itOrbWater;
else c2->wall = waNone; else c2->wall = waNone;
} }
if(c2->wall == waReptile) c2->wall = waNone;
if(c2->wall == waMineMine || c2->wall == waMineUnknown) if(c2->wall == waMineMine || c2->wall == waMineUnknown)
c2->wall = waMineOpen; c2->wall = waMineOpen;
if(c2->wall == waTrapdoor && i == -1) if(c2->wall == waTrapdoor && i == -1)
@ -269,14 +283,20 @@ namespace yendor {
if(isGravityLand(c2->land) && key->land == c2->land && if(isGravityLand(c2->land) && key->land == c2->land &&
c2->landparam < key->landparam && c2->wall != waTrunk) c2->landparam < key->landparam && c2->wall != waTrunk)
c2->wall = waPlatform; c2->wall = waPlatform;
if(c2->land == laReptile && i >= 0)
c2->wall = waChasm;
} }
key->item = itKey; key->item = itKey;
yi.push_back(nyi); yi.push_back(nyi);
} }
yii = byi;
addMessage(XLAT("You need to find the right Key to unlock this Orb of Yendor!")); addMessage(XLAT("You need to find the right Key to unlock this Orb of Yendor!"));
achievement_gain("YENDOR1"); if(yii != byi) {
yii = byi;
achievement_gain("YENDOR1");
playSound(yendor, "pickup-yendor");
return true;
}
return false; return false;
} }
@ -314,6 +334,16 @@ namespace yendor {
if(clev().flags & YF_DEAD) items[itGreenStone] = 100; if(clev().flags & YF_DEAD) items[itGreenStone] = 100;
if(clev().flags & YF_DEAD5) items[itGreenStone] = 5; if(clev().flags & YF_DEAD5) items[itGreenStone] = 5;
} }
if(clev().flags & YF_RECALL) {
int yq = items[itOrbYendor];
items[itOrbRecall] = 60 - yq;
items[itOrbTime] = 60 - yq;
items[itOrbEnergy] = 60 - yq;
items[itOrbTeleport] = 60 - yq;
items[itOrbSpace] = 60 - yq;
items[itOrbDash] = 60 - yq;
items[itOrbFrog] = 60 - yq;
}
nexttostart = laNone; nexttostart = laNone;
} }
@ -321,7 +351,7 @@ namespace yendor {
cell *c2 = cwt.c->mov[0]; cell *c2 = cwt.c->mov[0];
c2->land = firstland; c2->land = firstland;
if(firstland == laRlyeh) c2->wall = waNone; if(firstland == laRlyeh) c2->wall = waNone;
yendor::check(c2, false); yendor::check(c2);
if(clev().flags & YF_NEAR_IVY) if(clev().flags & YF_NEAR_IVY)
nexttostart = laJungle; nexttostart = laJungle;
if(clev().flags & YF_NEAR_TENT) if(clev().flags & YF_NEAR_TENT)
@ -354,6 +384,7 @@ namespace yendor {
makeEmpty(c2); makeEmpty(c2);
c2->item = itOrbYendor; c2->item = itOrbYendor;
nexttostart = laNone; nexttostart = laNone;
if(clev().flags & YF_RECALL) recallCell = cwt.c;
} }
} }
@ -368,6 +399,7 @@ namespace yendor {
if((ylev.flags & YF_NEAR_TENT) && hiitemsMax(itStatue) < 10) return false; if((ylev.flags & YF_NEAR_TENT) && hiitemsMax(itStatue) < 10) return false;
if((ylev.flags & YF_CHAOS) && !chaosUnlocked) return false; if((ylev.flags & YF_CHAOS) && !chaosUnlocked) return false;
if((ylev.flags & (YF_DEAD|YF_DEAD5)) && hiitemsMax(itBone) < 10) return false; if((ylev.flags & (YF_DEAD|YF_DEAD5)) && hiitemsMax(itBone) < 10) return false;
if((ylev.flags & YF_RECALL) && hiitemsMax(itSlime) < 10) return false;
return true; return true;
} }
@ -380,13 +412,13 @@ namespace yendor {
void showMenu() { void showMenu() {
int s = vid.fsize; int s = vid.fsize;
vid.fsize = vid.fsize * 4/5; vid.fsize = vid.fsize * 4/5;
displayStatHelp(-8, XLAT("Yendor Challenge")); dialog::init(XLAT("Yendor Challenge"), iinf[itOrbYendor].color, 150, 100);
for(int i=1; i<YENDORLEVELS; i++) { for(int i=1; i<YENDORLEVELS; i++) {
string s; string s;
yendorlevel& ylev(levels[i]); yendorlevel& ylev(levels[i]);
if(levelUnlocked(i)) { if(autocheat || levelUnlocked(i)) {
s = XLATT1(ylev.l); s = XLATT1(ylev.l);
@ -399,6 +431,7 @@ namespace yendor {
if(ylev.flags & YF_NEAR_RED) { s += "+"; s += XLATT1(laRedRock); } if(ylev.flags & YF_NEAR_RED) { s += "+"; s += XLATT1(laRedRock); }
if(ylev.flags & YF_START_AL) { s += "+"; s += XLATT1(laAlchemist); } if(ylev.flags & YF_START_AL) { s += "+"; s += XLATT1(laAlchemist); }
if(ylev.flags & YF_DEAD) { s += "+"; s += XLATT1(itGreenStone); } if(ylev.flags & YF_DEAD) { s += "+"; s += XLATT1(itGreenStone); }
if(ylev.flags & YF_RECALL) { s += "+"; s += XLATT1(itOrbRecall); }
} }
} }
@ -412,14 +445,17 @@ namespace yendor {
else if(bestscore[modecode()][i]) else if(bestscore[modecode()][i])
v = XLAT(" (won at level %1!)", its(bestscore[modecode()][i])); v = XLAT(" (won at level %1!)", its(bestscore[modecode()][i]));
displayStat(i-6, s, v, 'a' + i-1); dialog::addSelItem(s, v, 'a' + i-1);
} }
displayStat(YENDORLEVELS+1-6, XLAT("Return to the normal game"), "", '0'); dialog::addBreak(60);
displayStat(YENDORLEVELS+1-5, XLAT( dialog::addItem(XLAT("Return to the normal game"), '0');
dialog::addSelItem(XLAT(
easy ? "Challenges do not get harder" : "Each challenge gets harder after each victory"), easy ? "Challenges do not get harder" : "Each challenge gets harder after each victory"),
" " + XLAT(easy ? "easy" : "challenge"), '1'); " " + XLAT(easy ? "easy" : "challenge"), '1');
dialog::display();
int yc = getcstat - 'a' + 1; int yc = getcstat - 'a' + 1;
if(yc > 0 && yc < YENDORLEVELS) { if(yc > 0 && yc < YENDORLEVELS) {
subscoreboard scorehere; subscoreboard scorehere;
@ -463,10 +499,11 @@ namespace yendor {
"You get 1000 points for each challenge won, and 1 extra point for " "You get 1000 points for each challenge won, and 1 extra point for "
"each extra difficulty level."; "each extra difficulty level.";
void handleKey(int uni, int sym) { void handleKey(int sym, int uni) {
dialog::handleNavigation(sym, uni);
if(uni >= 'a' && uni < 'a'+YENDORLEVELS-1) { if(uni >= 'a' && uni < 'a'+YENDORLEVELS-1) {
challenge = uni-'a' + 1; challenge = uni-'a' + 1;
if(levelUnlocked(challenge)) { if(levelUnlocked(challenge) || autocheat) {
restartGame(yendor::on ? 0 : 'y'); restartGame(yendor::on ? 0 : 'y');
cmode = emNormal; cmode = emNormal;
} }
@ -522,6 +559,7 @@ namespace tactic {
bool tacticUnlocked(int i) { bool tacticUnlocked(int i) {
eLand l = land_tac[i].l; eLand l = land_tac[i].l;
if(autocheat) return true;
if(l == laWildWest) return true; if(l == laWildWest) return true;
return hiitemsMax(treasureType(l)) * landMultiplier(l) >= 20; return hiitemsMax(treasureType(l)) * landMultiplier(l) >= 20;
} }
@ -552,11 +590,20 @@ namespace tactic {
unrecord(lasttactic); unrecord(lasttactic);
} }
int tscorelast;
void uploadScoreCode(int code, int lb) { void uploadScoreCode(int code, int lb) {
int tscore = 0; int tscore = 0;
for(int i=0; i<landtypes; i++) for(int i=0; i<landtypes; i++)
tscore += recordsum[code][i] * tacmultiplier(eLand(i)); tscore += recordsum[code][i] * tacmultiplier(eLand(i));
// printf("PTM score = %d\n", tscore); // printf("PTM score = %d\n", tscore);
if(code == 0 && tscore > tscorelast) {
tscorelast = tscore;
if(tscore >= 1000) achievement_gain("PTM1", 'x');
if(tscore >= 5000) achievement_gain("PTM2", 'x');
if(tscore >= 15000) achievement_gain("PTM3", 'x');
}
achievement_score(lb, tscore); achievement_score(lb, tscore);
} }
@ -565,22 +612,41 @@ namespace tactic {
uploadScoreCode(2, LB_PURE_TACTICS_SHMUP); uploadScoreCode(2, LB_PURE_TACTICS_SHMUP);
uploadScoreCode(4, LB_PURE_TACTICS_COOP); uploadScoreCode(4, LB_PURE_TACTICS_COOP);
} }
int nl;
eLand getLandById(int i) {
return
sphere ? land_sph[i] :
euclid ? land_euc[i] :
land_tac[i].l;
}
void showMenu() { void showMenu() {
mouseovers = XLAT("pure tactics mode") + " - " + mouseovers; mouseovers = XLAT("pure tactics mode") + " - " + mouseovers;
int nl = LAND_TAC; nl = LAND_TAC;
int vf = min((vid.yres-64) / nl, vid.xres/40); if(euclid) nl = LAND_EUC;
if(sphere) nl = LAND_SPH;
int nlm;
int ofs = dialog::handlePage(nl, nlm, nl/2);
int vf = min((vid.yres-64-vid.fsize) / nlm, vid.xres/40);
int xr = vid.xres / 64; int xr = vid.xres / 64;
if(on) record(firstland, items[treasureType(firstland)]); if(on) record(firstland, items[treasureType(firstland)]);
int xc = modecode(); int xc = modecode();
getcstat = SDLK_ESCAPE;
for(int i=0; i<nl; i++) { for(int i=0; i<nl; i++) {
eLand l = land_tac[i].l; int i1 = i + ofs;
eLand l = getLandById(i1);
int i0 = 56 + i * vf; int i0 = 56 + i * vf;
int col; int col;
@ -588,36 +654,32 @@ namespace tactic {
if(!ch) continue; if(!ch) continue;
bool unlocked = tacticUnlocked(i); bool unlocked = tacticUnlocked(i1);
if(unlocked) col = linf[l].color; else col = 0x202020; if(unlocked) col = linf[l].color; else col = 0x202020;
if(displayfr(xr*1, i0, 1, vf-4, XLAT1(linf[l].name), col, 0) && unlocked) { if(displayfrZ(xr*1, i0, 1, vf-4, XLAT1(linf[l].name), col, 0) && unlocked) {
getcstat = 1000 + i; getcstat = 1000 + i1;
} }
if(unlocked) { if(unlocked || autocheat) {
for(int ii=0; ii<ch; ii++) for(int ii=0; ii<ch; ii++)
if(displayfr(xr*(24+2*ii), i0, 1, (vf-4)*4/5, lsc[xc][l][ii] >= 0 ? its(lsc[xc][l][ii]) : "-", col, 16)) if(displayfrZ(xr*(24+2*ii), i0, 1, (vf-4)*4/5, lsc[xc][l][ii] >= 0 ? its(lsc[xc][l][ii]) : "-", col, 16))
getcstat = 1000 + i; getcstat = 1000 + i1;
if(displayfr(xr*(24+2*10), i0, 1, (vf-4)*4/5, if(displayfrZ(xr*(24+2*10), i0, 1, (vf-4)*4/5,
its(recordsum[xc][l]) + " x" + its(tacmultiplier(l)), col, 0)) its(recordsum[xc][l]) + " x" + its(tacmultiplier(l)), col, 0))
getcstat = 1000 + i; getcstat = 1000 + i1;
} }
else { else {
int m = landMultiplier(l); int m = landMultiplier(l);
displayfr(xr*26, i0, 1, (vf-4)*4/5, displayfrZ(xr*26, i0, 1, (vf-4)*4/5,
XLAT("Collect %1x %2 to unlock", its((20+m-1)/m), treasureType(l)), XLAT("Collect %1x %2 to unlock", its((20+m-1)/m), treasureType(l)),
col, 0); col, 0);
} }
} }
if(on || ISIOS) { dialog::displayPageButtons(3, true);
int i0 = 56 + nl * vf;
if(displayfr(xr*24, i0, 1, vf-4, "press 0 to leave this mode", 0xFFD500, 8))
getcstat = '0';
}
uploadScore(); uploadScore();
if(on) unrecord(firstland); if(on) unrecord(firstland);
@ -635,9 +697,9 @@ namespace tactic {
} }
} }
void handleKey(int uni, int sym) { void handleKey(int sym, int uni) {
if(uni >= 1000 && uni < 1000 + LAND_TAC) { if(uni >= 1000 && uni < 1000 + LAND_TAC) {
firstland = land_tac[uni - 1000].l; firstland = euclidland = getLandById(uni - 1000);
restartGame(tactic::on ? 0 : 't'); restartGame(tactic::on ? 0 : 't');
cmode = emNormal; cmode = emNormal;
} }
@ -646,7 +708,7 @@ namespace tactic {
firstland = laIce; firstland = laIce;
if(tactic::on) restartGame('t'); if(tactic::on) restartGame('t');
} }
else if(uni == '2' || sym == SDLK_F1) { else if(sym == SDLK_F1) {
lastmode = cmode; lastmode = cmode;
cmode = emHelp; cmode = emHelp;
help = help =
@ -673,27 +735,124 @@ namespace tactic {
"Good luck, and have fun!"; "Good luck, and have fun!";
} }
else if(uni) cmode = emNormal; else if(dialog::handlePageButtons(uni)) ;
else if(uni || sym == SDLK_F10) cmode = emNormal;
} }
}; };
int modecodetable[42][6] = {
{ 0, 38, 39, 40, 41, 42}, // softcore hyperbolic
{ 7, 43, 44, 45, 46, 47}, // hardcore hyperbolic
{ 2, 4, 9, 11, 48, 49}, // shmup hyperbolic
{ 13, 50, 51, 52, 53, 54}, // softcore heptagonal hyperbolic
{ 16, 55, 56, 57, 58, 59}, // hardcore heptagonal hyperbolic
{ 14, 15, 17, 18, 60, 61}, // shmup heptagonal hyperbolic
{ 1, 62, 63, 64, 65, 66}, // softcore euclidean
{ 8, 67, 68, 69, 70, 71}, // hardcore euclidean
{ 3, 5, 10, 12, 72, 73}, // shmup euclidean
{110,111,112,113,114,115}, // softcore spherical
{116,117,118,119,120,121}, // hardcore spherical
{122,123,124,125,126,127}, // shmup spherical
{128,129,130,131,132,133}, // softcore heptagonal spherical
{134,135,136,137,138,139}, // hardcore heptagonal spherical
{140,141,142,143,144,145}, // shmup heptagonal spherical
{146,147,148,149,150,151}, // softcore elliptic
{152,153,154,155,156,157}, // hardcore elliptic
{158,159,160,161,162,163}, // shmup elliptic
{164,165,166,167,168,169}, // softcore heptagonal elliptic
{170,171,172,173,174,175}, // hardcore heptagonal elliptic
{176,177,178,179,180,181}, // shmup heptagonal elliptic
{ 19, 74, 75, 76, 77, 78}, // softcore hyperbolic chaosmode
{ 26, 79, 80, 81, 82, 83}, // hardcore hyperbolic chaosmode
{ 21, 23, 28, 30, 84, 85}, // shmup hyperbolic chaosmode
{ 32, 86, 87, 88, 89, 90}, // softcore heptagonal hyperbolic chaosmode
{ 35, 91, 92, 93, 94, 95}, // hardcore heptagonal hyperbolic chaosmode
{ 33, 34, 36, 37, 96, 97}, // shmup heptagonal hyperbolic chaosmode
{ 20, 98, 99,100,101,102}, // softcore euclidean chaosmode
{ 27,103,104,105,106,107}, // hardcore euclidean chaosmode
{ 22, 24, 29, 31,108,109}, // shmup euclidean chaosmode
{182,183,184,185,186,187}, // softcore spherical chaosmode
{188,189,190,191,192,193}, // hardcore spherical chaosmode
{194,195,196,197,198,199}, // shmup spherical chaosmode
{200,201,202,203,204,205}, // softcore heptagonal spherical chaosmode
{206,207,208,209,210,211}, // hardcore heptagonal spherical chaosmode
{212,213,214,215,216,217}, // shmup heptagonal spherical chaosmode
{218,219,220,221,222,223}, // softcore elliptic chaosmode
{224,225,226,227,228,229}, // hardcore elliptic chaosmode
{230,231,232,233,234,235}, // shmup elliptic chaosmode
{236,237,238,239,240,241}, // softcore heptagonal elliptic chaosmode
{242,243,244,245,246,247}, // hardcore heptagonal elliptic chaosmode
{248,249,250,251,252,253}, // shmup heptagonal elliptic chaosmode
};
// unused code: 25
int newmodecode = 254;
int modecode() { int modecode() {
int xcode = 0; #ifndef NOSAVE
if(euclid) xcode += 1;
if(shmup::on) {
if(numplayers() == 1) xcode += 2;
if(numplayers() == 2) xcode += 4;
if(numplayers() == 3) xcode += 9;
if(numplayers() == 4) xcode += 11;
}
if(pureHardcore() && !shmup::on) xcode += 7;
if(anticheat::tampered || cheater) return 6; if(anticheat::tampered || cheater) return 6;
if(purehepta) { if(quotient) return 6;
if(xcode > 6) xcode--; #endif
xcode /= 2; int xcode = 0;
xcode += 13;
if(shmup::on) xcode += 2;
else if(pureHardcore()) xcode ++;
if(euclid) xcode += 6;
else if(purehepta) xcode += 3;
if(sphere) {
xcode += 9;
if(elliptic) xcode += 6;
if(purehepta) xcode += 3;
} }
if(chaosmode && !yendor::on && cmode != emYendor) xcode += 19;
return xcode; if(chaosmode) xcode += 21;
int np = numplayers()-1; if(np<0 || np>5) np=5;
return modecodetable[xcode][np];
} }
void buildmodetable() {
bool codeused[600];
for(int q=0; q<600; q++) codeused[q] = 0;
codeused[6] = true; // cheater
printf("int modecodetable[42][6] = {\n");
for(int b=0; b<42; b++) {
extern bool hardcore;
hardcore = (b%3 == 1);
shmup::on = (b%3 == 2);
purehepta = (b/3)%7 == 1 || (b/3)%7 == 4 || (b/3)%7 == 6;
geometry = gNormal;
if((b/3)%7 == 2) geometry = gEuclid;
if((b/3)%7 >= 3) geometry = gSphere;
if((b/3)%7 >= 5) geometry = gElliptic;
chaosmode = b >= 21;
printf(" {");
for(int p=0; p<6; p++) {
multi::players = p+1;
if(p) printf(",");
int mc = modecode();
if(codeused[mc]) mc = newmodecode++;
codeused[mc] = true;
printf("%3d", mc);
}
printf("}, //");
if(hardcore) printf(" hardcore");
else if(shmup::on) printf(" shmup");
else printf(" softcore");
if(purehepta) printf(" heptagonal");
if(euclid) printf(" euclidean");
else if(elliptic) printf(" elliptic");
else if(sphere) printf(" spherical");
else printf(" hyperbolic");
if(chaosmode) printf(" chaosmode");
printf("\n");
}
printf(" }\n");
for(int i=0; i<newmodecode; i++) if(!codeused[i]) printf("// unused code: %d\n", i);
printf("int newmodecode = %d;\n", newmodecode);
}