mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
* support for new creature abilities: hate, spell cost decreasing, spell vulnerability
* fixed crash when vcmiistari is applied on hero without spell book
This commit is contained in:
parent
56fe3b0547
commit
fe2085fe42
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user