diff --git a/CCallback.cpp b/CCallback.cpp index 9d3e7bae0..6bee1c91f 100644 --- a/CCallback.cpp +++ b/CCallback.cpp @@ -15,6 +15,7 @@ #include #include #include +#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 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 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 lock(*gs->mx); diff --git a/CCallback.h b/CCallback.h index ffa6ebac7..75fa7940d 100644 --- a/CCallback.h +++ b/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) diff --git a/client/CSpellWindow.cpp b/client/CSpellWindow.cpp index 67e467d21..389ef6ebc 100644 --- a/client/CSpellWindow.cpp +++ b/client/CSpellWindow.cpp @@ -11,6 +11,7 @@ #include "SDL_Extensions.h" #include "CMessage.h" #include "CPlayerInterface.h" +#include "../CCallback.h" #include #include @@ -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<generaltexth->allTexts[387]<<": "<spellh->spells[spellAreas[b]->mySpell].costs[bestslvl]; + ss<generaltexth->allTexts[387]<<": "<cb->getSpellCost(spell, myHero); CSDL_Ext::printAtMiddle(ss.str(), spellAreas[b]->pos.x + 39, spellAreas[b]->pos.y + 94, GEORM, zwykly, to); } diff --git a/config/cr_abils.txt b/config/cr_abils.txt index 4fdffa9d9..833466741 100644 --- a/config/cr_abils.txt +++ b/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 diff --git a/lib/CGameState.cpp b/lib/CGameState.cpp index a2b7bc472..8d0e6de15 100644 --- a/lib/CGameState.cpp +++ b/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; gowner == 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); diff --git a/lib/CGameState.h b/lib/CGameState.h index 14fbe9989..3702bc834 100644 --- a/lib/CGameState.h +++ b/lib/CGameState.h @@ -141,6 +141,7 @@ struct DLL_EXPORT BattleInfo std::set 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 diff --git a/lib/NetPacksLib.cpp b/lib/NetPacksLib.cpp index 30dbf68b2..8108e23c1 100644 --- a/lib/NetPacksLib.cpp +++ b/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) diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 050af381a..1f6c2ab06 100644 --- a/server/CGameHandler.cpp +++ b/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