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

Exploded mines now send ACTIVATE flag to client to play effect

This commit is contained in:
Ivan Savenko 2022-12-17 19:37:00 +02:00
parent deffba01b9
commit 52fc5b3c39
12 changed files with 48 additions and 57 deletions

View File

@ -72,10 +72,6 @@ void BattleObstacleController::loadObstacleImage(const CObstacleInstance & oi)
void BattleObstacleController::obstaclePlaced(const std::vector<std::shared_ptr<const CObstacleInstance>> & obstacles) void BattleObstacleController::obstaclePlaced(const std::vector<std::shared_ptr<const CObstacleInstance>> & obstacles)
{ {
assert(obstaclesBeingPlaced.empty());
for (auto const & oi : obstacles)
obstaclesBeingPlaced.push_back(oi->uniqueID);
for (auto const & oi : obstacles) for (auto const & oi : obstacles)
{ {
auto spellObstacle = dynamic_cast<const SpellCreatedObstacle*>(oi.get()); auto spellObstacle = dynamic_cast<const SpellCreatedObstacle*>(oi.get());
@ -83,7 +79,6 @@ 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 appearing obstacle of type %d", (int)oi->obstacleType);
obstaclesBeingPlaced.erase(obstaclesBeingPlaced.begin());
continue; continue;
} }
@ -92,10 +87,7 @@ void BattleObstacleController::obstaclePlaced(const std::vector<std::shared_ptr<
auto first = animation->getImage(0, 0); auto first = animation->getImage(0, 0);
if(!first) if(!first)
{
obstaclesBeingPlaced.erase(obstaclesBeingPlaced.begin());
continue; continue;
}
//we assume here that effect graphics have the same size as the usual obstacle image //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 // -> if we know how to blit obstacle, let's blit the effect in the same place
@ -105,7 +97,6 @@ void BattleObstacleController::obstaclePlaced(const std::vector<std::shared_ptr<
//so when multiple obstacles are added, they show up one after another //so when multiple obstacles are added, they show up one after another
owner.waitForAnimationCondition(EAnimationEvents::ACTION, false); owner.waitForAnimationCondition(EAnimationEvents::ACTION, false);
obstaclesBeingPlaced.erase(obstaclesBeingPlaced.begin());
loadObstacleImage(*spellObstacle); loadObstacleImage(*spellObstacle);
} }
} }
@ -150,19 +141,9 @@ std::shared_ptr<IImage> BattleObstacleController::getObstacleImage(const CObstac
int frameIndex = (owner.animCount+1) *25 / owner.getAnimSpeed(); int frameIndex = (owner.animCount+1) *25 / owner.getAnimSpeed();
std::shared_ptr<CAnimation> animation; std::shared_ptr<CAnimation> animation;
// obstacle is not loaded yet, don't show anything
if (obstacleAnimations.count(oi.uniqueID) == 0) if (obstacleAnimations.count(oi.uniqueID) == 0)
{ return nullptr;
if (boost::range::find(obstaclesBeingPlaced, oi.uniqueID) != obstaclesBeingPlaced.end())
{
// obstacle is not loaded yet, don't show anything
return nullptr;
}
else
{
assert(0); // how?
loadObstacleImage(oi);
}
}
animation = obstacleAnimations[oi.uniqueID]; animation = obstacleAnimations[oi.uniqueID];
assert(animation); assert(animation);

View File

@ -35,10 +35,6 @@ class BattleObstacleController
/// list of all obstacles that are currently being rendered /// list of all obstacles that are currently being rendered
std::map<si32, std::shared_ptr<CAnimation>> obstacleAnimations; std::map<si32, std::shared_ptr<CAnimation>> obstacleAnimations;
/// semi-debug member, contains obstacles that should not yet be visible due to ongoing placement animation
/// used only for sanity checks to ensure that there are no invisible obstacles
std::vector<si32> obstaclesBeingPlaced;
void loadObstacleImage(const CObstacleInstance & oi); void loadObstacleImage(const CObstacleInstance & oi);
std::shared_ptr<IImage> getObstacleImage(const CObstacleInstance & oi); std::shared_ptr<IImage> getObstacleImage(const CObstacleInstance & oi);

View File

@ -187,7 +187,7 @@ void BattleStacksController::stackReset(const CStack * stack)
void BattleStacksController::stackAdded(const CStack * stack, bool instant) void BattleStacksController::stackAdded(const CStack * stack, bool instant)
{ {
// Tower shooters have only their upper half visible // Tower shooters have only their upper half visible
static const int turretCreatureAnimationHeight = 235; static const int turretCreatureAnimationHeight = 225;
stackFacingRight[stack->ID] = stack->side == BattleSide::ATTACKER; // must be set before getting stack position stackFacingRight[stack->ID] = stack->side == BattleSide::ATTACKER; // must be set before getting stack position

View File

@ -57,7 +57,7 @@
"targetType" : "NO_TARGET", "targetType" : "NO_TARGET",
"sounds": { "sounds": {
"cast": "" // no casting sound, only obstacle placement sound "cast": "", // no casting sound, only obstacle placement sound
}, },
"levels" : { "levels" : {
"base":{ "base":{
@ -75,12 +75,16 @@
"attacker" :{ "attacker" :{
"animation" : "C09SPF1", "animation" : "C09SPF1",
"appearAnimation" : "C09SPF0", "appearAnimation" : "C09SPF0",
"appearSound" : "LANDMINE" "appearSound" : "LANDMINE",
"triggerAnimation" : "C09SPF3",
"triggerSound" : "LANDKILL"
}, },
"defender" :{ "defender" :{
"animation" : "C09SPF1", "animation" : "C09SPF1",
"appearAnimation" : "C09SPF0", "appearAnimation" : "C09SPF0",
"appearSound" : "LANDMINE" "appearSound" : "LANDMINE",
"triggerAnimation" : "C09SPF3",
"triggerSound" : "LANDKILL"
} }
}, },
"damage":{ "damage":{

View File

@ -278,7 +278,9 @@ public:
ADD, ADD,
RESET_STATE, RESET_STATE,
UPDATE, UPDATE,
REMOVE REMOVE,
ACTIVATE_AND_UPDATE,
ACTIVATE_AND_REMOVE
}; };
JsonNode data; JsonNode data;

View File

@ -1663,6 +1663,7 @@ DLL_LINKAGE void BattleObstaclesChanged::applyBattle(IBattleState * battleState)
case BattleChanges::EOperation::ADD: case BattleChanges::EOperation::ADD:
battleState->addObstacle(change); battleState->addObstacle(change);
break; break;
case BattleChanges::EOperation::ACTIVATE_AND_UPDATE:
case BattleChanges::EOperation::UPDATE: case BattleChanges::EOperation::UPDATE:
battleState->updateObstacle(change); battleState->updateObstacle(change);
break; break;

View File

@ -32,7 +32,7 @@ public:
Obstacle obstacle; Obstacle obstacle;
si32 iconIndex; si32 iconIndex;
std::string identifier; std::string identifier;
std::string appearSound, appearAnimation, animation, dissapearAnimation; std::string appearSound, appearAnimation, triggerAnimation, triggerSound, animation;
std::vector<TerrainId> allowedTerrains; std::vector<TerrainId> allowedTerrains;
std::vector<std::string> allowedSpecialBfields; std::vector<std::string> allowedSpecialBfields;
@ -63,7 +63,8 @@ public:
h & animation; h & animation;
h & appearSound; h & appearSound;
h & appearAnimation; h & appearAnimation;
h & dissapearAnimation; h & triggerSound;
h & triggerAnimation;
h & allowedTerrains; h & allowedTerrains;
h & allowedSpecialBfields; h & allowedSpecialBfields;
h & isAbsoluteObstacle; h & isAbsoluteObstacle;

View File

@ -178,6 +178,8 @@ void SpellCreatedObstacle::serializeJson(JsonSerializeFormat & handler)
handler.serializeString("appearSound", appearSound); handler.serializeString("appearSound", appearSound);
handler.serializeString("appearAnimation", appearAnimation); handler.serializeString("appearAnimation", appearAnimation);
handler.serializeString("triggerSound", triggerSound);
handler.serializeString("triggerAnimation", triggerAnimation);
handler.serializeString("animation", animation); handler.serializeString("animation", animation);
handler.serializeInt("animationYOffset", animationYOffset); handler.serializeInt("animationYOffset", animationYOffset);

View File

@ -81,6 +81,8 @@ struct DLL_LINKAGE SpellCreatedObstacle : CObstacleInstance
std::string appearSound; std::string appearSound;
std::string appearAnimation; std::string appearAnimation;
std::string triggerSound;
std::string triggerAnimation;
std::string animation; std::string animation;
int animationYOffset; int animationYOffset;

View File

@ -43,6 +43,8 @@ void ObstacleSideOptions::serializeJson(JsonSerializeFormat & handler)
handler.serializeString("appearSound", appearSound); handler.serializeString("appearSound", appearSound);
handler.serializeString("appearAnimation", appearAnimation); handler.serializeString("appearAnimation", appearAnimation);
handler.serializeString("triggerSound", triggerSound);
handler.serializeString("triggerAnimation", triggerAnimation);
handler.serializeString("animation", animation); handler.serializeString("animation", animation);
handler.serializeInt("offsetY", offsetY); handler.serializeInt("offsetY", offsetY);
@ -316,6 +318,8 @@ void Obstacle::placeObstacles(ServerCallback * server, const Mechanics * m, cons
obstacle.appearSound = options.appearSound; obstacle.appearSound = options.appearSound;
obstacle.appearAnimation = options.appearAnimation; obstacle.appearAnimation = options.appearAnimation;
obstacle.triggerSound = options.triggerSound;
obstacle.triggerAnimation = options.triggerAnimation;
obstacle.animation = options.animation; obstacle.animation = options.animation;
obstacle.animationYOffset = options.offsetY; obstacle.animationYOffset = options.offsetY;

View File

@ -31,6 +31,8 @@ public:
std::string appearSound; std::string appearSound;
std::string appearAnimation; std::string appearAnimation;
std::string triggerSound;
std::string triggerAnimation;
std::string animation; std::string animation;
int offsetY; int offsetY;

View File

@ -5459,33 +5459,29 @@ bool CGameHandler::handleDamageFromObstacle(const CStack * curStack, bool stackI
if(!sp) if(!sp)
COMPLAIN_RET("Invalid obstacle instance"); COMPLAIN_RET("Invalid obstacle instance");
// For the hidden spell created obstacles, e.g. QuickSand, it should be revealed after taking damage
ObstacleChanges changeInfo;
changeInfo.id = spellObstacle->uniqueID;
if (oneTimeObstacle)
changeInfo.operation = ObstacleChanges::EOperation::ACTIVATE_AND_REMOVE;
else
changeInfo.operation = ObstacleChanges::EOperation::ACTIVATE_AND_UPDATE;
SpellCreatedObstacle changedObstacle;
changedObstacle.uniqueID = spellObstacle->uniqueID;
changedObstacle.revealed = true;
changeInfo.data.clear();
JsonSerializer ser(nullptr, changeInfo.data);
ser.serializeStruct("obstacle", changedObstacle);
BattleObstaclesChanged bocp;
bocp.changes.emplace_back(changeInfo);
sendAndApply(&bocp);
spells::BattleCast battleCast(gs->curB, &caster, spells::Mode::HERO, sp); spells::BattleCast battleCast(gs->curB, &caster, spells::Mode::HERO, sp);
battleCast.applyEffects(spellEnv, spells::Target(1, spells::Destination(curStack)), true); battleCast.applyEffects(spellEnv, spells::Target(1, spells::Destination(curStack)), true);
if(oneTimeObstacle)
{
removeObstacle(*obstacle);
} }
else
{
// For the hidden spell created obstacles, e.g. QuickSand, it should be revealed after taking damage
ObstacleChanges changeInfo;
changeInfo.id = spellObstacle->uniqueID;
changeInfo.operation = ObstacleChanges::EOperation::UPDATE;
SpellCreatedObstacle changedObstacle;
changedObstacle.uniqueID = spellObstacle->uniqueID;
changedObstacle.revealed = true;
changeInfo.data.clear();
JsonSerializer ser(nullptr, changeInfo.data);
ser.serializeStruct("obstacle", changedObstacle);
BattleObstaclesChanged bocp;
bocp.changes.emplace_back(changeInfo);
sendAndApply(&bocp);
}
}
} }
} }
else if(obstacle->obstacleType == CObstacleInstance::MOAT) else if(obstacle->obstacleType == CObstacleInstance::MOAT)
@ -7225,7 +7221,7 @@ void CGameHandler::handleCheatCode(std::string & cheat, PlayerColor player, cons
void CGameHandler::removeObstacle(const CObstacleInstance & obstacle) void CGameHandler::removeObstacle(const CObstacleInstance & obstacle)
{ {
BattleObstaclesChanged obsRem; BattleObstaclesChanged obsRem;
obsRem.changes.emplace_back(obstacle.uniqueID, BattleChanges::EOperation::REMOVE); obsRem.changes.emplace_back(obstacle.uniqueID, ObstacleChanges::EOperation::REMOVE);
sendAndApply(&obsRem); sendAndApply(&obsRem);
} }