mirror of
https://github.com/vcmi/vcmi.git
synced 2025-07-17 01:32:21 +02:00
* 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.
This commit is contained in:
@ -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(attackerHero)
|
||||||
{
|
{
|
||||||
if(shooting)
|
if(shooting)
|
||||||
@ -1856,6 +1856,12 @@ int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender, con
|
|||||||
dmgBonusMultiplier *= 1.5f;
|
dmgBonusMultiplier *= 1.5f;
|
||||||
break;
|
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
|
else
|
||||||
{
|
{
|
||||||
|
@ -80,14 +80,14 @@ CSpellWindow::CSpellWindow(const SDL_Rect & myRect, const CGHeroInstance * myHer
|
|||||||
selectedTab(4),
|
selectedTab(4),
|
||||||
spellSite(0)
|
spellSite(0)
|
||||||
{
|
{
|
||||||
mySpells = myHero->spells;
|
//initializing castable spells
|
||||||
//XXX for testing only
|
for(ui32 v=0; v<CGI->spellh->spells.size(); ++v)
|
||||||
//for(ui32 v=0; v<CGI->spellh->spells.size(); ++v)
|
{
|
||||||
//{
|
if( !CGI->spellh->spells[v].creatureAbility && myHero->canCastThisSpell(&CGI->spellh->spells[v]) )
|
||||||
// if(!CGI->spellh->spells[v].creatureAbility)
|
mySpells.insert(v);
|
||||||
// mySpells.insert(v);
|
}
|
||||||
//}
|
|
||||||
|
|
||||||
|
//initializing schools' levels
|
||||||
for(int b=0; b<4; ++b) schoolLvls[b] = 0;
|
for(int b=0; b<4; ++b) schoolLvls[b] = 0;
|
||||||
for(size_t b=0; b<myHero->secSkills.size(); ++b)
|
for(size_t b=0; b<myHero->secSkills.size(); ++b)
|
||||||
{
|
{
|
||||||
|
@ -804,6 +804,34 @@ ui8 CGHeroInstance::getSpellSchoolLevel(const CSpell * spell) const
|
|||||||
return skill;
|
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
|
int3 CGHeroInstance::getSightCenter() const
|
||||||
{
|
{
|
||||||
return getPosition(false);
|
return getPosition(false);
|
||||||
@ -819,15 +847,40 @@ si32 CGHeroInstance::manaRegain() const
|
|||||||
return 1 + getSecSkillLevel(8) + valOfBonuses(HeroBonus::MANA_REGENERATION); //1 + Mysticism level
|
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;
|
int ret = 0;
|
||||||
for(std::list<HeroBonus>::const_iterator i=bonuses.begin(); i != bonuses.end(); i++)
|
if(subtype == -1)
|
||||||
if(i->type == type)
|
{
|
||||||
ret += i->val;
|
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;
|
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
|
int CGTownInstance::getSightRadious() const //returns sight distance
|
||||||
{
|
{
|
||||||
return 5;
|
return 5;
|
||||||
|
@ -241,7 +241,8 @@ public:
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
const HeroBonus *getBonus(int from, int id) const;
|
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;
|
const std::string &getBiography() const;
|
||||||
bool needsLastStack()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
|
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;
|
double getHeroStrength() const;
|
||||||
int getTotalStrength() const;
|
int getTotalStrength() const;
|
||||||
ui8 getSpellSchoolLevel(const CSpell * spell) const; //returns level on which given spell would be casted by this hero
|
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
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@ -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
|
next->state -= WAITING; //if stack was waiting it'll now make move, so it won't be "waiting" anymore
|
||||||
|
|
||||||
//check for bad morale => freeze
|
//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 )
|
if( rand()%24 < (-next->Morale())*2 )
|
||||||
{
|
{
|
||||||
@ -386,6 +388,7 @@ askInterfaceForMove:
|
|||||||
&& !vstd::contains(next->state,WAITING)
|
&& !vstd::contains(next->state,WAITING)
|
||||||
&& next->alive()
|
&& next->alive()
|
||||||
&& next->Morale() > 0
|
&& 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
|
if(rand()%24 < next->Morale()) //this stack hasn't got morale this turn
|
||||||
goto askInterfaceForMove; //move this stack once more
|
goto askInterfaceForMove; //move this stack once more
|
||||||
@ -2313,6 +2316,23 @@ ui32 calculateSpellDmg(const CSpell * sp, const CGHeroInstance * caster, const C
|
|||||||
ret *= 1.15f;
|
ret *= 1.15f;
|
||||||
break;
|
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)
|
//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
|
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
|
case 1: //hero casts spell
|
||||||
{
|
{
|
||||||
CGHeroInstance *h = (ba.side) ? gs->getHero(gs->curB->hero2) : gs->getHero(gs->curB->hero1);
|
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)
|
if(!h)
|
||||||
{
|
{
|
||||||
tlog2 << "Wrong caster!\n";
|
tlog2 << "Wrong caster!\n";
|
||||||
@ -2360,10 +2381,13 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
|
|||||||
CSpell *s = &VLC->spellh->spells[ba.additionalInfo];
|
CSpell *s = &VLC->spellh->spells[ba.additionalInfo];
|
||||||
ui8 skill = h->getSpellSchoolLevel(s); //skill level
|
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
|
|| (h->mana < s->costs[skill]) //not enough mana
|
||||||
|| (ba.additionalInfo < 10) //it's adventure spell (not combat)
|
|| (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";
|
tlog2 << "Spell cannot be casted!\n";
|
||||||
|
Reference in New Issue
Block a user