// Hyperbolic Rogue -- commandline options // Copyright (C) 2011-2018 Zeno Rogue, see 'hyper.cpp' for details /** \file commandline.cpp * \brief Commandline options support */ #include "hyper.h" namespace hr { #ifdef RESOURCEDESTDIR EX string rsrcdir = RESOURCEDESTDIR; #endif #ifndef RESOURCEDESTDIR EX string rsrcdir = ""; #endif EX bool delayed_start; #if CAP_COMMANDLINE EX string scorefile = "hyperrogue.log"; EX namespace arg { template T read_index(T fallback, int max, const string& ss) { if(ss[0] < '0' && ss[0] > '9') return fallback; int val = atoi(ss.c_str()); if(val < 0 || val >= max) return fallback; return T(val); } EX eLand readland(const string& ss) { if(ss == "II") return laCrossroads2; if(ss == "III") return laCrossroads3; if(ss == "IV") return laCrossroads4; if(ss == "V") return laCrossroads5; for(int l=0; l, version " VER "\n"); #if !NOLICENSE printf("released under GNU General Public License version 2 and thus\n"); printf("comes with absolutely no warranty; see COPYING for details\n"); #endif #ifdef FHS auto try_place = [&] (string env, string suffix, string& which_file, bool only_file) { char *res = getenv(env.c_str()); if(!res) return false; string buf = res; buf += suffix; buf += "/hyperrogue"; if(only_file && file_exists(buf + "/" + which_file)) { which_file = buf + "/" + which_file; return true; } if(!file_exists(buf)) system(("mkdir -p " +buf).c_str()); which_file = buf + "/" + which_file; return true; }; auto try_dot = [&] (string& which_file) { char *res = getenv("HOME"); string buf = res; buf += "/."; buf += which_file; if(!file_exists(buf)) return false; which_file = buf; return true; }; if(try_dot(scorefile)) {} else if(try_place("XDG_DATA_HOME", "", scorefile, true)) {} else if(try_place("HOME", "/.local/share", scorefile, false)) {} else if(try_place("XDG_DATA_HOME", "", scorefile, false)) {} if(try_dot(conffile)) {} else if(try_place("XDG_CONFIG_HOME", "", conffile, true)) {} else if(try_place("HOME", "/.config", conffile, true)) {} else if(try_place("XDG_CONFIG_HOME", "", conffile, false)) {} #endif } EX namespace arg { EX int curphase; EX vector argument; EX int pos; EX void lshift() { pos++; } EX void unshift() { pos--; } EX void shift() { lshift(); if(pos >= isize(argument)) { printf("Missing parameter\n"); exit(1); } } EX bool nomore() { return pos >= isize(argument); } EX const string& args() { return argument[pos]; } EX const char* argcs() { return args().c_str(); } EX int argi() { return atoi(argcs()); } EX long long argll() { return atoll(argcs()); } EX int shift_argi() { shift(); return argi(); } EX const string& shift_args() { shift(); return args(); } EX unsigned arghex() { return strtoll(argcs(), NULL, 16); } EX ld argf() { try { return parseld(args()); } catch(hr_parse_exception& ex) { println(hlog, "error parsing commandline parameters: ", ex.s); exit(1); } } EX bool argis(const string& s) { if(args()[0] == '-' && args()[1] == '-') return args().substr(1) == s; return args() == s; } EX color_t argcolor(int bits) { return parsecolor(args(), bits == 32); } int parameter_id; EX void shift_arg_formula(ld& x, const reaction_t& r IS(reaction_t())) { shift(); auto par = anims::find_param(&x); if(!par) par = param_f(x, "tmp_parameter_" + its(parameter_id++))->set_reaction(r); par->load_as_animation(args()); } #if HDR // an useful macro #define PHASE(x) { if(arg::curphase > x) arg::phaseerror(x); else if(arg::curphase < x) return 2; } #define PHASEFROM(x) { if(arg::curphase < x) return 2; } #define TOGGLE(x, param, act) \ else if(args()[0] == '-' && args()[1] == x && !args()[2]) { PHASEFROM(2); showstartmenu = false; act; } \ else if(args()[0] == '-' && args()[1] == x && args()[2] == '1') { PHASEFROM(2); showstartmenu = false; if(!param) act; } \ else if(args()[0] == '-' && args()[1] == x && args()[2] == '0') { PHASEFROM(2); showstartmenu = false; if(param) act; } #endif EX void cheat() { autocheat = true; cheater++; timerghost = false; } EX void run_arguments(const vector vec) { dynamicval p(pos, 0); dynamicval> orig(argument, vec); read(3); } EX void init(int argc, char **argv) { for(int i=0; iwhich_copy = View * inverse(T) * current_display->which_copy; } else if(argis("-rotate-up")) { start_game(); shiftmatrix S = ggmatrix(cwt.at->master->move(0)->c7); View = spin90() * spintox(S.T*C0) * View; playermoved = false; } else if(argis("-face-vertex")) { PHASE(3); start_game(); auto &ss = currentmap->get_cellshape(cwt.at); View = cspin90(0, 2) * spintox(ss.vertices_only_local[0]); playermoved = false; } else if(argis("-face-face")) { PHASE(3); start_game(); View = cspin90(0, 2); } else if(argis("-center-vertex")) { PHASE(3); shift(); int i = argi(); shift(); int j = argi(); shift(); int k = argi(); start_game(); auto fh = currentmap->get_cellshape(cwt.at).faces[j][k]; hyperpoint h = View * fh; if(i == 0) { shift_view_to(shiftless(h)); playermoved = false; } if(i == 1) { rotate_view(spintox(h)); rotate_view(cspin90(0, 2)); } } else if(argis("-exit")) { PHASE(3); int t = SDL_GetTicks(); if(t > 1800 * 1000) println(hlog, "Great Success!\n"); else println(hlog, "Success.\n"); fflush(stdout); exit(0); } // graphical options else if(argis("-noscr")) { PHASE(3); popScreenAll(); showstartmenu = false; } else if(argis("-viz")) { PHASE(3); showstartmenu = false; start_game(); popScreenAll(); clearMessages(); nohud = true; mapeditor::drawplayer = false; no_find_player = true; } else if(argis("-vizhr")) { PHASE(3); showstartmenu = false; popScreenAll(); clearMessages(); } else if(argis("-save-mode")) { PHASEFROM(2); save_mode_to_file(shift_args()); } else if(argis("-load-mode")) { PHASEFROM(2); try { load_mode_from_file(shift_args()); } catch(hstream_exception& e) { println(hlog, "exception!"); } } // informational else if(argis("-version") || argis("-v")) { printf("HyperRogue version " VER "\n"); exit(0); } else if(argis("-L")) { printf("+ Treasures:\n"); int qty = 0; for(int i=1; i hooks_args; EX map> *added_commands; EX namespace arg { int read_added_commands() { if(!added_commands) return 1; if(added_commands->count(args())) { auto& ac = (*added_commands)[args()]; if(ac.first == 2) PHASEFROM(2); if(ac.first == 3) PHASE(3); ac.second(); return 0; } return 1; } EX int add_at(const string& s, int at, const reaction_t& r) { if(!added_commands) added_commands = new map> (); if(added_commands->count(s)) throw hr_exception("arg::add conflict"); (*added_commands)[s] = {at, r}; return 1; } EX int add1(const string& s, const reaction_t& r) { return add_at(s, 1, r); } EX int add2(const string& s, const reaction_t& r) { return add_at(s, 2, r); } EX int add3(const string& s, const reaction_t& r) { return add_at(s, 3, r); } auto ah = addHook(hooks_args, 0, readCommon) + addHook(hooks_args, 200, read_added_commands); void read(int phase) { curphase = phase; callhooks(hooks_config); dynamicval ds(delayed_start, true); while(pos < isize(argument)) { int r = callhandlers(1, hooks_args); switch (r) { case 0: lshift(); break; case 1: printf("Unknown option: %s\n", argcs()); exit(3); break; case 2: return; default: assert(false); } } } EX } #endif #if !CAP_COMMANDLINE EX namespace arg { EX int add1(const string& s, const reaction_t& r) { return 0; } EX int add2(const string& s, const reaction_t& r) { return 0; } EX int add3(const string& s, const reaction_t& r) { return 0; } EX } #endif }