Browse Source

* new spell: cure
* minor changes

mateuszb 16 years ago
parent
commit
1872c2d575

+ 4 - 4
AI/GeniusAI/BattleLogic.cpp

@@ -300,7 +300,7 @@ BattleAction CBattleLogic::MakeDecision(int stackID)
 
 
 
-std::vector<int> CBattleLogic::GetAvailableHexesForAttacker(CStack *defender, CStack *attacker)
+std::vector<int> CBattleLogic::GetAvailableHexesForAttacker(const CStack *defender, const CStack *attacker)
 {
 	int x = m_battleHelper.DecodeXPosition(defender->position);
 	int y = m_battleHelper.DecodeYPosition(defender->position);
@@ -408,7 +408,7 @@ std::vector<int> CBattleLogic::GetAvailableHexesForAttacker(CStack *defender, CS
 		}
 
 		int new_pos = m_battleHelper.GetBattleFieldPosition(it->first, it->second);
-		CStack *st = m_cb->battleGetStackByPos(new_pos);
+		const CStack *st = m_cb->battleGetStackByPos(new_pos);
 
 		if (st == NULL || st->amount < 1)
 		{
@@ -479,7 +479,7 @@ BattleAction CBattleLogic::MakeWait(int stackID)
 
 BattleAction CBattleLogic::MakeAttack(int attackerID, int destinationID)
 {
-	CStack *attackerStack = m_cb->battleGetStackByID(attackerID),
+	const CStack *attackerStack = m_cb->battleGetStackByID(attackerID),
 		*destinationStack = m_cb->battleGetStackByID(destinationID);
 	assert(attackerStack && destinationStack);
 
@@ -744,7 +744,7 @@ void CBattleLogic::PrintBattleAction(const BattleAction &action) // for debug pu
 		message += "stack - " + boost::lexical_cast<std::string>(m_battleHelper.DecodeXPosition(action.additionalInfo));
 		message += ", " + boost::lexical_cast<std::string>(m_battleHelper.DecodeYPosition(action.additionalInfo));
 		message += ", creature - ";
-		CStack *c = m_cb->battleGetStackByPos(action.additionalInfo);
+		const CStack *c = m_cb->battleGetStackByPos(action.additionalInfo);
 		if (c && c->creature)
 		{
 			message += c->creature->nameRef;

+ 1 - 1
AI/GeniusAI/BattleLogic.h

@@ -105,7 +105,7 @@ private:
 	/**
 	 * Helper function. It's used for performing an attack action.
 	 */
-	std::vector<int> GetAvailableHexesForAttacker(CStack *defender, CStack *attacker = NULL);
+	std::vector<int> GetAvailableHexesForAttacker(const CStack *defender, const CStack *attacker = NULL);
 	/**
 	 * Just make defend action.
 	 */

+ 3 - 3
CCallback.cpp

@@ -442,7 +442,7 @@ int CCallback::battleGetStack(int pos)
 	return gs->battleGetStack(pos);
 }
 
-CStack* CCallback::battleGetStackByID(int ID)
+const CStack* CCallback::battleGetStackByID(int ID)
 {
 	boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
 	if(!gs->curB) return NULL;
@@ -456,7 +456,7 @@ int CCallback::battleMakeAction(BattleAction* action)
 	return 0;
 }
 
-CStack* CCallback::battleGetStackByPos(int pos)
+const CStack* CCallback::battleGetStackByPos(int pos)
 {
 	boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
 	return battleGetStackByID(battleGetStack(pos));
@@ -553,7 +553,7 @@ bool CCallback::battleIsStackMine(int ID)
 bool CCallback::battleCanShoot(int ID, int dest)
 {
 	boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
-	CStack *our = battleGetStackByID(ID), *dst = battleGetStackByPos(dest);
+	const CStack *our = battleGetStackByID(ID), *dst = battleGetStackByPos(dest);
 	if(!our || !dst || !gs->curB) return false; 
 
 	//for(size_t g=0; g<our->effects.size(); ++g)

+ 4 - 4
CCallback.h

@@ -166,8 +166,8 @@ public:
 	virtual int battleGetObstaclesAtTile(int tile)=0; //returns bitfield
 	virtual std::vector<CObstacleInstance> battleGetAllObstacles()=0; //returns all obstacles on the battlefield
 	virtual int battleGetStack(int pos)=0; //returns ID of stack on the tile
-	virtual CStack * battleGetStackByID(int ID)=0; //returns stack info by given ID
-	virtual CStack * battleGetStackByPos(int pos)=0; //returns stack info by given pos
+	virtual const CStack * battleGetStackByID(int ID)=0; //returns stack info by given ID
+	virtual const CStack * battleGetStackByPos(int pos)=0; //returns stack info by given pos
 	virtual int battleGetPos(int stack)=0; //returns position (tile ID) of stack
 	virtual int battleMakeAction(BattleAction* action)=0;//for casting spells by hero - DO NOT use it for moving active stack
 	virtual std::map<int, CStack> battleGetStacks()=0; //returns stacks on battlefield
@@ -267,8 +267,8 @@ public:
 	int battleGetObstaclesAtTile(int tile); //returns bitfield
 	std::vector<CObstacleInstance> battleGetAllObstacles(); //returns all obstacles on the battlefield
 	int battleGetStack(int pos); //returns ID of stack on the tile
-	CStack * battleGetStackByID(int ID); //returns stack info by given ID
-	CStack * battleGetStackByPos(int pos); //returns stack info by given pos
+	const CStack * battleGetStackByID(int ID); //returns stack info by given ID
+	const CStack * battleGetStackByPos(int pos); //returns stack info by given pos
 	int battleGetPos(int stack); //returns position (tile ID) of stack
 	int battleMakeAction(BattleAction* action);//for casting spells by hero - DO NOT use it for moving active stack
 	std::map<int, CStack> battleGetStacks(); //returns stacks on battlefield

+ 17 - 10
client/CBattleInterface.cpp

@@ -709,8 +709,8 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent)
 		{
 			if(std::find(shadedHexes.begin(),shadedHexes.end(),myNumber) == shadedHexes.end())
 			{
-				CStack *shere = LOCPLINT->cb->battleGetStackByPos(myNumber);
-				CStack *sactive = LOCPLINT->cb->battleGetStackByID(activeStack);
+				const CStack *shere = LOCPLINT->cb->battleGetStackByPos(myNumber);
+				const CStack *sactive = LOCPLINT->cb->battleGetStackByID(activeStack);
 				if(shere)
 				{
 					if(shere->owner == LOCPLINT->playerID) //our stack
@@ -762,7 +762,7 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent)
 			}
 			else //available tile
 			{
-				CStack *sactive = LOCPLINT->cb->battleGetStackByID(activeStack);
+				const CStack *sactive = LOCPLINT->cb->battleGetStackByID(activeStack);
 				if(LOCPLINT->cb->battleGetStackByID(activeStack)->creature->isFlying())
 				{
 					CGI->curh->changeGraphic(1,2);
@@ -805,7 +805,7 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent)
 		}
 		else
 		{
-			CStack * stackUnder = LOCPLINT->cb->battleGetStackByPos(myNumber);
+			const CStack * stackUnder = LOCPLINT->cb->battleGetStackByPos(myNumber);
 			bool whichCase; //for cases 1, 2 and 3
 			switch(spellSelMode)
 			{
@@ -1031,7 +1031,7 @@ void CBattleInterface::stackMoved(int number, int destHex, bool endMoving, int d
 	int steps = creAnims[number]->framesInGroup(0)*getAnimSpeedMultiplier()-1;
 	int hexWbase = 44, hexHbase = 42;
 	bool twoTiles = LOCPLINT->cb->battleGetCreature(number).isDoubleWide();
-	CStack * movedStack = LOCPLINT->cb->battleGetStackByID(number);
+	const CStack * movedStack = LOCPLINT->cb->battleGetStackByID(number);
 	
 	std::pair<int, int> begPosition = CBattleHex::getXYUnitAnim(curStackPos, movedStack->attackerOwned, movedStack->creature);
 	std::pair<int, int> endPosition = CBattleHex::getXYUnitAnim(destHex, movedStack->attackerOwned, movedStack->creature);
@@ -1451,7 +1451,7 @@ bool CBattleInterface::isTileAttackable(const int & number) const
 
 void CBattleInterface::handleEndOfMove(int stackNumber, int destinationTile)
 {
-	CStack * movedStack = LOCPLINT->cb->battleGetStackByID(stackNumber);
+	const CStack * movedStack = LOCPLINT->cb->battleGetStackByID(stackNumber);
 	if(creAnims[stackNumber]->framesInGroup(21)!=0) // some units don't have this animation (ie. halberdier)
 	{
 		if (movedStack->creature->sounds.endMoving)
@@ -1514,7 +1514,7 @@ void CBattleInterface::hexLclicked(int whichOne)
 		}
 		else
 		{
-			CStack* dest = LOCPLINT->cb->battleGetStackByPos(whichOne); //creature at destination tile; -1 if there is no one
+			const CStack* dest = LOCPLINT->cb->battleGetStackByPos(whichOne); //creature at destination tile; -1 if there is no one
 			if(!dest || !dest->alive()) //no creature at that tile
 			{
 				if(std::find(shadedHexes.begin(),shadedHexes.end(),whichOne)!=shadedHexes.end())// and it's in our range
@@ -1811,8 +1811,14 @@ void CBattleInterface::spellCast(SpellCast * sc)
 	case 17: //lightning bolt
 		displayEffect(1, sc->tile);
 		displayEffect(spell.mainEffectAnim, sc->tile);
+		break;
 	case 35: //dispel
-		displayEffect(spell.mainEffectAnim, sc->tile);
+	case 37: //cure
+		for(std::set<ui32>::const_iterator it = sc->affectedCres.begin(); it != sc->affectedCres.end(); ++it)
+		{
+			displayEffect(spell.mainEffectAnim, LOCPLINT->cb->battleGetStackByID(*it)->position);
+		}
+		break;
 	} //switch(sc->id)
 
 	//support for resistance
@@ -1861,7 +1867,8 @@ void CBattleInterface::castThisSpell(int spellID)
 			break;
 		}
 	}
-	if(CGI->spellh->spells[spellID].attributes.find("CREATURE_TARGET_2") != std::string::npos) //spell to be cast on a specific creature but massive on expert
+	if(CGI->spellh->spells[spellID].attributes.find("CREATURE_TARGET_1") != std::string::npos ||
+		CGI->spellh->spells[spellID].attributes.find("CREATURE_TARGET_2") != std::string::npos) //spell to be cast on a specific creature but massive on expert
 	{
 		if(castingHero && castingHero->getSpellSecLevel(spellID) < 3)
 		{
@@ -2030,7 +2037,7 @@ void CBattleInterface::attackingShowHelper()
 		{
 			attackingInfo->reversing = true;
 
-			CStack* aStackp = LOCPLINT->cb->battleGetStackByID(attackingInfo->ID); //attacking stack
+			const CStack* aStackp = LOCPLINT->cb->battleGetStackByID(attackingInfo->ID); //attacking stack
 			if(aStackp == NULL)
 				return;
 			CStack aStack = *aStackp;

+ 4 - 4
client/CPlayerInterface.cpp

@@ -1180,7 +1180,7 @@ void CPlayerInterface::actionStarted(const BattleAction* action)
 
 	battleInt->deactivate();
 
-	CStack *stack = cb->battleGetStackByID(action->stackNumber);
+	const CStack *stack = cb->battleGetStackByID(action->stackNumber);
 	char txt[400];
 
 	if(action->actionType == 1)
@@ -1252,7 +1252,7 @@ BattleAction CPlayerInterface::activeStack(int stackID) //called when it's turn
 	{
 		boost::unique_lock<boost::recursive_mutex> un(*pim);
 
-		CStack *stack = cb->battleGetStackByID(stackID);
+		const CStack *stack = cb->battleGetStackByID(stackID);
 		if(vstd::contains(stack->state,MOVED)) //this stack has moved and makes second action -> high morale
 		{
 			std::string hlp = CGI->generaltexth->allTexts[33];
@@ -1331,7 +1331,7 @@ void CPlayerInterface::battleAttack(BattleAttack *ba)
 	assert(curAction);
 	if(ba->lucky()) //lucky hit
 	{
-		CStack *stack = cb->battleGetStackByID(ba->stackAttacking);
+		const CStack *stack = cb->battleGetStackByID(ba->stackAttacking);
 		std::string hlp = CGI->generaltexth->allTexts[45];
 		boost::algorithm::replace_first(hlp,"%s",(stack->amount != 1) ? stack->creature->namePl.c_str() : stack->creature->nameSing.c_str());
 		battleInt->console->addText(hlp);
@@ -1346,7 +1346,7 @@ void CPlayerInterface::battleAttack(BattleAttack *ba)
 	}
 	else
 	{
-		CStack * attacker = cb->battleGetStackByID(ba->stackAttacking);
+		const CStack * attacker = cb->battleGetStackByID(ba->stackAttacking);
 		int shift = 0;		
 		if(ba->counter() && BattleInfo::mutualPosition(curAction->destinationTile, attacker->position) < 0)		
 		{			

+ 1 - 1
config/spell_info.txt

@@ -37,7 +37,7 @@
 34 1 -1 0 0 0 X
 35 0 41 0 0 0 X
 36 1 -1 0 0 0 0
-37 1 -1 0 0 0 0
+37 1 39 0 0 0 0
 38 1 -1 0 0 0 0
 39 1 -1 0 0 0 0
 40 1 -1 0 0 0 0

+ 2 - 1
lib/CGameState.cpp

@@ -2098,7 +2098,8 @@ std::set<CStack*> BattleInfo::getAttackedCreatures(const CSpell * s, const CGHer
 			}
 		}
 	}
-	else if(VLC->spellh->spells[s->id].attributes.find("CREATURE_TARGET_2") != std::string::npos) //spell to be cast on a specific creature but massive on expert
+	else if(VLC->spellh->spells[s->id].attributes.find("CREATURE_TARGET_1") != std::string::npos
+		|| VLC->spellh->spells[s->id].attributes.find("CREATURE_TARGET_2") != std::string::npos) //spell to be cast on a specific creature but massive on expert
 	{
 		if(caster->getSpellSchoolLevel(s) < 3)  /*not expert */
 		{

+ 27 - 1
lib/NetPacks.h

@@ -904,9 +904,10 @@ struct SpellCast : public CPackForClient//3009
 	ui8 skill;
 	ui16 tile; //destination tile (may not be set in some global/mass spells
 	std::vector<ui32> resisted; //ids of creatures that resisted this spell
+	std::set<ui32> affectedCres; //ids of creatures affected by this spell, generally used if spell does not set any effect (like dispel or cure)
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & side & id & skill & tile & resisted;
+		h & side & id & skill & tile & resisted & affectedCres;
 	}
 };
 
@@ -950,6 +951,31 @@ struct BattleResultsApplied : public CPackForClient //3012
 	}
 };
 
+struct StacksHealedOrResurrected : public CPackForClient //3013
+{
+	StacksHealedOrResurrected(){type = 3013;}
+
+	DLL_EXPORT void applyGs(CGameState *gs);
+
+	struct HealInfo
+	{
+		ui32 stackID;
+		ui32 healForFirstStack;
+		ui32 resurrectedCres;
+		template <typename Handler> void serialize(Handler &h, const int version)
+		{
+			h & stackID & healForFirstStack & resurrectedCres;
+		}
+	};
+
+	std::vector<HealInfo> healedStacks;
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & healedStacks;
+	}
+};
+
 struct ShowInInfobox : public CPackForClient //107
 {
 	ShowInInfobox(){type = 107;};

+ 49 - 9
lib/NetPacksLib.cpp

@@ -696,18 +696,21 @@ DLL_EXPORT void SpellCast::applyGs( CGameState *gs )
 
 	if(gs->curB && id == 35) //dispel
 	{
-		CStack *s = gs->curB->getStackT(tile);
-		if(s && !vstd::contains(resisted, s->ID)) //if stack exists and it didn't resist
+		for(std::set<ui32>::const_iterator it = affectedCres.begin(); it != affectedCres.end(); ++it)
 		{
-			s->effects.clear(); //removing all effects
-			//removing all features from spells
-			std::vector<StackFeature> tmpFeatures = s->features;
-			s->features.clear();
-			for(int i=0; i < tmpFeatures.size(); i++)
+			CStack *s = gs->curB->getStack(*it);
+			if(s && !vstd::contains(resisted, s->ID)) //if stack exists and it didn't resist
 			{
-				if(tmpFeatures[i].source != StackFeature::SPELL_EFFECT)
+				s->effects.clear(); //removing all effects
+				//removing all features from spells
+				std::vector<StackFeature> tmpFeatures = s->features;
+				s->features.clear();
+				for(int i=0; i < tmpFeatures.size(); i++)
 				{
-					s->features.push_back(tmpFeatures[i]);
+					if(tmpFeatures[i].source != StackFeature::SPELL_EFFECT)
+					{
+						s->features.push_back(tmpFeatures[i]);
+					}
 				}
 			}
 		}
@@ -797,6 +800,12 @@ static std::vector<StackFeature> stackEffectToFeature(const CStack::StackEffect
 		break;
 	}
 
+	//setting positiveness
+	for(int g=0; g<sf.size(); ++g)
+	{
+		sf[g].positiveness = VLC->spellh->spells[sse.id].positiveness;
+	}
+
 	return sf;
 }
 
@@ -867,6 +876,37 @@ DLL_EXPORT void StacksInjured::applyGs( CGameState *gs )
 		stackAttacked.applyGs(gs);
 }
 
+DLL_EXPORT void StacksHealedOrResurrected::applyGs( CGameState *gs )
+{
+	for(int g=0; g<healedStacks.size(); ++g)
+	{
+		CStack * changedStack = gs->curB->stacks[healedStacks[g].stackID];
+		changedStack->firstHPleft += healedStacks[g].healForFirstStack;
+		changedStack->amount += healedStacks[g].resurrectedCres;
+		//removal of negative effects
+		{
+			for(int h=0; h<changedStack->effects.size(); ++h)
+			{
+				if(VLC->spellh->spells[changedStack->effects[h].id].positiveness < 0)
+				{
+					changedStack->effects.erase(changedStack->effects.begin() + h);
+				}
+			}
+			
+			//removing all features from negative spells
+			std::vector<StackFeature> tmpFeatures = changedStack->features;
+			changedStack->features.clear();
+			for(int i=0; i < tmpFeatures.size(); i++)
+			{
+				if(tmpFeatures[i].source != StackFeature::SPELL_EFFECT || tmpFeatures[i].positiveness >= 0)
+				{
+					changedStack->features.push_back(tmpFeatures[i]);
+				}
+			}
+		}
+	}
+}
+
 DLL_EXPORT void YourTurn::applyGs( CGameState *gs )
 {
 	gs->currentPlayer = player;

+ 1 - 0
lib/RegisterTypes.cpp

@@ -97,6 +97,7 @@ void registerTypes2(Serializer &s)
 	s.template registerType<SetStackEffect>();
 	s.template registerType<StacksInjured>();
 	s.template registerType<BattleResultsApplied>();
+	s.template registerType<StacksHealedOrResurrected>();
 	s.template registerType<ShowInInfobox>();
 	s.template registerType<OpenWindow>();
 	s.template registerType<NewObject>();

+ 2 - 1
lib/StackFeature.h

@@ -109,6 +109,7 @@ struct StackFeature
 	ui8 type;//ECombatFeatures
 	ui8 duration;//EDuration
 	ui8 source;//ESource
+	si8 positiveness; //+1 - positive, 0 - neutral, -1 - negative; used mostly for spell features
 	ui16 turnsRemain; //if duration is N_TURNS it describes how long the effect will last
 	si16 subtype; //subtype of bonus/feature
 	si32 value;
@@ -123,7 +124,7 @@ struct StackFeature
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & type & duration & source & turnsRemain & subtype & value & additionalInfo;
+		h & type & duration & source & positiveness & turnsRemain & subtype & value & additionalInfo;
 	}
 };
 

+ 23 - 1
server/CGameHandler.cpp

@@ -2722,6 +2722,10 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
 
 			//calculating affected creatures for all spells
 			std::set<CStack*> attackedCres = gs->curB->getAttackedCreatures(s, h, ba.destinationTile);
+			for(std::set<CStack*>::const_iterator it = attackedCres.begin(); it != attackedCres.end(); ++it)
+			{
+				sc.affectedCres.insert((*it)->ID);
+			}
 
 			//checking if creatures resist
 			sc.resisted = calculateResistedStacks(s, h, secondHero, attackedCres);
@@ -2752,7 +2756,7 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
 						BattleStackAttacked bsa;
 						bsa.flags |= 2;
 						bsa.effect = VLC->spellh->spells[ba.additionalInfo].mainEffectAnim;
-						bsa.damageAmount = calculateSpellDmg(&VLC->spellh->spells[ba.additionalInfo], h, *it);
+						bsa.damageAmount = calculateSpellDmg(s, h, *it);
 						bsa.stackAttacked = (*it)->ID;
 						prepareAttacked(bsa,*it);
 						si.stacks.insert(bsa);
@@ -2814,6 +2818,24 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
 						sendAndApply(&sse);
 					break;
 				}
+			case 37: //cure
+				{
+					StacksHealedOrResurrected shr;
+					for(std::set<CStack*>::iterator it = attackedCres.begin(); it != attackedCres.end(); ++it)
+					{
+						if(vstd::contains(sc.resisted, (*it)->ID)) //this creature resisted the spell
+							continue;
+						StacksHealedOrResurrected::HealInfo hi;
+						hi.stackID = (*it)->ID;
+						int healedHP = h->getPrimSkillLevel(2) * 5 + s->powers[h->getSpellSchoolLevel(s)];
+						hi.healForFirstStack = std::min<ui32>(healedHP, (*it)->MaxHealth() - (*it)->firstHPleft);
+						hi.resurrectedCres = 0;
+						shr.healedStacks.push_back(hi);
+					}
+					if(!shr.healedStacks.empty())
+						sendAndApply(&shr);
+					break;
+				}
 			}
 			sendAndApply(&EndAction());
 			return true;