further work for 10.0

This commit is contained in:
Zeno Rogue 2017-07-12 18:03:53 +02:00
parent a22eef683f
commit 94efef5d65
20 changed files with 441 additions and 661 deletions

View File

@ -1003,7 +1003,7 @@ void setvideomode() {
flags = SDL_OPENGL | SDL_HWSURFACE | SDL_GL_DOUBLEBUFFER;
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 1);
if(vid.antialias && AA_MULTI) {
if(vid.antialias & AA_MULTI) {
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 16);
glEnable(GL_MULTISAMPLE);

View File

@ -1703,3 +1703,34 @@
- added a missing russian translation
- [RogueViz] fixed legend in the svg/high quality output
- more control for text in svg output
2017.07.04 14:40 work in progress
- peaceful mode (work in progress)
- anti-aliased lines, and linewidth setting, option to make lines further from the model center narrower
- rearranged the menus
- '9' key to list all the frames in the current slideshow; better support for multiple slideshows compiled in
- configurable border and foreground color (mostly for presentations, not available in the menus)
- aura effect adjusts to the background color
- nicer text frames
- aura in the spherical geometry
- fixed the Hypersian Rug on some machines (using another OpenGL function), glew used on Linux
- unicode superscript d is now used in the expansion screen instead of "^d"
- some preparation for the Inventory Mode
- texts changed, some minor translation fixes
- fixed the default wsad keys
- [technical] improved the NOGL compilation flag to avoid OpenGL
- [technical] refactoring (gotoHelp, sdltogl)
- [technical] changed #ifdef LOCAL to #ifdef EXTRA_...; extra features are now included by starting the compilation from another file
- [technical] HYPERPATH added, for reaching the files when HyperRogue is called from a different location
- [technical] private source files moved to the "private" dir
- antialiased multisampling
- major refactoring: return to previous menu
- image in the character selection screen
- ignore zero-score games
- do not save zero-score games
- consistency in menu
- multiple selectable columns in scores
- menu -> scores => list the current game if in game over
- yendor hardness fix
- hints shown on the quest status/quit screen

View File

@ -736,7 +736,7 @@ enum eMonster {
// shmup specials
moPlayer, moBullet, moFlailBullet, moFireball, moTongue, moAirball,
// temporary
moDeadBug, moLightningBolt, moDeadBird, moEnergySword, moWarning,
moDeadBug, moLightningBolt, moDeadBird, moEnergySword, moWarning,
moRogueviz
};
@ -767,7 +767,7 @@ genderswitch_t genderswitch[NUM_GS] = {
// --- items ---
const int ittypes = 111;
const int ittypes = 112;
struct itemtype {
char glyph;
@ -1153,6 +1153,7 @@ itemtype iinf[ittypes] = {
"with this Orb." },
{ '$', 0xC060C0, "Spinel", bulldashdesc },
{ 'o', 0xC0C0FF, "Orb of the Mirror", NODESCYET },
{ 'O', 0xF0F0F0, "your orbs", NODESC},
};
enum eItem { itNone, itDiamond, itGold, itSpice, itRuby, itElixir, itShard, itBone, itHell, itStatue,
@ -1185,7 +1186,8 @@ enum eItem { itNone, itDiamond, itGold, itSpice, itRuby, itElixir, itShard, itBo
itOrbSword, itKraken, itOrbSword2, itBarrow,
itTrollEgg, itWarning, itOrbStone, itOrbNature, itTreat,
itSlime, itAmethyst, itOrbRecall, itDodeca, itOrbDash, itGreenGrass, itOrbHorns,
itOrbBull, itBull, itOrbMirror
itOrbBull, itBull, itOrbMirror,
itInventory
};
// --- wall types ---

View File

@ -589,6 +589,8 @@ namespace princess {
achievement_gain("PRINCESS1");
princess::saved = true;
princess::everSaved = true;
if(inv::on && !princess::reviveAt)
princess::reviveAt = gold(NO_LOVE);
items[itSavedPrincess]++;
}
if(newdist == OUT_OF_PRISON && princess::challenge) {

View File

@ -407,6 +407,8 @@ void showAllConfig() {
dialog::addItem(XLAT("exit configuration"), 'v');
#ifndef NOCONFIG
dialog::addItem(XLAT("save the current config"), 's');
if(getcstat == 's')
mouseovers = XLAT("Config file: %1", conffile);
#endif
}
@ -448,6 +450,8 @@ void showGraphConfig() {
#ifndef MOBWEB
dialog::addSelItem(XLAT("framerate limit"), its(vid.framelimit), 'l');
if(getcstat == 'l')
mouseovers = XLAT("Reduce the framerate limit to conserve CPU energy");
#endif
#ifndef IOS
@ -455,6 +459,7 @@ void showGraphConfig() {
#endif
dialog::addSelItem(XLAT("scrolling speed"), fts(vid.sspeed), 'a');
dialog::addSelItem(XLAT("movement animation speed"), fts(vid.mspeed), 'm');
dialog::addBoolItem(XLAT("extra graphical effects"), (vid.particles), 'u');
@ -508,7 +513,9 @@ void showGraphConfig() {
if(xuni == 'a') dialog::editNumber(vid.sspeed, -5, 5, 1, 0,
XLAT("scrolling speed"),
XLAT("+5 = center instantly, -5 = do not center the map"));
XLAT("+5 = center instantly, -5 = do not center the map")
+ "\n\n" +
XLAT("press Space or Home to center on the PC"));
if(xuni == 'm') dialog::editNumber(vid.mspeed, -5, 5, 1, 0,
XLAT("movement animation speed"),
@ -613,6 +620,8 @@ void showBasicConfig() {
dialog::addSelItem(XLAT("language"), XLAT("EN"), 'l');
#endif
dialog::addSelItem(XLAT("player character"), numplayers() > 1 ? "" : csname(vid.cs), 'g');
if(getcstat == 'g')
mouseovers = XLAT("Affects looks and grammar");
#ifndef NOAUDIO
dialog::addSelItem(XLAT("background music volume"), its(musicvolume), 'b');
@ -719,6 +728,12 @@ void showJoyConfig() {
#ifndef MOBWEB
dialog::addSelItem(XLAT("joystick mode"), XLAT(autojoy ? "automatic" : "manual"), 'p');
if(getcstat == 'p') {
if(autojoy)
mouseovers = XLAT("joystick mode: automatic (release the joystick to move)");
if(!autojoy)
mouseovers = XLAT("joystick mode: manual (press a button to move)");
}
dialog::addSelItem(XLAT("first joystick: movement threshold"), its(vid.joyvalue), 'a');
dialog::addSelItem(XLAT("first joystick: execute movement threshold"), its(vid.joyvalue2), 'b');

View File

@ -10,7 +10,7 @@ bool gtouched;
int getcstat, lgetcstat; ld getcshift; bool inslider;
int andmode = 0;
function <void(int sym, int uni)> keyhandler;
// is the player using mouse? (used for auto-cross)
bool mousing = true;
@ -32,12 +32,6 @@ int lastt;
Uint8 *SDL_GetKeyState(void *v) { static Uint8 tab[1024]; return tab; }
#endif
bool quitsaves() { return (items[itOrbSafety] && havesave); }
bool needConfirmation() {
return canmove && (gold() >= 30 || tkills() >= 50) && !cheater && !quitsaves();
}
bool mouseout() {
if((getcstat != '-' && getcstat) || (lgetcstat && lgetcstat != '-')) return true;
return outofmap(mouseh);
@ -210,52 +204,6 @@ bool doexiton(int sym, int uni) {
return false;
}
void handleKeyQuit(int sym, int uni) {
dialog::handleNavigation(sym, uni);
// ignore the camera movement keys
#ifndef NORUG
if(rug::rugged && (sym == SDLK_UP || sym == SDLK_DOWN || sym == SDLK_PAGEUP || sym == SDLK_PAGEDOWN ||
sym == SDLK_RIGHT || sym == SDLK_LEFT))
sym = 0;
#endif
if(sym == SDLK_RETURN || sym == SDLK_KP_ENTER || sym == SDLK_F10) quitmainloop = true;
else if(uni == 'r' || sym == SDLK_F5) {
restartGame(), popScreen();
msgs.clear();
}
else if(sym == SDLK_UP || sym == SDLK_KP8 || sym == PSEUDOKEY_WHEELUP) msgscroll++;
else if(sym == SDLK_DOWN || sym == SDLK_KP2 || sym == PSEUDOKEY_WHEELDOWN) msgscroll--;
else if(sym == SDLK_PAGEUP || sym == SDLK_KP9) msgscroll+=5;
else if(sym == SDLK_PAGEDOWN || sym == SDLK_KP3) msgscroll-=5;
else if(uni == 'v') popScreenAll(), pushScreen(showMainMenu);
else if(sym == SDLK_F3 || (sym == ' ' || sym == SDLK_HOME))
fullcenter();
else if(uni == 'o' && DEFAULTNOR(sym)) setAppropriateOverview();
#ifdef INV
else if(uni == 'i' && DEFAULTNOR(sym) && inv::on)
pushScreen(inv::show);
#endif
#ifndef NOSAVE
else if(uni == 't') {
if(!canmove) restartGame();
loadScores();
msgs.clear();
}
#endif
else if(doexiton(sym, uni) && !didsomething) {
popScreen();
msgscroll = 0;
msgs.clear();
if(!canmove) {
addMessage(XLAT("GAME OVER"));
addMessage(timeline());
}
}
}
bool didsomething;
#ifdef MOBILE
@ -396,24 +344,6 @@ void handleKeyNormal(int sym, int uni) {
else quitmainloop = true;
}
if(!canmove) {
if(sym == SDLK_RETURN || sym == SDLK_KP_ENTER) quitmainloop = true;
else if(uni == 'r') restartGame();
#ifndef NOSAVE
else if(uni == 't') {
restartGame();
loadScores();
}
#endif
#ifndef NORUG
else if(rug::rugged) ;
#endif
else if(sym == SDLK_UP || sym == SDLK_KP8) msgscroll++;
else if(sym == SDLK_DOWN || sym == SDLK_KP2) msgscroll--;
else if(sym == SDLK_PAGEUP || sym == SDLK_KP9) msgscroll+=5;
else if(sym == SDLK_PAGEDOWN || sym == SDLK_KP3) msgscroll-=5;
}
if(uni == 'o' && DEFAULTNOR(sym)) setAppropriateOverview();
#ifdef INV
if(uni == 'i' && DEFAULTNOR(sym) && inv::on)
@ -776,3 +706,17 @@ void displayabutton(int px, int py, string s, int col) {
}
#endif
void gmodekeys(int sym, int uni) {
if(uni == '1') { vid.alpha = 999; vid.scale = 998; }
if(uni == '2') { vid.alpha = 1; vid.scale = 0.4; }
if(uni == '3') { vid.alpha = 1; vid.scale = 1; }
if(uni == '4') { vid.alpha = 0; vid.scale = 1; }
if(uni == '5') { vid.wallmode += 60 + (shiftmul > 0 ? 1 : -1); vid.wallmode %= 6; }
if(uni == '6') vid.grid = !vid.grid;
if(uni == '7') { vid.darkhepta = !vid.darkhepta; }
if(uni == '%' && sym == '5') {
if(vid.wallmode == 0) vid.wallmode = 6;
vid.wallmode--;
}
}

View File

@ -267,7 +267,7 @@ int itemclass(eItem i) {
if(i == itSavedPrincess || i == itStrongWind || i == itWarning)
return IC_NAI;
if(i == itKey || i == itOrbYendor || i == itGreenStone || i == itHolyGrail || i == itCompass ||
isElementalShard(i) || i == itRevolver)
isElementalShard(i) || i == itRevolver || i == itInventory)
return IC_OTHER;
return IC_ORB;
}

112
game.cpp
View File

@ -189,15 +189,6 @@ bool itemHiddenFromSight(cell *c) {
&& !(shmup::on && shmup::boatAt(c));
}
int puregold() {
int i = items[itOrbYendor] * 50 + items[itHolyGrail] * 10;
if(items[itOrbLove]) i += 30;
for(int t=0; t<ittypes; t++)
if(itemclass(eItem(t)) == IC_TREASURE)
i += items[t];
return i;
}
int numplayers() {
return multi::players;
}
@ -273,8 +264,24 @@ void countLocalTreasure() {
}
}
int gold() {
return puregold();
int gold(int no) {
int i = 0;
if(!(no & NO_YENDOR)) i += items[itOrbYendor] * 50;
if(!(no & NO_GRAIL)) i += items[itHolyGrail] * 10;
if(!(no & NO_LOVE)) {
bool love = items[itOrbLove];
#ifdef INV
if(inv::on && inv::remaining[itOrbLove])
love = true;
#endif
if(love) i += 30;
}
if(!(no & NO_TREASURE))
for(int t=0; t<ittypes; t++)
if(itemclass(eItem(t)) == IC_TREASURE)
i += items[t];
return i;
}
int maxgold() {
@ -1721,9 +1728,9 @@ void killMonster(cell *c, eMonster who, flagtype deathflags) {
i->princess = NULL;
if(i->bestdist == OUT_OF_PALACE) {
items[itSavedPrincess]--;
if(items[itSavedPrincess] == 0) {
if(items[itSavedPrincess] == 0 && !inv::on) {
items[itOrbLove] = 0;
princess::reviveAt = gold() + 20;
princess::reviveAt = gold(NO_LOVE) + 20;
}
}
if(princess::challenge) showMissionScreen();
@ -2154,13 +2161,13 @@ bool attackMonster(cell *c, flagtype flags, eMonster killer) {
addMessage(XLAT("That was easy, but groups could be dangerous."));
}
if(tk < 10 && ntk >= 10 && !tactic::on && !euclid && !sphere)
if(tk < 10 && ntk >= 10 && !tactic::on && !euclid && !sphere && !inv::on)
addMessage(XLAT("Good to know that your fighting skills serve you well in this strange world."));
if(tk < 50 && ntk >= 50 && !euclid && !sphere)
if(tk < R100/2 && ntk >= R100/2 && !euclid && !sphere)
addMessage(XLAT("You wonder where all these monsters go, after their death..."));
if(tk < 100 && ntk >= 100 && !euclid && !sphere)
if(tk < R100 && ntk >= R100 && !euclid && !sphere)
addMessage(XLAT("You feel that the souls of slain enemies pull you to the Graveyard..."));
if(!tu && trollUnlocked()) {
@ -5429,6 +5436,10 @@ void checkmove() {
for(int i=0; i<ittypes; i++) orbused[i] = orbusedbak[i];
if(recallCell && !markOrb(itOrbRecall)) activateRecall();
#ifdef INV
if(inv::on) inv::compute();
#endif
}
// move the PC. Warning: a very long function! todo: refactor
@ -5586,48 +5597,55 @@ void collectMessage(cell *c2, eItem which) {
addMessage(XLAT("Prove yourself here, then find new lands, with new quests..."));
else if(!items[which] && itemclass(which) == IC_TREASURE)
addMessage(XLAT("You collect your first %1!", which));
else if(items[which] == 4 && maxgold() == 4 && !specialmode) {
else if(items[which] == 4 && maxgold() == U5-1 && !specialmode) {
addMessage(XLAT("You feel that %the2 become%s2 more dangerous.", which, c2->land));
addMessage(XLAT("With each %1 you collect...", which, c2->land));
}
else if(items[which] == 9 && maxgold() == 9 && !specialmode)
addMessage(XLAT("Are there any magical orbs in %the1?...", c2->land));
else if(items[which] == 10 && maxgold() == 10 && !specialmode) {
else if(items[which] == 9 && maxgold() == 9 && !specialmode) {
if(inv::on) {
addMessage(XLAT("The treasure gives your magical powers!", c2->land));
if(!ISMOBILE)
addMessage(XLAT("Press 'i' to access your magical powers.", c2->land));
}
else
addMessage(XLAT("Are there any magical orbs in %the1?...", c2->land));
}
else if(items[which] == R10 && maxgold() == R10 && !specialmode && !inv::on) {
addMessage(XLAT("You feel that %the1 slowly become%s1 dangerous...", c2->land));
addMessage(XLAT("Better find some other place."));
}
else if(which == itSpice && items[itSpice] == 7 && !specialmode)
else if(which == itSpice && items[itSpice] == U10*7/10 && !specialmode)
addMessage(XLAT("You have a vision of the future, fighting demons in Hell..."));
else if(which == itSpice && items[itSpice] == 9 && !specialmode)
else if(which == itSpice && items[itSpice] == U10-1 && !specialmode)
addMessage(XLAT("You will be fighting red rock snakes, too..."));
else if(which == itKraken && items[itKraken] == 9 && !specialmode)
else if(which == itKraken && items[itKraken] == U10-1 && !specialmode)
addMessage(XLAT("You feel that a magical weapon is waiting for you..."));
// else if(which == itFeather && items[itFeather] == 10)
// addMessage(XLAT("There should be a Palace somewhere nearby..."));
else if(which == itElixir && items[itElixir] == 4 && !specialmode)
else if(which == itElixir && items[itElixir] == U5-1 && !specialmode)
addMessage(XLAT("With this Elixir, your life should be long and prosperous..."));
else if(which == itRuby && items[itRuby] == 4 && !specialmode) {
else if(which == itRuby && items[itRuby] == U5-1 && !specialmode) {
addMessage(XLAT("You feel something strange about gravity here..."));
}
else if(which == itPalace && items[itPalace] == 4 && !specialmode) {
else if(which == itPalace && items[itPalace] == U5-1 && !specialmode) {
addMessage(XLAT("The rug depicts a man in a deep dungeon, unable to leave."));
}
else if(which == itIvory && items[itIvory] == 4 && !specialmode) {
else if(which == itIvory && items[itIvory] == U5-1 && !specialmode) {
addMessage(XLAT("You feel attuned to gravity, ready to face mountains and dungeons."));
}
else if(which == itBone && items[itBone] == 6 && !specialmode)
else if(which == itBone && items[itBone] == U5+1 && !specialmode)
addMessage(XLAT("The Necromancer's Totem contains hellish incantations..."));
else if(which == itStatue && items[itStatue] == 6 && !specialmode)
else if(which == itStatue && items[itStatue] == U5+1 && !specialmode)
addMessage(XLAT("The inscriptions on the Statue of Cthulhu point you toward your destiny..."));
else if(which == itStatue && items[itStatue] == 4 && !specialmode)
else if(which == itStatue && items[itStatue] == U5-1 && !specialmode)
addMessage(XLAT("There must be some temples of Cthulhu in R'Lyeh..."));
else if(which == itDiamond && items[itDiamond] == 8 && !specialmode)
else if(which == itDiamond && items[itDiamond] == U10-2 && !specialmode)
addMessage(XLAT("Still, even greater treasures lie ahead..."));
else if(which == itFernFlower && items[itFernFlower] == 4 && !specialmode)
else if(which == itFernFlower && items[itFernFlower] == U5-1 && !specialmode)
addMessage(XLAT("You overheard Hedgehog Warriors talking about emeralds..."));
else if(which == itEmerald && items[itEmerald] == 4 && !specialmode && !chaosmode)
else if(which == itEmerald && items[itEmerald] == U5-1 && !specialmode && !chaosmode)
addMessage(XLAT("You overhear miners talking about a castle..."));
else if(which == itEmerald && items[itEmerald] == 5 && !specialmode && !chaosmode)
else if(which == itEmerald && items[itEmerald] == U5 && !specialmode && !chaosmode)
addMessage(XLAT("A castle in the Crossroads..."));
else if(which == itShard) ;
else {
@ -5983,21 +6001,23 @@ bool collectItem(cell *c2, bool telekinesis) {
}
#ifdef MOBILE
if(pg < lastsafety + 45 && g2 >= lastsafety + 45)
if(pg < lastsafety + R30*3/2 && g2 >= lastsafety + R30*3/2)
addMessage(XLAT("The Orb of Safety from the Land of Eternal Motion might save you."));
#endif
if(pg < 15 && g2 >= 15)
#define IF(x) if(pg < (x) && g2 >= x)
IF(R60/4)
addMessage(XLAT("Collect treasure to access more different lands..."));
if(pg < 30 && g2 >= 30)
IF(R30)
addMessage(XLAT("You feel that you have enough treasure to access new lands!"));
if(pg < 45 && g2 >= 45)
IF(R30*3/2)
addMessage(XLAT("Collect more treasures, there are still more lands waiting..."));
if(pg < 60 && g2 >= 60)
IF(R60)
addMessage(XLAT("You feel that the stars are right, and you can access R'Lyeh!"));
if(pg < 75 && g2 >= 75)
IF(R30*5/2)
addMessage(XLAT("Kill monsters and collect treasures, and you may get access to Hell..."));
if(pg < 90 && g2 >= 90)
IF(R10 * 9)
addMessage(XLAT("To access Hell, collect %1 treasures each of 9 kinds...", its(R10)));
if(hellUnlocked() && !lhu) {
addMessage(XLAT("Abandon all hope, the gates of Hell are opened!"));
@ -6021,7 +6041,7 @@ bool collectItem(cell *c2, bool telekinesis) {
numOrb++;
if(numOrb) achievement_count("ORB", numOrb, 0);
if(princess::reviveAt && gold() >= princess::reviveAt) {
if(princess::reviveAt && gold(NO_LOVE) >= princess::reviveAt && !inv::on) {
princess::reviveAt = 0,
items[itSavedPrincess] = 1;
addMessage("You have enough treasure now to revive the Princess!");
@ -6095,8 +6115,12 @@ void roundTableMessage(cell *c2) {
}
long long circlesize[100], disksize[100];
ld circlesizeD[10000];
int lastsize;
void computeSizes() {
lastsize = purehepta ? 44 : 76;
circlesize[0] = 1;
if(!purehepta) {
@ -6168,12 +6192,12 @@ void knightFlavorMessage(cell *c2) {
addMessage(XLAT("\"Train in the Desert first!\""));
}
else if(msgid == 8) {
if(rad <= 76)
if(rad <= lastsize)
addMessage(XLAT("\"Our Table seats %1 Knights!\"", llts(circlesize[rad])));
else
addMessage(XLAT("\"By now, you should have your own formula, you know?\""));
}
else if(msgid == 9 && rad <= 76) {
else if(msgid == 9 && rad <= lastsize) {
addMessage(XLAT("\"There are %1 floor tiles inside our Table!\"", llts(disksize[rad])));
}
else if(msgid == 10 && !items[itPirate] && !items[itWhirlpool]) {

View File

@ -602,7 +602,7 @@ bool drawItemType(eItem it, cell *c, const transmatrix& V, int icol, int ticks,
queuepolyat(V * spin(ticks / 1500. + M_PI/(ct6+6)), *xsh, darkena(0x202020, 0, hidden ? 0x40 : 0xF0), PPR_ITEMb);
}
else if(xch == 'o') {
else if(xch == 'o' || it == itInventory) {
if(it == itOrbFire) icol = firecolor(100);
queuepoly(V, shDisk, darkena(icol, 0, hidden ? 0x20 : 0xC0));
if(it == itOrbFire) icol = firecolor(200);
@ -4330,13 +4330,7 @@ void drawthemap() {
mapeditor::ewsearch.dist = 1e30;
modist = 1e20; mouseover = NULL;
modist2 = 1e20; mouseover2 = NULL;
mouseovers = XLAT("Press F1 or right click for help");
#ifdef ROGUEVIZ
if(rogueviz::on) mouseovers = " ";
#endif
#ifdef TOUR
if(tour::on) mouseovers = tour::tourhelp;
#endif
centdist = 1e20;
if(!torus) centerover = NULL;
@ -4643,6 +4637,16 @@ void gamescreen(int _darken) {
void normalscreen() {
help = "@";
#ifdef ROGUEVIZ
if(!rogueviz::on)
#endif
mouseovers = XLAT("Press F1 or right click for help");
#ifdef TOUR
if(tour::on) mouseovers = tour::tourhelp;
#endif
if(!outofmap(mouseh)) getcstat = '-';
cmode2 = smNormal;
gamescreen(hiliteclick && mmmon ? 1 : 0); drawStats();
@ -4655,6 +4659,8 @@ void normalscreen() {
#endif
displayButton(vid.xres-8, vid.yres-vid.fsize, XLAT("(v) menu"), 'v', 16);
keyhandler = handleKeyNormal;
describeMouseover();
}
vector< function<void()> > screens = { normalscreen };
@ -4689,14 +4695,21 @@ void drawscreen() {
lgetcstat = getcstat;
getcstat = 0; inslider = false;
mouseovers = " ";
cmode2 = smMenu;
keyhandler = [] (int sym, int uni) { return false; };
screens.back()();
int col = linf[cwt.c->land].color;
if(cwt.c->land == laRedRock) col = 0xC00000;
#ifndef MOBILE
displayfr(vid.xres/2, vid.fsize, 2, vid.fsize, mouseovers, col, 8);
#endif
drawmessages();
describeMouseover();
if((havewhat&HF_BUG) && darken == 0 && cmode2 == smNormal) for(int k=0; k<3; k++)
displayfr(vid.xres/2 + vid.fsize * 5 * (k-1), vid.fsize*2, 2, vid.fsize,
its(hive::bugcount[k]), minf[moBug0+k].color, 8);

113
help.cpp
View File

@ -60,7 +60,9 @@ string buildHelpText() {
h += XLAT(
"You can right click any element to get more information about it.\n\n"
);
#ifdef MAC
h += XLAT("(You can also use right Shift)\n\n");
#endif
#endif
h += XLAT("See more on the website: ")
+ "http//roguetemple.com/z/hyper/\n\n";
@ -158,7 +160,7 @@ string generateHelpForItem(eItem it) {
help += XLAT(iinf[it].help);
if(it == itSavedPrincess || it == itOrbLove)
if(it == itSavedPrincess || it == itOrbLove) if(!inv::on)
help += princessReviveHelp();
if(it == itTrollEgg)
@ -530,16 +532,12 @@ void describeMouseover() {
DEBB(DF_GRAPH, (debugfile,"describeMouseover\n"));
cell *c = mousing ? mouseover : playermoved ? NULL : centerover;
string out = mouseovers;
if(!c || instat || getcstat) { }
string& out = mouseovers;
if(!c || instat || getcstat != '-') { }
else if(c->wall != waInvisibleFloor) {
out = XLAT1(linf[c->land].name);
help = generateHelpForLand(c->land);
// Celsius
// if(c->land == laIce) out = "Icy Lands (" + fts(60 * (c->heat - .4)) + " C)";
if(c->land == laIce || c->land == laCocytus)
out += " (" + fts(heat::celsius(c)) + " °C)";
if(c->land == laDryForest && c->landparam)
@ -562,29 +560,10 @@ void describeMouseover() {
if(c->land == laTortoise && tortoise::seek()) out += " " + tortoise::measure(getBits(c));
/* if(c->land == laGraveyard || c->land == laHauntedBorder || c->land == laHaunted)
out += " (" + its(c->landparam)+")"; */
if(buggyGeneration) {
char buf[20]; sprintf(buf, " H=%d M=%d", c->landparam, c->mpdist); out += buf;
}
// if(c->land == laBarrier)
// out += "(" + string(linf[c->barleft].name) + " / " + string(linf[c->barright].name) + ")";
// out += "(" + its(c->bardir) + ":" + string(linf[c->barleft].name) + " / " + string(linf[c->barright].name) + ")";
// out += " MD"+its(c->mpdist);
// out += " WP:" + its(c->wparam);
// out += " rose:" + its(rosemap[c]/4) + "." + its(rosemap[c]%4);
// out += " MP:" + its(c->mpdist);
// out += " cda:" + its(celldistAlt(c));
/* out += " DP=" + its(celldistance(c, cwt.c));
out += " DO=" + its(celldist(c));
out += " PD=" + its(c->pathdist); */
if(false) {
out += " LP:" + itsh(c->landparam)+"/"+its(turncount);
@ -594,33 +573,17 @@ void describeMouseover() {
out += " D:" + its(c->mpdist);
char zz[64]; sprintf(zz, " P%p", c); out += zz;
// out += " rv" + its(rosedist(c));
// if(rosemap.count(c))
// out += " rv " + its(rosemap[c]/8) + "." + its(rosemap[c]%8);
// out += " ai" + its(c->aitmp);
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 += " " + itsh(getHeptagonCdata(c->master)->bits);
out += " " + fts(tortoise::getScent(getBits(c)));
}
// itsh(getHeptagonCdata(c->master)->bits);
// out += " barleft: " + s0 + dnameof(c->barleft);
// out += " barright: " + s0 + dnameof(c->barright);
}
// char zz[64]; sprintf(zz, " P%p", c); out += zz;
/* whirlwind::calcdirs(c);
for(int i=0; i<whirlwind::qdirs; i++)
out += " " + its(whirlwind::dfrom[i]) + ":" + its(whirlwind::dto[i]); */
// out += " : " + its(whirlwinddir(c));
if(randomPatternsMode)
out += " " + describeRPM(c->land);
@ -635,26 +598,6 @@ void describeMouseover() {
}
}
// char zz[64]; sprintf(zz, " P%d", princess::dist(c)); out += zz;
// out += " MD"+its(c->mpdist);
// out += " H "+its(c->heat);
// if(c->type != 6) out += " Z"+its(c->master->zebraval);
// out += " H"+its(c->heat);
/* // Hive debug
if(c->land == laHive) {
out += " [" + its(c->tmp) + " H" + its(int(c->heat));
if(c->tmp >= 0 && c->tmp < size(buginfo) && buginfo[c->tmp].where == c) {
buginfo_t b(buginfo[c->tmp]);
for(int k=0; k<3; k++) out += ":" + its(b.dist[k]);
for(int k=0; k<3; k++)
for(int i=0; i<size(bugqueue[k]); i++)
if(bugqueue[k][i] == c->tmp)
out += " B"+its(k)+":"+its(i);
}
out += "]";
} */
if(c->wall &&
!((c->wall == waFloorA || c->wall == waFloorB || c->wall == waFloorC || c->wall == waFloorD) && c->item)) {
out += ", "; out += XLAT1(winf[c->wall].name);
@ -721,55 +664,11 @@ void describeMouseover() {
if(isWarped(c))
help += s0 + "\n\n" + warpdesc;
}
/*
else if(cmode == emGraphConfig) {
if(getcstat == 'a' && vid.sspeed > -4.99)
out = XLAT("+5 = center instantly, -5 = do not center the map");
else if(getcstat == 'a')
out = XLAT("press Space or Home to center on the PC");
else if(getcstat == 'w')
out = XLAT("also hold Alt during the game to toggle high contrast");
else if(getcstat == 'f')
out = XLAT("Reduce the framerate limit to conserve CPU energy");
}
else if(cmode == emBasicConfig) {
if(getcstat == 'c')
out = XLAT("The axes help with keyboard movement");
else if(getcstat == 'g')
out = XLAT("Affects looks and grammar");
#ifndef MOBILE
else if(getcstat == 's')
out = XLAT("Config file: %1", conffile);
#endif
else out = "";
}
else if(cmode == emDisplayMode) {
if(getcstat == 'p') {
if(autojoy)
out = XLAT("joystick mode: automatic (release the joystick to move)");
if(!autojoy)
out = XLAT("joystick mode: manual (press a button to move)");
}
}
else if(cmode == emChangeMode) {
if(getcstat == 'h')
out = XLAT("One wrong move and it is game over!");
}
*/
mouseovers = out;
#ifdef ROGUEVIZ
rogueviz::describe(c);
#endif
int col = linf[cwt.c->land].color;
if(cwt.c->land == laRedRock) col = 0xC00000;
#ifndef MOBILE
displayfr(vid.xres/2, vid.fsize, 2, vid.fsize, out, col, 8);
#endif
if(mousey < vid.fsize * 3/2) getcstat = SDLK_F1;
}

View File

@ -231,6 +231,10 @@ void displayglyph2(int cx, int cy, int buttonsize, int i) {
mouseovers += XLAT(" (click to drop)");
getcstat = 'g';
}
if(it == itInventory) {
mouseovers += XLAT(" (click to use)");
getcstat = 'i';
}
if(imp & GLYPH_LOCAL) mouseovers += XLAT(" (local treasure)");
help = generateHelpForItem(it);
}

27
hyper.h
View File

@ -559,7 +559,12 @@ bool isFriendly(eMonster m);
bool isFriendly(cell *c);
bool isChild(cell *w, cell *killed); // is w killed if killed is killed?
int gold();
static const int NO_TREASURE = 1;
static const int NO_YENDOR = 2;
static const int NO_GRAIL = 4;
static const int NO_LOVE = 8;
int gold(int no = 0);
int tkills();
bool hellUnlocked();
@ -1037,10 +1042,6 @@ void checkmove();
transmatrix eumove(int x, int y);
transmatrix eumovedir(int d);
#ifndef NOSAVE
void loadScores();
#endif
int reptilemax();
extern bool mousing;
@ -1289,7 +1290,9 @@ eLand getNewSealand(eLand old);
bool createOnSea(eLand old);
namespace inv {
bool on;
extern bool on;
extern int remaining[ittypes];
void compute();
}
bool drawItemType(eItem it, cell *c, const transmatrix& V, int icol, int ticks, bool hidden);
@ -1315,7 +1318,7 @@ template<class T, class U> int addHook(hookset<T>*& m, int prio, const U& hook)
return 0;
}
extern purehookset hooks_frame, hooks_stats, clearmemory;
extern purehookset hooks_frame, hooks_stats, clearmemory, hooks_config;
template<class T, class... U> void callhooks(hookset<T> *h, U... args) {
if(h) for(auto& p: *h) p.second(args...);
@ -1429,10 +1432,10 @@ void switchGL();
void switchFullscreen();
extern screenmode cmode2;
namespace scores { void load(); }
void gotoHelp(const string& h);
void showCustomizeChar();
void showScores();
void showPickScores();
void showCheatMenu();
void showDisplayMode();
void showChangeMode();
@ -1445,3 +1448,9 @@ void gamescreen(int darken);
void showMission();
void handleKeyQuit(int sym, int uni);
void handlePanning(int sym, int uni);
#ifdef MOBILE
namespace leader { void showMenu(); void handleKey(int sym, int uni); }
#endif
bool needConfirmation();

View File

@ -1,6 +1,6 @@
#define VER "9.4n2"
#define VERNUM 9416
#define VERNUM_HEX 0x9416
#define VER "9.4n3"
#define VERNUM 9417
#define VERNUM_HEX 0x9417
#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 "inventory.cpp"
#include "closed/inventory.cpp"
#endif
#include "system.cpp"
#include "geometry.cpp"
@ -281,6 +281,7 @@ const char *loadlevel = NULL;
#include "config.cpp"
#include "scores.cpp"
#include "menus.cpp"
#include "quit.cpp"
#ifdef FIXEDSIZE
#include "nofont.cpp"
#endif

View File

@ -361,7 +361,7 @@ void run(const char *fname, int _perdist, double _maxfac) {
}
void describe(cell *c) {
if(cmode == emHelp) return;
if(cmode2 == smHelp) return;
neuron *n = getNeuronSlow(c);
if(!n) return;
help += "cell number: " + its(n - &net[0]) + "\n";

View File

@ -1721,7 +1721,7 @@ namespace mapeditor {
if(mapeditor::painttype == 4)
mapeditor::painttype = 0, mapeditor::paintwhat = 0,
mapeditor::paintwhat_str = "clear monster";
mapeditor::copywhat = NULL;
mapeditor::copywhat = NULL;
mapeditor::undo.clear();
if(!cheater) mapeditor::displaycodes = 0;
if(!cheater) mapeditor::whichShape = 0;

258
menus.cpp
View File

@ -3,6 +3,8 @@
#include "dialogs.cpp"
// -- overview --
#define BLACKISH 0x404040
#define REDDISH 0x400000
@ -159,6 +161,8 @@ void showOverview() {
};
}
// -- main menu --
bool checkHalloweenDate() {
time_t t = time(NULL);
struct tm tm = *localtime(&t);
@ -241,7 +245,7 @@ void showMainMenu() {
else if(sym == 'd') pushScreen(showDisplayMode);
else if(sym == 'm') pushScreen(showChangeMode);
#ifndef NOSAVE
else if(sym == 't') loadScores();
else if(sym == 't') scores::load();
#endif
else if(uni == 'y'-96) {
if(!sphere) {
@ -271,7 +275,7 @@ void showMainMenu() {
#ifdef INV
else if(sym == 'i') {
clearMessages();
pushScreen(inv::show());
pushScreen(inv::show);
}
#endif
else if(sym == SDLK_ESCAPE)
@ -294,6 +298,8 @@ void showMainMenu() {
};
}
// -- display modes --
void showDisplayMode() {
gamescreen(3);
@ -308,6 +314,8 @@ void showDisplayMode() {
dialog::addBoolItem(XLAT("big Poincaré model"), vid.alpha == 1 && vid.scale >= 1, '3');
dialog::addBoolItem(XLAT("Klein-Beltrami model"), vid.alpha == 0, '4');
dialog::addSelItem(XLAT("wall display mode"), XLAT(wdmodes[vid.wallmode]), '5');
if(getcstat == '5')
mouseovers = XLAT("also hold Alt during the game to toggle high contrast");
dialog::addBoolItem(XLAT("draw the grid"), (vid.grid), '6');
dialog::addBoolItem(XLAT("mark heptagons"), (vid.darkhepta), '7');
dialog::addSelItem(XLAT("3D configuration"), "", '9');
@ -383,19 +391,7 @@ void showDisplayMode() {
};
}
void gmodekeys(int sym, int uni) {
if(uni == '1') { vid.alpha = 999; vid.scale = 998; }
if(uni == '2') { vid.alpha = 1; vid.scale = 0.4; }
if(uni == '3') { vid.alpha = 1; vid.scale = 1; }
if(uni == '4') { vid.alpha = 0; vid.scale = 1; }
if(uni == '5') { vid.wallmode += 60 + (shiftmul > 0 ? 1 : -1); vid.wallmode %= 6; }
if(uni == '6') vid.grid = !vid.grid;
if(uni == '7') { vid.darkhepta = !vid.darkhepta; }
if(uni == '%' && sym == '5') {
if(vid.wallmode == 0) vid.wallmode = 6;
vid.wallmode--;
}
}
// -- game modes --
void switchHardcore() {
if(hardcore && !canmove) {
@ -426,16 +422,18 @@ void showChangeMode() {
dialog::addBoolItem(XLAT(SHMUPTITLE), (shmup::on || multi::players > 1), 's');
if(!shmup::on) dialog::addSelItem(XLAT("hardcore mode"),
hardcore && !pureHardcore() ? XLAT("PARTIAL") : ONOFF(hardcore), 'h');
if(getcstat == 'h')
mouseovers = XLAT("One wrong move and it is game over!");
multi::cpid = 0;
dialog::addBoolItem(XLAT("%1 Challenge", moPrincess), (princess::challenge), 'p');
dialog::addBoolItem(XLAT("random pattern mode"), (randomPatternsMode), 'r');
dialog::addBoolItem(XLAT("Yendor Challenge"), (yendor::on), 'y');
dialog::addBoolItem(XLAT("pure tactics mode"), (tactic::on), 't');
dialog::addBoolItem(XLAT("heptagonal mode"), (purehepta), '7');
dialog::addBoolItem(XLAT("Chaos mode"), (chaosmode), 'C');
dialog::addBoolItem(XLAT("peaceful mode"), (chaosmode), 'P');
dialog::addBoolItem(XLAT("peaceful mode"), (chaosmode), 'p');
dialog::addBoolItem(XLAT("inventory mode"), (inv::on), 'i');
dialog::addBoolItem(XLAT("pure tactics mode"), (tactic::on), 't');
dialog::addBoolItem(XLAT("Yendor Challenge"), (yendor::on), 'y');
dialog::addBoolItem(XLAT("%1 Challenge", moPrincess), (princess::challenge), 'P');
dialog::addBoolItem(XLAT("random pattern mode"), (randomPatternsMode), 'r');
dialog::addBreak(50);
// cheating and map editor
@ -489,7 +487,7 @@ void showChangeMode() {
}
else if(xuni == '7')
restartGame('7');
else if(xuni == 'P')
else if(xuni == 'p')
pushScreen(peace::showMenu);
else if(xuni == 'i') {
restartGame('i');
@ -512,7 +510,7 @@ void showChangeMode() {
if(!princess::everSaved)
addMessage(XLAT("Save %the1 first to unlock this challenge!", moPrincess));
else
restartGame('p');
restartGame('P');
}
#ifndef NOEDIT
else if(xuni == 'm') {
@ -545,6 +543,8 @@ void showChangeMode() {
};
}
// -- cheat menu --
void showCheatMenu() {
gamescreen(1);
dialog::init("cheat menu");
@ -592,6 +592,8 @@ void showCheatMenu() {
};
}
// -- geometry menu --
int eupage = 0;
int euperpage = 21;
@ -698,27 +700,7 @@ void showEuclideanMenu() {
};
}
#ifdef MOBILE
namespace leader { void showMenu(); void handleKey(int sym, int uni); }
#endif
void handleQuit(int sym, int uni) {
if(uni == 'r' || sym == SDLK_F5) {
restartGame(), popScreen();
msgs.clear();
}
else if(uni == 'v') pushScreen(showMainMenu);
else if(uni == SDLK_ESCAPE) popScreen();
else if(uni == 'o') setAppropriateOverview();
#ifndef NOSAVE
else if(uni == 't') {
if(!canmove) restartGame();
loadScores();
msgs.clear();
}
#endif
}
// -- demo --
#ifdef DEMO
bool demoanim;
@ -804,188 +786,8 @@ void handleDemoKey(int sym, int uni) {
}
}
#endif
function <void(int sym, int uni)> keyhandler;
#ifndef MOBILE
void quitOrAgain() {
int y = vid.yres * (618) / 1000;
displayButton(vid.xres/2, y + vid.fsize*1/2,
(items[itOrbSafety] && havesave) ?
XLAT("Press Enter or F10 to save") :
XLAT("Press Enter or F10 to quit"),
SDLK_RETURN, 8, 2);
displayButton(vid.xres/2, y + vid.fsize*2, XLAT("or 'r' or F5 to restart"), 'r', 8, 2);
displayButton(vid.xres/2, y + vid.fsize*7/2, XLAT("or 't' to see the top scores"), 't', 8, 2);
displayButton(vid.xres/2, y + vid.fsize*10/2, XLAT("or 'v' to see the main menu"), 'v', 8, 2);
displayButton(vid.xres/2, y + vid.fsize*13/2, XLAT("or 'o' to see the world overview"), 'o', 8, 2);
}
#endif
int msgscroll = 0;
string timeline() {
int timespent = (int) (savetime + (timerstopped ? 0 : (time(NULL) - timerstart)));
char buf[20];
sprintf(buf, "%d:%02d", timespent/60, timespent % 60);
return
shmup::on ?
XLAT("%1 knives (%2)", its(turncount), buf)
:
XLAT("%1 turns (%2)", its(turncount), buf);
}
void showMission() {
cmode2 = smMission;
gamescreen(1); drawStats();
keyhandler = handleKeyQuit;
dialog::init(
#ifdef TOUR
tour::on ? (canmove ? XLAT("Tutorial") : XLAT("GAME OVER")) :
#endif
cheater ? XLAT("It is a shame to cheat!") :
showoff ? XLAT("Showoff mode") :
canmove && princess::challenge ? XLAT("%1 Challenge", moPrincess) :
canmove ? XLAT("Quest status") :
XLAT("GAME OVER"),
0xC00000, 200, 100
);
dialog::addInfo(XLAT("Your score: %1", its(gold())));
dialog::addInfo(XLAT("Enemies killed: %1", its(tkills())));
#ifdef TOUR
if(tour::on) ; else
#endif
if(items[itOrbYendor]) {
dialog::addInfo(XLAT("Orbs of Yendor found: %1", its(items[itOrbYendor])), iinf[itOrbYendor].color);
dialog::addInfo(XLAT("CONGRATULATIONS!"), iinf[itOrbYendor].color);
}
else {
if(princess::challenge)
dialog::addInfo(XLAT("Follow the Mouse and escape with %the1!", moPrincess));
else if(gold() < R30)
dialog::addInfo(XLAT("Collect %1 $$$ to access more worlds", its(R30)));
else if(gold() < R60)
dialog::addInfo(XLAT("Collect %1 $$$ to access even more lands", its(R60)));
else if(!hellUnlocked())
dialog::addInfo(XLAT("Collect at least %1 treasures in each of 9 types to access Hell", its(R10)));
else if(items[itHell] < R10)
dialog::addInfo(XLAT("Collect at least %1 Demon Daisies to find the Orbs of Yendor", its(R10)));
else if(size(yendor::yi) == 0)
dialog::addInfo(XLAT("Look for the Orbs of Yendor in Hell or in the Crossroads!"));
else
dialog::addInfo(XLAT("Unlock the Orb of Yendor!"));
}
if(!timerstopped && !canmove) {
savetime += time(NULL) - timerstart;
timerstopped = true;
}
if(canmove && !timerstart)
timerstart = time(NULL);
if(princess::challenge) ;
#ifdef TOUR
else if(tour::on) ;
#endif
else if(tkills() < R100)
dialog::addInfo(XLAT("Defeat %1 enemies to access the Graveyard", its(R100)));
else if(kills[moVizier] == 0 && (items[itFernFlower] < U5 || items[itGold] < U5))
dialog::addInfo(XLAT("Kill a Vizier in the Palace to access Emerald Mine"));
else if(items[itEmerald] < U5)
dialog::addInfo(XLAT("Collect 5 Emeralds to access Camelot"));
else if(hellUnlocked() && !chaosmode) {
bool b = true;
for(int i=0; i<LAND_HYP; i++)
if(b && items[treasureType(land_hyp[i])] < R10) {
dialog::addInfo(
XLAT(
land_hyp[i] == laTortoise ? "Hyperstone Quest: collect at least %3 points in %the2" :
"Hyperstone Quest: collect at least %3 %1 in %the2",
treasureType(land_hyp[i]), land_hyp[i], its(R10)));
b = false;
}
if(b)
dialog::addInfo(XLAT("Hyperstone Quest completed!"), iinf[itHyperstone].color);
}
else dialog::addInfo(XLAT("Some lands unlock at specific treasures or kills"));
if(cheater) {
dialog::addInfo(XLAT("you have cheated %1 times", its(cheater)), 0xFF2020);
}
if(!cheater) {
dialog::addInfo(timeline(), 0xC0C0C0);
}
msgs.clear();
if(msgscroll < 0) msgscroll = 0;
int gls = size(gamelog) - msgscroll;
int mnum = 0;
for(int i=gls-5; i<gls; i++)
if(i>=0) {
msginfo m;
m.spamtype = 0;
m.flashout = true;
m.stamp = ticks-128*vid.flashtime-128*(gls-i);
m.msg = gamelog[i].msg;
m.quantity = gamelog[i].quantity;
mnum++,
msgs.push_back(m);
}
dialog::addBreak(100);
bool intour = false;
#ifdef TOUR
intour = tour::on;
#endif
if(intour) {
#ifdef TOUR
if(canmove) {
dialog::addItem(XLAT("spherical geometry"), '1');
dialog::addItem(XLAT("Euclidean geometry"), '2');
dialog::addItem(XLAT("more curved hyperbolic geometry"), '3');
}
if(!items[itOrbTeleport])
dialog::addItem(XLAT("teleport away"), '4');
else if(!items[itOrbAether])
dialog::addItem(XLAT("move through walls"), '4');
else
dialog::addItem(XLAT("flash"), '4');
if(canmove) {
if(tour::slidecommand != "")
dialog::addItem(tour::slidecommand, '5');
dialog::addItem(XLAT("static mode"), '6');
dialog::addItem(XLAT("enable/disable texts"), '7');
dialog::addItem(XLAT("next slide"), SDLK_RETURN);
dialog::addItem(XLAT("previous slide"), SDLK_BACKSPACE);
dialog::addItem(XLAT("list of slides"), '9');
}
else
dialog::addBreak(200);
dialog::addItem(XLAT("main menu"), 'v');
#endif
}
else {
dialog::addItem(XLAT(canmove ? "continue" : "see how it ended"), SDLK_ESCAPE);
dialog::addItem(XLAT("main menu"), 'v');
dialog::addItem(XLAT("restart"), SDLK_F5);
#ifndef MOBILE
dialog::addItem(XLAT(quitsaves() ? "save" : "quit"), SDLK_F10);
#endif
#ifdef ANDROIDSHARE
dialog::addItem(XLAT("SHARE"), 's'-96);
#endif
}
dialog::display();
if(mnum)
displayfr(vid.xres/2, vid.yres-vid.fsize*(mnum+1), 2, vid.fsize/2, XLAT("last messages:"), 0xC0C0C0, 8);
}
// -- overview --
void setAppropriateOverview() {
clearMessages();
@ -1001,9 +803,3 @@ void setAppropriateOverview() {
pushScreen(showOverview);
}
void showMissionScreen() {
popScreenAll();
pushScreen(showMission);
achievement_final(false);
msgscroll = 0;
}

View File

@ -1987,8 +1987,8 @@ slide rvslides[] = {
auto hooks =
addHook(hooks_frame, 0, drawExtra) +
addHook(hooks_args, 100, readArgs) +
addHook(clearmemory, 0, clear) +
addHook(hooks_config, 0, [] () { ss::list(rogueviz::rvtour::rvslides); });
addHook(clearmemory, 0, close) +
addHook(hooks_config, 0, [] () { tour::ss::list(rogueviz::rvtour::rvslides); });
};

View File

@ -1,5 +1,9 @@
#ifndef NOSAVE
namespace scores {
vector<score> scores;
score *currentgame;
int scoresort = 2;
int scoredisplay = 1;
@ -15,14 +19,37 @@ bool fakescore() {
return fakebox[scoredisplay];
}
string displayfor(score* S) {
int colwidth() {
if(scoredisplay == 0) return 5;
if(scoredisplay == 1) return 16;
if(scoredisplay == 5) return 8;
return 4;
}
string displayfor(score* S, bool shorten = false) {
// printf("S=%p, scoredisplay = %d\n", S, scoredisplay);
if(S == NULL) {
return XLATN(boxname[scoredisplay]);
string str = XLATN(boxname[scoredisplay]);
if(!shorten) return str;
if(scoredisplay == 0 || scoredisplay == 65) return XLAT("time");
if(scoredisplay == 2) return "$$$";
if(scoredisplay == 3) return XLAT("kills");
if(scoredisplay == 4) return XLAT("turns");
if(scoredisplay == 5) return XLAT("cells");
if(scoredisplay == 67) return XLAT("cheats");
if(scoredisplay == 66) return XLAT("saves");
if(scoredisplay == 197) return XLAT("players");
int i = 0;
for(int j=0; j<5; j++) if(i < size(str)) getnext(str.c_str(), i);
return str.substr(0, i);
}
if(scoredisplay == 0) {
char buf[10];
snprintf(buf, 10, "%d:%02d", S->box[0]/60, S->box[0]%60);
if(scoredisplay == 0 || scoredisplay == 65) {
char buf[20];
int t = S->box[0];
if(t >= 3600)
snprintf(buf, 20, "%d:%02d:%02d", t/3600, (t/60)%60, t%60);
else
snprintf(buf, 20, "%d:%02d", t/60, t%60);
return buf;
}
if(scoredisplay == 1) {
@ -33,58 +60,6 @@ string displayfor(score* S) {
return its(S->box[scoredisplay]);
}
void loadScores() {
scores.clear();
FILE *f = fopen(scorefile, "rt");
if(!f) {
printf("Could not open the score file '%s'!\n", scorefile);
addMessage(s0 + "Could not open the score file: " + scorefile);
return;
}
while(!feof(f)) {
char buf[120];
if(fgets(buf, 120, f) == NULL) break;
if(buf[0] == 'H' && buf[1] == 'y') {
score sc; bool ok = true;
{if(fscanf(f, "%s", buf) <= 0) break;} sc.ver = buf;
for(int i=0; i<MAXBOX; i++) {
if(fscanf(f, "%d", &sc.box[i]) <= 0) { boxid = i; break; }
}
for(int i=boxid; i<MAXBOX; i++) sc.box[i] = 0;
if(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) {
sc.box[0] = sc.box[65] - sc.box[1];
sc.box[65] = sc.box[0];
}
// do not include saves
if(sc.box[65 + 4 + itOrbSafety - itOrbLightning]) ok = false;
}
else
sc.box[0] = sc.box[1] - sc.box[0]; // could not save then
if(ok && boxid > 20) scores.push_back(sc);
}
}
fclose(f);
addMessage(its(size(scores))+" games have been recorded in "+scorefile);
pushScreen(showScores);
boxid = 0; applyBoxes();
scoresort = 2; reverse(scores.begin(), scores.end());
scoremode = 0;
if(shmup::on) scoremode = 1;
else if(hardcore) scoremode = 2;
scorefrom = 0;
stable_sort(scores.begin(), scores.end(), scorecompare);
#ifdef MOBILE
extern int andmode;
andmode = 2;
#endif
}
vector<pair<string, int> > pickscore_options;
void sortScores() {
@ -101,28 +76,84 @@ void shiftScoreDisplay(int delta) {
if(fakescore()) shiftScoreDisplay(delta);
}
void showScores() {
int y = vid.fsize * 7/2;
int bx = vid.fsize;
getcstat = 1;
int curcol;
vector<int> columns;
bool monsterpage = false;
void showPickScores() {
int d = scoredisplay = columns[curcol];
string modes =
scoremode == 0 ? XLAT(", m - mode: normal") :
scoremode == 1 ? XLAT(", m - mode: shoot'em up") :
scoremode == 2 ? XLAT(", m - mode: hardcore only") :
"?";
pickscore_options.clear();
if(euclid) modes += XLAT(" (E:%1)", euclidland);
scorerev = false;
for(int i=0; i<POSSCORE; i++) {
scoredisplay = i;
if(!fakescore()) {
string s = displayfor(NULL);
if(mapeditor::hasInfix(s))
if(monsbox[scoredisplay] == monsterpage)
pickscore_options.push_back(make_pair(s, i));
}
}
sort(pickscore_options.begin(), pickscore_options.end());
int q = (int) pickscore_options.size();
int percolumn = vid.yres / (vid.fsize+3) - 4;
int qcolumns = 1 + (q-1) / percolumn;
for(int i=0; i<q; i++) {
int x = 16 + (vid.xres * (i/percolumn)) / qcolumns;
int y = (vid.fsize+3) * (i % percolumn) + vid.fsize*2;
scoredisplay = pickscore_options[i].second;
if(q <= 9)
pickscore_options[i].first = pickscore_options[i].first + " [" + its(i+1) + "]";
if(!fakescore())
displayButton(x, y, pickscore_options[i].first, 1000+i, 0);
}
displayButton(vid.xres/2, vid.yres - vid.fsize*2, "kills", 'm', 8);
mouseovers = XLAT("t/left/right - change display, up/down - scroll, s - sort by") + modes;
scoredisplay = d;
displaystr(bx*4, vid.fsize*2, 0, vid.fsize, "#", forecolor, 16);
displaystr(bx*8, vid.fsize*2, 0, vid.fsize, "$$$", forecolor, 16);
displaystr(bx*12, vid.fsize*2, 0, vid.fsize, XLAT("kills"), forecolor, 16);
displaystr(bx*18, vid.fsize*2, 0, vid.fsize, XLAT("time"), forecolor, 16);
displaystr(bx*22, vid.fsize*2, 0, vid.fsize, XLAT("ver"), forecolor, 16);
displaystr(bx*23, vid.fsize*2, 0, vid.fsize, displayfor(NULL), forecolor, 0);
mouseovers = mapeditor::infix;
keyhandler = [] (int sym, int uni) {
if(uni == 'm') monsterpage = !monsterpage; else
if(uni >= '1' && uni <= '9') uni = uni + 1000 - '1';
else if(uni >= 1000 && uni < 1000 + size(pickscore_options)) {
scoredisplay = pickscore_options[uni - 1000].second;
for(int i=0; i<POSSCORE; i++)
if(columns[i] == scoredisplay) swap(columns[i], columns[curcol]);
popScreen();
}
else if(mapeditor::editInfix(uni)) ;
else if(doexiton(sym, uni)) popScreen();
};
}
void show() {
if(columns.size() == 0) for(int i=0; i<POSSCORE; i++) columns.push_back(i);
int y = vid.fsize * 5/2;
int bx = vid.fsize;
getcstat = 0;
displaystr(bx*4, vid.fsize, 0, vid.fsize, "#", forecolor, 16);
displaystr(bx*8, vid.fsize, 0, vid.fsize, XLAT("ver"), forecolor, 16);
int at = 9;
for(int i=0; i<POSSCORE; i++) {
scoredisplay = columns[i];
if(bx*at > vid.xres) break;
if(displaystr(bx*at, vid.fsize, 0, vid.fsize, displayfor(NULL, true), i == curcol ? 0xFFD500 : forecolor, 0))
getcstat = 1000+i;
at += colwidth();
}
if(scorefrom < 0) scorefrom = 0;
int id = 0;
int omit = scorefrom;
@ -144,41 +175,58 @@ void showScores() {
if(wrongtype) { id++; continue; }
if(omit) { omit--; rank++; id++; continue; }
char buf[16];
rank++; sprintf(buf, "%d", rank);
displaystr(bx*4, y, 0, vid.fsize, buf, 0xC0C0C0, 16);
bool cur = S.box[MAXBOX-1];
if(cur) {
saveBox();
for(int i=0; i<POSSCORE; i++) S.box[i] = savebox[i];
S.box[0] = S.box[65];
}
int col = cur ? 0xFFD500 : 0xC0C0C0;
sprintf(buf, "%d", S.box[2]);
displaystr(bx*8, y, 0, vid.fsize, buf, 0xC0C0C0, 16);
rank++;
displaystr(bx*4, y, 0, vid.fsize, its(rank), col, 16);
sprintf(buf, "%d", S.box[3]);
displaystr(bx*12, y, 0, vid.fsize, buf, 0xC0C0C0, 16);
displaystr(bx*8, y, 0, vid.fsize, S.ver, col, 16);
sprintf(buf, "%d:%02d", S.box[0]/60, S.box[0] % 60);
displaystr(bx*18, y, 0, vid.fsize, buf, 0xC0C0C0, 16);
int at = 9;
for(int i=0; i<POSSCORE; i++) {
scoredisplay = columns[i];
if(bx*at > vid.xres) break;
at += colwidth();
if(displaystr(bx*(at-1), y, 0, vid.fsize, displayfor(&S), col, 16))
getcstat = 1000+i;
}
displaystr(bx*22, y, 0, vid.fsize, S.ver, 0xC0C0C0, 16);
displaystr(bx*23, y, 0, vid.fsize, displayfor(&S), 0xC0C0C0, 0);
y += vid.fsize*5/4; id++;
}
#ifdef MOBILE
buttonclicked = false;
displayabutton(-1, +1, XLAT("SORT"), BTON);
displayabutton( 0, +1, XLAT("PICK"), BTON);
displayabutton(+1, +1, XLAT("PLAY"), BTON);
#endif
int i0 = vid.yres - vid.fsize;
int xr = vid.xres / 80;
string modes =
scoremode == 0 ? XLAT(", m - mode: normal") :
scoremode == 1 ? XLAT(", m - mode: shoot'em up") :
scoremode == 2 ? XLAT(", m - mode: hardcore only") :
"?";
if(euclid) modes += XLAT(" (E:%1)", euclidland);
displayButton(xr*10, i0, IFM("s - ") + XLAT("sort"), 's', 8);
displayButton(xr*25, i0, IFM("t - ") + XLAT("choose"), 't', 8);
displayButton(xr*40, i0, IFM("0 - ") + XLAT("play"), '0', 8);
displayButton(xr*65, i0, IFM("m - ") + modes.substr(6), 'm', 8);
keyhandler = [] (int sym, int uni) {
#ifndef MOBILE
if(sym == SDLK_LEFT || sym == SDLK_KP4 || sym == 'h' || sym == 'a')
shiftScoreDisplay(-1);
else if(sym == SDLK_RIGHT || sym == SDLK_KP6 || sym == 'l' || sym == 'd')
shiftScoreDisplay(1);
if(sym == SDLK_LEFT || sym == SDLK_KP4 || sym == 'h' || sym == 'a') {
if(curcol > 0) curcol--;
}
else if(sym == SDLK_RIGHT || sym == SDLK_KP6 || sym == 'l' || sym == 'd') {
if(curcol < POSSCORE-1) curcol++;
}
else if(sym >= 1000 && sym < 1000+POSSCORE)
curcol = sym - 1000;
else if(sym == 't') { mapeditor::infix = ""; pushScreen(showPickScores); }
else if(sym == SDLK_UP || sym == 'k' || sym == 'w')
scorefrom -= 5;
@ -191,98 +239,88 @@ void showScores() {
else if(sym == 's') sortScores();
else if(sym == 'm') { scoremode++; scoremode %= 3; }
else if(doexiton(sym, uni)) popScreen();
#else
static int scoredragx, scoredragy;
extern bool clicked, lclicked;
extern int andmode;
static int scoredragy;
static bool lclicked;
if(andmode) {
if(!clicked && !lclicked) {
andmode = 0;
scoredragx = mousex;
if(mousepressed) {
if(!lclicked) {
// scoredragx = mousex;
scoredragy = mousey;
}
}
else {
if(clicked && !lclicked)
scoredragx = mousex, scoredragy = mousey;
else if(lclicked && !clicked) {
if(mousey > vid.ycenter - 2 * vid.fsize) {
if(mousex < vid.xcenter*2/3) sortScores();
else if(mousex < vid.xcenter*4/3)
cmode = emPickScores;
else andmode = 0, popScreen();
}
}
else if(clicked && lclicked) {
// if(mousex > scoredragx + 80) scoredragx += 80, shiftScoreDisplay(1);
// if(mousex < scoredragx - 80) scoredragx -= 80, shiftScoreDisplay(-1);
else {
while(mousey > scoredragy + vid.fsize) scoredragy += vid.fsize, scorefrom--;
while(mousey < scoredragy - vid.fsize) scoredragy -= vid.fsize, scorefrom++;
}
lclicked = mousepressed;
}
#endif
};
}
bool monsterpage = false;
void showPickScores() {
getcstat = '0';
int d = scoredisplay;
pickscore_options.clear();
scorerev = false;
for(int i=0; i<POSSCORE; i++) {
scoredisplay = i;
if(!fakescore()) {
string s = displayfor(NULL);
if(mapeditor::hasInfix(s))
if(monsbox[scoredisplay] == monsterpage)
pickscore_options.push_back(make_pair(s, i));
}
void load() {
scores.clear();
FILE *f = fopen(scorefile, "rt");
if(!f) {
printf("Could not open the score file '%s'!\n", scorefile);
addMessage(s0 + "Could not open the score file: " + scorefile);
return;
}
sort(pickscore_options.begin(), pickscore_options.end());
int q = (int) pickscore_options.size();
int percolumn = vid.yres / (vid.fsize+3) - 4;
int columns = 1 + (q-1) / percolumn;
for(int i=0; i<q; i++) {
int x = 16 + (vid.xres * (i/percolumn)) / columns;
int y = (vid.fsize+3) * (i % percolumn) + vid.fsize*2;
while(!feof(f)) {
char buf[120];
if(fgets(buf, 120, f) == NULL) break;
if(buf[0] == 'H' && buf[1] == 'y') {
score sc; bool ok = true;
sc.box[MAXBOX-1] = 0;
{if(fscanf(f, "%s", buf) <= 0) break;} sc.ver = buf;
scoredisplay = pickscore_options[i].second;
if(q <= 9)
pickscore_options[i].first = pickscore_options[i].first + " [" + its(i+1) + "]";
if(!fakescore())
displayButton(x, y, pickscore_options[i].first, 1000+i, 0);
}
displayButton(vid.xres/2, vid.yres - vid.fsize*2, "kills", 'm', 8);
scoredisplay = d;
for(int i=0; i<MAXBOX; i++) {
if(fscanf(f, "%d", &sc.box[i]) <= 0) { boxid = i; break; }
}
for(int i=boxid; i<MAXBOX; i++) sc.box[i] = 0;
mouseovers = mapeditor::infix;
keyhandler = [] (int sym, int uni) {
extern int andmode;
andmode = 2;
if(uni == 'm') monsterpage = !monsterpage; else
if(uni >= '1' && uni <= '9') uni = uni + 1000 - '1';
else if(uni >= 1000 && uni < 1000 + size(pickscore_options)) {
scoredisplay = pickscore_options[uni - 1000].second;
popScreen();
if(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) {
sc.box[0] = sc.box[65] - sc.box[1];
sc.box[65] = sc.box[0];
}
// do not include saves
if(sc.box[65 + 4 + itOrbSafety - itOrbLightning]) ok = false;
}
else
sc.box[0] = sc.box[1] - sc.box[0]; // could not save then
if(sc.box[2] == 0) continue; // do not list zero scores
if(ok && boxid > 20) scores.push_back(sc);
}
else if(mapeditor::editInfix(uni)) ;
else if(doexiton(sym, uni)) popScreen();
};
}
saveBox();
score sc;
for(int i=0; i<POSSCORE; i++) sc.box[i] = savebox[i];
sc.box[MAXBOX-1] = 1; sc.ver = "NOW";
scores.push_back(sc);
fclose(f);
clearMessages();
// addMessage(its(size(scores))+" games have been recorded in "+scorefile);
pushScreen(show);
boxid = 0; applyBoxes();
scoresort = 2; reverse(scores.begin(), scores.end());
scoremode = 0;
if(shmup::on) scoremode = 1;
else if(hardcore) scoremode = 2;
scorefrom = 0;
stable_sort(scores.begin(), scores.end(), scorecompare);
}
}
#endif

View File

@ -645,6 +645,7 @@ void saveStats(bool emergency = false) {
#endif
if(randomPatternsMode) return;
if(peace::on) return;
if(!gold()) return;
remove_emergency_save();

View File

@ -154,6 +154,7 @@ namespace yendor {
int hardness() {
if(peace::on) return 15; // just to generate monsters
if(!yendor::generating && !yendor::path && !yendor::on) return 0;
int thf = 0;
for(int i=0; i<size(yi); i++) {
yendorinfo& ye ( yi[i] );