mirror of
https://github.com/vcmi/vcmi.git
synced 2025-03-25 21:38:59 +02:00
vcmi: now obstacles can have disappearing anim
It is a reverse version of appearingAnimation.
This commit is contained in:
parent
7543fdf787
commit
eff41f66ed
@ -759,6 +759,7 @@ void CPlayerInterface::battleObstaclesChanged(const std::vector<ObstacleChanges>
|
|||||||
BATTLE_EVENT_POSSIBLE_RETURN;
|
BATTLE_EVENT_POSSIBLE_RETURN;
|
||||||
|
|
||||||
std::vector<std::shared_ptr<const CObstacleInstance>> newObstacles;
|
std::vector<std::shared_ptr<const CObstacleInstance>> newObstacles;
|
||||||
|
std::vector<ObstacleChanges> removedObstacles;
|
||||||
|
|
||||||
for(auto & change : obstacles)
|
for(auto & change : obstacles)
|
||||||
{
|
{
|
||||||
@ -770,11 +771,16 @@ void CPlayerInterface::battleObstaclesChanged(const std::vector<ObstacleChanges>
|
|||||||
else
|
else
|
||||||
logNetwork->error("Invalid obstacle instance %d", change.id);
|
logNetwork->error("Invalid obstacle instance %d", change.id);
|
||||||
}
|
}
|
||||||
|
if(change.operation == BattleChanges::EOperation::REMOVE)
|
||||||
|
removedObstacles.push_back(change); //Obstacles are already removed, so, show animation based on json struct
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!newObstacles.empty())
|
if (!newObstacles.empty())
|
||||||
battleInt->obstaclePlaced(newObstacles);
|
battleInt->obstaclePlaced(newObstacles);
|
||||||
|
|
||||||
|
if (!removedObstacles.empty())
|
||||||
|
battleInt->obstacleRemoved(removedObstacles);
|
||||||
|
|
||||||
battleInt->fieldController->redrawBackgroundWithHexes();
|
battleInt->fieldController->redrawBackgroundWithHexes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -653,6 +653,11 @@ void BattleInterface::obstaclePlaced(const std::vector<std::shared_ptr<const COb
|
|||||||
obstacleController->obstaclePlaced(oi);
|
obstacleController->obstaclePlaced(oi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BattleInterface::obstacleRemoved(const std::vector<ObstacleChanges> & obstacles)
|
||||||
|
{
|
||||||
|
obstacleController->obstacleRemoved(obstacles);
|
||||||
|
}
|
||||||
|
|
||||||
const CGHeroInstance *BattleInterface::currentHero() const
|
const CGHeroInstance *BattleInterface::currentHero() const
|
||||||
{
|
{
|
||||||
if (attackingHeroInstance && attackingHeroInstance->tempOwner == curInt->playerID)
|
if (attackingHeroInstance && attackingHeroInstance->tempOwner == curInt->playerID)
|
||||||
|
@ -29,6 +29,7 @@ struct CatapultAttack;
|
|||||||
struct BattleTriggerEffect;
|
struct BattleTriggerEffect;
|
||||||
struct BattleHex;
|
struct BattleHex;
|
||||||
struct InfoAboutHero;
|
struct InfoAboutHero;
|
||||||
|
class ObstacleChanges;
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_END
|
VCMI_LIB_NAMESPACE_END
|
||||||
|
|
||||||
@ -214,6 +215,7 @@ public:
|
|||||||
void endAction(const BattleAction* action);
|
void endAction(const BattleAction* action);
|
||||||
|
|
||||||
void obstaclePlaced(const std::vector<std::shared_ptr<const CObstacleInstance>> oi);
|
void obstaclePlaced(const std::vector<std::shared_ptr<const CObstacleInstance>> oi);
|
||||||
|
void obstacleRemoved(const std::vector<ObstacleChanges> & obstacles);
|
||||||
|
|
||||||
void gateStateChanged(const EGateState state);
|
void gateStateChanged(const EGateState state);
|
||||||
|
|
||||||
|
@ -74,6 +74,37 @@ void BattleObstacleController::loadObstacleImage(const CObstacleInstance & oi)
|
|||||||
obstacleAnimations[oi.uniqueID] = animationsCache[animationName];
|
obstacleAnimations[oi.uniqueID] = animationsCache[animationName];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BattleObstacleController::obstacleRemoved(const std::vector<ObstacleChanges> & obstacles)
|
||||||
|
{
|
||||||
|
for (auto const & oi : obstacles)
|
||||||
|
{
|
||||||
|
auto & obstacle = oi.data["obstacle"];
|
||||||
|
|
||||||
|
if (!obstacle.isStruct())
|
||||||
|
{
|
||||||
|
logGlobal->error("I don't know how to animate removal of this obstacle");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto animation = std::make_shared<CAnimation>(obstacle["appearAnimation"].String());
|
||||||
|
animation->preload();
|
||||||
|
|
||||||
|
auto first = animation->getImage(0, 0);
|
||||||
|
if(!first)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//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, obstacle);
|
||||||
|
//AFAIK, in H3 there is no sound of obstacle removal
|
||||||
|
owner.stacksController->addNewAnim(new EffectAnimation(owner, obstacle["appearAnimation"].String(), whereTo, obstacle["position"].Integer(), 0, true));
|
||||||
|
|
||||||
|
obstacleAnimations.erase(oi.id);
|
||||||
|
//so when multiple obstacles are removed, they show up one after another
|
||||||
|
owner.waitForAnimations();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void BattleObstacleController::obstaclePlaced(const std::vector<std::shared_ptr<const CObstacleInstance>> & obstacles)
|
void BattleObstacleController::obstaclePlaced(const std::vector<std::shared_ptr<const CObstacleInstance>> & obstacles)
|
||||||
{
|
{
|
||||||
for (auto const & oi : obstacles)
|
for (auto const & oi : obstacles)
|
||||||
@ -87,7 +118,7 @@ void BattleObstacleController::obstaclePlaced(const std::vector<std::shared_ptr<
|
|||||||
|
|
||||||
if (!spellObstacle)
|
if (!spellObstacle)
|
||||||
{
|
{
|
||||||
logGlobal->error("I don't know how to animate appearing obstacle of type %d", (int)oi->obstacleType);
|
logGlobal->error("I don't know how to animate removal of obstacle of type %d", (int)oi->obstacleType);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,3 +211,19 @@ Point BattleObstacleController::getObstaclePosition(std::shared_ptr<IImage> imag
|
|||||||
|
|
||||||
return r.topLeft();
|
return r.topLeft();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Point BattleObstacleController::getObstaclePosition(std::shared_ptr<IImage> image, const JsonNode & obstacle)
|
||||||
|
{
|
||||||
|
auto animationYOffset = obstacle["animationYOffset"].Integer();
|
||||||
|
auto offset = image->height() % 42;
|
||||||
|
|
||||||
|
if(obstacle["needAnimationOffsetFix"].Bool() && offset > 37)
|
||||||
|
animationYOffset -= 42;
|
||||||
|
|
||||||
|
offset += animationYOffset;
|
||||||
|
|
||||||
|
Rect r = owner.fieldController->hexPositionLocal(obstacle["position"].Integer());
|
||||||
|
r.y += 42 - image->height() + offset;
|
||||||
|
|
||||||
|
return r.topLeft();
|
||||||
|
}
|
||||||
|
@ -13,6 +13,8 @@ VCMI_LIB_NAMESPACE_BEGIN
|
|||||||
|
|
||||||
struct BattleHex;
|
struct BattleHex;
|
||||||
struct CObstacleInstance;
|
struct CObstacleInstance;
|
||||||
|
class JsonNode;
|
||||||
|
class ObstacleChanges;
|
||||||
class Point;
|
class Point;
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_END
|
VCMI_LIB_NAMESPACE_END
|
||||||
@ -42,6 +44,7 @@ class BattleObstacleController
|
|||||||
|
|
||||||
std::shared_ptr<IImage> getObstacleImage(const CObstacleInstance & oi);
|
std::shared_ptr<IImage> getObstacleImage(const CObstacleInstance & oi);
|
||||||
Point getObstaclePosition(std::shared_ptr<IImage> image, const CObstacleInstance & obstacle);
|
Point getObstaclePosition(std::shared_ptr<IImage> image, const CObstacleInstance & obstacle);
|
||||||
|
Point getObstaclePosition(std::shared_ptr<IImage> image, const JsonNode & obstacle);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BattleObstacleController(BattleInterface & owner);
|
BattleObstacleController(BattleInterface & owner);
|
||||||
@ -52,6 +55,9 @@ public:
|
|||||||
/// call-in from network pack, add newly placed obstacles with any required animations
|
/// call-in from network pack, add newly placed obstacles with any required animations
|
||||||
void obstaclePlaced(const std::vector<std::shared_ptr<const CObstacleInstance>> & oi);
|
void obstaclePlaced(const std::vector<std::shared_ptr<const CObstacleInstance>> & oi);
|
||||||
|
|
||||||
|
/// call-in from network pack, remove required obstacles with any required animations
|
||||||
|
void obstacleRemoved(const std::vector<ObstacleChanges> & obstacles);
|
||||||
|
|
||||||
/// renders all "absolute" obstacles
|
/// renders all "absolute" obstacles
|
||||||
void showAbsoluteObstacles(Canvas & canvas);
|
void showAbsoluteObstacles(Canvas & canvas);
|
||||||
|
|
||||||
|
@ -86,6 +86,37 @@ bool CObstacleInstance::triggersEffects() const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CObstacleInstance::serializeJson(JsonSerializeFormat & handler)
|
||||||
|
{
|
||||||
|
auto obstacleInfo = getInfo();
|
||||||
|
auto hidden = false;
|
||||||
|
auto needAnimationOffsetFix = obstacleType == CObstacleInstance::USUAL;
|
||||||
|
int animationYOffset = 0;
|
||||||
|
|
||||||
|
if(getInfo().blockedTiles.front() < 0) //TODO: holy ground ID=62,65,63
|
||||||
|
animationYOffset -= 42;
|
||||||
|
|
||||||
|
//We need only a subset of obstacle info for correct render
|
||||||
|
handler.serializeInt("position", pos);
|
||||||
|
handler.serializeString("appearSound", obstacleInfo.appearSound);
|
||||||
|
handler.serializeString("appearAnimation", obstacleInfo.appearAnimation);
|
||||||
|
handler.serializeString("animation", obstacleInfo.animation);
|
||||||
|
handler.serializeInt("animationYOffset", animationYOffset);
|
||||||
|
|
||||||
|
handler.serializeBool("hidden", hidden);
|
||||||
|
handler.serializeBool("needAnimationOffsetFix", needAnimationOffsetFix);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CObstacleInstance::toInfo(ObstacleChanges & info, BattleChanges::EOperation operation)
|
||||||
|
{
|
||||||
|
info.id = uniqueID;
|
||||||
|
info.operation = operation;
|
||||||
|
|
||||||
|
info.data.clear();
|
||||||
|
JsonSerializer ser(nullptr, info.data);
|
||||||
|
ser.serializeStruct("obstacle", *this);
|
||||||
|
}
|
||||||
|
|
||||||
SpellCreatedObstacle::SpellCreatedObstacle()
|
SpellCreatedObstacle::SpellCreatedObstacle()
|
||||||
: turnsRemaining(-1),
|
: turnsRemaining(-1),
|
||||||
casterSpellPower(0),
|
casterSpellPower(0),
|
||||||
@ -131,16 +162,6 @@ bool SpellCreatedObstacle::triggersEffects() const
|
|||||||
return trigger;
|
return trigger;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpellCreatedObstacle::toInfo(ObstacleChanges & info)
|
|
||||||
{
|
|
||||||
info.id = uniqueID;
|
|
||||||
info.operation = ObstacleChanges::EOperation::ADD;
|
|
||||||
|
|
||||||
info.data.clear();
|
|
||||||
JsonSerializer ser(nullptr, info.data);
|
|
||||||
ser.serializeStruct("obstacle", *this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SpellCreatedObstacle::fromInfo(const ObstacleChanges & info)
|
void SpellCreatedObstacle::fromInfo(const ObstacleChanges & info)
|
||||||
{
|
{
|
||||||
uniqueID = info.id;
|
uniqueID = info.id;
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "BattleHex.h"
|
#include "BattleHex.h"
|
||||||
|
#include "NetPacksBase.h"
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
@ -49,6 +50,10 @@ struct DLL_LINKAGE CObstacleInstance
|
|||||||
|
|
||||||
virtual int getAnimationYOffset(int imageHeight) const;
|
virtual int getAnimationYOffset(int imageHeight) const;
|
||||||
|
|
||||||
|
void toInfo(ObstacleChanges & info, BattleChanges::EOperation operation = BattleChanges::EOperation::ADD);
|
||||||
|
|
||||||
|
virtual void serializeJson(JsonSerializeFormat & handler);
|
||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
{
|
{
|
||||||
h & ID;
|
h & ID;
|
||||||
@ -96,10 +101,9 @@ struct DLL_LINKAGE SpellCreatedObstacle : CObstacleInstance
|
|||||||
|
|
||||||
int getAnimationYOffset(int imageHeight) const override;
|
int getAnimationYOffset(int imageHeight) const override;
|
||||||
|
|
||||||
void toInfo(ObstacleChanges & info);
|
|
||||||
void fromInfo(const ObstacleChanges & info);
|
void fromInfo(const ObstacleChanges & info);
|
||||||
|
|
||||||
void serializeJson(JsonSerializeFormat & handler);
|
void serializeJson(JsonSerializeFormat & handler) override;
|
||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
{
|
{
|
||||||
|
@ -50,7 +50,11 @@ void RemoveObstacle::apply(ServerCallback * server, const Mechanics * m, const E
|
|||||||
BattleObstaclesChanged pack;
|
BattleObstaclesChanged pack;
|
||||||
|
|
||||||
for(const auto & obstacle : getTargets(m, target, false))
|
for(const auto & obstacle : getTargets(m, target, false))
|
||||||
|
{
|
||||||
|
auto * serializable = const_cast<CObstacleInstance*>(obstacle); //Workaround
|
||||||
pack.changes.emplace_back(obstacle->uniqueID, BattleChanges::EOperation::REMOVE);
|
pack.changes.emplace_back(obstacle->uniqueID, BattleChanges::EOperation::REMOVE);
|
||||||
|
serializable->toInfo(pack.changes.back(), BattleChanges::EOperation::REMOVE);
|
||||||
|
}
|
||||||
|
|
||||||
if(!pack.changes.empty())
|
if(!pack.changes.empty())
|
||||||
server->apply(&pack);
|
server->apply(&pack);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user