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:
parent
44619757e8
commit
4e631fc530
@ -596,10 +596,7 @@ bool CBattleCallback::battleCanCastSpell()
|
|||||||
if(!gs->curB) //there is no battle
|
if(!gs->curB) //there is no battle
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if(gs->curB->sides[0] == player)
|
return gs->curB->battleCanCastSpell(player) == SpellCasting::OK;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CBattleCallback::battleCanFlee()
|
bool CBattleCallback::battleCanFlee()
|
||||||
@ -1091,29 +1088,16 @@ std::vector<int> CBattleCallback::battleGetDistances(const CStack * stack, THex
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
CBattleCallback::ESpellCastProblem CBattleCallback::battleCanCastThisSpell( const CSpell * spell )
|
SpellCasting::ESpellCastProblem CBattleCallback::battleCanCastThisSpell( const CSpell * spell )
|
||||||
{
|
{
|
||||||
if(!battleCanCastSpell())
|
if(!gs->curB)
|
||||||
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))
|
|
||||||
{
|
{
|
||||||
//check if there are summoned elementals of other type
|
|
||||||
BOOST_FOREACH ( const CStack * st, gs->curB->stacks)
|
tlog1 << "battleCanCastThisSpell called when there is no battle!\n";
|
||||||
{
|
return SpellCasting::NO_HERO_TO_CAST_SPELL;
|
||||||
if (vstd::contains(st->state, SUMMONED) && st->getCreature()->idNumber != creIDs[arpos])
|
|
||||||
{
|
|
||||||
return ANOTHER_ELEMENTAL_SUMMONED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return OK;
|
return gs->curB->battleCanCastThisSpell(player, spell);
|
||||||
}
|
}
|
||||||
|
|
||||||
si8 CBattleCallback::battleGetTacticDist()
|
si8 CBattleCallback::battleGetTacticDist()
|
||||||
|
@ -75,10 +75,6 @@ class IBattleCallback
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
///describes why player cannot cast a specific spell
|
///describes why player cannot cast a specific spell
|
||||||
enum ESpellCastProblem
|
|
||||||
{
|
|
||||||
OK, GENERAL_CASTING_PROBLEM, ANOTHER_ELEMENTAL_SUMMONED
|
|
||||||
};
|
|
||||||
|
|
||||||
enum EStackOwnership
|
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 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 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 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 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 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
|
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
|
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 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
|
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
|
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
|
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
|
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
|
||||||
|
@ -17,8 +17,10 @@
|
|||||||
#include <boost/algorithm/string/replace.hpp>
|
#include <boost/algorithm/string/replace.hpp>
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
|
#include <boost/format.hpp>
|
||||||
#include "CBitmapHandler.h"
|
#include "CBitmapHandler.h"
|
||||||
#include "../lib/CHeroHandler.h"
|
#include "../lib/CHeroHandler.h"
|
||||||
|
#include "../lib/BattleState.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CSpellWindow.cpp, part of VCMI engine
|
* CSpellWindow.cpp, part of VCMI engine
|
||||||
@ -619,20 +621,29 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
|
|||||||
//we will cast a spell
|
//we will cast a spell
|
||||||
if(sp->combatSpell && owner->myInt->battleInt && owner->myInt->cb->battleCanCastSpell()) //if battle window is open
|
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)
|
switch (problem)
|
||||||
{
|
{
|
||||||
case IBattleCallback::OK:
|
case SpellCasting::OK:
|
||||||
{
|
{
|
||||||
int spell = mySpell;
|
int spell = mySpell;
|
||||||
owner->fexitb();
|
owner->fexitb();
|
||||||
owner->myInt->battleInt->castThisSpell(spell);
|
owner->myInt->battleInt->castThisSpell(spell);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IBattleCallback::ANOTHER_ELEMENTAL_SUMMONED:
|
case SpellCasting::ANOTHER_ELEMENTAL_SUMMONED:
|
||||||
{
|
{
|
||||||
std::string text = CGI->generaltexth->allTexts[538], summoner, elemental, caster;
|
std::string text = CGI->generaltexth->allTexts[538], summoner, elemental, caster;
|
||||||
std::vector<const CStack *> stacks = owner->myInt->cb->battleGetStacks();
|
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)
|
if (owner->myHero->type->sex)
|
||||||
{ //female
|
{ //female
|
||||||
caster = CGI->generaltexth->allTexts[540];
|
caster = CGI->generaltexth->allTexts[540];
|
||||||
@ -641,6 +652,8 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
|
|||||||
{ //male
|
{ //male
|
||||||
caster = CGI->generaltexth->allTexts[539];
|
caster = CGI->generaltexth->allTexts[539];
|
||||||
}
|
}
|
||||||
|
text = boost::str(boost::format(text) % summoner % elemental % caster);
|
||||||
|
|
||||||
|
|
||||||
owner->myInt->showInfoDialog(text);
|
owner->myInt->showInfoDialog(text);
|
||||||
}
|
}
|
||||||
|
10
global.h
10
global.h
@ -307,6 +307,16 @@ enum EMarketMode
|
|||||||
MARTKET_AFTER_LAST_PLACEHOLDER
|
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
|
namespace Res
|
||||||
{
|
{
|
||||||
enum ERes
|
enum ERes
|
||||||
|
@ -1617,6 +1617,62 @@ bool BattleInfo::isInTacticRange( THex dest ) const
|
|||||||
|| (tacticsSide && dest.getX() < BFIELD_WIDTH - 1 && dest.getX() >= BFIELD_WIDTH - tacticDistance - 1));
|
|| (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)
|
CStack::CStack(const CStackInstance *Base, int O, int I, bool AO, int S)
|
||||||
: base(Base), ID(I), owner(O), slot(S), attackerOwned(AO),
|
: base(Base), ID(I), owner(O), slot(S), attackerOwned(AO),
|
||||||
counterAttacks(1)
|
counterAttacks(1)
|
||||||
|
@ -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
|
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
|
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
|
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 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
|
const CGHeroInstance * battleGetOwner(const CStack * stack) const; //returns hero that owns given stack; NULL if none
|
||||||
|
@ -3824,15 +3824,11 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
|
|||||||
const CSpell *s = VLC->spellh->spells[ba.additionalInfo];
|
const CSpell *s = VLC->spellh->spells[ba.additionalInfo];
|
||||||
ui8 skill = h->getSpellSchoolLevel(s); //skill level
|
ui8 skill = h->getSpellSchoolLevel(s); //skill level
|
||||||
|
|
||||||
if( !(h->canCastThisSpell(s)) //hero cannot cast this spell at all
|
SpellCasting::ESpellCastProblem escp = gs->curB->battleCanCastThisSpell(h->tempOwner, s);
|
||||||
|| (h->mana < gs->curB->getSpellCost(s, h)) //not enough mana
|
if(escp != SpellCasting::OK)
|
||||||
|| (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
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
tlog2 << "Spell cannot be cast!\n";
|
tlog2 << "Spell cannot be cast!\n";
|
||||||
|
tlog2 << "Problem : " << escp << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user