diff --git a/classes.cpp b/classes.cpp index 8149737c..c7ab5ee4 100644 --- a/classes.cpp +++ b/classes.cpp @@ -1211,6 +1211,9 @@ itemtype iinf[ittypes] = { { '*', 0x80FF80, "Invix Treasure", NODESCYET}, { '*', 0x80FF80, "Monopole", NODESCYET}, { '*', 0xFFFF80, "Junk", NODESCYET}, + { 'o', 0x80FF80, "Orb of Phasing", NODESCYET}, + { 'o', 0xFFFF80, "Orb of Magnetism", NODESCYET}, + { 'o', 0xFFFF80, "Orb of Destruction", NODESCYET}, }; // --- wall types --- diff --git a/classes.h b/classes.h index 6ea4950f..51119680 100644 --- a/classes.h +++ b/classes.h @@ -70,7 +70,7 @@ struct genderswitch_t { #define NUM_GS 6 -static const int ittypes = 127; +static const int ittypes = 130; struct itemtype { char glyph; @@ -115,7 +115,8 @@ enum eItem { itLavaLily, itHunting, itBlizzard, itTerra, itOrbSide1, itOrbSide2, itOrbSide3, itOrbLava, itOrbMorph, itGlowCrystal, itSnake, - itDock, itInvix, itMagnet, itSwitch + itDock, itInvix, itMagnet, itSwitch, + itOrbPhasing, itOrbMagnetism, itOrbDestruction }; static const int walltypes = 107; diff --git a/complex.cpp b/complex.cpp index dbb60a23..17074226 100644 --- a/complex.cpp +++ b/complex.cpp @@ -139,8 +139,7 @@ namespace whirlwind { animateMovement(whirlline[i+1], whirlline[i], LAYER_BOAT); } for(int i=0; iitem) - collectItem(whirlline[i], true); + pickupMovedItems(whirlline[i]); } void move() { @@ -985,6 +984,8 @@ namespace whirlpool { if(wfrom->item == itKey || wfrom->item == itOrbYendor) for(int i=0; itype; i++) createMov(wto, i); moveItem(wfrom, wto, false); + pickupMovedItems(wfrom); + pickupMovedItems(wto); } if(wto && !wfrom) @@ -2184,7 +2185,7 @@ void livecaves() { } if(c->aitmp < 0 && c->wall == waBoat) c->wall = waStrandedBoat; if(c->aitmp < 0 && c->wall == waSea) c->wall = waNone; - } + } } for(int i=0; i sw(passive_switch, passive_switch); if(sm.moveto->item && itemclass(sm.moveto->item) == IC_TREASURE) passive_switch = active_switch(); + if(items[itOrbMagnetism]) forCellEx(c2, sm.moveto) + if(canPickupItemWithMagnetism(c2, sm.comefrom) && itemclass(c2->item) == IC_TREASURE) + passive_switch = active_switch(); int res = 0; bool fast = false; @@ -3177,6 +3180,16 @@ void playerMoveEffects(cell *c1, cell *c2) { addMessage(XLAT("Better not to let your greed make you stray from your path.")); playSound(c2, "nervous"); } + + if(items[itOrbMagnetism]) + forCellEx(c3, c2) if(canPickupItemWithMagnetism(c3, c2)) { + if(c3->item == itCompass) { + if(!c2->item) + moveItem(c3, c2, false); + } + else if(markOrb(itOrbMagnetism)) + collectItem(c3, false); + } } void beastcrash(cell *c, cell *beast) { @@ -6292,12 +6305,33 @@ int ambush(cell *c, eItem what) { return dogs + dogs0; } +bool cannotPickupItem(cell *c, bool telekinesis) { + return itemHidden(c) && !telekinesis && !(isWatery(c) && markOrb(itOrbFish)); + } + +bool canPickupItemWithMagnetism(cell *c, cell *from) { + if(!c->item || c->item == itOrbYendor || isWall(c) || cannotPickupItem(c, false)) + return false; + if(c->item == itCompass && from->item) + return false; + return true; + } + +void pickupMovedItems(cell *c) { + if(!c->item) return; + if(isPlayerOn(c)) collectItem(c, true); + if(items[itOrbMagnetism]) + forCellEx(c2, c) + if(isPlayerOn(c2) && canPickupItemWithMagnetism(c, c2)) + collectItem(c, true); + } + bool collectItem(cell *c2, bool telekinesis) { int pg = gold(); bool dopickup = true; - if(itemHidden(c2) && !telekinesis && !(isWatery(c2) && markOrb(itOrbFish))) + if(cannotPickupItem(c2, telekinesis)) return false; /* if(c2->item == itHolyGrail && telekinesis) @@ -6823,8 +6857,12 @@ void terracotta() { eMonster passive_switch; -void monstersTurn() { +void checkSwitch() { passive_switch = (gold() & 1) ? moSwitch1 : moSwitch2; + } + +void monstersTurn() { + checkSwitch(); mirror::breakAll(); DEBT("bfs"); bfs(); @@ -7099,7 +7137,7 @@ bool movepcto(int d, int subdir, bool checkonly) { } if(againstCurrent(c2, cwt.c) && !markOrb(itOrbWater)) { - if(markOrb(itOrbFish)) goto escape; + if(markOrb(itOrbFish) || markOrb(itOrbAether)) goto escape; if(!checkonly) addMessage(XLAT("You cannot go against the current!")); return false; diff --git a/hyper.h b/hyper.h index a55bba97..5f56521b 100644 --- a/hyper.h +++ b/hyper.h @@ -823,6 +823,7 @@ void setGLProjection(); #define P_CLIMBDOWN Flag(30) // allow climbing down #define P_REPTILE Flag(31) // is reptile #define P_VOID Flag(32) // void beast +#define P_PHASE Flag(33) // phasing movement bool passable(cell *w, cell *from, flagtype flags); @@ -2430,3 +2431,6 @@ void clear_euland(eLand first); extern eMonster passive_switch; +bool cannotPickupItem(cell *c, bool telekinesis); +bool canPickupItemWithMagnetism(cell *c, cell *from); +void pickupMovedItems(cell *c); diff --git a/inventory.cpp b/inventory.cpp index ca85eef6..b54b9fca 100644 --- a/inventory.cpp +++ b/inventory.cpp @@ -329,6 +329,9 @@ namespace inv { for(auto& it: lateextraorbs) gainLate(it.treasure, it.orb); gainOrbs(itGlowCrystal, itOrbSide2); + gainOrbs(itSwitch, itOrbPhasing); + gainOrbs(itMagnet, itOrbMagnetism); + gainOrbs(itInvix, itOrbDestruction); if(items[itOrbLove] && !items[itSavedPrincess]) items[itSavedPrincess] = 1; diff --git a/orbgen.cpp b/orbgen.cpp index 3c270061..a83df713 100644 --- a/orbgen.cpp +++ b/orbgen.cpp @@ -1,4 +1,4 @@ -#define ORBLINES 66 +#define ORBLINES 70 // orbgen flags @@ -111,6 +111,10 @@ const orbinfo orbinfos[ORBLINES] = { {orbgenflags::S_GUEST, laDocks, 3000, 0, itOrbFish}, {orbgenflags::S_GUEST, laDocks, 3000, 0, itOrbDragon}, {orbgenflags::S_GUEST, laDocks, 3000, 0, itOrbDash}, + {orbgenflags::S_GUEST, laSwitch, 2000, 0, itOrbSpace}, + {orbgenflags::S_NATIVE, laSwitch, 2000, 3000, itOrbPhasing}, + {orbgenflags::S_NATIVE, laMagnetic, 2000, 3000, itOrbMagnetism}, + {orbgenflags::S_NATIVE, laInvincible, 2000, 3000, itOrbDestruction}, {orbgenflags::S_NATIVE, laWhirlpool, 0, 2000, itOrbWater}, // needs to be last }; diff --git a/orbs.cpp b/orbs.cpp index 7befe526..058df6c3 100644 --- a/orbs.cpp +++ b/orbs.cpp @@ -593,6 +593,11 @@ void jumpTo(cell *dest, eItem byWhat, int bonuskill = 0, eMonster dashmon = moNo addMessage(XLAT("You vault over %the1!", dashmon)); } + if(byWhat == itOrbPhasing) { + useupOrb(itOrbPhasing, 5); + addMessage(XLAT("You jump!")); + } + mirror::destroyAll(); for(int i=9; i>=0; i--) @@ -619,9 +624,16 @@ void growIvyTo(cell *dest, cell *src) { monstersTurn(); } +pair spacedrain(cell *c) { + int d = c->cpdist; + bool usemagnet = items[itOrbMagnetism] && d > 0; + if(usemagnet) d--; + return {d * d, usemagnet}; + } + void telekinesis(cell *dest) { - - int cost = dest->cpdist * dest->cpdist; + + auto cost = spacedrain(dest); if(dest->land == laAlchemist && isAlchAny(dest) && isAlchAny(cwt.c)) dest->wall = cwt.c->wall; @@ -642,9 +654,12 @@ void telekinesis(cell *dest) { moveItem(dest, cwt.c, true); collectItem(cwt.c, true); - useupOrb(itOrbSpace, cost); + useupOrb(itOrbSpace, cost.first); + if(cost.second) + markOrb(itOrbMagnetism); createNoise(3); + checkSwitch(); bfs(); if(!shmup::on) checkmoveO(); } @@ -984,7 +999,7 @@ eItem targetRangedOrb(cell *c, orbAction a) { } // (0) telekinesis - if(c->item && !itemHiddenFromSight(c) && !cwt.c->item && items[itOrbSpace] >= fixpower(c->cpdist * c->cpdist) && !cantGetGrimoire(c, !isCheck(a)) + if(c->item && !itemHiddenFromSight(c) && !cwt.c->item && items[itOrbSpace] >= fixpower(spacedrain(c).first) && !cantGetGrimoire(c, !isCheck(a)) && c->item != itBarrow) { if(!isCheck(a)) telekinesis(c); return itOrbSpace; @@ -1091,6 +1106,31 @@ eItem targetRangedOrb(cell *c, orbAction a) { } } + if(items[itOrbPhasing] && c->cpdist == 2) { + jumpstate = 21; + int i = items[itOrbAether]; + if(i) items[itOrbAether] = i-1; + for(int i=0; itype; i++) { + cell *c2 = cwt.c->mov[i]; + if(isNeighbor(c2, c) && !nonAdjacent(cwt.c, c2) && !nonAdjacent(c2, c)) { + jumpthru = c2; + if(passable(c, cwt.c, P_ISPLAYER | P_PHASE)) { + jumpstate = 22; + if(c2->monst || isWall(c2)) { + jumpstate = 23; + break; + } + } + } + } + items[itOrbAether] = i; + if(jumpstate == 23 && !monstersnearO(a, c, NULL, moPlayer, NULL, cwt.c)) { + jumpstate = 24; + if(!isCheck(a)) jumpTo(c, itOrbPhasing); + return itOrbPhasing; + } + } + // (1) switch with an illusion if(items[itOrbTeleport] && c->monst == moIllusion && !cwt.c->monst && teleportAction() == 1) { if(!isCheck(a)) teleportTo(c);