diff --git a/AI/StupidAI/StupidAI.cpp b/AI/StupidAI/StupidAI.cpp index f6bd0c04e..07678fb0a 100644 --- a/AI/StupidAI/StupidAI.cpp +++ b/AI/StupidAI/StupidAI.cpp @@ -202,7 +202,7 @@ void CStupidAI::battleNewRound(int round) print("battleNewRound called"); } -void CStupidAI::battleStackMoved(const CStack * stack, std::vector dest, int distance) +void CStupidAI::battleStackMoved(const CStack * stack, std::vector dest, int distance, bool teleport) { print("battleStackMoved called"); } diff --git a/AI/StupidAI/StupidAI.h b/AI/StupidAI/StupidAI.h index 6521f0902..4e4dc4062 100644 --- a/AI/StupidAI/StupidAI.h +++ b/AI/StupidAI/StupidAI.h @@ -36,7 +36,7 @@ public: //void battleResultsApplied() override; //called when all effects of last battle are applied void battleNewRoundFirst(int round) override; //called at the beginning of each turn before changes are applied; void battleNewRound(int round) override; //called at the beginning of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn - void battleStackMoved(const CStack * stack, std::vector dest, int distance) override; + void battleStackMoved(const CStack * stack, std::vector dest, int distance, bool teleport) override; void battleSpellCast(const BattleSpellCast *sc) override; void battleStacksEffectsSet(const SetStackEffect & sse) override;//called when a specific effect is set to stacks //void battleTriggerEffect(const BattleTriggerEffect & bte) override; diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index 4959a0c69..588c07aee 100644 --- a/client/CPlayerInterface.cpp +++ b/client/CPlayerInterface.cpp @@ -913,12 +913,12 @@ void CPlayerInterface::battleLogMessage(const std::vector & lines) battleInt->displayBattleLog(lines); } -void CPlayerInterface::battleStackMoved(const CStack * stack, std::vector dest, int distance) +void CPlayerInterface::battleStackMoved(const CStack * stack, std::vector dest, int distance, bool teleport) { EVENT_HANDLER_CALLED_BY_CLIENT; BATTLE_EVENT_POSSIBLE_RETURN; - battleInt->stackMoved(stack, dest, distance); + battleInt->stackMoved(stack, dest, distance, teleport); } void CPlayerInterface::battleSpellCast( const BattleSpellCast *sc ) { diff --git a/client/CPlayerInterface.h b/client/CPlayerInterface.h index c1b07a4db..106a4d524 100644 --- a/client/CPlayerInterface.h +++ b/client/CPlayerInterface.h @@ -193,7 +193,7 @@ public: void battleNewRoundFirst(int round) override; //called at the beginning of each turn before changes are applied; used for HP regen handling void battleNewRound(int round) override; //called at the beginning of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn void battleLogMessage(const std::vector & lines) override; - void battleStackMoved(const CStack * stack, std::vector dest, int distance) override; + void battleStackMoved(const CStack * stack, std::vector dest, int distance, bool teleport) override; void battleSpellCast(const BattleSpellCast *sc) override; void battleStacksEffectsSet(const SetStackEffect & sse) override; //called when a specific effect is set to stacks void battleTriggerEffect(const BattleTriggerEffect & bte) override; //various one-shot effect diff --git a/client/NetPacksClient.cpp b/client/NetPacksClient.cpp index 68ddf3789..3d4784d04 100644 --- a/client/NetPacksClient.cpp +++ b/client/NetPacksClient.cpp @@ -738,7 +738,7 @@ void BattleResult::applyFirstCl(CClient *cl) void BattleStackMoved::applyFirstCl(CClient *cl) { const CStack * movedStack = GS(cl)->curB->battleGetStackByID(stack); - callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleStackMoved, movedStack, tilesToMove, distance); + callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleStackMoved, movedStack, tilesToMove, distance, teleporting); } void BattleAttack::applyFirstCl(CClient *cl) diff --git a/client/battle/BattleAnimationClasses.cpp b/client/battle/BattleAnimationClasses.cpp index 8a3e78a68..ad9a84d55 100644 --- a/client/battle/BattleAnimationClasses.cpp +++ b/client/battle/BattleAnimationClasses.cpp @@ -331,11 +331,11 @@ bool MovementAnimation::init() { assert(stack); assert(!myAnim->isDeadOrDying()); + assert(stackAnimation(stack)->framesInGroup(ECreatureAnimType::MOVING) > 0); - if(stackAnimation(stack)->framesInGroup(ECreatureAnimType::MOVING) == 0 || - stack->hasBonus(Selector::typeSubtype(Bonus::FLYING, 1))) + if(stackAnimation(stack)->framesInGroup(ECreatureAnimType::MOVING) == 0) { - //no movement or teleport, end immediately + //no movement, end immediately delete this; return false; } @@ -576,6 +576,11 @@ ResurrectionAnimation::ResurrectionAnimation(BattleInterface & owner, const CSta logAnim->debug("Created ResurrectionAnimation for %s", stack->getName()); } +bool ColorTransformAnimation::init() +{ + return true; +} + void ColorTransformAnimation::nextFrame() { float elapsed = GH.mainFPSmng->getElapsedMilliseconds() / 1000.f; @@ -614,7 +619,7 @@ void ColorTransformAnimation::nextFrame() } ColorTransformAnimation::ColorTransformAnimation(BattleInterface & owner, const CStack * _stack, const CSpell * spell): - StackActionAnimation(owner, _stack), + BattleStackAnimation(owner, _stack), spell(spell), totalProgress(0.f) { @@ -658,20 +663,35 @@ ColorTransformAnimation * ColorTransformAnimation::petrifyAnimation(BattleInterf return result; } -ColorTransformAnimation * ColorTransformAnimation::fadeInAnimation(BattleInterface & owner, const CStack * stack) +ColorTransformAnimation * ColorTransformAnimation::summonAnimation(BattleInterface & owner, const CStack * stack) +{ + auto result = teleportInAnimation(owner, stack); + result->timePoints.back() = 1.0f; + return result; +} + + +ColorTransformAnimation * ColorTransformAnimation::teleportInAnimation(BattleInterface & owner, const CStack * stack) { auto result = new ColorTransformAnimation(owner, stack, nullptr); result->steps.push_back(ColorFilter::genAlphaShifter(0.f)); result->steps.push_back(ColorFilter::genEmptyShifter()); - result->timePoints.push_back(0.f); - result->timePoints.push_back(1.f); + result->timePoints.push_back(0.0f); + result->timePoints.push_back(0.2f); + return result; +} + +ColorTransformAnimation * ColorTransformAnimation::teleportOutAnimation(BattleInterface & owner, const CStack * stack) +{ + auto result = teleportInAnimation(owner, stack); + std::swap(result->steps[0], result->steps[1]); return result; } ColorTransformAnimation * ColorTransformAnimation::fadeOutAnimation(BattleInterface & owner, const CStack * stack) { - auto result = fadeInAnimation(owner, stack); - std::swap(result->steps[0], result->steps[1]); + auto result = teleportOutAnimation(owner, stack); + result->timePoints.back() = 1.0f; return result; } diff --git a/client/battle/BattleAnimationClasses.h b/client/battle/BattleAnimationClasses.h index 01a8c532f..2f465dea1 100644 --- a/client/battle/BattleAnimationClasses.h +++ b/client/battle/BattleAnimationClasses.h @@ -112,7 +112,7 @@ public: ResurrectionAnimation(BattleInterface & owner, const CStack * _stack); }; -class ColorTransformAnimation : public StackActionAnimation +class ColorTransformAnimation : public BattleStackAnimation { std::vector steps; std::vector timePoints; @@ -120,16 +120,19 @@ class ColorTransformAnimation : public StackActionAnimation float totalProgress; + bool init() override; void nextFrame() override; ColorTransformAnimation(BattleInterface & owner, const CStack * _stack, const CSpell * spell); public: - static ColorTransformAnimation * petrifyAnimation (BattleInterface & owner, const CStack * _stack, const CSpell * spell); - static ColorTransformAnimation * cloneAnimation (BattleInterface & owner, const CStack * _stack, const CSpell * spell); - static ColorTransformAnimation * bloodlustAnimation(BattleInterface & owner, const CStack * _stack, const CSpell * spell); - static ColorTransformAnimation * fadeInAnimation (BattleInterface & owner, const CStack * _stack); - static ColorTransformAnimation * fadeOutAnimation (BattleInterface & owner, const CStack * _stack); + static ColorTransformAnimation * petrifyAnimation (BattleInterface & owner, const CStack * _stack, const CSpell * spell); + static ColorTransformAnimation * cloneAnimation (BattleInterface & owner, const CStack * _stack, const CSpell * spell); + static ColorTransformAnimation * bloodlustAnimation (BattleInterface & owner, const CStack * _stack, const CSpell * spell); + static ColorTransformAnimation * summonAnimation (BattleInterface & owner, const CStack * _stack); + static ColorTransformAnimation * fadeOutAnimation (BattleInterface & owner, const CStack * _stack); + static ColorTransformAnimation * teleportInAnimation (BattleInterface & owner, const CStack * _stack); + static ColorTransformAnimation * teleportOutAnimation (BattleInterface & owner, const CStack * _stack); }; /// Base class for all animations that play during stack movement diff --git a/client/battle/BattleInterface.cpp b/client/battle/BattleInterface.cpp index c83a19dea..413b75308 100644 --- a/client/battle/BattleInterface.cpp +++ b/client/battle/BattleInterface.cpp @@ -335,9 +335,12 @@ void BattleInterface::stackActivated(const CStack *stack) stacksController->stackActivated(stack); } -void BattleInterface::stackMoved(const CStack *stack, std::vector destHex, int distance) +void BattleInterface::stackMoved(const CStack *stack, std::vector destHex, int distance, bool teleport) { - stacksController->stackMoved(stack, destHex, distance); + if (teleport) + stacksController->stackTeleported(stack, destHex, distance); + else + stacksController->stackMoved(stack, destHex, distance); } void BattleInterface::stacksAreAttacked(std::vector attackedInfos) diff --git a/client/battle/BattleInterface.h b/client/battle/BattleInterface.h index 1c3ae65a2..6608128ab 100644 --- a/client/battle/BattleInterface.h +++ b/client/battle/BattleInterface.h @@ -197,7 +197,7 @@ public: void stackAdded(const CStack * stack); //new stack appeared on battlefield void stackRemoved(uint32_t stackID); //stack disappeared from batlefiled void stackActivated(const CStack *stack); //active stack has been changed - void stackMoved(const CStack *stack, std::vector destHex, int distance); //stack with id number moved to destHex + void stackMoved(const CStack *stack, std::vector destHex, int distance, bool teleport); //stack with id number moved to destHex void stacksAreAttacked(std::vector attackedInfos); //called when a certain amount of stacks has been attacked void stackAttacking(const StackAttackInfo & attackInfo); //called when stack with id ID is attacking something on hex dest void newRoundFirst( int round ); diff --git a/client/battle/BattleStacksController.cpp b/client/battle/BattleStacksController.cpp index b6cedeccf..dc7e27342 100644 --- a/client/battle/BattleStacksController.cpp +++ b/client/battle/BattleStacksController.cpp @@ -223,7 +223,7 @@ void BattleStacksController::stackAdded(const CStack * stack, bool instant) owner.executeOnAnimationCondition(EAnimationEvents::HIT, true, [=]() { - addNewAnim(ColorTransformAnimation::fadeInAnimation(owner, stack)); + addNewAnim(ColorTransformAnimation::summonAnimation(owner, stack)); if (stack->isClone()) addNewAnim(ColorTransformAnimation::cloneAnimation(owner, stack, SpellID(SpellID::CLONE).toSpell())); }); @@ -472,6 +472,23 @@ void BattleStacksController::stacksAreAttacked(std::vector at executeAttackAnimations(); } +void BattleStacksController::stackTeleported(const CStack *stack, std::vector destHex, int distance) +{ + assert(destHex.size() > 0); + assert(owner.getAnimationCondition(EAnimationEvents::ACTION) == false); + + owner.executeOnAnimationCondition(EAnimationEvents::HIT, true, [=](){ + addNewAnim( ColorTransformAnimation::teleportOutAnimation(owner, stack) ); + }); + + owner.executeOnAnimationCondition(EAnimationEvents::AFTER_HIT, true, [=](){ + stackAnimation[stack->ID]->pos.moveTo(getStackPositionAtHex(destHex.back(), stack)); + addNewAnim( ColorTransformAnimation::teleportInAnimation(owner, stack) ); + }); + + // animations will be executed by spell +} + void BattleStacksController::stackMoved(const CStack *stack, std::vector destHex, int distance) { assert(destHex.size() > 0); @@ -486,8 +503,12 @@ void BattleStacksController::stackMoved(const CStack *stack, std::vectorhasBonus(Selector::typeSubtype(Bonus::FLYING, 1)) ) + { + addNewAnim(new MovementAnimation(owner, stack, destHex, distance)); + owner.waitForAnimationCondition(EAnimationEvents::ACTION, false); + } addNewAnim(new MovementEndAnimation(owner, stack, destHex.back())); owner.waitForAnimationCondition(EAnimationEvents::ACTION, false); @@ -806,7 +827,7 @@ void BattleStacksController::removeExpiredColorFilters() return false; if (filter.effect == ColorFilter::genEmptyShifter()) return false; - if (filter.target->hasBonus(Selector::source(Bonus::SPELL_EFFECT, filter.source->id))) + if (filter.source && filter.target->hasBonus(Selector::source(Bonus::SPELL_EFFECT, filter.source->id))) return false; return true; }); diff --git a/client/battle/BattleStacksController.h b/client/battle/BattleStacksController.h index feca64a4e..f2e54fcb8 100644 --- a/client/battle/BattleStacksController.h +++ b/client/battle/BattleStacksController.h @@ -113,6 +113,7 @@ public: void stackRemoved(uint32_t stackID); //stack disappeared from batlefiled void stackActivated(const CStack *stack); //active stack has been changed void stackMoved(const CStack *stack, std::vector destHex, int distance); //stack with id number moved to destHex + void stackTeleported(const CStack *stack, std::vector destHex, int distance); //stack with id number moved to destHex void stacksAreAttacked(std::vector attackedInfos); //called when a certain amount of stacks has been attacked void stackAttacking(const StackAttackInfo & info); //called when stack with id ID is attacking something on hex dest diff --git a/lib/CGameInterface.cpp b/lib/CGameInterface.cpp index 56c576acc..0d0ab859d 100644 --- a/lib/CGameInterface.cpp +++ b/lib/CGameInterface.cpp @@ -204,9 +204,9 @@ void CAdventureAI::battleObstaclesChanged(const std::vector & o battleAI->battleObstaclesChanged(obstacles); } -void CAdventureAI::battleStackMoved(const CStack * stack, std::vector dest, int distance) +void CAdventureAI::battleStackMoved(const CStack * stack, std::vector dest, int distance, bool teleport) { - battleAI->battleStackMoved(stack, dest, distance); + battleAI->battleStackMoved(stack, dest, distance, teleport); } void CAdventureAI::battleAttack(const BattleAttack * ba) diff --git a/lib/CGameInterface.h b/lib/CGameInterface.h index 30b2e8174..895552441 100644 --- a/lib/CGameInterface.h +++ b/lib/CGameInterface.h @@ -160,7 +160,7 @@ public: virtual void actionFinished(const BattleAction &action) override; virtual void battleStacksEffectsSet(const SetStackEffect & sse) override; virtual void battleObstaclesChanged(const std::vector & obstacles) override; - virtual void battleStackMoved(const CStack * stack, std::vector dest, int distance) override; + virtual void battleStackMoved(const CStack * stack, std::vector dest, int distance, bool teleport) override; virtual void battleAttack(const BattleAttack *ba) override; virtual void battleSpellCast(const BattleSpellCast *sc) override; virtual void battleEnd(const BattleResult *br) override; diff --git a/lib/IGameEventsReceiver.h b/lib/IGameEventsReceiver.h index 1388bb6ec..c237c15ac 100644 --- a/lib/IGameEventsReceiver.h +++ b/lib/IGameEventsReceiver.h @@ -63,7 +63,7 @@ public: virtual void battleNewRoundFirst(int round){}; //called at the beginning of each turn before changes are applied; virtual void battleNewRound(int round){}; //called at the beginning of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn virtual void battleLogMessage(const std::vector & lines){}; - virtual void battleStackMoved(const CStack * stack, std::vector dest, int distance){}; + virtual void battleStackMoved(const CStack * stack, std::vector dest, int distance, bool teleport){}; virtual void battleSpellCast(const BattleSpellCast *sc){}; virtual void battleStacksEffectsSet(const SetStackEffect & sse){};//called when a specific effect is set to stacks virtual void battleTriggerEffect(const BattleTriggerEffect & bte){}; //called for various one-shot effects diff --git a/lib/NetPacks.h b/lib/NetPacks.h index 5a8a94eda..f4b5db7ca 100644 --- a/lib/NetPacks.h +++ b/lib/NetPacks.h @@ -1545,6 +1545,7 @@ struct BattleStackMoved : public CPackForClient h & stack; h & tilesToMove; h & distance; + h & teleporting; } };