mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2024-11-27 14:37:16 +00:00
newlands:: implemented new Orbs: Gravity, Intensity, Choice
This commit is contained in:
parent
9d82cea995
commit
2bc66342dd
@ -1245,7 +1245,12 @@ itemtype iinf[ittypes] = {
|
||||
"Tasty cookie."
|
||||
},
|
||||
{ '*', 0x20C0C0, "West Treasure", NODESCYET},
|
||||
{ '*', 0xC020C0, "Variant Treasure", NODESCYET}
|
||||
{ '*', 0xC020C0, "Variant Treasure", NODESCYET},
|
||||
|
||||
{ 'o', 0x703800, "Orb of Intensity", NODESCYET},
|
||||
{ 'o', 0x80D080, "Orb of Gravity", NODESCYET},
|
||||
{ 'o', 0xD08080, "Orb of Choice", NODESCYET},
|
||||
|
||||
// { '*', 0x26619C, "Lapis Lazuli", NODESCYET},
|
||||
};
|
||||
|
||||
|
@ -84,7 +84,7 @@ struct genderswitch_t {
|
||||
|
||||
#define NUM_GS 6
|
||||
|
||||
static const int ittypes = 133;
|
||||
static const int ittypes = 136;
|
||||
|
||||
struct itemtype {
|
||||
char glyph;
|
||||
@ -131,7 +131,8 @@ enum eItem {
|
||||
itOrbLava, itOrbMorph, itGlowCrystal, itSnake,
|
||||
itDock, itRuins, itMagnet, itSwitch,
|
||||
itOrbPhasing, itOrbMagnetism, itOrbSlaying,
|
||||
itBrownian, itWest, itVarTreasure
|
||||
itBrownian, itWest, itVarTreasure,
|
||||
itOrbBrown, itOrbGravity, itOrbChoice
|
||||
};
|
||||
|
||||
static const int walltypes = 111;
|
||||
|
@ -157,7 +157,7 @@ namespace westwall {
|
||||
vector<cell*> whirlline;
|
||||
int d = coastvalEdge(c);
|
||||
whirlline.push_back(c);
|
||||
whirlline.push_back(ts::left_of(c, coastvalEdge1));
|
||||
whirlline.push_back(gravity_state == gsAnti ? ts::right_of(c, coastvalEdge1) : ts::left_of(c, coastvalEdge1));
|
||||
build(whirlline, d);
|
||||
reverse(whirlline.begin(), whirlline.end());
|
||||
build(whirlline, d);
|
||||
@ -178,6 +178,7 @@ namespace westwall {
|
||||
|
||||
void move() {
|
||||
manual_celllister cl;
|
||||
if(gravity_state == gsLevitation) return;
|
||||
for(cell *c: dcal) moveAt(c, cl);
|
||||
// Keys and Orbs of Yendor always move
|
||||
using namespace yendor;
|
||||
@ -186,7 +187,8 @@ namespace westwall {
|
||||
// println(hlog, "coastval of actual key is ", coastvalEdge1(yi[i].actual_key()), " and item is ", dnameof(yi[i].actual_key()->item), "and mpdist is ", yi[i].actual_key()->mpdist);
|
||||
moveAt(yi[i].actual_key(), cl);
|
||||
if(yi[i].actualKey) {
|
||||
yi[i].age++;
|
||||
if(gravity_state == gsAnti) yi[i].age--;
|
||||
else yi[i].age++;
|
||||
setdist(yi[i].actual_key(), 8, NULL);
|
||||
}
|
||||
}
|
||||
|
@ -78,6 +78,21 @@ void operator ++(bignum &b, int) {
|
||||
}
|
||||
}
|
||||
|
||||
void operator --(bignum &b, int) {
|
||||
int i = 0;
|
||||
while(true) {
|
||||
if(isize(b.digits) == i) { b.digits.push_back(bignum::BASE-1); break; }
|
||||
else if(b.digits[i] == 0) {
|
||||
b.digits[i] = bignum::BASE-1;
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
b.digits[i]--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string bignum::get_str(int max_length) {
|
||||
if(digits.empty()) return "0";
|
||||
string ret = its(digits.back());
|
||||
|
204
game.cpp
204
game.cpp
@ -196,7 +196,7 @@ void initcell(cell *c) {
|
||||
|
||||
bool doesnotFall(cell *c) {
|
||||
if(c->wall == waChasm) return false;
|
||||
else if(cellUnstable(c)) {
|
||||
else if(cellUnstable(c) && !in_gravity_zone(c)) {
|
||||
fallingFloorAnimation(c);
|
||||
c->wall = waChasm;
|
||||
return false;
|
||||
@ -393,6 +393,68 @@ int killtypes() {
|
||||
return res;
|
||||
}
|
||||
|
||||
eGravity gravity_state, last_gravity_state;
|
||||
|
||||
bool bird_disruption(cell *c) {
|
||||
return c->cpdist <= 5 && items[itOrbGravity];
|
||||
}
|
||||
|
||||
bool in_gravity_zone(cell *c) {
|
||||
return gravity_state && c->cpdist <= 5;
|
||||
}
|
||||
|
||||
int gravity_zone_diff(cell *c) {
|
||||
if(in_gravity_zone(c)) {
|
||||
if(gravity_state == gsLevitation) return 0;
|
||||
if(gravity_state == gsAnti) return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool isJWall(cell *c) {
|
||||
return isWall(c) || c->monst == passive_switch;
|
||||
}
|
||||
|
||||
eGravity get_static_gravity(cell *c) {
|
||||
if(isGravityLand(c->land))
|
||||
return gsLevitation;
|
||||
if(among(c->wall, waArrowTrap, waFireTrap, waClosePlate, waOpenPlate, waTrapdoor))
|
||||
return gsNormal;
|
||||
forCellEx(c2, c) if(isJWall(c2))
|
||||
return gsAnti;
|
||||
if(isWatery(c) || isChasmy(c) || among(c->wall, waMagma, waMineUnknown, waMineMine, waMineOpen))
|
||||
return gsLevitation;
|
||||
return gsNormal;
|
||||
}
|
||||
|
||||
eGravity get_move_gravity(cell *c, cell *c2) {
|
||||
if(isGravityLand(c->land) && isGravityLand(c2->land)) {
|
||||
int d = gravityLevelDiff(c, c2);
|
||||
if(d > 0) return gsNormal;
|
||||
if(d == 0) return gsLevitation;
|
||||
if(d < 0) return gsAnti;
|
||||
return gsNormal;
|
||||
}
|
||||
else {
|
||||
if(snakelevel(c) != snakelevel(c2)) {
|
||||
int d = snakelevel(c2) - snakelevel(c);
|
||||
if(d > 0) return gsAnti;
|
||||
if(d == -3) return gsLevitation;
|
||||
return gsNormal;
|
||||
}
|
||||
forCellEx(c3, c) if(isJWall(c3))
|
||||
return gsAnti;
|
||||
forCellEx(c3, c2) if(isJWall(c3))
|
||||
return gsAnti;
|
||||
if(isWatery(c2) && c->wall == waBoat && !againstCurrent(c2, c))
|
||||
return gsNormal;
|
||||
if(isWatery(c2) || isChasmy(c2) || among(c2->wall, waMagma, waMineUnknown, waMineMine, waMineOpen) || anti_alchemy(c2, c))
|
||||
return gsLevitation;
|
||||
return gsNormal;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool isWarped(cell *c) {
|
||||
return isWarped(c->land) || (!inmirrororwall(c->land) && (items[itOrb37] && c->cpdist <= 4));
|
||||
}
|
||||
@ -486,7 +548,13 @@ bool checkflags(flagtype flags, int x) {
|
||||
bool strictlyAgainstGravity(cell *w, cell *from, bool revdir, flagtype flags) {
|
||||
return
|
||||
cellEdgeUnstable(w, flags) && cellEdgeUnstable(from, flags) &&
|
||||
!(shmup::on && from == w) && gravityLevelDiff(w, from) != (revdir?1:-1);
|
||||
!(shmup::on && from == w) && gravityLevelDiff(from, w) != (revdir?-1:1) * gravity_zone_diff(from);
|
||||
}
|
||||
|
||||
bool anti_alchemy(cell *w, cell *from) {
|
||||
bool alch1 = w->wall == waFloorA && from && from->wall == waFloorB && !w->item && !from->item;
|
||||
alch1 |= w->wall == waFloorB && from && from->wall == waFloorA && !w->item && !from->item;
|
||||
return alch1;
|
||||
}
|
||||
|
||||
bool passable(cell *w, cell *from, flagtype flags) {
|
||||
@ -503,6 +571,10 @@ bool passable(cell *w, cell *from, flagtype flags) {
|
||||
|
||||
if(from && !((flags & P_ISPLAYER) && pp->monst)) {
|
||||
int i = vrevdir ? incline(w, from) : incline(from, w);
|
||||
if(in_gravity_zone(w)) {
|
||||
if(gravity_state == gsLevitation) i = 0;
|
||||
if(gravity_state == gsAnti && i > 1) i = 1;
|
||||
}
|
||||
if(i < -1 && F(P_ROSE)) return false;
|
||||
if((i > 1) && !F(P_JUMP1 | P_JUMP2 | P_BULLET | P_FLYING | P_BLOW | P_CLIMBUP | P_AETHER | P_REPTILE))
|
||||
return false;
|
||||
@ -528,12 +600,12 @@ bool passable(cell *w, cell *from, flagtype flags) {
|
||||
if(!shmup::on && sword::at(w, flags & P_ISPLAYER) && !F(P_DEADLY | P_BULLET | P_ROSE))
|
||||
return false;
|
||||
|
||||
bool alch1 = w->wall == waFloorA && from && from->wall == waFloorB && !w->item && !from->item;
|
||||
alch1 |= w->wall == waFloorB && from && from->wall == waFloorA && !w->item && !from->item;
|
||||
bool alch1 = anti_alchemy(w, from);
|
||||
|
||||
if(alch1) {
|
||||
bool alchok = F(P_JUMP1 | P_JUMP2 | P_FLYING | P_TELE | P_BLOW | P_AETHER | P_BULLET)
|
||||
&& !F(P_ROSE);
|
||||
bool alchok = (in_gravity_zone(w) || in_gravity_zone(from));
|
||||
alchok = alchok || (F(P_JUMP1 | P_JUMP2 | P_FLYING | P_TELE | P_BLOW | P_AETHER | P_BULLET)
|
||||
&& !F(P_ROSE));
|
||||
if(!alchok) return false;
|
||||
}
|
||||
|
||||
@ -590,16 +662,27 @@ bool passable(cell *w, cell *from, flagtype flags) {
|
||||
if(isThorny(w->wall) && F(P_BLOW | P_DEADLY)) return true;
|
||||
|
||||
if(isFire(w) || w->wall == waMagma) {
|
||||
if(!F(P_AETHER | P_WINTER | P_BLOW | P_JUMP1 | P_BULLET | P_DEADLY)) return false;
|
||||
if(w->wall == waMagma && in_gravity_zone(w)) ;
|
||||
else if(!F(P_AETHER | P_WINTER | P_BLOW | P_JUMP1 | P_BULLET | P_DEADLY)) return false;
|
||||
}
|
||||
|
||||
if(in_gravity_zone(w) && gravity_state == gsAnti && !isGravityLand(w->land) && (!from || !isGravityLand(from->land)))
|
||||
if(!F(P_AETHER | P_BLOW | P_JUMP1 | P_BULLET | P_FLYING)) {
|
||||
bool next_to_wall = false;
|
||||
forCellEx(c2, w) if(isJWall(c2)) next_to_wall = true;
|
||||
if(from) forCellEx(c2, from) if(isJWall(c2)) next_to_wall = true;
|
||||
if(!next_to_wall && (!from || incline(from, w) * (vrevdir?-1:1) <= 0)) return false;
|
||||
}
|
||||
|
||||
if(isWatery(w)) {
|
||||
if(from && from->wall == waBoat && F(P_USEBOAT) &&
|
||||
if(in_gravity_zone(w)) ;
|
||||
else if(from && from->wall == waBoat && F(P_USEBOAT) &&
|
||||
(!againstCurrent(w, from) || F(P_MARKWATER))) ;
|
||||
else if(!F(P_AETHER | P_FISH | P_FLYING | P_BLOW | P_JUMP1 | P_BULLET | P_DEADLY | P_REPTILE)) return false;
|
||||
}
|
||||
if(isChasmy(w)) {
|
||||
if(!F(P_AETHER | P_FLYING | P_BLOW | P_JUMP1 | P_BULLET | P_DEADLY | P_REPTILE)) return false;
|
||||
if(in_gravity_zone(w)) ;
|
||||
else if(!F(P_AETHER | P_FLYING | P_BLOW | P_JUMP1 | P_BULLET | P_DEADLY | P_REPTILE)) return false;
|
||||
}
|
||||
|
||||
if(w->wall == waRoundTable && from && from->wall != waRoundTable && (flags & P_ISPLAYER)) return true;
|
||||
@ -843,8 +926,12 @@ bool passable_for(eMonster m, cell *w, cell *from, flagtype extra) {
|
||||
return passable(w, from, extra | P_FLYING | P_ISFRIEND);
|
||||
if(m == moHexSnake)
|
||||
return !pseudohept(w) && passable(w, from, extra|P_WIND|P_FISH);
|
||||
if(isBird(m))
|
||||
if(isBird(m)) {
|
||||
if(bird_disruption(w) && (!from || bird_disruption(from)) && markOrb(itOrbGravity))
|
||||
return passable(w, from, extra);
|
||||
else
|
||||
return passable(w, from, extra | P_FLYING);
|
||||
}
|
||||
if(m == moReptile)
|
||||
return passable(w, from, extra | P_REPTILE);
|
||||
if(isDragon(m))
|
||||
@ -2570,14 +2657,17 @@ int gravityLevel(cell *c) {
|
||||
int gravityLevelDiff(cell *c, cell *d) {
|
||||
if(c->land != laWestWall || d->land != laWestWall)
|
||||
return gravityLevel(c) - gravityLevel(d);
|
||||
int bonus = 0;
|
||||
int id = parent_id(c, 1, coastvalEdge);
|
||||
for(int a=0; a<3; a++)
|
||||
if(c->modmove(id+a) == d) bonus++;
|
||||
id = parent_id(c, -1, coastvalEdge);
|
||||
for(int a=0; a<3; a++)
|
||||
if(c->modmove(id-a) == d) bonus--;
|
||||
return bonus;
|
||||
|
||||
int nid = neighborId(c, d);
|
||||
int id1 = parent_id(c, 1, coastvalEdge) + 1;
|
||||
int di1 = angledist(c->type, id1, nid);
|
||||
|
||||
int id2 = parent_id(c, -1, coastvalEdge) - 1;
|
||||
int di2 = angledist(c->type, id2, nid);
|
||||
|
||||
if(di1 < di2) return 1;
|
||||
if(di1 > di2) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool canUnstable(eWall w, flagtype flags) {
|
||||
@ -2591,7 +2681,7 @@ bool cellEdgeUnstable(cell *c, flagtype flags) {
|
||||
for(int i=0; i<c->type; i++) if(c->move(i)) {
|
||||
if(isAnyIvy(c->move(i)->monst) &&
|
||||
c->land == laMountain && !(flags & MF_IVY)) return false;
|
||||
if(gravityLevelDiff(c, c->move(i)) == 1) {
|
||||
if(gravityLevelDiff(c, c->move(i)) == gravity_zone_diff(c)) {
|
||||
if(againstWind(c->move(i), c)) return false;
|
||||
if(!passable(c->move(i), NULL, P_MONSTER | P_DEADLY))
|
||||
return false;
|
||||
@ -3363,20 +3453,20 @@ void moveEffect(cell *ct, cell *cf, eMonster m, int direction_hint) {
|
||||
|
||||
if(!isNonliving(m)) terracottaAround(ct);
|
||||
|
||||
if(ct->wall == waMineUnknown && !ct->item && !ignoresPlates(m))
|
||||
if(ct->wall == waMineUnknown && !ct->item && !ignoresPlates(m) && normal_gravity_at(ct))
|
||||
ct->landparam |= 2; // mark as safe
|
||||
|
||||
if((ct->wall == waClosePlate || ct->wall == waOpenPlate) && !ignoresPlates(m))
|
||||
if((ct->wall == waClosePlate || ct->wall == waOpenPlate) && !ignoresPlates(m) && normal_gravity_at(ct))
|
||||
toggleGates(ct, ct->wall);
|
||||
if(m == moDeadBird && cf == ct && cellUnstable(cf)) {
|
||||
if(m == moDeadBird && cf == ct && cellUnstable(cf) && normal_gravity_at(ct)) {
|
||||
fallingFloorAnimation(cf);
|
||||
cf->wall = waChasm;
|
||||
}
|
||||
|
||||
if(ct->wall == waArrowTrap && !ignoresPlates(m))
|
||||
if(ct->wall == waArrowTrap && !ignoresPlates(m) && normal_gravity_at(ct))
|
||||
activateArrowTrap(ct);
|
||||
|
||||
if(ct->wall == waFireTrap && !ignoresPlates(m) && ct->wparam == 0)
|
||||
if(ct->wall == waFireTrap && !ignoresPlates(m) && ct->wparam == 0 && normal_gravity_at(ct))
|
||||
ct->wparam = 1;
|
||||
|
||||
if(cf && isPrincess(m)) princess::move(ct, cf);
|
||||
@ -3455,13 +3545,13 @@ void playerMoveEffects(cell *c1, cell *c2) {
|
||||
|
||||
uncoverMinesFull(c2);
|
||||
|
||||
if((c2->wall == waClosePlate || c2->wall == waOpenPlate) && !markOrb(itOrbAether))
|
||||
if((c2->wall == waClosePlate || c2->wall == waOpenPlate) && normal_gravity_at(c2) && !markOrb(itOrbAether))
|
||||
toggleGates(c2, c2->wall);
|
||||
|
||||
if(c2->wall == waArrowTrap && c2->wparam == 0 && !markOrb(itOrbAether))
|
||||
if(c2->wall == waArrowTrap && c2->wparam == 0 && normal_gravity_at(c2) && !markOrb(itOrbAether))
|
||||
activateArrowTrap(c2);
|
||||
|
||||
if(c2->wall == waFireTrap && c2->wparam == 0 && !markOrb(itOrbAether))
|
||||
if(c2->wall == waFireTrap && c2->wparam == 0 && normal_gravity_at(c2) &&!markOrb(itOrbAether))
|
||||
c2->wparam = 1;
|
||||
|
||||
princess::playernear(c2);
|
||||
@ -3718,7 +3808,7 @@ void moveMonster(cell *ct, cell *cf, int direction_hint) {
|
||||
ct->stuntime = 2;
|
||||
else if(inc == 3 && ct->monst == moReptile)
|
||||
ct->stuntime = 3;
|
||||
else if(inc == -3 && !survivesFall(ct->monst)) {
|
||||
else if(inc == -3 && !survivesFall(ct->monst) && !passable(cf, ct, P_MONSTER)) {
|
||||
addMessage(XLAT("%The1 falls!", ct->monst));
|
||||
fallMonster(ct, AF_FALL);
|
||||
}
|
||||
@ -4664,6 +4754,7 @@ void groupmove2(cell *c, cell *from, int d, eMonster movtype, flagtype mf) {
|
||||
if(!ignoresSmell(c->monst) && againstRose(c, from)) return;
|
||||
if((mf & MF_ONLYEAGLE) && c->monst != moEagle && c->monst != moBat)
|
||||
return;
|
||||
if((mf & MF_ONLYEAGLE) && bird_disruption(c) && markOrb(itOrbGravity)) return;
|
||||
// in the gravity lands, eagles cannot ascend in their second move
|
||||
if((mf & MF_ONLYEAGLE) && gravityLevelDiff(c, from) < 0) {
|
||||
onpath(c, 0);
|
||||
@ -4742,7 +4833,7 @@ void groupmove(eMonster movtype, flagtype mf) {
|
||||
groupmove2(c->move(t),c,t,movtype,mf);
|
||||
}
|
||||
|
||||
if(movtype == moEagle && c->monst == moNone && !isPlayerOn(c)) {
|
||||
if(movtype == moEagle && c->monst == moNone && !isPlayerOn(c) && !bird_disruption(c)) {
|
||||
cell *c2 = whirlwind::jumpFromWhereTo(c, false);
|
||||
groupmove2(c2, c, NODIR, movtype, mf);
|
||||
}
|
||||
@ -5664,6 +5755,10 @@ bool saved_tortoise_on(cell *c) {
|
||||
!((tortoise::getb(c) ^ tortoise::babymap[c]) & tortoise::mask));
|
||||
}
|
||||
|
||||
bool normal_gravity_at(cell *c) {
|
||||
return !in_gravity_zone(c);
|
||||
}
|
||||
|
||||
void moverefresh(bool turn = true) {
|
||||
int dcs = isize(dcal);
|
||||
|
||||
@ -5761,7 +5856,7 @@ void moverefresh(bool turn = true) {
|
||||
if(c->wall == waChasm) {
|
||||
if(c->land != laWhirlwind) c->item = itNone;
|
||||
|
||||
if(c->monst && !survivesChasm(c->monst) && c->monst != moReptile) {
|
||||
if(c->monst && !survivesChasm(c->monst) && c->monst != moReptile && normal_gravity_at(c)) {
|
||||
if(c->monst != moRunDog && c->land == laMotion)
|
||||
achievement_gain("FALLDEATH1");
|
||||
addMessage(XLAT("%The1 falls!", c->monst));
|
||||
@ -5814,7 +5909,7 @@ void moverefresh(bool turn = true) {
|
||||
else if(isWatery(c)) {
|
||||
if(c->monst == moLesser || c->monst == moLesserM || c->monst == moGreater || c->monst == moGreaterM)
|
||||
c->monst = moGreaterShark;
|
||||
if(c->monst && !survivesWater(c->monst)) {
|
||||
if(c->monst && !survivesWater(c->monst) && normal_gravity_at(c)) {
|
||||
playSound(c, "splash"+pick12());
|
||||
if(isNonliving(c->monst))
|
||||
addMessage(XLAT("%The1 sinks!", c->monst));
|
||||
@ -5828,7 +5923,7 @@ void moverefresh(bool turn = true) {
|
||||
}
|
||||
}
|
||||
else if(c->wall == waSulphur || c->wall == waSulphurC || c->wall == waMercury) {
|
||||
if(c->monst && !survivesPoison(c->monst, c->wall)) {
|
||||
if(c->monst && !survivesPoison(c->monst, c->wall) && normal_gravity_at(c)) {
|
||||
playSound(c, "splash"+pick12());
|
||||
if(isNonliving(c->monst))
|
||||
addMessage(XLAT("%The1 sinks!", c->monst));
|
||||
@ -5843,7 +5938,7 @@ void moverefresh(bool turn = true) {
|
||||
}
|
||||
else if(c->wall == waMagma) {
|
||||
if(c->monst == moSalamander) c->stuntime = max<int>(c->stuntime, 1);
|
||||
else if(c->monst && !survivesPoison(c->monst, c->wall)) {
|
||||
else if(c->monst && !survivesPoison(c->monst, c->wall) && normal_gravity_at(c)) {
|
||||
if(isNonliving(c->monst))
|
||||
addMessage(XLAT("%The1 is destroyed by lava!", c->monst));
|
||||
else
|
||||
@ -6121,6 +6216,7 @@ bool checkNeedMove(bool checkonly, bool attacking) {
|
||||
else if(cwt.at->wall == waLake) {
|
||||
if(markOrb2(itOrbAether)) return false;
|
||||
if(markOrb2(itOrbFish)) return false;
|
||||
if(in_gravity_zone(cwt.at) && passable(cwt.at, NULL, P_ISPLAYER)) return false;
|
||||
if(checkonly) return true;
|
||||
flags |= AF_FALL;
|
||||
addMessage(XLAT("Ice below you is melting! RUN!"));
|
||||
@ -6128,11 +6224,13 @@ bool checkNeedMove(bool checkonly, bool attacking) {
|
||||
else if(!attacking && cellEdgeUnstable(cwt.at)) {
|
||||
if(markOrb2(itOrbAether)) return false;
|
||||
if(checkonly) return true;
|
||||
if(in_gravity_zone(cwt.at) && passable(cwt.at, NULL, P_ISPLAYER)) return false;
|
||||
addMessage(XLAT("Nothing to stand on here!"));
|
||||
}
|
||||
else if(cwt.at->wall == waSea || cwt.at->wall == waCamelotMoat) {
|
||||
if(markOrb(itOrbFish)) return false;
|
||||
if(markOrb2(itOrbAether)) return false;
|
||||
if(in_gravity_zone(cwt.at) && passable(cwt.at, NULL, P_ISPLAYER)) return false;
|
||||
if(checkonly) return true;
|
||||
addMessage(XLAT("You have to run away from the water!"));
|
||||
}
|
||||
@ -6148,11 +6246,13 @@ bool checkNeedMove(bool checkonly, bool attacking) {
|
||||
}
|
||||
else if(cwt.at->wall == waMagma && !markOrb(itOrbWinter) && !markOrb2(itOrbShield)) {
|
||||
if(markOrb2(itOrbAether)) return false;
|
||||
if(in_gravity_zone(cwt.at) && passable(cwt.at, cwt.at, P_ISPLAYER)) return false;
|
||||
if(checkonly) return true;
|
||||
addMessage(XLAT("Run away from the magma!"));
|
||||
}
|
||||
else if(cwt.at->wall == waChasm) {
|
||||
if(markOrb2(itOrbAether)) return false;
|
||||
if(in_gravity_zone(cwt.at) && passable(cwt.at, cwt.at, P_ISPLAYER)) return false;
|
||||
if(checkonly) return true;
|
||||
flags |= AF_FALL;
|
||||
addMessage(XLAT("The floor has collapsed! RUN!"));
|
||||
@ -6314,6 +6414,8 @@ bool hasSafeOrb(cell *c) {
|
||||
|
||||
void checkmove() {
|
||||
|
||||
dynamicval<eGravity> gs(gravity_state, gravity_state);
|
||||
|
||||
#if CAP_INV
|
||||
if(inv::on) inv::compute();
|
||||
#endif
|
||||
@ -6825,8 +6927,10 @@ bool collectItem(cell *c2, bool telekinesis) {
|
||||
else if(it == itOrbSpeed) playSound(c2, "pickup-speed");
|
||||
else if(it == itRevolver) playSound(c2, "pickup-key");
|
||||
else playSound(c2, "pickup-orb");
|
||||
int oc = orbcharges(it);
|
||||
if(markOrb(itOrbBrown)) oc = oc * 6 / 5;
|
||||
if(!items[it]) items[it]++;
|
||||
items[it] += orbcharges(it);
|
||||
items[it] += oc;
|
||||
}
|
||||
else if(c2->item == itOrbLife) {
|
||||
playSound(c2, "pickup-orb"); // TODO summon
|
||||
@ -6987,6 +7091,15 @@ bool collectItem(cell *c2, bool telekinesis) {
|
||||
eItem dummy = c2->item;
|
||||
conformal::findhistory.emplace_back(c2, dummy);
|
||||
#endif
|
||||
|
||||
if(c2->item == itBombEgg && c2->land == laMinefield) {
|
||||
c2->landparam |= 2;
|
||||
c2->landparam &= ~1;
|
||||
}
|
||||
|
||||
if(items[itOrbChoice] && itemclass(c2->item) == IC_ORB)
|
||||
items[itOrbChoice] = 0;
|
||||
else
|
||||
c2->item = itNone;
|
||||
}
|
||||
// if(c2->land == laHive)
|
||||
@ -7584,10 +7697,20 @@ bool movepcto(int d, int subdir, bool checkonly) {
|
||||
return false;
|
||||
}
|
||||
|
||||
gravity_state = gsNormal;
|
||||
|
||||
if(d >= 0) {
|
||||
cell *c2 = cwt.at->move(d);
|
||||
bool goodTortoise = c2->monst == moTortoise && tortoise::seek() && !tortoise::diff(tortoise::getb(c2)) && !c2->item;
|
||||
|
||||
if(items[itOrbGravity]) {
|
||||
if(c2->monst && !should_switchplace(cwt.at, c2))
|
||||
gravity_state = get_static_gravity(cwt.at);
|
||||
else
|
||||
gravity_state = get_move_gravity(cwt.at, c2);
|
||||
if(gravity_state) markOrb(itOrbGravity);
|
||||
}
|
||||
|
||||
if(againstRose(cwt.at, c2) && !scentResistant()) {
|
||||
if(checkonly) return false;
|
||||
addMessage("Those roses smell too nicely. You have to come towards them.");
|
||||
@ -7676,7 +7799,7 @@ bool movepcto(int d, int subdir, bool checkonly) {
|
||||
}
|
||||
|
||||
if(againstCurrent(c2, cwt.at) && !markOrb(itOrbWater)) {
|
||||
if(markOrb(itOrbFish) || markOrb(itOrbAether)) goto escape;
|
||||
if(markOrb(itOrbFish) || markOrb(itOrbAether) || gravity_state) goto escape;
|
||||
if(!checkonly)
|
||||
addMessage(XLAT("You cannot go against the current!"));
|
||||
return false;
|
||||
@ -7934,8 +8057,9 @@ bool movepcto(int d, int subdir, bool checkonly) {
|
||||
addMessage(XLAT("You would get hurt!", c2->wall));
|
||||
else if(cwt.at->wall == waTower && snakelevel(c2) == 0)
|
||||
addMessage(XLAT("You would get hurt!", c2->wall));
|
||||
else if(cellEdgeUnstable(cwt.at) && cellEdgeUnstable(c2))
|
||||
else if(cellEdgeUnstable(cwt.at) && cellEdgeUnstable(c2)) {
|
||||
addMessage(XLAT("Gravity does not allow this!"));
|
||||
}
|
||||
else if(c2->wall == waChasm && c2->land == laDual)
|
||||
addMessage(XLAT("You cannot move there!"));
|
||||
else {
|
||||
@ -8084,6 +8208,10 @@ bool movepcto(int d, int subdir, bool checkonly) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(items[itOrbGravity]) {
|
||||
gravity_state = get_static_gravity(cwt.at);
|
||||
if(gravity_state) markOrb(itOrbGravity);
|
||||
}
|
||||
lastmovetype = lmSkip; lastmove = NULL;
|
||||
if(checkNeedMove(checkonly, false))
|
||||
return false;
|
||||
@ -8098,6 +8226,9 @@ bool movepcto(int d, int subdir, bool checkonly) {
|
||||
dropGreenStone(cwt.at);
|
||||
if(cellUnstable(cwt.at) && !markOrb(itOrbAether))
|
||||
doesFallSound(cwt.at);
|
||||
|
||||
if(last_gravity_state && !gravity_state)
|
||||
playerMoveEffects(cwt.at, cwt.at);
|
||||
}
|
||||
|
||||
invisfish = false;
|
||||
@ -8110,6 +8241,7 @@ bool movepcto(int d, int subdir, bool checkonly) {
|
||||
if(invisfish) invismove = true, markOrb(itOrbFish);
|
||||
}
|
||||
|
||||
last_gravity_state = gravity_state;
|
||||
if(multi::players == 1) monstersTurn();
|
||||
|
||||
save_memory();
|
||||
|
80
graph.cpp
80
graph.cpp
@ -524,7 +524,7 @@ transmatrix otherbodyparts(const transmatrix& V, color_t col, eMonster who, doub
|
||||
#define VAHEAD mmscale(V, geom3::AHEAD)
|
||||
|
||||
#define VFISH V
|
||||
#define VBIRD mmscale(V, geom3::BIRD + .05 * sintick(1000, (int) (size_t(where))/1000.))
|
||||
#define VBIRD ((where && bird_disruption(where)) ? V : mmscale(V, geom3::BIRD + .05 * sintick(1000, (int) (size_t(where))/1000.)))
|
||||
#define VGHOST mmscale(V, geom3::GHOST)
|
||||
|
||||
#define VSLIMEEYE mscale(V, geom3::FLATEYE)
|
||||
@ -781,7 +781,7 @@ bool drawItemType(eItem it, cell *c, const transmatrix& V, int icol, int pticks,
|
||||
isFriendOrb(it) ? shPeaceRing :
|
||||
isUtilityOrb(it) ? shGearRing :
|
||||
isDirectionalOrb(it) ? shSpearRing :
|
||||
it == itOrb37 ? shHeptaRing :
|
||||
among(it, itOrb37, itOrbGravity) ? shHeptaRing :
|
||||
shRing;
|
||||
queuepolyat(V * spinptick(1500), sh, col, prio);
|
||||
}
|
||||
@ -3626,6 +3626,76 @@ int colorhash(color_t i) {
|
||||
return (i * 0x471211 + i*i*0x124159 + i*i*i*0x982165) & 0xFFFFFF;
|
||||
}
|
||||
|
||||
void draw_gravity_particles(cell *c, const transmatrix V) {
|
||||
int u = (int)(size_t)(c);
|
||||
u = ((u * 137) + (u % 1000) * 51) % 1000;
|
||||
int tt = ticks + u;
|
||||
ld r0 = (tt % 900) / 1100.;
|
||||
ld r1 = (tt % 900 + 200) / 1100.;
|
||||
|
||||
const color_t grav_normal_color = 0x808080FF;
|
||||
const color_t antigrav_color = 0xF04040FF;
|
||||
const color_t levitate_color = 0x40F040FF;
|
||||
|
||||
ld lev = 2;
|
||||
|
||||
if(spatial_graphics) {
|
||||
|
||||
switch(gravity_state) {
|
||||
case gsNormal:
|
||||
for(int i=0; i<6; i++) {
|
||||
transmatrix T = V * spin(i*degree*60) * xpush(crossf/3);
|
||||
queueline(mmscale(T, 1 + (1-r0) * (lev-1)) * C0, mmscale(T, 1 + (1-r1) * (lev - 1)) * C0, grav_normal_color);
|
||||
}
|
||||
break;
|
||||
|
||||
case gsAnti:
|
||||
for(int i=0; i<6; i++) {
|
||||
transmatrix T = V * spin(i*degree*60) * xpush(crossf/3);
|
||||
queueline(mmscale(T, 1 + r0 * (lev-1)) * C0, mmscale(T, 1 + r1 * (lev-1)) * C0, antigrav_color);
|
||||
}
|
||||
break;
|
||||
|
||||
case gsLevitation:
|
||||
for(int i=0; i<6; i++) {
|
||||
transmatrix T0 = V * spin(i*degree*60 + tt/60. * degree) * xpush(crossf/3);
|
||||
transmatrix T1 = V * spin(i*degree*60 + (tt/60. + 30) * degree) * xpush(crossf/3);
|
||||
queueline(mmscale(T0, (lev+1)/2) * C0, mmscale(T1, (lev+1)/2) * C0, levitate_color);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
switch(gravity_state) {
|
||||
case gsNormal:
|
||||
for(int i=0; i<6; i++) {
|
||||
transmatrix T0 = V * spin(i*degree*60) * xpush(crossf/3 * (1-r0));
|
||||
transmatrix T1 = V * spin(i*degree*60) * xpush(crossf/3 * (1-r1));
|
||||
queueline(T0 * C0, T1 * C0, grav_normal_color);
|
||||
}
|
||||
break;
|
||||
|
||||
case gsAnti:
|
||||
for(int i=0; i<6; i++) {
|
||||
transmatrix T0 = V * spin(i*degree*60) * xpush(crossf/3 * r0);
|
||||
transmatrix T1 = V * spin(i*degree*60) * xpush(crossf/3 * r1);
|
||||
queueline(T0 * C0, T1 * C0, antigrav_color);
|
||||
}
|
||||
break;
|
||||
|
||||
case gsLevitation:
|
||||
for(int i=0; i<6; i++) {
|
||||
transmatrix T0 = V * spin(i*degree*60 + tt/60. * degree) * xpush(crossf/3);
|
||||
transmatrix T1 = V * spin(i*degree*60 + (tt/60. + 30) * degree) * xpush(crossf/3);
|
||||
queueline(T0 * C0, T1 * C0, levitate_color);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
|
||||
|
||||
cells_drawn++;
|
||||
@ -4887,6 +4957,9 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
|
||||
}
|
||||
}
|
||||
|
||||
if(items[itOrbGravity] && c->cpdist <= 5)
|
||||
draw_gravity_particles(c, V);
|
||||
|
||||
if(c->land == laWhirlwind) {
|
||||
whirlwind::calcdirs(c);
|
||||
|
||||
@ -5527,6 +5600,7 @@ void drawthemap() {
|
||||
lmouseover = mouseover;
|
||||
bool useRangedOrb = (!(vid.shifttarget & 1) && haveRangedOrb() && lmouseover && lmouseover->cpdist > 1) || (keystate[SDLK_RSHIFT] | keystate[SDLK_LSHIFT]);
|
||||
if(!useRangedOrb && !(cmode & sm::MAP) && !(cmode & sm::DRAW) && DEFAULTCONTROL && !mouseout()) {
|
||||
dynamicval<eGravity> gs(gravity_state, gravity_state);
|
||||
void calcMousedest();
|
||||
calcMousedest();
|
||||
cellwalker cw = cwt; bool f = flipplayer;
|
||||
@ -5886,7 +5960,7 @@ void drawscreen() {
|
||||
}
|
||||
}
|
||||
|
||||
if((minefieldNearby || tmines) && !items[itOrbAether] && darken == 0 && normal) {
|
||||
if((minefieldNearby || tmines) && !items[itOrbAether] && !last_gravity_state && darken == 0 && normal) {
|
||||
string s;
|
||||
if(tmines > 7) tmines = 7;
|
||||
color_t col = minecolors[tmines];
|
||||
|
6
hyper.h
6
hyper.h
@ -1437,6 +1437,7 @@ void setGLProjection(color_t col = backcolor);
|
||||
|
||||
bool passable(cell *w, cell *from, flagtype flags);
|
||||
|
||||
bool anti_alchemy(cell *w, cell *from);
|
||||
bool isElemental(eLand l);
|
||||
int coastval(cell *c, eLand base);
|
||||
int getHauntedDepth(cell *c);
|
||||
@ -2082,6 +2083,9 @@ bool mayExplodeMine(cell *c, eMonster who);
|
||||
void explosion(cell *c, int power, int central);
|
||||
void explodeBarrel(cell *c);
|
||||
|
||||
enum eGravity { gsNormal, gsLevitation, gsAnti };
|
||||
extern eGravity gravity_state, last_gravity_state;
|
||||
|
||||
int gravityLevel(cell *c);
|
||||
int gravityLevelDiff(cell *c, cell *f);
|
||||
void fullcenter();
|
||||
@ -4715,6 +4719,8 @@ namespace racing {
|
||||
inline bool subscreen_split(reaction_t for_each_subscreen) { return false; }
|
||||
#endif
|
||||
|
||||
bool in_gravity_zone(cell *c);
|
||||
bool normal_gravity_at(cell *c);
|
||||
|
||||
}
|
||||
|
||||
|
@ -336,6 +336,10 @@ namespace hr { namespace inv {
|
||||
gainOrbs(itMagnet, itOrbMagnetism);
|
||||
gainOrbs(itRuins, itOrbSlaying);
|
||||
|
||||
gainOrbs(itWest, itOrbGravity);
|
||||
gainOrbs(itVarTreasure, itOrbChoice);
|
||||
gainOrbs(itOrbBrown, itBrownian);
|
||||
|
||||
#if CAP_DAILY
|
||||
daily::gifts();
|
||||
#endif
|
||||
|
@ -117,6 +117,9 @@ const vector<orbinfo> orbinfos = {
|
||||
{orbgenflags::S_NATIVE, laSwitch, 2000, 3000, itOrbPhasing},
|
||||
{orbgenflags::S_NATIVE, laMagnetic, 2000, 3000, itOrbMagnetism},
|
||||
{orbgenflags::S_NATIVE, laRuins, 1200, 2500, itOrbSlaying},
|
||||
{orbgenflags::S_NATIVE, laWestWall, 2000, 4200, itOrbGravity},
|
||||
{orbgenflags::S_NATIVE, laVariant, 900, 4200, itOrbChoice},
|
||||
{orbgenflags::S_NATIVE, laBrownian, 900, 4200, itOrbBrown},
|
||||
{orbgenflags::S_NATIVE, laWhirlpool, 0, 2000, itOrbWater}, // needs to be last
|
||||
};
|
||||
|
||||
|
10
orbs.cpp
10
orbs.cpp
@ -72,6 +72,7 @@ bool reduceOrbPower(eItem it, int cap) {
|
||||
items[it] -= multi::activePlayers();
|
||||
if(isHaunted(cwt.at->land)) survivalist = false;
|
||||
if(items[it] < 0) items[it] = 0;
|
||||
if(items[it] > cap && markOrb(itOrbBrown)) cap = cap * 6 / 5;
|
||||
if(items[it] > cap && timerghost) items[it] = cap;
|
||||
if(items[it] == 0 && it == itOrbLove)
|
||||
princess::bringBack();
|
||||
@ -143,6 +144,9 @@ void reduceOrbPowers() {
|
||||
reduceOrbPower(itOrbLava, 80);
|
||||
reduceOrbPower(itOrbMorph, 80);
|
||||
reduceOrbPower(itOrbSlaying, 120);
|
||||
reduceOrbPower(itOrbGravity, 120);
|
||||
reduceOrbPower(itOrbChoice, 120);
|
||||
reduceOrbPower(itOrbBrown, 120);
|
||||
|
||||
reduceOrbPower(itOrbSide1, 120);
|
||||
reduceOrbPower(itOrbSide2, 120);
|
||||
@ -1342,6 +1346,12 @@ int orbcharges(eItem it) {
|
||||
case itOrbInvis:
|
||||
case itOrbAether:
|
||||
return 30;
|
||||
case itOrbGravity:
|
||||
return 45;
|
||||
case itOrbChoice:
|
||||
return 60;
|
||||
case itOrbBrown:
|
||||
return 50;
|
||||
case itOrbWinter: // "pickup-winter"
|
||||
return inv::on ? 45 : 30;
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user