Browse Source

Harmonize grow logic of firewall and flamewave

pull/8252/head
obligaron 8 months ago committed by Anders Jenbo
parent
commit
38389b3bf4
  1. 155
      Source/missiles.cpp

155
Source/missiles.cpp

@ -731,20 +731,38 @@ bool GuardianTryFireAt(Missile &missile, Point target)
return true;
}
bool GrowWall(int id, Point position, Point target, MissileID type, int spellLevel, int damage, bool skipWall = false)
bool CanPlaceWall(Point position)
{
if (!InDungeonBounds(position))
return false;
[[maybe_unused]] const int dp = dPiece[position.x][position.y];
assert(dp <= MAXTILES && dp >= 0);
if (TileHasAny(position, TileProperties::BlockMissile) || !InDungeonBounds(target)) {
return false;
}
return !TileHasAny(position, TileProperties::BlockMissile);
}
Missile *PlaceWall(int id, MissileID type, Point position, Direction direction, int spellLevel, int damage)
{
return AddMissile(position, position + direction, direction, type, TARGET_BOTH, id, damage, spellLevel);
}
if (!skipWall)
AddMissile(position, position, Direction::South, type, TARGET_BOTH, id, damage, spellLevel);
bool TryGrowWall(int id, MissileID type, Point position, Direction direction, int spellLevel, int damage)
{
if (!CanPlaceWall(position))
return false;
PlaceWall(id, type, position, direction, spellLevel, damage);
return true;
}
std::optional<Point> MoveWallToNextPosition(Point position, Direction growDirection)
{
Point nextPosition = position + growDirection;
if (!InDungeonBounds(nextPosition))
return std::nullopt;
return nextPosition;
}
/** @brief Sync missile position with parent missile */
void SyncPositionWithParent(Missile &missile, const AddMissileParameter &parameter)
{
@ -3725,45 +3743,6 @@ void ProcessRhino(Missile &missile)
PutMissile(missile);
}
/*
* @brief Moves the control missile towards the right and grows walls.
* @param missile The control missile.
* @param type The missile ID of the wall missile.
* @param dmg The damage of the wall missile.
*/
static void ProcessWallControlLeft(Missile &missile, const MissileID type, const int dmg)
{
const Point leftPosition = { missile.var1, missile.var2 };
const Point target = leftPosition + static_cast<Direction>(missile.var3);
if (!missile.limitReached && GrowWall(missile._misource, leftPosition, target, type, missile._mispllvl, dmg)) {
missile.var1 = target.x;
missile.var2 = target.y;
} else {
missile.limitReached = true;
}
}
/*
* @brief Moves the control missile towards the right and grows walls.
* @param missile The control missile.
* @param type The missile ID of the wall missile.
* @param dmg The damage of the wall missile.
* @param skipTile Should the tile be skipped.
*/
static void ProcessWallControlRight(Missile &missile, const MissileID type, const int dmg, const bool skipWall = false)
{
const Point rightPosition = { missile.var5, missile.var6 };
const Point target = rightPosition + static_cast<Direction>(missile.var4);
if (missile.var7 == 0 && GrowWall(missile._misource, rightPosition, target, type, missile._mispllvl, dmg, skipWall)) {
missile.var5 = target.x;
missile.var6 = target.y;
} else {
missile.var7 = 1;
}
}
void ProcessWallControl(Missile &missile)
{
missile.duration--;
@ -3792,9 +3771,43 @@ void ProcessWallControl(Missile &missile)
const Point leftPosition = { missile.var1, missile.var2 };
const Point rightPosition = { missile.var5, missile.var6 };
const Direction leftDirection = static_cast<Direction>(missile.var3);
const Direction rightDirection = static_cast<Direction>(missile.var4);
bool isStart = leftPosition == rightPosition;
std::optional<Point> nextLeftPosition = std::nullopt;
std::optional<Point> nextRightPosition = std::nullopt;
if (isStart) {
if (!CanPlaceWall(leftPosition)) {
missile._miDelFlag = true;
return;
}
PlaceWall(missile._misource, type, leftPosition, leftDirection, missile._mispllvl, dmg);
nextLeftPosition = MoveWallToNextPosition(leftPosition, leftDirection);
nextRightPosition = MoveWallToNextPosition(rightPosition, rightDirection);
} else {
if (!missile.limitReached && TryGrowWall(missile._misource, type, leftPosition, Direction::South, missile._mispllvl, dmg)) {
nextLeftPosition = MoveWallToNextPosition(leftPosition, leftDirection);
}
if (missile.var7 == 0 && TryGrowWall(missile._misource, type, rightPosition, Direction::South, missile._mispllvl, dmg)) {
nextRightPosition = MoveWallToNextPosition(rightPosition, rightDirection);
}
}
ProcessWallControlLeft(missile, type, dmg);
ProcessWallControlRight(missile, type, dmg, leftPosition == rightPosition);
if (nextLeftPosition) {
missile.var1 = nextLeftPosition->x;
missile.var2 = nextLeftPosition->y;
} else {
missile.limitReached = true;
}
if (nextRightPosition) {
missile.var5 = nextRightPosition->x;
missile.var6 = nextRightPosition->y;
} else {
missile.var7 = 1;
}
}
void ProcessInfravision(Missile &missile)
@ -3835,39 +3848,27 @@ void ProcessApocalypse(Missile &missile)
void ProcessFlameWaveControl(Missile &missile)
{
bool f1 = false;
bool f2 = false;
const int id = missile._misource;
const Direction pdir = Players[id]._pdir;
const Point src = missile.position.tile;
const Direction sd = GetDirection(src, { missile.var1, missile.var2 });
const Direction dira = Left(Left(sd));
const Direction dirb = Right(Right(sd));
Point na = src + sd;
[[maybe_unused]] int pn = dPiece[na.x][na.y];
assert(pn >= 0 && pn <= MAXTILES);
if (!TileHasAny(na, TileProperties::BlockMissile)) {
const Direction pdir = Players[id]._pdir;
AddMissile(na, na + sd, pdir, MissileID::FlameWave, TARGET_MONSTERS, id, 0, missile._mispllvl);
na += dira;
Point nb = src + sd + dirb;
for (int j = 0; j < (missile._mispllvl / 2) + 2; j++) {
pn = dPiece[na.x][na.y]; // BUGFIX: dPiece is accessed before check against dungeon size and 0
assert(pn >= 0 && pn <= MAXTILES);
if (TileHasAny(na, TileProperties::BlockMissile) || f1 || !InDungeonBounds(na)) {
f1 = true;
} else {
AddMissile(na, na + sd, pdir, MissileID::FlameWave, TARGET_MONSTERS, id, 0, missile._mispllvl);
na += dira;
}
pn = dPiece[nb.x][nb.y]; // BUGFIX: dPiece is accessed before check against dungeon size and 0
assert(pn >= 0 && pn <= MAXTILES);
if (TileHasAny(nb, TileProperties::BlockMissile) || f2 || !InDungeonBounds(nb)) {
f2 = true;
} else {
AddMissile(nb, nb + sd, pdir, MissileID::FlameWave, TARGET_MONSTERS, id, 0, missile._mispllvl);
nb += dirb;
}
const Point start = src + sd;
if (CanPlaceWall(start)) {
PlaceWall(id, MissileID::FlameWave, start, pdir, missile._mispllvl, 0);
int segmentsToAdd = (missile._mispllvl / 2) + 2;
Point left = start;
const Direction dirLeft = Left(Left(sd));
for (int j = 0; j < segmentsToAdd; j++) {
left += dirLeft;
if (!TryGrowWall(id, MissileID::FlameWave, left, pdir, missile._mispllvl, 0))
break;
}
Point right = start;
const Direction dirRight = Right(Right(sd));
for (int j = 0; j < segmentsToAdd; j++) {
right += dirRight;
if (!TryGrowWall(id, MissileID::FlameWave, right, pdir, missile._mispllvl, 0))
break;
}
}

Loading…
Cancel
Save