1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-28 23:06:24 +02:00

CStack refactoring

* removed all occurrences of attackerOwned
* Use BattleSide enum
* more tweaks
This commit is contained in:
AlexVinS 2017-07-01 11:34:00 +03:00
parent 29e50cc21c
commit 4f8c7bd4bb
31 changed files with 304 additions and 273 deletions

View File

@ -24,7 +24,7 @@ struct CurrentOffensivePotential
{
for(auto stack : cbc->battleGetStacks())
{
if(stack->attackerOwned == !side)
if(stack->side == side)
ourAttacks[stack] = PotentialTargets(stack);
else
enemyAttacks[stack] = PotentialTargets(stack);

View File

@ -18,7 +18,7 @@ PotentialTargets::PotentialTargets(const CStack *attacker, const HypotheticChang
for(const CStack *enemy : getCbc()->battleGetStacks())
{
//Consider only stacks of different owner
if(enemy->attackerOwned == attacker->attackerOwned)
if(enemy->side == attacker->side)
continue;
auto GenerateAttackInfo = [&](bool shooting, BattleHex hex) -> AttackPossibility

View File

@ -31,7 +31,7 @@ ThreatMap::ThreatMap(const CStack *Endangered) : endangered(Endangered)
for(const CStack *enemy : getCbc()->battleGetStacks())
{
//Consider only stacks of different owner
if(enemy->attackerOwned == endangered->attackerOwned)
if(enemy->side == endangered->side)
continue;
//Look-up which tiles can be melee-attacked

View File

@ -855,7 +855,7 @@ void CClient::commenceTacticPhaseForInt(std::shared_ptr<CBattleGameInterface> ba
battleInt->yourTacticPhase(gs->curB->tacticDistance);
if(gs && !!gs->curB && gs->curB->tacticDistance) //while awaiting for end of tactics phase, many things can happen (end of battle... or game)
{
MakeAction ma(BattleAction::makeEndOFTacticPhase(gs->curB->playerToSide(battleInt->playerID)));
MakeAction ma(BattleAction::makeEndOFTacticPhase(gs->curB->playerToSide(battleInt->playerID).get()));
sendRequest(&ma, battleInt->playerID);
}
}

View File

@ -338,7 +338,7 @@ bool CMeleeAttackAnimation::init()
static const CCreatureAnim::EAnimType mutPosToGroup[] = {CCreatureAnim::ATTACK_UP, CCreatureAnim::ATTACK_UP,
CCreatureAnim::ATTACK_FRONT, CCreatureAnim::ATTACK_DOWN, CCreatureAnim::ATTACK_DOWN, CCreatureAnim::ATTACK_FRONT};
int revShiftattacker = (attackingStack->attackerOwned ? -1 : 1);
int revShiftattacker = (attackingStack->side == BattleSide::ATTACKER ? -1 : 1);
int mutPos = BattleHex::mutualPosition(attackingStackPosBeforeReturn, dest);
if(mutPos == -1 && attackingStack->doubleWide())
@ -988,7 +988,7 @@ bool CSpellEffectAnimation::init()
// Correction for 2-hex creatures.
if (destStack != nullptr && destStack->doubleWide())
be.x += (destStack->attackerOwned ? -1 : 1)*tilePos.w/2;
be.x += (destStack->side == BattleSide::ATTACKER ? -1 : 1)*tilePos.w/2;
//Indicate if effect should be drawn on top of everything or just on top of the hex
be.position = destTile;

View File

@ -949,7 +949,7 @@ void CBattleInterface::bConsoleDownf()
void CBattleInterface::newStack(const CStack *stack)
{
creDir[stack->ID] = stack->attackerOwned; // must be set before getting stack position
creDir[stack->ID] = stack->side == BattleSide::ATTACKER; // must be set before getting stack position
Point coords = CClickableHex::getXYUnitAnim(stack->position, stack, this);
@ -1180,15 +1180,15 @@ bool CBattleInterface::isCatapultAttackable(BattleHex hex) const
return state != EWallState::DESTROYED && state != EWallState::NONE;
}
const CGHeroInstance *CBattleInterface::getActiveHero()
const CGHeroInstance * CBattleInterface::getActiveHero()
{
const CStack *attacker = activeStack;
if (!attacker)
if(!attacker)
{
return nullptr;
}
if (attacker->attackerOwned)
if(attacker->side == BattleSide::ATTACKER)
{
return attackingHeroInstance;
}
@ -1801,7 +1801,7 @@ void CBattleInterface::endAction(const BattleAction* action)
for (const CStack *s : stacks)
{
if (s && creDir[s->ID] != bool(s->attackerOwned) && s->alive()
if (s && creDir[s->ID] != (s->side == BattleSide::ATTACKER) && s->alive()
&& creAnims[s->ID]->isIdle())
{
addNewAnim(new CReverseAnimation(this, s, s->position, false));
@ -2033,10 +2033,10 @@ std::string formatDmgRange(std::pair<ui32, ui32> dmgRange)
return (boost::format("%d") % dmgRange.first).str();
}
bool CBattleInterface::canStackMoveHere (const CStack *activeStack, BattleHex myNumber)
bool CBattleInterface::canStackMoveHere(const CStack * activeStack, BattleHex myNumber)
{
std::vector<BattleHex> acc = curInt->cb->battleGetAvailableHexes (activeStack, false);
int shiftedDest = myNumber + (activeStack->attackerOwned ? 1 : -1);
BattleHex shiftedDest = myNumber + activeStack->destShiftDir();
if (vstd::contains(acc, myNumber))
return true;
@ -2262,14 +2262,14 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
realizeAction = [=]
{
if (activeStack->doubleWide())
if(activeStack->doubleWide())
{
std::vector<BattleHex> acc = curInt->cb->battleGetAvailableHexes(activeStack, false);
int shiftedDest = myNumber + (activeStack->attackerOwned ? 1 : -1);
if (vstd::contains(acc, myNumber))
giveCommand (Battle::WALK ,myNumber, activeStack->ID);
else if (vstd::contains(acc, shiftedDest))
giveCommand (Battle::WALK, shiftedDest, activeStack->ID);
BattleHex shiftedDest = myNumber + activeStack->destShiftDir();
if(vstd::contains(acc, myNumber))
giveCommand(Battle::WALK, myNumber, activeStack->ID);
else if(vstd::contains(acc, shiftedDest))
giveCommand(Battle::WALK, shiftedDest, activeStack->ID);
}
else
{
@ -2547,17 +2547,17 @@ BattleHex CBattleInterface::fromWhichHexAttack(BattleHex myNumber)
{
bool doubleWide = activeStack->doubleWide();
destHex = myNumber + ( (myNumber/GameConstants::BFIELD_WIDTH)%2 ? GameConstants::BFIELD_WIDTH : GameConstants::BFIELD_WIDTH+1 ) +
(activeStack->attackerOwned && doubleWide ? 1 : 0);
if (vstd::contains(occupyableHexes, destHex))
(activeStack->side == BattleSide::ATTACKER && doubleWide ? 1 : 0);
if(vstd::contains(occupyableHexes, destHex))
return destHex;
else if (activeStack->attackerOwned) //if we are attacker
else if(activeStack->side == BattleSide::ATTACKER)
{
if (vstd::contains(occupyableHexes, destHex+1))
return destHex+1;
}
else //if we are defender
{
if (vstd::contains(occupyableHexes, destHex-1))
if(vstd::contains(occupyableHexes, destHex-1))
return destHex-1;
}
break;
@ -2567,21 +2567,21 @@ BattleHex CBattleInterface::fromWhichHexAttack(BattleHex myNumber)
destHex = myNumber + ( (myNumber/GameConstants::BFIELD_WIDTH)%2 ? GameConstants::BFIELD_WIDTH-1 : GameConstants::BFIELD_WIDTH );
if (vstd::contains(occupyableHexes, destHex))
return destHex;
else if (activeStack->attackerOwned) //if we are attacker
else if(activeStack->side == BattleSide::ATTACKER)
{
if (vstd::contains(occupyableHexes, destHex+1))
if(vstd::contains(occupyableHexes, destHex+1))
return destHex+1;
}
else //if we are defender
else //we are defender
{
if (vstd::contains(occupyableHexes, destHex-1))
if(vstd::contains(occupyableHexes, destHex-1))
return destHex-1;
}
break;
}
case 8: //from left
{
if (activeStack->doubleWide() && !activeStack->attackerOwned)
if(activeStack->doubleWide() && activeStack->side == activeStack->side == BattleSide::DEFENDER)
{
std::vector<BattleHex> acc = curInt->cb->battleGetAvailableHexes(activeStack, false);
if (vstd::contains(acc, myNumber))
@ -2597,17 +2597,17 @@ BattleHex CBattleInterface::fromWhichHexAttack(BattleHex myNumber)
}
case 9: //from top left
{
destHex = myNumber - ( (myNumber/GameConstants::BFIELD_WIDTH)%2 ? GameConstants::BFIELD_WIDTH+1 : GameConstants::BFIELD_WIDTH );
if (vstd::contains(occupyableHexes, destHex))
destHex = myNumber - ((myNumber/GameConstants::BFIELD_WIDTH) % 2 ? GameConstants::BFIELD_WIDTH + 1 : GameConstants::BFIELD_WIDTH);
if(vstd::contains(occupyableHexes, destHex))
return destHex;
else if (activeStack->attackerOwned) //if we are attacker
else if(activeStack->side == BattleSide::ATTACKER)
{
if (vstd::contains(occupyableHexes, destHex+1))
if(vstd::contains(occupyableHexes, destHex+1))
return destHex+1;
}
else //if we are defender
{
if (vstd::contains(occupyableHexes, destHex-1))
if(vstd::contains(occupyableHexes, destHex-1))
return destHex-1;
}
break;
@ -2616,27 +2616,27 @@ BattleHex CBattleInterface::fromWhichHexAttack(BattleHex myNumber)
{
bool doubleWide = activeStack->doubleWide();
destHex = myNumber - ( (myNumber/GameConstants::BFIELD_WIDTH)%2 ? GameConstants::BFIELD_WIDTH : GameConstants::BFIELD_WIDTH-1 ) +
(activeStack->attackerOwned && doubleWide ? 1 : 0);
if (vstd::contains(occupyableHexes, destHex))
(activeStack->side == BattleSide::ATTACKER && doubleWide ? 1 : 0);
if(vstd::contains(occupyableHexes, destHex))
return destHex;
else if (activeStack->attackerOwned) //if we are attacker
else if(activeStack->side == BattleSide::ATTACKER)
{
if (vstd::contains(occupyableHexes, destHex+1))
if(vstd::contains(occupyableHexes, destHex+1))
return destHex+1;
}
else //if we are defender
{
if (vstd::contains(occupyableHexes, destHex-1))
if(vstd::contains(occupyableHexes, destHex-1))
return destHex-1;
}
break;
}
case 11: //from right
{
if (activeStack->doubleWide() && activeStack->attackerOwned)
if(activeStack->doubleWide() && activeStack->side == BattleSide::ATTACKER)
{
std::vector<BattleHex> acc = curInt->cb->battleGetAvailableHexes(activeStack, false);
if (vstd::contains(acc, myNumber))
if(vstd::contains(acc, myNumber))
return myNumber + 1;
else
return myNumber + 2;
@ -2650,16 +2650,16 @@ BattleHex CBattleInterface::fromWhichHexAttack(BattleHex myNumber)
case 13: //from bottom
{
destHex = myNumber + ( (myNumber/GameConstants::BFIELD_WIDTH)%2 ? GameConstants::BFIELD_WIDTH : GameConstants::BFIELD_WIDTH+1 );
if (vstd::contains(occupyableHexes, destHex))
if(vstd::contains(occupyableHexes, destHex))
return destHex;
else if (attackingHeroInstance->tempOwner == curInt->cb->getMyColor()) //if we are attacker
else if(activeStack->side == BattleSide::ATTACKER)
{
if (vstd::contains(occupyableHexes, destHex+1))
if(vstd::contains(occupyableHexes, destHex+1))
return destHex+1;
}
else //if we are defender
{
if (vstd::contains(occupyableHexes, destHex-1))
if(vstd::contains(occupyableHexes, destHex-1))
return destHex-1;
}
break;
@ -2669,14 +2669,14 @@ BattleHex CBattleInterface::fromWhichHexAttack(BattleHex myNumber)
destHex = myNumber - ( (myNumber/GameConstants::BFIELD_WIDTH)%2 ? GameConstants::BFIELD_WIDTH : GameConstants::BFIELD_WIDTH-1 );
if (vstd::contains(occupyableHexes, destHex))
return destHex;
else if (attackingHeroInstance->tempOwner == curInt->cb->getMyColor()) //if we are attacker
else if(activeStack->side == BattleSide::ATTACKER)
{
if (vstd::contains(occupyableHexes, destHex+1))
if(vstd::contains(occupyableHexes, destHex+1))
return destHex+1;
}
else //if we are defender
{
if (vstd::contains(occupyableHexes, destHex-1))
if(vstd::contains(occupyableHexes, destHex-1))
return destHex-1;
}
break;
@ -3082,52 +3082,52 @@ void CBattleInterface::showAbsoluteObstacles(SDL_Surface *to)
void CBattleInterface::showHighlightedHexes(SDL_Surface *to)
{
for (int b=0; b<GameConstants::BFIELD_SIZE; ++b)
for(int b=0; b<GameConstants::BFIELD_SIZE; ++b)
{
if (bfield[b]->strictHovered && bfield[b]->hovered)
if(bfield[b]->strictHovered && bfield[b]->hovered)
{
if (previouslyHoveredHex == -1)
if(previouslyHoveredHex == -1)
previouslyHoveredHex = b; //something to start with
if (currentlyHoveredHex == -1)
if(currentlyHoveredHex == -1)
currentlyHoveredHex = b; //something to start with
if (currentlyHoveredHex != b) //repair hover info
if(currentlyHoveredHex != b) //repair hover info
{
previouslyHoveredHex = currentlyHoveredHex;
currentlyHoveredHex = b;
}
if (settings["battle"]["mouseShadow"].Bool())
if(settings["battle"]["mouseShadow"].Bool())
{
const ISpellCaster *caster = nullptr;
const CSpell *spell = nullptr;
if (spellToCast)//hero casts spell
if(spellToCast)//hero casts spell
{
spell = SpellID(spellToCast->additionalInfo).toSpell();
caster = activeStack->attackerOwned ? attackingHeroInstance : defendingHeroInstance;
caster = activeStack->side == BattleSide::ATTACKER ? attackingHeroInstance : defendingHeroInstance;
}
else if (creatureSpellToCast >= 0 && stackCanCastSpell && creatureCasting)//stack casts spell
else if(creatureSpellToCast >= 0 && stackCanCastSpell && creatureCasting)//stack casts spell
{
spell = SpellID(creatureSpellToCast).toSpell();
caster = activeStack;
}
if (caster && spell) //when casting spell
if(caster && spell) //when casting spell
{
//calculating spell school level
ui8 schoolLevel = caster->getSpellSchoolLevel(spell);
// printing shaded hex(es)
auto shaded = spell->rangeInHexes(currentlyHoveredHex, schoolLevel, curInt->cb->battleGetMySide());
for (BattleHex shadedHex : shaded)
for(BattleHex shadedHex : shaded)
{
if ((shadedHex.getX() != 0) && (shadedHex.getX() != GameConstants::BFIELD_WIDTH -1))
if((shadedHex.getX() != 0) && (shadedHex.getX() != GameConstants::BFIELD_WIDTH - 1))
showHighlightedHex(to, shadedHex);
}
}
else if (active)//always highlight pointed hex
else if(active)//always highlight pointed hex
{
if (currentlyHoveredHex.getX() != 0
if(currentlyHoveredHex.getX() != 0
&& currentlyHoveredHex.getX() != GameConstants::BFIELD_WIDTH - 1)
showHighlightedHex(to, currentlyHoveredHex);
}
@ -3135,18 +3135,18 @@ void CBattleInterface::showHighlightedHexes(SDL_Surface *to)
}
}
if (activeStack && settings["battle"]["stackRange"].Bool())
if(activeStack && settings["battle"]["stackRange"].Bool())
{
std::set<BattleHex> set = curInt->cb->battleGetAttackedHexes(activeStack, currentlyHoveredHex, attackingHex);
for (BattleHex hex : set)
for(BattleHex hex : set)
showHighlightedHex(to, hex);
// display the movement shadow of the stack at b (i.e. stack under mouse)
const CStack *const shere = curInt->cb->battleGetStackByPos(currentlyHoveredHex, false);
if (shere && shere != activeStack && shere->alive())
const CStack * const shere = curInt->cb->battleGetStackByPos(currentlyHoveredHex, false);
if(shere && shere != activeStack && shere->alive())
{
std::vector<BattleHex> v = curInt->cb->battleGetAvailableHexes(shere, true );
for (BattleHex hex : v)
for(BattleHex hex : v)
showHighlightedHex(to, hex);
}
}
@ -3321,13 +3321,15 @@ void CBattleInterface::showAliveStacks(SDL_Surface *to, std::vector<const CStack
//printing amount
if (isAmountBoxVisible(stack))
{
const BattleHex nextPos = stack->position + (stack->attackerOwned ? 1 : -1);
const bool edge = stack->position % GameConstants::BFIELD_WIDTH == (stack->attackerOwned ? GameConstants::BFIELD_WIDTH - 2 : 1);
const int sideShift = stack->side == BattleSide::ATTACKER ? 1 : -1;
const int reverseSideShift = stack->side == BattleSide::ATTACKER ? -1 : 1;
const BattleHex nextPos = stack->position + sideShift;
const bool edge = stack->position % GameConstants::BFIELD_WIDTH == (stack->side == BattleSide::ATTACKER ? GameConstants::BFIELD_WIDTH - 2 : 1);
const bool moveInside = !edge && !stackCountOutsideHexes[nextPos];
int xAdd = (stack->attackerOwned ? 220 : 202) +
(stack->doubleWide() ? 44 : 0) *(stack->attackerOwned ? +1 : -1) +
(moveInside ? amountNormal->w + 10 : 0) *(stack->attackerOwned ? -1 : +1);
int yAdd = 260 + ((stack->attackerOwned || moveInside) ? 0 : -15);
int xAdd = (stack->side == BattleSide::ATTACKER ? 220 : 202) +
(stack->doubleWide() ? 44 : 0) * sideShift +
(moveInside ? amountNormal->w + 10 : 0) * reverseSideShift;
int yAdd = 260 + ((stack->side == BattleSide::ATTACKER || moveInside) ? 0 : -15);
//blitting amount background box
SDL_Surface *amountBG = amountNormal;

View File

@ -384,7 +384,7 @@ CBattleResultWindow::CBattleResultWindow(const BattleResult &br, const SDL_Rect
{
auto stacks = owner.cb->battleGetAllStacks();
vstd::erase_if(stacks, [i](const CStack *stack) //erase stack of other side and not coming from garrison
{ return stack->attackerOwned == i || !stack->base; });
{ return stack->side != i || !stack->base; });
auto best = vstd::maxElementByFun(stacks, [](const CStack *stack){ return stack->type->AIValue; });
if(best != stacks.end()) //should be always but to be safe...
@ -548,7 +548,7 @@ Point CClickableHex::getXYUnitAnim(BattleHex hexNum, const CStack * stack, CBatt
//shifting position for double - hex creatures
if(stack->doubleWide())
{
if(stack->attackerOwned)
if(stack->side == BattleSide::ATTACKER)
{
if(cbi->creDir[stack->ID])
ret.x -= 44;

View File

@ -15,8 +15,8 @@
#include "NetPacks.h"
CStack::CStack(const CStackInstance *Base, PlayerColor O, int I, bool AO, SlotID S)
: base(Base), ID(I), owner(O), slot(S), attackerOwned(AO),
CStack::CStack(const CStackInstance *Base, PlayerColor O, int I, ui8 Side, SlotID S)
: base(Base), ID(I), owner(O), slot(S), side(Side),
counterAttacksPerformed(0),counterAttacksTotalCache(0), cloneID(-1),
firstHPleft(-1), position(), shots(0), casts(0), resurrected(0)
{
@ -30,8 +30,8 @@ CStack::CStack()
init();
setNodeType(STACK_BATTLE);
}
CStack::CStack(const CStackBasicDescriptor *stack, PlayerColor O, int I, bool AO, SlotID S)
: base(nullptr), ID(I), owner(O), slot(S), attackerOwned(AO),
CStack::CStack(const CStackBasicDescriptor *stack, PlayerColor O, int I, ui8 Side, SlotID S)
: base(nullptr), ID(I), owner(O), slot(S), side(Side),
counterAttacksPerformed(0), counterAttacksTotalCache(0), cloneID(-1),
firstHPleft(-1), position(), shots(0), casts(0), resurrected(0)
{
@ -49,7 +49,7 @@ void CStack::init()
firstHPleft = -1;
owner = PlayerColor::NEUTRAL;
slot = SlotID(255);
attackerOwned = false;
side = 1;
position = BattleHex();
counterAttacksPerformed = 0;
counterAttacksTotalCache = 0;
@ -145,9 +145,9 @@ BattleHex CStack::occupiedHex() const
BattleHex CStack::occupiedHex(BattleHex assumedPos) const
{
if (doubleWide())
if(doubleWide())
{
if (attackerOwned)
if(side == BattleSide::ATTACKER)
return assumedPos - 1;
else
return assumedPos + 1;
@ -165,17 +165,17 @@ std::vector<BattleHex> CStack::getHexes() const
std::vector<BattleHex> CStack::getHexes(BattleHex assumedPos) const
{
return getHexes(assumedPos, doubleWide(), attackerOwned);
return getHexes(assumedPos, doubleWide(), side);
}
std::vector<BattleHex> CStack::getHexes(BattleHex assumedPos, bool twoHex, bool AttackerOwned)
std::vector<BattleHex> CStack::getHexes(BattleHex assumedPos, bool twoHex, ui8 side)
{
std::vector<BattleHex> hexes;
hexes.push_back(assumedPos);
if (twoHex)
if(twoHex)
{
if (AttackerOwned)
if(side == BattleSide::ATTACKER)
hexes.push_back(assumedPos - 1);
else
hexes.push_back(assumedPos + 1);
@ -193,10 +193,10 @@ std::vector<BattleHex> CStack::getSurroundingHexes(BattleHex attackerPos) const
{
BattleHex hex = (attackerPos != BattleHex::INVALID) ? attackerPos : position; //use hypothetical position
std::vector<BattleHex> hexes;
if (doubleWide())
if(doubleWide())
{
const int WN = GameConstants::BFIELD_WIDTH;
if(attackerOwned)
if(side == BattleSide::ATTACKER)
{ //position is equal to front hex
BattleHex::checkAndPush(hex - ( (hex/WN)%2 ? WN+2 : WN+1 ), hexes);
BattleHex::checkAndPush(hex - ( (hex/WN)%2 ? WN+1 : WN ), hexes);
@ -226,6 +226,21 @@ std::vector<BattleHex> CStack::getSurroundingHexes(BattleHex attackerPos) const
}
}
BattleHex::EDir CStack::destShiftDir() const
{
if(doubleWide())
{
if(side == BattleSide::ATTACKER)
return BattleHex::EDir::RIGHT;
else
return BattleHex::EDir::LEFT;
}
else
{
return BattleHex::EDir::NONE;
}
}
std::vector<si32> CStack::activeSpells() const
{
std::vector<si32> ret;
@ -382,11 +397,11 @@ bool CStack::isMeleeAttackPossible(const CStack * attacker, const CStack * defen
return
(BattleHex::mutualPosition(attackerPos, defenderPos) >= 0) //front <=> front
|| (attacker->doubleWide() //back <=> front
&& BattleHex::mutualPosition(attackerPos + (attacker->attackerOwned ? -1 : 1), defenderPos) >= 0)
&& BattleHex::mutualPosition(attackerPos + (attacker->side == BattleSide::ATTACKER ? -1 : 1), defenderPos) >= 0)
|| (defender->doubleWide() //front <=> back
&& BattleHex::mutualPosition(attackerPos, defenderPos + (defender->attackerOwned ? -1 : 1)) >= 0)
&& BattleHex::mutualPosition(attackerPos, defenderPos + (defender->side == BattleSide::ATTACKER ? -1 : 1)) >= 0)
|| (defender->doubleWide() && attacker->doubleWide()//back <=> back
&& BattleHex::mutualPosition(attackerPos + (attacker->attackerOwned ? -1 : 1), defenderPos + (defender->attackerOwned ? -1 : 1)) >= 0);
&& BattleHex::mutualPosition(attackerPos + (attacker->side == BattleSide::ATTACKER ? -1 : 1), defenderPos + (defender->side == BattleSide::ATTACKER ? -1 : 1)) >= 0);
}

View File

@ -24,7 +24,7 @@ public:
ui32 firstHPleft; //HP of first creature in stack
PlayerColor owner; //owner - player colour (255 for neutrals)
SlotID slot; //slot - position in garrison (may be 255 for neutrals/called creatures)
bool attackerOwned; //if true, this stack is owned by attakcer (this one from left hand side of battle)
ui8 side;
BattleHex position; //position on battlefield; -2 - keep, -3 - lower tower, -4 - upper tower
///how many times this stack has been counterattacked this round
ui8 counterAttacksPerformed;
@ -39,8 +39,8 @@ public:
//overrides
const CCreature* getCreature() const {return type;}
CStack(const CStackInstance *base, PlayerColor O, int I, bool AO, SlotID S); //c-tor
CStack(const CStackBasicDescriptor *stack, PlayerColor O, int I, bool AO, SlotID S = SlotID(255)); //c-tor
CStack(const CStackInstance *base, PlayerColor O, int I, ui8 Side, SlotID S); //c-tor
CStack(const CStackBasicDescriptor *stack, PlayerColor O, int I, ui8 Side, SlotID S = SlotID(255)); //c-tor
CStack(); //c-tor
~CStack();
std::string nodeName() const override;
@ -73,10 +73,12 @@ public:
BattleHex occupiedHex(BattleHex assumedPos) const; //returns number of occupied hex (not the position) if stack is double wide and would stand on assumedPos; otherwise -1
std::vector<BattleHex> getHexes() const; //up to two occupied hexes, starting from front
std::vector<BattleHex> getHexes(BattleHex assumedPos) const; //up to two occupied hexes, starting from front
static std::vector<BattleHex> getHexes(BattleHex assumedPos, bool twoHex, bool AttackerOwned); //up to two occupied hexes, starting from front
static std::vector<BattleHex> getHexes(BattleHex assumedPos, bool twoHex, ui8 side); //up to two occupied hexes, starting from front
bool coversPos(BattleHex position) const; //checks also if unit is double-wide
std::vector<BattleHex> getSurroundingHexes(BattleHex attackerPos = BattleHex::INVALID) const; // get six or 8 surrounding hexes depending on creature size
BattleHex::EDir destShiftDir() const;
std::pair<int,int> countKilledByAttack(int damageReceived) const; //returns pair<killed count, new left HP>
void prepareAttacked(BattleStackAttacked &bsa, CRandomGenerator & rand, boost::optional<int> customCount = boost::none) const; //requires bsa.damageAmout filled
@ -110,7 +112,7 @@ public:
assert(isIndependentNode());
h & static_cast<CBonusSystemNode&>(*this);
h & static_cast<CStackBasicDescriptor&>(*this);
h & ID & baseAmount & firstHPleft & owner & slot & attackerOwned & position & state & counterAttacksPerformed
h & ID & baseAmount & firstHPleft & owner & slot & side & position & state & counterAttacksPerformed
& shots & casts & count & resurrected;
const CArmedInstance *army = (base ? base->armyObj : nullptr);

View File

@ -11,6 +11,7 @@
#include "battle/BattleHex.h"
#include "GameConstants.h"
#include "int3.h"
class CGTownInstance;

View File

@ -1628,13 +1628,13 @@ struct BattleStacksRemoved : public CPackForClient
struct BattleStackAdded : public CPackForClient
{
BattleStackAdded()
: attacker(0), amount(0), pos(0), summoned(0), newStackID(0)
: side(0), amount(0), pos(0), summoned(0), newStackID(0)
{};
DLL_LINKAGE void applyGs(CGameState *gs);
void applyCl(CClient *cl);
int attacker; // if true, stack belongs to attacker
ui8 side;
CreatureID creID;
int amount;
int pos;
@ -1645,7 +1645,7 @@ struct BattleStackAdded : public CPackForClient
template <typename Handler> void serialize(Handler &h, const int version)
{
h & attacker & creID & amount & pos & summoned;
h & side & creID & amount & pos & summoned;
}
};

View File

@ -1384,7 +1384,7 @@ void BattleStackMoved::applyGs(CGameState *gs)
{
SpellCreatedObstacle *sands = dynamic_cast<SpellCreatedObstacle*>(oi.get());
assert(sands);
if(sands->casterSide != !s->attackerOwned)
if(sands->casterSide != s->side)
sands->visibleForAnotherSide = true;
}
}
@ -1803,7 +1803,7 @@ DLL_LINKAGE void BattleStackAdded::applyGs(CGameState *gs)
}
CStackBasicDescriptor csbd(creID, amount);
CStack * addedStack = gs->curB->generateNewStack(csbd, attacker, SlotID::SUMMONED_SLOT_PLACEHOLDER, pos); //TODO: netpacks?
CStack * addedStack = gs->curB->generateNewStack(csbd, side, SlotID::SUMMONED_SLOT_PLACEHOLDER, pos); //TODO: netpacks?
if (summoned)
addedStack->state.insert(EBattleStackState::SUMMONED);

View File

@ -10,16 +10,17 @@
#include "../StdInc.h"
#include "AccessibilityInfo.h"
#include "../CStack.h"
#include "../GameConstants.h"
bool AccessibilityInfo::accessible(BattleHex tile, const CStack * stack) const
{
return accessible(tile, stack->doubleWide(), stack->attackerOwned);
return accessible(tile, stack->doubleWide(), stack->side);
}
bool AccessibilityInfo::accessible(BattleHex tile, bool doubleWide, bool attackerOwned) const
bool AccessibilityInfo::accessible(BattleHex tile, bool doubleWide, ui8 side) const
{
// All hexes that stack would cover if standing on tile have to be accessible.
for(auto hex : CStack::getHexes(tile, doubleWide, attackerOwned))
for(auto hex : CStack::getHexes(tile, doubleWide, side))
{
// If the hex is out of range then the tile isn't accessible
if(!hex.isValid())
@ -27,25 +28,10 @@ bool AccessibilityInfo::accessible(BattleHex tile, bool doubleWide, bool attacke
// If we're no defender which step on gate and the hex isn't accessible, then the tile
// isn't accessible
else if(at(hex) != EAccessibility::ACCESSIBLE &&
!(at(hex) == EAccessibility::GATE && !attackerOwned))
!(at(hex) == EAccessibility::GATE && side == BattleSide::DEFENDER))
{
return false;
}
}
return true;
}
bool AccessibilityInfo::occupiable(const CStack * stack, BattleHex tile) const
{
//obviously, we can occupy tile by standing on it
if(accessible(tile, stack))
return true;
if(stack->doubleWide())
{
//Check the tile next to -> if stack stands there, it'll also occupy considered hex
const BattleHex anotherTile = tile + (stack->attackerOwned ? BattleHex::RIGHT : BattleHex::LEFT);
if(accessible(anotherTile, stack))
return true;
}
return false;
}

View File

@ -9,6 +9,7 @@
*/
#pragma once
#include "BattleHex.h"
#include "../GameConstants.h"
class CStack;
@ -29,7 +30,6 @@ typedef std::array<EAccessibility, GameConstants::BFIELD_SIZE> TAccessibilityArr
struct DLL_LINKAGE AccessibilityInfo : TAccessibilityArray
{
bool occupiable(const CStack * stack, BattleHex tile) const;
bool accessible(BattleHex tile, const CStack * stack) const; //checks for both tiles if stack is double wide
bool accessible(BattleHex tile, bool doubleWide, bool attackerOwned) const; //checks for both tiles if stack is double wide
bool accessible(BattleHex tile, bool doubleWide, ui8 side) const; //checks for both tiles if stack is double wide
};

View File

@ -27,7 +27,7 @@ BattleAction::BattleAction():
BattleAction BattleAction::makeHeal(const CStack * healer, const CStack * healed)
{
BattleAction ba;
ba.side = !healer->attackerOwned;
ba.side = healer->side;
ba.actionType = STACK_HEAL;
ba.stackNumber = healer->ID;
ba.destinationTile = healed->position;
@ -37,7 +37,7 @@ BattleAction BattleAction::makeHeal(const CStack * healer, const CStack * healed
BattleAction BattleAction::makeDefend(const CStack * stack)
{
BattleAction ba;
ba.side = !stack->attackerOwned;
ba.side = stack->side;
ba.actionType = DEFEND;
ba.stackNumber = stack->ID;
return ba;
@ -47,7 +47,7 @@ BattleAction BattleAction::makeDefend(const CStack * stack)
BattleAction BattleAction::makeMeleeAttack(const CStack * stack, const CStack * attacked, BattleHex attackFrom /*= BattleHex::INVALID*/)
{
BattleAction ba;
ba.side = !stack->attackerOwned;
ba.side = stack->side;
ba.actionType = WALK_AND_ATTACK;
ba.stackNumber = stack->ID;
ba.destinationTile = attackFrom;
@ -58,7 +58,7 @@ BattleAction BattleAction::makeMeleeAttack(const CStack * stack, const CStack *
BattleAction BattleAction::makeWait(const CStack * stack)
{
BattleAction ba;
ba.side = !stack->attackerOwned;
ba.side = stack->side;
ba.actionType = WAIT;
ba.stackNumber = stack->ID;
return ba;
@ -67,7 +67,7 @@ BattleAction BattleAction::makeWait(const CStack * stack)
BattleAction BattleAction::makeShotAttack(const CStack * shooter, const CStack * target)
{
BattleAction ba;
ba.side = !shooter->attackerOwned;
ba.side = shooter->side;
ba.actionType = SHOOT;
ba.stackNumber = shooter->ID;
ba.destinationTile = target->position;
@ -77,7 +77,7 @@ BattleAction BattleAction::makeShotAttack(const CStack * shooter, const CStack *
BattleAction BattleAction::makeMove(const CStack * stack, BattleHex dest)
{
BattleAction ba;
ba.side = !stack->attackerOwned;
ba.side = stack->side;
ba.actionType = WALK;
ba.stackNumber = stack->ID;
ba.destinationTile = dest;

View File

@ -9,6 +9,7 @@
*/
#pragma once
#include "BattleHex.h"
#include "../GameConstants.h"
class CStack;

View File

@ -9,6 +9,7 @@
*/
#include "../StdInc.h"
#include "BattleHex.h"
#include "../GameConstants.h"
BattleHex::BattleHex() : hex(INVALID) {}
@ -99,6 +100,8 @@ BattleHex& BattleHex::moveInDirection(EDir dir, bool hasToBeValid)
case LEFT:
setXY(x-1, y, hasToBeValid);
break;
case NONE:
break;
default:
throw std::runtime_error("Disaster: wrong direction in BattleHex::operator+=!\n");
break;
@ -160,7 +163,7 @@ void BattleHex::checkAndPush(BattleHex tile, std::vector<BattleHex> & ret)
ret.push_back(tile);
}
BattleHex BattleHex::getClosestTile(bool attackerOwned, BattleHex initialPos, std::set<BattleHex> & possibilities)
BattleHex BattleHex::getClosestTile(ui8 side, BattleHex initialPos, std::set<BattleHex> & possibilities)
{
std::vector<BattleHex> sortedTiles (possibilities.begin(), possibilities.end()); //set can't be sorted properly :(
BattleHex initialHex = BattleHex(initialPos);
@ -175,11 +178,11 @@ BattleHex BattleHex::getClosestTile(bool attackerOwned, BattleHex initialPos, st
return closestDistance < here.getDistance (initialPos, here);
};
vstd::erase_if(sortedTiles, notClosest); //only closest tiles are interesting
auto compareHorizontal = [attackerOwned, initialPos](const BattleHex left, const BattleHex right) -> bool
auto compareHorizontal = [side, initialPos](const BattleHex left, const BattleHex right) -> bool
{
if(left.getX() != right.getX())
{
if (attackerOwned)
if(side == BattleSide::ATTACKER)
return left.getX() > right.getX(); //find furthest right
else
return left.getX() < right.getX(); //find furthest left

View File

@ -8,14 +8,35 @@
*
*/
#pragma once
#include "../GameConstants.h"
//TODO: change to enum class
namespace BattleSide
{
enum
{
ATTACKER = 0,
DEFENDER = 1
};
}
typedef boost::optional<ui8> BattleSideOpt;
// for battle stacks' positions
struct DLL_LINKAGE BattleHex //TODO: decide if this should be changed to class for better code design
{
si16 hex;
static const si16 INVALID = -1;
enum EDir { TOP_LEFT, TOP_RIGHT, RIGHT, BOTTOM_RIGHT, BOTTOM_LEFT, LEFT};
enum EDir
{
TOP_LEFT,
TOP_RIGHT,
RIGHT,
BOTTOM_RIGHT,
BOTTOM_LEFT,
LEFT,
NONE
};
BattleHex();
BattleHex(si16 _hex);
@ -39,7 +60,7 @@ struct DLL_LINKAGE BattleHex //TODO: decide if this should be changed to class f
static signed char mutualPosition(BattleHex hex1, BattleHex hex2);
static char getDistance(BattleHex hex1, BattleHex hex2);
static void checkAndPush(BattleHex tile, std::vector<BattleHex> & ret);
static BattleHex getClosestTile(bool attackerOwned, BattleHex initialPos, std::set<BattleHex> & possibilities); //TODO: vector or set? copying one to another is bad
static BattleHex getClosestTile(ui8 side, BattleHex initialPos, std::set<BattleHex> & possibilities); //TODO: vector or set? copying one to another is bad
template <typename Handler>
void serialize(Handler &h, const int version)

View File

@ -26,7 +26,7 @@ const CStack * BattleInfo::getNextStack() const
return nullptr;
}
int BattleInfo::getAvaliableHex(CreatureID creID, bool attackerOwned, int initialPos) const
int BattleInfo::getAvaliableHex(CreatureID creID, ui8 side, int initialPos) const
{
bool twoHex = VLC->creh->creatures[creID]->isDoubleWide();
//bool flying = VLC->creh->creatures[creID]->isFlying();
@ -36,7 +36,7 @@ int BattleInfo::getAvaliableHex(CreatureID creID, bool attackerOwned, int initia
pos = initialPos;
else //summon elementals depending on player side
{
if (attackerOwned)
if(side == BattleSide::ATTACKER)
pos = 0; //top left
else
pos = GameConstants::BFIELD_WIDTH - 1; //top right
@ -46,7 +46,7 @@ int BattleInfo::getAvaliableHex(CreatureID creID, bool attackerOwned, int initia
std::set<BattleHex> occupyable;
for(int i = 0; i < accessibility.size(); i++)
if(accessibility.accessible(i, twoHex, attackerOwned))
if(accessibility.accessible(i, twoHex, side))
occupyable.insert(i);
if (occupyable.empty())
@ -54,7 +54,7 @@ int BattleInfo::getAvaliableHex(CreatureID creID, bool attackerOwned, int initia
return BattleHex::INVALID; //all tiles are covered
}
return BattleHex::getClosestTile(attackerOwned, pos, occupyable);
return BattleHex::getClosestTile(side, pos, occupyable);
}
std::pair< std::vector<BattleHex>, int > BattleInfo::getPath(BattleHex start, BattleHex dest, const CStack * stack)
@ -104,28 +104,28 @@ void BattleInfo::calculateCasualties(std::map<ui32,si32> * casualties) const
si32 killed = (st->alive() ? (st->baseAmount - st->count + st->resurrected) : st->baseAmount);
vstd::amax(killed, 0);
if(killed)
casualties[!st->attackerOwned][st->getCreature()->idNumber] += killed;
casualties[st->side][st->getCreature()->idNumber] += killed;
}
}
CStack * BattleInfo::generateNewStack(const CStackInstance &base, bool attackerOwned, SlotID slot, BattleHex position) const
CStack * BattleInfo::generateNewStack(const CStackInstance & base, ui8 side, SlotID slot, BattleHex position) const
{
int stackID = getIdForNewStack();
PlayerColor owner = sides[attackerOwned ? 0 : 1].color;
PlayerColor owner = sides[side].color;
assert((owner >= PlayerColor::PLAYER_LIMIT) ||
(base.armyObj && base.armyObj->tempOwner == owner));
auto ret = new CStack(&base, owner, stackID, attackerOwned, slot);
ret->position = getAvaliableHex (base.getCreatureID(), attackerOwned, position); //TODO: what if no free tile on battlefield was found?
auto ret = new CStack(&base, owner, stackID, side, slot);
ret->position = getAvaliableHex(base.getCreatureID(), side, position); //TODO: what if no free tile on battlefield was found?
ret->state.insert(EBattleStackState::ALIVE); //alive state indication
return ret;
}
CStack * BattleInfo::generateNewStack(const CStackBasicDescriptor &base, bool attackerOwned, SlotID slot, BattleHex position) const
CStack * BattleInfo::generateNewStack(const CStackBasicDescriptor & base, ui8 side, SlotID slot, BattleHex position) const
{
int stackID = getIdForNewStack();
PlayerColor owner = sides[attackerOwned ? 0 : 1].color;
auto ret = new CStack(&base, owner, stackID, attackerOwned, slot);
PlayerColor owner = sides[side].color;
auto ret = new CStack(&base, owner, stackID, side, slot);
ret->position = position;
ret->state.insert(EBattleStackState::ALIVE); //alive state indication
return ret;
@ -155,7 +155,7 @@ void BattleInfo::localInitStack(CStack * s)
}
else //attach directly to obj to which stack belongs and creature type
{
CArmedInstance *army = battleGetArmyObject(!s->attackerOwned);
CArmedInstance *army = battleGetArmyObject(s->side);
s->attachTo(army);
assert(s->type);
s->attachTo(const_cast<CCreature*>(s->type));
@ -486,7 +486,7 @@ BattleInfo * BattleInfo::setupBattle(int3 tile, ETerrainType terrain, BFieldType
if(creatureBank && i->second->type->isDoubleWide())
pos += side ? BattleHex::LEFT : BattleHex::RIGHT;
CStack * stack = curB->generateNewStack(*i->second, !side, i->first, pos);
CStack * stack = curB->generateNewStack(*i->second, side, i->first, pos);
stacks.push_back(stack);
}
}
@ -496,7 +496,7 @@ BattleInfo * BattleInfo::setupBattle(int3 tile, ETerrainType terrain, BFieldType
{
if (heroes[i] && heroes[i]->commander && heroes[i]->commander->alive)
{
CStack * stack = curB->generateNewStack (*heroes[i]->commander, !i, SlotID::COMMANDER_SLOT_PLACEHOLDER,
CStack * stack = curB->generateNewStack (*heroes[i]->commander, i, SlotID::COMMANDER_SLOT_PLACEHOLDER,
creatureBank ? commanderBank[i] : commanderField[i]);
stacks.push_back(stack);
}
@ -506,15 +506,15 @@ BattleInfo * BattleInfo::setupBattle(int3 tile, ETerrainType terrain, BFieldType
if (curB->town && curB->town->fortLevel() >= CGTownInstance::CITADEL)
{
// keep tower
CStack * stack = curB->generateNewStack(CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), false, SlotID::ARROW_TOWERS_SLOT, -2);
CStack * stack = curB->generateNewStack(CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), 1, SlotID::ARROW_TOWERS_SLOT, -2);
stacks.push_back(stack);
if (curB->town->fortLevel() >= CGTownInstance::CASTLE)
{
// lower tower + upper tower
CStack * stack = curB->generateNewStack(CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), false, SlotID::ARROW_TOWERS_SLOT, -4);
CStack * stack = curB->generateNewStack(CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), 1, SlotID::ARROW_TOWERS_SLOT, -4);
stacks.push_back(stack);
stack = curB->generateNewStack(CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), false, SlotID::ARROW_TOWERS_SLOT, -3);
stack = curB->generateNewStack(CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), 1, SlotID::ARROW_TOWERS_SLOT, -3);
stacks.push_back(stack);
}

View File

@ -55,28 +55,17 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallb
CGHeroInstance * battleGetFightingHero(ui8 side) const;
const CStack * getNextStack() const; //which stack will have turn after current one
//void getStackQueue(std::vector<const CStack *> &out, int howMany, int turn = 0, int lastMoved = -1) const; //returns stack in order of their movement action
//void getAccessibilityMap(bool *accessibility, bool twoHex, bool attackerOwned, bool addOccupiable, std::set<BattleHex> & occupyable, bool flying, const CStack* stackToOmmit = nullptr) const; //send pointer to at least 187 allocated bytes
//static bool isAccessible(BattleHex hex, bool * accessibility, bool twoHex, bool attackerOwned, bool flying, bool lastPos); //helper for makeBFS
int getAvaliableHex(CreatureID creID, bool attackerOwned, int initialPos = -1) const; //find place for summon / clone effects
//void makeBFS(BattleHex start, bool*accessibility, BattleHex *predecessor, int *dists, bool twoHex, bool attackerOwned, bool flying, bool fillPredecessors) const; //*accessibility must be prepared bool[187] array; last two pointers must point to the at least 187-elements int arrays - there is written result
int getAvaliableHex(CreatureID creID, ui8 side, int initialPos = -1) const; //find place for summon / clone effects
std::pair< std::vector<BattleHex>, int > getPath(BattleHex start, BattleHex dest, const CStack * stack); //returned value: pair<path, length>; length may be different than number of elements in path since flying vreatures jump between distant hexes
//std::vector<BattleHex> getAccessibility(const CStack * stack, bool addOccupiable, std::vector<BattleHex> * attackable = nullptr, bool forPassingBy = false) const; //returns vector of accessible tiles (taking into account the creature range)
//bool isObstacleVisibleForSide(const CObstacleInstance &obstacle, ui8 side) const;
std::shared_ptr<CObstacleInstance> getObstacleOnTile(BattleHex tile) const;
std::set<BattleHex> getStoppers(bool whichSidePerspective) const;
ui32 calculateDmg(const CStack * attacker, const CStack * defender, bool shooting, ui8 charge, bool lucky, bool unlucky, bool deathBlow, bool ballistaDoubleDmg, CRandomGenerator & rand); //charge - number of hexes travelled before attack (for champion's jousting)
void calculateCasualties(std::map<ui32,si32> * casualties) const; //casualties are array of maps size 2 (attacker, defeneder), maps are (crid => amount)
//void getPotentiallyAttackableHexes(AttackableTiles &at, const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos); //hexes around target that could be attacked in melee
//std::set<CStack*> getAttackedCreatures(const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos = BattleHex::INVALID); //calculates range of multi-hex attacks
//std::set<BattleHex> getAttackedHexes(const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos = BattleHex::INVALID); //calculates range of multi-hex attacks
CStack * generateNewStack(const CStackInstance &base, bool attackerOwned, SlotID slot, BattleHex position) const; //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield
CStack * generateNewStack(const CStackBasicDescriptor &base, bool attackerOwned, SlotID slot, BattleHex position) const; //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield
CStack * generateNewStack(const CStackInstance &base, ui8 side, SlotID slot, BattleHex position) const; //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield
CStack * generateNewStack(const CStackBasicDescriptor &base, ui8 side, SlotID slot, BattleHex position) const; //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield
int getIdForNewStack() const; //suggest a currently unused ID that'd suitable for generating a new stack
const CGHeroInstance * getHero(PlayerColor player) const; //returns fighting hero that belongs to given player

View File

@ -103,10 +103,10 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastSpell(con
return ESpellCastProblem::INVALID;
}
const PlayerColor player = caster->getOwner();
const si8 side = playerToSide(player);
if(side < 0)
const auto side = playerToSide(player);
if(!side)
return ESpellCastProblem::INVALID;
if(!battleDoWeKnowAbout(side))
if(!battleDoWeKnowAbout(side.get()))
{
logGlobal->warnStream() << "You can't check if enemy can cast given spell!";
return ESpellCastProblem::INVALID;
@ -119,7 +119,7 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastSpell(con
{
case ECastingMode::HERO_CASTING:
{
if(battleCastSpells(side) > 0)
if(battleCastSpells(side.get()) > 0)
return ESpellCastProblem::ALREADY_CASTED_THIS_TURN;
auto hero = dynamic_cast<const CGHeroInstance *>(caster);
@ -255,7 +255,7 @@ void CBattleInfoCallback::battleGetStackQueue(std::vector<const CStack *> &out,
int bestSpeed = fastest->Speed(turn);
//FIXME: comparison between bool and integer. Logic does not makes sense either
if(fastest->attackerOwned != lastMoved)
if(fastest->side != lastMoved)
{
ret = fastest;
}
@ -264,7 +264,7 @@ void CBattleInfoCallback::battleGetStackQueue(std::vector<const CStack *> &out,
for(j = i + 1; j < st.size(); j++)
{
if(!st[j]) continue;
if(st[j]->attackerOwned != lastMoved || st[j]->Speed(turn) != bestSpeed)
if(st[j]->side != lastMoved || st[j]->Speed(turn) != bestSpeed)
break;
}
@ -288,7 +288,7 @@ void CBattleInfoCallback::battleGetStackQueue(std::vector<const CStack *> &out,
else
st[j] = nullptr;
lastMoved = ret->attackerOwned;
lastMoved = ret->side;
return ret;
};
@ -362,9 +362,9 @@ void CBattleInfoCallback::battleGetStackQueue(std::vector<const CStack *> &out,
{
//FIXME: both branches contain same code!!!
if(out.size() && out.front() == active)
lastMoved = active->attackerOwned;
lastMoved = active->side;
else
lastMoved = active->attackerOwned;
lastMoved = active->side;
}
else
{
@ -418,7 +418,7 @@ std::vector<BattleHex> CBattleInfoCallback::battleGetAvailableHexes(const CStack
if(!reachability.isReachable(i))
continue;
if(battleTacticDist() && battleGetTacticsSide() == !stack->attackerOwned)
if(battleTacticDist() && battleGetTacticsSide() == stack->side)
{
//Stack has to perform tactic-phase movement -> can enter any reachable tile within given range
if(!isInTacticRange(i))
@ -453,7 +453,7 @@ std::vector<BattleHex> CBattleInfoCallback::battleGetAvailableHexes(const CStack
});
return availableNeighbor != ret.end();
};
for(const CStack * otherSt : battleAliveStacks(stack->attackerOwned))
for(const CStack * otherSt : battleAliveStacks(1-stack->side))
{
if(!otherSt->isValidTarget(false))
continue;
@ -800,7 +800,6 @@ std::pair<ui32, ui32> CBattleInfoCallback::battleEstimateDamage(CRandomGenerator
RETURN_IF_NOT_BATTLE(std::make_pair(0, 0));
//const bool shooting = battleCanShoot(bai.attacker, bai.defenderPosition); //TODO handle bonus bearer
//const ui8 mySide = !attacker->attackerOwned;
TDmgRange ret = calculateDmgRange(bai);
@ -965,7 +964,7 @@ ReachabilityInfo CBattleInfoCallback::makeBFS(const AccessibilityInfo &accessibi
const int costToNeighbour = ret.distances[curHex] + 1;
for(BattleHex neighbour : curHex.neighbouringTiles())
{
const bool accessible = accessibility.accessible(neighbour, params.doubleWide, params.attackerOwned);
const bool accessible = accessibility.accessible(neighbour, params.doubleWide, params.side);
const int costFoundSoFar = ret.distances[neighbour];
if(accessible && costToNeighbour < costFoundSoFar)
@ -1001,7 +1000,7 @@ std::set<BattleHex> CBattleInfoCallback::getStoppers(BattlePerspective::BattlePe
return ret;
}
std::pair<const CStack *, BattleHex> CBattleInfoCallback::getNearestStack(const CStack * closest, boost::logic::tribool attackerOwned) const
std::pair<const CStack *, BattleHex> CBattleInfoCallback::getNearestStack(const CStack * closest, BattleSideOpt side) const
{
auto reachability = getReachability(closest);
auto avHexes = battleGetAvailableHexes(closest, false);
@ -1018,7 +1017,7 @@ std::pair<const CStack *, BattleHex> CBattleInfoCallback::getNearestStack(const
std::vector<const CStack *> possibleStacks = battleGetStacksIf([=](const CStack * s)
{
return s->isValidTarget(false) && s != closest && (boost::logic::indeterminate(attackerOwned) || s->attackerOwned == attackerOwned);
return s->isValidTarget(false) && s != closest && (!side || side.get() == s->side);
});
for(const CStack * st : possibleStacks)
@ -1064,7 +1063,7 @@ ReachabilityInfo CBattleInfoCallback::getReachability(const CStack *stack) const
{
ReachabilityInfo::Parameters params(stack);
if(!battleDoWeKnowAbout(!stack->attackerOwned))
if(!battleDoWeKnowAbout(stack->side))
{
//Stack is held by enemy, we can't use his perspective to check for reachability.
// Happens ie. when hovering enemy stack for its range. The arg could be set properly, but it's easier to fix it here.
@ -1089,7 +1088,7 @@ ReachabilityInfo CBattleInfoCallback::getFlyingReachability(const ReachabilityIn
for(int i = 0; i < GameConstants::BFIELD_SIZE; i++)
{
if(ret.accessibility.accessible(i, params.doubleWide, params.attackerOwned))
if(ret.accessibility.accessible(i, params.doubleWide, params.side))
{
ret.predecessors[i] = params.startPosition;
ret.distances[i] = BattleHex::getDistance(params.startPosition, i);
@ -1103,7 +1102,7 @@ AttackableTiles CBattleInfoCallback::getPotentiallyAttackableHexes (const CStack
{
//does not return hex attacked directly
//TODO: apply rotation to two-hex attackers
bool isAttacker = attacker->attackerOwned;
bool isAttacker = attacker->side == BattleSide::ATTACKER;
AttackableTiles at;
RETURN_IF_NOT_BATTLE(at);
@ -1482,7 +1481,7 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(CRandomGenerator & rand, c
case SpellID::PROTECTION_FROM_FIRE:
case SpellID::PROTECTION_FROM_WATER:
{
const ui8 enemySide = (ui8)subject->attackerOwned;
const ui8 enemySide = 1 - subject->side;
//todo: only if enemy has spellbook
if (!battleHasHero(enemySide)) //only if there is enemy hero
continue;
@ -1567,17 +1566,17 @@ int CBattleInfoCallback::battleGetSurrenderCost(PlayerColor Player) const
if(!battleCanSurrender(Player))
return -1;
const si8 playerSide = playerToSide(Player);
if(playerSide < 0)
const auto side = playerToSide(Player);
if(!side)
return -1;
int ret = 0;
double discount = 0;
for(const CStack *s : battleAliveStacks(playerSide))
for(const CStack * s : battleAliveStacks(side.get()))
if(s->base) //we pay for our stack that comes from our army slots - condition eliminates summoned cres and war machines
ret += s->getCreature()->cost[Res::GOLD] * s->count;
if(const CGHeroInstance * h = battleGetFightingHero(playerSide))
if(const CGHeroInstance * h = battleGetFightingHero(side.get()))
discount += h->valOfBonuses(Bonus::SURRENDER_DISCOUNT);
ret *= (100.0 - discount) / 100.0;
@ -1616,7 +1615,7 @@ boost::optional<int> CBattleInfoCallback::battleIsFinished() const
{
if(stack->alive() && !stack->hasBonusOfType(Bonus::SIEGE_WEAPON))
{
hasStack[1-stack->attackerOwned] = true;
hasStack[stack->side] = true;
}
}

View File

@ -101,7 +101,7 @@ public:
AccessibilityInfo getAccesibility() const;
AccessibilityInfo getAccesibility(const CStack *stack) const; //Hexes ocupied by stack will be marked as accessible.
AccessibilityInfo getAccesibility(const std::vector<BattleHex> & accessibleHexes) const; //given hexes will be marked as accessible
std::pair<const CStack *, BattleHex> getNearestStack(const CStack * closest, boost::logic::tribool attackerOwned) const;
std::pair<const CStack *, BattleHex> getNearestStack(const CStack * closest, BattleSideOpt side) const;
protected:
ReachabilityInfo getFlyingReachability(const ReachabilityInfo::Parameters & params) const;
ReachabilityInfo makeBFS(const AccessibilityInfo & accessibility, const ReachabilityInfo::Parameters & params) const;

View File

@ -67,7 +67,7 @@ bool CBattleInfoEssentials::battleHasNativeStack(ui8 side) const
for(const CStack * s : battleGetAllStacks())
{
if(s->attackerOwned == !side && s->getCreature()->isItNativeTerrain(getBattle()->terrainType))
if(s->side == side && s->getCreature()->isItNativeTerrain(getBattle()->terrainType))
return true;
}
@ -102,7 +102,7 @@ TStacks CBattleInfoEssentials::battleAliveStacks() const
TStacks CBattleInfoEssentials::battleAliveStacks(ui8 side) const
{
return battleGetStacksIf([=](const CStack * s){
return s->isValidTarget(false) && s->attackerOwned == !side;
return s->isValidTarget(false) && s->side == side;
});
}
@ -237,8 +237,11 @@ const IBonusBearer * CBattleInfoEssentials::getBattleNode() const
bool CBattleInfoEssentials::battleCanFlee(PlayerColor player) const
{
RETURN_IF_NOT_BATTLE(false);
const si8 mySide = playerToSide(player);
const CGHeroInstance *myHero = battleGetFightingHero(mySide);
const auto side = playerToSide(player);
if(!side)
return false;
const CGHeroInstance *myHero = battleGetFightingHero(side.get());
//current player have no hero
if(!myHero)
@ -249,7 +252,7 @@ bool CBattleInfoEssentials::battleCanFlee(PlayerColor player) const
return false;
//we are besieged defender
if(mySide == BattleSide::DEFENDER && battleGetSiegeLevel())
if(side.get() == BattleSide::DEFENDER && battleGetSiegeLevel())
{
auto town = battleGetDefendedTown();
if(!town->hasBuilt(BuildingID::ESCAPE_TUNNEL, ETownType::STRONGHOLD))
@ -259,23 +262,31 @@ bool CBattleInfoEssentials::battleCanFlee(PlayerColor player) const
return true;
}
si8 CBattleInfoEssentials::playerToSide(PlayerColor player) const
BattleSideOpt CBattleInfoEssentials::playerToSide(PlayerColor player) const
{
RETURN_IF_NOT_BATTLE(-1);
RETURN_IF_NOT_BATTLE(boost::none);
int ret = vstd::find_pos_if(getBattle()->sides, [=](const SideInBattle &side){ return side.color == player; });
if(ret < 0)
logGlobal->warnStream() << "Cannot find side for player " << player;
return ret;
return BattleSideOpt(ret);
}
ui8 CBattleInfoEssentials::otherSide(ui8 side) const
{
if(side == BattleSide::ATTACKER)
return BattleSide::DEFENDER;
else
return BattleSide::ATTACKER;
}
bool CBattleInfoEssentials::playerHasAccessToHeroInfo(PlayerColor player, const CGHeroInstance * h) const
{
RETURN_IF_NOT_BATTLE(false);
const si8 playerSide = playerToSide(player);
if (playerSide >= 0)
const auto side = playerToSide(player);
if(side)
{
if (getBattle()->sides[!playerSide].hero == h)
if (getBattle()->sides[otherSide(side.get())].hero == h)
return true;
}
return false;
@ -290,10 +301,12 @@ ui8 CBattleInfoEssentials::battleGetSiegeLevel() const
bool CBattleInfoEssentials::battleCanSurrender(PlayerColor player) const
{
RETURN_IF_NOT_BATTLE(false);
ui8 mySide = playerToSide(player);
bool iAmSiegeDefender = (mySide == BattleSide::DEFENDER && battleGetSiegeLevel());
const auto side = playerToSide(player);
if(!side)
return false;
bool iAmSiegeDefender = (side.get() == BattleSide::DEFENDER && battleGetSiegeLevel());
//conditions like for fleeing (except escape tunnel presence) + enemy must have a hero
return battleCanFlee(player) && !iAmSiegeDefender && battleHasHero(!mySide);
return battleCanFlee(player) && !iAmSiegeDefender && battleHasHero(otherSide(side.get()));
}
bool CBattleInfoEssentials::battleHasHero(ui8 side) const
@ -334,7 +347,10 @@ PlayerColor CBattleInfoEssentials::battleGetOwner(const CStack * stack) const
const CGHeroInstance * CBattleInfoEssentials::battleGetOwnerHero(const CStack * stack) const
{
RETURN_IF_NOT_BATTLE(nullptr);
return getBattle()->sides.at(playerToSide(battleGetOwner(stack))).hero;
const auto side = playerToSide(battleGetOwner(stack));
if(!side)
return nullptr;
return getBattle()->sides.at(side.get()).hero;
}
bool CBattleInfoEssentials::battleMatchOwner(const CStack * attacker, const CStack * defender, const boost::logic::tribool positivness /* = false*/) const

View File

@ -9,6 +9,7 @@
*/
#pragma once
#include "CCallbackBase.h"
#include "BattleHex.h"
class CGTownInstance;
class CGHeroInstance;
@ -32,12 +33,6 @@ namespace BattlePerspective
};
}
namespace BattleSide
{
enum {ATTACKER = 0, DEFENDER = 1};
}
class DLL_LINKAGE CBattleInfoEssentials : public virtual CCallbackBase
{
protected:
@ -71,7 +66,8 @@ public:
si8 battleGetTacticsSide() const; //returns which side is in tactics phase, undefined if none (?)
bool battleCanFlee(PlayerColor player) const;
bool battleCanSurrender(PlayerColor player) const;
si8 playerToSide(PlayerColor player) const;
ui8 otherSide(ui8 side) const;
BattleSideOpt playerToSide(PlayerColor player) const;
bool playerHasAccessToHeroInfo(PlayerColor player, const CGHeroInstance * h) const;
ui8 battleGetSiegeLevel() const; //returns 0 when there is no siege, 1 if fort, 2 is citadel, 3 is castle
bool battleHasHero(ui8 side) const;

View File

@ -17,16 +17,17 @@ ReachabilityInfo::Parameters::Parameters()
{
stack = nullptr;
perspective = BattlePerspective::ALL_KNOWING;
attackerOwned = doubleWide = flying = false;
side = 0;
doubleWide = flying = false;
}
ReachabilityInfo::Parameters::Parameters(const CStack * Stack)
{
stack = Stack;
perspective = (BattlePerspective::BattlePerspective)(!Stack->attackerOwned);
perspective = (BattlePerspective::BattlePerspective)(Stack->side);
startPosition = Stack->position;
doubleWide = stack->doubleWide();
attackerOwned = stack->attackerOwned;
side = stack->side;
flying = stack->hasBonusOfType(Bonus::FLYING);
knownAccessible = stack->getHexes();
}

View File

@ -27,7 +27,7 @@ struct DLL_LINKAGE ReachabilityInfo
{
const CStack * stack; //stack for which calculation is mage => not required (kept for debugging mostly), following variables are enough
bool attackerOwned;
ui8 side;
bool doubleWide;
bool flying;
std::vector<BattleHex> knownAccessible; //hexes that will be treated as accessible, even if they're occupied by stack (by default - tiles occupied by stack we do reachability for, so it doesn't block itself)

View File

@ -104,7 +104,7 @@ std::vector<const CStack *> ChainLightningMechanics::calculateAffectedStacks(con
}
if(possibleHexes.empty()) //not enough targets
break;
lightningHex = BattleHex::getClosestTile(stack->attackerOwned, lightningHex, possibleHexes);
lightningHex = BattleHex::getClosestTile(stack->side, lightningHex, possibleHexes);
}
return res;
@ -121,13 +121,12 @@ void CloneMechanics::applyBattleEffects(const SpellCastEnvironment * env, const
env->complain ("No target stack to clone!");
return;
}
const int attacker = !(bool)parameters.casterSide;
BattleStackAdded bsa;
bsa.creID = clonedStack->type->idNumber;
bsa.attacker = attacker;
bsa.side = parameters.casterSide;
bsa.summoned = true;
bsa.pos = parameters.cb->getAvaliableHex(bsa.creID, attacker); //TODO: unify it
bsa.pos = parameters.cb->getAvaliableHex(bsa.creID, parameters.casterSide);
bsa.amount = clonedStack->count;
env->sendAndApply(&bsa);
@ -370,8 +369,11 @@ ESpellCastProblem::ESpellCastProblem EarthquakeMechanics::canBeCast(const CBattl
CSpell::TargetInfo ti(owner, caster->getSpellSchoolLevel(owner));
if(ti.smart)
{
const auto side = cb->playerToSide(caster->getOwner());
if(!side)
return ESpellCastProblem::INVALID;
//if spell targeting is smart, then only attacker can use it
if(cb->playerToSide(caster->getOwner()) != BattleSide::ATTACKER)
if(side.get() != BattleSide::ATTACKER)
return ESpellCastProblem::NO_APPROPRIATE_TARGET;
}
@ -407,13 +409,13 @@ ESpellCastProblem::ESpellCastProblem HypnotizeMechanics::isImmuneByStack(const I
///ObstacleMechanics
ESpellCastProblem::ESpellCastProblem ObstacleMechanics::canBeCast(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const
{
const si8 side = cb->playerToSide(ctx.caster->getOwner());
if(side < 0)
const auto side = cb->playerToSide(ctx.caster->getOwner());
if(!side)
return ESpellCastProblem::INVALID;
bool hexesOutsideBattlefield = false;
auto tilesThatMustBeClear = owner->rangeInHexes(ctx.destination, ctx.schoolLvl, side, &hexesOutsideBattlefield);
auto tilesThatMustBeClear = owner->rangeInHexes(ctx.destination, ctx.schoolLvl, side.get(), &hexesOutsideBattlefield);
for(const BattleHex & hex : tilesThatMustBeClear)
if(!isHexAviable(cb, hex, ctx.ti.clearAffected))
@ -499,11 +501,11 @@ void PatchObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * env
ESpellCastProblem::ESpellCastProblem LandMineMechanics::canBeCast(const CBattleInfoCallback * cb, const ECastingMode::ECastingMode mode, const ISpellCaster * caster) const
{
//LandMine are useless if enemy has native stack and can see mines, check for LandMine damage immunity is done in general way by CSpell
const si8 playerSide = cb->playerToSide(caster->getOwner());
if(playerSide < 0)
const auto side = cb->playerToSide(caster->getOwner());
if(!side)
return ESpellCastProblem::INVALID;
const si8 otherSide = !playerSide;
const ui8 otherSide = cb->otherSide(side.get());
if(cb->battleHasNativeStack(otherSide))
return ESpellCastProblem::NO_APPROPRIATE_TARGET;
@ -887,9 +889,9 @@ void SummonMechanics::applyBattleEffects(const SpellCastEnvironment * env, const
{
BattleStackAdded bsa;
bsa.creID = creatureToSummon;
bsa.attacker = !(bool)parameters.casterSide;
bsa.side = parameters.casterSide;
bsa.summoned = true;
bsa.pos = parameters.cb->getAvaliableHex(creatureToSummon, !(bool)parameters.casterSide); //TODO: unify it
bsa.pos = parameters.cb->getAvaliableHex(creatureToSummon, parameters.casterSide); //TODO: unify it
//TODO stack casting -> probably power will be zero; set the proper number of creatures manually
int percentBonus = parameters.casterHero ? parameters.casterHero->valOfBonuses(Bonus::SPECIFIC_SPELL_DAMAGE, owner->id.toEnum()) : 0;

View File

@ -649,10 +649,10 @@ std::vector<const CStack *> DefaultSpellMechanics::calculateAffectedStacks(const
{
std::set<const CStack* > attackedCres;//std::set to exclude multiple occurrences of two hex creatures
const si8 playerSide = cb->playerToSide(ctx.caster->getOwner());
if(playerSide < 0)
const auto side = cb->playerToSide(ctx.caster->getOwner());
if(!side)
return std::vector<const CStack *>();
auto attackedHexes = rangeInHexes(ctx.destination, ctx.schoolLvl, playerSide);
auto attackedHexes = rangeInHexes(ctx.destination, ctx.schoolLvl, side.get());
//hackfix for banned creature massive spells
if(!ctx.ti.massive && owner->getLevelInfo(ctx.schoolLvl).range == "X")

View File

@ -186,15 +186,15 @@ ESpellCastProblem::ESpellCastProblem CSpell::canBeCast(const CBattleInfoCallback
return ESpellCastProblem::ADVMAP_SPELL_INSTEAD_OF_BATTLE_SPELL;
const PlayerColor player = caster->getOwner();
const si8 side = cb->playerToSide(player);
const auto side = cb->playerToSide(player);
if(side < 0)
if(!side)
return ESpellCastProblem::INVALID;
//effect like Recanter's Cloak. Blocks also passive casting.
//TODO: check creature abilities to block
//TODO: check any possible caster
if(cb->battleMaxSpellLevel(side) < level)
if(cb->battleMaxSpellLevel(side.get()) < level)
return ESpellCastProblem::SPELL_LEVEL_LIMIT_EXCEEDED;
const ESpellCastProblem::ESpellCastProblem specificProblem = mechanics->canBeCast(cb, mode, caster);

View File

@ -138,11 +138,13 @@ static void giveExp(BattleResult &r)
}
}
static void summonGuardiansHelper(std::vector<BattleHex> & output, const BattleHex & targetPosition, bool targetIsAttacker, bool targetIsTwoHex) //return hexes for summoning two hex monsters in output, target = unit to guard
static void summonGuardiansHelper(std::vector<BattleHex> & output, const BattleHex & targetPosition, ui8 side, bool targetIsTwoHex) //return hexes for summoning two hex monsters in output, target = unit to guard
{
int x = targetPosition.getX();
int y = targetPosition.getY();
const bool targetIsAttacker = side == BattleSide::ATTACKER;
if (targetIsAttacker) //handle front guardians, TODO: should we handle situation when units start battle near opposite side of the battlefield? Cannot happen in normal H3...
BattleHex::checkAndPush(targetPosition.cloneInDirection(BattleHex::EDir::RIGHT, false).cloneInDirection(BattleHex::EDir::RIGHT, false), output);
else
@ -1160,21 +1162,15 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
auto accessibility = getAccesibility(curStack);
//shifting destination (if we have double wide stack and we can occupy dest but not be exactly there)
if (!stackAtEnd && curStack->doubleWide() && !accessibility.accessible(dest, curStack))
if(!stackAtEnd && curStack->doubleWide() && !accessibility.accessible(dest, curStack))
{
if (curStack->attackerOwned)
{
if (accessibility.accessible(dest+1, curStack))
dest += BattleHex::RIGHT;
}
else
{
if (accessibility.accessible(dest-1, curStack))
dest += BattleHex::LEFT;
}
BattleHex shifted = dest.cloneInDirection(curStack->destShiftDir());
if(accessibility.accessible(shifted, curStack))
dest = shifted;
}
if ((stackAtEnd && stackAtEnd!=curStack && stackAtEnd->alive()) || !accessibility.accessible(dest, curStack))
if((stackAtEnd && stackAtEnd!=curStack && stackAtEnd->alive()) || !accessibility.accessible(dest, curStack))
{
complain("Given destination is not accessible!");
return 0;
@ -1182,7 +1178,7 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
bool canUseGate = false;
auto dbState = gs->curB->si.gateState;
if (battleGetSiegeLevel() > 0 && !curStack->attackerOwned &&
if(battleGetSiegeLevel() > 0 && curStack->side == BattleSide::DEFENDER &&
dbState != EGateState::DESTROYED &&
dbState != EGateState::BLOCKED)
{
@ -3857,7 +3853,7 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
if (battleTacticDist())
{
if (stack && !stack->attackerOwned != battleGetTacticsSide())
if (stack && stack->side != battleGetTacticsSide())
{
complain("This is not a stack of side that has tactics!");
return false;
@ -3951,10 +3947,8 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
logGlobal->trace("%s will attack %s", stack->nodeName(), destinationStack->nodeName());
if (stack->position != ba.destinationTile //we wasn't able to reach destination tile
&& !(stack->doubleWide()
&& (stack->position == ba.destinationTile + (stack->attackerOwned ? +1 : -1))
) //nor occupy specified hex
if(stack->position != ba.destinationTile //we wasn't able to reach destination tile
&& !(stack->doubleWide() && (stack->position == ba.destinationTile.cloneInDirection(stack->destShiftDir()))) //nor occupy specified hex
)
{
complain("We cannot move this stack to its destination " + stack->getCreature()->namePl);
@ -4292,7 +4286,7 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
CreatureID summonedType(summoner->getBonusLocalFirst(Selector::type(Bonus::DAEMON_SUMMONING))->subtype);//in case summoner can summon more than one type of monsters... scream!
BattleStackAdded bsa;
bsa.attacker = summoner->attackerOwned;
bsa.side = summoner->side;
bsa.creID = summonedType;
ui64 risedHp = summoner->count * summoner->valOfBonuses(Bonus::DAEMON_SUMMONING, bsa.creID.toEnum());
@ -4303,7 +4297,7 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
bsa.amount = std::min(canRiseAmount, destStack->baseAmount);
bsa.pos = gs->curB->getAvaliableHex(bsa.creID, bsa.attacker, destStack->position);
bsa.pos = gs->curB->getAvaliableHex(bsa.creID, bsa.side, destStack->position);
bsa.summoned = false;
if (bsa.amount) //there's rare possibility single creature cannot rise desired type
@ -4661,7 +4655,7 @@ void CGameHandler::handleDamageFromObstacle(const CObstacleInstance &obstacle, c
//helper info
const SpellCreatedObstacle *spellObstacle = dynamic_cast<const SpellCreatedObstacle*>(&obstacle); //not nice but we may need spell params
const ui8 side = !curStack->attackerOwned; //if enemy is defending (false = 0), side of enemy hero is 1 (true)
const ui8 side = curStack->side; //if enemy is defending (false = 0), side of enemy hero is 1 (true)
const CGHeroInstance *hero = gs->curB->battleGetFightingHero(side);//FIXME: there may be no hero - landmines in Tower
if (obstacle.obstacleType == CObstacleInstance::MOAT)
@ -5416,6 +5410,7 @@ void CGameHandler::handleAfterAttackCasting(const BattleAttack & bat)
BattleStackAdded resurrectInfo;
resurrectInfo.pos = defender->position;
resurrectInfo.side = defender->side;
if (bonusAdditionalInfo != -1)
resurrectInfo.creID = (CreatureID)bonusAdditionalInfo;
@ -5515,7 +5510,7 @@ void CGameHandler::makeStackDoNothing(const CStack * next)
doNothing.actionType = Battle::NO_ACTION;
doNothing.additionalInfo = 0;
doNothing.destinationTile = -1;
doNothing.side = !next->attackerOwned;
doNothing.side = next->side;
doNothing.stackNumber = next->ID;
makeAutomaticAction(next, doNothing);
@ -5708,16 +5703,16 @@ void CGameHandler::runBattle()
if (!guardianIsBig)
targetHexes = stack->getSurroundingHexes();
else
summonGuardiansHelper(targetHexes, stack->position, stack->attackerOwned, targetIsBig);
summonGuardiansHelper(targetHexes, stack->position, stack->side, targetIsBig);
for (auto hex : targetHexes)
{
if (accessibility.accessible(hex, guardianIsBig, stack->attackerOwned)) //without this multiple creatures can occupy one hex
if (accessibility.accessible(hex, guardianIsBig, stack->side)) //without this multiple creatures can occupy one hex
{
BattleStackAdded newStack;
newStack.amount = std::max(1, (int)(stack->count * 0.01 * summonInfo->val));
newStack.creID = creatureData.num;
newStack.attacker = stack->attackerOwned;
newStack.side = stack->side;
newStack.summoned = true;
newStack.pos = hex.hex;
sendAndApply(&newStack);
@ -5808,7 +5803,7 @@ void CGameHandler::runBattle()
BattleAction ba;
ba.actionType = Battle::BAD_MORALE;
ba.additionalInfo = 1;
ba.side = !next->attackerOwned;
ba.side = next->side;
ba.stackNumber = next->ID;
makeAutomaticAction(next, ba);
@ -5819,12 +5814,12 @@ void CGameHandler::runBattle()
if (next->hasBonusOfType(Bonus::ATTACKS_NEAREST_CREATURE)) //while in berserk
{
logGlobal->debug("Handle Berserk effect");
std::pair<const CStack *, int> attackInfo = curB.getNearestStack(next, boost::logic::indeterminate);
std::pair<const CStack *, int> attackInfo = curB.getNearestStack(next, boost::none);
if (attackInfo.first != nullptr)
{
BattleAction attack;
attack.actionType = Battle::WALK_AND_ATTACK;
attack.side = !next->attackerOwned;
attack.side = next->side;
attack.stackNumber = next->ID;
attack.additionalInfo = attackInfo.first->position;
attack.destinationTile = attackInfo.second;
@ -5847,7 +5842,7 @@ void CGameHandler::runBattle()
{
BattleAction attack;
attack.actionType = Battle::SHOOT;
attack.side = !next->attackerOwned;
attack.side = next->side;
attack.stackNumber = next->ID;
for (auto & elem : gs->curB->stacks)
@ -5880,7 +5875,7 @@ void CGameHandler::runBattle()
getRandomGenerator());
attack.actionType = Battle::CATAPULT;
attack.additionalInfo = 0;
attack.side = !next->attackerOwned;
attack.side = next->side;
attack.stackNumber = next->ID;
makeAutomaticAction(next, attack);
@ -5910,7 +5905,7 @@ void CGameHandler::runBattle()
heal.actionType = Battle::STACK_HEAL;
heal.additionalInfo = 0;
heal.destinationTile = toBeHealed->position;
heal.side = !next->attackerOwned;
heal.side = next->side;
heal.stackNumber = next->ID;
makeAutomaticAction(next, heal);

View File

@ -91,16 +91,16 @@ BOOST_AUTO_TEST_CASE(getClosestTile)
possibilities.insert(119);
possibilities.insert(186);
BOOST_TEST(mainHex.getClosestTile(true,mainHex,possibilities)==3);
BOOST_TEST(mainHex.getClosestTile(0,mainHex,possibilities)==3);
mainHex = 139;
BOOST_TEST(mainHex.getClosestTile(false,mainHex,possibilities)==119);
BOOST_TEST(mainHex.getClosestTile(1,mainHex,possibilities)==119);
mainHex = 16;
BOOST_TEST(mainHex.getClosestTile(false,mainHex,possibilities)==100);
BOOST_TEST(mainHex.getClosestTile(1,mainHex,possibilities)==100);
mainHex = 166;
BOOST_TEST(mainHex.getClosestTile(true,mainHex,possibilities)==186);
BOOST_TEST(mainHex.getClosestTile(0,mainHex,possibilities)==186);
mainHex = 76;
BOOST_TEST(mainHex.getClosestTile(false,mainHex,possibilities)==3);
BOOST_TEST(mainHex.getClosestTile(true,mainHex,possibilities)==100);
BOOST_TEST(mainHex.getClosestTile(1,mainHex,possibilities)==3);
BOOST_TEST(mainHex.getClosestTile(0,mainHex,possibilities)==100);
}
BOOST_AUTO_TEST_CASE(moveEDir)
@ -118,6 +118,8 @@ BOOST_AUTO_TEST_CASE(moveEDir)
BOOST_TEST(mainHex==3);
mainHex.moveInDirection(BattleHex::EDir::BOTTOM_LEFT);
BOOST_TEST(mainHex==20);
mainHex.moveInDirection(BattleHex::EDir::NONE);
BOOST_TEST(mainHex==20);
}
BOOST_AUTO_TEST_SUITE_END()