1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00
* fixed crash when AI attacked player before his first turn
* fixed various crashes when mass-effect spells affected town turrets in sieges
* some refactoring around spell positiveness
This commit is contained in:
Michał W. Urbańczyk 2012-02-16 21:19:07 +00:00
parent 0c3e88226f
commit 4baf4e13ed
11 changed files with 287 additions and 157 deletions

View File

@ -949,7 +949,7 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent)
const CSpell * spell = CGI->spellh->spells[creatureSpellToCast];
if (curInt->cb->battleCanCastThisSpell(spell, BattleHex(myNumber)) == ESpellCastProblem::OK)
{
if ((spell->positiveness > -1 && ourStack) || (spell->positiveness < 1 && !ourStack))
if ((!spell->isNegative() && ourStack) || (!spell->isPositive() && !ourStack))
{
CCS->curh->changeGraphic(3, 0);
stackCastsSpell = true;
@ -1788,7 +1788,7 @@ void CBattleInterface::hexLclicked(int whichOne)
const CSpell * spell = CGI->spellh->spells[creatureSpellToCast];
if (curInt->cb->battleCanCastThisSpell(spell, BattleHex(whichOne)) == ESpellCastProblem::OK)
{
if ((spell->positiveness > -1 && ourStack) || (spell->positiveness < 1 && !ourStack))
if ((!spell->isNegative() && ourStack) || (!spell->isPositive() && !ourStack))
{
giveCommand(BattleAction::MONSTER_SPELL, whichOne, actSt->ID, creatureSpellToCast);
spellCast = true;
@ -2371,41 +2371,15 @@ void CBattleInterface::castThisSpell(int spellID)
spellSelMode = ANY_LOCATION;
if(spell.getTargetType() == CSpell::CREATURE)
{
switch(spell.positiveness)
{
case -1 :
spellSelMode = HOSTILE_CREATURE;
break;
case 0:
spellSelMode = ANY_CREATURE;
break;
case 1:
spellSelMode = FRIENDLY_CREATURE;
break;
}
spellSelMode = selectionTypeByPositiveness(spell);
}
if(spell.getTargetType() == CSpell::CREATURE_EXPERT_MASSIVE)
{
if(castingHero && castingHero->getSpellSchoolLevel(&spell) < 3)
{
switch(spell.positiveness)
{
case -1 :
spellSelMode = HOSTILE_CREATURE;
break;
case 0:
spellSelMode = ANY_CREATURE;
break;
case 1:
spellSelMode = FRIENDLY_CREATURE;
break;
}
}
spellSelMode = selectionTypeByPositiveness(spell);
else
{
spellSelMode = NO_LOCATION;
}
}
if(spell.getTargetType() == CSpell::OBSTACLE)
{
spellSelMode = OBSTACLE;
@ -3088,6 +3062,19 @@ void CBattleInterface::bTacticNextStack()
stackActivated(stacksOfMine.front());
}
CBattleInterface::SpellSelectionType CBattleInterface::selectionTypeByPositiveness(const CSpell & spell)
{
switch(spell.positiveness)
{
case CSpell::NEGATIVE :
return HOSTILE_CREATURE;
case CSpell::NEUTRAL:
return ANY_CREATURE;
case CSpell::POSITIVE:
return FRIENDLY_CREATURE;
}
}
std::string CBattleInterface::SiegeHelper::townTypeInfixes[GameConstants::F_NUMBER] = {"CS", "RM", "TW", "IN", "NC", "DN", "ST", "FR", "EL"};
CBattleInterface::SiegeHelper::SiegeHelper(const CGTownInstance *siegeTown, const CBattleInterface * _owner)

View File

@ -246,6 +246,7 @@ public:
void endAction(const BattleAction* action);
void hideQueue();
void showQueue();
SpellSelectionType selectionTypeByPositiveness(const CSpell & spell);
friend class CPlayerInterface;

View File

@ -157,12 +157,6 @@ void CPlayerInterface::yourTurn()
autosaveCount = getLastIndex("Autosave_");
if(!GH.listInt.size())
{
GH.pushInt(adventureInt);
adventureInt->activateKeys();
}
if(firstCall > 0) //new game, not loaded
{
int index = getLastIndex("Newgame_Autosave_");
@ -224,6 +218,7 @@ STRONG_INLINE void delObjRect(const int & x, const int & y, const int & z, const
}
void CPlayerInterface::heroMoved(const TryMoveHero & details)
{
waitWhileDialog();
if(LOCPLINT != this)
return;
boost::unique_lock<boost::recursive_mutex> un(*pim);
@ -2345,8 +2340,24 @@ void CPlayerInterface::artifactDisassembled(const ArtifactLocation &al)
void CPlayerInterface::playerStartsTurn(ui8 player)
{
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
if(!GH.listInt.size())
{
GH.pushInt(adventureInt);
adventureInt->activateKeys();
}
if(howManyPeople == 1)
{
GH.curInt = this;
adventureInt->startTurn();
}
}
if(player != playerID && this == LOCPLINT)
{
waitWhileDialog();
boost::unique_lock<boost::recursive_mutex> un(*pim);
adventureInt->minimap.redraw();
adventureInt->infoBar.enemyTurn(player, 0.5);

View File

@ -1,136 +1,247 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="CAdvmapInterface.cpp" />
<ClCompile Include="CAnimation.cpp" />
<ClCompile Include="..\CCallback.cpp" />
<ClCompile Include="CBitmapHandler.cpp" />
<ClCompile Include="CCastleInterface.cpp" />
<ClCompile Include="CConfigHandler.cpp" />
<ClCompile Include="CCreatureWindow.cpp" />
<ClCompile Include="CDefHandler.cpp" />
<ClCompile Include="CGameInfo.cpp" />
<ClCompile Include="CHeroWindow.cpp" />
<ClCompile Include="CKingdomInterface.cpp" />
<ClCompile Include="Client.cpp" />
<ClCompile Include="CMessage.cpp" />
<ClCompile Include="CMT.cpp" />
<ClCompile Include="CMusicHandler.cpp" />
<ClCompile Include="CPlayerInterface.cpp" />
<ClCompile Include="CPreGame.cpp" />
<ClCompile Include="CSndHandler.cpp" />
<ClCompile Include="CSpellWindow.cpp" />
<ClCompile Include="CVideoHandler.cpp" />
<ClCompile Include="Graphics.cpp" />
<ClCompile Include="GUIClasses.cpp" />
<ClCompile Include="mapHandler.cpp" />
<ClCompile Include="NetPacksClient.cpp" />
<ClCompile Include="StdInc.cpp" />
<ClCompile Include="UIFramework\CCursorHandler.cpp">
<Filter>UIFramework</Filter>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="CAdvmapInterface.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="UIFramework\CGuiHandler.cpp">
<Filter>UIFramework</Filter>
<ClCompile Include="CBitmapHandler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="UIFramework\CIntObject.cpp">
<Filter>UIFramework</Filter>
<ClCompile Include="..\CCallback.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="UIFramework\CIntObjectClasses.cpp">
<Filter>UIFramework</Filter>
<ClCompile Include="CCastleInterface.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="UIFramework\Geometries.cpp">
<Filter>UIFramework</Filter>
<ClCompile Include="CConfigHandler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="UIFramework\SDL_Extensions.cpp">
<Filter>UIFramework</Filter>
<ClCompile Include="CGameInfo.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CHeroWindow.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CKingdomInterface.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Client.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CMessage.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CMT.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CPlayerInterface.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CPreGame.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CSpellWindow.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Graphics.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GUIClasses.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="NetPacksClient.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="mapHandler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CAnimation.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CDefHandler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CMusicHandler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CSndHandler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CVideoHandler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CCreatureWindow.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="BattleInterface\CBattleAnimations.cpp">
<Filter>BattleInterface</Filter>
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="BattleInterface\CBattleInterface.cpp">
<Filter>BattleInterface</Filter>
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="BattleInterface\CBattleInterfaceClasses.cpp">
<Filter>BattleInterface</Filter>
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="BattleInterface\CCreatureAnimation.cpp">
<Filter>BattleInterface</Filter>
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="StdInc.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="UIFramework\CCursorHandler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="UIFramework\CGuiHandler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="UIFramework\CIntObject.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="UIFramework\CIntObjectClasses.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="UIFramework\Geometries.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="UIFramework\SDL_Extensions.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="CAdvmapInterface.h" />
<ClInclude Include="CAnimation.h" />
<ClInclude Include="CBitmapHandler.h" />
<ClInclude Include="..\CCallback.h" />
<ClInclude Include="CCastleInterface.h" />
<ClInclude Include="CConfigHandler.h" />
<ClInclude Include="CCreatureWindow.h" />
<ClInclude Include="CDefHandler.h" />
<ClInclude Include="CGameInfo.h" />
<ClInclude Include="CHeroWindow.h" />
<ClInclude Include="CKingdomInterface.h" />
<ClInclude Include="Client.h" />
<ClInclude Include="CMessage.h" />
<ClInclude Include="CMusicBase.h" />
<ClInclude Include="CMusicHandler.h" />
<ClInclude Include="CPlayerInterface.h" />
<ClInclude Include="CPreGame.h" />
<ClInclude Include="CSndHandler.h" />
<ClInclude Include="CSoundBase.h" />
<ClInclude Include="CSpellWindow.h" />
<ClInclude Include="CVideoHandler.h" />
<ClInclude Include="FontBase.h" />
<ClInclude Include="FunctionList.h" />
<ClInclude Include="Graphics.h" />
<ClInclude Include="GUIClasses.h" />
<ClInclude Include="mapHandler.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="StdInc.h" />
<ClInclude Include="..\Global.h" />
<ClInclude Include="UIFramework\CCursorHandler.h">
<Filter>UIFramework</Filter>
<ClInclude Include="CAdvmapInterface.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="UIFramework\CGuiHandler.h">
<Filter>UIFramework</Filter>
<ClInclude Include="CBitmapHandler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="UIFramework\CIntObject.h">
<Filter>UIFramework</Filter>
<ClInclude Include="..\CCallback.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="UIFramework\CIntObjectClasses.h">
<Filter>UIFramework</Filter>
<ClInclude Include="CCastleInterface.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="UIFramework\Geometries.h">
<Filter>UIFramework</Filter>
<ClInclude Include="CConfigHandler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="UIFramework\SDL_Extensions.h">
<Filter>UIFramework</Filter>
<ClInclude Include="CGameInfo.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CHeroWindow.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CKingdomInterface.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Client.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CMessage.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CPlayerInterface.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CPreGame.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CSpellWindow.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="FontBase.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="FunctionList.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\global.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Graphics.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GUIClasses.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="mapHandler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CAnimation.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CDefHandler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CMusicBase.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CMusicHandler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CSndHandler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CSoundBase.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CVideoHandler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CCreatureWindow.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="BattleInterface\CBattleAnimations.h">
<Filter>BattleInterface</Filter>
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="BattleInterface\CBattleInterface.h">
<Filter>BattleInterface</Filter>
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="BattleInterface\CBattleInterfaceClasses.h">
<Filter>BattleInterface</Filter>
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="BattleInterface\CCreatureAnimation.h">
<Filter>BattleInterface</Filter>
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="StdInc.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="UIFramework\CCursorHandler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="UIFramework\CGuiHandler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="UIFramework\CIntObject.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="UIFramework\CIntObjectClasses.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="UIFramework\Geometries.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="UIFramework\SDL_Extensions.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="VCMI_client.rc" />
</ItemGroup>
<ItemGroup>
<None Include="..\ChangeLog" />
<None Include="vcmi.ico" />
<None Include="ClassDiagram21.cd" />
</ItemGroup>
<ItemGroup>
<Filter Include="BattleInterface">
<UniqueIdentifier>{3b4624b5-80f2-4bd8-b4c0-af29d3be4b58}</UniqueIdentifier>
</Filter>
<Filter Include="UIFramework">
<UniqueIdentifier>{918a73d4-7386-4d29-9515-a3579051d4ac}</UniqueIdentifier>
</Filter>
<ResourceCompile Include="VCMI_client.rc" />
</ItemGroup>
</Project>

View File

@ -728,16 +728,16 @@ std::set<CStack*> BattleInfo::getAttackedCreatures(const CSpell * s, int skillLe
bool onlyAlive = s->id != 38 && s->id != 39; //when casting resurrection or animate dead we should be allow to select dead stack
if(s->id == 24 || s->id == 25 || s->id == 26) //death ripple, destroy undead and Armageddon
if(s->id == Spells::DEATH_RIPPLE || s->id == Spells::DESTROY_UNDEAD || s->id == Spells::ARMAGEDDON)
{
for(int it=0; it<stacks.size(); ++it)
{
if((s->id == 24 && !stacks[it]->getCreature()->isUndead()) //death ripple
|| (s->id == 25 && stacks[it]->getCreature()->isUndead()) //destroy undead
|| (s->id == 26) //Armageddon
if((s->id == Spells::DEATH_RIPPLE && !stacks[it]->getCreature()->isUndead()) //death ripple
|| (s->id == Spells::DESTROY_UNDEAD && stacks[it]->getCreature()->isUndead()) //destroy undead
|| (s->id == Spells::ARMAGEDDON) //Armageddon
)
{
if(stacks[it]->alive())
if(stacks[it]->isValidTarget())
attackedCres.insert(stacks[it]);
}
}
@ -774,11 +774,11 @@ std::set<CStack*> BattleInfo::getAttackedCreatures(const CSpell * s, int skillLe
for(int it=0; it<stacks.size(); ++it)
{
/*if it's non negative spell and our unit or non positive spell and hostile unit */
if((s->positiveness >= 0 && stacks[it]->owner == attackerOwner)
||(s->positiveness <= 0 && stacks[it]->owner != attackerOwner )
if((!s->isNegative() && stacks[it]->owner == attackerOwner)
||(!s->isPositive() && stacks[it]->owner != attackerOwner )
)
{
if(!onlyAlive || stacks[it]->alive())
if(stacks[it]->isValidTarget(!onlyAlive))
attackedCres.insert(stacks[it]);
}
}
@ -1889,7 +1889,7 @@ ESpellCastProblem::ESpellCastProblem BattleInfo::battleCanCastThisSpell( int pla
{
switch (spell->positiveness)
{
case 1:
case CSpell::POSITIVE:
if(stack->owner == caster->getOwner())
{
if(battleIsImmune(caster, spell, mode, stack->position) == ESpellCastProblem::OK)
@ -1899,14 +1899,14 @@ ESpellCastProblem::ESpellCastProblem BattleInfo::battleCanCastThisSpell( int pla
}
}
break;
case 0:
case CSpell::NEUTRAL:
if(battleIsImmune(caster, spell, mode, stack->position) == ESpellCastProblem::OK)
{
targetExists = true;
break;
}
break;
case -1:
case CSpell::NEGATIVE:
if(stack->owner != caster->getOwner())
{
if(battleIsImmune(caster, spell, mode, stack->position) == ESpellCastProblem::OK)
@ -1950,7 +1950,7 @@ TSpell BattleInfo::getRandomBeneficialSpell(const CStack * subject) const
for (int i = 0; i < GameConstants::SPELLS_QUANTITY; ++i) //should not use future spells added by mods
{
spell = VLC->spellh->spells[i];
if (spell->positiveness == 1) //only positive
if (spell->isPositive()) //only positive
{
if (subject->hasBonusFrom(Bonus::SPELL_EFFECT, i) ||
battleCanCastThisSpellHere(subject->owner, spell, ECastingMode::CREATURE_ACTIVE_CASTING, subject->position) != ESpellCastProblem::OK)
@ -2080,12 +2080,12 @@ bool NegateRemover(const Bonus* b)
bool BattleInfo::battleTestElementalImmunity(const CStack * subject, const CSpell * spell, Bonus::BonusType element, bool damageSpell) const //helper for battleisImmune
{
if (spell->positiveness < 1) //negative or indifferent
if (!spell->isPositive()) //negative or indifferent
{
if ((damageSpell && subject->hasBonusOfType(element, 2)) || subject->hasBonusOfType(element, 1))
return true;
}
else if (spell->positiveness == 1) //positive
else if (spell->isPositive()) //positive
{
if (subject->hasBonusOfType(element, 0)) //must be immune to all spells
return true;
@ -2098,7 +2098,7 @@ ESpellCastProblem::ESpellCastProblem BattleInfo::battleIsImmune(const CGHeroInst
const CStack * subject = getStackT(dest, false);
if(subject)
{
if (spell->positiveness == 1 && subject->hasBonusOfType(Bonus::RECEPTIVE)) //accept all positive spells
if (spell->isPositive() && subject->hasBonusOfType(Bonus::RECEPTIVE)) //accept all positive spells
return ESpellCastProblem::OK;
switch (spell->id) //TODO: more general logic for new spells?
@ -2132,7 +2132,7 @@ ESpellCastProblem::ESpellCastProblem BattleInfo::battleIsImmune(const CGHeroInst
bool hasPositiveSpell = false;
BOOST_FOREACH(const Bonus * b, *spellBon)
{
if(VLC->spellh->spells[b->sid]->positiveness > 0)
if(VLC->spellh->spells[b->sid]->isPositive())
{
hasPositiveSpell = true;
break;
@ -2220,7 +2220,7 @@ std::vector<ui32> BattleInfo::calculateResistedStacks(const CSpell * sp, const C
}
//non-negative spells on friendly stacks should always succeed, unless immune
if(sp->positiveness >= 0 && (*it)->owner == casterSideOwner)
if(!sp->isNegative() && (*it)->owner == casterSideOwner)
continue;
/*
@ -2811,6 +2811,11 @@ std::string CStack::getName() const
return (count > 1) ? type->namePl : type->nameSing; //War machines can't use base
}
bool CStack::isValidTarget(bool allowDead/* = false*/) const /*alive non-turret stacks (can be attacked or be object of magic effect) */
{
return (alive() || allowDead) && position.isValid();
}
bool CMP_stack::operator()( const CStack* a, const CStack* b )
{
switch(phase)

View File

@ -250,6 +250,7 @@ public:
{
return vstd::contains(state,EBattleStackState::ALIVE);
}
bool isValidTarget(bool allowDead = false) const; //alive non-turret stacks (can be attacked or be object of magic effect)
};
class DLL_LINKAGE CMP_stack

View File

@ -205,6 +205,16 @@ CSpell::ETargetType CSpell::getTargetType() const
return NO_TARGET;
}
bool CSpell::isPositive() const
{
return positiveness == POSITIVE;
}
bool CSpell::isNegative() const
{
return positiveness == NEGATIVE;
}
static bool startsWithX(const std::string &s)
{
return s.size() && s[0] == 'x';

View File

@ -18,6 +18,7 @@ class DLL_LINKAGE CSpell
{
public:
enum ETargetType {NO_TARGET, CREATURE, CREATURE_EXPERT_MASSIVE, OBSTACLE};
enum ESpellPositiveness {NEGATIVE = -1, NEUTRAL = 0, POSITIVE = 1};
ui32 id;
std::string name;
std::string abbName; //abbreviated name
@ -41,6 +42,9 @@ public:
si16 mainEffectAnim; //main spell effect animation, in AC format (or -1 when none)
ETargetType getTargetType() const;
bool isPositive() const;
bool isNegative() const;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & id & name & abbName & descriptions & level & earth & water & fire & air & power & costs

View File

@ -1030,7 +1030,7 @@ namespace Selector
if(b->source == Bonus::SPELL_EFFECT)
{
CSpell *sp = VLC->spellh->spells[b->sid];
return sp->positiveness == 1;
return sp->isPositive();
}
return false; //not a spell effect
}

View File

@ -1209,7 +1209,7 @@ DLL_LINKAGE void StacksHealedOrResurrected::applyGs( CGameState *gs )
BOOST_FOREACH(Bonus *b, tmpFeatures)
{
const CSpell *s = b->sourceSpell();
if(s && s->positiveness < 0)
if(s && s->isNegative())
{
changedStack->removeBonus(b);
}

View File

@ -3579,10 +3579,10 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
BOOST_FOREACH (CStack * stack, gs->curB->stacks)
{
/*if it's non negative spell and our unit or non positive spell and hostile unit */
if((spell->positiveness >= 0 && stack->owner == casterColor)
||(spell->positiveness <= 0 && stack->owner != casterColor ))
if((!spell->isNegative() && stack->owner == casterColor)
|| (!spell->isPositive() && stack->owner != casterColor))
{
if(stack->alive()) //TODO: allow dead targets somewhere in the future
if(stack->isValidTarget()) //TODO: allow dead targets somewhere in the future
attackedCres.insert(stack);
}
}
@ -3967,7 +3967,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
}
//Magic Mirror effect
if (spell->positiveness < 0 && mode != ECastingMode::MAGIC_MIRROR && spell->level && spell->range[0] == "0") //it is actual spell and can be reflected to single target, no recurrence
if (spell->isNegative() && mode != ECastingMode::MAGIC_MIRROR && spell->level && spell->range[0] == "0") //it is actual spell and can be reflected to single target, no recurrence
{
for(std::set<CStack*>::iterator it = attackedCres.begin(); it != attackedCres.end(); ++it)
{
@ -5376,7 +5376,7 @@ void CGameHandler::runBattle()
for(int g=0; g<gs->curB->stacks.size(); ++g)
{
if(gs->curB->stacks[g]->owner != next->owner && gs->curB->stacks[g]->alive())
if(gs->curB->stacks[g]->owner != next->owner && gs->curB->stacks[g]->isValidTarget())
{
attack.destinationTile = gs->curB->stacks[g]->position;
break;
@ -5412,7 +5412,7 @@ void CGameHandler::runBattle()
for (int v=0; v<gs->curB->stacks.size(); ++v)
{
const CStack * cstack = gs->curB->stacks[v];
if (cstack->owner == next->owner && cstack->firstHPleft < cstack->MaxHealth() && cstack->alive()) //it's friendly and not fully healthy
if (cstack->owner == next->owner && cstack->firstHPleft < cstack->MaxHealth() && cstack->isValidTarget()) //it's friendly and not fully healthy
{
if (cstack->hasBonusOfType(Bonus::SIEGE_WEAPON))
secondPriority.push_back(cstack);