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
// Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details
#define NUMLEADER 69
#define NUMLEADER 70
#define SCORE_UNKNOWN (-1)
#define NO_SCORE_YET (-2)
@ -14,7 +14,7 @@ int currentscore[NUMLEADER];
const char* leadernames[NUMLEADER] = {
"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",
"Time to 10 Hyperstones-94", "Turns to 10 Hyperstones-94", "Orbs of Yendor",
"Fern Flowers",
@ -58,7 +58,8 @@ const char* leadernames[NUMLEADER] = {
"Slime Molds", // 65
"Dodecahedra", // 66
"Green Grass", // 67
"Spinel" // 68
"Spinel", // 68
"Orb Strategy Score", // 69
};
#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 == 10) {
if(q == U10) {
if(it == itDiamond) achievement_gain("DIAMOND2");
if(it == itRuby) achievement_gain("RUBY2");
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(q == 25) {
if(q == R10) {
if(it == itDiamond) achievement_gain("DIAMOND3");
if(it == itRuby) achievement_gain("RUBY3");
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(q == 50) {
if(q == 50 && !inv::on) {
if(it == itDiamond) achievement_gain("DIAMOND4");
if(it == itRuby) achievement_gain("RUBY4");
if(it == itHyperstone) achievement_gain("HYPER4");
@ -553,18 +554,21 @@ void achievement_final(bool really_final) {
if(shmup::on) specials++;
if(chaosmode) specials++;
if(purehepta) specials++;
if(inv::on) specials++;
if(specials > 1) return;
if(numplayers() > 1 && chaosmode) return;
if(numplayers() > 1 && purehepta) return;
if(numplayers() > 1 && inv::on) return;
int total_improved = 0;
specific_improved = 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) :
inv::on ? 69 :
(numplayers() > 1 ? 61 : 0);
int tg = gold();
@ -601,6 +605,19 @@ void achievement_final(bool really_final) {
#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) {
DEBB(DF_STEAM, (debugfile,"achievement_victory\n"))
if(offlineMode) return;

View File

@ -88,8 +88,6 @@ int textwidth(int siz, const string &str) {
#endif
int gradient(int c0, int c1, ld v0, ld v, ld v1);
int darkenedby(int c, int lev) {
for(int i=0; i<lev; i++)
c = ((c & 0xFEFEFE) >> 1);
@ -100,6 +98,10 @@ int darkened(int c) {
#ifdef EXTRA_FADEOUT
c = gradient(backcolor, c, 0, extra::fadeout, 1);
#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++)
c = ((c & 0xFEFEFE) >> 1) + ((backcolor & 0xFEFEFE) >> 1);
return c;
@ -1008,8 +1010,10 @@ void setvideomode() {
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 16);
glEnable(GL_MULTISAMPLE);
}
#ifndef MAC
else
glDisable(GL_MULTISAMPLE);
#endif
}
#endif

View File

@ -648,7 +648,7 @@ struct cellwalker {
cell *c;
int spin;
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; }
};

View File

@ -1143,17 +1143,23 @@ itemtype iinf[ittypes] = {
"Target a cell on the other side to use it."
},
{ '$', 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 "
"(or two cells, when moving on a heptagon). This attack is slightly stronger than your normal "
"attack: it can stun some of the monsters which cannot be killed or stunned normally."
},
{ 'o', 0x8080FF, "Orb of the Bull",
{ 'o', 0xA05020, "Orb of the Bull",
"You get the powers of Shield, Horns, and Thorns after you move two moves in a straight line "
"with this Orb." },
{ '$', 0xC060C0, "Spinel", bulldashdesc },
{ 'o', 0xC0C0FF, "Orb of the Mirror", NODESCYET },
{ 'O', 0xF0F0F0, "your orbs", NODESC},
{ 'o', 0xC0C0FF, "Orb of the Mirror",
"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,
@ -1192,7 +1198,7 @@ enum eItem { itNone, itDiamond, itGold, itSpice, itRuby, itElixir, itShard, itBo
// --- wall types ---
const int walltypes = 97;
const int walltypes = 98;
struct walltype {
char glyph;
@ -1372,6 +1378,7 @@ walltype winf[walltypes] = {
{ '.', 0xFFFF00, "Reptile floor", reptiledesc},
{ '.', 0xFFFF00, "Reptile bridge", reptiledesc},
{ '.', 0xFFFF00, "invisible floor", NODESCYET},
{ '#', 0xC0C0FF, "mirror wall", NODESCYET},
};
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,
waBigBush, waSmallBush,
waReptile, waReptileBridge,
waInvisibleFloor
waInvisibleFloor,
waMirrorWall
};
// --- land types ---
const int landtypes = 67;
const int landtypes = 71;
struct landtype {
int color;
@ -1437,7 +1445,7 @@ const landtype linf[landtypes] = {
"A land filled with huge ivy plants and dangerous animals."
},
{ 0x900090, "Alchemist Lab", slimehelp},
{ 0x704070, "Mirror Land",
{ 0x704070, "Hall of Mirrors",
"A strange land which contains mirrors and mirages, protected by Mirror Rangers."},
{ 0x404070, "Graveyard",
"All the monsters you kill are carried to this strange land, and buried. "
@ -1578,7 +1586,11 @@ const landtype linf[landtypes] = {
{ 0x0000D0, "Prairie", prairiedesc},
{ 0x800080, "Bull Dash", bulldashdesc},
{ 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,
@ -1595,7 +1607,8 @@ enum eLand { laNone, laBarrier, laCrossroads, laDesert, laIce, laCaves, laJungle
laEndorian, laTortoise, laDragon,
laKraken, laBurial, laTrollheim,
laHalloween, laDungeon, laMountain, laReptile,
laPrairie, laBull, laCrossroads5, laCA
laPrairie, laBull, laCrossroads5, laCA,
laMirrorWall, laMirrored, laMirrorWall2, laMirrored2
};
// cell information for the game

View File

@ -466,6 +466,8 @@ namespace princess {
#define OUT_OF_PRISON 200
#define OUT_OF_PALACE 250
#define PRADIUS0 (141)
#define PRADIUS1 (150)
bool generating = false;
bool challenge = false;
@ -475,6 +477,8 @@ namespace princess {
bool forceVizier = false;
bool forceMouse = false;
bool gotoPrincess = false;
bool nodungeon = false;
bool squeaked = false;
int saveHP = 0, saveArmedHP = 0;
@ -496,7 +500,7 @@ namespace princess {
if(i->alt) i->alt->emeraldval = i->id;
}
void newInfo(cell *c) {
int newInfo(cell *c) {
info *i = new info;
i->prison = c;
i->princess = c;
@ -506,6 +510,7 @@ namespace princess {
i->bestnear = OUT_OF_PRISON;
infos.push_back(i);
assign(i);
return i->id;
}
void newFakeInfo(cell *c) {
@ -514,7 +519,7 @@ namespace princess {
i->princess = c;
i->alt = NULL;
i->id = size(infos);
i->bestdist = OUT_OF_PALACE;
i->bestdist = items[itSavedPrincess] ? OUT_OF_PALACE : OUT_OF_PRISON;
i->bestnear = 0;
infos.push_back(i);
assign(i);
@ -524,7 +529,7 @@ namespace princess {
if(euclid) return NULL;
if(c->land != laPalace) 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(infos[ev]->alt != c->master->alt->alt) return NULL;
return infos[ev];
@ -535,6 +540,7 @@ namespace princess {
while(i) {
infos[i]->id = i-1; assign(infos[i]);
infos[i-1]->id = i; assign(infos[i-1]);
swap(infos[i], infos[i-1]);
i--;
}
return infos[i];
@ -543,7 +549,7 @@ namespace princess {
}
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(euclid) return celldistAlt(c);
else if(!c->master->alt) return OUT_OF_PRISON;
@ -565,10 +571,10 @@ namespace princess {
playSound(c, princessgender() ? "heal-princess" : "heal-prince");
info *inf = NULL;
for(int i=0; i<size(infos); i++)
if(infos[i]->princess && infos[i]->bestdist == OUT_OF_PALACE)
for(int i=0; i<size(infos); i++) {
if(infos[i]->princess && infos[i]->bestdist == OUT_OF_PALACE && isPrincess(infos[i]->princess->monst))
inf = infos[i];
}
if(inf) { inf->princess->monst = moNone; inf->princess = c; }
else newFakeInfo(c);
return true;
@ -586,6 +592,9 @@ namespace princess {
// printf("Improved dist to %d\n", newdist);
if(newdist == OUT_OF_PALACE) {
if(!princess::saved)
#ifdef INV
if(!inv::on || !inv::usedForbidden)
#endif
achievement_gain("PRINCESS1");
princess::saved = true;
princess::everSaved = true;
@ -600,25 +609,27 @@ namespace princess {
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) {
if(euclid) return;
princess::info *i = princess::getPrincessInfo(princess);
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) {
if(euclid) return;
princess::info *i = princess::getPrincessInfo(cf);
if(!i) {
static bool warn = true;
// note: OK if mapediting or loading
if(warn) printf("Warning: unknown princess\n");
if(warn && !cheater)
printf("Warning: unknown princess\n");
if(!cheater)
addMessage("Warning: unknown princess (that's a bug, please report)");
warn = false;
}
else {
i->princess = ct;
@ -661,31 +672,33 @@ namespace princess {
retry:
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));
}
else if(msgid == 1 && d >= 20 && c->land == laPalace) {
else if(msgid == 1 && d >= 20 && inpalace) {
if(m == moPrincess)
addMessage(XLAT("\"I want my revenge. Stun a guard and leave him for me!\"", m));
else
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));
}
else if(msgid == 3 && c->land != laPalace) {
else if(msgid == 3 && !inpalace) {
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));
}
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));
}
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));
}
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));
}
else {
@ -1005,23 +1018,31 @@ namespace mirror {
c->wall == waFrozenLake || c->wall == waDeadfloor || c->wall == waDeadfloor2 ||
c->wall == waGiantRug || c->wall == waCIsland || c->wall == waCIsland2 ||
c->wall == waGargoyleFloor || c->wall == waRubble ||
c->wall == waGargoyleBridge || c->wall == waTempFloor || c->wall == waTempBridge;
}
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;
}
c->wall == waGargoyleBridge || c->wall == waTempFloor || c->wall == waTempBridge ||
c->wall == waMirrorWall;
}
inline eMonster switchtype(eMonster m) {
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) {
if(!b) return m;
return (m == moMirror) ? moMirage : moMirror;
@ -1113,7 +1134,7 @@ namespace mirror {
}
}
}
void go(bool fwd) {
int tk = tkills();
int nummirage = 0;
@ -1123,9 +1144,24 @@ namespace mirror {
if(c->hitpoints != multi::cpid) continue;
eMonster m = c->monst;
if(isMimic(m)) {
if(m == moMirage) nummirage++;
int dir = c->mondir;
if(m == moMirage) nummirage++;
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))
attackMonster(c2, AF_MSG | AF_ORSTUN, m);
if(c2->wall == waBigTree)
@ -1135,7 +1171,7 @@ namespace mirror {
if(!fwd) continue;
c->monst = moNone;
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(c2->monst == moGreater) {
c2->monst = moLesser; continue;
@ -1192,7 +1228,123 @@ namespace mirror {
if(multi::players > 1) spin(d);
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 {
@ -2765,7 +2917,7 @@ namespace ca {
}
auto ccm = addHook(clearmemory, 0, [] () {
offscreen.clear();
offscreen.clear();
princess::clear();
mirrors.clear();
clearing::bpdata.clear();

View File

@ -45,43 +45,91 @@ int lang() {
bool autojoy = true;
/*struct saver {
struct supersaver {
string name;
virtual string save();
virtual void load(string& s);
virtual string save() = 0;
virtual void load(const string& s) = 0;
virtual bool dosave() = 0;
};
struct intsaver : saver {
int& val;
int dft;
void intsaver() { val = dft; }
string save() { return its(val); }
void load(string& s) { val = atoi(s.c_str()); }
vector<shared_ptr<supersaver>> savers;
template<class T> struct dsaver : supersaver {
T& val;
T dft;
bool dosave() { return val != dft; }
dsaver(T& val) : val(val) { }
};
struct hexsaver : saver {
int& val;
int dft;
void intsaver() { val = dft; }
string save() { return itsh(val); }
void load(string& s) { val = strtol(s.c_str(), 16); }
};
template<class T> struct saver : dsaver<T> {};
struct ldsaver : saver {
ld& val;
ld dft;
void intsaver() { val = dft; }
string save() { return ffts(val); }
void load(string& s) { val = atof(s.c_str()); }
};
vector<shared_ptr<saver>> savers;
void initConfig0() {
savers.push_back(make_shared<intsaver> ({"cs.charid", cs.charid, 0}));
template<class T, class U, class V> void addsaver(T& i, U name, V dft) {
auto s = make_shared<saver<T>> (i);
s->dft = i = dft;
s->name = name;
savers.push_back(s);
}
*/
template<class T> void addsaver(T& i, string name) {
addsaver(i, name, i);
}
template<class T> struct saverenum : supersaver {
T& val;
T dft;
bool dosave() { return val != dft; }
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
unsigned int skincolors[] = { 7, 0xD0D0D0FF, 0xEFD0C9FF, 0xC77A58FF, 0xA58869FF, 0x602010FF, 0xFFDCB1FF, 0xEDE4C8FF };
@ -127,69 +175,109 @@ void loadcs(FILE *f, charstyle& cs, int xvernum) {
}
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
vid.monmode = 2;
vid.wallmode = 3;
#else
#ifdef PANDORA
vid.monmode = 2;
vid.wallmode = 3;
#else
vid.monmode = 4;
vid.wallmode = 5;
#endif
#endif
vid.particles = 1;
vid.mobilecompasssize = 30;
vid.joyvalue = 4800;
vid.joyvalue2 = 5600;
vid.joypanthreshold = 2500;
#ifdef PANDORA
vid.joypanspeed = 0.0001;
#else
vid.joypanspeed = 0;
#endif
vid.framelimit = 75;
vid.axes = 1;
vid.shifttarget = 2;
vid.steamscore = 1;
initcs(vid.cs);
// basic config
addsaver(vid.flashtime, "flashtime", 8);
addsaver(vid.mobilecompasssize, "mobile compass size", 30);
addsaver(vid.axes, "movement help", 1);
addsaver(vid.shifttarget, "shift-targetting", 2);
addsaver(vid.steamscore, "scores to Steam", 1);
initcs(vid.cs); addsaver(vid.cs, "single");
addsaver(vid.samegender, "princess choice", false);
addsaver(vid.language, "language", -1);
addsaver(vid.drawmousecircle, "mouse circle", ISMOBILE || ISPANDORA);
addsaver(vid.revcontrol, "reverse control", false);
addsaver(musicvolume, "music volume");
addsaver(effvolume, "sound effect volume");
addsaverenum(glyphsortorder, "glyph sort order");
// basic graphics
addsaver(vid.usingGL, "usingGL", true);
addsaver(vid.antialias, "antialias", AA_NOGL | AA_FONT | AA_LINES | AA_LINEWIDTH | AA_VERSION);
addsaver(vid.linewidth, "linewidth", 1);
addsaver(vid.scale, "scale", 1);
addsaver(vid.alpha, "projection", 1);
addsaver(vid.sspeed, "scrollingspeed", 0);
addsaver(vid.mspeed, "movement speed", 1);
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);
// special graphics
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.samegender = false;
vid.language = -1;
vid.drawmousecircle = false;
vid.revcontrol = false;
#ifdef MOBILE
vid.drawmousecircle = true;
#endif
#ifdef PANDORA
vid.drawmousecircle = true;
#endif
// modes
addsaverenum(geometry, "mode-geometry");
addsaverenum(euclidland, "mode-geometry land");
addsaver(shmup::on, "mode-shmup", false);
addsaver(hardcore, "mode-hardcore", false);
addsaver(chaosmode, "mode-chaos");
addsaver(inv::on, "mode-Orb Strategy");
addsaver(purehepta, "mode-heptagonal", false);
shmup::initConfig();
}
@ -201,36 +289,6 @@ void saveConfig() {
addMessage(s0 + "Could not open the config file: " + conffile);
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;
@ -241,43 +299,13 @@ void saveConfig() {
if(tc_depth < tc_alpha ) pt_alpha ++;
if(tc_alpha > tc_camera) pt_alpha++;
if(tc_alpha < tc_camera) pt_camera++;
fprintf(f, "%f %f %f %f %f %f %f %d %d %d %f %f %d\n",
float(geom3::depth), float(geom3::camera), float(geom3::wall_height),
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));
tc_alpha = pt_alpha;
tc_camera = pt_camera;
tc_depth = pt_depth;
}
fprintf(f, "\n\nThis is a configuration file for HyperRogue (version " VER ")\n");
fprintf(f, "\n\nThe numbers are:\n");
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");
for(auto s: savers) if(s->dosave())
fprintf(f, "%s=%s\n", s->name.c_str(), s->save().c_str());
fclose(f);
#ifndef MOBILE
@ -294,110 +322,150 @@ void readf(FILE *f, ld& x) {
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() {
DEBB(DF_INIT, (debugfile,"load config\n"));
DEBB(DF_INIT, (debugfile,"load config\n"));
vid.xres = 9999; vid.yres = 9999; vid.framelimit = 300;
FILE *f = fopen(conffile, "rt");
if(f) {
int fs, gl=1, aa=1, bb=1, cc, dd, ee;
int err;
int fs;
err=fscanf(f, "%d%d%d%d", &vid.xres, &vid.yres, &fs, &vid.fsize);
vid.full = fs;
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;
if(!err)
loadNewConfig(f);
else {
vid.full = fs;
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);
DEBB(DF_INIT, (debugfile,"Loaded configuration: %s\n", conffile));
if(err)
;
}
polygonal::solve();
precalc();
}
#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);
}

View File

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

View File

@ -526,7 +526,7 @@ void mainloopiter() {
drawscreen();
}
if(ev.type == SDL_JOYAXISMOTION) {
if(ev.type == SDL_JOYAXISMOTION && normal && DEFAULTCONTROL) {
if(ev.jaxis.which == 0) {
if(ev.jaxis.axis == 0)
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_DOWN) dir = 2;
if(ev.jhat.value == SDL_HAT_LEFT) dir = 3;
printf("%d %d %d\n", joyid, hat, dir);
if(joyid < 8 && hat < 4 && dir < 4) {
vid.scfg.hataction[joyid][hat][dir] = vid.scfg.setwhat;
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();
movepcto(joydir);
checkjoy();
}
else if(ev.type == SDL_JOYBUTTONDOWN && !normal) {
sym = uni = SDLK_RETURN;
}
if(ev.type == SDL_KEYDOWN) {
flashMessages();
mousing = false;

View File

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

View File

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

248
game.cpp
View File

@ -124,9 +124,9 @@ cellwalker cwt; // single player character position
inline cell*& singlepos() { return cwt.c; }
inline bool singleused() { return !(shmup::on || multi::players > 1); }
#include "mtrand.cpp"
#include <random>
MTRand_int32 r;
mt19937 r;
void shrand(int i) {
r.seed(i);
@ -510,6 +510,9 @@ bool passable(cell *w, cell *from, flagtype flags) {
if(w->wall == waMirror || w->wall == waCloud)
return F(P_MIRROR | P_AETHER);
if(w->wall == waMirrorWall)
return F(P_MIRRORWALL);
if(F(P_BULLET)) {
if(isFire(w) || w->wall == waBonfireOff || cellHalfvine(w) ||
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)
return false;
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) &&
(to->mov[i]->monst == moFriendlyGhost) == (m== moFriendlyGhost))
return false;
}
if(isGhost(m) || m == moWitchGhost) return true;
if(m == moGreaterShark) return isWatery(to);
if(m == moWitchWinter)
@ -1728,6 +1733,10 @@ void killMonster(cell *c, eMonster who, flagtype deathflags) {
i->princess = NULL;
if(i->bestdist == OUT_OF_PALACE) {
items[itSavedPrincess]--;
if(items[itSavedPrincess] < 0) {
printf("princess below 0\n");
items[itSavedPrincess] = 0;
}
if(items[itSavedPrincess] == 0 && !inv::on) {
items[itOrbLove] = 0;
princess::reviveAt = gold(NO_LOVE) + 20;
@ -5399,6 +5408,11 @@ bool hasSafeOrb(cell *c) {
}
void checkmove() {
#ifdef INV
if(inv::on) inv::compute();
#endif
if(multi::players > 1 && !multi::checkonly) return;
if(hardcore) return;
msgscroll = 0;
@ -5423,6 +5437,20 @@ void checkmove() {
canmove = legalmoves[cwt.spin] = true;
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) {
achievement_final(true);
if(cmode & sm::NORMAL) showMissionScreen();
@ -5435,11 +5463,7 @@ void checkmove() {
items[itWarning]-=2;
for(int i=0; i<ittypes; i++) orbused[i] = orbusedbak[i];
if(recallCell && !markOrb(itOrbRecall)) activateRecall();
#ifdef INV
if(inv::on) inv::compute();
#endif
if(recallCell && !markOrb(itOrbRecall)) activateRecall();
}
// move the PC. Warning: a very long function! todo: refactor
@ -5554,7 +5578,7 @@ bool cantGetGrimoire(cell *c2, bool verbose = true) {
void gainLife() {
items[itOrbLife] ++;
if(items[itOrbLife] > 5) items[itOrbLife] = 5;
if(items[itOrbLife] > 5 && !shmup::on) items[itOrbLife] = 5;
}
void collectMessage(cell *c2, eItem which) {
@ -5686,19 +5710,29 @@ bool collectItem(cell *c2, bool telekinesis) {
if(isRevivalOrb(c2->item) && multi::revive_queue.size()) {
multiRevival(cwt.c, c2);
}
else if(c2->item == itOrbSpeed) {
items[c2->item] += 31;
playSound(c2, "pickup-speed");
else if(isShmupLifeOrb(c2->item) && shmup::on) {
playSound(c2, "pickup-orb"); // TODO summon
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) {
playSound(c2, "pickup-orb"); // TODO summon
if(shmup::on) gainLife();
else placeGolem(cwt.c, c2, moGolem);
placeGolem(cwt.c, c2, moGolem);
}
else if(c2->item == itOrbFriend) {
playSound(c2, "pickup-orb"); // TODO summon
if(shmup::on) gainLife();
else placeGolem(cwt.c, c2, moTameBomberbird);
placeGolem(cwt.c, c2, moTameBomberbird);
}
#ifdef TOUR
else if(tour::on && (c2->item == itOrbSafety || c2->item == itOrbRecall)) {
@ -5715,145 +5749,6 @@ bool collectItem(cell *c2, bool telekinesis) {
activateSafety(c2->land);
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) {
using namespace tortoise;
int bnew = babymap[c2];
@ -5869,47 +5764,6 @@ bool collectItem(cell *c2, bool telekinesis) {
}
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) {
if(!items[itDodeca]) {
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();
check_total_victory();
if(items[itWhirlpool] && cwt.c->land != laWhirlpool && !whirlpool::escaped) {
whirlpool::escaped = true;
achievement_gain("WHIRL1");

122
graph.cpp
View File

@ -4,6 +4,8 @@
// basic graphics:
int inmirrorcount = 0;
bool wmspatial, wmescher, wmplain, wmblack, wmascii;
bool mmspatial, mmhigh, mmmon, mmitem;
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 == itOrbRecall) icol = 0x101010;
hpcshape& sh =
it == itOrbLove ? shLoveRing :
isRangedOrb(it) ? shTargetRing :
isOffensiveOrb(it) ? shSawRing :
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));
}
else if(m == moVampire || m == moBat) {
if(m == moBat) ShadowV(V, shBatWings); // but vampires have no shadow
queuepoly(VBIRD, shBatWings, darkena(0x303030, 0, 0xFF));
queuepoly(VBIRD, shBatBody, darkena(0x606060, 0, 0xFF));
// vampires have no shadow and no mirror images
if(m == moBat) ShadowV(V, shBatWings);
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, 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) {
if(!gmatrix0.count(c2)) return dft;
if(inmirrorcount || !gmatrix0.count(c2)) return dft;
hyperpoint h = C0;
if(animations[LAYER_BIG].count(c2)) h = animations[LAYER_BIG][c2].wherenow * 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));
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);
return false;
}
@ -1502,7 +1508,8 @@ bool drawMonster(const transmatrix& Vparam, int ct, cell *c, int col) {
double footphaseb = 0, footphase = 0;
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;
eMonster m = c->monst;
@ -1638,6 +1645,8 @@ bool drawMonster(const transmatrix& Vparam, int ct, cell *c, int col) {
if(!nospins)
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;
@ -2240,7 +2249,8 @@ void setcolors(cell *c, int& wcol, int &fcol) {
if(c->wall == waPlatform) wcol = 0xF0F0A0;
}
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 == laGraveyard) fcol = 0x107010;
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)
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;
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;
ivoryz = isGravityLand(c->land);
transmatrix& gm = gmatrix[c];
bool orig =
gm[2][2] == 0 ? true :
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;
bool orig = false;
if(!inmirrorcount) {
transmatrix& gm = gmatrix[c];
orig =
gm[2][2] == 0 ? true :
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;
@ -2862,7 +2875,8 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
hyperpoint VC0 = tC0(V);
if(intval(mouseh, VC0) < modist) {
if(inmirrorcount) ;
else if(intval(mouseh, VC0) < modist) {
modist2 = modist; mouseover2 = mouseover;
modist = intval(mouseh, VC0);
mouseover = c;
@ -2871,7 +2885,7 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
modist2 = intval(mouseh, VC0);
mouseover2 = c;
}
if(!torus) {
double dfc = euclid ? intval(VC0, C0) : VC0[2];
@ -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;
if(!buggyGeneration && c->mpdist > 8 && !cheater) return; // not yet generated
@ -2904,8 +2931,20 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
int wcol, fcol, asciicol;
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);
int zcol = fcol;
int zcol = fcol;
if(peace::on && peace::hint && c->land != laTortoise) {
int d =
@ -2918,6 +2957,11 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
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) {
int cd = celldistance(c, cwt.c);
string label = its(cd);
@ -3113,6 +3157,44 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
}
#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)) {
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)) {
zcol = wcol;
int wcol0 = wcol;
@ -4363,6 +4447,7 @@ void drawthemap() {
maxreclevel,
hsOrigin, ypush(vid.yshift) * sphereflip * View);
}
ivoryz = false;
linepatterns::drawAll();
@ -4589,6 +4674,7 @@ void drawfullmap() {
}
#endif
profile_start(2);
drawaura();
drawqueue();
profile_stop(2);

View File

@ -36,6 +36,15 @@ string buildHelpText() {
"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(
"There are many lands in HyperRogue. Collect 10 treasure "
"in the given land type to complete it; this enables you to "
@ -127,6 +136,7 @@ string helptitle(string s, int col) {
}
string princessReviveHelp() {
if(inv::on) return "";
string h = "\n\n" +
XLAT("Killed %1 can be revived with Orb of the Love, after you collect 20 more $$$.", moPrincess);
if(princess::reviveAt)
@ -136,7 +146,8 @@ string princessReviveHelp() {
}
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);
help += "\n\n" + XLAT(olrDescriptions[olr], cwt.c->land, tr, treasureType(cwt.c->land));
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) {
for(int i=0; i<ORBLINES; i++) {
const orbinfo& oi(orbinfos[i]);
@ -237,7 +293,7 @@ string generateHelpForItem(eItem it) {
help += XLAT("\n\nOrb unlocked: %1", oi.orb);
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);
describeOrb(help, oi);
}
@ -537,7 +593,7 @@ void describeMouseover() {
else if(c->wall != waInvisibleFloor) {
out = XLAT1(linf[c->land].name);
help = generateHelpForLand(c->land);
if(c->land == laIce || c->land == laCocytus)
out += " (" + fts(heat::celsius(c)) + " °C)";
if(c->land == laDryForest && c->landparam)
@ -561,27 +617,7 @@ void describeMouseover() {
if(c->land == laTortoise && tortoise::seek()) out += " " + tortoise::measure(getBits(c));
if(buggyGeneration) {
char buf[20]; sprintf(buf, " H=%d M=%d", 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)));
}
char buf[80]; sprintf(buf, " %p H=%d M=%d", c, c->landparam, c->mpdist); out += buf;
}
if(randomPatternsMode)

View File

@ -209,6 +209,14 @@ else if(args()[0] == '-' && args()[1] == x && args()[2] == '0') { if(curphase ==
else if(argis("-fix")) {
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")) {
int p;
shift(); sscanf(args(), "%d,%d,%d",

65
hyper.h
View File

@ -7,7 +7,7 @@
#define LB_YENDOR_CHALLENGE 40
#define LB_PURE_TACTICS 41
#define NUMLEADER 69
#define NUMLEADER 70
#define LB_PURE_TACTICS_SHMUP 49
#define LB_PURE_TACTICS_COOP 50
@ -73,6 +73,7 @@ eItem treasureType(eLand l);
void buildBarrier(cell *c, int d, eLand l = laNone);
void extendBarrier(cell *c);
bool buildBarrier4(cell *c, int d, int mode, eLand ll, eLand lr);
bool buildBarrier6(struct cellwalker cw, int type);
bool makeEmpty(cell *c);
bool isCrossroads(eLand l);
enum orbAction { roMouse, roKeyboard, roCheck, roMouseForce, roMultiCheck, roMultiGo };
@ -134,7 +135,8 @@ void activateActiv(cell *c, bool msg);
// shmup
struct charstyle {
int charid, skincolor, haircolor, dresscolor, swordcolor, dresscolor2, uicolor;
int charid;
unsigned skincolor, haircolor, dresscolor, swordcolor, dresscolor2, uicolor;
};
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 string& str, int color, int align);
extern int darken;
extern int darken, inmirrorcount;
void calcparam();
#ifdef USE_SDL
@ -395,7 +397,7 @@ namespace rug {
extern bool renderonce;
extern bool rendernogl;
extern int texturesize;
extern double scale;
extern ld scale;
void show();
void init();
void close();
@ -406,8 +408,6 @@ namespace rug {
#endif
#define HASLINEVIEW
#include <complex>
typedef complex<ld> cld;
namespace conformal {
extern bool on;
@ -440,7 +440,7 @@ namespace polygonal {
extern int SI;
extern ld STAR;
extern int deg;
extern complex<ld> coef[MSI];
extern ld coefr[MSI], coefi[MSI];
extern int maxcoef, coefid;
void solve();
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_FLYING (1<<7) // is flying
#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_JUMP2 (1<<11) // second part of a jump
#define P_TELE (1<<12) // teleport onto
@ -519,7 +520,7 @@ extern bool safety;
#define SAGEMELT .1
#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 WORMLENGTH 15
#define PUREHARDCORE_LEVEL 10
@ -540,7 +541,7 @@ bool isAlchAny(eWall w);
bool isAlchAny(cell *c);
#define YDIST 101
#define MODECODES 254
#define MODECODES 255
extern cellwalker cwt; // player character position
extern int sval;
@ -827,7 +828,7 @@ namespace dialog {
void addSelItem(string body, string value, int key);
void addBoolItem(string body, bool value, int key);
void addColorItem(string body, int value, int key);
void openColorDialog(int& col, unsigned int *pal = palette);
void openColorDialog(unsigned int& col, unsigned int *pal = palette);
void addHelp(string body);
void addInfo(string body, int color = 0xC0C0C0);
void addItem(string body, int key);
@ -1304,8 +1305,14 @@ bool createOnSea(eLand old);
namespace inv {
extern bool on;
extern bool usedForbidden;
extern int remaining[ittypes];
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);
@ -1327,6 +1334,9 @@ typedef hookset<void()> *purehookset;
template<class T, class U> int addHook(hookset<T>*& m, int prio, const U& hook) {
if(!m) m = new hookset<T> ();
while(m->count(prio)) {
prio++;
}
(*m)[prio] = hook;
return 0;
}
@ -1469,3 +1479,38 @@ namespace leader { void showMenu(); void handleKey(int sym, int uni); }
bool needConfirmation();
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"
1 VERSIONINFO
FILEVERSION 9,4,0,15
PRODUCTVERSION 9,4,0,15
FILEVERSION 9,4,0,13
PRODUCTVERSION 9,4,0,13
BEGIN
BLOCK "StringFileInfo"
BEGIN
@ -10,12 +10,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "Zeno Rogue"
VALUE "FileDescription", "A roguelike in non-euclidean space"
VALUE "FileVersion", "94n1"
VALUE "FileVersion", "A10.0"
VALUE "InternalName", "hyper"
VALUE "LegalCopyright", "Zeno Rogue"
VALUE "OriginalFilename", "hyper.exe"
VALUE "ProductName", "HyperRogue"
VALUE "ProductVersion", "9.4n1"
VALUE "ProductVersion", "10.0"
END
END

View File

@ -255,6 +255,11 @@ hyperpoint mirrorif(const hyperpoint& V, bool b) {
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
int away(const transmatrix& 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)) {
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);
}

View File

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

View File

@ -4,6 +4,19 @@
// 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;
cell *pathTowards(cell *pf, cell *pt) {
@ -57,7 +70,7 @@ int isNative(eLand l, eMonster m) {
case laAlchemist:
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;
case laMotion:
@ -217,7 +230,10 @@ eItem treasureType(eLand l) {
case laDesert: return itSpice;
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 laGraveyard: return itBone;
@ -310,7 +326,7 @@ eItem wanderingTreasure(cell *c) {
return treasureType(l);
}
#define ORBLINES 54
#define ORBLINES 56
struct orbinfo {
eLand l;
@ -350,6 +366,7 @@ const orbinfo orbinfos[ORBLINES] = {
{laOcean, 0, 3000, itOrbEmpathy},
{laOcean, 0, 0, itOrbAir},
{laPalace, 0, 4000, itOrbDiscord},
{laPalace, 0, 0, itOrbFrog},
{laZebra, 500, 2100, itOrbFrog},
{laLivefjord, 0, 1800, itOrbFish},
{laPrincessQuest, 0, 200, itOrbLove},
@ -374,6 +391,7 @@ const orbinfo orbinfos[ORBLINES] = {
{laReptile, 500, 2100, itOrbDash},
{laBull, 720, 3000, itOrbHorns},
{laPrairie, 0, 3500, itOrbBull},
{laWhirlpool, 0, 0, itOrbSafety},
{laWhirlpool, 0, 2000, itOrbWater}, // must be last because it generates a boat
};
@ -635,7 +653,8 @@ bool landUnlocked(eLand l) {
return true;
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;
case laCaribbean: case laWhirlpool:
@ -926,6 +945,10 @@ void setbarrier(cell *c) {
else if(c->barleft == laHaunted || c->barright == laHaunted) {
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 {
c->wall = waBarrier;
c->land = laBarrier;
@ -1016,24 +1039,36 @@ bool buildPrizeMirror(cell *c, int freq) {
return true;
}
void placePrizeOrb(cell *c) {
eLand getPrizeLand(cell *c = cwt.c) {
eLand l = c->land;
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;
eLand l = getPrizeLand(c);
// these two lands would have too much orbs according to normal rules
if(l == laPalace && hrand(100) >= 20) return;
if(l == laPrincessQuest && hrand(100) >= 20) return;
if(l == laGraveyard && hrand(100) >= 15) return;
if(l == laBurial && hrand(100) >= 10) return;
if(l == laLivefjord && hrand(100) >= 35) return;
if(l == laMinefield && 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++) {
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);
if(olr != olrPrize25 && olr != olrPrize3) continue;
int treas = items[treasureType(oi.l)];
@ -1069,7 +1104,10 @@ void placeLocalOrbs(cell *c) {
for(int i=0; i<ORBLINES; i++) {
const orbinfo& oi(orbinfos[i]);
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))
continue;
if(!oi.lchance) continue;
@ -1093,7 +1131,12 @@ void placeCrossroadOrbs(cell *c) {
for(int i=0; i<ORBLINES; i++) {
const orbinfo& oi(orbinfos[i]);
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);
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)
@ -1117,7 +1160,13 @@ void placeOceanOrbs(cell *c) {
if(peace::on) return;
for(int i=0; i<ORBLINES; 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(!oi.gchance) continue;
if(oi.orb == itOrbLife) continue; // useless
@ -1193,8 +1242,28 @@ void extendcheck(cell *c) {
raiseBuggyGeneration(c, "extend error");
}
}
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) {
limitgen("extend front %p\n", c);
if(buggyGeneration) return;
int ht = c->landparam;
extendcheck(c);
@ -1205,7 +1274,8 @@ void extendBarrierFront(cell *c) {
bb.c->barleft = c->barleft;
bb.c->barright = c->barright;
setbarrier(bb.c);
bb.c->landparam = (ht-4);
if(!mirrorwall(bb.c))
bb.c->landparam = (ht-4);
//printf("[A heat %d]\n", ht-4);
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->barright = c->barleft;
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);
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);
@ -1238,6 +1312,8 @@ void extendBarrierFront(cell *c) {
}
void extendBarrierBack(cell *c) {
limitgen("extend back %p\n", c);
if(buggyGeneration) return;
int ht = c->landparam;
extendcheck(c);
@ -1248,7 +1324,8 @@ void extendBarrierBack(cell *c) {
bb.c->bardir = bb.spin;
bb.c->barleft = c->barright;
bb.c->barright = c->barleft;
bb.c->landparam = ht ^ 11;
if(!mirrorwall(bb.c))
bb.c->landparam = ht ^ 11;
extendcheck(bb.c);
//printf("[D heat %d]\n", (ht^11));
@ -1257,7 +1334,8 @@ void extendBarrierBack(cell *c) {
cwstep(bb);
bb.c->barleft = c->barright;
bb.c->barright = c->barleft;
bb.c->landparam = (ht^11)-4;
if(!mirrorwall(bb.c))
bb.c->landparam = (ht^11)-4;
cwstep(bb);
}
//printf("[E heat %d]\n", (ht^11));
@ -1266,11 +1344,13 @@ void extendBarrierBack(cell *c) {
extendBarrier(bb.c);
}
eLand oppositeElement(eLand l) {
eLand oppositeElement(eLand l, eLand l2) {
if(l == laEFire) return laEWater;
if(l == laEWater) return laEFire;
if(l == laEAir) return laEEarth;
if(l == laEEarth) return laEAir;
if(l == laMirror && l2 == laMirrored) return laMirrored2;
if(l == laMirrored2 && l2 == laMirrored) return laMirror;
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) {
limitgen("extend barrier %p\n", c);
if(buggyGeneration) return;
if(c->barleft == NOWALLSEP_USED) return;
@ -1361,7 +1448,8 @@ void extendBarrier(cell *c) {
extendcheck(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");
return;
}
@ -1376,14 +1464,40 @@ void extendBarrier(cell *c) {
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) ||
(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);
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);
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;
}
else {
@ -1394,9 +1508,9 @@ void extendBarrier(cell *c) {
else {
cwspin(cw, 3); cwstep(cw);
cell *cp = cwpeek(cw, 4);
if(cp->wall != waBarrier && cp->land != laElementalWall) {
if(!isbar4(cp)) {
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;
}
else {
@ -1602,6 +1716,8 @@ eLand getNewLand(eLand old) {
eLand l = callhandlers(laNone, hooks_nextland, old);
if(l) return l;
if(old == laMirror && !oldmirror && hrand(10)) return laMirrored;
if(cheatdest != old) if(!isCyclic(cheatdest) && !isTechnicalLand(cheatdest)) return cheatdest;
@ -1927,7 +2043,7 @@ void buildBarrierForce(cell *c, int d, eLand l) {
landcount[newland]++;
if(d == 4 || d == 5 || d == 6) c->barleft = oldland, c->barright = newland;
else c->barleft = newland, c->barright = oldland;
c->landparam = 40;
if(!mirrorwall(c)) c->landparam = 40;
extendcheck(c);
}
@ -1939,7 +2055,124 @@ void buildBarrier(cell *c, int d, eLand 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) {
limitgen("build4 %p\n", c);
if(buggyGeneration) return true;
d %= 7;
cellwalker b1(c, d);
@ -1978,8 +2211,8 @@ bool buildBarrier4(cell *c, int d, int mode, eLand ll, eLand lr) {
return false;
}
eLand xl = oppositeElement(ll);
eLand xr = oppositeElement(lr);
eLand xl = oppositeElement(ll, lr);
eLand xr = oppositeElement(lr, ll);
c->bardir = d, c->barleft = ll, c->barright = lr; extendBarrierBack(c);
@ -2235,6 +2468,9 @@ int coastval(cell *c, eLand base) {
return 0;
if(c->land != laGraveyard && c->land != laHauntedBorder) return 30;
}
else if(base == laMirrored) {
if(!inmirror(c)) return 0;
}
else {
if(c->land == laOceanWall || c->land == laCaribbean || c->land == laWhirlpool ||
c->land == laLivefjord || c->land == laWarpSea || c->land == laKraken)
@ -2303,6 +2539,7 @@ void buildEquidistant(cell *c) {
// buggycells.push_back(c);
}
if(b == laHauntedBorder) b = laGraveyard;
if(inmirror(b)) b = laMirrored;
int mcv = UNKNOWN;
// find the lowest coastval
@ -2326,7 +2563,7 @@ void buildEquidistant(cell *c) {
for(int i=0; i<c->type; i++)
if(coastval(c->mov[i], b) == mcv)
qcv++, sid = i;
// if(generatingEquidistant) printf("qcv=%d mcv=%d\n", qcv, mcv);
if(qcv >= 2) c->landparam = mcv+1; // (mcv == UNKNOWN ? UNKNOWN : mcv+1);
else {
@ -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) {
if(sphere || quotient) return;
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 &&
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) &&
(c->land != laRlyeh || rlyehComplete()) &&
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) :
inmirror(c) ? 0 :
isGravityLand(c->land) ? 0 :
generatingEquidistant ? 0 :
c->land == laPrairie ? 0 :
@ -2915,6 +3157,7 @@ void buildBigStuff(cell *c, cell *from) {
(c->land == laGraveyard && items[itBone] >= 10) ? 120 :
c->land == laOcean ? (deepOcean ? (purehepta ? 250 : 2000) : 0) :
c->land == laDragon ? 120 :
(c->land == laMirror && !oldmirror) ? 6000 :
50))
{
@ -2927,7 +3170,7 @@ void buildBigStuff(cell *c, cell *from) {
}
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))) {
int rtr = newRoundTableRadius();
heptagon *alt = createAlternateMap(c, rtr+14, hsOrigin);
@ -2942,18 +3185,18 @@ void buildBigStuff(cell *c, cell *from) {
// buildbigstuff
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 &&
!tactic::on && !yendor::on)))
createAlternateMap(c, 2, hsA);
if(c->land == laJungle && c->type == 7 &&
(quickfind(laMountain) || (hrand(2000) < 100 &&
(quickfind(laMountain) || (hrand(I2000) < 100 &&
!randomPatternsMode && !tactic::on && !yendor::on && landUnlocked(laMountain))))
createAlternateMap(c, 2, hsA);
if(c->land == laOvergrown && c->type == 7 &&
(quickfind(laClearing) || (hrand(2000) < 25 &&
(quickfind(laClearing) || (hrand(I2000) < 25 &&
!randomPatternsMode && items[itMutant] >= U5 &&
!tactic::on && !yendor::on))) {
heptagon *h = createAlternateMap(c, 2, hsA);
@ -2977,8 +3220,11 @@ void buildBigStuff(cell *c, cell *from) {
(princess::forceMouse ? (from && from->pathdist != INF) :
(hrand(2000) < (peace::on ? 100 : 20))) &&
!c->master->alt &&
(princess::challenge || kills[moVizier] || peace::on) && !tactic::on && !yendor::on)
createAlternateMap(c, 141, hsOrigin, waPalace);
(princess::challenge || kills[moVizier] || peace::on) && !tactic::on && !yendor::on) {
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);
@ -3265,6 +3511,8 @@ void setdist(cell *c, int d, cell *from) {
if(d <= 3) lastexplore = shmup::on ? shmup::curtime : turncount;
oldmirror = euclid || chaosmode || yendor::on || yendor::generating;
if(buggyGeneration) {
if(d < BARLEV) for(int i=0; i<c->type; i++) {
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)
buildBigStuff(c, from);
if(buggyGeneration) return;
if(d < 10) {
explore[d]++;
exploreland[d][c->land]++;
@ -3322,6 +3572,9 @@ void setdist(cell *c, int d, cell *from) {
if(d == BARLEV-2 && c->land == laOcean)
buildEquidistant(c);
if(d == BARLEV-2 && inmirror(c))
buildEquidistant(c);
if(d == BARLEV-2 && (c->land == laGraveyard || c->land == laHauntedBorder || c->land == laHaunted))
buildEquidistant(c);
@ -3908,7 +4161,7 @@ void setdist(cell *c, int d, cell *from) {
if(c->land == laPalace && !euclid && c->master->alt) {
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)
@ -4734,9 +4987,12 @@ void setdist(cell *c, int d, cell *from) {
princess::getPrisonInfo(c) &&
(euclid || (princess::getPrisonInfo(c)->bestdist < 6 && princess::getPrisonInfo(c)->princess))) {
c->monst = moMouse;
addMessage(XLAT("You hear a distant squeak!"));
playSound(c, "mousesqueak");
drawBigFlash(c);
if(!princess::squeaked) {
addMessage(XLAT("You hear a distant squeak!"));
playSound(c, "mousesqueak");
drawBigFlash(c);
princess::squeaked = true;
}
/* {
cell *c2= c;
z:
@ -5024,7 +5280,7 @@ void setdist(cell *c, int d, cell *from) {
else {
if(hyperstonesUnlocked() && hrand(25000) < min(PT(tkills(), 2000), 5000) && notDippingFor(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!
eMonster cm = crossroadsMonster();
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((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;
else if(ishept(c) && hrand(5000) < 10 * PRIZEMUL)
else if(ishept(c) && hrand(5000/freqt) < 10 * PRIZEMUL)
placePrizeOrb(c);
else if(hrand(12000) < 8 + items[itShard] + hard)
else if(hrand(12000/freqt) < 8 + items[itShard] + hard)
c->monst = moRanger;
else if(hrand(60000) < 8 + items[itShard] + hard)
else if(hrand(60000/freqm) < 8 + items[itShard] + hard)
c->monst = moEagle;
}
if(c->land == laGraveyard) {
@ -5186,14 +5447,14 @@ void setdist(cell *c, int d, cell *from) {
bool wchance(int a, int of) {
of *= 10;
a += yendor::hardness() + items[itHolyGrail] + 1;
a += yendor::hardness() + 1;
if(isCrossroads(cwt.c->land))
a+= items[itHyperstone] * 10;
//if(cwt.c->land == laWhirlwind && !nowhirl) a += items[itWindstone] * 3;
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;
}
@ -5298,6 +5559,7 @@ void wandering() {
while(first7 < size(dcal)) {
int i = first7 + hrand(size(dcal) - first7);
cell *c = dcal[i];
if(inmirror(c)) continue;
if(smallbounded && !c->item && hrand(5) == 0 && c->land != laHalloween) {
if(passable(c, NULL, 0) || euclidland == laKraken) {
@ -5327,7 +5589,7 @@ void wandering() {
continue;
}
if(ghostcount && !c->monst) {
if(ghostcount && !c->monst && !inmirror(c)) {
c->monst = moGhost;
playSeenSound(c);
ghostcount--;

View File

@ -7,12 +7,12 @@
#define GEN_N 2
#define GEN_O 3
using namespace std;
#include <map>
#include <string>
#include <stdio.h>
#include <vector>
#include <stdlib.h>
using namespace std;
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("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("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("you have cheated %1 times", "liczba oszustw: %1")
S("%1 turns (%2)", "kolejek: %1 (%2)")
@ -5440,19 +5440,31 @@ S(
"Naciśnij '5' by opuścić podręcznik."
)
#undef Orb
/*
// for 10.0
*/
S("configure keys/joysticks", "konfiguracja klawiszy/joysticka")
S("Press F5 or 'o' to try again!", "Naciśnij F5 lub 'o' by spróbować jeszcze raz!")
S("peaceful mode", "tryb pokojowy")
S("inventory mode", "tryb inwentarza")
S("inventory", "sfery")
// Orb Strategy mode
S("Orb Strategy mode", "tryb strategii sfer")
S(
"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("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 to %2)", " (kolejny przy %1 do %2)")
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.",
"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(
"\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') {
painttype = 6;
paintwhat_str = "paint";
dialog::openColorDialog(paintwhat = (painttype ==6 ? paintwhat : 0x808080));
dialog::openColorDialog((unsigned&)(paintwhat = (painttype ==6 ? paintwhat : 0x808080)));
}
else if(sym == SDLK_F2) {
if(mapstream::saveMap(levelfile.c_str()))
@ -1219,7 +1219,7 @@ namespace mapeditor {
int dslayer;
bool coloring;
int colortouse = 0xC0C0C0FF;
unsigned int colortouse = 0xC0C0C0FFu;
transmatrix drawtrans, drawtransnew;
@ -1280,6 +1280,7 @@ namespace mapeditor {
void showDrawEditor() {
cmode = sm::DRAW;
gamescreen(0);
drawGrid();
if(!mouseout()) getcstat = '-';
@ -1882,7 +1883,7 @@ namespace mapeditor {
}
#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++) {
hyperpoint P2 = V * ds.list[a];
@ -1913,6 +1914,8 @@ namespace mapeditor {
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]);
int state = 0;
int gstate = 0;
@ -2004,27 +2007,27 @@ namespace linepatterns {
struct {
int id;
const char *lpname;
int color;
unsigned int color;
} patterns[] = {
{patTriNet, "triangle grid: not rings", (int) 0xFFFFFF00},
{patTriRings, "triangle grid: rings", (int) 0xFFFFFF00},
{patHepta, "heptagonal grid", (int) 0x0000C000},
{patRhomb, "rhombic tesselation", (int) 0x0000C000},
{patTrihepta, "triheptagonal tesselation", (int) 0x0000C000},
{patNormal, "normal tesselation", (int) 0x0000C000},
{patBigTriangles, "big triangular grid", (int) 0x00606000},
{patBigRings, "big triangles: rings", (int) 0x0000C000},
{patTriNet, "triangle grid: not rings", 0xFFFFFF00},
{patTriRings, "triangle grid: rings", 0xFFFFFF00},
{patHepta, "heptagonal grid", 0x0000C000},
{patRhomb, "rhombic tesselation", 0x0000C000},
{patTrihepta, "triheptagonal tesselation", 0x0000C000},
{patNormal, "normal tesselation", 0x0000C000},
{patBigTriangles, "big triangular grid", 0x00606000},
{patBigRings, "big triangles: rings", 0x0000C000},
{patTree, "underlying tree", (int) 0x00d0d000},
{patAltTree, "circle/horocycle tree", (int) 0xd000d000},
{patTree, "underlying tree", 0x00d0d000},
{patAltTree, "circle/horocycle tree", 0xd000d000},
{patZebraTriangles, "zebra triangles", (int) 0x40FF4000},
{patZebraLines, "zebra lines", (int) 0xFF000000},
{patVine, "vineyard pattern", (int) 0x8438A400},
{patPalacelike, "firewall lines", (int) 0xFF400000},
{patPalace, "firewall lines: Palace", (int) 0xFFD50000},
{patPower, "firewall lines: Power", (int) 0xFFFF0000},
{patZebraTriangles, "zebra triangles", 0x40FF4000},
{patZebraLines, "zebra lines", 0xFF000000},
{patVine, "vineyard pattern", 0x8438A400},
{patPalacelike, "firewall lines", 0xFF400000},
{patPalace, "firewall lines: Palace", 0xFFD50000},
{patPower, "firewall lines: Power", 0xFFFF0000},
{0, NULL, 0}
};

View File

@ -401,7 +401,7 @@ void showChangeMode() {
dialog::addBoolItem(XLAT("heptagonal mode"), (purehepta), '7');
dialog::addBoolItem(XLAT("Chaos mode"), (chaosmode), 'C');
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("Yendor Challenge"), (yendor::on), 'y');
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;
cwstep(lig);
if(inmirror(lig)) lig = mirror::reflect(lig);
cell *c = lig.c;
@ -1188,3 +1189,79 @@ eItem targetRangedOrb(cell *c, orbAction a) {
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],
shTriheptaFloor[11], shTriheptaFloor2[2], shTriheptaEuc[3],
shCross, shGiantStar[2], shLake, shMirror,
shHalfFloor[3], shHalfMirror[3],
shGem[2], shStar, shDisk, shDiskT, shDiskS, shDiskM, shDiskSq, shRing,
shEgg,
shSpikedRing, shTargetRing, shSawRing, shGearRing, shPeaceRing, shHeptaRing,
shSpearRing,
shSpearRing, shLoveRing,
shDaisy, shTriangle, shNecro, shStatue, shKey,
shGun,
shFigurine, shTreat,
@ -1112,6 +1113,36 @@ void buildpolys() {
}
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);
for(int i=0; i<=S84; i+=3)
hpcpush(ddi(i, crossf * .25) * C0);
@ -1242,6 +1273,13 @@ void buildpolys() {
bshape(shButterflyFloor[0], PPR_FLOOR, scalef*spzoom6, 325);
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[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);
}
void queuemarkerat(const transmatrix& V, int col) {
queuepolyat(V, shTriangle, col, PPR_LINE);
}
long double polydata[] = {
// shStarFloor[0] (6x1)
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]
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
};

View File

@ -19,13 +19,6 @@ string timeline() {
XLAT("%1 turns (%2)", its(turncount), buf);
}
struct hint {
time_t last;
function<bool()> usable;
function<void()> display;
function<void()> action;
};
void noaction() {}
function<void()> cancel = noaction;
@ -58,7 +51,7 @@ hint hints[] = {
},
[]() {
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!"));
},
noaction},
@ -97,7 +90,7 @@ hint hints[] = {
[]() { return !inv::on; },
[]() {
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!"
));
},
@ -136,7 +129,7 @@ hint hints[] = {
0,
[]() { return !canmove; },
[]() {
dialog::addInfo(XLAT(
dialog::addHelp(XLAT(
"Want another type of game? Want more challenge?\n"
"HyperRogue has many special modes and challenges that "
"significantly change the gameplay. Try them!"
@ -174,8 +167,6 @@ hint hints[] = {
dialog::addBreak(50);
#ifdef INF
dialog::addItem(XLAT("Orb Strategy mode"), 'z');
#else
dialog::addItem(XLAT("(paid versions only)"), 'z');
#endif
},
[]() {
@ -193,7 +184,7 @@ hint hints[] = {
"This is far from the truth!\n"
));
dialog::addBreak(50);
dialog::addItem(XLAT("Hypersian Rug mode"), 'z');
dialog::addItem(XLAT("hypersian rug mode"), 'z');
},
[] () {
popScreen();
@ -217,7 +208,7 @@ hint hints[] = {
[]() {
dialog::addHelp(XLAT(
"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::addItem(XLAT("Show me!"), 'z');
@ -299,6 +290,10 @@ hint hints[] = {
int hinttoshow;
string contstr() {
return XLAT(canmove ? "continue" : "see how it ended");
}
void showMission() {
cmode = sm::DOTOUR | sm::MISSION | sm::CENTER;
@ -439,9 +434,11 @@ void showMission() {
#endif
}
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("restart"), SDLK_F5);
if(inv::on && items[itInventory])
dialog::addItem(XLAT("inventory"), 'i');
#ifndef MOBILE
dialog::addItem(XLAT(quitsaves() ? "save" : "quit"), SDLK_F10);
#endif
@ -469,7 +466,7 @@ void handleKeyQuit(int sym, int uni) {
if(sym == SDLK_RETURN || sym == SDLK_KP_ENTER || sym == SDLK_F10) quitmainloop = true;
else if(uni == 'r' || sym == SDLK_F5) {
restartGame(), popScreen();
restartGame();
msgs.clear();
}
else if(sym == SDLK_UP || sym == SDLK_KP8 || sym == PSEUDOKEY_WHEELUP) msgscroll++;
@ -524,5 +521,7 @@ void showMissionScreen() {
}
hints[hinttoshow].last = time(NULL);
}
dialog::highlight_text = contstr();
}

View File

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

View File

@ -39,6 +39,7 @@ bool isHardcore(score *S) {
int modediff(score *S) {
int diff = 0;
eGeometry g = (eGeometry) S->box[116];
if(S->box[306] != inv::on) diff += 4;
if(S->box[238]) g = gSphere;
if(S->box[239]) g = gElliptic;
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[119]) s += "/s";
if(S->box[197] > 1) s += "/P" + its(S->box[197]);
if(S->box[306]) s += "/i";
if(isHardcore(S)) s += "/h";
return s;
}
@ -301,7 +303,7 @@ void load() {
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];
// the first executable on Steam included a corruption
if(sc.box[65] > 1420000000 && sc.box[65] < 1430000000) {

233
shmup.cpp
View File

@ -60,6 +60,9 @@ namespace multi {
movedir whereto[MAXPLAYER]; // player's target cell
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] = {
"forward", "backward", "turn left", "turn right",
@ -77,13 +80,15 @@ namespace multi {
""
};
const char* pancmds[7] = {
const char* pancmds[11] = {
"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 ((SHMUPAXES_BASE) + 4 * (MAXPLAYER))
#define SHMUPAXES_CUR ((SHMUPAXES_BASE) + 4 * vid.scfg.players)
const char* axemodes[SHMUPAXES] = {
"do nothing",
@ -122,44 +127,6 @@ const char* axemodes[SHMUPAXES] = {
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;
const char** shmupcmdtable;
@ -213,15 +180,16 @@ void handleConfig(int sym, int uni);
void showShmupConfig() {
#ifndef NOSDL
cmode = sm::SHMUPCONFIG;
int sc = vid.scfg.subconfig;
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;
}
else if(sc == 3) {
shmupnumkeys = 7;
shmupnumkeys = CMDS_PAN;
shmupcmdtable = pancmds;
}
else if(sc == SCJOY) {
@ -304,7 +272,7 @@ void showShmupConfig() {
else dialog::addBreak(100);
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);
if(numsticks > 0) {
@ -442,8 +410,8 @@ help += XLAT("This menu can be also used to configure keys.\n\n");
else {
int v = (*axeconfigs[xuni - 'a']);
v += (shiftmul>0?1:-1);
v += SHMUPAXES;
v %= SHMUPAXES;
v += SHMUPAXES_CUR;
v %= SHMUPAXES_CUR;
(*axeconfigs[xuni - 'a']) = v;
}
}
@ -494,63 +462,7 @@ bool notremapped(int sym) {
return k > multi::players;
}
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(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};
#ifndef NOCONFIG
void initConfig() {
vid.scfg.players = 1;
@ -650,8 +562,125 @@ void initConfig() {
multi::scs[4].uicolor = 0xC000C0FF;
multi::scs[5].uicolor = 0x00C0C0FF;
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) {
multi::player[i].c = NULL;
multi::deaths[i]++;

View File

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

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 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 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 llts(long long i) {
// sprintf does not work on Windows IIRC

View File

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