1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-26 22:57:00 +02:00

Fixes to effects of earthquake, obstacle-creating and offensive spells

This commit is contained in:
Ivan Savenko 2022-12-02 01:55:09 +02:00
parent d8742dac3f
commit 58ba5f1aee
6 changed files with 105 additions and 56 deletions

View File

@ -980,17 +980,17 @@ CPointEffectAnimation::CPointEffectAnimation(CBattleInterface * _owner, soundBas
{
}
CPointEffectAnimation::CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, std::vector<BattleHex> pos, int effects):
CPointEffectAnimation::CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, std::vector<BattleHex> hex, int effects):
CPointEffectAnimation(_owner, sound, animationName, effects)
{
battlehexes = pos;
battlehexes = hex;
}
CPointEffectAnimation::CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, BattleHex pos, int effects):
CPointEffectAnimation::CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, BattleHex hex, int effects):
CPointEffectAnimation(_owner, sound, animationName, effects)
{
assert(pos.isValid());
battlehexes.push_back(pos);
assert(hex.isValid());
battlehexes.push_back(hex);
}
CPointEffectAnimation::CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, std::vector<Point> pos, int effects):
@ -1005,6 +1005,14 @@ CPointEffectAnimation::CPointEffectAnimation(CBattleInterface * _owner, soundBas
positions.push_back(pos);
}
CPointEffectAnimation::CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, Point pos, BattleHex hex, int effects):
CPointEffectAnimation(_owner, sound, animationName, effects)
{
assert(hex.isValid());
battlehexes.push_back(hex);
positions.push_back(pos);
}
bool CPointEffectAnimation::init()
{
if(!CBattleAnimation::checkInitialConditions())
@ -1019,9 +1027,8 @@ bool CPointEffectAnimation::init()
return false;
}
if (positions.empty() && battlehexes.empty())
if (screenFill())
{
//armageddon, create screen fill
for(int i=0; i * first->width() < owner->pos.w ; ++i)
for(int j=0; j * first->height() < owner->pos.h ; ++j)
positions.push_back(Point(i * first->width(), j * first->height()));
@ -1032,35 +1039,36 @@ bool CPointEffectAnimation::init()
be.animation = animation;
be.currentFrame = 0;
for ( auto const position : positions)
for (size_t i = 0; i < std::max(battlehexes.size(), positions.size()); ++i)
{
be.x = position.x;
be.y = position.y;
be.position = BattleHex::INVALID;
bool hasTile = i < battlehexes.size();
bool hasPosition = i < positions.size();
owner->effectsController->battleEffects.push_back(be);
}
for ( auto const tile : battlehexes)
{
const CStack * destStack = owner->getCurrentPlayerInterface()->cb->battleGetStackByPos(tile, false);
assert(tile.isValid());
if(!tile.isValid())
continue;
Rect tilePos = owner->fieldController->hexPosition(tile);
be.position = tile;
be.x = tilePos.x + tilePos.w/2 - first->width()/2;
if(destStack && destStack->doubleWide()) // Correction for 2-hex creatures.
be.x += (destStack->side == BattleSide::ATTACKER ? -1 : 1)*tilePos.w/2;
if (alignToBottom())
be.y = tilePos.y + tilePos.h - first->height();
if (hasTile && !forceOnTop())
be.position = battlehexes[i];
else
be.y = tilePos.y - first->height()/2;
be.position = BattleHex::INVALID;
if (hasPosition)
{
be.x = positions[i].x;
be.y = positions[i].y;
}
else
{
const CStack * destStack = owner->getCurrentPlayerInterface()->cb->battleGetStackByPos(battlehexes[i], false);
Rect tilePos = owner->fieldController->hexPosition(battlehexes[i]);
be.x = tilePos.x + tilePos.w/2 - first->width()/2;
if(destStack && destStack->doubleWide()) // Correction for 2-hex creatures.
be.x += (destStack->side == BattleSide::ATTACKER ? -1 : 1)*tilePos.w/2;
if (alignToBottom())
be.y = tilePos.y + tilePos.h - first->height();
else
be.y = tilePos.y - first->height()/2;
}
owner->effectsController->battleEffects.push_back(be);
}
return true;
@ -1072,7 +1080,11 @@ void CPointEffectAnimation::nextFrame()
playEffect();
if (soundFinished && effectFinished)
{
//remove visual effect itself only if sound has finished as well - necessary for obstacles like force field
clearEffect();
delete this;
}
}
bool CPointEffectAnimation::alignToBottom() const
@ -1085,10 +1097,19 @@ bool CPointEffectAnimation::waitForSound() const
return effectFlags & WAIT_FOR_SOUND;
}
bool CPointEffectAnimation::forceOnTop() const
{
return effectFlags & FORCE_ON_TOP;
}
bool CPointEffectAnimation::screenFill() const
{
return effectFlags & SCREEN_FILL;
}
void CPointEffectAnimation::onEffectFinished()
{
effectFinished = true;
clearEffect();
}
void CPointEffectAnimation::onSoundFinished()
@ -1118,6 +1139,9 @@ void CPointEffectAnimation::playSound()
void CPointEffectAnimation::playEffect()
{
if ( effectFinished )
return;
for(auto & elem : owner->effectsController->battleEffects)
{
if(elem.effectID == ID)
@ -1126,6 +1150,7 @@ void CPointEffectAnimation::playEffect()
if(elem.currentFrame >= elem.animation->size())
{
elem.currentFrame = elem.animation->size() - 1;
onEffectFinished();
break;
}

View File

@ -262,6 +262,19 @@ public:
CCastAnimation(CBattleInterface * owner_, const CStack * attacker, BattleHex dest_, const CStack * defender, const CSpell * spell);
};
struct CPointEffectParameters
{
std::vector<Point> positions;
std::vector<BattleHex> tiles;
std::string animation;
soundBase::soundID sound = soundBase::invalid;
BattleHex boundHex = BattleHex::INVALID;
bool aligntoBottom = false;
bool waitForSound = false;
bool screenFill = false;
};
/// Class that plays effect at one or more positions along with (single) sound effect
class CPointEffectAnimation : public CBattleAnimation
{
@ -277,6 +290,8 @@ class CPointEffectAnimation : public CBattleAnimation
bool alignToBottom() const;
bool waitForSound() const;
bool forceOnTop() const;
bool screenFill() const;
void onEffectFinished();
void onSoundFinished();
@ -289,7 +304,9 @@ public:
enum EEffectFlags
{
ALIGN_TO_BOTTOM = 1,
WAIT_FOR_SOUND = 2
WAIT_FOR_SOUND = 2,
FORCE_ON_TOP = 4,
SCREEN_FILL = 8,
};
/// Create animation with screen-wide effect
@ -300,8 +317,10 @@ public:
CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, std::vector<Point> pos , int effects = 0);
/// Create animation positioned at certain hex(es)
CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, BattleHex pos , int effects = 0);
CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, std::vector<BattleHex> pos, int effects = 0);
CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, BattleHex hex , int effects = 0);
CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, std::vector<BattleHex> hex, int effects = 0);
CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, Point pos, BattleHex hex, int effects = 0);
~CPointEffectAnimation();
bool init() override;

View File

@ -583,7 +583,7 @@ void CBattleInterface::displayBattleLog(const std::vector<MetaString> & battleLo
}
}
void CBattleInterface::displaySpellAnimationQueue(const CSpell::TAnimationQueue & q, BattleHex destinationTile)
void CBattleInterface::displaySpellAnimationQueue(const CSpell::TAnimationQueue & q, BattleHex destinationTile, bool isHit)
{
for(const CSpell::TAnimation & animation : q)
{
@ -591,12 +591,21 @@ void CBattleInterface::displaySpellAnimationQueue(const CSpell::TAnimationQueue
stacksController->addNewAnim(new CDummyAnimation(this, animation.pause));
else
{
int flags = 0;
if (isHit)
flags |= CPointEffectAnimation::FORCE_ON_TOP;
if (animation.verticalPosition == VerticalPosition::BOTTOM)
flags |= CPointEffectAnimation::ALIGN_TO_BOTTOM;
if (!destinationTile.isValid())
stacksController->addNewAnim(new CPointEffectAnimation(this, soundBase::invalid, animation.resourceName));
else if (animation.verticalPosition == VerticalPosition::BOTTOM)
stacksController->addNewAnim(new CPointEffectAnimation(this, soundBase::invalid, animation.resourceName, destinationTile, CPointEffectAnimation::ALIGN_TO_BOTTOM));
flags |= CPointEffectAnimation::SCREEN_FILL;
if (!destinationTile.isValid())
stacksController->addNewAnim(new CPointEffectAnimation(this, soundBase::invalid, animation.resourceName, flags));
else
stacksController->addNewAnim(new CPointEffectAnimation(this, soundBase::invalid, animation.resourceName, destinationTile));
stacksController->addNewAnim(new CPointEffectAnimation(this, soundBase::invalid, animation.resourceName, destinationTile, flags));
}
}
}
@ -606,7 +615,7 @@ void CBattleInterface::displaySpellCast(SpellID spellID, BattleHex destinationTi
const CSpell * spell = spellID.toSpell();
if(spell)
displaySpellAnimationQueue(spell->animationInfo.cast, destinationTile);
displaySpellAnimationQueue(spell->animationInfo.cast, destinationTile, false);
}
void CBattleInterface::displaySpellEffect(SpellID spellID, BattleHex destinationTile)
@ -614,7 +623,7 @@ void CBattleInterface::displaySpellEffect(SpellID spellID, BattleHex destination
const CSpell *spell = spellID.toSpell();
if(spell)
displaySpellAnimationQueue(spell->animationInfo.affect, destinationTile);
displaySpellAnimationQueue(spell->animationInfo.affect, destinationTile, false);
}
void CBattleInterface::displaySpellHit(SpellID spellID, BattleHex destinationTile)
@ -622,7 +631,7 @@ void CBattleInterface::displaySpellHit(SpellID spellID, BattleHex destinationTil
const CSpell * spell = spellID.toSpell();
if(spell)
displaySpellAnimationQueue(spell->animationInfo.hit, destinationTile);
displaySpellAnimationQueue(spell->animationInfo.hit, destinationTile, true);
}
void CBattleInterface::setAnimSpeed(int set)

View File

@ -166,7 +166,7 @@ public:
void displayBattleLog(const std::vector<MetaString> & battleLog);
void displaySpellAnimationQueue(const CSpell::TAnimationQueue & q, BattleHex destinationTile);
void displaySpellAnimationQueue(const CSpell::TAnimationQueue & q, BattleHex destinationTile, bool isHit);
void displaySpellCast(SpellID spellID, BattleHex destinationTile); //displays spell`s cast animation
void displaySpellEffect(SpellID spellID, BattleHex destinationTile); //displays spell`s affected animation
void displaySpellHit(SpellID spellID, BattleHex destinationTile); //displays spell`s affected animation

View File

@ -85,15 +85,7 @@ void CBattleObstacleController::obstaclePlaced(const std::vector<std::shared_ptr
continue;
}
std::string defname = spellObstacle->appearAnimation;
//TODO: sound
//soundBase::QUIKSAND
//soundBase::LANDMINE
//soundBase::FORCEFLD
//soundBase::fireWall
auto animation = std::make_shared<CAnimation>(defname);
auto animation = std::make_shared<CAnimation>(spellObstacle->appearAnimation);
animation->preload();
auto first = animation->getImage(0, 0);
@ -103,10 +95,14 @@ void CBattleObstacleController::obstaclePlaced(const std::vector<std::shared_ptr
continue;
}
//TODO: sound
//soundBase::QUIKSAND
//soundBase::LANDMINE
//we assume here that effect graphics have the same size as the usual obstacle image
// -> if we know how to blit obstacle, let's blit the effect in the same place
Point whereTo = getObstaclePosition(first, *oi);
owner->stacksController->addNewAnim(new CPointEffectAnimation(owner, soundBase::QUIKSAND, defname, whereTo, CPointEffectAnimation::WAIT_FOR_SOUND));
owner->stacksController->addNewAnim(new CPointEffectAnimation(owner, soundBase::invalid, spellObstacle->appearAnimation, whereTo, oi->pos, CPointEffectAnimation::WAIT_FOR_SOUND));
//so when multiple obstacles are added, they show up one after another
owner->waitForAnims();

View File

@ -333,7 +333,7 @@ void CBattleSiegeController::stackIsCatapulting(const CatapultAttack & ca)
positions.push_back(owner->stacksController->getStackPositionAtHex(attackInfo.destinationTile, nullptr) + Point(99, 120));
owner->stacksController->addNewAnim(new CPointEffectAnimation(owner, soundBase::invalid, "SGEXPL.DEF", positions));
owner->stacksController->addNewAnim(new CPointEffectAnimation(owner, soundBase::WALLHIT, "SGEXPL.DEF", positions));
}
owner->waitForAnims();