1
0
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:
mateuszb 2009-08-23 13:41:57 +00:00
parent 56fe3b0547
commit fe2085fe42
8 changed files with 79 additions and 19 deletions

View File

@ -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);

View File

@ -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)

View File

@ -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);
}

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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)

View File

@ -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