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:
parent
66f5b5e2d7
commit
aeb9cf9460
@ -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:
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user