1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2024-11-27 14:37:16 +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."},
{ '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."},
{ 'B', 0xC00000, "North Pole", NODESCYET},
{ 'B', 0x0000C0, "South Pole", NODESCYET},
{ '@', 0xC00000, "Switcher A", NODESCYET},
{ '@', 0x0000C0, "Switcher B", NODESCYET},
// shmup specials
{ '@', 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."},
{ '!', 0x80FF00, "Glowing Crystal", crystaldesc},
{ '!', 0x80FF80, "Snake Oil", NODESCYET},
{ '*', 0x80FF80, "Dock Treasure", NODESCYET},
{ '*', 0x80FF80, "Sea Glass", NODESCYET},
{ '*', 0x80FF80, "Invix Treasure", NODESCYET},
{ '*', 0x80FF80, "Monopole", NODESCYET},
{ '*', 0xFFFF80, "Junk", NODESCYET},
};
// --- wall types ---
@ -1571,7 +1577,9 @@ const landtype linf[landtypes] = {
{ 0x80FF00, "Crystal World", crystaldesc},
{ 0x306030, "Snake Nest", NODESCYET},
{ 0x80FF00, "Docks", NODESCYET},
{ 0x306030, "Invisible", NODESCYET},
{ 0x306030, "Invincible", NODESCYET},
{ 0x306030, "Magnetosphere", NODESCYET},
{ 0x306030, "Switch", NODESCYET},
};
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 {
char glyph;
@ -52,6 +52,8 @@ enum eMonster {
moButterfly, moNarciss, moMirrorSpirit,
moHunterDog, moTerraWarrior, moJiangshi, moVoidBeast, moLavaWolf, moHunterGuard,
moIceGolem, moSandBird, moSalamander, moHunterChanging,
moNorthPole, moSouthPole,
moSwitch1, moSwitch2,
// shmup specials
moPlayer, moBullet, moFlailBullet, moFireball, moTongue, moAirball,
// temporary
@ -68,7 +70,7 @@ struct genderswitch_t {
#define NUM_GS 6
static const int ittypes = 125;
static const int ittypes = 127;
struct itemtype {
char glyph;
@ -113,7 +115,7 @@ enum eItem {
itLavaLily, itHunting, itBlizzard, itTerra,
itOrbSide1, itOrbSide2, itOrbSide3,
itOrbLava, itOrbMorph, itGlowCrystal, itSnake,
itDock, itInvix
itDock, itInvix, itMagnet, itSwitch
};
static const int walltypes = 107;
@ -160,7 +162,7 @@ enum eWall { waNone, waIcewall, waBarrier, waFloorA, waFloorB, waCavewall, waCav
waDock, waBurningDock
};
static const int landtypes = 81;
static const int landtypes = 83;
struct landtype {
int color;
@ -186,7 +188,8 @@ enum eLand { laNone, laBarrier, laCrossroads, laDesert, laIce, laCaves, laJungle
laMirrorWall, laMirrored, laMirrorWall2, laMirrored2,
laMirrorOld,
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};

View File

@ -276,7 +276,7 @@ int itemclass(eItem i) {
i == itGreenGrass || i == itBull ||
i == itLavaLily || i == itHunting ||
i == itBlizzard || i == itTerra || i == itGlowCrystal || i == itSnake ||
i == itDock || i == itInvix
i == itDock || i == itInvix || i == itSwitch
)
return IC_TREASURE;
if(i == itSavedPrincess || i == itStrongWind || i == itWarning)
@ -385,7 +385,18 @@ bool normalMover(eMonster m) {
m == moHunterDog || m == moTerraWarrior || m == moJiangshi ||
m == moLavaWolf || m == moSalamander ||
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
@ -494,6 +505,7 @@ bool isInactiveEnemy(cell *w, eMonster forwho) {
bool isActiveEnemy(cell *w, eMonster forwho) {
if(((forwho == moPlayer) ? realstuntime(w) : realstuntime(w) > 1))
return false;
if(w->monst == passive_switch) return false;
if(w->monst == moNone) return false;
if(isFriendly(w)) 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) {
if(w->monst && !(extra & P_MONSTER) && !isPlayerOn(w))
return false;
if(m == moWolf) {
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((isWitch(m) || m == moEvilGolem) && w->land != laPower && w->land != laHalloween)
return false;
@ -866,6 +882,8 @@ bool canAttack(cell *c1, eMonster m1, cell *c2, eMonster m2, flagtype flags) {
// cannot eat worms
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(!m2) return false;
@ -1096,12 +1114,20 @@ bool krakensafe(cell *c) {
(c->item == itOrbAether && c->wall == waBoat);
}
eMonster active_switch() {
return eMonster(passive_switch ^ moSwitch1 ^ moSwitch2);
}
int monstersnear(stalemate1& sm) {
cell *c = sm.moveto;
bool eaten = false;
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;
bool fast = false;
@ -3232,6 +3258,14 @@ void moveMonster(cell *ct, cell *cf) {
ct->hitpoints = cf->hitpoints;
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(isLeader(m)) {
@ -6787,7 +6821,10 @@ void terracotta() {
}
}
eMonster passive_switch;
void monstersTurn() {
passive_switch = (gold() & 1) ? moSwitch1 : moSwitch2;
mirror::breakAll();
DEBT("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);
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) {
queuepoly(VBODY, shSabre, 0xFFFFFFFF);
if(m == moSkeleton) {
@ -1537,6 +1544,11 @@ bool drawMonsterType(eMonster m, cell *where, const transmatrix& V, int col, dou
if(xch == 'D') acol = 0xD0D0D0;
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)) {
ShadowV(V, shTrylobite);
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)
// 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(!nospins) Vs = Vs * ddspin(c, c->mondir, S42);
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)
fcol = minf[moBug0+c->barright].color;
break;
case laSwitch:
fcol = minf[passive_switch].color;
break;
case laTortoise:
fcol = tortoise::getMatchColor(getBits(c));
if(c->wall == waBigTree) wcol = 0x709000;

View File

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

View File

@ -651,6 +651,15 @@ void giantLandSwitch(cell *c, int d, cell *from) {
}
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:
if(d == 9) {
int cd = getCdata(c, 3);
@ -1876,6 +1885,23 @@ void giantLandSwitch(cell *c, int d, cell *from) {
}
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: {
if(d == 8) {
patterns::patterninfo si;

View File

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

View File

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