mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2024-12-24 09:00:34 +00:00
multigame support, including dualmode
This commit is contained in:
parent
587652e540
commit
8295251cdc
@ -942,7 +942,9 @@ ld realradius() {
|
|||||||
void drawmessage(const string& s, int& y, color_t col) {
|
void drawmessage(const string& s, int& y, color_t col) {
|
||||||
int rrad = (int) realradius();
|
int rrad = (int) realradius();
|
||||||
int space;
|
int space;
|
||||||
if(y > current_display->ycenter + rrad * vid.stretch)
|
if(dual::state)
|
||||||
|
space = vid.xres;
|
||||||
|
else if(y > current_display->ycenter + rrad * vid.stretch)
|
||||||
space = vid.xres;
|
space = vid.xres;
|
||||||
else if(y > current_display->ycenter)
|
else if(y > current_display->ycenter)
|
||||||
space = current_display->xcenter - rhypot(rrad, (y-current_display->ycenter) / vid.stretch);
|
space = current_display->xcenter - rhypot(rrad, (y-current_display->ycenter) / vid.stretch);
|
||||||
|
14
complex.cpp
14
complex.cpp
@ -3202,6 +3202,20 @@ auto ccm = addHook(clearmemory, 0, [] () {
|
|||||||
#endif
|
#endif
|
||||||
mirror::clearcache();
|
mirror::clearcache();
|
||||||
}) +
|
}) +
|
||||||
|
addHook(hooks_gamedata, 0, [] (gamedata* gd) {
|
||||||
|
gd->store(heat::offscreen_heat);
|
||||||
|
gd->store(heat::offscreen_fire);
|
||||||
|
gd->store(princess::infos);
|
||||||
|
gd->store(mirror::mirrors);
|
||||||
|
gd->store(clearing::bpdata);
|
||||||
|
gd->store(tortoise::emap);
|
||||||
|
gd->store(tortoise::babymap);
|
||||||
|
gd->store(prairie::lasttreasure);
|
||||||
|
gd->store(prairie::enter);
|
||||||
|
gd->store(prairie::tchoices);
|
||||||
|
gd->store(prairie::beaststogen);
|
||||||
|
gd->store(sword::angle);
|
||||||
|
}) +
|
||||||
addHook(hooks_removecells, 0, [] () {
|
addHook(hooks_removecells, 0, [] () {
|
||||||
eliminate_if(heat::offscreen_heat, is_cell_removed);
|
eliminate_if(heat::offscreen_heat, is_cell_removed);
|
||||||
eliminate_if(heat::offscreen_fire, is_cell_removed);
|
eliminate_if(heat::offscreen_fire, is_cell_removed);
|
||||||
|
@ -515,7 +515,10 @@ void reset_graph_settings() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void resetModes(char leave) {
|
void resetModes(char leave) {
|
||||||
popAllGames();
|
while(game_active || gamestack::pushed()) {
|
||||||
|
if(game_active) stop_game();
|
||||||
|
if(gamestack::pushed()) gamestack::pop();
|
||||||
|
}
|
||||||
if(shmup::on != (leave == rg::shmup)) stop_game_and_switch_mode(rg::shmup);
|
if(shmup::on != (leave == rg::shmup)) stop_game_and_switch_mode(rg::shmup);
|
||||||
if(inv::on != (leave == rg::inv)) stop_game_and_switch_mode(rg::inv);
|
if(inv::on != (leave == rg::inv)) stop_game_and_switch_mode(rg::inv);
|
||||||
if(chaosmode != (leave == rg::chaos)) stop_game_and_switch_mode(rg::chaos);
|
if(chaosmode != (leave == rg::chaos)) stop_game_and_switch_mode(rg::chaos);
|
||||||
|
13
control.cpp
13
control.cpp
@ -247,6 +247,7 @@ typedef SDL_Event eventtype;
|
|||||||
bool smooth_scrolling = false;
|
bool smooth_scrolling = false;
|
||||||
|
|
||||||
void handlePanning(int sym, int uni) {
|
void handlePanning(int sym, int uni) {
|
||||||
|
if(dual::split([=] { handlePanning(sym, uni); })) return;
|
||||||
if(DIM == 3) {
|
if(DIM == 3) {
|
||||||
if(sym == PSEUDOKEY_WHEELUP) View = cpush(2, -0.05*shiftmul) * View, didsomething = true, playermoved = false;
|
if(sym == PSEUDOKEY_WHEELUP) View = cpush(2, -0.05*shiftmul) * View, didsomething = true, playermoved = false;
|
||||||
if(sym == PSEUDOKEY_WHEELDOWN) View = cpush(2, 0.05*shiftmul) * View, didsomething = true, playermoved = false;
|
if(sym == PSEUDOKEY_WHEELDOWN) View = cpush(2, 0.05*shiftmul) * View, didsomething = true, playermoved = false;
|
||||||
@ -473,8 +474,16 @@ void fix_mouseh() {
|
|||||||
else if(rug::rugged)
|
else if(rug::rugged)
|
||||||
mouseh = rug::gethyper(mousex, mousey);
|
mouseh = rug::gethyper(mousex, mousey);
|
||||||
#endif
|
#endif
|
||||||
else
|
else {
|
||||||
mouseh = gethyper(mousex, mousey);
|
if(dual::state) {
|
||||||
|
if(cmode & (sm::NORMAL | sm::DRAW | sm::MAP)) {
|
||||||
|
dual::main_side = (mousex >= current_display->xcenter);
|
||||||
|
dual::switch_to(dual::main_side);
|
||||||
|
}
|
||||||
|
dual::in_subscreen([=] () { calcparam(); mouseh = gethyper(mousex, mousey); });
|
||||||
|
}
|
||||||
|
else mouseh = gethyper(mousex, mousey);
|
||||||
|
}
|
||||||
need_mouseh = false;
|
need_mouseh = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
76
game.cpp
76
game.cpp
@ -15,8 +15,8 @@ int gamerange_bonus = 0;
|
|||||||
int gamerange() { return getDistLimit() + gamerange_bonus; }
|
int gamerange() { return getDistLimit() + gamerange_bonus; }
|
||||||
|
|
||||||
cell *lastmove;
|
cell *lastmove;
|
||||||
enum eLastmovetype {lmSkip, lmMove, lmAttack, lmSpecial, lmPush, lmTree};
|
eLastmovetype lastmovetype, nextmovetype;
|
||||||
eLastmovetype lastmovetype;
|
eForcemovetype forcedmovetype;
|
||||||
|
|
||||||
bool hauntedWarning;
|
bool hauntedWarning;
|
||||||
bool survivalist;
|
bool survivalist;
|
||||||
@ -7581,8 +7581,9 @@ void monstersTurn() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
DEBB(DF_TURN, ("rop"));
|
DEBB(DF_TURN, ("rop"));
|
||||||
reduceOrbPowers();
|
if(!dual::state) reduceOrbPowers();
|
||||||
int phase1 = (1 & items[itOrbSpeed]);
|
int phase1 = (1 & items[itOrbSpeed]);
|
||||||
|
if(dual::state && items[itOrbSpeed]) phase1 = !phase1;
|
||||||
DEBB(DF_TURN, ("lc"));
|
DEBB(DF_TURN, ("lc"));
|
||||||
if(!phase1) livecaves();
|
if(!phase1) livecaves();
|
||||||
if(!phase1) ca::simulate();
|
if(!phase1) ca::simulate();
|
||||||
@ -7787,6 +7788,7 @@ void handle_switchplaces(cell *c1, cell *c2, bool& switchplaces) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool movepcto(int d, int subdir, bool checkonly) {
|
bool movepcto(int d, int subdir, bool checkonly) {
|
||||||
|
if(dual::state == 1) return dual::movepc(d, subdir, checkonly);
|
||||||
if(d >= 0 && !checkonly && subdir != 1 && subdir != -1) printf("subdir = %d\n", subdir);
|
if(d >= 0 && !checkonly && subdir != 1 && subdir != -1) printf("subdir = %d\n", subdir);
|
||||||
global_pushto = NULL;
|
global_pushto = NULL;
|
||||||
bool switchplaces = false;
|
bool switchplaces = false;
|
||||||
@ -7824,6 +7826,10 @@ bool movepcto(int d, int subdir, bool checkonly) {
|
|||||||
|
|
||||||
gravity_state = gsNormal;
|
gravity_state = gsNormal;
|
||||||
|
|
||||||
|
bool fmsMove = forcedmovetype == fmSkip || forcedmovetype == fmMove;
|
||||||
|
bool fmsAttack = forcedmovetype == fmSkip || forcedmovetype == fmAttack;
|
||||||
|
bool fmsActivate = forcedmovetype == fmSkip || forcedmovetype == fmActivate;
|
||||||
|
|
||||||
if(d >= 0) {
|
if(d >= 0) {
|
||||||
cell *c2 = cwt.at->move(d);
|
cell *c2 = cwt.at->move(d);
|
||||||
bool goodTortoise = c2->monst == moTortoise && tortoise::seek() && !tortoise::diff(tortoise::getb(c2)) && !c2->item;
|
bool goodTortoise = c2->monst == moTortoise && tortoise::seek() && !tortoise::diff(tortoise::getb(c2)) && !c2->item;
|
||||||
@ -7842,8 +7848,10 @@ bool movepcto(int d, int subdir, bool checkonly) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(items[itOrbDomination] > ORBBASE && isMountable(c2->monst) && !monstersnear2()) {
|
bool try_instant = (forcedmovetype == fmInstant) || (forcedmovetype == fmSkip && !passable(c2, cwt.at, P_ISPLAYER | P_MIRROR | P_USEBOAT | P_FRIENDSWAP));
|
||||||
if(checkonly) return true;
|
|
||||||
|
if(items[itOrbDomination] > ORBBASE && isMountable(c2->monst) && !monstersnear2() && fmsMove) {
|
||||||
|
if(checkonly) { nextmovetype = lmMove; return true; }
|
||||||
if(!isMountable(cwt.at->monst)) dragon::target = NULL;
|
if(!isMountable(cwt.at->monst)) dragon::target = NULL;
|
||||||
movecost(cwt.at, c2, 3);
|
movecost(cwt.at, c2, 3);
|
||||||
|
|
||||||
@ -7853,8 +7861,8 @@ bool movepcto(int d, int subdir, bool checkonly) {
|
|||||||
goto mountjump;
|
goto mountjump;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!passable(c2, cwt.at, P_ISPLAYER | P_MIRROR | P_USEBOAT | P_FRIENDSWAP) && items[itOrbFlash]) {
|
if(items[itOrbFlash] && try_instant) {
|
||||||
if(checkonly) return true;
|
if(checkonly) { nextmovetype = lmInstant; return true; }
|
||||||
if(orbProtection(itOrbFlash)) return true;
|
if(orbProtection(itOrbFlash)) return true;
|
||||||
activateFlash();
|
activateFlash();
|
||||||
bfs();
|
bfs();
|
||||||
@ -7863,8 +7871,8 @@ bool movepcto(int d, int subdir, bool checkonly) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!passable(c2, cwt.at, P_ISPLAYER | P_MIRROR | P_USEBOAT | P_FRIENDSWAP) && items[itOrbLightning]) {
|
if(items[itOrbLightning] && try_instant) {
|
||||||
if(checkonly) return true;
|
if(checkonly) { nextmovetype = lmInstant; return true; }
|
||||||
if(orbProtection(itOrbLightning)) return true;
|
if(orbProtection(itOrbLightning)) return true;
|
||||||
activateLightning();
|
activateLightning();
|
||||||
keepLightning = true;
|
keepLightning = true;
|
||||||
@ -7875,8 +7883,8 @@ bool movepcto(int d, int subdir, bool checkonly) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isActivable(c2)) {
|
if(isActivable(c2) && fmsActivate) {
|
||||||
if(checkonly) return true;
|
if(checkonly) { nextmovetype = lmInstant; return true; }
|
||||||
activateActiv(c2, true);
|
activateActiv(c2, true);
|
||||||
bfs();
|
bfs();
|
||||||
if(multi::players > 1) { multi::whereto[multi::cpid].d = MD_UNDECIDED; return false; }
|
if(multi::players > 1) { multi::whereto[multi::cpid].d = MD_UNDECIDED; return false; }
|
||||||
@ -7884,7 +7892,7 @@ bool movepcto(int d, int subdir, bool checkonly) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isPushable(c2->wall) && !c2->monst && !nonAdjacentPlayer(c2, cwt.at)) {
|
if(isPushable(c2->wall) && !c2->monst && !nonAdjacentPlayer(c2, cwt.at) && fmsMove) {
|
||||||
int pushdir;
|
int pushdir;
|
||||||
cell *c3 = determinePush(cwt, c2, subdir, [c2] (cell *c) { return canPushThumperOn(c, c2, cwt.at); }, pushdir);
|
cell *c3 = determinePush(cwt, c2, subdir, [c2] (cell *c) { return canPushThumperOn(c, c2, cwt.at); }, pushdir);
|
||||||
if(c3 == c2) {
|
if(c3 == c2) {
|
||||||
@ -7897,7 +7905,7 @@ bool movepcto(int d, int subdir, bool checkonly) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
global_pushto = c3;
|
global_pushto = c3;
|
||||||
if(checkonly) return true;
|
if(checkonly) { nextmovetype = lmMove; return true; }
|
||||||
addMessage(XLAT("You push %the1.", c2->wall));
|
addMessage(XLAT("You push %the1.", c2->wall));
|
||||||
lastmovetype = lmPush; lastmove = cwt.at;
|
lastmovetype = lmPush; lastmove = cwt.at;
|
||||||
pushThumper(c2, c3);
|
pushThumper(c2, c3);
|
||||||
@ -7913,7 +7921,7 @@ bool movepcto(int d, int subdir, bool checkonly) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isWatery(c2) && !nonAdjacentPlayer(cwt.at,c2) && !c2->monst && cwt.at->wall == waBoat) {
|
if(isWatery(c2) && !nonAdjacentPlayer(cwt.at,c2) && !c2->monst && cwt.at->wall == waBoat && fmsMove) {
|
||||||
|
|
||||||
if(havePushConflict(cwt.at, checkonly)) return false;
|
if(havePushConflict(cwt.at, checkonly)) return false;
|
||||||
|
|
||||||
@ -7939,14 +7947,14 @@ bool movepcto(int d, int subdir, bool checkonly) {
|
|||||||
if(!checkonly && errormsgs) wouldkill("%The1 would kill you there!");
|
if(!checkonly && errormsgs) wouldkill("%The1 would kill you there!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(checkonly) return true;
|
if(checkonly) { nextmovetype = lmMove; return true; }
|
||||||
moveBoat(c2, cwt.at, d);
|
moveBoat(c2, cwt.at, d);
|
||||||
boatmove = true;
|
boatmove = true;
|
||||||
goto boatjump;
|
goto boatjump;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!c2->monst && cwt.at->wall == waBoat && boatGoesThrough(c2) && markOrb(itOrbWater) && !nonAdjacentPlayer(c2, cwt.at)) {
|
if(!c2->monst && cwt.at->wall == waBoat && boatGoesThrough(c2) && markOrb(itOrbWater) && !nonAdjacentPlayer(c2, cwt.at) && fmsMove) {
|
||||||
|
|
||||||
if(havePushConflict(cwt.at, checkonly)) return false;
|
if(havePushConflict(cwt.at, checkonly)) return false;
|
||||||
if(monstersnear(c2,NULL,moPlayer,NULL,cwt.at)) {
|
if(monstersnear(c2,NULL,moPlayer,NULL,cwt.at)) {
|
||||||
@ -7954,7 +7962,7 @@ bool movepcto(int d, int subdir, bool checkonly) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(checkonly) return true;
|
if(checkonly) { nextmovetype = lmMove; return true; }
|
||||||
if(c2->item && !cwt.at->item) moveItem(c2, cwt.at, false), boatmove = true;
|
if(c2->item && !cwt.at->item) moveItem(c2, cwt.at, false), boatmove = true;
|
||||||
placeWater(c2, cwt.at);
|
placeWater(c2, cwt.at);
|
||||||
moveBoat(c2, cwt.at, d);
|
moveBoat(c2, cwt.at, d);
|
||||||
@ -7964,7 +7972,7 @@ bool movepcto(int d, int subdir, bool checkonly) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
escape:
|
escape:
|
||||||
if(c2->wall == waBigStatue && !c2->monst && !nonAdjacentPlayer(c2, cwt.at)) {
|
if(c2->wall == waBigStatue && !c2->monst && !nonAdjacentPlayer(c2, cwt.at) && fmsMove) {
|
||||||
if(!canPushStatueOn(cwt.at)) {
|
if(!canPushStatueOn(cwt.at)) {
|
||||||
if(checkonly) return false;
|
if(checkonly) return false;
|
||||||
if(isFire(cwt.at))
|
if(isFire(cwt.at))
|
||||||
@ -7988,7 +7996,7 @@ bool movepcto(int d, int subdir, bool checkonly) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(checkonly) { c2->wall = save_c2; cwt.at->wall = save_cw; return true; }
|
if(checkonly) { c2->wall = save_c2; cwt.at->wall = save_cw; nextmovetype = lmMove; return true; }
|
||||||
addMessage(XLAT("You push %the1 behind you!", waBigStatue));
|
addMessage(XLAT("You push %the1 behind you!", waBigStatue));
|
||||||
animateMovement(c2, cwt.at, LAYER_BOAT, cwt.at->c.spin(d));
|
animateMovement(c2, cwt.at, LAYER_BOAT, cwt.at->c.spin(d));
|
||||||
goto statuejump;
|
goto statuejump;
|
||||||
@ -7999,18 +8007,19 @@ bool movepcto(int d, int subdir, bool checkonly) {
|
|||||||
c2->wall == waBigTree ||
|
c2->wall == waBigTree ||
|
||||||
c2->wall == waSmallTree ||
|
c2->wall == waSmallTree ||
|
||||||
c2->wall == waMirrorWall;
|
c2->wall == waMirrorWall;
|
||||||
attackable = attackable && (!c2->monst || isFriendly(c2));
|
|
||||||
if(attackable && markOrb(itOrbAether) && c2->wall != waMirrorWall)
|
if(attackable && markOrb(itOrbAether) && c2->wall != waMirrorWall)
|
||||||
attackable = false;
|
attackable = false;
|
||||||
|
if(forcedmovetype == fmAttack) attackable = true;
|
||||||
|
attackable = attackable && (!c2->monst || isFriendly(c2));
|
||||||
attackable = attackable && !nonAdjacentPlayer(cwt.at,c2);
|
attackable = attackable && !nonAdjacentPlayer(cwt.at,c2);
|
||||||
|
|
||||||
if(attackable) {
|
if(attackable && fmsAttack) {
|
||||||
if(checkNeedMove(checkonly, true)) return false;
|
if(checkNeedMove(checkonly, true)) return false;
|
||||||
if(monstersnear(cwt.at,c2,moPlayer,NULL,cwt.at)) {
|
if(monstersnear(cwt.at,c2,moPlayer,NULL,cwt.at)) {
|
||||||
if(!checkonly && errormsgs) wouldkill("%The1 would get you!");
|
if(!checkonly && errormsgs) wouldkill("%The1 would get you!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(checkonly) return true;
|
if(checkonly) { nextmovetype = lmAttack; return true; }
|
||||||
if(c2->wall == waSmallTree) {
|
if(c2->wall == waSmallTree) {
|
||||||
drawParticles(c2, winf[c2->wall].color, 4);
|
drawParticles(c2, winf[c2->wall].color, 4);
|
||||||
addMessage(XLAT("You chop down the tree."));
|
addMessage(XLAT("You chop down the tree."));
|
||||||
@ -8029,7 +8038,12 @@ bool movepcto(int d, int subdir, bool checkonly) {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if(!peace::on) {
|
if(!peace::on) {
|
||||||
addMessage(XLAT("You swing your sword at the mirror."));
|
if(c2->wall == waMirrorWall)
|
||||||
|
addMessage(XLAT("You swing your sword at the mirror."));
|
||||||
|
else if(c2->wall)
|
||||||
|
addMessage(XLAT("You swing your sword at %the1.", c2->wall));
|
||||||
|
else
|
||||||
|
addMessage(XLAT("You swing your sword."));
|
||||||
sideAttack(cwt.at, d, moPlayer, 0);
|
sideAttack(cwt.at, d, moPlayer, 0);
|
||||||
animateAttack(cwt.at, c2, LAYER_SMALL, d);
|
animateAttack(cwt.at, c2, LAYER_SMALL, d);
|
||||||
}
|
}
|
||||||
@ -8047,6 +8061,7 @@ bool movepcto(int d, int subdir, bool checkonly) {
|
|||||||
}
|
}
|
||||||
else if(c2->monst && (!isFriendly(c2) || c2->monst == moTameBomberbird || isMountable(c2->monst))
|
else if(c2->monst && (!isFriendly(c2) || c2->monst == moTameBomberbird || isMountable(c2->monst))
|
||||||
&& !(peace::on && !isMultitile(c2->monst) && !goodTortoise)) {
|
&& !(peace::on && !isMultitile(c2->monst) && !goodTortoise)) {
|
||||||
|
if(!fmsAttack) return false;
|
||||||
|
|
||||||
flagtype attackflags = AF_NORMAL;
|
flagtype attackflags = AF_NORMAL;
|
||||||
if(items[itOrbSpeed]&1) attackflags |= AF_FAST;
|
if(items[itOrbSpeed]&1) attackflags |= AF_FAST;
|
||||||
@ -8122,7 +8137,7 @@ bool movepcto(int d, int subdir, bool checkonly) {
|
|||||||
|
|
||||||
if(c2->monst == moTameBomberbird && warningprotection_hit(moTameBomberbird)) return false;
|
if(c2->monst == moTameBomberbird && warningprotection_hit(moTameBomberbird)) return false;
|
||||||
|
|
||||||
if(checkonly) return true;
|
if(checkonly) { nextmovetype = lmAttack; return true; }
|
||||||
|
|
||||||
/* if(c2->monst == moTortoise) {
|
/* if(c2->monst == moTortoise) {
|
||||||
printf("seek=%d get=%d <%x/%x> item=%d\n",
|
printf("seek=%d get=%d <%x/%x> item=%d\n",
|
||||||
@ -8197,14 +8212,14 @@ bool movepcto(int d, int subdir, bool checkonly) {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else {
|
else if(fmsMove) {
|
||||||
if(mineMarked(c2) && !minesafe() && !checkonly && warningprotection(XLAT("Are you sure you want to step there?")))
|
if(mineMarked(c2) && !minesafe() && !checkonly && warningprotection(XLAT("Are you sure you want to step there?")))
|
||||||
return false;
|
return false;
|
||||||
if(monstersnear(c2, NULL, moPlayer, NULL, cwt.at)) {
|
if(monstersnear(c2, NULL, moPlayer, NULL, cwt.at)) {
|
||||||
if(checkonly) return false;
|
if(checkonly) return false;
|
||||||
|
|
||||||
if(items[itOrbFlash]) {
|
if(items[itOrbFlash]) {
|
||||||
if(checkonly) return true;
|
if(checkonly) { nextmovetype = lmInstant; return true; }
|
||||||
if(orbProtection(itOrbFlash)) return true;
|
if(orbProtection(itOrbFlash)) return true;
|
||||||
activateFlash();
|
activateFlash();
|
||||||
checkmove();
|
checkmove();
|
||||||
@ -8212,7 +8227,7 @@ bool movepcto(int d, int subdir, bool checkonly) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(items[itOrbLightning]) {
|
if(items[itOrbLightning]) {
|
||||||
if(checkonly) return true;
|
if(checkonly) { nextmovetype = lmInstant; return true; }
|
||||||
if(orbProtection(itOrbLightning)) return true;
|
if(orbProtection(itOrbLightning)) return true;
|
||||||
activateLightning();
|
activateLightning();
|
||||||
checkmove();
|
checkmove();
|
||||||
@ -8244,7 +8259,7 @@ bool movepcto(int d, int subdir, bool checkonly) {
|
|||||||
if(!checkonly && warningprotection_hit(do_we_stab_a_friend(cwt.at, c2, moPlayer)))
|
if(!checkonly && warningprotection_hit(do_we_stab_a_friend(cwt.at, c2, moPlayer)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if(checkonly) return true;
|
if(checkonly) { nextmovetype = lmMove; return true; }
|
||||||
boatjump:
|
boatjump:
|
||||||
statuejump:
|
statuejump:
|
||||||
flipplayer = true; if(multi::players > 1) multi::flipped[multi::cpid] = true;
|
flipplayer = true; if(multi::players > 1) multi::flipped[multi::cpid] = true;
|
||||||
@ -8336,6 +8351,7 @@ bool movepcto(int d, int subdir, bool checkonly) {
|
|||||||
landvisited[cwt.at->land] = true;
|
landvisited[cwt.at->land] = true;
|
||||||
afterplayermoved();
|
afterplayermoved();
|
||||||
}
|
}
|
||||||
|
else return false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if(items[itOrbGravity]) {
|
if(items[itOrbGravity]) {
|
||||||
@ -8350,7 +8366,7 @@ bool movepcto(int d, int subdir, bool checkonly) {
|
|||||||
wouldkill("%The1 would get you!");
|
wouldkill("%The1 would get you!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(checkonly) return true;
|
if(checkonly) { nextmovetype = lmSkip; return true; }
|
||||||
swordAttackStatic();
|
swordAttackStatic();
|
||||||
if(d == -2)
|
if(d == -2)
|
||||||
dropGreenStone(cwt.at);
|
dropGreenStone(cwt.at);
|
||||||
|
@ -361,6 +361,7 @@ namespace geom3 {
|
|||||||
namespace geom3 {
|
namespace geom3 {
|
||||||
#if MAXMDIM >= 4
|
#if MAXMDIM >= 4
|
||||||
void switch_always3() {
|
void switch_always3() {
|
||||||
|
if(dual::split(switch_always3)) return;
|
||||||
if(rug::rugged) rug::close();
|
if(rug::rugged) rug::close();
|
||||||
geom3::always3 = !geom3::always3;
|
geom3::always3 = !geom3::always3;
|
||||||
swapmatrix(View);
|
swapmatrix(View);
|
||||||
@ -369,6 +370,7 @@ void switch_always3() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void switch_tpp() {
|
void switch_tpp() {
|
||||||
|
if(dual::split(switch_fpp)) return;
|
||||||
if(pmodel == mdDisk && vid.camera_angle) {
|
if(pmodel == mdDisk && vid.camera_angle) {
|
||||||
vid.yshift = 0;
|
vid.yshift = 0;
|
||||||
vid.camera_angle = 0;
|
vid.camera_angle = 0;
|
||||||
@ -391,6 +393,7 @@ void switch_always3() {
|
|||||||
void switch_fpp() {
|
void switch_fpp() {
|
||||||
#if MAXMDIM >= 4
|
#if MAXMDIM >= 4
|
||||||
if(rug::rugged) rug::close();
|
if(rug::rugged) rug::close();
|
||||||
|
if(dual::split(switch_fpp)) return;
|
||||||
if(!geom3::always3) {
|
if(!geom3::always3) {
|
||||||
geom3::always3 = true;
|
geom3::always3 = true;
|
||||||
geom3::wall_height = 1.5;
|
geom3::wall_height = 1.5;
|
||||||
|
19
graph.cpp
19
graph.cpp
@ -7240,7 +7240,14 @@ void gamescreen(int _darken) {
|
|||||||
just_gmatrix = false;
|
just_gmatrix = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(dual::split([=] () {
|
||||||
|
dual::in_subscreen([=] () { gamescreen(_darken); });
|
||||||
|
})) {
|
||||||
|
calcparam();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if((cmode & sm::MAYDARK) && !current_display->sidescreen) {
|
if((cmode & sm::MAYDARK) && !current_display->sidescreen) {
|
||||||
_darken += 2;
|
_darken += 2;
|
||||||
}
|
}
|
||||||
@ -7463,11 +7470,19 @@ auto graphcm = addHook(clearmemory, 0, [] () {
|
|||||||
mouseover = centerover.at = lmouseover = NULL;
|
mouseover = centerover.at = lmouseover = NULL;
|
||||||
gmatrix.clear(); gmatrix0.clear();
|
gmatrix.clear(); gmatrix0.clear();
|
||||||
clearAnimations();
|
clearAnimations();
|
||||||
|
})
|
||||||
|
+ addHook(hooks_gamedata, 0, [] (gamedata* gd) {
|
||||||
|
gd->store(mouseover);
|
||||||
|
gd->store(lmouseover);
|
||||||
|
gd->store(animations);
|
||||||
|
gd->store(flashes);
|
||||||
|
gd->store(fallanims);
|
||||||
});
|
});
|
||||||
|
;
|
||||||
|
|
||||||
//=== animation
|
//=== animation
|
||||||
|
|
||||||
map<cell*, animation> animations[ANIMLAYERS];
|
array<map<cell*, animation>, ANIMLAYERS> animations;
|
||||||
|
|
||||||
int revhint(cell *c, int hint) {
|
int revhint(cell *c, int hint) {
|
||||||
if(hint >= 0 && hint < c->type) return c->c.spin(hint);
|
if(hint >= 0 && hint < c->type) return c->c.spin(hint);
|
||||||
|
61
hyper.h
61
hyper.h
@ -2090,7 +2090,7 @@ struct animation {
|
|||||||
#define LAYER_SMALL 1 // for others
|
#define LAYER_SMALL 1 // for others
|
||||||
#define LAYER_BOAT 2 // mark that a boat has moved
|
#define LAYER_BOAT 2 // mark that a boat has moved
|
||||||
|
|
||||||
extern map<cell*, animation> animations[ANIMLAYERS];
|
extern array<map<cell*, animation>, ANIMLAYERS> animations;
|
||||||
|
|
||||||
void animateAttack(cell *src, cell *tgt, int layer, int direction_hint);
|
void animateAttack(cell *src, cell *tgt, int layer, int direction_hint);
|
||||||
|
|
||||||
@ -4196,8 +4196,6 @@ bool score_loaded(int id);
|
|||||||
int score_default(int id);
|
int score_default(int id);
|
||||||
void handle_event(SDL_Event& ev);
|
void handle_event(SDL_Event& ev);
|
||||||
|
|
||||||
void pop_game();
|
|
||||||
void push_game();
|
|
||||||
void start_game();
|
void start_game();
|
||||||
void stop_game();
|
void stop_game();
|
||||||
void switch_game_mode(char switchWhat);
|
void switch_game_mode(char switchWhat);
|
||||||
@ -4612,6 +4610,8 @@ extern vector<help_extension> help_extensions;
|
|||||||
|
|
||||||
namespace gamestack {
|
namespace gamestack {
|
||||||
bool pushed();
|
bool pushed();
|
||||||
|
void push();
|
||||||
|
void pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace geom3 {
|
namespace geom3 {
|
||||||
@ -5407,5 +5407,58 @@ static const int POLY_INTENSE = (1<<23); // extra intense colors
|
|||||||
|
|
||||||
void pregen();
|
void pregen();
|
||||||
extern vector<eLand> currentlands;
|
extern vector<eLand> currentlands;
|
||||||
}
|
|
||||||
|
|
||||||
|
struct gamedata {
|
||||||
|
// important parameters should be visible
|
||||||
|
eGeometry geo;
|
||||||
|
eVariation var;
|
||||||
|
eLand specland;
|
||||||
|
bool active;
|
||||||
|
// other properties are recorded
|
||||||
|
vector<char> record;
|
||||||
|
int index, mode;
|
||||||
|
void storegame();
|
||||||
|
void restoregame();
|
||||||
|
template<class T> void store(T& x) {
|
||||||
|
int ssize = sizeof(x);
|
||||||
|
if(ssize & 7) ssize = (ssize | 7) + 1;
|
||||||
|
if(mode == 0) {
|
||||||
|
record.resize(index+ssize);
|
||||||
|
T& at = *(new (&record[index]) T());
|
||||||
|
at = move(x);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
T& at = (T&) record[index];
|
||||||
|
x = move(at);
|
||||||
|
at.~T();
|
||||||
|
}
|
||||||
|
index += ssize;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* lastmovetype uses lmSkip, lmMove, lmAttack, lmPush, lmTree */
|
||||||
|
enum eLastmovetype { lmSkip, lmMove, lmAttack, lmPush, lmTree, lmInstant };
|
||||||
|
extern eLastmovetype lastmovetype, nextmovetype;
|
||||||
|
|
||||||
|
enum eForcemovetype { fmSkip, fmMove, fmAttack, fmInstant, fmActivate };
|
||||||
|
extern eForcemovetype forcedmovetype;
|
||||||
|
|
||||||
|
extern hookset<void(gamedata*)> *hooks_gamedata;
|
||||||
|
|
||||||
|
namespace dual {
|
||||||
|
// 0 = dualmode off, 1 = in dualmode (no game chosen), 2 = in dualmode (working on one of subgames)
|
||||||
|
extern int state;
|
||||||
|
extern int currently_loaded, main_side;
|
||||||
|
|
||||||
|
bool movepc(int d, int subdir, bool checkonly);
|
||||||
|
extern transmatrix player_orientation[2];
|
||||||
|
|
||||||
|
bool split(reaction_t what);
|
||||||
|
void switch_to(int i);
|
||||||
|
void in_subscreen(reaction_t what);
|
||||||
|
|
||||||
|
bool check_side(eLand l);
|
||||||
|
void assign_landsides();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
16
hypgraph.cpp
16
hypgraph.cpp
@ -1063,7 +1063,19 @@ transmatrix eumovedir(int d) {
|
|||||||
|
|
||||||
void spinEdge(ld aspd) {
|
void spinEdge(ld aspd) {
|
||||||
ld downspin = 0;
|
ld downspin = 0;
|
||||||
if(playerfound && vid.fixed_facing) {
|
if(dual::state == 2 && dual::currently_loaded != dual::main_side) {
|
||||||
|
transmatrix our = gpushxto0(tC0(cwtV)) * cwtV;
|
||||||
|
transmatrix their = dual::player_orientation[dual::main_side];
|
||||||
|
fixmatrix(our);
|
||||||
|
fixmatrix(their);
|
||||||
|
if(DIM == 2) {
|
||||||
|
transmatrix T = their * inverse(our);
|
||||||
|
hyperpoint H = T * xpush0(1);
|
||||||
|
downspin = -atan2(H[1], H[0]);
|
||||||
|
}
|
||||||
|
else View = their * inverse(our) * View;
|
||||||
|
}
|
||||||
|
else if(playerfound && vid.fixed_facing) {
|
||||||
hyperpoint H = gpushxto0(playerV * C0) * playerV * xpush0(5);
|
hyperpoint H = gpushxto0(playerV * C0) * playerV * xpush0(5);
|
||||||
downspin = atan2(H[1], H[0]);
|
downspin = atan2(H[1], H[0]);
|
||||||
downspin += vid.fixed_facing_dir * degree;
|
downspin += vid.fixed_facing_dir * degree;
|
||||||
@ -1099,6 +1111,7 @@ void spinEdge(ld aspd) {
|
|||||||
void centerpc(ld aspd) {
|
void centerpc(ld aspd) {
|
||||||
|
|
||||||
if(subscreens::split([=] () {centerpc(aspd);})) return;
|
if(subscreens::split([=] () {centerpc(aspd);})) return;
|
||||||
|
if(dual::split([=] () { centerpc(aspd); })) return;
|
||||||
|
|
||||||
#if CAP_CRYSTAL
|
#if CAP_CRYSTAL
|
||||||
if(geometry == gCrystal)
|
if(geometry == gCrystal)
|
||||||
@ -1179,6 +1192,7 @@ void centerpc(ld aspd) {
|
|||||||
void optimizeview() {
|
void optimizeview() {
|
||||||
|
|
||||||
if(subscreens::split(optimizeview)) return;
|
if(subscreens::split(optimizeview)) return;
|
||||||
|
if(dual::split(optimizeview)) return;
|
||||||
|
|
||||||
#if CAP_ANIMATIONS
|
#if CAP_ANIMATIONS
|
||||||
if(centerover.at && inmirror(centerover.at)) {
|
if(centerover.at && inmirror(centerover.at)) {
|
||||||
|
@ -156,6 +156,9 @@ void place_elemental_wall(cell *c) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int hrand_monster(int x) {
|
int hrand_monster(int x) {
|
||||||
|
// dual geometry mode is much harder, so generate less monsters to balance it
|
||||||
|
if(dual::state) x *= 3;
|
||||||
|
// in 3D monster generation depends on the sight range
|
||||||
if(WDIM == 3 && !sphere) {
|
if(WDIM == 3 && !sphere) {
|
||||||
int t = isize(gmatrix);
|
int t = isize(gmatrix);
|
||||||
if(t > 300) x = ((long long)(x)) * t / 300;
|
if(t > 300) x = ((long long)(x)) * t / 300;
|
||||||
|
@ -572,6 +572,7 @@ eLand getLandForList(cell *c) {
|
|||||||
|
|
||||||
bool isLandIngame(eLand l) {
|
bool isLandIngame(eLand l) {
|
||||||
if(isElemental(l)) l = laElementalWall;
|
if(isElemental(l)) l = laElementalWall;
|
||||||
|
if(dual::state == 2 && !dual::check_side(l)) return false;
|
||||||
return land_validity(l).flags & lv::appears_in_full;
|
return land_validity(l).flags & lv::appears_in_full;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +37,10 @@ void showOverview() {
|
|||||||
|
|
||||||
bool pages;
|
bool pages;
|
||||||
|
|
||||||
|
{
|
||||||
|
dynamicval<int> ds(dual::state, dual::state ? 2 : 0);
|
||||||
generateLandList(isLandIngame);
|
generateLandList(isLandIngame);
|
||||||
|
}
|
||||||
|
|
||||||
bool not_in_game = false;
|
bool not_in_game = false;
|
||||||
|
|
||||||
|
281
multigame.cpp
Normal file
281
multigame.cpp
Normal file
@ -0,0 +1,281 @@
|
|||||||
|
// 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)
|
||||||
|
|
||||||
|
#include "allhyper.h"
|
||||||
|
|
||||||
|
namespace hr {
|
||||||
|
|
||||||
|
bool isEquidLand(eLand);
|
||||||
|
extern bool orbused[ittypes];
|
||||||
|
|
||||||
|
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<void(gamedata*)> *hooks_gamedata;
|
||||||
|
|
||||||
|
namespace gamestack {
|
||||||
|
|
||||||
|
vector<gamedata> 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<int> dm(dual::state, 2);
|
||||||
|
int cg = currently_loaded;
|
||||||
|
|
||||||
|
bool orbusedbak[ittypes];
|
||||||
|
for(int i=0; i<ittypes; i++) orbusedbak[i] = orbused[i];
|
||||||
|
|
||||||
|
if(d < 0) {
|
||||||
|
if(d == -2 && items[itGreenStone] == 1) {
|
||||||
|
switch_to(cg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool ok = true;
|
||||||
|
|
||||||
|
for(int k=0; k<2; k++) {
|
||||||
|
switch_to(k);
|
||||||
|
ok = ok && movepcto(d, subdir, true);
|
||||||
|
for(int i=0; i<ittypes; i++) orbused[i] = orbusedbak[i];
|
||||||
|
}
|
||||||
|
if(ok && checkonly) {
|
||||||
|
switch_to(cg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(ok) for(int k=0; k<2; k++) {
|
||||||
|
switch_to(k);
|
||||||
|
movepcto(d, subdir, false);
|
||||||
|
}
|
||||||
|
switch_to(cg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool lms[2][5];
|
||||||
|
for(int k=0; k<2; k++) {
|
||||||
|
switch_to(k);
|
||||||
|
for(eForcemovetype fm: { fmMove, fmAttack, fmInstant, fmActivate }) {
|
||||||
|
forcedmovetype = fm;
|
||||||
|
lms[k][fm] = movepcto(fm == fmMove ? d : 0, subdir, true);
|
||||||
|
println(hlog, k, int(fm), " -> ", lms[k][fm]);
|
||||||
|
forcedmovetype = fmSkip;
|
||||||
|
for(int i=0; i<ittypes; i++) orbused[i] = orbusedbak[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(lms[0][fmActivate]) {
|
||||||
|
if(checkonly) { switch_to(cg); return true; }
|
||||||
|
switch_to(0); forcedmovetype = fmActivate; movepcto(0, subdir, false); forcedmovetype = fmSkip;
|
||||||
|
if(!lms[1][fmActivate]) return true;
|
||||||
|
}
|
||||||
|
if(lms[1][fmActivate]) {
|
||||||
|
if(checkonly) { switch_to(cg); return true; }
|
||||||
|
switch_to(1); forcedmovetype = fmActivate; movepcto(0, subdir, false); forcedmovetype = fmSkip;
|
||||||
|
switch_to(cg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for(auto fm: {fmMove, fmInstant, fmAttack}) if(lms[0][fm] && lms[1][fm]) {
|
||||||
|
println(hlog, "apply ", int(fm));
|
||||||
|
if(checkonly) { switch_to(cg); return true; }
|
||||||
|
int flash = items[itOrbFlash], lgt = items[itOrbLightning];
|
||||||
|
switch_to(0); forcedmovetype = fm; movepcto(0, subdir, false); forcedmovetype = fmSkip;
|
||||||
|
if(fm == fmInstant) { items[itOrbFlash] = flash, items[itOrbLightning] = lgt; }
|
||||||
|
switch_to(1); forcedmovetype = fm; movepcto(0, subdir, false); forcedmovetype = fmSkip;
|
||||||
|
switch_to(cg);
|
||||||
|
reduceOrbPowers();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
println(hlog, "no match");
|
||||||
|
switch_to(cg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void in_subscreen(reaction_t what) {
|
||||||
|
dynamicval<ld> xmax(current_display->xmax, 0.5 * (currently_loaded+1));
|
||||||
|
dynamicval<ld> 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
int args() {
|
||||||
|
using namespace arg;
|
||||||
|
|
||||||
|
if(0) ;
|
||||||
|
else if(argis("-dual")) {
|
||||||
|
PHASEFROM(3);
|
||||||
|
stop_game();
|
||||||
|
subscreens::prepare();
|
||||||
|
|
||||||
|
for(int s=0; s<2; s++) {
|
||||||
|
// dynamicval<display_data*> 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;
|
||||||
|
}
|
||||||
|
else if(argis("-dual0:")) {
|
||||||
|
switch_to(0);
|
||||||
|
}
|
||||||
|
else if(argis("-dual1:")) {
|
||||||
|
switch_to(1);
|
||||||
|
}
|
||||||
|
else return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto hook = addHook(hooks_args, 100, args);
|
||||||
|
|
||||||
|
vector<int> 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<landtypes; i++) {
|
||||||
|
eLand l = eLand(i);
|
||||||
|
auto& v = landsides[i];
|
||||||
|
land_validity_t lv[2];
|
||||||
|
for(int s=0; s<2; s++) {
|
||||||
|
switch_to(s);
|
||||||
|
lv[s] = land_validity(l);
|
||||||
|
}
|
||||||
|
if(!(lv[0].flags & lv::appears_in_full) && !(lv[1].flags & lv::appears_in_full)) {
|
||||||
|
v = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if(isCrossroads(l))
|
||||||
|
v = -1; /* simply boring */
|
||||||
|
else if(isGravityLand(l))
|
||||||
|
v = -1; /* too confusing */
|
||||||
|
else if(among(l, laTortoise))
|
||||||
|
v = -1; /* does not work in hyperbolic geos available, and better not do it in Euclidean ones either */
|
||||||
|
else if(among(l, laHaunted))
|
||||||
|
v = -1; /* graveyard prefers Euclidean, while Haunted prefers hyperbolic */
|
||||||
|
else if(l == dgd[0].specland && l == dgd[1].specland)
|
||||||
|
v = 2;
|
||||||
|
else if(l == dgd[0].specland)
|
||||||
|
v = 0;
|
||||||
|
else if(l == dgd[1].specland)
|
||||||
|
v = 1;
|
||||||
|
else if(isElemental(l))
|
||||||
|
v = 1;
|
||||||
|
else if(!(lv[0].flags & lv::appears_in_full))
|
||||||
|
v = 1;
|
||||||
|
else if(!(lv[1].flags & lv::appears_in_full))
|
||||||
|
v = 0;
|
||||||
|
else if(lv[0].quality_level > 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
2
rug.cpp
2
rug.cpp
@ -1491,6 +1491,7 @@ void init_model() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void init() {
|
void init() {
|
||||||
|
if(dual::state) return;
|
||||||
reopen();
|
reopen();
|
||||||
if(rugged) init_model();
|
if(rugged) init_model();
|
||||||
}
|
}
|
||||||
@ -2016,6 +2017,7 @@ void show() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void select() {
|
void select() {
|
||||||
|
if(dual::state) return;
|
||||||
pushScreen(rug::show);
|
pushScreen(rug::show);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3272,6 +3272,7 @@ hookset<bool(int)> *hooks_turn;
|
|||||||
void turn(int delta) {
|
void turn(int delta) {
|
||||||
|
|
||||||
if(racing::on && subscreens::split( [delta] () { turn(delta); })) return;
|
if(racing::on && subscreens::split( [delta] () { turn(delta); })) return;
|
||||||
|
if(dual::split( [delta] () { turn(delta); })) return;
|
||||||
|
|
||||||
if(callhandlers(false, hooks_turn, delta)) return;
|
if(callhandlers(false, hooks_turn, delta)) return;
|
||||||
if(!shmup::on) return;
|
if(!shmup::on) return;
|
||||||
|
98
system.cpp
98
system.cpp
@ -1082,76 +1082,9 @@ void loadsave() {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace gamestack {
|
|
||||||
|
|
||||||
struct gamedata {
|
|
||||||
hrmap *hmap;
|
|
||||||
cellwalker cwt;
|
|
||||||
display_data d;
|
|
||||||
eGeometry geometry;
|
|
||||||
eVariation variation;
|
|
||||||
bool shmup;
|
|
||||||
void store();
|
|
||||||
void restore();
|
|
||||||
};
|
|
||||||
|
|
||||||
vector<gamedata> gd;
|
|
||||||
|
|
||||||
bool pushed() { return isize(gd); }
|
|
||||||
|
|
||||||
void gamedata::store() {
|
|
||||||
hmap = currentmap;
|
|
||||||
cwt = hr::cwt;
|
|
||||||
geometry = hr::geometry;
|
|
||||||
shmup = hr::shmup::on;
|
|
||||||
variation = hr::variation;
|
|
||||||
d = *current_display;
|
|
||||||
}
|
|
||||||
|
|
||||||
void gamedata::restore() {
|
|
||||||
currentmap = hmap;
|
|
||||||
hr::cwt = cwt;
|
|
||||||
hr::geometry = geometry;
|
|
||||||
hr::variation = variation;
|
|
||||||
if(shmup::on) shmup::clearMonsters();
|
|
||||||
shmup::on = shmup;
|
|
||||||
check_cgi();
|
|
||||||
cgi.require_basics();
|
|
||||||
*current_display = d;
|
|
||||||
bfs();
|
|
||||||
}
|
|
||||||
|
|
||||||
void push() {
|
|
||||||
if(geometry) {
|
|
||||||
printf("ERROR: push implemented only in non-hyperbolic geometry\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
gd.emplace_back();
|
|
||||||
gd.back().store();
|
|
||||||
}
|
|
||||||
|
|
||||||
void pop() {
|
|
||||||
gd.back().restore();
|
|
||||||
gd.pop_back();
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
void pop_game() {
|
|
||||||
if(gamestack::pushed()) {
|
|
||||||
gamestack::pop();
|
|
||||||
game_active = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void popAllGames() {
|
|
||||||
while(gamestack::pushed()) {
|
|
||||||
gamestack::pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void stop_game() {
|
void stop_game() {
|
||||||
if(!game_active) return;
|
if(!game_active) return;
|
||||||
|
if(dual::split(stop_game)) return;
|
||||||
DEBBI(DF_INIT, ("stop_game"));
|
DEBBI(DF_INIT, ("stop_game"));
|
||||||
achievement_final(true);
|
achievement_final(true);
|
||||||
#if CAP_SAVE
|
#if CAP_SAVE
|
||||||
@ -1186,13 +1119,6 @@ void stop_game() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_game() {
|
|
||||||
gamestack::push();
|
|
||||||
pd_from = NULL;
|
|
||||||
centerover.at = NULL;
|
|
||||||
game_active = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_geometry(eGeometry target) {
|
void set_geometry(eGeometry target) {
|
||||||
if(geometry != target) {
|
if(geometry != target) {
|
||||||
int old_DIM = DIM;
|
int old_DIM = DIM;
|
||||||
@ -1269,6 +1195,10 @@ void switch_game_mode(char switchWhat) {
|
|||||||
|
|
||||||
#if CAP_TOUR
|
#if CAP_TOUR
|
||||||
case rg::tour:
|
case rg::tour:
|
||||||
|
while(gamestack::pushed()) {
|
||||||
|
gamestack::pop();
|
||||||
|
stop_game();
|
||||||
|
}
|
||||||
geometry = gNormal;
|
geometry = gNormal;
|
||||||
yendor::on = tactic::on = princess::challenge = peace::on = inv::on = false;
|
yendor::on = tactic::on = princess::challenge = peace::on = inv::on = false;
|
||||||
chaosmode = randomPatternsMode = false;
|
chaosmode = randomPatternsMode = false;
|
||||||
@ -1360,6 +1290,8 @@ void switch_game_mode(char switchWhat) {
|
|||||||
void start_game() {
|
void start_game() {
|
||||||
if(game_active) return;
|
if(game_active) return;
|
||||||
DEBBI(DF_INIT, ("start_game"));
|
DEBBI(DF_INIT, ("start_game"));
|
||||||
|
if(dual::state == 1) dual::assign_landsides();
|
||||||
|
if(dual::split(start_game)) return;
|
||||||
restart:
|
restart:
|
||||||
game_active = true;
|
game_active = true;
|
||||||
gamegen_failure = false;
|
gamegen_failure = false;
|
||||||
@ -1397,7 +1329,6 @@ void start_game() {
|
|||||||
|
|
||||||
void restart_game(char switchWhat) {
|
void restart_game(char switchWhat) {
|
||||||
popScreenAll();
|
popScreenAll();
|
||||||
popAllGames();
|
|
||||||
stop_game();
|
stop_game();
|
||||||
switch_game_mode(switchWhat);
|
switch_game_mode(switchWhat);
|
||||||
start_game();
|
start_game();
|
||||||
@ -1428,6 +1359,21 @@ auto cgm = addHook(clearmemory, 40, [] () {
|
|||||||
rosemap.clear();
|
rosemap.clear();
|
||||||
adj_memo.clear();
|
adj_memo.clear();
|
||||||
}) +
|
}) +
|
||||||
|
addHook(hooks_gamedata, 0, [] (gamedata* gd) {
|
||||||
|
gd->store(pathq);
|
||||||
|
gd->store(dcal);
|
||||||
|
gd->store(recallCell);
|
||||||
|
gd->store(butterflies);
|
||||||
|
gd->store(buggycells);
|
||||||
|
gd->store(crush_now);
|
||||||
|
gd->store(crush_next);
|
||||||
|
gd->store(rosemap);
|
||||||
|
gd->store(adj_memo);
|
||||||
|
gd->store(pd_from);
|
||||||
|
gd->store(pd_range);
|
||||||
|
gd->store(pathqm);
|
||||||
|
gd->store(reachedfrom);
|
||||||
|
}) +
|
||||||
addHook(hooks_removecells, 0, [] () {
|
addHook(hooks_removecells, 0, [] () {
|
||||||
eliminate_if(crush_next, is_cell_removed);
|
eliminate_if(crush_next, is_cell_removed);
|
||||||
eliminate_if(crush_now, is_cell_removed);
|
eliminate_if(crush_now, is_cell_removed);
|
||||||
|
18
tour.cpp
18
tour.cpp
@ -22,7 +22,7 @@ void setCanvas(presmode mode, char canv) {
|
|||||||
static char wc;
|
static char wc;
|
||||||
static eLand ld;
|
static eLand ld;
|
||||||
if(mode == pmStart) {
|
if(mode == pmStart) {
|
||||||
push_game();
|
gamestack::push();
|
||||||
wc = patterns::whichCanvas;
|
wc = patterns::whichCanvas;
|
||||||
patterns::whichCanvas = canv;
|
patterns::whichCanvas = canv;
|
||||||
ld = firstland;
|
ld = firstland;
|
||||||
@ -30,9 +30,9 @@ void setCanvas(presmode mode, char canv) {
|
|||||||
start_game();
|
start_game();
|
||||||
}
|
}
|
||||||
if(mode == pmStop) {
|
if(mode == pmStop) {
|
||||||
|
gamestack::pop();
|
||||||
patterns::whichCanvas = wc;
|
patterns::whichCanvas = wc;
|
||||||
firstland = ld;
|
firstland = ld;
|
||||||
pop_game();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ void slidehelp() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void return_geometry() {
|
void return_geometry() {
|
||||||
pop_game();
|
gamestack::pop();
|
||||||
vid.scale = 1; vid.alpha = 1;
|
vid.scale = 1; vid.alpha = 1;
|
||||||
presentation(pmGeometryReset);
|
presentation(pmGeometryReset);
|
||||||
addMessage(XLAT("Returned to your game."));
|
addMessage(XLAT("Returned to your game."));
|
||||||
@ -103,7 +103,7 @@ bool handleKeyTour(int sym, int uni) {
|
|||||||
}
|
}
|
||||||
if(sym == SDLK_BACKSPACE) {
|
if(sym == SDLK_BACKSPACE) {
|
||||||
if(gamestack::pushed()) {
|
if(gamestack::pushed()) {
|
||||||
pop_game();
|
gamestack::pop();
|
||||||
if(!(flags & QUICKGEO)) return true;
|
if(!(flags & QUICKGEO)) return true;
|
||||||
}
|
}
|
||||||
if(currentslide == 0) { slidehelp(); return true; }
|
if(currentslide == 0) { slidehelp(); return true; }
|
||||||
@ -158,7 +158,7 @@ bool handleKeyTour(int sym, int uni) {
|
|||||||
presentation(pmGeometry);
|
presentation(pmGeometry);
|
||||||
|
|
||||||
firstland = specialland = cwt.at->land;
|
firstland = specialland = cwt.at->land;
|
||||||
push_game();
|
gamestack::push();
|
||||||
switch(NUMBERKEY) {
|
switch(NUMBERKEY) {
|
||||||
case '3':
|
case '3':
|
||||||
set_variation(eVariation::pure);
|
set_variation(eVariation::pure);
|
||||||
@ -290,8 +290,8 @@ namespace ss {
|
|||||||
for(int i=0;; i++) {
|
for(int i=0;; i++) {
|
||||||
dialog::addBoolItem(XLAT(wts[i].name), wts == slides && i == currentslide, slidechars[i]);
|
dialog::addBoolItem(XLAT(wts[i].name), wts == slides && i == currentslide, slidechars[i]);
|
||||||
dialog::add_action([i] {
|
dialog::add_action([i] {
|
||||||
if(geometry || CHANGED_VARIATION) {
|
if(gamestack::pushed()) {
|
||||||
pop_game();
|
gamestack::pop();
|
||||||
presentation(pmGeometryReset);
|
presentation(pmGeometryReset);
|
||||||
}
|
}
|
||||||
if(slides != wts) {
|
if(slides != wts) {
|
||||||
@ -770,13 +770,13 @@ slide default_slides[] = {
|
|||||||
[] (presmode mode) {
|
[] (presmode mode) {
|
||||||
if(mode == 1) {
|
if(mode == 1) {
|
||||||
firstland = cwt.at->land;
|
firstland = cwt.at->land;
|
||||||
push_game();
|
gamestack::push();
|
||||||
switch_game_mode(rg::shmup);
|
switch_game_mode(rg::shmup);
|
||||||
start_game();
|
start_game();
|
||||||
}
|
}
|
||||||
if(mode == 3) {
|
if(mode == 3) {
|
||||||
shmup::clearMonsters();
|
shmup::clearMonsters();
|
||||||
pop_game();
|
gamestack::pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user