1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-06 09:09:40 +02:00

Fixing sieges, part 1

This commit is contained in:
Ivan Savenko
2022-11-27 20:01:52 +02:00
parent b5d1cb4996
commit 35576834c9
10 changed files with 74 additions and 66 deletions

View File

@@ -134,9 +134,9 @@ void CAttackAnimation::nextFrame()
if(!soundPlayed) if(!soundPlayed)
{ {
if(shooting) if(shooting)
CCS->soundh->playSound(battle_sound(attackingStack->getCreature(), shoot)); CCS->soundh->playSound(battle_sound(getCreature(), shoot));
else else
CCS->soundh->playSound(battle_sound(attackingStack->getCreature(), attack)); CCS->soundh->playSound(battle_sound(getCreature(), attack));
soundPlayed = true; soundPlayed = true;
} }
CBattleAnimation::nextFrame(); CBattleAnimation::nextFrame();
@@ -164,6 +164,14 @@ bool CAttackAnimation::checkInitialConditions()
return isEarliest(false); return isEarliest(false);
} }
const CCreature * CAttackAnimation::getCreature()
{
if (attackingStack->getCreature()->idNumber == CreatureID::ARROW_TOWERS)
return owner->siegeController->getTurretCreature();
else
return attackingStack->getCreature();
}
CAttackAnimation::CAttackAnimation(CBattleInterface *_owner, const CStack *attacker, BattleHex _dest, const CStack *defender) CAttackAnimation::CAttackAnimation(CBattleInterface *_owner, const CStack *attacker, BattleHex _dest, const CStack *defender)
: CBattleStackAnimation(_owner, attacker), : CBattleStackAnimation(_owner, attacker),
shooting(false), group(CCreatureAnim::SHOOT_FRONT), shooting(false), group(CCreatureAnim::SHOOT_FRONT),
@@ -767,7 +775,7 @@ void CShootingAnimation::setAnimationGroup()
//maximal angle in radians between straight horizontal line and shooting line for which shot is considered to be straight (absoulte value) //maximal angle in radians between straight horizontal line and shooting line for which shot is considered to be straight (absoulte value)
static const double straightAngle = 0.2; static const double straightAngle = 0.2;
double projectileAngle = atan2(shotTarget.y - shooterPos.y, std::abs(shotTarget.x - shooterPos.x)); double projectileAngle = -atan2(shotTarget.y - shooterPos.y, std::abs(shotTarget.x - shooterPos.x));
// Calculate projectile start position. Offsets are read out of the CRANIM.TXT. // Calculate projectile start position. Offsets are read out of the CRANIM.TXT.
if (projectileAngle > straightAngle) if (projectileAngle > straightAngle)
@@ -780,11 +788,7 @@ void CShootingAnimation::setAnimationGroup()
void CShootingAnimation::initializeProjectile() void CShootingAnimation::initializeProjectile()
{ {
const CCreature *shooterInfo = attackingStack->getCreature(); const CCreature *shooterInfo = getCreature();
if(shooterInfo->idNumber == CreatureID::ARROW_TOWERS)
shooterInfo = owner->siegeController->getTurretCreature();
Point shotTarget = owner->stacksController->getStackPositionAtHex(dest, attackedStack) + Point(225, 225); Point shotTarget = owner->stacksController->getStackPositionAtHex(dest, attackedStack) + Point(225, 225);
Point shotOrigin = stackAnimation(attackingStack)->pos.topLeft() + Point(222, 265); Point shotOrigin = stackAnimation(attackingStack)->pos.topLeft() + Point(222, 265);
int multiplier = stackFacingRight(attackingStack) ? 1 : -1; int multiplier = stackFacingRight(attackingStack) ? 1 : -1;
@@ -828,12 +832,25 @@ void CShootingAnimation::nextFrame()
return; return;
} }
// animation should be paused if there is an active projectile
if (projectileEmitted)
{
if (owner->projectilesController->hasActiveProjectile(attackingStack))
{
stackAnimation(attackingStack)->pause();
return;
}
else
stackAnimation(attackingStack)->play();
}
CAttackAnimation::nextFrame();
if (!projectileEmitted) if (!projectileEmitted)
{ {
const CCreature *shooterInfo = attackingStack->getCreature(); const CCreature *shooterInfo = getCreature();
if(shooterInfo->idNumber == CreatureID::ARROW_TOWERS) assert(stackAnimation(attackingStack)->isShooting());
shooterInfo = owner->siegeController->getTurretCreature();
// emit projectile once animation playback reached "climax" frame // emit projectile once animation playback reached "climax" frame
if ( stackAnimation(attackingStack)->getCurrentFrame() >= shooterInfo->animation.attackClimaxFrame ) if ( stackAnimation(attackingStack)->getCurrentFrame() >= shooterInfo->animation.attackClimaxFrame )
@@ -842,17 +859,13 @@ void CShootingAnimation::nextFrame()
return; return;
} }
} }
// animation should be paused if there is an active projectile
if (projectileEmitted && owner->projectilesController->hasActiveProjectile(attackingStack))
return;
CAttackAnimation::nextFrame();
} }
void CShootingAnimation::endAnim() void CShootingAnimation::endAnim()
{ {
assert(!owner->projectilesController->hasActiveProjectile(attackingStack));
assert(projectileEmitted);
// FIXME: is this possible? Animation is over but we're yet to fire projectile? // FIXME: is this possible? Animation is over but we're yet to fire projectile?
if (!projectileEmitted) if (!projectileEmitted)
{ {
@@ -1157,11 +1170,15 @@ void CEffectAnimation::endAnim()
{ {
CBattleAnimation::endAnim(); CBattleAnimation::endAnim();
boost::range::remove_if(owner->effectsController->battleEffects, auto & effects = owner->effectsController->battleEffects;
[&](const BattleEffect & elem)
{ for ( auto it = effects.begin(); it != effects.end(); )
return elem.effectID == ID; {
}); if (it->effectID == ID)
it = effects.erase(it);
else
it++;
}
delete this; delete this;
} }

View File

@@ -73,6 +73,8 @@ protected:
const CStack *attackedStack; const CStack *attackedStack;
const CStack *attackingStack; const CStack *attackingStack;
int attackingStackPosBeforeReturn; //for stacks with return_after_strike feature int attackingStackPosBeforeReturn; //for stacks with return_after_strike feature
const CCreature * getCreature();
public: public:
void nextFrame() override; void nextFrame() override;
void endAnim() override; void endAnim() override;

View File

@@ -106,7 +106,9 @@ void CBattleFieldController::redrawBackgroundWithHexes()
//prepare background graphic with hexes and shaded hexes //prepare background graphic with hexes and shaded hexes
backgroundWithHexes->draw(background, Point(0,0)); backgroundWithHexes->draw(background, Point(0,0));
owner->obstacleController->redrawBackgroundWithHexes(backgroundWithHexes); owner->obstacleController->showAbsoluteObstacles(backgroundWithHexes, Point(0,0));
if ( owner->siegeController )
owner->siegeController->showAbsoluteObstacles(backgroundWithHexes, Point(0,0));
if (settings["battle"]["stackRange"].Bool()) if (settings["battle"]["stackRange"].Bool())
{ {

View File

@@ -927,9 +927,9 @@ void CBattleInterface::show(SDL_Surface *to)
else else
{ {
fieldController->showBackgroundImage(canvas); fieldController->showBackgroundImage(canvas);
obstacleController->showAbsoluteObstacles(canvas); obstacleController->showAbsoluteObstacles(canvas, pos.topLeft());
if ( siegeController ) if ( siegeController )
siegeController->showAbsoluteObstacles(canvas); siegeController->showAbsoluteObstacles(canvas, pos.topLeft());
} }
fieldController->showHighlightedHexes(canvas); fieldController->showHighlightedHexes(canvas);

View File

@@ -109,7 +109,7 @@ void CBattleObstacleController::obstaclePlaced(const CObstacleInstance & oi)
//CCS->soundh->playSound(sound); //CCS->soundh->playSound(sound);
} }
void CBattleObstacleController::showAbsoluteObstacles(std::shared_ptr<CCanvas> canvas) void CBattleObstacleController::showAbsoluteObstacles(std::shared_ptr<CCanvas> canvas, const Point & offset)
{ {
//Blit absolute obstacles //Blit absolute obstacles
for(auto & oi : owner->curInt->cb->battleGetAllObstacles()) for(auto & oi : owner->curInt->cb->battleGetAllObstacles())
@@ -118,7 +118,7 @@ void CBattleObstacleController::showAbsoluteObstacles(std::shared_ptr<CCanvas> c
{ {
auto img = getObstacleImage(*oi); auto img = getObstacleImage(*oi);
if(img) if(img)
canvas->draw(img, Point(owner->pos.x + oi->getInfo().width, owner->pos.y + oi->getInfo().height)); canvas->draw(img, Point(offset.x + oi->getInfo().width, offset.y + oi->getInfo().height));
} }
} }
} }
@@ -196,17 +196,3 @@ Point CBattleObstacleController::getObstaclePosition(std::shared_ptr<IImage> ima
return r.topLeft(); return r.topLeft();
} }
void CBattleObstacleController::redrawBackgroundWithHexes(std::shared_ptr<CCanvas> to)
{
//draw absolute obstacles (cliffs and so on)
for(auto & oi : owner->curInt->cb->battleGetAllObstacles())
{
if(oi->obstacleType == CObstacleInstance::ABSOLUTE_OBSTACLE)
{
auto img = getObstacleImage(*oi);
if(img)
to->draw(img, Point(oi->getInfo().width, oi->getInfo().height));
}
}
}

View File

@@ -35,9 +35,7 @@ public:
void obstaclePlaced(const CObstacleInstance & oi); void obstaclePlaced(const CObstacleInstance & oi);
void showObstacles(SDL_Surface *to, std::vector<std::shared_ptr<const CObstacleInstance>> &obstacles); void showObstacles(SDL_Surface *to, std::vector<std::shared_ptr<const CObstacleInstance>> &obstacles);
void showAbsoluteObstacles(std::shared_ptr<CCanvas> canvas); void showAbsoluteObstacles(std::shared_ptr<CCanvas> canvas, const Point & offset);
void showBattlefieldObjects(std::shared_ptr<CCanvas> canvas, const BattleHex & location ); void showBattlefieldObjects(std::shared_ptr<CCanvas> canvas, const BattleHex & location );
void redrawBackgroundWithHexes(std::shared_ptr<CCanvas> to);
}; };

View File

@@ -246,7 +246,7 @@ bool CBattleProjectileController::hasActiveProjectile(const CStack * stack)
void CBattleProjectileController::createProjectile(const CStack * shooter, const CStack * target, Point from, Point dest) void CBattleProjectileController::createProjectile(const CStack * shooter, const CStack * target, Point from, Point dest)
{ {
const CCreature *shooterInfo = shooter->getCreature(); const CCreature *shooterInfo = getShooter(shooter);
std::shared_ptr<ProjectileBase> projectile; std::shared_ptr<ProjectileBase> projectile;
@@ -262,8 +262,8 @@ void CBattleProjectileController::createProjectile(const CStack * shooter, const
catapultProjectile->step = 0; catapultProjectile->step = 0;
catapultProjectile->steps = 0; catapultProjectile->steps = 0;
double animSpeed = AnimationControls::getProjectileSpeed() / 10; //double animSpeed = AnimationControls::getProjectileSpeed() / 10;
catapultProjectile->steps = std::round(std::abs((dest.x - from.x) / animSpeed)); //catapultProjectile->steps = std::round(std::abs((dest.x - from.x) / animSpeed));
} }
else else
{ {
@@ -312,16 +312,18 @@ void CBattleProjectileController::createProjectile(const CStack * shooter, const
} }
missileProjectile->frameNum = bestID; missileProjectile->frameNum = bestID;
} }
double animSpeed = AnimationControls::getProjectileSpeed(); // flight speed of projectile
double distanceSquared = (dest.x - from.x) * (dest.x - from.x) + (dest.y - from.y) * (dest.y - from.y);
double distance = sqrt(distanceSquared);
projectile->steps = std::round(distance / animSpeed);
if(projectile->steps == 0)
projectile->steps = 1;
} }
double animSpeed = AnimationControls::getProjectileSpeed(); // flight speed of projectile
if (!target)
animSpeed *= 0.2; // catapult attack needs slower speed
double distanceSquared = (dest.x - from.x) * (dest.x - from.x) + (dest.y - from.y) * (dest.y - from.y);
double distance = sqrt(distanceSquared);
projectile->steps = std::round(distance / animSpeed);
if(projectile->steps == 0)
projectile->steps = 1;
projectile->from = from; projectile->from = from;
projectile->dest = dest; projectile->dest = dest;
projectile->shooterID = shooter->ID; projectile->shooterID = shooter->ID;

View File

@@ -104,12 +104,13 @@ std::string CBattleSiegeController::getWallPieceImageName(EWallVisual::EWallVisu
} }
} }
void CBattleSiegeController::showWallPiece(std::shared_ptr<CCanvas> canvas, EWallVisual::EWallVisual what) void CBattleSiegeController::showWallPiece(std::shared_ptr<CCanvas> canvas, EWallVisual::EWallVisual what, const Point & offset)
{ {
auto & ci = town->town->clientInfo; auto & ci = town->town->clientInfo;
auto const & pos = ci.siegePositions[what]; auto const & pos = ci.siegePositions[what];
canvas->draw(wallPieceImages[what], owner->pos.topLeft() + Point(pos.x, pos.y)); if ( wallPieceImages[what])
canvas->draw(wallPieceImages[what], offset + Point(pos.x, pos.y));
} }
std::string CBattleSiegeController::getBattleBackgroundName() const std::string CBattleSiegeController::getBattleBackgroundName() const
@@ -250,13 +251,13 @@ void CBattleSiegeController::gateStateChanged(const EGateState state)
CCS->soundh->playSound(soundBase::DRAWBRG); CCS->soundh->playSound(soundBase::DRAWBRG);
} }
void CBattleSiegeController::showAbsoluteObstacles(std::shared_ptr<CCanvas> canvas) void CBattleSiegeController::showAbsoluteObstacles(std::shared_ptr<CCanvas> canvas, const Point & offset)
{ {
if (getWallPieceExistance(EWallVisual::MOAT)) if (getWallPieceExistance(EWallVisual::MOAT))
showWallPiece(canvas, EWallVisual::MOAT); showWallPiece(canvas, EWallVisual::MOAT, owner->pos.topLeft());
if (getWallPieceExistance(EWallVisual::BACKGROUND_MOAT)) if (getWallPieceExistance(EWallVisual::BACKGROUND_MOAT))
showWallPiece(canvas, EWallVisual::BACKGROUND_MOAT); showWallPiece(canvas, EWallVisual::BACKGROUND_MOAT, owner->pos.topLeft());
} }
void CBattleSiegeController::showBattlefieldObjects(std::shared_ptr<CCanvas> canvas, const BattleHex & location ) void CBattleSiegeController::showBattlefieldObjects(std::shared_ptr<CCanvas> canvas, const BattleHex & location )
@@ -275,7 +276,7 @@ void CBattleSiegeController::showBattlefieldObjects(std::shared_ptr<CCanvas> can
wallPiece != EWallVisual::BOTTOM_BATTLEMENT && wallPiece != EWallVisual::BOTTOM_BATTLEMENT &&
wallPiece != EWallVisual::UPPER_BATTLEMENT) wallPiece != EWallVisual::UPPER_BATTLEMENT)
{ {
showWallPiece(canvas, wallPiece); showWallPiece(canvas, wallPiece, owner->pos.topLeft());
continue; continue;
} }
@@ -308,7 +309,7 @@ void CBattleSiegeController::showBattlefieldObjects(std::shared_ptr<CCanvas> can
if (turret) if (turret)
{ {
owner->stacksController->showStack(canvas, turret); owner->stacksController->showStack(canvas, turret);
showWallPiece(canvas, wallPiece); showWallPiece(canvas, wallPiece, owner->pos.topLeft());
} }
} }
} }

View File

@@ -78,7 +78,7 @@ class CBattleSiegeController
/// returns true if chosen wall piece should be present in current battle /// returns true if chosen wall piece should be present in current battle
bool getWallPieceExistance(EWallVisual::EWallVisual what) const; bool getWallPieceExistance(EWallVisual::EWallVisual what) const;
void showWallPiece(std::shared_ptr<CCanvas> canvas, EWallVisual::EWallVisual what); void showWallPiece(std::shared_ptr<CCanvas> canvas, EWallVisual::EWallVisual what, const Point & offset);
public: public:
CBattleSiegeController(CBattleInterface * owner, const CGTownInstance *siegeTown); CBattleSiegeController(CBattleInterface * owner, const CGTownInstance *siegeTown);
@@ -88,7 +88,7 @@ public:
void stackIsCatapulting(const CatapultAttack & ca); void stackIsCatapulting(const CatapultAttack & ca);
/// call-ins from other battle controllers /// call-ins from other battle controllers
void showAbsoluteObstacles(std::shared_ptr<CCanvas> canvas); void showAbsoluteObstacles(std::shared_ptr<CCanvas> canvas, const Point & offset);
void showBattlefieldObjects(std::shared_ptr<CCanvas> canvas, const BattleHex & location ); void showBattlefieldObjects(std::shared_ptr<CCanvas> canvas, const BattleHex & location );
/// queries from other battle controllers /// queries from other battle controllers

View File

@@ -222,7 +222,7 @@
}, },
"moat" : "moat" :
{ {
"bank" : { "x" : -1, "y" : -1 }, "bank" : { "x" : 406, "y" : 77 },
"moat" : { "x" : 406, "y" : 77 } "moat" : { "x" : 406, "y" : 77 }
}, },
"static" : "static" :