1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

* fix for bug 573

* minor changes
This commit is contained in:
mateuszb 2011-02-15 19:54:55 +00:00
parent 44619757e8
commit 4e631fc530
7 changed files with 97 additions and 39 deletions

View File

@ -596,10 +596,7 @@ bool CBattleCallback::battleCanCastSpell()
if(!gs->curB) //there is no battle
return false;
if(gs->curB->sides[0] == player)
return gs->curB->castSpells[0] == 0 && gs->curB->heroes[0] && gs->curB->heroes[0]->getArt(17);
else
return gs->curB->castSpells[1] == 0 && gs->curB->heroes[1] && gs->curB->heroes[1]->getArt(17);
return gs->curB->battleCanCastSpell(player) == SpellCasting::OK;
}
bool CBattleCallback::battleCanFlee()
@ -1091,29 +1088,16 @@ std::vector<int> CBattleCallback::battleGetDistances(const CStack * stack, THex
return ret;
}
CBattleCallback::ESpellCastProblem CBattleCallback::battleCanCastThisSpell( const CSpell * spell )
SpellCasting::ESpellCastProblem CBattleCallback::battleCanCastThisSpell( const CSpell * spell )
{
if(!battleCanCastSpell())
return GENERAL_CASTING_PROBLEM;
int spellIDs[] = {66, 67, 68, 69}; //IDs of summon elemental spells (fire, earth, water, air)
int creIDs[] = {114, 113, 115, 112}; //(fire, earth, water, air)
int * idp = std::find(spellIDs, spellIDs + ARRAY_COUNT(spellIDs), spell->id);
int arpos = idp - spellIDs;
if(arpos < ARRAY_COUNT(spellIDs))
if(!gs->curB)
{
//check if there are summoned elementals of other type
BOOST_FOREACH ( const CStack * st, gs->curB->stacks)
{
if (vstd::contains(st->state, SUMMONED) && st->getCreature()->idNumber != creIDs[arpos])
{
return ANOTHER_ELEMENTAL_SUMMONED;
}
}
tlog1 << "battleCanCastThisSpell called when there is no battle!\n";
return SpellCasting::NO_HERO_TO_CAST_SPELL;
}
return OK;
return gs->curB->battleCanCastThisSpell(player, spell);
}
si8 CBattleCallback::battleGetTacticDist()

View File

@ -75,10 +75,6 @@ class IBattleCallback
{
public:
///describes why player cannot cast a specific spell
enum ESpellCastProblem
{
OK, GENERAL_CASTING_PROBLEM, ANOTHER_ELEMENTAL_SUMMONED
};
enum EStackOwnership
{
@ -100,7 +96,7 @@ public:
virtual std::vector<int> battleGetDistances(const CStack * stack, THex hex = THex::INVALID, THex * predecessors = NULL)=0; //returns vector of distances to [dest hex number]
virtual bool battleCanShoot(const CStack * stack, THex dest)=0; //returns true if unit with id ID can shoot to dest
virtual bool battleCanCastSpell()=0; //returns true, if caller can cast a spell
virtual ESpellCastProblem battleCanCastThisSpell(const CSpell * spell)=0; //determines if given spell can be casted (and returns problem description)
virtual SpellCasting::ESpellCastProblem battleCanCastThisSpell(const CSpell * spell)=0; //determines if given spell can be casted (and returns problem description)
virtual bool battleCanFlee()=0; //returns true if caller can flee from the battle
virtual const CGTownInstance * battleGetDefendedTown()=0; //returns defended town if current battle is a siege, NULL instead
virtual ui8 battleGetWallState(int partOfWall)=0; //for determining state of a part of the wall; format: parameter [0] - keep, [1] - bottom tower, [2] - bottom wall, [3] - below gate, [4] - over gate, [5] - upper wall, [6] - uppert tower, [7] - gate; returned value: 1 - intact, 2 - damaged, 3 - destroyed; 0 - no battle
@ -238,7 +234,7 @@ public:
std::vector<int> battleGetDistances(const CStack * stack, THex hex = THex::INVALID, THex * predecessors = NULL) OVERRIDE; //returns vector of distances to [dest hex number]; if predecessors is not null, it must point to BFIELD_SIZE * sizeof(int) of allocated memory
bool battleCanShoot(const CStack * stack, THex dest) OVERRIDE; //returns true if unit with id ID can shoot to dest
bool battleCanCastSpell() OVERRIDE; //returns true, if caller can cast a spell
ESpellCastProblem battleCanCastThisSpell(const CSpell * spell) OVERRIDE; //determines if given spell can be casted (and returns problem description)
SpellCasting::ESpellCastProblem battleCanCastThisSpell(const CSpell * spell) OVERRIDE; //determines if given spell can be casted (and returns problem description)
bool battleCanFlee() OVERRIDE; //returns true if caller can flee from the battle
const CGTownInstance * battleGetDefendedTown() OVERRIDE; //returns defended town if current battle is a siege, NULL instead
ui8 battleGetWallState(int partOfWall) OVERRIDE; //for determining state of a part of the wall; format: parameter [0] - keep, [1] - bottom tower, [2] - bottom wall, [3] - below gate, [4] - over gate, [5] - upper wall, [6] - uppert tower, [7] - gate; returned value: 1 - intact, 2 - damaged, 3 - destroyed; 0 - no battle

View File

@ -17,8 +17,10 @@
#include <boost/algorithm/string/replace.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/foreach.hpp>
#include <boost/format.hpp>
#include "CBitmapHandler.h"
#include "../lib/CHeroHandler.h"
#include "../lib/BattleState.h"
/*
* CSpellWindow.cpp, part of VCMI engine
@ -619,20 +621,29 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
//we will cast a spell
if(sp->combatSpell && owner->myInt->battleInt && owner->myInt->cb->battleCanCastSpell()) //if battle window is open
{
IBattleCallback::ESpellCastProblem problem = owner->myInt->cb->battleCanCastThisSpell(sp);
SpellCasting::ESpellCastProblem problem = owner->myInt->cb->battleCanCastThisSpell(sp);
switch (problem)
{
case IBattleCallback::OK:
case SpellCasting::OK:
{
int spell = mySpell;
owner->fexitb();
owner->myInt->battleInt->castThisSpell(spell);
break;
}
case IBattleCallback::ANOTHER_ELEMENTAL_SUMMONED:
case SpellCasting::ANOTHER_ELEMENTAL_SUMMONED:
{
std::string text = CGI->generaltexth->allTexts[538], summoner, elemental, caster;
std::vector<const CStack *> stacks = owner->myInt->cb->battleGetStacks();
BOOST_FOREACH(const CStack * s, stacks)
{
if(vstd::contains(s->state, SUMMONED))
{
elemental = s->getCreature()->namePl;
summoner = owner->myInt->cb->battleGetFightingHero(!s->attackerOwned)->name;
break;
}
}
if (owner->myHero->type->sex)
{ //female
caster = CGI->generaltexth->allTexts[540];
@ -641,6 +652,8 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
{ //male
caster = CGI->generaltexth->allTexts[539];
}
text = boost::str(boost::format(text) % summoner % elemental % caster);
owner->myInt->showInfoDialog(text);
}

View File

@ -307,6 +307,16 @@ enum EMarketMode
MARTKET_AFTER_LAST_PLACEHOLDER
};
namespace SpellCasting
{
enum ESpellCastProblem
{
OK, NO_HERO_TO_CAST_SPELL, ALREADY_CASTED_THIS_TURN, NO_SPELLBOOK, ANOTHER_ELEMENTAL_SUMMONED,
HERO_DOESNT_KNOW_SPELL, NOT_ENOUGH_MANA, ADVMAP_SPELL_INSTEAD_OF_BATTLE_SPELL,
SECOND_HEROS_SPELL_IMMUNITY, SPELL_LEVEL_LIMIT_EXCEEDED
};
}
namespace Res
{
enum ERes

View File

@ -1617,6 +1617,62 @@ bool BattleInfo::isInTacticRange( THex dest ) const
|| (tacticsSide && dest.getX() < BFIELD_WIDTH - 1 && dest.getX() >= BFIELD_WIDTH - tacticDistance - 1));
}
SpellCasting::ESpellCastProblem BattleInfo::battleCanCastSpell(int player) const
{
int side = sides[0] == player ? 0 : 1;
if(castSpells[side] > 0)
return SpellCasting::ALREADY_CASTED_THIS_TURN;
if(!heroes[side])
return SpellCasting::NO_HERO_TO_CAST_SPELL;
if(!heroes[side]->getArt(17))
return SpellCasting::NO_SPELLBOOK;
return SpellCasting::OK;
}
SpellCasting::ESpellCastProblem BattleInfo::battleCanCastThisSpell( int player, const CSpell * spell ) const
{
SpellCasting::ESpellCastProblem genProblem = battleCanCastSpell(player);
if(genProblem != SpellCasting::OK)
return genProblem;
int cside = sides[0] == player ? 0 : 1; //caster's side
const CGHeroInstance * caster = heroes[cside];
if(!caster->canCastThisSpell(spell))
return SpellCasting::HERO_DOESNT_KNOW_SPELL;
if(caster->mana < getSpellCost(spell, caster)) //not enough mana
return SpellCasting::NOT_ENOUGH_MANA;
if(spell->id < 10) //it's adventure spell (not combat))
return SpellCasting::ADVMAP_SPELL_INSTEAD_OF_BATTLE_SPELL;
if(NBonus::hasOfType(heroes[1-cside], Bonus::SPELL_IMMUNITY, spell->id)) //non - casting hero provides immunity for this spell
return SpellCasting::SECOND_HEROS_SPELL_IMMUNITY;
if(battleMaxSpellLevel() < spell->level) //non - casting hero stops caster from casting this spell
return SpellCasting::SPELL_LEVEL_LIMIT_EXCEEDED;
int spellIDs[] = {66, 67, 68, 69}; //IDs of summon elemental spells (fire, earth, water, air)
int creIDs[] = {114, 113, 115, 112}; //(fire, earth, water, air)
int * idp = std::find(spellIDs, spellIDs + ARRAY_COUNT(spellIDs), spell->id);
int arpos = idp - spellIDs;
if(arpos < ARRAY_COUNT(spellIDs))
{
//check if there are summoned elementals of other type
BOOST_FOREACH ( const CStack * st, stacks)
{
if (vstd::contains(st->state, SUMMONED) && st->getCreature()->idNumber != creIDs[arpos])
{
return SpellCasting::ANOTHER_ELEMENTAL_SUMMONED;
}
}
}
return SpellCasting::OK;
}
CStack::CStack(const CStackInstance *Base, int O, int I, bool AO, int S)
: base(Base), ID(I), owner(O), slot(S), attackerOwned(AO),
counterAttacks(1)

View File

@ -115,6 +115,9 @@ struct DLL_EXPORT BattleInfo : public CBonusSystemNode
si8 canTeleportTo(const CStack * stack, THex destHex, int telportLevel) const; //determines if given stack can teleport to given place
bool battleCanShoot(const CStack * stack, THex dest) const; //determines if stack with given ID shoot at the selected destination
SpellCasting::ESpellCastProblem battleCanCastSpell(int player) const; //returns true if there are no general issues preventing from castng a spell
SpellCasting::ESpellCastProblem battleCanCastThisSpell(int player, const CSpell * spell) const; //chcecks if given player can cast given spell
bool battleCanFlee(int player) const; //returns true if player can flee from the battle
const CStack * battleGetStack(THex pos, bool onlyAlive); //returns stack at given tile
const CGHeroInstance * battleGetOwner(const CStack * stack) const; //returns hero that owns given stack; NULL if none

View File

@ -3824,15 +3824,11 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
const CSpell *s = VLC->spellh->spells[ba.additionalInfo];
ui8 skill = h->getSpellSchoolLevel(s); //skill level
if( !(h->canCastThisSpell(s)) //hero cannot cast this spell at all
|| (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
|| (NBonus::hasOfType(secondHero, Bonus::SPELL_IMMUNITY, s->id)) //non - casting hero provides immunity for this spell
|| (gs->curB->battleMaxSpellLevel() < s->level) //non - casting hero stops caster from casting this spell
)
SpellCasting::ESpellCastProblem escp = gs->curB->battleCanCastThisSpell(h->tempOwner, s);
if(escp != SpellCasting::OK)
{
tlog2 << "Spell cannot be cast!\n";
tlog2 << "Problem : " << escp << std::endl;
return false;
}