Ver código fonte

* support for new creature abilities: hate, spell cost decreasing, spell vulnerability
* fixed crash when vcmiistari is applied on hero without spell book

mateuszb 16 anos atrás
pai
commit
fe2085fe42
8 arquivos alterados com 79 adições e 19 exclusões
  1. 14 0
      CCallback.cpp
  2. 3 0
      CCallback.h
  3. 10 8
      client/CSpellWindow.cpp
  4. 2 2
      config/cr_abils.txt
  5. 29 7
      lib/CGameState.cpp
  6. 1 0
      lib/CGameState.h
  7. 10 1
      lib/NetPacksLib.cpp
  8. 10 1
      server/CGameHandler.cpp

+ 14 - 0
CCallback.cpp

@@ -15,6 +15,7 @@
 #include <boost/foreach.hpp>
 #include <boost/thread.hpp>
 #include <boost/thread/shared_mutex.hpp>
+#include "hch/CSpellHandler.h"
 #ifdef min
 #undef min
 #endif
@@ -111,11 +112,24 @@ const StartInfo * CCallback::getStartInfo() const
 	return gs->scenarioOps;
 }
 
+int CCallback::getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const
+{
+	boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
+
+	//if there is a battle
+	if(gs->curB)
+		return gs->curB->getSpellCost(sp, caster);
+
+	//if there is no battle
+	return sp->costs[caster->getSpellSchoolLevel(sp)];
+}
+
 int CCallback::howManyTowns() const
 {
 	boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
 	return gs->players[player].towns.size();
 }
+
 const CGTownInstance * CCallback::getTownInfo(int val, bool mode) const //mode = 0 -> val = serial; mode = 1 -> val = ID
 {
 	boost::shared_lock<boost::shared_mutex> lock(*gs->mx);

+ 3 - 0
CCallback.h

@@ -125,6 +125,7 @@ public:
 	virtual int getMySerial()const =0;
 	virtual int getHeroSerial(const CGHeroInstance * hero)const =0;
 	virtual const StartInfo * getStartInfo()const =0;
+	virtual int getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const =0; //when called during battle, takes into account creatures' spell cost reduction
 
 	//hero
 	virtual int howManyHeroes(bool includeGarrisoned = true)const =0;
@@ -243,6 +244,8 @@ public:
 	const CCreatureSet* getGarrison(const CGObjectInstance *obj) const;
 	UpgradeInfo getUpgradeInfo(const CArmedInstance *obj, int stackPos) const;
 	const StartInfo * getStartInfo() const;
+	int getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const; //when called during battle, takes into account creatures' spell cost reduction
+
 	std::vector < const CGObjectInstance * > getBlockingObjs(int3 pos) const;
 	std::vector < const CGObjectInstance * > getVisitableObjs(int3 pos) const;
 	void getMarketOffer(int t1, int t2, int &give, int &rec, int mode=0) const; //t1 - type of given resource, t2 - type of received resource; give is the amount of resource t1 that can be traded for amount rec of resource t2 (one of them is 1)

+ 10 - 8
client/CSpellWindow.cpp

@@ -11,6 +11,7 @@
 #include "SDL_Extensions.h"
 #include "CMessage.h"
 #include "CPlayerInterface.h"
+#include "../CCallback.h"
 #include <boost/bind.hpp>
 #include <sstream>
 
@@ -441,32 +442,33 @@ void CSpellWindow::show(SDL_Surface *to)
 	{
 		if(spellAreas[b]->mySpell == -1)
 			continue;
+		const CSpell * spell = &CGI->spellh->spells[spellAreas[b]->mySpell];
 		//int b2 = -1; //TODO use me
 
 		blitAt(spells->ourImages[spellAreas[b]->mySpell].bitmap, spellAreas[b]->pos.x, spellAreas[b]->pos.y, to);
 
 		Uint8 bestSchool = -1,
-			bestslvl =  myHero->getSpellSchoolLevel( &CGI->spellh->spells[spellAreas[b]->mySpell] );
+			bestslvl =  myHero->getSpellSchoolLevel( spell );
 
-		if(CGI->spellh->spells[spellAreas[b]->mySpell].air)
+		if(spell->air)
 			bestSchool = 0;
-		if(CGI->spellh->spells[spellAreas[b]->mySpell].fire)
+		if(spell->fire)
 			bestSchool = 1;
-		if(CGI->spellh->spells[spellAreas[b]->mySpell].water)
+		if(spell->water)
 			bestSchool = 2;
-		if(CGI->spellh->spells[spellAreas[b]->mySpell].earth)
+		if(spell->earth)
 			bestSchool = 3;
 
 		//printing border (indicates level of magic school)
 		blitAt(schoolBorders[bestSchool]->ourImages[bestslvl].bitmap, spellAreas[b]->pos.x, spellAreas[b]->pos.y, to);
 
 		//printing spell's name
-		CSDL_Ext::printAtMiddle(CGI->spellh->spells[spellAreas[b]->mySpell].name, spellAreas[b]->pos.x + 39, spellAreas[b]->pos.y + 70, GEORM, tytulowy, to);
+		CSDL_Ext::printAtMiddle(spell->name, spellAreas[b]->pos.x + 39, spellAreas[b]->pos.y + 70, GEORM, tytulowy, to);
 		//printing lvl
-		CSDL_Ext::printAtMiddle(CGI->generaltexth->allTexts[171 + CGI->spellh->spells[spellAreas[b]->mySpell].level], spellAreas[b]->pos.x + 39, spellAreas[b]->pos.y + 82, GEORM, zwykly, to);
+		CSDL_Ext::printAtMiddle(CGI->generaltexth->allTexts[171 + spell->level], spellAreas[b]->pos.x + 39, spellAreas[b]->pos.y + 82, GEORM, zwykly, to);
 		//printing  cost
 		std::ostringstream ss;
-		ss<<CGI->generaltexth->allTexts[387]<<": "<<CGI->spellh->spells[spellAreas[b]->mySpell].costs[bestslvl];
+		ss<<CGI->generaltexth->allTexts[387]<<": "<<LOCPLINT->cb->getSpellCost(spell, myHero);
 
 		CSDL_Ext::printAtMiddle(ss.str(), spellAreas[b]->pos.x + 39, spellAreas[b]->pos.y + 94, GEORM, zwykly, to);
 	}

+ 2 - 2
config/cr_abils.txt

@@ -19,9 +19,9 @@
 +  21 CHANGES_SPELL_COST_FOR_ENEMY 2 0 0 	//silver pegasus makes spell cost higher for enemy mage
 +  22 SPELL_AFTER_ATTACK 0 72 100   //dendroids cast bind
 +  23 SPELL_AFTER_ATTACK 0 72 100 	//dendroid guards cast bind
-+  24 SPELL_AFTER_ATTACK 0 62 100 	//unicorns cast blind with 20% probability
++  24 SPELL_AFTER_ATTACK 0 62 20 	//unicorns cast blind with 20% probability
 +  24 SPELL_RESISTANCE_AURA 0 55 0	//unicorn
-+  25 SPELL_AFTER_ATTACK 0 62 100 	//war unicorns cast blind with 20% probability
++  25 SPELL_AFTER_ATTACK 0 62 20 	//war unicorns cast blind with 20% probability
 +  25 SPELL_RESISTANCE_AURA 0 55 0 	//war unicorn
 +  26 LEVEL_SPELL_IMMUNITY 3 0 0 	//green dragon's spell immunity
 +  26 TWO_HEX_ATTACK_BREATH 0 0 0  	//green dragon's breath

+ 29 - 7
lib/CGameState.cpp

@@ -2022,20 +2022,20 @@ int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender, con
 			switch(attackerHero->getSecSkillLevel(1)) //archery
 			{
 			case 1: //basic
-				dmgBonusMultiplier *= 1.1f;
+				dmgBonusMultiplier += 0.1f;
 				break;
 			case 2: //advanced
-				dmgBonusMultiplier *= 1.25f;
+				dmgBonusMultiplier += 0.25f;
 				break;
 			case 3: //expert
-				dmgBonusMultiplier *= 1.5f;
+				dmgBonusMultiplier += 0.5f;
 				break;
 			}
 
 			if(attackerHero->getSecSkillLevel(1) > 0) //non-none level
 			{
 				//apply artifact premy to archery
-				dmgBonusMultiplier *= (100.0f + attackerHero->valOfBonuses(HeroBonus::SECONDARY_SKILL_PREMY, 1)) / 100.0f;
+				dmgBonusMultiplier += attackerHero->valOfBonuses(HeroBonus::SECONDARY_SKILL_PREMY, 1) / 100.0f;
 			}
 		}
 		else
@@ -2043,13 +2043,13 @@ int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender, con
 			switch(attackerHero->getSecSkillLevel(22)) //offense
 			{
 			case 1: //basic
-				dmgBonusMultiplier *= 1.1f;
+				dmgBonusMultiplier += 0.1f;
 				break;
 			case 2: //advanced
-				dmgBonusMultiplier *= 1.2f;
+				dmgBonusMultiplier += 0.2f;
 				break;
 			case 3: //expert
-				dmgBonusMultiplier *= 1.3f;
+				dmgBonusMultiplier += 0.3f;
 				break;
 			}
 		}
@@ -2069,6 +2069,11 @@ int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender, con
 			break;
 		}
 	}
+
+	//handling hate effect
+	if( attacker->hasFeatureOfType(StackFeature::HATE, defender->creature->idNumber) )
+		dmgBonusMultiplier += 0.5f;
+
 	//handling spell effects
 	if(!shooting && defender->hasFeatureOfType(StackFeature::GENERAL_DAMAGE_REDUCTION, 0)) //eg. shield
 	{
@@ -2267,6 +2272,23 @@ CStack * BattleInfo::generateNewStack(const CGHeroInstance * owner, int creature
 	return ret;
 }
 
+ui32 BattleInfo::getSpellCost(const CSpell * sp, const CGHeroInstance * caster)
+{
+	ui32 ret = VLC->spellh->spells[sp->id].costs[caster->getSpellSchoolLevel(sp)];
+
+	//checking for friendly stacks reducing cost of the spell
+	si32 manaReduction = 0;
+	for(int g=0; g<stacks.size(); ++g)
+	{
+		if( stacks[g]->owner == caster->tempOwner && stacks[g]->hasFeatureOfType(StackFeature::CHANGES_SPELL_COST_FOR_ALLY) )
+		{
+			amin(manaReduction, stacks[g]->valOfFeatures(StackFeature::CHANGES_SPELL_COST_FOR_ALLY));
+		}
+	}
+
+	return ret + manaReduction;
+}
+
 CStack * BattleInfo::getNextStack()
 {
 	CStack *current = getStack(activeStack);

+ 1 - 0
lib/CGameState.h

@@ -141,6 +141,7 @@ struct DLL_EXPORT BattleInfo
 	std::set<CStack*> getAttackedCreatures(const CSpell * s, const CGHeroInstance * caster, int destinationTile); //calculates stack affected by given spell
 	static int calculateSpellDuration(const CSpell * spell, const CGHeroInstance * caster);
 	static CStack * generateNewStack(const CGHeroInstance * owner, int creatureID, int amount, int stackID, bool attackerOwned, int slot, int /*TerrainTile::EterrainType*/ terrain, int position); //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield
+	ui32 getSpellCost(const CSpell * sp, const CGHeroInstance * caster); //returns cost of given spell
 };
 
 class DLL_EXPORT CStack

+ 10 - 1
lib/NetPacksLib.cpp

@@ -736,7 +736,16 @@ DLL_EXPORT void SpellCast::applyGs( CGameState *gs )
 	CGHeroInstance *h = (side) ? gs->getHero(gs->curB->hero2) : gs->getHero(gs->curB->hero1);
 	if(h)
 	{
-		h->mana -= VLC->spellh->spells[id].costs[skill];
+		int spellCost = 0;
+		if(gs->curB)
+		{
+			spellCost = gs->curB->getSpellCost(&VLC->spellh->spells[id], h);
+		}
+		else
+		{
+			spellCost = VLC->spellh->spells[id].costs[skill];
+		}
+		h->mana -= spellCost;
 		if(h->mana < 0) h->mana = 0;
 	}
 	if(side >= 0 && side < 2)

+ 10 - 1
server/CGameHandler.cpp

@@ -2490,6 +2490,7 @@ void CGameHandler::playerMessage( ui8 player, const std::string &message )
 		if(!h->getArt(17)) //hero doesn't have spellbook
 		{
 			//give spellbook
+			sha.hid = h->id;
 			sha.artifacts = h->artifacts;
 			sha.artifWorn = h->artifWorn;
 			sha.artifWorn[17] = 0;
@@ -2648,6 +2649,14 @@ static ui32 calculateSpellDmg(const CSpell * sp, const CGHeroInstance * caster,
 		ret /= 100;
 	}
 
+	//dmg increasing
+	if( affectedCreature->hasFeatureOfType(StackFeature::MORE_DAMAGE_FROM_SPELL, sp->id) )
+	{
+		ret *= 100 + affectedCreature->valOfFeatures(StackFeature::MORE_DAMAGE_FROM_SPELL, sp->id);
+		ret /= 100;
+	}
+
+
 	return ret;
 }
 
@@ -2763,7 +2772,7 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
 			ui8 skill = h->getSpellSchoolLevel(s); //skill level
 
 			if(   !(h->canCastThisSpell(s)) //hero cannot cast this spell at all
-				|| (h->mana < s->costs[skill]) //not enough mana
+				|| (h->mana < gs->curB->getSpellCost(s, h)) //not enough mana
 				|| (ba.additionalInfo < 10) //it's adventure spell (not combat)
 				|| (gs->curB->castSpells[ba.side]) //spell has been cast
 				|| (secondHero && secondHero->hasBonusOfType(HeroBonus::SPELL_IMMUNITY, s->id)) //non - casting hero provides immunity for this spell