mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2024-12-24 01:00:25 +00:00
improved the checkmove.cpp, also works for golems now
This commit is contained in:
parent
2e236be695
commit
63f895974e
20
attack.cpp
20
attack.cpp
@ -1183,19 +1183,19 @@ EX void killThePlayerAt(eMonster m, cell *c, flagtype flags) {
|
||||
}
|
||||
|
||||
#if HDR
|
||||
template<class T> void do_swords(cell *mf, cell *mt, eMonster who, const T& f) {
|
||||
template<class T> void do_swords(movei mi, eMonster who, const T& f) {
|
||||
for(int bb=0; bb<2; bb++) if(who == moPlayer && sword::orbcount(bb)) {
|
||||
cell *sf = sword::pos(mf, sword::dir[multi::cpid], bb);
|
||||
cell *st = sword::pos(mt, sword::shift(mf, mt, sword::dir[multi::cpid]), bb);
|
||||
cell *sf = sword::pos(mi.s, sword::dir[multi::cpid], bb);
|
||||
cell *st = sword::pos(mi.t, sword::shift(mi, sword::dir[multi::cpid]), bb);
|
||||
f(st, bb);
|
||||
if(sf != st && !isNeighbor(sf,st)) {
|
||||
// also attack the in-transit cell
|
||||
if(S3 == 3) {
|
||||
forCellEx(sb, sf) if(isNeighbor(sb, st) && sb != mf && sb != mt) f(sb, bb);
|
||||
forCellEx(sb, sf) if(isNeighbor(sb, st) && sb != mi.s && sb != mi.t) f(sb, bb);
|
||||
}
|
||||
else {
|
||||
forCellEx(sb, mf) if(isNeighbor(sb, st) && sb != mt) f(sb, bb);
|
||||
forCellEx(sb, mt) if(isNeighbor(sb, sf) && sb != mf) f(sb, bb);
|
||||
forCellEx(sb, mi.s) if(isNeighbor(sb, st) && sb != mi.t) f(sb, bb);
|
||||
forCellEx(sb, mi.t) if(isNeighbor(sb, sf) && sb != mi.s) f(sb, bb);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1204,14 +1204,16 @@ template<class T> void do_swords(cell *mf, cell *mt, eMonster who, const T& f) {
|
||||
|
||||
int lastdouble = -3;
|
||||
|
||||
EX void stabbingAttack(cell *mf, cell *mt, eMonster who, int bonuskill IS(0)) {
|
||||
EX void stabbingAttack(movei mi, eMonster who, int bonuskill IS(0)) {
|
||||
int numsh = 0, numflail = 0, numlance = 0, numslash = 0, numbb[2];
|
||||
|
||||
numbb[0] = numbb[1] = 0;
|
||||
|
||||
int backdir = neighborId(mt, mf);
|
||||
cell *mf = mi.s;
|
||||
cell *mt = mi.t;
|
||||
int backdir = mi.rev_dir();
|
||||
|
||||
do_swords(mf, mt, who, [&] (cell *c, int bb) { if(swordAttack(mt, who, c, bb)) numbb[bb]++, numslash++; });
|
||||
do_swords(mi, who, [&] (cell *c, int bb) { if(swordAttack(mt, who, c, bb)) numbb[bb]++, numslash++; });
|
||||
|
||||
for(int bb=0; bb<2; bb++) achievement_count("SLASH", numbb[bb], 0);
|
||||
|
||||
|
183
checkmove.cpp
183
checkmove.cpp
@ -39,28 +39,47 @@ EX bool hasSafeOrb(cell *c) {
|
||||
}
|
||||
|
||||
#if HDR
|
||||
struct stalemate1 {
|
||||
eMonster who;
|
||||
cell *moveto;
|
||||
cell *pushto;
|
||||
cell *comefrom;
|
||||
struct player_move_info {
|
||||
movei mi;
|
||||
cell *swordlast[2], *swordtransit[2], *swordnext[2];
|
||||
stalemate1(eMonster w, cell *mt, cell *pt, cell *cf) : who(w), moveto(mt), pushto(pt), comefrom(cf) {}
|
||||
player_move_info(movei mi);
|
||||
};
|
||||
#endif
|
||||
|
||||
EX vector<player_move_info> pmi;
|
||||
EX vector<cell*> pushes;
|
||||
|
||||
player_move_info::player_move_info(movei _mi) : mi(_mi) {
|
||||
for(int b=0; b<2; b++) swordlast[b] = sword::pos(multi::cpid, b);
|
||||
|
||||
dynamicval<sword::sworddir> x7(sword::dir[multi::cpid], sword::shift(mi, sword::dir[multi::cpid]));
|
||||
|
||||
for(int b=0; b<2; b++) {
|
||||
swordnext[b] = sword::pos(multi::cpid, b);
|
||||
swordtransit[b] = NULL;
|
||||
if(swordnext[b] && swordnext[b] != swordlast[b] && !isNeighbor(swordlast[b], swordnext[b])) {
|
||||
forCellEx(c2, swordnext[b])
|
||||
if(c2 != mi.t && c2 != mi.s && isNeighbor(c2, S3==3 ? swordlast[b] : mi.t))
|
||||
swordtransit[b] = c2;
|
||||
if(S3 == 4)
|
||||
forCellEx(c2, mi.s)
|
||||
if(c2 != mi.s && isNeighbor(c2, swordlast[b]))
|
||||
swordtransit[b] = c2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EX bool krakensafe(cell *c) {
|
||||
return items[itOrbFish] || items[itOrbAether] ||
|
||||
(c->item == itOrbFish && c->wall == waBoat) ||
|
||||
(c->item == itOrbAether && c->wall == waBoat);
|
||||
}
|
||||
|
||||
EX bool monstersnear(stalemate1& sm) {
|
||||
EX bool monstersnear(cell *c, eMonster who) {
|
||||
|
||||
cell *c = sm.moveto;
|
||||
bool eaten = false;
|
||||
|
||||
if(hardcore && sm.who == moPlayer) return false;
|
||||
if(hardcore && who == moPlayer) return false;
|
||||
|
||||
int res = 0;
|
||||
bool fast = false;
|
||||
@ -76,9 +95,9 @@ EX bool monstersnear(stalemate1& sm) {
|
||||
who_kills_me = moCrusher; res++;
|
||||
}
|
||||
|
||||
if(sm.who == moPlayer || items[itOrbEmpathy]) {
|
||||
if(who == moPlayer || items[itOrbEmpathy]) {
|
||||
fast = (items[itOrbSpeed] && (items[itOrbSpeed] & 1));
|
||||
if(sm.who == moPlayer && sm.moveto->item == itOrbSpeed && !items[itOrbSpeed]) fast = true;
|
||||
if(who == moPlayer && c->item == itOrbSpeed && !items[itOrbSpeed]) fast = true;
|
||||
}
|
||||
|
||||
if(havewhat&HF_OUTLAW) {
|
||||
@ -103,7 +122,7 @@ EX bool monstersnear(stalemate1& sm) {
|
||||
if(!logical_adjacent(c3, c3->monst, c2) || !logical_adjacent(c2, c3->monst, c) || (c3->monst == moWitchSpeed && c2->land != laPower))
|
||||
continue;
|
||||
if(elec::affected(c3)) continue;
|
||||
if(c3->stuntime > (sm.who == moPlayer ? 0 : 1)) continue;
|
||||
if(c3->stuntime > (who == moPlayer ? 0 : 1)) continue;
|
||||
// speedwitches can only attack not-fastened monsters,
|
||||
// others can only attack if the move is not fastened
|
||||
if(c3->monst == moWitchSpeed && items[itOrbSpeed]) continue;
|
||||
@ -120,19 +139,19 @@ EX bool monstersnear(stalemate1& sm) {
|
||||
|
||||
// consider normal monsters
|
||||
if(c2 &&
|
||||
isArmedEnemy(c2, sm.who) &&
|
||||
(c2->monst != moLancer || isUnarmed(sm.who) || !logical_adjacent(c, sm.who, c2))) {
|
||||
isArmedEnemy(c2, who) &&
|
||||
(c2->monst != moLancer || isUnarmed(who) || !logical_adjacent(c, who, c2))) {
|
||||
eMonster m = c2->monst;
|
||||
if(elec::affected(c2)) continue;
|
||||
if(fast && c2->monst != moWitchSpeed) continue;
|
||||
// Krakens just destroy boats
|
||||
if(c2->monst == moKrakenT && onboat(sm)) {
|
||||
if(c2->monst == moKrakenT && c->wall == waBoat) {
|
||||
if(krakensafe(c)) continue;
|
||||
else if(warningprotection(XLAT("This move appears dangerous -- are you sure?")) && res == 0) m = moWarning;
|
||||
else continue;
|
||||
}
|
||||
// they cannot attack through vines
|
||||
if(!canAttack(c2, c2->monst, c, sm.who, AF_NEXTTURN)) continue;
|
||||
if(!canAttack(c2, c2->monst, c, who, AF_NEXTTURN)) continue;
|
||||
if(c2->monst == moWorm || c2->monst == moTentacle || c2->monst == moHexSnake) {
|
||||
if(passable_for(c2->monst, c, c2, 0))
|
||||
eaten = true;
|
||||
@ -142,18 +161,16 @@ EX bool monstersnear(stalemate1& sm) {
|
||||
}
|
||||
}
|
||||
|
||||
if(sm.who == moPlayer && res && (markOrb2(itOrbShield) || markOrb2(itOrbShell)) && !eaten)
|
||||
if(who == moPlayer && res && (markOrb2(itOrbShield) || markOrb2(itOrbShell)) && !eaten)
|
||||
res = 0;
|
||||
|
||||
if(sm.who == moPlayer && res && markOrb2(itOrbDomination) && c->monst)
|
||||
if(who == moPlayer && res && markOrb2(itOrbDomination) && c->monst)
|
||||
res = 0;
|
||||
|
||||
return !!res;
|
||||
}
|
||||
|
||||
EX bool monstersnear2();
|
||||
|
||||
EX bool monstersnear2() {
|
||||
EX bool monstersnear_aux() {
|
||||
changes.value_set(passive_switch, (gold() & 1) ? moSwitch1 : moSwitch2);
|
||||
multi::cpid++;
|
||||
bool b = false;
|
||||
@ -162,22 +179,33 @@ EX bool monstersnear2() {
|
||||
if(multi::cpid == multi::players || multi::players == 1 || multi::checkonly) {
|
||||
|
||||
if(shmup::delayed_safety) return false;
|
||||
dynamicval<eMonster> sw(passive_switch, passive_switch);
|
||||
|
||||
for(int i=0; i<isize(stalemate::moves); i++)
|
||||
for(int j=0; j<isize(stalemate::moves); j++) if(i != j) {
|
||||
if(swordConflict(stalemate::moves[i], stalemate::moves[j])) {
|
||||
|
||||
for(int i=0; i<isize(pmi); i++)
|
||||
for(int j=0; j<isize(pmi); j++) if(i != j) {
|
||||
if(swordConflict(pmi[i], pmi[j])) {
|
||||
b = true;
|
||||
who_kills_me = moEnergySword;
|
||||
}
|
||||
if(multi::player[i].at == multi::player[j].at)
|
||||
if(pmi[i].mi.t == pmi[j].mi.t)
|
||||
{ b = true; who_kills_me = moFireball; }
|
||||
if(celldistance(multi::player[i].at, multi::player[j].at) > 8)
|
||||
if(celldistance(pmi[i].mi.t, pmi[j].mi.t) > 8)
|
||||
{ b = true; who_kills_me = moAirball; }
|
||||
}
|
||||
|
||||
for(int i=0; !b && i<isize(stalemate::moves); i++)
|
||||
b = monstersnear(stalemate::moves[i]);
|
||||
for(auto& pushto: pushes)
|
||||
for(auto& mi: pmi)
|
||||
if(pushto == mi.mi.t) {
|
||||
b = true; who_kills_me = moTongue;
|
||||
}
|
||||
|
||||
for(int i=0; i<isize(pushes); i++)
|
||||
for(int j=0; j<i; j++)
|
||||
if(pushes[i] == pushes[j]) {
|
||||
b = true; who_kills_me = moCrushball;
|
||||
}
|
||||
|
||||
for(int i=0; !b && i<isize(pmi); i++)
|
||||
b = monstersnear(pmi[i].mi.t, moPlayer);
|
||||
}
|
||||
else b = !multimove();
|
||||
multi::cpid--;
|
||||
@ -185,94 +213,17 @@ EX bool monstersnear2() {
|
||||
return b;
|
||||
}
|
||||
|
||||
EX bool monstersnear(cell *c, eMonster who, cell *pushto, cell *comefrom) {
|
||||
|
||||
if(peace::on) return 0; // you are safe
|
||||
|
||||
stalemate1 sm(who, c, pushto, comefrom);
|
||||
|
||||
if(who == moPlayer) for(int b=0; b<2; b++) sm.swordlast[b] = sword::pos(multi::cpid, b);
|
||||
|
||||
cell *none = NULL;
|
||||
cell **wcw = &cwt.at;
|
||||
if(who != moPlayer) wcw = &none;
|
||||
else if(multi::players > 1) wcw = &multi::player[multi::cpid].at;
|
||||
|
||||
dynamicval<cell*> x5(*wcw, c);
|
||||
dynamicval<bool> x6(stalemate::nextturn, true);
|
||||
dynamicval<sword::sworddir> x7(sword::dir[multi::cpid],
|
||||
who == moPlayer ? sword::shift(comefrom, c, sword::dir[multi::cpid]) :
|
||||
sword::dir[multi::cpid]);
|
||||
|
||||
for(int b=0; b<2; b++) {
|
||||
if(who == moPlayer) {
|
||||
sm.swordnext[b] = sword::pos(multi::cpid, b);
|
||||
sm.swordtransit[b] = NULL;
|
||||
if(sm.swordnext[b] && sm.swordnext[b] != sm.swordlast[b] && !isNeighbor(sm.swordlast[b], sm.swordnext[b])) {
|
||||
forCellEx(c2, sm.swordnext[b])
|
||||
if(c2 != c && c2 != comefrom && isNeighbor(c2, S3==3 ? sm.swordlast[b] : *wcw))
|
||||
sm.swordtransit[b] = c2;
|
||||
if(S3 == 4)
|
||||
forCellEx(c2, c)
|
||||
if(c2 != comefrom && isNeighbor(c2, sm.swordlast[b]))
|
||||
sm.swordtransit[b] = c2;
|
||||
}
|
||||
}
|
||||
else {
|
||||
sm.swordnext[b] = sm.swordtransit[b] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
stalemate::moves.push_back(sm);
|
||||
|
||||
// dynamicval<eMonster> x7(stalemate::who, who);
|
||||
|
||||
bool b;
|
||||
if(who == moPlayer && c->wall == waBigStatue) {
|
||||
eWall w = comefrom->wall;
|
||||
c->wall = waNone;
|
||||
if(doesnotFall(comefrom)) comefrom->wall = waBigStatue;
|
||||
b = monstersnear2();
|
||||
comefrom->wall = w;
|
||||
c->wall = waBigStatue;
|
||||
}
|
||||
else if(who == moPlayer && isPushable(c->wall)) {
|
||||
eWall w = c->wall;
|
||||
c->wall = waNone;
|
||||
b = monstersnear2();
|
||||
c->wall = w;
|
||||
}
|
||||
else {
|
||||
b = monstersnear2();
|
||||
}
|
||||
stalemate::moves.pop_back();
|
||||
/** like monstersnear but add the potential moves of other players into account */
|
||||
EX bool monstersnear_add_pmi(player_move_info pmi0) {
|
||||
pmi.push_back(pmi0);
|
||||
bool b = monstersnear_aux();
|
||||
pmi.pop_back();
|
||||
return b;
|
||||
}
|
||||
|
||||
EX namespace stalemate {
|
||||
EX vector<stalemate1> moves;
|
||||
EX bool nextturn;
|
||||
|
||||
EX bool isMoveto(cell *c) {
|
||||
for(int i=0; i<isize(moves); i++) if(moves[i].moveto == c) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
EX bool isPushto(cell *c) {
|
||||
for(int i=0; i<isize(moves); i++) if(moves[i].pushto == c) return true;
|
||||
return false;
|
||||
}
|
||||
EX }
|
||||
|
||||
EX bool onboat(stalemate1& sm) {
|
||||
cell *c = sm.moveto;
|
||||
cell *cf = sm.comefrom;
|
||||
return (c->wall == waBoat) || (cf->wall == waBoat && c->wall == waSea);
|
||||
}
|
||||
|
||||
EX bool multimove() {
|
||||
if(multi::cpid == 0) lastkills = tkills();
|
||||
if(!multi::playerActive(multi::cpid)) return !monstersnear2();
|
||||
if(!multi::playerActive(multi::cpid)) return !monstersnear_aux();
|
||||
cellwalker bcwt = cwt;
|
||||
cwt = multi::player[multi::cpid];
|
||||
bool b = movepcto(multi::whereto[multi::cpid]);
|
||||
@ -293,11 +244,11 @@ EX namespace multi {
|
||||
EX bool aftermove;
|
||||
EX }
|
||||
|
||||
EX bool swordConflict(const stalemate1& sm1, const stalemate1& sm2) {
|
||||
EX bool swordConflict(const player_move_info& sm1, const player_move_info& sm2) {
|
||||
if(items[itOrbSword] || items[itOrbSword2])
|
||||
for(int b=0; b<2; b++)
|
||||
if(sm1.comefrom == sm2.swordlast[b] || sm1.comefrom == sm2.swordtransit[b] || sm1.comefrom == sm2.swordnext[b])
|
||||
if(sm1.moveto == sm2.swordlast[b] || sm1.moveto == sm2.swordtransit[b] || sm1.moveto == sm2.swordnext[b])
|
||||
if(sm1.mi.s == sm2.swordlast[b] || sm1.mi.s == sm2.swordtransit[b] || sm1.mi.s == sm2.swordnext[b])
|
||||
if(sm1.mi.t == sm2.swordlast[b] || sm1.mi.t == sm2.swordtransit[b] || sm1.mi.t == sm2.swordnext[b])
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
11
complex.cpp
11
complex.cpp
@ -2867,10 +2867,13 @@ EX namespace sword {
|
||||
}
|
||||
|
||||
// from c1 to c2
|
||||
EX sworddir shift(cell *c1, cell *c2, sworddir d) {
|
||||
if(!c1 || !c2) return d;
|
||||
int s1 = neighborId(c1, c2);
|
||||
int s2 = neighborId(c2, c1);
|
||||
EX sworddir shift(movei mi, sworddir d) {
|
||||
cell *c1 = mi.s;
|
||||
cell *c2 = mi.t;
|
||||
if(!mi.proper()) return d;
|
||||
int s1 = mi.d;
|
||||
int s2 = mi.rev_dir();
|
||||
neighborId(c2, c1);
|
||||
if(s1 < 0 || s2 < 0) return d;
|
||||
if(SWORDDIM == 2) {
|
||||
int sub = (hybri) ? 2 : 0;
|
||||
|
2
game.cpp
2
game.cpp
@ -182,7 +182,7 @@ EX bool activateRecall() {
|
||||
|
||||
killFriendlyIvy();
|
||||
movecost(cwt.at, recallCell.at, 3);
|
||||
playerMoveEffects(cwt.at, recallCell.at);
|
||||
playerMoveEffects(movei(cwt.at, recallCell.at, TELEPORT));
|
||||
mirror::destroyAll();
|
||||
|
||||
sword::reset();
|
||||
|
@ -313,6 +313,8 @@ EX void dropGreenStone(cell *c) {
|
||||
return;
|
||||
}
|
||||
if(items[itGreenStone] && c->item == itNone) {
|
||||
changes.ccell(c);
|
||||
changes.value_keep(items[itGreenStone]);
|
||||
items[itGreenStone]--;
|
||||
if(false) {
|
||||
c->item = itNone;
|
||||
|
@ -459,6 +459,7 @@ constexpr int FALL = 98;
|
||||
constexpr int NO_SPACE = 97;
|
||||
constexpr int TELEPORT = 96;
|
||||
constexpr int JUMP = 95;
|
||||
constexpr int STAY = 94;
|
||||
|
||||
namespace whirlwind { cell *jumpDestination(cell*); }
|
||||
|
||||
|
@ -108,6 +108,8 @@ EX void moveMonster(const movei& mi) {
|
||||
auto& cf = mi.s;
|
||||
auto& ct = mi.t;
|
||||
eMonster m = cf->monst;
|
||||
changes.ccell(cf);
|
||||
changes.ccell(ct);
|
||||
bool fri = isFriendly(cf);
|
||||
if(isDragon(m)) {
|
||||
printf("called for Dragon\n");
|
||||
@ -117,6 +119,7 @@ EX void moveMonster(const movei& mi) {
|
||||
// the following line is necessary because otherwise plates disappear only inside the sight range
|
||||
if(cellUnstable(cf) && !ignoresPlates(m)) {
|
||||
fallingFloorAnimation(cf);
|
||||
changes.ccell(cf);
|
||||
cf->wall = waChasm;
|
||||
}
|
||||
moveEffect(mi, m);
|
||||
@ -124,6 +127,7 @@ EX void moveMonster(const movei& mi) {
|
||||
(m == moShark || m == moCShark || m == moGreaterShark))
|
||||
achievement_gain_once("MOATSHARK");
|
||||
if(m == moTentacleGhost) {
|
||||
changes.ccell(cf);
|
||||
cf->monst = moTentacletail;
|
||||
m = moGhost;
|
||||
}
|
||||
@ -156,10 +160,11 @@ EX void moveMonster(const movei& mi) {
|
||||
}
|
||||
}
|
||||
|
||||
if(fri || isBug(m) || items[itOrbDiscord]) stabbingAttack(cf, ct, m);
|
||||
if(fri || isBug(m) || items[itOrbDiscord]) stabbingAttack(mi, m);
|
||||
|
||||
if(mi.d == JUMP && m == moVaulter) {
|
||||
cell *cm = common_neighbor(cf, ct);
|
||||
changes.ccell(cm);
|
||||
if(cm->wall == waShrub) cm->wall = waNone;
|
||||
if(cm->wall == waSmallTree) cm->wall = waNone;
|
||||
if(cm->wall == waBigTree) cm->wall = waSmallTree;
|
||||
@ -1518,7 +1523,10 @@ EX int stayvalue(eMonster m, cell *c) {
|
||||
}
|
||||
|
||||
/** for an ally m at c, evaluate moving to c2 */
|
||||
EX int movevalue(eMonster m, cell *c, cell *c2, flagtype flags) {
|
||||
EX int movevalue(eMonster m, cell *c, int dir, flagtype flags) {
|
||||
|
||||
auto mi = movei(c, dir);
|
||||
auto& c2 = mi.t;
|
||||
int val = 0;
|
||||
|
||||
if(isPlayerOn(c2)) val = -3000;
|
||||
@ -1537,7 +1545,6 @@ EX int movevalue(eMonster m, cell *c, cell *c2, flagtype flags) {
|
||||
isInactiveEnemy(c2,m) ? 1000 :
|
||||
-500;
|
||||
|
||||
else if(monstersnear(c2, m, NULL, c)) val = 50; // linked with mouse suicide!
|
||||
else if(passable_for(m, c2, c, 0)) {
|
||||
#if CAP_COMPLEX2
|
||||
if(mine::marked_mine(c2) && !ignoresPlates(m))
|
||||
@ -1545,6 +1552,12 @@ EX int movevalue(eMonster m, cell *c, cell *c2, flagtype flags) {
|
||||
else
|
||||
#endif
|
||||
val = 4000;
|
||||
|
||||
changes.init(true);
|
||||
moveMonster(mi);
|
||||
bool b = monstersnear(mi.t, m);
|
||||
changes.rollback();
|
||||
if(b) val = 50;
|
||||
}
|
||||
else if(passable_for(m, c2, c, P_DEADLY)) val = -1100;
|
||||
else val = -1750;
|
||||
@ -1636,8 +1649,7 @@ EX void movegolems(flagtype flags) {
|
||||
|
||||
DEBB(DF_TURN, ("moveval"));
|
||||
for(int k=0; k<c->type; k++) if(c->move(k)) {
|
||||
cell *c2 = c->move(k);
|
||||
int val = movevalue(m, c, c2, flags);
|
||||
int val = movevalue(m, c, k, flags);
|
||||
|
||||
if(val > bestv) bestv = val, bdirs.clear();
|
||||
if(val == bestv) bdirs.push_back(k);
|
||||
@ -1646,7 +1658,7 @@ EX void movegolems(flagtype flags) {
|
||||
if(m == moTameBomberbird) {
|
||||
cell *c2 = whirlwind::jumpDestination(c);
|
||||
if(c2 && !c2->monst) {
|
||||
int val = movevalue(m, c, c2, flags);
|
||||
int val = movevalue(m, c, STRONGWIND, flags);
|
||||
// printf("val = %d bestv = %d\n",
|
||||
if(val > bestv) bestv = val, bdirs.clear();
|
||||
if(val == bestv) bdirs.push_back(STRONGWIND);
|
||||
|
23
orbs.cpp
23
orbs.cpp
@ -567,8 +567,8 @@ EX void teleportTo(cell *dest) {
|
||||
if(b) {
|
||||
killFriendlyIvy();
|
||||
drainOrb(itOrbTeleport);
|
||||
movecost(cwt.at, dest, 3);
|
||||
playerMoveEffects(cwt.at, dest);
|
||||
movecost(cwt.at, dest, 3);
|
||||
playerMoveEffects(movei(cwt.at, dest, TELEPORT));
|
||||
afterplayermoved();
|
||||
bfs();
|
||||
}
|
||||
@ -580,7 +580,7 @@ EX void teleportTo(cell *dest) {
|
||||
killFriendlyIvy();
|
||||
cell *from = cwt.at;
|
||||
movecost(from, dest, 1);
|
||||
playerMoveEffects(cwt.at, dest);
|
||||
playerMoveEffects(movei(cwt.at, dest, TELEPORT));
|
||||
current_display->which_copy = unshift(ggmatrix(dest));
|
||||
cwt.at = dest; cwt.spin = hrand(dest->type); flipplayer = !!(hrand(2));
|
||||
drainOrb(itOrbTeleport);
|
||||
@ -638,8 +638,9 @@ EX bool jumpTo(orbAction a, cell *dest, eItem byWhat, int bonuskill IS(0), eMons
|
||||
}
|
||||
|
||||
sword::reset();
|
||||
stabbingAttack(c1, dest, moPlayer, bonuskill);
|
||||
playerMoveEffects(c1, dest);
|
||||
auto mi = movei(c1, dest, JUMP);
|
||||
stabbingAttack(mi, moPlayer, bonuskill);
|
||||
playerMoveEffects(mi);
|
||||
|
||||
if(itemclass(byWhat) == IC_ORB)
|
||||
apply_impact(dest);
|
||||
@ -658,7 +659,7 @@ EX bool jumpTo(orbAction a, cell *dest, eItem byWhat, int bonuskill IS(0), eMons
|
||||
|
||||
mirror::destroyAll();
|
||||
|
||||
if(monstersnearO(a, dest, moPlayer, NULL, c1)) {
|
||||
if(monstersnearO(a, dest)) {
|
||||
changes.rollback();
|
||||
return false;
|
||||
}
|
||||
@ -939,7 +940,7 @@ bool gun_attack(orbAction a, cell *dest) {
|
||||
attackMonster(dest, AF_GUN, moNone);
|
||||
apply_impact(dest);
|
||||
|
||||
if(monstersnearO(a, cwt.at, moPlayer, NULL, cwt.at)) {
|
||||
if(monstersnearO(a, cwt.at)) {
|
||||
changes.rollback();
|
||||
return false;
|
||||
}
|
||||
@ -1068,13 +1069,13 @@ void useOrbOfDragon(cell *c) {
|
||||
checkmoveO();
|
||||
}
|
||||
|
||||
EX bool monstersnearO(orbAction a, cell *c, eMonster who, cell *pushto, cell *comefrom) {
|
||||
EX bool monstersnearO(orbAction a, cell *c) {
|
||||
// printf("[a = %d] ", a);
|
||||
if(shmup::on) return false;
|
||||
if(a == roCheck && multi::players > 1)
|
||||
return true;
|
||||
else if(a == roMultiCheck) return false;
|
||||
else return monstersnear(c, who, pushto, comefrom);
|
||||
else return monstersnear(c, moPlayer);
|
||||
}
|
||||
|
||||
EX bool isCheck(orbAction a) { return a == roCheck || a == roMultiCheck; }
|
||||
@ -1241,12 +1242,12 @@ EX eItem targetRangedOrb(cell *c, orbAction a) {
|
||||
|
||||
if(c->monst) {
|
||||
if(!canAttack(cf, moFriendlyIvy, c, c->monst, 0)) continue;
|
||||
if(monstersnear(cwt.at, moPlayer, NULL, cwt.at)) continue;
|
||||
if(monstersnear(cwt.at, moPlayer)) continue;
|
||||
}
|
||||
else {
|
||||
if(!passable(c, cf, P_ISPLAYER | P_MONSTER)) continue;
|
||||
if(strictlyAgainstGravity(c, cf, false, MF_IVY)) continue;
|
||||
if(monstersnear(cwt.at, moPlayer, c, cwt.at)) continue;
|
||||
if(monstersnear(cwt.at, moPlayer)) continue;
|
||||
}
|
||||
dirs.push_back(d);
|
||||
}
|
||||
|
93
pcmove.cpp
93
pcmove.cpp
@ -357,8 +357,8 @@ bool pcmove::swing() {
|
||||
sideAttack(cwt.at, d, moPlayer, 0);
|
||||
|
||||
mirror::act(origd, mirror::SPINMULTI | mirror::ATTACK);
|
||||
|
||||
if(monstersnear(cwt.at, moPlayer, nullptr, cwt.at)) {
|
||||
|
||||
if(monstersnear_add_pmi(movei(cwt.at, STAY))) {
|
||||
if(vmsg())
|
||||
wouldkill("You would be killed by %the1!");
|
||||
return false;
|
||||
@ -510,6 +510,11 @@ struct changes_t {
|
||||
void at_rollback(reaction_t act) {
|
||||
if(on) rollbacks.emplace_back(act);
|
||||
}
|
||||
|
||||
void push_push(cell *tgt) {
|
||||
pushes.push_back(tgt);
|
||||
rollbacks.push_back([] { pushes.pop_back(); });
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
@ -601,7 +606,7 @@ bool pcmove::actual_move() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(items[itOrbDomination] > ORBBASE && isMountable(c2->monst) && !monstersnear2() && fmsMove) {
|
||||
if(items[itOrbDomination] > ORBBASE && isMountable(c2->monst) && fmsMove) {
|
||||
if(checkonly) { nextmovetype = lmMove; return true; }
|
||||
if(!isMountable(cwt.at->monst)) dragon::target = NULL;
|
||||
movecost(cwt.at, c2, 3);
|
||||
@ -629,6 +634,7 @@ bool pcmove::actual_move() {
|
||||
addMessage(XLAT("You push %the1.", c2->wall));
|
||||
lastmovetype = lmPush; lastmove = cwt.at;
|
||||
pushThumper(mip);
|
||||
changes.push_push(mip.t);
|
||||
return perform_actual_move();
|
||||
}
|
||||
|
||||
@ -646,8 +652,6 @@ bool pcmove::actual_move() {
|
||||
|
||||
if(!c2->monst && cwt.at->wall == waBoat && cwt.at->item != itOrbYendor && boatGoesThrough(c2) && markOrb(itOrbWater) && !nonAdjacentPlayer(c2, cwt.at) && fmsMove) {
|
||||
|
||||
if(havePushConflict(cwt.at, checkonly)) return false;
|
||||
|
||||
if(c2->item && !cwt.at->item) moveItem(c2, cwt.at, false), boatmove = true;
|
||||
placeWater(c2, cwt.at);
|
||||
moveBoat(mi);
|
||||
@ -663,7 +667,6 @@ bool pcmove::actual_move() {
|
||||
bool pcmove::boat_move() {
|
||||
|
||||
cell *& c2 = mi.t;
|
||||
if(havePushConflict(cwt.at, checkonly)) return false;
|
||||
|
||||
if(againstWind(c2, cwt.at)) {
|
||||
if(vmsg()) addMessage(XLAT(airdist(c2) < 3 ? "The Air Elemental blows you away!" : "You cannot go against the wind!"));
|
||||
@ -744,8 +747,6 @@ bool pcmove::after_escape() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(havePushConflict(cwt.at, checkonly)) return false;
|
||||
|
||||
changes.ccell(c2);
|
||||
changes.ccell(cwt.at);
|
||||
|
||||
@ -849,7 +850,7 @@ bool pcmove::move_if_okay() {
|
||||
|
||||
if(switchplace_prevent(cwt.at, c2, checkonly))
|
||||
return false;
|
||||
if(!checkonly && warningprotection_hit(do_we_stab_a_friend(cwt.at, c2, moPlayer)))
|
||||
if(!checkonly && warningprotection_hit(do_we_stab_a_friend(mi, moPlayer)))
|
||||
return false;
|
||||
|
||||
nextmovetype = lmMove;
|
||||
@ -899,7 +900,7 @@ bool pcmove::attack() {
|
||||
|
||||
if(!ca) {
|
||||
if(forcedmovetype == fmAttack) {
|
||||
if(monstersnear(cwt.at,moPlayer,NULL,cwt.at)) {
|
||||
if(monstersnear_add_pmi(movei(cwt.at, STAY))) {
|
||||
if(vmsg()) wouldkill("%The1 would get you!");
|
||||
return false;
|
||||
}
|
||||
@ -922,10 +923,9 @@ bool pcmove::attack() {
|
||||
else
|
||||
mip.t = c2;
|
||||
if(mip.t) changes.ccell(mip.t);
|
||||
changes.push_push(mip.t);
|
||||
}
|
||||
|
||||
if(havePushConflict(mip.t, checkonly)) return false;
|
||||
|
||||
if(!(isWatery(cwt.at) && c2->monst == moWaterElemental) && checkNeedMove(checkonly, true))
|
||||
return false;
|
||||
|
||||
@ -982,7 +982,7 @@ bool pcmove::attack() {
|
||||
lastmovetype = lmAttack; lastmove = c2;
|
||||
swordAttackStatic();
|
||||
|
||||
if(monstersnear(cwt.at, moPlayer, nullptr, cwt.at)) {
|
||||
if(monstersnear_add_pmi(movei(cwt.at, STAY))) {
|
||||
if(vmsg()) wouldkill("You would be killed by %the1!");
|
||||
return false;
|
||||
}
|
||||
@ -1090,18 +1090,18 @@ bool pcmove::perform_move_or_jump() {
|
||||
lastmovetype = lmMove; lastmove = cwt.at;
|
||||
apply_chaos();
|
||||
|
||||
stabbingAttack(cwt.at, mi.t, moPlayer);
|
||||
cell *c1 = cwt.at;
|
||||
stabbingAttack(mi, moPlayer);
|
||||
changes.value_keep(cwt);
|
||||
cwt += wstep;
|
||||
|
||||
mirror::act(origd, mirror::SPINMULTI | mirror::ATTACK | mirror::GO);
|
||||
|
||||
playerMoveEffects(c1, mi.t);
|
||||
|
||||
auto pmi = player_move_info(mi);
|
||||
playerMoveEffects(mi);
|
||||
|
||||
if(mi.t->monst == moFriendlyIvy) changes.ccell(mi.t), mi.t->monst = moNone;
|
||||
|
||||
if(monstersnear(cwt.at, moPlayer, nullptr, c1)) {
|
||||
if(monstersnear_add_pmi(pmi)) {
|
||||
if(vmsg()) wouldkill("%The1 would kill you there!");
|
||||
return false;
|
||||
}
|
||||
@ -1135,19 +1135,21 @@ bool pcmove::stay() {
|
||||
return false;
|
||||
swordAttackStatic();
|
||||
nextmovetype = lmSkip;
|
||||
if(monstersnear(cwt.at, moPlayer, nullptr, cwt.at)) {
|
||||
|
||||
mi = movei(cwt.at, STAY);
|
||||
if(last_gravity_state && !gravity_state)
|
||||
playerMoveEffects(mi);
|
||||
if(d == -2)
|
||||
dropGreenStone(cwt.at);
|
||||
|
||||
if(monstersnear_add_pmi(mi)) {
|
||||
if(vmsg()) wouldkill("%The1 would get you!");
|
||||
return false;
|
||||
}
|
||||
if(checkonly) return true;
|
||||
if(changes.on) changes.commit();
|
||||
if(d == -2)
|
||||
dropGreenStone(cwt.at);
|
||||
if(cellUnstable(cwt.at) && !markOrb(itOrbAether))
|
||||
doesFallSound(cwt.at);
|
||||
|
||||
if(last_gravity_state && !gravity_state)
|
||||
playerMoveEffects(cwt.at, cwt.at);
|
||||
doesFallSound(cwt.at);
|
||||
|
||||
return after_move();
|
||||
}
|
||||
@ -1246,12 +1248,14 @@ EX bool playerInPower() {
|
||||
return false;
|
||||
}
|
||||
|
||||
EX void playerMoveEffects(cell *c1, cell *c2) {
|
||||
EX void playerMoveEffects(movei mi) {
|
||||
cell *c1 = mi.s;
|
||||
cell *c2 = mi.t;
|
||||
|
||||
if(peace::on) items[itOrbSword] = c2->land == laBurial ? 100 : 0;
|
||||
|
||||
changes.value_keep(sword::dir[multi::cpid]);
|
||||
sword::dir[multi::cpid] = sword::shift(c1, c2, sword::dir[multi::cpid]);
|
||||
sword::dir[multi::cpid] = sword::shift(mi, sword::dir[multi::cpid]);
|
||||
|
||||
destroyWeakBranch(c1, c2, moPlayer);
|
||||
|
||||
@ -1457,20 +1461,20 @@ EX void sideAttack(cell *mf, int dir, eMonster who, int bonuskill) {
|
||||
}
|
||||
}
|
||||
|
||||
EX eMonster do_we_stab_a_friend(cell *mf, cell *mt, eMonster who) {
|
||||
EX eMonster do_we_stab_a_friend(movei mi, eMonster who) {
|
||||
eMonster m = moNone;
|
||||
do_swords(mf, mt, who, [&] (cell *c, int bb) {
|
||||
if(!peace::on && canAttack(mt, who, c, c->monst, AF_SWORD) && c->monst && isFriendly(c)) m = c->monst;
|
||||
do_swords(mi, who, [&] (cell *c, int bb) {
|
||||
if(!peace::on && canAttack(mi.t, who, c, c->monst, AF_SWORD) && c->monst && isFriendly(c)) m = c->monst;
|
||||
});
|
||||
|
||||
for(int t=0; t<mf->type; t++) {
|
||||
cell *c = mf->move(t);
|
||||
for(int t=0; t<mi.s->type; t++) {
|
||||
cell *c = mi.s->move(t);
|
||||
if(!c) continue;
|
||||
|
||||
bool stabthere = false;
|
||||
if(logical_adjacent(mt, who, c)) stabthere = true;
|
||||
if(logical_adjacent(mi.t, who, c)) stabthere = true;
|
||||
|
||||
if(stabthere && canAttack(mt,who,c,c->monst,AF_STAB) && isFriendly(c))
|
||||
if(stabthere && canAttack(mi.t,who,c,c->monst,AF_STAB) && isFriendly(c))
|
||||
return c->monst;
|
||||
}
|
||||
|
||||
@ -1484,27 +1488,14 @@ EX void wouldkill(const char *msg) {
|
||||
addMessage(XLAT("Cannot move into the current location of another player!"));
|
||||
else if(who_kills_me == moAirball)
|
||||
addMessage(XLAT("Players cannot get that far away!"));
|
||||
else if(who_kills_me == moTongue)
|
||||
addMessage(XLAT("Cannot push into another player!"));
|
||||
else if(who_kills_me == moCrushball)
|
||||
addMessage(XLAT("Cannot push into the same location!"));
|
||||
else
|
||||
addMessage(XLAT(msg, who_kills_me));
|
||||
}
|
||||
|
||||
EX bool havePushConflict(cell *pushto, bool checkonly) {
|
||||
if(pushto && multi::activePlayers() > 1) {
|
||||
for(int i=0; i<multi::players; i++) if(i != multi::cpid && multi::playerActive(i))
|
||||
if(multi::origpos[i] == pushto || multi::origtarget[i] == pushto) {
|
||||
addMessage(XLAT("Cannot push into another player!"));
|
||||
return true;
|
||||
}
|
||||
for(int i=0; i<isize(stalemate::moves); i++) {
|
||||
if(pushto == stalemate::moves[i].pushto) {
|
||||
addMessage(XLAT("Cannot push into the same location!"));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
EX void movecost(cell* from, cell *to, int phase) {
|
||||
if(from->land == laPower && to->land != laPower && (phase & 1)) {
|
||||
int n=0;
|
||||
|
Loading…
Reference in New Issue
Block a user