diff --git a/Source/missiles.cpp b/Source/missiles.cpp index 21a3cf401..bd5d2845f 100644 --- a/Source/missiles.cpp +++ b/Source/missiles.cpp @@ -472,7 +472,17 @@ void RotateBlockedMissile(Missile &missile) missile.setFrameGroupRaw(dir); } -void CheckMissileCol(Missile &missile, DamageType damageType, int minDamage, int maxDamage, bool isDamageShifted, Point position, bool dontDeleteOnCollision) +bool CheckCanHitOnlyWalking(const Missile &missile, const ActorPosition &position, Direction wallDir) +{ + Point other = missile.position.tile + wallDir; + if (missile.position.tile == position.tile && other == position.future) + return true; + if (missile.position.tile == position.future && other == position.tile) + return true; + return false; +} + +void CheckMissileCol(Missile &missile, DamageType damageType, int minDamage, int maxDamage, bool isDamageShifted, Point position, bool dontDeleteOnCollision, std::optional onlyHitWalking = {}) { if (!InDungeonBounds(position)) return; @@ -481,7 +491,7 @@ void CheckMissileCol(Missile &missile, DamageType damageType, int minDamage, int int mid = dMonster[position.x][position.y]; if (mid != 0) { Monster &monster = Monsters[std::abs(mid) - 1]; - if (mid > 0 || monster.mode == MonsterMode::Petrified) { + if (onlyHitWalking.has_value() ? (monster.isWalking() && CheckCanHitOnlyWalking(missile, monster.position, *onlyHitWalking)) : (mid > 0 || monster.mode == MonsterMode::Petrified)) { if (missile.IsTrap() || (missile._micaster == TARGET_PLAYERS && ( // or was fired by a monster and monster.isPlayerMinion() != Monsters[missile._misource].isPlayerMinion() // the monsters are on opposing factions @@ -504,8 +514,8 @@ void CheckMissileCol(Missile &missile, DamageType damageType, int minDamage, int bool isPlayerHit = false; bool blocked = false; - Player *player = PlayerAtPosition(position, true); - if (player != nullptr) { + Player *player = PlayerAtPosition(position, !onlyHitWalking.has_value()); + if (player != nullptr && (onlyHitWalking.has_value() ? (player->isWalking() && CheckCanHitOnlyWalking(missile, player->position, *onlyHitWalking)) : true)) { if (missile._micaster != TARGET_BOTH && !missile.IsTrap()) { if (missile._micaster == TARGET_MONSTERS) { if (player->getId() != missile._misource) @@ -758,6 +768,7 @@ bool TryGrowWall(int id, MissileID type, Point position, Direction growDirection Displacement travelled = Displacement(Right(Right(growDirection))).worldToNormalScreen() * 30; // Move the wall to the edge to the next tile, but not over it missile->position.traveled += travelled; missile->_miDrawFlag = false; + missile->var3 = static_cast(Left(Left(growDirection))) + 1; UpdateMissilePos(*missile); assert(gapPos == missile->position.tile); // Check that the tile we checked against (CanPlaceWall) didn't change } @@ -3052,7 +3063,10 @@ void ProcessFireWall(Missile &missile) missile._miAnimFrame = 13; missile._miAnimAdd = -1; } - CheckMissileCol(missile, GetMissileData(missile._mitype).damageType(), missile._midam, missile._midam, true, missile.position.tile, true); + std::optional onlyHitWalking = {}; + if (missile.var3 != 0) + onlyHitWalking = static_cast(missile.var3 - 1); + CheckMissileCol(missile, GetMissileData(missile._mitype).damageType(), missile._midam, missile._midam, true, missile.position.tile, true, onlyHitWalking); if (missile.duration == 0) { missile._miDelFlag = true; AddUnLight(missile._mlid); @@ -3184,7 +3198,10 @@ void ProcessLightningWall(Missile &missile) { missile.duration--; const int range = missile.duration; - CheckMissileCol(missile, GetMissileData(missile._mitype).damageType(), missile._midam, missile._midam, true, missile.position.tile, false); + std::optional onlyHitWalking = {}; + if (missile.var3 != 0) + onlyHitWalking = static_cast(missile.var3 - 1); + CheckMissileCol(missile, GetMissileData(missile._mitype).damageType(), missile._midam, missile._midam, true, missile.position.tile, false, onlyHitWalking); if (missile._miHitFlag) missile.duration = range; if (missile.duration == 0)