1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +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(shooting)
CCS->soundh->playSound(battle_sound(attackingStack->getCreature(), shoot));
CCS->soundh->playSound(battle_sound(getCreature(), shoot));
else
CCS->soundh->playSound(battle_sound(attackingStack->getCreature(), attack));
CCS->soundh->playSound(battle_sound(getCreature(), attack));
soundPlayed = true;
}
CBattleAnimation::nextFrame();
@ -164,6 +164,14 @@ bool CAttackAnimation::checkInitialConditions()
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)
: CBattleStackAnimation(_owner, attacker),
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)
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.
if (projectileAngle > straightAngle)
@ -780,11 +788,7 @@ void CShootingAnimation::setAnimationGroup()
void CShootingAnimation::initializeProjectile()
{
const CCreature *shooterInfo = attackingStack->getCreature();
if(shooterInfo->idNumber == CreatureID::ARROW_TOWERS)
shooterInfo = owner->siegeController->getTurretCreature();
const CCreature *shooterInfo = getCreature();
Point shotTarget = owner->stacksController->getStackPositionAtHex(dest, attackedStack) + Point(225, 225);
Point shotOrigin = stackAnimation(attackingStack)->pos.topLeft() + Point(222, 265);
int multiplier = stackFacingRight(attackingStack) ? 1 : -1;
@ -828,12 +832,25 @@ void CShootingAnimation::nextFrame()
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)
{
const CCreature *shooterInfo = attackingStack->getCreature();
const CCreature *shooterInfo = getCreature();
if(shooterInfo->idNumber == CreatureID::ARROW_TOWERS)
shooterInfo = owner->siegeController->getTurretCreature();
assert(stackAnimation(attackingStack)->isShooting());
// emit projectile once animation playback reached "climax" frame
if ( stackAnimation(attackingStack)->getCurrentFrame() >= shooterInfo->animation.attackClimaxFrame )
@ -842,17 +859,13 @@ void CShootingAnimation::nextFrame()
return;
}
}
// animation should be paused if there is an active projectile
if (projectileEmitted && owner->projectilesController->hasActiveProjectile(attackingStack))
return;
CAttackAnimation::nextFrame();
}
void CShootingAnimation::endAnim()
{
assert(!owner->projectilesController->hasActiveProjectile(attackingStack));
assert(projectileEmitted);
// FIXME: is this possible? Animation is over but we're yet to fire projectile?
if (!projectileEmitted)
{
@ -1157,11 +1170,15 @@ void CEffectAnimation::endAnim()
{
CBattleAnimation::endAnim();
boost::range::remove_if(owner->effectsController->battleEffects,
[&](const BattleEffect & elem)
{
return elem.effectID == ID;
});
auto & effects = owner->effectsController->battleEffects;
for ( auto it = effects.begin(); it != effects.end(); )
{
if (it->effectID == ID)
it = effects.erase(it);
else
it++;
}
delete this;
}

View File

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

View File

@ -106,7 +106,9 @@ void CBattleFieldController::redrawBackgroundWithHexes()
//prepare background graphic with hexes and shaded hexes
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())
{

View File

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

View File

@ -109,7 +109,7 @@ void CBattleObstacleController::obstaclePlaced(const CObstacleInstance & oi)
//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
for(auto & oi : owner->curInt->cb->battleGetAllObstacles())
@ -118,7 +118,7 @@ void CBattleObstacleController::showAbsoluteObstacles(std::shared_ptr<CCanvas> c
{
auto img = getObstacleImage(*oi);
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();
}
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 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 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)
{
const CCreature *shooterInfo = shooter->getCreature();
const CCreature *shooterInfo = getShooter(shooter);
std::shared_ptr<ProjectileBase> projectile;
@ -262,8 +262,8 @@ void CBattleProjectileController::createProjectile(const CStack * shooter, const
catapultProjectile->step = 0;
catapultProjectile->steps = 0;
double animSpeed = AnimationControls::getProjectileSpeed() / 10;
catapultProjectile->steps = std::round(std::abs((dest.x - from.x) / animSpeed));
//double animSpeed = AnimationControls::getProjectileSpeed() / 10;
//catapultProjectile->steps = std::round(std::abs((dest.x - from.x) / animSpeed));
}
else
{
@ -312,16 +312,18 @@ void CBattleProjectileController::createProjectile(const CStack * shooter, const
}
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->dest = dest;
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 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
@ -250,13 +251,13 @@ void CBattleSiegeController::gateStateChanged(const EGateState state)
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))
showWallPiece(canvas, EWallVisual::MOAT);
showWallPiece(canvas, EWallVisual::MOAT, owner->pos.topLeft());
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 )
@ -275,7 +276,7 @@ void CBattleSiegeController::showBattlefieldObjects(std::shared_ptr<CCanvas> can
wallPiece != EWallVisual::BOTTOM_BATTLEMENT &&
wallPiece != EWallVisual::UPPER_BATTLEMENT)
{
showWallPiece(canvas, wallPiece);
showWallPiece(canvas, wallPiece, owner->pos.topLeft());
continue;
}
@ -308,7 +309,7 @@ void CBattleSiegeController::showBattlefieldObjects(std::shared_ptr<CCanvas> can
if (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
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:
CBattleSiegeController(CBattleInterface * owner, const CGTownInstance *siegeTown);
@ -88,7 +88,7 @@ public:
void stackIsCatapulting(const CatapultAttack & ca);
/// 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 );
/// queries from other battle controllers

View File

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