// Hyperbolic Rogue // Copyright (C) 2011-2018 Zeno Rogue, see 'hyper.cpp' for details // gamedata structure, for recording the game data in memory temporarily // namespace dual (dual mode) namespace hr { void gamedata_all(gamedata& gd) { gd.index = 0; gd.store(currentmap); gd.store(cwt); gd.store(allmaps); gd.store(shmup::on); gd.store(*current_display); gd.store(cgip); if(GOLDBERG) gd.store(gp::param); callhooks(hooks_gamedata, &gd); } void gamedata::storegame() { geo = geometry; var = variation; specland = specialland; active = game_active; record.clear(); mode = 0; gamedata_all(*this); game_active = false; } void gamedata::restoregame() { geometry = geo; variation = var; specialland = specland; game_active = active; mode = 1; gamedata_all(*this); } hookset *hooks_gamedata; namespace gamestack { vector gd; bool pushed() { return isize(gd); } void push() { gd.emplace_back(); gd.back().storegame(); } void pop() { if(!pushed()) return; if(game_active) stop_game(); gd.back().restoregame(); gd.pop_back(); } }; namespace dual { int state; int currently_loaded; int main_side; gamedata dgd[2]; ld scales[2]; transmatrix player_orientation[2]; void switch_to(int k) { if(k != currently_loaded) { scales[currently_loaded] = vid.scale; player_orientation[currently_loaded] = gpushxto0(tC0(cwtV)) * cwtV; dgd[currently_loaded].storegame(); currently_loaded = k; dgd[currently_loaded].restoregame(); vid.scale = scales[currently_loaded]; } } bool movepc(int d, int subdir, bool checkonly) { dynamicval dm(dual::state, 2); int cg = currently_loaded; bool orbusedbak[ittypes]; for(int i=0; i ", lms[k][fm]); forcedmovetype = fmSkip; for(int i=0; i xmax(current_display->xmax, 0.5 * (currently_loaded+1)); dynamicval xmin(current_display->xmin, 0.5 * (currently_loaded)); what(); } bool split(reaction_t what) { if(state != 1) return false; state = 2; for(int a=0; a<2; a++) { switch_to(currently_loaded ^ 1); what(); } state = 1; return true; } void enable() { if(dual::state) return; stop_game(); for(int s=0; s<2; s++) { // dynamicval pds(current_display, &subscreens::player_displays[s]); variation = eVariation::pure; geometry = s == 0 ? gEuclidSquare : gArchimedean; arcm::current.parse("4,4,4,4,4"); scales[s] = vid.scale; dgd[s].storegame(); } currently_loaded = 0; dgd[0].restoregame(); state = 1; } void disable() { if(!dual::state) return; stop_game(); state = 0; } int args() { using namespace arg; if(0) ; else if(argis("-dual0")) { enable(); switch_to(0); } else if(argis("-dual1")) { enable(); switch_to(1); } else if(argis("-dualoff")) { disable(); } else return 1; return 0; } auto hook = addHook(hooks_args, 100, args); vector landsides; bool check_side(eLand l) { return landsides[l] == currently_loaded || landsides[l] == 2; } void assign_landsides() { landsides.resize(landtypes); int which_hyperbolic = -1; if(ginf[dgd[0].geo].cclass == gcHyperbolic && ginf[dgd[1].geo].cclass != gcHyperbolic) which_hyperbolic = 0; else if(ginf[dgd[1].geo].cclass == gcHyperbolic && ginf[dgd[0].geo].cclass != gcHyperbolic) which_hyperbolic = 1; int nxt = 0; for(int i=0; i lv[1].quality_level) v = 0; else if(lv[1].quality_level > lv[0].quality_level) v = 1; else if(isEquidLand(l) && which_hyperbolic >= 0) v = which_hyperbolic; else if(among(l, laHunting, laMotion, laCaves, laAlchemist) && which_hyperbolic >= 0) v = which_hyperbolic; else if(among(l, laMirrorOld, laIce, laJungle, laDesert, laDryForest, laStorms) && which_hyperbolic >= 0) v = 1 - which_hyperbolic; else if(which_hyperbolic >= 0) v = which_hyperbolic; else { println(hlog, "equivalent"); v = nxt, nxt = 1 - nxt; } println(hlog, dnameof(l), ": ", lv[0].msg, " vs ", lv[1].msg, " verdict = ", v); } } void add_choice() { if(!state) return; dialog::addSelItem(XLAT("subgame affected"), XLAT(affect_both ? "both" : main_side == 0 ? "left" : "right"), '`'); dialog::add_action([] () { affect_both = !affect_both; if(!affect_both) { main_side = !main_side; switch_to(main_side); } }); } void split_or_do(reaction_t what) { if(split(what)) return; else what(); } bool may_split(reaction_t what) { if(state == 1 && affect_both) { split(what); return true; } return false; } void may_split_or_do(reaction_t what) { if(state == 1 && affect_both) { split(what); } else what(); } } }