Selaa lähdekoodia

* support for new hero bonuses (BLOCK_MORALE, SECONDARY_SKILL_PREMY (archery), AIR_SPELL_DMG_PREMY, EARTH_SPELL_DMG_PREMY, FIRE_SPELL_DMG_PREMY, WATER_SPELL_DMG_PREMY, BLOCK_SPELLS_ABOVE_LEVEL, SPELL_IMMUNITY, BLOCK_MORALE, FIRE_SPELLS, AIR_SPELLS, WATER_SPELLS, EARTH_SPELLS, SPELL, SPELLS_OF_LEVEL). It means that following artifacts are now supported:
- Orb of the Firmament
- Orb of Silt
- Orb of Tempestuous Fire
- Orb of Driving Rain
- Bow of Elven Cherrywood
- Bowstring of the Unicorn's Mane
- Angel Feather Arrows
- Tome of Fire Magic
- Tome of Air Magic
- Tome of Water Magic
- Tome of Earth Magic
- Recanter's Cloak
- Orb of Inhibition
- Pendant of Dispassion
- Pendant of Second Sight
- Pendant of Holiness
- Pendant of Life
- Pendant of Death
- Pendant of Free Will
- Pendant of Negativity
- Pendant of Total Recall
- Spellbinder's Hat
- Spirit of Oppression
- Sphere of Permanence
I hope I listed them all here :). Please try them and report if something's wrong.

mateuszb 16 vuotta sitten
vanhempi
sitoutus
047590427f
5 muutettua tiedostoa jossa 101 lisäystä ja 16 poistoa
  1. 7 1
      CGameState.cpp
  2. 7 7
      client/CSpellWindow.cpp
  3. 57 4
      hch/CObjectHandler.cpp
  4. 3 1
      hch/CObjectHandler.h
  5. 27 3
      server/CGameHandler.cpp

+ 7 - 1
CGameState.cpp

@@ -1839,7 +1839,7 @@ int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender, con
 		}
 	}
 
-	//handling secondary abilities
+	//handling secondary abilities and artifacts giving premies to them
 	if(attackerHero)
 	{
 		if(shooting)
@@ -1856,6 +1856,12 @@ int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender, con
 				dmgBonusMultiplier *= 1.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;
+			}
 		}
 		else
 		{

+ 7 - 7
client/CSpellWindow.cpp

@@ -80,14 +80,14 @@ CSpellWindow::CSpellWindow(const SDL_Rect & myRect, const CGHeroInstance * myHer
 	selectedTab(4),
 	spellSite(0)
 {
-	mySpells = myHero->spells;
-	//XXX for testing only
-	//for(ui32 v=0; v<CGI->spellh->spells.size(); ++v)
-	//{
-	//	if(!CGI->spellh->spells[v].creatureAbility)
-	//		mySpells.insert(v);
-	//}
+	//initializing castable spells
+	for(ui32 v=0; v<CGI->spellh->spells.size(); ++v)
+	{
+		if( !CGI->spellh->spells[v].creatureAbility && myHero->canCastThisSpell(&CGI->spellh->spells[v]) )
+			mySpells.insert(v);
+	}
 
+	//initializing schools' levels
 	for(int b=0; b<4; ++b) schoolLvls[b] = 0;
 	for(size_t b=0; b<myHero->secSkills.size(); ++b)
 	{

+ 57 - 4
hch/CObjectHandler.cpp

@@ -804,6 +804,34 @@ ui8 CGHeroInstance::getSpellSchoolLevel(const CSpell * spell) const
 	return skill;
 }
 
+bool CGHeroInstance::canCastThisSpell(const CSpell * spell) const
+{
+	if(!getArt(17)) //if hero has no spellbook
+		return false;
+
+	if(vstd::contains(spells, spell->id) //hero does not have this spell in spellbook
+		|| (spell->air && hasBonusOfType(HeroBonus::AIR_SPELLS)) // this is air spell and hero can cast all air spells
+		|| (spell->fire && hasBonusOfType(HeroBonus::FIRE_SPELLS)) // this is fire spell and hero can cast all fire spells
+		|| (spell->water && hasBonusOfType(HeroBonus::WATER_SPELLS)) // this is water spell and hero can cast all water spells
+		|| (spell->earth && hasBonusOfType(HeroBonus::EARTH_SPELLS)) // this is earth spell and hero can cast all earth spells
+		)
+		return true;
+
+	for(std::list<HeroBonus>::const_iterator it = bonuses.begin(); it != bonuses.end(); ++it)
+	{
+		if(it->type == HeroBonus::SPELL && it->subtype == spell->id)
+		{
+			return true;
+		}
+		if(it->type == HeroBonus::SPELLS_OF_LEVEL && it->subtype == spell->level)
+		{
+			return true;
+		}
+	}
+
+	return false;
+}
+
 int3 CGHeroInstance::getSightCenter() const
 {
 	return getPosition(false);
@@ -819,15 +847,40 @@ si32 CGHeroInstance::manaRegain() const
 	return 1 + getSecSkillLevel(8) + valOfBonuses(HeroBonus::MANA_REGENERATION); //1 + Mysticism level 
 }
 
-int CGHeroInstance::valOfBonuses( HeroBonus::BonusType type ) const
+int CGHeroInstance::valOfBonuses( HeroBonus::BonusType type, int subtype /*= -1*/ ) const
 {
 	int ret = 0;
-	for(std::list<HeroBonus>::const_iterator i=bonuses.begin(); i != bonuses.end(); i++)
-		if(i->type == type)
-			ret += i->val;
+	if(subtype == -1)
+	{
+		for(std::list<HeroBonus>::const_iterator i=bonuses.begin(); i != bonuses.end(); i++)
+			if(i->type == type)
+				ret += i->val;
+	}
+	else
+	{
+		for(std::list<HeroBonus>::const_iterator i=bonuses.begin(); i != bonuses.end(); i++)
+			if(i->type == type && i->subtype == subtype)
+				ret += i->val;
+	}
 	return ret;
 }
 
+bool CGHeroInstance::hasBonusOfType(HeroBonus::BonusType type, int subtype /*= -1*/) const
+{
+	if(subtype == -1)
+	{
+		for(std::list<HeroBonus>::const_iterator i=bonuses.begin(); i != bonuses.end(); i++)
+			if(i->type == type)
+				return true;
+	}
+	else
+	{
+		for(std::list<HeroBonus>::const_iterator i=bonuses.begin(); i != bonuses.end(); i++)
+			if(i->type == type && i->subtype == subtype)
+				return true;
+	}
+}
+
 int CGTownInstance::getSightRadious() const //returns sight distance
 {
 	return 5;

+ 3 - 1
hch/CObjectHandler.h

@@ -241,7 +241,8 @@ public:
 
 	//////////////////////////////////////////////////////////////////////////
 	const HeroBonus *getBonus(int from, int id) const;
-	int valOfBonuses(HeroBonus::BonusType type) const;
+	int valOfBonuses(HeroBonus::BonusType type, int subtype = -1) const; //subtype -> subtype of bonus, if -1 then any
+	bool hasBonusOfType(HeroBonus::BonusType type, int subtype = -1) const; //determines if hero has a bonus of given type (and optionally subtype)
 	const std::string &getBiography() const;
 	bool needsLastStack()const;
 	unsigned int getTileCost(const TerrainTile &dest, const TerrainTile &from) const; //move cost - applying pathfinding skill, road and terrain modifiers. NOT includes diagonal move penalty, last move levelling
@@ -264,6 +265,7 @@ public:
 	double getHeroStrength() const;
 	int getTotalStrength() const;
 	ui8 getSpellSchoolLevel(const CSpell * spell) const; //returns level on which given spell would be casted by this hero
+	bool canCastThisSpell(const CSpell * spell) const; //determines if this hero can cast given spell; takes into account existing spell in spellbook, existing spellbook and artifact bonuses
 
 	//////////////////////////////////////////////////////////////////////////
 

+ 27 - 3
server/CGameHandler.cpp

@@ -343,7 +343,9 @@ void CGameHandler::startBattle(CCreatureSet army1, CCreatureSet army2, int3 tile
 			next->state -= WAITING; //if stack was waiting it'll now make move, so it won't be "waiting" anymore
 
 			//check for bad morale => freeze
-			if(next->Morale() < 0)
+			if(next->Morale() < 0 &&
+				!((hero1 && hero1->hasBonusOfType(HeroBonus::BLOCK_MORALE)) || (hero2 && hero2->hasBonusOfType(HeroBonus::BLOCK_MORALE))) //checking if heroes have (or don't have) morale blocking bonuses)
+				)
 			{
 				if( rand()%24   <   (-next->Morale())*2 )
 				{
@@ -386,6 +388,7 @@ askInterfaceForMove:
 				&& !vstd::contains(next->state,WAITING)
 				&&  next->alive()
 				&&  next->Morale() > 0
+				&& !((hero1 && hero1->hasBonusOfType(HeroBonus::BLOCK_MORALE)) || (hero2 && hero2->hasBonusOfType(HeroBonus::BLOCK_MORALE)) ) //checking if heroes have (or don't have) morale blocking bonuses
 			)
 				if(rand()%24 < next->Morale()) //this stack hasn't got morale this turn
 					goto askInterfaceForMove; //move this stack once more
@@ -2313,6 +2316,23 @@ ui32 calculateSpellDmg(const CSpell * sp, const CGHeroInstance * caster, const C
 		ret *= 1.15f;
 		break;
 	}
+	//applying hero bonuses
+	if(sp->air && caster->valOfBonuses(HeroBonus::AIR_SPELL_DMG_PREMY) != 0)
+	{
+		ret *= (100.0f + caster->valOfBonuses(HeroBonus::AIR_SPELL_DMG_PREMY) / 100.0f);
+	}
+	else if(sp->fire && caster->valOfBonuses(HeroBonus::FIRE_SPELL_DMG_PREMY) != 0)
+	{
+		ret *= (100.0f + caster->valOfBonuses(HeroBonus::FIRE_SPELL_DMG_PREMY) / 100.0f);
+	}
+	else if(sp->water && caster->valOfBonuses(HeroBonus::WATER_SPELL_DMG_PREMY) != 0)
+	{
+		ret *= (100.0f + caster->valOfBonuses(HeroBonus::WATER_SPELL_DMG_PREMY) / 100.0f);
+	}
+	else if(sp->earth && caster->valOfBonuses(HeroBonus::EARTH_SPELL_DMG_PREMY) != 0)
+	{
+		ret *= (100.0f + caster->valOfBonuses(HeroBonus::EARTH_SPELL_DMG_PREMY) / 100.0f);
+	}
 
 	//applying protections - when spell has more then one elements, only one protection should be applied (I think)
 	if(sp->air && affectedCreature->getEffect(30)) //air spell & protection from air
@@ -2346,6 +2366,7 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
 	case 1: //hero casts spell
 		{
 			CGHeroInstance *h = (ba.side) ? gs->getHero(gs->curB->hero2) : gs->getHero(gs->curB->hero1);
+			CGHeroInstance *secondHero = (!ba.side) ? gs->getHero(gs->curB->hero2) : gs->getHero(gs->curB->hero1);
 			if(!h)
 			{
 				tlog2 << "Wrong caster!\n";
@@ -2360,10 +2381,13 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
 			CSpell *s = &VLC->spellh->spells[ba.additionalInfo];
 			ui8 skill = h->getSpellSchoolLevel(s); //skill level
 
-			if(   !(vstd::contains(h->spells,ba.additionalInfo)) //hero doesn't know this spell 
+			if(   !(h->canCastThisSpell(s)) //hero cannot cast this spell at all
 				|| (h->mana < s->costs[skill]) //not enough mana
 				|| (ba.additionalInfo < 10) //it's adventure spell (not combat)
-				|| (gs->curB->castedSpells[ba.side])     
+				|| (gs->curB->castedSpells[ba.side]) //spell has been casted
+				|| (secondHero && secondHero->hasBonusOfType(HeroBonus::SPELL_IMMUNITY, s->id)) //non - casting hero provides immunity for this spell
+				|| (h->valOfBonuses(HeroBonus::BLOCK_SPELLS_ABOVE_LEVEL) <= s->level) //caster's 'bonus' prevents him from casting this spell
+				|| (secondHero && secondHero->valOfBonuses(HeroBonus::BLOCK_SPELLS_ABOVE_LEVEL) <= s->level) //non - casting hero stops caster from casting this spell
 				)
 			{
 				tlog2 << "Spell cannot be casted!\n";