hyperrogue/flags.cpp

397 lines
13 KiB
C++
Raw Normal View History

// Hyperbolic Rogue - Flags
2016-08-26 09:58:03 +00:00
// Copyright (C) 2011-2019 Zeno Rogue, see 'hyper.cpp' for details
2016-08-26 09:58:03 +00:00
/** \file flags.cpp
* \brief Implementation of various simple flags for lands, items, monsters, and walls.
*/
2016-08-26 09:58:03 +00:00
#include "hyper.h"
namespace hr {
2016-08-26 09:58:03 +00:00
#if HDR
2019-09-06 06:18:00 +00:00
const inline flagtype& classflag(eItem it) { return iinf[it].flags; }
const inline flagtype& classflag(eWall w) { return winf[w].flags; }
const inline flagtype& classflag(eMonster m) { return minf[m].flags; }
const inline flagtype& classflag(eLand l) { return linf[l].flags; }
#define ANYFLAGCHECK(name, cond, field, enum) inline bool name(enum w) { flagtype flag = classflag(w); return cond; } inline bool name(cell *c) { return name(c->field); }
#define MONFLAGCHECK(name, cond) ANYFLAGCHECK(name, cond, monst, eMonster)
#define WALLFLAGCHECK(name, cond) ANYFLAGCHECK(name, cond, wall, eWall)
#define ITEMFLAGCHECK(name, cond) ANYFLAGCHECK(name, cond, item, eItem)
#define LANDFLAGCHECK(name, cond) ANYFLAGCHECK(name, cond, land, eLand)
WALLFLAGCHECK(isWatery, flag & WF_WATER)
WALLFLAGCHECK(isBoat, flag & WF_BOAT)
WALLFLAGCHECK(isChasmy, flag & WF_CHASM)
2019-03-24 00:26:53 +00:00
WALLFLAGCHECK(isWateryOrBoat, (flag & WF_WATER) || w == waBoat)
WALLFLAGCHECK(isNoFlight, flag & WF_NOFLIGHT)
WALLFLAGCHECK(isFire, flag & WF_FIRE)
WALLFLAGCHECK(isThumper, flag & WF_THUMPER)
WALLFLAGCHECK(isActivable, flag & WF_ACTIVABLE)
WALLFLAGCHECK(hasTimeout, flag & WF_TIMEOUT)
WALLFLAGCHECK(isOnCIsland, flag & WF_CISLAND)
WALLFLAGCHECK(cellHalfvine, flag & WF_HALFVINE)
WALLFLAGCHECK(isAlch, flag & WF_ALCHEMY)
WALLFLAGCHECK(isAlchAny, flag & WF_ALCHEMY)
WALLFLAGCHECK(realred, flag & WF_RED)
WALLFLAGCHECK(isWall, flag & WF_WALL)
WALLFLAGCHECK(isNonblock, flag & WF_NONBLOCK)
WALLFLAGCHECK(isPushable, flag & WF_PUSHABLE)
WALLFLAGCHECK(conegraphtype, flag & WF_CONE)
WALLFLAGCHECK(isStandardTree, flag & WF_STDTREE)
WALLFLAGCHECK(isGrave, flag & WF_GRAVE)
WALLFLAGCHECK(isReptile, flag & WF_REPTILE)
WALLFLAGCHECK(useHeatColoring, flag & WF_HEATCOLOR)
2019-03-23 15:40:02 +00:00
WALLFLAGCHECK(isThorny, flag & WF_THORNY)
LANDFLAGCHECK(generateAll, flag & LF_GENERATE_ALL)
LANDFLAGCHECK(isIcyLand, flag & LF_ICY)
LANDFLAGCHECK(isGravityLand, flag & LF_GRAVITY)
LANDFLAGCHECK(isEquidLand, flag & LF_EQUI)
LANDFLAGCHECK(isWarpedType, flag & LF_WARPED)
LANDFLAGCHECK(isCyclic, flag & LF_CYCLIC)
LANDFLAGCHECK(isTechnicalLand, flag & LF_TECHNICAL)
LANDFLAGCHECK(is_mirrorland, flag & LF_MIRROR)
LANDFLAGCHECK(isSealand, flag & LF_SEA)
LANDFLAGCHECK(isCoastal, flag & LF_COASTAL)
LANDFLAGCHECK(isPureSealand, flag & LF_PURESEA)
LANDFLAGCHECK(isElemental, flag & LF_ELEMENTAL)
LANDFLAGCHECK(isHaunted, flag & LF_HAUNTED)
LANDFLAGCHECK(isTrollLand, flag & LF_TROLL)
LANDFLAGCHECK(inmirror, flag & LF_INMIRROR)
LANDFLAGCHECK(inmirrororwall, flag & LF_INMIRRORORWALL)
2020-02-26 00:22:26 +00:00
LANDFLAGCHECK(isElectricLand, flag & LF_ELECTRIC)
MONFLAGCHECK(isGhostable, !(flag & CF_NOGHOST))
MONFLAGCHECK(isRaider, flag & CF_RAIDER)
MONFLAGCHECK(isMimic, flag & CF_MIMIC)
MONFLAGCHECK(isPrincess, flag & CF_PRINCESS)
MONFLAGCHECK(isGolemOrKnight, flag & CF_GOK)
MONFLAGCHECK(isNonliving, flag & CF_NONLIVING)
MONFLAGCHECK(isMetalBeast, flag & CF_METAL)
MONFLAGCHECK(isStunnable, flag & CF_STUNNABLE)
MONFLAGCHECK(hasHitpoints, flag & CF_HP)
MONFLAGCHECK(isMountable, flag & CF_MOUNTABLE)
MONFLAGCHECK(isFriendlyType, flag & CF_FRIENDLY)
MONFLAGCHECK(isFriendlyOrPlayer, flag & (CF_FRIENDLY | CF_PLAYER))
MONFLAGCHECK(isBug, flag & CF_BUG)
MONFLAGCHECK(isIvy, flag & CF_IVY)
MONFLAGCHECK(isMonsterPart, flag & CF_PART)
MONFLAGCHECK(isMutantIvy, flag & CF_MUTANTIVY)
MONFLAGCHECK(isAnyIvy, flag & CF_ANYIVY)
MONFLAGCHECK(isBulletType, flag & CF_BULLET)
MONFLAGCHECK(isDemon, flag & CF_DEMON)
MONFLAGCHECK(isWorm, flag & CF_WORM)
MONFLAGCHECK(isWitch, flag & CF_WITCH)
MONFLAGCHECK(isAngryBird, (flag & CF_BIRD) && !(flag & CF_FRIENDLY))
MONFLAGCHECK(isBird, flag & CF_BIRD)
MONFLAGCHECK(slowMover, flag & CF_SLOWMOVER)
MONFLAGCHECK(isMagneticPole, flag & CF_MAGNETIC)
MONFLAGCHECK(isSwitch, flag & CF_SWITCH)
MONFLAGCHECK(isGhost, flag & CF_GHOST)
MONFLAGCHECK(isShark, flag & CF_SHARK)
MONFLAGCHECK(isSlimeMover, flag & CF_SLIME)
MONFLAGCHECK(isDragon, flag & CF_DRAGON)
MONFLAGCHECK(isKraken, flag & CF_KRAKEN)
MONFLAGCHECK(isBlowableMonster, !(flag & CF_NOBLOW))
MONFLAGCHECK(isMultitile, flag & CF_MULTITILE)
MONFLAGCHECK(isLeader, flag & CF_LEADER)
MONFLAGCHECK(isFlyingType, flag & CF_FLYING)
MONFLAGCHECK(attackThruVine, flag & CF_ATTACK_THRU_VINE)
MONFLAGCHECK(attackNonAdjacent, flag & CF_ATTACK_NONADJACENT)
MONFLAGCHECK(noHighlight, flag & CF_NOHIGHLIGHT)
MONFLAGCHECK(isInactiveEnemyType, flag & CF_INACTIVE)
MONFLAGCHECK(isUnarmed, flag & CF_UNARMED)
MONFLAGCHECK(ignoresPlatesType, flag & CF_IGNORE_PLATE)
MONFLAGCHECK(isBull, flag & CF_BULL)
MONFLAGCHECK(isTroll, flag & CF_TROLL)
MONFLAGCHECK(ignoresSmellType, flag & CF_IGNORE_SMELL)
MONFLAGCHECK(isRatling, flag & CF_RATLING)
MONFLAGCHECK(isGhostMover, flag & CF_GHOSTMOVER)
MONFLAGCHECK(isPowerMonster, flag & CF_POWER)
2019-03-30 12:35:03 +00:00
MONFLAGCHECK(hasFacing, flag & CF_FACING)
ITEMFLAGCHECK(isElementalShard, flag & IF_SHARD)
ITEMFLAGCHECK(itemBurns, !(flag & IF_FIREPROOF))
ITEMFLAGCHECK(isProtectionOrb, flag & IF_PROTECTION)
ITEMFLAGCHECK(isEmpathyOrb, flag & IF_EMPATHY)
ITEMFLAGCHECK(isRangedOrb, flag & IF_RANGED)
2019-03-23 15:42:11 +00:00
ITEMFLAGCHECK(isRevivalOrb, flag & IF_REVIVAL)
#endif
eMonster movegroup(eMonster m);
2016-08-26 09:58:03 +00:00
// watery
2016-08-26 09:58:03 +00:00
EX bool boatStrandable(cell *c) {
2016-08-26 09:58:03 +00:00
return c->wall == waNone && (c->land == laLivefjord || c->land == laOcean);
}
// monster/wall types
EX bool isFireOrMagma(cell *w) {
return isFire(w) || w->wall == waMagma;
}
EX int mirrorcolor(bool mirrored) {
return winf[mirrored ? waMirror : waCloud].color;
2016-08-26 09:58:03 +00:00
}
EX bool isMounted(cell *c) {
if(c && c->monst && c->monst != moTentacleGhost && isMountable(c->monst)) {
2021-03-06 10:46:13 +00:00
for(int i: player_indices()) {
2018-02-27 22:43:21 +00:00
if(playerpos(i)->monst && sameMonster(c, playerpos(i)))
return true;
if(lastmountpos[i] && lastmountpos[i]->monst && sameMonster(c, lastmountpos[i]))
2017-03-23 10:53:57 +00:00
return true;
2018-02-27 22:43:21 +00:00
}
2017-03-23 10:53:57 +00:00
}
2018-02-27 22:43:21 +00:00
return false;
}
EX int itemclass(eItem it) { return iinf[it].itemclass; }
2016-08-26 09:58:03 +00:00
EX bool isFriendly(eMonster m) { return isFriendlyType(m); }
2016-08-26 09:58:03 +00:00
EX bool isFriendly(cell *c) {
return isMounted(c) || isFriendly(c->monst);
2016-08-26 09:58:03 +00:00
}
EX eThreatLevel get_threat_level(cell *c) {
if(!c->monst) return tlNoThreat;
if(isFriendly(c)) return tlNoThreat;
if(classflag(c->monst) & CF_HIGH_THREAT) return tlHighThreat;
if(classflag(c->monst) & CF_SPAM) return tlSpam;
return tlNormal;
}
EX bool isFriendlyOrBug(cell *c) { // or killable discord!
2016-08-26 09:58:03 +00:00
// do not attack the stunned Princess
if(isPrincess(c->monst) && c->stuntime) return false;
return isFriendly(c) || isBug(c) || (c->monst && markOrb(itOrbDiscord) && !c->stuntime);
}
EX bool cellUnstable(cell *c) {
2016-08-26 09:58:03 +00:00
return (c->land == laMotion && c->wall == waNone) || c->wall == waTrapdoor;
}
EX bool cellUnstableOrChasm(cell *c) {
2016-08-26 09:58:03 +00:00
return
(c->land == laMotion && c->wall == waNone) ||
c->wall == waChasm || c->wall == waTrapdoor;
}
EX eMonster elementalOf(eLand l) {
2016-08-26 09:58:03 +00:00
if(l == laEFire) return moFireElemental;
if(l == laEWater) return moWaterElemental;
if(l == laEAir) return moAirElemental;
if(l == laEEarth) return moEarthElemental;
return moNone;
}
EX eItem localshardof(eLand l) {
2017-03-23 10:53:57 +00:00
return eItem(itFireShard + (l - laEFire));
}
EX int snakelevel(cell *c) {
2018-10-25 00:43:14 +00:00
#if CAP_COMPLEX2
if(c->land == laBrownian && among(c->wall, waNone, waMineMine, waFire)) return min(c->landparam / brownian::level, 3);
#endif
return winf[c->wall].snakelevel;
2016-08-26 09:58:03 +00:00
}
// from-to
EX eSlimegroup slimegroup(cell *c) {
return winf[c->wall].sg;
2016-08-26 09:58:03 +00:00
}
EX bool isFlying(eMonster m) {
return isFlyingType(m) || checkOrb(m, itOrbAether);
2016-08-26 09:58:03 +00:00
}
EX bool survivesChasm(eMonster m) {
2016-08-26 09:58:03 +00:00
return isFlying(m);
}
EX bool ignoresPlates(eMonster m) {
return ignoresPlatesType(m) || isFlying(m);
2017-03-23 10:53:57 +00:00
}
EX bool isInactiveEnemy(cell *w, eMonster forwho) {
if(forwho != moPlayer) {
if(w->monst == moGreaterM || w->monst == moLesserM) return false;
if(w->monst == moGreater || w->monst == moLesser) return true;
}
if(isInactiveEnemyType(w->monst)) return true;
2016-08-26 09:58:03 +00:00
if(w->monst && ((forwho == moPlayer) ? realstuntime(w) : realstuntime(w) > 1) && !isFriendly(w))
return true;
return false;
}
// forpc = true (for PC), false (for golems)
EX bool isActiveEnemy(cell *w, eMonster forwho) {
2016-08-26 09:58:03 +00:00
if(((forwho == moPlayer) ? realstuntime(w) : realstuntime(w) > 1))
return false;
2017-12-30 14:12:15 +00:00
if(w->monst == passive_switch) return false;
2016-08-26 09:58:03 +00:00
if(w->monst == moNone) return false;
if(isFriendly(w)) return false;
if(isInactiveEnemy(w, forwho)) return false;
return true;
}
EX bool isArmedEnemy(cell *w, eMonster forwho) {
2018-01-02 10:15:42 +00:00
return w->monst != moCrystalSage && w->monst != moCrusher && isActiveEnemy(w, forwho);
2016-08-26 09:58:03 +00:00
}
EX bool eternalFire(cell *c) {
return c->land == laDryForest || (c->land == laPower && !smallbounded) || c->land == laMinefield ||
2016-08-26 09:58:03 +00:00
c->land == laEFire || c->land == laElementalWall;
}
EX bool haveRangedOrb() {
2016-08-26 09:58:03 +00:00
return
items[itOrbPsi] || items[itOrbDragon] || items[itOrbTeleport] ||
2017-03-23 10:53:57 +00:00
items[itOrbIllusion] || items[itOrbSpace] || items[itOrbAir] ||
2016-08-26 09:58:03 +00:00
items[itOrbFrog] || items[itOrbSummon] || items[itOrbMatter] ||
items[itRevolver] || items[itOrbStunning] || items[itStrongWind] ||
items[itOrbDomination] || items[itOrbNature] || items[itOrbDash] ||
items[itOrbMorph] || items[itOrbPhasing];
2016-08-26 09:58:03 +00:00
}
EX bool isFriendlyGhost(eMonster m) {
2017-03-23 10:53:57 +00:00
return m == moFriendlyGhost || (markEmpathy(itOrbAether) && isFriendly(m));
2016-08-26 09:58:03 +00:00
}
EX bool isGhostAether(eMonster m) {
return isGhost(m) || checkOrb(m, itOrbAether);
}
EX bool survivesWater(eMonster m) {
2016-08-26 09:58:03 +00:00
return
m == moShark || m == moGreaterShark || m == moCShark ||
isGhostAether(m) || m == moWitchGhost || m == moShadow ||
2016-08-26 09:58:03 +00:00
isBird(m) || m == moWaterElemental || m == moAirElemental ||
2017-03-23 10:53:57 +00:00
isWorm(m) || isIvy(m) || isDragon(m) || isKraken(m) ||
m == moMutant || m == moFriendlyIvy ||
checkOrb(m, itOrbFish) ||
2020-03-02 17:00:03 +00:00
among(m, moPike, moRusalka) ||
2016-08-26 09:58:03 +00:00
m == moTortoise; // Tortoises and Ivies survive, but don't go through water
}
// survives Mercury or Sulphur or Lava
EX bool survivesPoison(eMonster m, eWall p) {
return
isGhostAether(m) || m == moWitchGhost || m == moShadow ||
isBird(m) || m == moAirElemental || isDragon(m) || isWorm(m);
}
2017-03-23 10:53:57 +00:00
// flying even if stunned
EX bool isPermanentFlying(eMonster m) {
return m == moAirElemental || isGhostAether(m);
2017-03-23 10:53:57 +00:00
}
2021-05-21 23:40:55 +00:00
EX bool isLuckyLand(eLand l) {
2021-05-27 14:35:11 +00:00
return among(l, laIce, laDesert, laDeadCaves, laOvergrown, laDice);
2021-05-21 23:40:55 +00:00
}
EX bool survivesFire(eMonster m) {
2016-08-26 09:58:03 +00:00
return
isGhostAether(m) || m == moWitchWinter || m == moWitchGhost ||
2016-08-26 09:58:03 +00:00
m == moBomberbird || m == moTameBomberbird || m == moTameBomberbirdMoved ||
checkOrb(m, itOrbWinter) || m == moFireElemental ||
2017-03-23 10:53:57 +00:00
isDragon(m) || m == moShadow;
2016-08-26 09:58:03 +00:00
}
EX bool survivesWall(eMonster m) {
return isGhostAether(m);
2016-08-26 09:58:03 +00:00
}
EX bool survivesThorns(eMonster m) {
return isGhostAether(m) || m == moSkeleton || m == moDraugr;
2016-08-26 09:58:03 +00:00
}
EX bool survivesFall(eMonster m) {
return isBird(m) || m == moAirElemental || m == moSkeleton || isDragon(m) || m == moShadow || isGhostAether(m);
2016-08-26 09:58:03 +00:00
}
2019-08-09 21:24:33 +00:00
EX bool checkOrb(eMonster m1, eItem orb) {
2016-08-26 09:58:03 +00:00
if(m1 == moPlayer) return markOrb(orb);
if(isFriendly(m1)) return markEmpathy(orb);
return false;
}
2019-08-09 21:24:33 +00:00
EX bool checkOrb2(eMonster m1, eItem orb) {
2017-03-23 10:53:57 +00:00
if(m1 == moPlayer) return markOrb2(orb);
if(isFriendly(m1)) return markEmpathy2(orb);
return false;
}
EX bool ignoresSmell(eMonster m) {
2019-03-23 15:38:34 +00:00
return ignoresSmellType(m) || checkOrb(m, itOrbBeauty) || checkOrb(m, itOrbAether) || checkOrb(m, itOrbShield);
2017-03-23 10:53:57 +00:00
}
EX bool highwall(cell *c) {
2017-03-23 10:53:57 +00:00
if(c->wall == waGlass) return false;
if(wmescher && wmspatial && c->wall == waBarrier && c->land == laOceanWall)
return false;
// if(wmspatial && isTree(c)) return false;
if(isGrave(c->wall)) return true;
2017-07-16 21:00:55 +00:00
if(c->wall == waMirrorWall) return false;
2019-02-28 16:06:53 +00:00
if(c->wall == waEditStatue) return false;
2017-03-23 10:53:57 +00:00
return winf[c->wall].glyph == '#' || c->wall == waClosedGate;
}
EX int chasmgraph(cell *c) {
2017-07-04 13:38:33 +00:00
if(c->wall == waChasm || c->wall == waInvisibleFloor) return 2;
2017-03-23 10:53:57 +00:00
if(isChasmy(c)) return 1;
if(isWateryOrBoat(c)) return 1;
2020-02-26 00:15:30 +00:00
if(c->wall == waShallow) return 1;
2017-03-23 10:53:57 +00:00
if(wmescher && c->wall == waBarrier && c->land == laOceanWall) return 1;
if(c->wall == waReptileBridge) return 1;
return 0;
}
EX bool conegraph(cell *c) {
return ((wmescher && wmspatial) || wmascii3) && (conegraphtype(c) || (c->wall == waBarrier && c->land == laOceanWall));
2017-03-23 10:53:57 +00:00
}
2020-02-29 19:45:01 +00:00
/** Determine the power of a frog monster. Also used to determine whether monster is a frog. */
EX eItem frog_power(eMonster m) {
if(m == moFrog) return itOrbFrog;
if(m == moPhaser) return itOrbPhasing;
if(m == moVaulter) return itOrbDash;
return itNone;
}
EX bool hornStuns(cell *c) {
2017-03-23 10:53:57 +00:00
eMonster m = c->monst;
return
m == moRagingBull || m == moSleepBull || m == moHerdBull ||
m == moButterfly || m == moGreater || m == moGreaterM || m == moDraugr ||
m == moHedge || m == moFlailer || m == moVizier || m == moReptile || m == moSalamander ||
m == moPair || m == moAltDemon || m == moHexDemon || m == moMonk || m == moCrusher ||
2018-12-16 23:04:59 +00:00
attackJustStuns(c, AF_NORMAL, moNone);
2017-03-23 10:53:57 +00:00
}
2020-03-02 01:37:59 +00:00
/** changing this wall for whatever reason may cause the game to crash */
EX bool do_not_touch_this_wall(cell *c) {
2020-03-07 23:01:40 +00:00
return among(c->wall, waMirrorWall, waBarrier, waRoundTable, waWarpGate);
2020-03-02 01:37:59 +00:00
}
2018-08-21 13:37:59 +00:00
EX bool is_paired(eMonster m) {
return among(m, moPair, moNorthPole, moSouthPole);
}
2021-05-30 11:43:17 +00:00
EX bool isDie(eMonster m) {
return among(m, moAnimatedDie, moAngryDie);
}
EX bool isDie(eWall w) {
return among(w, waRichDie, waHappyDie);
}
}