1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-26 03:52:01 +02:00

All battle effects are now fully client sided

This commit is contained in:
Ivan Savenko 2022-12-17 17:35:15 +02:00
parent ced2ece954
commit deffba01b9
19 changed files with 66 additions and 134 deletions

View File

@ -707,7 +707,7 @@ void CPlayerInterface::battleStart(const CCreatureSet *army1, const CCreatureSet
BATTLE_EVENT_POSSIBLE_RETURN;
}
void CPlayerInterface::battleUnitsChanged(const std::vector<UnitChanges> & units, const std::vector<CustomEffectInfo> & customEffects)
void CPlayerInterface::battleUnitsChanged(const std::vector<UnitChanges> & units)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
BATTLE_EVENT_POSSIBLE_RETURN;
@ -747,8 +747,6 @@ void CPlayerInterface::battleUnitsChanged(const std::vector<UnitChanges> & units
break;
}
}
battleInt->effectsController->displayCustomEffects(customEffects);
}
void CPlayerInterface::battleObstaclesChanged(const std::vector<ObstacleChanges> & obstacles)
@ -962,15 +960,12 @@ void CPlayerInterface::battleStacksAttacked(const std::vector<BattleStackAttacke
info.attacker = attacker;
info.damageDealt = elem.damageAmount;
info.amountKilled = elem.killedAmount;
info.battleEffect = EBattleEffect::INVALID;
info.spellEffect = SpellID::NONE;
info.indirectAttack = ranged;
info.killed = elem.killed();
info.rebirth = elem.willRebirth();
info.cloneKilled = elem.cloneKilled();
if(elem.isEffect() && !elem.isSecondary())
info.battleEffect = EBattleEffect::EBattleEffect(elem.effect);
info.fireShield = elem.fireShield();
if (elem.isSpell())
info.spellEffect = elem.spellID;

View File

@ -200,7 +200,7 @@ public:
void battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa, bool ranged) override;
void battleStartBefore(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2) override; //called by engine just before battle starts; side=0 - left, side=1 - right
void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side) override; //called by engine when battle starts; side=0 - left, side=1 - right
void battleUnitsChanged(const std::vector<UnitChanges> & units, const std::vector<CustomEffectInfo> & customEffects) override;
void battleUnitsChanged(const std::vector<UnitChanges> & units) override;
void battleObstaclesChanged(const std::vector<ObstacleChanges> & obstacles) override;
void battleCatapultAttacked(const CatapultAttack & ca) override; //called when catapult makes an attack
void battleGateStateChanged(const EGateState state) override;

View File

@ -782,7 +782,7 @@ void BattleResultsApplied::applyCl(CClient *cl)
void BattleUnitsChanged::applyCl(CClient * cl)
{
callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleUnitsChanged, changedStacks, customEffects);
callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleUnitsChanged, changedStacks);
}
void BattleObstaclesChanged::applyCl(CClient *cl)

View File

@ -9,6 +9,27 @@
*/
#pragma once
enum class EBattleEffect
{
// list of battle effects that have hardcoded triggers
MAGIC_MIRROR = 3,
FIRE_SHIELD = 11,
FEAR = 15,
GOOD_LUCK = 18,
GOOD_MORALE = 20,
BAD_MORALE = 30,
BAD_LUCK = 48,
RESURRECT = 50,
DRAIN_LIFE = 52,
POISON = 67,
DEATH_BLOW = 73,
REGENERATION = 74,
MANA_DRAIN = 77,
RESISTANCE = 78,
INVALID = -1,
};
enum class EAnimationEvents {
OPENING = 0, // TODO battle opening sound is playing
ACTION = 1, // there are any ongoing animations
@ -22,27 +43,6 @@ enum class EAnimationEvents {
COUNT
};
namespace EBattleEffect
{
enum EBattleEffect
{
// list of battle effects that have hardcoded triggers
FEAR = 15,
GOOD_LUCK = 18,
GOOD_MORALE = 20,
BAD_MORALE = 30,
BAD_LUCK = 48,
RESURRECT = 50,
DRAIN_LIFE = 52,
POISON = 67,
DEATH_BLOW = 73,
REGENERATION = 74,
MANA_DRAIN = 77,
INVALID = -1,
};
}
enum class EHeroAnimType
{
HOLDING = 0,

View File

@ -35,31 +35,20 @@ BattleEffectsController::BattleEffectsController(BattleInterface & owner):
owner(owner)
{}
void BattleEffectsController::displayEffect(EBattleEffect::EBattleEffect effect, const BattleHex & destTile)
void BattleEffectsController::displayEffect(EBattleEffect effect, const BattleHex & destTile)
{
displayEffect(effect, soundBase::invalid, destTile);
}
void BattleEffectsController::displayEffect(EBattleEffect::EBattleEffect effect, uint32_t soundID, const BattleHex & destTile)
void BattleEffectsController::displayEffect(EBattleEffect effect, uint32_t soundID, const BattleHex & destTile)
{
std::string customAnim = graphics->battleACToDef[effect][0];
size_t effectID = static_cast<size_t>(effect);
std::string customAnim = graphics->battleACToDef[effectID][0];
owner.stacksController->addNewAnim(new PointEffectAnimation(owner, soundBase::stringsList()[soundID], customAnim, destTile));
}
void BattleEffectsController::displayCustomEffects(const std::vector<CustomEffectInfo> & customEffects)
{
for(const CustomEffectInfo & one : customEffects)
{
const CStack * s = owner.curInt->cb->battleGetStackByID(one.stack, false);
assert(s);
assert(one.effect != 0);
displayEffect(EBattleEffect::EBattleEffect(one.effect), soundBase::soundID(one.sound), s->getPosition());
}
}
void BattleEffectsController::battleTriggerEffect(const BattleTriggerEffect & bte)
{
assert(owner.getAnimationCondition(EAnimationEvents::ACTION) == false);

View File

@ -15,7 +15,6 @@
VCMI_LIB_NAMESPACE_BEGIN
class BattleAction;
struct CustomEffectInfo;
struct BattleTriggerEffect;
VCMI_LIB_NAMESPACE_END
@ -49,11 +48,9 @@ public:
void startAction(const BattleAction* action);
void displayCustomEffects(const std::vector<CustomEffectInfo> & customEffects);
//displays custom effect on the battlefield
void displayEffect(EBattleEffect::EBattleEffect effect, const BattleHex & destTile);
void displayEffect(EBattleEffect::EBattleEffect effect, uint32_t soundID, const BattleHex & destTile);
void displayEffect(EBattleEffect effect, const BattleHex & destTile);
void displayEffect(EBattleEffect effect, uint32_t soundID, const BattleHex & destTile);
void battleTriggerEffect(const BattleTriggerEffect & bte);

View File

@ -550,17 +550,22 @@ void BattleInterface::spellCast(const BattleSpellCast * sc)
}
}
//queuing additional animation (magic mirror / resistance)
for(auto & elem : sc->customEffects)
for(auto & elem : sc->reflectedCres)
{
auto stack = curInt->cb->battleGetStackByID(elem.stack, false);
auto stack = curInt->cb->battleGetStackByID(elem, false);
assert(stack);
if(stack)
{
executeOnAnimationCondition(EAnimationEvents::HIT, true, [=](){
effectsController->displayEffect(EBattleEffect::EBattleEffect(elem.effect), stack->getPosition());
effectsController->displayEffect(EBattleEffect::MAGIC_MIRROR, stack->getPosition());
});
}
for(auto & elem : sc->resistedCres)
{
auto stack = curInt->cb->battleGetStackByID(elem, false);
assert(stack);
executeOnAnimationCondition(EAnimationEvents::HIT, true, [=](){
effectsController->displayEffect(EBattleEffect::RESISTANCE, stack->getPosition());
});
}
//mana absorption

View File

@ -29,7 +29,6 @@ struct CatapultAttack;
struct BattleTriggerEffect;
struct BattleHex;
struct InfoAboutHero;
struct CustomEffectInfo;
VCMI_LIB_NAMESPACE_END
@ -62,14 +61,13 @@ struct StackAttackedInfo
int64_t damageDealt;
uint32_t amountKilled;
EBattleEffect::EBattleEffect battleEffect;
SpellID spellEffect;
bool indirectAttack; //if true, stack was attacked indirectly - spell or ranged attack
bool killed; //if true, stack has been killed
bool rebirth; //if true, play rebirth animation after all
bool cloneKilled;
bool fireShield;
};
struct StackAttackInfo
@ -78,7 +76,6 @@ struct StackAttackInfo
const CStack *defender;
std::vector< const CStack *> secondaryDefender;
//EBattleEffect::EBattleEffect battleEffect;
SpellID spellEffect;
BattleHex tile;

View File

@ -444,8 +444,8 @@ void BattleStacksController::stacksAreAttacked(std::vector<StackAttackedInfo> at
else
addNewAnim(new HittedAnimation(owner, attackedInfo.defender));
if (attackedInfo.battleEffect != EBattleEffect::INVALID)
owner.effectsController->displayEffect(EBattleEffect::EBattleEffect(attackedInfo.battleEffect), attackedInfo.defender->getPosition());
if (attackedInfo.fireShield)
owner.effectsController->displayEffect(EBattleEffect::FIRE_SHIELD, attackedInfo.attacker->getPosition());
if (attackedInfo.spellEffect != SpellID::NONE)
owner.displaySpellEffect(attackedInfo.spellEffect, attackedInfo.defender->getPosition());

View File

@ -225,9 +225,9 @@ void CAdventureAI::battleEnd(const BattleResult * br)
battleAI.reset();
}
void CAdventureAI::battleUnitsChanged(const std::vector<UnitChanges> & units, const std::vector<CustomEffectInfo> & customEffects)
void CAdventureAI::battleUnitsChanged(const std::vector<UnitChanges> & units)
{
battleAI->battleUnitsChanged(units, customEffects);
battleAI->battleUnitsChanged(units);
}
BattleAction CAdventureAI::activeStack(const CStack * stack)

View File

@ -164,7 +164,7 @@ public:
virtual void battleAttack(const BattleAttack *ba) override;
virtual void battleSpellCast(const BattleSpellCast *sc) override;
virtual void battleEnd(const BattleResult *br) override;
virtual void battleUnitsChanged(const std::vector<UnitChanges> & units, const std::vector<CustomEffectInfo> & customEffects) override;
virtual void battleUnitsChanged(const std::vector<UnitChanges> & units) override;
virtual void saveGame(BinarySerializer & h, const int version) override;
virtual void loadGame(BinaryDeserializer & h, const int version) override;

View File

@ -49,7 +49,6 @@ struct CObstacleInstance;
struct CPackForServer;
class EVictoryLossCheckResult;
struct MetaString;
struct CustomEffectInfo;
class ObstacleChanges;
class UnitChanges;
@ -70,7 +69,7 @@ public:
virtual void battleTriggerEffect(const BattleTriggerEffect & bte){}; //called for various one-shot effects
virtual void battleStartBefore(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2) {}; //called just before battle start
virtual void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side){}; //called by engine when battle starts; side=0 - left, side=1 - right
virtual void battleUnitsChanged(const std::vector<UnitChanges> & units, const std::vector<CustomEffectInfo> & customEffects){};
virtual void battleUnitsChanged(const std::vector<UnitChanges> & units){};
virtual void battleObstaclesChanged(const std::vector<ObstacleChanges> & obstacles){};
virtual void battleCatapultAttacked(const CatapultAttack & ca){}; //called when catapult makes an attack
virtual void battleGateStateChanged(const EGateState state){};

View File

@ -1557,12 +1557,10 @@ struct BattleUnitsChanged : public CPackForClient
void applyCl(CClient *cl);
std::vector<UnitChanges> changedStacks;
std::vector<CustomEffectInfo> customEffects;
template <typename Handler> void serialize(Handler & h, const int version)
{
h & changedStacks;
h & customEffects;
}
};
@ -1575,7 +1573,6 @@ struct BattleStackAttacked
damageAmount(0),
newState(),
flags(0),
effect(0),
spellID(SpellID::NONE)
{};
@ -1586,9 +1583,8 @@ struct BattleStackAttacked
ui32 killedAmount;
int64_t damageAmount;
UnitChanges newState;
enum EFlags {KILLED = 1, EFFECT = 2/*deprecated */, SECONDARY = 4, REBIRTH = 8, CLONE_KILLED = 16, SPELL_EFFECT = 32 /*, BONUS_EFFECT = 64 */};
enum EFlags {KILLED = 1, SECONDARY = 2, REBIRTH = 4, CLONE_KILLED = 8, SPELL_EFFECT = 16, FIRE_SHIELD = 32, };
ui32 flags; //uses EFlags (above)
ui32 effect; //set only if flag EFFECT is set
SpellID spellID; //only if flag SPELL_EFFECT is set
bool killed() const//if target stack was killed
@ -1599,10 +1595,6 @@ struct BattleStackAttacked
{
return flags & CLONE_KILLED;
}
bool isEffect() const//if stack has been attacked by a spell
{
return flags & EFFECT;
}
bool isSecondary() const//if stack was not a primary target (receives no spell effects)
{
return flags & SECONDARY;
@ -1616,6 +1608,10 @@ struct BattleStackAttacked
{
return flags & REBIRTH;
}
bool fireShield() const
{
return flags & FIRE_SHIELD;
}
template <typename Handler> void serialize(Handler &h, const int version)
{
h & stackAttacked;
@ -1624,7 +1620,6 @@ struct BattleStackAttacked
h & flags;
h & killedAmount;
h & damageAmount;
h & effect;
h & spellID;
}
bool operator<(const BattleStackAttacked &b) const
@ -1737,8 +1732,9 @@ struct BattleSpellCast : public CPackForClient
SpellID spellID; //id of spell
ui8 manaGained; //mana channeling ability
BattleHex tile; //destination tile (may not be set in some global/mass spells
std::vector<CustomEffectInfo> customEffects;
std::set<ui32> affectedCres; //ids of creatures affected by this spell, generally used if spell does not set any effect (like dispel or cure)
std::set<ui32> resistedCres; // creatures that resisted the spell (e.g. Dwarves)
std::set<ui32> reflectedCres; // creatures that reflected the spell (e.g. Magic Mirror spell)
si32 casterStack;// -1 if not cated by creature, >=0 caster stack ID
bool castByHero; //if true - spell has been cast by hero, otherwise by a creature
@ -1748,8 +1744,9 @@ struct BattleSpellCast : public CPackForClient
h & spellID;
h & manaGained;
h & tile;
h & customEffects;
h & affectedCres;
h & resistedCres;
h & reflectedCres;
h & casterStack;
h & castByHero;
h & activeCast;

View File

@ -250,27 +250,6 @@ struct ArtifactLocation
}
};
///custom effect (resistance, reflection, etc)
struct CustomEffectInfo
{
CustomEffectInfo()
:effect(0),
sound(0),
stack(0)
{
}
/// WoG AC format
ui32 effect;
ui32 sound;
ui32 stack;
template <typename Handler> void serialize(Handler & h, const int version)
{
h & effect;
h & sound;
h & stack;
}
};
class EntityChanges
{
public:

View File

@ -401,12 +401,12 @@ void BattleSpellMechanics::beforeCast(BattleSpellCast & sc, vstd::RNG & rng, con
{
if(caster->getCasterUnitId() >= 0)
{
addCustomEffect(sc, caster->getCasterUnitId(), 3);
sc.reflectedCres.insert(caster->getCasterUnitId());
}
}
for(auto unit : resisted)
addCustomEffect(sc, unit, 78);
sc.resistedCres.insert(unit->unitId());
}
void BattleSpellMechanics::castEval(ServerCallback * server, const Target & target)
@ -430,19 +430,6 @@ void BattleSpellMechanics::castEval(ServerCallback * server, const Target & targ
p.first->apply(server, this, p.second);
}
void BattleSpellMechanics::addCustomEffect(BattleSpellCast & sc, const battle::Unit * target, ui32 effect)
{
addCustomEffect(sc, target->unitId(), effect);
}
void BattleSpellMechanics::addCustomEffect(BattleSpellCast & sc, ui32 targetId, ui32 effect)
{
CustomEffectInfo customEffect;
customEffect.effect = effect;
customEffect.stack = targetId;
sc.customEffects.push_back(customEffect);
}
std::set<const battle::Unit *> BattleSpellMechanics::collectTargets() const
{
std::set<const battle::Unit *> result;

View File

@ -57,9 +57,6 @@ private:
void beforeCast(BattleSpellCast & sc, vstd::RNG & rng, const Target & target);
void addCustomEffect(BattleSpellCast & sc, const battle::Unit * target, ui32 effect);
void addCustomEffect(BattleSpellCast & sc, ui32 targetId, ui32 effect);
std::set<const battle::Unit *> collectTargets() const;
static void doRemoveEffects(ServerCallback * server, const std::vector<const battle::Unit *> & targets, const CSelector & selector);

View File

@ -33,7 +33,6 @@ VCMI_REGISTER_SPELL_EFFECT(Damage, EFFECT_NAME);
Damage::Damage()
: UnitEffect(),
customEffectId(-1),
killByPercentage(false),
killByCount(false)
{
@ -74,12 +73,6 @@ void Damage::apply(ServerCallback * server, const Mechanics * m, const EffectTar
damageToDisplay += bsa.damageAmount;
killed += bsa.killedAmount;
}
if(customEffectId >= 0)
{
bsa.effect = 82;
bsa.flags |= BattleStackAttacked::EFFECT;
}
stacksInjured.stacks.push_back(bsa);
}
targetIndex++;
@ -116,7 +109,6 @@ bool Damage::isReceptive(const Mechanics * m, const battle::Unit * unit) const
void Damage::serializeJsonUnitEffect(JsonSerializeFormat & handler)
{
handler.serializeInt("customEffectId", customEffectId, -1);
handler.serializeBool("killByPercentage", killByPercentage);
handler.serializeBool("killByCount", killByCount);
}

View File

@ -39,7 +39,6 @@ protected:
virtual void describeEffect(std::vector<MetaString> & log, const Mechanics * m, const battle::Unit * firstTarget, uint32_t kills, int64_t damage, bool multiple) const;
private:
int32_t customEffectId;
bool killByPercentage;
bool killByCount;
};

View File

@ -1182,10 +1182,9 @@ void CGameHandler::makeAttack(const CStack * attacker, const CStack * defender,
BattleStackAttacked bsa;
bsa.flags |= BattleStackAttacked::FIRE_SHIELD;
bsa.stackAttacked = attacker->ID; //invert
bsa.attackerID = uint32_t(-1);
bsa.flags |= BattleStackAttacked::EFFECT;
bsa.effect = 11;
bsa.attackerID = defender->ID;
bsa.damageAmount = totalDamage;
attacker->prepareAttacked(bsa, getRandomGenerator());