1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2025-10-18 07:27:40 +00:00
This commit is contained in:
Zeno Rogue
2017-07-16 23:00:55 +02:00
parent 2c88dfabd2
commit ce5650a81f
32 changed files with 1861 additions and 840 deletions

View File

@@ -1,7 +1,7 @@
// Hyperbolic Rogue -- achievements // Hyperbolic Rogue -- achievements
// Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details // Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details
#define NUMLEADER 69 #define NUMLEADER 70
#define SCORE_UNKNOWN (-1) #define SCORE_UNKNOWN (-1)
#define NO_SCORE_YET (-2) #define NO_SCORE_YET (-2)
@@ -14,7 +14,7 @@ int currentscore[NUMLEADER];
const char* leadernames[NUMLEADER] = { const char* leadernames[NUMLEADER] = {
"Score", "Diamonds", "Gold", "Spice", "Rubies", "Elixirs", "Score", "Diamonds", "Gold", "Spice", "Rubies", "Elixirs",
"Shards", "Totems", "Daisies", "Statues", "Feathers", "Sapphires", "Shards100", "Totems", "Daisies", "Statues", "Feathers", "Sapphires",
"Hyperstones", "Time to Win-71", "Turns to Win-71", "Hyperstones", "Time to Win-71", "Turns to Win-71",
"Time to 10 Hyperstones-94", "Turns to 10 Hyperstones-94", "Orbs of Yendor", "Time to 10 Hyperstones-94", "Turns to 10 Hyperstones-94", "Orbs of Yendor",
"Fern Flowers", "Fern Flowers",
@@ -58,7 +58,8 @@ const char* leadernames[NUMLEADER] = {
"Slime Molds", // 65 "Slime Molds", // 65
"Dodecahedra", // 66 "Dodecahedra", // 66
"Green Grass", // 67 "Green Grass", // 67
"Spinel" // 68 "Spinel", // 68
"Orb Strategy Score", // 69
}; };
#define LB_STATISTICS 62 #define LB_STATISTICS 62
@@ -212,7 +213,7 @@ void achievement_collection(eItem it, int prevgold, int newgold) {
if(q == 8) achievement_gain("GRAIL4"); if(q == 8) achievement_gain("GRAIL4");
} }
if(q == 10) { if(q == U10) {
if(it == itDiamond) achievement_gain("DIAMOND2"); if(it == itDiamond) achievement_gain("DIAMOND2");
if(it == itRuby) achievement_gain("RUBY2"); if(it == itRuby) achievement_gain("RUBY2");
if(it == itHyperstone) achievement_gain("HYPER2"); if(it == itHyperstone) achievement_gain("HYPER2");
@@ -268,7 +269,7 @@ void achievement_collection(eItem it, int prevgold, int newgold) {
if(it == itBull) achievement_gain("BULL2"); if(it == itBull) achievement_gain("BULL2");
} }
if(q == 25) { if(q == R10) {
if(it == itDiamond) achievement_gain("DIAMOND3"); if(it == itDiamond) achievement_gain("DIAMOND3");
if(it == itRuby) achievement_gain("RUBY3"); if(it == itRuby) achievement_gain("RUBY3");
if(it == itHyperstone) achievement_gain("HYPER3"); if(it == itHyperstone) achievement_gain("HYPER3");
@@ -327,7 +328,7 @@ void achievement_collection(eItem it, int prevgold, int newgold) {
if(it == itBull) achievement_gain("BULL3"); if(it == itBull) achievement_gain("BULL3");
} }
if(q == 50) { if(q == 50 && !inv::on) {
if(it == itDiamond) achievement_gain("DIAMOND4"); if(it == itDiamond) achievement_gain("DIAMOND4");
if(it == itRuby) achievement_gain("RUBY4"); if(it == itRuby) achievement_gain("RUBY4");
if(it == itHyperstone) achievement_gain("HYPER4"); if(it == itHyperstone) achievement_gain("HYPER4");
@@ -553,18 +554,21 @@ void achievement_final(bool really_final) {
if(shmup::on) specials++; if(shmup::on) specials++;
if(chaosmode) specials++; if(chaosmode) specials++;
if(purehepta) specials++; if(purehepta) specials++;
if(inv::on) specials++;
if(specials > 1) return; if(specials > 1) return;
if(numplayers() > 1 && chaosmode) return; if(numplayers() > 1 && chaosmode) return;
if(numplayers() > 1 && purehepta) return; if(numplayers() > 1 && purehepta) return;
if(numplayers() > 1 && inv::on) return;
int total_improved = 0; int total_improved = 0;
specific_improved = 0; specific_improved = 0;
specific_what = 0; specific_what = 0;
if(!shmup::on && !chaosmode && !purehepta && numplayers() == 1) improveItemScores(); if(!shmup::on && !chaosmode && !purehepta && numplayers() == 1 && !inv::on) improveItemScores();
int sid = purehepta ? 57 : chaosmode ? 53 : shmup::on ? (numplayers() > 1 ? 44 : 28) : int sid = purehepta ? 57 : chaosmode ? 53 : shmup::on ? (numplayers() > 1 ? 44 : 28) :
inv::on ? 69 :
(numplayers() > 1 ? 61 : 0); (numplayers() > 1 ? 61 : 0);
int tg = gold(); int tg = gold();
@@ -601,6 +605,19 @@ void achievement_final(bool really_final) {
#endif #endif
} }
bool hadtotalvictory;
void check_total_victory() {
if(!inv::on) return;
if(hadtotalvictory) return;
if(!items[itOrbYendor]) return;
if(!items[itHolyGrail]) return;
if(items[itHyperstone] < 50) return;
if(!princess::saved) return;
hadtotalvictory = true;
achievement_gain("TOTALVICTORY");
}
void achievement_victory(bool hyper) { void achievement_victory(bool hyper) {
DEBB(DF_STEAM, (debugfile,"achievement_victory\n")) DEBB(DF_STEAM, (debugfile,"achievement_victory\n"))
if(offlineMode) return; if(offlineMode) return;

View File

@@ -88,8 +88,6 @@ int textwidth(int siz, const string &str) {
#endif #endif
int gradient(int c0, int c1, ld v0, ld v, ld v1);
int darkenedby(int c, int lev) { int darkenedby(int c, int lev) {
for(int i=0; i<lev; i++) for(int i=0; i<lev; i++)
c = ((c & 0xFEFEFE) >> 1); c = ((c & 0xFEFEFE) >> 1);
@@ -100,6 +98,10 @@ int darkened(int c) {
#ifdef EXTRA_FADEOUT #ifdef EXTRA_FADEOUT
c = gradient(backcolor, c, 0, extra::fadeout, 1); c = gradient(backcolor, c, 0, extra::fadeout, 1);
#endif #endif
if(inmirrorcount&1)
c = gradient(c, winf[waMirror].color, 0, 0.5, 1);
else if(inmirrorcount)
c = gradient(c, winf[waCloud].color, 0, 0.5, 1);
for(int i=0; i<darken; i++) for(int i=0; i<darken; i++)
c = ((c & 0xFEFEFE) >> 1) + ((backcolor & 0xFEFEFE) >> 1); c = ((c & 0xFEFEFE) >> 1) + ((backcolor & 0xFEFEFE) >> 1);
return c; return c;
@@ -1008,8 +1010,10 @@ void setvideomode() {
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 16); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 16);
glEnable(GL_MULTISAMPLE); glEnable(GL_MULTISAMPLE);
} }
#ifndef MAC
else else
glDisable(GL_MULTISAMPLE); glDisable(GL_MULTISAMPLE);
#endif
} }
#endif #endif

View File

@@ -648,7 +648,7 @@ struct cellwalker {
cell *c; cell *c;
int spin; int spin;
bool mirrored; bool mirrored;
cellwalker(cell *c, int spin) : c(c), spin(spin) { mirrored = false; } cellwalker(cell *c, int spin, bool m=false) : c(c), spin(spin), mirrored(m) { }
cellwalker() { mirrored = false; } cellwalker() { mirrored = false; }
}; };

View File

@@ -1143,17 +1143,23 @@ itemtype iinf[ittypes] = {
"Target a cell on the other side to use it." "Target a cell on the other side to use it."
}, },
{ '$', 0x80FF80, "Green Grass", prairiedesc }, { '$', 0x80FF80, "Green Grass", prairiedesc },
{ 'o', 0x8080FF, "Orb of Horns", { 'o', 0xC09090, "Orb of Horns",
"After you move while having this Orb, you immediately attack the next cell in the straight line " "After you move while having this Orb, you immediately attack the next cell in the straight line "
"(or two cells, when moving on a heptagon). This attack is slightly stronger than your normal " "(or two cells, when moving on a heptagon). This attack is slightly stronger than your normal "
"attack: it can stun some of the monsters which cannot be killed or stunned normally." "attack: it can stun some of the monsters which cannot be killed or stunned normally."
}, },
{ 'o', 0x8080FF, "Orb of the Bull", { 'o', 0xA05020, "Orb of the Bull",
"You get the powers of Shield, Horns, and Thorns after you move two moves in a straight line " "You get the powers of Shield, Horns, and Thorns after you move two moves in a straight line "
"with this Orb." }, "with this Orb." },
{ '$', 0xC060C0, "Spinel", bulldashdesc }, { '$', 0xC060C0, "Spinel", bulldashdesc },
{ 'o', 0xC0C0FF, "Orb of the Mirror", NODESCYET }, { 'o', 0xC0C0FF, "Orb of the Mirror",
{ 'O', 0xF0F0F0, "your orbs", NODESC}, "Use Orb of the Mirror to gain copies of one of your Orbs; "
"mirroring weaker Orbs usually yields more copies. "
"It can only be used once per Orb type, "
"and only when you are next to a mirror.",
},
{ 'O', 0xF0F0F0, "your orbs",
"Click this to see your orbs."},
}; };
enum eItem { itNone, itDiamond, itGold, itSpice, itRuby, itElixir, itShard, itBone, itHell, itStatue, enum eItem { itNone, itDiamond, itGold, itSpice, itRuby, itElixir, itShard, itBone, itHell, itStatue,
@@ -1192,7 +1198,7 @@ enum eItem { itNone, itDiamond, itGold, itSpice, itRuby, itElixir, itShard, itBo
// --- wall types --- // --- wall types ---
const int walltypes = 97; const int walltypes = 98;
struct walltype { struct walltype {
char glyph; char glyph;
@@ -1372,6 +1378,7 @@ walltype winf[walltypes] = {
{ '.', 0xFFFF00, "Reptile floor", reptiledesc}, { '.', 0xFFFF00, "Reptile floor", reptiledesc},
{ '.', 0xFFFF00, "Reptile bridge", reptiledesc}, { '.', 0xFFFF00, "Reptile bridge", reptiledesc},
{ '.', 0xFFFF00, "invisible floor", NODESCYET}, { '.', 0xFFFF00, "invisible floor", NODESCYET},
{ '#', 0xC0C0FF, "mirror wall", NODESCYET},
}; };
enum eWall { waNone, waIcewall, waBarrier, waFloorA, waFloorB, waCavewall, waCavefloor, waDeadTroll, waDune, enum eWall { waNone, waIcewall, waBarrier, waFloorA, waFloorB, waCavewall, waCavefloor, waDeadTroll, waDune,
@@ -1400,12 +1407,13 @@ enum eWall { waNone, waIcewall, waBarrier, waFloorA, waFloorB, waCavewall, waCav
waPetrified, waTower, waPetrified, waTower,
waBigBush, waSmallBush, waBigBush, waSmallBush,
waReptile, waReptileBridge, waReptile, waReptileBridge,
waInvisibleFloor waInvisibleFloor,
waMirrorWall
}; };
// --- land types --- // --- land types ---
const int landtypes = 67; const int landtypes = 71;
struct landtype { struct landtype {
int color; int color;
@@ -1437,7 +1445,7 @@ const landtype linf[landtypes] = {
"A land filled with huge ivy plants and dangerous animals." "A land filled with huge ivy plants and dangerous animals."
}, },
{ 0x900090, "Alchemist Lab", slimehelp}, { 0x900090, "Alchemist Lab", slimehelp},
{ 0x704070, "Mirror Land", { 0x704070, "Hall of Mirrors",
"A strange land which contains mirrors and mirages, protected by Mirror Rangers."}, "A strange land which contains mirrors and mirages, protected by Mirror Rangers."},
{ 0x404070, "Graveyard", { 0x404070, "Graveyard",
"All the monsters you kill are carried to this strange land, and buried. " "All the monsters you kill are carried to this strange land, and buried. "
@@ -1578,7 +1586,11 @@ const landtype linf[landtypes] = {
{ 0x0000D0, "Prairie", prairiedesc}, { 0x0000D0, "Prairie", prairiedesc},
{ 0x800080, "Bull Dash", bulldashdesc}, { 0x800080, "Bull Dash", bulldashdesc},
{ 0xC000C0, "Crossroads V", "Extremely narrow Crossroads layout.\n"}, { 0xC000C0, "Crossroads V", "Extremely narrow Crossroads layout.\n"},
{ 0xC0C0C0, "Cellular Automaton", cadesc} { 0xC0C0C0, "Cellular Automaton", cadesc},
{ 0xC0C0FF, "Mirror Wall", NODESCYET},
{ 0xC8C8FF, "Reflection", NODESCYET},
{ 0xC0C0FF, "Reflection", NODESCYET},
{ 0xC8C8FF, "Reflection", NODESCYET},
}; };
enum eLand { laNone, laBarrier, laCrossroads, laDesert, laIce, laCaves, laJungle, laAlchemist, laMirror, laGraveyard, enum eLand { laNone, laBarrier, laCrossroads, laDesert, laIce, laCaves, laJungle, laAlchemist, laMirror, laGraveyard,
@@ -1595,7 +1607,8 @@ enum eLand { laNone, laBarrier, laCrossroads, laDesert, laIce, laCaves, laJungle
laEndorian, laTortoise, laDragon, laEndorian, laTortoise, laDragon,
laKraken, laBurial, laTrollheim, laKraken, laBurial, laTrollheim,
laHalloween, laDungeon, laMountain, laReptile, laHalloween, laDungeon, laMountain, laReptile,
laPrairie, laBull, laCrossroads5, laCA laPrairie, laBull, laCrossroads5, laCA,
laMirrorWall, laMirrored, laMirrorWall2, laMirrored2
}; };
// cell information for the game // cell information for the game

View File

@@ -466,6 +466,8 @@ namespace princess {
#define OUT_OF_PRISON 200 #define OUT_OF_PRISON 200
#define OUT_OF_PALACE 250 #define OUT_OF_PALACE 250
#define PRADIUS0 (141)
#define PRADIUS1 (150)
bool generating = false; bool generating = false;
bool challenge = false; bool challenge = false;
@@ -475,6 +477,8 @@ namespace princess {
bool forceVizier = false; bool forceVizier = false;
bool forceMouse = false; bool forceMouse = false;
bool gotoPrincess = false; bool gotoPrincess = false;
bool nodungeon = false;
bool squeaked = false;
int saveHP = 0, saveArmedHP = 0; int saveHP = 0, saveArmedHP = 0;
@@ -496,7 +500,7 @@ namespace princess {
if(i->alt) i->alt->emeraldval = i->id; if(i->alt) i->alt->emeraldval = i->id;
} }
void newInfo(cell *c) { int newInfo(cell *c) {
info *i = new info; info *i = new info;
i->prison = c; i->prison = c;
i->princess = c; i->princess = c;
@@ -506,6 +510,7 @@ namespace princess {
i->bestnear = OUT_OF_PRISON; i->bestnear = OUT_OF_PRISON;
infos.push_back(i); infos.push_back(i);
assign(i); assign(i);
return i->id;
} }
void newFakeInfo(cell *c) { void newFakeInfo(cell *c) {
@@ -514,7 +519,7 @@ namespace princess {
i->princess = c; i->princess = c;
i->alt = NULL; i->alt = NULL;
i->id = size(infos); i->id = size(infos);
i->bestdist = OUT_OF_PALACE; i->bestdist = items[itSavedPrincess] ? OUT_OF_PALACE : OUT_OF_PRISON;
i->bestnear = 0; i->bestnear = 0;
infos.push_back(i); infos.push_back(i);
assign(i); assign(i);
@@ -524,7 +529,7 @@ namespace princess {
if(euclid) return NULL; if(euclid) return NULL;
if(c->land != laPalace) return NULL; if(c->land != laPalace) return NULL;
if(!c->master->alt) return NULL; if(!c->master->alt) return NULL;
int ev = c->master->alt->emeraldval; // NEWYEARFIX int ev = c->master->alt->alt->emeraldval; // NEWYEARFIX
if(ev < 0 || ev >= size(infos)) return NULL; if(ev < 0 || ev >= size(infos)) return NULL;
if(infos[ev]->alt != c->master->alt->alt) return NULL; if(infos[ev]->alt != c->master->alt->alt) return NULL;
return infos[ev]; return infos[ev];
@@ -535,6 +540,7 @@ namespace princess {
while(i) { while(i) {
infos[i]->id = i-1; assign(infos[i]); infos[i]->id = i-1; assign(infos[i]);
infos[i-1]->id = i; assign(infos[i-1]); infos[i-1]->id = i; assign(infos[i-1]);
swap(infos[i], infos[i-1]);
i--; i--;
} }
return infos[i]; return infos[i];
@@ -543,7 +549,7 @@ namespace princess {
} }
int dist(cell *c) { int dist(cell *c) {
if(c->land != laPalace) return OUT_OF_PALACE; if(c->land != laPalace && c->land != laDungeon) return OUT_OF_PALACE;
else if(quotient || sphere || torus) return OUT_OF_PRISON; else if(quotient || sphere || torus) return OUT_OF_PRISON;
else if(euclid) return celldistAlt(c); else if(euclid) return celldistAlt(c);
else if(!c->master->alt) return OUT_OF_PRISON; else if(!c->master->alt) return OUT_OF_PRISON;
@@ -565,10 +571,10 @@ namespace princess {
playSound(c, princessgender() ? "heal-princess" : "heal-prince"); playSound(c, princessgender() ? "heal-princess" : "heal-prince");
info *inf = NULL; info *inf = NULL;
for(int i=0; i<size(infos); i++) for(int i=0; i<size(infos); i++) {
if(infos[i]->princess && infos[i]->bestdist == OUT_OF_PALACE) if(infos[i]->princess && infos[i]->bestdist == OUT_OF_PALACE && isPrincess(infos[i]->princess->monst))
inf = infos[i]; inf = infos[i];
}
if(inf) { inf->princess->monst = moNone; inf->princess = c; } if(inf) { inf->princess->monst = moNone; inf->princess = c; }
else newFakeInfo(c); else newFakeInfo(c);
return true; return true;
@@ -586,6 +592,9 @@ namespace princess {
// printf("Improved dist to %d\n", newdist); // printf("Improved dist to %d\n", newdist);
if(newdist == OUT_OF_PALACE) { if(newdist == OUT_OF_PALACE) {
if(!princess::saved) if(!princess::saved)
#ifdef INV
if(!inv::on || !inv::usedForbidden)
#endif
achievement_gain("PRINCESS1"); achievement_gain("PRINCESS1");
princess::saved = true; princess::saved = true;
princess::everSaved = true; princess::everSaved = true;
@@ -600,25 +609,27 @@ namespace princess {
showMissionScreen(); showMissionScreen();
} }
} }
if(i->princess->land == laDungeon && !saved && !nodungeon) {
addMessage(XLAT("%The1 says, \"not this place, it looks even worse...\"", moPrincess));
nodungeon = true;
}
} }
void save(cell *princess) { void save(cell *princess) {
if(euclid) return; if(euclid) return;
princess::info *i = princess::getPrincessInfo(princess); princess::info *i = princess::getPrincessInfo(princess);
if(!i || i->bestdist <= 3) princess->monst = moNone; if(!i || i->bestdist <= 3) princess->monst = moNone;
else if(i) setdist(i, OUT_OF_PALACE); else if(i) setdist(i, OUT_OF_PRISON);
} }
void move(cell *ct, cell *cf) { void move(cell *ct, cell *cf) {
if(euclid) return; if(euclid) return;
princess::info *i = princess::getPrincessInfo(cf); princess::info *i = princess::getPrincessInfo(cf);
if(!i) { if(!i) {
static bool warn = true;
// note: OK if mapediting or loading // note: OK if mapediting or loading
if(warn) printf("Warning: unknown princess\n"); printf("Warning: unknown princess\n");
if(warn && !cheater) if(!cheater)
addMessage("Warning: unknown princess (that's a bug, please report)"); addMessage("Warning: unknown princess (that's a bug, please report)");
warn = false;
} }
else { else {
i->princess = ct; i->princess = ct;
@@ -661,31 +672,33 @@ namespace princess {
retry: retry:
if(msgid >= 32) msgid = 0; if(msgid >= 32) msgid = 0;
if(msgid == 0 && d < 20 && c->land == laPalace) { bool inpalace = c->land == laPalace || c->land == laDungeon;
if(msgid == 0 && d < 20 && inpalace) {
addMessage(XLAT("%The1 kisses you, and begs you to bring %him1 away from here.", m)); addMessage(XLAT("%The1 kisses you, and begs you to bring %him1 away from here.", m));
} }
else if(msgid == 1 && d >= 20 && c->land == laPalace) { else if(msgid == 1 && d >= 20 && inpalace) {
if(m == moPrincess) if(m == moPrincess)
addMessage(XLAT("\"I want my revenge. Stun a guard and leave him for me!\"", m)); addMessage(XLAT("\"I want my revenge. Stun a guard and leave him for me!\"", m));
else else
addMessage(XLAT("\"That felt great. Thanks!\"", m)); addMessage(XLAT("\"That felt great. Thanks!\"", m));
} }
else if(msgid == 2 && d >= 70 && c->land == laPalace) { else if(msgid == 2 && d >= 70 && inpalace) {
addMessage(XLAT("\"Bring me out of here please!\"", m)); addMessage(XLAT("\"Bring me out of here please!\"", m));
} }
else if(msgid == 3 && c->land != laPalace) { else if(msgid == 3 && !inpalace) {
addMessage(XLAT("%The1 kisses you, and thanks you for saving %him1.", m)); addMessage(XLAT("%The1 kisses you, and thanks you for saving %him1.", m));
} }
else if(msgid == 4 && c->land != laPalace && m == moPrincess) { else if(msgid == 4 && !inpalace && m == moPrincess) {
addMessage(XLAT("\"I have been trained to fight with a Hypersian scimitar, you know?\"", m)); addMessage(XLAT("\"I have been trained to fight with a Hypersian scimitar, you know?\"", m));
} }
else if(msgid == 5 && c->land != laPalace) { else if(msgid == 5 && !inpalace) {
addMessage(XLAT("\"I would love to come to your world with you!\"", m)); addMessage(XLAT("\"I would love to come to your world with you!\"", m));
} }
else if(msgid == 6 && c->land != laPalace) { else if(msgid == 6 && !inpalace) {
addMessage(XLAT("\"Straight lines stay close to each other forever, this is so romantic!\"", m)); addMessage(XLAT("\"Straight lines stay close to each other forever, this is so romantic!\"", m));
} }
else if(msgid == 7 && c->land != laPalace) { else if(msgid == 7 && !inpalace) {
addMessage(XLAT("\"Maps... Just like the world, but smaller... how is that even possible?!\"", m)); addMessage(XLAT("\"Maps... Just like the world, but smaller... how is that even possible?!\"", m));
} }
else { else {
@@ -1005,23 +1018,31 @@ namespace mirror {
c->wall == waFrozenLake || c->wall == waDeadfloor || c->wall == waDeadfloor2 || c->wall == waFrozenLake || c->wall == waDeadfloor || c->wall == waDeadfloor2 ||
c->wall == waGiantRug || c->wall == waCIsland || c->wall == waCIsland2 || c->wall == waGiantRug || c->wall == waCIsland || c->wall == waCIsland2 ||
c->wall == waGargoyleFloor || c->wall == waRubble || c->wall == waGargoyleFloor || c->wall == waRubble ||
c->wall == waGargoyleBridge || c->wall == waTempFloor || c->wall == waTempBridge; c->wall == waGargoyleBridge || c->wall == waTempFloor || c->wall == waTempBridge ||
} c->wall == waMirrorWall;
void createMM(cellwalker& cw, eMonster type) {
if(type == moLightningBolt)
castLightningBolt(cw);
else if(cw.c->monst == moNone && cellMirrorable(cw.c) && !isPlayerOn(cw.c)) {
cw.c->monst = type;
cw.c->mondir = cw.spin;
cw.c->hitpoints = multi::cpid;
}
} }
inline eMonster switchtype(eMonster m) { inline eMonster switchtype(eMonster m) {
return (m == moMirror) ? moMirage : moMirror; return (m == moMirror) ? moMirage : moMirror;
} }
void createMM(cellwalker& cw, eMonster type) {
if(type == moLightningBolt) {
castLightningBolt(cw);
return;
}
if(inmirror(cw)) {
bool b = cw.mirrored;
cw = reflect(cw);
if(cw.mirrored != b) type = switchtype(type);
}
if(cw.c->monst == moNone && cellMirrorable(cw.c) && !isPlayerOn(cw.c)) {
cw.c->monst = type;
cw.c->mondir = cw.spin;
cw.c->hitpoints = multi::cpid;
}
}
inline eMonster switchtypeif(eMonster m, bool b) { inline eMonster switchtypeif(eMonster m, bool b) {
if(!b) return m; if(!b) return m;
return (m == moMirror) ? moMirage : moMirror; return (m == moMirror) ? moMirage : moMirror;
@@ -1123,9 +1144,24 @@ namespace mirror {
if(c->hitpoints != multi::cpid) continue; if(c->hitpoints != multi::cpid) continue;
eMonster m = c->monst; eMonster m = c->monst;
if(isMimic(m)) { if(isMimic(m)) {
if(m == moMirage) nummirage++;
int dir = c->mondir; int dir = c->mondir;
if(m == moMirage) nummirage++;
cell *c2 = c->mov[dir]; cell *c2 = c->mov[dir];
if(c2 && inmirror(c2)) {
if(c->land == laMirror) {
// c->mondir = (dir+3) % 6;
c->monst = switchtype(m);
continue;
}
cellwalker cw(c2, c->spin(dir), false);
cw = reflect(cw);
dir = c->mondir = cw.c->spin(cw.spin);
if(cw.mirrored) m = c->monst = switchtype(m);
c2 = c->mov[dir];
}
if(c2 && !isMimic(c2) && canAttack(c,m,c2,c2->monst, 0)) if(c2 && !isMimic(c2) && canAttack(c,m,c2,c2->monst, 0))
attackMonster(c2, AF_MSG | AF_ORSTUN, m); attackMonster(c2, AF_MSG | AF_ORSTUN, m);
if(c2->wall == waBigTree) if(c2->wall == waBigTree)
@@ -1135,7 +1171,7 @@ namespace mirror {
if(!fwd) continue; if(!fwd) continue;
c->monst = moNone; c->monst = moNone;
if(!c2) continue; if(!c2) continue;
if(!passable(c2, c, P_MONSTER | P_MIRROR)) continue; if(!passable(c2, c, P_MONSTER | P_MIRROR | P_MIRRORWALL)) continue;
if(isWorm(c2)) continue; if(isWorm(c2)) continue;
if(c2->monst == moGreater) { if(c2->monst == moGreater) {
c2->monst = moLesser; continue; c2->monst = moLesser; continue;
@@ -1193,6 +1229,122 @@ namespace mirror {
go(fwd); go(fwd);
} }
int mirrordir(cell *c) {
if(c->type == 7) return c->bardir;
int icount = 0, isum = 0;
for(int i=0; i<6; i+=2) {
if(createMov(c, i)->bardir == c->spin(i))
icount++, isum+=i;
}
if(icount > 1) return -1;
return isum;
}
pair<bool, cellwalker> traceback(vector<int>& v, cellwalker cw) {
bool goout = false;
for(int i=size(v)-1; i>=0; i--) {
if(v[i]) cwspin(cw, -v[i]);
else {
cwstep(cw);
if(cw.c->land == laMirrorWall || cw.c->land == laMirror) goout = true;
}
}
return make_pair(goout, cw);
}
cellwalker reflect(cellwalker cw, bool debug) {
int stepcount = 0;
cellwalker cwcopy = cw;
static vector<int> v;
v.clear();
while(true) {
if(!inmirror(cw)) break;
stepcount++; if(stepcount > 10000) {
if(debug) cw.c->wall = waBoat;
if(debug) printf("fail\n"); return cw;
}
cell *c0 = cwpeek(cw, 0);
int go = 0;
if(!inmirror(c0)) go = 2;
else if(c0->landparam && c0->landparam < cw.c->landparam) go = 1;
if(go) {
v.push_back(0);
cwstep(cw);
if(debug) queuemarkerat(gmatrix[cw.c], 0x00FF0020);
if(go == 2) break;
}
else {
v.push_back(1);
cwspin(cw, 1);
}
}
if(cw.c->land == laMirrorWall || cw.c->land == laMirrorWall2) {
if(cw.c->type == 7) {
while(cw.spin != cw.c->bardir) {
cwspin(cw, 1);
v.push_back(1);
stepcount++; if(stepcount > 10000) { printf("failhep\n"); return cw; }
}
if(purehepta && cwpeek(cw,0) == cwcopy.c)
v.pop_back();
if(purehepta && cwpeek(cw,3)->land == laMirrored && cwpeek(cw,2)->land == laMirrorWall) {
cw.mirrored = !cw.mirrored;
auto p = traceback(v, cw);
if(p.first) return p.second;
cwspin(cw, 2);
v.push_back(2);
cwstep(cw);
if(debug) queuemarkerat(gmatrix[cw.c], 0xC9C90080);
v.push_back(0);
cwspin(cw, 3);
v.push_back(3);
}
}
else {
while(cwpeek(cw,0)->type != 7) {
cwspin(cw, 1);
v.push_back(1);
}
int icount = 0;
for(int i=0; i<3; i++) {
if(cwpeek(cw, 0)->bardir == cw.c->spin(cw.spin))
icount++;
cwspin(cw, 2);
}
if(icount >= 2) {
cellwalker cwcopy = cw;
for(int a=0; a<3; a++) for(int m=0; m<2; m++) {
cellwalker cw = cwcopy;
if(m) cw.mirrored = !cw.mirrored;
cwspin(cw, a*2);
auto p = traceback(v,cw);
if(p.first) return p.second;
}
printf("icount >= 2 but failed\n");
return cw;
}
while(cwpeek(cw, 0)->bardir != cw.c->spin(cw.spin)) {
stepcount++; if(stepcount > 10000) { printf("fail2\n"); return cw; }
cwspin(cw, 2);
v.push_back(1);
v.push_back(1);
}
}
}
else v.pop_back();
cw.mirrored = !cw.mirrored;
cw = traceback(v,cw).second;
return cw;
}
void debug() {
if(!mouseover) return;
queuemarkerat(gmatrix[mouseover], 0xFF0000FF);
cellwalker mw(mouseover, (SDL_GetTicks()/1000) % mouseover->type, (SDL_GetTicks()/500) % 2);
mw = mirror::reflect(mw, true);
queuemarkerat(gmatrix[mw.c], 0x800000FF);
}
} }
namespace hive { namespace hive {

View File

@@ -45,42 +45,90 @@ int lang() {
bool autojoy = true; bool autojoy = true;
/*struct saver { struct supersaver {
string name; string name;
virtual string save(); virtual string save() = 0;
virtual void load(string& s); virtual void load(const string& s) = 0;
virtual bool dosave() = 0;
}; };
struct intsaver : saver { vector<shared_ptr<supersaver>> savers;
int& val;
int dft; template<class T> struct dsaver : supersaver {
void intsaver() { val = dft; } T& val;
string save() { return its(val); } T dft;
void load(string& s) { val = atoi(s.c_str()); } bool dosave() { return val != dft; }
dsaver(T& val) : val(val) { }
}; };
struct hexsaver : saver { template<class T> struct saver : dsaver<T> {};
int& val;
int dft;
void intsaver() { val = dft; }
string save() { return itsh(val); }
void load(string& s) { val = strtol(s.c_str(), 16); }
};
struct ldsaver : saver { template<class T, class U, class V> void addsaver(T& i, U name, V dft) {
ld& val; auto s = make_shared<saver<T>> (i);
ld dft; s->dft = i = dft;
void intsaver() { val = dft; } s->name = name;
string save() { return ffts(val); } savers.push_back(s);
void load(string& s) { val = atof(s.c_str()); } }
};
template<class T> void addsaver(T& i, string name) {
vector<shared_ptr<saver>> savers; addsaver(i, name, i);
}
void initConfig0() {
savers.push_back(make_shared<intsaver> ({"cs.charid", cs.charid, 0})); template<class T> struct saverenum : supersaver {
T& val;
T dft;
bool dosave() { return val != dft; }
saverenum<T>(T& v) : val(v) { }
string save() { return its(val); }
void load(const string& s) { val = (T) atoi(s.c_str()); }
};
template<class T, class U> void addsaverenum(T& i, U name) {
auto s = make_shared<saverenum<T>> (i);
s->dft = i;
s->name = name;
savers.push_back(s);
}
template<> struct saver<int> : dsaver<int> {
saver<int>(int& val) : dsaver<int>(val) { }
string save() { return its(val); }
void load(const string& s) { val = atoi(s.c_str()); }
};
template<> struct saver<char> : dsaver<char> {
saver<char>(char& val) : dsaver<char>(val) { }
string save() { return its(val); }
void load(const string& s) { val = atoi(s.c_str()); }
};
template<> struct saver<bool> : dsaver<bool> {
saver<bool>(bool& val) : dsaver<bool>(val) { }
string save() { return val ? "yes" : "no"; }
void load(const string& s) { val = size(s) && s[0] == 'y'; }
};
template<> struct saver<unsigned> : dsaver<unsigned> {
saver<unsigned>(unsigned& val) : dsaver<unsigned>(val) { }
string save() { return itsh(val); }
void load(const string& s) { val = strtol(s.c_str(), NULL, 16); }
};
template<> struct saver<ld> : dsaver<ld> {
saver<ld>(ld& val) : dsaver<ld>(val) { }
string save() { return ftssmart(val); }
void load(const string& s) { val = atof(s.c_str()); }
};
void addsaver(charstyle& cs, string s) {
addsaver(cs.charid, s + ".charid");
addsaver(cs.skincolor, s + ".skincolor");
addsaver(cs.haircolor, s + ".haircolor");
addsaver(cs.dresscolor, s + ".dresscolor");
addsaver(cs.swordcolor, s + ".swordcolor");
addsaver(cs.dresscolor2, s + ".dresscolor2");
addsaver(cs.uicolor, s + ".uicolor");
} }
*/
// R:239, G:208, B:207 // R:239, G:208, B:207
@@ -127,69 +175,109 @@ void loadcs(FILE *f, charstyle& cs, int xvernum) {
} }
void initConfig() { void initConfig() {
vid.usingGL = true;
vid.antialias = AA_NOGL | AA_FONT | AA_LINES | AA_LINEWIDTH | AA_VERSION;
vid.linewidth = 1;
vid.flashtime = 8;
vid.scale = 1;
vid.alpha = 1;
vid.sspeed = 0;
vid.mspeed = 1;
vid.eye = 0;
vid.full = false;
vid.ballangle = 20;
vid.yshift = 0;
vid.camera_angle = 0;
vid.ballproj = 1;
vid.aurastr = 128;
vid.aurasmoothen = 5;
vid.graphglyph = 1;
#ifdef ANDROID // basic config
vid.monmode = 2; addsaver(vid.flashtime, "flashtime", 8);
vid.wallmode = 3; addsaver(vid.mobilecompasssize, "mobile compass size", 30);
#else addsaver(vid.axes, "movement help", 1);
#ifdef PANDORA addsaver(vid.shifttarget, "shift-targetting", 2);
vid.monmode = 2; addsaver(vid.steamscore, "scores to Steam", 1);
vid.wallmode = 3; initcs(vid.cs); addsaver(vid.cs, "single");
#else addsaver(vid.samegender, "princess choice", false);
vid.monmode = 4; addsaver(vid.language, "language", -1);
vid.wallmode = 5; addsaver(vid.drawmousecircle, "mouse circle", ISMOBILE || ISPANDORA);
#endif addsaver(vid.revcontrol, "reverse control", false);
#endif addsaver(musicvolume, "music volume");
addsaver(effvolume, "sound effect volume");
addsaverenum(glyphsortorder, "glyph sort order");
vid.particles = 1; // basic graphics
vid.mobilecompasssize = 30;
vid.joyvalue = 4800; addsaver(vid.usingGL, "usingGL", true);
vid.joyvalue2 = 5600; addsaver(vid.antialias, "antialias", AA_NOGL | AA_FONT | AA_LINES | AA_LINEWIDTH | AA_VERSION);
vid.joypanthreshold = 2500; addsaver(vid.linewidth, "linewidth", 1);
#ifdef PANDORA addsaver(vid.scale, "scale", 1);
vid.joypanspeed = 0.0001; addsaver(vid.alpha, "projection", 1);
#else addsaver(vid.sspeed, "scrollingspeed", 0);
vid.joypanspeed = 0; addsaver(vid.mspeed, "movement speed", 1);
#endif addsaver(vid.full, "fullscreen", false);
addsaver(vid.aurastr, "aura strength", 128);
addsaver(vid.aurasmoothen, "aura smoothen", 5);
addsaver(vid.graphglyph, "graphical items/kills", 1);
addsaver(vid.particles, "extra effects", 1);
addsaver(vid.framelimit, "frame limit", 75);
addsaver(vid.xres, "xres");
addsaver(vid.yres, "yres");
addsaver(vid.fsize, "font size");
addsaver(vid.darkhepta, "mark heptagons", false);
vid.framelimit = 75; // special graphics
vid.axes = 1;
vid.shifttarget = 2;
vid.steamscore = 1;
initcs(vid.cs); addsaver(vid.eye, "eye distance", 0);
addsaver(vid.ballangle, "ball angle", 20);
addsaver(vid.yshift, "Y shift", 0);
addsaver(vid.camera_angle, "camera angle", 0);
addsaver(vid.ballproj, "ballproj", 1);
addsaver(vid.monmode, "monster display mode", (ISANDROID || ISPANDORA) ? 2 : 4);
addsaver(vid.wallmode, "wall display mode", (ISANDROID || ISPANDORA) ? 3 : 5);
addsaver(geom3::depth, "3D depth");
addsaver(geom3::camera, "3D camera level");
addsaver(geom3::wall_height, "3D wall height");
addsaver(geom3::rock_wall_ratio, "3D rock-wall ratio");
addsaver(geom3::human_wall_ratio, "3D human-wall ratio");
addsaver(geom3::lake_top, "3D lake top");
addsaver(geom3::lake_bottom, "3D lake bottom");
addsaver(geom3::tc_depth, "3D TC depth");
addsaver(geom3::tc_camera, "3D TC camera");
addsaver(geom3::tc_alpha, "3D TC alpha");
addsaver(geom3::highdetail, "3D highdetail");
addsaver(geom3::middetail, "3D middetail");
addsaver(rug::renderonce, "rug-renderonce");
addsaver(rug::rendernogl, "rug-rendernogl");
addsaver(rug::texturesize, "rug-texturesize");
addsaver(rug::scale, "rug-scale");
addsaverenum(pmodel, "used model");
addsaver(polygonal::SI, "polygon sides");
addsaver(polygonal::STAR, "polygon star factor");
addsaver(polygonal::deg, "polygonal degree");
addsaver(conformal::includeHistory, "include history"); // check!
addsaver(conformal::lvspeed, "lineview speed");
addsaver(polygonal::maxcoef, "polynomial degree");
for(int i=0; i<polygonal::MSI; i++) {
addsaver(polygonal::coefr[i], "polynomial "+its(i)+".real");
addsaver(polygonal::coefi[i], "polynomial "+its(i)+".imag");
}
addsaver(conformal::bandhalf, "band width");
addsaver(conformal::bandsegment, "band segment");
addsaver(conformal::rotation, "conformal rotation");
addsaver(conformal::autoband, "automatic band");
addsaver(conformal::autobandhistory, "automatic band history");
addsaver(conformal::dospiral, "do spiral");
// control
addsaver(vid.joyvalue, "vid.joyvalue", 4800);
addsaver(vid.joyvalue2, "vid.joyvalue2", 5600);
addsaver(vid.joypanthreshold, "vid.joypanthreshold", 2500);
addsaver(vid.joypanspeed, "vid.joypanspeed", ISPANDORA ? 0.0001 : 0);
addsaver(autojoy, "autojoy");
vid.killreduction = 0; vid.killreduction = 0;
vid.samegender = false; // modes
vid.language = -1;
vid.drawmousecircle = false; addsaverenum(geometry, "mode-geometry");
vid.revcontrol = false; addsaverenum(euclidland, "mode-geometry land");
#ifdef MOBILE addsaver(shmup::on, "mode-shmup", false);
vid.drawmousecircle = true; addsaver(hardcore, "mode-hardcore", false);
#endif addsaver(chaosmode, "mode-chaos");
#ifdef PANDORA addsaver(inv::on, "mode-Orb Strategy");
vid.drawmousecircle = true; addsaver(purehepta, "mode-heptagonal", false);
#endif
shmup::initConfig(); shmup::initConfig();
} }
@@ -201,36 +289,6 @@ void saveConfig() {
addMessage(s0 + "Could not open the config file: " + conffile); addMessage(s0 + "Could not open the config file: " + conffile);
return; return;
} }
fprintf(f, "%d %d %d %d\n", vid.xres, vid.yres, vid.full, vid.fsize);
fprintf(f, "%f %f %f %f\n", float(vid.scale), float(vid.eye), float(vid.alpha), float(vid.sspeed));
fprintf(f, "%d %d %d %d %d %d %d\n", vid.wallmode, vid.monmode, vid.axes, musicvolume, vid.framelimit, vid.usingGL, vid.antialias);
fprintf(f, "%d %d %d %f %d %d\n", vid.joyvalue, vid.joyvalue2, vid.joypanthreshold, float(vid.joypanspeed), autojoy, vid.flashtime);
savecs(f, vid.cs, 0);
fprintf(f, "%d %d\n", vid.darkhepta, vid.shifttarget);
fprintf(f, "%d %d %d %d\n", euclid, euclidland, shmup::on, hardcore);
shmup::saveConfig(f);
fprintf(f, "%d %d %d %d %f %d %d\n", rug::renderonce, rug::rendernogl, rug::texturesize, purehepta, rug::scale, vid.steamscore, chaosmode);
fprintf(f, "%d %d %f %d %d %f\n",
pmodel, polygonal::SI, float(polygonal::STAR), polygonal::deg,
conformal::includeHistory, float(conformal::lvspeed));
fprintf(f, "%d %d %d %d %d %d\n",
conformal::bandhalf, conformal::bandsegment,
conformal::rotation, conformal::autoband, conformal::autobandhistory,
conformal::dospiral);
fprintf(f, "%d", polygonal::maxcoef);
for(int i=0; i<=polygonal::maxcoef; i++) fprintf(f, " %lf %lf",
(double) real(polygonal::coef[i]), (double) imag(polygonal::coef[i]));
fprintf(f, "\n%d %d %d %f %d %d\n",
vid.revcontrol, vid.drawmousecircle, sightrange, float(vid.mspeed), effvolume, vid.particles);
{ {
int pt_depth = 0, pt_camera = 0, pt_alpha = 0; int pt_depth = 0, pt_camera = 0, pt_alpha = 0;
@@ -241,43 +299,13 @@ void saveConfig() {
if(tc_depth < tc_alpha ) pt_alpha ++; if(tc_depth < tc_alpha ) pt_alpha ++;
if(tc_alpha > tc_camera) pt_alpha++; if(tc_alpha > tc_camera) pt_alpha++;
if(tc_alpha < tc_camera) pt_camera++; if(tc_alpha < tc_camera) pt_camera++;
tc_alpha = pt_alpha;
fprintf(f, "%f %f %f %f %f %f %f %d %d %d %f %f %d\n", tc_camera = pt_camera;
float(geom3::depth), float(geom3::camera), float(geom3::wall_height), tc_depth = pt_depth;
float(geom3::rock_wall_ratio),
float(geom3::human_wall_ratio),
float(geom3::lake_top),
float(geom3::lake_bottom),
pt_depth, pt_camera, pt_alpha,
float(geom3::highdetail), float(geom3::middetail),
glyphsortorder);
fprintf(f, "%f %f %f %f\n",
float(vid.yshift), float(vid.camera_angle),
float(vid.ballangle), float(vid.ballproj)
);
fprintf(f, "%d %d %d %d %f\n", vid.mobilecompasssize, vid.aurastr, vid.aurasmoothen, vid.graphglyph, float(vid.linewidth));
} }
fprintf(f, "\n\nThis is a configuration file for HyperRogue (version " VER ")\n"); for(auto s: savers) if(s->dosave())
fprintf(f, "\n\nThe numbers are:\n"); fprintf(f, "%s=%s\n", s->name.c_str(), s->save().c_str());
fprintf(f, "screen width & height, fullscreen mode (0=windowed, 1=fullscreen), font size\n");
fprintf(f, "scale, eye distance, parameter, scrolling speed\n");
fprintf(f, "wallmode, monster mode, cross mode, music volume, framerate limit, usingGL, antialiasing flags\n");
fprintf(f, "calibrate first joystick (threshold A, threshold B), calibrate second joystick (pan threshold, pan speed), joy mode\n");
fprintf(f, "gender (1=female, 16=same gender prince), language, skin color, hair color, sword color, dress color\n");
fprintf(f, "darken hepta, shift target\n");
fprintf(f, "euclid, euclid land, shmup, hardcore\n");
fprintf(f, "version number, shmup players, alwaysuse, shmup keyboard/joystick config\n");
fprintf(f, "hypersian rug config: renderonce, rendernogl, texturesize; purehepta; rug scale; share score; chaosmode\n");
fprintf(f, "conformal: model, sides, star, degree, includeHistory, speed\n");
fprintf(f, "conformal: bandwidth, segment, rotation, autoband, autohistory, dospiral\n");
fprintf(f, "conformal: degree, (degree+1) times {real, imag}\n");
fprintf(f, "vid.revcontrol, drawmousecircle, sight range, movement animation speed, sound effect volume, particle effects\n");
fprintf(f, "3D parameters, sort order\n");
fprintf(f, "yhsift, camera angle, ball angle, ball projection\n");
fprintf(f, "compass size, aura strength, aura smoothen factor, graphical glyphs\n");
fclose(f); fclose(f);
#ifndef MOBILE #ifndef MOBILE
@@ -294,110 +322,150 @@ void readf(FILE *f, ld& x) {
x = fl; x = fl;
} }
void loadOldConfig(FILE *f) {
int gl=1, aa=1, bb=1, cc, dd, ee;
int err;
float a, b, c, d;
err=fscanf(f, "%f%f%f%f\n", &a, &b, &c, &d);
if(err == 4) {
vid.scale = a; vid.eye = b; vid.alpha = c; vid.sspeed = d;
}
err=fscanf(f, "%d%d%d%d%d%d%d", &vid.wallmode, &vid.monmode, &vid.axes, &musicvolume, &vid.framelimit, &gl, &vid.antialias);
vid.usingGL = gl;
if(vid.antialias == 0) vid.antialias = AA_VERSION | AA_LINES | AA_LINEWIDTH;
if(vid.antialias == 1) vid.antialias = AA_NOGL | AA_VERSION | AA_LINES | AA_LINEWIDTH | AA_FONT;
double jps = vid.joypanspeed;
err=fscanf(f, "%d%d%d%lf%d%d", &vid.joyvalue, &vid.joyvalue2, &vid.joypanthreshold, &jps, &aa, &vid.flashtime);
vid.joypanspeed = jps;
autojoy = aa; aa = 0;
loadcs(f, vid.cs, 0);
aa=0; bb=0;
err=fscanf(f, "%d%d", &aa, &bb);
vid.darkhepta = aa; vid.shifttarget = bb;
aa = geometry; bb = euclidland; cc = shmup::on; dd = hardcore;
err=fscanf(f, "%d%d%d%d", &aa, &bb, &cc, &dd);
geometry = eGeometry(aa); euclidland = eLand(bb); shmup::on = cc; hardcore = dd;
shmup::loadConfig(f);
aa = rug::renderonce; bb = rug::rendernogl; cc = purehepta; dd = chaosmode; ee = vid.steamscore;
double rs = rug::scale;
err=fscanf(f, "%d%d%d%d%lf%d%d", &aa, &bb, &rug::texturesize, &cc, &rs, &ee, &dd);
rug::renderonce = aa; rug::rendernogl = bb; purehepta = cc; chaosmode = dd; vid.steamscore = ee;
rug::scale = rs;
aa=conformal::includeHistory;
double ps = polygonal::STAR, lv = conformal::lvspeed;
int pmb = pmodel;
err=fscanf(f, "%d%d%lf%d%d%lf",
&pmb, &polygonal::SI, &ps, &polygonal::deg,
&aa, &lv);
pmodel = eModel(pmb);
conformal::includeHistory = aa; polygonal::STAR = ps; conformal::lvspeed = lv;
aa=conformal::autoband; bb=conformal::autobandhistory; cc=conformal::dospiral;
err=fscanf(f, "%d%d%d%d%d%d",
&conformal::bandhalf, &conformal::bandsegment, &conformal::rotation,
&aa, &bb, &cc);
conformal::autoband = aa; conformal::autobandhistory = bb; conformal::dospiral = cc;
err=fscanf(f, "%d", &polygonal::maxcoef);
if(polygonal::maxcoef < 0) polygonal::maxcoef = 0;
if(polygonal::maxcoef > polygonal::MSI) polygonal::maxcoef = polygonal::MSI;
for(int i=0; i<=polygonal::maxcoef; i++) {
double re=0, im=0;
err=fscanf(f, "%lf%lf", &re, &im);
polygonal::coefr[i] = re;
polygonal::coefi[i] = im;
}
aa=vid.revcontrol; bb=vid.drawmousecircle;
d = vid.mspeed;
err=fscanf(f, "%d%d%d%f%d%d", &aa, &bb, &sightrange, &d, &effvolume, &vid.particles);
vid.mspeed = d;
if(sightrange < 4) sightrange = 4;
if(sightrange > 7) sightrange = 7;
vid.revcontrol = aa; vid.drawmousecircle = bb;
readf(f, geom3::depth); readf(f, geom3::camera); readf(f, geom3::wall_height);
readf(f, geom3::rock_wall_ratio); readf(f, geom3::human_wall_ratio);
readf(f, geom3::lake_top); readf(f, geom3::lake_bottom);
err=fscanf(f, "%d %d %d", &geom3::tc_depth, &geom3::tc_camera, &geom3::tc_alpha);
readf(f, geom3::highdetail);
geom3::middetail = 200; readf(f, geom3::middetail);
if(geom3::middetail == 200) {
if(ISMOBILE)
geom3::highdetail = 0, geom3::middetail = 3;
else
geom3::highdetail = geom3::middetail = 5;
}
int gso = glyphsortorder; err=fscanf(f, "%d", &gso); glyphsortorder = eGlyphsortorder(gso);
readf(f, vid.yshift); readf(f, vid.camera_angle); readf(f, vid.ballangle); readf(f, vid.ballproj);
jps = vid.linewidth;
err=fscanf(f, "%d%d%d%d%lf\n", &vid.mobilecompasssize, &vid.aurastr, &vid.aurasmoothen, &vid.graphglyph, &jps);
vid.linewidth = jps;
}
map<string, shared_ptr<supersaver> > allconfigs;
void parseline(const string& str) {
for(int i=0; i<size(str); i++) if(str[i] == '=') {
string cname = str.substr(0, i);
if(!allconfigs.count(cname)) {
printf("Warning: unknown config variable: %s\n", str.c_str());
return;
}
auto sav = allconfigs[cname];
sav->load(str.substr(i+1));
return;
}
printf("Warning: config line without equality sign: %s\n", str.c_str());
}
void loadNewConfig(FILE *f) {
for(auto& c: savers) allconfigs[c->name] = c;
string rd;
while(true) {
int c = fgetc(f);
if(c == -1) break;
if(c == 10 || c == 13) {
if(rd != "") parseline(rd);
rd = "";
}
else rd += c;
}
allconfigs.clear();
}
void loadConfig() { void loadConfig() {
DEBB(DF_INIT, (debugfile,"load config\n")); DEBB(DF_INIT, (debugfile,"load config\n"));
vid.xres = 9999; vid.yres = 9999; vid.framelimit = 300; vid.xres = 9999; vid.yres = 9999; vid.framelimit = 300;
FILE *f = fopen(conffile, "rt"); FILE *f = fopen(conffile, "rt");
if(f) { if(f) {
int fs, gl=1, aa=1, bb=1, cc, dd, ee;
int err; int err;
int fs;
err=fscanf(f, "%d%d%d%d", &vid.xres, &vid.yres, &fs, &vid.fsize); err=fscanf(f, "%d%d%d%d", &vid.xres, &vid.yres, &fs, &vid.fsize);
vid.full = fs; if(!err)
float a, b, c, d; loadNewConfig(f);
err=fscanf(f, "%f%f%f%f\n", &a, &b, &c, &d); else {
if(err == 4) { vid.full = fs;
vid.scale = a; vid.eye = b; vid.alpha = c; vid.sspeed = d; loadOldConfig(f);
} }
err=fscanf(f, "%d%d%d%d%d%d%d", &vid.wallmode, &vid.monmode, &vid.axes, &musicvolume, &vid.framelimit, &gl, &vid.antialias);
vid.usingGL = gl;
if(vid.antialias == 0) vid.antialias = AA_VERSION | AA_LINES | AA_LINEWIDTH;
if(vid.antialias == 1) vid.antialias = AA_NOGL | AA_VERSION | AA_LINES | AA_LINEWIDTH | AA_FONT;
double jps = vid.joypanspeed;
err=fscanf(f, "%d%d%d%lf%d%d", &vid.joyvalue, &vid.joyvalue2, &vid.joypanthreshold, &jps, &aa, &vid.flashtime);
vid.joypanspeed = jps;
autojoy = aa; aa = 0;
loadcs(f, vid.cs, 0);
aa=0; bb=0;
err=fscanf(f, "%d%d", &aa, &bb);
vid.darkhepta = aa; vid.shifttarget = bb;
aa = geometry; bb = euclidland; cc = shmup::on; dd = hardcore;
err=fscanf(f, "%d%d%d%d", &aa, &bb, &cc, &dd);
geometry = eGeometry(aa); euclidland = eLand(bb); shmup::on = cc; hardcore = dd;
shmup::loadConfig(f);
aa = rug::renderonce; bb = rug::rendernogl; cc = purehepta; dd = chaosmode; ee = vid.steamscore;
double rs = rug::scale;
err=fscanf(f, "%d%d%d%d%lf%d%d", &aa, &bb, &rug::texturesize, &cc, &rs, &ee, &dd);
rug::renderonce = aa; rug::rendernogl = bb; purehepta = cc; chaosmode = dd; vid.steamscore = ee;
rug::scale = rs;
aa=conformal::includeHistory;
double ps = polygonal::STAR, lv = conformal::lvspeed;
int pmb = pmodel;
err=fscanf(f, "%d%d%lf%d%d%lf",
&pmb, &polygonal::SI, &ps, &polygonal::deg,
&aa, &lv);
pmodel = eModel(pmb);
conformal::includeHistory = aa; polygonal::STAR = ps; conformal::lvspeed = lv;
aa=conformal::autoband; bb=conformal::autobandhistory; cc=conformal::dospiral;
err=fscanf(f, "%d%d%d%d%d%d",
&conformal::bandhalf, &conformal::bandsegment, &conformal::rotation,
&aa, &bb, &cc);
conformal::autoband = aa; conformal::autobandhistory = bb; conformal::dospiral = cc;
err=fscanf(f, "%d", &polygonal::maxcoef);
if(polygonal::maxcoef < 0) polygonal::maxcoef = 0;
if(polygonal::maxcoef > polygonal::MSI) polygonal::maxcoef = polygonal::MSI;
for(int i=0; i<=polygonal::maxcoef; i++) {
double re=0, im=0;
err=fscanf(f, "%lf%lf", &re, &im);
polygonal::coef[i] = cld(re, im);
}
aa=vid.revcontrol; bb=vid.drawmousecircle;
d = vid.mspeed;
err=fscanf(f, "%d%d%d%f%d%d", &aa, &bb, &sightrange, &d, &effvolume, &vid.particles);
vid.mspeed = d;
if(sightrange < 4) sightrange = 4;
if(sightrange > 7) sightrange = 7;
vid.revcontrol = aa; vid.drawmousecircle = bb;
readf(f, geom3::depth); readf(f, geom3::camera); readf(f, geom3::wall_height);
readf(f, geom3::rock_wall_ratio); readf(f, geom3::human_wall_ratio);
readf(f, geom3::lake_top); readf(f, geom3::lake_bottom);
err=fscanf(f, "%d %d %d", &geom3::tc_depth, &geom3::tc_camera, &geom3::tc_alpha);
readf(f, geom3::highdetail);
geom3::middetail = 200; readf(f, geom3::middetail);
if(geom3::middetail == 200) {
if(ISMOBILE)
geom3::highdetail = 0, geom3::middetail = 3;
else
geom3::highdetail = geom3::middetail = 5;
}
int gso = glyphsortorder; err=fscanf(f, "%d", &gso); glyphsortorder = eGlyphsortorder(gso);
readf(f, vid.yshift); readf(f, vid.camera_angle); readf(f, vid.ballangle); readf(f, vid.ballproj);
jps = vid.linewidth;
err=fscanf(f, "%d%d%d%d%lf\n", &vid.mobilecompasssize, &vid.aurastr, &vid.aurasmoothen, &vid.graphglyph, &jps);
vid.linewidth = jps;
fclose(f); fclose(f);
DEBB(DF_INIT, (debugfile,"Loaded configuration: %s\n", conffile)); DEBB(DF_INIT, (debugfile,"Loaded configuration: %s\n", conffile));
if(err)
;
} }
polygonal::solve();
precalc(); precalc();
} }
#endif #endif
@@ -957,7 +1025,7 @@ void show3D() {
}; };
} }
void switchcolor(int& c, unsigned int* cs) { void switchcolor(unsigned int& c, unsigned int* cs) {
dialog::openColorDialog(c, cs); dialog::openColorDialog(c, cs);
} }

View File

@@ -1,6 +1,9 @@
// Hyperbolic Rogue -- the conformal/history mode // Hyperbolic Rogue -- the conformal/history mode
// Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details // Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details
#include <complex>
typedef complex<ld> cld;
namespace polygonal { namespace polygonal {
typedef complex<ld> cld; typedef complex<ld> cld;
@@ -14,9 +17,15 @@ namespace polygonal {
ld ans[MSI]; ld ans[MSI];
cld coef[MSI]; cld coef[MSI];
ld coefr[MSI], coefi[MSI];
int maxcoef, coefid; int maxcoef, coefid;
void solve() { void solve() {
if(pmodel == mdPolynomial) {
for(int i=0; i<MSI; i++) coef[i] = cld(coefr[i], coefi[i]);
return;
}
if(pmodel != mdPolygonal) return;
if(SI < 3) SI = 3; if(SI < 3) SI = 3;
for(int i=0; i<MSI; i++) ans[i] = cos(M_PI / SI); for(int i=0; i<MSI; i++) ans[i] = cos(M_PI / SI);
for(int i=0; i<MSI; i++) for(int i=0; i<MSI; i++)
@@ -547,9 +556,9 @@ namespace conformal {
if(pmodel == 4) { if(pmodel == 4) {
dialog::addSelItem(XLAT("coefficient"), dialog::addSelItem(XLAT("coefficient"),
fts4(real(polygonal::coef[polygonal::coefid])), 'x'); fts4(polygonal::coefr[polygonal::coefid]), 'x');
dialog::addSelItem(XLAT("coefficient (imaginary)"), dialog::addSelItem(XLAT("coefficient (imaginary)"),
fts4(imag(polygonal::coef[polygonal::coefid])), 'y'); fts4(polygonal::coefi[polygonal::coefid]), 'y');
dialog::addSelItem(XLAT("which coefficient"), its(polygonal::coefid), 'n'); dialog::addSelItem(XLAT("which coefficient"), its(polygonal::coefid), 'n');
} }
@@ -583,19 +592,8 @@ namespace conformal {
keyhandler = handleKeyC; keyhandler = handleKeyC;
} }
int ib = 0;
ld compbuf;
void applyIB() {
using namespace polygonal;
cld& tgt = coef[coefid];
if(ib == 1) tgt = cld(compbuf, imag(tgt));
if(ib == 2) tgt = cld(real(tgt), compbuf);
}
void handleKeyC(int sym, int uni) { void handleKeyC(int sym, int uni) {
dialog::handleNavigation(sym, uni); dialog::handleNavigation(sym, uni);
ib = 0;
if(uni == 'e') { if(uni == 'e') {
if(on) clear(); if(on) clear();
@@ -618,7 +616,7 @@ namespace conformal {
if(pmodel == mdHalfplane || pmodel == mdBand || pmodel == mdEquidistant || pmodel == mdEquiarea) if(pmodel == mdHalfplane || pmodel == mdBand || pmodel == mdEquidistant || pmodel == mdEquiarea)
goto switchagain; goto switchagain;
} }
if(pmodel == mdPolygonal) polygonal::solve(); polygonal::solve();
/* if(pmodel && vid.usingGL) { /* if(pmodel && vid.usingGL) {
addMessage(XLAT("openGL mode disabled")); addMessage(XLAT("openGL mode disabled"));
vid.usingGL = false; vid.usingGL = false;
@@ -634,16 +632,12 @@ namespace conformal {
else if(sym == 'x' && pmodel == mdPolynomial) { else if(sym == 'x' && pmodel == mdPolynomial) {
polygonal::maxcoef = max(polygonal::maxcoef, polygonal::coefid); polygonal::maxcoef = max(polygonal::maxcoef, polygonal::coefid);
int ci = polygonal::coefid + 1; int ci = polygonal::coefid + 1;
compbuf = real(polygonal::coef[polygonal::coefid]); dialog::editNumber(polygonal::coefr[polygonal::coefid], -10, 10, .01/ci/ci, 0, XLAT("coefficient"), "");
dialog::editNumber(compbuf, -10, 10, .01/ci/ci, 0, XLAT("coefficient"), "");
ib = 1;
} }
else if(sym == 'y' && pmodel == mdPolynomial) { else if(sym == 'y' && pmodel == mdPolynomial) {
polygonal::maxcoef = max(polygonal::maxcoef, polygonal::coefid); polygonal::maxcoef = max(polygonal::maxcoef, polygonal::coefid);
int ci = polygonal::coefid + 1; int ci = polygonal::coefid + 1;
compbuf = imag(polygonal::coef[polygonal::coefid]); dialog::editNumber(polygonal::coefi[polygonal::coefid], -10, 10, .01/ci/ci, 0, XLAT("coefficient (imaginary)"), "");
dialog::editNumber(compbuf, -10, 10, .01/ci/ci, 0, XLAT("coefficient (imaginary)"), "");
ib = 2;
} }
else if(sym == 'n' && pmodel == mdPolynomial) else if(sym == 'n' && pmodel == mdPolynomial)
dialog::editNumber(polygonal::coefid, 0, polygonal::MSI-1, 1, 0, XLAT("which coefficient"), ""); dialog::editNumber(polygonal::coefid, 0, polygonal::MSI-1, 1, 0, XLAT("which coefficient"), "");

View File

@@ -526,7 +526,7 @@ void mainloopiter() {
drawscreen(); drawscreen();
} }
if(ev.type == SDL_JOYAXISMOTION) { if(ev.type == SDL_JOYAXISMOTION && normal && DEFAULTCONTROL) {
if(ev.jaxis.which == 0) { if(ev.jaxis.which == 0) {
if(ev.jaxis.axis == 0) if(ev.jaxis.axis == 0)
joyx = ev.jaxis.value; joyx = ev.jaxis.value;
@@ -565,18 +565,30 @@ void mainloopiter() {
if(ev.jhat.value == SDL_HAT_RIGHT) dir = 1; if(ev.jhat.value == SDL_HAT_RIGHT) dir = 1;
if(ev.jhat.value == SDL_HAT_DOWN) dir = 2; if(ev.jhat.value == SDL_HAT_DOWN) dir = 2;
if(ev.jhat.value == SDL_HAT_LEFT) dir = 3; if(ev.jhat.value == SDL_HAT_LEFT) dir = 3;
printf("%d %d %d\n", joyid, hat, dir);
if(joyid < 8 && hat < 4 && dir < 4) { if(joyid < 8 && hat < 4 && dir < 4) {
vid.scfg.hataction[joyid][hat][dir] = vid.scfg.setwhat; vid.scfg.hataction[joyid][hat][dir] = vid.scfg.setwhat;
vid.scfg.setwhat = 0; vid.scfg.setwhat = 0;
} }
} }
else if(ev.type == SDL_JOYBUTTONDOWN && DEFAULTCONTROL) { else if(ev.type == SDL_JOYHATMOTION && !normal) {
if(ev.jhat.value == SDL_HAT_UP) sym = SDLK_UP;
if(ev.jhat.value == SDL_HAT_DOWN) sym = SDLK_DOWN;
if(ev.jhat.value == SDL_HAT_LEFT) sym = SDLK_LEFT;
if(ev.jhat.value == SDL_HAT_RIGHT) sym = SDLK_RIGHT;
}
else if(ev.type == SDL_JOYBUTTONDOWN && normal && DEFAULTCONTROL) {
flashMessages(); flashMessages();
movepcto(joydir); movepcto(joydir);
checkjoy(); checkjoy();
} }
else if(ev.type == SDL_JOYBUTTONDOWN && !normal) {
sym = uni = SDLK_RETURN;
}
if(ev.type == SDL_KEYDOWN) { if(ev.type == SDL_KEYDOWN) {
flashMessages(); flashMessages();
mousing = false; mousing = false;

View File

@@ -387,10 +387,10 @@ namespace dialog {
int colorp = 0; int colorp = 0;
int *colorPointer; unsigned int *colorPointer;
bool handleKeyColor(int sym, int uni) { bool handleKeyColor(int sym, int uni) {
int& color = *colorPointer; unsigned& color = *colorPointer;
if(uni >= 'A' && uni <= 'D') { if(uni >= 'A' && uni <= 'D') {
int x = (mousex - vid.xres/4) * 510 / vid.xres; int x = (mousex - vid.xres/4) * 510 / vid.xres;
@@ -478,7 +478,7 @@ namespace dialog {
keyhandler = handleKeyColor; keyhandler = handleKeyColor;
} }
void openColorDialog(int& col, unsigned int *pal) { void openColorDialog(unsigned int& col, unsigned int *pal) {
colorPointer = &col; palette = pal; colorPointer = &col; palette = pal;
pushScreen(drawColorDialog); pushScreen(drawColorDialog);
} }
@@ -593,7 +593,7 @@ namespace dialog {
if(ne.intval == &polygonal::SI) polygonal::solve(); if(ne.intval == &polygonal::SI) polygonal::solve();
if(ne.editwhat == &polygonal::STAR) polygonal::solve(); if(ne.editwhat == &polygonal::STAR) polygonal::solve();
conformal::applyIB(); polygonal::solve();
if(ne.editwhat == &geom3::highdetail && geom3::highdetail > geom3::middetail) if(ne.editwhat == &geom3::highdetail && geom3::highdetail > geom3::middetail)
geom3::middetail = geom3::highdetail; geom3::middetail = geom3::highdetail;
@@ -626,7 +626,7 @@ namespace dialog {
addBreak(100); addBreak(100);
if(cmode && sm::A3) ne.help = explain3D(ne.editwhat); if(cmode & sm::A3) ne.help = explain3D(ne.editwhat);
if(ne.help != "") { if(ne.help != "") {
addHelp(ne.help); addHelp(ne.help);

View File

@@ -637,6 +637,7 @@ bool highwall(cell *c) {
return false; return false;
// if(wmspatial && isTree(c)) return false; // if(wmspatial && isTree(c)) return false;
if(isGrave(c->wall)) return true; if(isGrave(c->wall)) return true;
if(c->wall == waMirrorWall) return false;
return winf[c->wall].glyph == '#' || c->wall == waClosedGate; return winf[c->wall].glyph == '#' || c->wall == waClosedGate;
} }

246
game.cpp
View File

@@ -124,9 +124,9 @@ cellwalker cwt; // single player character position
inline cell*& singlepos() { return cwt.c; } inline cell*& singlepos() { return cwt.c; }
inline bool singleused() { return !(shmup::on || multi::players > 1); } inline bool singleused() { return !(shmup::on || multi::players > 1); }
#include "mtrand.cpp" #include <random>
MTRand_int32 r; mt19937 r;
void shrand(int i) { void shrand(int i) {
r.seed(i); r.seed(i);
@@ -510,6 +510,9 @@ bool passable(cell *w, cell *from, flagtype flags) {
if(w->wall == waMirror || w->wall == waCloud) if(w->wall == waMirror || w->wall == waCloud)
return F(P_MIRROR | P_AETHER); return F(P_MIRROR | P_AETHER);
if(w->wall == waMirrorWall)
return F(P_MIRRORWALL);
if(F(P_BULLET)) { if(F(P_BULLET)) {
if(isFire(w) || w->wall == waBonfireOff || cellHalfvine(w) || if(isFire(w) || w->wall == waBonfireOff || cellHalfvine(w) ||
w->wall == waAncientGrave || w->wall == waFreshGrave || w->wall == waRoundTable) w->wall == waAncientGrave || w->wall == waFreshGrave || w->wall == waRoundTable)
@@ -632,10 +635,12 @@ bool ghostmove(eMonster m, cell* to, cell* from) {
if((m == moWitchGhost || m == moWitchWinter) && to->land != laPower) if((m == moWitchGhost || m == moWitchWinter) && to->land != laPower)
return false; return false;
if(isGhost(m)) if(isGhost(m))
for(int i=0; i<to->type; i++) for(int i=0; i<to->type; i++) {
if(inmirror(to->mov[i])) return false;
if(to->mov[i] && to->mov[i] != from && isGhost(to->mov[i]->monst) && if(to->mov[i] && to->mov[i] != from && isGhost(to->mov[i]->monst) &&
(to->mov[i]->monst == moFriendlyGhost) == (m== moFriendlyGhost)) (to->mov[i]->monst == moFriendlyGhost) == (m== moFriendlyGhost))
return false; return false;
}
if(isGhost(m) || m == moWitchGhost) return true; if(isGhost(m) || m == moWitchGhost) return true;
if(m == moGreaterShark) return isWatery(to); if(m == moGreaterShark) return isWatery(to);
if(m == moWitchWinter) if(m == moWitchWinter)
@@ -1728,6 +1733,10 @@ void killMonster(cell *c, eMonster who, flagtype deathflags) {
i->princess = NULL; i->princess = NULL;
if(i->bestdist == OUT_OF_PALACE) { if(i->bestdist == OUT_OF_PALACE) {
items[itSavedPrincess]--; items[itSavedPrincess]--;
if(items[itSavedPrincess] < 0) {
printf("princess below 0\n");
items[itSavedPrincess] = 0;
}
if(items[itSavedPrincess] == 0 && !inv::on) { if(items[itSavedPrincess] == 0 && !inv::on) {
items[itOrbLove] = 0; items[itOrbLove] = 0;
princess::reviveAt = gold(NO_LOVE) + 20; princess::reviveAt = gold(NO_LOVE) + 20;
@@ -5399,6 +5408,11 @@ bool hasSafeOrb(cell *c) {
} }
void checkmove() { void checkmove() {
#ifdef INV
if(inv::on) inv::compute();
#endif
if(multi::players > 1 && !multi::checkonly) return; if(multi::players > 1 && !multi::checkonly) return;
if(hardcore) return; if(hardcore) return;
msgscroll = 0; msgscroll = 0;
@@ -5423,6 +5437,20 @@ void checkmove() {
canmove = legalmoves[cwt.spin] = true; canmove = legalmoves[cwt.spin] = true;
if(kills[moPlayer]) canmove = false; if(kills[moPlayer]) canmove = false;
#ifdef INV
if(!canmove && !inv::incheck) {
if(inv::remaining[itOrbSafety])
canmove = true;
else {
inv::check(1);
checkmove();
inv::check(-1);
}
if(canmove)
pushScreen(inv::show);
}
#endif
if(!canmove) { if(!canmove) {
achievement_final(true); achievement_final(true);
if(cmode & sm::NORMAL) showMissionScreen(); if(cmode & sm::NORMAL) showMissionScreen();
@@ -5436,10 +5464,6 @@ void checkmove() {
for(int i=0; i<ittypes; i++) orbused[i] = orbusedbak[i]; for(int i=0; i<ittypes; i++) orbused[i] = orbusedbak[i];
if(recallCell && !markOrb(itOrbRecall)) activateRecall(); if(recallCell && !markOrb(itOrbRecall)) activateRecall();
#ifdef INV
if(inv::on) inv::compute();
#endif
} }
// move the PC. Warning: a very long function! todo: refactor // move the PC. Warning: a very long function! todo: refactor
@@ -5554,7 +5578,7 @@ bool cantGetGrimoire(cell *c2, bool verbose = true) {
void gainLife() { void gainLife() {
items[itOrbLife] ++; items[itOrbLife] ++;
if(items[itOrbLife] > 5) items[itOrbLife] = 5; if(items[itOrbLife] > 5 && !shmup::on) items[itOrbLife] = 5;
} }
void collectMessage(cell *c2, eItem which) { void collectMessage(cell *c2, eItem which) {
@@ -5686,19 +5710,29 @@ bool collectItem(cell *c2, bool telekinesis) {
if(isRevivalOrb(c2->item) && multi::revive_queue.size()) { if(isRevivalOrb(c2->item) && multi::revive_queue.size()) {
multiRevival(cwt.c, c2); multiRevival(cwt.c, c2);
} }
else if(c2->item == itOrbSpeed) { else if(isShmupLifeOrb(c2->item) && shmup::on) {
items[c2->item] += 31; playSound(c2, "pickup-orb"); // TODO summon
playSound(c2, "pickup-speed"); gainLife();
}
else if(orbcharges(c2->item)) {
eItem it = c2->item;
if(it == itOrbRecall) saveRecall(c2);
if(it == itOrbFire) playSound(c2, "fire");
else if(it == itOrbFire) playSound(c2, "fire");
else if(it == itOrbWinter) playSound(c2, "pickup-winter");
else if(it == itOrbSpeed) playSound(c2, "pickup-speed");
else if(it == itRevolver) playSound(c2, "pickup-key");
else playSound(c2, "pickup-orb");
if(!items[it]) items[it]++;
items[it] += orbcharges(it);
} }
else if(c2->item == itOrbLife) { else if(c2->item == itOrbLife) {
playSound(c2, "pickup-orb"); // TODO summon playSound(c2, "pickup-orb"); // TODO summon
if(shmup::on) gainLife(); placeGolem(cwt.c, c2, moGolem);
else placeGolem(cwt.c, c2, moGolem);
} }
else if(c2->item == itOrbFriend) { else if(c2->item == itOrbFriend) {
playSound(c2, "pickup-orb"); // TODO summon playSound(c2, "pickup-orb"); // TODO summon
if(shmup::on) gainLife(); placeGolem(cwt.c, c2, moTameBomberbird);
else placeGolem(cwt.c, c2, moTameBomberbird);
} }
#ifdef TOUR #ifdef TOUR
else if(tour::on && (c2->item == itOrbSafety || c2->item == itOrbRecall)) { else if(tour::on && (c2->item == itOrbSafety || c2->item == itOrbRecall)) {
@@ -5715,145 +5749,6 @@ bool collectItem(cell *c2, bool telekinesis) {
activateSafety(c2->land); activateSafety(c2->land);
return true; return true;
} }
else if(c2->item == itOrbLightning) {
playSound(c2, "pickup-orb");
items[c2->item] += 78;
}
else if(c2->item == itOrbStone) {
playSound(c2, "pickup-orb");
items[c2->item] += 61;
}
else if(c2->item == itOrbNature) {
playSound(c2, "pickup-orb");
if(shmup::on) gainLife();
else items[c2->item] += 61;
}
else if(c2->item == itOrbRecall) {
saveRecall(c2);
playSound(c2, "pickup-orb");
items[c2->item] += 61;
}
else if(c2->item == itOrbTime) {
playSound(c2, "pickup-orb");
items[c2->item] += 78;
}
else if(c2->item == itOrbLove) {
playSound(c2, "pickup-orb");
items[c2->item] += 31;
}
else if(c2->item == itOrbSpace) {
playSound(c2, "pickup-orb");
items[c2->item] += 78;
}
else if(c2->item == itOrbThorns) {
playSound(c2, "pickup-orb");
items[c2->item] += 78;
}
else if(c2->item == itOrbSword) {
playSound(c2, "pickup-orb");
if(!items[itOrbSword] && !items[itOrbSword2])
sword::shuffle();
items[c2->item] += 61 + 30 * multi::activePlayers();
}
else if(c2->item == itOrbSword2) {
playSound(c2, "pickup-orb");
if(!items[itOrbSword] && !items[itOrbSword2])
sword::shuffle();
items[c2->item] += 41 + 20 * multi::activePlayers();
}
else if(c2->item == itOrbFlash) {
playSound(c2, "pickup-orb");
items[c2->item] += 78;
}
else if(c2->item == itOrbShield) {
playSound(c2, "pickup-orb"); // TODO Shield
items[c2->item] += 16;
orbused[itOrbShield] = false;
}
else if(c2->item == itOrbWater) {
playSound(c2, "pickup-orb");
items[c2->item] += 31;
}
else if(c2->item == itOrbAir) {
playSound(c2, "pickup-orb");
items[c2->item] += 67;
}
else if(c2->item == itOrbFrog) {
playSound(c2, "pickup-orb");
items[c2->item] += 45;
}
else if(c2->item == itOrbDash) {
playSound(c2, "pickup-orb");
items[c2->item] += 45;
}
else if(c2->item == itOrbDiscord) {
playSound(c2, "pickup-orb");
// make it seem to be 23
if(!items[c2->item]) items[c2->item]++;
items[c2->item] += 23;
}
else if(c2->item == itOrbSummon) {
playSound(c2, "pickup-orb");
items[c2->item] += 121;
}
else if(c2->item == itOrbMatter) {
playSound(c2, "pickup-orb");
items[c2->item] += 67;
}
else if(c2->item == itOrbHorns) {
playSound(c2, "pickup-orb");
items[c2->item] += 67;
}
else if(c2->item == itOrbBull) {
playSound(c2, "pickup-orb");
items[c2->item] += 67;
}
else if(c2->item == itOrbFish) {
playSound(c2, "pickup-orb");
items[c2->item] += 21 + 10 * multi::activePlayers();
}
else if(c2->item == itOrbWinter) {
playSound(c2, "pickup-winter");
items[c2->item] += 31;
}
else if(c2->item == itRevolver) {
playSound(c2, "pickup-key");
items[c2->item] = 6;
}
else if(c2->item == itOrbStunning) {
playSound(c2, "pickup-orb");
items[c2->item] += 61;
}
else if(c2->item == itOrbLuck) {
playSound(c2, "pickup-orb");
items[c2->item] += 61;
}
else if(c2->item == itOrbUndeath) {
playSound(c2, "pickup-orb");
if(shmup::on) gainLife();
else items[c2->item] += 31;
}
else if(c2->item == itOrbFreedom) {
playSound(c2, "pickup-orb");
items[c2->item] += 31;
}
else if(c2->item == itOrb37) {
playSound(c2, "pickup-orb");
items[c2->item] += 51;
}
else if(c2->item == itOrbEnergy) {
playSound(c2, "pickup-orb");
items[c2->item] += 51;
}
else if(c2->item == itOrbDomination) {
playSound(c2, "pickup-orb");
if(shmup::on) gainLife();
else items[c2->item] += 91;
}
else if(c2->item == itOrbShell) {
playSound(c2, "pickup-orb"); // TOOD shield
items[c2->item] += 67;
}
else if(c2->item == itBabyTortoise) { else if(c2->item == itBabyTortoise) {
using namespace tortoise; using namespace tortoise;
int bnew = babymap[c2]; int bnew = babymap[c2];
@@ -5869,47 +5764,6 @@ bool collectItem(cell *c2, bool telekinesis) {
} }
else items[itBabyTortoise]++; else items[itBabyTortoise]++;
} }
else if(c2->item == itOrbBeauty) {
playSound(c2, "pickup-orb");
items[c2->item] += 41;
}
else if(c2->item == itOrbEmpathy) {
playSound(c2, "pickup-orb");
if(shmup::on) gainLife();
else items[c2->item] += 41;
}
else if(c2->item == itOrbFire) {
playSound(c2, "fire");
items[c2->item] += (sphere ? 3 : 31);
}
else if(c2->item == itOrbDragon) {
playSound(c2, "pickup-orb");
items[c2->item] += sphere ? 10 : 78;
}
else if(c2->item == itOrbIllusion) {
playSound(c2, "pickup-orb");
items[c2->item] += 78;
}
else if(c2->item == itOrbPsi) {
playSound(c2, "pickup-orb");
items[c2->item] += 78;
}
else if(c2->item == itOrbInvis) {
playSound(c2, "pickup-orb");
items[c2->item] += 31;
}
else if(c2->item == itOrbAether) {
playSound(c2, "pickup-orb");
items[c2->item] += 31;
}
else if(c2->item == itOrbDigging) {
playSound(c2, "pickup-orb");
items[c2->item] += 78;
}
else if(c2->item == itOrbTeleport) {
playSound(c2, "pickup-orb");
items[c2->item] += 78;
}
else if(c2->item == itOrbYendor && peace::on) { else if(c2->item == itOrbYendor && peace::on) {
if(!items[itDodeca]) { if(!items[itDodeca]) {
addMessage(XLAT("Collect as many Dodecahedra as you can, then return here!")); addMessage(XLAT("Collect as many Dodecahedra as you can, then return here!"));
@@ -7003,6 +6857,8 @@ bool movepcto(int d, int subdir, bool checkonly) {
if(multi::players == 1) monstersTurn(); if(multi::players == 1) monstersTurn();
check_total_victory();
if(items[itWhirlpool] && cwt.c->land != laWhirlpool && !whirlpool::escaped) { if(items[itWhirlpool] && cwt.c->land != laWhirlpool && !whirlpool::escaped) {
whirlpool::escaped = true; whirlpool::escaped = true;
achievement_gain("WHIRL1"); achievement_gain("WHIRL1");

118
graph.cpp
View File

@@ -4,6 +4,8 @@
// basic graphics: // basic graphics:
int inmirrorcount = 0;
bool wmspatial, wmescher, wmplain, wmblack, wmascii; bool wmspatial, wmescher, wmplain, wmblack, wmascii;
bool mmspatial, mmhigh, mmmon, mmitem; bool mmspatial, mmhigh, mmmon, mmitem;
int maxreclevel, reclevel; int maxreclevel, reclevel;
@@ -614,6 +616,7 @@ bool drawItemType(eItem it, cell *c, const transmatrix& V, int icol, int ticks,
if(it == itOrbUndeath) icol = minf[moFriendlyGhost].color; if(it == itOrbUndeath) icol = minf[moFriendlyGhost].color;
if(it == itOrbRecall) icol = 0x101010; if(it == itOrbRecall) icol = 0x101010;
hpcshape& sh = hpcshape& sh =
it == itOrbLove ? shLoveRing :
isRangedOrb(it) ? shTargetRing : isRangedOrb(it) ? shTargetRing :
isOffensiveOrb(it) ? shSawRing : isOffensiveOrb(it) ? shSawRing :
isFriendOrb(it) ? shPeaceRing : isFriendOrb(it) ? shPeaceRing :
@@ -1023,9 +1026,12 @@ bool drawMonsterType(eMonster m, cell *where, const transmatrix& V, int col, dou
queuepoly(VBIRD * Mirror, shGadflyEye, darkena(col, 2, 0xFF)); queuepoly(VBIRD * Mirror, shGadflyEye, darkena(col, 2, 0xFF));
} }
else if(m == moVampire || m == moBat) { else if(m == moVampire || m == moBat) {
if(m == moBat) ShadowV(V, shBatWings); // but vampires have no shadow // vampires have no shadow and no mirror images
queuepoly(VBIRD, shBatWings, darkena(0x303030, 0, 0xFF)); if(m == moBat) ShadowV(V, shBatWings);
queuepoly(VBIRD, shBatBody, darkena(0x606060, 0, 0xFF)); if(m == moBat || !inmirrorcount) {
queuepoly(VBIRD, shBatWings, darkena(0x303030, 0, 0xFF));
queuepoly(VBIRD, shBatBody, darkena(0x606060, 0, 0xFF));
}
/* queuepoly(V, shBatMouth, darkena(0xC00000, 0, 0xFF)); /* queuepoly(V, shBatMouth, darkena(0xC00000, 0, 0xFF));
queuepoly(V, shBatFang, darkena(0xFFC0C0, 0, 0xFF)); queuepoly(V, shBatFang, darkena(0xFFC0C0, 0, 0xFF));
queuepoly(V*Mirror, shBatFang, darkena(0xFFC0C0, 0, 0xFF)); queuepoly(V*Mirror, shBatFang, darkena(0xFFC0C0, 0, 0xFF));
@@ -1444,7 +1450,7 @@ bool applyAnimation(cell *c, transmatrix& V, double& footphase, int layer) {
} }
double chainAngle(cell *c, transmatrix& V, cell *c2, double dft) { double chainAngle(cell *c, transmatrix& V, cell *c2, double dft) {
if(!gmatrix0.count(c2)) return dft; if(inmirrorcount || !gmatrix0.count(c2)) return dft;
hyperpoint h = C0; hyperpoint h = C0;
if(animations[LAYER_BIG].count(c2)) h = animations[LAYER_BIG][c2].wherenow * h; if(animations[LAYER_BIG].count(c2)) h = animations[LAYER_BIG][c2].wherenow * h;
h = inverse(V) * gmatrix0[c2] * h; h = inverse(V) * gmatrix0[c2] * h;
@@ -1453,7 +1459,7 @@ double chainAngle(cell *c, transmatrix& V, cell *c2, double dft) {
// equivalent to V = V * spin(-chainAngle(c,V,c2,dft)); // equivalent to V = V * spin(-chainAngle(c,V,c2,dft));
bool chainAnimation(cell *c, transmatrix& V, cell *c2, int i, int b) { bool chainAnimation(cell *c, transmatrix& V, cell *c2, int i, int b) {
if(!gmatrix0.count(c2)) { if(inmirrorcount || !gmatrix0.count(c2)) {
V = V * ddspin(c,i,b); V = V * ddspin(c,i,b);
return false; return false;
} }
@@ -1502,7 +1508,8 @@ bool drawMonster(const transmatrix& Vparam, int ct, cell *c, int col) {
double footphaseb = 0, footphase = 0; double footphaseb = 0, footphase = 0;
transmatrix Vs = Vparam; nospins = applyAnimation(c, Vs, footphase, LAYER_SMALL); transmatrix Vs = Vparam; nospins = applyAnimation(c, Vs, footphase, LAYER_SMALL);
transmatrix Vb = Vparam; nospinb = applyAnimation(c, Vb, footphaseb, LAYER_BIG); transmatrix Vb = Vparam;
if(!inmirrorcount) nospinb = applyAnimation(c, Vb, footphaseb, LAYER_BIG);
// nospin = true; // nospin = true;
eMonster m = c->monst; eMonster m = c->monst;
@@ -1639,6 +1646,8 @@ bool drawMonster(const transmatrix& Vparam, int ct, cell *c, int col) {
if(!nospins) if(!nospins)
Vs = Vs * ddspin(c, c->mondir, flipplayer ? S42 : 0); Vs = Vs * ddspin(c, c->mondir, flipplayer ? S42 : 0);
if(inmirrorcount&1) col ^= minf[moMirror].color ^ minf[moMirage].color;
if(c->monst == moMirror) Vs = Vs * Mirror; if(c->monst == moMirror) Vs = Vs * Mirror;
multi::cpid = c->hitpoints; multi::cpid = c->hitpoints;
@@ -2240,7 +2249,8 @@ void setcolors(cell *c, int& wcol, int &fcol) {
if(c->wall == waPlatform) wcol = 0xF0F0A0; if(c->wall == waPlatform) wcol = 0xF0F0A0;
} }
if(c->land == laWineyard) fcol = 0x006000; if(c->land == laWineyard) fcol = 0x006000;
if(c->land == laMirror) fcol = 0x808080; if(c->land == laMirror || c->land == laMirrorWall)
fcol = 0x808080;
if(c->land == laMotion) fcol = 0xF0F000; if(c->land == laMotion) fcol = 0xF0F000;
if(c->land == laGraveyard) fcol = 0x107010; if(c->land == laGraveyard) fcol = 0x107010;
if(c->land == laDryForest) fcol = gradient(0x008000, 0x800000, 0, c->landparam, 10); if(c->land == laDryForest) fcol = gradient(0x008000, 0x800000, 0, c->landparam, 10);
@@ -2509,7 +2519,7 @@ void setcolors(cell *c, int& wcol, int &fcol) {
if(c->wall == waAncientGrave || c->wall == waFreshGrave || c->wall == waThumperOn || c->wall == waThumperOff || c->wall == waBonfireOff) if(c->wall == waAncientGrave || c->wall == waFreshGrave || c->wall == waThumperOn || c->wall == waThumperOff || c->wall == waBonfireOff)
fcol = wcol; fcol = wcol;
if(c->land == laMinefield && c->wall == waMineMine && ((cmode && sm::MAP) || !canmove)) if(c->land == laMinefield && c->wall == waMineMine && ((cmode & sm::MAP) || !canmove))
fcol = wcol = 0xFF4040; fcol = wcol = 0xFF4040;
if(mightBeMine(c) && mineMarkedSafe(c)) if(mightBeMine(c) && mineMarkedSafe(c))
@@ -2792,14 +2802,17 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
qfi.shape = NULL; qfi.special = false; qfi.shape = NULL; qfi.special = false;
ivoryz = isGravityLand(c->land); ivoryz = isGravityLand(c->land);
transmatrix& gm = gmatrix[c]; bool orig = false;
bool orig = if(!inmirrorcount) {
gm[2][2] == 0 ? true : transmatrix& gm = gmatrix[c];
torus ? hypot(gm[0][2], gm[1][2]) >= hypot(V[0][2], V[1][2]) : orig =
(sphere && vid.alphax >= 1.001) ? fabs(gm[2][2]-1) <= fabs(V[2][2]-1) : gm[2][2] == 0 ? true :
fabs(gm[2][2]-1) >= fabs(V[2][2]-1) - 1e-8; torus ? hypot(gm[0][2], gm[1][2]) >= hypot(V[0][2], V[1][2]) :
(sphere && vid.alphax >= 1.001) ? fabs(gm[2][2]-1) <= fabs(V[2][2]-1) :
fabs(gm[2][2]-1) >= fabs(V[2][2]-1) - 1e-8;
if(orig) gm = V; if(orig) gm = V;
}
if(behindsphere(V)) return; if(behindsphere(V)) return;
@@ -2862,7 +2875,8 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
hyperpoint VC0 = tC0(V); hyperpoint VC0 = tC0(V);
if(intval(mouseh, VC0) < modist) { if(inmirrorcount) ;
else if(intval(mouseh, VC0) < modist) {
modist2 = modist; mouseover2 = mouseover; modist2 = modist; mouseover2 = mouseover;
modist = intval(mouseh, VC0); modist = intval(mouseh, VC0);
mouseover = c; mouseover = c;
@@ -2892,6 +2906,19 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
} }
} }
if(inmirror(c)) {
if(inmirrorcount >= 10) return;
cellwalker cw(c, 0, mirrored);
cw = mirror::reflect(cw);
int cmc = (cw.mirrored == mirrored) ? 2 : 1;
inmirrorcount += cmc;
if(cw.mirrored != mirrored) V = V * Mirror;
if(cw.spin) V = V * spin(2*M_PI*cw.spin/cw.c->type);
drawcell(cw.c, V, 0, cw.mirrored);
inmirrorcount -= cmc;
return;
}
// int col = 0xFFFFFF - 0x20 * c->maxdist - 0x2000 * c->cpdist; // int col = 0xFFFFFF - 0x20 * c->maxdist - 0x2000 * c->cpdist;
if(!buggyGeneration && c->mpdist > 8 && !cheater) return; // not yet generated if(!buggyGeneration && c->mpdist > 8 && !cheater) return; // not yet generated
@@ -2904,6 +2931,18 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
int wcol, fcol, asciicol; int wcol, fcol, asciicol;
setcolors(c, wcol, fcol); setcolors(c, wcol, fcol);
if(inmirror(c)) {
// for debugging
if(c->land == laMirrored) fcol = 0x008000;
if(c->land == laMirrorWall2) fcol = 0x800000;
if(c->land == laMirrored2) fcol = 0x000080;
}
for(int k=0; k<inmirrorcount; k++)
wcol = gradient(wcol, 0xC0C0FF, 0, 0.2, 1),
fcol = gradient(fcol, 0xC0C0FF, 0, 0.2, 1);
// addaura(tC0(V), wcol); // addaura(tC0(V), wcol);
int zcol = fcol; int zcol = fcol;
@@ -2918,6 +2957,11 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
fcol = gradient(fcol, dc, 0, .3, 1); fcol = gradient(fcol, dc, 0, .3, 1);
} }
if(c->land == laMirrored || c->land == laMirrorWall2 || c->land == laMirrored2) {
string label = its(c->landparam);
queuestr(V, 1 * .2, label, 0xFFFFFFFF, 1);
}
if(viewdists) { if(viewdists) {
int cd = celldistance(c, cwt.c); int cd = celldistance(c, cwt.c);
string label = its(cd); string label = its(cd);
@@ -3113,6 +3157,44 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
} }
#endif #endif
else if(c->land == laMirrorWall) {
int d = mirror::mirrordir(c);
bool onleft = c->type == 7;
if(c->type == 7 && c->barleft == laMirror)
onleft = !onleft;
if(c->type == 6 && c->mov[d]->barleft == laMirror)
onleft = !onleft;
if(purehepta) onleft = !onleft;
if(d == -1) {
for(d=0; d<6; d++)
if(c->mov[d] && c->mov[(1+d)%6] && c->mov[d]->land == laMirrorWall && c->mov[(1+d)%6]->land == laMirrorWall)
break;
qfi.spin = ddspin(c, d, 0);
transmatrix V2 = V * qfi.spin;
for(int d=0; d<6; d++) {
inmirrorcount+=d;
qfloor(c, V2 * spin(d*M_PI/3), shHalfFloor[2], darkena(fcol, fd, 0xFF));
inmirrorcount-=d;
}
const int layers = 2 << detaillevel;
for(int z=1; z<layers; z++)
queuepolyat(mscale(V2, zgrad0(0, geom3::wall_height, z, layers)), shHalfMirror[2], 0xC0C0C080, PPR_WALL3+z-layers);
}
else {
qfi.spin = ddspin(c, d, S42);
transmatrix V2 = V * qfi.spin;
inmirrorcount++;
qfloor(c, mirrorif(V2, !onleft), shHalfFloor[ct6], darkena(fcol, fd, 0xFF));
inmirrorcount--;
qfloor(c, mirrorif(V2, onleft), shHalfFloor[ct6], darkena(fcol, fd, 0xFF));
const int layers = 2 << detaillevel;
for(int z=1; z<layers; z++)
queuepolyat(mscale(V2, zgrad0(0, geom3::wall_height, z, layers)), shHalfMirror[ct6], 0xC0C0C080, PPR_WALL3+z-layers);
}
}
else if(c->land == laWineyard && cellHalfvine(c)) { else if(c->land == laWineyard && cellHalfvine(c)) {
int i =-1; int i =-1;
@@ -3606,6 +3688,8 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
} }
} }
else if(c->wall == waMirrorWall) ;
else if(highwall(c)) { else if(highwall(c)) {
zcol = wcol; zcol = wcol;
int wcol0 = wcol; int wcol0 = wcol;
@@ -4363,6 +4447,7 @@ void drawthemap() {
maxreclevel, maxreclevel,
hsOrigin, ypush(vid.yshift) * sphereflip * View); hsOrigin, ypush(vid.yshift) * sphereflip * View);
} }
ivoryz = false;
linepatterns::drawAll(); linepatterns::drawAll();
@@ -4589,6 +4674,7 @@ void drawfullmap() {
} }
#endif #endif
profile_start(2); profile_start(2);
drawaura(); drawaura();
drawqueue(); drawqueue();
profile_stop(2); profile_stop(2);

View File

@@ -36,6 +36,15 @@ string buildHelpText() {
"automatically cancels all moves which result in that.\n\n" "automatically cancels all moves which result in that.\n\n"
); );
if(inv::on)
h += XLAT(
"You are playing in the Orb Strategy Mode. Collecting treasure "
"gives you access to magical Orb powers. In this mode, "
"unlocking requirements are generally higher, and "
"several quests and lands "
"give you extremely powerful Orbs of the Mirror.\n"
);
else
h += XLAT( h += XLAT(
"There are many lands in HyperRogue. Collect 10 treasure " "There are many lands in HyperRogue. Collect 10 treasure "
"in the given land type to complete it; this enables you to " "in the given land type to complete it; this enables you to "
@@ -127,6 +136,7 @@ string helptitle(string s, int col) {
} }
string princessReviveHelp() { string princessReviveHelp() {
if(inv::on) return "";
string h = "\n\n" + string h = "\n\n" +
XLAT("Killed %1 can be revived with Orb of the Love, after you collect 20 more $$$.", moPrincess); XLAT("Killed %1 can be revived with Orb of the Love, after you collect 20 more $$$.", moPrincess);
if(princess::reviveAt) if(princess::reviveAt)
@@ -136,7 +146,8 @@ string princessReviveHelp() {
} }
void describeOrb(string& help, const orbinfo& oi) { void describeOrb(string& help, const orbinfo& oi) {
eOrbLandRelation olr = getOLR(oi.orb, cwt.c->land); if(inv::on) return;
eOrbLandRelation olr = getOLR(oi.orb, getPrizeLand());
eItem tr = treasureType(oi.l); eItem tr = treasureType(oi.l);
help += "\n\n" + XLAT(olrDescriptions[olr], cwt.c->land, tr, treasureType(cwt.c->land)); help += "\n\n" + XLAT(olrDescriptions[olr], cwt.c->land, tr, treasureType(cwt.c->land));
int t = items[tr] * landMultiplier(oi.l); int t = items[tr] * landMultiplier(oi.l);
@@ -222,6 +233,51 @@ string generateHelpForItem(eItem it) {
} }
} }
if(inv::on) {
if(it == itOrbYendor || it == itHell) {
help += XLAT(
"\n\nIn the Orb Strategy Mode, Orbs of Yendor appear in Hell after "
"you collect 25 Demon Daisies in Hell, in Crossroads/Ocean after you collect 50, "
"and everywhere after you collect 100.");
}
if(it == itBone || it == itGreenStone) {
help += XLAT(
"\n\nIn the Orb Strategy Mode, dead orbs are available once you collect "
"10 Necromancer Totems in the Graveyard."
);
}
if(it == itFeather || it == itOrbSafety) {
help += XLAT(
"\n\nIn the Orb Strategy Mode, Orbs of Safety can be gained by "
"collecting Phoenix Feathers in the Land of Eternal Motion. "
"You can also find unlimited Orbs of Safety in the Crossroads "
"and the Ocean (after collecting 25 Phoenix Feathers) "
"and in the Prairie."
);
}
if(it == itOrbYendor || it == itHolyGrail)
help += XLAT(
"\n\nCollect %the1 to gain an extra Orb of the Mirror. "
"You can gain further Orbs of the Mirror by collecting 2, 4, 8..."
);
if(it == itOrbLuck)
help += XLAT(
"\n\nIn the Orb Strategy Mode, the Orb of Luck also "
"significantly increases the frequency of Great Walls, Crossroads IV, "
"and sub-lands."
);
if(it == itBone)
help += XLAT(
"\n\nIn the Orb Strategy Mode, each 25 Necromancer's Totems "
"you are given a random offensive Orb."
);
}
if(itemclass(it) == IC_ORB || it == itGreenStone || it == itOrbYendor) { if(itemclass(it) == IC_ORB || it == itGreenStone || it == itOrbYendor) {
for(int i=0; i<ORBLINES; i++) { for(int i=0; i<ORBLINES; i++) {
const orbinfo& oi(orbinfos[i]); const orbinfo& oi(orbinfos[i]);
@@ -237,7 +293,7 @@ string generateHelpForItem(eItem it) {
help += XLAT("\n\nOrb unlocked: %1", oi.orb); help += XLAT("\n\nOrb unlocked: %1", oi.orb);
describeOrb(help, oi); describeOrb(help, oi);
} }
else if(oi.l == cwt.c->land) { else if(oi.l == cwt.c->land || inv::on) {
help += XLAT("\n\nSecondary orb: %1", oi.orb); help += XLAT("\n\nSecondary orb: %1", oi.orb);
describeOrb(help, oi); describeOrb(help, oi);
} }
@@ -561,27 +617,7 @@ void describeMouseover() {
if(c->land == laTortoise && tortoise::seek()) out += " " + tortoise::measure(getBits(c)); if(c->land == laTortoise && tortoise::seek()) out += " " + tortoise::measure(getBits(c));
if(buggyGeneration) { if(buggyGeneration) {
char buf[20]; sprintf(buf, " H=%d M=%d", c->landparam, c->mpdist); out += buf; char buf[80]; sprintf(buf, " %p H=%d M=%d", c, c->landparam, c->mpdist); out += buf;
}
if(false) {
out += " LP:" + itsh(c->landparam)+"/"+its(turncount);
out += " CD:" + its(celldist(c));
out += " D:" + its(c->mpdist);
char zz[64]; sprintf(zz, " P%p", c); out += zz;
if(euclid) {
for(int i=0; i<4; i++) out += " " + its(getEuclidCdata(c->master)->val[i]);
out += " " + itsh(getBits(c));
}
else {
for(int i=0; i<4; i++) out += " " + its(getHeptagonCdata(c->master)->val[i]);
out += " " + fts(tortoise::getScent(getBits(c)));
}
} }
if(randomPatternsMode) if(randomPatternsMode)

View File

@@ -209,6 +209,14 @@ else if(args()[0] == '-' && args()[1] == x && args()[2] == '0') { if(curphase ==
else if(argis("-fix")) { else if(argis("-fix")) {
fixseed = true; autocheat = true; fixseed = true; autocheat = true;
} }
else if(argis("-fixx")) {
fixseed = true; autocheat = true;
shift(); startseed = argi();
}
else if(argis("-steplimit")) {
fixseed = true; autocheat = true;
shift(); steplimit = argi();
}
else if(argis("-qpar")) { else if(argis("-qpar")) {
int p; int p;
shift(); sscanf(args(), "%d,%d,%d", shift(); sscanf(args(), "%d,%d,%d",

65
hyper.h
View File

@@ -7,7 +7,7 @@
#define LB_YENDOR_CHALLENGE 40 #define LB_YENDOR_CHALLENGE 40
#define LB_PURE_TACTICS 41 #define LB_PURE_TACTICS 41
#define NUMLEADER 69 #define NUMLEADER 70
#define LB_PURE_TACTICS_SHMUP 49 #define LB_PURE_TACTICS_SHMUP 49
#define LB_PURE_TACTICS_COOP 50 #define LB_PURE_TACTICS_COOP 50
@@ -73,6 +73,7 @@ eItem treasureType(eLand l);
void buildBarrier(cell *c, int d, eLand l = laNone); void buildBarrier(cell *c, int d, eLand l = laNone);
void extendBarrier(cell *c); void extendBarrier(cell *c);
bool buildBarrier4(cell *c, int d, int mode, eLand ll, eLand lr); bool buildBarrier4(cell *c, int d, int mode, eLand ll, eLand lr);
bool buildBarrier6(struct cellwalker cw, int type);
bool makeEmpty(cell *c); bool makeEmpty(cell *c);
bool isCrossroads(eLand l); bool isCrossroads(eLand l);
enum orbAction { roMouse, roKeyboard, roCheck, roMouseForce, roMultiCheck, roMultiGo }; enum orbAction { roMouse, roKeyboard, roCheck, roMouseForce, roMultiCheck, roMultiGo };
@@ -134,7 +135,8 @@ void activateActiv(cell *c, bool msg);
// shmup // shmup
struct charstyle { struct charstyle {
int charid, skincolor, haircolor, dresscolor, swordcolor, dresscolor2, uicolor; int charid;
unsigned skincolor, haircolor, dresscolor, swordcolor, dresscolor2, uicolor;
}; };
string csname(charstyle& cs); string csname(charstyle& cs);
@@ -271,7 +273,7 @@ void drawfullmap();
bool displaystr(int x, int y, int shift, int size, const char *str, int color, int align); bool displaystr(int x, int y, int shift, int size, const char *str, int color, int align);
bool displaystr(int x, int y, int shift, int size, const string& str, int color, int align); bool displaystr(int x, int y, int shift, int size, const string& str, int color, int align);
extern int darken; extern int darken, inmirrorcount;
void calcparam(); void calcparam();
#ifdef USE_SDL #ifdef USE_SDL
@@ -395,7 +397,7 @@ namespace rug {
extern bool renderonce; extern bool renderonce;
extern bool rendernogl; extern bool rendernogl;
extern int texturesize; extern int texturesize;
extern double scale; extern ld scale;
void show(); void show();
void init(); void init();
void close(); void close();
@@ -406,8 +408,6 @@ namespace rug {
#endif #endif
#define HASLINEVIEW #define HASLINEVIEW
#include <complex>
typedef complex<ld> cld;
namespace conformal { namespace conformal {
extern bool on; extern bool on;
@@ -440,7 +440,7 @@ namespace polygonal {
extern int SI; extern int SI;
extern ld STAR; extern ld STAR;
extern int deg; extern int deg;
extern complex<ld> coef[MSI]; extern ld coefr[MSI], coefi[MSI];
extern int maxcoef, coefid; extern int maxcoef, coefid;
void solve(); void solve();
pair<ld, ld> compute(ld x, ld y); pair<ld, ld> compute(ld x, ld y);
@@ -469,6 +469,7 @@ extern bool localKill(shmup::monster *m);
#define P_ONPLAYER (1<<6) // always can step on the player #define P_ONPLAYER (1<<6) // always can step on the player
#define P_FLYING (1<<7) // is flying #define P_FLYING (1<<7) // is flying
#define P_BULLET (1<<8) // bullet can fly through more things #define P_BULLET (1<<8) // bullet can fly through more things
#define P_MIRRORWALL (1<<9) // mirror images go through mirror walls
#define P_JUMP1 (1<<10) // first part of a jump #define P_JUMP1 (1<<10) // first part of a jump
#define P_JUMP2 (1<<11) // second part of a jump #define P_JUMP2 (1<<11) // second part of a jump
#define P_TELE (1<<12) // teleport onto #define P_TELE (1<<12) // teleport onto
@@ -519,7 +520,7 @@ extern bool safety;
#define SAGEMELT .1 #define SAGEMELT .1
#define TEMPLE_EACH 6 #define TEMPLE_EACH 6
#define PT(x, y) ((tactic::on || quotient == 2) ? (y) : (x)) #define PT(x, y) ((tactic::on || quotient == 2) ? (y) : inv::on ? min(2*(y),x) : (x))
#define ROCKSNAKELENGTH 50 #define ROCKSNAKELENGTH 50
#define WORMLENGTH 15 #define WORMLENGTH 15
#define PUREHARDCORE_LEVEL 10 #define PUREHARDCORE_LEVEL 10
@@ -540,7 +541,7 @@ bool isAlchAny(eWall w);
bool isAlchAny(cell *c); bool isAlchAny(cell *c);
#define YDIST 101 #define YDIST 101
#define MODECODES 254 #define MODECODES 255
extern cellwalker cwt; // player character position extern cellwalker cwt; // player character position
extern int sval; extern int sval;
@@ -827,7 +828,7 @@ namespace dialog {
void addSelItem(string body, string value, int key); void addSelItem(string body, string value, int key);
void addBoolItem(string body, bool value, int key); void addBoolItem(string body, bool value, int key);
void addColorItem(string body, int value, int key); void addColorItem(string body, int value, int key);
void openColorDialog(int& col, unsigned int *pal = palette); void openColorDialog(unsigned int& col, unsigned int *pal = palette);
void addHelp(string body); void addHelp(string body);
void addInfo(string body, int color = 0xC0C0C0); void addInfo(string body, int color = 0xC0C0C0);
void addItem(string body, int key); void addItem(string body, int key);
@@ -1304,8 +1305,14 @@ bool createOnSea(eLand old);
namespace inv { namespace inv {
extern bool on; extern bool on;
extern bool usedForbidden;
extern int remaining[ittypes]; extern int remaining[ittypes];
void compute(); void compute();
void applyBox(eItem it);
extern int incheck;
void check(int delta);
void show();
} }
bool drawItemType(eItem it, cell *c, const transmatrix& V, int icol, int ticks, bool hidden); bool drawItemType(eItem it, cell *c, const transmatrix& V, int icol, int ticks, bool hidden);
@@ -1327,6 +1334,9 @@ typedef hookset<void()> *purehookset;
template<class T, class U> int addHook(hookset<T>*& m, int prio, const U& hook) { template<class T, class U> int addHook(hookset<T>*& m, int prio, const U& hook) {
if(!m) m = new hookset<T> (); if(!m) m = new hookset<T> ();
while(m->count(prio)) {
prio++;
}
(*m)[prio] = hook; (*m)[prio] = hook;
return 0; return 0;
} }
@@ -1469,3 +1479,38 @@ namespace leader { void showMenu(); void handleKey(int sym, int uni); }
bool needConfirmation(); bool needConfirmation();
extern const char* geometrynames_short[gGUARD]; extern const char* geometrynames_short[gGUARD];
namespace mirror {
cellwalker reflect(cellwalker cw, bool debug = false);
}
bool inmirror(eLand l);
bool inmirror(cell *c);
bool inmirror(const cellwalker& cw);
void queuemarkerat(const transmatrix& V, int col);
void check_total_victory();
void applyBoxNum(int& i, string name = "");
extern int hinttoshow;
bool isShmupLifeOrb(eItem it);
int orbcharges(eItem it);
#ifdef PANDORA
static const bool ISPANDORA = true;
#else
static const bool ISPANDORA = false;
#endif
int gradient(int c0, int c1, ld v0, ld v, ld v1);
struct hint {
time_t last;
function<bool()> usable;
function<void()> display;
function<void()> action;
};
extern hint hints[];
int counthints();

View File

@@ -1,8 +1,8 @@
id ICON "hr-icon.ico" id ICON "hr-icon.ico"
1 VERSIONINFO 1 VERSIONINFO
FILEVERSION 9,4,0,15 FILEVERSION 9,4,0,13
PRODUCTVERSION 9,4,0,15 PRODUCTVERSION 9,4,0,13
BEGIN BEGIN
BLOCK "StringFileInfo" BLOCK "StringFileInfo"
BEGIN BEGIN
@@ -10,12 +10,12 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "Zeno Rogue" VALUE "CompanyName", "Zeno Rogue"
VALUE "FileDescription", "A roguelike in non-euclidean space" VALUE "FileDescription", "A roguelike in non-euclidean space"
VALUE "FileVersion", "94n1" VALUE "FileVersion", "A10.0"
VALUE "InternalName", "hyper" VALUE "InternalName", "hyper"
VALUE "LegalCopyright", "Zeno Rogue" VALUE "LegalCopyright", "Zeno Rogue"
VALUE "OriginalFilename", "hyper.exe" VALUE "OriginalFilename", "hyper.exe"
VALUE "ProductName", "HyperRogue" VALUE "ProductName", "HyperRogue"
VALUE "ProductVersion", "9.4n1" VALUE "ProductVersion", "10.0"
END END
END END

View File

@@ -255,6 +255,11 @@ hyperpoint mirrorif(const hyperpoint& V, bool b) {
else return V; else return V;
} }
transmatrix mirrorif(const transmatrix& V, bool b) {
if(b) return V*Mirror;
else return V;
}
// -1 if away, 0 if not away // -1 if away, 0 if not away
int away(const transmatrix& V2) { int away(const transmatrix& V2) {
return intval(C0, V2 * xpush0(1)) > intval(C0, tC0(V2)); return intval(C0, V2 * xpush0(1)) > intval(C0, tC0(V2));
@@ -305,7 +310,7 @@ void drawrec(const heptspin& hs, int lev, hstate s, const transmatrix& V) {
if(dodrawcell(c)) { if(dodrawcell(c)) {
reclevel = maxreclevel - lev; reclevel = maxreclevel - lev;
drawcell(c, (hs.spin || purehepta) ? V1 * spin(hs.spin*2*M_PI/S7 + (purehepta ? M_PI:0)) : V1, hs.spin, drawcell(c, (hs.spin || purehepta) ? V1 * spin(hs.spin*2*M_PI/S7 + (purehepta ? M_PI:0)) : V1, 0,
hs.mirrored); hs.mirrored);
} }

View File

@@ -1,6 +1,6 @@
#define VER "9.4n2" #define VER "10.0"
#define VERNUM 9416 #define VERNUM 10000
#define VERNUM_HEX 0x9416 #define VERNUM_HEX 0xA000
#define GEN_M 0 #define GEN_M 0
#define GEN_F 1 #define GEN_F 1
@@ -264,7 +264,7 @@ const char *loadlevel = NULL;
#include "landgen.cpp" #include "landgen.cpp"
#include "orbs.cpp" #include "orbs.cpp"
#ifdef INV #ifdef INV
#include "closed/inventory.cpp" #include "inventory.cpp"
#else #else
bool inv::on; bool inv::on;
#endif #endif
@@ -307,12 +307,13 @@ bool inv::on;
#endif #endif
bool fixseed = false; bool fixseed = false;
int startseed = 0;
void initAll() { void initAll() {
ca::init(); ca::init();
arg::read(1); arg::read(1);
srand(time(NULL)); srand(time(NULL));
shrand(fixseed ? 0 : time(NULL)); shrand(fixseed ? startseed : time(NULL));
achievement_init(); // not in ANDROID achievement_init(); // not in ANDROID

View File

@@ -4,6 +4,19 @@
// land generation routines // land generation routines
int steplimit = 0;
int cstep;
template<class... T>
void limitgen(T... args) {
if(steplimit) {
cstep++;
printf("%6d ", cstep);
printf(args...);
if(cstep == steplimit) buggyGeneration = true;
}
}
vector<cell*> buggycells; vector<cell*> buggycells;
cell *pathTowards(cell *pf, cell *pt) { cell *pathTowards(cell *pf, cell *pt) {
@@ -57,7 +70,7 @@ int isNative(eLand l, eMonster m) {
case laAlchemist: case laAlchemist:
return (m == moSlime) ? 2 : 0; return (m == moSlime) ? 2 : 0;
case laMirror: case laMirror: case laMirrored: case laMirrorWall: case laMirrorWall2: case laMirrored2:
return (m == moEagle || m == moRanger || m == moMirror || m == moMirage) ? 1 : 0; return (m == moEagle || m == moRanger || m == moMirror || m == moMirage) ? 1 : 0;
case laMotion: case laMotion:
@@ -217,7 +230,10 @@ eItem treasureType(eLand l) {
case laDesert: return itSpice; case laDesert: return itSpice;
case laAlchemist: return itElixir; case laAlchemist: return itElixir;
case laMirror: return itShard;
case laMirror: case laMirrored: case laMirrorWall: case laMirrorWall2: case laMirrored2:
return itShard;
case laMotion: return itFeather; case laMotion: return itFeather;
case laGraveyard: return itBone; case laGraveyard: return itBone;
@@ -310,7 +326,7 @@ eItem wanderingTreasure(cell *c) {
return treasureType(l); return treasureType(l);
} }
#define ORBLINES 54 #define ORBLINES 56
struct orbinfo { struct orbinfo {
eLand l; eLand l;
@@ -350,6 +366,7 @@ const orbinfo orbinfos[ORBLINES] = {
{laOcean, 0, 3000, itOrbEmpathy}, {laOcean, 0, 3000, itOrbEmpathy},
{laOcean, 0, 0, itOrbAir}, {laOcean, 0, 0, itOrbAir},
{laPalace, 0, 4000, itOrbDiscord}, {laPalace, 0, 4000, itOrbDiscord},
{laPalace, 0, 0, itOrbFrog},
{laZebra, 500, 2100, itOrbFrog}, {laZebra, 500, 2100, itOrbFrog},
{laLivefjord, 0, 1800, itOrbFish}, {laLivefjord, 0, 1800, itOrbFish},
{laPrincessQuest, 0, 200, itOrbLove}, {laPrincessQuest, 0, 200, itOrbLove},
@@ -374,6 +391,7 @@ const orbinfo orbinfos[ORBLINES] = {
{laReptile, 500, 2100, itOrbDash}, {laReptile, 500, 2100, itOrbDash},
{laBull, 720, 3000, itOrbHorns}, {laBull, 720, 3000, itOrbHorns},
{laPrairie, 0, 3500, itOrbBull}, {laPrairie, 0, 3500, itOrbBull},
{laWhirlpool, 0, 0, itOrbSafety},
{laWhirlpool, 0, 2000, itOrbWater}, // must be last because it generates a boat {laWhirlpool, 0, 2000, itOrbWater}, // must be last because it generates a boat
}; };
@@ -635,7 +653,8 @@ bool landUnlocked(eLand l) {
return true; return true;
case laMirror: case laMinefield: case laPalace: case laMirror: case laMinefield: case laPalace:
case laOcean: case laLivefjord: case laOcean: case laLivefjord: case laMirrored: case laMirrorWall: case laMirrorWall2:
case laMirrored2:
return gold() >= R30; return gold() >= R30;
case laCaribbean: case laWhirlpool: case laCaribbean: case laWhirlpool:
@@ -926,6 +945,10 @@ void setbarrier(cell *c) {
else if(c->barleft == laHaunted || c->barright == laHaunted) { else if(c->barleft == laHaunted || c->barright == laHaunted) {
c->land = laHauntedWall; c->land = laHauntedWall;
} }
else if(c->barleft == laMirrored2 || c->barright == laMirrored2)
c->land = laMirrorWall2;
else if(c->barleft == laMirrored || c->barright == laMirrored)
c->land = laMirrorWall;
else { else {
c->wall = waBarrier; c->wall = waBarrier;
c->land = laBarrier; c->land = laBarrier;
@@ -1016,24 +1039,36 @@ bool buildPrizeMirror(cell *c, int freq) {
return true; return true;
} }
void placePrizeOrb(cell *c) { eLand getPrizeLand(cell *c = cwt.c) {
eLand l = c->land; eLand l = c->land;
if(isElemental(l)) l = laElementalWall; if(isElemental(l)) l = laElementalWall;
if(l == laPalace && princess::dist(c) < OUT_OF_PRISON)
l = laPrincessQuest;
return l;
}
void placePrizeOrb(cell *c) {
if(peace::on) return; if(peace::on) return;
eLand l = getPrizeLand(c);
// these two lands would have too much orbs according to normal rules // these two lands would have too much orbs according to normal rules
if(l == laPalace && hrand(100) >= 20) return; if(l == laPalace && hrand(100) >= 20) return;
if(l == laPrincessQuest && hrand(100) >= 20) return;
if(l == laGraveyard && hrand(100) >= 15) return; if(l == laGraveyard && hrand(100) >= 15) return;
if(l == laBurial && hrand(100) >= 10) return; if(l == laBurial && hrand(100) >= 10) return;
if(l == laLivefjord && hrand(100) >= 35) return; if(l == laLivefjord && hrand(100) >= 35) return;
if(l == laMinefield && hrand(100) >= 25) return; if(l == laMinefield && hrand(100) >= 25) return;
if(l == laElementalWall && hrand(100) >= 25) return; if(l == laElementalWall && hrand(100) >= 25) return;
if(l == laPalace && princess::dist(c) < OUT_OF_PRISON)
l = laPrincessQuest;
for(int i=0; i<ORBLINES; i++) { for(int i=0; i<ORBLINES; i++) {
const orbinfo& oi(orbinfos[i]); const orbinfo& oi(orbinfos[i]);
if(inv::on && oi.orb != itOrbYendor) return;
if(inv::on) {
if(oi.orb == itOrbYendor && items[itHell] >= 100) ;
else continue;
}
eOrbLandRelation olr = getOLR(oi.orb, l); eOrbLandRelation olr = getOLR(oi.orb, l);
if(olr != olrPrize25 && olr != olrPrize3) continue; if(olr != olrPrize25 && olr != olrPrize3) continue;
int treas = items[treasureType(oi.l)]; int treas = items[treasureType(oi.l)];
@@ -1069,7 +1104,10 @@ void placeLocalOrbs(cell *c) {
for(int i=0; i<ORBLINES; i++) { for(int i=0; i<ORBLINES; i++) {
const orbinfo& oi(orbinfos[i]); const orbinfo& oi(orbinfos[i]);
if(oi.l != l) continue; if(oi.l != l) continue;
if(inv::on && (oi.orb != itOrbYendor)) continue; if(inv::on) {
if(oi.orb != itOrbYendor) continue;
if(items[itHell] < 25) continue;
}
if(yendor::on && (oi.orb == itOrbSafety || oi.orb == itOrbYendor)) if(yendor::on && (oi.orb == itOrbSafety || oi.orb == itOrbYendor))
continue; continue;
if(!oi.lchance) continue; if(!oi.lchance) continue;
@@ -1093,7 +1131,12 @@ void placeCrossroadOrbs(cell *c) {
for(int i=0; i<ORBLINES; i++) { for(int i=0; i<ORBLINES; i++) {
const orbinfo& oi(orbinfos[i]); const orbinfo& oi(orbinfos[i]);
if(!oi.gchance) continue; if(!oi.gchance) continue;
if(inv::on && oi.orb != itOrbSafety && oi.orb != itOrbYendor) return;
if(inv::on) {
if(oi.orb == itOrbYendor && items[itHell] >= 50) ;
else if(oi.orb == itOrbSafety && items[itFeather] >= 25) ;
else continue;
}
int treas = items[treasureType(oi.l)] * landMultiplier(oi.l); int treas = items[treasureType(oi.l)] * landMultiplier(oi.l);
if(tactic::on && isCrossroads(tactic::lasttactic)) { if(tactic::on && isCrossroads(tactic::lasttactic)) {
if(oi.orb == itOrbYendor || oi.orb == itOrbSummon || oi.orb == itOrbFish || oi.orb == itOrbDigging || oi.orb == itOrbLove || oi.orb == itOrbLuck) if(oi.orb == itOrbYendor || oi.orb == itOrbSummon || oi.orb == itOrbFish || oi.orb == itOrbDigging || oi.orb == itOrbLove || oi.orb == itOrbLuck)
@@ -1117,7 +1160,13 @@ void placeOceanOrbs(cell *c) {
if(peace::on) return; if(peace::on) return;
for(int i=0; i<ORBLINES; i++) { for(int i=0; i<ORBLINES; i++) {
const orbinfo& oi(orbinfos[i]); const orbinfo& oi(orbinfos[i]);
if(inv::on && oi.orb != itOrbSafety && oi.orb != itOrbYendor) return;
if(inv::on) {
if(oi.orb == itOrbYendor && items[itHell] >= 50) ;
else if(oi.orb == itOrbSafety && items[itFeather] >= 25) ;
else continue;
}
if(items[treasureType(oi.l)] * landMultiplier(oi.l) < 10) continue; if(items[treasureType(oi.l)] * landMultiplier(oi.l) < 10) continue;
if(!oi.gchance) continue; if(!oi.gchance) continue;
if(oi.orb == itOrbLife) continue; // useless if(oi.orb == itOrbLife) continue; // useless
@@ -1194,7 +1243,27 @@ void extendcheck(cell *c) {
} }
} }
bool oldmirror;
bool inmirror(eLand l) {
return l == laMirrored || l == laMirrorWall2 || l == laMirrored2;
}
bool inmirror(cell *c) {
return inmirror(c->land);
}
bool inmirror(const cellwalker& cw) {
return inmirror(cw.c->land);
}
bool mirrorwall(cell *c) {
return c->barleft == laMirrored || c->barright == laMirrored;
}
void extendBarrierFront(cell *c) { void extendBarrierFront(cell *c) {
limitgen("extend front %p\n", c);
if(buggyGeneration) return;
int ht = c->landparam; int ht = c->landparam;
extendcheck(c); extendcheck(c);
@@ -1205,7 +1274,8 @@ void extendBarrierFront(cell *c) {
bb.c->barleft = c->barleft; bb.c->barleft = c->barleft;
bb.c->barright = c->barright; bb.c->barright = c->barright;
setbarrier(bb.c); setbarrier(bb.c);
bb.c->landparam = (ht-4); if(!mirrorwall(bb.c))
bb.c->landparam = (ht-4);
//printf("[A heat %d]\n", ht-4); //printf("[A heat %d]\n", ht-4);
cwspin(bb, 2); cwstep(bb); setland(bb.c, c->barleft); cwstep(bb); cwspin(bb, 2); cwstep(bb); setland(bb.c, c->barleft); cwstep(bb);
@@ -1216,11 +1286,15 @@ void extendBarrierFront(cell *c) {
bb.c->barleft = c->barright; bb.c->barleft = c->barright;
bb.c->barright = c->barleft; bb.c->barright = c->barleft;
setbarrier(bb.c); setbarrier(bb.c);
bb.c->landparam = (ht-4)^2; if(!mirrorwall(bb.c))
bb.c->landparam = (ht-4)^2;
//printf("[B heat %d]\n", (ht-4)^2); //printf("[B heat %d]\n", (ht-4)^2);
cwspin(bb, 3); cwstep(bb); cwspin(bb, 3); cwstep(bb);
bb.c->landparam = ht ^ 2; bb.c->barleft = c->barleft;
bb.c->barright = c->barright;
if(!mirrorwall(bb.c))
bb.c->landparam = ht ^ 2;
} }
//printf("[C heat %d]\n", (ht)^2); //printf("[C heat %d]\n", (ht)^2);
@@ -1238,6 +1312,8 @@ void extendBarrierFront(cell *c) {
} }
void extendBarrierBack(cell *c) { void extendBarrierBack(cell *c) {
limitgen("extend back %p\n", c);
if(buggyGeneration) return;
int ht = c->landparam; int ht = c->landparam;
extendcheck(c); extendcheck(c);
@@ -1248,7 +1324,8 @@ void extendBarrierBack(cell *c) {
bb.c->bardir = bb.spin; bb.c->bardir = bb.spin;
bb.c->barleft = c->barright; bb.c->barleft = c->barright;
bb.c->barright = c->barleft; bb.c->barright = c->barleft;
bb.c->landparam = ht ^ 11; if(!mirrorwall(bb.c))
bb.c->landparam = ht ^ 11;
extendcheck(bb.c); extendcheck(bb.c);
//printf("[D heat %d]\n", (ht^11)); //printf("[D heat %d]\n", (ht^11));
@@ -1257,7 +1334,8 @@ void extendBarrierBack(cell *c) {
cwstep(bb); cwstep(bb);
bb.c->barleft = c->barright; bb.c->barleft = c->barright;
bb.c->barright = c->barleft; bb.c->barright = c->barleft;
bb.c->landparam = (ht^11)-4; if(!mirrorwall(bb.c))
bb.c->landparam = (ht^11)-4;
cwstep(bb); cwstep(bb);
} }
//printf("[E heat %d]\n", (ht^11)); //printf("[E heat %d]\n", (ht^11));
@@ -1266,11 +1344,13 @@ void extendBarrierBack(cell *c) {
extendBarrier(bb.c); extendBarrier(bb.c);
} }
eLand oppositeElement(eLand l) { eLand oppositeElement(eLand l, eLand l2) {
if(l == laEFire) return laEWater; if(l == laEFire) return laEWater;
if(l == laEWater) return laEFire; if(l == laEWater) return laEFire;
if(l == laEAir) return laEEarth; if(l == laEAir) return laEEarth;
if(l == laEEarth) return laEAir; if(l == laEEarth) return laEAir;
if(l == laMirror && l2 == laMirrored) return laMirrored2;
if(l == laMirrored2 && l2 == laMirrored) return laMirror;
return l; return l;
} }
@@ -1353,7 +1433,14 @@ void extendCR5(cell *c) {
} }
} }
bool isbar4(cell *c) {
return
c->wall == waBarrier || c->land == laElementalWall ||
c->land == laMirrorWall || c->land == laMirrorWall2;
}
void extendBarrier(cell *c) { void extendBarrier(cell *c) {
limitgen("extend barrier %p\n", c);
if(buggyGeneration) return; if(buggyGeneration) return;
if(c->barleft == NOWALLSEP_USED) return; if(c->barleft == NOWALLSEP_USED) return;
@@ -1361,7 +1448,8 @@ void extendBarrier(cell *c) {
extendcheck(c); extendcheck(c);
// printf("build barrier at %p", c); // printf("build barrier at %p", c);
if(c->land == laBarrier || c->land == laElementalWall || c->land == laHauntedWall || c->land == laOceanWall) { if(c->land == laBarrier || c->land == laElementalWall || c->land == laHauntedWall || c->land == laOceanWall ||
c->land == laMirrorWall || c->land == laMirrorWall2) {
// printf("-> ready\n"); // printf("-> ready\n");
return; return;
} }
@@ -1376,14 +1464,40 @@ void extendBarrier(cell *c) {
return; return;
} }
bool firstmirror =
(c->barleft == laMirrored || c->barright == laMirrored) &&
c->barleft != laMirrored2 && c->barright != laMirrored2;
if(firstmirror && c->barleft == laMirror && hrand(100) < 60) {
cellwalker cw(c, c->bardir);
if(!purehepta) cwstep(cw);
if(cw.c->land != laMirrorWall)
if(buildBarrier6(cw, 1)) return;
}
if(firstmirror && (purehepta?c->barleft == laMirror : c->barright == laMirror) && hrand(100) < 60) {
cellwalker cw(c, c->bardir);
if(purehepta) {
cwspin(cw, -3); cwstep(cw); cwspin(cw, -3);
// cwspin(cw, 3); cwstep(cw); cwspin(cw, -2); cwstep(cw); cwspin(cw, 3);
}
else {
cwstep(cw); cwspin(cw, 3); cwstep(cw); cwspin(cw, -1); // check this
}
if(buildBarrier6(cw, 2)) return;
}
if(((c->barleft == laCrossroads3 || c->barright == laCrossroads3) && hrand(100) < 66) || if(((c->barleft == laCrossroads3 || c->barright == laCrossroads3) && hrand(100) < 66) ||
(isElemental(c->barleft) && isElemental(c->barright) && hrand(100) < 25)) { (isElemental(c->barleft) && isElemental(c->barright) && hrand(100) < 75)
|| (firstmirror && hrand(100) < 60)
) {
cellwalker cw(c, c->bardir); cellwalker cw(c, c->bardir);
if(purehepta) { if(purehepta) {
cwstep(cw); if(cw.c->wall == waBarrier || cw.c->land == laElementalWall) { cwstep(cw);
if(isbar4(cw.c)) {
cwstep(cw); cwspin(cw, 3); cwstep(cw); cwspin(cw, -1); cwstep(cw); cwstep(cw); cwspin(cw, 3); cwstep(cw); cwspin(cw, -1); cwstep(cw);
bool b = buildBarrier4(cw.c, cw.spin, 2, oppositeElement(c->barleft), c->barright); bool b = buildBarrier4(cw.c, cw.spin, 2, oppositeElement(c->barleft, c->barright), c->barright);
if(b) return; if(b) return;
} }
else { else {
@@ -1394,9 +1508,9 @@ void extendBarrier(cell *c) {
else { else {
cwspin(cw, 3); cwstep(cw); cwspin(cw, 3); cwstep(cw);
cell *cp = cwpeek(cw, 4); cell *cp = cwpeek(cw, 4);
if(cp->wall != waBarrier && cp->land != laElementalWall) { if(!isbar4(cp)) {
cwspin(cw, 2); cwstep(cw); cwspin(cw, 2); cwstep(cw);
bool b = buildBarrier4(cw.c, cw.spin, 2, oppositeElement(c->barleft), c->barright); bool b = buildBarrier4(cw.c, cw.spin, 2, oppositeElement(c->barleft, c->barright), c->barright);
if(b) return; if(b) return;
} }
else { else {
@@ -1603,6 +1717,8 @@ eLand getNewLand(eLand old) {
eLand l = callhandlers(laNone, hooks_nextland, old); eLand l = callhandlers(laNone, hooks_nextland, old);
if(l) return l; if(l) return l;
if(old == laMirror && !oldmirror && hrand(10)) return laMirrored;
if(cheatdest != old) if(!isCyclic(cheatdest) && !isTechnicalLand(cheatdest)) return cheatdest; if(cheatdest != old) if(!isCyclic(cheatdest) && !isTechnicalLand(cheatdest)) return cheatdest;
if(old == laTortoise) return laDragon; if(old == laTortoise) return laDragon;
@@ -1927,7 +2043,7 @@ void buildBarrierForce(cell *c, int d, eLand l) {
landcount[newland]++; landcount[newland]++;
if(d == 4 || d == 5 || d == 6) c->barleft = oldland, c->barright = newland; if(d == 4 || d == 5 || d == 6) c->barleft = oldland, c->barright = newland;
else c->barleft = newland, c->barright = oldland; else c->barleft = newland, c->barright = oldland;
c->landparam = 40; if(!mirrorwall(c)) c->landparam = 40;
extendcheck(c); extendcheck(c);
} }
@@ -1939,7 +2055,124 @@ void buildBarrier(cell *c, int d, eLand l) {
buildBarrierForce(c, d, l); buildBarrierForce(c, d, l);
} }
bool buildBarrier6(cellwalker cw, int type) {
limitgen("build6 %p/%d (%d)\n", cw.c, cw.spin, type);
cellwalker b[4];
for(int i=0; i<4; i++) b[i] = cw;
if(buggyGeneration) return true;
if(!purehepta) {
cwstep(b[0]);
cwspin(b[1], 1); cwstep(b[1]); cwspin(b[1], 3); cwstep(b[1]);
cwspin(b[2], 4); cwstep(b[2]);
cwspin(b[3], 3); cwstep(b[3]); cwspin(b[3], 3); cwstep(b[3]);
}
else {
cwspin(b[1], 3); cwstep(b[1]); cwspin(b[1], 3);
cwspin(b[2], -2); cwstep(b[2]); cwspin(b[2], -3);
cwspin(b[3], -3); cwstep(b[3]); cwspin(b[3], 2); cwstep(b[3]); cwspin(b[3],-3);
if(type == 1 && b[3].c->land != laMirrorWall) return false;
if(type == 2 && cwpeek(b[1], 0)->land != laMirrorWall) return false;
// if(type == 2 && b[2].c->land != laMirrorWall) return false;
}
if(false) {
for(int z=0; z<4; z++) {
printf("%p/%d\n", b[z].c, b[z].spin);
b[z].c->wall = waStrandedBoat; b[z].c->land = laAlchemist;
b[z].c->mondir = b[z].spin;
b[z].c->mpdist = 7;
b[z].c->item = eItem(1+z);
buggyGeneration = true;
}
return true;
}
if(type == 1) {
if(!(purehepta?checkBarriersFront:checkBarriersBack)(b[1], 6, true)) return false;
if(!(purehepta?checkBarriersFront:checkBarriersBack)(b[2], 6, true)) return false;
}
else {
if(!(purehepta?checkBarriersFront:checkBarriersBack)(b[0], 6, true)) return false;
if(!(purehepta?checkBarriersFront:checkBarriersBack)(b[3], 6, true)) return false;
}
for(int d=0; d<4; d++) {
b[d].c->bardir = b[d].spin;
if(purehepta) {
b[0].c->barleft = laMirrored, b[0].c->barright = laMirrored2;
b[1].c->barleft = laMirror, b[1].c->barright = laMirrored;
b[2].c->barleft = laMirrored2, b[2].c->barright = laMirrored;
b[3].c->barleft = laMirrored, b[3].c->barright = laMirror;
}
else {
b[0].c->barleft = laMirror, b[0].c->barright = laMirrored;
b[1].c->barleft = laMirrored, b[1].c->barright = laMirror;
b[2].c->barleft = laMirrored, b[2].c->barright = laMirrored2;
b[3].c->barleft = laMirrored2, b[3].c->barright = laMirrored;
}
(purehepta?extendBarrierFront:extendBarrierBack)(b[d].c);
}
if(purehepta && false) {
for(int a=0; a<4; a++)
extendBarrierBack(cwpeek(b[a],0));
}
if(!purehepta) {
setland(cwpeek(cw, 1), laMirrorWall);
setland(cwpeek(cw, 2), laMirrored);
setland(cwpeek(cw, 3), laMirrorWall2);
setland(cwpeek(cw, 4), laMirrorWall2);
setland(cwpeek(cw, 5), laMirrored);
setland(cwpeek(cw, 0), laMirrorWall);
setland(cwpeek(b[0], 2), laMirrored);
setland(cwpeek(b[3], 6), laMirrored2);
setland(cwpeek(b[3], 5), laMirrored2);
setland(cwpeek(b[1], -1), laMirrored);
setland(cwpeek(b[2], -2), laMirrored);
setland(cwpeek(b[1], -2), laMirrored);
setland(cwpeek(b[0], -2), laMirror);
cw.c->land = laMirrorWall;
cw.c->wall = waMirrorWall;
cw.c->landparam = 1;
}
else {
setland(cw.c, laMirrorWall2);
setland(cwpeek(cw, 0), laMirrorWall2);
setland(cwpeek(cw, 1), laMirrored);
setland(cwpeek(cw, 2), laMirrored);
setland(cwpeek(cw, 3), laMirrorWall);
setland(cwpeek(cw, 4), laMirrored);
setland(cwpeek(cw, 5), laMirrorWall2);
setland(cwpeek(cw, 6), laMirrored2);
setland(cwpeek(b[1], 0), laMirrorWall);
setland(cwpeek(b[1], 1), laMirror);
setland(cwpeek(b[1], 2), laMirrorWall);
setland(cwpeek(b[1], 6), laMirrored);
cellwalker cf = b[0];
cwstep(cf);
setland(cwpeek(cf, -2), laMirrored);
cf = b[3];
cwstep(cf);
setland(cwpeek(cf, -2), laMirrored);
}
return true;
}
bool buildBarrier4(cell *c, int d, int mode, eLand ll, eLand lr) { bool buildBarrier4(cell *c, int d, int mode, eLand ll, eLand lr) {
limitgen("build4 %p\n", c);
if(buggyGeneration) return true;
d %= 7; d %= 7;
cellwalker b1(c, d); cellwalker b1(c, d);
@@ -1978,8 +2211,8 @@ bool buildBarrier4(cell *c, int d, int mode, eLand ll, eLand lr) {
return false; return false;
} }
eLand xl = oppositeElement(ll); eLand xl = oppositeElement(ll, lr);
eLand xr = oppositeElement(lr); eLand xr = oppositeElement(lr, ll);
c->bardir = d, c->barleft = ll, c->barright = lr; extendBarrierBack(c); c->bardir = d, c->barleft = ll, c->barright = lr; extendBarrierBack(c);
@@ -2235,6 +2468,9 @@ int coastval(cell *c, eLand base) {
return 0; return 0;
if(c->land != laGraveyard && c->land != laHauntedBorder) return 30; if(c->land != laGraveyard && c->land != laHauntedBorder) return 30;
} }
else if(base == laMirrored) {
if(!inmirror(c)) return 0;
}
else { else {
if(c->land == laOceanWall || c->land == laCaribbean || c->land == laWhirlpool || if(c->land == laOceanWall || c->land == laCaribbean || c->land == laWhirlpool ||
c->land == laLivefjord || c->land == laWarpSea || c->land == laKraken) c->land == laLivefjord || c->land == laWarpSea || c->land == laKraken)
@@ -2303,6 +2539,7 @@ void buildEquidistant(cell *c) {
// buggycells.push_back(c); // buggycells.push_back(c);
} }
if(b == laHauntedBorder) b = laGraveyard; if(b == laHauntedBorder) b = laGraveyard;
if(inmirror(b)) b = laMirrored;
int mcv = UNKNOWN; int mcv = UNKNOWN;
// find the lowest coastval // find the lowest coastval
@@ -2827,6 +3064,10 @@ void setLandEuclid(cell *c) {
} }
} }
#define INVLUCK (items[itOrbLuck] && inv::on)
#define I2000 (INVLUCK?600:2000)
#define I10000 (INVLUCK?3000:10000)
void buildBigStuff(cell *c, cell *from) { void buildBigStuff(cell *c, cell *from) {
if(sphere || quotient) return; if(sphere || quotient) return;
bool deepOcean = false; bool deepOcean = false;
@@ -2867,7 +3108,7 @@ void buildBigStuff(cell *c, cell *from) {
else if(c->type == 7 && c->land == laCrossroads4 && hrand(10000) < 7000 && c->land && else if(c->type == 7 && c->land == laCrossroads4 && hrand(10000) < 7000 && c->land &&
buildBarrierNowall(c, getNewLand(laCrossroads4))) ; buildBarrierNowall(c, getNewLand(laCrossroads4))) ;
else if(c->type == 7 && hrand(10000) < 20 && !generatingEquidistant && !yendor::on && !tactic::on && !isCrossroads(c->land) && gold() >= R200 && else if(c->type == 7 && hrand(I10000) < 20 && !generatingEquidistant && !yendor::on && !tactic::on && !isCrossroads(c->land) && gold() >= R200 &&
!isSealand(c->land) && !isHaunted(c->land) && !isGravityLand(c->land) && !isSealand(c->land) && !isHaunted(c->land) && !isGravityLand(c->land) &&
(c->land != laRlyeh || rlyehComplete()) && (c->land != laRlyeh || rlyehComplete()) &&
c->land != laTortoise && c->land != laPrairie && c->land && c->land != laTortoise && c->land != laPrairie && c->land &&
@@ -2891,8 +3132,9 @@ void buildBigStuff(cell *c, cell *from) {
} }
} }
else if(c->type == 7 && c->land && hrand(10000) < ( else if(c->type == 7 && c->land && hrand(I10000) < (
showoff ? (cwt.c->mpdist > 7 ? 0 : 10000) : showoff ? (cwt.c->mpdist > 7 ? 0 : 10000) :
inmirror(c) ? 0 :
isGravityLand(c->land) ? 0 : isGravityLand(c->land) ? 0 :
generatingEquidistant ? 0 : generatingEquidistant ? 0 :
c->land == laPrairie ? 0 : c->land == laPrairie ? 0 :
@@ -2915,6 +3157,7 @@ void buildBigStuff(cell *c, cell *from) {
(c->land == laGraveyard && items[itBone] >= 10) ? 120 : (c->land == laGraveyard && items[itBone] >= 10) ? 120 :
c->land == laOcean ? (deepOcean ? (purehepta ? 250 : 2000) : 0) : c->land == laOcean ? (deepOcean ? (purehepta ? 250 : 2000) : 0) :
c->land == laDragon ? 120 : c->land == laDragon ? 120 :
(c->land == laMirror && !oldmirror) ? 6000 :
50)) 50))
{ {
@@ -2927,7 +3170,7 @@ void buildBigStuff(cell *c, cell *from) {
} }
if((!chaosmode) && bearsCamelot(c->land) && c->type == 7 && if((!chaosmode) && bearsCamelot(c->land) && c->type == 7 &&
(quickfind(laCamelot) || peace::on || (hrand(2000) < 200 && (quickfind(laCamelot) || peace::on || (hrand(I2000) < 200 &&
items[itEmerald] >= U5 && !tactic::on))) { items[itEmerald] >= U5 && !tactic::on))) {
int rtr = newRoundTableRadius(); int rtr = newRoundTableRadius();
heptagon *alt = createAlternateMap(c, rtr+14, hsOrigin); heptagon *alt = createAlternateMap(c, rtr+14, hsOrigin);
@@ -2942,18 +3185,18 @@ void buildBigStuff(cell *c, cell *from) {
// buildbigstuff // buildbigstuff
if(c->land == laRlyeh && c->type == 7 && if(c->land == laRlyeh && c->type == 7 &&
(quickfind(laTemple) || peace::on || (hrand(2000) < 100 && (quickfind(laTemple) || peace::on || (hrand(I2000) < 100 &&
items[itStatue] >= U5 && !randomPatternsMode && items[itStatue] >= U5 && !randomPatternsMode &&
!tactic::on && !yendor::on))) !tactic::on && !yendor::on)))
createAlternateMap(c, 2, hsA); createAlternateMap(c, 2, hsA);
if(c->land == laJungle && c->type == 7 && if(c->land == laJungle && c->type == 7 &&
(quickfind(laMountain) || (hrand(2000) < 100 && (quickfind(laMountain) || (hrand(I2000) < 100 &&
!randomPatternsMode && !tactic::on && !yendor::on && landUnlocked(laMountain)))) !randomPatternsMode && !tactic::on && !yendor::on && landUnlocked(laMountain))))
createAlternateMap(c, 2, hsA); createAlternateMap(c, 2, hsA);
if(c->land == laOvergrown && c->type == 7 && if(c->land == laOvergrown && c->type == 7 &&
(quickfind(laClearing) || (hrand(2000) < 25 && (quickfind(laClearing) || (hrand(I2000) < 25 &&
!randomPatternsMode && items[itMutant] >= U5 && !randomPatternsMode && items[itMutant] >= U5 &&
!tactic::on && !yendor::on))) { !tactic::on && !yendor::on))) {
heptagon *h = createAlternateMap(c, 2, hsA); heptagon *h = createAlternateMap(c, 2, hsA);
@@ -2977,8 +3220,11 @@ void buildBigStuff(cell *c, cell *from) {
(princess::forceMouse ? (from && from->pathdist != INF) : (princess::forceMouse ? (from && from->pathdist != INF) :
(hrand(2000) < (peace::on ? 100 : 20))) && (hrand(2000) < (peace::on ? 100 : 20))) &&
!c->master->alt && !c->master->alt &&
(princess::challenge || kills[moVizier] || peace::on) && !tactic::on && !yendor::on) (princess::challenge || kills[moVizier] || peace::on) && !tactic::on && !yendor::on) {
createAlternateMap(c, 141, hsOrigin, waPalace); createAlternateMap(c, PRADIUS0, hsOrigin, waPalace);
celllister cl(c, 5, 1000000, NULL);
for(cell *c: cl.lst) if(c->master->alt) generateAlts(c->master);
}
} }
if(hasbardir(c)) extendBarrier(c); if(hasbardir(c)) extendBarrier(c);
@@ -3265,6 +3511,8 @@ void setdist(cell *c, int d, cell *from) {
if(d <= 3) lastexplore = shmup::on ? shmup::curtime : turncount; if(d <= 3) lastexplore = shmup::on ? shmup::curtime : turncount;
oldmirror = euclid || chaosmode || yendor::on || yendor::generating;
if(buggyGeneration) { if(buggyGeneration) {
if(d < BARLEV) for(int i=0; i<c->type; i++) { if(d < BARLEV) for(int i=0; i<c->type; i++) {
setdist(createMov(c, i), d+(purehepta?2:1), c); setdist(createMov(c, i), d+(purehepta?2:1), c);
@@ -3310,6 +3558,8 @@ void setdist(cell *c, int d, cell *from) {
if(d == BARLEV && !euclid && c != cwt.c) if(d == BARLEV && !euclid && c != cwt.c)
buildBigStuff(c, from); buildBigStuff(c, from);
if(buggyGeneration) return;
if(d < 10) { if(d < 10) {
explore[d]++; explore[d]++;
exploreland[d][c->land]++; exploreland[d][c->land]++;
@@ -3322,6 +3572,9 @@ void setdist(cell *c, int d, cell *from) {
if(d == BARLEV-2 && c->land == laOcean) if(d == BARLEV-2 && c->land == laOcean)
buildEquidistant(c); buildEquidistant(c);
if(d == BARLEV-2 && inmirror(c))
buildEquidistant(c);
if(d == BARLEV-2 && (c->land == laGraveyard || c->land == laHauntedBorder || c->land == laHaunted)) if(d == BARLEV-2 && (c->land == laGraveyard || c->land == laHauntedBorder || c->land == laHaunted))
buildEquidistant(c); buildEquidistant(c);
@@ -3908,7 +4161,7 @@ void setdist(cell *c, int d, cell *from) {
if(c->land == laPalace && !euclid && c->master->alt) { if(c->land == laPalace && !euclid && c->master->alt) {
int d = celldistAlt(c); int d = celldistAlt(c);
if(d <= 150) generateAlts(c->master); if(d <= PRADIUS1) generateAlts(c->master);
} }
if((bearsCamelot(c->land) && !euclid && !quotient) || c->land == laCamelot) if((bearsCamelot(c->land) && !euclid && !quotient) || c->land == laCamelot)
@@ -4734,9 +4987,12 @@ void setdist(cell *c, int d, cell *from) {
princess::getPrisonInfo(c) && princess::getPrisonInfo(c) &&
(euclid || (princess::getPrisonInfo(c)->bestdist < 6 && princess::getPrisonInfo(c)->princess))) { (euclid || (princess::getPrisonInfo(c)->bestdist < 6 && princess::getPrisonInfo(c)->princess))) {
c->monst = moMouse; c->monst = moMouse;
addMessage(XLAT("You hear a distant squeak!")); if(!princess::squeaked) {
playSound(c, "mousesqueak"); addMessage(XLAT("You hear a distant squeak!"));
drawBigFlash(c); playSound(c, "mousesqueak");
drawBigFlash(c);
princess::squeaked = true;
}
/* { /* {
cell *c2= c; cell *c2= c;
z: z:
@@ -5024,7 +5280,7 @@ void setdist(cell *c, int d, cell *from) {
else { else {
if(hyperstonesUnlocked() && hrand(25000) < min(PT(tkills(), 2000), 5000) && notDippingFor(itHyperstone)) if(hyperstonesUnlocked() && hrand(25000) < min(PT(tkills(), 2000), 5000) && notDippingFor(itHyperstone))
c->item = itHyperstone; c->item = itHyperstone;
if(hrand(4000) < items[itHyperstone] + 2 * items[itHolyGrail] && !c->monst) { if(hrand(4000) < items[itHyperstone] && !c->monst) {
// only interesting monsters here! // only interesting monsters here!
eMonster cm = crossroadsMonster(); eMonster cm = crossroadsMonster();
if(cm == moIvyRoot) buildIvy(c, 0, c->type); if(cm == moIvyRoot) buildIvy(c, 0, c->type);
@@ -5035,14 +5291,19 @@ void setdist(cell *c, int d, cell *from) {
} }
} }
} }
if(c->land == laMirrored || c->land == laMirrorWall || c->land == laMirrorWall2 ||
c->land == laMirrored2)
c->wall = waMirrorWall;
if(c->land == laMirror) { if(c->land == laMirror) {
if((purehepta?pseudohept(c):!ishept(c)) && hrand(5000) < 120 && notDippingFor(itShard)) int freqt = oldmirror ? 1 : 4;
int freqm = (oldmirror || cwt.c->land != laMirror) ? 1 : 30;
if((purehepta?pseudohept(c):!ishept(c)) && hrand(5000/freqt) < 120 && notDippingFor(itShard))
c->wall = hrand(2) ? waMirror : waCloud; c->wall = hrand(2) ? waMirror : waCloud;
else if(ishept(c) && hrand(5000) < 10 * PRIZEMUL) else if(ishept(c) && hrand(5000/freqt) < 10 * PRIZEMUL)
placePrizeOrb(c); placePrizeOrb(c);
else if(hrand(12000) < 8 + items[itShard] + hard) else if(hrand(12000/freqt) < 8 + items[itShard] + hard)
c->monst = moRanger; c->monst = moRanger;
else if(hrand(60000) < 8 + items[itShard] + hard) else if(hrand(60000/freqm) < 8 + items[itShard] + hard)
c->monst = moEagle; c->monst = moEagle;
} }
if(c->land == laGraveyard) { if(c->land == laGraveyard) {
@@ -5186,14 +5447,14 @@ void setdist(cell *c, int d, cell *from) {
bool wchance(int a, int of) { bool wchance(int a, int of) {
of *= 10; of *= 10;
a += yendor::hardness() + items[itHolyGrail] + 1; a += yendor::hardness() + 1;
if(isCrossroads(cwt.c->land)) if(isCrossroads(cwt.c->land))
a+= items[itHyperstone] * 10; a+= items[itHyperstone] * 10;
//if(cwt.c->land == laWhirlwind && !nowhirl) a += items[itWindstone] * 3; //if(cwt.c->land == laWhirlwind && !nowhirl) a += items[itWindstone] * 3;
for(int i=0; i<ittypes; i++) if(itemclass(eItem(i)) == IC_TREASURE) for(int i=0; i<ittypes; i++) if(itemclass(eItem(i)) == IC_TREASURE)
a = max(a, (items[i]-10) / 10); a = max(a, (items[i]-R10) / 10);
return hrand(a+of) < a; return hrand(a+of) < a;
} }
@@ -5298,6 +5559,7 @@ void wandering() {
while(first7 < size(dcal)) { while(first7 < size(dcal)) {
int i = first7 + hrand(size(dcal) - first7); int i = first7 + hrand(size(dcal) - first7);
cell *c = dcal[i]; cell *c = dcal[i];
if(inmirror(c)) continue;
if(smallbounded && !c->item && hrand(5) == 0 && c->land != laHalloween) { if(smallbounded && !c->item && hrand(5) == 0 && c->land != laHalloween) {
if(passable(c, NULL, 0) || euclidland == laKraken) { if(passable(c, NULL, 0) || euclidland == laKraken) {
@@ -5327,7 +5589,7 @@ void wandering() {
continue; continue;
} }
if(ghostcount && !c->monst) { if(ghostcount && !c->monst && !inmirror(c)) {
c->monst = moGhost; c->monst = moGhost;
playSeenSound(c); playSeenSound(c);
ghostcount--; ghostcount--;

View File

@@ -7,12 +7,12 @@
#define GEN_N 2 #define GEN_N 2
#define GEN_O 3 #define GEN_O 3
using namespace std;
#include <map> #include <map>
#include <string> #include <string>
#include <stdio.h> #include <stdio.h>
#include <vector> #include <vector>
#include <stdlib.h> #include <stdlib.h>
using namespace std;
template<class T> int size(T x) { return x.size(); } template<class T> int size(T x) { return x.size(); }

View File

@@ -346,7 +346,7 @@ S("Hyperstone Quest: collect at least %3 %1 in %the2", "Misja alternatywna: znaj
S("Hyperstone Quest completed!", "Misja alternatywna zakończona!") S("Hyperstone Quest completed!", "Misja alternatywna zakończona!")
S("Look for the Orbs of Yendor in Hell or in the Crossroads!", "Szukaj Sfer Yendoru w Piekle albo na Skrzyżowaniu!") S("Look for the Orbs of Yendor in Hell or in the Crossroads!", "Szukaj Sfer Yendoru w Piekle albo na Skrzyżowaniu!")
S("Unlock the Orb of Yendor!", "Otwórz Sferę Yendoru!") S("Unlock the Orb of Yendor!", "Otwórz Sferę Yendoru!")
S("Defeat 100 enemies to access the Graveyard", "Pokonaj 100 przeciwników, by trafić na Cmentarz") S("Defeat %1 enemies to access the Graveyard", "Pokonaj %1 przeciwników, by trafić na Cmentarz")
S("(press ESC during the game to review your quest)", "(naciśnij ESC w trakcie gry, by zobaczyć stan swojej misji)") S("(press ESC during the game to review your quest)", "(naciśnij ESC w trakcie gry, by zobaczyć stan swojej misji)")
S("you have cheated %1 times", "liczba oszustw: %1") S("you have cheated %1 times", "liczba oszustw: %1")
S("%1 turns (%2)", "kolejek: %1 (%2)") S("%1 turns (%2)", "kolejek: %1 (%2)")
@@ -5440,19 +5440,31 @@ S(
"Naciśnij '5' by opuścić podręcznik." "Naciśnij '5' by opuścić podręcznik."
) )
#undef Orb
/* /*
// for 10.0 // for 10.0
*/
S("configure keys/joysticks", "konfiguracja klawiszy/joysticka") // Orb Strategy mode
S("Press F5 or 'o' to try again!", "Naciśnij F5 lub 'o' by spróbować jeszcze raz!") S("Orb Strategy mode", "tryb strategii sfer")
S("peaceful mode", "tryb pokojowy")
S("inventory mode", "tryb inwentarza") S(
S("inventory", "sfery") "You are playing in the Orb Strategy Mode. Collecting treasure "
"gives you access to magical Orb powers. In this mode, "
"unlocking requirements are generally higher, and "
"several quests and lands "
"give you extremely powerful Orbs of the Mirror.\n",
"Grasz w trybie strategii sfer. Zebrane skarby dają Ci "
"dostęp do magicznych mocy. W tym trybie wymagania "
"są generalnie wyższe, i niektóre krainy i misje "
"dają Ci bardzo potężne Sfery Lustra.\n")
S("The treasure gives your magical powers!", "Skarby dają Ci moce magiczne!")
S("Press 'i' to access your magical powers.", "Naciśnij 'i', by użyć mocy.")
S("inventory", "Twoje sfery")
S("mirror what?", "co odbić?") S("mirror what?", "co odbić?")
S("Which orb to use?", "Której Sfery użyć?") S("Which orb to use?", "Której Sfery użyć?")
S("Unlocked by: %1 in %2", "Odblokwane przez: %1 %abl2") S("Unlocked by: %1 in %2", "Odblokowane przez: %1 %abl2")
S(" (next at %1)", " (kolejny przy %1)") S(" (next at %1)", " (kolejny przy %1)")
S(" (next at %1 to %2)", " (kolejny przy %1 do %2)") S(" (next at %1 to %2)", " (kolejny przy %1 do %2)")
S("Number of uses left: %1", "Pozostało użyć: %1") S("Number of uses left: %1", "Pozostało użyć: %1")
@@ -5460,4 +5472,223 @@ S("You mirror %the1.", "Odbijasz %a1.")
S("You need to stand next to a magic mirror or cloud to use %the1.", S("You need to stand next to a magic mirror or cloud to use %the1.",
"Musisz stać przy magicznym lustrze, by odbić %a1.") "Musisz stać przy magicznym lustrze, by odbić %a1.")
S("Each orb type can be mirrored only once.", "Każdy typ sfery może być odbity tylko raz.") S("Each orb type can be mirrored only once.", "Każdy typ sfery może być odbity tylko raz.")
*/
S(
"\n\nIn the Orb Strategy Mode, Orbs of Yendor appear in Hell after "
"you collect 25 Demon Daisies in Hell, in Crossroads/Ocean after you collect 50, "
"and everywhere after you collect 100.",
"\n\nW trybie strategii sfer Sfery Yendoru się pojawiają w Piekle "
"po zebraniu 25 Czarcich Ziel, na Skrzyżowaniu/Oceanie po zebraniu 50, "
"wszędzie po zebraniu 100."
);
S(
"\n\nIn the Orb Strategy Mode, dead orbs are available once you collect "
"10 Necromancer Totems in the Graveyard.",
"\n\nW trybie strategii sfer martwe sfery są dostępne po zdobyciu "
"10 Totemów Nekromanty na Cmentarzu.")
S(
"\n\nIn the Orb Strategy Mode, Orbs of Safety can be gained by "
"collecting Phoenix Feathers in the Land of Eternal Motion. "
"You can also find unlimited Orbs of Safety in the Crossroads "
"and the Ocean (after collecting 25 Phoenix Feathers) "
"and in the Prairie.",
"\n\nW trybie strategii sfer Sfery Bezpieczeństwa mogą być zdobyte "
"przez zbieranie Piór Feniksa w Krainie Wiecznego Ruchu. "
"Można też znaleźć nieograniczone Sfery Bezpieczeństwa na "
"Skrzyżowaniach (po zdobyciu 25 Piór Feniksa) i na Prerii."
)
S(
"\n\nCollect %the1 to gain an extra Orb of the Mirror. "
"You can gain further Orbs of the Mirror by collecting 2, 4, 8...",
"\n\nZdobądź %a1 by dostać dodatkową Sferę Lustra. "
"Więcej Sfer Lustra dostaniesz przy 2, 4, 8..."
)
S(
"\n\nIn the Orb Strategy Mode, the Orb of Luck also "
"significantly increases the frequency of Great Walls, Crossroads IV, "
"and sub-lands.",
"\n\nW trybie strategii sfer Sfera Szczęścia dodatkowo "
"znacznie zwiększa częstotliwość wielkich ścian, Skrzyżowań IV, "
"i podkrain.")
S("\n\nIn the Orb Strategy Mode, each 25 Necromancer's Totems "
"you are given a random offensive Orb.",
"\n\nW trybie strategii sfer każde 25 Totemów Nekromanty "
"daje dodatkową ofensywną sferę.")
S(
"Use Orb of the Mirror to gain copies of one of your Orbs; "
"mirroring weaker Orbs usually yields more copies. "
"It can only be used once per Orb type, "
"and only when you are next to a mirror.",
"Użyj Sfery Lustra by skopiować jedną z Twoich sfer; "
"odbijanie słabszych Sfer zwykle daje więcej kopii. "
"Możesz użyć tylko raz na każdy typ Sfery, "
"i tylko stojąc obok lustra.")
S("Uses to gain: %1", "Dostaniesz użyć: %1")
S("already mirrored", "już było odbijane")
N("your orbs", GEN_F, "Twoje Sfery", "Twoje Sfery", "Twoje Sfery", "Twoje Sfery")
S("Click this to see your orbs.", "Kliknij by zobaczyć Twoje sfery.")
// peaceful mode
S("configure keys/joysticks", "konfiguracja klawiszy/joysticka")
S("peaceful mode", "tryb spokojny")
// config changes
S("Press F5 or 'o' to try again!", "Naciśnij F5 lub 'o' by spróbować jeszcze raz!")
S("aura brightness", "jasność aury")
S("aura smoothening factor", "wygładzanie aury")
S("graphics configuration", "konfiguracja grafiki")
S("special display modes", "specjalne tryby ekranu")
S("openGL mode", "tryb OpenGL")
S("anti-aliasing", "anti-aliasing")
S("line width", "szerokość linii")
S("configure panning and general keys", "skonfiguruj klawisze ogólne")
S("\n\nHint: use 'm' to toggle cells quickly",
"\n\nWsk: użyj 'm' by szybko przestawiać pola");
// cell pattern names
S("football", "piłka nożna")
S("dark rainbow landscape", "ciemna tęcza")
S("field pattern", "wzór pola")
S("field pattern C", "wzór pola C")
S("field pattern D", "wzór pola D")
S("field pattern N", "wzór pola N")
S("field pattern S", "wzór pola S")
S("four triangles", "cztery trójkąty")
S("big triangles: rings", "duże trójkąty: pierścenie")
// missing for the Tutorial
S("tutorial", "podręcznik")
S("This Orb is not compatible with the Tutorial.", "Ta Sfera nie jest kompatybilna z podręcznikiem.")
// local scores
S("turns", "kol")
S("cells", "pola")
S("sort", "sortuj")
S("choose", "wybór")
S("play", "graj")
// draw editor
S("autochoose", "autowybór")
S("c = choose", "c = wybór")
S("b = switch auto", "b = ustaw auto")
// mission screen hints
S(
"If you collect too many treasures in a given land, it will become "
"extremely dangerous. Try other lands once you have enough!",
"Jeśli zbierzesz za dużo skarbów w jednej krainie, stanie się ona "
"bardzo niebezpieczna. Spróbuj pójść do innych krain, gdy masz dość!");
S(
"Remember that you can right click mostly anything for more information.",
"Pamiętaj, że prawie wszystko możesz kliknąć prawym przyciskiem, "
"by dowiedzieć się czegoś na dany temat.")
S("Want to understand the geometry in HyperRogue? Try the Tutorial!",
"Chcesz zrozumieć geometrię w HyperRogue? Obejrzyj Podręcznik!");
S(
"Collecting 25 treasures in a given land may be dangerous, "
"but allows magical Orbs of this land to appear in other places!",
"Zebranie 25 skarbów w jednej krainie może być niebezpieczne, "
"ale powoduje, że magiczne Sfery z tej krainy "
"pojawiają się w pozostałych krainach!")
S(
"Press ESC to view this screen during the game.",
"Naciśnij ESC w czasie gry, by obejrzeć ten ekran.")
S("The 'world overview' shows all the lands in HyperRogue.",
"'Przegląd krain' pokazuje wszystkie krainy w HyperRogue."
)
S("Press 'o' to see all the lands in HyperRogue.",
"Naciśnij 'o', by zobaczyć wszystkie krainy w HyperRogue.")
S(
"Want another type of game? Want more challenge?\n"
"HyperRogue has many special modes and challenges that "
"significantly change the gameplay. Try them!",
"Chcesz spróbować innego typu gry? Dodatkowych wyzwań?\n"
"HyperRogue ma dużo specjalnych trybów, istotnie "
"zmieniających styl gry. Wypróbuj je!")
S(
"Hyperbolic geometry can be shown in many ways.",
"Geometria hiperboliczna może być pokazana na wiele sposobów...")
S(
"You do not want to lose the game from a single mistake?\n"
"Do you want to use the Orbs strategically?\n"
"Try the Orb Strategy mode!",
"Nie chcesz ginąć od jednego błędu? Chcesz używać Sfer strategicznie? "
"Wypróbuj tryb strategii sfer!")
S(
"Do you think you are playing on a ball? "
"This is far from the truth!\n",
"Myślisz, że grasz na sferze? Jest to dalekie od prawdy!\n")
S(
"Did you know that the path you take during the game "
"is usually very close to a straight line?\n",
"Czy wiesz, że droga, którą przebywasz w czasie gry, "
"jest zwykle bardzo zbliżona do linii prostej?")
S("Show me!", "Pokaż!")
S(
"You are %1 cells away from the starting point, or "
"the place where you used an Orb of Safety last time. "
"There are %2 such cells.\n",
"Jesteś %1 kroków od punktu startu, lub miejsca "
"ostatniego użycia Sfery Bezpieczeństwa. "
"Takich pól jest %2.\n")
S("about ", "około ")
S(" (%1 more digits)", " (jeszcze cyfr: %1)")
S("see how it ended", "jak się skończyło")
// other missing/new things
S("\n\nOrb unlocked: %1", "\n\nOdblokowana Sfera: %1")
S("Orb unlocked: %1", "Odblokowana Sfera: %1")
S("\n\nSecondary orb: %1", "\n\nDodatkowa Sfera: %1")
S(" to submerge", " do zanurzenia")
S(" to surface", " do wynurzenia")
S("%The1 says, \"not this place, it looks even worse...\"",
"%The1 mówi, \"nie tu, tu jest jeszcze gorzej...\"")
S("torus", "torus")
S(" (click to use)", " (klik by użyć)")
N("Hall of Mirrors", GEN_F, "Lustrzana Sala", "Lustrzane Sale", "Lustzaną Salę", "w Lustrzanej Sali")
Orb("the Mirror", "Lustra")
N("Reflection", GEN_N, "Odbicie", "Odbicia", "Odbicie", "w Odbiciu")
N("mirror wall", GEN_F, "lustrzana ściana", "lustrzane ściany", "lustrzaną ścianę", "lustrzaną ścianą")
S("This would only move you deeper into the trap!",
"To tylko przeniesie Cię w głąb pułapki!");
#undef Orb

View File

@@ -1150,7 +1150,7 @@ namespace mapeditor {
else if(uni == 'p') { else if(uni == 'p') {
painttype = 6; painttype = 6;
paintwhat_str = "paint"; paintwhat_str = "paint";
dialog::openColorDialog(paintwhat = (painttype ==6 ? paintwhat : 0x808080)); dialog::openColorDialog((unsigned&)(paintwhat = (painttype ==6 ? paintwhat : 0x808080)));
} }
else if(sym == SDLK_F2) { else if(sym == SDLK_F2) {
if(mapstream::saveMap(levelfile.c_str())) if(mapstream::saveMap(levelfile.c_str()))
@@ -1219,7 +1219,7 @@ namespace mapeditor {
int dslayer; int dslayer;
bool coloring; bool coloring;
int colortouse = 0xC0C0C0FF; unsigned int colortouse = 0xC0C0C0FFu;
transmatrix drawtrans, drawtransnew; transmatrix drawtrans, drawtransnew;
@@ -1280,6 +1280,7 @@ namespace mapeditor {
void showDrawEditor() { void showDrawEditor() {
cmode = sm::DRAW; cmode = sm::DRAW;
gamescreen(0);
drawGrid(); drawGrid();
if(!mouseout()) getcstat = '-'; if(!mouseout()) getcstat = '-';
@@ -1882,7 +1883,7 @@ namespace mapeditor {
} }
#ifndef NOEDIT #ifndef NOEDIT
if((cmode == sm::DRAW) && mapeditor::editingShape(group, id)) { if((cmode & sm::DRAW) && mapeditor::editingShape(group, id)) {
/* for(int a=0; a<size(ds.list); a++) { /* for(int a=0; a<size(ds.list); a++) {
hyperpoint P2 = V * ds.list[a]; hyperpoint P2 = V * ds.list[a];
@@ -1913,6 +1914,8 @@ namespace mapeditor {
queuechr(P2, 10, 'x', 0xFF00FF); queuechr(P2, 10, 'x', 0xFF00FF);
} }
if(size(ds.list) == 0) return us;
hyperpoint Plast = V * spin(-2*M_PI/ds.rots) * (ds.sym?Mirror*ds.list[0]:ds.list[size(ds.list)-1]); hyperpoint Plast = V * spin(-2*M_PI/ds.rots) * (ds.sym?Mirror*ds.list[0]:ds.list[size(ds.list)-1]);
int state = 0; int state = 0;
int gstate = 0; int gstate = 0;
@@ -2004,27 +2007,27 @@ namespace linepatterns {
struct { struct {
int id; int id;
const char *lpname; const char *lpname;
int color; unsigned int color;
} patterns[] = { } patterns[] = {
{patTriNet, "triangle grid: not rings", (int) 0xFFFFFF00}, {patTriNet, "triangle grid: not rings", 0xFFFFFF00},
{patTriRings, "triangle grid: rings", (int) 0xFFFFFF00}, {patTriRings, "triangle grid: rings", 0xFFFFFF00},
{patHepta, "heptagonal grid", (int) 0x0000C000}, {patHepta, "heptagonal grid", 0x0000C000},
{patRhomb, "rhombic tesselation", (int) 0x0000C000}, {patRhomb, "rhombic tesselation", 0x0000C000},
{patTrihepta, "triheptagonal tesselation", (int) 0x0000C000}, {patTrihepta, "triheptagonal tesselation", 0x0000C000},
{patNormal, "normal tesselation", (int) 0x0000C000}, {patNormal, "normal tesselation", 0x0000C000},
{patBigTriangles, "big triangular grid", (int) 0x00606000}, {patBigTriangles, "big triangular grid", 0x00606000},
{patBigRings, "big triangles: rings", (int) 0x0000C000}, {patBigRings, "big triangles: rings", 0x0000C000},
{patTree, "underlying tree", (int) 0x00d0d000}, {patTree, "underlying tree", 0x00d0d000},
{patAltTree, "circle/horocycle tree", (int) 0xd000d000}, {patAltTree, "circle/horocycle tree", 0xd000d000},
{patZebraTriangles, "zebra triangles", (int) 0x40FF4000}, {patZebraTriangles, "zebra triangles", 0x40FF4000},
{patZebraLines, "zebra lines", (int) 0xFF000000}, {patZebraLines, "zebra lines", 0xFF000000},
{patVine, "vineyard pattern", (int) 0x8438A400}, {patVine, "vineyard pattern", 0x8438A400},
{patPalacelike, "firewall lines", (int) 0xFF400000}, {patPalacelike, "firewall lines", 0xFF400000},
{patPalace, "firewall lines: Palace", (int) 0xFFD50000}, {patPalace, "firewall lines: Palace", 0xFFD50000},
{patPower, "firewall lines: Power", (int) 0xFFFF0000}, {patPower, "firewall lines: Power", 0xFFFF0000},
{0, NULL, 0} {0, NULL, 0}
}; };

View File

@@ -401,7 +401,7 @@ void showChangeMode() {
dialog::addBoolItem(XLAT("heptagonal mode"), (purehepta), '7'); dialog::addBoolItem(XLAT("heptagonal mode"), (purehepta), '7');
dialog::addBoolItem(XLAT("Chaos mode"), (chaosmode), 'C'); dialog::addBoolItem(XLAT("Chaos mode"), (chaosmode), 'C');
dialog::addBoolItem(XLAT("peaceful mode"), (chaosmode), 'p'); dialog::addBoolItem(XLAT("peaceful mode"), (chaosmode), 'p');
dialog::addBoolItem(XLAT("inventory mode"), (inv::on), 'i'); dialog::addBoolItem(XLAT("Orb Strategy mode"), (inv::on), 'i');
dialog::addBoolItem(XLAT("pure tactics mode"), (tactic::on), 't'); dialog::addBoolItem(XLAT("pure tactics mode"), (tactic::on), 't');
dialog::addBoolItem(XLAT("Yendor Challenge"), (yendor::on), 'y'); dialog::addBoolItem(XLAT("Yendor Challenge"), (yendor::on), 'y');
dialog::addBoolItem(XLAT("%1 Challenge", moPrincess), (princess::challenge), 'P'); dialog::addBoolItem(XLAT("%1 Challenge", moPrincess), (princess::challenge), 'P');

View File

@@ -343,6 +343,7 @@ void castLightningBolt(cellwalker lig) {
if(lig.c->mov[lig.spin] == NULL) break; if(lig.c->mov[lig.spin] == NULL) break;
cwstep(lig); cwstep(lig);
if(inmirror(lig)) lig = mirror::reflect(lig);
cell *c = lig.c; cell *c = lig.c;
@@ -1188,3 +1189,79 @@ eItem targetRangedOrb(cell *c, orbAction a) {
return eItem(-1); return eItem(-1);
} }
int orbcharges(eItem it) {
switch(it) {
case itRevolver: //pickup-key
return 6;
case itOrbShield:
return inv::on ? 30 : 20;
case itOrbDiscord:
return inv::on ? 46 : 23;
case itOrbLove:
case itOrbUndeath:
case itOrbSpeed: //"pickup-speed");
case itOrbInvis:
case itOrbAether:
return 30;
case itOrbWinter: // "pickup-winter"
return inv::on ? 45 : 30;
break;
case itOrbBeauty:
case itOrbEmpathy:
case itOrbFreedom:
return 40;
case itOrbFrog:
case itOrbDash:
return 45;
case itOrb37:
case itOrbEnergy:
return 50;
case itOrbRecall:
case itOrbNature:
case itOrbStone:
case itOrbStunning:
case itOrbLuck:
return 60;
case itOrbWater:
case itOrbMatter:
case itOrbHorns:
case itOrbBull:
case itOrbShell:
return 66;
case itOrbTime:
case itOrbSpace:
case itOrbThorns:
case itOrbLightning:
case itOrbFlash:
case itOrbIllusion:
case itOrbPsi:
case itOrbDigging:
case itOrbTeleport:
return 77;
case itOrbDomination:
return 90;
case itOrbSummon:
return 120;
case itOrbSword:
return 60 + 30 * multi::activePlayers();
case itOrbSword2:
return 40 + 20 * multi::activePlayers();
case itOrbFish:
return 20 + 10 * multi::activePlayers();
case itOrbFire:
return sphere ? 3 : 30;
case itOrbDragon:
return sphere ? 10 : 77;
default:
return 0;
}
}
bool isShmupLifeOrb(eItem it) {
return
it == itOrbLife || it == itOrbFriend ||
it == itOrbNature || it == itOrbEmpathy ||
it == itOrbUndeath || it == itOrbLove ||
it == itOrbDomination;
}

View File

@@ -630,10 +630,11 @@ hpcshape
shBarrowFloor[3], shBarrowFloor[3],
shTriheptaFloor[11], shTriheptaFloor2[2], shTriheptaEuc[3], shTriheptaFloor[11], shTriheptaFloor2[2], shTriheptaEuc[3],
shCross, shGiantStar[2], shLake, shMirror, shCross, shGiantStar[2], shLake, shMirror,
shHalfFloor[3], shHalfMirror[3],
shGem[2], shStar, shDisk, shDiskT, shDiskS, shDiskM, shDiskSq, shRing, shGem[2], shStar, shDisk, shDiskT, shDiskS, shDiskM, shDiskSq, shRing,
shEgg, shEgg,
shSpikedRing, shTargetRing, shSawRing, shGearRing, shPeaceRing, shHeptaRing, shSpikedRing, shTargetRing, shSawRing, shGearRing, shPeaceRing, shHeptaRing,
shSpearRing, shSpearRing, shLoveRing,
shDaisy, shTriangle, shNecro, shStatue, shKey, shDaisy, shTriangle, shNecro, shStatue, shKey,
shGun, shGun,
shFigurine, shTreat, shFigurine, shTreat,
@@ -1112,6 +1113,36 @@ void buildpolys() {
} }
hpcpush(ddi(0, crossf * .25) * C0); hpcpush(ddi(0, crossf * .25) * C0);
/* three nice spikes
bshape(shLoveRing, PPR_ITEM);
for(int i=0; i<=S84; i+=3)
hpcpush(ddi(i, crossf * .25) * C0);
for(int i=S84; i>=0; i--) {
int j = i*3 % S84;
int d = j - S42;
if(d<0) d = -d;
d = 8 - 2 * d;
if(d<0) d = 0;
hpcpush(ddi(i, crossf * (.3 + .02 * d)) * C0);
}
hpcpush(ddi(0, crossf * .25) * C0);
*/
bshape(shLoveRing, PPR_ITEM);
for(int i=0; i<=S84; i+=3)
hpcpush(ddi(i, crossf * .25) * C0);
for(int i=S84; i>=0; i--) {
int j = i*3 % S84;
double d = j - S42;
d = d / 9;
if(d<0) d = -d;
d = 8 - 2 * d;
if(d<0) d = 0;
if(d >= 6) d -= (d-6)/3;
hpcpush(ddi(i, crossf * (.27 + .02 * d)) * C0);
}
hpcpush(ddi(0, crossf * .25) * C0);
bshape(shSawRing, PPR_ITEM); bshape(shSawRing, PPR_ITEM);
for(int i=0; i<=S84; i+=3) for(int i=0; i<=S84; i+=3)
hpcpush(ddi(i, crossf * .25) * C0); hpcpush(ddi(i, crossf * .25) * C0);
@@ -1242,6 +1273,13 @@ void buildpolys() {
bshape(shButterflyFloor[0], PPR_FLOOR, scalef*spzoom6, 325); bshape(shButterflyFloor[0], PPR_FLOOR, scalef*spzoom6, 325);
bshape(shButterflyFloor[1], PPR_FLOOR, scalef*spzoomd7, 326); bshape(shButterflyFloor[1], PPR_FLOOR, scalef*spzoomd7, 326);
bshape(shHalfFloor[0], PPR_FLOOR, scalef*spzoom6, 329);
bshape(shHalfFloor[1], PPR_FLOOR, scalef*spzoom6, 327);
bshape(shHalfFloor[2], PPR_FLOOR, scalef*spzoom6, 331);
bshape(shHalfMirror[0], PPR_WALL, scalef*spzoom6, 330);
bshape(shHalfMirror[1], PPR_WALL, scalef*spzoom6, 328);
bshape(shHalfMirror[2], PPR_WALL, scalef*spzoom6, 332);
bshape(shLeafFloor[0], PPR_FLOOR_DRAGON, 1*spzoom6, 313); bshape(shLeafFloor[0], PPR_FLOOR_DRAGON, 1*spzoom6, 313);
bshape(shLeafFloor[1], PPR_FLOOR_DRAGON, 1*spzoomd7, 314); bshape(shLeafFloor[1], PPR_FLOOR_DRAGON, 1*spzoomd7, 314);
@@ -2009,6 +2047,10 @@ void queuecircle(const transmatrix& V, double size, int col) {
queuecircle(xc, yc, int(sqrt(squar(xc-xs)+squar(yc-ys)) * size), col); queuecircle(xc, yc, int(sqrt(squar(xc-xs)+squar(yc-ys)) * size), col);
} }
void queuemarkerat(const transmatrix& V, int col) {
queuepolyat(V, shTriangle, col, PPR_LINE);
}
long double polydata[] = { long double polydata[] = {
// shStarFloor[0] (6x1) // shStarFloor[0] (6x1)
NEWSHAPE, 1,6,1, 0.267355,0.153145, 0.158858,0.062321, 0.357493,-0.060252, NEWSHAPE, 1,6,1, 0.267355,0.153145, 0.158858,0.062321, 0.357493,-0.060252,
@@ -2660,6 +2702,20 @@ NEWSHAPE, 325, 3, 1, 0.003906,-0.017741, -0.005665,-0.023874, -0.001296,-0.05925
// shButterflyFloor[1] // shButterflyFloor[1]
NEWSHAPE, 326, 7, 1, -0.199281,-0.117040, -0.202870,-0.110023, -0.247957,-0.128116, -0.298501,0.006170, -0.226086,0.045756, -0.061553,0.006677, -0.059070,0.020733, -0.217691,0.072727, NEWSHAPE, 326, 7, 1, -0.199281,-0.117040, -0.202870,-0.110023, -0.247957,-0.128116, -0.298501,0.006170, -0.226086,0.045756, -0.061553,0.006677, -0.059070,0.020733, -0.217691,0.072727,
// halfhepta
NEWSHAPE, 327, 1, 1, 0.335252,0.044112, 0.225849,0.283419, -0.081851,0.347313, -0.325491,0.159424, -0.323584,0.033019,
// hepta mirror
NEWSHAPE, 328, 1, 2, -0.315398,0.010102, 0.568278,0.010645,
// halfhex
NEWSHAPE, 329, 1, 1, 0.263160,0.022375, 0.265137,0.152727, 0.000228,0.306625, -0.261438,0.151819, -0.263489,0.020161,
// halfhex mirror
NEWSHAPE, 330, 1, 2, 0.262597,0.018558, -0.261563,0.016306,
NEWSHAPE, 331, 1, 1, 0.148337,0.215535, 0.267624,0.150567, 0.262973,0.019662, 0.033981,0.019835,
// 0 0 1 [000000]
NEWSHAPE, 332, 6, 2, -0.016778,-0.008267, -0.261607,-0.011992,
NEWSHAPE NEWSHAPE
}; };

View File

@@ -19,13 +19,6 @@ string timeline() {
XLAT("%1 turns (%2)", its(turncount), buf); XLAT("%1 turns (%2)", its(turncount), buf);
} }
struct hint {
time_t last;
function<bool()> usable;
function<void()> display;
function<void()> action;
};
void noaction() {} void noaction() {}
function<void()> cancel = noaction; function<void()> cancel = noaction;
@@ -58,7 +51,7 @@ hint hints[] = {
}, },
[]() { []() {
dialog::addHelp(XLAT( dialog::addHelp(XLAT(
"If you collect too many treasures in a given land, monsters will be " "If you collect too many treasures in a given land, it will become "
"extremely dangerous. Try other lands once you have enough!")); "extremely dangerous. Try other lands once you have enough!"));
}, },
noaction}, noaction},
@@ -97,7 +90,7 @@ hint hints[] = {
[]() { return !inv::on; }, []() { return !inv::on; },
[]() { []() {
dialog::addHelp(XLAT( dialog::addHelp(XLAT(
"Collecting 25 treasures in a given land is dangerous, " "Collecting 25 treasures in a given land may be dangerous, "
"but allows magical Orbs of this land to appear in other places!" "but allows magical Orbs of this land to appear in other places!"
)); ));
}, },
@@ -136,7 +129,7 @@ hint hints[] = {
0, 0,
[]() { return !canmove; }, []() { return !canmove; },
[]() { []() {
dialog::addInfo(XLAT( dialog::addHelp(XLAT(
"Want another type of game? Want more challenge?\n" "Want another type of game? Want more challenge?\n"
"HyperRogue has many special modes and challenges that " "HyperRogue has many special modes and challenges that "
"significantly change the gameplay. Try them!" "significantly change the gameplay. Try them!"
@@ -174,8 +167,6 @@ hint hints[] = {
dialog::addBreak(50); dialog::addBreak(50);
#ifdef INF #ifdef INF
dialog::addItem(XLAT("Orb Strategy mode"), 'z'); dialog::addItem(XLAT("Orb Strategy mode"), 'z');
#else
dialog::addItem(XLAT("(paid versions only)"), 'z');
#endif #endif
}, },
[]() { []() {
@@ -193,7 +184,7 @@ hint hints[] = {
"This is far from the truth!\n" "This is far from the truth!\n"
)); ));
dialog::addBreak(50); dialog::addBreak(50);
dialog::addItem(XLAT("Hypersian Rug mode"), 'z'); dialog::addItem(XLAT("hypersian rug mode"), 'z');
}, },
[] () { [] () {
popScreen(); popScreen();
@@ -217,7 +208,7 @@ hint hints[] = {
[]() { []() {
dialog::addHelp(XLAT( dialog::addHelp(XLAT(
"Did you know that the path you take during the game " "Did you know that the path you take during the game "
"is very close to a straight line?\n" "is usually very close to a straight line?\n"
)); ));
dialog::addBreak(50); dialog::addBreak(50);
dialog::addItem(XLAT("Show me!"), 'z'); dialog::addItem(XLAT("Show me!"), 'z');
@@ -299,6 +290,10 @@ hint hints[] = {
int hinttoshow; int hinttoshow;
string contstr() {
return XLAT(canmove ? "continue" : "see how it ended");
}
void showMission() { void showMission() {
cmode = sm::DOTOUR | sm::MISSION | sm::CENTER; cmode = sm::DOTOUR | sm::MISSION | sm::CENTER;
@@ -439,9 +434,11 @@ void showMission() {
#endif #endif
} }
else { else {
dialog::addItem(XLAT(canmove ? "continue" : "see how it ended"), SDLK_ESCAPE); dialog::addItem(contstr(), SDLK_ESCAPE);
dialog::addItem(XLAT("main menu"), 'v'); dialog::addItem(XLAT("main menu"), 'v');
dialog::addItem(XLAT("restart"), SDLK_F5); dialog::addItem(XLAT("restart"), SDLK_F5);
if(inv::on && items[itInventory])
dialog::addItem(XLAT("inventory"), 'i');
#ifndef MOBILE #ifndef MOBILE
dialog::addItem(XLAT(quitsaves() ? "save" : "quit"), SDLK_F10); dialog::addItem(XLAT(quitsaves() ? "save" : "quit"), SDLK_F10);
#endif #endif
@@ -469,7 +466,7 @@ void handleKeyQuit(int sym, int uni) {
if(sym == SDLK_RETURN || sym == SDLK_KP_ENTER || sym == SDLK_F10) quitmainloop = true; if(sym == SDLK_RETURN || sym == SDLK_KP_ENTER || sym == SDLK_F10) quitmainloop = true;
else if(uni == 'r' || sym == SDLK_F5) { else if(uni == 'r' || sym == SDLK_F5) {
restartGame(), popScreen(); restartGame();
msgs.clear(); msgs.clear();
} }
else if(sym == SDLK_UP || sym == SDLK_KP8 || sym == PSEUDOKEY_WHEELUP) msgscroll++; else if(sym == SDLK_UP || sym == SDLK_KP8 || sym == PSEUDOKEY_WHEELUP) msgscroll++;
@@ -524,5 +521,7 @@ void showMissionScreen() {
} }
hints[hinttoshow].last = time(NULL); hints[hinttoshow].last = time(NULL);
} }
dialog::highlight_text = contstr();
} }

View File

@@ -42,7 +42,7 @@ bool glew = false;
bool renderonce = false; bool renderonce = false;
bool rendernogl = false; bool rendernogl = false;
int texturesize = 1024; int texturesize = 1024;
double scale = 1; ld scale = 1;
int queueiter, qvalid, dt; int queueiter, qvalid, dt;
double err; double err;

View File

@@ -39,6 +39,7 @@ bool isHardcore(score *S) {
int modediff(score *S) { int modediff(score *S) {
int diff = 0; int diff = 0;
eGeometry g = (eGeometry) S->box[116]; eGeometry g = (eGeometry) S->box[116];
if(S->box[306] != inv::on) diff += 4;
if(S->box[238]) g = gSphere; if(S->box[238]) g = gSphere;
if(S->box[239]) g = gElliptic; if(S->box[239]) g = gElliptic;
if(max(S->box[197], 1) != multi::players) diff += 8; if(max(S->box[197], 1) != multi::players) diff += 8;
@@ -64,6 +65,7 @@ string modedesc(score *S) {
if(S->box[196]) s += "/C"; if(S->box[196]) s += "/C";
if(S->box[119]) s += "/s"; if(S->box[119]) s += "/s";
if(S->box[197] > 1) s += "/P" + its(S->box[197]); if(S->box[197] > 1) s += "/P" + its(S->box[197]);
if(S->box[306]) s += "/i";
if(isHardcore(S)) s += "/h"; if(isHardcore(S)) s += "/h";
return s; return s;
} }
@@ -301,7 +303,7 @@ void load() {
for(int i=boxid; i<MAXBOX; i++) sc.box[i] = 0; for(int i=boxid; i<MAXBOX; i++) sc.box[i] = 0;
if(sc.ver >= "4.4") { if(!verless(sc.ver, "4.4")) {
sc.box[0] = sc.box[65]; sc.box[0] = sc.box[65];
// the first executable on Steam included a corruption // the first executable on Steam included a corruption
if(sc.box[65] > 1420000000 && sc.box[65] < 1430000000) { if(sc.box[65] > 1420000000 && sc.box[65] < 1430000000) {

233
shmup.cpp
View File

@@ -61,6 +61,9 @@ namespace multi {
double mdx[MAXPLAYER], mdy[MAXPLAYER]; // movement vector for the next move double mdx[MAXPLAYER], mdy[MAXPLAYER]; // movement vector for the next move
static const int CMDS = 15;
static const int CMDS_PAN = 11;
const char* playercmds_shmup[15] = { const char* playercmds_shmup[15] = {
"forward", "backward", "turn left", "turn right", "forward", "backward", "turn left", "turn right",
"move up", "move right", "move down", "move left", "move up", "move right", "move down", "move left",
@@ -77,13 +80,15 @@ namespace multi {
"" ""
}; };
const char* pancmds[7] = { const char* pancmds[11] = {
"pan up", "pan right", "pan down", "pan left", "pan up", "pan right", "pan down", "pan left",
"rotate left", "rotate right", "home" "rotate left", "rotate right", "home",
"world overview", "review your quest", "inventory", "main menu"
}; };
#define SHMUPAXES_BASE 4 #define SHMUPAXES_BASE 4
#define SHMUPAXES ((SHMUPAXES_BASE) + 4 * (MAXPLAYER)) #define SHMUPAXES ((SHMUPAXES_BASE) + 4 * (MAXPLAYER))
#define SHMUPAXES_CUR ((SHMUPAXES_BASE) + 4 * vid.scfg.players)
const char* axemodes[SHMUPAXES] = { const char* axemodes[SHMUPAXES] = {
"do nothing", "do nothing",
@@ -122,44 +127,6 @@ const char* axemodes[SHMUPAXES] = {
int centerplayer = -1; int centerplayer = -1;
#ifndef NOCONFIG
void saveConfig(FILE *f) {
fprintf(f, "%d %d %d", VERNUM, vid.scfg.players, alwaysuse);
for(int i=0; i<512; i++) fprintf(f, " %d", vid.scfg.keyaction[i]);
for(int i=0; i<MAXJOY; i++) for(int j=0; j<MAXBUTTON; j++) fprintf(f, " %d", vid.scfg.joyaction[i][j]);
for(int i=0; i<MAXJOY; i++) for(int j=0; j<MAXAXE; j++) fprintf(f, " %d", vid.scfg.axeaction[i][j]);
for(int i=0; i<MAXJOY; i++) for(int j=0; j<MAXAXE; j++) fprintf(f, " %d", vid.scfg.deadzoneval[i][j]);
for(int i=0; i<MAXJOY; i++) for(int j=0; j<MAXHAT; j++) for(int k=0; k<4; k++)
fprintf(f, " %d", vid.scfg.hataction[i][j][k]);
fprintf(f, "\n");
for(int i=0; i<MAXPLAYER; i++) savecs(f, scs[i], VERNUM);
}
void scanchar(FILE *f, char& c) {
int i = c;
int err = fscanf(f, "%d", &i);
if(err == 1) c = i;
}
void loadConfig(FILE *f) {
int xvernum;
int err = fscanf(f, "%d %d", &xvernum, &vid.scfg.players);
if(vid.scfg.players < 1 || vid.scfg.players > MAXPLAYER)
vid.scfg.players = 1;
if(err != 2) return;
if(xvernum >= 8990) { int b=alwaysuse; err=fscanf(f, " %d", &b); alwaysuse = b; }
for(int i=0; i<512; i++) scanchar(f, vid.scfg.keyaction[i]);
for(int i=0; i<MAXJOY; i++) for(int j=0; j<MAXBUTTON; j++) scanchar(f, vid.scfg.joyaction[i][j]);
for(int i=0; i<MAXJOY; i++) for(int j=0; j<MAXAXE; j++) scanchar(f, vid.scfg.axeaction[i][j]);
if(xvernum >= 9007)
for(int i=0; i<MAXJOY; i++) for(int j=0; j<MAXAXE; j++) err = fscanf(f, " %d", &vid.scfg.deadzoneval[i][j]);
for(int i=0; i<MAXJOY; i++) for(int j=0; j<MAXHAT; j++) for(int k=0; k<4; k++)
scanchar(f, vid.scfg.hataction[i][j][k]);
for(int i=0; i<(xvernum < 8990 ? 4 : 7); i++) loadcs(f, scs[i], xvernum);
}
#endif
int shmupnumkeys; int shmupnumkeys;
const char** shmupcmdtable; const char** shmupcmdtable;
@@ -213,15 +180,16 @@ void handleConfig(int sym, int uni);
void showShmupConfig() { void showShmupConfig() {
#ifndef NOSDL #ifndef NOSDL
cmode = sm::SHMUPCONFIG;
int sc = vid.scfg.subconfig; int sc = vid.scfg.subconfig;
if(sc == 1 || sc == 2 || sc == 4 || sc == 5 || sc == 6 || sc == 7 || sc == 8) { if(sc == 1 || sc == 2 || sc == 4 || sc == 5 || sc == 6 || sc == 7 || sc == 8) {
shmupnumkeys = 15; shmupnumkeys = CMDS;
shmupcmdtable = shmup::on ? playercmds_shmup : playercmds_turn; shmupcmdtable = shmup::on ? playercmds_shmup : playercmds_turn;
} }
else if(sc == 3) { else if(sc == 3) {
shmupnumkeys = 7; shmupnumkeys = CMDS_PAN;
shmupcmdtable = pancmds; shmupcmdtable = pancmds;
} }
else if(sc == SCJOY) { else if(sc == SCJOY) {
@@ -304,7 +272,7 @@ void showShmupConfig() {
else dialog::addBreak(100); else dialog::addBreak(100);
if(shmupcfg || multi::alwaysuse || vid.scfg.players > 1) if(shmupcfg || multi::alwaysuse || vid.scfg.players > 1)
dialog::addItem(XLAT("configure panning"), 'p'); dialog::addItem(XLAT("configure panning and general keys"), 'p');
else dialog::addBreak(100); else dialog::addBreak(100);
if(numsticks > 0) { if(numsticks > 0) {
@@ -442,8 +410,8 @@ help += XLAT("This menu can be also used to configure keys.\n\n");
else { else {
int v = (*axeconfigs[xuni - 'a']); int v = (*axeconfigs[xuni - 'a']);
v += (shiftmul>0?1:-1); v += (shiftmul>0?1:-1);
v += SHMUPAXES; v += SHMUPAXES_CUR;
v %= SHMUPAXES; v %= SHMUPAXES_CUR;
(*axeconfigs[xuni - 'a']) = v; (*axeconfigs[xuni - 'a']) = v;
} }
} }
@@ -494,63 +462,7 @@ bool notremapped(int sym) {
return k > multi::players; return k > multi::players;
} }
void handleInput(int delta) { #ifndef NOCONFIG
#ifndef NOSDL
double d = delta / 500.;
Uint8 *keystate = SDL_GetKeyState(NULL);
for(int i=0; i<NUMACT; i++)
lactionpressed[i] = actionspressed[i],
actionspressed[i] = 0;
for(int i=0; i<SHMUPAXES; i++) axespressed[i] = 0;
for(int i=0; i<SDLK_LAST; i++) if(keystate[i])
pressaction(vid.scfg.keyaction[i]);
for(int j=0; j<numsticks; j++) {
for(int b=0; b<SDL_JoystickNumButtons(sticks[j]) && b<MAXBUTTON; b++)
if(SDL_JoystickGetButton(sticks[j], b))
pressaction(vid.scfg.joyaction[j][b]);
for(int b=0; b<SDL_JoystickNumHats(sticks[j]) && b<MAXHAT; b++) {
int stat = SDL_JoystickGetHat(sticks[j], b);
if(stat & SDL_HAT_UP) pressaction(vid.scfg.hataction[j][b][0]);
if(stat & SDL_HAT_RIGHT) pressaction(vid.scfg.hataction[j][b][1]);
if(stat & SDL_HAT_DOWN) pressaction(vid.scfg.hataction[j][b][2]);
if(stat & SDL_HAT_LEFT) pressaction(vid.scfg.hataction[j][b][3]);
}
for(int b=0; b<SDL_JoystickNumAxes(sticks[j]) && b<MAXAXE; b++) {
int value = SDL_JoystickGetAxis(sticks[j], b);
int dz = vid.scfg.deadzoneval[j][b];
if(value > dz) value -= dz; else if(value < -dz) value += dz;
else value = 0;
axespressed[vid.scfg.axeaction[j][b] % SHMUPAXES] += value;
}
}
if(keystate[SDLK_LCTRL] || keystate[SDLK_RCTRL]) d /= 5;
double panx =
actionspressed[49] - actionspressed[51] + axespressed[2] / 32000.0;
double pany =
actionspressed[50] - actionspressed[48] + axespressed[3] / 20000.0;
double panspin = actionspressed[52] - actionspressed[53] + axespressed[1] / 20000.0;
if(actionspressed[54]) { centerplayer = -1, playermoved = true; centerpc(100); }
if(panx || pany || panspin) {
View = xpush(-panx * d) * ypush(-pany * d) * spin(panspin * d) * View;
playermoved = false;
}
#endif
}
int tableid[7] = {1, 2, 4, 5, 6, 7, 8};
void initConfig() { void initConfig() {
vid.scfg.players = 1; vid.scfg.players = 1;
@@ -650,8 +562,125 @@ void initConfig() {
multi::scs[4].uicolor = 0xC000C0FF; multi::scs[4].uicolor = 0xC000C0FF;
multi::scs[5].uicolor = 0x00C0C0FF; multi::scs[5].uicolor = 0x00C0C0FF;
multi::scs[6].uicolor = 0xC0C0C0FF; multi::scs[6].uicolor = 0xC0C0C0FF;
addsaver(vid.scfg.players, "mode-number of players");
addsaver(alwaysuse, "use configured keys");
// unfortunately we cannot use key names here because SDL is not yet initialized
for(int i=0; i<512; i++)
addsaver(vid.scfg.keyaction[i], string("key:")+its(i));
for(int i=0; i<MAXJOY; i++) {
string pre = "joystick "+cts('A'+i);
for(int j=0; j<MAXBUTTON; j++)
addsaver(vid.scfg.joyaction[i][j], pre+"-B"+its(j));
for(int j=0; j<MAXAXE; j++) {
addsaver(vid.scfg.axeaction[i][j], pre+" axis "+its(j));
addsaver(vid.scfg.deadzoneval[i][j], pre+" deadzone "+its(j));
}
for(int j=0; j<MAXHAT; j++) for(int k=0; k<4; k++) {
addsaver(vid.scfg.hataction[i][j][k], pre+" hat "+its(j)+" "+"URDL"[k]);
}
}
for(int i=0; i<7; i++) addsaver(multi::scs[i], "player"+its(i));
} }
void scanchar(FILE *f, char& c) {
int i = c;
int err = fscanf(f, "%d", &i);
if(err == 1) c = i;
}
void loadConfig(FILE *f) {
int xvernum;
int err = fscanf(f, "%d %d", &xvernum, &vid.scfg.players);
if(vid.scfg.players < 1 || vid.scfg.players > MAXPLAYER)
vid.scfg.players = 1;
if(err != 2) return;
if(xvernum >= 8990) { int b=alwaysuse; err=fscanf(f, " %d", &b); alwaysuse = b; }
for(int i=0; i<512; i++) scanchar(f, vid.scfg.keyaction[i]);
for(int i=0; i<MAXJOY; i++) for(int j=0; j<MAXBUTTON; j++) scanchar(f, vid.scfg.joyaction[i][j]);
for(int i=0; i<MAXJOY; i++) for(int j=0; j<MAXAXE; j++) scanchar(f, vid.scfg.axeaction[i][j]);
if(xvernum >= 9007)
for(int i=0; i<MAXJOY; i++) for(int j=0; j<MAXAXE; j++) err = fscanf(f, " %d", &vid.scfg.deadzoneval[i][j]);
for(int i=0; i<MAXJOY; i++) for(int j=0; j<MAXHAT; j++) for(int k=0; k<4; k++)
scanchar(f, vid.scfg.hataction[i][j][k]);
for(int i=0; i<(xvernum < 8990 ? 4 : 7); i++) loadcs(f, scs[i], xvernum);
}
#endif
void handleInput(int delta) {
#ifndef NOSDL
double d = delta / 500.;
Uint8 *keystate = SDL_GetKeyState(NULL);
for(int i=0; i<NUMACT; i++)
lactionpressed[i] = actionspressed[i],
actionspressed[i] = 0;
for(int i=0; i<SHMUPAXES; i++) axespressed[i] = 0;
for(int i=0; i<SDLK_LAST; i++) if(keystate[i])
pressaction(vid.scfg.keyaction[i]);
for(int j=0; j<numsticks; j++) {
for(int b=0; b<SDL_JoystickNumButtons(sticks[j]) && b<MAXBUTTON; b++)
if(SDL_JoystickGetButton(sticks[j], b))
pressaction(vid.scfg.joyaction[j][b]);
for(int b=0; b<SDL_JoystickNumHats(sticks[j]) && b<MAXHAT; b++) {
int stat = SDL_JoystickGetHat(sticks[j], b);
if(stat & SDL_HAT_UP) pressaction(vid.scfg.hataction[j][b][0]);
if(stat & SDL_HAT_RIGHT) pressaction(vid.scfg.hataction[j][b][1]);
if(stat & SDL_HAT_DOWN) pressaction(vid.scfg.hataction[j][b][2]);
if(stat & SDL_HAT_LEFT) pressaction(vid.scfg.hataction[j][b][3]);
}
for(int b=0; b<SDL_JoystickNumAxes(sticks[j]) && b<MAXAXE; b++) {
int value = SDL_JoystickGetAxis(sticks[j], b);
int dz = vid.scfg.deadzoneval[j][b];
if(value > dz) value -= dz; else if(value < -dz) value += dz;
else value = 0;
axespressed[vid.scfg.axeaction[j][b] % SHMUPAXES] += value;
}
}
if(keystate[SDLK_LCTRL] || keystate[SDLK_RCTRL]) d /= 5;
double panx =
actionspressed[49] - actionspressed[51] + axespressed[2] / 32000.0;
double pany =
actionspressed[50] - actionspressed[48] + axespressed[3] / 20000.0;
double panspin = actionspressed[52] - actionspressed[53] + axespressed[1] / 20000.0;
if(actionspressed[54]) { centerplayer = -1, playermoved = true; centerpc(100); }
if(actionspressed[55] && !lactionpressed[55])
pushScreen(showOverview);
if(actionspressed[56] && !lactionpressed[56])
showMissionScreen();
#ifdef INV
if(actionspressed[57] && !lactionpressed[57])
pushScreen(inv::show);
#endif
if(actionspressed[58] && !lactionpressed[58])
pushScreen(showMainMenu);
if(panx || pany || panspin) {
View = xpush(-panx * d) * ypush(-pany * d) * spin(panspin * d) * View;
playermoved = false;
}
#endif
}
int tableid[7] = {1, 2, 4, 5, 6, 7, 8};
void leaveGame(int i) { void leaveGame(int i) {
multi::player[i].c = NULL; multi::player[i].c = NULL;
multi::deaths[i]++; multi::deaths[i]++;

View File

@@ -15,6 +15,13 @@ bool timerstopped;
int savecount; int savecount;
bool showoff = false, doCross = false; bool showoff = false, doCross = false;
bool verless(const string& v, const string& cmp) {
// no checks exists for versions greater than 10.0 yet
if(isdigit(v[0]) && isdigit(v[1]))
return false;
return v < cmp;
}
// initialize the game // initialize the game
void initgame() { void initgame() {
DEBB(DF_INIT, (debugfile,"initGame\n")); DEBB(DF_INIT, (debugfile,"initGame\n"));
@@ -167,6 +174,8 @@ void initgame() {
makeEmpty(cwt.c); makeEmpty(cwt.c);
} }
princess::squeaked = false;
if(!safety) { if(!safety) {
usedSafety = false; usedSafety = false;
timerstart = time(NULL); turncount = 0; rosewave = 0; rosephase = 0; timerstart = time(NULL); turncount = 0; rosewave = 0; rosephase = 0;
@@ -254,8 +263,8 @@ void initgame() {
bool havesave = true; bool havesave = true;
#ifndef NOSAVE #ifndef NOSAVE
#define MAXBOX 300 #define MAXBOX 500
#define POSSCORE 258 // update this when new boxes are added! #define POSSCORE 308 // update this when new boxes are added!
struct score { struct score {
string ver; string ver;
@@ -275,7 +284,7 @@ void applyBox(int& t) {
else boxid++; else boxid++;
} }
void applyBoxNum(int& i, string name = "") { void applyBoxNum(int& i, string name) {
fakebox[boxid] = (name == ""); fakebox[boxid] = (name == "");
boxname[boxid] = name; boxname[boxid] = name;
monsbox[boxid] = false; monsbox[boxid] = false;
@@ -313,6 +322,31 @@ void applyBoxI(eItem it, bool f = false) {
else applyBox(items[it]); else applyBox(items[it]);
} }
vector<eItem> invorb;
void addinv(eItem it) {
invorb.push_back(it);
}
void applyBoxOrb(eItem it) {
applyBoxI(it, true);
invorb.push_back(it);
}
void list_invorb() {
for(eItem it: invorb) {
#ifdef INV
if(true) {
inv::applyBox(it);
continue;
}
#endif
int u = 0;
applyBoxNum(u);
}
invorb.clear();
}
void applyBoxM(eMonster m, bool f = false) { void applyBoxM(eMonster m, bool f = false) {
fakebox[boxid] = f; fakebox[boxid] = f;
boxname[boxid] = minf[m].name; boxname[boxid] = minf[m].name;
@@ -321,6 +355,7 @@ void applyBoxM(eMonster m, bool f = false) {
} }
void applyBoxes() { void applyBoxes() {
invorb.clear();
eLand lostin = laNone; eLand lostin = laNone;
@@ -347,9 +382,9 @@ void applyBoxes() {
else if(i == moWormwait) applyBoxM(moFireFairy); else if(i == moWormwait) applyBoxM(moFireFairy);
else if(i == moTentacleEscaping) applyBoxM(moMiner); else if(i == moTentacleEscaping) applyBoxM(moMiner);
else if(i == moGolemMoved) applyBoxM(moIllusion); else if(i == moGolemMoved) applyBoxM(moIllusion);
else if(i == moTentaclewait) applyBoxI(itOrbThorns, true); else if(i == moTentaclewait) applyBoxOrb(itOrbThorns);
else if(i == moGreater) applyBoxI(itOrbDragon, true); else if(i == moGreater) applyBoxOrb(itOrbDragon);
else if(i == moGreaterM) applyBoxI(itOrbIllusion, true); else if(i == moGreaterM) applyBoxOrb(itOrbIllusion);
else applyBoxM(eMonster(i), fake); else applyBoxM(eMonster(i), fake);
} }
@@ -371,17 +406,17 @@ void applyBoxes() {
else if(loading) firstland = safetyland = eLand(applyBoxLoad()); else if(loading) firstland = safetyland = eLand(applyBoxLoad());
else lostin = eLand(savebox[boxid++]); else lostin = eLand(savebox[boxid++]);
for(int i=itOrbLightning; i<25; i++) applyBoxI(eItem(i), true); for(int i=itOrbLightning; i<25; i++) applyBoxOrb(eItem(i));
applyBoxI(itRoyalJelly); applyBoxI(itRoyalJelly);
applyBoxI(itWine); applyBoxI(itWine);
applyBoxI(itSilver); applyBoxI(itSilver);
applyBoxI(itEmerald); applyBoxI(itEmerald);
applyBoxI(itPower); applyBoxI(itPower);
applyBoxI(itOrbFire, true); applyBoxOrb(itOrbFire);
applyBoxI(itOrbInvis, true); applyBoxOrb(itOrbInvis);
applyBoxI(itOrbAether, true); applyBoxOrb(itOrbAether);
applyBoxI(itOrbPsi, true); applyBoxOrb(itOrbPsi);
applyBoxM(moBug0); applyBoxM(moBug0);
applyBoxM(moBug1); applyBoxM(moBug1);
applyBoxM(moBug2); applyBoxM(moBug2);
@@ -407,12 +442,12 @@ void applyBoxes() {
applyBoxM(moCShark); applyBoxM(moCShark);
applyBoxM(moParrot); applyBoxM(moParrot);
applyBoxI(itPirate); applyBoxI(itPirate);
applyBoxI(itOrbTime, true); applyBoxOrb(itOrbTime);
applyBoxM(moHexSnake); applyBoxM(moHexSnake);
applyBoxM(moRedTroll); applyBoxM(moRedTroll);
applyBoxI(itRedGem); applyBoxI(itRedGem);
applyBoxI(itOrbSpace, true); applyBoxOrb(itOrbSpace);
int geo = geometry; int geo = geometry;
applyBoxNum(geo, ""); geometry = eGeometry(geo); applyBoxNum(geo, ""); geometry = eGeometry(geo);
@@ -429,14 +464,14 @@ void applyBoxes() {
applyBoxM(moBomberbird); applyBoxM(moBomberbird);
applyBoxM(moTameBomberbird); applyBoxM(moTameBomberbird);
applyBoxM(moAlbatross); applyBoxM(moAlbatross);
applyBoxI(itOrbFriend, true); applyBoxOrb(itOrbFriend);
applyBoxI(itOrbAir, true); applyBoxOrb(itOrbAir);
applyBoxI(itOrbWater, true); applyBoxOrb(itOrbWater);
applyBoxI(itPalace); applyBoxI(itPalace);
applyBoxI(itFjord); applyBoxI(itFjord);
applyBoxI(itOrbFrog, true); applyBoxOrb(itOrbFrog);
applyBoxI(itOrbDiscord, true); applyBoxOrb(itOrbDiscord);
applyBoxM(moPalace); applyBoxM(moPalace);
applyBoxM(moFatGuard); applyBoxM(moFatGuard);
applyBoxM(moSkeleton); applyBoxM(moSkeleton);
@@ -446,7 +481,7 @@ void applyBoxes() {
applyBoxM(moWaterElemental); applyBoxM(moWaterElemental);
applyBoxI(itSavedPrincess); applyBoxI(itSavedPrincess);
applyBoxI(itOrbLove, true); applyBoxOrb(itOrbLove);
applyBoxM(moPrincess); applyBoxM(moPrincess);
applyBoxM(moPrincessMoved, false); // live Princess for Safety applyBoxM(moPrincessMoved, false); // live Princess for Safety
applyBoxM(moPrincessArmedMoved, false); // live Princess for Safety applyBoxM(moPrincessArmedMoved, false); // live Princess for Safety
@@ -467,8 +502,8 @@ void applyBoxes() {
applyBoxM(moFamiliar); applyBoxM(moFamiliar);
applyBoxM(moGargoyle); applyBoxM(moGargoyle);
applyBoxM(moOrangeDog); applyBoxM(moOrangeDog);
applyBoxI(itOrbSummon, true); applyBoxOrb(itOrbSummon);
applyBoxI(itOrbMatter, true); applyBoxOrb(itOrbMatter);
applyBoxM(moForestTroll); applyBoxM(moForestTroll);
applyBoxM(moStormTroll); applyBoxM(moStormTroll);
@@ -479,8 +514,8 @@ void applyBoxes() {
applyBoxI(itMutant); applyBoxI(itMutant);
applyBoxI(itFulgurite); applyBoxI(itFulgurite);
applyBoxI(itBounty); applyBoxI(itBounty);
applyBoxI(itOrbLuck, true); applyBoxOrb(itOrbLuck);
applyBoxI(itOrbStunning, true); applyBoxOrb(itOrbStunning);
applyBoxBool(tactic::on, ""); applyBoxBool(tactic::on, "");
applyBoxNum(elec::lightningfast, ""); applyBoxNum(elec::lightningfast, "");
@@ -488,22 +523,22 @@ void applyBoxes() {
// if(savebox[boxid]) printf("lotus = %d (lost = %d)\n", savebox[boxid], isHaunted(lostin)); // if(savebox[boxid]) printf("lotus = %d (lost = %d)\n", savebox[boxid], isHaunted(lostin));
if(loadingHi && isHaunted(lostin)) boxid++; if(loadingHi && isHaunted(lostin)) boxid++;
else applyBoxI(itLotus); else applyBoxI(itLotus);
applyBoxI(itOrbUndeath, true); applyBoxOrb(itOrbUndeath);
applyBoxI(itWindstone); applyBoxI(itWindstone);
applyBoxI(itOrbEmpathy, true); applyBoxOrb(itOrbEmpathy);
applyBoxM(moWindCrow); applyBoxM(moWindCrow);
applyBoxI(itMutant2); applyBoxOrb(itMutant2);
applyBoxI(itOrbFreedom, true); applyBoxOrb(itOrbFreedom);
applyBoxM(moRedFox); applyBoxM(moRedFox);
applyBoxBool(survivalist); applyBoxBool(survivalist);
if(loadingHi) applyBoxI(itLotus); if(loadingHi) applyBoxI(itLotus);
else applyBoxNum(truelotus, "lotus/escape"); else applyBoxNum(truelotus, "lotus/escape");
applyBoxBool(purehepta, "heptagons only"); applyBoxBool(purehepta, "heptagons only");
applyBoxI(itRose); applyBoxI(itRose);
applyBoxI(itOrbBeauty, true); applyBoxOrb(itOrbBeauty);
applyBoxI(itCoral); applyBoxI(itCoral);
applyBoxI(itOrb37, true); applyBoxOrb(itOrb37);
applyBoxI(itOrbEnergy, true); applyBoxOrb(itOrbEnergy);
applyBoxM(moRatling); applyBoxM(moRatling);
applyBoxM(moFalsePrincess); applyBoxM(moFalsePrincess);
applyBoxM(moRoseLady); applyBoxM(moRoseLady);
@@ -520,11 +555,11 @@ void applyBoxes() {
applyBoxM(moResearcher); applyBoxM(moResearcher);
applyBoxI(itDragon); applyBoxI(itDragon);
applyBoxM(moDragonHead); applyBoxM(moDragonHead);
applyBoxI(itOrbDomination, true); applyBoxOrb(itOrbDomination);
applyBoxI(itBabyTortoise); applyBoxI(itBabyTortoise);
applyBoxNum(tortoise::seekbits, ""); applyBoxNum(tortoise::seekbits, "");
applyBoxM(moTortoise); applyBoxM(moTortoise);
applyBoxI(itOrbShell, true); applyBoxOrb(itOrbShell);
applyBoxNum(safetyseed); applyBoxNum(safetyseed);
@@ -539,12 +574,12 @@ void applyBoxes() {
applyBoxI(itKraken); applyBoxI(itKraken);
applyBoxM(moKrakenH); applyBoxM(moKrakenH);
applyBoxM(moKrakenT); applyBoxM(moKrakenT);
applyBoxI(itOrbSword, true); applyBoxOrb(itOrbSword);
applyBoxI(itBarrow); applyBoxI(itBarrow);
applyBoxM(moDraugr); applyBoxM(moDraugr);
applyBoxI(itOrbSword2, true); applyBoxOrb(itOrbSword2);
applyBoxI(itTrollEgg); applyBoxI(itTrollEgg);
applyBoxI(itOrbStone, true); applyBoxOrb(itOrbStone);
bool sph; bool sph;
sph = false; applyBoxBool(sph, "sphere"); if(sph) geometry = gSphere; sph = false; applyBoxBool(sph, "sphere"); if(sph) geometry = gSphere;
@@ -554,23 +589,35 @@ void applyBoxes() {
applyBoxI(itDodeca); applyBoxI(itDodeca);
applyBoxI(itAmethyst); applyBoxI(itAmethyst);
applyBoxI(itSlime); applyBoxI(itSlime);
applyBoxI(itOrbNature, true); applyBoxOrb(itOrbNature);
applyBoxI(itOrbDash, true); applyBoxOrb(itOrbDash);
// itOrbRecall should not be here addinv(itOrbRecall);
applyBoxM(moBat); applyBoxM(moBat);
applyBoxM(moReptile); applyBoxM(moReptile);
applyBoxM(moFriendlyIvy); applyBoxM(moFriendlyIvy);
applyBoxI(itGreenGrass); applyBoxI(itGreenGrass);
applyBoxI(itBull); applyBoxI(itBull);
applyBoxI(itOrbHorns, true); applyBoxOrb(itOrbHorns);
applyBoxI(itOrbBull, true); applyBoxOrb(itOrbBull);
applyBoxM(moSleepBull); applyBoxM(moSleepBull);
applyBoxM(moRagingBull); applyBoxM(moRagingBull);
applyBoxM(moHerdBull); applyBoxM(moHerdBull);
applyBoxM(moButterfly); applyBoxM(moButterfly);
applyBoxM(moGadfly); applyBoxM(moGadfly);
// 10.0:
applyBoxNum(hinttoshow); // 258
addinv(itOrbMirror);
addinv(itGreenStone);
list_invorb();
applyBoxBool(inv::on, "inventory"); // 306
#ifdef INV
applyBoxNum(inv::rseed);
#else
{ int u; applyBoxNum(u); }
#endif
if(POSSCORE != boxid) printf("ERROR: %d boxes\n", boxid); if(POSSCORE != boxid) printf("ERROR: %d boxes\n", boxid);
} }
@@ -785,6 +832,7 @@ void loadsave() {
score sc; score sc;
bool ok = false; bool ok = false;
bool tamper = false; bool tamper = false;
int coh = counthints();
while(!feof(f)) { while(!feof(f)) {
char buf[120]; char buf[120];
if(fgets(buf, 120, f) == NULL) break; if(fgets(buf, 120, f) == NULL) break;
@@ -792,7 +840,8 @@ void loadsave() {
gamecount++; gamecount++;
if(fscanf(f, "%s", buf) <= 0) break; if(fscanf(f, "%s", buf) <= 0) break;
sc.ver = buf; sc.ver = buf;
if(sc.ver < "4.4" || sc.ver == "CHEATER!") { ok = false; continue; } if(sc.ver[1] != '.') sc.ver = '0' + sc.ver;
if(verless(sc.ver, "4.4") || sc.ver == "CHEATER!") { ok = false; continue; }
ok = true; ok = true;
for(int i=0; i<MAXBOX; i++) { for(int i=0; i<MAXBOX; i++) {
if(fscanf(f, "%d", &sc.box[i]) <= 0) { if(fscanf(f, "%d", &sc.box[i]) <= 0) {
@@ -803,6 +852,10 @@ void loadsave() {
for(int i=0; i<boxid; i++) savebox[i] = sc.box[i]; for(int i=0; i<boxid; i++) savebox[i] = sc.box[i];
for(int i=boxid; i<MAXBOX; i++) savebox[i] = 0, sc.box[i] = 0; for(int i=boxid; i<MAXBOX; i++) savebox[i] = 0, sc.box[i] = 0;
if(savebox[258] >= 0 && savebox[258] < coh) {
hints[savebox[258]].last = savebox[1];
}
loadBoxHigh(); loadBoxHigh();
break; break;
@@ -826,7 +879,10 @@ void loadsave() {
for(int xc=0; xc<MODECODES; xc++) for(int xc=0; xc<MODECODES; xc++)
if(tid == tactic::id && (anticheat::check(cert, ver, dnameof(eLand(land)), tc, t, ts, xc*999+tid + 256 * score))) { if(tid == tactic::id && (anticheat::check(cert, ver, dnameof(eLand(land)), tc, t, ts, xc*999+tid + 256 * score))) {
if(score != 0 && !(land == laOcean && ver < string("8.0f"))) if(score != 0
&& !(land == laOcean && verless(ver, "8.0f"))
&& !(land == laMirror && verless(ver, "10.0"))
)
tactic::record(eLand(land), score, xc); tactic::record(eLand(land), score, xc);
anticheat::nextid(tactic::id, ver, cert); anticheat::nextid(tactic::id, ver, cert);
break; break;
@@ -843,8 +899,8 @@ void loadsave() {
if(anticheat::check(cert, ver, won ? "WON" : "LOST", tc, t, ts, xc*999 + cid + 256 * oy)) { if(anticheat::check(cert, ver, won ? "WON" : "LOST", tc, t, ts, xc*999 + cid + 256 * oy)) {
if(xc == 19 && cid == 25) xc = 0; if(xc == 19 && cid == 25) xc = 0;
if(cid > 0 && cid < YENDORLEVELS) if(cid > 0 && cid < YENDORLEVELS)
if(!(ver < string("8.0f") && oy > 1 && cid == 15)) if(!(verless(ver, "8.0f") && oy > 1 && cid == 15))
if(!(ver < string("9.3b") && oy > 1 && (cid == 27 || cid == 28))) if(!(verless(ver, "9.3b") && oy > 1 && (cid == 27 || cid == 28)))
{ {
yendor::bestscore[xc][cid] = max(yendor::bestscore[xc][cid], oy); yendor::bestscore[xc][cid] = max(yendor::bestscore[xc][cid], oy);
} }
@@ -955,6 +1011,7 @@ void restartGame(char switchWhat, bool push) {
#endif #endif
achievementsReceived.clear(); achievementsReceived.clear();
princess::saved = false; princess::saved = false;
princess::nodungeon = false;
princess::reviveAt = 0; princess::reviveAt = 0;
princess::forceVizier = false; princess::forceVizier = false;
princess::forceMouse = false; princess::forceMouse = false;
@@ -1101,7 +1158,8 @@ eItem randomTreasure2(int cv) {
bool isTechnicalLand(eLand l) { bool isTechnicalLand(eLand l) {
return l == laNone || l == laOceanWall || l == laBarrier || l == laCanvas || return l == laNone || l == laOceanWall || l == laBarrier || l == laCanvas ||
l == laHauntedWall || l == laHauntedBorder || l == laCA; l == laHauntedWall || l == laHauntedBorder || l == laCA ||
l == laMirrorWall || l == laMirrored;
} }
eLand cheatdest; eLand cheatdest;

View File

@@ -29,6 +29,13 @@ 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 fts(float x) { char buf[64]; sprintf(buf, "%4.2f", x); return buf; }
string fts3(float x) { char buf[64]; sprintf(buf, "%5.3f", x); return buf; } string fts3(float x) { char buf[64]; sprintf(buf, "%5.3f", x); return buf; }
string fts4(float x) { char buf[64]; sprintf(buf, "%6.4f", x); return buf; } string fts4(float x) { char buf[64]; sprintf(buf, "%6.4f", x); return buf; }
string ftssmart(ld x) {
if(x == int(x)) return its(int(x));
if(abs(x) > 1) return fts4(x);
char buf[64]; sprintf(buf, "%.10le", (double) x); return buf;
}
string cts(char c) { char buf[8]; buf[0] = c; buf[1] = 0; return buf; } string cts(char c) { char buf[8]; buf[0] = c; buf[1] = 0; return buf; }
string llts(long long i) { string llts(long long i) {
// sprintf does not work on Windows IIRC // sprintf does not work on Windows IIRC

View File

@@ -7,7 +7,7 @@
namespace peace { extern bool on; } namespace peace { extern bool on; }
#define MODECODES 254 #define MODECODES 255
int hiitemsMax(eItem it) { int hiitemsMax(eItem it) {
int mx = 0; int mx = 0;
@@ -211,6 +211,7 @@ namespace yendor {
nyi.path[i] = lig.c; nyi.path[i] = lig.c;
cwstep(lig); cwstep(lig);
if(inmirror(lig)) lig = mirror::reflect(lig);
cwspin(lig, 3); cwspin(lig, 3);
if(lig.c->type == 7) { if(lig.c->type == 7) {
if(in_endorian && endorian_change && i >= YDIST - 20) { if(in_endorian && endorian_change && i >= YDIST - 20) {
@@ -289,6 +290,8 @@ namespace yendor {
c2->wall = waPlatform; c2->wall = waPlatform;
if(c2->land == laReptile && i >= 0) if(c2->land == laReptile && i >= 0)
c2->wall = waChasm; c2->wall = waChasm;
if(c2->land == laMirrorWall && i == -1)
c2->wall = waNone;
} }
key->item = itKey; key->item = itKey;
@@ -508,14 +511,12 @@ namespace yendor {
challenge = uni-'a' + 1; challenge = uni-'a' + 1;
if(levelUnlocked(challenge) || autocheat) { if(levelUnlocked(challenge) || autocheat) {
restartGame(yendor::on ? 0 : 'y'); restartGame(yendor::on ? 0 : 'y');
popScreen();
} }
else else
addMessage("Collect 10 treasures in various lands to unlock the challenges there"); addMessage("Collect 10 treasures in various lands to unlock the challenges there");
} }
else if(uni == '0') { else if(uni == '0') {
if(yendor::on) restartGame('y'); if(yendor::on) restartGame('y');
popScreen();
} }
else if(uni == '1') easy = !easy; else if(uni == '1') easy = !easy;
else if(uni == '2' || sym == SDLK_F1) gotoHelp(chelp); else if(uni == '2' || sym == SDLK_F1) gotoHelp(chelp);
@@ -744,12 +745,11 @@ namespace tactic {
if(uni >= 1000 && uni < 1000 + LAND_TAC) { if(uni >= 1000 && uni < 1000 + LAND_TAC) {
firstland = euclidland = getLandById(uni - 1000); firstland = euclidland = getLandById(uni - 1000);
restartGame(tactic::on ? 0 : 't'); restartGame(tactic::on ? 0 : 't');
popScreen();
} }
else if(uni == '0') { else if(uni == '0') {
popScreen();
firstland = laIce; firstland = laIce;
if(tactic::on) restartGame('t'); if(tactic::on) restartGame('t');
else popScreen();
} }
else if(sym == SDLK_F1) gotoHelp( else if(sym == SDLK_F1) gotoHelp(
@@ -827,7 +827,7 @@ int modecodetable[42][6] = {
{248,249,250,251,252,253}, // shmup heptagonal elliptic chaosmode {248,249,250,251,252,253}, // shmup heptagonal elliptic chaosmode
}; };
// unused code: 25 // unused code: 25
int newmodecode = 254; int newmodecode = 255;
int modecode() { int modecode() {
#ifndef NOSAVE #ifndef NOSAVE
@@ -838,6 +838,7 @@ int modecode() {
if(quotient) return 6; if(quotient) return 6;
#endif #endif
if(peace::on) return 6; if(peace::on) return 6;
if(inv::on) return 254; // no code yet
int xcode = 0; int xcode = 0;
if(shmup::on) xcode += 2; if(shmup::on) xcode += 2;
@@ -1049,13 +1050,11 @@ namespace peace {
else if(uni >= 'a' && uni < 'a' + qty) { else if(uni >= 'a' && uni < 'a' + qty) {
whichland = levellist[uni - 'a']; whichland = levellist[uni - 'a'];
restartGame(peace::on ? 0 : 'P'); restartGame(peace::on ? 0 : 'P');
popScreen();
} }
else if(uni == '2') { hint = !hint; popScreen(); } else if(uni == '2') { hint = !hint; popScreen(); }
else if(uni == '0') { else if(uni == '0') {
firstland = laIce; firstland = laIce;
if(peace::on) restartGame('P'); if(peace::on) restartGame('P');
popScreen();
} }
else if(uni == 'h' || sym == SDLK_F1) gotoHelp(chelp); else if(uni == 'h' || sym == SDLK_F1) gotoHelp(chelp);
else if(doexiton(sym, uni)) popScreen(); else if(doexiton(sym, uni)) popScreen();