mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2024-12-23 16:50:27 +00:00
Updated to 8.3j
This commit is contained in:
parent
da74e6e976
commit
3237ff455e
@ -1,5 +1,10 @@
|
||||
all: hyper.exe
|
||||
|
||||
# for simplicity we use NOPNG here
|
||||
# you can also include savepng.c and remove -DNOPNG
|
||||
|
||||
hyper.exe: hyper.cpp graph.cpp hyperpoint.cpp geometry.cpp cell.cpp heptagon.cpp game.cpp polygons.cpp classes.cpp hyper.res language-data.cpp
|
||||
g++ -mwindows hyper.cpp hyper.res -o hyper.exe -lSDL -lSDL_mixer -lopengl32 SDL_ttf.dll SDL_gfx.dll -O3
|
||||
g++ -mwindows hyper.cpp hyper.res -o hyper.exe -lSDL -lSDL_mixer -lopengl32 SDL_ttf.dll SDL_gfx.dll -O3 -DNOPNG
|
||||
|
||||
hyper.res: hyper.rc hr-icon.ico
|
||||
windres hyper.rc -O coff -o hyper.res
|
||||
|
220
achievement.cpp
220
achievement.cpp
@ -1,15 +1,22 @@
|
||||
#define NUMLEADER 40
|
||||
// Hyperbolic Rogue -- achievements
|
||||
// Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details
|
||||
|
||||
#define NUMLEADER 57
|
||||
|
||||
#define SCORE_UNKNOWN (-1)
|
||||
#define NO_SCORE_YET (-2)
|
||||
|
||||
bool offlineMode = false;
|
||||
|
||||
int syncstate = 0;
|
||||
|
||||
int currentscore[NUMLEADER];
|
||||
|
||||
const char* leadernames[NUMLEADER] = {
|
||||
"Score", "Diamonds", "Gold", "Spice", "Rubies", "Elixirs",
|
||||
"Shards", "Totems", "Daisies", "Statues", "Feathers", "Sapphires",
|
||||
"Hyperstones", "Time to Win-71", "Turns to Win-71",
|
||||
"Time to 10 Hyperstones-73", "Turns to 10 Hyperstones-73", "Orbs of Yendor",
|
||||
"Time to 10 Hyperstones-83", "Turns to 10 Hyperstones-83", "Orbs of Yendor",
|
||||
"Fern Flowers",
|
||||
"Royal Jellies", "Powerstones", "Silver", "Wine", "Emeralds", "Grimoires",
|
||||
"Holy Grails", "Red Gems", "Pirate Treasures",
|
||||
@ -22,7 +29,24 @@ const char* leadernames[NUMLEADER] = {
|
||||
"Princess Challenge", // 36
|
||||
"Ivory Figurines", // 37
|
||||
"Elemental Gems", // 38
|
||||
"Onyxes" // 39
|
||||
"Onyxes", // 39
|
||||
"Yendor Challenge", // 40
|
||||
"Pure Tactics Mode", // 41
|
||||
"Mutant Saplings", // 42
|
||||
"Fulgurites", // 43
|
||||
"Shmup Score 2p", // 44
|
||||
"Coop Shmup Time to Win", // 45
|
||||
"Black Lotuses", // 46
|
||||
"Mutant Fruits", // 47
|
||||
"White Dove Feathers", // 48
|
||||
"Pure Tactics Mode (shmup)", // 49
|
||||
"Pure Tactics Mode (2p)", // 50
|
||||
"Corals", // 51
|
||||
"Thornless Roses", // 52
|
||||
"Chaos Mode", // 53
|
||||
"Tortoise points", // 54
|
||||
"Dragon Scales", // 55
|
||||
"Apples", // 56
|
||||
};
|
||||
|
||||
bool haveLeaderboard(int id);
|
||||
@ -33,11 +57,25 @@ string achievementMessage[3];
|
||||
int achievementTimer;
|
||||
// vector<string> achievementsReceived;
|
||||
|
||||
void achievement_log(const char* s, bool euclideanAchievement, bool shmupAchievement) {
|
||||
if(cheater) return;
|
||||
if(euclid != euclideanAchievement) return;
|
||||
if(shmup::on != shmupAchievement) return;
|
||||
if(randomPatternsMode) return;
|
||||
bool wrongMode(char flags) {
|
||||
if(cheater) return true;
|
||||
if(purehepta != (flags == '7')) return true;
|
||||
if(euclid != (flags == 'e')) return true;
|
||||
if(shmup::on != (flags == 's')) return true;
|
||||
if(randomPatternsMode) return true;
|
||||
if(yendor::on) return true;
|
||||
if(tactic::on) return true;
|
||||
if(chaosmode != (flags == 'C')) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void achievement_log(const char* s, char flags) {
|
||||
|
||||
#ifdef LOCAL
|
||||
printf("achievement = %s [%d]\n", s, wrongMode(flags));
|
||||
#endif
|
||||
|
||||
if(wrongMode(flags)) return;
|
||||
|
||||
for(int i=0; i<size(achievementsReceived); i++)
|
||||
if(achievementsReceived[i] == s) return;
|
||||
@ -46,13 +84,13 @@ void achievement_log(const char* s, bool euclideanAchievement, bool shmupAchieve
|
||||
#ifndef ANDROID
|
||||
FILE *f = fopen(scorefile, "at");
|
||||
if(!f) return;
|
||||
int t = time(NULL) - timerstart;
|
||||
int t = (int) (time(NULL) - timerstart);
|
||||
|
||||
time_t timer = time(NULL);
|
||||
char buf[128]; strftime(buf, 128, "%c", localtime(&timer));
|
||||
|
||||
fprintf(f, "ACHIEVEMENT %s turns: %d time: %d at: %d c: %d date: %s\n",
|
||||
s, turncount, t, int(timerstart), achievement_certify(s, turncount, t, timerstart), buf);
|
||||
fprintf(f, "ACHIEVEMENT %s turns: %d time: %d at: %d ver: %s c: %d date: %s\n",
|
||||
s, turncount, t, int(timerstart), VER, anticheat::certify(s, turncount, t, (int) timerstart, 0), buf);
|
||||
|
||||
fclose(f);
|
||||
#endif
|
||||
@ -65,8 +103,8 @@ void improveItemScores();
|
||||
#ifndef ANDROID
|
||||
void achievement_init() {}
|
||||
void achievement_close() {}
|
||||
void achievement_gain(const char* s, bool euclideanAchievement, bool shmupAchievement) {
|
||||
achievement_log(s, euclideanAchievement, shmupAchievement);
|
||||
void achievement_gain(const char* s, char flags) {
|
||||
achievement_log(s, flags);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@ -99,7 +137,7 @@ void achievement_collection(eItem it, int prevgold, int newgold) {
|
||||
if(it == itRedGem) achievement_gain("REDGEM1");
|
||||
if(it == itPirate) achievement_gain("PIRATE1");
|
||||
if(it == itCoast) achievement_gain("COAST1");
|
||||
// if(it == itWhirlpool) achievement_gain("WHIRL1");
|
||||
// if(it == itWhirlpool) achievement_gain("WHIRL1"); // requires escape
|
||||
if(it == itBombEgg) achievement_gain("MINE1");
|
||||
if(it == itPalace) achievement_gain("RUG1");
|
||||
if(it == itFjord) achievement_gain("GARNET1");
|
||||
@ -107,11 +145,23 @@ void achievement_collection(eItem it, int prevgold, int newgold) {
|
||||
if(it == itEdge) achievement_gain("TOWER1");
|
||||
if(it == itElemental) achievement_gain("ELEMENT1");
|
||||
if(it == itZebra) achievement_gain("ZEBRA1");
|
||||
|
||||
if(it == itMutant) achievement_gain("MUTANT1");
|
||||
if(it == itFulgurite) achievement_gain("FULGUR1");
|
||||
|
||||
if(it == itMutant2) achievement_gain("FRUIT1");
|
||||
if(it == itWindstone) achievement_gain("DOVE1");
|
||||
if(it == itCoral) achievement_gain("CORAL1");
|
||||
if(it == itRose) achievement_gain("ROSE1");
|
||||
|
||||
if(it == itBabyTortoise) achievement_gain("TORTOISE1");
|
||||
if(it == itDragon) achievement_gain("DRAGON1");
|
||||
if(it == itApple) achievement_gain("APPLE1");
|
||||
}
|
||||
|
||||
// 32
|
||||
if(it == itHolyGrail) {
|
||||
if(q == 1) achievement_gain("GRAIL2");
|
||||
if(q == 1) achievement_gain("GRAIL2"), achievement_gain("GRAILH", '7');
|
||||
if(q == 3) achievement_gain("GRAIL3");
|
||||
if(q == 8) achievement_gain("GRAIL4");
|
||||
}
|
||||
@ -147,6 +197,18 @@ void achievement_collection(eItem it, int prevgold, int newgold) {
|
||||
if(it == itEdge) achievement_gain("TOWER2");
|
||||
if(it == itElemental) achievement_gain("ELEMENT2");
|
||||
if(it == itZebra) achievement_gain("ZEBRA2");
|
||||
|
||||
if(it == itMutant) achievement_gain("MUTANT2");
|
||||
if(it == itFulgurite) achievement_gain("FULGUR2");
|
||||
|
||||
if(it == itMutant2) achievement_gain("FRUIT2");
|
||||
if(it == itWindstone) achievement_gain("DOVE2");
|
||||
if(it == itCoral) achievement_gain("CORAL2");
|
||||
if(it == itRose) achievement_gain("ROSE2");
|
||||
|
||||
if(it == itBabyTortoise) achievement_gain("TORTOISE2");
|
||||
if(it == itDragon) achievement_gain("DRAGON2");
|
||||
if(it == itApple) achievement_gain("APPLE2");
|
||||
}
|
||||
|
||||
if(q == 25) {
|
||||
@ -180,6 +242,21 @@ void achievement_collection(eItem it, int prevgold, int newgold) {
|
||||
if(it == itEdge) achievement_gain("TOWER3");
|
||||
if(it == itElemental) achievement_gain("ELEMENT3");
|
||||
if(it == itZebra) achievement_gain("ZEBRA3");
|
||||
|
||||
if(it == itMutant) achievement_gain("MUTANT3");
|
||||
if(it == itFulgurite) achievement_gain("FULGUR3");
|
||||
|
||||
if(it == itMutant2) achievement_gain("FRUIT3");
|
||||
if(it == itWindstone) achievement_gain("DOVE3");
|
||||
if(it == itCoral) achievement_gain("CORAL3");
|
||||
if(it == itRose) achievement_gain("ROSE3");
|
||||
|
||||
if(it == itFulgurite && pureHardcore() && elec::lightningfast == 0)
|
||||
achievement_gain("HARDMETAL");
|
||||
|
||||
if(it == itBabyTortoise) achievement_gain("TORTOISE3");
|
||||
if(it == itDragon) achievement_gain("DRAGON3");
|
||||
if(it == itApple) achievement_gain("APPLE3");
|
||||
}
|
||||
|
||||
if(q == 50) {
|
||||
@ -213,12 +290,24 @@ void achievement_collection(eItem it, int prevgold, int newgold) {
|
||||
if(it == itEdge) achievement_gain("TOWER4");
|
||||
if(it == itElemental) achievement_gain("ELEMENT4");
|
||||
if(it == itZebra) achievement_gain("ZEBRA4");
|
||||
|
||||
if(it == itMutant) achievement_gain("MUTANT4");
|
||||
if(it == itFulgurite) achievement_gain("FULGUR4");
|
||||
|
||||
if(it == itMutant2) achievement_gain("FRUIT4");
|
||||
if(it == itWindstone) achievement_gain("DOVE4");
|
||||
if(it == itCoral) achievement_gain("CORAL4");
|
||||
if(it == itRose) achievement_gain("ROSE4");
|
||||
|
||||
if(it == itBabyTortoise) achievement_gain("TORTOISE4");
|
||||
if(it == itDragon) achievement_gain("DRAGON4");
|
||||
if(it == itApple) achievement_gain("APPLE4");
|
||||
}
|
||||
|
||||
if(it == itOrbYendor) {
|
||||
achievement_gain("YENDOR2");
|
||||
if(pureHardcore()) achievement_gain("HARDCORE");
|
||||
if(shmup::on) achievement_gain("SHMUP", false, true);
|
||||
if(shmup::on) achievement_gain("SHMUP", 's');
|
||||
}
|
||||
}
|
||||
|
||||
@ -255,35 +344,42 @@ void achievement_count(const string& s, int current, int prev) {
|
||||
if(s == "LIGHTNING" && current-prev >= 10)
|
||||
achievement_gain("LIGHTNING3");
|
||||
if(s == "MIRAGE" && current >= 35)
|
||||
achievement_gain("MIRAGE", true);
|
||||
achievement_gain("MIRAGE", 'e');
|
||||
if(s == "ORB" && current >= 10)
|
||||
achievement_gain("ORB3");
|
||||
if(s == "BUG" && current >= 1000)
|
||||
achievement_gain("BUG3");
|
||||
if(s == "ELEC" && current >= 10)
|
||||
achievement_gain("ELEC3");
|
||||
}
|
||||
|
||||
int specific_improved = 0;
|
||||
int specific_what = 0;
|
||||
|
||||
void improve_score(int i, eItem what) {
|
||||
if(offlineMode) return;
|
||||
#ifdef HAVE_ACHIEVEMENTS
|
||||
if(haveLeaderboard(i)) updateHi(what, currentscore[i]);
|
||||
if(items[what] && haveLeaderboard(i)) {
|
||||
if(items[what] > currentscore[i] && currentscore[i] != SCORE_UNKNOWN) {
|
||||
specific_improved++; specific_what = what;
|
||||
currentscore[i] = items[what];
|
||||
}
|
||||
|
||||
upload_score(i, items[what]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void achievement_score(int cat, int number) {
|
||||
if(offlineMode) return;
|
||||
#ifdef HAVE_ACHIEVEMENTS
|
||||
if(cheater) return;
|
||||
if(euclid) return;
|
||||
if(purehepta) return;
|
||||
if(randomPatternsMode) return;
|
||||
if(shmup::on && cat != LB_PURE_TACTICS_SHMUP && cat != LB_PURE_TACTICS_COOP) return;
|
||||
if(yendor::on && cat != LB_YENDOR_CHALLENGE) return;
|
||||
if(tactic::on && cat != LB_PURE_TACTICS && cat != LB_PURE_TACTICS_SHMUP && cat != LB_PURE_TACTICS_COOP)
|
||||
return;
|
||||
upload_score(cat, number);
|
||||
#endif
|
||||
}
|
||||
@ -310,57 +406,98 @@ void improveItemScores() {
|
||||
improve_score(37, itEdge);
|
||||
improve_score(38, itElemental);
|
||||
improve_score(39, itZebra);
|
||||
|
||||
improve_score(42, itMutant);
|
||||
improve_score(43, itFulgurite);
|
||||
|
||||
if(!isHaunted(cwt.c->land)) improve_score(46, itLotus);
|
||||
improve_score(47, itMutant2);
|
||||
improve_score(48, itWindstone);
|
||||
|
||||
improve_score(51, itCoral);
|
||||
improve_score(52, itRose);
|
||||
|
||||
improve_score(54, itBabyTortoise);
|
||||
improve_score(55, itDragon);
|
||||
improve_score(56, itApple);
|
||||
}
|
||||
|
||||
void achievement_final(bool really_final) {
|
||||
if(offlineMode) return;
|
||||
#ifdef HAVE_ACHIEVEMENTS
|
||||
if(cheater) return;
|
||||
if(euclid) return;
|
||||
if(purehepta) return;
|
||||
if(randomPatternsMode) return;
|
||||
|
||||
if(tactic::on) {
|
||||
tactic::record();
|
||||
tactic::unrecord();
|
||||
tactic::uploadScore();
|
||||
return;
|
||||
}
|
||||
|
||||
if(yendor::on) return;
|
||||
|
||||
if(shmup::on && chaosmode) return;
|
||||
|
||||
int total_improved = 0;
|
||||
specific_improved = 0;
|
||||
specific_what = 0;
|
||||
|
||||
if(!shmup::on) improveItemScores();
|
||||
if(!shmup::on && !chaosmode) improveItemScores();
|
||||
|
||||
int sid = shmup::on ? 28 : 0;
|
||||
int sid = chaosmode ? 53 : shmup::on ? (numplayers() > 1 ? 44 : 28) : 0;
|
||||
|
||||
int tg = gold();
|
||||
if(tg && haveLeaderboard(sid)) {
|
||||
if(tg > currentscore[sid] && currentscore[sid] != SCORE_UNKNOWN) {
|
||||
if(currentscore[sid] < 0) total_improved += 2;
|
||||
total_improved++; currentscore[sid] = tg;
|
||||
total_improved++; // currentscore[sid] = tg;
|
||||
}
|
||||
upload_score(sid, tg);
|
||||
}
|
||||
|
||||
if(total_improved >= 2) {
|
||||
addMessage(XLAT("Your total treasure has been recorded in the "LEADERFULL"."));
|
||||
#ifndef ANDROID
|
||||
addMessage(XLAT("Your total treasure has been recorded in the " LEADERFULL "."));
|
||||
addMessage(XLAT("Congratulations!"));
|
||||
#endif
|
||||
}
|
||||
else if(total_improved && specific_improved >= 2)
|
||||
addMessage(XLAT("You have improved your total high score and %1 specific high scores!", its(specific_improved)));
|
||||
else if(total_improved && specific_improved)
|
||||
addMessage(XLAT("You have improved your total and '%1' high score!", iinf[specific_what].name));
|
||||
else if(total_improved)
|
||||
addMessage(XLAT("You have improved your total high score on "LEADER". Congratulations!"));
|
||||
else if(total_improved) {
|
||||
#ifndef ANDROID
|
||||
addMessage(XLAT("You have improved your total high score on " LEADER ". Congratulations!"));
|
||||
#endif
|
||||
}
|
||||
else if(specific_improved >= 2)
|
||||
addMessage(XLAT("You have improved %1 of your specific high scores!", its(specific_improved)));
|
||||
else if(specific_improved)
|
||||
addMessage(XLAT("You have improved your '%1' high score on "LEADER"!", iinf[specific_what].name));
|
||||
else if(specific_improved) {
|
||||
#ifndef ANDROID
|
||||
addMessage(XLAT("You have improved your '%1' high score on " LEADER "!", iinf[specific_what].name));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void achievement_victory(bool hyper) {
|
||||
if(offlineMode) return;
|
||||
#ifdef HAVE_ACHIEVEMENTS
|
||||
if(cheater) return;
|
||||
if(euclid) return;
|
||||
if(purehepta) return;
|
||||
if(randomPatternsMode) return;
|
||||
if(hyper && shmup::on) return;
|
||||
if(yendor::on) return;
|
||||
if(tactic::on) return;
|
||||
if(chaosmode) return;
|
||||
|
||||
int t = savetime + time(NULL) - timerstart;
|
||||
|
||||
int ih1 = hyper ? 15 : shmup::on ? 29 : 13;
|
||||
int ih1 = hyper ? 15 : shmup::on ? (numplayers() > 1 ? 45 : 29) : 13;
|
||||
int ih2 = hyper ? 16 : shmup::on ? 30 : 14;
|
||||
|
||||
int improved = 0;
|
||||
@ -368,11 +505,11 @@ void achievement_victory(bool hyper) {
|
||||
improved += 4;
|
||||
|
||||
if(currentscore[ih1] < 0 || currentscore[ih1] > t) {
|
||||
improved++; currentscore[ih1] = t;
|
||||
improved++; // currentscore[ih1] = t;
|
||||
}
|
||||
|
||||
if(currentscore[ih2] < 0 || currentscore[ih2] > turncount) {
|
||||
improved+=2; currentscore[ih2] = turncount;
|
||||
improved+=2; // currentscore[ih2] = turncount;
|
||||
}
|
||||
|
||||
if(hyper)
|
||||
@ -381,7 +518,9 @@ void achievement_victory(bool hyper) {
|
||||
if(improved) {
|
||||
if(improved >= 4) {
|
||||
if(!hyper) addMessage(XLAT("This is your first victory!"));
|
||||
#ifndef ANDROID
|
||||
addMessage(XLAT("This has been recorded in the " LEADERFULL "."));
|
||||
#endif
|
||||
addMessage(XLAT("The faster you get here, the better you are!"));
|
||||
}
|
||||
else if(improved >= 3) {
|
||||
@ -407,18 +546,29 @@ void achievement_victory(bool hyper) {
|
||||
|
||||
void achievement_pump();
|
||||
|
||||
#ifndef HAVE_ACHIEVEMENTS
|
||||
void achievement_pump() {}
|
||||
#endif
|
||||
|
||||
void achievement_display() {
|
||||
#ifdef HAVE_ACHIEVEMENTS
|
||||
achievement_pump();
|
||||
#ifdef HAVE_ACHIEVEMENTS
|
||||
if(achievementTimer) {
|
||||
int col = (ticks - achievementTimer);
|
||||
if(col > 5000) { achievementTimer = 0; return; }
|
||||
if(col > 2500) col = 5000 - col;
|
||||
col /= 10; col *= 0x10101;
|
||||
displayfr(vid.xres/2, vid.yres/4, 2, vid.fsize * 2, achievementMessage[0], col & 0xFFFF00, 8);
|
||||
displayfr(vid.xres/2, vid.yres/4 + vid.fsize*2, 2, vid.fsize * 2, achievementMessage[1], col, 8);
|
||||
displayfr(vid.xres/2, vid.yres/4 + vid.fsize*4, 2, vid.fsize, achievementMessage[2], col, 8);
|
||||
}
|
||||
int w = 2 * vid.fsize;
|
||||
#ifndef MOBILE
|
||||
while(w>3 && textwidth(w, achievementMessage[1]) > vid.xres) w--;
|
||||
#endif
|
||||
displayfr(vid.xres/2, vid.yres/4 + vid.fsize*2, 2, w, achievementMessage[1], col, 8);
|
||||
w = vid.fsize;
|
||||
#ifndef MOBILE
|
||||
while(w>3 && textwidth(w, achievementMessage[2]) > vid.xres) w--;
|
||||
#endif
|
||||
displayfr(vid.xres/2, vid.yres/4 + vid.fsize*4, 2, w, achievementMessage[2], col, 8);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1,30 +0,0 @@
|
||||
// initialize the achievement system.
|
||||
void achievement_init();
|
||||
|
||||
// close the achievement system.
|
||||
void achievement_close();
|
||||
|
||||
// gain the achievement with the given name.
|
||||
// Only awarded if euclid equals euclideanAchievement.
|
||||
void achievement_gain(const char*, bool euclideanAchievement = false);
|
||||
|
||||
// gain the achievement for collecting a number of 'it'.
|
||||
void achievement_collection(eItem it, int prevgold, int newgold);
|
||||
|
||||
// this is used for 'counting' achievements, such as kill 10
|
||||
// monsters at the same time.
|
||||
void achievement_count(const string& s, int current, int prev);
|
||||
|
||||
// gain the victory achievements. Set 'hyper' to true for
|
||||
// the Hyperstone victory, and false for the Orb of Yendor victory.
|
||||
void achievement_victory(bool hyper);
|
||||
|
||||
// gain the final achievements. Called with really=false whenever the user
|
||||
// looks at their score, and really=true when the game really ends.
|
||||
void achievement_final(bool really);
|
||||
|
||||
// display the last achievement gained.
|
||||
void achievement_display();
|
||||
|
||||
// achievements received this game
|
||||
vector<string> achievementsReceived;
|
372
cell.cpp
372
cell.cpp
@ -1,11 +1,18 @@
|
||||
// Hyperbolic Rogue
|
||||
// Copyright (C) 2011-2012 Zeno Rogue, see 'hyper.cpp' for details
|
||||
// Hyperbolic Rogue -- cells
|
||||
// Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details
|
||||
|
||||
// cells the game is played on
|
||||
|
||||
int fix6(int a) { return (a+96)% 6; }
|
||||
int fix7(int a) { return (a+84)% 7; }
|
||||
|
||||
int dirdiff(int dd, int t) {
|
||||
dd %= t;
|
||||
if(dd<0) dd += t;
|
||||
if(t-dd < dd) dd = t-dd;
|
||||
return dd;
|
||||
}
|
||||
|
||||
struct cell : gcell {
|
||||
char type; // 6 for hexagons, 7 for heptagons
|
||||
unsigned char spn[7];
|
||||
@ -38,6 +45,8 @@ void merge(cell *c, int d, cell *c2, int d2) {
|
||||
|
||||
typedef unsigned short eucoord;
|
||||
|
||||
#include <map>
|
||||
|
||||
cell*& euclideanAtCreate(eucoord x, eucoord y);
|
||||
|
||||
union heptacoder {
|
||||
@ -69,6 +78,13 @@ cell *createMov(cell *c, int d) {
|
||||
}
|
||||
|
||||
if(c->mov[d]) return c->mov[d];
|
||||
else if(purehepta) {
|
||||
heptagon *h2 = createStep(c->master, d);
|
||||
c->mov[d] = h2->c7;
|
||||
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) {
|
||||
cell *n = newCell(6, c->master);
|
||||
|
||||
@ -203,11 +219,17 @@ cell*& euclideanAtCreate(eucoord x, eucoord y) {
|
||||
|
||||
// initializer (also inits origin from heptagon.cpp)
|
||||
void initcells() {
|
||||
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;
|
||||
@ -265,7 +287,7 @@ void clearfrom(heptagon *at) {
|
||||
}
|
||||
DEBMEM ( printf("at %p\n", at); )
|
||||
if(at->c7) {
|
||||
for(int i=0; i<7; i++)
|
||||
if(!purehepta) for(int i=0; i<7; i++)
|
||||
clearcell(at->c7->mov[i]);
|
||||
clearcell(at->c7);
|
||||
}
|
||||
@ -280,7 +302,7 @@ void verifycell(cell *c) {
|
||||
for(int i=0; i<t; i++) {
|
||||
cell *c2 = c->mov[i];
|
||||
if(c2) {
|
||||
if(t == 7) verifycell(c2);
|
||||
if(t == 7 && !purehepta) verifycell(c2);
|
||||
if(c2->mov[c->spn[i]] && c2->mov[c->spn[i]] != c)
|
||||
printf("cell error %p %p\n", c, c2);
|
||||
}
|
||||
@ -318,31 +340,6 @@ bool ishex1(cell *c) {
|
||||
else return c->type == 7;
|
||||
}
|
||||
|
||||
void clearMemory() {
|
||||
extern void clearGameMemory();
|
||||
clearGameMemory();
|
||||
if(shmup::on) shmup::clearMemory();
|
||||
cleargraphmemory();
|
||||
#ifndef MOBILE
|
||||
mapeditor::clearModelCells();
|
||||
#endif
|
||||
// EUCLIDEAN
|
||||
if(euclid) {
|
||||
for(int y=0; y<256; y++) for(int x=0; x<256; x++)
|
||||
if(euclidean[y][x]) {
|
||||
delete euclidean[y][x];
|
||||
euclidean[y][x] = NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DEBMEM ( verifycells(&origin); )
|
||||
clearfrom(&origin);
|
||||
for(int i=0; i<size(allAlts); i++) clearfrom(allAlts[i]);
|
||||
allAlts.clear();
|
||||
}
|
||||
DEBMEM ( printf("ok\n"); )
|
||||
}
|
||||
|
||||
int emeraldval(cell *c) {
|
||||
if(euclid) return 0;
|
||||
if(c->type == 7)
|
||||
@ -441,6 +438,7 @@ int cdist50(cell *c) {
|
||||
decodeMaster(c->master, x, y);
|
||||
int ix = short(x) + 99999 + short(y);
|
||||
int iy = short(y) + 99999;
|
||||
if(c->land == laPalace) {
|
||||
char palacemap[3][10] = {
|
||||
"012333321",
|
||||
"112322232",
|
||||
@ -450,6 +448,12 @@ int cdist50(cell *c) {
|
||||
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));
|
||||
int a0 = cdist50(createMov(c,0));
|
||||
int a1 = cdist50(createMov(c,2));
|
||||
@ -566,11 +570,33 @@ int zebra3(cell *c) {
|
||||
}
|
||||
}
|
||||
|
||||
#define RPV_MODULO 5
|
||||
|
||||
#define RPV_RAND 0
|
||||
#define RPV_ZEBRA 1
|
||||
#define RPV_EMERALD 2
|
||||
#define RPV_PALACE 3
|
||||
#define RPV_CYCLE 4
|
||||
|
||||
int getCdata(cell *c, int j);
|
||||
|
||||
// x mod 5 = pattern type
|
||||
// x mod (powers of 2) = pattern type specific
|
||||
// (x/5) mod 15 = picture for drawing floors
|
||||
// x mod 7 = chance of pattern-specific pic
|
||||
// whole = randomization
|
||||
|
||||
bool randpattern(cell *c, int rval) {
|
||||
int i, sw=0;
|
||||
switch(rval & 3) {
|
||||
switch(rval%5) {
|
||||
case 0:
|
||||
return rand() < rval;
|
||||
if(rval&1) {
|
||||
return hrandpos() < rval;
|
||||
}
|
||||
else {
|
||||
int cd = getCdata(c, 0);
|
||||
return !((cd/(((rval/2)&15)+1))&1);
|
||||
}
|
||||
case 1:
|
||||
i = zebra40(c);
|
||||
if(i&1) { if(rval&4) sw^=1; i &= ~1; }
|
||||
@ -583,26 +609,58 @@ bool randpattern(cell *c, int rval) {
|
||||
i = emeraldval(c);
|
||||
if(i&1) { if(rval&4) sw^=1; i &= ~1; }
|
||||
if(i&2) { if(rval&8) sw^=1; i &= ~2; }
|
||||
i >>= 2; i--;
|
||||
if(rval & (16<<i)) sw^=1;
|
||||
return sw;
|
||||
case 3:
|
||||
if(polara50(c)) { if(rval&4) sw^=1; }
|
||||
if(polarb50(c)) { if(rval&8) sw^=1; }
|
||||
int i = fiftyval049(c); i += 6; i /= 7;
|
||||
i = fiftyval049(c); i += 6; i /= 7;
|
||||
if(rval & (16<<i)) sw^=1;
|
||||
return sw;
|
||||
case 4:
|
||||
i = (rval&3);
|
||||
if(i == 1 && (celldist(c)&1)) sw ^= 1;
|
||||
if(i == 2 && (celldist(c)&2)) sw ^= 1;
|
||||
if(i == 3 && ((celldist(c)/3)&1)) sw ^= 1;
|
||||
if(rval & (4<<towerval(c, celldist))) sw ^= 1;
|
||||
return sw;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern int randompattern[landtypes];
|
||||
|
||||
string describeRPM(eLand l) {
|
||||
int rval = randompattern[l];
|
||||
switch(rval%5) {
|
||||
case 0:
|
||||
if(rval&1)
|
||||
return "R:"+its(rval/(HRANDMAX/100))+"%";
|
||||
else
|
||||
return "Landscape/"+its(((rval/2)&15)+1);
|
||||
case 1:
|
||||
return "Z/"+its((rval>>2)&3)+"/"+its((rval>>4)&15);
|
||||
case 2:
|
||||
return "E/"+its((rval>>2)&3)+"/"+its((rval>>4)&2047);
|
||||
case 3:
|
||||
return "P/"+its((rval>>2)&3)+"/"+its((rval>>4)&255);
|
||||
case 4:
|
||||
return "C/"+its(rval&3)+"/"+its((rval>>2)&65535);
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
int randpatternCode(cell *c, int rval) {
|
||||
switch(rval & 3) {
|
||||
switch(rval % RPV_MODULO) {
|
||||
case 1:
|
||||
return zebra40(c);
|
||||
case 2:
|
||||
return emeraldval(c);
|
||||
case 3:
|
||||
return fiftyval049(c) + (polara50(c)?50:0) + (polarb50(c)?1000:0);
|
||||
case 4:
|
||||
return towerval(c, celldist) * 6 + celldist(c) % 6;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -616,14 +674,12 @@ void clearMemoRPM() {
|
||||
rpm_memoize[a][b][i] = 2;
|
||||
}
|
||||
|
||||
extern int randompattern[landtypes];
|
||||
|
||||
bool randpatternMajority(cell *c, int ival, int iterations) {
|
||||
int rval = 0;
|
||||
if(ival == 0) rval = randompattern[laCaves];
|
||||
if(ival == 1) rval = randompattern[laLivefjord];
|
||||
if(ival == 2) rval = randompattern[laEmerald];
|
||||
if((rval&3) == 0) return randpattern(c, rval);
|
||||
if(rval%RPV_MODULO == RPV_RAND) return randpattern(c, rval);
|
||||
int code = randpatternCode(c, rval);
|
||||
char& memo(rpm_memoize[ival][code][iterations]);
|
||||
if(memo < 2) return memo;
|
||||
@ -639,3 +695,247 @@ bool randpatternMajority(cell *c, int ival, int iterations) {
|
||||
// printf("%p] rval = %X code = %d iterations = %d result = %d\n", c, rval, code, iterations, memo);
|
||||
return memo;
|
||||
}
|
||||
|
||||
#ifdef CDATA
|
||||
|
||||
#include <map>
|
||||
map<heptagon*, int> spins;
|
||||
|
||||
#define RVAL_MASK 0x10000000
|
||||
#define DATA_MASK 0x20000000
|
||||
|
||||
struct cdata {
|
||||
int val[4];
|
||||
int bits;
|
||||
};
|
||||
|
||||
map<heptagon*, struct cdata> eucdata;
|
||||
cdata orig_cdata;
|
||||
|
||||
void affect(cdata& d, short rv, signed char signum) {
|
||||
if(rv&1) d.val[0]+=signum; else d.val[0]-=signum;
|
||||
if(rv&2) d.val[1]+=signum; else d.val[1]-=signum;
|
||||
if(rv&4) d.val[2]+=signum; else d.val[2]-=signum;
|
||||
if(rv&8) d.val[3]+=signum; else d.val[3]-=signum;
|
||||
int id = (rv>>4) & 63;
|
||||
if(id < 32)
|
||||
d.bits ^= (1 << id);
|
||||
}
|
||||
|
||||
void setHeptagonRval(heptagon *h) {
|
||||
if(!(h->rval0 || h->rval1)) {
|
||||
h->rval0 = hrand(0x10000);
|
||||
h->rval1 = hrand(0x10000);
|
||||
}
|
||||
}
|
||||
|
||||
cdata *getHeptagonCdata(heptagon *h) {
|
||||
if(h->cdata) return h->cdata;
|
||||
|
||||
if(h == &origin) {
|
||||
return h->cdata = new cdata(orig_cdata);
|
||||
}
|
||||
|
||||
cdata mydata = *getHeptagonCdata(h->move[0]);
|
||||
|
||||
for(int di=3; di<5; di++) {
|
||||
heptspin hs; hs.h = h; hs.spin = di;
|
||||
int signum = +1;
|
||||
while(true) {
|
||||
heptspin hstab[15];
|
||||
hstab[7] = hs;
|
||||
|
||||
for(int i=8; i<12; i++) {
|
||||
hstab[i] = hsspin(hstab[i-1], (i&1) ? 4 : 3);
|
||||
hstab[i] = hsstep(hstab[i], 0);
|
||||
hstab[i] = hsspin(hstab[i], (i&1) ? 3 : 4);
|
||||
}
|
||||
|
||||
for(int i=6; i>=3; i--) {
|
||||
hstab[i] = hsspin(hstab[i+1], (i&1) ? 3 : 4);
|
||||
hstab[i] = hsstep(hstab[i], 0);
|
||||
hstab[i] = hsspin(hstab[i], (i&1) ? 4 : 3);
|
||||
}
|
||||
|
||||
if(hstab[3].h->distance < hstab[7].h->distance) {
|
||||
hs = hstab[3]; continue;
|
||||
}
|
||||
|
||||
if(hstab[11].h->distance < hstab[7].h->distance) {
|
||||
hs = hstab[11]; continue;
|
||||
}
|
||||
|
||||
int jj = 7;
|
||||
for(int k=3; k<12; k++) if(hstab[k].h->distance < hstab[jj].h->distance) jj = k;
|
||||
|
||||
int ties = 0, tiespos = 0;
|
||||
for(int k=3; k<12; k++) if(hstab[k].h->distance == hstab[jj].h->distance)
|
||||
ties++, tiespos += (k-jj);
|
||||
|
||||
// printf("ties=%d tiespos=%d jj=%d\n", ties, tiespos, jj);
|
||||
if(ties == 2) jj += tiespos/2;
|
||||
|
||||
if(jj&1) signum = -1;
|
||||
hs = hstab[jj];
|
||||
|
||||
break;
|
||||
}
|
||||
hs = hsstep(hsspin(hs, 3), 0);
|
||||
setHeptagonRval(hs.h);
|
||||
|
||||
affect(mydata, hs.spin ? hs.h->rval0 : hs.h->rval1, signum);
|
||||
|
||||
/* if(!(spins[hs.h] & hs.spin)) {
|
||||
spins[hs.h] |= (1<<hs.spin);
|
||||
int t = 0;
|
||||
for(int k=0; k<7; k++) if(spins[hs.h] & (1<<k)) t++;
|
||||
static bool wast[256];
|
||||
if(!wast[spins[hs.h]]) {
|
||||
printf("%p %4x\n", hs.h, spins[hs.h]);
|
||||
wast[spins[hs.h]] = true;
|
||||
}
|
||||
} */
|
||||
}
|
||||
|
||||
return h->cdata = new cdata(mydata);
|
||||
}
|
||||
|
||||
cdata *getEuclidCdata(heptagon *h) {
|
||||
eucoord x, y;
|
||||
if(eucdata.count(h)) return &(eucdata[h]);
|
||||
decodeMaster(h, x, y);
|
||||
|
||||
if(x == 0 && y == 0) {
|
||||
cdata xx;
|
||||
for(int i=0; i<4; i++) xx.val[i] = 0;
|
||||
xx.bits = 0;
|
||||
return &(eucdata[h] = xx);
|
||||
}
|
||||
int ord = 1, bid = 0;
|
||||
while(!((x|y)&ord)) ord <<= 1, bid++;
|
||||
|
||||
for(int k=0; k<3; k++) {
|
||||
eucoord x1 = x + (k<2 ? ord : 0);
|
||||
eucoord y1 = y - (k>0 ? ord : 0);
|
||||
if((x1&ord) || (y1&ord)) continue;
|
||||
eucoord x2 = x - (k<2 ? ord : 0);
|
||||
eucoord y2 = y + (k>0 ? ord : 0);
|
||||
|
||||
cdata *d1 = getEuclidCdata(encodeMaster(x1,y1));
|
||||
cdata *d2 = getEuclidCdata(encodeMaster(x2,y2));
|
||||
cdata xx;
|
||||
double disp = pow(2, bid/2.) * 6;
|
||||
|
||||
for(int i=0; i<4; i++) {
|
||||
double dv = (d1->val[i] + d2->val[i])/2 + (hrand(1000) - hrand(1000))/1000. * disp;
|
||||
xx.val[i] = floor(dv);
|
||||
if(hrand(1000) / 1000. < dv - floor(dv)) xx.val[i]++;
|
||||
}
|
||||
xx.bits = 0;
|
||||
|
||||
for(int b=0; b<32; b++) {
|
||||
bool gbit = ((hrand(2)?d1:d2)->bits >> b) & 1;
|
||||
int flipchance = (1<<bid);
|
||||
if(flipchance > 512) flipchance = 512;
|
||||
if(hrand(1024) < flipchance) gbit = !gbit;
|
||||
if(gbit) xx.bits |= (1<<b);
|
||||
}
|
||||
|
||||
return &(eucdata[h] = xx);
|
||||
}
|
||||
|
||||
// impossible!
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int getCdata(cell *c, int j) {
|
||||
if(euclid) return getEuclidCdata(c->master)->val[j];
|
||||
else if(c->type == 7) return getHeptagonCdata(c->master)->val[j]*3;
|
||||
else {
|
||||
int jj = 0;
|
||||
for(int k=0; k<6; k++) if(c->mov[k] && c->mov[k]->type == 7)
|
||||
jj += getHeptagonCdata(c->mov[k]->master)->val[j];
|
||||
return jj;
|
||||
}
|
||||
}
|
||||
|
||||
int getBits(cell *c) {
|
||||
if(euclid) return getEuclidCdata(c->master)->bits;
|
||||
else if(c->type == 7) return getHeptagonCdata(c->master)->bits;
|
||||
else {
|
||||
int b0 = getHeptagonCdata(createMov(c, 0)->master)->bits;
|
||||
int b1 = getHeptagonCdata(createMov(c, 2)->master)->bits;
|
||||
int b2 = getHeptagonCdata(createMov(c, 4)->master)->bits;
|
||||
return (b0 & b1) | (b1 & b2) | (b2 & b0);
|
||||
}
|
||||
}
|
||||
|
||||
eLand getCLand(cell *c) {
|
||||
int b = getBits(c);
|
||||
b = (b&31) ^ (b>>5);
|
||||
return land_scape[b & 31];
|
||||
}
|
||||
|
||||
int celldistance(cell *c1, cell *c2) {
|
||||
int d = 0;
|
||||
cell *cl1=c1, *cr1=c1, *cl2=c2, *cr2=c2;
|
||||
while(true) {
|
||||
if(cl1 == cl2) return d;
|
||||
if(cl1 == cr2) return d;
|
||||
if(cr1 == cl2) return d;
|
||||
if(cr1 == cr2) return d;
|
||||
|
||||
if(isNeighbor(cl1, cl2)) return d+1;
|
||||
if(isNeighbor(cl1, cr2)) return d+1;
|
||||
if(isNeighbor(cr1, cl2)) return d+1;
|
||||
if(isNeighbor(cr1, cr2)) return d+1;
|
||||
|
||||
forCellEx(c, cl2) if(isNeighbor(c, cr1)) return d+2;
|
||||
forCellEx(c, cl1) if(isNeighbor(c, cr2)) return d+2;
|
||||
|
||||
int d1 = celldist(cl1), d2 = celldist(cl2);
|
||||
|
||||
if(d1 >= d2) {
|
||||
cl1 = chosenDown(cl1, -1, 0, celldist);
|
||||
// cl1->item = eItem(rand() % 10);
|
||||
cr1 = chosenDown(cr1, 1, 0, celldist);
|
||||
// cr1->item = eItem(rand() % 10);
|
||||
d++;
|
||||
}
|
||||
if(d1 <= d2) {
|
||||
cl2 = chosenDown(cl2, -1, 0, celldist);
|
||||
// cl2->item = eItem(rand() % 10);
|
||||
cr2 = chosenDown(cr2, 1, 0, celldist);
|
||||
// cr2->item = eItem(rand() % 10);
|
||||
d++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void clearMemory() {
|
||||
extern void clearGameMemory();
|
||||
clearGameMemory();
|
||||
if(shmup::on) shmup::clearMemory();
|
||||
cleargraphmemory();
|
||||
#ifndef MOBILE
|
||||
mapeditor::clearModelCells();
|
||||
#endif
|
||||
// EUCLIDEAN
|
||||
if(euclid) {
|
||||
for(int y=0; y<256; y++) for(int x=0; x<256; x++)
|
||||
if(euclidean[y][x]) {
|
||||
delete euclidean[y][x];
|
||||
euclidean[y][x] = NULL;
|
||||
}
|
||||
eucdata.clear();
|
||||
}
|
||||
else {
|
||||
DEBMEM ( verifycells(&origin); )
|
||||
clearfrom(&origin);
|
||||
for(int i=0; i<size(allAlts); i++) clearfrom(allAlts[i]);
|
||||
allAlts.clear();
|
||||
}
|
||||
DEBMEM ( printf("ok\n"); )
|
||||
}
|
||||
|
||||
#endif
|
||||
|
504
classes.cpp
504
classes.cpp
@ -1,3 +1,10 @@
|
||||
// Hyperbolic Rogue -- items, monsters, walls, lands, descriptions, etc.
|
||||
// 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 ---
|
||||
|
||||
@ -53,11 +60,15 @@ const char *trollhelp =
|
||||
const char *trollhelp2 =
|
||||
" Additionally, all items around the killed Troll will be destroyed.";
|
||||
|
||||
const char *trollhelpX =
|
||||
"There are several species of trolls living in the hyperbolic world. "
|
||||
"Some of them leave this wall behind them when they die.";
|
||||
|
||||
const char *camelothelp =
|
||||
"The Knights of the Round Table are the greatest warriors of these lands. "
|
||||
"They are not very inventive with names though, as they call each of their "
|
||||
"castles Camelot. "
|
||||
"You are probably worth of joining them, but they will surely give you "
|
||||
"You are probably worthy of joining them, but they will surely give you "
|
||||
"some quest to prove yourself...\n\n"
|
||||
"Each castle contains a single treasure, the Holy Grail, in the center. "
|
||||
"The radius of the Round Table is usually 28, but after you find a Holy Grail "
|
||||
@ -158,10 +169,114 @@ const char *elemdesc =
|
||||
"You need to collect a Shard from each Plane to construct an Elemental Gem. "
|
||||
"It is dangerous to collect too many Shards of the same type without constructing a Gem.";
|
||||
|
||||
const char *wildwestdesc =
|
||||
"Take a revolver, kill outlaws, collect bounties.\n\n"
|
||||
"Note: since this land is anachronistic, it is not available in normal game. "
|
||||
"It is only available in special modes.";
|
||||
|
||||
const char *elecdesc =
|
||||
"Whenever after your move there is a connection between a charged and a "
|
||||
"grounded cell, there is a short circuit. All cells on any "
|
||||
"path connecting a charged and a grounded cell (without repeated cells, "
|
||||
"or two consecutive grounded/charged cells) become damaged.\n\n"
|
||||
|
||||
"Sandstone walls and most creatures are conductive. Great Walls are "
|
||||
"isolators, but lands beyond them count as grounded.\n\n"
|
||||
|
||||
"Fulgurite, the treasure, is created when you manage to short circuit "
|
||||
"a sandstone wall, or a Rich Metal Beast.\n\n"
|
||||
|
||||
"Trolls leave conductive rocks when killed, and Metal Beasts can only "
|
||||
"be killed by electricity -- your attacks only stun them, or push "
|
||||
"them away if already stunned.";
|
||||
|
||||
const char *overdesc =
|
||||
"The Overgrown Woods are filled with mutant ivies! These plants "
|
||||
"grow very fast. Each leaf, after being grown, can grow itself "
|
||||
"on the next turn. However, each part is only able to grow "
|
||||
"once in 16 turns. Outside of the Overgrown Woods, the Mutant Ivy "
|
||||
"may grow only on hexagonal cells.\n\n"
|
||||
"Maybe such fast growing plants could help you solve the problem "
|
||||
"of hunger in your world? Kill the Mutant Ivies to collect Mutant Saplings.";
|
||||
|
||||
const char *cleardesc =
|
||||
"A clearing in the Overgrown Woods. Obviously, this gives "
|
||||
"the Mutant Ivies an infinite space to grow...\n\n"
|
||||
"Mutant Fruits rot if they are not adjacent to a Mutant Ivy.";
|
||||
|
||||
const char *winddesc =
|
||||
"Someone has put air fans in these plains, causing strong winds everywhere. "
|
||||
"You think that the purpose is to harness the magical power of Air Elementals, but "
|
||||
"you are not sure.\n\n"
|
||||
"All cells except fans are grouped into three colors according to a pattern. "
|
||||
"Wind blows counterclockwise around each group of cells of a single color. "
|
||||
"Cells which are blocked by walls, or at distance at most 2 from an Air Elemental, "
|
||||
"do not count for this.\n\n"
|
||||
"It is illegal to move in a direction which is closer to incoming wind than to "
|
||||
"outcoming wind. However, you can move two cells with the wind in a single turn, "
|
||||
"and so can the birds.";
|
||||
|
||||
const char *hauntdesc =
|
||||
"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 "
|
||||
"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";
|
||||
|
||||
const char *NODESC = "No description yet.";
|
||||
const char *GENDERSWITCH = NODESC;
|
||||
|
||||
// --- monsters ---
|
||||
|
||||
const int motypes = 102;
|
||||
const char *rosedesc =
|
||||
"Each eight turns, each rosebush at distance at most 5 from you will "
|
||||
"release a wave of alluring scent. Creatures on the frontwave "
|
||||
"will move towards where the scent came from. Even if it causes them "
|
||||
"to attack their friends or beautiful creatures, or move into water, fire, chasm, or thorns of the rosebush. "
|
||||
"Ivies, Ghosts, Rock Snakes, Rose Ladies and Lords, and monsters restricted to a specific "
|
||||
"terrain are immune to scents.";
|
||||
|
||||
const char *warpdesc =
|
||||
"This part of the world is warped, restricting the movement somewhat. "
|
||||
"\"Diagonal\" movement and attacking between triangular cells is not allowed. "
|
||||
"Flash, Storms, and Freedom spells ignore this, and Ghosts can move, attack, and "
|
||||
"be attacked diagonally.";
|
||||
|
||||
const char *warplanddesc =
|
||||
"This land is warped. Ironically, the coast is completely straight...";
|
||||
|
||||
const char *roselanddesc =
|
||||
"This land is filled with beautiful, but dangerous, creatures and plants.";
|
||||
|
||||
const char *dragondesc =
|
||||
"Dragons are powerful monsters. They are slow, but evil, "
|
||||
"and love to pick on creatures who are even slower than "
|
||||
"them. They must be stopped!\n\n"
|
||||
|
||||
"A Dragon moves each two turns. It may attack with all its segments, "
|
||||
"or move its whole body forwards or "
|
||||
"backwards, it may also move a frontal part backwards. To kill a Dragon, "
|
||||
"you need to hit each of its segments. "
|
||||
"The head will regenerate on the "
|
||||
"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 "
|
||||
"fire (at range 3), losing the hitpoint. Killing the Dragon gives you "
|
||||
"treasure.";
|
||||
|
||||
const char *tortoisedesc =
|
||||
"Galápagos is the land of Tortoises. "
|
||||
"They are very slow, which allows the Dragons to pick on them by "
|
||||
"stealing and eating their young. Bring the Baby Tortoises back, "
|
||||
"but, there is a catch: the Tortoises come in many varieties, depending "
|
||||
"on the part of Galápagos they live in -- there are 21 binary environmental "
|
||||
"factors, and thus "
|
||||
"2097152 varieties. You'll have to find a "
|
||||
"Tortoise which matches the baby exactly!\n\n"
|
||||
"Tortoises move each 3 turns, and attacks only stun them.\n\n"
|
||||
"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.";
|
||||
|
||||
|
||||
const int motypes = 125;
|
||||
|
||||
struct monstertype {
|
||||
char glyph;
|
||||
@ -181,7 +296,7 @@ const char *gargdesc =
|
||||
"killed, but only if next to something stable -- otherwise it falls.";
|
||||
|
||||
monstertype minf[motypes] = {
|
||||
{ 0, 0, "none" , NULL},
|
||||
{ 0, 0, "no monster" , NULL},
|
||||
{ 'Y', 0x4040FF, "Yeti" ,
|
||||
"A big and quite intelligent monster living in the Icy Land."
|
||||
},
|
||||
@ -420,13 +535,64 @@ monstertype minf[motypes] = {
|
||||
"This also affects most monsters."},
|
||||
{ 'D', 0xC06000, "Striped Dog", "A predator native to the Zebra."},
|
||||
{ 'G', 0xFFFFFF, "Tentacle+Ghost", tentdes },
|
||||
{ 'B', 0x8080C0, "Metal Beast", elecdesc },
|
||||
{ 'B', 0xC060C0, "Rich Metal Beast", elecdesc },
|
||||
{ 'O', 0xA06020, "Outlaw", wildwestdesc },
|
||||
{ 'C', 0xC0C060, "Mutant Ivy", overdesc },
|
||||
{ 'T', 0x0080FF, "Storm Troll", elecdesc },
|
||||
{ 'T', 0x00C080, "Forest Troll",
|
||||
"Forest Trolls create an impassable wall when they die."
|
||||
},
|
||||
{ 'F', 0xC35817, "Giant Fox",
|
||||
"What is freedom for you? A situation when you can walk wherever you want? "
|
||||
"Or a situation when you do not have to work, since you have as much tasty food "
|
||||
"as you want?\n\n"
|
||||
"Well, this creature has chosen the second option. It won't be happy "
|
||||
"if you destroy its prison.\n"
|
||||
},
|
||||
{ 'C', 0x8080FF, "Wind Crow",
|
||||
"A large bird who likes strong winds. Just as you, it can fly quickly in the wind."
|
||||
},
|
||||
{ 'G', 0xC0FFC0, "Friendly Ghost",
|
||||
"Friendly ghosts are friendly beings who can go through any obstacles. However, "
|
||||
"unlike most friends, they tend to fly away from you."
|
||||
},
|
||||
{ 'R', 0x906030, "Ratling",
|
||||
"These warped humanoids are skilled warriors and sailors, and they "
|
||||
"feel at home at the Warped Coast. Their battle experience has taught them "
|
||||
"that enemies who wait without moving or attacking anything are the most deadly. "
|
||||
"If they see such an enemy, they become extremely suspicious, and they also wait."
|
||||
},
|
||||
{ 'F', 0xC00000, "False Princess", GENDERSWITCH },
|
||||
{ 'R', 0x500050, "Rose Lady", GENDERSWITCH },
|
||||
{ 'R', 0xF0A0D0, "Rose Beauty", GENDERSWITCH },
|
||||
{ 'R', 0x806040, "Ratling Avenger",
|
||||
"So, you have killed a Ratling on the unwarped sea? You will be punished for this! "
|
||||
"Luckily, if you run away from the Warped Sea quickly, the Ratling Avengers will lose track of you."
|
||||
},
|
||||
{ 'T', 0x487830, "Tortoise", tortoisedesc},
|
||||
{ 'D', 0xC03000, "Dragon", dragondesc},
|
||||
{ 'd', 0xC03000, "Dragon", dragondesc},
|
||||
{ 'N', 0x303030, "Nighthawk", NODESC},
|
||||
{ 'Y', 0xFF8000, "Yendorian Researcher",
|
||||
"These people study gravity and infinite trees. "
|
||||
"They have no special features, other than wearing a strange hat."
|
||||
},
|
||||
{ 'K', 0xA8A8A8, "Sparrowhawk",
|
||||
"A bird who hunts in the treetops of Yendorian Forest."
|
||||
},
|
||||
|
||||
// shmup specials
|
||||
{ '@', 0xC0C0C0, "Rogue", "In the Shoot'em Up mode, you are armed with thrown Knives."},
|
||||
{ '*', 0xC0C0C0, "Knife", "A simple, but effective, missile, used by rogues."},
|
||||
{ '*', 0xFF0000, "Flail", "This attack is likely to hit the attacker."},
|
||||
{ '*', 0xFFFF00, "Fireball", "This magical missile burns whatever it hits."},
|
||||
{ '*', 0xFFFF00, "Tongue", "Some monsters have long tongues, which allow them to attack enemies in nearby cells."},
|
||||
{ '*', 0xFFFFFF, "Airball", "This magical missile pushes back whatever it hits."}
|
||||
{ '*', 0xFFFFFF, "Airball", "This magical missile pushes back whatever it hits."},
|
||||
// technical
|
||||
{ '?', 0x00C000, "dead bug", NODESC},
|
||||
{ '?', 0xFFFF00, "electric discharge", NODESC}, // appears as 'killed by electrocution'
|
||||
{ '?', 0xE06000, "dead bird", NODESC},
|
||||
};
|
||||
|
||||
enum eMonster {
|
||||
@ -462,15 +628,46 @@ enum eMonster {
|
||||
moPrincessArmed, moPrincessArmedMoved,
|
||||
moEdgeMonkey, moGargoyle, moFireElemental, moAirElemental,
|
||||
moOrangeDog, moTentacleGhost,
|
||||
moMetalBeast, moMetalBeast2, moOutlaw, moMutant,
|
||||
moStormTroll, moForestTroll,
|
||||
moRedFox, moWindCrow, moFriendlyGhost, moRatling, moFalsePrincess, moRoseLady,
|
||||
moRoseBeauty, moRatlingAvenger,
|
||||
moTortoise, moDragonHead, moDragonTail,
|
||||
moNighthawk, moLemur, moKestrel,
|
||||
// shmup specials
|
||||
moPlayer, moBullet, moFlailBullet, moFireball, moTongue, moAirball,
|
||||
// temporary
|
||||
moDeadBug, moLightningBolt, moDeadBird
|
||||
};
|
||||
|
||||
// --- items ----
|
||||
struct genderswitch_t {
|
||||
int gender;
|
||||
eMonster m;
|
||||
const char *name;
|
||||
const char *desc;
|
||||
};
|
||||
|
||||
const int ittypes = 67;
|
||||
#define NUM_GS 6
|
||||
|
||||
genderswitch_t genderswitch[NUM_GS] = {
|
||||
{ GEN_F, moFalsePrincess, "False Princess",
|
||||
"Don't be fooled by this red-haired girl, or you will be stabbed if you come too close!"},
|
||||
{ GEN_M, moFalsePrincess, "False Prince",
|
||||
"Don't be fooled by this red-haired boy, or you will be stabbed if you come too close!"},
|
||||
{ GEN_F, moRoseLady, "Rose Lady",
|
||||
"This false princess is immune to the alluring scent of roses."},
|
||||
{ GEN_M, moRoseLady, "Rose Lord",
|
||||
"This false prince is immune to the alluring scent of roses."},
|
||||
{ GEN_F, moRoseBeauty, "Rose Beauty",
|
||||
"She has flowers in her long fair hair. You could not bring yourself to attack such a beautiful woman."},
|
||||
{ GEN_M, moRoseBeauty, "Handsome Gardener",
|
||||
"Tall, strong, and holding a flower in his hand. You could "
|
||||
"not bring yourself to attack such a handsome man."}
|
||||
};
|
||||
|
||||
// --- items ---
|
||||
|
||||
const int ittypes = 92;
|
||||
|
||||
struct itemtype {
|
||||
char glyph;
|
||||
@ -480,7 +677,7 @@ struct itemtype {
|
||||
};
|
||||
|
||||
itemtype iinf[ittypes] = {
|
||||
{ 0, 0, "none", NULL},
|
||||
{ 0, 0, "no item", NULL},
|
||||
{ '*', 0xFFFFFF, "Ice Diamond",
|
||||
"Cold white gems, found in the Icy Land."
|
||||
},
|
||||
@ -653,7 +850,7 @@ itemtype iinf[ittypes] = {
|
||||
"This Orb allows your boat to go against the current, "
|
||||
"and also to go into the land, creating water on the way."
|
||||
},
|
||||
{ 'o', 0xC00060, "Orb of Air",
|
||||
{ 'o', 0xC0C0FF, "Orb of Air",
|
||||
"This Orb allows you to blow your enemies away.\n\n"
|
||||
"Click a monster to blow it one cell away. It cannot be used against mimics, ghosts, sharks and other monsters restricted to a specific terrain, and multi-tile monsters."
|
||||
},
|
||||
@ -692,7 +889,109 @@ itemtype iinf[ittypes] = {
|
||||
},
|
||||
{ 'o', 0x306090, "Orb of Matter",
|
||||
"This Orb allows to temporarily create impassable matter, either to block paths or "
|
||||
"to build bridges across chasms and waters."}
|
||||
"to build bridges across chasms and waters."},
|
||||
{ '*', 0xF0F000, "Bounty", wildwestdesc},
|
||||
{ '[', 0xC0C0C0, "Revolver", wildwestdesc},
|
||||
{ '*', 0xF0F080, "Fulgurite", elecdesc},
|
||||
{ '%', 0xFFFFFF, "Mutant Sapling", overdesc},
|
||||
{ 'o', 0xA08000, "Orb of Stunning",
|
||||
"This Orb allows you to target monsters to stun them. "
|
||||
"10 charges are used to stun for 5 turns. Does not "
|
||||
"work against multi-tile monsters."},
|
||||
{ 'o', 0xC00000, "Orb of Luck",
|
||||
"This Orb allows you to find new lands more easily. "
|
||||
"Lands where you have already collected less treasure, "
|
||||
"and especially the Crossroads, are more likely to "
|
||||
"spawn while you have this. Additionally, Orbs of Safety "
|
||||
"are more likely to spawn in the Whirlpool."
|
||||
},
|
||||
{ '%', 0xD03030, "Mutant Fruit", cleardesc},
|
||||
{ 'o', 0xC00000, "Orb of Freedom",
|
||||
"This orb is activated if you are unable to escape (radius 4) "
|
||||
"without making illegal moves or "
|
||||
"going through cells which are currently adjacent to enemy monsters. "
|
||||
"Most game over situations are covered by this, but generally, "
|
||||
"this orb is oversensitive...\n\n"
|
||||
"When activated, it creates a Flash effect of radius 5."
|
||||
},
|
||||
{ '%', 0x606060, "Black Lotus",
|
||||
"This beautiful flower is greatly prized by wizards, as it allows them to cast powerful magical spells "
|
||||
"without preparation.\n"
|
||||
},
|
||||
{ 'o', 0x505050, "Orb of Undeath",
|
||||
"Monsters slain by you in melee are turned into friendly ghosts, "
|
||||
"Does not affect plants and friends."
|
||||
},
|
||||
{ '*', 0x8080FF, "White Dove Feather",
|
||||
"This feather is truly beautiful and strong."
|
||||
},
|
||||
{ 'o', 0xC00060, "Orb of Empathy",
|
||||
"This Orb lets your allies to share your Orb powers.\n\n"
|
||||
"The following Orbs are affected:"
|
||||
},
|
||||
{ '>', 0x0000FF, "strong wind",
|
||||
"In the Windy Plains, you can let the wind carry you, "
|
||||
"causing you to move two cells with the wind in a single turn. "
|
||||
"This cannot be done if you are standing at distance at most 2 "
|
||||
"from the Air Elemental, or if any of the three cells on the way "
|
||||
"has two wind directions.\n\n"
|
||||
"Press 't' or click the destination to activate."
|
||||
},
|
||||
{ 'x', 0xFF00FF, "buggy item",
|
||||
"Please report this as a bug."
|
||||
},
|
||||
{ 'x', 0xFFFF00, "buggy item",
|
||||
"Please report this as a bug."
|
||||
},
|
||||
{ '%', 0x744c7c / 4 + 0x800000, "Thornless Rose",
|
||||
"A big, beautiful, magical flower."
|
||||
},
|
||||
{ '*', 0xFF40A0, "Coral",
|
||||
"Corals have a somewhat hyperbolic structure even in your home world, "
|
||||
"but natural corals from the Warped Sea have truly beautiful shapes. "
|
||||
"Ratlings know the value of corals, and thus keep them in boats for safety."
|
||||
},
|
||||
{ 'o', 0x764e7c*2, "Orb of Beauty",
|
||||
"This Orb makes you stunningly beautiful. "
|
||||
"Monsters which come next to you will be stunned for one turn. "
|
||||
"Multi-tile monsters are not affected. Additionally, it makes you immune to "
|
||||
"beauty."
|
||||
},
|
||||
{ 'o', 0xFFFF80, "Orb of the Warp",
|
||||
"This Orb creates a warped zone of radius 5 around you, "
|
||||
"and also allows you to move diagonally in warped zones."
|
||||
},
|
||||
{ 'o', 0xFFFF80, "Orb of Energy",
|
||||
"This Orb halves the power usage of orbs which cost some "
|
||||
"charges with each activation. It even affects the "
|
||||
"one-shot orbs such as Flash or Teleport. If such an activation "
|
||||
"normally costs x charges, it costs only x/2 (rounded up) "
|
||||
"if you have an Orb of Energy."
|
||||
},
|
||||
{ 't', 0x487830, "Baby Tortoise", tortoisedesc},
|
||||
{ 'o', 0x487830, "Orb of the Shell",
|
||||
"This Orb protects you from physical attacks. "
|
||||
"It lasts for more turns than the Orb of Shielding, but "
|
||||
"10 charges are lost whenever you are attacked. "
|
||||
"It also does not protect you from fires, scents, and being eaten."
|
||||
},
|
||||
|
||||
{ '!', 0xc00000, "Apple", "A fruit from the Yendorian Forest."},
|
||||
{ '!', 0xFF6000, "Dragon Scale",
|
||||
"Dragon Scales are a prized material for armors. "
|
||||
"They are also prized by collectors, who would like to boast "
|
||||
"about how they have killed a Dragon.\n\n"
|
||||
"Dragon Scales disappear after 500 turns."
|
||||
},
|
||||
{ 'o', 0x900000, "Orb of Domination",
|
||||
"This Orb lets you ride Dragons and other worm-like creatures. "
|
||||
"Simply move onto such a creature to ride them; while riding, you are protected from dangerous terrains "
|
||||
"and partially from attacks (they cause you to lose half of your Domination power), "
|
||||
"but you cannot collect items. When only one charge is left, "
|
||||
"you have to dismount this turn -- be very careful to make this possible, "
|
||||
"as your mount could attack you immediately!\n\n" "While riding, "
|
||||
"click on a location to order your mount to move or attack there.",
|
||||
}
|
||||
};
|
||||
|
||||
enum eItem { itNone, itDiamond, itGold, itSpice, itRuby, itElixir, itShard, itBone, itHell, itStatue,
|
||||
@ -715,12 +1014,18 @@ enum eItem { itNone, itDiamond, itGold, itSpice, itRuby, itElixir, itShard, itBo
|
||||
itSavedPrincess, itOrbLove,
|
||||
itEdge, itZebra,
|
||||
itFireShard, itAirShard, itEarthShard, itWaterShard,
|
||||
itElemental, itOrbSummon, itOrbMatter
|
||||
itElemental, itOrbSummon, itOrbMatter,
|
||||
itBounty, itRevolver, itFulgurite, itMutant,
|
||||
itOrbStunning, itOrbLuck,
|
||||
itMutant2, itOrbFreedom, itLotus, itOrbUndeath,
|
||||
itWindstone, itOrbEmpathy, itStrongWind, itBuggy, itBuggy2,
|
||||
itRose, itCoral, itOrbSkunk, itOrb37, itOrbEnergy,
|
||||
itBabyTortoise, itOrbShell, itApple, itDragon, itOrbDomination
|
||||
};
|
||||
|
||||
// --- wall types ---
|
||||
|
||||
const int walltypes = 69;
|
||||
const int walltypes = 88;
|
||||
|
||||
struct walltype {
|
||||
char glyph;
|
||||
@ -736,7 +1041,7 @@ const char *thumpdesc = "A device that attracts sandworms and other enemies. You
|
||||
const char *twdesc = "This structure will disappear after some time.";
|
||||
|
||||
walltype winf[walltypes] = {
|
||||
{ '.', 0xFF00FF, "none", NULL},
|
||||
{ '.', 0xFF00FF, "no wall", NULL},
|
||||
{ '#', 0x8080FF, "ice wall",
|
||||
"Ice Walls melt after some time has passed."
|
||||
},
|
||||
@ -745,7 +1050,7 @@ walltype winf[walltypes] = {
|
||||
{ '+', 0x300090, "blue slime", slimehelp },
|
||||
{ '#', 0xA0D0A0, "living wall", cavehelp},
|
||||
{ '.', 0x306060, "living floor",cavehelp},
|
||||
{ '#', 0xD03030, "dead troll", trollhelp},
|
||||
{ '#', 0xD03030, "dead rock troll", trollhelp},
|
||||
{ '#', 0xCDA98F, "sand dune",
|
||||
"A natural terrain feature of the Desert."
|
||||
},
|
||||
@ -816,7 +1121,7 @@ walltype winf[walltypes] = {
|
||||
"a water cell (and the boat will come with you)."
|
||||
},
|
||||
{ '.', 0x00FF00, "island", cislandhelp},
|
||||
{ '.', 0x80C000, "island", cislandhelp},
|
||||
{ '.', 0x80C060, "island", cislandhelp},
|
||||
{ '#', 0x006000, "tree",
|
||||
"The forests of Caribbean are too dense to be traversed by humans, "
|
||||
"and they are hard to burn. Many colorful parrots can be found there."
|
||||
@ -835,14 +1140,14 @@ walltype winf[walltypes] = {
|
||||
{ '+', 0xFFFFFF, "closed gate", gatedesc },
|
||||
{ '-', 0x404040, "open gate", gatedesc },
|
||||
{ '_', 0xC00000, "closing plate", gatedesc },
|
||||
{ '_', 0x00C000, "opening plate", gatedesc },
|
||||
{ '_', 0x00C050, "opening plate", gatedesc },
|
||||
{ '_', 0x202020, "trapdoor", "This floor will fall after someone goes there. Go quickly!" },
|
||||
{ '+', 0xFF0000, "giant rug",
|
||||
"This is the biggest Hypersian Rug you have ever seen! "
|
||||
"Unfortunately, it is too large to take it as a trophy." },
|
||||
{ '#', 0xfffff0, "platform", "You can stand here."},
|
||||
{ '#', 0x909090, "stone gargoyle", gargdesc},
|
||||
{ '.', 0x909090, "stone gargoyle floor", gargdesc},
|
||||
{ '.', 0xB0B0B0, "stone gargoyle floor", gargdesc},
|
||||
{ '.', 0x909090, "rubble", "Some rubble."},
|
||||
{ '+', 0x804000, "ladder",
|
||||
"You can use this ladder to climb the Tower."
|
||||
@ -859,12 +1164,36 @@ walltype winf[walltypes] = {
|
||||
{ '.', 0x909090, "stone gargoyle bridge", gargdesc},
|
||||
{ '#', 0x309060, "temporary wall", twdesc},
|
||||
{ '.', 0x309060, "temporary floor", twdesc},
|
||||
{ '.', 0x309060, "temporary bridge", twdesc}
|
||||
{ '.', 0x309060, "temporary bridge", twdesc},
|
||||
{ '#', 0x3030FF, "charged wall", elecdesc},
|
||||
{ '#', 0xFF3030, "grounded wall", elecdesc},
|
||||
{ '#', 0xA0A060, "sandstone wall", elecdesc},
|
||||
{ '+', 0x704000, "saloon wall", wildwestdesc},
|
||||
{ '#', 0x90C0C0, "metal wall", elecdesc},
|
||||
{ '#', 0x607030, "dead troll", trollhelpX},
|
||||
{ '+', 0xC0C0FF, "fan", winddesc},
|
||||
{ '?', 0xFF00FF, "<temporary>", NODESC},
|
||||
{ '?', 0xFF00FF, "<earth d", NODESC},
|
||||
{ '?', 0xFF00FF, "<elemental tmp>", NODESC},
|
||||
{ '?', 0xFF00FF, "<elemental d>", NODESC},
|
||||
{ '+', 0x607030, "unnamed floor C", NODESC},
|
||||
{ '+', 0xC0C0FF, "unnamed floor D", NODESC},
|
||||
{ '#', 0x764e7c, "rosebush", roselanddesc},
|
||||
{ '#', 0xC0C000, "warp gate",
|
||||
"This gate separates the warped area from the normal land."},
|
||||
{ '+', 0x804000, "trunk", "The skeleton of a tree."},
|
||||
{ '+', 0x804000, "solid branch", "Branches here could bear your weight easily."},
|
||||
{ '+', 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."},
|
||||
{ '+', 0x60C060, "canopy",
|
||||
"Only thin twigs and leaves here. They may bear fruits, but for you, these cells count "
|
||||
"as unstable."
|
||||
}
|
||||
};
|
||||
|
||||
enum eWall { waNone, waIcewall, waBarrier, waFloorA, waFloorB, waCavewall, waCavefloor, waDeadTroll, waDune,
|
||||
waMirror, waCloud, waThumperOff, waFire, waAncientGrave, waFreshGrave, waColumn, waSulphurC, waSulphur,
|
||||
waLake, waFrozenLake, waChasm, waChasmD, waDryTree, waWetTree,
|
||||
waLake, waFrozenLake, waChasm, waChasmD, waBigTree, waSmallTree,
|
||||
waVinePlant, waVineHalfA, waVineHalfB, waPartialFire,
|
||||
waDeadwall, waDeadfloor, waDeadfloor2, waWaxWall, waGlass, waCamelot, waRoundTable,
|
||||
waCamelotMoat,
|
||||
@ -879,14 +1208,16 @@ enum eWall { waNone, waIcewall, waBarrier, waFloorA, waFloorB, waCavewall, waCav
|
||||
waBonfireOff, waThumperOn, waEternalFire,
|
||||
waGargoyleBridge,
|
||||
waTempWall, waTempFloor, waTempBridge,
|
||||
// temporary walls for various purposes
|
||||
waTemporary, waEarthD, waElementalTmp, waElementalD
|
||||
waCharged, waGrounded, waSandstone, waSaloon, waMetal,
|
||||
waDeadTroll2, waFan,
|
||||
waTemporary, waEarthD, waElementalTmp, waElementalD,
|
||||
waFloorC, waFloorD, waRose, waWarpGate,
|
||||
waTrunk, waSolidBranch, waWeakBranch, waCanopy
|
||||
};
|
||||
|
||||
// --- land types ---
|
||||
|
||||
const int numLands = 35;
|
||||
const int landtypes = numLands + 6;
|
||||
const int landtypes = 56;
|
||||
|
||||
struct landtype {
|
||||
int color;
|
||||
@ -940,12 +1271,12 @@ landtype linf[landtypes] = {
|
||||
"the floor.\n"
|
||||
},
|
||||
{ 0x008000, "Dry Forest", foresthelp},
|
||||
{ 0x0000C0, "Emerald Mine",
|
||||
{ 0x60C060, "Emerald Mine",
|
||||
"Evil people are mining for emeralds in this living cave. "
|
||||
"It does not grow naturally, but it is dug out in a regular "
|
||||
"pattern, which is optimal according to the evil engineers."
|
||||
},
|
||||
{ 0x421C52, "Vineyard", foresthelp},
|
||||
{ 0x421C52, "Vineyard", vinehelp},
|
||||
{ 0x104040, "Dead Cave", deadcavehelp},
|
||||
{ 0x705020, "Hive", hivehelp},
|
||||
{ 0xFFFF00, "Land of Power",
|
||||
@ -1004,6 +1335,26 @@ landtype linf[landtypes] = {
|
||||
{ 0x4040C0, "Elemental Planes", elemdesc},
|
||||
{ 0xE08020, "Canvas", "A fake Land with colored floors."},
|
||||
{ 0x00C000, "Palace Quest", princessdesc}, // this is fake
|
||||
{ 0xD0D060, "Wild West", wildwestdesc},
|
||||
{ 0x80A080, "Land of Storms", elecdesc},
|
||||
{ 0x20A050, "Overgrown Woods", overdesc},
|
||||
{ 0x20D050, "Clearing", cleardesc},
|
||||
{ 0x303030, "Haunted Woods", hauntdesc},
|
||||
{ 0x303030, "Haunted Woods", hauntdesc},
|
||||
{ 0x303030, "Haunted Woods", hauntdesc},
|
||||
{ 0xC0C0FF, "Windy Plains", winddesc},
|
||||
{ 0x764e7c*2, "Rose Garden", roselanddesc},
|
||||
{ 0xFFD580, "Warped Coast", warplanddesc},
|
||||
{ 0xFFD580, "Warped Sea", warplanddesc},
|
||||
{ 0xC08080, "Crossroads IV",
|
||||
"An alternate layout of the Crossroads, without walls."
|
||||
},
|
||||
{ 0xFFD580, "Yendorian Forest",
|
||||
"This forest was planted by one of the wizards from the Ivory Tower "
|
||||
"to conduct experiments with gravity."
|
||||
},
|
||||
{ 0x487830, "Galápagos", tortoisedesc},
|
||||
{ 0xD04000, "Dragon Chasms", dragondesc},
|
||||
};
|
||||
|
||||
enum eLand { laNone, laBarrier, laCrossroads, laDesert, laIce, laCaves, laJungle, laAlchemist, laMirror, laGraveyard,
|
||||
@ -1011,8 +1362,14 @@ enum eLand { laNone, laBarrier, laCrossroads, laDesert, laIce, laCaves, laJungle
|
||||
laHive, laPower, laCamelot, laTemple,
|
||||
laCrossroads2, laCaribbean, laRedRock, laMinefield, laOcean, laWhirlpool,
|
||||
laPalace, laLivefjord,
|
||||
laEdge, laZebra, laEFire, laEAir, laEEarth, laEWater, laCrossroads3,
|
||||
laOceanWall, laElementalWall, laCanvas, laPrincessQuest };
|
||||
laIvoryTower, laZebra, laEFire, laEAir, laEEarth, laEWater, laCrossroads3,
|
||||
laOceanWall, laElementalWall,
|
||||
laCanvas, laPrincessQuest,
|
||||
laWildWest, laStorms, laOvergrown, laClearing,
|
||||
laHaunted, laHauntedWall, laHauntedBorder,
|
||||
laWhirlwind, laRose, laGridCoast, laGridSea, laCrossroads4,
|
||||
laEndorian, laTortoise, laDragon
|
||||
};
|
||||
|
||||
// cell information for the game
|
||||
|
||||
@ -1052,10 +1409,103 @@ struct gcell {
|
||||
// CR2 structure;
|
||||
// hive Weird Rock color / pheromones;
|
||||
// Ocean/coast depth
|
||||
union { int32_t landpar; float heat; } LHU;
|
||||
union { int32_t landpar; float heat; char bytes[4]; } LHU;
|
||||
};
|
||||
|
||||
#define landparam LHU.landpar
|
||||
|
||||
#define NODIR 7
|
||||
#define NOBARRIERS 8
|
||||
|
||||
#define LAND_OVER 44
|
||||
eLand land_over[LAND_OVER] = {
|
||||
laIce, laCaves, laDesert, laMotion, laJungle, laAlchemist,
|
||||
laCrossroads,
|
||||
laMirror, laMinefield, laZebra, laPalace, laPrincessQuest,
|
||||
laOcean, laLivefjord, laGridCoast, laCaribbean, laWhirlpool, laRlyeh, laTemple,
|
||||
laCrossroads2,
|
||||
laDryForest, laWineyard, laDeadCaves, laGraveyard, laHaunted, laHive,
|
||||
laRedRock,
|
||||
laIvoryTower, laEndorian,
|
||||
laDragon, laTortoise,
|
||||
laOvergrown, laClearing, laStorms, laWhirlwind, laRose,
|
||||
laEmerald, laCamelot, laElementalWall,
|
||||
laHell, laCrossroads3, laCocytus, laPower, laCrossroads4
|
||||
};
|
||||
|
||||
#define LAND_EUC 42
|
||||
eLand land_euc[LAND_EUC] = {
|
||||
laIce, laCaves, laDesert, laMotion, laJungle,
|
||||
laCrossroads,
|
||||
laMirror, laMinefield, laAlchemist, laZebra, laPalace, laPrincessQuest,
|
||||
laOcean, laLivefjord, laGridCoast, laCaribbean, laWhirlpool, laRlyeh, laTemple,
|
||||
laElementalWall,
|
||||
laDryForest, laWineyard, laDeadCaves, laGraveyard, laHive, laRedRock, laIvoryTower,
|
||||
laOvergrown, laClearing, laStorms, laWhirlwind, laRose,
|
||||
laEmerald, laCamelot, laDragon, laTortoise,
|
||||
laHell, laCrossroads3, laCocytus, laPower,
|
||||
laCrossroads4,
|
||||
laWildWest
|
||||
};
|
||||
// MISSING: laCrossroads2
|
||||
|
||||
#define LAND_HYP 39
|
||||
eLand land_hyp[LAND_HYP] = {
|
||||
laHell, laCocytus, laGraveyard,
|
||||
laWineyard, laDryForest, laCaves,
|
||||
laPalace, laEmerald, laHive, laDeadCaves, laPower,
|
||||
laOcean, laLivefjord, laRlyeh, laTemple, laIce,
|
||||
laDesert, laRedRock,
|
||||
laWhirlpool, laOvergrown, laClearing, laStorms,
|
||||
laCaribbean, laJungle, laAlchemist, laMotion, laMirror, laMinefield,
|
||||
laZebra, laElementalWall, laIvoryTower, laHaunted, laWhirlwind, laCrossroads,
|
||||
laGridCoast, laRose, laDragon, laEndorian, laTortoise
|
||||
};
|
||||
|
||||
#define LAND_SCAPE 32
|
||||
eLand land_scape[LAND_SCAPE] = {
|
||||
laHell, laCocytus, laGraveyard,
|
||||
laWineyard, laDryForest, laCaves,
|
||||
laPalace, laEmerald, laDeadCaves, laPower,
|
||||
laOcean, laLivefjord, laRlyeh, laTemple, laIce,
|
||||
laDesert, laRedRock,
|
||||
laOvergrown, laStorms,
|
||||
laJungle, laAlchemist, laMotion, laMirror, laMinefield,
|
||||
laZebra, laWhirlwind, laCrossroads,
|
||||
laGridCoast, laRose,
|
||||
laCrossroads, laCrossroads2, laCrossroads3
|
||||
};
|
||||
|
||||
#define LAND_TAC 44
|
||||
|
||||
struct landtacinfo { eLand l; int tries, multiplier; };
|
||||
|
||||
landtacinfo land_tac[LAND_TAC] = {
|
||||
{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},
|
||||
{laOcean, 10, 1}, {laLivefjord, 10, 1}, {laGridCoast, 10, 1}, {laRlyeh, 10, 1}, {laHell, 10, 1},
|
||||
{laElementalWall, 10, 1}, {laDryForest, 10, 1}, {laWineyard, 10, 1},
|
||||
{laDeadCaves, 10, 1}, {laGraveyard, 10, 1},
|
||||
{laHaunted, 10, 1},
|
||||
{laIvoryTower, 10, 1}, {laEndorian, 10, 1},
|
||||
{laEmerald, 10, 1},
|
||||
{laCocytus, 10, 1},
|
||||
|
||||
{laCaribbean, 5, 2}, {laWhirlpool, 5, 2}, {laTemple, 5, 2}, {laMinefield, 5, 2},
|
||||
{laPower, 5, 2}, {laHive, 5, 2}, {laRedRock, 5, 2}, {laStorms, 5, 2}, {laOvergrown, 5, 2},
|
||||
{laClearing, 5, 2},
|
||||
{laWhirlwind, 5, 2}, {laRose, 5, 2}, {laDragon, 2, 5}, {laTortoise, 1, 10},
|
||||
|
||||
{laCrossroads, 10, 1}, {laCrossroads2, 10, 1}, {laCrossroads3, 10, 1}, {laCrossroads4, 10, 1},
|
||||
|
||||
{laCamelot, 1, 100},
|
||||
{laWildWest, 10, 1}
|
||||
};
|
||||
|
||||
#define RANDLANDS 17
|
||||
eLand randlands[RANDLANDS] = {
|
||||
laIce, laDesert, laCaves, laAlchemist, laGraveyard, laPower, laLivefjord, laZebra,
|
||||
laRlyeh, laDryForest, laEmerald, laWineyard, laDeadCaves, laRedRock,
|
||||
laOvergrown, laWildWest, laGridCoast
|
||||
};
|
||||
|
||||
|
2102
complex.cpp
Normal file
2102
complex.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,7 @@
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ([2.68])
|
||||
AC_INIT([hyperrogue], [7.4h])
|
||||
AC_INIT([hyperrogue], [8.3j])
|
||||
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
|
||||
${CXXFLAGS=""}
|
||||
AC_CONFIG_SRCDIR([hyperpoint.cpp])
|
||||
@ -43,7 +43,7 @@ AC_CHECK_HEADERS([SDL/SDL_mixer.h], [], AC_MSG_ERROR([SDL/SDL_mixer.h header was
|
||||
AC_CHECK_HEADERS([SDL/SDL_ttf.h], [], AS_IF( test ["${host_os#*mingw}" != "$host_os"], [] ,AC_MSG_ERROR([SDL/SDL_ttf.h header was not found])))
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_CHECK_HEADER_STDBOOL
|
||||
# AC_CHECK_HEADER_STDBOOL
|
||||
AC_C_INLINE
|
||||
AC_TYPE_SIZE_T
|
||||
|
||||
|
660
conformal.cpp
Normal file
660
conformal.cpp
Normal file
@ -0,0 +1,660 @@
|
||||
// Hyperbolic Rogue -- the conformal/history mode
|
||||
// Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details
|
||||
#include <complex>
|
||||
|
||||
namespace polygonal {
|
||||
|
||||
typedef long double ld;
|
||||
typedef complex<long double> cld;
|
||||
|
||||
int SI = 4;
|
||||
double STAR = 0;
|
||||
|
||||
int deg = 20;
|
||||
|
||||
#define MSI 120
|
||||
|
||||
ld matrix[MSI][MSI];
|
||||
ld ans[MSI];
|
||||
|
||||
cld coef[MSI];
|
||||
int maxcoef, coefid;
|
||||
|
||||
void solve() {
|
||||
for(int i=0; i<MSI; i++) ans[i] = cos(M_PI / SI);
|
||||
for(int i=0; i<MSI; i++)
|
||||
for(int j=0; j<MSI; j++) {
|
||||
double i0 = (i+0.) / (MSI-1);
|
||||
// i0 *= i0;
|
||||
// i0 = 1 - i0;
|
||||
i0 *= M_PI;
|
||||
matrix[i][j] =
|
||||
cos(i0 * (j + 1./SI)) * (STAR > 0 ? (1+STAR) : 1)
|
||||
- sin(i0 * (j + 1./SI)) * (STAR > 0 ? STAR : STAR/(1+STAR));
|
||||
}
|
||||
|
||||
for(int i=0; i<MSI; i++) {
|
||||
ld dby = matrix[i][i];
|
||||
for(int k=0; k<MSI; k++) matrix[i][k] /= dby;
|
||||
ans[i] /= dby;
|
||||
for(int j=i+1; j<MSI; j++) {
|
||||
ld sub = matrix[j][i];
|
||||
ans[j] -= ans[i] * sub;
|
||||
for(int k=0; k<MSI; k++)
|
||||
matrix[j][k] -= sub * matrix[i][k];
|
||||
}
|
||||
}
|
||||
for(int i=MSI-1; i>=0; i--) {
|
||||
for(int j=0; j<i; j++) {
|
||||
ld sub = matrix[j][i];
|
||||
ans[j] -= ans[i] * sub;
|
||||
for(int k=0; k<MSI; k++)
|
||||
matrix[j][k] -= sub * matrix[i][k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pair<ld, ld> compute(ld x, ld y, int prec) {
|
||||
if(pmodel == 4) {
|
||||
cld z(x,y);
|
||||
cld res (0,0);
|
||||
for(int i=maxcoef; i>=0; i--) { res += coef[i]; if(i) res *= z; }
|
||||
return make_pair(real(res), imag(res));
|
||||
}
|
||||
|
||||
cld z(x, y);
|
||||
cld res (0,0);
|
||||
cld zp = 1; for(int i=0; i<SI; i++) zp *= z;
|
||||
|
||||
for(int i=prec; i>0; i--) {
|
||||
res += ans[i];
|
||||
res *= zp;
|
||||
}
|
||||
res += ans[0]; res *= z;
|
||||
return make_pair(real(res), imag(res));
|
||||
}
|
||||
|
||||
pair<ld, ld> compute(ld x, ld y) { return compute(x,y,deg); }
|
||||
|
||||
void drawBoundary(int color) {
|
||||
#ifdef GL
|
||||
if(vid.usingGL) {
|
||||
qglcoords = 0;
|
||||
glcolor(color);
|
||||
int pts = 0;
|
||||
for(int r=0; r<2000; r++) {
|
||||
cld z = exp(cld(0, 2*M_PI * r / 2000.0));
|
||||
pair<ld,ld> z2 = compute(real(z), imag(z), deg);
|
||||
glcoords[pts][0] = vid.radius * z2.first;
|
||||
glcoords[pts][1] = vid.radius * z2.second;
|
||||
glcoords[pts][2] = vid.scrdist;
|
||||
pts++;
|
||||
}
|
||||
|
||||
glVertexPointer(3, GL_FLOAT, 0, glcoords);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glDrawArrays(GL_LINE_LOOP, 0, pts);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#ifndef MOBILE
|
||||
namespace spiral {
|
||||
|
||||
typedef long double ld;
|
||||
typedef complex<long double> cld;
|
||||
|
||||
int shiftx, shifty, velx, vely;
|
||||
|
||||
vector<pair<short, short> > quickmap;
|
||||
|
||||
int CX, CY, SX, SY, Yshift;
|
||||
|
||||
SDL_Surface *band, *out;
|
||||
|
||||
bool displayhelp = true;
|
||||
|
||||
void precompute() {
|
||||
|
||||
CX = band->w;
|
||||
CY = band->h;
|
||||
SX = out->w;
|
||||
SY = out->h;
|
||||
|
||||
ld k = -2*M_PI*M_PI / log(2.6180339);
|
||||
|
||||
// cld mnoznik = cld(0, M_PI) / cld(k, M_PI);
|
||||
|
||||
cld factor = cld(0, -CY/2/M_PI/M_PI) * cld(k, M_PI);
|
||||
|
||||
Yshift = CY * k / M_PI;
|
||||
|
||||
quickmap.clear();
|
||||
|
||||
double xc = ((SX | 1) - 2) / 2.;
|
||||
double yc = ((SY | 1) - 2) / 2.;
|
||||
|
||||
for(int y=0; y<SY; y++)
|
||||
for(int x=0; x<SX; x++) {
|
||||
cld z(x-xc, y-yc);
|
||||
cld z1 = log(z);
|
||||
|
||||
z1 = z1 * factor;
|
||||
|
||||
quickmap.push_back(make_pair(int(real(z1)) % CX, int(imag(z1))));
|
||||
}
|
||||
}
|
||||
|
||||
void draw() {
|
||||
int c = 0;
|
||||
for(int y=0; y<SY; y++) for(int x=0; x<SX; x++) {
|
||||
pair<short,short> p = quickmap[c++];
|
||||
int cx = p.first + shiftx;
|
||||
int cy = p.second + + shifty;
|
||||
int d = cy / CY;
|
||||
cy -= d * CY; cx -= d * Yshift;
|
||||
if(cy<0) cy += CY, cx += Yshift;
|
||||
cx %= CX; if(cx<0) cx += CX;
|
||||
qpixel(out, x, y) = qpixel(band, cx, cy);
|
||||
}
|
||||
}
|
||||
|
||||
void loop(SDL_Surface *_band) {
|
||||
|
||||
bool saveGL = vid.usingGL;
|
||||
if(saveGL) { vid.usingGL = false; setvideomode(); }
|
||||
|
||||
band = _band;
|
||||
out = s;
|
||||
precompute();
|
||||
shiftx = shifty = 0;
|
||||
velx=1; vely=1;
|
||||
bool dosave = false;
|
||||
while(true) {
|
||||
|
||||
time_t timer;
|
||||
timer = time(NULL);
|
||||
char buf[128];
|
||||
strftime(buf, 128, "spiral-%y%m%d-%H%M%S" IMAGEEXT, localtime(&timer));
|
||||
|
||||
SDL_LockSurface(s);
|
||||
draw();
|
||||
if(dosave) { dosave = false; IMAGESAVE(s, buf); }
|
||||
SDL_UnlockSurface(s);
|
||||
if(displayhelp) {
|
||||
displaystr(SX/2, vid.fsize*2, 0, vid.fsize, "arrows = navigate, ESC = return, h = hide help", 0xFFFFFF, 8);
|
||||
displaystr(SX/2, SY - vid.fsize*2, 0, vid.fsize, XLAT("s = save to " IMAGEEXT, buf), 0xFFFFFF, 8);
|
||||
}
|
||||
SDL_UpdateRect(s, 0, 0, 0, 0);
|
||||
shiftx += velx; shifty += vely;
|
||||
|
||||
SDL_Event event;
|
||||
while(SDL_PollEvent(&event)) switch (event.type) {
|
||||
case SDL_QUIT: case SDL_MOUSEBUTTONDOWN:
|
||||
goto breakloop;
|
||||
|
||||
case SDL_KEYDOWN: {
|
||||
int key = event.key.keysym.sym;
|
||||
// int uni = event.key.keysym.unicode;
|
||||
if(key == SDLK_RIGHT) velx++;
|
||||
if(key == SDLK_LEFT) velx--;
|
||||
if(key == SDLK_UP) vely++;
|
||||
if(key == SDLK_DOWN) vely--;
|
||||
if(key == SDLK_ESCAPE) goto breakloop;
|
||||
if(key == 'h') displayhelp = !displayhelp;
|
||||
if(key == 's') dosave = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
breakloop:
|
||||
quickmap.clear();
|
||||
if(saveGL) { vid.usingGL = true; setvideomode(); }
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
bool isbad(ld z) { return !isfinite(z) || fabs(z) > 1e6; }
|
||||
|
||||
namespace conformal {
|
||||
|
||||
int lastprogress;
|
||||
|
||||
void progress(string str) {
|
||||
#ifndef MOBILE
|
||||
int tick = SDL_GetTicks();
|
||||
if(tick > lastprogress + 250) {
|
||||
lastprogress = tick;
|
||||
msgs.clear();
|
||||
addMessage(str);
|
||||
drawscreen();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool on;
|
||||
vector<shmup::monster*> v;
|
||||
int llv;
|
||||
double phase;
|
||||
|
||||
vector<pair<cell*, eMonster> > killhistory;
|
||||
vector<pair<cell*, eItem> > findhistory;
|
||||
vector<cell*> movehistory;
|
||||
|
||||
bool includeHistory;
|
||||
double lvspeed = 1;
|
||||
int bandhalf = 200;
|
||||
int bandsegment = 16000;
|
||||
int rotation = 0;
|
||||
bool autoband = false;
|
||||
bool autobandhistory = false;
|
||||
bool dospiral = true;
|
||||
|
||||
void clear() {
|
||||
on = false;
|
||||
int N = size(v);
|
||||
for(int i=0; i<N; i++) delete v[i];
|
||||
v.resize(0);
|
||||
}
|
||||
|
||||
void create() {
|
||||
if(celldist(cwt.c) <= 7) {
|
||||
addMessage("Must go a distance from the starting point");
|
||||
return;
|
||||
}
|
||||
|
||||
on = true;
|
||||
cell *c = cwt.c;
|
||||
|
||||
for(int q=0; q<5; q++) {
|
||||
for(int i=0; i<c->type; i++)
|
||||
if(celldist(c->mov[i]) > celldist(c)) {
|
||||
c = c->mov[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while(true) {
|
||||
shmup::monster *m = new shmup::monster;
|
||||
m->at = Id;
|
||||
m->base = c;
|
||||
v.push_back(m);
|
||||
if(c == origin.c7) break;
|
||||
for(int i=0; i<c->type; i++)
|
||||
if(celldist(c->mov[i]) < celldist(c)) {
|
||||
c = c->mov[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
reverse(v.begin(), v.end());
|
||||
|
||||
int Q = size(v)-1;
|
||||
|
||||
for(int i=0; i<1000; i++) {
|
||||
progress(XLAT("Preparing the line (%1/1000)...", its(i+1)));
|
||||
|
||||
/*for(int j=1; j<Q; j++) {
|
||||
hyperpoint cur = v[j]->at * C0;
|
||||
printf("%4d/%3d. %p [%3d] %Lf %Lf %Lf\n", i, j, v[j]->base, celldist(v[j]->base), cur[0], cur[1], cur[2]);
|
||||
} */
|
||||
|
||||
for(int j=1; j<Q; j++) if((j^i)&1) {
|
||||
|
||||
virtualRebase(v[j], false);
|
||||
|
||||
hyperpoint prev = shmup::calc_relative_matrix(v[j-1]->base, v[j]->base->master) *
|
||||
v[j-1]->at * C0;
|
||||
|
||||
hyperpoint next = shmup::calc_relative_matrix(v[j+1]->base, v[j]->base->master) *
|
||||
v[j+1]->at * C0;
|
||||
|
||||
hyperpoint hmid = mid(prev, next);
|
||||
|
||||
v[j]->at = rgpushxto0(hmid);
|
||||
|
||||
v[j]->at = v[j]->at * rspintox(inverse(v[j]->at) * next);
|
||||
fixmatrix(v[j]->at);
|
||||
}
|
||||
}
|
||||
llv = ticks;
|
||||
phase = 0;
|
||||
}
|
||||
|
||||
void apply() {
|
||||
int t = ticks;
|
||||
phase += (t-llv) * lvspeed / 400.;
|
||||
llv = t;
|
||||
|
||||
int siz = size(v);
|
||||
|
||||
while(phase < 1) phase += siz - 2;
|
||||
while(phase >= siz-1) phase -= siz - 2;
|
||||
|
||||
int ph = int(phase);
|
||||
if(ph<1 || ph >= siz-1) return;
|
||||
|
||||
viewctr.h = v[ph]->base->master;
|
||||
viewctr.spin = 0;
|
||||
|
||||
View = inverse(v[ph]->at);
|
||||
|
||||
int j = ph;
|
||||
|
||||
hyperpoint now = v[j]->at * C0;
|
||||
|
||||
hyperpoint next = shmup::calc_relative_matrix(v[j+1]->base, v[j]->base->master) *
|
||||
v[j+1]->at * C0;
|
||||
|
||||
View = spin(M_PI/2 * rotation) * xpush(-(phase-ph) * hdist(now, next)) * View;
|
||||
playermoved = false;
|
||||
}
|
||||
|
||||
int measureLength() {
|
||||
int rad = vid.radius;
|
||||
vid.radius = bandhalf;
|
||||
|
||||
int tpixels = 0;
|
||||
int siz = size(v);
|
||||
|
||||
for(int j=1; j<siz-1; j++) {
|
||||
hyperpoint next =
|
||||
inverse(v[j]->at) *
|
||||
shmup::calc_relative_matrix(v[j+1]->base, v[j]->base->master) *
|
||||
v[j+1]->at * C0;
|
||||
|
||||
int x, y, shift;
|
||||
getcoord(next, x, y, shift);
|
||||
|
||||
tpixels += x-vid.xcenter;
|
||||
}
|
||||
|
||||
vid.radius = rad;
|
||||
return tpixels;
|
||||
}
|
||||
|
||||
void restore();
|
||||
void restoreBack();
|
||||
|
||||
#ifndef MOBILE
|
||||
void createImage(bool dospiral) {
|
||||
int segid = 1;
|
||||
inHighQual = true;
|
||||
if(includeHistory) restore();
|
||||
|
||||
int bandfull = 2*bandhalf;
|
||||
int len = measureLength();
|
||||
|
||||
time_t timer;
|
||||
timer = time(NULL);
|
||||
char timebuf[128];
|
||||
strftime(timebuf, 128, "%y%m%d-%H%M%S", localtime(&timer));
|
||||
|
||||
rotation = 0;
|
||||
|
||||
SDL_Surface *sav = s;
|
||||
|
||||
SDL_Surface *bbuf = SDL_CreateRGBSurface(SDL_SWSURFACE,bandfull,bandfull,32,0,0,0,0);
|
||||
s = bbuf;
|
||||
int ssr = sightrange; sightrange = 10; int sch = cheater; cheater = 0;
|
||||
videopar vid2 = vid; vid.xres = vid.yres = bandfull; vid.scale = 1;
|
||||
calcparam();
|
||||
vid.radius = bandhalf;
|
||||
|
||||
int xpos = 0;
|
||||
|
||||
SDL_Surface *band = SDL_CreateRGBSurface(SDL_SWSURFACE, min(len, bandsegment), bandfull,32,0,0,0,0);
|
||||
|
||||
if(!band) {
|
||||
addMessage("Could not create an image of that size.");
|
||||
}
|
||||
else {
|
||||
|
||||
int siz = size(v);
|
||||
for(int j=1; j<siz-1; j++) {
|
||||
SDL_Surface *buffer = s;
|
||||
emtype cm = cmode;
|
||||
s = sav;
|
||||
cmode = emProgress;
|
||||
|
||||
char buf[128];
|
||||
sprintf(buf, "#%03d", segid);
|
||||
|
||||
progress(s0 + buf + " ("+its(j)+"/"+its(siz-2)+")");
|
||||
calcparam();
|
||||
vid.radius = bandhalf;
|
||||
|
||||
cmode = cm;
|
||||
s = buffer;
|
||||
viewctr.h = v[j]->base->master;
|
||||
viewctr.spin = 0;
|
||||
View = inverse(v[j]->at);
|
||||
|
||||
SDL_FillRect(s, NULL, 0);
|
||||
bool ugl = vid.usingGL;
|
||||
vid.usingGL = false;
|
||||
drawfullmap();
|
||||
vid.usingGL = ugl;
|
||||
|
||||
hyperpoint next =
|
||||
inverse(v[j]->at) *
|
||||
shmup::calc_relative_matrix(v[j+1]->base, v[j]->base->master) *
|
||||
v[j+1]->at * C0;
|
||||
|
||||
int x, y, shift;
|
||||
getcoord(next, x, y, shift);
|
||||
|
||||
int bwidth = x-bandhalf;
|
||||
|
||||
drawsegment:
|
||||
|
||||
for(int cy=0; cy<bandfull; cy++) for(int cx=0; cx<bwidth; cx++)
|
||||
qpixel(band, xpos+cx, cy) = qpixel(s, bandhalf+cx, cy);
|
||||
|
||||
if(xpos+bwidth > bandsegment) {
|
||||
char buf[128];
|
||||
sprintf(buf, "bandmodel-%s-%03d" IMAGEEXT, timebuf, segid++);
|
||||
|
||||
if(dospiral) {
|
||||
swap(vid.xres, vid2.xres); swap(vid.yres, vid2.yres); s = sav;
|
||||
spiral::loop(band);
|
||||
swap(vid.xres, vid2.xres); swap(vid.yres, vid2.yres); s = bbuf;
|
||||
}
|
||||
|
||||
IMAGESAVE(band, buf);
|
||||
SDL_FreeSurface(band);
|
||||
len -= bandsegment; xpos -= bandsegment;
|
||||
band = SDL_CreateRGBSurface(SDL_SWSURFACE, min(len, bandsegment), bandfull,32,0,0,0,0);
|
||||
goto drawsegment;
|
||||
}
|
||||
xpos += bwidth;
|
||||
}
|
||||
}
|
||||
|
||||
char buf[128];
|
||||
sprintf(buf, "bandmodel-%s-%03d" IMAGEEXT, timebuf, segid++);
|
||||
IMAGESAVE(band, buf);
|
||||
SDL_FreeSurface(sav);
|
||||
s = sav; vid = vid2; sightrange = ssr; cheater = sch;
|
||||
if(includeHistory) restoreBack();
|
||||
if(dospiral) spiral::loop(band);
|
||||
addMessage(XLAT("Saved the band image as: ") + buf);
|
||||
SDL_FreeSurface(band);
|
||||
inHighQual = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
const char* directions[5][4] = {
|
||||
{ "right", "up", "left", "down" },
|
||||
{ "counterclockwise", "zoom out", "clockwise", "zoom in" },
|
||||
{ "left to right", "spin down", "right to left", "spin up" },
|
||||
{ "right", "up", "left", "down" },
|
||||
{ "right", "up", "left", "down" }
|
||||
};
|
||||
|
||||
const char *modelnames[5] = {
|
||||
"disk", "half-plane", "band", "polygonal", "polynomial"
|
||||
};
|
||||
|
||||
void show() {
|
||||
displayStat( 0, XLAT("conformal/history mode"), "", ' ');
|
||||
|
||||
displayStat( 2, XLAT("include history"), ONOFF(includeHistory), 'i');
|
||||
|
||||
displayStat( 4, XLAT("model used"), modelnames[pmodel], 'm');
|
||||
displayStat( 5, XLAT("rotation"), directions[pmodel][rotation&3], 'r');
|
||||
|
||||
if(pmodel == 4) {
|
||||
displayStat( 6, XLAT("coefficient"),
|
||||
fts4(real(polygonal::coef[polygonal::coefid]))+"+"+
|
||||
fts4(imag(polygonal::coef[polygonal::coefid]))+"i", 'x');
|
||||
displayStat( 7, XLAT("which coefficient"), its(polygonal::coefid), 'n');
|
||||
}
|
||||
|
||||
if(pmodel == 3) {
|
||||
displayStat( 6, XLAT("polygon sides"), its(polygonal::SI), 'x');
|
||||
displayStat( 7, XLAT("star factor"), fts(polygonal::STAR), 'y');
|
||||
displayStat( 8, XLAT("degree of the approximation"), its(polygonal::deg), 'n');
|
||||
}
|
||||
|
||||
displayStat(10, XLAT("prepare the line animation"), ONOFF(on), 'e');
|
||||
if(on) displayStat(11, XLAT("animation speed"), fts(lvspeed), 'a');
|
||||
|
||||
#ifndef MOBILE
|
||||
displayStat(13, XLAT("render bands automatically"), ONOFF(autoband), 'o');
|
||||
if(autoband)
|
||||
displayStat(14, XLAT("include history when auto-rendering"), ONOFF(autobandhistory), 'j');
|
||||
|
||||
bool renderable = on && pmodel == 2;
|
||||
if(renderable || autoband) {
|
||||
displayStat(15, XLAT("band width"), its(bandhalf*2), 'd');
|
||||
displayStat(16, XLAT("length of a segment"), its(bandsegment), 's');
|
||||
displayStat(17, XLAT("spiral on rendering"), ONOFF(dospiral), 'g');
|
||||
if(renderable)
|
||||
displayStat(18, XLAT("render now (length: %1)", its(measureLength())), "", 'f');
|
||||
}
|
||||
#endif
|
||||
|
||||
displayStat(20, XLAT("exit this menu"), "", 'q');
|
||||
mouseovers = XLAT("see http://www.roguetemple.com/z/hyper/conformal.php");
|
||||
}
|
||||
|
||||
void handleKey(int uni, int sym) {
|
||||
|
||||
if(uni == 'e') {
|
||||
if(on) clear();
|
||||
else {
|
||||
if(canmove && !cheater) {
|
||||
addMessage("Enable cheat mode or GAME OVER to use this");
|
||||
return;
|
||||
}
|
||||
if(canmove && cheater) cheater++;
|
||||
create();
|
||||
}
|
||||
}
|
||||
else if(uni == 'o')
|
||||
autoband = !autoband;
|
||||
else if(uni == 'm') {
|
||||
pmodel++;
|
||||
pmodel %= 5;
|
||||
if(pmodel == 3) polygonal::solve();
|
||||
/* if(pmodel && vid.usingGL) {
|
||||
addMessage(XLAT("openGL mode disabled"));
|
||||
vid.usingGL = false;
|
||||
setvideomode();
|
||||
} */
|
||||
}
|
||||
else if(sym == 'x' && pmodel == 3) { polygonal::SI += (shiftmul > 0 ? 1:-1); polygonal::solve(); }
|
||||
else if(sym == 'y' && pmodel == 3) { polygonal::STAR += shiftmul/10; polygonal::solve(); }
|
||||
else if(sym == 'n' && pmodel == 3) { polygonal::deg += (shiftmul>0?1:-1);
|
||||
if(polygonal::deg < 2) polygonal::deg = 2;
|
||||
if(polygonal::deg > MSI-1) polygonal::deg = MSI-1;
|
||||
}
|
||||
else if(sym == 'x' && pmodel == 4) {
|
||||
int ci = polygonal::coefid;
|
||||
polygonal::coef[polygonal::coefid] += polygonal::cld(shiftmul/100/ci/ci, 0);
|
||||
}
|
||||
else if(sym == 'y' && pmodel == 4) {
|
||||
int ci = polygonal::coefid;
|
||||
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 == 'a') { lvspeed += shiftmul/10; }
|
||||
else if(sym == 'd') { bandhalf += int(5 * shiftmul); if(bandhalf < 5) bandhalf = 5; }
|
||||
else if(sym == 's') { bandsegment += int(500 * shiftmul); if(bandsegment < 500) bandsegment = 500; }
|
||||
else if(sym == 'g') { dospiral = !dospiral; }
|
||||
#ifndef MOBILE
|
||||
else if(uni == 'f' && pmodel == 2 && on) createImage(dospiral);
|
||||
#endif
|
||||
else if(sym == 'q' || sym == SDLK_ESCAPE || sym == '0') { cmode = emNormal; }
|
||||
else if(sym == 'i') {
|
||||
if(canmove && !cheater) {
|
||||
addMessage("Enable cheat mode or GAME OVER to use this");
|
||||
return;
|
||||
}
|
||||
if(canmove && cheater) cheater++;
|
||||
includeHistory = !includeHistory;
|
||||
}
|
||||
else if(sym == 'j') {
|
||||
autobandhistory = !autobandhistory;
|
||||
}
|
||||
}
|
||||
|
||||
void restore() {
|
||||
sval++;
|
||||
for(int i=0; i<size(movehistory); i++)
|
||||
movehistory[i]->aitmp = sval;
|
||||
sval++;
|
||||
int sk = size(killhistory);
|
||||
for(int i=0; i<sk; i++) {
|
||||
eMonster m = killhistory[i].second;
|
||||
killhistory[i].second = killhistory[i].first->monst;
|
||||
killhistory[i].first->monst = m;
|
||||
killhistory[i].first->aitmp = sval;
|
||||
}
|
||||
int si = size(findhistory);
|
||||
for(int i=0; i<si; i++) {
|
||||
eItem m = findhistory[i].second;
|
||||
findhistory[i].second = findhistory[i].first->item;
|
||||
findhistory[i].first->item = m;
|
||||
findhistory[i].first->aitmp = sval;
|
||||
}
|
||||
}
|
||||
|
||||
void restoreBack() {
|
||||
int sk = size(killhistory);
|
||||
for(int i=sk-1; i>=0; i--) {
|
||||
eMonster m = killhistory[i].second;
|
||||
killhistory[i].second = killhistory[i].first->monst;
|
||||
killhistory[i].first->monst = m;
|
||||
}
|
||||
int si = size(findhistory);
|
||||
for(int i=si-1; i>=0; i--) {
|
||||
eItem m = findhistory[i].second;
|
||||
findhistory[i].second = findhistory[i].first->item;
|
||||
findhistory[i].first->item = m;
|
||||
}
|
||||
}
|
||||
|
||||
void renderAutoband() {
|
||||
#ifndef MOBILE
|
||||
if(celldist(cwt.c) <= 7) return;
|
||||
if(!autoband) return;
|
||||
int spm = pmodel;
|
||||
bool ih = includeHistory;
|
||||
includeHistory = autobandhistory;
|
||||
pmodel = 2;
|
||||
create();
|
||||
createImage(dospiral);
|
||||
clear();
|
||||
pmodel = spm;
|
||||
includeHistory = ih;
|
||||
#endif
|
||||
}
|
||||
}
|
555
flags.cpp
Normal file
555
flags.cpp
Normal file
@ -0,0 +1,555 @@
|
||||
// Hyperbolic Rogue
|
||||
// implementation of various simple flags for lands, items, monsters, and walls
|
||||
|
||||
// Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details
|
||||
|
||||
bool isIcyLand(eLand l) {
|
||||
return l == laIce || l == laCocytus;
|
||||
}
|
||||
|
||||
bool isIcyLand(cell *c) {
|
||||
return isIcyLand(c->land);
|
||||
}
|
||||
|
||||
bool isGravityLand(eLand l) {
|
||||
return l == laIvoryTower || l == laEndorian;
|
||||
}
|
||||
|
||||
// watery
|
||||
|
||||
bool isWatery(cell *c) {
|
||||
return c->wall == waCamelotMoat || c->wall == waSea || c->wall == waLake;
|
||||
}
|
||||
|
||||
bool isChasmy(cell *c) {
|
||||
return c->wall == waChasm || c->wall == waSulphur || c->wall == waSulphurC;
|
||||
}
|
||||
|
||||
bool isWateryOrBoat(cell *c) {
|
||||
return isWatery(c) || c->wall == waBoat;
|
||||
}
|
||||
|
||||
bool isNoFlight(cell *c) {
|
||||
return
|
||||
c->wall == waBoat || c->wall == waVineHalfA || c->wall == waVineHalfB ||
|
||||
c->wall == waStrandedBoat || c->wall == waTrunk;
|
||||
}
|
||||
|
||||
bool boatStrandable(cell *c) {
|
||||
return c->wall == waNone && (c->land == laLivefjord || c->land == laOcean);
|
||||
}
|
||||
|
||||
// monster/wall types
|
||||
|
||||
bool isFire(cell *w) {
|
||||
return w->wall == waFire || w->wall == waPartialFire || w->wall == waEternalFire;
|
||||
}
|
||||
|
||||
bool isThumper(eWall w) {
|
||||
return w == waThumperOff || w == waThumperOn;
|
||||
}
|
||||
|
||||
bool isThumper(cell *c) {
|
||||
return isThumper(c->wall);
|
||||
}
|
||||
|
||||
bool isActivable(cell *c) {
|
||||
return c->wall == waThumperOff || c->wall == waBonfireOff;
|
||||
}
|
||||
|
||||
bool hasTimeout(cell *c) {
|
||||
return c->wall == waThumperOn || c->wall == waFire || c->wall == waPartialFire ||
|
||||
c->wall == waTempWall || c->wall == waTempFloor || c->wall == waTempBridge;
|
||||
}
|
||||
|
||||
bool isMimic(eMonster m) {
|
||||
return m == moMirror || m == moMirage;
|
||||
}
|
||||
|
||||
bool isMimic(cell *c) {
|
||||
return isMimic(c->monst);
|
||||
}
|
||||
|
||||
bool isPrincess(eMonster m) {
|
||||
return
|
||||
m == moPrincess || m == moPrincessMoved ||
|
||||
m == moPrincessArmed || m == moPrincessArmedMoved;
|
||||
}
|
||||
|
||||
bool isGolemOrKnight(eMonster m) {
|
||||
return
|
||||
m == moGolem || m == moGolemMoved ||
|
||||
m == moKnight || m == moKnightMoved ||
|
||||
m == moTameBomberbird || m == moTameBomberbirdMoved ||
|
||||
m == moMouse || m == moMouseMoved ||
|
||||
m == moFriendlyGhost ||
|
||||
isPrincess(m);
|
||||
}
|
||||
|
||||
bool isGolemOrKnight(cell *c) { return isGolemOrKnight(c->monst); }
|
||||
|
||||
bool isNonliving(eMonster m) {
|
||||
return
|
||||
m == moMirage || m == moMirror || m == moGolem || m == moGolemMoved ||
|
||||
m == moZombie || m == moGhost || m == moShadow || m == moSkeleton ||
|
||||
m == moEvilGolem || m == moIllusion || m == moEarthElemental ||
|
||||
m == moWaterElemental;
|
||||
}
|
||||
|
||||
bool isMetalBeast(eMonster m) {
|
||||
return m == moMetalBeast || m == moMetalBeast2;
|
||||
}
|
||||
|
||||
bool isStunnable(eMonster m) {
|
||||
return m == moPalace || m == moFatGuard || m == moSkeleton || isPrincess(m) ||
|
||||
isMetalBeast(m) || m == moTortoise || isDragon(m);
|
||||
}
|
||||
|
||||
bool hasHitpoints(eMonster m) {
|
||||
return m == moPalace || m == moFatGuard || m == moVizier || isPrincess(m);
|
||||
}
|
||||
|
||||
bool isMountable(eMonster m) {
|
||||
return isWorm(m);
|
||||
}
|
||||
|
||||
bool isFriendly(eMonster m) {
|
||||
return isMimic(m) || isGolemOrKnight(m) || m == moIllusion;
|
||||
}
|
||||
|
||||
bool isFriendly(cell *c) {
|
||||
if(items[itOrbDomination] && c->monst && sameMonster(c, cwt.c)) return true;
|
||||
return isFriendly(c->monst);
|
||||
}
|
||||
|
||||
bool isBug(eMonster m) {
|
||||
return m >= moBug0 && m < moBug0+BUGCOLORS;
|
||||
}
|
||||
|
||||
bool isBug(cell *c) {
|
||||
return isBug(c->monst);
|
||||
}
|
||||
|
||||
bool isFriendlyOrBug(cell *c) { // or killable discord!
|
||||
// do not attack the stunned Princess
|
||||
if(isPrincess(c->monst) && c->stuntime) return false;
|
||||
return isFriendly(c) || isBug(c) || (c->monst && markOrb(itOrbDiscord) && !c->stuntime);
|
||||
}
|
||||
|
||||
bool isIvy(eMonster m) {
|
||||
return m == moIvyRoot || m == moIvyHead || m == moIvyBranch || m == moIvyWait ||
|
||||
m == moIvyNext || m == moIvyDead;
|
||||
}
|
||||
|
||||
bool isIvy(cell *c) {
|
||||
return isIvy(c->monst);
|
||||
}
|
||||
|
||||
bool isMonsterPart(eMonster m) {
|
||||
return m == moMutant || (isIvy(m) && m != moIvyRoot);
|
||||
}
|
||||
|
||||
bool isMutantIvy(eMonster m) {
|
||||
return m == moMutant;
|
||||
}
|
||||
|
||||
bool isBulletType(eMonster m) {
|
||||
return
|
||||
m == moBullet || m == moFlailBullet ||
|
||||
m == moFireball || m == moTongue || m == moAirball;
|
||||
}
|
||||
|
||||
bool isMutantIvy(cell *c) { return isMutantIvy(c->monst); }
|
||||
|
||||
bool isDemon(eMonster m) {
|
||||
return m == moLesser || m == moLesserM || m == moGreater || m == moGreaterM;
|
||||
}
|
||||
|
||||
bool isDemon(cell *c) {
|
||||
return isDemon(c->monst);
|
||||
}
|
||||
|
||||
bool isWormHead(eMonster m) {
|
||||
return m == moWorm || m == moTentacle || m == moHexSnake || m == moDragonHead;
|
||||
}
|
||||
|
||||
bool isWorm(eMonster m) {
|
||||
return m == moWorm || m == moWormtail || m == moWormwait ||
|
||||
m == moTentacle || m == moTentacletail || m == moTentaclewait ||
|
||||
m == moTentacleEscaping || m == moTentacleGhost ||
|
||||
m == moHexSnake || m == moHexSnakeTail ||
|
||||
m == moDragonHead || m == moDragonTail;
|
||||
}
|
||||
|
||||
bool isWorm(cell *c) {
|
||||
return isWorm(c->monst);
|
||||
}
|
||||
|
||||
bool isWitch(eMonster m) {
|
||||
// evil golems don't count
|
||||
return m >= moWitch && m < moWitch+NUMWITCH-1;
|
||||
}
|
||||
|
||||
bool isOnCIsland(cell *c) {
|
||||
return (c->wall == waCIsland || c->wall == waCTree || c->wall == waCIsland2);
|
||||
}
|
||||
|
||||
bool isGhostable(eMonster m) {
|
||||
return m && !isFriendly(m) && !isIvy(m) && !isMultitile(m) && !isMutantIvy(m);
|
||||
}
|
||||
|
||||
bool cellUnstable(cell *c) {
|
||||
return (c->land == laMotion && c->wall == waNone) || c->wall == waTrapdoor;
|
||||
}
|
||||
|
||||
bool cellUnstableOrChasm(cell *c) {
|
||||
return
|
||||
(c->land == laMotion && c->wall == waNone) ||
|
||||
c->wall == waChasm || c->wall == waTrapdoor;
|
||||
}
|
||||
|
||||
bool cellHalfvine(cell *c) {
|
||||
return c->wall == waVineHalfA || c->wall == waVineHalfB;
|
||||
}
|
||||
|
||||
bool isWarped(eLand l) {
|
||||
return l == laGridCoast || l == laGridSea;
|
||||
}
|
||||
|
||||
bool isElementalShard(eItem i) {
|
||||
return
|
||||
i == itFireShard || i == itAirShard || i == itEarthShard || i == itWaterShard;
|
||||
}
|
||||
|
||||
eMonster elementalOf(eLand l) {
|
||||
if(l == laEFire) return moFireElemental;
|
||||
if(l == laEWater) return moWaterElemental;
|
||||
if(l == laEAir) return moAirElemental;
|
||||
if(l == laEEarth) return moEarthElemental;
|
||||
return moNone;
|
||||
}
|
||||
|
||||
int itemclass(eItem i) {
|
||||
if(i == 0) return -1;
|
||||
if(i < itKey || i == itFernFlower ||
|
||||
i == itWine || i == itSilver || i == itEmerald || i == itRoyalJelly || i == itPower ||
|
||||
i == itGrimoire || i == itPirate || i == itRedGem || i == itBombEgg ||
|
||||
i == itCoast || i == itWhirlpool || i == itPalace || i == itFjord ||
|
||||
i == itElemental || i == itZebra || i == itEdge ||
|
||||
i == itBounty || i == itFulgurite || i == itMutant || i == itLotus || i == itMutant2 ||
|
||||
i == itWindstone || i == itCoral || i == itRose ||
|
||||
i == itBabyTortoise || i == itDragon || i == itApple)
|
||||
return IC_TREASURE;
|
||||
if(i == itKey || i == itOrbYendor || i == itGreenStone || i == itHolyGrail || i == itCompass ||
|
||||
i == itSavedPrincess || isElementalShard(i) || i == itRevolver || i == itStrongWind)
|
||||
return IC_OTHER;
|
||||
return IC_ORB;
|
||||
}
|
||||
|
||||
bool isAlch(eWall w) {
|
||||
return w == waFloorA || w == waFloorB;
|
||||
}
|
||||
|
||||
bool isAlch(cell *c) { return isAlch(c->wall); }
|
||||
|
||||
bool isAlchAny(eWall w) {
|
||||
return w == waFloorA || w == waFloorB || w == waFloorC || w == waFloorD;
|
||||
}
|
||||
|
||||
bool isAlchAny(cell *c) { return isAlchAny(c->wall); }
|
||||
|
||||
bool realred(eWall w) {
|
||||
return w == waRed1 || w == waRed2 || w == waRed3;
|
||||
}
|
||||
|
||||
int snakelevel(eWall w) {
|
||||
if(w == waRed1 || w == waDeadfloor2 || w == waRubble || w == waGargoyleFloor ||
|
||||
w == waGargoyleBridge || w == waTempFloor || w == waTempBridge)
|
||||
return 1;
|
||||
if(w == waRed2) return 2;
|
||||
if(w == waRed3) return 3;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int snakelevel(cell *c) { return snakelevel(c->wall); }
|
||||
|
||||
bool isWall(cell *w) {
|
||||
if(w->wall == waNone || isAlchAny(w) ||
|
||||
w->wall == waCavefloor || w->wall == waFrozenLake || w->wall == waVineHalfA ||
|
||||
w->wall == waVineHalfB || w->wall == waDeadfloor || w->wall == waDeadfloor2 ||
|
||||
w->wall == waRubble || w->wall == waGargoyleFloor || w->wall == waGargoyleBridge ||
|
||||
w->wall == waTempFloor || w->wall == waTempBridge ||
|
||||
w->wall == waBoat || w->wall == waCIsland || w->wall == waCIsland2 ||
|
||||
w->wall == waRed1 || w->wall == waRed2 || w->wall == waRed3 ||
|
||||
w->wall == waMineUnknown || w->wall == waMineMine || w->wall == waMineOpen ||
|
||||
w->wall == waStrandedBoat || w->wall == waOpenGate || w->wall == waClosePlate ||
|
||||
w->wall == waOpenPlate || w->wall == waTrapdoor || w->wall == waGiantRug ||
|
||||
w->wall == waLadder || w->wall == waTrunk || w->wall == waSolidBranch ||
|
||||
w->wall == waWeakBranch || w->wall == waCanopy)
|
||||
return false;
|
||||
if(isWatery(w) || isChasmy(w) || isFire(w)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isAngryBird(eMonster m) {
|
||||
return m == moEagle || m == moAlbatross || m == moBomberbird || m == moGargoyle ||
|
||||
m == moWindCrow || m == moKestrel || m == moNighthawk;
|
||||
}
|
||||
|
||||
bool isBird(eMonster m) {
|
||||
return isAngryBird(m) || m == moTameBomberbird || m == moTameBomberbirdMoved;
|
||||
}
|
||||
|
||||
bool normalMover(eMonster m) {
|
||||
return
|
||||
m == moYeti || m == moRanger || m == moGoblin || m == moTroll || m == moDesertman ||
|
||||
m == moMonkey || m == moZombie || m == moNecromancer || m == moCultist ||
|
||||
m == moLesser || m == moGreater || m == moRunDog || m == moPyroCultist ||
|
||||
m == moFireFairy || m == moCrystalSage || m == moHedge ||
|
||||
m == moVineBeast || m == moLancer || m == moFlailer ||
|
||||
m == moMiner || m == moDarkTroll ||
|
||||
(playerInPower() && (
|
||||
(isWitch(m) && m != moWitchGhost && m != moWitchWinter) || m == moEvilGolem
|
||||
)) ||
|
||||
m == moRedTroll ||
|
||||
m == moPalace || m == moFatGuard || m == moSkeleton || m == moVizier ||
|
||||
m == moFjordTroll || m == moStormTroll || m == moForestTroll ||
|
||||
m == moEdgeMonkey ||
|
||||
m == moFireElemental || m == moOrangeDog ||
|
||||
isMetalBeast(m) ||
|
||||
m == moOutlaw || m == moRedFox || m == moFalsePrincess || m == moRoseLady ||
|
||||
m == moRoseBeauty || m == moWolf ||
|
||||
m == moTortoise || m == moLemur;
|
||||
}
|
||||
|
||||
// from-to
|
||||
|
||||
bool isGhost(eMonster m) {
|
||||
return m == moGhost || m == moTentacleGhost || m == moFriendlyGhost;
|
||||
}
|
||||
|
||||
bool isGhostMover(eMonster m) {
|
||||
return m == moGhost || m == moGreaterShark || m == moTentacleGhost ||
|
||||
(playerInPower() && (m == moWitchGhost || m == moWitchWinter));
|
||||
}
|
||||
|
||||
bool isShark(eMonster m) {
|
||||
return m == moShark || m == moCShark || m == moGreaterShark;
|
||||
}
|
||||
|
||||
bool isSlimeMover(eMonster m) {
|
||||
return
|
||||
m == moSlime || m == moSeep || m == moShark ||
|
||||
m == moVineSpirit || m == moCShark || m == moParrot;
|
||||
}
|
||||
|
||||
bool isBlowableMonster(eMonster m) {
|
||||
return m && !(
|
||||
isWorm(m) || isIvy(m) || isMutantIvy(m) || isSlimeMover(m) ||
|
||||
m == moGhost || m == moGreaterShark ||
|
||||
m == moWaterElemental || m == moWitchGhost || isMimic(m)
|
||||
);
|
||||
}
|
||||
|
||||
bool isMultitile(eMonster m) {
|
||||
return isWorm(m) || isIvy(m) || isMutantIvy(m);
|
||||
}
|
||||
|
||||
bool isSlimeMover(cell *c) {
|
||||
return isSlimeMover(c->monst);
|
||||
}
|
||||
|
||||
int slimegroup(cell *c) {
|
||||
if(c->wall == waCavewall || c->wall == waDeadwall)
|
||||
return 1;
|
||||
if(isWatery(c))
|
||||
return 2;
|
||||
if(c->wall == waFloorA)
|
||||
return 3;
|
||||
if(c->wall == waFloorB)
|
||||
return 4;
|
||||
if(c->wall == waVinePlant || cellHalfvine(c))
|
||||
return 5;
|
||||
if(c->wall == waCTree)
|
||||
return 6;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool isLeader(eMonster m) {
|
||||
return m == moPirate || m == moCultistLeader || m == moViking || m == moRatling || m == moRatlingAvenger;
|
||||
}
|
||||
|
||||
bool isFlying(eMonster m) {
|
||||
return isBird(m) || isGhost(m) || m == moAirElemental || isDragon(m) ||
|
||||
(isFriendly(m) && checkOrb(m, itOrbGhost));
|
||||
}
|
||||
|
||||
bool survivesChasm(eMonster m) {
|
||||
return isFlying(m);
|
||||
}
|
||||
|
||||
bool ignoresPlates(eMonster m) {
|
||||
return m == moMouse || isFlying(m);
|
||||
}
|
||||
|
||||
bool itemBurns(eItem it) {
|
||||
return it && it != itOrbDragon && it != itOrbFire && it != itDragon;
|
||||
}
|
||||
|
||||
bool attackThruVine(eMonster m) {
|
||||
return m == moGhost || m == moVineSpirit || m == moFriendlyGhost || m == moTentacleGhost;
|
||||
}
|
||||
|
||||
bool attackNonAdjacent(eMonster m) {
|
||||
return m == moGhost || m == moFriendlyGhost || m == moTentacleGhost;
|
||||
}
|
||||
|
||||
bool isInactiveEnemy(cell *w, eMonster forwho) {
|
||||
if(w->monst == moWormtail || w->monst == moWormwait || w->monst == moTentacletail || w->monst == moTentaclewait || w->monst == moHexSnakeTail)
|
||||
return true;
|
||||
if(w->monst == moLesserM || w->monst == moGreaterM)
|
||||
return true;
|
||||
if(w->monst == moIvyRoot || w->monst == moIvyWait || w->monst == moIvyNext || w->monst == moIvyDead)
|
||||
return true;
|
||||
if(w->monst && ((forwho == moPlayer) ? realstuntime(w) : realstuntime(w) > 1) && !isFriendly(w))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// forpc = true (for PC), false (for golems)
|
||||
bool isActiveEnemy(cell *w, eMonster forwho) {
|
||||
if(((forwho == moPlayer) ? realstuntime(w) : realstuntime(w) > 1))
|
||||
return false;
|
||||
if(w->monst == moNone) return false;
|
||||
if(isFriendly(w)) return false;
|
||||
if(isInactiveEnemy(w, forwho)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isUnarmed(eMonster m) {
|
||||
return
|
||||
m == moMouse || m == moMouseMoved || m == moPrincess || m == moPrincessMoved ||
|
||||
m == moCrystalSage;
|
||||
}
|
||||
|
||||
bool isArmedEnemy(cell *w, eMonster forwho) {
|
||||
return w->monst != moCrystalSage && isActiveEnemy(w, forwho);
|
||||
}
|
||||
|
||||
bool isHive(eLand l) {
|
||||
return l == laHive;
|
||||
}
|
||||
|
||||
bool isIcyWall(cell *c) {
|
||||
return c->wall == waNone || c->wall == waIcewall || c->wall == waFrozenLake || c->wall == waLake;
|
||||
}
|
||||
|
||||
bool eternalFire(cell *c) {
|
||||
return c->land == laDryForest || c->land == laPower || c->land == laMinefield ||
|
||||
c->land == laEFire || c->land == laElementalWall;
|
||||
}
|
||||
|
||||
bool isCyclic(eLand l) {
|
||||
return
|
||||
l == laWhirlpool || l == laTemple || l == laCamelot || l == laClearing;
|
||||
}
|
||||
|
||||
bool haveRangedOrb() {
|
||||
return
|
||||
items[itOrbPsi] || items[itOrbDragon] || items[itOrbTeleport] ||
|
||||
items[itOrbIllusion] || items[itOrbTelekinesis] || items[itOrbAir] ||
|
||||
items[itOrbFrog] || items[itOrbSummon] || items[itOrbMatter] ||
|
||||
items[itRevolver] || items[itOrbStunning] || items[itStrongWind] ||
|
||||
items[itOrbDomination];
|
||||
}
|
||||
|
||||
bool isOffensiveOrb(eItem it) {
|
||||
return it == itOrbLightning || it == itOrbFlash || it == itOrbThorns ||
|
||||
it == itOrbDragon || it == itOrbStunning ||
|
||||
it == itOrbFreedom || it == itOrbPsi;
|
||||
}
|
||||
|
||||
bool isRangedOrb(eItem i) {
|
||||
return i == itOrbPsi || i == itOrbDragon || i == itOrbTeleport || i == itOrbIllusion ||
|
||||
i == itOrbTelekinesis || i == itOrbAir || i == itOrbFrog ||
|
||||
i == itOrbSummon || i == itOrbMatter || i == itRevolver || i == itOrbStunning ||
|
||||
i == itOrbDomination;
|
||||
}
|
||||
|
||||
bool isProtectionOrb(eItem i) {
|
||||
return i == itOrbWinter || i == itOrbShield || i == itOrbInvis || i == itOrbShell;
|
||||
}
|
||||
|
||||
bool isEmpathyOrb(eItem i) {
|
||||
return
|
||||
i == itOrbFire || i == itOrbDigging || i == itOrbWinter ||
|
||||
i == itOrbUndeath || i == itOrbSpeed || i == itOrbShield ||
|
||||
i == itOrbGhost || i == itOrbInvis || i == itOrbThorns ||
|
||||
i == itOrbWater;
|
||||
}
|
||||
|
||||
bool isUtilityOrb(eItem i) {
|
||||
return i == itOrbSpeed || i == itOrbDigging ||
|
||||
i == itOrbSafety || i == itOrbTeleport || i == itOrbGhost ||
|
||||
i == itOrbPreserve || i == itOrbTelekinesis ||
|
||||
i == itOrbSummon || i == itOrbLuck || i == itOrbEnergy;
|
||||
}
|
||||
|
||||
bool isFriendOrb(eItem i) {
|
||||
return i == itOrbLife || i == itOrbFriend || i == itOrbDiscord || i == itOrbLove ||
|
||||
i == itOrbEmpathy || i == itOrbUndeath;
|
||||
}
|
||||
|
||||
bool isFriendlyGhost(eMonster m) {
|
||||
return m == moFriendlyGhost || (markEmpathy(itOrbGhost) && isFriendly(m));
|
||||
}
|
||||
|
||||
bool isDragon(eMonster m) { return m == moDragonHead || m == moDragonTail; }
|
||||
|
||||
bool survivesWater(eMonster m) {
|
||||
return
|
||||
m == moShark || m == moGreaterShark || m == moCShark ||
|
||||
isGhost(m) || m == moWitchGhost ||
|
||||
isBird(m) || m == moWaterElemental || m == moAirElemental ||
|
||||
isWorm(m) || isIvy(m) || isDragon(m) ||
|
||||
m == moTortoise; // Tortoises and Ivies survive, but don't go through water
|
||||
}
|
||||
|
||||
bool survivesFire(eMonster m) {
|
||||
return
|
||||
isGhost(m) || m == moWitchWinter || m == moWitchGhost ||
|
||||
m == moBomberbird || m == moTameBomberbird || m == moTameBomberbirdMoved ||
|
||||
(isFriendly(m) && markOrb(itOrbWinter)) || isWorm(m) || m == moFireElemental ||
|
||||
isDragon(m);
|
||||
}
|
||||
|
||||
bool survivesMine(eMonster m) {
|
||||
return isFlying(m);
|
||||
}
|
||||
|
||||
bool survivesWall(eMonster m) {
|
||||
return isGhost(m);
|
||||
}
|
||||
|
||||
bool survivesThorns(eMonster m) {
|
||||
return isGhost(m) || m == moSkeleton;
|
||||
}
|
||||
|
||||
bool survivesFall(eMonster m) {
|
||||
return isBird(m) || m == moAirElemental || m == moSkeleton || isDragon(m);
|
||||
}
|
||||
|
||||
bool isThorny(eWall w) { return w == waRose; }
|
||||
|
||||
bool checkOrb(eMonster m1, eItem orb) {
|
||||
if(m1 == moPlayer) return markOrb(orb);
|
||||
if(isFriendly(m1)) return markEmpathy(orb);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ignoresSmell(eMonster m) {
|
||||
return
|
||||
m == moHexSnake || isIvy(m) || isMutantIvy(m) || isGhostMover(m) || isSlimeMover(m) ||
|
||||
m == moRoseLady || checkOrb(m, itOrbSkunk) || checkOrb(m, itOrbGhost) || checkOrb(m, itOrbShield);
|
||||
}
|
||||
|
26
geometry.cpp
26
geometry.cpp
@ -1,18 +1,31 @@
|
||||
// Hyperbolic Rogue
|
||||
// Copyright (C) 2011-2012 Zeno Rogue, see 'hyper.cpp' for details
|
||||
|
||||
// geometrical constants
|
||||
|
||||
ld tessf, crossf, hexf;
|
||||
// Copyright (C) 2011-2012 Zeno Rogue, see 'hyper.cpp' for details
|
||||
|
||||
|
||||
ld tessf, crossf, hexf, hcrossf;
|
||||
|
||||
// tessf: distance from heptagon center to another heptagon center
|
||||
// hexf: distance from heptagon center to heptagon vertex
|
||||
// crossf: distance from heptagon center to adjacent hexagon center
|
||||
|
||||
#define ALPHA (M_PI*2/7)
|
||||
|
||||
hyperpoint Crad[42];
|
||||
|
||||
transmatrix heptmove[7], hexmove[7];
|
||||
transmatrix invheptmove[7], invhexmove[7];
|
||||
|
||||
// the results are:
|
||||
// hexf = 0.378077 hcrossf = 0.620672 tessf = 1.090550
|
||||
|
||||
void precalc() {
|
||||
|
||||
DEBB(DF_INIT, (debugfile,"precalc\n"));
|
||||
|
||||
if(euclid) return;
|
||||
|
||||
ld fmin = 1, fmax = 2;
|
||||
|
||||
for(int p=0; p<100; p++) {
|
||||
@ -30,7 +43,8 @@ void precalc() {
|
||||
ld v1 = intval(H, C0), v2 = intval(H, xpush(tessf) * C0);
|
||||
if(v1 < v2) fmin = f; else fmax = f;
|
||||
}
|
||||
crossf = fmin;
|
||||
hcrossf = fmin;
|
||||
crossf = purehepta ? tessf : hcrossf;
|
||||
|
||||
fmin = 0, fmax = tessf;
|
||||
for(int p=0; p<100; p++) {
|
||||
@ -43,6 +57,8 @@ void precalc() {
|
||||
}
|
||||
hexf = fmin;
|
||||
|
||||
// printf("hexf = %.6Lf cross = %.6Lf tessf = %.6Lf\n", hexf, crossf, tessf);
|
||||
|
||||
for(int i=0; i<42; i++)
|
||||
Crad[i] = spin(2*M_PI*i/42) * xpush(.4) * C0;
|
||||
for(int d=0; d<7; d++)
|
||||
@ -50,6 +66,8 @@ void precalc() {
|
||||
for(int d=0; d<7; d++)
|
||||
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<7; d++) invhexmove[d] = inverse(hexmove[d]);
|
||||
}
|
||||
|
||||
transmatrix ddi(ld dir, ld dist) {
|
||||
|
19
heptagon.cpp
19
heptagon.cpp
@ -15,6 +15,8 @@ struct heptagon;
|
||||
struct cell;
|
||||
cell *newCell(int type, heptagon *master);
|
||||
|
||||
#define CDATA
|
||||
|
||||
struct heptagon {
|
||||
// automaton state
|
||||
hstate s : 8;
|
||||
@ -31,6 +33,11 @@ struct heptagon {
|
||||
short fiftyval;
|
||||
// zebra generator (1B actually)
|
||||
short zebraval;
|
||||
#ifdef CDATA
|
||||
// evolution data
|
||||
short rval0, rval1;
|
||||
struct cdata *cdata;
|
||||
#endif
|
||||
// central cell
|
||||
cell *c7;
|
||||
// associated generator of alternate structure, for Camelot and horocycles
|
||||
@ -73,6 +80,9 @@ heptagon *buildHeptagon(heptagon *parent, int d, hstate s, int pard = 0) {
|
||||
h->c7 = newCell(7, h);
|
||||
h->emeraldval = emerald_heptagon(parent->emeraldval, d);
|
||||
h->zebraval = zebra_heptagon(parent->zebraval, d);
|
||||
#ifdef CDATA
|
||||
h->rval0 = h->rval1 = 0; h->cdata = NULL;
|
||||
#endif
|
||||
if(parent == &origin)
|
||||
h->fiftyval = fiftytable[0][d];
|
||||
else
|
||||
@ -86,14 +96,15 @@ heptagon *buildHeptagon(heptagon *parent, int d, hstate s, int pard = 0) {
|
||||
//generateEmeraldval(parent);
|
||||
//generateEmeraldval(h);
|
||||
if(pard == 0) {
|
||||
if(parent->s == hsOrigin) h->distance = 2;
|
||||
if(purehepta) h->distance = parent->distance + 1;
|
||||
else if(parent->s == hsOrigin) h->distance = 2;
|
||||
else if(h->spin[0] == 5)
|
||||
h->distance = parent->distance + 1;
|
||||
else if(h->spin[0] == 4 && h->move[0]->s == hsB)
|
||||
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);
|
||||
return h;
|
||||
}
|
||||
|
||||
@ -107,10 +118,12 @@ void addSpin(heptagon *h, int d, heptagon *from, int rot, int spin) {
|
||||
//generateEmeraldval(h->move[d]); generateEmeraldval(h);
|
||||
}
|
||||
|
||||
extern int hrand(int);
|
||||
|
||||
heptagon *createStep(heptagon *h, int d) {
|
||||
d = fixrot(d);
|
||||
if(h->s != hsOrigin && !h->move[0]) {
|
||||
buildHeptagon(h, 0, hsA, 4);
|
||||
buildHeptagon(h, 0, hsA, 3 + hrand(2));
|
||||
}
|
||||
if(h->move[d]) return h->move[d];
|
||||
if(h->s == hsOrigin) {
|
||||
|
139
hyper.cpp
139
hyper.cpp
@ -15,13 +15,19 @@
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
// disable for the Android version
|
||||
#ifdef LOCAL
|
||||
#define CDATA
|
||||
#endif
|
||||
|
||||
#define VER "8.3j"
|
||||
#define VERNUM 8310
|
||||
#define VERNUM_HEX 0x8310
|
||||
|
||||
#define ISANDROID 0
|
||||
#define ISMOBILE 0
|
||||
#define ISIOS 0
|
||||
#define VER "7.4h"
|
||||
#define VERNUM 7480
|
||||
#define VERNUM_HEX 0x7480
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <SDL/SDL.h>
|
||||
|
||||
@ -38,6 +44,9 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
FILE *debugfile;
|
||||
int debugflags;
|
||||
|
||||
const char *scorefile = "hyperrogue.log";
|
||||
const char *conffile = "hyperrogue.ini";
|
||||
|
||||
@ -47,25 +56,26 @@ string picfile = "hyperrogue.pic";
|
||||
const char *loadlevel = NULL;
|
||||
const char *musicfile = "";
|
||||
|
||||
typedef long double ld;
|
||||
#ifdef LINUX
|
||||
#include <sys/resource.h>
|
||||
|
||||
template<class T> int size(T& x) {return x.size(); }
|
||||
string its(int i) { char buf[64]; sprintf(buf, "%d", i); 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(i);
|
||||
return llts(i/10) + its(i%10);
|
||||
}
|
||||
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 itsh(int i) {static char buf[16]; sprintf(buf, "%03X", i); return buf; }
|
||||
void moreStack() {
|
||||
const rlim_t kStackSize = 1 << 28; // 28;
|
||||
struct rlimit rl;
|
||||
int result;
|
||||
|
||||
#undef DEBT
|
||||
void DEBT(const char *buf) {
|
||||
printf("%4d %s\n", SDL_GetTicks(), buf);
|
||||
result = getrlimit(RLIMIT_STACK, &rl);
|
||||
if(result == 0) {
|
||||
if(rl.rlim_cur < kStackSize) {
|
||||
// rl.rlim_cur = 1 << 19; // kStackSize;
|
||||
result = setrlimit(RLIMIT_STACK, &rl);
|
||||
if (result != 0) {
|
||||
fprintf(stderr, "setrlimit returned result = %d\n", result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
string s0;
|
||||
void addMessage(string s, char spamtype = 0);
|
||||
@ -86,7 +96,14 @@ string commandline;
|
||||
#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"
|
||||
|
||||
@ -98,6 +115,8 @@ string commandline;
|
||||
#include "mapeditor.cpp"
|
||||
#endif
|
||||
|
||||
#include "netgen.cpp"
|
||||
|
||||
#include "graph.cpp"
|
||||
|
||||
#include "achievement.cpp"
|
||||
@ -106,15 +125,17 @@ string commandline;
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
printf("HyperRogue by Zeno Rogue <zeno@attnam.com>, version "VER"\n");
|
||||
#ifdef LINUX
|
||||
moreStack();
|
||||
#endif
|
||||
|
||||
printf("HyperRogue by Zeno Rogue <zeno@attnam.com>, version " VER "\n");
|
||||
|
||||
#ifndef NOLICENSE
|
||||
printf("released under GNU General Public License version 2 and thus\n");
|
||||
printf("comes with absolutely no warranty; see COPYING for details\n");
|
||||
#endif
|
||||
|
||||
achievement_init();
|
||||
|
||||
// printf("cell size = %d\n", int(sizeof(cell)));
|
||||
srand(time(NULL));
|
||||
shrand(time(NULL));
|
||||
@ -177,11 +198,43 @@ int main(int argc, char **argv) {
|
||||
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], "-P") == 0) { commandline += "P"; }
|
||||
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
|
||||
else if(strcmp(argv[i], "-ch") == 0) { autocheat = true; }
|
||||
else if(strcmp(argv[i], "-Y") == 0) {
|
||||
yendor::on = true;
|
||||
yendor::challenge = atoi(argv[i+1]);
|
||||
i++;
|
||||
}
|
||||
else if(strcmp(argv[i], "-r") == 0) {
|
||||
i++;
|
||||
sscanf(argv[i], "%dx%dx%d", &clWidth, &clHeight, &clFont);
|
||||
@ -203,13 +256,25 @@ int main(int argc, char **argv) {
|
||||
printf(" -f, -w - start in the fullscreen or windowed mode\n");
|
||||
printf(" -e, -a, -p - start in the Escher, ASCII, or Plain mode\n");
|
||||
printf(" -r WxHxF - use the given resolution and font size\n");
|
||||
printf(" -o - switch the OpenGL mode on or off\n");
|
||||
printf(" -o - switch the OpenGL mode\n");
|
||||
printf(" -o0 - switch the OpenGL mode off\n");
|
||||
printf(" -o1 - switch the OpenGL mode on\n");
|
||||
printf(" -W LAND - start in the given land (cheat)\n");
|
||||
printf(" -ch - auto-enable cheat mode\n");
|
||||
printf(" -E - switch Euclidean\n");
|
||||
printf(" -S - switch Shmup\n");
|
||||
printf(" -P - switch Shmup number of players\n");
|
||||
printf(" -Pn - switch Shmup number of players (n=1..4)\n");
|
||||
printf(" -H - switch Hardcore\n");
|
||||
printf(" -T - switch Tactical\n");
|
||||
printf(" -7 - switch heptagonal mode\n");
|
||||
printf(" -C - switch Chaos mode\n");
|
||||
printf(" -R - switch Random Pattern\n");
|
||||
printf(" -Y id - switch 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");
|
||||
exit(0);
|
||||
}
|
||||
else {
|
||||
@ -218,30 +283,22 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
}
|
||||
|
||||
/* transmatrix T;
|
||||
for(int a=0; a<3; a++) for(int b=0; b<3; b++)
|
||||
T[a][b] = (10 + a*a + b*4 + (b==1?a:0)) / 20.;
|
||||
display(T);
|
||||
transmatrix T2 = inverse(T);
|
||||
display(T2);
|
||||
display(T*T2); */
|
||||
achievement_init();
|
||||
|
||||
eLand f = firstland;
|
||||
|
||||
// initlanguage();
|
||||
initgraph();
|
||||
loadsave();
|
||||
precalc();
|
||||
resetGL();
|
||||
initcells();
|
||||
/* for(int uu=9; uu >= 0; uu--) {
|
||||
printf("uu=%d\n", uu);
|
||||
initgame(uu);
|
||||
restartGame();
|
||||
} */
|
||||
|
||||
#ifdef BUILDZEBRA
|
||||
firstland = laCanvas;
|
||||
shmup::on = false;
|
||||
#endif
|
||||
shmup::safety = safety;
|
||||
initgame();
|
||||
#ifdef BUILDZEBRA
|
||||
zebraPattern();
|
||||
@ -265,13 +322,17 @@ int main(int argc, char **argv) {
|
||||
|
||||
if(loadlevel) mapstream::loadMap(loadlevel);
|
||||
|
||||
#ifdef LOCAL
|
||||
// river();
|
||||
autoplay();
|
||||
#endif
|
||||
mainloop();
|
||||
|
||||
achievement_final(!items[itOrbSafety]);
|
||||
|
||||
saveStats();
|
||||
int msec = SDL_GetTicks() - t1;
|
||||
printf("frame : %f ms (%f fps)\n", 1.*msec/frames, 1000.*frames/msec);
|
||||
DEBB(DF_INIT, (debugfile, "frame : %f ms (%f fps)\n", 1.*msec/frames, 1000.*frames/msec));
|
||||
offscreen.clear();
|
||||
clearMemory();
|
||||
cleargraph();
|
||||
|
440
hyper.h
440
hyper.h
@ -11,6 +11,10 @@
|
||||
#undef GFX
|
||||
#endif
|
||||
|
||||
#ifdef MAC
|
||||
#define NOPNG
|
||||
#endif
|
||||
|
||||
// scale the Euclidean
|
||||
#define EUCSCALE 2.3
|
||||
|
||||
@ -23,6 +27,15 @@
|
||||
|
||||
// achievements
|
||||
|
||||
#define LB_YENDOR_CHALLENGE 40
|
||||
#define LB_PURE_TACTICS 41
|
||||
#define NUMLEADER 57
|
||||
#define LB_PURE_TACTICS_SHMUP 49
|
||||
#define LB_PURE_TACTICS_COOP 50
|
||||
|
||||
extern int currentscore[NUMLEADER];
|
||||
extern int syncstate;
|
||||
|
||||
// initialize the achievement system.
|
||||
void achievement_init();
|
||||
|
||||
@ -30,8 +43,9 @@ void achievement_init();
|
||||
void achievement_close();
|
||||
|
||||
// gain the achievement with the given name.
|
||||
// Only awarded if euclid equals euclideanAchievement.
|
||||
void achievement_gain(const char*, bool euclideanAchievement = false, bool shmupAchievement = false);
|
||||
// flags: 'e' - for Euclidean, 's' - for Shmup, '7' - for heptagonal
|
||||
// Only awarded if special modes are matched exactly.
|
||||
void achievement_gain(const char*, char flags = 0);
|
||||
|
||||
// gain the achievement for collecting a number of 'it'.
|
||||
void achievement_collection(eItem it, int prevgold, int newgold);
|
||||
@ -54,11 +68,33 @@ void achievement_final(bool really);
|
||||
// display the last achievement gained.
|
||||
void achievement_display();
|
||||
|
||||
// call the achievement callbacks
|
||||
void achievement_pump();
|
||||
|
||||
// achievements received this game
|
||||
vector<string> achievementsReceived;
|
||||
|
||||
// game forward declarations
|
||||
|
||||
bool mirrorkill(cell *c);
|
||||
bool isNeighbor(cell *c1, cell *c2);
|
||||
void checkTide(cell *c);
|
||||
namespace anticheat { extern bool tampered; }
|
||||
int numplayers();
|
||||
void removeIvy(cell *c);
|
||||
bool cellEdgeUnstable(cell *c);
|
||||
int coastvalEdge(cell *c);
|
||||
typedef int cellfunction(cell*);
|
||||
int towerval(cell *c, cellfunction* cf = &coastvalEdge);
|
||||
#define HRANDMAX 0x7FFFFFFF
|
||||
int hrandpos(); // 0 to HRANDMAX
|
||||
void restartGame(char switchWhat = 0);
|
||||
int landMultiplier(eLand l);
|
||||
eItem treasureType(eLand l);
|
||||
void buildBarrier(cell *c, int d, eLand l = laNone);
|
||||
void extendBarrier(cell *c);
|
||||
bool buildBarrier4(cell *c, int d, int mode, eLand ll, eLand lr);
|
||||
void makeEmpty(cell *c);
|
||||
bool isCrossroads(eLand l);
|
||||
enum orbAction { roMouse, roKeyboard, roCheck, roMouseForce };
|
||||
void moveItem (cell *from, cell *to, bool activateYendor);
|
||||
@ -68,24 +104,36 @@ void killMonster(cell *c);
|
||||
void toggleGates(cell *ct, eWall type, int rad);
|
||||
bool destroyHalfvine(cell *c, eWall newwall = waNone, int tval = 6);
|
||||
void buildCrossroads2(cell *c);
|
||||
void createBugArmy(cell *c);
|
||||
bool isHaunted(eLand l);
|
||||
heptagon *createAlternateMap(cell *c, int rad, hstate firststate, int special=0);
|
||||
void generateAlts(heptagon *h);
|
||||
void whirlGenerate(cell *wto);
|
||||
void setdist(cell *c, int d, cell *from);
|
||||
void checkOnYendorPath();
|
||||
void killThePlayerAt(eMonster m, cell *c);
|
||||
void killThePlayerAt(eMonster m, cell *c, int flags);
|
||||
bool notDippingFor(eItem i);
|
||||
bool collectItem(cell *c2, bool telekinesis = false);
|
||||
void castLightningBolt(struct cellwalker lig);
|
||||
bool movepcto(int d, int subdir = 1, bool checkonly = false);
|
||||
void stabbingAttack(cell *mf, cell *mt, eMonster who = moNone);
|
||||
void stabbingAttack(cell *mf, cell *mt, eMonster who);
|
||||
bool earthMove(cell *from, int dir);
|
||||
void messageKill(eMonster killer, eMonster victim);
|
||||
void moveMonster(cell *ct, cell *cf);
|
||||
int palaceHP();
|
||||
void placeLocalOrbs(cell *c);
|
||||
int elementalKills();
|
||||
bool elementalUnlocked();
|
||||
bool isMultitile(eMonster m);
|
||||
void checkFreedom(cell *cf);
|
||||
int rosedist(cell *c);
|
||||
bool canPushStatueOn(cell *c);
|
||||
|
||||
void createMirrors(cell *c, int dir, eMonster type);
|
||||
void createMirages(cell *c, int dir, eMonster type);
|
||||
namespace hive { void createBugArmy(cell *c); }
|
||||
namespace whirlpool { void generate(cell *wto); }
|
||||
namespace whirlwind { void generate(cell *wto); }
|
||||
namespace mirror {
|
||||
void createMirrors(cell *c, int dir, eMonster type);
|
||||
void createMirages(cell *c, int dir, eMonster type);
|
||||
}
|
||||
|
||||
int neighborId(cell *c1, cell *c2);
|
||||
|
||||
@ -96,6 +144,15 @@ void activateActiv(cell *c, bool msg);
|
||||
|
||||
// shmup
|
||||
|
||||
struct charstyle {
|
||||
int charid, skincolor, haircolor, dresscolor, swordcolor, dresscolor2;
|
||||
};
|
||||
|
||||
string csname(charstyle& cs);
|
||||
void initcs(charstyle& cs);
|
||||
void savecs(FILE *f, charstyle& cs);
|
||||
void loadcs(FILE *f, charstyle& cs);
|
||||
|
||||
namespace shmup {
|
||||
extern bool on;
|
||||
extern bool safety;
|
||||
@ -110,6 +167,8 @@ namespace shmup {
|
||||
void killThePlayer(eMonster m);
|
||||
void killThePlayer(eMonster m, int i);
|
||||
void visibleFor(int t);
|
||||
bool verifyTeleport();
|
||||
bool dragonbreath(cell *dragon);
|
||||
|
||||
void shmupDrownPlayers(cell *c);
|
||||
|
||||
@ -130,10 +189,14 @@ namespace shmup {
|
||||
char axeaction[8][MAXAXE];
|
||||
char hataction[8][MAXHAT][4];
|
||||
};
|
||||
|
||||
charstyle scs[4];
|
||||
}
|
||||
|
||||
// graph
|
||||
|
||||
extern int msgscroll;
|
||||
|
||||
void showMissionScreen();
|
||||
|
||||
void restartGraph();
|
||||
@ -142,6 +205,7 @@ void resetmusic();
|
||||
void cleargraphmemory();
|
||||
|
||||
void drawFlash(cell* c);
|
||||
void drawBigFlash(cell* c);
|
||||
|
||||
void drawLightning();
|
||||
void drawSafety();
|
||||
@ -150,6 +214,7 @@ void movepckeydir(int);
|
||||
|
||||
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 displayColorButton(int x, int y, const string& name, int key, int align, int rad, int color, int color2 = 0);
|
||||
@ -164,6 +229,21 @@ bool outofmap(hyperpoint h);
|
||||
void getcoord(const hyperpoint& H, int& x, int& y, int &shift);
|
||||
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 fixcolor(int& col);
|
||||
int displaydir(cell *c, int d);
|
||||
hyperpoint gethyper(ld x, ld y);
|
||||
void resetview(); extern cell *lcenterover; extern heptspin viewctr;
|
||||
#ifndef MOBILE
|
||||
int& qpixel(SDL_Surface *surf, int x, int y);
|
||||
#endif
|
||||
void drawthemap();
|
||||
void drawfullmap();
|
||||
bool displaystr(int x, int y, int shift, int size, const char *str, int color, int align);
|
||||
|
||||
extern int darken;
|
||||
void setvideomode();
|
||||
void calcparam();
|
||||
|
||||
string ifMousing(string key, string s);
|
||||
|
||||
@ -185,7 +265,8 @@ extern int lalpha;
|
||||
struct videopar {
|
||||
ld scale, eye, alpha, aspeed;
|
||||
bool full;
|
||||
bool goteyes;
|
||||
bool goteyes; // for rendering
|
||||
bool goteyes2; // for choosing colors
|
||||
bool quick;
|
||||
bool darkhepta;
|
||||
bool shifttarget;
|
||||
@ -213,14 +294,16 @@ struct videopar {
|
||||
int joyvalue, joyvalue2, joypanthreshold;
|
||||
float joypanspeed;
|
||||
|
||||
bool female;
|
||||
charstyle cs;
|
||||
|
||||
bool samegender; // same gender for the Princess?
|
||||
int language;
|
||||
|
||||
int skincolor, haircolor, dresscolor, swordcolor;
|
||||
int killreduction;
|
||||
int killreduction, itemreduction, portreduction;
|
||||
|
||||
shmup::config scfg;
|
||||
|
||||
bool steamscore;
|
||||
};
|
||||
|
||||
extern videopar vid;
|
||||
@ -234,7 +317,12 @@ enum emtype {emNormal, emHelp,
|
||||
emShmupConfig,
|
||||
emMapEditor,
|
||||
emPatternPicker,
|
||||
emOverview
|
||||
emOverview,
|
||||
emNetgen,
|
||||
emYendor, emTactic, emRugConfig,
|
||||
emConformal,
|
||||
emProgress,
|
||||
emCheatMenu
|
||||
};
|
||||
|
||||
extern emtype cmode, lastmode;
|
||||
@ -243,18 +331,342 @@ extern transmatrix View; // current rotation, relative to viewctr
|
||||
extern transmatrix cwtV; // player-relative view
|
||||
|
||||
extern cell *mouseover, *mouseover2;
|
||||
extern string mouseovers;
|
||||
|
||||
extern struct SDL_Surface *s;
|
||||
|
||||
namespace mapeditor {
|
||||
extern bool drawplayer;
|
||||
extern char whichPattern;
|
||||
extern char whichPattern, whichShape;
|
||||
int generateCanvas(cell *c);
|
||||
void clearModelCells();
|
||||
void applyModelcell(cell *c);
|
||||
int realpattern(cell *c);
|
||||
int patterndir(cell *c, char w = whichPattern);
|
||||
extern cell *drawcell;
|
||||
}
|
||||
|
||||
namespace rug {
|
||||
extern bool rugged;
|
||||
void init();
|
||||
void close();
|
||||
void actDraw();
|
||||
void buildVertexInfo(cell *c, transmatrix V);
|
||||
}
|
||||
|
||||
#define HASLINEVIEW
|
||||
namespace conformal {
|
||||
extern bool on;
|
||||
extern vector<pair<cell*, eMonster> > killhistory;
|
||||
extern vector<pair<cell*, eItem> > findhistory;
|
||||
extern vector<cell*> movehistory;
|
||||
extern bool includeHistory;
|
||||
|
||||
void create();
|
||||
void clear();
|
||||
void handleKey();
|
||||
void show();
|
||||
void apply();
|
||||
void renderAutoband();
|
||||
}
|
||||
|
||||
namespace polygonal {
|
||||
extern int SI;
|
||||
extern double STAR;
|
||||
void solve();
|
||||
typedef long double ld;
|
||||
pair<ld, ld> compute(ld x, ld y);
|
||||
}
|
||||
|
||||
void selectEyeGL(int ed);
|
||||
void selectEyeMask(int ed);
|
||||
extern int ticks;
|
||||
void setGLProjection();
|
||||
|
||||
#ifdef LOCAL
|
||||
extern void process_local_stats();
|
||||
bool localDescribe();
|
||||
void localDrawMap();
|
||||
extern bool localKill(shmup::monster *m);
|
||||
#endif
|
||||
|
||||
// passable flags
|
||||
|
||||
#define P_MONSTER (1<<0) // can move through monsters
|
||||
#define P_MIRROR (1<<1) // can move through mirrors
|
||||
#define P_REVDIR (1<<2) // reverse direction movement
|
||||
#define P_WIND (1<<3) // can move against the wind
|
||||
#define P_GRAVITY (1<<4) // can move against the gravity
|
||||
#define P_ISPLAYER (1<<5) // player-only moves (like the Round Table jump)
|
||||
#define P_ONPLAYER (1<<6) // always can step on the player
|
||||
#define P_FLYING (1<<7) // is flying
|
||||
#define P_BULLET (1<<8) // bullet can fly through more things
|
||||
#define P_JUMP1 (1<<10) // first part of a jump
|
||||
#define P_JUMP2 (1<<11) // second part of a jump
|
||||
#define P_TELE (1<<12) // teleport onto
|
||||
#define P_BLOW (1<<13) // Orb of Air -- blow, or push
|
||||
#define P_AETHER (1<<14) // aethereal
|
||||
#define P_FISH (1<<15) // swimming
|
||||
#define P_WINTER (1<<16) // fire resistant
|
||||
#define P_USEBOAT (1<<17) // can use boat
|
||||
#define P_NOAETHER (1<<18) // disable AETHER
|
||||
#define P_FRIENDSWAP (1<<19) // can move on friends (to swap with tem)
|
||||
#define P_ISFRIEND (1<<20) // is a friend (can use Empathy + Winter/Aether/Fish combo)
|
||||
#define P_LEADER (1<<21) // can push statues and use boats
|
||||
#define P_MARKWATER (1<<22) // mark Orb of Water as used
|
||||
#define P_EARTHELEM (1<<23) // Earth Elemental
|
||||
#define P_WATERELEM (1<<24) // Water Elemental
|
||||
#define P_IGNORE37 (1<<25) // ignore the triheptagonal board
|
||||
#define P_CHAIN (1<<26) // for chaining moves with boats
|
||||
#define P_DEADLY (1<<27) // suicide moves allowed
|
||||
#define P_ROSE (1<<28) // rose smell
|
||||
#define P_CLIMBUP (1<<29) // allow climbing up
|
||||
#define P_CLIMBDOWN (1<<30) // allow climbing down
|
||||
|
||||
bool passable(cell *w, cell *from, int flags);
|
||||
|
||||
bool isElemental(eLand l);
|
||||
int coastval(cell *c, eLand base);
|
||||
int getHauntedDepth(cell *c);
|
||||
eLand randomElementalLand();
|
||||
extern eLand euland[65536];
|
||||
bool notDippingForExtra(eItem i, eItem x);
|
||||
void placePrizeOrb(cell *c);
|
||||
int hivehard();
|
||||
eMonster randomHyperbug();
|
||||
void wandering();
|
||||
bool isSealand(eLand l);
|
||||
int newRoundTableRadius();
|
||||
bool grailWasFound(cell *c);
|
||||
extern bool buggyGeneration;
|
||||
int buildIvy(cell *c, int children, int minleaf);
|
||||
int celldistAltRelative(cell *c);
|
||||
int roundTableRadius(cell *c);
|
||||
cell *chosenDown(cell *c, int which, int bonus, cellfunction* cf = &coastvalEdge);
|
||||
eLand pickLandRPM(eLand old);
|
||||
bool bearsCamelot(eLand l);
|
||||
|
||||
extern bool safety;
|
||||
|
||||
#define SAGEMELT .1
|
||||
#define TEMPLE_EACH 6
|
||||
#define PT(x, y) (tactic::on ? (y) : (x))
|
||||
#define ROCKSNAKELENGTH 50
|
||||
#define PUREHARDCORE_LEVEL 10
|
||||
#define PRIZEMUL 7
|
||||
|
||||
#define INF 9999
|
||||
#define INFD 20
|
||||
#define BARLEV ((ISANDROID||ISIOS||purehepta)?9:10)
|
||||
#define BUGLEV 15
|
||||
// #define BARLEV 9
|
||||
|
||||
bool isKillable(cell *c);
|
||||
bool isKillableSomehow(cell *c);
|
||||
|
||||
extern vector<cell*> mirrors, mirrors2;
|
||||
bool isAlchAny(eWall w);
|
||||
bool isAlchAny(cell *c);
|
||||
|
||||
#define YDIST 101
|
||||
#define MODECODES 38
|
||||
|
||||
extern cellwalker cwt; // player character position
|
||||
extern int sval;
|
||||
|
||||
extern int items[ittypes], hiitems[MODECODES][ittypes], kills[motypes], explore[10], exploreland[10][landtypes], landcount[landtypes];
|
||||
|
||||
extern eLand firstland, euclidland;
|
||||
bool pseudohept(cell *c);
|
||||
bool pureHardcore();
|
||||
extern int cheater;
|
||||
int airdist(cell *c);
|
||||
bool eq(short a, short b);
|
||||
extern vector<cell*> dcal; // queue for cpdist
|
||||
bool isPlayerOn(cell *c);
|
||||
bool isFriendly(eMonster m);
|
||||
bool isFriendly(cell *c);
|
||||
bool isChild(cell *w, cell *killed); // is w killed if killed is killed?
|
||||
|
||||
int gold();
|
||||
int tkills();
|
||||
bool hellUnlocked();
|
||||
|
||||
bool markOrb(eItem it); // mark the orb as 'used', return true if exists
|
||||
bool markEmpathy(eItem it); // mark both the given orb and Empathy as 'used', return true if exists
|
||||
|
||||
bool isMimic(eMonster m);
|
||||
bool isMimic(cell *c);
|
||||
void killWithMessage(cell *c, bool orStun = false, eMonster killer = moNone);
|
||||
|
||||
bool isWorm(eMonster m);
|
||||
bool isWorm(cell *c);
|
||||
void empathyMove(cell *c, cell *cto, int dir);
|
||||
bool isIvy(eMonster m);
|
||||
bool isIvy(cell *c);
|
||||
|
||||
#define GUNRANGE 3
|
||||
|
||||
// 0 = basic treasure, 1 = something else, 2 = power orb
|
||||
#define IC_TREASURE 0
|
||||
#define IC_OTHER 1
|
||||
#define IC_ORB 2
|
||||
|
||||
bool playerInPower();
|
||||
void activateFlash();
|
||||
void activateLightning();
|
||||
bool markOrb(eItem it);
|
||||
bool markOrb2(eItem it);
|
||||
void drainOrb(eItem it, int target = 0);
|
||||
void useupOrb(eItem it, int qty);
|
||||
|
||||
void initgame();
|
||||
bool haveRangedTarget();
|
||||
eItem targetRangedOrb(cell *c, orbAction a);
|
||||
void reduceOrbPowers();
|
||||
int realstuntime(cell *c);
|
||||
|
||||
extern bool invismove, invisfish;
|
||||
bool attackingForbidden(cell *c, cell *c2);
|
||||
void killOrStunMonster(cell *c2);
|
||||
|
||||
extern vector<cell*> offscreen; // offscreen cells to take care off
|
||||
|
||||
void useup(cell *c); // useup thumpers/bonfires
|
||||
cell *playerpos(int i);
|
||||
|
||||
bool makeflame(cell *c, int timeout, bool checkonly);
|
||||
void bfs();
|
||||
bool isPlayerInBoatOn(cell *c);
|
||||
extern bool showoff;
|
||||
extern int lastexplore;
|
||||
extern int truelotus;
|
||||
extern eLand lastland;
|
||||
extern time_t timerstart;
|
||||
extern bool timerstopped;
|
||||
bool againstRose(cell *cfrom, cell *cto);
|
||||
bool withRose(cell *cfrom, cell *cto);
|
||||
|
||||
// loops
|
||||
|
||||
#define fakecellloop(ct) for(cell *ct = (cell*)1; ct; ct=NULL)
|
||||
|
||||
#define forCellIdAll(ct, i, cf) fakecellloop(ct) for(int i=0; i<(cf)->type && (ct=(cf)->mov[i],true); i++)
|
||||
#define forCellIdCM(ct, i, cf) fakecellloop(ct) for(int i=0; i<(cf)->type && (ct=createMov((cf),i),true); i++)
|
||||
#define forCellIdEx(ct, i, cf) forCellIdAll(ct,i,cf) if(ct)
|
||||
|
||||
#define forCellEx(ct, cf) forCellIdEx(ct,forCellEx ## __LINE__,cf)
|
||||
#define forCellCM(ct, cf) forCellIdCM(ct,forCellCM ## __LINE__,cf)
|
||||
#define forCellAll(ct, cf) forCellIdCM(ct,forCellAll ## __LINE__,cf)
|
||||
|
||||
// canAttack/moveval flags
|
||||
|
||||
#define AF_TOUGH (1<<0) // tough attacks: Hyperbugs
|
||||
#define AF_MAGIC (1<<1) // magical attacks: Flash
|
||||
#define AF_STAB (1<<2) // stabbing attacks (usually ignored except Hedgehogs)
|
||||
#define AF_LANCE (1<<3) // lance attacks (used by Lancers)
|
||||
#define AF_ONLY_ENEMY (1<<4) // only say YES if it is an enemy
|
||||
#define AF_ONLY_FRIEND (1<<5) // only say YES if it is a friend
|
||||
#define AF_ONLY_FBUG (1<<6) // only say YES if it is a bug_or friend
|
||||
#define AF_BACK (1<<7) // backward attacks (ignored except Viziers and Flailers)
|
||||
#define AF_APPROACH (1<<8) // approach attacks (ignored except Lancers)
|
||||
#define AF_IGNORE_UNARMED (1<<9) // ignore the UNARMED flag
|
||||
#define AF_NOSHIELD (1<<10) // ignore the shielded status
|
||||
#define AF_GETPLAYER (1<<11) // check for player (replace m2 with moPlayer for player position)
|
||||
#define AF_GUN (1<<12) // revolver attack
|
||||
#define AF_FAST (1<<13) // fast attack
|
||||
#define AF_EAT (1<<17) // eating attacks from Worm-likes
|
||||
|
||||
#define MF_NOATTACKS (1<<14) // don't do any attacks
|
||||
#define MF_PATHDIST (1<<15) // consider pathdist for moveval
|
||||
#define MF_ONLYEAGLE (1<<16) // do this only for Eagles
|
||||
#define MF_MOUNT (1<<18) // don't do
|
||||
#define MF_NOFRIEND (1<<19) // don't do it for friends
|
||||
|
||||
bool canAttack(cell *c1, eMonster m1, cell *c2, eMonster m2, int flags);
|
||||
|
||||
extern bool chaosmode;
|
||||
extern bool chaosUnlocked;
|
||||
extern bool chaosAchieved;
|
||||
bool isTechnicalLand(eLand l);
|
||||
int getGhostcount();
|
||||
|
||||
void raiseBuggyGeneration(cell *c, const char *s);
|
||||
void verifyMutantAround(cell *c);
|
||||
|
||||
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
|
||||
#define NOPNG
|
||||
#endif
|
||||
|
||||
// #define NOPNG
|
||||
|
||||
#ifdef NOPNG
|
||||
#define IMAGEEXT ".bmp"
|
||||
#define IMAGESAVE SDL_SaveBMP
|
||||
#else
|
||||
#include "savepng.h"
|
||||
#define IMAGEEXT ".png"
|
||||
|
||||
void IMAGESAVE(SDL_Surface *s, const char *fname);
|
||||
#endif
|
||||
|
||||
void drawscreen();
|
||||
|
||||
void buildAirmap();
|
||||
|
||||
// currently works for worms only
|
||||
bool sameMonster(cell *c1, cell *c2);
|
||||
cell *wormhead(cell *c);
|
||||
eMonster getMount();
|
||||
|
||||
bool isDragon(eMonster m);
|
||||
|
||||
// for some reason I need this to compile under OSX
|
||||
|
||||
#ifdef MAC
|
||||
extern "C" { void *_Unwind_Resume = 0; }
|
||||
#endif
|
||||
|
||||
extern bool autocheat;
|
||||
extern bool inHighQual;
|
||||
|
||||
void mountmove(cell *c, int spin, bool fp);
|
||||
|
||||
template<class T> struct dynamicval {
|
||||
T& where;
|
||||
T backup;
|
||||
dynamicval(T& wh, T val) : where(wh) { backup = wh; wh = val; }
|
||||
~dynamicval() { where = backup; }
|
||||
};
|
||||
|
||||
namespace stalemate {
|
||||
eMonster who;
|
||||
cell *moveto;
|
||||
cell *killed;
|
||||
cell *pushto;
|
||||
cell *comefrom;
|
||||
bool nextturn;
|
||||
|
||||
bool isKilled(cell *c);
|
||||
};
|
||||
|
||||
extern int turncount;
|
||||
|
||||
bool reduceOrbPower(eItem it, int cap);
|
||||
bool checkOrb(eMonster m1, eItem orb);
|
||||
|
8
hyper.rc
8
hyper.rc
@ -1,8 +1,8 @@
|
||||
id ICON "hr-icon.ico"
|
||||
|
||||
1 VERSIONINFO
|
||||
FILEVERSION 8,1,7,0
|
||||
PRODUCTVERSION 8,1,7,0
|
||||
FILEVERSION 8,3,0,10
|
||||
PRODUCTVERSION 8,3,0,10
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
@ -10,12 +10,12 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Zeno Rogue"
|
||||
VALUE "FileDescription", "A roguelike in non-euclidean space"
|
||||
VALUE "FileVersion", "81g"
|
||||
VALUE "FileVersion", "83"
|
||||
VALUE "InternalName", "hyper"
|
||||
VALUE "LegalCopyright", "Zeno Rogue"
|
||||
VALUE "OriginalFilename", "hyper.exe"
|
||||
VALUE "ProductName", "HyperRogue"
|
||||
VALUE "ProductVersion", "8.1g"
|
||||
VALUE "ProductVersion", "8.3j"
|
||||
END
|
||||
END
|
||||
|
||||
|
@ -1,16 +1,42 @@
|
||||
// Hyperbolic Rogue
|
||||
// Copyright (C) 2011-2012 Zeno Rogue, see 'hyper.cpp' for details
|
||||
|
||||
// basic utility functions
|
||||
|
||||
#ifdef MOBILE
|
||||
typedef double ld;
|
||||
#else
|
||||
typedef long double ld;
|
||||
#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
|
||||
bool purehepta = false;
|
||||
|
||||
// hyperbolic points and matrices
|
||||
|
||||
// basic functions and types
|
||||
//===========================
|
||||
|
||||
#ifdef SINHCOSH
|
||||
ld sinh(ld alpha) { return (exp(alpha) - exp(-alpha)) / 2; }
|
||||
ld cosh(ld alpha) { return (exp(alpha) + exp(-alpha)) / 2; }
|
||||
#endif
|
||||
|
||||
ld squar(ld x) { return x*x; }
|
||||
|
||||
@ -36,7 +62,7 @@ hyperpoint hpxyz(ld x, ld y, ld z) {
|
||||
|
||||
hyperpoint hpxy(ld x, ld y) {
|
||||
// EUCLIDEAN
|
||||
return hpxyz(x,y, euclid ? 1 : 1+x*x+y*y);
|
||||
return hpxyz(x,y, euclid ? 1 : sqrt(1+x*x+y*y));
|
||||
}
|
||||
|
||||
// center of the pseudosphere
|
||||
@ -84,6 +110,44 @@ hyperpoint mid(const hyperpoint& H1, const hyperpoint& H2) {
|
||||
return H3;
|
||||
}
|
||||
|
||||
hyperpoint mid3(const hyperpoint& H1, const hyperpoint& H2, const hyperpoint& H3) {
|
||||
|
||||
hyperpoint Hx;
|
||||
Hx[0] = H1[0] + H2[0] + H3[0];
|
||||
Hx[1] = H1[1] + H2[1] + H3[1];
|
||||
Hx[2] = H1[2] + H2[2] + H3[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;
|
||||
}
|
||||
|
||||
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
|
||||
//==========
|
||||
|
||||
@ -268,3 +332,32 @@ transmatrix inverse(transmatrix T) {
|
||||
|
||||
return T2;
|
||||
}
|
||||
|
||||
double hdist(hyperpoint h1, hyperpoint h2) {
|
||||
hyperpoint mh = gpushxto0(h1) * h2;
|
||||
return inverse_sinh(sqrt(mh[0]*mh[0]+mh[1]*mh[1]));
|
||||
}
|
||||
|
||||
namespace hyperpoint_vec {
|
||||
|
||||
hyperpoint operator * (double d, hyperpoint h) {
|
||||
return hpxyz(h[0]*d, h[1]*d, h[2]*d);
|
||||
}
|
||||
|
||||
hyperpoint operator * (hyperpoint h, double d) {
|
||||
return hpxyz(h[0]*d, h[1]*d, h[2]*d);
|
||||
}
|
||||
|
||||
hyperpoint operator / (hyperpoint h, double d) {
|
||||
return hpxyz(h[0]/d, h[1]/d, h[2]/d);
|
||||
}
|
||||
|
||||
hyperpoint operator + (hyperpoint h, hyperpoint h2) {
|
||||
return hpxyz(h[0]+h2[0], h[1]+h2[1], h[2]+h2[2]);
|
||||
}
|
||||
|
||||
hyperpoint operator - (hyperpoint h, hyperpoint h2) {
|
||||
return hpxyz(h[0]-h2[0], h[1]-h2[1], h[2]-h2[2]);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,77 +1,101 @@
|
||||
# Crossroads [02]
|
||||
[02] music/hr3-crossroads.ogg
|
||||
[02] */hr3-crossroads.ogg
|
||||
# Desert [03]
|
||||
[03] music/hr3-desert.ogg
|
||||
[03] */hr3-desert.ogg
|
||||
# Icy Lands [04]
|
||||
[04] music/hr3-icyland.ogg
|
||||
[04] */hr3-icyland.ogg
|
||||
# Living Caves [05]
|
||||
[05] music/hr3-caves.ogg
|
||||
[05] */hr3-caves.ogg
|
||||
# Jungle [06]
|
||||
[06] music/hr3-jungle.ogg
|
||||
[06] */hr3-jungle.ogg
|
||||
# Alchemist's Lab [07]
|
||||
[07] music/hr3-laboratory.ogg
|
||||
[07] */hr3-laboratory.ogg
|
||||
# Mirror [08]
|
||||
[08] music/hr3-mirror.ogg
|
||||
[08] */hr3-mirror.ogg
|
||||
# Graveyard [09]
|
||||
[09] music/hr3-graveyard.ogg
|
||||
[09] */hr3-graveyard.ogg
|
||||
# R'Lyeh [10]
|
||||
[10] music/hr3-rlyeh.ogg
|
||||
[10] */hr3-rlyeh.ogg
|
||||
# Hell [11]
|
||||
[11] music/hr3-hell.ogg
|
||||
[11] */hr3-hell.ogg
|
||||
# Cocytus [12]
|
||||
[12] music/hr3-icyland.ogg
|
||||
[12] */hr3-icyland.ogg
|
||||
# Motion [13]
|
||||
[13] music/hr3-motion.ogg
|
||||
[13] */hr3-motion.ogg
|
||||
# Dry Forest [14]
|
||||
[14] music/hr3-jungle.ogg
|
||||
[14] */hr3-jungle.ogg
|
||||
# Emerald Mines [15]
|
||||
[15] music/hr3-caves.ogg
|
||||
[15] */hr3-caves.ogg
|
||||
# Vineyard [16]
|
||||
[16] music/hr3-laboratory.ogg
|
||||
[16] */hr3-laboratory.ogg
|
||||
# Dead Caves [17]
|
||||
[17] music/hr3-graveyard.ogg
|
||||
[17] */hr3-graveyard.ogg
|
||||
# Hive [18]
|
||||
[18] music/hr3-motion.ogg
|
||||
[18] */hr3-motion.ogg
|
||||
# Land of Power [19]
|
||||
[19] music/hr3-mirror.ogg
|
||||
[19] */hr3-mirror.ogg
|
||||
# Camelot [20]
|
||||
[20] music/hr3-hell.ogg
|
||||
[20] */hr3-hell.ogg
|
||||
# Temple [21]
|
||||
[21] music/hr3-rlyeh.ogg
|
||||
[21] */hr3-rlyeh.ogg
|
||||
# CR2 [22]
|
||||
[22] music/hr3-crossroads.ogg
|
||||
[22] */hr3-crossroads.ogg
|
||||
# Caribbean [23]
|
||||
[23] music/hr3-crossroads.ogg
|
||||
[23] */hr3-crossroads.ogg
|
||||
# Red Rock Valley [24]
|
||||
[24] music/hr3-desert.ogg
|
||||
[24] */hr3-desert.ogg
|
||||
# Minefield [25]
|
||||
[25] music/hr3-hell.ogg
|
||||
[25] */hr3-hell.ogg
|
||||
# Ocean [26]
|
||||
[26] music/hr3-caves.ogg
|
||||
[26] */hr3-caves.ogg
|
||||
# Whirlpool [27]
|
||||
[27] music/hr3-rlyeh.ogg
|
||||
[27] */hr3-rlyeh.ogg
|
||||
# Palace [28]
|
||||
[28] music/hr3-crossroads.ogg
|
||||
[28] */hr3-crossroads.ogg
|
||||
# Living Fjord [39]
|
||||
[29] music/hr3-caves.ogg
|
||||
[29] */hr3-caves.ogg
|
||||
# Ivory Tower [30]
|
||||
[30] music/hr3-laboratory.ogg
|
||||
[30] */hr3-laboratory.ogg
|
||||
# Zebra [31]
|
||||
[31] music/hr3-motion.ogg
|
||||
[31] */hr3-motion.ogg
|
||||
# Elemental Fire [32]
|
||||
[32] music/hr3-hell.ogg
|
||||
[32] */hr3-hell.ogg
|
||||
# Elemental Air [33]
|
||||
[33] music/hr3-motion.ogg
|
||||
[33] */hr3-motion.ogg
|
||||
# Elemental Earth [34]
|
||||
[34] music/hr3-caves.ogg
|
||||
[34] */hr3-caves.ogg
|
||||
# Elemental Water [35]
|
||||
[35] music/hr3-crossroads.ogg
|
||||
[35] */hr3-crossroads.ogg
|
||||
# Crossroads III [36]
|
||||
[36] music/hr3-crossroads.ogg
|
||||
[36] */hr3-crossroads.ogg
|
||||
# Seawall [37] (useless)
|
||||
# Elemental Wall [38] (useless)
|
||||
# Canvas [39]
|
||||
[39] music/hr3-laboratory.ogg
|
||||
[39] */hr3-laboratory.ogg
|
||||
# Wild West [41]
|
||||
[41] */hr3-caves.ogg
|
||||
# Storms [42]
|
||||
[42] */hr3-laboratory.ogg
|
||||
# Overgrown [43]
|
||||
[43] */hr3-jungle.ogg
|
||||
# Clearing [44]
|
||||
[44] */hr3-jungle.ogg
|
||||
# Haunted [45]
|
||||
[45] */hr3-graveyard.ogg
|
||||
# Windy Plains [48]
|
||||
[48] */hr3-laboratory.ogg
|
||||
# Rose Garden [49]
|
||||
[49] */hr3-hell.ogg
|
||||
# Warped Coast/Sea [50, 51 -> 50]
|
||||
[50] */hr3-caves.ogg
|
||||
# Crossroads IV [52]
|
||||
[52] */hr3-crossroads.ogg
|
||||
# Yendorian [53]
|
||||
[53] */hr3-laboratory.ogg
|
||||
# Galapagos [54]
|
||||
[54] */hr3-crossroads.ogg
|
||||
# Dragon Chasms [55]
|
||||
[55] */hr3-caves.ogg
|
||||
# None [00] (used when the window is out of focus)
|
||||
|
||||
|
||||
|
4427
landgen.cpp
Normal file
4427
landgen.cpp
Normal file
File diff suppressed because it is too large
Load Diff
19
langen.cpp
19
langen.cpp
@ -1,3 +1,7 @@
|
||||
// Hyperbolic Rogue language file generator
|
||||
|
||||
// Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details
|
||||
|
||||
#define GEN_M 0
|
||||
#define GEN_F 1
|
||||
#define GEN_N 2
|
||||
@ -84,7 +88,7 @@ typedef unsigned hashcode;
|
||||
|
||||
hashcode hashval;
|
||||
|
||||
hashcode hash(const string& s) {
|
||||
hashcode langhash(const string& s) {
|
||||
hashcode r = 0;
|
||||
for(int i=0; i<size(s); i++) r = hashval * r + s[i];
|
||||
return r;
|
||||
@ -93,7 +97,7 @@ hashcode hash(const string& s) {
|
||||
map<hashcode, string> buildHashTable(set<string>& s) {
|
||||
map<hashcode, string> res;
|
||||
for(set<string>::iterator it = s.begin(); it != s.end(); it++)
|
||||
res[hash(*it)] = *it;
|
||||
res[langhash(*it)] = *it;
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -122,6 +126,13 @@ const char* allstr[] = {
|
||||
};
|
||||
#endif
|
||||
|
||||
void setstats(set<string>& s, const char* bn) {
|
||||
int tlen=0, tc = 0;
|
||||
for(set<string>::iterator it = s.begin(); it != s.end(); it++)
|
||||
tc++, tlen += it->size();
|
||||
printf("// %-10s %5d %5d\n", bn, tc, tlen);
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
nothe.insert("R'Lyeh");
|
||||
@ -177,7 +188,7 @@ int main() {
|
||||
string mis = "";
|
||||
for(int i=1; i<NUMLAN; i++) if(d[i].count(*x) == 0)
|
||||
mis += d[i]["EN"];
|
||||
if(mis != "" && mis != "DE")
|
||||
if(mis != "" && mis != "TR" && mis != "TRDE" && mis != "DE")
|
||||
printf("#warning Missing [%s]: %s\n", mis.c_str(), escape(*x, "?"));
|
||||
}
|
||||
|
||||
@ -191,7 +202,7 @@ int main() {
|
||||
string mis = "";
|
||||
for(int i=1; i<NUMLAN; i++) if(nouns[i].count(*x) == 0)
|
||||
mis += d[i]["EN"];
|
||||
if(mis != "" && mis != "DE")
|
||||
if(mis != "" && mis != "TR" && mis != "TRDE" && mis != "DE")
|
||||
printf("#warning Missing [%s]: %s\n", mis.c_str(), escape(*x, "?"));
|
||||
}
|
||||
|
||||
|
1074
language-cz.cpp
1074
language-cz.cpp
File diff suppressed because it is too large
Load Diff
10242
language-data.cpp
Normal file
10242
language-data.cpp
Normal file
File diff suppressed because it is too large
Load Diff
2146
language-de.cpp
2146
language-de.cpp
File diff suppressed because it is too large
Load Diff
1060
language-pl.cpp
1060
language-pl.cpp
File diff suppressed because it is too large
Load Diff
1166
language-ru.cpp
1166
language-ru.cpp
File diff suppressed because it is too large
Load Diff
318
language-tr.cpp
318
language-tr.cpp
@ -1,8 +1,11 @@
|
||||
// HyperRogue Turkish translation, by zulmetefza & Seyacim
|
||||
// Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details
|
||||
|
||||
// This translation file is encoded with UTF-8
|
||||
|
||||
// Nouns.
|
||||
|
||||
#define Orb(X,Y) N("Orb of "X, GEN_F, Y" Küresi", Y" Küreleri", Y" Küresini", Y" Küresiyle")
|
||||
#define Orb(X,Y) N("Orb of " X, GEN_F, Y " Küresi", Y " Küreleri", Y " Küresini", Y " Küresiyle")
|
||||
|
||||
|
||||
// For each noun, provide the type of the noun, and all the grammatical forms
|
||||
@ -682,7 +685,7 @@ S("A beautiful gem from the Jungle.", "Vahşi Ormandan elde edilmiş bir mücevh
|
||||
|
||||
S(
|
||||
"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.",
|
||||
"Şahane bir içki, görünen o ki kırmızı ve mavi balçığın karıştırılmasıyla elde edilmiş. İçince daha sağlıklı hissediyorsun ama bir canavarın tek vuruşunun seni öldüreceğine de eminsin.")
|
||||
|
||||
S("A piece of a magic mirror, or a mirage cloud, that can be used for magical purposes. Only mirrors and clouds "
|
||||
@ -1191,7 +1194,7 @@ S(
|
||||
"The Knights of the Round Table are the greatest warriors of these lands. "
|
||||
"They are not very inventive with names though, as they call each of their "
|
||||
"castles Camelot. "
|
||||
"You are probably worth of joining them, but they will surely give you "
|
||||
"You are probably worthy of joining them, but they will surely give you "
|
||||
"some quest to prove yourself...\n\n"
|
||||
"Each castle contains a single treasure, the Holy Grail, in the center. "
|
||||
"The radius of the Round Table is usually 28, but after you find a Holy Grail "
|
||||
@ -2639,8 +2642,313 @@ S("A coastal area, from where you can get both to the inland worlds and to the O
|
||||
"Ancak Yaşayan Fiyortların dışındaki hücreler, Unsurlar ve Ölü Trollerin etkisi çok güçlüdür."
|
||||
)
|
||||
|
||||
// S("TRANSLATIONWARNING", "Uyarı: Türkçe çeviri henüz Sürüm 8.0' daki yeni özellikleri kapsamıyor.")
|
||||
// S("TRANSLATIONWARNING", "")
|
||||
|
||||
|
||||
|
||||
// Also, as the game is constantly updated, the Steam version includes the newest features, such as new lands with new mechanics, or new game modes -- see [ http://www.roguetemple.com/z/hyper/gallery.php]Gallery[/url] for the current differences.
|
||||
|
||||
//CORRECTION:
|
||||
N("great wall", GEN_F, "Yüksek Duvar", "Yüksek Duvarlar", "Yüksek Duvarı", "Yüksek Duvarda")
|
||||
// VERSION 8.0
|
||||
//=============
|
||||
|
||||
S("The Air Elemental blows you away!", "Hava Unsuru seni uzağa uçuruyor!")
|
||||
|
||||
// appended to cave troll description
|
||||
S(" Additionally, all items around the killed Troll will be destroyed.",
|
||||
" Ayrıca, Trolün etrafındaki bütün eşyalar yok olur.")
|
||||
|
||||
// 'dead cave troll' and 'dead troll' are separated now
|
||||
|
||||
N("dead rock troll", GEN_M, "ölü mağara trolü" ,"ölü mağara trolleri", "ölü mağara trolünü", "ölü mağara trolüyle")
|
||||
|
||||
S("There are several species of trolls living in the hyperbolic world. "
|
||||
"Some of them leave this wall behind them when they die.",
|
||||
|
||||
"Hiperbolik dünyada pek çok tür trol yaşar."
|
||||
"Bazıları öldüğünde bu duvarı geride bırakır.")
|
||||
|
||||
// paper model creator
|
||||
//---------------------
|
||||
|
||||
S("paper model creator", "kâğıt modeli üreticisi")
|
||||
S("synchronize net and map", "haritayı ve ağı eşle")
|
||||
S("display the scope", "odağı göster")
|
||||
S("create the model", "modeli üret")
|
||||
S("back to HyperRogue", "HyperRogue'a geri dön")
|
||||
S("design the net", "ağı tasarla")
|
||||
|
||||
S("The paper model created as papermodel-*.bmp", "Kâğıt model papermodel-*.bmp şeklinde üretildi")
|
||||
S("Failed to load the file 'papermodeldata.txt'", "papermodeldata.txt dosyası yüklenemedi")
|
||||
S("Could not save the paper model data", "Kâğıt modeli verisi kaydedilemedi")
|
||||
|
||||
// pure tactics mode
|
||||
//-------------------
|
||||
|
||||
S("pure tactics mode", "saf taktik modu")
|
||||
S("Not available in the pure tactics mode!", "Taktik modunda kullanılamaz!")
|
||||
S("\"The Knights of the Horocyclic Table salute you!\"", "\"Horosikıl Masa Şövalyeleri seni selamlıyor!\"")
|
||||
S("press 0 to leave this mode", "Bu moddan çıkmak için 0'a bas")
|
||||
S("Collect %1x %2 to unlock", " %1 tane %2 toplayarak aktifleştir")
|
||||
|
||||
S(
|
||||
"In the pure tactics mode, you concentrate on a specific land. "
|
||||
"Your goal to obtain as high score as possible, without using "
|
||||
"features of the other lands. You can then compare your score "
|
||||
"with your friends!\n\n"
|
||||
|
||||
"You need to be somewhat proficient in the normal game to "
|
||||
"unlock the given land in this challenge "
|
||||
"(collect 20 treasure in the given land, or 2 in case of Camelot).\n\n"
|
||||
|
||||
"Since getting high scores in some lands is somewhat luck dependent, "
|
||||
"you play each land N times, and your score is based on N consecutive "
|
||||
"plays. The value of N depends on how 'fast' the land is to play, and "
|
||||
"how random it is.\n\n"
|
||||
|
||||
"In the Caribbean, you can access Orbs of Thorns, Aether, and "
|
||||
"Space if you have ever collected 25 treasure in their native lands.\n\n"
|
||||
|
||||
"The rate of treasure spawn is static in this mode. It is not "
|
||||
"increased by killing monsters.\n\n"
|
||||
|
||||
"Good luck, and have fun!",
|
||||
|
||||
"Saf taktik modunda sadece tek bir diyara odaklanırsın. Amacın diğer diyarların özelliklerini hiç kullanmadan mümkün olduğunca yüksek puan yapmak. Sonra skorunu arkadaşlarınınkiyle karşılaştırabilirsin!\n\n "
|
||||
|
||||
"Normal oyunda maharetini ispatlayarak belli bir diyarı bu modda açabilirsin. "
|
||||
"(Belli bir diyarda 20 hazine toplamak, Kamelot için 2 hazine toplamak gibi).\n\n"
|
||||
|
||||
"Yüksek skor almak şöyle böyle şansa bağlı olduğundan, her diyarı N defa oynarsın ve skorun bu ardarda N oyuna göre belirlenir. N'in değeri diyarın ne kadar hızlı oynandığına ve ne derece rassal olduğuna göre değişir.\n\n"
|
||||
|
||||
"Karayiplerde, Diken Küresine, Ether'e ve Uzay'a eğer daha önce ilgili diyarlarda 25'er hazine topladıysan erişebilirsin.\n\n"
|
||||
|
||||
"Hazine üretimi bu modda statiktir ve canavar öldürmekle artmaz.\n\n"
|
||||
|
||||
"İyi şanslar ve iyi eğlenceler!")
|
||||
|
||||
// Yendor Challenge
|
||||
//------------------
|
||||
|
||||
S("Yendor Challenge", "Yendor Ek Görevi")
|
||||
//Görev?
|
||||
S("Collect 10 treasures in various lands to unlock the challenges there",
|
||||
"Çeşitli diyarlarda 10 hazine toplayarak o diyarın özel görevini aktifleştirebilirsin")
|
||||
|
||||
S("easy", "kolay")
|
||||
S("challenge", " ek görev")
|
||||
|
||||
S("Challenges do not get harder", "Ek görevler zorlaşmaz.")
|
||||
S("Each challenge gets harder after each victory", "Her zaferinden sonra ek görevler zorlaşır.")
|
||||
|
||||
S(" (won!)", " (kazandın!)")
|
||||
S(" (won at level %1!)", " (%1. seviyede kazandın!)")
|
||||
S("(locked)", "(aktif değil)")
|
||||
|
||||
S(
|
||||
"There are many possible solutions to the Yendor Quest. In the Yendor "
|
||||
"Challenge, you will try many of them!\n\n"
|
||||
"Each challenge takes part in a specific land, and you have to use what "
|
||||
"you have available.\n\n"
|
||||
|
||||
"You need to obtain an Orb of Yendor in the normal game to activate "
|
||||
"this challenge, and (ever) collect 10 treasures in one or two lands "
|
||||
"to activate a specific level.\n\n"
|
||||
|
||||
"After you complete each challenge, you can try it again, on a harder "
|
||||
"difficulty level.\n\n"
|
||||
|
||||
"All the solutions showcased in the Yendor Challenge work in the normal "
|
||||
"play too. However, passages to other lands, and (sometimes) some land features "
|
||||
"are disabled in the Yendor "
|
||||
"Challenge, so that you have to use the expected method. Also, "
|
||||
"the generation rules are changed slightly for the Palace "
|
||||
"and Minefield while you are looking for the Orb of Yendor, "
|
||||
"to make the challenge more balanced "
|
||||
"(but these changes are also active during the normal Yendor Quest).\n\n"
|
||||
|
||||
"You get 1000 points for each challenge won, and 1 extra point for "
|
||||
"each extra difficulty level.",
|
||||
|
||||
"Yendor Görevinin bir sürü çözümü var. Yendor Ek Görevi'nde bunların pek çoğunu deneyeceksin!\n\n"
|
||||
"Her görev belirli bir diyarda geçiyor ve elindekileri bütün verimliliğiyle kullanman gerekecek.\n\n"
|
||||
"Bu görevi aktifleştirmek için normal oyunda bir kez Yendor'un Küresi'ni ele geçirmen gerekiyor. Ayrıca her hangi bir seviyeyi aktifleştirmek için ilgili diyar(lar)da 10 hazine toplamış olman gerekiyor.\n\n"
|
||||
|
||||
"Ek görevi tamamladıktan sonra aynı görevi bir üst zorluk seviyesinde yeniden deneyebilirsin.\n\n"
|
||||
|
||||
"Yendor Ek Görevi'ndeki bütün çözümler normal oyunda da işe yarar. Ancak, Yendor Ek görevinde, diğer diyarlara geçiş ve bazen diyarın bazı özellikleri devredışıdır, bu yüzden beklenen çözümü bulman beklenir. "
|
||||
"Ayrıca, Yendor'un Küresi'ni ararken görevin daha dengeli olması için Saray ve Mayın Tarlasındaki harita üretimi biraz değiştirilmiştir. (bu değişiklikler normal Yendor Görevi'nde de mevcuttur).\n\n"
|
||||
"Her kazanılan ek görev için 1000 puan ve her fazladan zorluk seviyesi için 1 fazladan puan kazanırsın.\n\n"
|
||||
)
|
||||
|
||||
S("Unlock this challenge by getting the Orb of Yendor!",
|
||||
"Yendor'un Küresi'ni alarak bu ek görevi aktif et!")
|
||||
|
||||
S("Collect 10 treasures in various lands to unlock the challenges there",
|
||||
"Diyarlardaki ek görevleri aktif etmek için oralarda 10 hazine topla.")
|
||||
|
||||
// Wild West
|
||||
//-----------
|
||||
|
||||
N("Wild West", GEN_O, "Vahşi Batı", "Vahşi Batılar", "Vahşi Batıyı", "Vahşi Batıda")
|
||||
N("Outlaw", GEN_M, "Haydut" ,"Haydutlar", "Haydutu", "Haydutla")
|
||||
N("Bounty", GEN_F, "Ödül", "Ödüller", "Ödülü", "Ödülle")
|
||||
N("saloon wall", GEN_F, "bar duvarı", "bar duvarları", "bar duvarını", "bar duvarıyla")
|
||||
N("Revolver", GEN_O, "Altıpatlar", "Altıpatlarlar", "Altıpatları", "Altıpatlarla")
|
||||
|
||||
S("%The1 shoots you!", "%1 sana ateş etti!")
|
||||
S("You shoot %the1!", "%1 düşmanına ateş ettin!")
|
||||
|
||||
S(
|
||||
"Take a revolver, kill outlaws, collect bounties.\n\n"
|
||||
"Note: since this land is anachronistic, it is not available in normal game. "
|
||||
"It is only available in special modes.",
|
||||
|
||||
"Altıpatları al, haydutları öldür, başlarına konan ödülleri topla!\n\n"
|
||||
"Not: Bu diyar anakronistik olduğu için, normal oyunda mevcut değil, sadece özel modlarda oynanabilir.")
|
||||
|
||||
// Land of Storms
|
||||
//----------------
|
||||
|
||||
S(
|
||||
"Whenever after your move there is a connection between a charged and a "
|
||||
"grounded cell, there is a short circuit. All cells on any "
|
||||
"path connecting a charged and a grounded cell (without repeated cells, "
|
||||
"or two consecutive grounded/charged cells) become damaged.\n\n"
|
||||
|
||||
"Sandstone walls and most creatures are conductive. Great Walls are "
|
||||
"isolators, but lands beyond them count as grounded.\n\n"
|
||||
|
||||
"Fulgurite, the treasure, is created when you manage to short circuit "
|
||||
"a sandstone wall, or a Rich Metal Beast.\n\n"
|
||||
|
||||
"Trolls leave conductive rocks when killed, and Metal Beasts can only "
|
||||
"be killed by electricity -- your attacks only stun them, or push "
|
||||
"them away if already stunned.",
|
||||
|
||||
"Hareketinden sonra, eğer yüklü ve topraklı bir hücre arasında bağlantı varsa, kısa devre olur."
|
||||
"Yüklü ve topraklı hücrenin arasındaki bütün hücreler (tekrarlayan hücreler, yahut iki ardışık topraklı yahut yüklü hücre hariç) hasar görür.\n\n"
|
||||
|
||||
"Kumtaşı duvarları ve çoğu yaratık iletkendir. Büyük Duvarlar yalıtkandır, ancak onlardan sonraki hücreler topraklanmış sayılır. \n\n"
|
||||
|
||||
"Fulgurit, buradaki hazine, bir kumtaşı duvarını veya Zengin Metal Canavarını kısa devreye uğratmanla ortaya çıkar.\n\n"
|
||||
|
||||
"Troller öldüklerinde artlarında iletken kayalar bırakırlar ve Metal Canavarlar sadece elektrik ile öldürülebilirler. Saldırıların metal canavarları sersemletir, yahut zaten sersemlemişlerse ittirir. ")
|
||||
|
||||
|
||||
N("Land of Storms", GEN_F, "Fırtına Diyarı", "Fırtına Diyarları", "Fırtına Diyarını", "Fırtına Diyarında")
|
||||
N("charged wall", GEN_F, "yüklü duvar", "yüklü duvarlar", "yüklü duvarı", "yüklü duvarla")
|
||||
N("grounded wall", GEN_F, "topraklı duvar", "topraklı duvarlar", "topraklı duvarı", "topraklı duvarla")
|
||||
N("metal wall", GEN_F, "metal duvar", "metal duvarlar", "metal duvarı", "metal duvarla")
|
||||
N("sandstone wall", GEN_F, "kumtaşı duvarı", "kumtaşı duvarları", "kumtaşı duvarını", "kumtaşı duvarla")
|
||||
N("Storm Troll", GEN_M, "Fırtına Trolü", "Fırtına Trolleri", "Fırtına Trolünü", "Fırtına Trolüyle")
|
||||
N("Metal Beast", GEN_O, "Metal Canavar", "Metal Canavarları", "Metal Canavarını", "Metal Canavarıyla")
|
||||
N("Rich Metal Beast", GEN_O, "Zengin Metal Canavar", "Zengin Metal Canavarları", "Zengin Metal Canavarını", "Zengin Metal Canavarıyla")
|
||||
N("electric discharge", GEN_N, "elektrik boşalımı", "elektrik boşalımları", "elektrik boşalımını", "elektrik boşalımıyla")
|
||||
|
||||
S("There is a flash of thunder!", "Bir şimşek çaktı!")
|
||||
|
||||
Orb("Stunning", "Sersemletme")
|
||||
|
||||
S("This Orb allows you to target monsters to stun them. "
|
||||
"10 charges are used to stun for 5 turns. Does not "
|
||||
"work against multi-tile monsters.",
|
||||
|
||||
"Bu Küre canavarları hedefleyerek sersemletmeni sağlar. 5 tur sersemletmek için 10 güç kullanır. Çokluhücre canavarlara karşı çalışmaz."
|
||||
)
|
||||
|
||||
S("You stun %the1!", "%a1! sersemlettin!")
|
||||
|
||||
// Overgrown Woods
|
||||
//-----------------
|
||||
|
||||
Orb("Luck", "Şans")
|
||||
|
||||
S("This Orb allows you to find new lands more easily. "
|
||||
"Lands where you have already collected less treasure, "
|
||||
"and especially the Crossroads, are more likely to "
|
||||
"spawn while you have this. Additionally, Orbs of Safety "
|
||||
"are more likely to spawn in the Whirlpool.",
|
||||
|
||||
"Bu küre yeni diyarlar bulmanı kolaylaştırır. Daha az hazine topladığın diyarlar ve özellikle Arayollar, bu küreyi elinde tutarken daha yüksek ihtimalle karşına çıkar. "
|
||||
"Ayrıca, Güvenlik Kürelerinin Tayfun'da ortaya çıkma ihtimalini artırır."
|
||||
)
|
||||
|
||||
N("Overgrown Woods", GEN_O, "Azman Orman", "Azman Ormanlar", "Azman Ormanı", "Azman Ormanda")
|
||||
N("Mutant Ivy", GEN_O, "Mutant Sarmaşık", "Mutant Sarmaşıklar", "Mutant Sarmaşığı", "Mutant Sarmaşıkla")
|
||||
N("Mutant Sapling", GEN_F, "Mutant Fidan", "Mutant Fidanlar", "Mutant Fidanı", "Mutant Fidanla")
|
||||
N("Forest Troll", GEN_M, "Orman Trolü", "Orman Trolleri", "Orman Trolünü", "Orman Trolüyle")
|
||||
|
||||
S("Forest Trolls create an impassable wall when they die.",
|
||||
"Orman Trolleri öldüklerinde artlarında aşılmaz bir duvar bırakır.")
|
||||
|
||||
S(
|
||||
"The Overgrown Woods are filled with mutant ivies! These plants "
|
||||
"grow very fast. Each leaf, after being grown, can grow itself "
|
||||
"on the next turn. However, each part is only able to grow "
|
||||
"once in 16 turns. Outside of the Overgrown Woods, the Mutant Ivy "
|
||||
"may grow only on hexagonal cells.\n\n"
|
||||
"Maybe such fast growing plants could help you solve the problem "
|
||||
"of hunger in your world? Kill the Mutant Ivies to collect Mutant Saplings.",
|
||||
|
||||
"Azman Orman mutant sarmaşıklarla dolu! Bu bitkiler çok hızlı büyür. Her yaprak, büyüdükten sonra sıradaki tur kendi başına büyüyebilir."
|
||||
" Ancak, her parça ancak 16 tur içinde bir kez büyüyebilir. Azman Orman dışındaki diyarlarda, Mutant Sarmaşık sadece altıgen hücrelerde büyüyebilir.\n\n"
|
||||
"Belki bu kadar hızlı büyüyen bitkiler dünyandaki açlık sorununu çözebilir? Mutant Fidanları toplamak için Mutant Sarmaşıkları öldür.")
|
||||
|
||||
S("Trees in this forest can be cut down. Big trees take two turns to cut down.",
|
||||
"Bu ormandaki ağaçlar kesilebilir. Büyük ağaçların kesilmesi iki tur alır."
|
||||
)
|
||||
|
||||
/* ACHIEVEMENTS
|
||||
|
||||
"NEW_ACHIEVEMENT_5_24_NAME" "Mutant Fidan"
|
||||
"NEW_ACHIEVEMENT_5_24_DESC" "Bir Mutant Fidan bul ve topla."
|
||||
"NEW_ACHIEVEMENT_5_25_NAME" "Orman Trolü"
|
||||
"NEW_ACHIEVEMENT_5_25_DESC" "10 Mutant Fidan topla."
|
||||
"NEW_ACHIEVEMENT_5_26_NAME" "Mutant Sarmaşık"
|
||||
"NEW_ACHIEVEMENT_5_26_DESC" "25 Mutant Fidan topla."
|
||||
"NEW_ACHIEVEMENT_5_27_NAME" "Sarmaşık Efendisi"
|
||||
"NEW_ACHIEVEMENT_5_27_DESC" "50 Mutant Fidan topla."
|
||||
"NEW_ACHIEVEMENT_5_28_NAME" "Şimşek Çakması"
|
||||
"NEW_ACHIEVEMENT_5_28_DESC" "Bir Fulgurit bul ve topla."
|
||||
"NEW_ACHIEVEMENT_5_29_NAME" "Fırtına Trolü"
|
||||
"NEW_ACHIEVEMENT_5_29_DESC" "10 Fulgurit topla."
|
||||
"NEW_ACHIEVEMENT_5_30_NAME" "Metal Canavarı"
|
||||
"NEW_ACHIEVEMENT_5_30_DESC" "25 Fulgurit topla."
|
||||
"NEW_ACHIEVEMENT_5_31_NAME" "Zengin Metal Canavarı"
|
||||
"NEW_ACHIEVEMENT_5_31_DESC" "50 Fulgurit topla."
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#undef Orb
|
||||
|
||||
// S("TRANSLATIONWARNING", "Uyarı: Türkçe çeviri henüz Sürüm 7.4' daki yeni özellikleri kapsamıyor.")
|
||||
S("TRANSLATIONWARNING", "")
|
||||
S("TRANSLATIONWARNING",
|
||||
"ÇEVİRİ UYARISI: Türkçe çevirisi güncel değil -- 8.1'den sonra eklenen özellikleri")
|
||||
|
||||
S("TRANSLATIONWARNING2",
|
||||
"çevirmek isterseniz lütfen zeno@attnam.com adresinden benimle iletişime geçin.")
|
||||
|
||||
S("summon Bonfire", "Kampateşi çıkar")
|
||||
S("Hyperstone Quest", "Aşkıntaş Görevi")
|
||||
S("summon dead orbs", "ölü küre çıkar")
|
||||
S("summon a Monster", "Bir canavar çıkar")
|
||||
S("gain orb powers", "küre güçleri kazan")
|
||||
S("summon a Golem", "Golem çıkar")
|
||||
S("summon Thumpers", "Gümleyen çıkar")
|
||||
S("summon Ivy", "Sarmaşık çıkar")
|
||||
S("lose all treasure", "tüm hazineyi kaybet")
|
||||
S("gain kills", "leşler kazan.")
|
||||
S("Select the land ---", "Diyar seç ---")
|
||||
S("summon Mimics", "Taklitçiler çıkar")
|
||||
S("summon orbs", "küre çıkar")
|
||||
S("deplete orb powers", "küre güçlerini tüket")
|
||||
S("Safety (quick save)", "Güvenlik (hızlı kayıt)")
|
||||
S("summon treasure", "hazine çıkar")
|
||||
S("summon lots of treasure", "çok hazine çıkar")
|
||||
S("--- and teleport there", "--- ve oraya ışınlan.")
|
||||
S("summon Sand Worm", "Kumkurdu çıkar")
|
||||
S("summon Orb of Yendor", "Yendorun Küresini çıkar")
|
||||
S("rotate the character", "karakteri döndür")
|
||||
|
41
language.cpp
41
language.cpp
@ -1,12 +1,10 @@
|
||||
// Hyperbolic Rogue language support
|
||||
// Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details
|
||||
|
||||
// #define CHECKTRANS
|
||||
|
||||
#define NUMLAN 6
|
||||
|
||||
#define GEN_M 0
|
||||
#define GEN_F 1
|
||||
#define GEN_N 2
|
||||
#define GEN_O 3
|
||||
|
||||
struct stringpar {
|
||||
string v;
|
||||
stringpar(string s) : v(s) { }
|
||||
@ -30,13 +28,16 @@ void rep(string& pattern, string what, string to) {
|
||||
}
|
||||
}
|
||||
|
||||
void reponce(string& pattern, string what, string to) {
|
||||
size_t at = pattern.find(what);
|
||||
if(at != string::npos)
|
||||
pattern = pattern.replace(at, what.size(), to);
|
||||
}
|
||||
|
||||
typedef unsigned hashcode;
|
||||
|
||||
// a quick hack to make this unambiguous on Android
|
||||
#define hash my_hash
|
||||
|
||||
struct sentence {
|
||||
hashcode hash;
|
||||
hashcode langhash;
|
||||
const char* xlat[NUMLAN-1];
|
||||
};
|
||||
|
||||
@ -46,14 +47,14 @@ struct noun {
|
||||
};
|
||||
|
||||
struct fullnoun {
|
||||
hashcode hash;
|
||||
hashcode langhash;
|
||||
int english_grammar_flags;
|
||||
noun n[NUMLAN-1];
|
||||
};
|
||||
|
||||
#include "language-data.cpp"
|
||||
|
||||
hashcode hash(const string& s) {
|
||||
hashcode langhash(const string& s) {
|
||||
hashcode r = 0;
|
||||
for(int i=0; i<size(s); i++) r = hashval * r + s[i];
|
||||
return r;
|
||||
@ -61,14 +62,14 @@ hashcode hash(const string& s) {
|
||||
|
||||
template<class T> const T* findInHashTableS(string s, const T *table, int size) {
|
||||
int b = 0, e = size;
|
||||
hashcode h = hash(s);
|
||||
hashcode h = langhash(s);
|
||||
while(b!=e) {
|
||||
int m = (b+e)>>1;
|
||||
// printf("b=%d e=%d m=%d h=%x s=%x\n", b, e, m, table[m].hash, h);
|
||||
if(table[m].hash >= h) e = m;
|
||||
// printf("b=%d e=%d m=%d h=%x s=%x\n", b, e, m, table[m].langhash, h);
|
||||
if(table[m].langhash >= h) e = m;
|
||||
else b = m+1;
|
||||
}
|
||||
if(e != size && table[e].hash == h)
|
||||
if(e != size && table[e].langhash == h)
|
||||
return &table[e];
|
||||
return NULL;
|
||||
}
|
||||
@ -211,9 +212,11 @@ void parrep(string& x, string w, stringpar p) {
|
||||
rep(x, "%P"+w, N->n[4].nomp);
|
||||
rep(x, "%a"+w, N->n[4].acc);
|
||||
rep(x, "%abl"+w, N->n[4].abl);
|
||||
rep(x, "%d"+w, N->n[4].abl); // Dativ (which equals Ablative in German)
|
||||
rep(x, "%Der"+w, choose3(N->n[4].genus, "Der", "Die", "Das"));
|
||||
rep(x, "%der"+w, choose3(N->n[4].genus, "der", "die", "das"));
|
||||
rep(x, "%den"+w, choose3(N->n[4].genus, "den", "die", "das"));
|
||||
rep(x, "%dem"+w, choose3(N->n[4].genus, "dem", "der", "dem"));
|
||||
}
|
||||
else {
|
||||
rep(x,"%"+w,p.v);
|
||||
@ -272,7 +275,7 @@ string XLAT(string x, stringpar p1, stringpar p2, stringpar p3) {
|
||||
basicrep(x);
|
||||
parrep(x,"1",p1.v);
|
||||
parrep(x,"2",p2.v);
|
||||
parrep(x,"3",p2.v);
|
||||
parrep(x,"3",p3.v);
|
||||
postrep(x);
|
||||
return x;
|
||||
}
|
||||
@ -280,8 +283,8 @@ string XLAT(string x, stringpar p1, stringpar p2, stringpar p3, stringpar p4) {
|
||||
basicrep(x);
|
||||
parrep(x,"1",p1.v);
|
||||
parrep(x,"2",p2.v);
|
||||
parrep(x,"3",p2.v);
|
||||
parrep(x,"4",p2.v);
|
||||
parrep(x,"3",p3.v);
|
||||
parrep(x,"4",p4.v);
|
||||
postrep(x);
|
||||
return x;
|
||||
}
|
||||
@ -302,3 +305,5 @@ string XLAT1(string x) {
|
||||
return x;
|
||||
}
|
||||
|
||||
string XLATT1(stringpar p) { return XLAT1(p.v); }
|
||||
|
||||
|
427
mapeditor.cpp
427
mapeditor.cpp
@ -1,3 +1,6 @@
|
||||
// HyperRogue map editor
|
||||
// Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details
|
||||
|
||||
#include <map>
|
||||
#include <stdint.h>
|
||||
|
||||
@ -9,6 +12,7 @@
|
||||
#endif
|
||||
|
||||
namespace mapeditor {
|
||||
#ifndef MOBILE
|
||||
cell *modelcell[200];
|
||||
|
||||
void clearModelCells() {
|
||||
@ -31,8 +35,10 @@ namespace mapeditor {
|
||||
c->mondir = (c2->mondir - patterndir(c2) + patterndir(c) + 7*6*5) % c->type;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef MOBILE
|
||||
namespace mapstream {
|
||||
std::map<cell*, int> cellids;
|
||||
vector<cell*> cellbyid;
|
||||
@ -199,7 +205,7 @@ namespace mapstream {
|
||||
for(int i=0; i<size(cellbyid); i++) {
|
||||
cell *c = cellbyid[i];
|
||||
if(c->bardir != NODIR && c->bardir != NOBARRIERS)
|
||||
buildBarrier(c);
|
||||
extendBarrier(c);
|
||||
}
|
||||
|
||||
for(int d=BARLEV-1; d>=0; d--)
|
||||
@ -252,8 +258,135 @@ namespace mapstream {
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace mapeditor {
|
||||
|
||||
bool drawplayer = true;
|
||||
char whichPattern = 0;
|
||||
char whichShape = 0;
|
||||
char whichCanvas = 0;
|
||||
|
||||
int nopattern(cell *c) {
|
||||
if(isWarped(c) && !euclid) {
|
||||
int u = ishept(c)?1:0;
|
||||
int qhex = 0;
|
||||
for(int v=0; v<c->type; v++) if(c->mov[v] && !isWarped(c->mov[v])) {
|
||||
u += 2;
|
||||
if(!ishept(c->mov[v])) qhex++;
|
||||
}
|
||||
if(u == 2 && qhex == 1) return 8;
|
||||
if(u == 6 && qhex == 2) return 10;
|
||||
return u;
|
||||
}
|
||||
return ishept(c) ? 1 : ishex1(c) ? 2 : 0; // 0 to 1
|
||||
}
|
||||
|
||||
bool reflectPatternAt(cell *c, char p = whichPattern) {
|
||||
if(p == 'p' && polarb50(c)) return true;
|
||||
if(p == 0 && nopattern(c) == 4) {
|
||||
int d = patterndir(c);
|
||||
return !isWarped(createMov(c, (d+1)%6));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int downdir(cell *c, cellfunction *cf = coastvalEdge) {
|
||||
cell *c2 = chosenDown(c, 1, 1, cf);
|
||||
if(!c2) return 0;
|
||||
return neighborId(c, c2);
|
||||
}
|
||||
|
||||
int patterndir(cell *c, char w) {
|
||||
switch(w) {
|
||||
case 'z': {
|
||||
int t = zebra40(c);
|
||||
|
||||
int t4 = t>>2, tcdir = 0;
|
||||
|
||||
if(purehepta) tcdir = t^1;
|
||||
|
||||
else if(t4 == 10) tcdir = t-20;
|
||||
else if(t4 >= 4 && t4 < 7) tcdir = 40 + (t&3);
|
||||
else if(t4 >= 1 && t4 < 4) tcdir = t+12;
|
||||
else if(t4 >= 7 && t4 < 10) tcdir = t-24;
|
||||
|
||||
for(int i=0; i<c->type; i++) if(c->mov[i] && zebra40(c->mov[i]) == tcdir)
|
||||
return i;
|
||||
|
||||
// printf("fail to fintd %d -> %d\n", t, tcdir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
case 'f': {
|
||||
int t = emeraldval(c);
|
||||
int tcdir = 0, tbest = (t&3);
|
||||
for(int i=0; i<c->type; i++) {
|
||||
cell *c2 = c->mov[i];
|
||||
if(c2) {
|
||||
int t2 = emeraldval(c2);
|
||||
if((t&3) == (t2&3) && t2 > tbest)
|
||||
tbest = t2, tcdir = i;
|
||||
}
|
||||
}
|
||||
return tcdir;
|
||||
}
|
||||
|
||||
case 'p': {
|
||||
int tcdir = -1, tbest = -1;
|
||||
int pa = polara50(c);
|
||||
int pb = polarb50(c);
|
||||
for(int i=0; i<c->type; i++) {
|
||||
cell *c2 = c->mov[i];
|
||||
if(c2 && polara50(c2) == pa && polarb50(c2) == pb) {
|
||||
int t2 = fiftyval049(c2);
|
||||
if(t2 > tbest) tbest = t2, tcdir = i;
|
||||
}
|
||||
}
|
||||
return tcdir;
|
||||
}
|
||||
|
||||
case 'H':
|
||||
return downdir(c);
|
||||
|
||||
case 0: {
|
||||
if(euclid) return 0;
|
||||
int u = nopattern(c);
|
||||
|
||||
if(u == 6)
|
||||
for(int i=1; i<c->type; i+=2) if(!isWarped(createMov(c,i)))
|
||||
return i;
|
||||
|
||||
if(u == 2 || u == 3 || u == 8)
|
||||
for(int i=0; i<c->type; i++) if(!isWarped(createMov(c,i)))
|
||||
return i;
|
||||
|
||||
if(u == 4 || u == 10)
|
||||
for(int i=0; i<c->type; i+=2) if(!isWarped(createMov(c,i)))
|
||||
return i;
|
||||
|
||||
if(u == 6)
|
||||
for(int i=1; i<c->type; i+=2) if(!isWarped(createMov(c,i)))
|
||||
return i;
|
||||
|
||||
if(u == 5)
|
||||
for(int i=0; i<c->type; i++) if(!isWarped(createMov(c,(i+3)%7)) && !isWarped(createMov(c,(i+4)%7)))
|
||||
return i;
|
||||
|
||||
if(u == 9)
|
||||
for(int i=0; i<c->type; i++) if(!isWarped(createMov(c,(i+2)%7)) && !isWarped(createMov(c,(i+5)%7)))
|
||||
return i;
|
||||
|
||||
if(u == 7)
|
||||
for(int i=0; i<c->type; i++) if(!isWarped(createMov(c,(i+1)%7)) && !isWarped(createMov(c,(i+6)%7)))
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef MOBILE
|
||||
int paintwhat = 0;
|
||||
int painttype = 0;
|
||||
int radius = 0;
|
||||
@ -262,14 +395,13 @@ namespace mapeditor {
|
||||
|
||||
int subscreen; //0=normal, 1=config, 2=patterns, 3=predesigned
|
||||
|
||||
char whichPattern;
|
||||
bool symRotation, sym01, sym02, sym03;
|
||||
int displaycodes;
|
||||
char whichShape, whichCanvas;
|
||||
int subcanvas;
|
||||
int whichpart;
|
||||
|
||||
bool drawplayer = true;
|
||||
string infix;
|
||||
|
||||
cell *drawcell;
|
||||
|
||||
const char *mapeditorhelp =
|
||||
@ -368,11 +500,6 @@ namespace mapeditor {
|
||||
if(checkEq(undo[size(undo)-1])) undo.pop_back();
|
||||
}
|
||||
|
||||
string actkeys = "-"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789!@#$%^&*()_+=[{]}\\|;:'\",<.>/?`~";
|
||||
|
||||
int itc(int k) {
|
||||
if(k == 0) return 0;
|
||||
if(k == 1) return 0x40;
|
||||
@ -524,6 +651,22 @@ namespace mapeditor {
|
||||
displayButton(8, vid.yres-8-fs*2, XLAT("ESC = return to the game"), SDLK_ESCAPE, 0);
|
||||
}
|
||||
|
||||
void vpush(int i, const char *name) {
|
||||
string s = XLATN(name);
|
||||
if(infix != "") {
|
||||
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));
|
||||
}
|
||||
|
||||
void showMapEditor() {
|
||||
|
||||
if(choosefile) { drawFileDialog(); return; }
|
||||
@ -544,22 +687,24 @@ namespace mapeditor {
|
||||
|
||||
displayStat(14, XLAT("display only hexagons"), ONOFF(whichShape == '6'), '6');
|
||||
displayStat(15, XLAT("display only heptagons"), ONOFF(whichShape == '7'), '7');
|
||||
displayStat(16, XLAT("display the triheptagonal grid"), ONOFF(whichShape == '8'), '8');
|
||||
|
||||
displayStat(17, XLAT("predesigned patterns"), "", 'r');
|
||||
displayStat(18, XLAT("predesigned patterns"), "", 'r');
|
||||
}
|
||||
else if(subscreen == 3) {
|
||||
displayStat(2, XLAT("Gameboard"), "", 'g');
|
||||
displayStat(3, XLAT("random colors"), "", 'r');
|
||||
displayStat(4, XLAT("rainbow landscape"), "", 'l');
|
||||
|
||||
displayStat(5, XLAT("emerald pattern"), "emerald", 'e');
|
||||
displayStat(6, XLAT("emerald pattern"), "emerald", 'e');
|
||||
|
||||
displayStat(7, XLAT("four elements"), "palace", 'b');
|
||||
displayStat(8, XLAT("eight domains"), "palace", 'a');
|
||||
displayStat(8, XLAT("four elements"), "palace", 'b');
|
||||
displayStat(9, XLAT("eight domains"), "palace", 'a');
|
||||
|
||||
displayStat(10, XLAT("zebra pattern"), "zebra", 'z');
|
||||
displayStat(11, XLAT("three stripes"), "zebra", 'x');
|
||||
displayStat(11, XLAT("zebra pattern"), "zebra", 'z');
|
||||
displayStat(12, XLAT("three stripes"), "zebra", 'x');
|
||||
|
||||
displayStat(13, XLAT("random black-and-white"), "current", 'w');
|
||||
displayStat(15, XLAT("random black-and-white"), "current", 'w');
|
||||
}
|
||||
else if(subscreen == 1 && painttype == 6)
|
||||
drawColorDialog(paintwhat);
|
||||
@ -575,30 +720,25 @@ namespace mapeditor {
|
||||
m == moFlailBullet || m == moShadow || m == moAirball ||
|
||||
m == moWolfMoved || m == moGolemMoved ||
|
||||
m == moTameBomberbirdMoved || m == moKnightMoved ||
|
||||
m == moDeadBug || m == moLightningBolt || m == moDeadBird ||
|
||||
m == moMouseMoved || m == moPrincessMoved || m == moPrincessArmedMoved) ;
|
||||
else
|
||||
v.push_back(make_pair(XLATN(minf[i].name), i));
|
||||
else vpush(i, minf[i].name);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
for(int i=0; i<ittypes; i++) {
|
||||
v.push_back(make_pair(XLATN(iinf[i].name), i));
|
||||
}
|
||||
for(int i=0; i<ittypes; i++) vpush(i, iinf[i].name);
|
||||
break;
|
||||
case 2:
|
||||
for(int i=0; i<landtypes; i++) {
|
||||
v.push_back(make_pair(XLATN(linf[i].name), i));
|
||||
}
|
||||
for(int i=0; i<landtypes; i++) vpush(i, linf[i].name);
|
||||
break;
|
||||
case 3:
|
||||
for(int i=0; i<walltypes; i++) {
|
||||
if(i != waChasmD)
|
||||
v.push_back(make_pair(XLATN(winf[i].name), i));
|
||||
}
|
||||
for(int i=0; i<walltypes; i++) if(i != waChasmD) vpush(i, winf[i].name);
|
||||
break;
|
||||
}
|
||||
// sort(v.begin(), v.end());
|
||||
|
||||
if(infix != "") mouseovers = infix;
|
||||
|
||||
int q = v.size();
|
||||
int percolumn = vid.yres / (vid.fsize+5) - 4;
|
||||
int columns = 1 + (q-1) / percolumn;
|
||||
@ -607,7 +747,11 @@ namespace mapeditor {
|
||||
int x = 16 + (vid.xres * (i/percolumn)) / columns;
|
||||
int y = (vid.fsize+5) * (i % percolumn) + vid.fsize*2;
|
||||
|
||||
displayButton(x, y, v[i].first + ": " + actkeys[i], actkeys[i], 0);
|
||||
int actkey = 1000 + i;
|
||||
string vv = v[i].first;
|
||||
if(i < 9) { vv += ": "; vv += ('1' + i); }
|
||||
|
||||
displayButton(x, y, vv, actkey, 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -713,7 +857,7 @@ namespace mapeditor {
|
||||
case 'H':
|
||||
return realpattern(c);
|
||||
}
|
||||
return c->type-6; // 0 to 1
|
||||
return nopattern(c);
|
||||
}
|
||||
|
||||
int realpattern(cell *c) {
|
||||
@ -732,7 +876,7 @@ namespace mapeditor {
|
||||
case 'H':
|
||||
return towerval(c);
|
||||
}
|
||||
return c->type-6; // 0 to 2
|
||||
return nopattern(c);
|
||||
}
|
||||
|
||||
int cellShapeGroup() {
|
||||
@ -751,7 +895,7 @@ namespace mapeditor {
|
||||
}
|
||||
|
||||
int drawcellShapeID() {
|
||||
if(drawcell == cwt.c) return vid.female;
|
||||
if(drawcell == cwt.c) return vid.cs.charid;
|
||||
if(drawcell->monst) return drawcell->monst;
|
||||
if(drawcell->item) return drawcell->item;
|
||||
return subpattern(drawcell);
|
||||
@ -770,63 +914,6 @@ namespace mapeditor {
|
||||
return subpatternShape(id) == subpattern(drawcell);
|
||||
}
|
||||
|
||||
bool reflectPatternAt(cell *c) {
|
||||
return whichPattern == 'p' && polarb50(c);
|
||||
}
|
||||
|
||||
int patterndir(cell *c, char w) {
|
||||
switch(w) {
|
||||
case 'z': {
|
||||
int t = zebra40(c);
|
||||
|
||||
int t4 = t>>2, tcdir;
|
||||
|
||||
if(t4 == 10) tcdir = 0;
|
||||
else if(t4 >= 4 && t4 < 7) tcdir = 40 + (t&3);
|
||||
else if(t4 >= 1 && t4 < 4) tcdir = t+12;
|
||||
else if(t4 >= 7 && t4 < 10) tcdir = t-24;
|
||||
|
||||
for(int i=0; i<c->type; i++) if(c->mov[i] && zebra40(c->mov[i]) == tcdir)
|
||||
return i;
|
||||
}
|
||||
|
||||
case 'f': {
|
||||
int t = emeraldval(c);
|
||||
int tcdir, tbest = (t&3);
|
||||
for(int i=0; i<c->type; i++) {
|
||||
cell *c2 = c->mov[i];
|
||||
if(c2) {
|
||||
int t2 = emeraldval(c2);
|
||||
if((t&3) == (t2&3) && t2 > tbest)
|
||||
tbest = t2, tcdir = i;
|
||||
}
|
||||
}
|
||||
return tcdir;
|
||||
}
|
||||
|
||||
case 'p': {
|
||||
int tcdir = -1, tbest = -1;
|
||||
int pa = polara50(c);
|
||||
int pb = polarb50(c);
|
||||
for(int i=0; i<c->type; i++) {
|
||||
cell *c2 = c->mov[i];
|
||||
if(c2 && polara50(c2) == pa && polarb50(c2) == pb) {
|
||||
int t2 = fiftyval049(c2);
|
||||
if(t2 > tbest) tbest = t2, tcdir = i;
|
||||
}
|
||||
}
|
||||
return tcdir;
|
||||
}
|
||||
|
||||
case 'H': {
|
||||
cell *c2 = chosenDown(c, 1, 1);
|
||||
if(!c2) return 0;
|
||||
return neighborId(c, c2);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void spill(cell *c, int r, int cdir) {
|
||||
|
||||
if(painttype == 4 && radius) {
|
||||
@ -846,7 +933,7 @@ namespace mapeditor {
|
||||
c->stuntime = 0;
|
||||
c->mondir = cdir;
|
||||
|
||||
if((isWorm(c) || isIvy(c)) && c->mov[cdir] &&
|
||||
if((isWorm(c) || isIvy(c) || isMutantIvy(c)) && c->mov[cdir] &&
|
||||
!isWorm(c->mov[cdir]) && !isIvy(c->mov[cdir]))
|
||||
c->mondir = NODIR;
|
||||
break;
|
||||
@ -876,7 +963,7 @@ namespace mapeditor {
|
||||
if(hasTimeout(c))
|
||||
c->wparam = 10;
|
||||
else if(c->wall == waWaxWall)
|
||||
c->landparam = rand() & 0xFFFFFF;
|
||||
c->landparam = hrand(0xFFFFFF + 1);
|
||||
}
|
||||
else if(hasTimeout(c))
|
||||
c->wparam += spillinc();
|
||||
@ -937,7 +1024,7 @@ namespace mapeditor {
|
||||
}
|
||||
for(int i=0; i<c2->type; i++) {
|
||||
cell *c3 = c2->mov[i];
|
||||
if(c3 && c3->aitmp != sval)
|
||||
if(c3 && !eq(c3->aitmp, sval))
|
||||
c3->aitmp = sval, v.push_back(c3);
|
||||
}
|
||||
}
|
||||
@ -995,13 +1082,19 @@ namespace mapeditor {
|
||||
if(v == 2) cmode = emNormal;
|
||||
}
|
||||
else if(subscreen == 1) {
|
||||
for(int z=0; z<size(v); z++) if(actkeys[z] == uni) {
|
||||
if(uni >= '1' && uni <= '9') uni = 1000 + uni - '1';
|
||||
if(sym == SDLK_RETURN || sym == '-') uni = 1000;
|
||||
for(int z=0; z<size(v); z++) if(1000 + z == uni) {
|
||||
paintwhat = v[z].second;
|
||||
paintwhat_str = v[z].first;
|
||||
subscreen = 0;
|
||||
mousepressed = false;
|
||||
}
|
||||
if(subscreen == 1 && uni != 0) cmode = emNormal;
|
||||
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 if(subscreen == 1 && uni != 0) cmode = emNormal;
|
||||
}
|
||||
else if(subscreen == 3) {
|
||||
if(uni >= 'a' && uni <= 'z') {
|
||||
@ -1023,7 +1116,7 @@ namespace mapeditor {
|
||||
else if(uni == '1') sym01 = !sym01;
|
||||
else if(uni == '2') sym02 = !sym02;
|
||||
else if(uni == '3') sym03 = !sym03;
|
||||
else if(uni == '6' || uni == '7') {
|
||||
else if(uni == '6' || uni == '7' || uni == '8') {
|
||||
if(whichShape == uni) whichShape = 0;
|
||||
else whichShape = uni;
|
||||
}
|
||||
@ -1046,10 +1139,10 @@ namespace mapeditor {
|
||||
if(uni == 'u') applyUndo();
|
||||
else if(uni == 'v' || sym == SDLK_F10 || sym == SDLK_ESCAPE) cmode = emNormal;
|
||||
else if(uni >= '0' && uni <= '9') radius = uni - '0';
|
||||
else if(uni == 'm') subscreen = 1, painttype = 0;
|
||||
else if(uni == 'i') subscreen = 1, painttype = 1;
|
||||
else if(uni == 'l') subscreen = 1, painttype = 2;
|
||||
else if(uni == 'w') subscreen = 1, painttype = 3;
|
||||
else if(uni == 'm') subscreen = 1, painttype = 0, infix = "";
|
||||
else if(uni == 'i') subscreen = 1, painttype = 1, infix = "";
|
||||
else if(uni == 'l') subscreen = 1, painttype = 2, infix = "";
|
||||
else if(uni == 'w') subscreen = 1, painttype = 3, infix = "";
|
||||
else if(uni == 'r') subscreen = 2;
|
||||
else if(uni == 't' && mouseover) {
|
||||
cwt.c = mouseover; playermoved = true;
|
||||
@ -1161,7 +1254,7 @@ namespace mapeditor {
|
||||
hyperpoint coldcenter = C0;
|
||||
|
||||
void drawGrid() {
|
||||
if(cmode == emDraw) {
|
||||
if(cmode == emDraw && !inHighQual) {
|
||||
lalpha = 0x20;
|
||||
for(int d=0; d<84; d++) {
|
||||
transmatrix d2 = drawtrans * rgpushxto0(ccenter);
|
||||
@ -1169,19 +1262,37 @@ namespace mapeditor {
|
||||
lalpha = 0x40;
|
||||
else
|
||||
lalpha = 0x20;
|
||||
drawline(d2 * C0, d2 * spin(M_PI*d/42)* xpush(1) * C0, 0xC0C0C0);
|
||||
queueline(d2 * C0, d2 * spin(M_PI*d/42)* xpush(1) * C0, 0xC0C0C0);
|
||||
for(int u=2; u<=20; u++) {
|
||||
if(u % 5 == 0) lalpha = 0x40;
|
||||
else lalpha = 0x20;
|
||||
drawline(
|
||||
queueline(
|
||||
d2 * spin(M_PI*d/42)* xpush(u/20.) * C0,
|
||||
d2 * spin(M_PI*(d+1)/42)* xpush(u/20.) * C0,
|
||||
0xC0C0C0);
|
||||
}
|
||||
}
|
||||
drawline(drawtrans*ccenter, drawtrans*coldcenter, 0xC0C0C0);
|
||||
queueline(drawtrans*ccenter, drawtrans*coldcenter, 0xC0C0C0);
|
||||
|
||||
lalpha = 0xFF;
|
||||
|
||||
int sg = drawcellShapeGroup();
|
||||
|
||||
for(int i=0; i<USERSHAPEIDS; i++) if(editingShape(sg, i) && usershapes[sg][i]) {
|
||||
|
||||
usershapelayer &ds(usershapes[sg][i]->d[mapeditor::dslayer]);
|
||||
|
||||
for(int a=0; a<size(ds.list); a++) {
|
||||
hyperpoint P2 = drawtrans * ds.list[a];
|
||||
|
||||
int xc, yc, sc;
|
||||
getcoord(P2, xc, yc, sc);
|
||||
queuechr(xc, yc, sc, 10, 'x',
|
||||
a == 0 ? 0x00FF00 :
|
||||
a == size(ds.list)-1 ? 0xFF0000 :
|
||||
0xFFFF00);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1201,7 +1312,7 @@ namespace mapeditor {
|
||||
switch(sg) {
|
||||
case 0:
|
||||
line1 = XLAT("character");
|
||||
line2 = XLAT(vid.female ? "female" : "male");
|
||||
line2 = csname(vid.cs);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
@ -1216,7 +1327,8 @@ namespace mapeditor {
|
||||
|
||||
case 3:
|
||||
line1 = XLAT("floor");
|
||||
line2 = XLAT(drawcell->type == 6 ? "hexagonal" : "heptagonal");
|
||||
line2 = XLAT(ishept(drawcell) ? "heptagonal" :
|
||||
ishex1(drawcell) ? "hexagonal #1" : "hexagonal");
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1274,14 +1386,20 @@ namespace mapeditor {
|
||||
|
||||
void applyToShape(int sg, int id, int uni, hyperpoint mh) {
|
||||
bool haveshape = usershapes[sg][id];
|
||||
bool xnew = false;
|
||||
if(!haveshape) {
|
||||
if(uni == 'n' || uni == 'u')
|
||||
initShape(sg, id);
|
||||
else return;
|
||||
else if(uni >= '0' && uni <= '9') {
|
||||
initShape(sg, id);
|
||||
xnew = true;
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
usershapelayer *dsCur = &usershapes[sg][id]->d[dslayer];
|
||||
if(uni == 'n') {
|
||||
if(uni == 'n' || xnew) {
|
||||
dsCur->list.clear();
|
||||
dsCur->list.push_back(mh);
|
||||
saveImages();
|
||||
@ -1319,27 +1437,72 @@ namespace mapeditor {
|
||||
saveImages();
|
||||
}
|
||||
|
||||
if(uni == 'L') {
|
||||
if(!vid.female) loadShape(sg, id, shPBody, 2, 0);
|
||||
if(uni == 'T') {
|
||||
/* loadShape(sg, id, shFemaleBody, 1, 1);
|
||||
loadShape(sg, id, shPKnife, 1, 2);
|
||||
loadShape(sg, id, shFemaleDress, 1, 3);
|
||||
loadShape(sg, id, shPrincessDress, 1, 4);
|
||||
loadShape(sg, id, shBeautyHair, 1, 5);
|
||||
loadShape(sg, id, shPFace, 1, 6);
|
||||
loadShape(sg, id, shFlowerHair, 1, 7); */
|
||||
|
||||
/* loadShape(sg, id, shYeti, 1, 2);
|
||||
loadShape(sg, id, shRatHead, 1, 3);
|
||||
loadShape(sg, id, shRatTail, 1, 1);
|
||||
loadShape(sg, id, shWolf1, 1, 4);
|
||||
loadShape(sg, id, shWolf2, 1, 5);
|
||||
loadShape(sg, id, shRatCape1, 1, 7);
|
||||
loadShape(sg, id, shRatCape2, 1, 6); */
|
||||
|
||||
// loadShape(sg, id, shTortoise[0][0], 1, 0);
|
||||
/* loadShape(sg, id, shTentacleX, 1, 0);
|
||||
loadShape(sg, id, shTentacle, 1, 1);
|
||||
loadShape(sg, id, shJoint, 1, 2); */
|
||||
|
||||
/* loadShape(3, 0, shTurtleFloor[0], 12, 0);
|
||||
loadShape(3, 1, shTurtleFloor[1], 14, 0); */
|
||||
|
||||
// loadShape(sg, id, shDragonSegment, 2, 0);
|
||||
loadShape(sg, id, shDragonSegment, 2, 1);
|
||||
// loadShape(sg, id, shEyes, 2, 2);
|
||||
|
||||
saveImages();
|
||||
}
|
||||
|
||||
if(uni == 'K') {
|
||||
if(vid.cs.charid >= 4) {
|
||||
loadShape(sg, id, shCatBody, 2, 0);
|
||||
loadShape(sg, id, shCatHead, 2, 1);
|
||||
}
|
||||
else {
|
||||
if(!(vid.cs.charid&1)) loadShape(sg, id, shPBody, 2, 0);
|
||||
else loadShape(sg, id, shFemaleBody, 2, 0);
|
||||
|
||||
loadShape(sg, id, shPSword, 1, 1);
|
||||
|
||||
if(vid.female)
|
||||
if(vid.cs.charid&1)
|
||||
loadShape(sg, id, shFemaleDress, 2, 2);
|
||||
|
||||
if(vid.female)
|
||||
loadShape(sg, id, shFemaleHair, 2, 3);
|
||||
if(vid.cs.charid&1)
|
||||
loadShape(sg, id, shPrincessDress, 1, 3);
|
||||
else
|
||||
loadShape(sg, id, shPHead, 2, 3);
|
||||
loadShape(sg, id, shPrinceDress, 2, 3);
|
||||
|
||||
loadShape(sg, id, shPFace, 2, 4);
|
||||
if(vid.cs.charid&1)
|
||||
loadShape(sg, id, shFemaleHair, 2, 4);
|
||||
else
|
||||
loadShape(sg, id, shPHead, 2, 4);
|
||||
|
||||
loadShape(sg, id, shPFace, 2, 5);
|
||||
}
|
||||
|
||||
// loadShape(sg, id, shWolf, 2, dslayer);
|
||||
|
||||
saveImages();
|
||||
}
|
||||
|
||||
if(uni == '+') dsCur->rots++;
|
||||
|
||||
if(uni >= '1' && uni <= '9') {
|
||||
dsCur->rots = uni - '0';
|
||||
if(dsCur->rots == 9) dsCur->rots = 21;
|
||||
@ -1372,7 +1535,8 @@ namespace mapeditor {
|
||||
hyperpoint h;
|
||||
for(int i=0; i<3; i++) {
|
||||
double d;
|
||||
fscanf(f, "%lf", &d);
|
||||
int err = fscanf(f, "%lf", &d);
|
||||
if(err) printf("Warning: read error\n");
|
||||
h[i] = d;
|
||||
}
|
||||
return h;
|
||||
@ -1393,7 +1557,7 @@ namespace mapeditor {
|
||||
else return;
|
||||
}
|
||||
|
||||
dslayer &= 7;
|
||||
dslayer %= USERLAYERS;
|
||||
hyperpoint mh = inverse(drawtrans) * mouseh;
|
||||
|
||||
int sg = drawcellShapeGroup();
|
||||
@ -1404,7 +1568,8 @@ namespace mapeditor {
|
||||
if(uni == 'e') {
|
||||
drawcell = mouseover ? mouseover : cwt.c;
|
||||
}
|
||||
if(uni == 'l') dslayer++;
|
||||
if(uni == 'l') { dslayer++; dslayer %= USERLAYERS; }
|
||||
if(uni == 'L') { dslayer--; if(dslayer < 0) dslayer += USERLAYERS; }
|
||||
|
||||
if(uni == 'g') coldcenter = ccenter, ccenter = mh;
|
||||
|
||||
@ -1467,12 +1632,17 @@ namespace mapeditor {
|
||||
addMessage(XLAT("Failed to load pictures from %1", picfile));
|
||||
return;
|
||||
}
|
||||
char buf[200]; fgets(buf, 200, f);
|
||||
int vernum; fscanf(f, "%x", &vernum);
|
||||
int err;
|
||||
char buf[200];
|
||||
if(!fgets(buf, 200, f)) {
|
||||
addMessage(XLAT("Failed to load pictures from %1", picfile));
|
||||
fclose(f); return;
|
||||
}
|
||||
int vernum; err = fscanf(f, "%x", &vernum);
|
||||
printf("vernum = %x\n", vernum);
|
||||
while(true) {
|
||||
int i, j, l, sym, rots, color, siz;
|
||||
int err = fscanf(f, "%d%d%d%d%d%x%d", &i, &j, &l, &sym, &rots, &color, &siz);
|
||||
err = fscanf(f, "%d%d%d%d%d%x%d", &i, &j, &l, &sym, &rots, &color, &siz);
|
||||
if(i == -1 || err < 6) break;
|
||||
if(siz < 0 || siz > 1000) break;
|
||||
initShape(i, j);
|
||||
@ -1524,7 +1694,7 @@ namespace mapeditor {
|
||||
if(whichCanvas == 'g')
|
||||
return linf[laCanvas].color >> 2;
|
||||
if(whichCanvas == 'r')
|
||||
return rand() & 0xFFFFFF;
|
||||
return hrand(0xFFFFFF + 1);
|
||||
if(whichCanvas == 'e') {
|
||||
static unsigned int fcol[4] = { 0x404040, 0x800000, 0x008000, 0x000080 };
|
||||
int fv = emeraldval(c);
|
||||
@ -1565,6 +1735,21 @@ namespace mapeditor {
|
||||
static unsigned int fcol[2] = { 0x303030, 0xC0C0C0 };
|
||||
return fcol[randpattern(c, subcanvas) ? 1 : 0];
|
||||
}
|
||||
if(whichCanvas == 'l') {
|
||||
#ifdef CDATA
|
||||
int col[4];
|
||||
bool err = false;
|
||||
for(int j=0; j<4; j++) {
|
||||
col[j] = getCdata(c, j);
|
||||
col[j] *= 3;
|
||||
col[j] %= 240;
|
||||
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);
|
||||
#endif
|
||||
}
|
||||
return linf[laCanvas].color >> 2;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
796
menus.cpp
Normal file
796
menus.cpp
Normal file
@ -0,0 +1,796 @@
|
||||
// HyperRogue menus
|
||||
// Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details
|
||||
|
||||
void showOverview() {
|
||||
DEBB(DF_GRAPH, (debugfile,"show overview\n"));
|
||||
mouseovers = XLAT("world overview");
|
||||
mouseovers += " ";
|
||||
mouseovers += XLAT(" kills: %1/%2", its(tkills()), its(killtypes()));
|
||||
mouseovers += XLAT(" $$$: %1", its(gold()));
|
||||
if(hellUnlocked()) {
|
||||
int i1, i2; countHyperstoneQuest(i1, i2);
|
||||
mouseovers += XLAT(" Hyperstone: %1/%2", its(i1), its(i2));
|
||||
}
|
||||
else
|
||||
mouseovers += XLAT(" Hell: %1/9", its(orbsUnlocked()));
|
||||
|
||||
int nl = LAND_OVER; eLand *landtab = land_over;
|
||||
if(randomPatternsMode) { nl = RANDLANDS; landtab = randlands; }
|
||||
|
||||
int vf = min((vid.yres-64) / nl, vid.xres/40);
|
||||
|
||||
eLand curland = cwt.c->land;
|
||||
if(curland == laPalace && princess::dist(cwt.c) < OUT_OF_PRISON)
|
||||
curland = laPrincessQuest;
|
||||
if(isElemental(curland)) curland = laElementalWall;
|
||||
|
||||
getcstat = '0';
|
||||
|
||||
for(int i=0; i<nl; i++) {
|
||||
eLand l = landtab[i];
|
||||
int xr = vid.xres / 64;
|
||||
int i0 = 56 + i * vf;
|
||||
int col;
|
||||
if(landUnlocked(l)) col = linf[l].color; else col = 0x202020;
|
||||
if(chaosmode && noChaos(l)) col = 0x200000;
|
||||
if(l == curland)
|
||||
displayfr(1, i0, 1, vf-4, "*", 0xFFFFFF, 0);
|
||||
if(displayfr(xr*1, i0, 1, vf-4, XLAT1(linf[l].name), col, 0))
|
||||
getcstat = 1000 + l;
|
||||
eItem it = treasureType(l);
|
||||
int lv = items[it] * landMultiplier(l);
|
||||
if(lv >= 25) col = 0xFFD500;
|
||||
else if(lv >= 10) col = 0x00D500;
|
||||
else if(items[it]) col = 0xC0C0C0;
|
||||
else col = 0x202020;
|
||||
if(chaosmode && noChaos(l)) col = 0x200000;
|
||||
if(displayfr(xr*24-48, i0, 1, vf-4, its(items[it]), col, 16))
|
||||
getcstat = 2000+it;
|
||||
if(!cheater)
|
||||
if(displayfr(xr*24, i0, 1, vf-4, its(hiitems[modecode()][it]), col, 16))
|
||||
getcstat = 2000+it;
|
||||
if(items[it]) col = iinf[it].color; else col = 0x202020;
|
||||
if(chaosmode && noChaos(l)) col = 0x200000;
|
||||
if(displayfr(xr*24+32, i0, 1, vf-4, s0 + iinf[it].glyph, col, 16))
|
||||
getcstat = 2000+it;
|
||||
if(displayfr(xr*24+40, i0, 1, vf-4, XLAT1(iinf[it].name), col, 0))
|
||||
getcstat = 2000+it;
|
||||
eItem io = orbType(l);
|
||||
if(io == itShard) {
|
||||
if(items[it] >= 10) col = winf[waMirror].color; else col = 0x202020;
|
||||
if(chaosmode && noChaos(l)) col = 0x200000;
|
||||
if(displayfr(xr*46, i0, 1, vf-4, XLAT1(winf[waMirror].name), col, 0))
|
||||
getcstat = 3000+waMirror;
|
||||
if(getcstat == 3000+waMirror)
|
||||
mouseovers = XLAT(
|
||||
olrDescriptions[getOLR(io, cwt.c->land)], cwt.c->land, it, treasureType(cwt.c->land));
|
||||
}
|
||||
else if(io) {
|
||||
if(lv >= 25) col = 0xFFD500;
|
||||
else if(lv >= 10) col = 0xC0C0C0;
|
||||
else col = 0x202020;
|
||||
if(chaosmode && noChaos(l)) col = 0x200000;
|
||||
if(displayfr(xr*46-32, i0, 1, vf-4, its(items[io]), col, 16))
|
||||
getcstat = 2000+io;
|
||||
if(lv >= 10) col = iinf[io].color; else col = 0x202020;
|
||||
if(chaosmode && noChaos(l)) col = 0x200000;
|
||||
if(displayfr(xr*46-8, i0, 1, vf-4, s0 + iinf[io].glyph, col, 16))
|
||||
getcstat = 2000+io;
|
||||
if(displayfr(xr*46, i0, 1, vf-4, XLAT1(iinf[io].name), col, 0))
|
||||
getcstat = 2000+io;
|
||||
if(getcstat == 2000+io)
|
||||
mouseovers = XLAT(
|
||||
olrDescriptions[getOLR(io, curland)], curland, it, treasureType(curland));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handleOverview(int uni) {
|
||||
int umod = uni % 1000;
|
||||
int udiv = uni / 1000;
|
||||
if(udiv == 1 && umod < landtypes) {
|
||||
if(cheater) {
|
||||
eLand l = eLand(umod);
|
||||
cheater++;
|
||||
if(l == laPrincessQuest) {
|
||||
if(kills[moVizier] == 0) kills[moVizier] = 1;
|
||||
princess::forceMouse = true;
|
||||
princess::gotoPrincess = true;
|
||||
l = laPalace;
|
||||
}
|
||||
activateSafety(l);
|
||||
cmode = emNormal;
|
||||
canmove = true;
|
||||
}
|
||||
else {
|
||||
lastmode = cmode;
|
||||
cmode = emHelp; help = generateHelpForLand(eLand(umod));
|
||||
}
|
||||
}
|
||||
else if(udiv == 2 && umod < ittypes) {
|
||||
if(cheater) {
|
||||
cheater++;
|
||||
double shiftmul = 1.001;
|
||||
if(anyshiftclick) shiftmul *= -1;
|
||||
if(rightclick) shiftmul /= 10;
|
||||
int ic = itemclass(eItem(umod));
|
||||
if(ic == IC_TREASURE) items[umod] += int(10*shiftmul);
|
||||
if(ic == IC_ORB) items[umod] += int(60*shiftmul);
|
||||
if(umod == itGreenStone) items[umod] += int(100*shiftmul);
|
||||
else if(ic == IC_OTHER) items[umod] += (shiftmul>0?1:-1);
|
||||
if(items[umod] < 0) items[umod] = 0;
|
||||
if(hardcore) canmove = true;
|
||||
else checkmove();
|
||||
}
|
||||
else {
|
||||
lastmode = cmode;
|
||||
cmode = emHelp; help = generateHelpForItem(eItem(umod));
|
||||
if(hardcore) canmove = true;
|
||||
else checkmove();
|
||||
}
|
||||
}
|
||||
else if(udiv == 3 && umod < walltypes) {
|
||||
lastmode = cmode;
|
||||
cmode = emHelp; help = generateHelpForWall(eWall(umod));
|
||||
}
|
||||
else if(uni) cmode = emNormal;
|
||||
}
|
||||
|
||||
void showMainMenu() {
|
||||
int y = vid.yres * .5 - vid.fsize * 10.5;
|
||||
displayfr(vid.xres/2, y-vid.fsize * 2, 4, vid.fsize*2,
|
||||
XLAT("HyperRogue %1", VER), 0xC00000, 8
|
||||
);
|
||||
|
||||
displayButton(vid.xres/2, y + vid.fsize*2, ifMousing("b", "basic configuration"), 'b', 8, 2);
|
||||
displayButton(vid.xres/2, y + vid.fsize*4, ifMousing("a", "advanced configuration"), 'a', 8, 2);
|
||||
|
||||
#ifndef ANDROID
|
||||
displayButton(vid.xres/2, y + vid.fsize*6, ifMousing("t", "local highscores"), 't', 8, 2);
|
||||
#endif
|
||||
displayButton(vid.xres/2, y + vid.fsize*8, ifMousing("h, F1", "help"), 'h', 8, 2);
|
||||
if(cheater)
|
||||
displayButton(vid.xres/2, y + vid.fsize*10, ifMousing("c", "cheats"), 'c', 8, 2);
|
||||
|
||||
displayButton(vid.xres/2, y + vid.fsize*12, ifMousing("r, F5", "restart game"), 'r', 8, 2);
|
||||
displayButton(vid.xres/2, y + vid.fsize*14, ifMousing("m", "special game modes"), 'm', 8, 2);
|
||||
|
||||
string q;
|
||||
|
||||
#ifndef ANDROID
|
||||
q = (items[itOrbSafety] && havesave) ? "save" : "quit";
|
||||
#ifdef IOS
|
||||
q = q + " and visit the website";
|
||||
#else
|
||||
q = q + " the game";
|
||||
#endif
|
||||
displayButton(vid.xres/2, y + vid.fsize*17, ifMousing("q, F10", q), 'q', 8, 2);
|
||||
#endif
|
||||
|
||||
if(canmove)
|
||||
q = "review your quest";
|
||||
else
|
||||
q = "review the scene";
|
||||
|
||||
displayButton(vid.xres/2, y + vid.fsize*20, ifMousing("ESC", q), SDLK_ESCAPE, 8, 2);
|
||||
|
||||
displayButton(vid.xres/2, y + vid.fsize*22, ifMousing("o", "world overview"), 'o', 8, 2);
|
||||
|
||||
if(!canmove) q = "game over screen";
|
||||
else if(turncount > 0) q = "continue game";
|
||||
else q = "play the game!";
|
||||
|
||||
displayButton(vid.xres/2, y + vid.fsize*25, ifMousing(XLAT("other"), q), ' ', 8, 2);
|
||||
}
|
||||
|
||||
void loadScores();
|
||||
|
||||
bool handleMenuKey(int sym, bool mdown) {
|
||||
if(sym == SDLK_F1 || sym == 'h') {
|
||||
lastmode = cmode;
|
||||
cmode = emHelp;
|
||||
}
|
||||
else if(sym == 'c' && cheater)
|
||||
cmode = emCheatMenu;
|
||||
else if(sym == 'b') cmode = emVisual1;
|
||||
else if(sym == 'a') cmode = emVisual2;
|
||||
else if(sym == 'm') cmode = emChangeMode;
|
||||
#ifndef ANDROID
|
||||
else if(sym == 't') loadScores();
|
||||
#endif
|
||||
else if(sym == 'r' || sym == SDLK_F5) {
|
||||
restartGame();
|
||||
cmode = emNormal;
|
||||
}
|
||||
else if(sym == 'q' || sym == SDLK_F10) return true;
|
||||
else if(sym == 'o') cmode = emOverview;
|
||||
else if(sym == SDLK_ESCAPE) cmode = emQuit;
|
||||
else if((sym != 0 && sym != SDLK_F12) || mdown) {
|
||||
cmode = emNormal;
|
||||
msgs.clear();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void showVisual1() {
|
||||
#ifndef MOBILE
|
||||
displayStat(2, XLAT("video resolution"), its(vid.xres) + "x"+its(vid.yres), 'r');
|
||||
displayStat(3, XLAT("fullscreen mode"), ONOFF(vid.full), 'f');
|
||||
#endif
|
||||
displayStat(4, XLAT("animation speed"), fts(vid.aspeed), 'a');
|
||||
displayStat(5, XLAT("dist from hyperboloid ctr"), fts(vid.alpha), 'p');
|
||||
displayStat(6, XLAT("scale factor"), fts(vid.scale), 'z');
|
||||
|
||||
const char *wdmodes[4] = {"ASCII", "black", "plain", "Escher"};
|
||||
const char *mdmodes[4] = {"ASCII", "items only", "items and monsters", "high contrast"};
|
||||
|
||||
displayStat(7, XLAT("draw the heptagons darker"), ONOFF(vid.darkhepta), '7');
|
||||
|
||||
displayStat(8, XLAT("wall display mode"),
|
||||
XLAT(wdmodes[vid.wallmode]), 'w');
|
||||
displayStat(9, XLAT("monster display mode"),
|
||||
XLAT(mdmodes[vid.monmode]), 'm');
|
||||
#ifndef MOBILE
|
||||
const char *axmodes[4] = {"no axes", "auto", "light", "heavy"};
|
||||
displayStat(10, XLAT("cross display mode"),
|
||||
XLAT(axmodes[vid.axes]), 'c');
|
||||
#endif
|
||||
#ifndef MOBILE
|
||||
displayStat(11, XLAT("background music volume"),
|
||||
its(audiovolume), 'b');
|
||||
#endif
|
||||
if(lang() != 0) {
|
||||
string s = XLAT("TRANSLATIONWARNING");
|
||||
if(s != "" && s != "TRANSLATIONWARNING") {
|
||||
int dy = vid.fsize * 23 + vid.yres/4;
|
||||
int dx = vid.xres/2;
|
||||
displaystr(dx, dy, 0, vid.fsize, s, 0xFF0000, 8);
|
||||
}
|
||||
s = XLAT("TRANSLATIONWARNING2");
|
||||
if(s != "" && s != "TRANSLATIONWARNING2") {
|
||||
int dy = vid.fsize * 24 + vid.yres/4;
|
||||
int dx = vid.xres/2;
|
||||
displaystr(dx, dy, 0, vid.fsize, s, 0xFF0000, 8);
|
||||
}
|
||||
}
|
||||
displayStat(13, XLAT("language"), XLAT("EN"), 'l');
|
||||
displayStat(14, XLAT("player character"),
|
||||
numplayers() > 1 ? "" : csname(vid.cs), 'g');
|
||||
}
|
||||
|
||||
void handleVisual1(int sym, int uni) {
|
||||
|
||||
char xuni = uni | 96;
|
||||
|
||||
if(uni >= 32 && uni < 64) xuni = uni;
|
||||
|
||||
if(xuni == 'p') vid.alpha += shiftmul * 0.1;
|
||||
if(xuni == 'z') vid.scale += shiftmul * 0.1;
|
||||
|
||||
if(xuni == 'i') {
|
||||
double d = exp(shiftmul/10);
|
||||
vid.alpha *= d;
|
||||
vid.scale *= d;
|
||||
}
|
||||
|
||||
if(xuni == 'a') vid.aspeed += shiftmul;
|
||||
#ifndef MOBILE
|
||||
if(xuni == 'f') {
|
||||
vid.full = !vid.full;
|
||||
if(shiftmul > 0) {
|
||||
vid.xres = vid.full ? vid.xscr : 9999;
|
||||
vid.yres = vid.full ? vid.yscr : 9999;
|
||||
extern bool setfsize;
|
||||
setfsize = true;
|
||||
}
|
||||
setvideomode();
|
||||
}
|
||||
#endif
|
||||
|
||||
if(xuni == 'v' || sym == SDLK_F2) cmode = emNormal;
|
||||
#ifndef ANDROID
|
||||
if(xuni == 's') saveConfig();
|
||||
#endif
|
||||
|
||||
if(xuni == '7') { vid.darkhepta = !vid.darkhepta; }
|
||||
if(xuni == 'w') { vid.wallmode += 60 + (shiftmul > 0 ? 1 : -1); vid.wallmode %= 4; }
|
||||
if(xuni == 'm') { vid.monmode += 60 + (shiftmul > 0 ? 1 : -1); vid.monmode %= 4; }
|
||||
if(xuni == 'c') { vid.axes += 60 + (shiftmul > 0 ? 1 : -1); vid.axes %= 4; }
|
||||
#ifndef MOBILE
|
||||
if(xuni == 'b') {
|
||||
audiovolume += int(10.5 * shiftmul);
|
||||
if(audiovolume < 0) audiovolume = 0;
|
||||
if(audiovolume > MIX_MAX_VOLUME) audiovolume = MIX_MAX_VOLUME;
|
||||
Mix_VolumeMusic(audiovolume);
|
||||
}
|
||||
#endif
|
||||
|
||||
if(sym == SDLK_ESCAPE) cmode = emNormal;
|
||||
|
||||
if(xuni == 'l') {
|
||||
vid.language += (shiftmul>0?1:-1);
|
||||
vid.language %= NUMLAN;
|
||||
if(vid.language < 0) vid.language += NUMLAN;
|
||||
}
|
||||
|
||||
if(xuni == 'g') cmode = emCustomizeChar;
|
||||
}
|
||||
|
||||
void showVisual2() {
|
||||
#ifndef MOBILE
|
||||
#ifdef GL
|
||||
displayStat(2, XLAT("openGL & antialiasing mode"), vid.usingGL ? "OpenGL" : vid.usingAA ? "AA" : "OFF", 'o');
|
||||
#endif
|
||||
#endif
|
||||
displayStat(3, XLAT("distance between eyes"), fts(vid.eye * 10), 'e');
|
||||
#ifndef MOBILE
|
||||
displayStat(4, XLAT("framerate limit"), its(vid.framelimit), 'f');
|
||||
#endif
|
||||
|
||||
#ifndef MOBILE
|
||||
displayStat(6, XLAT("joystick mode"), XLAT(autojoy ? "automatic" : "manual"), 'p');
|
||||
|
||||
displayStat(7, XLAT("first joystick: movement threshold"), its(vid.joyvalue), 'a');
|
||||
displayStat(8, XLAT("first joystick: execute movement threshold"), its(vid.joyvalue2), 'b');
|
||||
displayStat(9, XLAT("second joystick: pan threshold"), its(vid.joypanthreshold), 'c');
|
||||
displayStat(10, XLAT("second joystick: panning speed"), fts(vid.joypanspeed * 1000), 'd');
|
||||
#endif
|
||||
|
||||
#ifdef MOBILE
|
||||
displayStat(6, XLAT("sight range"), its(sightrange), 'a');
|
||||
extern int fontscale;
|
||||
displayStat(7, XLAT("font scale"), its(fontscale), 'b');
|
||||
#endif
|
||||
|
||||
displayStat(12, XLAT("message flash time"), its(vid.flashtime), 't');
|
||||
#ifndef MOBILE
|
||||
displayStat(13, XLAT("targetting ranged Orbs Shift+click only"), ONOFF(vid.shifttarget), 'i');
|
||||
#endif
|
||||
#ifdef STEAM
|
||||
displayStat(14, XLAT("send scores to Steam leaderboards"), ONOFF(vid.steamscore), 'l');
|
||||
#endif
|
||||
}
|
||||
|
||||
void handleVisual2(int sym, int uni) {
|
||||
char xuni = uni | 96;
|
||||
|
||||
if(xuni == 'v' || sym == SDLK_F2 || sym == SDLK_ESCAPE) cmode = emNormal;
|
||||
#ifndef ANDROID
|
||||
if(xuni == 's') saveConfig();
|
||||
#endif
|
||||
|
||||
if(sym == SDLK_F1 || sym == 'h')
|
||||
lastmode = cmode, cmode = emHelp;
|
||||
#ifdef GL
|
||||
|
||||
#ifndef MOBILE
|
||||
if(xuni == 'o' && shiftmul > 0) {
|
||||
vid.usingGL = !vid.usingGL;
|
||||
if(vid.usingGL) addMessage(XLAT("openGL mode enabled"));
|
||||
if(!vid.usingGL) addMessage(XLAT("openGL mode disabled"));
|
||||
setvideomode();
|
||||
}
|
||||
#endif
|
||||
|
||||
if(xuni == 'o' && shiftmul < 0 && !vid.usingGL) {
|
||||
vid.usingAA = !vid.usingAA;
|
||||
if(vid.usingAA) addMessage(XLAT("anti-aliasing enabled"));
|
||||
if(!vid.usingAA) addMessage(XLAT("anti-aliasing disabled"));
|
||||
}
|
||||
#endif
|
||||
|
||||
if(xuni == 'f') {
|
||||
vid.framelimit += int(10.5 * shiftmul);
|
||||
if(vid.framelimit < 5) vid.framelimit = 5;
|
||||
}
|
||||
|
||||
#ifdef MOBILE
|
||||
if(xuni == 'a') {
|
||||
sightrange += shiftmul>0?1:-1;
|
||||
if(sightrange < 4) sightrange = 4;
|
||||
if(sightrange > 7) sightrange = 7;
|
||||
}
|
||||
|
||||
if(xuni =='b') {
|
||||
extern int fontscale;
|
||||
fontscale += int(shiftmul * 10);
|
||||
}
|
||||
#endif
|
||||
|
||||
if(xuni == 'a') vid.joyvalue += int(shiftmul * 100);
|
||||
if(xuni == 'b') vid.joyvalue2 += int(shiftmul * 100);
|
||||
if(xuni == 'c') vid.joypanthreshold += int(shiftmul * 100);
|
||||
if(xuni == 'd') vid.joypanspeed += shiftmul / 50000;
|
||||
if(xuni == 'e') vid.eye += shiftmul * 0.01;
|
||||
#ifdef STEAM
|
||||
if(xuni == 'l') vid.steamscore = !vid.steamscore;
|
||||
#endif
|
||||
if(xuni == 't') vid.flashtime += shiftmul>0?1:-1;
|
||||
|
||||
if(xuni == 'p') autojoy = !autojoy;
|
||||
if(xuni == 'i') { vid.shifttarget = !vid.shifttarget; }
|
||||
}
|
||||
|
||||
void showChangeMode() {
|
||||
#ifndef MOBILE
|
||||
displayStat(2, XLAT("vector graphics editor"), "", 'g');
|
||||
displayStat(3, XLAT("map editor"), ONOFF(false), 'm');
|
||||
#endif
|
||||
displayStat(4, XLAT("cheat mode"), ONOFF(cheater), 'c');
|
||||
|
||||
displayStat(6, XLAT("Euclidean mode"), ONOFF(euclid), 'e');
|
||||
#ifndef MOBILE
|
||||
displayStat(7,
|
||||
XLAT("shoot'em up mode") + " " + XLAT("(includes co-op)"),
|
||||
ONOFF(shmup::on), 's');
|
||||
#endif
|
||||
if(!shmup::on) displayStat(8, XLAT("hardcore mode"),
|
||||
hardcore && !pureHardcore() ? XLAT("PARTIAL") : ONOFF(hardcore), 'h');
|
||||
|
||||
displayStat(9, XLAT("%1 Challenge", moPrincess), ONOFF(princess::challenge), 'p');
|
||||
displayStat(10, XLAT("random pattern mode"), ONOFF(randomPatternsMode), 'r');
|
||||
displayStat(11, XLAT("Yendor Challenge"), ONOFF(yendor::on), 'y');
|
||||
#ifndef ANDROID
|
||||
displayStat(12, XLAT("pure tactics mode"), ONOFF(tactic::on), 't');
|
||||
#endif
|
||||
#ifndef MOBILE
|
||||
displayStat(13, XLAT("hypersian rug mode"), ONOFF(rug::rugged), 'u');
|
||||
#endif
|
||||
displayStat(14, XLAT("heptagonal mode"), ONOFF(purehepta), '7');
|
||||
displayStat(15, XLAT("Chaos mode"), ONOFF(chaosmode), 'C');
|
||||
|
||||
#ifndef MOBILE
|
||||
displayStat(16, XLAT("paper model creator"), ONOFF(false), 'n');
|
||||
#endif
|
||||
displayStat(17, XLAT("conformal/history mode"), ONOFF(conformal::on), 'a');
|
||||
|
||||
displayStat(19, XLAT("return to the game"), "", 'v');
|
||||
}
|
||||
|
||||
void handleChangeMode(int sym, int uni) {
|
||||
|
||||
char xuni = uni;
|
||||
|
||||
if((uni >= 'A' && uni <= 'Z') || (uni >= 1 && uni <= 26)) xuni |= 96;
|
||||
|
||||
if(xuni == 'v' || sym == SDLK_F2 || sym == SDLK_ESCAPE) cmode = emNormal;
|
||||
|
||||
if(uni == 'c') {
|
||||
if(tactic::on && gold()) {
|
||||
addMessage(XLAT("Not available in the pure tactics mode!"));
|
||||
}
|
||||
else if(!cheater) {
|
||||
cheater++;
|
||||
addMessage(XLAT("You activate your demonic powers!"));
|
||||
#ifndef MOBILE
|
||||
addMessage(XLAT("Shift+F, Shift+O, Shift+T, Shift+L, Shift+U, etc."));
|
||||
#endif
|
||||
cmode = emNormal;
|
||||
}
|
||||
else {
|
||||
cmode = emNormal;
|
||||
firstland = princess::challenge ? laPalace : laIce;
|
||||
restartGame();
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef MOBILE
|
||||
if(xuni == 'g') {
|
||||
cmode = emDraw;
|
||||
mapeditor::drawcell = cwt.c;
|
||||
}
|
||||
#endif
|
||||
if(xuni == 'e') {
|
||||
cmode = emPickEuclidean;
|
||||
}
|
||||
if(xuni == 't') {
|
||||
cmode = emTactic;
|
||||
}
|
||||
#ifndef MOBILE
|
||||
if(xuni == 'u')
|
||||
rug::select();
|
||||
#endif
|
||||
if(xuni == 'y') {
|
||||
if(yendor::everwon)
|
||||
cmode = emYendor;
|
||||
else {
|
||||
cmode = emHelp;
|
||||
help = yendor::chelp;
|
||||
lastmode = emChangeMode;
|
||||
}
|
||||
}
|
||||
if(xuni == '7')
|
||||
restartGame('7');
|
||||
if(uni == 'a')
|
||||
cmode = emConformal;
|
||||
if(uni == 'C') {
|
||||
if(!chaosmode) {
|
||||
cmode = emHelp;
|
||||
help =
|
||||
"In the Chaos mode, lands change very often, and "
|
||||
"there are no walls between them. "
|
||||
"Some lands are incompatible with this."
|
||||
"\n\nYou need to reach Crossroads IV to unlock the Chaos mode.";
|
||||
lastmode = chaosUnlocked ? emNormal : emChangeMode;
|
||||
}
|
||||
if(chaosUnlocked) restartGame('C');
|
||||
}
|
||||
if(xuni == 'p') {
|
||||
if(!princess::everSaved)
|
||||
addMessage(XLAT("Save %the1 first to unlock this challenge!", moPrincess));
|
||||
else {
|
||||
restartGame('p');
|
||||
cmode = emNormal;
|
||||
}
|
||||
}
|
||||
#ifndef MOBILE
|
||||
if(xuni == 'm') {
|
||||
if(tactic::on)
|
||||
addMessage(XLAT("Not available in the pure tactics mode!"));
|
||||
else {
|
||||
cheater++;
|
||||
cmode = emMapEditor;
|
||||
lastexplore = turncount;
|
||||
addMessage(XLAT("You activate your terraforming powers!"));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if(xuni == 's')
|
||||
cmode = emShmupConfig;
|
||||
if(xuni == 'n')
|
||||
cmode = emNetgen;
|
||||
if(xuni == 'h' && !shmup::on) {
|
||||
if(hardcore && !canmove) { }
|
||||
else if(hardcore && canmove) { hardcore = false; }
|
||||
else { hardcore = true; canmove = true; hardcoreAt = turncount; }
|
||||
if(hardcore)
|
||||
addMessage("One wrong move, and it is game over!");
|
||||
else
|
||||
addMessage("Not so hardcore?");
|
||||
if(pureHardcore()) cmode = emNormal;
|
||||
}
|
||||
if(xuni == 'r') {
|
||||
firstland = laIce;
|
||||
restartGame('r');
|
||||
cmode = emNormal;
|
||||
}
|
||||
}
|
||||
|
||||
void showCheatMenu() {
|
||||
displayStat(0, XLAT("gain orb powers"), "", 'F');
|
||||
displayStat(1, XLAT("summon treasure"), "", 'T');
|
||||
displayStat(2, XLAT("summon dead orbs"), "", 'D');
|
||||
displayStat(3, XLAT("lose all treasure"), "", 'J');
|
||||
displayStat(4, XLAT("gain kills"), "", 'K');
|
||||
displayStat(5, XLAT("Hyperstone Quest"), "", 'C');
|
||||
displayStat(6, XLAT("summon orbs"), "", 'O');
|
||||
displayStat(7, XLAT("gain Orb of Yendor"), "", 'Y');
|
||||
displayStat(8, XLAT("summon lots of treasure"), "", 'T'-64);
|
||||
displayStat(9, XLAT("Safety (quick save)"), "", 'S');
|
||||
displayStat(10, XLAT("Select the land ---"), "", 'L');
|
||||
displayStat(11, XLAT("--- and teleport there"), "", 'U');
|
||||
displayStat(12, XLAT("rotate the character"), "", 'Z');
|
||||
displayStat(13, XLAT("summon a Golem"), "", 'G');
|
||||
displayStat(14, XLAT("summon Sandworm"), "", 'W');
|
||||
displayStat(15, XLAT("summon Ivy"), "", 'I');
|
||||
displayStat(16, XLAT("summon a Monster"), "", 'E');
|
||||
displayStat(17, XLAT("summon Thumpers"), "", 'H');
|
||||
displayStat(18, XLAT("summon Bonfire"), "", 'B');
|
||||
displayStat(19, XLAT("summon Mimics"), "", 'M');
|
||||
displayStat(20, XLAT("deplete orb powers"), "", 'P');
|
||||
displayStat(21, XLAT("summon Orb of Yendor"), "", 'Y'-64);
|
||||
displayStat(22, XLAT("switch ghost timer"), "", 'G'-64);
|
||||
displayStat(23, XLAT("switch web display"), "", 'W'-64);
|
||||
displayStat(-2, XLAT("return to the game"), "", ' ');
|
||||
}
|
||||
|
||||
void handleCheatMenu(int uni) {
|
||||
if(uni != 0) {
|
||||
applyCheat(uni);
|
||||
if(uni == 'F' || uni == 'C' || uni == 'O' ||
|
||||
uni == 'S' || uni == 'U' || uni == 'G' ||
|
||||
uni == 'W' || uni == 'I' || uni == 'E' ||
|
||||
uni == 'H' || uni == 'B' || uni == 'M' ||
|
||||
uni == 'P' || uni == 'Y'-64 || uni == 'G'-64 ||
|
||||
uni == ' ')
|
||||
cmode = emNormal;
|
||||
}
|
||||
}
|
||||
|
||||
void showCustomizeChar() {
|
||||
displayStatHelp(0, XLAT("Customize character"));
|
||||
|
||||
if(shmup::on) shmup::cpid = shmup::cpid_edit % shmup::players;
|
||||
charstyle& cs = getcs();
|
||||
|
||||
displayStat(2, XLAT("character"), csname(cs), 'g');
|
||||
displayStat(3, XLAT("skin color"), "?", 's');
|
||||
displayStat(4, XLAT("weapon color"), "?", 'w');
|
||||
displayStat(5, XLAT("hair color"), "?", 'h');
|
||||
|
||||
if(cs.charid >= 1) displayStat(6, XLAT("dress color"), "?", 'd');
|
||||
if(cs.charid == 3) displayStat(7, XLAT("dress color II"), "?", 'f');
|
||||
|
||||
if(!shmup::on) displayStat(8, XLAT("save whom"), XLAT1(minf[moPrincess].name), 'p');
|
||||
|
||||
if(numplayers() > 1) displayStat(8, XLAT("player"), its(shmup::cpid+1), 'a');
|
||||
|
||||
displayStatHelp(16, XLAT("Shift=random, Ctrl=mix"));
|
||||
|
||||
displayStat(19, XLAT("return to the game"), "", 'v');
|
||||
}
|
||||
|
||||
void switchcolor(int& c, unsigned int* cs, int mod) {
|
||||
int id = 0;
|
||||
int q = cs[0]; cs++;
|
||||
for(int i=0; i<q; i++) if(c == (int) cs[i]) id = i;
|
||||
if(mod == 1)
|
||||
c = ((rand() % 0x1000000) << 8) | 0xFF;
|
||||
else if(mod == 2)
|
||||
c = (gradient(cs[rand() % q] >> 8, cs[rand() % q] >> 8, 0, rand() % 101, 100) << 8) + 0xFF;
|
||||
else
|
||||
c = cs[(id+1) % q];
|
||||
}
|
||||
|
||||
void handleCustomizeChar(int sym, int uni, int mod) {
|
||||
|
||||
char xuni = uni | 96;
|
||||
if(shiftmul < -.5) mod = 1;
|
||||
else if(shiftmul > -.2 && shiftmul < .2) mod = 2;
|
||||
else mod = 0;
|
||||
|
||||
if(shmup::on) shmup::cpid = shmup::cpid_edit % shmup::players;
|
||||
charstyle& cs = getcs();
|
||||
if(xuni == 'a') { shmup::cpid_edit++; shmup::cpid_edit %= 60; }
|
||||
if(xuni == 'g') {
|
||||
cs.charid++;
|
||||
if(cs.charid == 2 && !princess::everSaved) cs.charid = 4;
|
||||
cs.charid %= 8;
|
||||
}
|
||||
if(xuni == 'p') vid.samegender = !vid.samegender;
|
||||
bool cat = cs.charid >= 4;
|
||||
if(xuni == 's') switchcolor(cs.skincolor, cat ? haircolors : skincolors, mod);
|
||||
if(xuni == 'h') switchcolor(cs.haircolor, haircolors, mod);
|
||||
if(xuni == 'w') switchcolor(cs.swordcolor, cat ? eyecolors : swordcolors, mod);
|
||||
if(xuni == 'd') switchcolor(cs.dresscolor, cat ? haircolors : dresscolors, mod);
|
||||
if(xuni == 'f') switchcolor(cs.dresscolor2, dresscolors2, mod);
|
||||
if(xuni == 'v' || sym == SDLK_F2 || sym == SDLK_ESCAPE) cmode = emNormal;
|
||||
}
|
||||
|
||||
int eupage = 0;
|
||||
int euperpage = 21;
|
||||
|
||||
void showEuclideanMenu() {
|
||||
int s = vid.fsize;
|
||||
vid.fsize = vid.fsize * 4/5;
|
||||
displayStatHelp(-8, XLAT("Euclidean mode"));
|
||||
if(cheater) for(int i=0; i<landtypes; i++) landvisited[i] = true;
|
||||
for(int i=0; i<landtypes; i++)
|
||||
if(hiitemsMax(treasureType(eLand(i))) >= 25) landvisited[i] = true;
|
||||
landvisited[laCrossroads] = true;
|
||||
landvisited[laIce] = true;
|
||||
landvisited[laMirror] = true;
|
||||
landvisited[laPrincessQuest] = princess::everSaved;
|
||||
landvisited[laWildWest] = true;
|
||||
// for(int i=2; i<lt; i++) landvisited[i] = true;
|
||||
for(int i=0; i<euperpage; i++) {
|
||||
if(euperpage * eupage + i >= LAND_EUC) break;
|
||||
eLand l = land_euc[euperpage * eupage + i];
|
||||
if(landvisited[l]) {
|
||||
char ch;
|
||||
if(i < 26) ch = 'a' + i;
|
||||
else ch = 'A' + (i-26);
|
||||
displayStat(i-6, XLAT1(linf[l].name), "", ch);
|
||||
}
|
||||
}
|
||||
displayStat(euperpage+1-6, XLAT("Return to the hyperbolic world"), "", '0');
|
||||
displayStat(euperpage+2-6, XLAT("Next page"), "", '-');
|
||||
displayStatHelp(euperpage+4-6, XLAT("Choose from the lands visited this game."));
|
||||
#ifdef HAVE_ACHIEVEMENTS
|
||||
displayStatHelp(euperpage+6-6, XLAT("Scores and achievements are not"));
|
||||
displayStatHelp(euperpage+7-6, XLAT("saved in the Euclidean mode!"));
|
||||
#endif
|
||||
vid.fsize = s;
|
||||
}
|
||||
|
||||
void handleEuclidean(int sym, int uni) {
|
||||
int lid;
|
||||
if(uni >= 'a' && uni <= 'z') lid = uni - 'a';
|
||||
else if(uni >= 'A' && uni <= 'Z') lid = 26 + uni - 'A';
|
||||
else lid = -1;
|
||||
|
||||
if(lid >= 0) lid += euperpage * eupage;
|
||||
|
||||
if(uni == '0') {
|
||||
if(euclid) restartGame('e');
|
||||
cmode = emNormal;
|
||||
}
|
||||
else if(uni == '-') {
|
||||
eupage++;
|
||||
if(eupage * euperpage >= LAND_EUC) eupage = 0;
|
||||
}
|
||||
else if(lid >= 0 && lid < LAND_EUC) {
|
||||
euclidland = land_euc[lid];
|
||||
if(landvisited[euclidland] && euclidland != laOceanWall) {
|
||||
if(euclid) restartGame();
|
||||
else restartGame('e');
|
||||
cmode = emNormal;
|
||||
}
|
||||
else euclidland = laIce;
|
||||
}
|
||||
else if(uni == '2' || sym == SDLK_F1) {
|
||||
help =
|
||||
"If you want to know how much the gameplay is affected by the "
|
||||
"hyperbolic geometry in HyperRogue, this mode is for you!\n\n"
|
||||
|
||||
"You can play an Euclidean version of each of the lands in "
|
||||
"HyperRogue. Lands which include horocycles (Temple, Caribbean, "
|
||||
"Whirlpool), infinite trees (Zebra, Emerald), or networks of "
|
||||
"ultraparallel lines (Crossroads, Vineyard, Palace) cannot be "
|
||||
"faithfully represented in Euclidean, so yo get more "
|
||||
"or less simplified versions of them. Choose Crossroads to play a game "
|
||||
"where many different lands appear.";
|
||||
cmode = emHelp;
|
||||
lastmode = emPickEuclidean;
|
||||
}
|
||||
else if(uni) cmode = emNormal;
|
||||
}
|
||||
|
||||
void showConfig() {
|
||||
displayStatHelp(0, XLAT("Configuration:"));
|
||||
|
||||
if(cmode == emVisual1) showVisual1(); else showVisual2();
|
||||
|
||||
#ifndef MOBILE
|
||||
displayStatHelp(16, XLAT("use Shift to decrease and Ctrl to fine tune "));
|
||||
displayStatHelp(17, XLAT("(e.g. Shift+Ctrl+Z)"));
|
||||
#endif
|
||||
|
||||
displayStat(19, XLAT("exit configuration"), "", 'v');
|
||||
#ifdef ANDROID
|
||||
displayStat(16, XLAT("settings set here won't be saved"), "", 's');
|
||||
displayStat(17, XLAT("-- use the Android menu instead"), "", 's');
|
||||
#else
|
||||
displayStat(21, XLAT("save the current config"), "", 's');
|
||||
#endif
|
||||
}
|
||||
|
||||
void handleMenus(int sym, int uni, int mod) {
|
||||
if(cmode == emOverview) handleOverview(uni);
|
||||
else if(cmode == emYendor) yendor::handleKey(uni, sym);
|
||||
else if(cmode == emChangeMode) handleChangeMode(uni, sym);
|
||||
else if(cmode == emVisual1) handleVisual1(uni, sym);
|
||||
else if(cmode == emMenu) handleMenuKey(uni, false);
|
||||
else if(cmode == emCheatMenu) handleCheatMenu(uni);
|
||||
else if(cmode == emVisual2) handleVisual2(uni, sym);
|
||||
else if(cmode == emPickEuclidean) handleEuclidean(uni, sym);
|
||||
else if(cmode == emCustomizeChar) handleCustomizeChar(uni, sym, 0);
|
||||
else if(cmode == emTactic) tactic::handleKey(uni, sym);
|
||||
else if(cmode == emConformal) conformal::handleKey(uni, sym);
|
||||
}
|
||||
|
||||
void displayMenus() {
|
||||
if(cmode == emOverview) showOverview();
|
||||
if(cmode == emYendor) yendor::showMenu();
|
||||
if(cmode == emChangeMode) showChangeMode();
|
||||
if(cmode == emCustomizeChar) showCustomizeChar();
|
||||
if(cmode == emShmupConfig) shmup::showShmupConfig();
|
||||
if(cmode == emConformal) conformal::show();
|
||||
if(cmode == emTactic) tactic::showMenu();
|
||||
if(cmode == emPickEuclidean) showEuclideanMenu();
|
||||
if(cmode == emMenu) showMainMenu();
|
||||
if(cmode == emCheatMenu) showCheatMenu();
|
||||
if(cmode == emVisual1 || cmode == emVisual2) showConfig();
|
||||
|
||||
#ifndef MOBILE
|
||||
if(cmode == emNetgen) netgen::show();
|
||||
if(cmode == emRugConfig) rug::show();
|
||||
if(cmode == emMapEditor) mapeditor::showMapEditor();
|
||||
if(cmode == emDraw) mapeditor::showDrawEditor();
|
||||
#endif
|
||||
|
||||
#ifndef ANDROID
|
||||
if(cmode == emScores) showScores();
|
||||
if(cmode == emPickScores) showPickScores();
|
||||
#endif
|
||||
}
|
@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
// mtrand.cpp, see include file mtrand.h for information
|
||||
|
||||
#include "mtrand.h"
|
||||
|
702
netgen.cpp
Normal file
702
netgen.cpp
Normal file
@ -0,0 +1,702 @@
|
||||
// HyperRogue paper model generator
|
||||
// Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details
|
||||
|
||||
#ifndef MOBILE
|
||||
namespace netgen {
|
||||
|
||||
// We need a two-dimensional vector class for this.
|
||||
|
||||
struct vec {
|
||||
double x, y;
|
||||
vec(double _x, double _y) : x(_x), y(_y) { }
|
||||
vec() : x(0), y(0) {}
|
||||
};
|
||||
|
||||
vec& operator += (vec& a, const vec b) { a.x += b.x; a.y += b.y; return a; }
|
||||
vec& operator -= (vec& a, const vec b) { a.x -= b.x; a.y -= b.y; return a; }
|
||||
|
||||
// coordinatewise multiplication and division
|
||||
vec& operator *= (vec& a, const vec b) { a.x *= b.x; a.y *= b.y; return a; }
|
||||
vec& operator *= (vec& a, double scalar) { a.x *= scalar; a.y *= scalar; return a; }
|
||||
vec& operator /= (vec& a, const vec b) { a.x /= b.x; a.y /= b.y; return a; }
|
||||
vec& operator /= (vec& a, double scalar) { a.x /= scalar; a.y /= scalar; return a; }
|
||||
|
||||
vec operator + (vec a, const vec b) { return a+=b; }
|
||||
vec operator - (vec a, const vec b) { return a-=b; }
|
||||
vec operator * (vec a, const vec b) { return a*=b; }
|
||||
vec operator / (vec a, const vec b) { return a/=b; }
|
||||
|
||||
vec operator * (vec a, double scalar) { return a*=scalar; }
|
||||
vec operator * (double scalar, vec a) { return a*=scalar; }
|
||||
vec operator / (vec a, double scalar) { return a/=scalar; }
|
||||
vec operator / (double scalar, vec a) { return a/=scalar; }
|
||||
|
||||
vec ang(double f) { return vec(cos(f), sin(f)); }
|
||||
|
||||
double norm(vec v) { return v.x*v.x+v.y*v.y; }
|
||||
|
||||
// the parameters.
|
||||
|
||||
bool loaded;
|
||||
|
||||
int SCALE, PX, PY, BASE, SX, SY, CELLS, fontsize, created;
|
||||
double el;
|
||||
#define MAXCELLS 1000
|
||||
|
||||
// All the datatables stored in the net files.
|
||||
|
||||
int ct[MAXCELLS];
|
||||
double vx[MAXCELLS][16];
|
||||
vec center[MAXCELLS];
|
||||
double rot[MAXCELLS];
|
||||
int glued[MAXCELLS];
|
||||
int nei[MAXCELLS][7];
|
||||
|
||||
// auxiliary data
|
||||
double raylen[MAXCELLS];
|
||||
double edgist[MAXCELLS];
|
||||
char patek[MAXCELLS][7];
|
||||
|
||||
// data generated by HyperRogue
|
||||
hyperpoint hcenter[MAXCELLS][8];
|
||||
|
||||
// Functions handling the data.
|
||||
//==============================
|
||||
|
||||
// Use HyperRogue to generate the data (ct, vx, nei).
|
||||
|
||||
int mode = 0;
|
||||
|
||||
void buildVertexInfo(cell *c, transmatrix V) {
|
||||
|
||||
if(mode == 1)
|
||||
for(int ii=0; ii<CELLS; ii++) if(dcal[ii] == c) {
|
||||
|
||||
hcenter[ii][7] = V * C0;
|
||||
|
||||
if(c->type == 7) {
|
||||
for(int i=0; i<c->type; i++) {
|
||||
|
||||
int hdir = displaydir(c, i) + 6;
|
||||
|
||||
transmatrix V2 = V * spin(hdir * M_PI / 42) * xpush(hexf);
|
||||
|
||||
hcenter[ii][i] = V2 * C0;
|
||||
}
|
||||
}
|
||||
|
||||
if(c->type == 6) {
|
||||
for(int i=0; i<c->type; i++) {
|
||||
|
||||
int hdir = displaydir(c, i);
|
||||
|
||||
transmatrix V2 =
|
||||
V * spin(hdir * M_PI / 42) * xpush(crossf) * spin(M_PI*8/7) * xpush(hexf);
|
||||
|
||||
hcenter[ii][i] = V2 * C0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void dataFromHR() {
|
||||
mode = 1;
|
||||
drawthemap();
|
||||
mode = 0;
|
||||
|
||||
for(int i=0; i<CELLS; i++) {
|
||||
ct[i] = dcal[i]->type;
|
||||
for(int k=0; k<8; k++)
|
||||
vx[i][2*k] = hcenter[i][k][0],
|
||||
vx[i][2*k+1] = hcenter[i][k][1];
|
||||
|
||||
for(int k=0; k<ct[i]; k++) nei[i][k] = -1;
|
||||
|
||||
for(int j=0; j<CELLS; j++) {
|
||||
cell *c1 = dcal[i];
|
||||
cell *c2 = dcal[j];
|
||||
for(int k=0; k<c1->type; k++) if(c1->mov[k] == c2)
|
||||
nei[i][k] = j;
|
||||
}
|
||||
}
|
||||
|
||||
for(int i=0; i<CELLS; i++) {
|
||||
center[i] = vec(SX/2, SY/2);
|
||||
rot[i] = 0;
|
||||
glued[i] = -1;
|
||||
for(int e=0; e<ct[i]; e++)
|
||||
if(nei[i][e] < i && nei[i][e] != -1 && (glued[i] == -1 || nei[i][e] < glued[i])) {
|
||||
glued[i] = nei[i][e];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loadData() {
|
||||
|
||||
FILE *f = fopen("papermodeldata.txt", "rt");
|
||||
if(!f) return;
|
||||
|
||||
int err = fscanf(f, "%d %d %d %d %d %d %d %lf %d\n\n",
|
||||
&CELLS, &SX, &SY, &PX, &PY, &SCALE, &BASE, &el, &created);
|
||||
if(err != 9) { fclose(f); return; }
|
||||
|
||||
loaded = true;
|
||||
|
||||
if(!created) return;
|
||||
|
||||
for(int i=0; i<CELLS; i++) err = fscanf(f, "%d", &ct[i]);
|
||||
|
||||
for(int i=0; i<CELLS; i++) for(int j=0; j<16; j++)
|
||||
err = fscanf(f, "%lf" ,&vx[i][j]);
|
||||
|
||||
for(int i=0; i<CELLS; i++)
|
||||
for(int j=0; j<7; j++) nei[i][j] = -1;
|
||||
|
||||
while(true) {
|
||||
int a, b, c;
|
||||
err = fscanf(f, "%d%d%d", &a, &b, &c);
|
||||
if(a < 0) break;
|
||||
else nei[a][c] = b;
|
||||
}
|
||||
|
||||
for(int i=0; i<CELLS; i++) {
|
||||
double dx, dy, dr;
|
||||
int g;
|
||||
err = fscanf(f, "%lf%lf%lf%d\n", &dx, &dy, &dr, &g);
|
||||
center[i] = vec(dx, dy);
|
||||
rot[i] = dr;
|
||||
glued[i] = g;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
void saveData() {
|
||||
// global parameters
|
||||
FILE *f = fopen("papermodeldata2.txt", "wt");
|
||||
if(!f) {
|
||||
addMessage("Could not save the paper model data");
|
||||
return;
|
||||
}
|
||||
fprintf(f, "%d %d %d %d %d %d %d %lf %d\n\n", CELLS, SX, SY, PX, PY, SCALE, BASE, el, created);
|
||||
|
||||
// net parameters: cell types
|
||||
for(int i=0; i<CELLS; i++)
|
||||
fprintf(f, "%d ", ct[i]);
|
||||
fprintf(f, "\n");
|
||||
|
||||
// net parameters: hcenters
|
||||
for(int i=0; i<CELLS; i++) {
|
||||
for(int k=0; k<16; k++)
|
||||
fprintf(f, "%9.6lf ", vx[i][k]);
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
fprintf(f, "\n\n");
|
||||
|
||||
// create netgen
|
||||
for(int i=0; i<CELLS; i++) for(int j=0; j<CELLS; j++) {
|
||||
for(int k=0; k<ct[i]; k++) if(nei[i][k] == j)
|
||||
fprintf(f, "%d %d %d ", i, j, k);
|
||||
}
|
||||
fprintf(f, "-1 -1 -1\n\n");
|
||||
|
||||
// graphics
|
||||
for(int i=0; i<CELLS; i++)
|
||||
fprintf(f, "%12.7lf %12.7lf %10.7lf %d\n",
|
||||
center[i].x, center[i].y, rot[i], glued[i]
|
||||
);
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
// Simple graphical functions
|
||||
//============================
|
||||
|
||||
void blackline(vec v1, vec v2, int col = 0x000000FF) {
|
||||
#ifdef GFX
|
||||
aalineColor(s, int(v1.x), int(v1.y), int(v2.x), int(v2.y), col);
|
||||
#endif
|
||||
}
|
||||
|
||||
void drawtriangle(vec v1, vec v2, vec v3, int col) {
|
||||
#ifdef GFX
|
||||
polyx[0] = int(v1.x);
|
||||
polyx[1] = int(v2.x);
|
||||
polyx[2] = int(v3.x);
|
||||
polyy[0] = int(v1.y);
|
||||
polyy[1] = int(v2.y);
|
||||
polyy[2] = int(v3.y);
|
||||
filledPolygonColor(s, polyx, polyy, 3, col);
|
||||
#endif
|
||||
}
|
||||
|
||||
void blackcircle(vec v, int r, int col = 0x000000FF) {
|
||||
#ifdef GFX
|
||||
aacircleColor(s, int(v.x), int(v.y), r, col);
|
||||
#endif
|
||||
}
|
||||
|
||||
void blacktext(vec v, char c) {
|
||||
char str[2]; str[0] = c; str[1] = 0;
|
||||
int tsize = int(el * 12/27);
|
||||
displaystr(int(v.x), int(v.y), 0, tsize, str, 0, 8);
|
||||
}
|
||||
|
||||
hyperpoint hvec(int i, int e) {
|
||||
return hpxy(vx[i][2*e], vx[i][2*e+1]);
|
||||
}
|
||||
|
||||
bool wellspread(double d1, double d2, double d3, int &co) {
|
||||
int id1 = int(d1);
|
||||
int id2 = int(d2);
|
||||
int id3 = int(d3);
|
||||
co = min(min(id1,id2),id3);
|
||||
return (id1 <= co+1 && id2 <= co+1 && id3 <= co+1);
|
||||
}
|
||||
|
||||
SDL_Surface *net, *hqsurface;
|
||||
|
||||
int& hqpixel(hyperpoint h) {
|
||||
int hx, hy, hs;
|
||||
getcoord(h, hx, hy, hs);
|
||||
return qpixel(hqsurface, hx, hy);
|
||||
}
|
||||
|
||||
void copyhypertriangle(
|
||||
vec g1, vec g2, vec g3,
|
||||
hyperpoint h1, hyperpoint h2, hyperpoint h3) {
|
||||
int ix, iy;
|
||||
|
||||
if(wellspread(g1.x,g2.x,g3.x,ix) && wellspread(g1.y,g2.y,g3.y,iy))
|
||||
qpixel(net,ix,iy) = hqpixel(h1);
|
||||
else {
|
||||
|
||||
vec g4 = (g2+g3)/2;
|
||||
vec g5 = (g3+g1)/2;
|
||||
vec g6 = (g1+g2)/2;
|
||||
|
||||
hyperpoint h4 = mid(h2,h3);
|
||||
hyperpoint h5 = mid(h3,h1);
|
||||
hyperpoint h6 = mid(h1,h2);
|
||||
|
||||
copyhypertriangle(g1,g5,g6, h1,h5,h6);
|
||||
copyhypertriangle(g5,g3,g4, h5,h3,h4);
|
||||
copyhypertriangle(g6,g4,g2, h6,h4,h2);
|
||||
copyhypertriangle(g4,g6,g5, h4,h6,h5);
|
||||
}
|
||||
}
|
||||
|
||||
void setRaylen() {
|
||||
for(int i=0; i<CELLS; i++) {
|
||||
raylen[i] = el / sin(M_PI / ct[i]);
|
||||
edgist[i] = raylen[i] * cos(M_PI / ct[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// draw the model
|
||||
void createPapermodel() {
|
||||
|
||||
#ifndef GFX
|
||||
addMessage(XLAT("High quality shots not available on this platform"));
|
||||
return;
|
||||
#endif
|
||||
|
||||
loadData();
|
||||
|
||||
SDL_Surface *sav = s;
|
||||
|
||||
s = hqsurface = SDL_CreateRGBSurface(SDL_SWSURFACE,BASE,BASE,32,0,0,0,0);
|
||||
|
||||
videopar vid2 = vid;
|
||||
vid.xres = vid.yres = 2000; vid.scale = 0.99; vid.usingGL = false;
|
||||
int sch = cheater; cheater = 0;
|
||||
calcparam();
|
||||
|
||||
mode = 2;
|
||||
|
||||
darken = 0;
|
||||
SDL_FillRect(s, NULL, 0);
|
||||
drawfullmap();
|
||||
|
||||
mode = 0;
|
||||
|
||||
/* for(int i=0; i<CELLS; i++) {
|
||||
int t = ct[i];
|
||||
for(int e=0; e<t; e++)
|
||||
drawline(hvec(i,e), hvec(i,(e+1)%t), 0x80808080);
|
||||
for(int e=0; e<7; e++)
|
||||
drawline(hvec(i,e), hvec(i,7), 0x80808080);
|
||||
} */
|
||||
|
||||
s = net = SDL_CreateRGBSurface(SDL_SWSURFACE,SX*SCALE,SY*SCALE,32,0,0,0,0);
|
||||
SDL_FillRect(net, NULL, 0xFFFFFF);
|
||||
|
||||
int pateks = 0;
|
||||
|
||||
int zeroi = nei[0][0];
|
||||
int zeroe = 0;
|
||||
for(int e=0; e<6; e++) if(nei[zeroi][e] == 0) zeroe = e;
|
||||
|
||||
el *= SCALE;
|
||||
setRaylen();
|
||||
|
||||
for(int faza=0; faza<2; faza++) for(int i=0; i<CELLS; i++) {
|
||||
|
||||
int t = ct[i];
|
||||
|
||||
printf("faza %d cell %d\n", faza, i);
|
||||
|
||||
for(int e=0; e<t; e++) {
|
||||
vec v1 = center[i] * SCALE + raylen[i] * ang(rot[i] + 2*M_PI*e/t);
|
||||
vec v2 = center[i] * SCALE + raylen[i] * ang(rot[i] + 2*M_PI*(e+1)/t);
|
||||
vec v3 = (v1+v2)/2;
|
||||
|
||||
if(faza == 1) blackline(v1, v2);
|
||||
|
||||
int ofs = t == 7 ? 0 : 5;
|
||||
|
||||
// 0,2,0 ~ 2,0,0
|
||||
|
||||
if(0) if((i==0 && e == 0) || (i == zeroi && e == zeroe)) {
|
||||
for(int ofs=0; ofs<t; ofs++) {
|
||||
printf("OFS %d: %s", ofs, display(hvec(i, (e+ofs)%t)));
|
||||
printf(" %s\n", display(hvec(i, (e+1+ofs)%t)));
|
||||
}
|
||||
}
|
||||
|
||||
if(faza == 0) copyhypertriangle(
|
||||
center[i] * SCALE, v1, v2,
|
||||
hvec(i,7), hvec(i, (e+ofs)%t), hvec(i, (e+1+ofs)%t)
|
||||
);
|
||||
|
||||
if(faza == 1)
|
||||
if(nei[i][e] != -1 && nei[i][e] != glued[i] && glued[nei[i][e]] != i) {
|
||||
vec vd = v2-v1;
|
||||
swap(vd.x, vd.y); vd.x = -vd.x;
|
||||
double factor = -sqrt(3)/6;
|
||||
vd.x *= factor;
|
||||
vd.y *= factor;
|
||||
vec v4 = v3 + vd;
|
||||
vec v5 = v3 + vd/2;
|
||||
|
||||
if(!patek[i][e]) {
|
||||
int i2 = nei[i][e];
|
||||
for(int e2=0; e2<ct[nei[i][e]]; e2++) if(nei[i2][e2] == i)
|
||||
patek[i][e] = patek[i2][e2] =
|
||||
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"!@#$%^&*+=~:;<>?/|\"., [{(\\]})" [(pateks++) % 85];
|
||||
}
|
||||
|
||||
int col = 0xFFFFFFFF;
|
||||
int p = patek[i][e];
|
||||
col -= 0x8000 * (p&1); p /= 2;
|
||||
col -= 0x800000 * (p&1); p /= 2;
|
||||
col -= 0x80000000 * (p&1); p /= 2;
|
||||
col -= 0x4000 * (p&1); p /= 2;
|
||||
col -= 0x400000 * (p&1); p /= 2;
|
||||
col -= 0x40000000 * (p&1); p /= 2;
|
||||
col -= 0x2000 * (p&1); p /= 2;
|
||||
col -= 0x200000 * (p&1); p /= 2;
|
||||
col -= 0x20000000 * (p&1); p /= 2;
|
||||
|
||||
drawtriangle(v1,v2,v4, col);
|
||||
|
||||
blacktext(v5, patek[i][e]);
|
||||
|
||||
blackline(v1, v4);
|
||||
blackline(v2, v4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("pateks = %d\n", pateks);
|
||||
|
||||
IMAGESAVE(net, "papermodel-all" IMAGEEXT);
|
||||
IMAGESAVE(hqsurface, "papermodel-source" IMAGEEXT);
|
||||
|
||||
int qx = SX*SCALE/PX;
|
||||
int qy = SY*SCALE/PY;
|
||||
SDL_Surface *quarter = SDL_CreateRGBSurface(SDL_SWSURFACE,qx,qy,32,0,0,0,0);
|
||||
for(int iy=0; iy<PY; iy++)
|
||||
for(int ix=0; ix<PX; ix++) {
|
||||
for(int y=0; y<qy; y++) for(int x=0; x<qx; x++)
|
||||
qpixel(quarter,x,y) = qpixel(net, x+qx*ix, y+qy*iy);
|
||||
char buf[64];
|
||||
sprintf(buf, "papermodel-page%d%d" IMAGEEXT, iy, ix);
|
||||
IMAGESAVE(quarter, buf);
|
||||
}
|
||||
|
||||
SDL_FreeSurface(net);
|
||||
SDL_FreeSurface(hqsurface);
|
||||
SDL_FreeSurface(quarter);
|
||||
|
||||
s = sav; vid = vid2; cheater = sch;
|
||||
}
|
||||
|
||||
vec mousepos, rel;
|
||||
|
||||
int bei = 0, bee = 0, whichcell = 0;
|
||||
double cedist;
|
||||
bool dragging = false;
|
||||
|
||||
int glueroot(int i) {
|
||||
if(glued[i] == -1) return i;
|
||||
return glueroot(glued[i]);
|
||||
}
|
||||
|
||||
void clicked(int x, int y, int b) {
|
||||
|
||||
mousepos = vec(x, y);
|
||||
|
||||
if(b == 1)
|
||||
rel = center[glueroot(whichcell)] - mousepos,
|
||||
dragging = true;
|
||||
|
||||
if(b == 17)
|
||||
dragging = false;
|
||||
|
||||
if(b == 32 && dragging)
|
||||
center[glueroot(whichcell)] = rel + mousepos;
|
||||
|
||||
}
|
||||
|
||||
void applyGlue(int i) {
|
||||
int j = glued[i];
|
||||
int it = ct[i];
|
||||
int jt = ct[j];
|
||||
int ie = 0, je = 0;
|
||||
for(int e=0; e<it; e++) if(nei[i][e] == j) ie = e;
|
||||
for(int e=0; e<jt; e++) if(nei[j][e] == i) je = e;
|
||||
|
||||
rot[i] = rot[j] + 2*M_PI*(je+.5)/jt - 2*M_PI*(ie+.5)/it + M_PI;
|
||||
center[i] =
|
||||
center[j] +
|
||||
(edgist[i]+edgist[j]) * ang(rot[j] + 2*M_PI*(je+.5)/jt);
|
||||
}
|
||||
|
||||
void displaynets() {
|
||||
SDL_LockSurface(s);
|
||||
|
||||
setRaylen();
|
||||
|
||||
for(int uy=SY-1; uy>=0; uy--)
|
||||
for(int ux=SX-1; ux>=0; ux--) {
|
||||
qpixel(s, ux, uy) = 0;
|
||||
}
|
||||
|
||||
for(int y=1; y<PY; y++)
|
||||
blackline(vec(0,SY*y/PY), vec(SX,SY*y/PY), 0x404080FF);
|
||||
|
||||
for(int x=1; x<PX; x++)
|
||||
blackline(vec(SX*x/PX,0), vec(SX*x/PX,SY), 0x404080FF);
|
||||
|
||||
for(int i=0; i<CELLS; i++) {
|
||||
|
||||
if(norm(center[i]-mousepos) < norm(center[whichcell]-mousepos))
|
||||
whichcell = i;
|
||||
|
||||
int t = ct[i];
|
||||
|
||||
if(i == whichcell)
|
||||
blackcircle(center[i], 10, 0x40FF40FF);
|
||||
|
||||
if(i == bei || i == nei[bei][bee])
|
||||
blackcircle(center[i], 5, 0x40FF40FF);
|
||||
|
||||
if(glued[i] == -1)
|
||||
blackcircle(center[i], 7, 0xFF4040FF);
|
||||
|
||||
if(glued[i] != -1)
|
||||
applyGlue(i);
|
||||
|
||||
for(int e=0; e<t; e++) {
|
||||
vec v1 = center[i] + raylen[i] * ang(rot[i] + 2*M_PI*e/t);
|
||||
vec v2 = center[i] + raylen[i] * ang(rot[i] + 2*M_PI*(e+1)/t);
|
||||
vec v3 = (v1+v2)/2;
|
||||
|
||||
if(nei[i][e] >= 0 && !dragging) {
|
||||
if(norm(v3-mousepos) < cedist) bei = i, bee = e;
|
||||
if(i == bei && e == bee) cedist = norm(v3-mousepos);
|
||||
}
|
||||
|
||||
int col =
|
||||
i == bei && e == bee ? 0x40FF40FF:
|
||||
i == nei[bei][bee] && nei[i][e] == bei ? 0x40FF40FF :
|
||||
nei[i][e] == glued[i] ? 0x303030FF :
|
||||
glued[nei[i][e]] == i ? 0x303030FF :
|
||||
nei[i][e] >= 0 ? 0xC0C0C0FF :
|
||||
0x808080FF;
|
||||
|
||||
blackline(v1, v2, col);
|
||||
|
||||
if(nei[i][e] != -1 && nei[i][e] != glued[i] && glued[nei[i][e]] != i) {
|
||||
vec vd = v2-v1;
|
||||
swap(vd.x, vd.y); vd.x = -vd.x;
|
||||
double factor = -sqrt(3)/6;
|
||||
vd.x *= factor; vd.y *= factor;
|
||||
vec v4 = v3 + vd;
|
||||
|
||||
blackline(v1, v4, 0xFFC0C0C0);
|
||||
blackline(v2, v4, 0xFFC0C0C0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_UnlockSurface(s);
|
||||
SDL_UpdateRect(s, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
double rs, rz;
|
||||
|
||||
void addglue() {
|
||||
int i = bei;
|
||||
int j = nei[bei][bee];
|
||||
if(glued[i] == j)
|
||||
glued[i] = -1;
|
||||
else if(glued[j] == i)
|
||||
glued[j] = -1;
|
||||
else if(glueroot(i) == glueroot(j))
|
||||
;
|
||||
else if(glued[j] == -1)
|
||||
glued[j] = i;
|
||||
}
|
||||
|
||||
int nti;
|
||||
|
||||
void smooth() {
|
||||
int ti = SDL_GetTicks();
|
||||
rot[whichcell] += rs * (nti - ti) / 1000.0;
|
||||
|
||||
el += rz * (nti - ti) / 1000.0;
|
||||
nti = ti;
|
||||
}
|
||||
|
||||
void netgen_loop() {
|
||||
nti = SDL_GetTicks();
|
||||
while(true) {
|
||||
smooth();
|
||||
displaynets();
|
||||
SDL_Event event;
|
||||
|
||||
while(SDL_PollEvent(&event)) switch (event.type) {
|
||||
case SDL_QUIT:
|
||||
exit(1);
|
||||
return;
|
||||
|
||||
case SDL_MOUSEBUTTONDOWN: {
|
||||
clicked(event.button.x, event.button.y, event.button.button);
|
||||
break;
|
||||
}
|
||||
|
||||
case SDL_MOUSEBUTTONUP: {
|
||||
clicked(event.button.x, event.button.y, 16+event.button.button);
|
||||
break;
|
||||
}
|
||||
|
||||
case SDL_MOUSEMOTION: {
|
||||
clicked(event.motion.x, event.motion.y, 32);
|
||||
break;
|
||||
}
|
||||
|
||||
case SDL_KEYDOWN: {
|
||||
int key = event.key.keysym.sym;
|
||||
int uni = event.key.keysym.unicode;
|
||||
|
||||
if(uni == 'q' || key == SDLK_ESCAPE || key == SDLK_F10)
|
||||
return;
|
||||
|
||||
if(key == SDLK_PAGEUP) rs = 3;
|
||||
if(key == SDLK_PAGEDOWN) rs = -3;
|
||||
if(uni == 'z') rz = 1;
|
||||
if(uni == 'x') rz = -1;
|
||||
if(uni == 'g') addglue();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SDL_KEYUP: {
|
||||
rs = 0;
|
||||
rz = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void designNet() {
|
||||
s = SDL_SetVideoMode(SX, SY, 32, 0);
|
||||
netgen_loop();
|
||||
saveData();
|
||||
setvideomode();
|
||||
}
|
||||
|
||||
void show() {
|
||||
if(true) {
|
||||
for(int i=0; i<CELLS; i++) {
|
||||
int t = ct[i];
|
||||
int ofs = t == 7 ? 0 : 5;
|
||||
for(int e=0; e<t; e++) {
|
||||
int col =
|
||||
nei[i][e] == glued[i] && glued[i] >= 0 ? 0x303030 :
|
||||
nei[i][e] >= 0 && glued[nei[i][e]] == i ? 0x303030 :
|
||||
nei[i][e] >= 0 ? 0x808080 :
|
||||
0xC0C0C0;
|
||||
|
||||
drawline(hvec(i, (e+ofs)%t), hvec(i, (e+1+ofs)%t), (col << 8) + 0xFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(mode != 2) {
|
||||
displayStat( 2, XLAT("synchronize net and map"), "", 's');
|
||||
displayStat( 3, XLAT("display the scope"), "", 't');
|
||||
displayStat( 5, XLAT("create the model"), "", 'c');
|
||||
displayStat( 7, XLAT("back to HyperRogue"), "", 'q');
|
||||
displayStat( 9, XLAT("design the net"), "", 'd');
|
||||
}
|
||||
}
|
||||
|
||||
void handleKey(int uni, int sym) {
|
||||
|
||||
if(!loaded) {
|
||||
loadData();
|
||||
if(!loaded) {
|
||||
addMessage(XLAT("Failed to load the file 'papermodeldata.txt'"));
|
||||
cmode = emNormal;
|
||||
return;
|
||||
}
|
||||
if(!created) {
|
||||
View = Id;
|
||||
if(lcenterover) viewctr.h = lcenterover->master;
|
||||
else viewctr.h = cwt.c->master;
|
||||
playermoved = false;
|
||||
dataFromHR();
|
||||
designNet();
|
||||
created = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(mode == 2 && uni != 0) {
|
||||
mode = 0;
|
||||
return;
|
||||
}
|
||||
if(uni == 's') {
|
||||
View = Id;
|
||||
if(lcenterover) viewctr.h = lcenterover->master;
|
||||
else viewctr.h = cwt.c->master;
|
||||
playermoved = false;
|
||||
}
|
||||
if(uni == 'c') {
|
||||
createPapermodel();
|
||||
addMessage(XLAT("The paper model created as papermodel-*.bmp"));
|
||||
}
|
||||
if(uni == 'd') designNet();
|
||||
if(uni == 't') mode = 2;
|
||||
if(uni == 'q' || sym == SDLK_ESCAPE)
|
||||
cmode = emNormal;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
949
orbs.cpp
Normal file
949
orbs.cpp
Normal file
@ -0,0 +1,949 @@
|
||||
// Hyperbolic Rogue
|
||||
|
||||
// Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details
|
||||
|
||||
// Orb-related routines
|
||||
|
||||
bool markOrb(eItem it) {
|
||||
if(!items[it]) return false;
|
||||
orbused[it] = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool markEmpathy(eItem it) {
|
||||
if(!items[itOrbEmpathy]) return false;
|
||||
if(!markOrb(it)) return false;
|
||||
markOrb(itOrbEmpathy);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool markOrb2(eItem it) {
|
||||
if(!items[it]) return false;
|
||||
orbused[it] = true;
|
||||
return items[it] > 1;
|
||||
}
|
||||
|
||||
int fixpower(int qty) {
|
||||
if(markOrb(itOrbEnergy)) qty = (qty+1)/2;
|
||||
return qty;
|
||||
}
|
||||
|
||||
void useupOrb(eItem it, int qty) {
|
||||
items[it] -= fixpower(qty);
|
||||
if(items[it] < 0) items[it] = 0;
|
||||
}
|
||||
|
||||
void drainOrb(eItem it, int target) {
|
||||
if(items[it] > target) useupOrb(it, items[it] - target);
|
||||
}
|
||||
|
||||
void empathyMove(cell *c, cell *cto, int dir) {
|
||||
if(!items[itOrbEmpathy]) return;
|
||||
|
||||
if(items[itOrbFire]) {
|
||||
invismove = false;
|
||||
if(makeflame(c, 10, false)) markEmpathy(itOrbFire);
|
||||
}
|
||||
|
||||
if(items[itOrbDigging]) {
|
||||
if(dir != STRONGWIND && earthMove(c, dir))
|
||||
markEmpathy(itOrbDigging), invismove = false;
|
||||
}
|
||||
|
||||
if(items[itOrbWinter] && isIcyLand(c) && c->wall == waNone) {
|
||||
invismove = false;
|
||||
c->wall = waIcewall;
|
||||
markEmpathy(itOrbWinter);
|
||||
}
|
||||
}
|
||||
|
||||
bool reduceOrbPower(eItem it, int cap) {
|
||||
if(items[it] && (lastorbused[it] || (it == itOrbShield && items[it]>3) || !markOrb(itOrbPreserve))) {
|
||||
items[it] -= numplayers();
|
||||
if(isHaunted(cwt.c->land)) survivalist = false;
|
||||
if(items[it] < 0) items[it] = 0;
|
||||
if(items[it] > cap) items[it] = cap;
|
||||
if(items[it] == 0 && it == itOrbLove)
|
||||
princess::bringBack();
|
||||
return true;
|
||||
}
|
||||
if(items[it] > cap) items[it] = cap;
|
||||
return false;
|
||||
}
|
||||
|
||||
void reduceOrbPowerAlways(eItem it) {
|
||||
if(items[it]) {
|
||||
items[it] -= numplayers();
|
||||
if(items[it] < 0) items[it] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void reduceOrbPowers() {
|
||||
if(getMount()) markOrb(itOrbDomination);
|
||||
for(int i=0; i<ittypes; i++)
|
||||
lastorbused[i] = orbused[i], orbused[i] = false;
|
||||
if(items[itOrbShield]) orbused[itOrbShield] = lastorbused[itOrbShield];
|
||||
reduceOrbPower(itOrbPreserve, cwt.c->land == laCaribbean ? 777 : 150);
|
||||
if(invismove && !invisfish) markOrb(itOrbInvis);
|
||||
reduceOrbPower(itOrbLightning, 777);
|
||||
reduceOrbPower(itOrbSpeed, 67);
|
||||
reduceOrbPower(itOrbShield, 77);
|
||||
reduceOrbPower(itOrbShell, 150);
|
||||
reduceOrbPower(itOrbFlash, 777);
|
||||
reduceOrbPower(itOrbWinter, 77);
|
||||
reduceOrbPower(itOrbFire, 77);
|
||||
reduceOrbPower(itOrbIllusion, 111);
|
||||
reduceOrbPower(itOrbDragon, 111);
|
||||
reduceOrbPower(itOrbPsi, 111);
|
||||
reduceOrbPower(itOrbInvis, 77);
|
||||
reduceOrbPower(itOrbGhost, 77);
|
||||
reduceOrbPower(itOrbDigging, 100);
|
||||
reduceOrbPower(itOrbTeleport, 200);
|
||||
reduceOrbPower(itOrbTelekinesis, 150);
|
||||
reduceOrbPowerAlways(itOrbSafety);
|
||||
reduceOrbPower(itOrbThorns, 150);
|
||||
reduceOrbPower(itOrbWater, 150);
|
||||
reduceOrbPower(itOrbAir, 150);
|
||||
reduceOrbPower(itOrbFrog, 77);
|
||||
reduceOrbPower(itOrbDiscord, 67);
|
||||
reduceOrbPower(itOrbSummon, 333);
|
||||
reduceOrbPower(itOrbMatter, 333);
|
||||
reduceOrbPower(itOrbFish, 77);
|
||||
if(!items[itSavedPrincess]) items[itOrbLove] = 0;
|
||||
reduceOrbPower(itOrbLove, 777);
|
||||
reduceOrbPower(itOrbStunning, 100);
|
||||
reduceOrbPower(itOrbLuck, 333);
|
||||
reduceOrbPower(itOrbUndeath, 77);
|
||||
reduceOrbPower(itOrbFreedom, 77);
|
||||
reduceOrbPower(itOrbEmpathy, 77);
|
||||
markOrb(itOrb37); reduceOrbPower(itOrb37, 333);
|
||||
reduceOrbPower(itOrbSkunk, 77);
|
||||
reduceOrbPower(itOrbEnergy, 77);
|
||||
reduceOrbPower(itOrbDomination, 120);
|
||||
if(cwt.c->land != laWildWest)
|
||||
reduceOrbPower(itRevolver, 6);
|
||||
whirlwind::calcdirs(cwt.c);
|
||||
items[itStrongWind] = !items[itOrbGhost] && whirlwind::qdirs == 1 && !euclid;
|
||||
}
|
||||
|
||||
void flashAlchemist(cell *c) {
|
||||
if(isAlch(c)) {
|
||||
if(isAlch(cwt.c))
|
||||
c->wall = cwt.c->wall;
|
||||
else
|
||||
c->wall = eWall(c->wall ^ waFloorB ^ waFloorA);
|
||||
}
|
||||
}
|
||||
|
||||
void flashCell(cell *c, bool msg) {
|
||||
flashAlchemist(c);
|
||||
if(msg && c->monst && !isWorm(c) && c->monst != moShadow)
|
||||
addMessage(XLAT("%The1 is destroyed by the Flash.", c->monst));
|
||||
killWithMessage(c, false);
|
||||
if(isIcyLand(c))
|
||||
HEAT(c) += 2;
|
||||
if(c->land == laDryForest)
|
||||
c->landparam += 2;
|
||||
if(c->wall == waCavewall) c->wall = waCavefloor;
|
||||
if(c->wall == waDeadTroll) c->wall = waCavefloor;
|
||||
if(c->wall == waDeadTroll2) c->wall = waNone;
|
||||
if(c->wall == waDeadfloor2) c->wall = waDeadfloor;
|
||||
if(c->wall == waGargoyleFloor) c->wall = waChasm;
|
||||
if(c->wall == waGargoyleBridge) placeWater(c, c);
|
||||
if(c->wall == waGargoyle) c->wall = waNone;
|
||||
if(c->wall == waPlatform) c->wall = waNone;
|
||||
if(c->wall == waStone) c->wall = waNone;
|
||||
if(c->wall == waRubble) c->wall = waNone;
|
||||
if(c->wall == waDeadwall) c->wall = waDeadfloor2;
|
||||
if(c->wall == waGiantRug) c->wall = waNone;
|
||||
if(c->wall == waMirror) c->wall = waNone;
|
||||
if(c->wall == waCloud) c->wall = waNone;
|
||||
if(c->wall == waDune) c->wall = waNone;
|
||||
if(c->wall == waSaloon) c->wall = waNone;
|
||||
if(c->wall == waSandstone) c->wall = waNone;
|
||||
if(c->wall == waAncientGrave) c->wall = waNone;
|
||||
if(c->wall == waFreshGrave) c->wall = waNone;
|
||||
if(c->wall == waColumn) c->wall = waNone;
|
||||
if(c->wall == waGlass) c->wall = waNone;
|
||||
if(c->wall == waBigTree || c->wall == waSmallTree) c->wall = waNone;
|
||||
if(c->wall == waBigStatue) c->wall = waNone;
|
||||
if(c->wall == waCTree) c->wall = waCIsland2;
|
||||
if(c->wall == waPalace) c->wall = waRubble;
|
||||
if(c->wall == waRose) c->wall = waNone;
|
||||
if(c->wall == waOpenGate || c->wall == waClosedGate) {
|
||||
eWall w = c->wall;
|
||||
c->wall = waNone;
|
||||
for(int i=0; i<c->type; i++) if(c->mov[i] && c->mov[i]->wall == w)
|
||||
flashCell(c->mov[i], msg);
|
||||
}
|
||||
if(c->wall == waRed1) c->wall = waNone;
|
||||
else if(c->wall == waRed2) c->wall = waRed1;
|
||||
else if(c->wall == waRed3) c->wall = waRed2;
|
||||
if(hasTimeout(c) && c->wparam < 77) c->wparam = 77;
|
||||
if(isActivable(c))
|
||||
activateActiv(c, false);
|
||||
}
|
||||
|
||||
void activateFlashFrom(cell *cf) {
|
||||
drawFlash(cf);
|
||||
for(int i=0; i<size(dcal); i++) {
|
||||
cell *c = dcal[i];
|
||||
if(c == cf) continue;
|
||||
for(int t=0; t<c->type; t++)
|
||||
for(int u=0; u<cf->type; u++)
|
||||
if(c->mov[t] == cf->mov[u] && c->mov[t] != NULL) {
|
||||
flashCell(c, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool distanceBound(cell *c1, cell *c2, int d) {
|
||||
if(!c1 || !c2) return false;
|
||||
if(d == 0) return c1 == c2;
|
||||
for(int i=0; i<c2->type; i++)
|
||||
if(distanceBound(c1, c2->mov[i], d-1)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void checkFreedom(cell *cf) {
|
||||
sval++;
|
||||
static vector<cell*> avcells;
|
||||
avcells.clear();
|
||||
avcells.push_back(cf);
|
||||
cf->aitmp = sval;
|
||||
for(int i=0; i<size(avcells); i++) {
|
||||
cell *c = avcells[i];
|
||||
if(c->cpdist >= 5) return;
|
||||
for(int i=0; i<c->type; i++) {
|
||||
cell *c2 = c->mov[i];
|
||||
// todo leader
|
||||
if(!passable(c2, c, P_ISPLAYER | P_MIRROR | P_LEADER)) continue;
|
||||
if(eq(c2->aitmp, sval)) continue;
|
||||
bool monsterhere = false;
|
||||
for(int j=0; j<c2->type; j++) {
|
||||
cell *c3 = c2->mov[j];
|
||||
if(c3 && c3->monst && !isFriendly(c3))
|
||||
monsterhere = true;
|
||||
}
|
||||
if(!monsterhere) {
|
||||
c2->aitmp = sval;
|
||||
avcells.push_back(c2);
|
||||
}
|
||||
}
|
||||
}
|
||||
addMessage(XLAT("Your %1 activates!", itOrbFreedom));
|
||||
drainOrb(itOrbFreedom);
|
||||
drawBigFlash(cf);
|
||||
for(int i=0; i<size(dcal); i++) {
|
||||
cell *c = dcal[i];
|
||||
if(c == cf) continue;
|
||||
if(c->cpdist > 5) break;
|
||||
flashCell(c, true);
|
||||
}
|
||||
}
|
||||
|
||||
void activateFlash() {
|
||||
int tk = tkills();
|
||||
drawFlash(cwt.c);
|
||||
addMessage(XLAT("You activate the Flash spell!"));
|
||||
drainOrb(itOrbFlash);
|
||||
for(int i=0; i<size(dcal); i++) {
|
||||
cell *c = dcal[i];
|
||||
if(c->cpdist > 2) break;
|
||||
flashCell(c, false);
|
||||
}
|
||||
achievement_count("FLASH", tkills(), tk);
|
||||
}
|
||||
|
||||
bool barrierAt(cellwalker& c, int d) {
|
||||
if(d >= 7) return true;
|
||||
if(d <= -7) return true;
|
||||
d = c.spin + d + 42;
|
||||
d%=c.c->type;
|
||||
if(!c.c->mov[d]) return true;
|
||||
// WAS:
|
||||
// if(c.c->mov[d]->wall == waBarrier) return true;
|
||||
if(c.c->mov[d]->land == laBarrier || c.c->mov[d]->land == laOceanWall ||
|
||||
c.c->mov[d]->land == laHauntedWall ||
|
||||
c.c->mov[d]->land == laElementalWall) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void killAdjacentSharks(cell *c) {
|
||||
for(int i=0; i<c->type; i++) {
|
||||
cell *c2 = c->mov[i];
|
||||
if(c2 && isShark(c2->monst)) {
|
||||
c2->ligon = true;
|
||||
killMonster(c2);
|
||||
killAdjacentSharks(c2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void castLightningBolt(cellwalker lig) {
|
||||
int bnc = 0;
|
||||
while(true) {
|
||||
// printf("at: %p i=%d d=%d\n", lig.c, i, lig.spin);
|
||||
|
||||
killAdjacentSharks(lig.c);
|
||||
|
||||
if(lig.c->mov[lig.spin] == NULL) break;
|
||||
|
||||
cwstep(lig);
|
||||
|
||||
cell *c = lig.c;
|
||||
|
||||
flashAlchemist(c);
|
||||
if(c->monst == moMetalBeast2 && !c->item) c->item = itFulgurite;
|
||||
killWithMessage(c, false);
|
||||
if(isIcyLand(c)) HEAT(c) += 2;
|
||||
if(c->land == laDryForest) c->landparam += 2;
|
||||
bool first = !c->ligon;
|
||||
c->ligon = 1;
|
||||
|
||||
bool brk = false, spin = false;
|
||||
|
||||
if(c->wall == waGargoyle) brk = true;
|
||||
if(c->wall == waCavewall) 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 == waDeadfloor2)c->wall = waDeadfloor;
|
||||
if(c->wall == waRubble) c->wall = waNone;
|
||||
if(c->wall == waDeadwall) c->wall = waDeadfloor2, brk = true;
|
||||
if(c->wall == waGlass) c->wall = waNone, spin = true;
|
||||
if(c->wall == waDune) 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 == waFreshGrave) 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 == waStone) c->wall = waNone, brk = true;
|
||||
|
||||
if(c->wall == waGrounded) brk = true;
|
||||
if(c->wall == waFan) spin = true;
|
||||
if(c->wall == waMetal) c->wall = waCharged, brk = true;
|
||||
if(c->wall == waSandstone) c->wall = waNone, c->item = itFulgurite, brk = true;
|
||||
|
||||
if(c->wall == waCharged && first) {
|
||||
for(int i=0; i<c->type; i++)
|
||||
// do not do strange things in horocyclic spires
|
||||
if(c->mov[i] && c->mov[i]->wall != waCharged) {
|
||||
cellwalker lig2(c, i);
|
||||
castLightningBolt(lig2);
|
||||
}
|
||||
brk = true;
|
||||
}
|
||||
|
||||
if(c->wall == waBoat && c != cwt.c) c->wall = waSea, spin = true;
|
||||
if(c->wall == waStrandedBoat && c !=cwt.c) c->wall = waNone, spin = true;
|
||||
|
||||
if((c->wall == waNone || c->wall == waSea) && c->land == laLivefjord)
|
||||
c->wall = eWall(c->wall ^ waSea ^ waNone);
|
||||
|
||||
if(c->wall == waRed1) c->wall = waNone;
|
||||
if(c->wall == waRed2) c->wall = waRed1;
|
||||
if(c->wall == waRed3) c->wall = waRed2, brk = true;
|
||||
|
||||
if(isActivable(c)) activateActiv(c, false);
|
||||
if(c->wall == waBigTree || c->wall == waSmallTree || c->wall == waVinePlant ||
|
||||
c->wall == waSaloon) {
|
||||
makeflame(c, 4, false);
|
||||
brk = true;
|
||||
}
|
||||
if(c->wall == waCTree) makeflame(c, 12, false);
|
||||
if(c->wall == waRose) makeflame(c, 60, false);
|
||||
if(cellHalfvine(c) && c->mov[lig.spin] && c->wall == c->mov[lig.spin]->wall) {
|
||||
destroyHalfvine(c, waPartialFire, 4);
|
||||
brk = true;
|
||||
}
|
||||
|
||||
if(c == cwt.c) {bnc++; if(bnc > 10) break; }
|
||||
if(spin) cwspin(lig, hrand(lig.c->type));
|
||||
|
||||
if(brk) break;
|
||||
|
||||
if(c->wall == waBarrier || c->wall == waCamelot || c->wall == waPalace || c->wall == waPlatform ||
|
||||
c->wall == waTempWall || c->wall == waWarpGate) {
|
||||
int left = -1;
|
||||
int right = 1;
|
||||
while(barrierAt(lig, left)) left--;
|
||||
while(barrierAt(lig, right)) right++;
|
||||
cwspin(lig, -(right + left));
|
||||
bnc++; if(bnc > 10) break;
|
||||
}
|
||||
else {
|
||||
cwspin(lig, 3);
|
||||
if(c->type == 7) cwspin(lig, hrand(2));
|
||||
}
|
||||
|
||||
if(c->wall == waCloud) {
|
||||
c->wall = waNone;
|
||||
mirror::createMirages(c, lig.spin, moLightningBolt);
|
||||
}
|
||||
|
||||
if(c->wall == waMirror) {
|
||||
c->wall = waNone;
|
||||
mirror::createMirrors(c, lig.spin, moLightningBolt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void activateLightning() {
|
||||
int tk = tkills();
|
||||
drawLightning();
|
||||
addMessage(XLAT("You activate the Lightning spell!"));
|
||||
|
||||
for(int i=0; i<size(dcal); i++) if(dcal[i]) dcal[i]->ligon = 0;
|
||||
|
||||
drainOrb(itOrbLightning);
|
||||
for(int i=0; i<cwt.c->type; i++)
|
||||
castLightningBolt(cellwalker(cwt.c, i));
|
||||
|
||||
elec::afterOrb = true;
|
||||
elec::act();
|
||||
elec::afterOrb = false;
|
||||
|
||||
achievement_count("LIGHTNING", tkills(), tk);
|
||||
}
|
||||
|
||||
// roCheck: return orb type if successful, 0 otherwise
|
||||
// roMouse/roKeyboard:
|
||||
// return orb type if successful, eItem(-1) if do nothing, 0 otherwise
|
||||
|
||||
bool haveRangedTarget() {
|
||||
if(!haveRangedOrb())
|
||||
return false;
|
||||
for(int i=0; i<size(dcal); i++) {
|
||||
cell *c = dcal[i];
|
||||
if(targetRangedOrb(c, roCheck)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void teleportTo(cell *dest) {
|
||||
if(dest->monst) {
|
||||
cwt.c->monst = dest->monst;
|
||||
dest->monst = moNone;
|
||||
}
|
||||
movecost(cwt.c, dest);
|
||||
playerMoveEffects(cwt.c, dest);
|
||||
cwt.c = dest; cwt.spin = hrand(dest->type); flipplayer = !!(hrand(2));
|
||||
drainOrb(itOrbTeleport);
|
||||
|
||||
addMessage(XLAT("You teleport to a new location!"));
|
||||
mirror::destroy();
|
||||
|
||||
for(int i=9; i>=0; i--)
|
||||
setdist(cwt.c, i, NULL);
|
||||
|
||||
bfs();
|
||||
|
||||
if(shmup::on)
|
||||
shmup::teleported();
|
||||
else
|
||||
checkmove();
|
||||
}
|
||||
|
||||
void jumpTo(cell *dest, eItem byWhat) {
|
||||
movecost(cwt.c, dest);
|
||||
|
||||
cell *c1 = cwt.c;
|
||||
cwt.c = dest;
|
||||
countLocalTreasure();
|
||||
|
||||
playerMoveEffects(c1, dest);
|
||||
if(cwt.c->item != itOrbYendor && cwt.c->item != itHolyGrail)
|
||||
collectItem(cwt.c, true);
|
||||
|
||||
if(byWhat == itOrbFrog) {
|
||||
useupOrb(itOrbFrog, 5);
|
||||
addMessage(XLAT("You jump!"));
|
||||
}
|
||||
|
||||
mirror::destroy();
|
||||
|
||||
for(int i=9; i>=0; i--)
|
||||
setdist(cwt.c, i, NULL);
|
||||
|
||||
createNoise(1);
|
||||
|
||||
if(shmup::on)
|
||||
shmup::teleported();
|
||||
else
|
||||
monstersTurn();
|
||||
}
|
||||
|
||||
void telekinesis(cell *dest) {
|
||||
|
||||
int cost = dest->cpdist * dest->cpdist;
|
||||
|
||||
if(dest->land == laAlchemist && isAlchAny(dest) && isAlchAny(cwt.c))
|
||||
dest->wall = cwt.c->wall;
|
||||
|
||||
if(dest->land == laPower && cwt.c->land != laPower && dest->item != itOrbFire && dest->item != itOrbLife) {
|
||||
if(itemclass(dest->item) != IC_ORB)
|
||||
items[dest->item] ++;
|
||||
else
|
||||
items[dest->item] += 2;
|
||||
addMessage(XLAT("The Orb loses its power as it leaves the Land of Power!"));
|
||||
dest->item = itNone;
|
||||
}
|
||||
|
||||
if(dest->wall == waGlass) {
|
||||
drainOrb(itOrbTelekinesis);
|
||||
addMessage(XLAT("Your power is drained by %the1!", dest->wall));
|
||||
}
|
||||
|
||||
moveItem(dest, cwt.c, true);
|
||||
collectItem(cwt.c, true);
|
||||
useupOrb(itOrbTelekinesis, cost);
|
||||
|
||||
createNoise(3);
|
||||
bfs();
|
||||
if(!shmup::on) checkmove();
|
||||
}
|
||||
|
||||
eMonster summonedAt(cell *dest) {
|
||||
if(dest->monst) return moNone;
|
||||
if(dest->wall == waVineHalfA || dest->wall == waVineHalfB || dest->wall == waVinePlant)
|
||||
return moVineSpirit;
|
||||
if(dest->wall == waCTree)
|
||||
return moParrot;
|
||||
if(dest->wall == waLake)
|
||||
return moGreaterShark;
|
||||
if(dest->wall == waAncientGrave || dest->wall == waFreshGrave)
|
||||
return moGhost;
|
||||
if(dest->wall == waClosePlate || dest->wall == waOpenPlate)
|
||||
return moPalace;
|
||||
if(dest->wall == waFloorA || dest->wall == waFloorB)
|
||||
return moSlime;
|
||||
if(dest->wall == waFloorC || dest->wall == waFloorD)
|
||||
return moRatling;
|
||||
if(dest->wall == waCavefloor)
|
||||
return moTroll;
|
||||
if(dest->wall == waDeadfloor)
|
||||
return moEarthElemental;
|
||||
if(dest->wall == waDeadfloor2)
|
||||
return moMiner;
|
||||
if(dest->wall == waMineOpen || dest->wall == waMineMine || dest->wall == waMineUnknown)
|
||||
return moBomberbird;
|
||||
if(dest->wall == waTrapdoor)
|
||||
return dest->land == laPalace ? moFatGuard : moOrangeDog;
|
||||
if(dest->wall == waSea)
|
||||
return
|
||||
isElemental(dest->land) ? moWaterElemental :
|
||||
dest->land == laLivefjord ? moViking :
|
||||
dest->land == laGridCoast ? moRatling :
|
||||
moPirate;
|
||||
if(dest->wall == waChasm)
|
||||
return moAirElemental;
|
||||
if(isFire(dest))
|
||||
return moFireElemental;
|
||||
if(dest->wall == waCavewall || dest->wall == waDeadwall)
|
||||
return moSeep;
|
||||
if(dest->wall == waRed1 || dest->wall == waRed2 || dest->wall == waRed3)
|
||||
return moRedTroll;
|
||||
if(dest->wall == waFrozenLake)
|
||||
return moFireElemental;
|
||||
if(dest->wall == waCIsland || dest->wall == waCIsland2)
|
||||
return moWaterElemental;
|
||||
if(dest->wall == waRubble || dest->wall == waGargoyleFloor || dest->wall == waGargoyleBridge || dest->wall == waLadder)
|
||||
return moGargoyle;
|
||||
if(dest->wall == waStrandedBoat)
|
||||
return moWaterElemental;
|
||||
if(dest->wall == waBoat)
|
||||
return moAirElemental;
|
||||
if(dest->wall == waStone)
|
||||
return moEarthElemental;
|
||||
if(dest->wall == waGiantRug)
|
||||
return moVizier;
|
||||
if(dest->wall == waNone) {
|
||||
if(dest->land == laIce) return moFireElemental;
|
||||
if(dest->land == laDesert) return moEarthElemental;
|
||||
if(dest->land == laJungle) return moWaterElemental;
|
||||
if(dest->land == laGraveyard) return moZombie;
|
||||
if(dest->land == laRlyeh || dest->land == laTemple) return moPyroCultist;
|
||||
if(dest->land == laHell) return moWaterElemental;
|
||||
if(dest->land == laPower) return moWitchFire;
|
||||
if(dest->land == laWineyard) return moVineBeast;
|
||||
if(dest->land == laEmerald) return moMiner;
|
||||
if(dest->land == laHive) return dest->type == 7 ? moBug1 : moBug0;
|
||||
if(dest->land == laRedRock) return moRedTroll;
|
||||
if(dest->land == laOcean) return moEarthElemental;
|
||||
if(dest->land == laDryForest) return moFireFairy;
|
||||
if(dest->land == laLivefjord) return moFjordTroll;
|
||||
if(dest->land == laStorms) return moStormTroll;
|
||||
if(dest->land == laOvergrown) return moForestTroll;
|
||||
if(dest->land == laIvoryTower) return moAirElemental;
|
||||
if(dest->land == laEndorian) return moAirElemental;
|
||||
if(dest->land == laEAir) return moAirElemental;
|
||||
if(dest->land == laEWater) return moWaterElemental;
|
||||
if(dest->land == laEEarth) return moEarthElemental;
|
||||
if(dest->land == laEFire) return moFireElemental;
|
||||
if(dest->land == laMotion) return moRunDog;
|
||||
if(dest->land == laWildWest) return moOutlaw;
|
||||
if(dest->land == laClearing) return moForestTroll;
|
||||
if(dest->land == laWhirlwind) return moAirElemental;
|
||||
if(dest->land == laGridCoast) return moRatling;
|
||||
if(dest->land == laRose) return moRoseLady;
|
||||
if(dest->land == laDragon) return moFireElemental;
|
||||
if(dest->land == laTortoise) return moTortoise;
|
||||
if(isHaunted(dest->land)) return moGhost;
|
||||
}
|
||||
return moNone;
|
||||
}
|
||||
|
||||
void summonAt(cell *dest) {
|
||||
dest->monst = summonedAt(dest);
|
||||
dest->stuntime = 3;
|
||||
if(dest->monst == moPirate || dest->monst == moViking || (dest->monst == moRatling && dest->wall == waSea))
|
||||
dest->wall = waBoat;
|
||||
if(dest->wall == waStrandedBoat)
|
||||
dest->wall = waBoat;
|
||||
else if(dest->monst == moWaterElemental)
|
||||
placeWater(dest, dest);
|
||||
if(dest->wall == waStone)
|
||||
dest->wall = waNone;
|
||||
if(dest->monst == moFireElemental && isFire(dest))
|
||||
dest->wall = waNone;
|
||||
if(dest->monst == moTortoise)
|
||||
tortoise::emap[dest] = dest;
|
||||
addMessage(XLAT("You summon %the1!", dest->monst));
|
||||
moveEffect(dest, dest, dest->monst);
|
||||
|
||||
if(hasHitpoints(dest->monst))
|
||||
dest->hitpoints = palaceHP();
|
||||
|
||||
useupOrb(itOrbSummon, 20);
|
||||
createNoise(2);
|
||||
bfs();
|
||||
checkmove();
|
||||
}
|
||||
|
||||
bool tempWallPossibleAt(cell *dest) {
|
||||
if(dest->monst || (dest->item && !itemHidden(dest))) return false;
|
||||
return dest->wall == waChasm || isWatery(dest) || dest->wall == waNone;
|
||||
}
|
||||
|
||||
void tempWallAt(cell *dest) {
|
||||
if(dest->wall == waChasm)
|
||||
dest->wall = waTempFloor;
|
||||
else if(dest->wall == waNone)
|
||||
dest->wall = waTempWall;
|
||||
else if(isWatery(dest))
|
||||
dest->wall = waTempBridge;
|
||||
int len = (items[itOrbMatter]+1) / 2;
|
||||
dest->wparam = len;
|
||||
useupOrb(itOrbMatter, len);
|
||||
dest->item = itNone; // underwater items are destroyed by this
|
||||
createNoise(2);
|
||||
bfs();
|
||||
checkmove();
|
||||
}
|
||||
|
||||
void psi_attack(cell *dest) {
|
||||
if(isNonliving(dest->monst))
|
||||
addMessage(XLAT("You destroy %the1 with a mental blast!", dest->monst));
|
||||
else if(isDragon(dest->monst))
|
||||
addMessage(XLAT("You damage %the1 with a mental blast!", dest->monst));
|
||||
else
|
||||
addMessage(XLAT("You kill %the1 with a mental blast!", dest->monst));
|
||||
killWithMessage(dest, false);
|
||||
useupOrb(itOrbPsi, 30);
|
||||
createNoise(2);
|
||||
bfs();
|
||||
checkmove();
|
||||
}
|
||||
|
||||
void gun_attack(cell *dest) {
|
||||
addMessage(XLAT("You shoot %the1!", dest->monst));
|
||||
killWithMessage(dest, false);
|
||||
items[itRevolver] --;
|
||||
bfs();
|
||||
checkmove();
|
||||
createNoise(5);
|
||||
monstersTurn();
|
||||
}
|
||||
|
||||
void stun_attack(cell *dest) {
|
||||
addMessage(XLAT("You stun %the1!", dest->monst));
|
||||
dest->stuntime += 5;
|
||||
if(isBird(dest->monst)) {
|
||||
moveEffect(dest, dest, moDeadBird);
|
||||
if(cellUnstableOrChasm(dest)) dest->wall = waChasm;
|
||||
if(isWatery(dest) || dest->wall == waChasm || isFire(dest))
|
||||
killMonster(dest);
|
||||
}
|
||||
useupOrb(itOrbStunning, 10);
|
||||
createNoise(3);
|
||||
bfs();
|
||||
checkmove();
|
||||
}
|
||||
|
||||
void placeIllusion(cell *c) {
|
||||
c->monst = moIllusion;
|
||||
useupOrb(itOrbIllusion, 5);
|
||||
addMessage(XLAT("You create an Illusion!"));
|
||||
bfs();
|
||||
checkmove();
|
||||
}
|
||||
|
||||
void blowoff(cell *cf, cell *ct) {
|
||||
addMessage(XLAT("You blow %the1 away!", cf->monst));
|
||||
pushMonster(ct, cf);
|
||||
if(cf->item == itBabyTortoise) {
|
||||
if(!ct->item) {
|
||||
ct->item = itBabyTortoise;
|
||||
tortoise::babymap[ct] = tortoise::babymap[cf];
|
||||
}
|
||||
tortoise::babymap.erase(cf);
|
||||
cf->item = itNone;
|
||||
}
|
||||
items[itOrbAir]--;
|
||||
createNoise(2);
|
||||
bfs();
|
||||
checkmove();
|
||||
}
|
||||
|
||||
void useOrbOfDragon(cell *c) {
|
||||
makeflame(c, 20, false);
|
||||
addMessage(XLAT("You throw fire!"));
|
||||
useupOrb(itOrbDragon, 5);
|
||||
createNoise(3);
|
||||
bfs();
|
||||
checkmove();
|
||||
}
|
||||
|
||||
eItem targetRangedOrb(cell *c, orbAction a) {
|
||||
|
||||
if(!haveRangedOrb()) return itNone;
|
||||
|
||||
if(rosedist(cwt.c) == 1) {
|
||||
int r = rosemap[cwt.c];
|
||||
int r2 = rosemap[c];
|
||||
if(r2 <= r) {
|
||||
if(a == roKeyboard || a == roMouseForce )
|
||||
addMessage(XLAT("Those roses smell too nicely. You can only target cells closer to them!"));
|
||||
return itNone;
|
||||
}
|
||||
}
|
||||
|
||||
// (-2) shmup variants
|
||||
eItem shmupEffect = shmup::targetRangedOrb(a);
|
||||
|
||||
if(shmupEffect) return shmupEffect;
|
||||
|
||||
// (-1) distance
|
||||
|
||||
if(c == cwt.c || isNeighbor(cwt.c, c)) {
|
||||
if(a == roKeyboard || a == roMouseForce )
|
||||
addMessage(XLAT("You cannot target that close!"));
|
||||
return itNone;
|
||||
}
|
||||
if(c->cpdist > 7) {
|
||||
if(a != roCheck)
|
||||
addMessage(XLAT("You cannot target that far away!"));
|
||||
return itNone;
|
||||
}
|
||||
|
||||
// (0-) strong wind
|
||||
if(items[itStrongWind] && c->cpdist == 2 && cwt.c == whirlwind::jumpFromWhereTo(c, true) && !monstersnear(c, NULL, moPlayer, NULL, cwt.c)) {
|
||||
if(a != roCheck) jumpTo(c, itStrongWind);
|
||||
return itStrongWind;
|
||||
}
|
||||
|
||||
// (0x) control
|
||||
if(getMount() && items[itOrbDomination] && dragon::whichturn != turncount) {
|
||||
if(a != roCheck) {
|
||||
dragon::target = c;
|
||||
dragon::whichturn = turncount;
|
||||
addMessage(XLAT("Commanded %the1!", getMount()));
|
||||
checkmove();
|
||||
}
|
||||
return itOrbDomination;
|
||||
}
|
||||
|
||||
// (0) telekinesis
|
||||
if(c->item && !itemHidden(c) && !cwt.c->item && items[itOrbTelekinesis] >= fixpower(c->cpdist * c->cpdist) && !cantGetGrimoire(c, a != roCheck)) {
|
||||
if(a != roCheck) telekinesis(c);
|
||||
return itOrbTelekinesis;
|
||||
}
|
||||
|
||||
// (0') air blow
|
||||
bool nowhereToBlow = false;
|
||||
if(items[itOrbAir] && isBlowableMonster(c->monst)) {
|
||||
int d = 0;
|
||||
for(; d<c->type; d++) if(c->mov[d] && c->mov[d]->cpdist < c->cpdist) break;
|
||||
if(d<c->type) for(int e=d; e<d+c->type; e++) {
|
||||
nowhereToBlow = true;
|
||||
cell *c2 = c->mov[e % c->type];
|
||||
if(c2 && c2->cpdist > c->cpdist && passable(c2, c, P_BLOW)) {
|
||||
if(a != roCheck) blowoff(c, c2);
|
||||
return itOrbAir;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// (0'') jump
|
||||
int jumpstate = 0;
|
||||
cell *jumpthru = NULL;
|
||||
|
||||
if(items[itOrbFrog] && c->cpdist == 2) {
|
||||
jumpstate = 1;
|
||||
int i = items[itOrbGhost];
|
||||
if(i) items[itOrbGhost] = i-1;
|
||||
for(int i=0; i<cwt.c->type; i++) {
|
||||
cell *c2 = cwt.c->mov[i];
|
||||
if(isNeighbor(c2, c)) {
|
||||
jumpthru = c2;
|
||||
if(passable(c2, cwt.c, P_ISPLAYER | P_JUMP1)) {
|
||||
jumpstate = 2;
|
||||
if(passable(c, c2, P_ISPLAYER | P_JUMP2)) {
|
||||
jumpstate = 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
items[itOrbGhost] = i;
|
||||
if(jumpstate == 3 && !monstersnear(c, NULL, moPlayer, NULL, c)) {
|
||||
jumpstate = 4;
|
||||
if(a != roCheck) jumpTo(c, itOrbFrog);
|
||||
return itOrbFrog;
|
||||
}
|
||||
}
|
||||
|
||||
// (1) switch with an illusion
|
||||
if(items[itOrbTeleport] && c->monst == moIllusion && !cwt.c->monst) {
|
||||
if(a != roCheck) teleportTo(c);
|
||||
return itOrbTeleport;
|
||||
}
|
||||
|
||||
// (2) place illusion
|
||||
if(!shmup::on && items[itOrbIllusion] && c->monst == moNone && c->item == itNone && passable(c, NULL, P_MIRROR)) {
|
||||
if(a != roCheck) placeIllusion(c);
|
||||
return itOrbIllusion;
|
||||
}
|
||||
|
||||
// (3) teleport
|
||||
if(items[itOrbTeleport] && c->monst == moNone && (c->item == itNone || itemHidden(c)) &&
|
||||
passable(c, NULL, P_ISPLAYER | P_TELE) && shmup::verifyTeleport()) {
|
||||
if(a != roCheck) teleportTo(c);
|
||||
return itOrbTeleport;
|
||||
}
|
||||
|
||||
// (4) remove an illusion
|
||||
if(!shmup::on && items[itOrbIllusion] && c->monst == moIllusion) {
|
||||
if(a != roCheck) {
|
||||
addMessage(XLAT("You take the Illusion away."));
|
||||
items[itOrbIllusion] += 3; // 100% effective with the Orb of Energy!
|
||||
c->monst = moNone;
|
||||
}
|
||||
return itOrbIllusion;
|
||||
}
|
||||
|
||||
// (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)
|
||||
&& c->pathdist <= GUNRANGE) {
|
||||
if(a != roCheck) gun_attack(c);
|
||||
return itRevolver;
|
||||
}
|
||||
|
||||
// (5) psi blast (non-shmup variant)
|
||||
if(!shmup::on && items[itOrbPsi] && c->monst && (isDragon(c->monst) || !isWorm(c)) && c->monst != moShadow) {
|
||||
if(a != roCheck) psi_attack(c);
|
||||
return itOrbPsi;
|
||||
}
|
||||
|
||||
// (5a) summoning
|
||||
if(items[itOrbSummon] && summonedAt(c)) {
|
||||
if(a != roCheck) summonAt(c);
|
||||
return itOrbSummon;
|
||||
}
|
||||
|
||||
// (5b) matter
|
||||
if(items[itOrbMatter] && tempWallPossibleAt(c)) {
|
||||
if(a != roCheck) tempWallAt(c);
|
||||
return itOrbMatter;
|
||||
}
|
||||
|
||||
// (5c) stun
|
||||
if(items[itOrbStunning] && c->monst && !isMultitile(c->monst) && c->stuntime < 3 && !shmup::on) {
|
||||
if(a != roCheck) stun_attack(c);
|
||||
return itOrbStunning;
|
||||
}
|
||||
|
||||
// (6) place fire (non-shmup variant)
|
||||
if(!shmup::on && items[itOrbDragon] && makeflame(c, 20, true)) {
|
||||
if(a != roCheck) useOrbOfDragon(c);
|
||||
return itOrbDragon;
|
||||
}
|
||||
|
||||
if(a == roCheck) return itNone;
|
||||
|
||||
if(nowhereToBlow) {
|
||||
addMessage(XLAT("Nowhere to blow %the1!", c->monst));
|
||||
}
|
||||
else if(jumpstate == 1 && jumpthru && jumpthru->monst) {
|
||||
addMessage(XLAT("Cannot jump through %the1!", jumpthru->monst));
|
||||
}
|
||||
else if(jumpstate == 1 && jumpthru) {
|
||||
addMessage(XLAT("Cannot jump through %the1!", jumpthru->wall));
|
||||
}
|
||||
else if(jumpstate == 2 && c->monst) {
|
||||
addMessage(XLAT("Cannot jump on %the1!", c->monst));
|
||||
}
|
||||
else if(jumpstate == 2 && c->wall) {
|
||||
addMessage(XLAT("Cannot jump on %the1!", c->wall));
|
||||
}
|
||||
else if(jumpstate == 3) {
|
||||
addMessage(XLAT("%The1 would get you there!", which));
|
||||
}
|
||||
else if(items[itOrbAir] && c->monst) {
|
||||
addMessage(XLAT("%The1 is immune to wind!", c->monst));
|
||||
}
|
||||
else if(items[itOrbPsi] && c->monst) {
|
||||
addMessage(XLAT("%The1 is immune to mental blasts!", c->monst));
|
||||
}
|
||||
else if(items[itOrbTeleport] && c->monst) {
|
||||
addMessage(XLAT("Cannot teleport on a monster!"));
|
||||
}
|
||||
else if(c->item && items[itOrbTelekinesis]) {
|
||||
addMessage(XLAT("Not enough power for telekinesis!"));
|
||||
}
|
||||
else if(items[itOrbIllusion] && c->item)
|
||||
addMessage(XLAT("Cannot cast illusion on an item!"));
|
||||
else if(items[itOrbIllusion] && c->monst)
|
||||
addMessage(XLAT("Cannot cast illusion on a monster!"));
|
||||
else if(items[itOrbIllusion] && !passable(c, NULL, P_MIRROR))
|
||||
addMessage(XLAT("Cannot cast illusion here!"));
|
||||
else if(items[itOrbTeleport] && !passable(c, NULL, P_TELE | P_ISPLAYER)) {
|
||||
addMessage(XLAT("Cannot teleport here!"));
|
||||
}
|
||||
else if(items[itOrbMatter] && !tempWallPossibleAt(c)) {
|
||||
if(c->monst)
|
||||
addMessage(XLAT("Cannot create temporary matter on a monster!"));
|
||||
else if(c->item)
|
||||
addMessage(XLAT("Cannot create temporary matter on an item!"));
|
||||
else addMessage(XLAT("Cannot create temporary matter here!"));
|
||||
}
|
||||
else if(items[itOrbSummon] && !summonedAt(c)) {
|
||||
if(c->monst)
|
||||
addMessage(XLAT("Cannot summon on a monster!"));
|
||||
else
|
||||
addMessage(XLAT("No summoning possible here!"));
|
||||
}
|
||||
else if(items[itOrbTeleport] && c->item) {
|
||||
addMessage(XLAT("Cannot teleport on an item!"));
|
||||
}
|
||||
else if(items[itOrbDragon] && !makeflame(c, 20, true)) {
|
||||
addMessage(XLAT("Cannot throw fire there!"));
|
||||
}
|
||||
else return eItem(0);
|
||||
|
||||
return eItem(-1);
|
||||
}
|
||||
|
@ -1,3 +1,7 @@
|
||||
// Hyperbolic Rogue pattern generator
|
||||
|
||||
// Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details
|
||||
|
||||
void spill50(cell *c, eWall w, int r) {
|
||||
c->wall = w;
|
||||
if(r) for(int i=0; i<c->type; i++) spill50(createMov(c, i), w, r-1);
|
||||
|
@ -1,3 +1,7 @@
|
||||
// HyperRogue patterns
|
||||
|
||||
// Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details
|
||||
|
||||
// === EMERALD PATTERN ===
|
||||
|
||||
// rules for the emeraldvalues of heptagons.
|
||||
|
13976
polygons.cpp
13976
polygons.cpp
File diff suppressed because it is too large
Load Diff
697
rug.cpp
Normal file
697
rug.cpp
Normal file
@ -0,0 +1,697 @@
|
||||
// Hyperbolic Rogue
|
||||
// Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details
|
||||
|
||||
// implementation of the Hypersian Rug mode
|
||||
|
||||
#ifndef MOBILE
|
||||
|
||||
#define TEXTURESIZE (texturesize)
|
||||
#define HTEXTURESIZE (texturesize/2)
|
||||
|
||||
#ifdef LINUX
|
||||
extern "C" {
|
||||
GLAPI void APIENTRY glGenFramebuffers (GLsizei n, GLuint *framebuffers);
|
||||
GLAPI void APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer);
|
||||
GLAPI void APIENTRY glFramebufferTexture (GLenum target, GLenum attachment, GLuint texture, GLint level);
|
||||
GLAPI GLenum APIENTRY glCheckFramebufferStatus (GLenum target);
|
||||
GLAPI void APIENTRY glDrawBuffers (GLsizei n, const GLenum *bufs);
|
||||
GLAPI void APIENTRY glGenRenderbuffers (GLsizei n, GLuint *renderbuffers);
|
||||
GLAPI void APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer);
|
||||
GLAPI void APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
|
||||
GLAPI void APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
|
||||
GLAPI void APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint *renderbuffers);
|
||||
GLAPI void APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint *framebuffers);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MAC
|
||||
#define glFramebufferTexture glFramebufferTextureEXT
|
||||
#endif
|
||||
|
||||
namespace rug {
|
||||
|
||||
// hypersian rug datatypes and globals
|
||||
//-------------------------------------
|
||||
|
||||
bool rugged = false;
|
||||
bool genrug = false;
|
||||
bool glew = false;
|
||||
|
||||
bool renderonce = false;
|
||||
bool rendernogl = false;
|
||||
int texturesize = 1024;
|
||||
double scale = 1;
|
||||
|
||||
int queueiter, qvalid, dt;
|
||||
double err;
|
||||
|
||||
struct edge {
|
||||
struct rugpoint *target;
|
||||
double len;
|
||||
};
|
||||
|
||||
struct rugpoint {
|
||||
double x1, y1;
|
||||
bool valid;
|
||||
bool inqueue;
|
||||
hyperpoint h;
|
||||
hyperpoint flat;
|
||||
vector<edge> edges;
|
||||
};
|
||||
|
||||
struct triangle {
|
||||
rugpoint *m[3];
|
||||
triangle(rugpoint *m1, rugpoint *m2, rugpoint *m3) {
|
||||
m[0] = m1; m[1] = m2; m[2] = m3;
|
||||
}
|
||||
};
|
||||
|
||||
vector<rugpoint*> points;
|
||||
vector<triangle> triangles;
|
||||
|
||||
// construct the graph
|
||||
//---------------------
|
||||
|
||||
map<cell*, hyperpoint> gmatrix;
|
||||
|
||||
void buildVertexInfo(cell *c, transmatrix V) { if(genrug) gmatrix[c] = V*C0; }
|
||||
|
||||
int hyprand;
|
||||
|
||||
rugpoint *addRugpoint(hyperpoint h) {
|
||||
rugpoint *m = new rugpoint;
|
||||
m->h = h;
|
||||
|
||||
ld tz = vid.alphax+h[2];
|
||||
m->x1 = (1 + h[0] / tz) / 2;
|
||||
m->y1 = (1 + h[1] / tz) / 2;
|
||||
m->flat = // hpxyz(h[0], h[1], sin(atan2(h[0], h[1]) * 3 + hyprand) * (h[2]-1) / 1000);
|
||||
hpxyz(h[0], h[1], (h[2]-1) * (rand() % 1000 - rand() % 1000) / 1000);
|
||||
m->valid = false;
|
||||
m->inqueue = false;
|
||||
points.push_back(m);
|
||||
return m;
|
||||
}
|
||||
|
||||
rugpoint *findRugpoint(hyperpoint h) {
|
||||
for(int i=0; i<size(points); i++)
|
||||
if(intval(points[i]->h, h) < 1e-5) return points[i];
|
||||
return addRugpoint(h);
|
||||
}
|
||||
|
||||
void addNewEdge(rugpoint *e1, rugpoint *e2) {
|
||||
edge e; e.target = e2; e1->edges.push_back(e);
|
||||
e.target = e1; e2->edges.push_back(e);
|
||||
}
|
||||
|
||||
void addEdge(rugpoint *e1, rugpoint *e2) {
|
||||
for(int i=0; i<size(e1->edges); i++)
|
||||
if(e1->edges[i].target == e2) return;
|
||||
addNewEdge(e1, e2);
|
||||
}
|
||||
|
||||
void addTriangle(rugpoint *t1, rugpoint *t2, rugpoint *t3) {
|
||||
addEdge(t1, t2); addEdge(t2, t3); addEdge(t3, t1);
|
||||
triangles.push_back(triangle(t1,t2,t3));
|
||||
}
|
||||
|
||||
void addTriangle1(rugpoint *t1, rugpoint *t2, rugpoint *t3) {
|
||||
rugpoint *t12 = findRugpoint(mid(t1->h, t2->h));
|
||||
rugpoint *t23 = findRugpoint(mid(t2->h, t3->h));
|
||||
rugpoint *t31 = findRugpoint(mid(t3->h, t1->h));
|
||||
addTriangle(t1, t12, t31);
|
||||
addTriangle(t12, t2, t23);
|
||||
addTriangle(t23, t3, t31);
|
||||
addTriangle(t23, t31, t12);
|
||||
}
|
||||
|
||||
bool psort(rugpoint *a, rugpoint *b) {
|
||||
return a->h[2] < b->h[2];
|
||||
}
|
||||
|
||||
void calcLengths() {
|
||||
for(int i=0; i<size(points); i++) for(int j=0; j<size(points[i]->edges); j++)
|
||||
points[i]->edges[j].len = hdist(points[i]->h, points[i]->edges[j].target->h);
|
||||
}
|
||||
|
||||
void buildRug() {
|
||||
|
||||
map<cell*, rugpoint *> vptr;
|
||||
|
||||
for(int i=0; i<size(dcal); i++)
|
||||
if(gmatrix.count(dcal[i]))
|
||||
vptr[dcal[i]] = addRugpoint(gmatrix[dcal[i]]);
|
||||
|
||||
for(int i=0; i<size(dcal); i++) {
|
||||
cell *c = dcal[i];
|
||||
rugpoint *v = vptr[c];
|
||||
if(!v) continue;
|
||||
for(int j=0; j<c->type; j++) {
|
||||
cell *c2 = c->mov[j];
|
||||
rugpoint *w = vptr[c2];
|
||||
if(!w) continue;
|
||||
// if(v<w) addEdge(v, w);
|
||||
|
||||
cell *c3 = c->mov[(j+1) % c->type];
|
||||
rugpoint *w2 = vptr[c3];
|
||||
if(!w2) continue;
|
||||
if(c->type == 7) addTriangle(v, w, w2);
|
||||
}
|
||||
}
|
||||
|
||||
printf("vertices = %d triangles= %d\n", size(points), size(triangles));
|
||||
|
||||
calcLengths();
|
||||
sort(points.begin(), points.end(), psort);
|
||||
}
|
||||
|
||||
// rug physics
|
||||
|
||||
queue<rugpoint*> pqueue;
|
||||
void enqueue(rugpoint *m) {
|
||||
if(m->inqueue) return;
|
||||
pqueue.push(m);
|
||||
m->inqueue = true;
|
||||
}
|
||||
|
||||
void force(rugpoint& m1, rugpoint& m2, double rd, double d1=1, double d2=1) {
|
||||
if(!m1.valid || !m2.valid) return;
|
||||
// double rd = hdist(m1.h, m2.h) * xd;
|
||||
// if(rd > rdz +1e-6 || rd< rdz-1e-6) printf("%lf %lf\n", rd, rdz);
|
||||
double t = 0;
|
||||
for(int i=0; i<3; i++) t += (m1.flat[i] - m2.flat[i]) * (m1.flat[i] - m2.flat[i]);
|
||||
t = sqrt(t);
|
||||
// printf("%lf %lf\n", t, rd);
|
||||
err += (t-rd) * (t-rd);
|
||||
bool nonzero = t < rd-1e-9 || t > rd+1e-9;
|
||||
double force = (t - rd) / t / 2; // 20.0;
|
||||
for(int i=0; i<3; i++) {
|
||||
double di = (m2.flat[i] - m1.flat[i]) * force;
|
||||
m1.flat[i] += di * d1;
|
||||
m2.flat[i] -= di * d2;
|
||||
if(nonzero && d2>0) enqueue(&m2);
|
||||
}
|
||||
}
|
||||
|
||||
void preset(rugpoint *m) {
|
||||
int q = 0;
|
||||
hyperpoint h;
|
||||
for(int i=0; i<3; i++) h[i] = 0;
|
||||
using namespace hyperpoint_vec;
|
||||
|
||||
for(int j=0; j<size(m->edges); j++)
|
||||
for(int k=0; k<j; k++) {
|
||||
rugpoint *a = m->edges[j].target;
|
||||
rugpoint *b = m->edges[k].target;
|
||||
if(!a->valid) continue;
|
||||
if(!b->valid) continue;
|
||||
double blen = -1;
|
||||
for(int j2=0; j2<size(a->edges); j2++)
|
||||
if(a->edges[j2].target == b) blen = a->edges[j2].len;
|
||||
if(blen <= 0) continue;
|
||||
for(int j2=0; j2<size(a->edges); j2++)
|
||||
for(int k2=0; k2<size(b->edges); k2++)
|
||||
if(a->edges[j2].target == b->edges[k2].target && a->edges[j2].target != m) {
|
||||
rugpoint *c = a->edges[j2].target;
|
||||
if(!c->valid) continue;
|
||||
|
||||
double a1 = m->edges[j].len/blen;
|
||||
double a2 = m->edges[k].len/blen;
|
||||
double c1 = a->edges[j2].len/blen;
|
||||
double c2 = b->edges[k2].len/blen;
|
||||
|
||||
double cz = (c1*c1-c2*c2+1) / 2;
|
||||
double ch = sqrt(c2*c2 - cz*cz);
|
||||
|
||||
double az = (a1*a1-a2*a2+1) / 2;
|
||||
double ah = sqrt(a2*a2 - az*az);
|
||||
|
||||
// c->h = a->h + (b->h-a->h) * cz + ch * ort
|
||||
hyperpoint ort = (c->flat - a->flat - cz * (b->flat-a->flat)) / ch;
|
||||
|
||||
// m->h = a->h + (b->h-a->h) * 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++;
|
||||
}
|
||||
}
|
||||
|
||||
if(q>0) for(int i=0; i<3; i++) m->flat[i] = h[i]/q;
|
||||
}
|
||||
|
||||
int divides = 0;
|
||||
bool stop = false;
|
||||
|
||||
void subdivide() {
|
||||
int N = size(points);
|
||||
if(divides > 4) {stop = true; return; }
|
||||
printf("subdivide (%d,%d)\n", N, size(triangles));
|
||||
divides++;
|
||||
vector<triangle> otriangles = triangles;
|
||||
triangles.clear();
|
||||
|
||||
// subdivide edges
|
||||
for(int i=0; i<N; i++) {
|
||||
rugpoint *m = points[i];
|
||||
for(int j=0; j<size(m->edges); j++) {
|
||||
rugpoint *m2 = m->edges[j].target;
|
||||
rugpoint *mm = addRugpoint(mid(m->h, m2->h));
|
||||
using namespace hyperpoint_vec;
|
||||
mm->flat = (m->flat + m2->flat) / 2;
|
||||
mm->valid = true; qvalid++;
|
||||
mm->inqueue = false; enqueue(mm);
|
||||
}
|
||||
m->edges.clear();
|
||||
}
|
||||
|
||||
for(int i=0; i<size(otriangles); i++)
|
||||
addTriangle1(otriangles[i].m[0], otriangles[i].m[1], otriangles[i].m[2]);
|
||||
|
||||
calcLengths();
|
||||
|
||||
printf("result (%d,%d)\n", size(points), size(triangles));
|
||||
}
|
||||
|
||||
void addNewPoints() {
|
||||
|
||||
if(qvalid == size(points)) {
|
||||
subdivide();
|
||||
return;
|
||||
}
|
||||
|
||||
double dist = points[qvalid]->h[2] + .1e-6;
|
||||
|
||||
int oqvalid = qvalid;
|
||||
|
||||
for(int i=0; i<size(points); i++) {
|
||||
rugpoint& m = *points[i];
|
||||
bool wasvalid = m.valid;
|
||||
m.valid = wasvalid || (m.h[2] >= .5 && m.h[2] < dist);
|
||||
if(m.valid && !wasvalid) {
|
||||
qvalid++;
|
||||
if(i > 7) preset(&m);
|
||||
|
||||
for(int it=0; it<50; it++)
|
||||
for(int j=0; j<size(m.edges); j++)
|
||||
force(m, *m.edges[j].target, m.edges[j].len, 1, 0);
|
||||
|
||||
enqueue(&m);
|
||||
}
|
||||
}
|
||||
if(qvalid != oqvalid) { printf("%4d %4d %4d %.9lf %9d %9d\n", oqvalid, qvalid, size(points), dist, dt, queueiter); }
|
||||
}
|
||||
|
||||
void physics() {
|
||||
|
||||
for(int it=0; it<10000 && !stop; it++)
|
||||
if(pqueue.empty()) addNewPoints();
|
||||
else {
|
||||
queueiter++;
|
||||
rugpoint *m = pqueue.front();
|
||||
pqueue.pop();
|
||||
m->inqueue = false;
|
||||
for(int j=0; j<size(m->edges); j++)
|
||||
force(*m, *m->edges[j].target, m->edges[j].len);
|
||||
}
|
||||
}
|
||||
|
||||
// drawing the Rug
|
||||
//-----------------
|
||||
|
||||
int eyemod;
|
||||
|
||||
void getco(rugpoint& m, double& x, double& y, double& z) {
|
||||
x = m.flat[0];
|
||||
y = m.flat[1];
|
||||
z = m.flat[2];
|
||||
if(eyemod) x += eyemod * z * vid.eye;
|
||||
}
|
||||
|
||||
extern int besti;
|
||||
|
||||
void drawTriangle(triangle& t) {
|
||||
rugpoint& m1 = *t.m[0];
|
||||
rugpoint& m2 = *t.m[1];
|
||||
rugpoint& m3 = *t.m[2];
|
||||
if(!m1.valid || !m2.valid || !m3.valid) return;
|
||||
dt++;
|
||||
double x1, y1, z1;
|
||||
double x2, y2, z2;
|
||||
double x3, y3, z3;
|
||||
getco(m1,x1,y1,z1);
|
||||
getco(m2,x2,y2,z2);
|
||||
getco(m3,x3,y3,z3);
|
||||
|
||||
double xa = x2-x1, ya = y2-y1, za = z2-z1;
|
||||
double xb = x3-x1, yb = y3-y1, zb = z3-z1;
|
||||
|
||||
double xn = ya * zb - za * yb;
|
||||
double yn = za * xb - xa * zb;
|
||||
double zn = xa * yb - ya * xb;
|
||||
double h = sqrt(xn*xn+yn*yn+zn*zn);
|
||||
|
||||
glNormal3f(xn/h,yn/h,zn/h);
|
||||
|
||||
glTexCoord2f(m1.x1, m1.y1);
|
||||
glVertex3f(x1, y1, z1);
|
||||
glTexCoord2f(m2.x1, m2.y1);
|
||||
glVertex3f(x2, y2, z2);
|
||||
glTexCoord2f(m3.x1, m3.y1);
|
||||
glVertex3f(x3, y3, z3);
|
||||
}
|
||||
|
||||
void setVidParam() {
|
||||
vid.xres = vid.yres = TEXTURESIZE; vid.scale = 1;
|
||||
vid.radius = HTEXTURESIZE; vid.xcenter = HTEXTURESIZE; vid.ycenter = HTEXTURESIZE;
|
||||
vid.beta = 2; vid.alphax = 1; vid.eye = 0; vid.goteyes = false;
|
||||
}
|
||||
|
||||
GLuint FramebufferName = 0;
|
||||
GLuint renderedTexture = 0;
|
||||
GLuint depth_stencil_rb = 0;
|
||||
|
||||
SDL_Surface *texture;
|
||||
Uint32 *expanded_data;
|
||||
|
||||
void initTexture() {
|
||||
|
||||
if(!rendernogl) {
|
||||
FramebufferName = 0;
|
||||
glGenFramebuffers(1, &FramebufferName);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
|
||||
|
||||
glGenTextures(1, &renderedTexture);
|
||||
glBindTexture(GL_TEXTURE_2D, renderedTexture);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, TEXTURESIZE, TEXTURESIZE, 0,GL_RGB, GL_UNSIGNED_BYTE, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
|
||||
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, renderedTexture, 0);
|
||||
GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0};
|
||||
glDrawBuffers(1, DrawBuffers);
|
||||
|
||||
glGenRenderbuffers(1, &depth_stencil_rb);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, depth_stencil_rb);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, TEXTURESIZE, TEXTURESIZE);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_stencil_rb);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depth_stencil_rb);
|
||||
|
||||
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||||
addMessage("Failed to initialize the framebuffer");
|
||||
rugged = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
texture = SDL_CreateRGBSurface(SDL_SWSURFACE,TEXTURESIZE,TEXTURESIZE,32,0,0,0,0);
|
||||
glGenTextures( 1, &renderedTexture );
|
||||
glBindTexture( GL_TEXTURE_2D, renderedTexture);
|
||||
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
|
||||
expanded_data = new Uint32[TEXTURESIZE * TEXTURESIZE];
|
||||
}
|
||||
}
|
||||
|
||||
void prepareTexture() {
|
||||
videopar svid = vid;
|
||||
|
||||
setVidParam();
|
||||
|
||||
if(rendernogl) {
|
||||
vid.usingGL = false;
|
||||
SDL_Surface *sav = s;
|
||||
s = texture;
|
||||
SDL_FillRect(s, NULL, 0);
|
||||
|
||||
drawfullmap();
|
||||
s = sav;
|
||||
for(int y=0; y<TEXTURESIZE; y++) for(int x=0; x<TEXTURESIZE; x++)
|
||||
expanded_data[y*TEXTURESIZE + x] = qpixel(texture, x, TEXTURESIZE-1-y) | 0xFF000000;
|
||||
glBindTexture( GL_TEXTURE_2D, renderedTexture);
|
||||
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, TEXTURESIZE, TEXTURESIZE, 0, GL_BGRA, GL_UNSIGNED_BYTE, expanded_data );
|
||||
}
|
||||
else {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
|
||||
glViewport(0,0,TEXTURESIZE,TEXTURESIZE);
|
||||
|
||||
setGLProjection();
|
||||
ptds.clear();
|
||||
drawthemap();
|
||||
if(!renderonce) queueline(C0, mouseh, 0xFF00FF);
|
||||
drawqueue();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
vid = svid;
|
||||
if(!rendernogl) glViewport(0,0,vid.xres,vid.yres);
|
||||
}
|
||||
|
||||
void closeTexture() {
|
||||
if(rendernogl) {
|
||||
SDL_FreeSurface(texture);
|
||||
glDeleteTextures(1, &renderedTexture);
|
||||
delete[] expanded_data;
|
||||
}
|
||||
else {
|
||||
glDeleteTextures(1, &renderedTexture);
|
||||
glDeleteRenderbuffers(1, &depth_stencil_rb);
|
||||
glDeleteFramebuffers(1, &FramebufferName);
|
||||
}
|
||||
}
|
||||
|
||||
double xview, yview;
|
||||
|
||||
void drawRugScene() {
|
||||
GLfloat light_ambient[] = { 3.5, 3.5, 3.5, 1.0 };
|
||||
GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
|
||||
GLfloat light_position[] = { 0.0, 0.0, 0.0, 1.0 };
|
||||
|
||||
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
|
||||
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
|
||||
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
|
||||
|
||||
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
|
||||
GLERR("lighting");
|
||||
|
||||
glEnable(GL_LIGHTING);
|
||||
glEnable(GL_LIGHT0);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, renderedTexture);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
|
||||
glClearColor(0.05,0.05,0.05,1);
|
||||
glClearDepth(1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
xview = vid.xres/(vid.radius*scale);
|
||||
yview = vid.yres/(vid.radius*scale);
|
||||
|
||||
glOrtho(-xview, xview, -yview, yview, -1000, 1000);
|
||||
|
||||
glColor4f(1,1,1,1);
|
||||
|
||||
if(vid.eye > .001 || vid.eye < -.001) {
|
||||
selectEyeMask(1);
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
glBegin(GL_TRIANGLES);
|
||||
eyemod = 1;
|
||||
for(int t=0; t<size(triangles); t++)
|
||||
drawTriangle(triangles[t]);
|
||||
glEnd();
|
||||
selectEyeMask(-1);
|
||||
eyemod = -1;
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
glBegin(GL_TRIANGLES);
|
||||
for(int t=0; t<size(triangles); t++)
|
||||
drawTriangle(triangles[t]);
|
||||
glEnd();
|
||||
selectEyeMask(0);
|
||||
}
|
||||
else {
|
||||
glBegin(GL_TRIANGLES);
|
||||
for(int t=0; t<size(triangles); t++)
|
||||
drawTriangle(triangles[t]);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_LIGHTING);
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
selectEyeGL(0);
|
||||
}
|
||||
|
||||
// organization
|
||||
//--------------
|
||||
|
||||
transmatrix rotmatrix(double rotation, int c0, int c1) {
|
||||
transmatrix t = Id;
|
||||
t[c0][c0] = cos(rotation);
|
||||
t[c1][c1] = cos(rotation);
|
||||
t[c0][c1] = sin(rotation);
|
||||
t[c1][c0] = -sin(rotation);
|
||||
return t;
|
||||
}
|
||||
|
||||
transmatrix currentrot;
|
||||
|
||||
void init() {
|
||||
#ifdef WINDOWS
|
||||
if(!glew) {
|
||||
glew = true;
|
||||
GLenum err = glewInit();
|
||||
if (GLEW_OK != err) {
|
||||
addMessage("Failed to initialize GLEW");
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if(rugged) return;
|
||||
rugged = true;
|
||||
if(scale < .01 || scale > 100) scale = 1;
|
||||
initTexture();
|
||||
if(renderonce) prepareTexture();
|
||||
if(!rugged) return;
|
||||
|
||||
gmatrix.clear();
|
||||
genrug = true;
|
||||
drawthemap();
|
||||
genrug = false;
|
||||
|
||||
buildRug();
|
||||
qvalid = 0; dt = 0; queueiter = 0;
|
||||
|
||||
currentrot = Id;
|
||||
}
|
||||
|
||||
void close() {
|
||||
if(!rugged) return;
|
||||
rugged = false;
|
||||
closeTexture();
|
||||
triangles.clear();
|
||||
for(int i=0; i<size(points); i++) delete points[i];
|
||||
points.clear();
|
||||
gmatrix.clear();
|
||||
pqueue = queue<rugpoint*> ();
|
||||
}
|
||||
|
||||
int lastticks;
|
||||
|
||||
void actDraw() {
|
||||
if(!renderonce) prepareTexture();
|
||||
physics();
|
||||
drawRugScene();
|
||||
Uint8 *keystate = SDL_GetKeyState(NULL);
|
||||
int qm = 0;
|
||||
transmatrix t = Id;
|
||||
double alpha = (ticks - lastticks) / 1000.0;
|
||||
lastticks = ticks;
|
||||
|
||||
if(keystate[SDLK_HOME]) qm++, t = inverse(currentrot);
|
||||
if(keystate[SDLK_END]) qm++, t = currentrot * rotmatrix(alpha, 0, 1) * inverse(currentrot);
|
||||
if(keystate[SDLK_DOWN]) qm++, t = t * rotmatrix(alpha, 1, 2);
|
||||
if(keystate[SDLK_UP]) qm++, t = t * rotmatrix(alpha, 2, 1);
|
||||
if(keystate[SDLK_LEFT]) qm++, t = t * rotmatrix(alpha, 0, 2);
|
||||
if(keystate[SDLK_RIGHT]) qm++, t = t * rotmatrix(alpha, 2, 0);
|
||||
if(keystate[SDLK_PAGEUP]) scale *= exp(alpha);
|
||||
if(keystate[SDLK_PAGEDOWN]) scale /= exp(alpha);
|
||||
|
||||
if(qm) {
|
||||
currentrot = t * currentrot;
|
||||
for(int i=0; i<size(points); i++) points[i]->flat = t * points[i]->flat;
|
||||
}
|
||||
}
|
||||
|
||||
int besti;
|
||||
|
||||
hyperpoint gethyper(ld x, ld y) {
|
||||
double mx = ((x*2 / vid.xres)-1) * xview;
|
||||
double my = (1-(y*2 / vid.yres)) * yview;
|
||||
double bdist = 1e12;
|
||||
besti = 0;
|
||||
|
||||
for(int i=0; i<size(points); i++) {
|
||||
rugpoint& m = *points[i];
|
||||
double dist = hypot(m.flat[0]-mx, m.flat[1]-my);
|
||||
if(dist < bdist) bdist = dist, besti = i;
|
||||
}
|
||||
|
||||
double px = points[besti]->x1 * TEXTURESIZE, py = (1-points[besti]->y1) * TEXTURESIZE;
|
||||
|
||||
videopar svid = vid;
|
||||
setVidParam();
|
||||
hyperpoint h = ::gethyper(px, py);
|
||||
vid = svid;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
void show() {
|
||||
displayStat( 0, XLAT("hypersian rug mode"), "", ' ');
|
||||
displayStat( 2, XLAT("what's this?"), "", 'h');
|
||||
displayStat( 3, XLAT("take me back"), "", 'q');
|
||||
displayStat( 4, XLAT("enable the Hypersian Rug mode"), "", 'u');
|
||||
displayStat( 6, XLAT("render the texture only once"), ONOFF(renderonce), 'o');
|
||||
displayStat( 7, XLAT("render texture without OpenGL"), ONOFF(rendernogl), 'g');
|
||||
displayStat( 8, XLAT("texture size"), its(texturesize)+"x"+its(texturesize), 's');
|
||||
}
|
||||
|
||||
void handleKey(int uni, int sym) {
|
||||
|
||||
if(uni == 'h') {
|
||||
lastmode = cmode;
|
||||
cmode = emHelp;
|
||||
help =
|
||||
"In this mode, HyperRogue is played on a 3D model of a part of the hyperbolic plane, "
|
||||
"similar to one you get from the 'paper model creator' or by hyperbolic crocheting.\n\n"
|
||||
"This requires some OpenGL extensions and may crash or not work correctly -- enabling "
|
||||
"the 'render texture without OpenGL' options may be helpful in this case. Also the 'render once' option "
|
||||
"will make the rendering faster, but the surface will be rendered only once, so "
|
||||
"you won't be able to play a game on it.\n\n"
|
||||
"Use arrow keys to rotate, Page Up/Down to zoom.";
|
||||
}
|
||||
else if(uni == 'u') {
|
||||
rug::init();
|
||||
cmode = emNormal;
|
||||
}
|
||||
else if(uni == 'q')
|
||||
cmode = emChangeMode;
|
||||
else if(uni == 'o')
|
||||
renderonce = !renderonce;
|
||||
else if(uni == 'g')
|
||||
rendernogl = !rendernogl;
|
||||
else if(uni == 's') {
|
||||
texturesize = 2*texturesize;
|
||||
if(texturesize == 8192) texturesize = 128;
|
||||
}
|
||||
}
|
||||
|
||||
void select() {
|
||||
if(rug::rugged) rug::close();
|
||||
else cmode = emRugConfig;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// fake for mobile
|
||||
namespace rug {
|
||||
bool rugged = false;
|
||||
bool renderonce = false;
|
||||
bool rendernogl = true;
|
||||
int texturesize = 512;
|
||||
double scale = 1.0f;
|
||||
}
|
||||
|
||||
#endif
|
45
savepng.h
Normal file
45
savepng.h
Normal file
@ -0,0 +1,45 @@
|
||||
#ifndef _SDL_SAVEPNG
|
||||
#define _SDL_SAVEPNG
|
||||
/*
|
||||
* SDL_SavePNG -- libpng-based SDL_Surface writer.
|
||||
*
|
||||
* This code is free software, available under zlib/libpng license.
|
||||
* http://www.libpng.org/pub/png/src/libpng-LICENSE.txt
|
||||
*/
|
||||
// #include <SDL_video.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" { /* This helps CPP projects that include this header */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Save an SDL_Surface as a PNG file.
|
||||
*
|
||||
* Returns 0 success or -1 on failure, the error message is then retrievable
|
||||
* via SDL_GetError().
|
||||
*/
|
||||
#define SDL_SavePNG(surface, file) \
|
||||
SDL_SavePNG_RW(surface, SDL_RWFromFile(file, "wb"), 1)
|
||||
|
||||
/*
|
||||
* Save an SDL_Surface as a PNG file, using writable RWops.
|
||||
*
|
||||
* surface - the SDL_Surface structure containing the image to be saved
|
||||
* dst - a data stream to save to
|
||||
* freedst - non-zero to close the stream after being written
|
||||
*
|
||||
* Returns 0 success or -1 on failure, the error message is then retrievable
|
||||
* via SDL_GetError().
|
||||
*/
|
||||
extern int SDL_SavePNG_RW(SDL_Surface *surface, SDL_RWops *rw, int freedst);
|
||||
|
||||
/*
|
||||
* Return new SDL_Surface with a format suitable for PNG output.
|
||||
*/
|
||||
extern SDL_Surface *SDL_PNGFormatAlpha(SDL_Surface *src);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
1104
system.cpp
Normal file
1104
system.cpp
Normal file
File diff suppressed because it is too large
Load Diff
15
tools.cpp
Normal file
15
tools.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include "hyper.h"
|
||||
|
||||
#include "hyperpoint.cpp"
|
||||
#include "fjordgen.cpp"
|
||||
#include "heptagon.cpp"
|
||||
#include "language.cpp"
|
||||
#include "achievement.cpp"
|
699
yendor.cpp
Normal file
699
yendor.cpp
Normal file
@ -0,0 +1,699 @@
|
||||
// Hyperbolic Rogue
|
||||
|
||||
// Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details
|
||||
|
||||
// Yendor Quest, together with the Yendor Challenge
|
||||
// also, the Pure Tactics Mode
|
||||
|
||||
#define MODECODES 38
|
||||
|
||||
int hiitemsMax(eItem it) {
|
||||
int mx = 0;
|
||||
for(int i=0; i<MODECODES; i++) if(hiitems[i][it] > mx) mx = hiitems[i][it];
|
||||
return mx;
|
||||
}
|
||||
|
||||
int modecode();
|
||||
|
||||
typedef vector<pair<int, string> > subscoreboard;
|
||||
|
||||
void displayScore(subscoreboard& s, int x) {
|
||||
int vf = min((vid.yres-64) / 70, vid.xres/80);
|
||||
|
||||
if(syncstate == 1) {
|
||||
displayfr(x, 56, 1, vf, "(syncing)", 0xC0C0C0, 0);
|
||||
}
|
||||
else {
|
||||
sort(s.begin(), s.end());
|
||||
for(int i=0; i<size(s); i++) {
|
||||
int i0 = 56 + i * vf;
|
||||
displayfr(x, i0, 1, vf, its(-s[i].first), 0xC0C0C0, 16);
|
||||
displayfr(x+8, i0, 1, vf, s[i].second, 0xC0C0C0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace yendor {
|
||||
|
||||
bool on = false;
|
||||
bool generating = false;
|
||||
bool path = false;
|
||||
bool everwon = false;
|
||||
bool won = false;
|
||||
bool easy = false;
|
||||
|
||||
struct yendorlevel {
|
||||
eLand l;
|
||||
int flags;
|
||||
};
|
||||
|
||||
int challenge; // id of the challenge
|
||||
int lastchallenge;
|
||||
|
||||
#define YENDORLEVELS 27
|
||||
|
||||
int bestscore[MODECODES][YENDORLEVELS];
|
||||
|
||||
#define YF_DEAD 1
|
||||
#define YF_WALLS 2
|
||||
#define YF_END 4
|
||||
#define YF_DEAD5 8
|
||||
|
||||
#define YF_NEAR_IVY 16
|
||||
#define YF_NEAR_ELEM 32
|
||||
#define YF_NEAR_OVER 64
|
||||
#define YF_NEAR_RED 128
|
||||
#define YF_REPEAT 512
|
||||
#define YF_NEAR_TENT 1024
|
||||
|
||||
#define YF_START_AL 2048
|
||||
#define YF_START_CR 4096
|
||||
#define YF_CHAOS 8192
|
||||
|
||||
#define YF_START_ANY (YF_START_AL|YF_START_CR)
|
||||
|
||||
eLand nexttostart;
|
||||
|
||||
#define LAND_YENDOR_CHAOS 41
|
||||
|
||||
yendorlevel levels[YENDORLEVELS] = {
|
||||
{laNone, 0},
|
||||
{laHell, YF_DEAD}, // FORCE BARRIERS?
|
||||
{laGraveyard, YF_DEAD5},
|
||||
{laDesert, YF_NEAR_IVY}, // IVY OR TENTACLE?
|
||||
{laMinefield, YF_END}, // NOT WON, SEEMS OKAY
|
||||
{laEmerald, 0}, // WON FINE
|
||||
{laOvergrown, 0}, // WON, TOO EASY?
|
||||
{laMotion, YF_START_AL | YF_END}, // NOT WON, SEEMS OKAY
|
||||
{laAlchemist, 0}, // ALMOST WON
|
||||
{laIvoryTower,YF_START_CR | YF_NEAR_ELEM | YF_REPEAT}, // won cool
|
||||
{laMirror, YF_NEAR_OVER}, // OK
|
||||
{laWhirlpool, 0}, // cool
|
||||
{laIce, YF_NEAR_ELEM}, // OK
|
||||
{laHive, YF_NEAR_RED}, // OK
|
||||
{laCaribbean, 0}, // seems OK
|
||||
{laOcean, YF_WALLS}, // well... stupid, add Caribbean/Fjord
|
||||
{laPalace, 0}, // more trapdoors!
|
||||
{laZebra, 0}, // TOO HARD?
|
||||
{laWineyard, 0}, // hard-ish
|
||||
{laStorms, 0}, // ?
|
||||
{laLivefjord, 0},
|
||||
{laJungle, 0},
|
||||
{laPower, YF_START_CR},
|
||||
{laWildWest, 0},
|
||||
{laWhirlwind, YF_NEAR_TENT},
|
||||
{laHell, YF_CHAOS | YF_DEAD},
|
||||
{laDragon, YF_DEAD}
|
||||
};
|
||||
|
||||
void uploadScore() {
|
||||
int tscore = 0;
|
||||
for(int i=1; i<YENDORLEVELS; i++)
|
||||
if(bestscore[0][i]) tscore += 999 + bestscore[0][i];
|
||||
// printf("Yendor score = %d\n", tscore);
|
||||
achievement_score(LB_YENDOR_CHALLENGE, tscore);
|
||||
}
|
||||
|
||||
yendorlevel& clev() { return levels[challenge]; }
|
||||
|
||||
eLand changeland(int i, eLand l) {
|
||||
if((clev().flags & YF_START_ANY) && i < 20 && l != clev().l) return clev().l;
|
||||
if((clev().flags & YF_END) && i > 80 && l == clev().l) return laIce;
|
||||
return laNone;
|
||||
}
|
||||
|
||||
string name;
|
||||
eLand first, second, last;
|
||||
|
||||
struct yendorinfo {
|
||||
cell *path[YDIST];
|
||||
bool found;
|
||||
bool foundOrb;
|
||||
int howfar;
|
||||
};
|
||||
|
||||
vector<yendorinfo> yi;
|
||||
|
||||
int yii = 0;
|
||||
|
||||
int hardness() {
|
||||
int thf = 0;
|
||||
for(int i=0; i<size(yi); i++) {
|
||||
yendorinfo& ye ( yi[i] );
|
||||
if(!ye.foundOrb && ye.howfar > 25)
|
||||
thf += (ye.howfar - 25);
|
||||
}
|
||||
thf -= 2 * (YDIST - 25);
|
||||
if(thf<0) thf = 0;
|
||||
return items[itOrbYendor] * 5 + (thf * 5) / (YDIST-25);
|
||||
}
|
||||
|
||||
enum eState { ysUntouched, ysLocked, ysUnlocked };
|
||||
|
||||
eState state(cell *yendor) {
|
||||
for(int i=0; i<size(yi); i++) if(yi[i].path[0] == yendor)
|
||||
return yi[i].found ? ysUnlocked : ysLocked;
|
||||
return ysUntouched;
|
||||
}
|
||||
|
||||
bool check(cell *yendor, bool checkonly) {
|
||||
int byi = size(yi);
|
||||
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(checkonly) return false;
|
||||
if(byi == size(yi)) {
|
||||
yendorinfo nyi;
|
||||
nyi.path[0] = yendor;
|
||||
nyi.howfar = 0;
|
||||
|
||||
if(euclid) {
|
||||
int di = hrand(6);
|
||||
int dj = (di+1) % 6;
|
||||
int qty = hrand(YDIST-1);
|
||||
int tot = 0;
|
||||
for(int i=0; i<YDIST-1; i++) {
|
||||
tot += qty;
|
||||
if(tot >= YDIST-1) {
|
||||
tot -= YDIST-1;
|
||||
nyi.path[i+1] = createMov(nyi.path[i], di);
|
||||
}
|
||||
else
|
||||
nyi.path[i+1] = createMov(nyi.path[i], dj);
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
bool endorian_change = true;
|
||||
bool in_endorian = false;
|
||||
cellwalker lig(yendor, hrand(yendor->type));
|
||||
for(int i=0; i<YDIST-1; i++) {
|
||||
if(lig.c->land == laEndorian)
|
||||
in_endorian = true;
|
||||
else if(!isTechnicalLand(lig.c->land))
|
||||
in_endorian = false;
|
||||
nyi.path[i] = lig.c;
|
||||
|
||||
cwstep(lig);
|
||||
cwspin(lig, 3);
|
||||
if(lig.c->type == 7) {
|
||||
if(in_endorian && endorian_change && i >= YDIST - 20) {
|
||||
// make the last leg a bit more difficult
|
||||
cwspin(lig, hrand(2)*3-1);
|
||||
endorian_change = false;
|
||||
}
|
||||
else
|
||||
cwspin(lig, hrand(2));
|
||||
}
|
||||
}
|
||||
nyi.path[YDIST-1] = lig.c;
|
||||
}
|
||||
|
||||
generating = true;
|
||||
|
||||
for(int i=1; i<YDIST-1; i++) {
|
||||
cell *c = nyi.path[i];
|
||||
cell *prev = nyi.path[i-1];
|
||||
|
||||
setdist(c, 10, prev);
|
||||
setdist(c, 9, prev);
|
||||
setdist(c, 8, prev);
|
||||
setdist(c, 7, prev);
|
||||
|
||||
if(challenge && i+BARLEV-7 < YDIST-5 && !euclid) {
|
||||
cell *c2 = nyi.path[i+BARLEV-7];
|
||||
if(c2->land == laIvoryTower) continue;
|
||||
eLand ycl = changeland(i, c2->land);
|
||||
if(ishept(c2) && ycl) {
|
||||
int bd = 2 + hrand(2) * 3;
|
||||
// printf("barrier at %d\n", i);
|
||||
buildBarrier(c2, bd, ycl);
|
||||
if(c2->bardir != NODIR && c2->bardir != NOBARRIERS)
|
||||
extendBarrier(c2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nyi.found = false;
|
||||
nyi.foundOrb = false;
|
||||
|
||||
cell *key = nyi.path[YDIST-1];
|
||||
|
||||
generating = false;
|
||||
|
||||
for(int b=10; b>=5; b--) setdist(key, b, nyi.path[YDIST-2]);
|
||||
|
||||
for(int i=-1; i<key->type; i++) {
|
||||
cell *c2 = i >= 0 ? key->mov[i] : key;
|
||||
checkTide(c2);
|
||||
c2->monst = moNone; c2->item = itNone;
|
||||
if(!passable(c2, NULL, P_MIRROR | P_MONSTER)) {
|
||||
if(c2->wall == waCavewall) c2->wall = waCavefloor;
|
||||
else if(c2->wall == waDeadwall) c2->wall = waDeadfloor2;
|
||||
else if(c2->wall == waLake) c2->wall = waFrozenLake;
|
||||
else if(c2->land == laCaribbean) c2->wall = waCIsland;
|
||||
else if(c2->land == laOcean) c2->wall = waCIsland;
|
||||
else if(c2->land == laRedRock) c2->wall = waRed3;
|
||||
else if(c2->land == laWhirlpool)
|
||||
c2->wall = waBoat, c2->monst = moPirate, c2->item = itOrbWater;
|
||||
else c2->wall = waNone;
|
||||
}
|
||||
if(c2->wall == waMineMine || c2->wall == waMineUnknown)
|
||||
c2->wall = waMineOpen;
|
||||
if(c2->wall == waTrapdoor && i == -1)
|
||||
c2->wall = waGargoyleFloor;
|
||||
if(c2->land == laLivefjord) {
|
||||
c2->wall = waSea;
|
||||
for(int i=0; i<c2->type; i++)
|
||||
c2->mov[i]->wall = waSea;
|
||||
}
|
||||
if(isGravityLand(c2->land) && key->land == c2->land &&
|
||||
c2->landparam < key->landparam && c2->wall != waTrunk)
|
||||
c2->wall = waPlatform;
|
||||
}
|
||||
key->item = itKey;
|
||||
|
||||
yi.push_back(nyi);
|
||||
}
|
||||
yii = byi;
|
||||
addMessage(XLAT("You need to find the right Key to unlock this Orb of Yendor!"));
|
||||
achievement_gain("YENDOR1");
|
||||
return false;
|
||||
}
|
||||
|
||||
void onpath() {
|
||||
path = false;
|
||||
if(yii < size(yi)) {
|
||||
for(int i=0; i<YDIST; i++) if(yi[yii].path[i]->cpdist <= 7) {
|
||||
if(i > yi[yii].howfar) yi[yii].howfar = i;
|
||||
path = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void init(int phase) {
|
||||
if(!on) return;
|
||||
|
||||
if(phase == 1) {
|
||||
won = false;
|
||||
if(!easy) items[itOrbYendor] = bestscore[modecode()][challenge];
|
||||
chaosmode = (clev().flags & YF_CHAOS);
|
||||
euclidland = firstland = clev().l;
|
||||
if(clev().flags & YF_START_AL) {
|
||||
firstland = laAlchemist;
|
||||
items[itElixir] = 50;
|
||||
items[itFeather] = 50;
|
||||
}
|
||||
if(firstland == laPower)
|
||||
items[itOrbSpeed] = 60, items[itOrbWinter] = 60;
|
||||
if(clev().flags & YF_START_CR) {
|
||||
firstland = laCrossroads;
|
||||
}
|
||||
if(firstland == laGraveyard) items[itBone] = 10;
|
||||
if(firstland == laEmerald) items[itEmerald] = 10;
|
||||
if(!euclid) {
|
||||
if(clev().flags & YF_DEAD) items[itGreenStone] = 100;
|
||||
if(clev().flags & YF_DEAD5) items[itGreenStone] = 5;
|
||||
}
|
||||
nexttostart = laNone;
|
||||
}
|
||||
|
||||
if(phase == 2) {
|
||||
cell *c2 = cwt.c->mov[0];
|
||||
c2->land = firstland;
|
||||
if(firstland == laRlyeh) c2->wall = waNone;
|
||||
yendor::check(c2, false);
|
||||
if(clev().flags & YF_NEAR_IVY)
|
||||
nexttostart = laJungle;
|
||||
if(clev().flags & YF_NEAR_TENT)
|
||||
nexttostart = laRlyeh;
|
||||
if(clev().flags & YF_NEAR_ELEM) {
|
||||
if(firstland == laIce) {
|
||||
nexttostart = laEWater;
|
||||
items[itWaterShard] = 10;
|
||||
}
|
||||
else nexttostart = laEAir;
|
||||
}
|
||||
if(clev().flags & YF_NEAR_OVER)
|
||||
nexttostart = laOvergrown;
|
||||
if(clev().flags & YF_NEAR_RED) {
|
||||
nexttostart = laRedRock;
|
||||
items[itRedGem] = 25;
|
||||
}
|
||||
if(clev().flags & YF_WALLS) {
|
||||
items[itPirate] += 25;
|
||||
items[itFjord] += 25;
|
||||
}
|
||||
if(clev().l == laWhirlpool) {
|
||||
items[itWhirlpool] += 10;
|
||||
items[itOrbWater] += 150;
|
||||
}
|
||||
}
|
||||
|
||||
if(phase == 3) {
|
||||
cell *c2 = cwt.c->mov[0];
|
||||
makeEmpty(c2);
|
||||
c2->item = itOrbYendor;
|
||||
nexttostart = laNone;
|
||||
}
|
||||
}
|
||||
|
||||
bool levelUnlocked(int i) {
|
||||
yendorlevel& ylev(levels[i]);
|
||||
|
||||
eItem t = treasureType(ylev.l);
|
||||
if(ylev.l != laWildWest && hiitemsMax(t) < 10) return false;
|
||||
if((ylev.flags & YF_NEAR_ELEM) && hiitemsMax(itElemental) < 10) return false;
|
||||
if((ylev.flags & YF_NEAR_RED) && hiitemsMax(itRedGem) < 10) return false;
|
||||
if((ylev.flags & YF_NEAR_OVER) && hiitemsMax(itMutant) < 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_DEAD|YF_DEAD5)) && hiitemsMax(itBone) < 10) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct scoredata {
|
||||
string username;
|
||||
int scores[landtypes];
|
||||
};
|
||||
vector<scoredata> scoreboard;
|
||||
|
||||
void showMenu() {
|
||||
int s = vid.fsize;
|
||||
vid.fsize = vid.fsize * 4/5;
|
||||
displayStatHelp(-8, XLAT("Yendor Challenge"));
|
||||
|
||||
for(int i=1; i<YENDORLEVELS; i++) {
|
||||
string s;
|
||||
yendorlevel& ylev(levels[i]);
|
||||
|
||||
if(levelUnlocked(i)) {
|
||||
|
||||
s = XLATT1(ylev.l);
|
||||
|
||||
if(!euclid) {
|
||||
if(ylev.flags & YF_CHAOS) { s = "Chaos mode"; }
|
||||
if(ylev.flags & YF_NEAR_IVY) { s += "+"; s += XLATT1(laJungle); }
|
||||
if(ylev.flags & YF_NEAR_TENT) { s += "+"; s += XLATT1(laRlyeh); }
|
||||
if(ylev.flags & YF_NEAR_ELEM) { s += "+"; s += XLATT1(laElementalWall); }
|
||||
if(ylev.flags & YF_NEAR_OVER) { s += "+"; s += XLATT1(laOvergrown); }
|
||||
if(ylev.flags & YF_NEAR_RED) { s += "+"; s += XLATT1(laRedRock); }
|
||||
if(ylev.flags & YF_START_AL) { s += "+"; s += XLATT1(laAlchemist); }
|
||||
if(ylev.flags & YF_DEAD) { s += "+"; s += XLATT1(itGreenStone); }
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
s = "(locked)";
|
||||
}
|
||||
|
||||
string v;
|
||||
if(bestscore[modecode()][i] == 1)
|
||||
v = XLAT(" (won!)");
|
||||
else if(bestscore[modecode()][i])
|
||||
v = XLAT(" (won at level %1!)", its(bestscore[modecode()][i]));
|
||||
|
||||
displayStat(i-6, s, v, 'a' + i-1);
|
||||
}
|
||||
|
||||
displayStat(YENDORLEVELS+1-6, XLAT("Return to the normal game"), "", '0');
|
||||
displayStat(YENDORLEVELS+1-5, XLAT(
|
||||
easy ? "Challenges do not get harder" : "Each challenge gets harder after each victory"),
|
||||
" " + XLAT(easy ? "easy" : "challenge"), '1');
|
||||
|
||||
int yc = getcstat - 'a' + 1;
|
||||
if(yc > 0 && yc < YENDORLEVELS) {
|
||||
subscoreboard scorehere;
|
||||
|
||||
for(int i=0; i<size(scoreboard); i++) {
|
||||
int sc = scoreboard[i].scores[yc];
|
||||
if(sc > 0)
|
||||
scorehere.push_back(
|
||||
make_pair(-sc, scoreboard[i].username));
|
||||
}
|
||||
|
||||
displayScore(scorehere, vid.xres / 4);
|
||||
}
|
||||
|
||||
yendor::uploadScore();
|
||||
vid.fsize = s;
|
||||
}
|
||||
|
||||
const char *chelp =
|
||||
"There are many possible solutions to the Yendor Quest. In the Yendor "
|
||||
"Challenge, you will try many of them!\n\n"
|
||||
"Each challenge takes part in a specific land, and you have to use what "
|
||||
"you have available.\n\n"
|
||||
|
||||
"You need to obtain an Orb of Yendor in the normal game to activate "
|
||||
"this challenge, and (ever) collect 10 treasures in one or two lands "
|
||||
"to activate a specific level.\n\n"
|
||||
|
||||
"After you complete each challenge, you can try it again, on a harder "
|
||||
"difficulty level.\n\n"
|
||||
|
||||
"All the solutions showcased in the Yendor Challenge work in the normal "
|
||||
"play too. However, passages to other lands, and (sometimes) some land features "
|
||||
"are disabled in the Yendor "
|
||||
"Challenge, so that you have to use the expected method. Also, "
|
||||
"the generation rules are changed slightly for the Palace "
|
||||
"and Minefield while you are looking for the Orb of Yendor, "
|
||||
"to make the challenge more balanced "
|
||||
"(but these changes are also active during the normal Yendor Quest).\n\n"
|
||||
|
||||
"You get 1000 points for each challenge won, and 1 extra point for "
|
||||
"each extra difficulty level.";
|
||||
|
||||
void handleKey(int uni, int sym) {
|
||||
if(uni >= 'a' && uni < 'a'+YENDORLEVELS-1) {
|
||||
challenge = uni-'a' + 1;
|
||||
if(levelUnlocked(challenge)) {
|
||||
restartGame(yendor::on ? 0 : 'y');
|
||||
cmode = emNormal;
|
||||
}
|
||||
else
|
||||
addMessage("Collect 10 treasures in various lands to unlock the challenges there");
|
||||
}
|
||||
else if(uni == '0') {
|
||||
if(yendor::on) restartGame('y');
|
||||
cmode = emNormal;
|
||||
}
|
||||
else if(uni == '1') easy = !easy;
|
||||
else if(uni == '2' || sym == SDLK_F1) {
|
||||
lastmode = cmode;
|
||||
cmode = emHelp;
|
||||
help = chelp;
|
||||
}
|
||||
else if(uni) cmode = emNormal;
|
||||
}
|
||||
};
|
||||
|
||||
#define MAXTAC 20
|
||||
namespace tactic {
|
||||
|
||||
bool trailer = false;
|
||||
bool on = false;
|
||||
int id;
|
||||
int recordsum[MODECODES][landtypes];
|
||||
int lsc[MODECODES][landtypes][MAXTAC];
|
||||
eLand lasttactic;
|
||||
|
||||
struct scoredata {
|
||||
string username;
|
||||
int scores[landtypes];
|
||||
};
|
||||
vector<scoredata> scoreboard[MODECODES];
|
||||
|
||||
int chances(eLand l) {
|
||||
if(modecode() != 0 && l != laCamelot) return 3;
|
||||
for(int i=0; i<LAND_TAC; i++)
|
||||
if(land_tac[i].l == l) {
|
||||
return land_tac[i].tries;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tacmultiplier(eLand l) {
|
||||
if(modecode() != 0 && l != laCamelot) return 1;
|
||||
if(modecode() != 0 && l == laCamelot) return 3;
|
||||
for(int i=0; i<LAND_TAC; i++)
|
||||
if(land_tac[i].l == l) return land_tac[i].multiplier;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool tacticUnlocked(int i) {
|
||||
eLand l = land_tac[i].l;
|
||||
if(l == laWildWest) return true;
|
||||
return hiitemsMax(treasureType(l)) * landMultiplier(l) >= 20;
|
||||
}
|
||||
|
||||
void record(eLand land, int score, int xc = modecode()) {
|
||||
if(land >=0 && land < landtypes) {
|
||||
for(int i=MAXTAC-1; i; i--) lsc[xc][land][i] = lsc[xc][land][i-1];
|
||||
tactic::lsc[xc][land][0] = score;
|
||||
}
|
||||
int t = chances(land);
|
||||
int csum = 0;
|
||||
for(int i=0; i<t; i++) if(lsc[xc][land][i] > 0) csum += lsc[xc][land][i];
|
||||
if(csum > recordsum[xc][land]) recordsum[xc][land] = csum;
|
||||
}
|
||||
|
||||
void record() {
|
||||
record(lasttactic, items[treasureType(lasttactic)]);
|
||||
}
|
||||
|
||||
void unrecord(eLand land, int xc = modecode()) {
|
||||
if(land >=0 && land < landtypes) {
|
||||
for(int i=0; i<MAXTAC-1; i++) lsc[xc][land][i] = lsc[xc][land][i+1];
|
||||
lsc[xc][land][MAXTAC-1] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void unrecord() {
|
||||
unrecord(lasttactic);
|
||||
}
|
||||
|
||||
void uploadScoreCode(int code, int lb) {
|
||||
int tscore = 0;
|
||||
for(int i=0; i<landtypes; i++)
|
||||
tscore += recordsum[code][i] * tacmultiplier(eLand(i));
|
||||
// printf("PTM score = %d\n", tscore);
|
||||
achievement_score(lb, tscore);
|
||||
}
|
||||
|
||||
void uploadScore() {
|
||||
uploadScoreCode(0, LB_PURE_TACTICS);
|
||||
uploadScoreCode(2, LB_PURE_TACTICS_SHMUP);
|
||||
uploadScoreCode(4, LB_PURE_TACTICS_COOP);
|
||||
}
|
||||
|
||||
void showMenu() {
|
||||
mouseovers = XLAT("pure tactics mode") + " - " + mouseovers;
|
||||
|
||||
int nl = LAND_TAC;
|
||||
|
||||
int vf = min((vid.yres-64) / nl, vid.xres/40);
|
||||
|
||||
int xr = vid.xres / 64;
|
||||
|
||||
if(on) record(firstland, items[treasureType(firstland)]);
|
||||
|
||||
int xc = modecode();
|
||||
|
||||
for(int i=0; i<nl; i++) {
|
||||
eLand l = land_tac[i].l;
|
||||
int i0 = 56 + i * vf;
|
||||
int col;
|
||||
|
||||
int ch = chances(l);
|
||||
|
||||
if(!ch) continue;
|
||||
|
||||
bool unlocked = tacticUnlocked(i);
|
||||
|
||||
if(unlocked) col = linf[l].color; else col = 0x202020;
|
||||
|
||||
if(displayfr(xr*1, i0, 1, vf-4, XLAT1(linf[l].name), col, 0) && unlocked) {
|
||||
getcstat = 1000 + i;
|
||||
}
|
||||
|
||||
if(unlocked) {
|
||||
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))
|
||||
getcstat = 1000 + i;
|
||||
|
||||
if(displayfr(xr*(24+2*10), i0, 1, (vf-4)*4/5,
|
||||
its(recordsum[xc][l]) + " x" + its(tacmultiplier(l)), col, 0))
|
||||
getcstat = 1000 + i;
|
||||
}
|
||||
else {
|
||||
int m = landMultiplier(l);
|
||||
displayfr(xr*26, i0, 1, (vf-4)*4/5,
|
||||
XLAT("Collect %1x %2 to unlock", its((20+m-1)/m), treasureType(l)),
|
||||
col, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if(on || ISIOS) {
|
||||
int i0 = 56 + nl * vf;
|
||||
if(displayfr(xr*24, i0, 1, vf-4, "press 0 to leave this mode", 0xFFD500, 8))
|
||||
getcstat = '0';
|
||||
}
|
||||
|
||||
uploadScore();
|
||||
if(on) unrecord(firstland);
|
||||
|
||||
if(getcstat >= 1000) {
|
||||
int ld = land_tac[getcstat-1000].l;
|
||||
subscoreboard scorehere;
|
||||
for(int i=0; i<size(scoreboard[xc]); i++) {
|
||||
int sc = scoreboard[xc][i].scores[ld];
|
||||
if(sc > 0)
|
||||
scorehere.push_back(
|
||||
make_pair(-sc, scoreboard[xc][i].username));
|
||||
}
|
||||
displayScore(scorehere, xr * 50);
|
||||
}
|
||||
}
|
||||
|
||||
void handleKey(int uni, int sym) {
|
||||
if(uni >= 1000 && uni < 1000 + LAND_TAC) {
|
||||
firstland = land_tac[uni - 1000].l;
|
||||
restartGame(tactic::on ? 0 : 't');
|
||||
cmode = emNormal;
|
||||
}
|
||||
else if(uni == '0') {
|
||||
cmode = emNormal;
|
||||
firstland = laIce;
|
||||
if(tactic::on) restartGame('t');
|
||||
}
|
||||
else if(uni == '2' || sym == SDLK_F1) {
|
||||
lastmode = cmode;
|
||||
cmode = emHelp;
|
||||
help =
|
||||
"In the pure tactics mode, you concentrate on a specific land. "
|
||||
"Your goal to obtain as high score as possible, without using "
|
||||
"features of the other lands. You can then compare your score "
|
||||
"with your friends!\n\n"
|
||||
|
||||
"You need to be somewhat proficient in the normal game to "
|
||||
"unlock the given land in this challenge "
|
||||
"(collect 20 treasure in the given land, or 2 in case of Camelot).\n\n"
|
||||
|
||||
"Since getting high scores in some lands is somewhat luck dependent, "
|
||||
"you play each land N times, and your score is based on N consecutive "
|
||||
"plays. The value of N depends on how 'fast' the land is to play, and "
|
||||
"how random it is.\n\n"
|
||||
|
||||
"In the Caribbean, you can access Orbs of Thorns, Aether, and "
|
||||
"Space if you have ever collected 25 treasure in their native lands.\n\n"
|
||||
|
||||
"The rate of treasure spawn is static in this mode. It is not "
|
||||
"increased by killing monsters.\n\n"
|
||||
|
||||
"Good luck, and have fun!";
|
||||
|
||||
}
|
||||
else if(uni) cmode = emNormal;
|
||||
}
|
||||
};
|
||||
|
||||
int modecode() {
|
||||
int xcode = 0;
|
||||
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(purehepta) {
|
||||
if(xcode > 6) xcode--;
|
||||
xcode /= 2;
|
||||
xcode += 13;
|
||||
}
|
||||
if(chaosmode && !yendor::on && cmode != emYendor) xcode += 19;
|
||||
return xcode;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user