1
0
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:
DjWarmonger 2011-10-08 13:02:58 +00:00
parent f4fc77ccb8
commit 0903d6037c
14 changed files with 167 additions and 70 deletions

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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();

View File

@ -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)

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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;};

View File

@ -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

View File

@ -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>();

View File

@ -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);

View File

@ -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 );