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

- First part of battle interface rewrite. Untested. May work or not work randomly.

- Tweaks for AI logging.
This commit is contained in:
DjWarmonger 2012-04-16 17:12:39 +00:00
parent 66f5b5e2d7
commit aeb9cf9460
4 changed files with 310 additions and 234 deletions

View File

@ -80,6 +80,8 @@ std::string goalName(EGoals goalType)
return "WIN";
case CONQUER:
return "CONQUER";
case BUILD:
return "BUILD";
case EXPLORE:
return "EXPLORE";
case GATHER_ARMY:
@ -1496,7 +1498,7 @@ void getVisibleNeighbours(const std::vector<int3> &tiles, std::vector<int3> &out
void VCAI::tryRealize(CGoal g)
{
BNLOG("Attempting realizing goal with code %d", g.goalType);
BNLOG("Attempting realizing goal with code %s", goalName(g.goalType));
switch(g.goalType)
{
case EXPLORE:

View File

@ -37,7 +37,8 @@ public:
enum EGoals
{
INVALID = -1,
WIN, DO_NOT_LOSE, CONQUER, BUILD, EXPLORE, GATHER_ARMY, BOOST_HERO,
WIN, DO_NOT_LOSE, CONQUER, BUILD, //build needs to get a real reasoning
EXPLORE, GATHER_ARMY, BOOST_HERO,
RECRUIT_HERO,
BUILD_STRUCTURE, //if hero set, then in visited town
COLLECT_RES,

View File

@ -93,7 +93,7 @@ void CBattleInterface::addNewAnim(CBattleAnimation * anim)
CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSet * army2, CGHeroInstance *hero1, CGHeroInstance *hero2, const SDL_Rect & myRect, CPlayerInterface * att, CPlayerInterface * defen)
: queue(NULL), attackingHeroInstance(hero1), defendingHeroInstance(hero2), animCount(0),
activeStack(NULL), stackToActivate(NULL), mouseHoveredStack(-1), lastMouseHoveredStackAnimationTime(-1), previouslyHoveredHex(-1),
currentlyHoveredHex(-1), attackingHex(-1), tacticianInterface(NULL), stackCanCastSpell(false), spellDestSelectMode(false), spellSelMode(NO_LOCATION), spellToCast(NULL),
currentlyHoveredHex(-1), attackingHex(-1), tacticianInterface(NULL), stackCanCastSpell(false), creatureCasting(false), spellDestSelectMode(false), spellSelMode(NO_LOCATION), spellToCast(NULL), sp(NULL),
siegeH(NULL), attackerInt(att), defenderInt(defen), curInt(att), animIDhelper(0), bfield(GameConstants::BFIELD_SIZE),
givenCommand(NULL), myTurn(false), resWindow(NULL), moveStarted(false), moveSh(-1), bresult(NULL)
@ -1833,7 +1833,7 @@ void CBattleInterface::castThisSpell(int spellID)
spellSelMode = ANY_LOCATION;
}
if(spellSelMode == NO_LOCATION) //user does not have to select location
if (spellSelMode == NO_LOCATION) //user does not have to select location
{
spellToCast->destinationTile = -1;
curInt->cb->battleMakeAction(spellToCast);
@ -1841,6 +1841,8 @@ void CBattleInterface::castThisSpell(int spellID)
}
else
{
possibleActions.clear();
possibleActions.push_back (spellSelMode); //only this one actions can be performed at the moment
GH.fakeMouseMove();//update cursor
}
}
@ -1986,10 +1988,16 @@ void CBattleInterface::getPossibleActionsForStack(const CStack * stack)
if (stack->hasBonusOfType (Bonus::SPELLCASTER))
{
//TODO: poll possible spells
possibleActions.push_back (OFFENSIVE_SPELL);
possibleActions.push_back (FRIENDLY_SPELL);
possibleActions.push_back (RISING_SPELL);
//TODO: stacks casting remove obstacle?
BOOST_FOREACH (Bonus * spellBonus, *stack->getBonuses (Selector::type(Bonus::SPELLCASTER)))
{
possibleActions.push_back (selectionTypeByPositiveness (*CGI->spellh->spells[spellBonus->subtype]));
}
//TODO: determine whether spell is rising
//possibleActions.push_back (RISING_SPELL);
//possibleActions.push_back (OBSTACLE);
//possibleActions.push_back (SACRIFICE);
//possibleActions.push_back (NO_LOCATION);
//possibleActions.push_back (ANY_LOCATION);
//possibleActions.push_back (OTHER_SPELL);
}
if (stack->hasBonusOfType (Bonus::RANDOM_SPELLCASTER))
@ -2557,7 +2565,7 @@ void CBattleInterface::bTacticNextStack(const CStack *current /*= NULL*/)
possibleActions += MOVE_TACTICS, CHOOSE_TACTICS_STACK;
}
CBattleInterface::SpellSelectionType CBattleInterface::selectionTypeByPositiveness(const CSpell & spell)
CBattleInterface::PossibleActions CBattleInterface::selectionTypeByPositiveness(const CSpell & spell)
{
switch(spell.positiveness)
{
@ -2600,6 +2608,7 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
std::function<void()> realizeAction;
//helper lambda that appropriately realizes action / sets cursor and tooltip
//TODO: separate action at mouse move and clicking
auto realizeThingsToDo = [&]()
{
if(eventType == MOVE)
@ -2620,232 +2629,136 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
const CStack * const shere = curInt->cb->battleGetStackByPos(myNumber, false);
const CStack * const sactive = activeStack;
if(!sactive)
if (!sactive)
return;
bool creatureCasting = !spellDestSelectMode && stackCanCastSpell && spellSelMode > STACK_SPELL_CANCELLED
&& shere != sactive;
bool ourStack = false;
if (shere)
ourStack = shere->owner == curInt->playerID;
bool noStackIsHovered = true; //will cause removing a blue glow
localActions.clear();
BOOST_FOREACH (int action, localActions)
BOOST_FOREACH (PossibleActions action, possibleActions)
{
bool legalAction = false;
bool illegalAction = false;
//TODO: copy actions avaliable to perform at this hex to localActions. set currentAction
}
switch (action)
{
case MOVE_TACTICS:
break;
case CHOOSE_TACTICS_STACK:
if (shere && ourStack)
legalAction = true;
break;
case MOVE_STACK:
if (vstd::contains(occupyableHexes, myNumber) || activeStack->coversPos(myNumber))
//TODO
legalAction = true;
break;
case ATTACK:
case WALK_AND_ATTACK:
case ATTACK_AND_RETURN:
{
std::vector<BattleHex> acc = curInt->cb->battleGetAvailableHexes (activeStack, false);
//handle spellcasting (by hero or creature)
if(!tacticsMode && (spellDestSelectMode || creatureCasting))
{
bool isCastingPossible = true;
int spellID = -1;
if(creatureCasting)
{
if(creatureSpellToCast > -1)
spellID = creatureSpellToCast;
else
{
if(!shere || curInt->cb->battleGetRandomStackSpell(shere, CBattleInfoCallback::RANDOM_GENIE)< 0) //no possible spell for this dest
goto pastCastingSpells; //behave as if stack were not a caster
BattleHex attackFromHex = fromWhichHexAttack(myNumber);
if(shere->alive() && isTileAttackable(myNumber) && attackFromHex >= 0) //we can be in this line when unreachable creature is L - clicked (as of revision 1308)
legalAction = true;
}
}
else if(spellDestSelectMode) //hero casting
spellID = spellToCast->additionalInfo;
const CSpell *sp = NULL;
if(spellID >= 0)
sp = CGI->spellh->spells[spellID];
if(!myNumber.isAvailable() && !shere) //empty tile outside battlefield (or in the unavailable border column)
isCastingPossible = false;
const ui8 skill = sp ? getActiveHero()->getSpellSchoolLevel(sp) : 0; //skill level
//TODO master genies cast on adv level, that was somewhere in bonuses
if(sp)
{
if(creatureCasting)
isCastingPossible = (curInt->cb->battleCanCreatureCastThisSpell(sp, myNumber) == ESpellCastProblem::OK);
else
isCastingPossible = (curInt->cb->battleCanCastThisSpell(sp, myNumber) == ESpellCastProblem::OK);
}
else
{
//needed for genie, otherwise covered by battleCan*CastThisSpell
if( !shere
|| !shere->alive()
|| (spellSelMode == HOSTILE_CREATURE && shere->owner == sactive->owner)
|| (spellSelMode == FRIENDLY_CREATURE && shere->owner != sactive->owner))
{
isCastingPossible = false;
}
}
switch(spellSelMode)
{
break;
case SHOOT:
if(curInt->cb->battleCanShoot (activeStack, myNumber))
legalAction = true;
break;
case HOSTILE_CREATURE: //TODO: check spell immunity
if (shere && !ourStack && isCastingPossibleHere (sactive, shere, myNumber))
legalAction = true;
break;
case FRIENDLY_CREATURE:
case HOSTILE_CREATURE:
case ANY_CREATURE:
if(isCastingPossible && shere)
if (shere && ourStack && isCastingPossibleHere (sactive, shere, myNumber))
legalAction = true;
break;
case RISING_SPELL:
if (shere && shere->canBeHealed() && isCastingPossibleHere (sactive, shere, myNumber)) //TODO: at least one stack has to be raised by resurrection / animate dead
legalAction = true;
break;
case RANDOM_GENIE_SPELL:
{
if(sp)
consoleMsg = boost::str(boost::format(CGI->generaltexth->allTexts[27]) % sp->name % shere->getName()); //Cast %s on %s
else
consoleMsg = boost::str(boost::format(CGI->generaltexth->allTexts[301]) % shere->getName()); //Cast a spell on %s
if (shere)
{
int spellID = curInt->cb->battleGetRandomStackSpell(shere, CBattleInfoCallback::RANDOM_GENIE);
if (spellID > -1)
{
sp = CGI->spellh->spells[spellID];
legalAction = true;
}
}
}
if(!shere) //there must be a creature as target
isCastingPossible = false;
break;
case OBSTACLE:
if(isCastingPossible)
consoleMsg = CGI->generaltexth->allTexts[550]; //Remove this obstacle
legalAction = false; //TODO
break;
case TELEPORT: //teleport
if (!curInt->cb->battleCanTeleportTo(activeStack, myNumber, skill))
isCastingPossible = false;
if(!isCastingPossible)
consoleMsg = CGI->generaltexth->allTexts[24]; //Invalid Teleport Destination
case TELEPORT:
{
const ui8 skill = spellToCast ? getActiveHero()->getSpellSchoolLevel(CGI->spellh->spells[spellToCast->additionalInfo]) : 0; //skill level
//TODO: creature can cast a spell with some skill / spellpower as well
//TODO: explicitely save spell_to_cast * CSpell, power, skill
if (curInt->cb->battleCanTeleportTo(activeStack, myNumber, skill))
legalAction = true;
else
consoleMsg = CGI->generaltexth->allTexts[25]; //Teleport Here
illegalAction = true;
}
break;
case OTHER_SPELL: //TODO
break;
case CATAPULT:
if (isCatapultAttackable(myNumber))
legalAction = true;
break;
case HEAL:
if (shere && ourStack && shere->canBeHealed())
legalAction = true;
break;
case RISE_DEMONS:
if (shere && ourStack && !shere->alive())
legalAction = true;
break;
}
//destination checked
if(isCastingPossible)
{
cursorType = ECursor::SPELLBOOK;
cursorFrame = 0;
if(consoleMsg.empty() && sp)
consoleMsg = boost::str(boost::format(CGI->generaltexth->allTexts[26]) % sp->name); //Cast %s
realizeAction = [=]
{
if(creatureCasting)
{
giveCommand(BattleAction::MONSTER_SPELL, myNumber, sactive->ID, creatureSpellToCast);
if (legalAction)
localActions.push_back (action);
else if (illegalAction)
illegalActions.push_back (action);
}
if (vstd::contains(localActions, selectedAction)) //try to use last selected action by default
currentAction = selectedAction;
else if (localActions.size()) //if not possible, select first avaliable action 9they are sorted by suggested priority)
currentAction = localActions.front();
else //no legal action possible
{
currentAction = INVALID; //don't allow to do anything
if (vstd::contains(illegalActions, selectedAction))
illegalAction = selectedAction;
else if (illegalActions.size())
illegalAction = illegalActions.front();
else
{
spellToCast->destinationTile = myNumber;
curInt->cb->battleMakeAction(spellToCast);
endCastingSpell();
}
};
}
else if(creatureCasting) //if creature can't cast on dest tile, we act as if it were not a caster
{
goto pastCastingSpells;
}
else
{
cursorFrame = ECursor::COMBAT_BLOCKED;
consoleMsg = CGI->generaltexth->allTexts[23];
illegalAction = INVALID; //we should never be here
}
//consume our settings and do not look further
realizeThingsToDo();
return;
}
bool isCastingPossible = false;
pastCastingSpells:
if(!vstd::contains(occupyableHexes, myNumber) || activeStack->coversPos(myNumber))
if (currentAction > INVALID)
{
if(shere)
{
bool ourStack = shere->owner == curInt->playerID;
if(ourStack) //our stack
{
if (shere->alive())
{
if(tacticsMode) //select stack in tactics mdoe
switch (currentAction) //display console message, realize selected action
{
case CHOOSE_TACTICS_STACK:
consoleMsg = (boost::format(CGI->generaltexth->allTexts[481]) % shere->getName()).str(); //Select %s
realizeAction = [=]{ stackActivated(shere); };
}
else if(sactive->hasBonusOfType(Bonus::HEALER) && shere->canBeHealed()) //heal
{
cursorFrame = ECursor::COMBAT_HEAL;
consoleMsg = (boost::format(CGI->generaltexth->allTexts[419]) % shere->getName()).str(); //Apply first aid to the %s
realizeAction = [=]{ giveCommand(BattleAction::STACK_HEAL, myNumber, activeStack->ID); }; //command healing
}
else //info about creature
{
cursorFrame = ECursor::COMBAT_QUERY;
consoleMsg = (boost::format(CGI->generaltexth->allTexts[297]) % shere->getName()).str();
realizeAction = [=]{ GH.pushInt(createCreWindow(shere, true)); };
}
//setting console text
const time_t curTime = time(NULL);
CCreatureAnimation *hoveredStackAnim = creAnims[shere->ID];
if (shere->ID != mouseHoveredStack
&& curTime > lastMouseHoveredStackAnimationTime + HOVER_ANIM_DELTA
&& hoveredStackAnim->getType() == CCreatureAnim::HOLDING
&& hoveredStackAnim->framesInGroup(CCreatureAnim::MOUSEON) > 0)
{
hoveredStackAnim->playOnce(CCreatureAnim::MOUSEON);
lastMouseHoveredStackAnimationTime = curTime;
}
noStackIsHovered = false;
mouseHoveredStack = shere->ID;
} //end of alive
else if (sactive->hasBonusOfType(Bonus::DAEMON_SUMMONING) && sactive->casts)
{
cursorType = ECursor::SPELLBOOK;
realizeAction = [=]{ giveCommand(BattleAction::DAEMON_SUMMONING, myNumber, activeStack->ID); };
}
}
//end of our stack hovered
else if(curInt->cb->battleCanShoot(activeStack,myNumber)) //we can shoot enemy
{
if(curInt->cb->battleHasShootingPenalty(activeStack, myNumber))
cursorFrame = ECursor::COMBAT_SHOOT_PENALTY;
else
cursorFrame = ECursor::COMBAT_SHOOT;
realizeAction = [=] {giveCommand(BattleAction::SHOOT, myNumber, activeStack->ID);};
std::string estDmgText = formatDmgRange(curInt->cb->battleEstimateDamage(sactive, shere)); //calculating estimated dmg
//printing - Shoot %s (%d shots left, %s damage)
consoleMsg = (boost::format(CGI->generaltexth->allTexts[296]) % shere->getName() % sactive->shots % estDmgText).str();
}
else if (shere->alive() && isTileAttackable(myNumber)) //available enemy (melee attackable)
{
setBattleCursor(myNumber); //handle direction of cursor and attackable tile
setCursor = false; //don't overwrite settings from the call above
realizeAction = [=]
{
BattleHex attackFromHex = fromWhichHexAttack(myNumber);
if(attackFromHex >= 0) //we can be in this line when unreachable creature is L - clicked (as of revision 1308)
{
giveCommand(BattleAction::WALK_AND_ATTACK, attackFromHex, activeStack->ID, myNumber);
}
};
std::string estDmgText = formatDmgRange(curInt->cb->battleEstimateDamage(sactive, shere)); //calculating estimated dmg
consoleMsg = (boost::format(CGI->generaltexth->allTexts[36]) % shere->getName() % estDmgText).str(); //Attack %s (%s damage)
}
else //unavailable enemy
{
cursorFrame = ECursor::COMBAT_BLOCKED;
}
} //end of stack on dest
else if (sactive && sactive->hasBonusOfType(Bonus::CATAPULT) && isCatapultAttackable(myNumber)) //"catapulting"
{
cursorFrame = ECursor::COMBAT_SHOOT_CATAPULT;
realizeAction = [=]{ giveCommand(BattleAction::CATAPULT, myNumber, activeStack->ID); };
}
else //empty unavailable tile
{
cursorFrame = ECursor::COMBAT_BLOCKED;
}
}
else //occuppiable tile
{
if (activeStack) //there can be a moment when stack is dead ut next is not yet activated
{
break;
case MOVE:
if(activeStack->hasBonusOfType(Bonus::FLYING))
{
cursorFrame = ECursor::COMBAT_FLY;
@ -2873,19 +2786,178 @@ pastCastingSpells:
giveCommand(BattleAction::WALK, myNumber, activeStack->ID);
}
};
break;
case ATTACK:
case WALK_AND_ATTACK:
case ATTACK_AND_RETURN: //TODO: allow to disable return
{
setBattleCursor(myNumber); //handle direction of cursor and attackable tile
setCursor = false; //don't overwrite settings from the call above
realizeAction = [=]
{
BattleHex attackFromHex = fromWhichHexAttack(myNumber);
if(attackFromHex >= 0) //we can be in this line when unreachable creature is L - clicked (as of revision 1308)
{
giveCommand(BattleAction::WALK_AND_ATTACK, attackFromHex, activeStack->ID, myNumber);
}
};
std::string estDmgText = formatDmgRange(curInt->cb->battleEstimateDamage(sactive, shere)); //calculating estimated dmg
consoleMsg = (boost::format(CGI->generaltexth->allTexts[36]) % shere->getName() % estDmgText).str(); //Attack %s (%s damage)
}
break;
case SHOOT:
{
if(curInt->cb->battleHasShootingPenalty(activeStack, myNumber))
cursorFrame = ECursor::COMBAT_SHOOT_PENALTY;
else
cursorFrame = ECursor::COMBAT_SHOOT;
realizeAction = [=] {giveCommand(BattleAction::SHOOT, myNumber, activeStack->ID);};
std::string estDmgText = formatDmgRange(curInt->cb->battleEstimateDamage(sactive, shere)); //calculating estimated dmg
//printing - Shoot %s (%d shots left, %s damage)
consoleMsg = (boost::format(CGI->generaltexth->allTexts[296]) % shere->getName() % sactive->shots % estDmgText).str();
}
break;
case HOSTILE_CREATURE:
case FRIENDLY_CREATURE:
case RISING_SPELL:
case RANDOM_GENIE_SPELL:
if (spellToCast) //TODO: merge hero spell and creature spell into it
consoleMsg = boost::str(boost::format(CGI->generaltexth->allTexts[27]) % sp->name % shere->getName()); //Cast %s on %s
else
consoleMsg = boost::str(boost::format(CGI->generaltexth->allTexts[301]) % shere->getName()); //Cast a spell on %s
isCastingPossible = true;
//TODO: refactor -> include Teleport and Remove Obstacle
break;
case TELEPORT:
consoleMsg = CGI->generaltexth->allTexts[25]; //Teleport Here
isCastingPossible = true;
break;
case OBSTACLE:
consoleMsg = CGI->generaltexth->allTexts[550];
isCastingPossible = true;
break;
case OTHER_SPELL:
break;
case HEAL:
cursorFrame = ECursor::COMBAT_HEAL;
consoleMsg = (boost::format(CGI->generaltexth->allTexts[419]) % shere->getName()).str(); //Apply first aid to the %s
realizeAction = [=]{ giveCommand(BattleAction::STACK_HEAL, myNumber, activeStack->ID); }; //command healing
break;
case RISE_DEMONS:
cursorType = ECursor::SPELLBOOK;
realizeAction = [=]{ giveCommand(BattleAction::DAEMON_SUMMONING, myNumber, activeStack->ID); };
break;
case CATAPULT:
cursorFrame = ECursor::COMBAT_SHOOT_CATAPULT;
realizeAction = [=]{ giveCommand(BattleAction::CATAPULT, myNumber, activeStack->ID); };
break;
}
}
else
{
switch (illegalAction)
{
case HOSTILE_CREATURE:
case FRIENDLY_CREATURE:
case RISING_SPELL:
case RANDOM_GENIE_SPELL:
cursorFrame = ECursor::COMBAT_BLOCKED;
consoleMsg = CGI->generaltexth->allTexts[23];
break;
case TELEPORT:
consoleMsg = CGI->generaltexth->allTexts[24]; //Invalid Teleport Destination
break;
default:
cursorFrame = ECursor::COMBAT_BLOCKED;
break;
}
}
if (vstd::contains(localActions, selectedAction))
currentAction = selectedAction;
else if (localActions.size())
currentAction = localActions.front();
if (isCastingPossible) //common part
{
cursorType = ECursor::SPELLBOOK;
cursorFrame = 0;
if(consoleMsg.empty() && sp)
consoleMsg = boost::str(boost::format(CGI->generaltexth->allTexts[26]) % sp->name); //Cast %s
realizeAction = [=]
{
if(creatureCasting)
{
giveCommand(BattleAction::MONSTER_SPELL, myNumber, sactive->ID, creatureSpellToCast);
}
else
currentAction = INVALID;
{
spellToCast->destinationTile = myNumber;
curInt->cb->battleMakeAction(spellToCast);
endCastingSpell();
}
};
}
realizeThingsToDo();
if(noStackIsHovered)
mouseHoveredStack = -1;
if (shere && ourStack && shere->alive()) //TODO: handle hover properly
{
cursorFrame = ECursor::COMBAT_QUERY;
consoleMsg = (boost::format(CGI->generaltexth->allTexts[297]) % shere->getName()).str();
realizeAction = [=]{ GH.pushInt(createCreWindow(shere, true)); };
//setting console text
const time_t curTime = time(NULL);
CCreatureAnimation *hoveredStackAnim = creAnims[shere->ID];
if (shere->ID != mouseHoveredStack
&& curTime > lastMouseHoveredStackAnimationTime + HOVER_ANIM_DELTA
&& hoveredStackAnim->getType() == CCreatureAnim::HOLDING
&& hoveredStackAnim->framesInGroup(CCreatureAnim::MOUSEON) > 0)
{
hoveredStackAnim->playOnce(CCreatureAnim::MOUSEON);
lastMouseHoveredStackAnimationTime = curTime;
}
noStackIsHovered = false;
mouseHoveredStack = shere->ID;
}
}
bool CBattleInterface::isCastingPossibleHere (const CStack * sactive, const CStack * shere, BattleHex myNumber)
{
creatureCasting = (spellDestSelectMode >= NO_LOCATION && spellDestSelectMode <= OTHER_SPELL) && //what does it really check?
stackCanCastSpell && shere != sactive;
//TODO: use currentAction
bool isCastingPossible = true;
int spellID = -1;
if (creatureCasting)
{
if (creatureSpellToCast > -1)
spellID = creatureSpellToCast;
}
else if(spellDestSelectMode) //hero casting
spellID = spellToCast->additionalInfo;
sp = NULL;
if (spellID >= 0)
sp = CGI->spellh->spells[spellID];
if (sp) //TODO: refactor?
{
if (creatureCasting)
isCastingPossible = (curInt->cb->battleCanCreatureCastThisSpell (sp, myNumber) == ESpellCastProblem::OK);
else
isCastingPossible = (curInt->cb->battleCanCastThisSpell (sp, myNumber) == ESpellCastProblem::OK);
}
if(!myNumber.isAvailable() && !shere) //empty tile outside battlefield (or in the unavailable border column)
isCastingPossible = false;
return isCastingPossible;
}
BattleHex CBattleInterface::fromWhichHexAttack(BattleHex myNumber)

View File

@ -91,16 +91,12 @@ struct CatapultProjectileInfo
/// drawing everything correctly.
class CBattleInterface : public CIntObject
{
enum SpellSelectionType
{
ANY_LOCATION = 0, FRIENDLY_CREATURE, HOSTILE_CREATURE, ANY_CREATURE, OBSTACLE, TELEPORT, NO_LOCATION = -1, STACK_SPELL_CANCELLED = -2
};
enum PossibleActions // actions performed at l-click
{
INVALID = -1,
MOVE_TACTICS, CHOOSE_TACTICS_STACK,
MOVE_STACK, ATTACK, WALK_AND_ATTACK, ATTACK_AND_RETURN, SHOOT, //OPEN_GATE, //we can open castle gate during siege
OFFENSIVE_SPELL, FRIENDLY_SPELL, RISING_SPELL, RANDOM_GENIE_SPELL, OTHER_SPELL, //use SpellSelectionType for non-standard spells - should we merge it?
NO_LOCATION, ANY_LOCATION, FRIENDLY_CREATURE, HOSTILE_CREATURE, RISING_SPELL, ANY_CREATURE, OBSTACLE, TELEPORT, SACRIFICE, RANDOM_GENIE_SPELL, OTHER_SPELL,
CATAPULT, HEAL, RISE_DEMONS
};
private:
@ -135,14 +131,18 @@ private:
CPlayerInterface * tacticianInterface; //used during tactics mode, points to the interface of player with higher tactics (can be either attacker or defender in hot-seat), valid onloy for human players
bool tacticsMode;
bool stackCanCastSpell; //if true, active stack could possibly cats some target spell
bool creatureCasting; //if true, stack currently aims to cats a spell
bool spellDestSelectMode; //if true, player is choosing destination for his spell
SpellSelectionType spellSelMode;
PossibleActions spellSelMode;
BattleAction * spellToCast; //spell for which player is choosing destination
const CSpell * sp; //spell pointer for convenience
si32 creatureSpellToCast;
std::vector<int> possibleActions; //all actions possible to call at the moment by player
std::vector<int> localActions; //actions possible to take on hovered hex
int currentAction; //action that will be performed on l-click
int selectedAction; //last action chosen (and saved) by player
std::vector<PossibleActions> possibleActions; //all actions possible to call at the moment by player
std::vector<PossibleActions> localActions; //actions possible to take on hovered hex
std::vector<PossibleActions> illegalActions; //these actions display message in case of illegal target
PossibleActions currentAction; //action that will be performed on l-click
PossibleActions selectedAction; //last action chosen (and saved) by player
PossibleActions illegalAction; //most likely action that can't be performed here
void getPossibleActionsForStack (const CStack * stack); //called when stack gets its turn
void endCastingSpell(); //ends casting spell (eg. when spell has been cast or canceled)
@ -260,9 +260,10 @@ public:
void endAction(const BattleAction* action);
void hideQueue();
void showQueue();
SpellSelectionType selectionTypeByPositiveness(const CSpell & spell);
PossibleActions selectionTypeByPositiveness(const CSpell & spell);
void handleHex(BattleHex myNumber, int eventType);
bool isCastingPossibleHere (const CStack * sactive, const CStack * shere, BattleHex myNumber);
BattleHex fromWhichHexAttack(BattleHex myNumber);