Bläddra i källkod

New pack - BattleEffectTrigger for various one-shot effects with animation

DjWarmonger 14 år sedan
förälder
incheckning
0903d6037c

+ 1 - 0
AI/StupidAI/StupidAI.h

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

+ 1 - 1
AUTHORS

@@ -29,7 +29,7 @@ Xiaomin Ding,                <[email protected]>
    * smack videos player
 
 Tom Zielinski aka Warmonger, 	<[email protected]>
-   * 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

+ 32 - 41
client/CBattleInterface.cpp

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

+ 2 - 0
client/CBattleInterface.h

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

+ 4 - 0
client/CPlayerInterface.cpp

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

+ 1 - 0
client/CPlayerInterface.h

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

+ 5 - 0
client/NetPacksClient.cpp

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

+ 1 - 0
lib/CGameInterface.h

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

+ 2 - 0
lib/IGameEventsReceiver.h

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

+ 20 - 0
lib/NetPacks.h

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

+ 30 - 28
lib/NetPacksLib.cpp

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

+ 1 - 0
lib/RegisterTypes.cpp

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

+ 66 - 0
server/CGameHandler.cpp

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

+ 1 - 0
server/CGameHandler.h

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