1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2024-11-01 03:46:16 +00:00
hyperrogue/quit.cpp

558 lines
15 KiB
C++
Raw Normal View History

// Hyperbolic Rogue -- the mission screen
// Copyright (C) 2011-2018 Zeno Rogue, see 'hyper.cpp' for details
2017-07-12 17:50:39 +00:00
/** \file quit.cpp
* \brief the mission screen, and routines related to it
*/
#include "hyper.h"
namespace hr {
EX bool quitsaves() { return (items[itOrbSafety] && CAP_SAVE && !arcm::in()); }
2017-07-12 17:50:39 +00:00
2019-08-09 19:00:52 +00:00
EX bool needConfirmationEvenIfSaved() {
return canmove && (gold() >= 30 || tkills() >= 50) && !cheater;
}
2019-08-09 19:00:52 +00:00
EX bool needConfirmation() {
return needConfirmationEvenIfSaved() && !quitsaves();
2017-07-12 17:50:39 +00:00
}
2019-08-09 19:00:52 +00:00
EX int getgametime() {
return (int) (savetime + (timerstopped ? 0 : (time(NULL) - timerstart)));
}
2017-07-12 17:50:39 +00:00
2019-08-10 08:57:14 +00:00
EX string getgametime_s(int timespent IS(getgametime())) {
2017-07-12 17:50:39 +00:00
char buf[20];
sprintf(buf, "%d:%02d", timespent/60, timespent % 60);
return buf;
}
string timeline() {
2017-07-12 17:50:39 +00:00
return
shmup::on ?
XLAT("%1 knives (%2)", its(turncount), getgametime_s())
2017-07-12 17:50:39 +00:00
:
XLAT("%1 turns (%2)", its(turncount), getgametime_s());
2017-07-12 17:50:39 +00:00
}
2020-03-07 23:59:42 +00:00
EX void noaction() {}
2017-07-12 17:50:39 +00:00
2020-03-07 23:59:42 +00:00
EX function<void()> cancel = noaction;
2017-07-12 17:50:39 +00:00
2019-12-14 10:53:27 +00:00
#if HDR
struct hint {
time_t last;
function<bool()> usable;
function<void()> display;
function<void()> action;
};
#endif
EX hint hints[] = {
2017-07-12 17:50:39 +00:00
{
0,
[]() {
return !inv::on && geometry == gNormal && items[localTreasureType()] >= 18;
},
[]() {
dialog::addHelp(XLAT(
2017-07-16 21:00:55 +00:00
"If you collect too many treasures in a given land, it will become "
2017-07-12 17:50:39 +00:00
"extremely dangerous. Try other lands once you have enough!"));
},
noaction},
{
0,
[]() {
return !ISMOBILE;
},
[]() {
dialog::addHelp(XLAT(
2017-07-24 22:21:36 +00:00
"Remember that you can right click almost anything for more information."));
2017-07-22 23:33:27 +00:00
#if ISMAC
2017-07-12 17:50:39 +00:00
dialog::addHelp(XLAT(
"(You can also use right Shift)\n\n"));
#endif
},
noaction},
{
0,
2017-07-22 23:33:27 +00:00
[]() { return !canmove; },
2017-07-12 17:50:39 +00:00
[]() {
dialog::addHelp(XLAT(
2019-09-13 16:01:28 +00:00
"Want to understand the geometry in HyperRogue? Try the Guided Tour!"
2017-07-12 17:50:39 +00:00
));
dialog::addBreak(50);
2019-09-13 16:01:28 +00:00
dialog::addItem(XLAT("guided tour"), 'z');
2017-07-12 17:50:39 +00:00
},
[]() {
2017-07-22 23:33:27 +00:00
#if CAP_TOUR
2017-07-12 17:50:39 +00:00
tour::start();
2017-07-22 23:33:27 +00:00
#else
addMessage("Not in this version");
#endif
2017-07-12 17:50:39 +00:00
}},
{
0,
[]() { return !inv::on; },
[]() {
dialog::addHelp(XLAT(
2017-07-16 21:00:55 +00:00
"Collecting 25 treasures in a given land may be dangerous, "
2017-07-12 17:50:39 +00:00
"but allows magical Orbs of this land to appear in other places!"
));
},
noaction},
{
0,
[]() { return !canmove; },
[]() {
dialog::addInfo(XLAT(
"Press ESC to view this screen during the game."
));
},
2017-07-22 23:33:27 +00:00
noaction
},
2017-07-12 17:50:39 +00:00
{
0,
[]() { return true; },
[]() {
dialog::addInfo(XLAT(
2017-07-22 23:33:27 +00:00
#if ISMOBILE==1
2017-07-12 17:50:39 +00:00
"The 'world overview' shows all the lands in HyperRogue."
#else
"Press 'o' to see all the lands in HyperRogue."
#endif
));
dialog::addBreak(50);
dialog::addItem(XLAT("world overview"), 'z');
},
[]() {
pushScreen(showOverview);
2017-07-12 17:50:39 +00:00
}},
{
0,
[]() { return !canmove; },
[]() {
2017-07-16 21:00:55 +00:00
dialog::addHelp(XLAT(
2017-07-12 17:50:39 +00:00
"Want another type of game? Want more challenge?\n"
"HyperRogue has many special modes and challenges that "
"significantly change the gameplay. Try them!"
));
dialog::addBreak(50);
dialog::addItem(XLAT("special game modes"), 'z');
},
[]() {
pushScreen(showChangeMode);
}},
{
0,
[]() { return true; },
[]() {
dialog::addInfo(XLAT(
"Hyperbolic geometry can be shown in many ways."
));
dialog::addBreak(50);
dialog::addItem(XLAT("special display modes"), 'z');
},
[]() {
pushScreen(models::model_menu);
2017-07-12 17:50:39 +00:00
}},
{
0,
[]() { return !canmove && !inv::on; },
[]() {
dialog::addHelp(XLAT(
"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!")
);
dialog::addBreak(50);
dialog::addItem(XLAT("Orb Strategy mode"), 'z');
},
[]() {
2017-07-22 23:33:27 +00:00
#if CAP_INV
restart_game(rg::inv);
2017-07-12 17:50:39 +00:00
#endif
}
},
{
0,
2017-07-22 23:33:27 +00:00
[]() { return CAP_RUG && geometry == gNormal; },
2017-07-12 17:50:39 +00:00
[]() {
dialog::addHelp(XLAT(
"Do you think you are playing on a ball? "
"This is far from the truth!\n"
));
dialog::addBreak(50);
2017-07-16 21:00:55 +00:00
dialog::addItem(XLAT("hypersian rug mode"), 'z');
2017-07-12 17:50:39 +00:00
},
[] () {
2017-07-22 23:33:27 +00:00
#if CAP_RUG
2017-07-12 17:50:39 +00:00
popScreen();
int wm, mm;
rug::init();
wm = vid.wallmode;
mm = vid.monmode;
vid.wallmode = 3;
vid.monmode = 2;
cancel = [wm, mm] () {
rug::close();
vid.wallmode = wm;
vid.monmode = mm;
};
2017-07-22 23:33:27 +00:00
#endif
2017-07-12 17:50:39 +00:00
}
},
{
0,
[]() { return !canmove && geometry == gNormal && celldist(cwt.at) >= 50; },
2017-07-12 17:50:39 +00:00
[]() {
dialog::addHelp(XLAT(
"Did you know that the path you take during the game "
2017-07-16 21:00:55 +00:00
"is usually very close to a straight line?\n"
2017-07-12 17:50:39 +00:00
));
dialog::addBreak(50);
dialog::addItem(XLAT("Show me!"), 'z');
},
[] () {
popScreen();
auto m = pmodel;
pmodel = mdBand;
int r = models::rotation;
bool h = history::includeHistory;
models::rotation = 0;
history::includeHistory = true;
history::create_playerpath();
2017-07-12 17:50:39 +00:00
cancel = [m,r,h] () {
history::clear(); pmodel = m;
models::rotation = r;
history::includeHistory = h;
2017-07-12 17:50:39 +00:00
fullcenter(); };
}
},
{
0,
[]() { return !canmove && sizes_known() && celldist(cwt.at) >= 50; },
2017-07-12 17:50:39 +00:00
[]() {
int d = celldist(cwt.at);
string s = expansion.approximate_descendants(d, 10000);
2017-07-12 17:50:39 +00:00
dialog::addHelp(XLAT(
"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",
its(d), s
2017-07-12 17:50:39 +00:00
));
dialog::addBreak(50);
dialog::addItem(XLAT("expansion"), 'z');
},
[] () {
viewdists = !viewdists;
popScreen();
cancel = [] () { viewdists = false; };
}
},
{
0,
2017-10-25 21:21:13 +00:00
[]() { return !canmove && showHalloween(); },
2017-07-12 17:50:39 +00:00
[]() {
dialog::addItem(XLAT("Halloween mini-game"), 'z');
},
[] () {
if(!sphere) {
resetModes();
stop_game();
2017-08-06 12:50:16 +00:00
specialland = laHalloween;
set_geometry(gSphere);
start_game();
2017-07-12 17:50:39 +00:00
vid.alpha = 999;
vid.scale = 998;
}
else {
resetModes();
2017-07-12 17:50:39 +00:00
vid.alpha = 1;
vid.scale = 1;
}
}
},
{-1, []() { return false; }, noaction, noaction}
};
2019-08-09 20:07:03 +00:00
EX int hinttoshow;
2017-07-12 17:50:39 +00:00
2017-07-16 21:00:55 +00:00
string contstr() {
return XLAT(canmove ? "continue" : "see how it ended");
}
2017-11-03 18:31:42 +00:00
eLand nextHyperstone() {
generateLandList(isLandIngame);
2017-11-03 18:31:42 +00:00
for(eLand l: landlist)
2017-11-03 22:55:20 +00:00
if(items[treasureType(l)] < R10 && !isCrossroads(l) && l != laPrincessQuest && l != laCamelot)
2017-11-03 18:31:42 +00:00
return l;
if(items[itHyperstone] >= 10) return laNone;
return laCrossroads;
}
2019-08-09 19:00:52 +00:00
EX void showMission() {
2017-07-12 17:50:39 +00:00
cmode = sm::DOTOUR | sm::MISSION | sm::CENTER;
gamescreen(1); drawStats();
dialog::init(
2017-07-22 23:33:27 +00:00
#if CAP_TOUR
2019-09-13 16:01:28 +00:00
tour::on ? (canmove ? XLAT("guided tour") : XLAT("GAME OVER")) :
2017-07-12 17:50:39 +00:00
#endif
(cheater && !autocheat)? XLAT("It is a shame to cheat!") :
racing::on ? "racing mode" :
2017-07-12 17:50:39 +00:00
(canmove && princess::challenge) ? XLAT("%1 Challenge", moPrincess) :
canmove ? XLAT("Quest status") :
XLAT("GAME OVER"),
0xC00000, 200, 100
);
keyhandler = handleKeyQuit;
if(!peace::on && !racing::on)
dialog::addInfo(XLAT("Your score: %1", its(gold())));
if(!peace::on && !racing::on)
dialog::addInfo(XLAT("Enemies killed: %1", its(tkills())));
2017-07-12 17:50:39 +00:00
2017-07-22 23:33:27 +00:00
#if CAP_TOUR
2017-07-12 17:50:39 +00:00
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(0)
;
#if CAP_TOUR
else if(tour::on)
;
#endif
else if(racing::on) ;
else if(princess::challenge)
2017-07-12 17:50:39 +00:00
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(!landUnlocked(laHell))
2017-07-12 17:50:39 +00:00
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)));
2018-06-22 12:47:24 +00:00
else if(isize(yendor::yi) == 0)
2017-07-12 17:50:39 +00:00
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) ;
2017-07-22 23:33:27 +00:00
#if CAP_TOUR
2017-07-12 17:50:39 +00:00
else if(tour::on) ;
#endif
else if(peace::on) ;
else if(racing::on) ;
2017-07-12 17:50:39 +00:00
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(landUnlocked(laHell) && !chaosmode) {
2017-11-03 18:31:42 +00:00
eLand l = nextHyperstone();
if(l)
2017-07-12 17:50:39 +00:00
dialog::addInfo(
XLAT(
2017-11-03 18:31:42 +00:00
l ? "Hyperstone Quest: collect at least %3 points in %the2" :
2017-07-12 17:50:39 +00:00
"Hyperstone Quest: collect at least %3 %1 in %the2",
2017-11-03 18:31:42 +00:00
treasureType(l), l, its(R10)));
else
2017-07-12 17:50:39 +00:00
dialog::addInfo(XLAT("Hyperstone Quest completed!"), iinf[itHyperstone].color);
}
else dialog::addInfo(XLAT("Some lands unlock at specific treasures or kills"));
if(cheater && !autocheat) {
2017-07-12 17:50:39 +00:00
dialog::addInfo(XLAT("you have cheated %1 times", its(cheater)), 0xFF2020);
}
else if(!racing::on) {
dialog::addInfo(timeline(), dialog::dialogcolor);
2017-07-12 17:50:39 +00:00
}
dialog::addBreak(100);
2017-07-22 23:33:27 +00:00
#if CAP_TOUR
2017-07-12 17:50:39 +00:00
if(!tour::on) {
hints[hinttoshow].display();
dialog::addBreak(100);
}
2017-07-22 23:33:27 +00:00
#endif
2017-07-12 17:50:39 +00:00
bool intour = false;
2017-07-22 23:33:27 +00:00
#if CAP_TOUR
2017-07-12 17:50:39 +00:00
intour = tour::on;
#endif
if(intour) {
2017-07-22 23:33:27 +00:00
#if CAP_TOUR
2017-07-12 17:50:39 +00:00
if(canmove) {
2018-04-22 09:10:19 +00:00
if(sphere) {
dialog::addItem(XLAT("return to your game"), '1');
dialog::addItem(XLAT(vid.alpha < 2 ? "orthogonal projection" : "stereographic projection"), '3');
}
else if(euclid) {
dialog::addItem(XLAT("return to your game"), '2');
dialog::addBreak(100);
}
else {
dialog::addItem(XLAT("spherical geometry"), '1');
dialog::addItem(XLAT("Euclidean geometry"), '2');
}
// dialog::addItem(XLAT("more curved hyperbolic geometry"), '3');
2017-07-12 17:50:39 +00:00
}
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');
2019-09-13 16:01:28 +00:00
dialog::addItem(XLAT("leave the tour mode"), '0');
2017-07-12 17:50:39 +00:00
}
else
dialog::addBreak(200);
dialog::addItem(XLAT("main menu"), 'v');
2017-08-06 14:53:12 +00:00
dialog::addItem("continue", SDLK_ESCAPE);
2017-07-12 17:50:39 +00:00
#endif
}
else {
2017-07-16 21:00:55 +00:00
dialog::addItem(contstr(), SDLK_ESCAPE);
2017-07-12 17:50:39 +00:00
dialog::addItem(XLAT("main menu"), 'v');
dialog::addItem(XLAT("restart"), SDLK_F5);
2017-07-16 21:00:55 +00:00
if(inv::on && items[itInventory])
dialog::addItem(XLAT("inventory"), 'i');
if(racing::on)
dialog::addItem(XLAT("racing menu"), 'o');
2017-07-22 23:33:27 +00:00
#if ISMOBILE==0
2017-07-12 17:50:39 +00:00
dialog::addItem(XLAT(quitsaves() ? "save" : "quit"), SDLK_F10);
#endif
2017-07-22 23:33:27 +00:00
#if CAP_ANDROIDSHARE
2017-07-12 17:50:39 +00:00
dialog::addItem(XLAT("SHARE"), 's'-96);
#endif
}
dialog::addItem(XLAT("message log"), 'l');
2017-07-12 17:50:39 +00:00
dialog::display();
}
2019-08-09 19:00:52 +00:00
EX void handleKeyQuit(int sym, int uni) {
2017-07-12 17:50:39 +00:00
dialog::handleNavigation(sym, uni);
// ignore the camera movement keys
2017-07-22 23:33:27 +00:00
#if CAP_RUG
2017-07-12 17:50:39 +00:00
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) {
if(needConfirmation()) pushScreen([] {
dialog::confirm_dialog(
XLAT("This will exit HyperRogue without saving your current game. Are you sure?"),
[] {
quitmainloop = true;
});
});
else quitmainloop = true;
}
else if(uni == 'r' || sym == SDLK_F5) dialog::do_if_confirmed([] {
restart_game(rg::nothing);
2017-07-12 17:50:39 +00:00
msgs.clear();
});
2017-07-12 17:50:39 +00:00
else if(uni == 'v') popScreenAll(), pushScreen(showMainMenu);
2018-06-22 12:47:24 +00:00
else if(uni == 'l') popScreenAll(), pushScreen(showMessageLog), messagelogpos = isize(gamelog);
2017-07-12 17:50:39 +00:00
else if(uni == 'z') hints[hinttoshow].action();
else if(sym == SDLK_F3 || (sym == ' ' || sym == SDLK_HOME))
fullcenter();
else if(uni == 'o') get_o_key().second();
2017-07-22 23:33:27 +00:00
#if CAP_INV
2017-07-12 17:50:39 +00:00
else if(uni == 'i' && inv::on)
pushScreen(inv::show);
#endif
2017-07-22 23:33:27 +00:00
#if CAP_SAVE
2017-07-12 17:50:39 +00:00
else if(uni == 't') {
msgs.clear();
scores::load();
}
#endif
else if(doexiton(sym, uni) && !didsomething) {
popScreen();
msgs.clear();
if(!canmove) {
addMessage(XLAT("GAME OVER"));
addMessage(timeline());
}
}
}
2019-12-14 10:53:27 +00:00
EX int counthints() {
2017-07-12 17:50:39 +00:00
for(int h=0;; h++) if(hints[h].last < 0) return h;
}
2019-08-09 19:00:52 +00:00
EX void showMissionScreen() {
2017-07-12 17:50:39 +00:00
cancel(); cancel = noaction;
popScreenAll();
achievement_final(false);
2018-05-15 21:26:04 +00:00
if(daily::on) {
#if CAP_DAILY
pushScreen(daily::showMenu);
#endif
}
else
pushScreen(showMission);
2017-07-22 23:33:27 +00:00
#if CAP_TOUR
if(!tour::on)
#endif
{
2017-07-12 17:50:39 +00:00
int ch = counthints();
hinttoshow = ch;
int h;
for(h=0; h < ch; h++) {
if(!hints[h].usable()) continue;
if(hinttoshow == ch || hints[h].last < hints[hinttoshow].last) hinttoshow = h;
}
hints[hinttoshow].last = time(NULL);
}
2017-07-16 21:00:55 +00:00
dialog::highlight_text = contstr();
2017-07-12 17:50:39 +00:00
}
}