Permalink
Browse files

fix multiple falling unit behaviour

  • Loading branch information...
Warboy1982 committed Jul 9, 2018
1 parent 642c7bb commit 49119b2160f616d6643e081e8d1c2285713f876c
Showing with 90 additions and 86 deletions.
  1. +90 −86 src/Battlescape/UnitFallBState.cpp
@@ -146,14 +146,14 @@ void UnitFallBState::think()
tilesToFallInto.push_back(tileTarget);
}
}
std::list<BattleUnit*> *fallingUnits = _parent->getSave()->getFallingUnits();
// Check each tile for units that need moving out of the way.
for (std::vector<Tile*>::iterator i = tilesToFallInto.begin(); i < tilesToFallInto.end(); ++i)
{
BattleUnit *unitBelow = (*i)->getUnit();
if (unitBelow
&& (*unit) != unitBelow // falling units do not fall on themselves
&& !(std::find(unitsToMove.begin(), unitsToMove.end(), unitBelow) != unitsToMove.end())) // already added
&& !(std::find(fallingUnits->begin(), fallingUnits->end(), unitBelow) != fallingUnits->end()) // ignore falling units (including self)
&& !(std::find(unitsToMove.begin(), unitsToMove.end(), unitBelow) != unitsToMove.end())) // ignore already added units
{
unitsToMove.push_back(unitBelow);
}
@@ -166,89 +166,6 @@ void UnitFallBState::think()
&& (*unit)->getMovementType() != MT_FLY
&& (*unit)->getWalkingPhase() == 0;
// Find somewhere to move the unit(s) endanger of being squashed.
if (!unitsToMove.empty())
{
std::vector<Tile*> escapeTiles;
for (std::vector<BattleUnit*>::iterator ub = unitsToMove.begin(); ub < unitsToMove.end(); )
{
BattleUnit *unitBelow = (*ub);
bool escapeFound = false;
// We need to move all sections of the unit out of the way.
std::vector<Position> bodySections;
for (int x = unitBelow->getArmor()->getSize() - 1; x >= 0; --x)
{
for (int y = unitBelow->getArmor()->getSize() - 1; y >= 0; --y)
{
Position bs = unitBelow->getPosition() + Position(x, y, 0);
bodySections.push_back(bs);
}
}
// Check in each compass direction.
for (int dir = 0; dir < Pathfinding::DIR_UP && !escapeFound; dir++)
{
Position offset;
Pathfinding::directionToVector(dir, &offset);
for (std::vector<Position>::iterator bs = bodySections.begin(); bs < bodySections.end(); )
{
Position originalPosition = (*bs);
Position endPosition = originalPosition + offset;
Tile *t = _parent->getSave()->getTile(endPosition);
Tile *bt = _parent->getSave()->getTile(endPosition + Position(0,0,-1));
bool aboutToBeOccupiedFromAbove = t && std::find(tilesToFallInto.begin(), tilesToFallInto.end(), t) != tilesToFallInto.end();
bool alreadyTaken = t && std::find(escapeTiles.begin(), escapeTiles.end(), t) != escapeTiles.end();
bool alreadyOccupied = t && t->getUnit() && (t->getUnit() != unitBelow);
bool movementBlocked = _parent->getSave()->getPathfinding()->getTUCost(originalPosition, dir, &endPosition, *ub, 0, false) == 255;
bool hasFloor = t && !t->hasNoFloor(bt);
bool unitCanFly = unitBelow->getMovementType() == MT_FLY;
bool canMoveToTile = t && !alreadyOccupied && !alreadyTaken && !aboutToBeOccupiedFromAbove && !movementBlocked && (hasFloor || unitCanFly);
if (canMoveToTile)
{
// Check next section of the unit.
++bs;
}
else
{
// Try next direction.
break;
}
// If all sections of the fallen onto unit can be moved, then we move it.
if (bs == bodySections.end())
{
if (_parent->getSave()->addFallingUnit(unitBelow))
{
escapeFound = true;
// Now ensure no other unit escapes to here too.
for (int x = unitBelow->getArmor()->getSize() - 1; x >= 0; --x)
{
for (int y = unitBelow->getArmor()->getSize() - 1; y >= 0; --y)
{
Tile *et = _parent->getSave()->getTile(t->getPosition() + Position(x,y,0));
escapeTiles.push_back(et);
}
}
Tile *bu = _parent->getSave()->getTile(originalPosition + Position(0,0,-1));
unitBelow->startWalking(dir, unitBelow->getPosition() + offset, bu, onScreen);
ub = unitsToMove.erase(ub);
}
}
}
}
if (!escapeFound)
{
unitBelow->knockOut(_parent);
ub = unitsToMove.erase(ub);
}
}
_parent->checkForCasualties(0,*unit);
}
// we are just standing around, we are done falling.
if ((*unit)->getStatus() == STATUS_STANDING)
{
@@ -295,6 +212,93 @@ void UnitFallBState::think()
}
}
// Find somewhere to move the unit(s) In danger of being squashed.
if (!unitsToMove.empty())
{
std::vector<Tile*> escapeTiles;
for (std::vector<BattleUnit*>::iterator ub = unitsToMove.begin(); ub < unitsToMove.end(); )
{
BattleUnit *unitBelow = (*ub);
bool escapeFound = false;
// We need to move all sections of the unit out of the way.
std::vector<Position> bodySections;
for (int x = unitBelow->getArmor()->getSize() - 1; x >= 0; --x)
{
for (int y = unitBelow->getArmor()->getSize() - 1; y >= 0; --y)
{
Position bs = unitBelow->getPosition() + Position(x, y, 0);
bodySections.push_back(bs);
}
}
// Check in each compass direction.
for (int dir = 0; dir < Pathfinding::DIR_UP && !escapeFound; dir++)
{
Position offset;
Pathfinding::directionToVector(dir, &offset);
for (std::vector<Position>::iterator bs = bodySections.begin(); bs < bodySections.end(); )
{
Position originalPosition = (*bs);
Position endPosition = originalPosition + offset;
Tile *t = _parent->getSave()->getTile(endPosition);
Tile *bt = _parent->getSave()->getTile(endPosition + Position(0,0,-1));
bool aboutToBeOccupiedFromAbove = t && std::find(tilesToFallInto.begin(), tilesToFallInto.end(), t) != tilesToFallInto.end();
bool alreadyTaken = t && std::find(escapeTiles.begin(), escapeTiles.end(), t) != escapeTiles.end();
bool alreadyOccupied = t && t->getUnit() && (t->getUnit() != unitBelow);
bool movementBlocked = _parent->getSave()->getPathfinding()->getTUCost(originalPosition, dir, &endPosition, *ub, 0, false) == 255;
bool hasFloor = t && !t->hasNoFloor(bt);
bool unitCanFly = unitBelow->getMovementType() == MT_FLY;
bool canMoveToTile = t && !alreadyOccupied && !alreadyTaken && !aboutToBeOccupiedFromAbove && !movementBlocked && (hasFloor || unitCanFly);
if (canMoveToTile)
{
// Check next section of the unit.
++bs;
}
else
{
// Try next direction.
break;
}
// If all sections of the fallen onto unit can be moved, then we move it.
if (bs == bodySections.end())
{
if (_parent->getSave()->addFallingUnit(unitBelow))
{
escapeFound = true;
// Now ensure no other unit escapes to here too.
for (int x = unitBelow->getArmor()->getSize() - 1; x >= 0; --x)
{
for (int y = unitBelow->getArmor()->getSize() - 1; y >= 0; --y)
{
Tile *et = _parent->getSave()->getTile(t->getPosition() + Position(x,y,0));
escapeTiles.push_back(et);
}
}
Tile *bu = _parent->getSave()->getTile(originalPosition + Position(0,0,-1));
unitBelow->startWalking(dir, unitBelow->getPosition() + offset, bu,
(unitBelow->getVisible() && _parent->getMap()->getCamera()->isOnScreen(unitBelow->getPosition(), true, unitBelow->getArmor()->getSize(), false)));

This comment has been minimized.

@Yankes

Yankes Aug 17, 2018

Contributor

You have bug there, param size should have 0 or 1 not 1 and 2 from armor->size(). Overall, should not this function be refactored and getting only unit? This hole expression is repeated multiple times (with unitBelow->getVisible()).

ub = unitsToMove.erase(ub);
}
}
}
}
if (!escapeFound)
{
// STOMP THAT GOOMBAH!
unitBelow->knockOut(_parent);
ub = unitsToMove.erase(ub);
}
}
_parent->checkForCasualties(0,0);
}
if (_parent->getSave()->getFallingUnits()->empty())
{
tilesToFallInto.clear();

0 comments on commit 49119b2

Please sign in to comment.