mirror of
				https://github.com/zenorogue/hyperrogue.git
				synced 2025-10-31 05:52:59 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			417 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			417 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Hyperbolic Rogue - Flags
 | |
| 
 | |
| // Copyright (C) 2011-2019 Zeno Rogue, see 'hyper.cpp' for details
 | |
| 
 | |
| /** \file flags.cpp
 | |
|  *  \brief Implementation of various simple flags for lands, items, monsters, and walls.
 | |
|  */
 | |
| 
 | |
| #include "hyper.h"
 | |
| namespace hr {
 | |
| 
 | |
| #if HDR
 | |
| 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)
 | |
| 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)
 | |
| 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)
 | |
| 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)
 | |
| MONFLAGCHECK(hasFacing, flag & CF_FACING)
 | |
| MONFLAGCHECK(isFrog, flag & CF_FROG)
 | |
| 
 | |
| 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)
 | |
| ITEMFLAGCHECK(isRevivalOrb, flag & IF_REVIVAL)
 | |
| #endif
 | |
| 
 | |
| eMonster movegroup(eMonster m);
 | |
| 
 | |
| // watery
 | |
| 
 | |
| EX bool boatStrandable(cell *c) {
 | |
|   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;
 | |
|   }
 | |
| 
 | |
| EX bool isMounted(cell *c) {
 | |
|   if(c && c->monst && c->monst != moTentacleGhost && isMountable(c->monst)) {
 | |
|     for(int i: player_indices()) {
 | |
|       if(playerpos(i)->monst && sameMonster(c, playerpos(i))) 
 | |
|         return true;
 | |
|       if(lastmountpos[i] && lastmountpos[i]->monst && sameMonster(c, lastmountpos[i]))
 | |
|         return true;
 | |
|       }
 | |
|     }
 | |
|   return false;
 | |
|   }
 | |
| 
 | |
| EX int itemclass(eItem it) { return iinf[it].itemclass; }
 | |
| 
 | |
| EX bool isFriendly(eMonster m) { return isFriendlyType(m); }
 | |
| 
 | |
| EX bool isFriendly(cell *c) { 
 | |
|   return isMounted(c) || isFriendly(c->monst); 
 | |
|   }
 | |
| 
 | |
| 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!
 | |
|   // 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) {
 | |
|   return (c->land == laMotion && c->wall == waNone) || c->wall == waTrapdoor;
 | |
|   }
 | |
| 
 | |
| EX bool cellUnstableOrChasm(cell *c) {
 | |
|   return 
 | |
|     (c->land == laMotion && c->wall == waNone) || 
 | |
|     c->wall == waChasm || c->wall == waTrapdoor;
 | |
|   }
 | |
| 
 | |
| EX eMonster elementalOf(eLand l) {
 | |
|   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) {
 | |
|   return eItem(itFireShard + (l - laEFire));
 | |
|   }
 | |
| 
 | |
| EX int snakelevel(cell *c) { 
 | |
| #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;
 | |
|   }
 | |
| 
 | |
| // from-to
 | |
| 
 | |
| EX eSlimegroup slimegroup(cell *c) {
 | |
|   return winf[c->wall].sg;
 | |
|   }
 | |
| 
 | |
| EX bool isFlying(eMonster m) {
 | |
|   return isFlyingType(m) || checkOrb(m, itOrbAether);
 | |
|   }
 | |
| 
 | |
| EX bool survivesChasm(eMonster m) {
 | |
|   return isFlying(m);
 | |
|   }
 | |
| 
 | |
| EX bool ignoresPlates(eMonster m) {
 | |
|   return ignoresPlatesType(m) || isFlying(m);
 | |
|   }
 | |
| 
 | |
| 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;
 | |
|   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) {
 | |
|   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;
 | |
|   return true;
 | |
|   }
 | |
| 
 | |
| EX bool isArmedEnemy(cell *w, eMonster forwho) {
 | |
|   return w->monst != moCrystalSage && w->monst != moCrusher && isActiveEnemy(w, forwho);
 | |
|   }
 | |
| 
 | |
| EX bool eternalFire(cell *c) {
 | |
|   return c->land == laDryForest || (c->land == laPower && !smallbounded) || c->land == laMinefield ||
 | |
|     c->land == laEFire || c->land == laElementalWall;
 | |
|   }
 | |
|   
 | |
| EX bool haveRangedOrb() {
 | |
|   return 
 | |
|     items[itOrbPsi] || items[itOrbDragon] || items[itOrbTeleport] ||
 | |
|     items[itOrbIllusion] || items[itOrbSpace] || items[itOrbAir] ||
 | |
|     items[itOrbFrog] || items[itOrbSummon] || items[itOrbMatter] ||
 | |
|     items[itRevolver] || items[itOrbStunning] || items[itStrongWind] ||
 | |
|     items[itOrbDomination] || items[itOrbNature] || items[itOrbDash] ||
 | |
|     items[itOrbMorph] || items[itOrbPhasing];
 | |
|   }
 | |
| 
 | |
| EX bool isFriendlyGhost(eMonster m) {
 | |
|   return m == moFriendlyGhost || (markEmpathy(itOrbAether) && isFriendly(m));
 | |
|   }
 | |
| 
 | |
| EX bool isGhostAether(eMonster m) {
 | |
|   return isGhost(m) || checkOrb(m, itOrbAether);
 | |
|   }
 | |
| 
 | |
| EX bool survivesWater(eMonster m) {
 | |
|   return 
 | |
|     m == moShark || m == moGreaterShark || m == moCShark || 
 | |
|     isGhostAether(m) || m == moWitchGhost || m == moShadow ||
 | |
|     isBird(m) || m == moWaterElemental || m == moAirElemental ||
 | |
|     isWorm(m) || isIvy(m) || isDragon(m) || isKraken(m) ||
 | |
|     m == moMutant || m == moFriendlyIvy || 
 | |
|     checkOrb(m, itOrbFish) ||
 | |
|     among(m, moPike, moRusalka) ||
 | |
|     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);
 | |
|   }
 | |
| 
 | |
| // flying even if stunned
 | |
| EX bool isPermanentFlying(eMonster m) {
 | |
|   return m == moAirElemental || isGhostAether(m);
 | |
|   }
 | |
| 
 | |
| EX bool isLuckyLand(eLand l) {
 | |
|   return among(l, laIce, laDesert, laDeadCaves, laOvergrown, laDice);
 | |
|   }
 | |
| 
 | |
| EX bool survivesFire(eMonster m) {
 | |
|   return
 | |
|     isGhostAether(m) || m == moWitchWinter || m == moWitchGhost ||
 | |
|     m == moBomberbird || m == moTameBomberbird || m == moTameBomberbirdMoved ||
 | |
|     checkOrb(m, itOrbWinter) || m == moFireElemental ||
 | |
|     isDragon(m) || m == moShadow;
 | |
|   }
 | |
| 
 | |
| EX bool survivesWall(eMonster m) {
 | |
|   return isGhostAether(m);
 | |
|   }
 | |
| 
 | |
| EX bool survivesThorns(eMonster m) {
 | |
|   return isGhostAether(m) || m == moSkeleton || m == moDraugr;
 | |
|   }
 | |
| 
 | |
| EX bool survivesFall(eMonster m) {
 | |
|   return isBird(m) || m == moAirElemental || m == moSkeleton || isDragon(m) || m == moShadow || isGhostAether(m);
 | |
|   }
 | |
| 
 | |
| EX bool checkOrb(eMonster m1, eItem orb) {
 | |
|   if(m1 == moPlayer) return markOrb(orb);
 | |
|   if(isFriendly(m1)) return markEmpathy(orb);
 | |
|   return false;
 | |
|   }
 | |
| 
 | |
| EX bool checkOrb2(eMonster m1, eItem orb) {
 | |
|   if(m1 == moPlayer) return markOrb2(orb);
 | |
|   if(isFriendly(m1)) return markEmpathy2(orb);
 | |
|   return false;
 | |
|   }
 | |
| 
 | |
| EX bool ignoresSmell(eMonster m) {
 | |
|   return ignoresSmellType(m) || checkOrb(m, itOrbBeauty) || checkOrb(m, itOrbAether) || checkOrb(m, itOrbShield);
 | |
|   }
 | |
| 
 | |
| EX bool highwall(cell *c) {
 | |
|   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;
 | |
|   if(c->wall == waMirrorWall) return false;
 | |
|   if(c->wall == waEditStatue) return false;
 | |
|   return winf[c->wall].glyph == '#' || c->wall == waClosedGate;
 | |
|   }
 | |
| 
 | |
| EX spatial_info get_spatial_info(cell *c) {
 | |
|   #define F(x) Flag((int) SIDE::x)
 | |
|   if(cellUnstable(c))
 | |
|     return spatial_info{SIDE::FLOOR, SIDE::FLOOR, 0, 0};
 | |
|   if(c->wall == waChasm || c->wall == waInvisibleFloor)
 | |
|     return spatial_info{SIDE::INFDEEP, SIDE::INFDEEP, 0, 0};
 | |
|   if(c->wall == waBarrier && wmescher && c->land == laOceanWall)
 | |
|     return spatial_info{SIDE::WATERLEVEL, SIDE::DEEP, F(DEEP), 0};
 | |
|   if(c->wall == waReptile)
 | |
|     return spatial_info{SIDE::FLOOR, SIDE::FLOOR, F(FLOOR) | F(DEEP), 0};
 | |
|   if(c->wall == waShallow)
 | |
|     return spatial_info{SIDE::WATERLEVEL, SIDE::SHALLOW, F(SHALLOW) | F(DEEP), 0};
 | |
|   if(isWateryOrBoat(c) || isChasmy(c))
 | |
|     return spatial_info{SIDE::WATERLEVEL, SIDE::DEEP, F(DEEP), 0};
 | |
|   if(among(c->wall, waReptileBridge, waGargoyleFloor, waGargoyleBridge, waTempFloor, waTempBridge, waPetrifiedBridge, waFrozenLake))
 | |
|     return spatial_info{SIDE::WATERLEVEL, SIDE::DEEP, F(WATERLEVEL) | F(DEEP), 0};
 | |
|   int slev = snakelevel(c);
 | |
|   if(slev == 1)
 | |
|     return spatial_info{SIDE::RED1, SIDE::RED1, F(RED1) | F(FLOOR) | F(WATERLEVEL) | F(SHALLOW) | F(DEEP), 1};
 | |
|   if(slev == 2)
 | |
|     return spatial_info{SIDE::RED2, SIDE::RED2, F(RED1) | F(RED2) | F(FLOOR) | F(WATERLEVEL) | F(SHALLOW) | F(DEEP), 2};
 | |
|   if(slev == 3)
 | |
|     return spatial_info{SIDE::RED3, SIDE::RED3, F(RED1) | F(RED2) | F(RED3) | F(FLOOR) | F(WATERLEVEL) | F(SHALLOW) | F(DEEP), 3};
 | |
|   if(highwall(c) && !conegraph(c) && c->wall != waRose)
 | |
|     return spatial_info{SIDE::WALL, SIDE::WALL, F(WALL) | F(FLOOR) | F(WATERLEVEL) | F(SHALLOW) | F(DEEP), 0};
 | |
|   return spatial_info{SIDE::FLOOR, SIDE::FLOOR, F(FLOOR) | F(WATERLEVEL) | F(SHALLOW) | F(DEEP), 0};
 | |
|   #undef F
 | |
|   }
 | |
| 
 | |
| EX bool conegraph(cell *c) {
 | |
|   return ((wmescher && wmspatial) || wmascii3) && (conegraphtype(c) || (c->wall == waBarrier && c->land == laOceanWall));
 | |
|   }
 | |
| 
 | |
| /** 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) {
 | |
|   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 ||
 | |
|     attackJustStuns(c, AF_NORMAL, moNone);
 | |
|   }
 | |
| 
 | |
| /** changing this wall for whatever reason may cause the game to crash */
 | |
| EX bool do_not_touch_this_wall(cell *c) {
 | |
|   return among(c->wall, waMirrorWall, waBarrier, waRoundTable, waWarpGate);
 | |
|   }
 | |
| 
 | |
| EX bool is_paired(eMonster m) {
 | |
|   return among(m, moPair, moNorthPole, moSouthPole);
 | |
|   }
 | |
| 
 | |
| EX bool isDie(eMonster m) {
 | |
|   return among(m, moAnimatedDie, moAngryDie);
 | |
|   }
 | |
| 
 | |
| EX bool isDie(eWall w) {
 | |
|   return among(w, waRichDie, waHappyDie);
 | |
|   }
 | |
| 
 | |
| }
 | 
