mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2024-11-23 21:07:17 +00:00
cleaned up jumping orbs; implemented Orb of Impact
This commit is contained in:
parent
99e64d862d
commit
b96eb32246
170
orbs.cpp
170
orbs.cpp
@ -156,6 +156,7 @@ EX void reduceOrbPowers() {
|
||||
reduceOrbPower(itOrbGravity, 120);
|
||||
reduceOrbPower(itOrbChoice, 120);
|
||||
reduceOrbPower(itOrbIntensity, 120);
|
||||
reduceOrbPower(itOrbImpact, 120);
|
||||
|
||||
reduceOrbPower(itOrbSide1, 120);
|
||||
reduceOrbPower(itOrbSide2, 120);
|
||||
@ -635,6 +636,9 @@ EX void jumpTo(cell *dest, eItem byWhat, int bonuskill IS(0), eMonster dashmon I
|
||||
|
||||
if(from) movecost(from, dest, 2);
|
||||
|
||||
if(itemclass(byWhat) == IC_ORB)
|
||||
apply_impact(dest);
|
||||
|
||||
createNoise(1);
|
||||
|
||||
if(shmup::on)
|
||||
@ -1014,6 +1018,11 @@ bool monstersnearO(orbAction a, cell *c, cell *nocount, eMonster who, cell *push
|
||||
else return monstersnear(c, nocount, who, pushto, comefrom);
|
||||
}
|
||||
|
||||
bool monstersnearOS(orbAction a, cell *c, cell *nocount, eMonster who, cell *pushto, cell *comefrom) {
|
||||
dynamicval<bool> b(used_impact, items[itOrbImpact]);
|
||||
return monstersnearO(a, c, nocount, who, pushto, comefrom);
|
||||
}
|
||||
|
||||
EX bool isCheck(orbAction a) { return a == roCheck || a == roMultiCheck; }
|
||||
EX bool isWeakCheck(orbAction a) { return a == roCheck || a == roMultiCheck || a == roMouse; }
|
||||
|
||||
@ -1028,6 +1037,73 @@ EX movei blowoff_destination(cell *c, int& di) {
|
||||
return movei(c, c, NO_SPACE);
|
||||
}
|
||||
|
||||
EX int check_jump(cell *cf, cell *ct, flagtype flags, cell*& jumpthru) {
|
||||
int partial = 1;
|
||||
forCellCM(c2, cf) {
|
||||
if(isNeighbor(c2, ct)) {
|
||||
jumpthru = c2;
|
||||
if(passable(c2, cf, flags | P_JUMP1)) {
|
||||
partial = 2;
|
||||
if(passable(ct, c2, flags | P_JUMP2)) {
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return partial;
|
||||
}
|
||||
|
||||
EX int check_phase(cell *cf, cell *ct, flagtype flags, cell*& jumpthru) {
|
||||
int partial = 1;
|
||||
forCellCM(c2, cf) {
|
||||
if(isNeighbor(c2, ct) && !nonAdjacent(cf, c2) && !nonAdjacent(c2, ct)) {
|
||||
jumpthru = c2;
|
||||
if(passable(ct, cf, P_ISPLAYER | P_PHASE)) {
|
||||
partial = 2;
|
||||
if(c2->monst || (isWall(c2) && c2->wall != waShrub)) {
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return partial;
|
||||
}
|
||||
|
||||
EX cell *common_neighbor(cell *cf, cell *ct) {
|
||||
forCellCM(cc, cf) {
|
||||
if(isNeighbor(cc, ct)) return cc;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EX void apply_impact(cell *c) {
|
||||
if(markOrb(itOrbImpact))
|
||||
forCellEx(c1, c) {
|
||||
if(!c1->monst) continue;
|
||||
if(isMultitile(c1->monst)) continue;
|
||||
addMessage(XLAT("You stun %the1!", c1->monst));
|
||||
c1->stuntime = min(c1->stuntime + 5, 7);
|
||||
checkStunKill(c1);
|
||||
}
|
||||
}
|
||||
|
||||
EX int check_vault(cell *cf, cell *ct, flagtype flags, cell*& jumpthru) {
|
||||
cell *c2 = NULL, *c3 = NULL;
|
||||
forCellCM(cc, cf) {
|
||||
if(isNeighbor(cc, ct)) c3 = c2, c2 = cc;
|
||||
}
|
||||
jumpthru = c2;
|
||||
if(!c2) return 0;
|
||||
if(!c2->monst && c2->wall != waShrub) return 1;
|
||||
bool for_monster = !(flags & P_ISPLAYER);
|
||||
if(for_monster && c2->monst && among(c2->monst, moFrog, moVaulter, moPhaser) && !items[itOrbDiscord]) return 1;
|
||||
if(c3) return 2;
|
||||
if(c2->wall != waShrub && !passable(c2, cwt.at, flags | P_JUMP1 | P_MONSTER)) return 3;
|
||||
if(!passable(ct, c2, flags | P_JUMP2)) return 4;
|
||||
if(c2->wall != waShrub && !canAttack(cwt.at, moPlayer, c2, c2->monst, 0)) return 5;
|
||||
return 6;
|
||||
}
|
||||
|
||||
EX eItem targetRangedOrb(cell *c, orbAction a) {
|
||||
|
||||
if(!haveRangedOrb()) {
|
||||
@ -1082,7 +1158,7 @@ EX eItem targetRangedOrb(cell *c, orbAction a) {
|
||||
// (0) telekinesis
|
||||
if(c->item && !itemHiddenFromSight(c) && !cwt.at->item && items[itOrbSpace] >= fixpower(spacedrain(c).first) && !cantGetGrimoire(c, !isCheck(a))
|
||||
&& c->item != itBarrow) {
|
||||
if(!isCheck(a)) telekinesis(c);
|
||||
if(!isCheck(a)) telekinesis(c), apply_impact(c);
|
||||
return itOrbSpace;
|
||||
}
|
||||
|
||||
@ -1096,7 +1172,7 @@ EX eItem targetRangedOrb(cell *c, orbAction a) {
|
||||
else if(isBoat(c) && !isWatery(c2) && c2->wall != waNone) nowhereToBlow = true;
|
||||
else if(c->wall == waBigStatue && !canPushStatueOn(c2)) nowhereToBlow = true;
|
||||
else {
|
||||
if(!isCheck(a)) blowoff(mi);
|
||||
if(!isCheck(a)) blowoff(mi), apply_impact(c);
|
||||
return itOrbAir;
|
||||
}
|
||||
}
|
||||
@ -1121,7 +1197,7 @@ EX eItem targetRangedOrb(cell *c, orbAction a) {
|
||||
|
||||
int di = hrand_elt(dirs, -1);
|
||||
if(di != -1) {
|
||||
if(!isCheck(a)) growIvyTo(movei(c, di).rev());
|
||||
if(!isCheck(a)) growIvyTo(movei(c, di).rev()), apply_impact(c);
|
||||
return itOrbNature;
|
||||
}
|
||||
}
|
||||
@ -1134,27 +1210,21 @@ EX eItem targetRangedOrb(cell *c, orbAction a) {
|
||||
if(!shmup::on && items[itOrbDash] && c->cpdist == 2) {
|
||||
int i = items[itOrbAether];
|
||||
if(i) items[itOrbAether] = i-1;
|
||||
cell *c2 = NULL, *c3 = NULL;
|
||||
for(int i=0; i<cwt.at->type; i++) {
|
||||
cell *cc = cwt.at->move(i);
|
||||
if(isNeighbor(cc, c)) c3 = c2, c2 = cc;
|
||||
}
|
||||
jumpthru = c2;
|
||||
jumpstate = 10;
|
||||
if(jumpstate == 10 && c2) jumpstate = 11;
|
||||
if(jumpstate == 11 && c2->monst) jumpstate = 12;
|
||||
if(jumpstate == 12 && !c3) jumpstate = 13;
|
||||
if(jumpstate == 13 && passable(c2, cwt.at, P_ISPLAYER | P_JUMP1 | P_MONSTER)) jumpstate = 14;
|
||||
if(jumpstate == 14 && passable(c, c2, P_ISPLAYER | P_JUMP2)) jumpstate = 15;
|
||||
if(jumpstate == 15 && canAttack(cwt.at, moPlayer, c2, c2->monst, 0)) jumpstate = 16;
|
||||
if(jumpstate == 16 && !monstersnearO(a, c, c2, moPlayer, NULL, cwt.at)) jumpstate = 17;
|
||||
jumpstate = 10 + check_vault(cwt.at, c, P_ISPLAYER, jumpthru);
|
||||
items[itOrbAether] = i;
|
||||
|
||||
if(jumpstate == 16 && !monstersnearOS(a, c, jumpthru, moPlayer, NULL, cwt.at)) jumpstate = 17;
|
||||
|
||||
if(jumpstate == 17) {
|
||||
if(!isCheck(a)) {
|
||||
int k = tkills();
|
||||
eMonster m = c2->monst;
|
||||
attackMonster(c2, AF_NORMAL | AF_MSG, moPlayer);
|
||||
eMonster m = jumpthru->monst;
|
||||
if(jumpthru->wall == waShrub) {
|
||||
addMessage(XLAT("You chop down the shrub."));
|
||||
jumpthru->wall = waNone;
|
||||
}
|
||||
if(m)
|
||||
attackMonster(jumpthru, AF_NORMAL | AF_MSG, moPlayer);
|
||||
k = tkills() - k;
|
||||
jumpTo(c, itOrbDash, k, m);
|
||||
}
|
||||
@ -1163,24 +1233,11 @@ EX eItem targetRangedOrb(cell *c, orbAction a) {
|
||||
}
|
||||
|
||||
if(items[itOrbFrog] && c->cpdist == 2) {
|
||||
jumpstate = 1;
|
||||
int i = items[itOrbAether];
|
||||
if(i) items[itOrbAether] = i-1;
|
||||
for(int i=0; i<cwt.at->type; i++) {
|
||||
cell *c2 = cwt.at->move(i);
|
||||
if(isNeighbor(c2, c)) {
|
||||
jumpthru = c2;
|
||||
if(passable(c2, cwt.at, P_ISPLAYER | P_JUMP1)) {
|
||||
jumpstate = 2;
|
||||
if(passable(c, c2, P_ISPLAYER | P_JUMP2)) {
|
||||
jumpstate = 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
jumpstate = check_jump(cwt.at, c, P_ISPLAYER, jumpthru);
|
||||
items[itOrbAether] = i;
|
||||
if(jumpstate == 3 && !monstersnearO(a, c, NULL, moPlayer, NULL, cwt.at)) {
|
||||
if(jumpstate == 3 && !monstersnearOS(a, c, NULL, moPlayer, NULL, cwt.at)) {
|
||||
jumpstate = 4;
|
||||
if(!isCheck(a)) jumpTo(c, itOrbFrog);
|
||||
return itOrbFrog;
|
||||
@ -1189,24 +1246,11 @@ EX eItem targetRangedOrb(cell *c, orbAction a) {
|
||||
|
||||
if(items[itOrbPhasing] && c->cpdist == 2) {
|
||||
if(shmup::on) shmup::pushmonsters();
|
||||
jumpstate = 21;
|
||||
int i = items[itOrbAether];
|
||||
if(i) items[itOrbAether] = i-1;
|
||||
for(int i=0; i<cwt.at->type; i++) {
|
||||
cell *c2 = cwt.at->move(i);
|
||||
if(isNeighbor(c2, c) && !nonAdjacent(cwt.at, c2) && !nonAdjacent(c2, c)) {
|
||||
jumpthru = c2;
|
||||
if(passable(c, cwt.at, P_ISPLAYER | P_PHASE)) {
|
||||
jumpstate = 22;
|
||||
if(c2->monst || isWall(c2)) {
|
||||
jumpstate = 23;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
jumpstate = 20 + check_phase(cwt.at, c, P_ISPLAYER, jumpthru);
|
||||
items[itOrbAether] = i;
|
||||
if(jumpstate == 23 && !monstersnearO(a, c, NULL, moPlayer, NULL, cwt.at)) {
|
||||
if(jumpstate == 23 && !monstersnearOS(a, c, NULL, moPlayer, NULL, cwt.at)) {
|
||||
jumpstate = 24;
|
||||
if(!isCheck(a)) jumpTo(c, itOrbPhasing);
|
||||
}
|
||||
@ -1216,20 +1260,20 @@ EX eItem targetRangedOrb(cell *c, orbAction a) {
|
||||
|
||||
// (1) switch with an illusion
|
||||
if(items[itOrbTeleport] && c->monst == moIllusion && !cwt.at->monst && teleportAction() == 1) {
|
||||
if(!isCheck(a)) teleportTo(c);
|
||||
if(!isCheck(a)) teleportTo(c), apply_impact(c);
|
||||
return itOrbTeleport;
|
||||
}
|
||||
|
||||
// (2) place illusion
|
||||
if(!shmup::on && items[itOrbIllusion] && c->monst == moNone && c->item == itNone && passable(c, NULL, P_MIRROR)) {
|
||||
if(!isCheck(a)) placeIllusion(c);
|
||||
if(!isCheck(a)) placeIllusion(c), apply_impact(c);
|
||||
return itOrbIllusion;
|
||||
}
|
||||
|
||||
// (3) teleport
|
||||
if(items[itOrbTeleport] && c->monst == moNone && (c->item == itNone || itemHidden(c)) &&
|
||||
passable(c, NULL, P_ISPLAYER | P_TELE) && teleportAction() && shmup::verifyTeleport()) {
|
||||
if(!isCheck(a)) teleportTo(c);
|
||||
if(!isCheck(a)) teleportTo(c), apply_impact(c);
|
||||
return itOrbTeleport;
|
||||
}
|
||||
|
||||
@ -1238,6 +1282,7 @@ EX eItem targetRangedOrb(cell *c, orbAction a) {
|
||||
if(!isCheck(a)) {
|
||||
addMessage(XLAT("You take the Illusion away."));
|
||||
items[itOrbIllusion] += 3; // 100% effective with the Orb of Energy!
|
||||
apply_impact(c);
|
||||
c->monst = moNone;
|
||||
}
|
||||
return itOrbIllusion;
|
||||
@ -1247,45 +1292,45 @@ EX eItem targetRangedOrb(cell *c, orbAction a) {
|
||||
if(!shmup::on && items[itRevolver] && c->monst && canAttack(cwt.at, moPlayer, c, c->monst, AF_GUN)) {
|
||||
bool inrange = false;
|
||||
for(cell *c1: gun_targets(cwt.at)) if(c1 == c) inrange = true;
|
||||
if(inrange && !monstersnearO(a, cwt.at, c, moPlayer, NULL, cwt.at)) {
|
||||
if(!isCheck(a)) gun_attack(c);
|
||||
if(inrange && !monstersnearOS(a, cwt.at, c, moPlayer, NULL, cwt.at)) {
|
||||
if(!isCheck(a)) gun_attack(c), apply_impact(c);
|
||||
return itRevolver;
|
||||
}
|
||||
}
|
||||
|
||||
// (5) psi blast (non-shmup variant)
|
||||
if(!shmup::on && items[itOrbPsi] && c->monst && (isDragon(c->monst) || !isWorm(c)) && c->monst != moShadow && c->monst != moKrakenH) {
|
||||
if(!isCheck(a)) psi_attack(c);
|
||||
if(!isCheck(a)) psi_attack(c), apply_impact(c);
|
||||
return itOrbPsi;
|
||||
}
|
||||
|
||||
// (5a) summoning
|
||||
if(items[itOrbSummon] && summonedAt(c)) {
|
||||
if(!isCheck(a)) summonAt(c);
|
||||
if(!isCheck(a)) summonAt(c), apply_impact(c);
|
||||
return itOrbSummon;
|
||||
}
|
||||
|
||||
// (5b) matter
|
||||
if(items[itOrbMatter] && tempWallPossibleAt(c)) {
|
||||
if(!isCheck(a)) tempWallAt(c);
|
||||
if(!isCheck(a)) tempWallAt(c), apply_impact(c);
|
||||
return itOrbMatter;
|
||||
}
|
||||
|
||||
// (5c) stun
|
||||
if(items[itOrbStunning] && c->monst && !isMultitile(c->monst) && c->stuntime < 3 && !shmup::on) {
|
||||
if(!isCheck(a)) stun_attack(c);
|
||||
if(!isCheck(a)) stun_attack(c), apply_impact(c);
|
||||
return itOrbStunning;
|
||||
}
|
||||
|
||||
// (5d) poly
|
||||
if(items[itOrbMorph] && c->monst && !isMultitile(c->monst) && !shmup::on) {
|
||||
if(!isCheck(a)) poly_attack(c);
|
||||
if(!isCheck(a)) poly_attack(c), apply_impact(c);
|
||||
return itOrbMorph;
|
||||
}
|
||||
|
||||
// (6) place fire (non-shmup variant)
|
||||
if(!shmup::on && items[itOrbDragon] && makeflame(c, 20, true)) {
|
||||
if(!isCheck(a)) useOrbOfDragon(c);
|
||||
if(!isCheck(a)) useOrbOfDragon(c), apply_impact(c);
|
||||
return itOrbDragon;
|
||||
}
|
||||
|
||||
@ -1447,7 +1492,10 @@ EX int orbcharges(eItem it) {
|
||||
case itOrbSide2:
|
||||
case itOrbSide3:
|
||||
return 50;
|
||||
|
||||
|
||||
case itOrbImpact:
|
||||
return 50;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user