diff --git a/config.cpp b/config.cpp index e5fa19e8..81bb9c1d 100644 --- a/config.cpp +++ b/config.cpp @@ -709,25 +709,6 @@ void loadConfig() { } #endif -void showAllConfig() { - dialog::addBreak(50); - dialog::addBack(); -#if CAP_CONFIG - dialog::addItem(XLAT("save the current config"), 's'); - if(getcstat == 's') - mouseovers = XLAT("Config file: %1", conffile); -#endif - } - -void handleAllConfig(int sym, int uni) { - if(sym == SDLK_F1 || uni == 'h') gotoHelp(help); - - else if(uni == ' ' || sym == SDLK_ESCAPE) popScreen(); -#if CAP_CONFIG - else if(uni == 's') saveConfig(); -#endif - } - void add_cells_drawn(char c = 'C') { dialog::addSelItem(XLAT("cells drawn"), its(cells_drawn), c); dialog::add_action([] () { @@ -858,26 +839,8 @@ void showGraphConfig() { dialog::addSelItem(XLAT("whatever"), fts(whatever), 'j'); #endif - const char *glyphsortnames[6] = { - "first on top", "first on bottom", - "last on top", "last on bottom", - "by land", "by number" - }; - - const char *glyphmodenames[3] = {"letters", "auto", "images"}; - dialog::addSelItem(XLAT("inventory/kill sorting"), XLAT(glyphsortnames[glyphsortorder]), 'k'); - - dialog::addSelItem(XLAT("inventory/kill mode"), XLAT(glyphmodenames[vid.graphglyph]), 'd'); - - dialog::addSelItem(XLAT("font scale"), its(fontscale), 'b'); - - menuitem_sightrange(); - - dialog::addSelItem(XLAT("move by clicking on compass"), its(vid.mobilecompasssize), 'C'); - - dialog::addItem(XLAT("customize colors and aura"), 'c'); - - showAllConfig(); + dialog::addBreak(50); + dialog::addBack(); dialog::display(); keyhandler = [] (int sym, int uni) { @@ -890,37 +853,30 @@ void showGraphConfig() { if((uni >= 32 && uni < 64) || uni == 'L' || uni == 'C') xuni = uni; if(xuni == 'u') vid.particles = !vid.particles; - if(xuni == 'd') vid.graphglyph = (1+vid.graphglyph)%3; - - if(xuni == 'c') pushScreen(show_color_dialog); - - if(xuni == 'j') { + + else if(xuni == 'j') { dialog::editNumber(whatever, -10, 10, 1, 0, XLAT("whatever"), XLAT("Whatever.")); dialog::reaction = delayed_geo_reset; } - if(xuni == 'a') dialog::editNumber(vid.sspeed, -5, 5, 1, 0, + else if(xuni == 'a') dialog::editNumber(vid.sspeed, -5, 5, 1, 0, XLAT("scrolling speed"), 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, + else if(xuni == 'm') dialog::editNumber(vid.mspeed, -5, 5, 1, 0, XLAT("movement animation speed"), XLAT("+5 = move instantly")); - if(xuni == 'k') { - glyphsortorder = eGlyphsortorder((glyphsortorder+6+(shiftmul>0?1:-1)) % gsoMAX); - } - - if(xuni == 'f') switchFullscreen(); + else if(xuni == 'f') switchFullscreen(); #if CAP_GLORNOT - if(xuni == 'o' && shiftmul > 0) switchGL(); + else if(xuni == 'o' && shiftmul > 0) switchGL(); #endif - if(xuni == 'o' && shiftmul < 0) { + else if(xuni == 'o' && shiftmul < 0) { if(!vid.usingGL) vid.antialias ^= AA_NOGL | AA_FONT; else if(vid.antialias & AA_MULTI) @@ -938,7 +894,7 @@ void showGraphConfig() { // if(xuni == 'b') vid.antialias ^= AA_LINEWIDTH; - if(xuni == 'w' && vid.usingGL) { + else if(xuni == 'w' && vid.usingGL) { dialog::editNumber(vid.linewidth, 0, 10, 0.1, 1, XLAT("line width"), ""); dialog::extra_options = [] () { dialog::addBoolItem("finer lines at the boundary", vid.antialias & AA_LINEWIDTH, 'O'); @@ -946,37 +902,23 @@ void showGraphConfig() { }; } - if(xuni == 'L') { + else if(xuni == 'L') { dialog::editNumber(vid.linequality, -3, 5, 1, 1, XLAT("line quality"), XLAT("Higher numbers make the curved lines smoother, but reduce the performance.")); dialog::reaction = delayed_geo_reset; } - if(xuni == 'C') { - dialog::editNumber(vid.mobilecompasssize, 0, 100, 10, 20, XLAT("compass size"), XLAT("0 to disable")); - // we need to check the moves - dialog::reaction = checkmove; - dialog::bound_low(0); - } - #if CAP_FRAMELIMIT - if(xuni == 'l') { + else if(xuni == 'l') { dialog::editNumber(vid.framelimit, 5, 300, 10, 300, XLAT("framerate limit"), ""); dialog::bound_low(5); } #endif - if(xuni =='b') { - dialog::editNumber(fontscale, 25, 400, 10, 100, XLAT("font scale"), ""); - const int minfontscale = ISMOBILE ? 50 : 25; - dialog::reaction = [] () { setfsize = true; do_setfsize(); }; - dialog::bound_low(minfontscale); - } - - if(xuni =='p') + else if(xuni =='p') vid.backeffects = !vid.backeffects; - - handleAllConfig(sym, xuni); + + else if(doexiton(sym, uni)) popScreen(); }; } @@ -1012,85 +954,25 @@ void switchGL() { void resetConfigMenu(); -void showBasicConfig() { +void configureOther() { gamescreen(3); - const char *axmodes[5] = {"OFF", "auto", "light", "heavy", "arrows"}; - dialog::init(XLAT("basic configuration")); - if(CAP_TRANS) dialog::addSelItem(XLAT("language"), XLAT("EN"), 'l'); - dialog::addSelItem(XLAT("player character"), numplayers() > 1 ? "" : csname(vid.cs), 'g'); - if(getcstat == 'g') - mouseovers = XLAT("Affects looks and grammar"); - - if(CAP_AUDIO) { - dialog::addSelItem(XLAT("background music volume"), its(musicvolume), 'b'); - dialog::addSelItem(XLAT("sound effects volume"), its(effvolume), 'e'); - } - -// input: - dialog::addSelItem(XLAT("help for keyboard users"), XLAT(axmodes[vid.axes]), 'c'); - - dialog::addBoolItem(XLAT("reverse pointer control"), (vid.revcontrol), 'r'); - dialog::addBoolItem(XLAT("draw circle around the target"), (vid.drawmousecircle), 'd'); - - dialog::addSelItem(XLAT("message flash time"), its(vid.flashtime), 't'); - dialog::addSelItem(XLAT("limit messages shown"), its(vid.msglimit), 'z'); - - const char* msgstyles[3] = {"centered", "left-aligned", "line-broken"}; - - dialog::addSelItem(XLAT("message style"), XLAT(msgstyles[vid.msgleft]), 'a'); - -#if ISMOBILE - dialog::addBoolItem(XLAT("targetting ranged Orbs long-click only"), (vid.shifttarget&2), 'i'); -#else - dialog::addBoolItem(XLAT("targetting ranged Orbs Shift+click only"), (vid.shifttarget&1), 'i'); -#endif + dialog::init(XLAT("other configuration")); #if ISSTEAM dialog::addBoolItem(XLAT("send scores to Steam leaderboards"), (vid.steamscore&1), 'x'); + dialog::add_action([] {vid.steamscore = vid.steamscore^1; }); #endif dialog::addBoolItem(XLAT("skip the start menu"), vid.skipstart, 'm'); -#if !ISMOBILE - dialog::addBoolItem(XLAT("quick mouse"), vid.quickmouse, 'M'); -#endif + dialog::add_action([] { vid.skipstart = !vid.skipstart; }); dialog::addBoolItem(XLAT("forget faraway cells"), memory_saving_mode, 'y'); + dialog::add_action([] { memory_saving_mode = !memory_saving_mode; }); - #if CAP_ORIENTATION - dialog::addSelItem(XLAT("scrolling by device rotation"), ors::choices[ors::mode], '1'); - #endif - - if(CAP_SHMUP && !ISMOBILE) - dialog::addSelItem(XLAT("configure keys/joysticks"), "", 'p'); - -#if CAP_CONFIG - dialog::addItem(XLAT("reset all configuration"), 'R'); -#endif - showAllConfig(); - - dialog::display(); - - keyhandler = [] (int sym, int uni) { - dialog::handleNavigation(sym, uni); - - char xuni = uni | 96; - - if(uni >= 32 && uni < 64) xuni = uni; - - #if CAP_ORIENTATION - if(xuni == '1') pushScreen(ors::show); - #endif - - if(uni == 'M') vid.quickmouse = !vid.quickmouse; - else if(xuni == 'm') vid.skipstart = !vid.skipstart; - - if(xuni == 'y') memory_saving_mode = !memory_saving_mode; - - if(xuni == 'c') { vid.axes += 60 + (shiftmul > 0 ? 1 : -1); vid.axes %= 5; } - - #if CAP_AUDIO - if(CAP_AUDIO && xuni == 'b') { + if(CAP_AUDIO) { + dialog::addSelItem(XLAT("background music volume"), its(musicvolume), 'b'); + dialog::add_action([] { dialog::editNumber(musicvolume, 0, 128, 10, 60, XLAT("background music volume"), ""); dialog::reaction = [] () { #if CAP_SDLAUDIO @@ -1102,9 +984,10 @@ void showBasicConfig() { }; dialog::bound_low(0); dialog::bound_up(MIX_MAX_VOLUME); - } + }); - if(CAP_AUDIO && xuni == 'e') { + dialog::addSelItem(XLAT("sound effects volume"), its(effvolume), 'e'); + dialog::add_action([] { dialog::editNumber(effvolume, 0, 128, 10, 60, XLAT("sound effects volume"), ""); dialog::reaction = [] () { #if ISANDROID @@ -1113,46 +996,79 @@ void showBasicConfig() { }; dialog::bound_low(0); dialog::bound_up(MIX_MAX_VOLUME); - } - #endif - - if(CAP_TRANS && xuni == 'l') - pushScreen(selectLanguageScreen); - - if(xuni == 'g') pushScreen(showCustomizeChar); - -#if CAP_SHMUP - if(xuni == 'p') - shmup::configure(); -#endif - - if(uni == 'r') vid.revcontrol = !vid.revcontrol; - if(xuni == 'd') vid.drawmousecircle = !vid.drawmousecircle; -#if CAP_CONFIG - if(uni == 'R') pushScreen(resetConfigMenu); -#endif - - #if ISSTEAM - if(xuni == 'x') vid.steamscore = vid.steamscore^1; - #endif - if(xuni == 't') { - dialog::editNumber(vid.flashtime, 0, 64, 1, 8, XLAT("message flash time"), - XLAT("How long should the messages stay on the screen.")); - dialog::bound_low(0); - } + }); + } - if(xuni == 'z') { - dialog::editNumber(vid.msglimit, 0, 64, 1, 5, XLAT("limit messages shown"), - XLAT("Maximum number of messages on screen.")); - dialog::bound_low(0); - } - - if(xuni == 'i') { vid.shifttarget = vid.shifttarget^3; } - - if(xuni == 'a') { vid.msgleft = (1+vid.msgleft) % 3; } + menuitem_sightrange('r'); + + dialog::addBreak(50); + dialog::addBack(); - handleAllConfig(sym, xuni); + dialog::display(); + } + +void configureInterface() { + gamescreen(3); + dialog::init(XLAT("interface")); + + if(CAP_TRANS) { + dialog::addSelItem(XLAT("language"), XLAT("EN"), 'l'); + dialog::add_action_push(selectLanguageScreen); + } + + dialog::addSelItem(XLAT("player character"), numplayers() > 1 ? "" : csname(vid.cs), 'g'); + dialog::add_action_push(showCustomizeChar); + if(getcstat == 'g') mouseovers = XLAT("Affects looks and grammar"); + + dialog::addSelItem(XLAT("message flash time"), its(vid.flashtime), 't'); + dialog::add_action([] { + dialog::editNumber(vid.flashtime, 0, 64, 1, 8, XLAT("message flash time"), + XLAT("How long should the messages stay on the screen.")); + dialog::bound_low(0); + }); + + dialog::addSelItem(XLAT("limit messages shown"), its(vid.msglimit), 'z'); + dialog::add_action([] { + dialog::editNumber(vid.msglimit, 0, 64, 1, 5, XLAT("limit messages shown"), + XLAT("Maximum number of messages on screen.")); + dialog::bound_low(0); + }); + + const char* msgstyles[3] = {"centered", "left-aligned", "line-broken"}; + + dialog::addSelItem(XLAT("message style"), XLAT(msgstyles[vid.msgleft]), 'a'); + dialog::add_action([] { + vid.msgleft = (1+vid.msgleft) % 3; + }); + + dialog::addSelItem(XLAT("font scale"), its(fontscale), 'b'); + dialog::add_action([] { + dialog::editNumber(fontscale, 25, 400, 10, 100, XLAT("font scale"), ""); + const int minfontscale = ISMOBILE ? 50 : 25; + dialog::reaction = [] () { setfsize = true; do_setfsize(); }; + dialog::bound_low(minfontscale); + }); + + const char *glyphsortnames[6] = { + "first on top", "first on bottom", + "last on top", "last on bottom", + "by land", "by number" }; + dialog::addSelItem(XLAT("inventory/kill sorting"), XLAT(glyphsortnames[glyphsortorder]), 'k'); + dialog::add_action([] { + glyphsortorder = eGlyphsortorder((glyphsortorder+6+(shiftmul>0?1:-1)) % gsoMAX); + }); + + const char *glyphmodenames[3] = {"letters", "auto", "images"}; + dialog::addSelItem(XLAT("inventory/kill mode"), XLAT(glyphmodenames[vid.graphglyph]), 'd'); + dialog::add_action([] { + vid.graphglyph = (1+vid.graphglyph)%3; + }); + + dialog::addBreak(50); + dialog::addBack(); + + dialog::display(); } #if CAP_SDLJOY @@ -1888,6 +1804,95 @@ void selectLanguageScreen() { } #endif +void configureMouse() { + gamescreen(1); + dialog::init(XLAT("mouse & touchscreen")); + + dialog::addBoolItem(XLAT("reverse pointer control"), (vid.revcontrol), 'r'); + dialog::add_action([] {vid.revcontrol = !vid.revcontrol; }); + + dialog::addBoolItem(XLAT("draw circle around the target"), (vid.drawmousecircle), 'd'); + dialog::add_action([] { vid.drawmousecircle = !vid.drawmousecircle; }); + +#if ISMOBILE + dialog::addBoolItem(XLAT("targetting ranged Orbs long-click only"), (vid.shifttarget&2), 'i'); +#else + dialog::addBoolItem(XLAT("targetting ranged Orbs Shift+click only"), (vid.shifttarget&1), 'i'); +#endif + dialog::add_action([] {vid.shifttarget = vid.shifttarget^3; }); + + #if !ISMOBILE + dialog::addBoolItem(XLAT("quick mouse"), vid.quickmouse, 'M'); + dialog::add_action([] {vid.quickmouse = !vid.quickmouse; }); + #endif + + dialog::addSelItem(XLAT("move by clicking on compass"), its(vid.mobilecompasssize), 'C'); + dialog::add_action([] { + dialog::editNumber(vid.mobilecompasssize, 0, 100, 10, 20, XLAT("compass size"), XLAT("0 to disable")); + // we need to check the moves + dialog::reaction = checkmove; + dialog::bound_low(0); + }); + + #if CAP_ORIENTATION + dialog::addSelItem(XLAT("scrolling by device rotation"), ors::choices[ors::mode], '1'); + dialog::add_action([] { pushScreen(ors::show); }); + #endif + + dialog::display(); + } + +void showSettings() { + gamescreen(1); + dialog::init(XLAT("settings")); + + dialog::addItem(XLAT("interface"), 'i'); + dialog::add_action_push(configureInterface); + + dialog::addItem(XLAT("general graphics"), 'g'); + dialog::add_action_push(showGraphConfig); + + dialog::addItem(XLAT("colors and aura"), 'c'); + dialog::add_action_push(show_color_dialog); + + dialog::addItem(XLAT("3D graphics"), '9'); + dialog::add_action_push(show3D); + + dialog::addItem(XLAT("quick options"), 'q'); + dialog::add_action_push(showGraphQuickKeys); + + dialog::addItem(XLAT("models and projections"), 'a'); + dialog::add_action_push(conformal::model_menu); + +#if CAP_SHMUP + if(CAP_SHMUP && !ISMOBILE) { + dialog::addSelItem(XLAT("keyboard & joysticks"), "", 'k'); + dialog::add_action(shmup::configure); + } +#endif + + dialog::addSelItem(XLAT("mouse & touchscreen"), "", 'm'); + dialog::add_action_push(configureMouse); + + dialog::addItem(XLAT("other settings"), 'o'); + dialog::add_action_push(configureOther); + + dialog::addBreak(100); + +#if CAP_CONFIG + dialog::addItem(XLAT("save the current config"), 's'); + dialog::add_action(saveConfig); + + dialog::addItem(XLAT("reset all configuration"), 'R'); + dialog::add_action_push(resetConfigMenu); +#endif + + if(getcstat == 's') mouseovers = XLAT("Config file: %1", conffile); + + dialog::addBack(); + dialog::display(); + } + #if CAP_COMMANDLINE int read_color_args() { @@ -2027,8 +2032,8 @@ int read_config_args() { else if(argis("-d:stereo")) { PHASEFROM(2); launch_dialog(showStereo); } - else if(argis("-d:basic")) { - PHASEFROM(2); launch_dialog(showBasicConfig); + else if(argis("-d:iface")) { + PHASEFROM(2); launch_dialog(configureInterface); } else if(argis("-d:graph")) { PHASEFROM(2); launch_dialog(showGraphConfig); diff --git a/control.cpp b/control.cpp index 22266e7e..6733a08d 100644 --- a/control.cpp +++ b/control.cpp @@ -956,29 +956,36 @@ int get_direction_key(int sym, int uni) { return sym; } -void gmodekeys(int sym, int uni) { +bool gmodekeys(int sym, int uni) { #if CAP_RUG - if(rug::rugged) rug::handlekeys(sym, uni); + if(rug::rugged && rug::handlekeys(sym, uni)) return true; #endif + + if(NUMBERKEY == '6') { vid.grid = !vid.grid; return true; } + if(NUMBERKEY == '7') { vid.darkhepta = !vid.darkhepta; return true; } + if(DIM == 2) { if(NUMBERKEY == '1' && !rug::rugged) { vid.alpha = 999; vid.scale = 998; vid.xposition = vid.yposition = 0; } - if(NUMBERKEY == '2' && !rug::rugged) { vid.alpha = 1; vid.scale = 0.4; vid.xposition = vid.yposition = 0; } - if(NUMBERKEY == '3' && !rug::rugged) { vid.alpha = 1; vid.scale = 1; vid.xposition = vid.yposition = 0; } - if(NUMBERKEY == '4' && !rug::rugged) { vid.alpha = 0; vid.scale = 1; vid.xposition = vid.yposition = 0; } - if(NUMBERKEY == '5') { vid.wallmode += 60 + (shiftmul > 0 ? 1 : -1); vid.wallmode %= 6; } - if(uni == '%') { + else if(NUMBERKEY == '2' && !rug::rugged) { vid.alpha = 1; vid.scale = 0.4; vid.xposition = vid.yposition = 0; } + else if(NUMBERKEY == '3' && !rug::rugged) { vid.alpha = 1; vid.scale = 1; vid.xposition = vid.yposition = 0; } + else if(NUMBERKEY == '4' && !rug::rugged) { vid.alpha = 0; vid.scale = 1; vid.xposition = vid.yposition = 0; } + else if(NUMBERKEY == '5') { vid.wallmode += 60 + (shiftmul > 0 ? 1 : -1); vid.wallmode %= 6; } + else if(NUMBERKEY == '8') { vid.monmode += 60 + (shiftmul > 0 ? 1 : -1); vid.monmode %= 6; } + else if(uni == '%') { if(vid.wallmode == 0) vid.wallmode = 6; vid.wallmode--; } + else return false; + return true; } else { if(NUMBERKEY == '1') { vid.yshift = 0; vid.sspeed = 0; } - if(NUMBERKEY == '2') { vid.yshift = 0; vid.sspeed = -10; } - if(NUMBERKEY == '3') { vid.yshift = 2; vid.sspeed = 0; } - if(NUMBERKEY == '5') { vid.wallmode = vid.wallmode == 5 ? 4 : 5; } + else if(NUMBERKEY == '2') { vid.yshift = 0; vid.sspeed = -10; } + else if(NUMBERKEY == '3') { vid.yshift = 2; vid.sspeed = 0; } + else if(NUMBERKEY == '5') { vid.wallmode = vid.wallmode == 5 ? 4 : 5; } + else return false; + return true; } - if(NUMBERKEY == '6') vid.grid = !vid.grid; - if(NUMBERKEY == '7') { vid.darkhepta = !vid.darkhepta; } } bool haveMobileCompass() { diff --git a/dialogs.cpp b/dialogs.cpp index e8fd9c10..830f0338 100644 --- a/dialogs.cpp +++ b/dialogs.cpp @@ -89,6 +89,8 @@ namespace dialog { add_key_action(lastItem().key, action); } + void add_action_push(const reaction_t& action) { add_action([action] { pushScreen(action); }); } + void handler(int sym, int uni) { dialog::handleNavigation(sym, uni); if(doexiton(sym, uni)) popScreen(); diff --git a/help.cpp b/help.cpp index 90033d39..8ad3a25d 100644 --- a/help.cpp +++ b/help.cpp @@ -74,6 +74,35 @@ void buildHelpText() { "The monster could also kill you by moving into your location, but the game " "automatically cancels all moves which result in that.\n\n" ); + + if(shmup::on) { + help += XLAT( + "Shmup (shoot'em up) mode: You can play a hyperbolic shoot'em up game. The game is based " + "on the usual turn-based grid-based HyperRogue, but there are some changes. You fight by " + "throwing knives, and you have three extra lives. There are no allies, so all Orbs " + "related to allies give you extra lives instead (up to 5). Some other rules have been " + "adapted too.\n\n"); + } + + if(shmup::on && multi::players > 1) { + help += XLAT( + "Multiplayer: Play cooperatively (locally); treasures, kills, and deaths are calculated " + "for each player too, for more competitive play. Orbs and treasures are shared, orbs drain " + "faster, knives recharge slower, and player characters are not allowed to separate.\n\n"); + } + + if(multi::players > 1 && !shmup::on) { + help += XLAT( + "Turn-based multiplayer: Turns are executed in parallel. A player can leave the game " + "by pressing a designated key (useful when about to get killed or lost). The following " + "Orbs work to bring such players back: "); + + help += XLATN(iinf[itOrbLife].name); help += ", "; + help += XLATN(iinf[itOrbFriend].name); help += ", "; + help += XLATN(iinf[itOrbUndeath].name); help += ", "; + help += XLATN(iinf[itOrbTeleport].name); help += ", "; + help += XLATN(iinf[itOrbSafety].name); help += "\n\n"; + } #if CAP_INV if(inv::on) diff --git a/hyper.h b/hyper.h index fcc41cb4..761d942e 100644 --- a/hyper.h +++ b/hyper.h @@ -869,6 +869,8 @@ namespace multi { void checklastmove(); void leaveGame(int i); void configure(); + + void showConfigureMultiplayer(); } template class hookset : public map> {}; @@ -963,6 +965,8 @@ namespace shmup { extern monster *pc[MAXPLAYER]; int reflect(cell*& c2, cell*& mbase, transmatrix& nat); + + void switch_shmup(); } transmatrix& ggmatrix(cell *c); @@ -1944,6 +1948,9 @@ namespace dialog { void addBack(); void add_action(const reaction_t& action); void add_key_action(int key, const reaction_t& action); + + void add_action_push(const reaction_t& action); + inline void add_action_push(void a()) { add_action_push((reaction_t) a); } string view_edited_string(); void start_editing(string& s); @@ -2625,11 +2632,7 @@ void closeJoysticks(); void preparesort(); -#if ISMOBILE==1 #define SHMUPTITLE "shoot'em up mode" -#else -#define SHMUPTITLE "shoot'em up / multiplayer / input" -#endif bool dodrawcell(cell *c); void drawcell(cell *c, transmatrix V, int spinv, bool mirrored); @@ -2643,7 +2646,7 @@ extern function keyhandler; #if CAP_SDL extern function joyhandler; #endif -void gmodekeys(int sym, int uni); +bool gmodekeys(int sym, int uni); // check for a plain number key #define NUMBERKEY (interpret_as_direction(sym, uni) ? 0 : uni) @@ -2662,7 +2665,7 @@ namespace scores { void load(); } void gotoHelp(const string& h); void showCustomizeChar(); void showCheatMenu(); -void showDisplayMode(); +void showGraphQuickKeys(); void showChangeMode(); void showEuclideanMenu(); void show3D(); diff --git a/menus.cpp b/menus.cpp index b20ac33d..4998ccb0 100644 --- a/menus.cpp +++ b/menus.cpp @@ -204,10 +204,9 @@ void showMainMenu() { dialog::init(XLAT("HyperRogue %1", VER), 0xC00000, 200, 100); - dialog::addItem(XLAT("basic configuration"), 'b'); - dialog::addItem(XLAT("graphics configuration"), 'g'); - dialog::addItem(XLAT("special display modes"), 'd'); - dialog::addItem(XLAT("special game modes"), 'm'); + dialog::addItem(XLAT("settings"), 's'); + dialog::add_action([] { pushScreen(showSettings); }); + dialog::addItem(XLAT("special modes"), 'm'); #if CAP_SAVE dialog::addItem(XLAT("local highscores"), 't'); @@ -262,9 +261,6 @@ void showMainMenu() { dialog::handleNavigation(sym, uni); if(sym == SDLK_F1 || uni == 'h') gotoHelp("@"); else if(uni == 'c' && cheater) pushScreen(showCheatMenu); - else if(uni == 'b') pushScreen(showBasicConfig); - else if(uni == 'g') pushScreen(showGraphConfig); - else if(uni == 'd') pushScreen(showDisplayMode); else if(uni == 'm') pushScreen(showChangeMode); else if(uni == 'R') dialog::do_if_confirmed([] { #if CAP_STARTANIM @@ -324,15 +320,11 @@ void editScale() { dialog::scaleSinh(); } -void showDisplayMode() { +void showGraphQuickKeys() { cmode = sm::SIDE | sm::MAYDARK; gamescreen(0); - dialog::init(XLAT("special display modes")); - - const char *wdmodes[6] = {"ASCII", "black", "plain", "Escher", "plain/3D", "Escher/3D"}; - const char *mdmodes[6] = {"ASCII", "items only", "items and monsters", "high contrast", - "3D", "high contrast/3D"}; + dialog::init(XLAT("quick options")); if(DIM == 2) { dialog::addBoolItem(XLAT("orthogonal projection"), vid.alpha >= 500, '1'); @@ -346,97 +338,29 @@ void showDisplayMode() { dialog::addBoolItem(XLAT("third person perspective"), vid.yshift > 0 && vid.sspeed > -5, '3'); } + const char *wdmodes[6] = {"ASCII", "black", "plain", "Escher", "plain/3D", "Escher/3D"}; 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"); + + const char *mdmodes[6] = {"ASCII", "items only", "items and monsters", "high contrast", + "3D", "high contrast/3D"}; + dialog::addSelItem(XLAT("monster display mode"), XLAT(mdmodes[vid.monmode]), '8'); + dialog::addBoolItem(XLAT("draw the grid"), (vid.grid), '6'); dialog::addBoolItem(XLAT("mark heptagons"), (vid.darkhepta), '7'); - dialog::addSelItem(XLAT("3D configuration"), "", '9'); - if(DIM == 2) - dialog::addSelItem(XLAT("scale factor"), fts(vid.scale), 'z'); - dialog::addSelItem(XLAT("monster display mode"), XLAT(mdmodes[vid.monmode]), 'm'); - - dialog::addBreak(50); - -#if CAP_EDIT - if(DIM == 2) - dialog::addBoolItem(XLAT("vector graphics editor"), (false), 'g'); -#endif - -#if CAP_TEXTURE - if(DIM == 2) - dialog::addBoolItem(XLAT("texture mode"), texture::config.tstate == texture::tsActive, 't'); -#endif - - - // display modes -#if CAP_RUG - if(DIM == 2) - dialog::addBoolItem(XLAT("hypersian rug mode"), (rug::rugged), 'u'); -#endif -#if CAP_MODEL - if(DIM == 2) - dialog::addBoolItem(XLAT("paper model creator"), (false), 'n'); -#endif - - dialog::addBoolItem(XLAT("models and projections"), pmodel, 'a'); - - dialog::addBoolItem(XLAT("animations/history"), anims::any_on(), 'A'); -// dialog::addBoolItem(XLAT("expansion"), viewdists, 'x'); - - showAllConfig(); + dialog::addBreak(50); + dialog::addInfo("Hint: these keys usually work during the game"); + dialog::addInfo("also hold Alt during the game to toggle high contrast"); + + dialog::addBreak(50); + dialog::addBack(); dialog::display(); - + keyhandler = [] (int sym, int uni) { dialog::handleNavigation(sym, uni); - char xuni = uni; - // if((xuni >= 'A' && xuni <= 'Z') || (xuni >= 1 && xuni <= 26)) xuni |= 32; - - if(xuni == 'p') projectionDialog(); - if(xuni == 'z') editScale(); - - #if CAP_TEXTURE - if(xuni == 't') pushScreen(texture::showMenu); - #endif - - if(xuni == 'm') { vid.monmode += 60 + (shiftmul > 0 ? 1 : -1); vid.monmode %= 6; } - - if(xuni == '9') pushScreen(show3D); - - #if CAP_EDIT - else if(xuni == 'g') { - pushScreen(mapeditor::showDrawEditor); - mapeditor::initdraw(cwt.at); - } - #endif - - else if(xuni == 'x') { - viewdists = !viewdists; - } - #if CAP_RUG - else if(xuni == 'u') { - //if(sphere) projectionDialog(); - //else - rug::select(); - } - #endif - else if(uni == 'a') - pushScreen(conformal::model_menu); - #if CAP_ANIMATIONS - else if(uni == 'A') - pushScreen(anims::show); - #endif - - #if CAP_MODEL - else if(xuni == 'n') - netgen::run(); - #endif - - else gmodekeys(sym, uni); - - handleAllConfig(sym, xuni); + if(gmodekeys(sym, uni)) ; + else if(doexiton(sym, uni)) popScreen(); }; } @@ -486,19 +410,82 @@ void help_nochaos() { "\n\nYou need to reach Crossroads IV to unlock the Chaos mode." ); } + +void showCreative() { + cmode = sm::SIDE | sm::MAYDARK; + gamescreen(3); + dialog::init(XLAT("creative mode")); + + dialog::addItem("map editor", 'm'); + dialog::add_action([] { + if(tactic::on) + addMessage(XLAT("Not available in the pure tactics mode!")); + else if(daily::on) { + addMessage(XLAT("Not available in the daily challenge!")); + } + else dialog::cheat_if_confirmed([] { + cheater++; + pushScreen(mapeditor::showMapEditor); + lastexplore = turncount; + addMessage(XLAT("You activate your terraforming powers!")); + }); + }); + +#if CAP_EDIT + dialog::addItem(XLAT("vector graphics editor"), 'g'); + dialog::add_action([] { + pushScreen(mapeditor::showDrawEditor); + mapeditor::initdraw(cwt.at); + }); +#endif + + // display modes +#if CAP_MODEL + if(DIM == 2) { + dialog::addItem(XLAT("paper model creator"), 'n'); + dialog::add_action([] { netgen::run(); }); + } +#endif + + dialog::addItem(XLAT("screenshots"), 's'); + dialog::add_action([] () { pushScreen(shot::menu); }); + + dialog::addBoolItem(XLAT("animations/history"), anims::any_on(), 'A'); + dialog::add_action_push(anims::show); + +#if CAP_TEXTURE + if(DIM == 2) { + dialog::addBoolItem(XLAT("texture mode"), texture::config.tstate == texture::tsActive, 't'); + dialog::add_action_push(texture::showMenu); + } +#endif + + dialog::addBoolItem(XLAT("cheat mode"), (cheater), 'c'); + dialog::add_action(enable_cheat); + +// dialog::addBoolItem(XLAT("expansion"), viewdists, 'x'); + + dialog::addBreak(50); + dialog::addBack(); + dialog::display(); + } void showChangeMode() { gamescreen(3); - dialog::init(XLAT("special game modes")); - - // gameplay modes + dialog::init(XLAT("special modes")); + // gameplay modes #if CAP_TOUR dialog::addBoolItem(XLAT("Tutorial"), tour::on, 'T'); #endif - + dialog::addBoolItem(XLAT("creative mode"), (false), 'c'); + dialog::add_action_push(showCreative); dialog::addBoolItem(XLAT("experiment with geometry"), geometry || CHANGED_VARIATION || viewdists, 'e'); - dialog::addBoolItem(XLAT(SHMUPTITLE), (shmup::on || multi::players > 1), 's'); + + dialog::addBreak(100); + + dialog::addBoolItem(XLAT(SHMUPTITLE), shmup::on, 's'); + dialog::addBoolItem(XLAT("multiplayer"), multi::players > 1, 'm'); if(!shmup::on) dialog::addSelItem(XLAT("hardcore mode"), hardcore && !pureHardcore() ? XLAT("PARTIAL") : ONOFF(hardcore), 'h'); if(getcstat == 'h') @@ -519,14 +506,6 @@ void showChangeMode() { dialog::addBoolItem(XLAT("Strange Challenge"), daily::on, 'z'); #endif - dialog::addBreak(50); - // cheating and map editor - - dialog::addBoolItem(XLAT("cheat mode"), (cheater), 'c'); -#if CAP_EDIT - dialog::addBoolItem(XLAT("map editor"), (false), 'm'); -#endif - dialog::addBreak(50); dialog::addBack(); @@ -543,9 +522,6 @@ void showChangeMode() { pushScreen(daily::showMenu); #endif - else if(uni == 'c') - enable_cheat(); - else if(xuni == 'e') runGeometryExperiments(); else if(xuni == 't') { @@ -583,28 +559,9 @@ void showChangeMode() { else dialog::do_if_confirmed([] { restart_game(rg::princess); }); } - #if CAP_EDIT - else if(xuni == 'm') { - if(tactic::on) - addMessage(XLAT("Not available in the pure tactics mode!")); - else if(daily::on) { - addMessage(XLAT("Not available in the daily challenge!")); - } - else dialog::cheat_if_confirmed([] { - cheater++; - pushScreen(mapeditor::showMapEditor); - lastexplore = turncount; - addMessage(XLAT("You activate your terraforming powers!")); - }); - } - #endif - else if(xuni == 's') { - #if ISMOBILE==1 - restart_game(rg::shmup); - #else - shmup::configure(); - #endif - } + else if(xuni == 's') + dialog::do_if_confirmed(shmup::switch_shmup); + else if(xuni == 'h' && !shmup::on) switchHardcore(); else if(xuni == 'r') { @@ -984,9 +941,6 @@ int read_menu_args() { else if(argis("-d:main")) { PHASEFROM(2); launch_dialog(showMainMenu); } - else if(argis("-d:display")) { - PHASEFROM(2); launch_dialog(showDisplayMode); - } else if(argis("-d:mode")) { PHASEFROM(2); launch_dialog(showChangeMode); } diff --git a/quit.cpp b/quit.cpp index e0136475..885f145e 100644 --- a/quit.cpp +++ b/quit.cpp @@ -147,7 +147,7 @@ hint hints[] = { dialog::addItem(XLAT("special display modes"), 'z'); }, []() { - pushScreen(showDisplayMode); + pushScreen(conformal::model_menu); }}, { diff --git a/shmup.cpp b/shmup.cpp index 3031ab0b..b2ff3d49 100644 --- a/shmup.cpp +++ b/shmup.cpp @@ -357,82 +357,75 @@ struct joy_configurer { struct shmup_configurer { - bool shmupcfg; - int playercfg; - - shmup_configurer() { shmupcfg = shmup::on; playercfg = multi::players; } - void operator()() { #if CAP_SDL cmode = sm::SHMUPCONFIG; - dialog::init(SHMUPTITLE); - - dialog::addItem(player_count_name(playercfg), 'n'); - - dialog::addItem(XLAT(shmupcfg ? "shoot'em up mode" : "turn-based mode"), 's'); + gamescreen(3); + dialog::init(XLAT("keyboard & joysticks")); - dialog::addItem(XLAT(shmup::on == shmupcfg && players == playercfg ? - "continue playing" - : "start a new game"), '0'); + bool haveconfig = shmup::on || players > 1 || multi::alwaysuse; - if(shmupcfg || multi::alwaysuse || playercfg > 1) - dialog::addItem(XLAT("configure player 1") + dsc(0), '1'); + if(haveconfig) + dialog::addItem(XLAT("configure player 1"), '1'); else dialog::addBreak(100); - if(playercfg > 1) - dialog::addItem(XLAT("configure player 2") + dsc(1), '2'); - else if(playercfg == 1 && !shmupcfg) + if(players > 1) + dialog::addItem(XLAT("configure player 2"), '2'); + else if(players == 1 && !shmup::on) dialog::addSelItem(XLAT("input"), XLAT(multi::alwaysuse ? "config" : "default"), 'a'); else dialog::addBreak(100); - if(playercfg > 2) - dialog::addItem(XLAT("configure player 3") + dsc(2), '3'); + if(players > 2) + dialog::addItem(XLAT("configure player 3"), '3'); #if CAP_SDLJOY - else if(playercfg == 1 && !shmupcfg && !shmupcfg && !multi::alwaysuse) + else if(!haveconfig) dialog::addItem(XLAT("old style joystick configuration"), 'b'); #endif else dialog::addBreak(100); - if(playercfg > 3) - dialog::addItem(XLAT("configure player 4") + dsc(3), '4'); + if(players > 3) + dialog::addItem(XLAT("configure player 4"), '4'); else if(!shmup::on && !multi::alwaysuse) { dialog::addBoolItem(XLAT("smooth scrolling"), smooth_scrolling, 'c'); } + else if(alwaysuse) + dialog::addInfo(XLAT("note: configured input is designed for")); else dialog::addBreak(100); - if(playercfg > 4) - dialog::addItem(XLAT("configure player 5") + dsc(4), '5'); + if(players > 4) + dialog::addItem(XLAT("configure player 5"), '5'); + else if(!shmup::on && !multi::alwaysuse) { + const char *axmodes[5] = {"OFF", "auto", "light", "heavy", "arrows"}; + dialog::addSelItem(XLAT("help for keyboard users"), XLAT(axmodes[vid.axes]), 'h'); + dialog::add_action([] {vid.axes += 60 + (shiftmul > 0 ? 1 : -1); vid.axes %= 5; } ); + } + else if(alwaysuse) + dialog::addInfo(XLAT("multiplayer and shmup mode; some features")); else dialog::addBreak(100); - if(playercfg > 5) - dialog::addItem(XLAT("configure player 6") + dsc(5), '6'); + if(players > 5) + dialog::addItem(XLAT("configure player 6"), '6'); + else if(alwaysuse) + dialog::addInfo(XLAT("work worse if you use it.")); else dialog::addBreak(100); - if(playercfg > 6) - dialog::addItem(XLAT("configure player 7") + dsc(6), '7'); + if(players > 6) + dialog::addItem(XLAT("configure player 7"), '7'); else dialog::addBreak(100); - if(shmupcfg || multi::alwaysuse || playercfg > 1) + if(shmup::on || multi::alwaysuse || players > 1) dialog::addItem(XLAT("configure panning and general keys"), 'p'); else dialog::addBreak(100); #if CAP_SDLJOY if(numsticks > 0) { - if(shmupcfg || multi::alwaysuse || playercfg > 1) + if(shmup::on || multi::alwaysuse || players > 1) dialog::addItem(XLAT("configure joystick axes"), 'j'); else dialog::addBreak(100); } #endif - if(multi::players > 1) - dialog::addItem(XLAT("reset per-player statistics"), 'r'); - else dialog::addBreak(100); - dialog::addBreak(50); - #if CAP_CONFIG - dialog::addItem(XLAT("save the configuration"), 'c'); - #endif - dialog::addHelp(); dialog::addBack(); @@ -443,7 +436,7 @@ struct shmup_configurer { } void handleConfig(int sym, int uni) { - auto& cmdlist = shmupcfg ? (DIM == 3 ? playercmds_shmup3 : playercmds_shmup) : playercmds_turn; + auto& cmdlist = shmup::on ? (DIM == 3 ? playercmds_shmup3 : playercmds_shmup) : playercmds_turn; #if CAP_SDL if(uni == '1') pushScreen(key_configurer(1, cmdlist)); @@ -455,74 +448,15 @@ struct shmup_configurer { else if(uni == '6') pushScreen(key_configurer(7, cmdlist)); else if(uni == '7') pushScreen(key_configurer(8, cmdlist)); #if CAP_SDLJOY - else if(uni == 'j') pushScreen(joy_configurer(playercfg)); + else if(uni == 'j') pushScreen(joy_configurer(players)); #endif else if(uni == 'a') multi::alwaysuse = !multi::alwaysuse; #if CAP_SDLJOY else if(uni == 'b') pushScreen(showJoyConfig); #endif else if(uni == 'c') smooth_scrolling = !smooth_scrolling; - else if(uni == 'r') - for(int i=0; i 0 ? 1 : -1; - playercfg %= MAXPLAYER; - if(playercfg <= 0) playercfg += MAXPLAYER; - } - else if(sym == SDLK_F1 || uni == '?' || uni == 'h') { - gotoHelp(""); - - help = XLAT( - "Shmup (shoot'em up) mode: You can play a hyperbolic shoot'em up game. The game is based " - "on the usual turn-based grid-based HyperRogue, but there are some changes. You fight by " - "throwing knives, and you have three extra lives. There are no allies, so all Orbs " - "related to allies give you extra lives instead (up to 5). Some other rules have been " - "adapted too.\n\n"); - - help += XLAT( - "Multiplayer: Play cooperatively (locally); treasures, kills, and deaths are calculated " - "for each player too, for more competitive play. Orbs and treasures are shared, orbs drain " - "faster, knives recharge slower, and player characters are not allowed to separate.\n\n"); - - help += XLAT( - "Turn-based multiplayer: Turns are executed in parallel. A player can leave the game " - "by pressing a designated key (useful when about to get killed or lost). The following " - "Orbs work to bring such players back: "); - - help += XLATN(iinf[itOrbLife].name); help += ", "; - help += XLATN(iinf[itOrbFriend].name); help += ", "; - help += XLATN(iinf[itOrbUndeath].name); help += ", "; - help += XLATN(iinf[itOrbTeleport].name); help += ", "; - help += XLATN(iinf[itOrbSafety].name); help += "\n\n"; - - help += XLAT("This menu can be also used to configure keys.\n\n"); - } - else if(doexiton(sym, uni)) { - popScreen(); - auto sc = shmupcfg; - auto pc = playercfg; - if(shmup::on != sc || pc != players) dialog::do_if_confirmed([sc, pc] { - if(shmup::on != sc) { - stop_game(); - switch_game_mode(rg::shmup); - resetScores(); - } - if(pc != players) { - stop_game(); - players = pc; - resetScores(); - } - start_game(); - }); - } #endif + else if(doexiton(sym, uni)) popScreen(); } }; @@ -530,6 +464,36 @@ void configure() { pushScreen(shmup_configurer()); } +void showConfigureMultiplayer() { + gamescreen(1); + dialog::init("multiplayer"); + + for(int i=1; i <= MAXPLAYER; i++) { + string s = player_count_name(i); + if(i <= players) s += dsc(i-1); + dialog::addBoolItem(s, '1', i == multi::players); + dialog::add_action([i] { + dialog::do_if_confirmed([i] { + stop_game(); + players = i; + start_game(); + }); + }); + } + + if(multi::players > 1) { + dialog::addItem(XLAT("reset per-player statistics"), 'r'); + dialog::add_action([] { + for(int i=0; i