mirror of
https://github.com/vcmi/vcmi.git
synced 2025-02-01 12:57:51 +02:00
New pack - BattleEffectTrigger for various one-shot effects with animation
This commit is contained in:
parent
f4fc77ccb8
commit
0903d6037c
@ -24,6 +24,7 @@ public:
|
||||
void battleStackMoved(const CStack * stack, std::vector<THex> dest, int distance) 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;
|
||||
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 battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks, bool lifeDrain, bool tentHeal, si32 lifeDrainFrom) OVERRIDE; //called when stacks are healed / resurrected first element of pair - stack id, second - healed hp
|
||||
void battleNewStackAppeared(const CStack * stack) OVERRIDE; //not called at the beginning of a battle or by resurrection; called eg. when elemental is summoned
|
||||
|
2
AUTHORS
2
AUTHORS
@ -29,7 +29,7 @@ Xiaomin Ding, <dingding303@gmail.com>
|
||||
* smack videos player
|
||||
|
||||
Tom Zielinski aka Warmonger, <Warmonger@vp.pl>
|
||||
* support for some of map objects and other items
|
||||
* game objects, mechanics
|
||||
|
||||
Frank Zago aka ubuntux, <>
|
||||
* GCC/Linux compatibility changes, sound/music support, video support on Linux
|
||||
|
@ -2631,47 +2631,6 @@ void CBattleInterface::stackRemoved(int stackID)
|
||||
|
||||
void CBattleInterface::stackActivated(const CStack * stack) //TODO: check it all before game state is changed due to abilities
|
||||
{
|
||||
//don't show animation when no HP is regenerated
|
||||
if (stack->firstHPleft != stack->MaxHealth())
|
||||
{
|
||||
if( stack->hasBonusOfType(Bonus::HP_REGENERATION) || stack->hasBonusOfType(Bonus::FULL_HP_REGENERATION, 1))
|
||||
{
|
||||
displayEffect(74, stack->position);
|
||||
CCS->soundh->playSound(soundBase::REGENER);
|
||||
}
|
||||
if( stack->hasBonusOfType(Bonus::FULL_HP_REGENERATION, 0))
|
||||
{
|
||||
displayEffect(74, stack->position);
|
||||
CCS->soundh->playSound(soundBase::REGENER);
|
||||
}
|
||||
}
|
||||
|
||||
if(stack->hasBonusOfType(Bonus::MANA_DRAIN))
|
||||
{
|
||||
CGHeroInstance * enemy = NULL; //probably could be smarter and not duplicated
|
||||
if (defendingHero)
|
||||
if (defendingHero->myHero->tempOwner != stack->owner)
|
||||
enemy = const_cast<CGHeroInstance *>(defendingHero->myHero);
|
||||
if (attackingHero)
|
||||
if (attackingHero->myHero->tempOwner != stack->owner)
|
||||
enemy = const_cast<CGHeroInstance *>(attackingHero->myHero);
|
||||
if (enemy)
|
||||
{
|
||||
ui32 manaDrained = stack->valOfBonuses(Bonus::MANA_DRAIN);
|
||||
amin (manaDrained, enemy->mana);
|
||||
if (manaDrained)
|
||||
{
|
||||
displayEffect(77, stack->position);
|
||||
CCS->soundh->playSound(soundBase::MANADRAI);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(stack->hasBonusOfType(Bonus::POISON))
|
||||
{
|
||||
displayEffect(67, stack->position);
|
||||
CCS->soundh->playSound(soundBase::POISON);
|
||||
}
|
||||
|
||||
//givenCommand = NULL;
|
||||
stackToActivate = stack;
|
||||
if(pendingAnims.size() == 0)
|
||||
@ -3546,6 +3505,38 @@ void CBattleInterface::displayEffect(ui32 effect, int destTile)
|
||||
addNewAnim(new CSpellEffectAnim(this, effect, destTile));
|
||||
}
|
||||
|
||||
void CBattleInterface::battleTriggerEffect(const BattleTriggerEffect & bte)
|
||||
{
|
||||
const CStack * stack = curInt->cb->battleGetStackByID(bte.stackID);
|
||||
//don't show animation when no HP is regenerated
|
||||
switch (bte.effect)
|
||||
{
|
||||
case Bonus::HP_REGENERATION:
|
||||
if( stack->hasBonusOfType(Bonus::HP_REGENERATION) || stack->hasBonusOfType(Bonus::FULL_HP_REGENERATION, 1))
|
||||
{
|
||||
displayEffect(74, stack->position);
|
||||
CCS->soundh->playSound(soundBase::REGENER);
|
||||
}
|
||||
if( stack->hasBonusOfType(Bonus::FULL_HP_REGENERATION, 0))
|
||||
{
|
||||
displayEffect(74, stack->position);
|
||||
CCS->soundh->playSound(soundBase::REGENER);
|
||||
}
|
||||
break;
|
||||
case Bonus::MANA_DRAIN:
|
||||
displayEffect(77, stack->position);
|
||||
CCS->soundh->playSound(soundBase::MANADRAI);
|
||||
break;
|
||||
case Bonus::POISON:
|
||||
displayEffect(67, stack->position);
|
||||
CCS->soundh->playSound(soundBase::POISON);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
//waitForAnims(); //fixme: freezes game :?
|
||||
}
|
||||
|
||||
void CBattleInterface::setAnimSpeed(int set)
|
||||
{
|
||||
curInt->sysOpts.animSpeed = set;
|
||||
|
@ -37,6 +37,7 @@ class CGTownInstance;
|
||||
struct CatapultAttack;
|
||||
class CBattleInterface;
|
||||
struct CatapultProjectileInfo;
|
||||
struct BattleTriggerEffect;
|
||||
|
||||
/// Small struct which contains information about the id of the attacked stack, the damage dealt,...
|
||||
struct SStackAttackedInfo
|
||||
@ -569,6 +570,7 @@ public:
|
||||
void battleStacksEffectsSet(const SetStackEffect & sse); //called when a specific effect is set to stacks
|
||||
void castThisSpell(int spellID); //called when player has chosen a spell from spellbook
|
||||
void displayEffect(ui32 effect, int destTile); //displays effect of a spell on the battlefield; affected: true - attacker. false - defender
|
||||
void battleTriggerEffect(const BattleTriggerEffect & bte);
|
||||
void setBattleCursor(const int myNumber); //really complex and messy
|
||||
void endAction(const BattleAction* action);
|
||||
void hideQueue();
|
||||
|
@ -801,6 +801,10 @@ void CPlayerInterface::battleStacksEffectsSet( const SetStackEffect & sse )
|
||||
boost::unique_lock<boost::recursive_mutex> un(*pim);
|
||||
battleInt->battleStacksEffectsSet(sse);
|
||||
}
|
||||
void CPlayerInterface::battleTriggerEffect (const BattleTriggerEffect & bte)
|
||||
{
|
||||
battleInt->battleTriggerEffect(bte);
|
||||
}
|
||||
void CPlayerInterface::battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa)
|
||||
{
|
||||
if(LOCPLINT != this)
|
||||
|
@ -224,6 +224,7 @@ public:
|
||||
void battleStackMoved(const CStack * stack, std::vector<THex> dest, int distance) 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
|
||||
void battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa) OVERRIDE;
|
||||
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 battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks, bool lifeDrain, bool tentHeal, si32 lifeDrainFrom) OVERRIDE; //called when stacks are healed / resurrected
|
||||
|
@ -587,6 +587,11 @@ void BattleSetActiveStack::applyCl( CClient *cl )
|
||||
boost::thread( boost::bind(&CClient::waitForMoveAndSend, cl, playerToCall) );
|
||||
}
|
||||
|
||||
void BattleTriggerEffect::applyCl(CClient * cl)
|
||||
{
|
||||
BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(battleTriggerEffect, *this);
|
||||
}
|
||||
|
||||
void BattleResult::applyFirstCl( CClient *cl )
|
||||
{
|
||||
BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(battleEnd,this);
|
||||
|
@ -126,6 +126,7 @@ public:
|
||||
virtual void battleNewRoundFirst(int round);
|
||||
virtual void actionFinished(const BattleAction *action);
|
||||
virtual void battleStacksEffectsSet(const SetStackEffect & sse);
|
||||
//virtual void battleTriggerEffect(const BattleTriggerEffect & bte);
|
||||
virtual void battleStacksRemoved(const BattleStacksRemoved & bsr);
|
||||
virtual void battleObstaclesRemoved(const std::set<si32> & removedObstacles);
|
||||
virtual void battleNewStackAppeared(const CStack * stack);
|
||||
|
@ -30,6 +30,7 @@ class CStack;
|
||||
class CCreatureSet;
|
||||
struct BattleAttack;
|
||||
struct SetStackEffect;
|
||||
struct BattleTriggerEffect;
|
||||
|
||||
|
||||
class DLL_EXPORT IBattleEventsReceiver
|
||||
@ -45,6 +46,7 @@ public:
|
||||
virtual void battleStackMoved(const CStack * stack, std::vector<THex> dest, int distance){};
|
||||
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
|
||||
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 battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks, bool lifeDrain, bool tentHeal, si32 lifeDrainFrom){}; //called when stacks are healed / resurrected first element of pair - stack id, second - healed hp
|
||||
virtual void battleNewStackAppeared(const CStack * stack){}; //not called at the beginning of a battle or by resurrection; called eg. when elemental is summoned
|
||||
|
@ -1522,6 +1522,26 @@ struct BattleSetStackProperty : public CPackForClient //3018
|
||||
}
|
||||
};
|
||||
|
||||
struct BattleTriggerEffect : public CPackForClient //3019
|
||||
{ //activated at the beginning of turn
|
||||
BattleTriggerEffect(){type = 3019;};
|
||||
|
||||
DLL_EXPORT void applyGs(CGameState *gs); //effect
|
||||
void applyCl(CClient *cl); //play animations & stuff
|
||||
|
||||
//enum BattleEffect {REGENERATION, MANA_DRAIN, FEAR, MANA_CHANNELING, ENCHANTER, UNBIND, POISON, ENCHANTED, SUMMONER};
|
||||
|
||||
int stackID;
|
||||
int effect; //use enumBattleEffect or corresponding Bonus type for sanity?
|
||||
int val;
|
||||
int additionalInfo;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & stackID & effect & val & additionalInfo;
|
||||
}
|
||||
};
|
||||
|
||||
struct ShowInInfobox : public CPackForClient //107
|
||||
{
|
||||
ShowInInfobox(){type = 107;};
|
||||
|
@ -858,34 +858,6 @@ DLL_EXPORT void BattleSetActiveStack::applyGs( CGameState *gs )
|
||||
gs->curB->activeStack = stack;
|
||||
CStack *st = gs->curB->getStack(stack);
|
||||
|
||||
if (st->alive())
|
||||
{
|
||||
//regeneration
|
||||
if(st->hasBonusOfType(Bonus::HP_REGENERATION))
|
||||
st->firstHPleft = std::min<ui32>( st->MaxHealth(), st->valOfBonuses(Bonus::HP_REGENERATION) );
|
||||
if(st->hasBonusOfType(Bonus::FULL_HP_REGENERATION))
|
||||
st->firstHPleft = st->MaxHealth();
|
||||
if(st->hasBonusOfType(Bonus::POISON))
|
||||
{
|
||||
Bonus * b = st->getBonus(Selector::source(Bonus::SPELL_EFFECT, 71) && Selector::type(Bonus::STACK_HEALTH));
|
||||
if (b) //TODO: what if not?...
|
||||
{
|
||||
b->val -= 10;
|
||||
amax (b->val, -(st->valOfBonuses(Bonus::POISON)));
|
||||
}
|
||||
}
|
||||
if(st->hasBonusOfType(Bonus::MANA_DRAIN))
|
||||
{
|
||||
const CGHeroInstance * enemy = gs->curB->getHero(gs->curB->theOtherPlayer(st->owner));
|
||||
if (enemy)
|
||||
{
|
||||
ui32 manaDrained = st->valOfBonuses(Bonus::MANA_DRAIN);
|
||||
amin (manaDrained, gs->curB->heroes[0]->mana);
|
||||
gs->getHero(enemy->id)->mana -= manaDrained; //jeez, it's overcomplicate
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//remove bonuses that last until when stack gets new turn
|
||||
st->getBonusList().remove_if(Bonus::UntilGetsTurn);
|
||||
|
||||
@ -893,6 +865,36 @@ DLL_EXPORT void BattleSetActiveStack::applyGs( CGameState *gs )
|
||||
st->state.insert(HAD_MORALE);
|
||||
}
|
||||
|
||||
DLL_EXPORT void BattleTriggerEffect::applyGs( CGameState *gs )
|
||||
{
|
||||
CStack *st = gs->curB->getStack(stackID);
|
||||
switch (effect)
|
||||
{
|
||||
case Bonus::HP_REGENERATION:
|
||||
st->firstHPleft += val;
|
||||
amin (st->firstHPleft, (ui32)st->MaxHealth());
|
||||
break;
|
||||
case Bonus::MANA_DRAIN:
|
||||
{
|
||||
CGHeroInstance * h = gs->getHero(additionalInfo);
|
||||
h->mana -= val;
|
||||
amax(h->mana, 0);
|
||||
break;
|
||||
}
|
||||
case Bonus::POISON:
|
||||
{
|
||||
Bonus * b = st->getBonus(Selector::source(Bonus::SPELL_EFFECT, 71) && Selector::type(Bonus::STACK_HEALTH));
|
||||
if (b)
|
||||
b->val = val;
|
||||
break;
|
||||
}
|
||||
case Bonus::ENCHANTER:
|
||||
case Bonus::FEAR:
|
||||
default:
|
||||
tlog2 << "Unrecognized trigger effect type "<< type <<"\n";
|
||||
}
|
||||
}
|
||||
|
||||
void BattleResult::applyGs( CGameState *gs )
|
||||
{
|
||||
//stack with SUMMONED flag but coming from garrison -> most likely resurrected, needs to be removed
|
||||
|
@ -150,6 +150,7 @@ void registerTypes2(Serializer &s)
|
||||
s.template registerType<EndAction>();
|
||||
s.template registerType<BattleSpellCast>();
|
||||
s.template registerType<SetStackEffect>();
|
||||
s.template registerType<BattleTriggerEffect>();
|
||||
s.template registerType<BattleSetStackProperty>();
|
||||
s.template registerType<StacksInjured>();
|
||||
s.template registerType<BattleResultsApplied>();
|
||||
|
@ -3935,6 +3935,70 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
|
||||
return false;
|
||||
}
|
||||
|
||||
void CGameHandler::stackTurnTrigger(const CStack * st)
|
||||
{
|
||||
BattleTriggerEffect bte;
|
||||
bte.stackID = st->ID;
|
||||
bte.effect = -1;
|
||||
bte.val = 0;
|
||||
bte.additionalInfo = 0;
|
||||
if (st->alive())
|
||||
{
|
||||
//regeneration
|
||||
if(st->hasBonusOfType(Bonus::HP_REGENERATION))
|
||||
{
|
||||
bte.effect = Bonus::HP_REGENERATION;
|
||||
bte.val = std::min((int)(st->MaxHealth() - st->firstHPleft), st->valOfBonuses(Bonus::HP_REGENERATION));
|
||||
}
|
||||
if(st->hasBonusOfType(Bonus::FULL_HP_REGENERATION))
|
||||
{
|
||||
bte.effect = Bonus::HP_REGENERATION;
|
||||
bte.val = st->MaxHealth() - st->firstHPleft;
|
||||
}
|
||||
if (bte.val) //anything to heal
|
||||
sendAndApply(&bte);
|
||||
|
||||
if(st->hasBonusOfType(Bonus::POISON))
|
||||
{
|
||||
const Bonus * b = st->getBonus(Selector::source(Bonus::SPELL_EFFECT, 71) && Selector::type(Bonus::STACK_HEALTH));
|
||||
if (b) //TODO: what if not?...
|
||||
{
|
||||
bte.val = std::max (b->val - 10, -(st->valOfBonuses(Bonus::POISON)));
|
||||
if (bte.val < b->val) //(negative) poison effect increases - update it
|
||||
{
|
||||
bte.effect = Bonus::POISON;
|
||||
sendAndApply(&bte);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(st->hasBonusOfType(Bonus::MANA_DRAIN))
|
||||
{
|
||||
const CGHeroInstance * enemy = gs->curB->getHero(gs->curB->theOtherPlayer(st->owner));
|
||||
if (enemy)
|
||||
{
|
||||
ui32 manaDrained = st->valOfBonuses(Bonus::MANA_DRAIN);
|
||||
amin (manaDrained, gs->curB->heroes[0]->mana);
|
||||
if (manaDrained)
|
||||
{
|
||||
bte.effect = Bonus::MANA_DRAIN;
|
||||
bte.val = manaDrained;
|
||||
bte.additionalInfo = enemy->id; //for sanity
|
||||
sendAndApply(&bte);
|
||||
}
|
||||
}
|
||||
}
|
||||
BonusList * bl = st->getBonuses(Selector::type(Bonus::ENCHANTER)).get();
|
||||
if (bl->size())
|
||||
{
|
||||
bte.effect = Bonus::ENCHANTER;
|
||||
int index = rand() % bl->size();
|
||||
bte.val = (*bl)[index]->subtype; //spell ID
|
||||
bte.additionalInfo = (*bl)[index]->val; //spell level
|
||||
sendAndApply(&bte);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CGameHandler::handleTimeEvents()
|
||||
{
|
||||
gs->map->events.sort(evntCmp);
|
||||
@ -5207,6 +5271,8 @@ void CGameHandler::runBattle()
|
||||
{//ask interface and wait for answer
|
||||
if(!battleResult.get())
|
||||
{
|
||||
stackTurnTrigger(next); //various effects
|
||||
|
||||
BattleSetActiveStack sas;
|
||||
sas.stack = next->ID;
|
||||
sendAndApply(&sas);
|
||||
|
@ -199,6 +199,7 @@ public:
|
||||
bool makeBattleAction(BattleAction &ba);
|
||||
void handleSpellCasting(int spellID, int spellLvl, THex destination, ui8 casterSide, ui8 casterColor, const CGHeroInstance * caster, const CGHeroInstance * secHero, int usedSpellPower, SpellCasting::ECastingMode mode, const CStack * stack);
|
||||
bool makeCustomAction(BattleAction &ba);
|
||||
void stackTurnTrigger(const CStack * stack);
|
||||
bool queryReply( ui32 qid, ui32 answer, ui8 player );
|
||||
bool hireHero( const CGObjectInstance *obj, ui8 hid, ui8 player );
|
||||
bool buildBoat( ui32 objid );
|
||||
|
Loading…
x
Reference in New Issue
Block a user