1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2024-10-18 06:30:41 +00:00

Strong Wind and Orb of Vaulting now better with Orb of the Sword

This commit is contained in:
Zeno Rogue 2024-10-11 17:09:37 +02:00
parent d90dcdcff5
commit 568389e629
5 changed files with 69 additions and 34 deletions

View File

@ -162,15 +162,19 @@ EX namespace whirlwind {
} }
} }
EX cell *jumpFromWhereTo(cell *c, bool player) { EX cell *jumpFromWhereTo(cell *c, bool player, struct jumpdata& jdata) {
jdata.uniq = true;
for(int i=0; i<2; i++) { for(int i=0; i<2; i++) {
calcdirs(c); calcdirs(c);
if(qdirs != 1) return NULL; if(qdirs != 1) return NULL;
auto mi = movei(c, dfrom[0]);
jdata.moves.push_back(mi.rev());
cell *c2 = c->move(dfrom[0]); cell *c2 = c->move(dfrom[0]);
if(!passable(c, c2, P_JUMP1)) return NULL; if(!passable(c, c2, P_JUMP1)) return NULL;
if(player && i == 0 && !passable(c, c2, P_ISPLAYER)) return NULL; if(player && i == 0 && !passable(c, c2, P_ISPLAYER)) return NULL;
c = c2; c = c2;
} }
reverse(jdata.moves.begin(), jdata.moves.end());
calcdirs(c); calcdirs(c);
if(qdirs != 1) return NULL; if(qdirs != 1) return NULL;
return c; return c;

View File

@ -502,6 +502,16 @@ struct movei {
}; };
#endif #endif
#if HDR
struct jumpdata {
eMonster dashmon;
cell *jumpthru;
bool uniq;
vector<movei> moves;
jumpdata() { dashmon = moNone; jumpthru = nullptr; uniq = false; }
};
#endif
EX movei moveimon(cell *c) { return movei(c, c->mondir); } EX movei moveimon(cell *c) { return movei(c, c->mondir); }
EX movei match(cell *f, cell *t) { EX movei match(cell *f, cell *t) {

View File

@ -1224,7 +1224,8 @@ EX void groupmove(eMonster movtype, flagtype mf) {
} }
if(movtype == moEagle && c->monst == moNone && !isPlayerOn(c) && !bird_disruption(c)) { if(movtype == moEagle && c->monst == moNone && !isPlayerOn(c) && !bird_disruption(c)) {
cell *c2 = whirlwind::jumpFromWhereTo(c, false); jumpdata jdata;
cell *c2 = whirlwind::jumpFromWhereTo(c, false, jdata);
groupmove2(movei(c2, c, STRONGWIND), movtype, mf); groupmove2(movei(c2, c, STRONGWIND), movtype, mf);
} }

View File

@ -665,12 +665,13 @@ EX void teleportTo(cell *dest) {
} }
/* calls changes.rollback or changes.commit */ /* calls changes.rollback or changes.commit */
EX bool jumpTo(orbAction a, cell *dest, eItem byWhat, int bonuskill IS(0), eMonster dashmon IS(moNone), cell *phasecell IS(nullptr)) { EX bool jumpTo(orbAction a, cell *dest, eItem byWhat, int bonuskill, jumpdata jdata) {
if(byWhat != itStrongWind) playSound(dest, "orb-frog"); if(byWhat != itStrongWind) playSound(dest, "orb-frog");
cell *from = cwt.at; cell *from = cwt.at;
changes.value_keep(cwt); changes.value_keep(cwt);
changes.ccell(dest); changes.ccell(dest);
changes.ccell(cwt.at); changes.ccell(cwt.at);
changes.value_keep(sword::dir);
if(byWhat == itOrbFrog) { if(byWhat == itOrbFrog) {
useupOrb(itOrbFrog, 5); useupOrb(itOrbFrog, 5);
@ -679,11 +680,12 @@ EX bool jumpTo(orbAction a, cell *dest, eItem byWhat, int bonuskill IS(0), eMons
if(byWhat == itOrbDash) { if(byWhat == itOrbDash) {
useupOrb(itOrbDash, 5); useupOrb(itOrbDash, 5);
if(dashmon) addMessage(XLAT("You vault over %the1!", dashmon)); if(jdata.dashmon) addMessage(XLAT("You vault over %the1!", jdata.dashmon));
} }
if(byWhat == itOrbPhasing) { if(byWhat == itOrbPhasing) {
useupOrb(itOrbPhasing, 5); useupOrb(itOrbPhasing, 5);
cell *phasecell = jdata.jumpthru;
if(phasecell->monst) if(phasecell->monst)
addMessage(XLAT("You phase through %the1!", phasecell->monst)); addMessage(XLAT("You phase through %the1!", phasecell->monst));
else else
@ -703,7 +705,22 @@ EX bool jumpTo(orbAction a, cell *dest, eItem byWhat, int bonuskill IS(0), eMons
flipplayer = true; flipplayer = true;
} }
sword::reset(); if(jdata.uniq) {
int numbb[2];
println(hlog, "moves = ", isize(jdata.moves));
for(int a=0; a<2; a++) numbb[a] = 0;
for(int a=0; a<2; a++) {
cell *mt = jdata.moves[a].t;
do_swords(jdata.moves[a], moPlayer,
[&] (cell *c, int bb) { if(swordAttack(mt, moPlayer, c, bb)) numbb[bb]++; });
sword::dir[multi::cpid] = sword::shift(jdata.moves[a], sword::dir[multi::cpid]);
}
for(int bb=0; bb<2; bb++) achievement_count("SLASH", numbb[bb], 0);
}
else {
sword::reset();
}
auto mi = movei(c1, dest, JUMP); auto mi = movei(c1, dest, JUMP);
stabbingAttack(mi, moPlayer, bonuskill); stabbingAttack(mi, moPlayer, bonuskill);
playerMoveEffects(mi); playerMoveEffects(mi);
@ -1243,11 +1260,11 @@ EX movei blowoff_destination(cell *c, int& di) {
return blowoff_destination_dir(c, di, rev); return blowoff_destination_dir(c, di, rev);
} }
EX int check_jump(cell *cf, cell *ct, flagtype flags, cell*& jumpthru) { EX int check_jump(cell *cf, cell *ct, flagtype flags, jumpdata& jdata) {
int partial = 1; int partial = 1;
forCellCM(c2, cf) { forCellCM(c2, cf) {
if(isNeighbor(c2, ct)) { if(isNeighbor(c2, ct)) {
jumpthru = c2; jdata.jumpthru = c2;
if(passable(c2, cf, flags | P_JUMP1)) { if(passable(c2, cf, flags | P_JUMP1)) {
partial = 2; partial = 2;
if(passable(ct, c2, flags | P_JUMP2)) { if(passable(ct, c2, flags | P_JUMP2)) {
@ -1259,11 +1276,11 @@ EX int check_jump(cell *cf, cell *ct, flagtype flags, cell*& jumpthru) {
return partial; return partial;
} }
EX int check_phase(cell *cf, cell *ct, flagtype flags, cell*& jumpthru) { EX int check_phase(cell *cf, cell *ct, flagtype flags, jumpdata& jdata) {
int partial = 1; int partial = 1;
forCellCM(c2, cf) { forCellCM(c2, cf) {
if(isNeighbor(c2, ct) && !nonAdjacent(cf, c2) && !nonAdjacent(c2, ct)) { if(isNeighbor(c2, ct) && !nonAdjacent(cf, c2) && !nonAdjacent(c2, ct)) {
jumpthru = c2; jdata.jumpthru = c2;
if(passable(ct, cf, flags | P_PHASE)) { if(passable(ct, cf, flags | P_PHASE)) {
partial = 2; partial = 2;
if(c2->monst || (isWall(c2) && c2->wall != waShrub)) { if(c2->monst || (isWall(c2) && c2->wall != waShrub)) {
@ -1295,14 +1312,17 @@ EX void apply_impact(cell *c) {
} }
} }
EX int check_vault(cell *cf, cell *ct, flagtype flags, cell*& jumpthru) { EX int check_vault(cell *cf, cell *ct, flagtype flags, jumpdata& jdata) {
cell *c2 = NULL, *c3 = NULL; cell *c2 = NULL, *c3 = NULL;
forCellCM(cc, cf) { forCellCM(cc, cf) {
if(isNeighbor(cc, ct) && c2 != cc) c3 = c2, c2 = cc; if(isNeighbor(cc, ct) && c2 != cc) c3 = c2, c2 = cc;
} }
jumpthru = c2;
if(!c2) return 0; if(!c2) return 0;
if(c3) return 1; if(c3) return 1;
jdata.moves.push_back(movei(cf, c2, neighborId(cf, c2)));
jdata.moves.push_back(movei(c2, ct, neighborId(c2, ct)));
jdata.jumpthru = c2;
jdata.uniq = true;
bool cutwall = among(c2->wall, waShrub, waExplosiveBarrel, waSmallTree, waBigTree); bool cutwall = among(c2->wall, waShrub, waExplosiveBarrel, waSmallTree, waBigTree);
if(!c2->monst && !cutwall) return 2; if(!c2->monst && !cutwall) return 2;
bool for_monster = !(flags & P_ISPLAYER); bool for_monster = !(flags & P_ISPLAYER);
@ -1363,11 +1383,13 @@ EX eItem targetRangedOrb(cell *c, orbAction a) {
bool wouldkill_there = false; bool wouldkill_there = false;
bool wouldkill_here = false; bool wouldkill_here = false;
jumpdata jdata;
// (0-) strong wind // (0-) strong wind
if(items[itStrongWind] if(items[itStrongWind]
&& CHK(c->cpdist == 2 && cwt.at == whirlwind::jumpFromWhereTo(c, true), XLAT("Strong wind can only take you to a specific place!"))) { && CHK(c->cpdist == 2 && cwt.at == whirlwind::jumpFromWhereTo(c, true, jdata), XLAT("Strong wind can only take you to a specific place!"))) {
changes.init(isCheck(a)); changes.init(isCheck(a));
if(jumpTo(a, c, itStrongWind)) return itStrongWind; if(jumpTo(a, c, itStrongWind, 0, jdata)) return itStrongWind;
} }
// (0x) control // (0x) control
@ -1450,25 +1472,23 @@ EX eItem targetRangedOrb(cell *c, orbAction a) {
else changes.rollback(); else changes.rollback();
} }
// (0'') jump
cell *jumpthru = NULL;
// orb of vaulting // orb of vaulting
if(!shmup::on && items[itOrbDash] && CHK(c->cpdist == 2, XLAT("Cannot vault that far!"))) { if(!shmup::on && items[itOrbDash] && CHK(c->cpdist == 2, XLAT("Cannot vault that far!"))) {
changes.init(isCheck(a)); changes.init(isCheck(a));
int vaultstate = check_vault(cwt.at, c, P_ISPLAYER, jumpthru); int vaultstate = check_vault(cwt.at, c, P_ISPLAYER, jdata);
if(vaultstate == 0) orb_error_messages.push_back(XLAT("ERROR: No common neighbor to vault through!")); if(vaultstate == 0) orb_error_messages.push_back(XLAT("ERROR: No common neighbor to vault through!"));
if(vaultstate == 1) orb_error_messages.push_back(XLAT("Can only vault in a roughly straight line!")); if(vaultstate == 1) orb_error_messages.push_back(XLAT("Can only vault in a roughly straight line!"));
if(vaultstate == 2) orb_error_messages.push_back(XLAT("Nothing to vault over!")); if(vaultstate == 2) orb_error_messages.push_back(XLAT("Nothing to vault over!"));
if(vaultstate == 3) orb_error_messages.push_back(XLAT("Cannot pass through %the1 while vaulting!", jumpthru->wall)); if(vaultstate == 3) orb_error_messages.push_back(XLAT("Cannot pass through %the1 while vaulting!", jdata.jumpthru->wall));
if(vaultstate == 4 && c->monst) orb_error_messages.push_back(XLAT("Cannot vault onto %the1!", c->monst)); if(vaultstate == 4 && c->monst) orb_error_messages.push_back(XLAT("Cannot vault onto %the1!", c->monst));
if(vaultstate == 4 && !c->monst) orb_error_messages.push_back(XLAT("Cannot vault to %the1!", c->wall)); if(vaultstate == 4 && !c->monst) orb_error_messages.push_back(XLAT("Cannot vault to %the1!", c->wall));
if(vaultstate == 5) orb_error_messages.push_back(XLAT("Cannot attack %the1 while vaulting!", jumpthru->monst)); if(vaultstate == 5) orb_error_messages.push_back(XLAT("Cannot attack %the1 while vaulting!", jdata.jumpthru->monst));
if(vaultstate == 6) { if(vaultstate == 6) {
int k = tkills(); int k = tkills();
eMonster m = jumpthru->monst; auto& jumpthru = jdata.jumpthru;
jdata.dashmon = jumpthru->monst;
if(jumpthru->wall == waShrub) { if(jumpthru->wall == waShrub) {
addMessage(XLAT("You chop down the shrub.")); addMessage(XLAT("You chop down the shrub."));
jumpthru->wall = waNone; jumpthru->wall = waNone;
@ -1484,10 +1504,10 @@ EX eItem targetRangedOrb(cell *c, orbAction a) {
if(jumpthru->wall == waExplosiveBarrel) { if(jumpthru->wall == waExplosiveBarrel) {
explodeBarrel(jumpthru); explodeBarrel(jumpthru);
} }
if(m) if(jdata.dashmon)
attackMonster(jumpthru, AF_NORMAL | AF_MSG, moPlayer); attackMonster(jumpthru, AF_NORMAL | AF_MSG, moPlayer);
k = tkills() - k; k = tkills() - k;
if(jumpTo(a, c, itOrbDash, k, m)) vaultstate = 7; if(jumpTo(a, c, itOrbDash, k, jdata)) vaultstate = 7;
else wouldkill_there = true; else wouldkill_there = true;
if(vaultstate == 7) return itOrbDash; if(vaultstate == 7) return itOrbDash;
} }
@ -1496,12 +1516,12 @@ EX eItem targetRangedOrb(cell *c, orbAction a) {
if(items[itOrbFrog] && CHK(c->cpdist == 2, XLAT("Cannot jump that far!"))) { if(items[itOrbFrog] && CHK(c->cpdist == 2, XLAT("Cannot jump that far!"))) {
changes.init(isCheck(a)); changes.init(isCheck(a));
int frogstate = check_jump(cwt.at, c, P_ISPLAYER, jumpthru); int frogstate = check_jump(cwt.at, c, P_ISPLAYER, jdata);
if(frogstate == 1 && jumpthru && jumpthru->monst) { if(frogstate == 1 && jdata.jumpthru && jdata.jumpthru->monst) {
orb_error_messages.push_back(XLAT("Cannot jump through %the1!", jumpthru->monst)); orb_error_messages.push_back(XLAT("Cannot jump through %the1!", jdata.jumpthru->monst));
} }
else if(frogstate == 1 && jumpthru) { else if(frogstate == 1 && jdata.jumpthru) {
orb_error_messages.push_back(XLAT("Cannot jump through %the1!", jumpthru->wall)); orb_error_messages.push_back(XLAT("Cannot jump through %the1!", jdata.jumpthru->wall));
} }
else if(frogstate == 2 && c->monst) { else if(frogstate == 2 && c->monst) {
orb_error_messages.push_back(XLAT("Cannot jump onto %the1!", c->monst)); orb_error_messages.push_back(XLAT("Cannot jump onto %the1!", c->monst));
@ -1511,7 +1531,7 @@ EX eItem targetRangedOrb(cell *c, orbAction a) {
} }
if(frogstate == 3) { if(frogstate == 3) {
if(jumpTo(a, c, itOrbFrog)) frogstate = 4; if(jumpTo(a, c, itOrbFrog, 0, jdata)) frogstate = 4;
else wouldkill_there = true; else wouldkill_there = true;
if(frogstate == 4) return itOrbFrog; if(frogstate == 4) return itOrbFrog;
} }
@ -1521,7 +1541,7 @@ EX eItem targetRangedOrb(cell *c, orbAction a) {
if(items[itOrbPhasing] && CHK(c->cpdist == 2, XLAT("Cannot phase that far!"))) { if(items[itOrbPhasing] && CHK(c->cpdist == 2, XLAT("Cannot phase that far!"))) {
changes.init(isCheck(a)); changes.init(isCheck(a));
if(shmup::on) shmup::pushmonsters(); if(shmup::on) shmup::pushmonsters();
int phasestate = check_phase(cwt.at, c, P_ISPLAYER, jumpthru); int phasestate = check_phase(cwt.at, c, P_ISPLAYER, jdata);
if(phasestate == 1 && c->monst) { if(phasestate == 1 && c->monst) {
orb_error_messages.push_back(XLAT("Cannot phase onto %the1!", c->monst)); orb_error_messages.push_back(XLAT("Cannot phase onto %the1!", c->monst));
} }
@ -1533,7 +1553,7 @@ EX eItem targetRangedOrb(cell *c, orbAction a) {
} }
if(phasestate == 3) { if(phasestate == 3) {
if(jumpTo(a, c, itOrbPhasing, 0, moNone, jumpthru)) phasestate = 4; if(jumpTo(a, c, itOrbPhasing, 0, jdata)) phasestate = 4;
else wouldkill_there = true; else wouldkill_there = true;
} }
else changes.rollback(); else changes.rollback();

View File

@ -475,7 +475,7 @@ EX bool isNeighbor1(cell *f, cell *w) {
} }
EX bool passable_for(eMonster m, cell *w, cell *from, flagtype extra) { EX bool passable_for(eMonster m, cell *w, cell *from, flagtype extra) {
cell *dummy; jumpdata jdummy;
if(w->monst && !(extra & P_MONSTER) && !isPlayerOn(w)) if(w->monst && !(extra & P_MONSTER) && !isPlayerOn(w))
return false; return false;
if(m == moWolf) { if(m == moWolf) {
@ -573,12 +573,12 @@ EX bool passable_for(eMonster m, cell *w, cell *from, flagtype extra) {
} }
#endif #endif
if(m == moFrog) { if(m == moFrog) {
return isNeighbor1(from, w) ? passable(w, from, extra) : check_jump(from, w, extra, dummy) == 3; return isNeighbor1(from, w) ? passable(w, from, extra) : check_jump(from, w, extra, jdummy) == 3;
} }
if(m == moPhaser) if(m == moPhaser)
return isNeighbor1(from, w) ? passable(w, from, extra) : check_phase(from, w, extra, dummy) == 3; return isNeighbor1(from, w) ? passable(w, from, extra) : check_phase(from, w, extra, jdummy) == 3;
if(m == moVaulter) if(m == moVaulter)
return isNeighbor1(from, w) ? passable(w, from, extra) : check_vault(from, w, extra, dummy) == 6; return isNeighbor1(from, w) ? passable(w, from, extra) : check_vault(from, w, extra, jdummy) == 6;
if(m == moAltDemon) { if(m == moAltDemon) {
if(extra & P_ONPLAYER) { if(extra & P_ONPLAYER) {
if(isPlayerOn(w)) return true; if(isPlayerOn(w)) return true;