1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2024-11-23 21:07:17 +00:00

Magnetic and Switch V1

This commit is contained in:
Zeno Rogue 2017-12-30 15:12:15 +01:00
parent 9948b09b69
commit d3e789bc93
9 changed files with 126 additions and 14 deletions

View File

@ -757,6 +757,10 @@ monstertype minf[motypes] = {
"are stunned for a longer time if you push them into lava, fire, or a solid obstacle."}, "are stunned for a longer time if you push them into lava, fire, or a solid obstacle."},
{ 'W', 0x202020, "Hunting Dog (regrouping)", { 'W', 0x202020, "Hunting Dog (regrouping)",
"When your plan has clearly failed, it is better to abandon it and go to a safe place, to have a chance of succeeding next time. This dog clearly knows this."}, "When your plan has clearly failed, it is better to abandon it and go to a safe place, to have a chance of succeeding next time. This dog clearly knows this."},
{ 'B', 0xC00000, "North Pole", NODESCYET},
{ 'B', 0x0000C0, "South Pole", NODESCYET},
{ '@', 0xC00000, "Switcher A", NODESCYET},
{ '@', 0x0000C0, "Switcher B", NODESCYET},
// shmup specials // shmup specials
{ '@', 0xC0C0C0, "Rogue", "In the Shoot'em Up mode, you are armed with thrown Knives."}, { '@', 0xC0C0C0, "Rogue", "In the Shoot'em Up mode, you are armed with thrown Knives."},
@ -1203,8 +1207,10 @@ itemtype iinf[ittypes] = {
"Does not affect multi-tile monsters."}, "Does not affect multi-tile monsters."},
{ '!', 0x80FF00, "Glowing Crystal", crystaldesc}, { '!', 0x80FF00, "Glowing Crystal", crystaldesc},
{ '!', 0x80FF80, "Snake Oil", NODESCYET}, { '!', 0x80FF80, "Snake Oil", NODESCYET},
{ '*', 0x80FF80, "Dock Treasure", NODESCYET}, { '*', 0x80FF80, "Sea Glass", NODESCYET},
{ '*', 0x80FF80, "Invix Treasure", NODESCYET}, { '*', 0x80FF80, "Invix Treasure", NODESCYET},
{ '*', 0x80FF80, "Monopole", NODESCYET},
{ '*', 0xFFFF80, "Junk", NODESCYET},
}; };
// --- wall types --- // --- wall types ---
@ -1571,7 +1577,9 @@ const landtype linf[landtypes] = {
{ 0x80FF00, "Crystal World", crystaldesc}, { 0x80FF00, "Crystal World", crystaldesc},
{ 0x306030, "Snake Nest", NODESCYET}, { 0x306030, "Snake Nest", NODESCYET},
{ 0x80FF00, "Docks", NODESCYET}, { 0x80FF00, "Docks", NODESCYET},
{ 0x306030, "Invisible", NODESCYET}, { 0x306030, "Invincible", NODESCYET},
{ 0x306030, "Magnetosphere", NODESCYET},
{ 0x306030, "Switch", NODESCYET},
}; };
struct landtacinfo { eLand l; int tries, multiplier; }; struct landtacinfo { eLand l; int tries, multiplier; };

View File

@ -1,4 +1,4 @@
static const int motypes = 152; static const int motypes = 156;
struct monstertype { struct monstertype {
char glyph; char glyph;
@ -52,6 +52,8 @@ enum eMonster {
moButterfly, moNarciss, moMirrorSpirit, moButterfly, moNarciss, moMirrorSpirit,
moHunterDog, moTerraWarrior, moJiangshi, moVoidBeast, moLavaWolf, moHunterGuard, moHunterDog, moTerraWarrior, moJiangshi, moVoidBeast, moLavaWolf, moHunterGuard,
moIceGolem, moSandBird, moSalamander, moHunterChanging, moIceGolem, moSandBird, moSalamander, moHunterChanging,
moNorthPole, moSouthPole,
moSwitch1, moSwitch2,
// shmup specials // shmup specials
moPlayer, moBullet, moFlailBullet, moFireball, moTongue, moAirball, moPlayer, moBullet, moFlailBullet, moFireball, moTongue, moAirball,
// temporary // temporary
@ -68,7 +70,7 @@ struct genderswitch_t {
#define NUM_GS 6 #define NUM_GS 6
static const int ittypes = 125; static const int ittypes = 127;
struct itemtype { struct itemtype {
char glyph; char glyph;
@ -113,7 +115,7 @@ enum eItem {
itLavaLily, itHunting, itBlizzard, itTerra, itLavaLily, itHunting, itBlizzard, itTerra,
itOrbSide1, itOrbSide2, itOrbSide3, itOrbSide1, itOrbSide2, itOrbSide3,
itOrbLava, itOrbMorph, itGlowCrystal, itSnake, itOrbLava, itOrbMorph, itGlowCrystal, itSnake,
itDock, itInvix itDock, itInvix, itMagnet, itSwitch
}; };
static const int walltypes = 107; static const int walltypes = 107;
@ -160,7 +162,7 @@ enum eWall { waNone, waIcewall, waBarrier, waFloorA, waFloorB, waCavewall, waCav
waDock, waBurningDock waDock, waBurningDock
}; };
static const int landtypes = 81; static const int landtypes = 83;
struct landtype { struct landtype {
int color; int color;
@ -186,7 +188,8 @@ enum eLand { laNone, laBarrier, laCrossroads, laDesert, laIce, laCaves, laJungle
laMirrorWall, laMirrored, laMirrorWall2, laMirrored2, laMirrorWall, laMirrored, laMirrorWall2, laMirrored2,
laMirrorOld, laMirrorOld,
laVolcano, laBlizzard, laHunting, laTerracotta, laMercuryRiver, laVolcano, laBlizzard, laHunting, laTerracotta, laMercuryRiver,
laDual, laSnakeNest, laDocks, laInvincible laDual, laSnakeNest, laDocks, laInvincible, laMagnetic,
laSwitch
}; };
enum eGeometry {gNormal, gEuclid, gSphere, gElliptic, gQuotient, gQuotient2, gTorus, gOctagon, g45, g46, g47, gSmallSphere, gTinySphere, gEuclidSquare, gGUARD}; enum eGeometry {gNormal, gEuclid, gSphere, gElliptic, gQuotient, gQuotient2, gTorus, gOctagon, g45, g46, g47, gSmallSphere, gTinySphere, gEuclidSquare, gGUARD};

View File

@ -276,7 +276,7 @@ int itemclass(eItem i) {
i == itGreenGrass || i == itBull || i == itGreenGrass || i == itBull ||
i == itLavaLily || i == itHunting || i == itLavaLily || i == itHunting ||
i == itBlizzard || i == itTerra || i == itGlowCrystal || i == itSnake || i == itBlizzard || i == itTerra || i == itGlowCrystal || i == itSnake ||
i == itDock || i == itInvix i == itDock || i == itInvix || i == itSwitch
) )
return IC_TREASURE; return IC_TREASURE;
if(i == itSavedPrincess || i == itStrongWind || i == itWarning) if(i == itSavedPrincess || i == itStrongWind || i == itWarning)
@ -385,7 +385,18 @@ bool normalMover(eMonster m) {
m == moHunterDog || m == moTerraWarrior || m == moJiangshi || m == moHunterDog || m == moTerraWarrior || m == moJiangshi ||
m == moLavaWolf || m == moSalamander || m == moLavaWolf || m == moSalamander ||
m == moHunterGuard || m == moHunterChanging || m == moHunterGuard || m == moHunterChanging ||
m == moIceGolem || slowMover(m); m == moIceGolem ||
m == moNorthPole || m == moSouthPole ||
m == moSwitch1 || m == moSwitch2 ||
slowMover(m);
}
bool isMagneticPole(eMonster m) {
return m == moNorthPole || m == moSouthPole;
}
bool isSwitch(eMonster m) {
return m == moSwitch1 || m == moSwitch2;
} }
// from-to // from-to
@ -494,6 +505,7 @@ bool isInactiveEnemy(cell *w, eMonster forwho) {
bool isActiveEnemy(cell *w, eMonster forwho) { bool isActiveEnemy(cell *w, eMonster forwho) {
if(((forwho == moPlayer) ? realstuntime(w) : realstuntime(w) > 1)) if(((forwho == moPlayer) ? realstuntime(w) : realstuntime(w) > 1))
return false; return false;
if(w->monst == passive_switch) return false;
if(w->monst == moNone) return false; if(w->monst == moNone) return false;
if(isFriendly(w)) return false; if(isFriendly(w)) return false;
if(isInactiveEnemy(w, forwho)) return false; if(isInactiveEnemy(w, forwho)) return false;

View File

@ -728,12 +728,28 @@ void moveBoatIfUsingOne(cell *to, cell *from) {
} }
} }
bool againstMagnet(cell *c1, cell *c2) { // (from, to)
if(!isMagneticPole(c1->monst))
return false;
forCellEx(c3, c2)
if(c3 != c1 && c3->monst == c1->monst)
return true;
forCellEx(c3, c1)
if(c3->monst != c1->monst && isMagneticPole(c3->monst))
if(!isNeighbor(c3, c2))
return true;
return false;
}
bool passable_for(eMonster m, cell *w, cell *from, flagtype extra) { bool passable_for(eMonster m, cell *w, cell *from, flagtype extra) {
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) {
return (isIcyLand(w) || w->land == laVolcano) && (isPlayerOn(w) || passable(w, from, extra)); return (isIcyLand(w) || w->land == laVolcano) && (isPlayerOn(w) || passable(w, from, extra));
} }
if(isMagneticPole(m) && w && from && againstMagnet(from, w))
return false;
if(m == passive_switch) return false;
if(normalMover(m) || isBug(m) || isDemon(m) || m == moHerdBull) { if(normalMover(m) || isBug(m) || isDemon(m) || m == moHerdBull) {
if((isWitch(m) || m == moEvilGolem) && w->land != laPower && w->land != laHalloween) if((isWitch(m) || m == moEvilGolem) && w->land != laPower && w->land != laHalloween)
return false; return false;
@ -866,6 +882,8 @@ bool canAttack(cell *c1, eMonster m1, cell *c2, eMonster m2, flagtype flags) {
// cannot eat worms // cannot eat worms
if((flags & AF_EAT) && isWorm(m2)) return false; if((flags & AF_EAT) && isWorm(m2)) return false;
if(m1 == passive_switch || m2 == passive_switch) return false;
if((flags & AF_GETPLAYER) && isPlayerOn(c2)) m2 = moPlayer; if((flags & AF_GETPLAYER) && isPlayerOn(c2)) m2 = moPlayer;
if(!m2) return false; if(!m2) return false;
@ -1095,6 +1113,10 @@ bool krakensafe(cell *c) {
(c->item == itOrbFish && c->wall == waBoat) || (c->item == itOrbFish && c->wall == waBoat) ||
(c->item == itOrbAether && c->wall == waBoat); (c->item == itOrbAether && c->wall == waBoat);
} }
eMonster active_switch() {
return eMonster(passive_switch ^ moSwitch1 ^ moSwitch2);
}
int monstersnear(stalemate1& sm) { int monstersnear(stalemate1& sm) {
@ -1102,6 +1124,10 @@ int monstersnear(stalemate1& sm) {
bool eaten = false; bool eaten = false;
if(hardcore && sm.who == moPlayer) return 0; if(hardcore && sm.who == moPlayer) return 0;
dynamicval<eMonster> sw(passive_switch, passive_switch);
if(sm.moveto->item && itemclass(sm.moveto->item) == IC_TREASURE)
passive_switch = active_switch();
int res = 0; int res = 0;
bool fast = false; bool fast = false;
@ -3201,7 +3227,7 @@ void makeTrollFootprints(cell *c) {
} }
void moveMonster(cell *ct, cell *cf) { void moveMonster(cell *ct, cell *cf) {
eMonster m = cf->monst; eMonster m = cf->monst;
bool fri = isFriendly(cf); bool fri = isFriendly(cf);
if(isDragon(m)) { if(isDragon(m)) {
printf("called for Dragon\n"); printf("called for Dragon\n");
@ -3232,6 +3258,14 @@ void moveMonster(cell *ct, cell *cf) {
ct->hitpoints = cf->hitpoints; ct->hitpoints = cf->hitpoints;
ct->stuntime = cf->stuntime; ct->stuntime = cf->stuntime;
if(isMagneticPole(m)) {
cell *other_pole = cf->mov[cf->mondir];
if(other_pole) {
ct->mondir = neighborId(ct, other_pole),
other_pole->mondir = neighborId(other_pole, ct);
}
}
if(fri || isBug(m) || items[itOrbDiscord]) stabbingAttack(cf, ct, m); if(fri || isBug(m) || items[itOrbDiscord]) stabbingAttack(cf, ct, m);
if(isLeader(m)) { if(isLeader(m)) {
@ -6787,7 +6821,10 @@ void terracotta() {
} }
} }
eMonster passive_switch;
void monstersTurn() { void monstersTurn() {
passive_switch = (gold() & 1) ? moSwitch1 : moSwitch2;
mirror::breakAll(); mirror::breakAll();
DEBT("bfs"); DEBT("bfs");
bfs(); bfs();

View File

@ -1212,6 +1212,13 @@ bool drawMonsterType(eMonster m, cell *where, const transmatrix& V, int col, dou
if(!peace::on) queuepoly(VBODY, shPSword, 0xFFFF00FF); if(!peace::on) queuepoly(VBODY, shPSword, 0xFFFF00FF);
queuepoly(VHEAD, shHood, 0xD0D000C0); queuepoly(VHEAD, shHood, 0xD0D000C0);
} }
else if(isSwitch(m)) {
otherbodyparts(V, darkena(col, 0, 0xC0), m, footphase);
ShadowV(V, shPBody);
queuepoly(VBODY, shPBody, darkena(col, 0, 0xC0));
if(!peace::on) queuepoly(VBODY, shPSword, 0xFFFF00FF);
queuepoly(VHEAD, shHood, darkena(col, 0, 0xFF));
}
else if(m == moPalace || m == moFatGuard || m == moVizier || m == moSkeleton) { else if(m == moPalace || m == moFatGuard || m == moVizier || m == moSkeleton) {
queuepoly(VBODY, shSabre, 0xFFFFFFFF); queuepoly(VBODY, shSabre, 0xFFFFFFFF);
if(m == moSkeleton) { if(m == moSkeleton) {
@ -1537,6 +1544,11 @@ bool drawMonsterType(eMonster m, cell *where, const transmatrix& V, int col, dou
if(xch == 'D') acol = 0xD0D0D0; if(xch == 'D') acol = 0xD0D0D0;
queuepoly(VHEAD, shDemon, darkena(acol, 0, 0xFF)); queuepoly(VHEAD, shDemon, darkena(acol, 0, 0xFF));
} }
else if(isMagneticPole(m)) {
if(m == moNorthPole)
queuepolyat(VBODY * spin(M_PI), shTentacle, 0x000000C0, PPR_TENTACLE1);
queuepolyat(VBODY, shDisk, darkena(col, 0, 0xFF), PPR_MONSTER_BODY);
}
else if(isMetalBeast(m)) { else if(isMetalBeast(m)) {
ShadowV(V, shTrylobite); ShadowV(V, shTrylobite);
if(!mmspatial) if(!mmspatial)
@ -1916,7 +1928,8 @@ bool drawMonster(const transmatrix& Vparam, int ct, cell *c, int col) {
// golems, knights, and hyperbugs don't face the player (mondir-controlled) // golems, knights, and hyperbugs don't face the player (mondir-controlled)
// also whatever in the lineview mode // also whatever in the lineview mode
else if(isFriendly(c) || isBug(c) || (c->monst && conformal::on) || c->monst == moKrakenH || (isBull(c->monst) && c->mondir != NODIR) || c->monst == moButterfly) { else if(isFriendly(c) || isBug(c) || (c->monst && conformal::on) || c->monst == moKrakenH || (isBull(c->monst) && c->mondir != NODIR) || c->monst == moButterfly || isMagneticPole(c->monst) ||
isSwitch(c->monst)) {
if(c->monst == moKrakenH) Vs = Vb, nospins = nospinb; if(c->monst == moKrakenH) Vs = Vb, nospins = nospinb;
if(!nospins) Vs = Vs * ddspin(c, c->mondir, S42); if(!nospins) Vs = Vs * ddspin(c, c->mondir, S42);
if(isFriendly(c)) drawPlayerEffects(Vs, c, false); if(isFriendly(c)) drawPlayerEffects(Vs, c, false);
@ -2573,6 +2586,9 @@ void setcolors(cell *c, int& wcol, int &fcol) {
if(c->bardir == NOBARRIERS && c->barleft) if(c->bardir == NOBARRIERS && c->barleft)
fcol = minf[moBug0+c->barright].color; fcol = minf[moBug0+c->barright].color;
break; break;
case laSwitch:
fcol = minf[passive_switch].color;
break;
case laTortoise: case laTortoise:
fcol = tortoise::getMatchColor(getBits(c)); fcol = tortoise::getMatchColor(getBits(c));
if(c->wall == waBigTree) wcol = 0x709000; if(c->wall == waBigTree) wcol = 0x709000;

View File

@ -2425,3 +2425,6 @@ extern bool need_mouseh;
extern int whateveri, whateveri2; extern int whateveri, whateveri2;
void clear_euland(eLand first); void clear_euland(eLand first);
extern eMonster passive_switch;

View File

@ -651,6 +651,15 @@ void giantLandSwitch(cell *c, int d, cell *from) {
} }
break; break;
case laSwitch:
ONEMPTY {
if(hrand(5000) < PT(100 + 2 * (kills[moSwitch1] + kills[moSwitch2]), 200) && notDippingFor(itSwitch))
c->item = itSwitch;
if(hrand(8000) < 40 + 5 * (items[itSwitch] + yendor::hardness()))
c->monst = hrand(2) ? moSwitch1 : moSwitch2;
}
break;
case laDragon: case laDragon:
if(d == 9) { if(d == 9) {
int cd = getCdata(c, 3); int cd = getCdata(c, 3);
@ -1876,6 +1885,23 @@ void giantLandSwitch(cell *c, int d, cell *from) {
} }
break; break;
case laMagnetic:
if(d == 8) {
if(hrand(10000) < 30 && !c->monst && !c->wall) {
cell *c1 = c;
cell *c2 = createMov(c1, hrand(c1->type));
if(c2->monst || c2->wall) return;
if(hrand(2)) swap(c1, c2);
forCellEx(c3, c1) if(c3->monst == moNorthPole) return;
forCellEx(c3, c2) if(c3->monst == moSouthPole) return;
c1->monst = moNorthPole;
c2->monst = moSouthPole;
c1->mondir = neighborId(c1, c2);
c2->mondir = neighborId(c2, c1);
}
}
break;
case laDocks: { case laDocks: {
if(d == 8) { if(d == 8) {
patterns::patterninfo si; patterns::patterninfo si;

View File

@ -208,6 +208,9 @@ int isNative(eLand l, eMonster m) {
case laDocks: case laDocks:
return among(m, moRatling, moPirate, moCShark, moAlbatross, moFireFairy) ? 2 : 0; return among(m, moRatling, moPirate, moCShark, moAlbatross, moFireFairy) ? 2 : 0;
case laSwitch:
return m == moSwitch1 || m == moSwitch2 ? 2 : 0;
} }
return false; return false;
} }
@ -303,6 +306,7 @@ eItem treasureType(eLand l) {
case laSnakeNest: return itSnake; case laSnakeNest: return itSnake;
case laDocks: return itDock; case laDocks: return itDock;
case laInvincible: return itInvix; case laInvincible: return itInvix;
case laSwitch: return itSwitch;
case laCA: return itNone; case laCA: return itNone;
} }
@ -535,6 +539,9 @@ bool landUnlocked(eLand l) {
case laDual: case laDual:
case laSnakeNest: case laSnakeNest:
return gold() >= R90; return gold() >= R90;
case laSwitch:
return gold() >= R90;
} }
return false; return false;
} }
@ -949,9 +956,9 @@ vector<eLand> land_over = {
laPrairie, laBull, laTerracotta, laRose, laPrairie, laBull, laTerracotta, laRose,
laElementalWall, laTrollheim, laElementalWall, laTrollheim,
laHell, laCrossroads3, laCocytus, laPower, laCrossroads4, laHell, laCrossroads3, laCocytus, laPower, laCrossroads4,
laCrossroads5, laCrossroads5,
// EXTRA // EXTRA
laWildWest, laHalloween, laDual, laSnakeNest, laDocks, laInvincible, laCA laWildWest, laHalloween, laDual, laSnakeNest, laDocks, laInvincible, laSwitch, laMagnetic, laCA
}; };
vector<eLand> landlist; vector<eLand> landlist;

View File

@ -772,7 +772,7 @@ void optimize(rugpoint *m, bool do_preset) {
if(do_preset) { if(do_preset) {
preset(m); preset(m);
int ed0 = size(preset_points); // int ed0 = size(preset_points);
for(auto& e: m->edges) if(e.target->valid) for(auto& e: m->edges) if(e.target->valid)
preset_points.emplace_back(e.len, e.target); preset_points.emplace_back(e.len, e.target);
if(gwhere >= gSphere) { if(gwhere >= gSphere) {