mirror of
https://github.com/vcmi/vcmi.git
synced 2025-03-21 21:17:49 +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;
|
||||
|
||||
std::vector<std::shared_ptr<const CObstacleInstance>> newObstacles;
|
||||
std::vector<ObstacleChanges> removedObstacles;
|
||||
|
||||
for(auto & change : obstacles)
|
||||
{
|
||||
@ -770,11 +771,16 @@ void CPlayerInterface::battleObstaclesChanged(const std::vector<ObstacleChanges>
|
||||
else
|
||||
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())
|
||||
battleInt->obstaclePlaced(newObstacles);
|
||||
|
||||
if (!removedObstacles.empty())
|
||||
battleInt->obstacleRemoved(removedObstacles);
|
||||
|
||||
battleInt->fieldController->redrawBackgroundWithHexes();
|
||||
}
|
||||
|
||||
|
@ -653,6 +653,11 @@ void BattleInterface::obstaclePlaced(const std::vector<std::shared_ptr<const COb
|
||||
obstacleController->obstaclePlaced(oi);
|
||||
}
|
||||
|
||||
void BattleInterface::obstacleRemoved(const std::vector<ObstacleChanges> & obstacles)
|
||||
{
|
||||
obstacleController->obstacleRemoved(obstacles);
|
||||
}
|
||||
|
||||
const CGHeroInstance *BattleInterface::currentHero() const
|
||||
{
|
||||
if (attackingHeroInstance && attackingHeroInstance->tempOwner == curInt->playerID)
|
||||
|
@ -29,6 +29,7 @@ struct CatapultAttack;
|
||||
struct BattleTriggerEffect;
|
||||
struct BattleHex;
|
||||
struct InfoAboutHero;
|
||||
class ObstacleChanges;
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
@ -214,6 +215,7 @@ public:
|
||||
void endAction(const BattleAction* action);
|
||||
|
||||
void obstaclePlaced(const std::vector<std::shared_ptr<const CObstacleInstance>> oi);
|
||||
void obstacleRemoved(const std::vector<ObstacleChanges> & obstacles);
|
||||
|
||||
void gateStateChanged(const EGateState state);
|
||||
|
||||
|
@ -74,6 +74,37 @@ void BattleObstacleController::loadObstacleImage(const CObstacleInstance & oi)
|
||||
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)
|
||||
{
|
||||
for (auto const & oi : obstacles)
|
||||
@ -87,7 +118,7 @@ void BattleObstacleController::obstaclePlaced(const std::vector<std::shared_ptr<
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -180,3 +211,19 @@ Point BattleObstacleController::getObstaclePosition(std::shared_ptr<IImage> imag
|
||||
|
||||
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 CObstacleInstance;
|
||||
class JsonNode;
|
||||
class ObstacleChanges;
|
||||
class Point;
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
@ -42,6 +44,7 @@ class BattleObstacleController
|
||||
|
||||
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 JsonNode & obstacle);
|
||||
|
||||
public:
|
||||
BattleObstacleController(BattleInterface & owner);
|
||||
@ -52,6 +55,9 @@ public:
|
||||
/// call-in from network pack, add newly placed obstacles with any required animations
|
||||
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
|
||||
void showAbsoluteObstacles(Canvas & canvas);
|
||||
|
||||
|
@ -86,6 +86,37 @@ bool CObstacleInstance::triggersEffects() const
|
||||
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()
|
||||
: turnsRemaining(-1),
|
||||
casterSpellPower(0),
|
||||
@ -131,16 +162,6 @@ bool SpellCreatedObstacle::triggersEffects() const
|
||||
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)
|
||||
{
|
||||
uniqueID = info.id;
|
||||
|
@ -9,6 +9,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
#include "BattleHex.h"
|
||||
#include "NetPacksBase.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@ -49,6 +50,10 @@ struct DLL_LINKAGE CObstacleInstance
|
||||
|
||||
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)
|
||||
{
|
||||
h & ID;
|
||||
@ -96,10 +101,9 @@ struct DLL_LINKAGE SpellCreatedObstacle : CObstacleInstance
|
||||
|
||||
int getAnimationYOffset(int imageHeight) const override;
|
||||
|
||||
void toInfo(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)
|
||||
{
|
||||
|
@ -50,7 +50,11 @@ void RemoveObstacle::apply(ServerCallback * server, const Mechanics * m, const E
|
||||
BattleObstaclesChanged pack;
|
||||
|
||||
for(const auto & obstacle : getTargets(m, target, false))
|
||||
{
|
||||
auto * serializable = const_cast<CObstacleInstance*>(obstacle); //Workaround
|
||||
pack.changes.emplace_back(obstacle->uniqueID, BattleChanges::EOperation::REMOVE);
|
||||
serializable->toInfo(pack.changes.back(), BattleChanges::EOperation::REMOVE);
|
||||
}
|
||||
|
||||
if(!pack.changes.empty())
|
||||
server->apply(&pack);
|
||||
|
Loading…
x
Reference in New Issue
Block a user