mirror of
https://github.com/vcmi/vcmi.git
synced 2024-11-28 08:48:48 +02:00
CStack refactoring
* removed all occurrences of attackerOwned * Use BattleSide enum * more tweaks
This commit is contained in:
parent
29e50cc21c
commit
4f8c7bd4bb
@ -24,7 +24,7 @@ struct CurrentOffensivePotential
|
|||||||
{
|
{
|
||||||
for(auto stack : cbc->battleGetStacks())
|
for(auto stack : cbc->battleGetStacks())
|
||||||
{
|
{
|
||||||
if(stack->attackerOwned == !side)
|
if(stack->side == side)
|
||||||
ourAttacks[stack] = PotentialTargets(stack);
|
ourAttacks[stack] = PotentialTargets(stack);
|
||||||
else
|
else
|
||||||
enemyAttacks[stack] = PotentialTargets(stack);
|
enemyAttacks[stack] = PotentialTargets(stack);
|
||||||
|
@ -18,7 +18,7 @@ PotentialTargets::PotentialTargets(const CStack *attacker, const HypotheticChang
|
|||||||
for(const CStack *enemy : getCbc()->battleGetStacks())
|
for(const CStack *enemy : getCbc()->battleGetStacks())
|
||||||
{
|
{
|
||||||
//Consider only stacks of different owner
|
//Consider only stacks of different owner
|
||||||
if(enemy->attackerOwned == attacker->attackerOwned)
|
if(enemy->side == attacker->side)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto GenerateAttackInfo = [&](bool shooting, BattleHex hex) -> AttackPossibility
|
auto GenerateAttackInfo = [&](bool shooting, BattleHex hex) -> AttackPossibility
|
||||||
|
@ -31,7 +31,7 @@ ThreatMap::ThreatMap(const CStack *Endangered) : endangered(Endangered)
|
|||||||
for(const CStack *enemy : getCbc()->battleGetStacks())
|
for(const CStack *enemy : getCbc()->battleGetStacks())
|
||||||
{
|
{
|
||||||
//Consider only stacks of different owner
|
//Consider only stacks of different owner
|
||||||
if(enemy->attackerOwned == endangered->attackerOwned)
|
if(enemy->side == endangered->side)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
//Look-up which tiles can be melee-attacked
|
//Look-up which tiles can be melee-attacked
|
||||||
|
@ -855,7 +855,7 @@ void CClient::commenceTacticPhaseForInt(std::shared_ptr<CBattleGameInterface> ba
|
|||||||
battleInt->yourTacticPhase(gs->curB->tacticDistance);
|
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)
|
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);
|
sendRequest(&ma, battleInt->playerID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -338,7 +338,7 @@ bool CMeleeAttackAnimation::init()
|
|||||||
static const CCreatureAnim::EAnimType mutPosToGroup[] = {CCreatureAnim::ATTACK_UP, CCreatureAnim::ATTACK_UP,
|
static const CCreatureAnim::EAnimType mutPosToGroup[] = {CCreatureAnim::ATTACK_UP, CCreatureAnim::ATTACK_UP,
|
||||||
CCreatureAnim::ATTACK_FRONT, CCreatureAnim::ATTACK_DOWN, CCreatureAnim::ATTACK_DOWN, CCreatureAnim::ATTACK_FRONT};
|
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);
|
int mutPos = BattleHex::mutualPosition(attackingStackPosBeforeReturn, dest);
|
||||||
if(mutPos == -1 && attackingStack->doubleWide())
|
if(mutPos == -1 && attackingStack->doubleWide())
|
||||||
@ -988,7 +988,7 @@ bool CSpellEffectAnimation::init()
|
|||||||
|
|
||||||
// Correction for 2-hex creatures.
|
// Correction for 2-hex creatures.
|
||||||
if (destStack != nullptr && destStack->doubleWide())
|
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
|
//Indicate if effect should be drawn on top of everything or just on top of the hex
|
||||||
be.position = destTile;
|
be.position = destTile;
|
||||||
|
@ -949,7 +949,7 @@ void CBattleInterface::bConsoleDownf()
|
|||||||
|
|
||||||
void CBattleInterface::newStack(const CStack *stack)
|
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);
|
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;
|
return state != EWallState::DESTROYED && state != EWallState::NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CGHeroInstance *CBattleInterface::getActiveHero()
|
const CGHeroInstance * CBattleInterface::getActiveHero()
|
||||||
{
|
{
|
||||||
const CStack *attacker = activeStack;
|
const CStack *attacker = activeStack;
|
||||||
if (!attacker)
|
if(!attacker)
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attacker->attackerOwned)
|
if(attacker->side == BattleSide::ATTACKER)
|
||||||
{
|
{
|
||||||
return attackingHeroInstance;
|
return attackingHeroInstance;
|
||||||
}
|
}
|
||||||
@ -1801,7 +1801,7 @@ void CBattleInterface::endAction(const BattleAction* action)
|
|||||||
|
|
||||||
for (const CStack *s : stacks)
|
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())
|
&& creAnims[s->ID]->isIdle())
|
||||||
{
|
{
|
||||||
addNewAnim(new CReverseAnimation(this, s, s->position, false));
|
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();
|
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);
|
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))
|
if (vstd::contains(acc, myNumber))
|
||||||
return true;
|
return true;
|
||||||
@ -2262,14 +2262,14 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
|
|||||||
|
|
||||||
realizeAction = [=]
|
realizeAction = [=]
|
||||||
{
|
{
|
||||||
if (activeStack->doubleWide())
|
if(activeStack->doubleWide())
|
||||||
{
|
{
|
||||||
std::vector<BattleHex> acc = curInt->cb->battleGetAvailableHexes(activeStack, false);
|
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))
|
if(vstd::contains(acc, myNumber))
|
||||||
giveCommand (Battle::WALK ,myNumber, activeStack->ID);
|
giveCommand(Battle::WALK, myNumber, activeStack->ID);
|
||||||
else if (vstd::contains(acc, shiftedDest))
|
else if(vstd::contains(acc, shiftedDest))
|
||||||
giveCommand (Battle::WALK, shiftedDest, activeStack->ID);
|
giveCommand(Battle::WALK, shiftedDest, activeStack->ID);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -2547,17 +2547,17 @@ BattleHex CBattleInterface::fromWhichHexAttack(BattleHex myNumber)
|
|||||||
{
|
{
|
||||||
bool doubleWide = activeStack->doubleWide();
|
bool doubleWide = activeStack->doubleWide();
|
||||||
destHex = myNumber + ( (myNumber/GameConstants::BFIELD_WIDTH)%2 ? GameConstants::BFIELD_WIDTH : GameConstants::BFIELD_WIDTH+1 ) +
|
destHex = myNumber + ( (myNumber/GameConstants::BFIELD_WIDTH)%2 ? GameConstants::BFIELD_WIDTH : GameConstants::BFIELD_WIDTH+1 ) +
|
||||||
(activeStack->attackerOwned && doubleWide ? 1 : 0);
|
(activeStack->side == BattleSide::ATTACKER && doubleWide ? 1 : 0);
|
||||||
if (vstd::contains(occupyableHexes, destHex))
|
if(vstd::contains(occupyableHexes, destHex))
|
||||||
return 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;
|
return destHex+1;
|
||||||
}
|
}
|
||||||
else //if we are defender
|
else //if we are defender
|
||||||
{
|
{
|
||||||
if (vstd::contains(occupyableHexes, destHex-1))
|
if(vstd::contains(occupyableHexes, destHex-1))
|
||||||
return destHex-1;
|
return destHex-1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -2567,21 +2567,21 @@ BattleHex CBattleInterface::fromWhichHexAttack(BattleHex myNumber)
|
|||||||
destHex = myNumber + ( (myNumber/GameConstants::BFIELD_WIDTH)%2 ? GameConstants::BFIELD_WIDTH-1 : GameConstants::BFIELD_WIDTH );
|
destHex = myNumber + ( (myNumber/GameConstants::BFIELD_WIDTH)%2 ? GameConstants::BFIELD_WIDTH-1 : GameConstants::BFIELD_WIDTH );
|
||||||
if (vstd::contains(occupyableHexes, destHex))
|
if (vstd::contains(occupyableHexes, destHex))
|
||||||
return 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;
|
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;
|
return destHex-1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 8: //from left
|
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);
|
std::vector<BattleHex> acc = curInt->cb->battleGetAvailableHexes(activeStack, false);
|
||||||
if (vstd::contains(acc, myNumber))
|
if (vstd::contains(acc, myNumber))
|
||||||
@ -2597,17 +2597,17 @@ BattleHex CBattleInterface::fromWhichHexAttack(BattleHex myNumber)
|
|||||||
}
|
}
|
||||||
case 9: //from top left
|
case 9: //from top left
|
||||||
{
|
{
|
||||||
destHex = myNumber - ( (myNumber/GameConstants::BFIELD_WIDTH)%2 ? GameConstants::BFIELD_WIDTH+1 : GameConstants::BFIELD_WIDTH );
|
destHex = myNumber - ((myNumber/GameConstants::BFIELD_WIDTH) % 2 ? GameConstants::BFIELD_WIDTH + 1 : GameConstants::BFIELD_WIDTH);
|
||||||
if (vstd::contains(occupyableHexes, destHex))
|
if(vstd::contains(occupyableHexes, destHex))
|
||||||
return 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;
|
return destHex+1;
|
||||||
}
|
}
|
||||||
else //if we are defender
|
else //if we are defender
|
||||||
{
|
{
|
||||||
if (vstd::contains(occupyableHexes, destHex-1))
|
if(vstd::contains(occupyableHexes, destHex-1))
|
||||||
return destHex-1;
|
return destHex-1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -2616,27 +2616,27 @@ BattleHex CBattleInterface::fromWhichHexAttack(BattleHex myNumber)
|
|||||||
{
|
{
|
||||||
bool doubleWide = activeStack->doubleWide();
|
bool doubleWide = activeStack->doubleWide();
|
||||||
destHex = myNumber - ( (myNumber/GameConstants::BFIELD_WIDTH)%2 ? GameConstants::BFIELD_WIDTH : GameConstants::BFIELD_WIDTH-1 ) +
|
destHex = myNumber - ( (myNumber/GameConstants::BFIELD_WIDTH)%2 ? GameConstants::BFIELD_WIDTH : GameConstants::BFIELD_WIDTH-1 ) +
|
||||||
(activeStack->attackerOwned && doubleWide ? 1 : 0);
|
(activeStack->side == BattleSide::ATTACKER && doubleWide ? 1 : 0);
|
||||||
if (vstd::contains(occupyableHexes, destHex))
|
if(vstd::contains(occupyableHexes, destHex))
|
||||||
return 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;
|
return destHex+1;
|
||||||
}
|
}
|
||||||
else //if we are defender
|
else //if we are defender
|
||||||
{
|
{
|
||||||
if (vstd::contains(occupyableHexes, destHex-1))
|
if(vstd::contains(occupyableHexes, destHex-1))
|
||||||
return destHex-1;
|
return destHex-1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 11: //from right
|
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);
|
std::vector<BattleHex> acc = curInt->cb->battleGetAvailableHexes(activeStack, false);
|
||||||
if (vstd::contains(acc, myNumber))
|
if(vstd::contains(acc, myNumber))
|
||||||
return myNumber + 1;
|
return myNumber + 1;
|
||||||
else
|
else
|
||||||
return myNumber + 2;
|
return myNumber + 2;
|
||||||
@ -2650,16 +2650,16 @@ BattleHex CBattleInterface::fromWhichHexAttack(BattleHex myNumber)
|
|||||||
case 13: //from bottom
|
case 13: //from bottom
|
||||||
{
|
{
|
||||||
destHex = myNumber + ( (myNumber/GameConstants::BFIELD_WIDTH)%2 ? GameConstants::BFIELD_WIDTH : GameConstants::BFIELD_WIDTH+1 );
|
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;
|
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;
|
return destHex+1;
|
||||||
}
|
}
|
||||||
else //if we are defender
|
else //if we are defender
|
||||||
{
|
{
|
||||||
if (vstd::contains(occupyableHexes, destHex-1))
|
if(vstd::contains(occupyableHexes, destHex-1))
|
||||||
return destHex-1;
|
return destHex-1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -2669,14 +2669,14 @@ BattleHex CBattleInterface::fromWhichHexAttack(BattleHex myNumber)
|
|||||||
destHex = myNumber - ( (myNumber/GameConstants::BFIELD_WIDTH)%2 ? GameConstants::BFIELD_WIDTH : GameConstants::BFIELD_WIDTH-1 );
|
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;
|
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;
|
return destHex+1;
|
||||||
}
|
}
|
||||||
else //if we are defender
|
else //if we are defender
|
||||||
{
|
{
|
||||||
if (vstd::contains(occupyableHexes, destHex-1))
|
if(vstd::contains(occupyableHexes, destHex-1))
|
||||||
return destHex-1;
|
return destHex-1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -3082,52 +3082,52 @@ void CBattleInterface::showAbsoluteObstacles(SDL_Surface *to)
|
|||||||
|
|
||||||
void CBattleInterface::showHighlightedHexes(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
|
previouslyHoveredHex = b; //something to start with
|
||||||
if (currentlyHoveredHex == -1)
|
if(currentlyHoveredHex == -1)
|
||||||
currentlyHoveredHex = b; //something to start with
|
currentlyHoveredHex = b; //something to start with
|
||||||
|
|
||||||
if (currentlyHoveredHex != b) //repair hover info
|
if(currentlyHoveredHex != b) //repair hover info
|
||||||
{
|
{
|
||||||
previouslyHoveredHex = currentlyHoveredHex;
|
previouslyHoveredHex = currentlyHoveredHex;
|
||||||
currentlyHoveredHex = b;
|
currentlyHoveredHex = b;
|
||||||
}
|
}
|
||||||
if (settings["battle"]["mouseShadow"].Bool())
|
if(settings["battle"]["mouseShadow"].Bool())
|
||||||
{
|
{
|
||||||
const ISpellCaster *caster = nullptr;
|
const ISpellCaster *caster = nullptr;
|
||||||
const CSpell *spell = nullptr;
|
const CSpell *spell = nullptr;
|
||||||
|
|
||||||
if (spellToCast)//hero casts spell
|
if(spellToCast)//hero casts spell
|
||||||
{
|
{
|
||||||
spell = SpellID(spellToCast->additionalInfo).toSpell();
|
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();
|
spell = SpellID(creatureSpellToCast).toSpell();
|
||||||
caster = activeStack;
|
caster = activeStack;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (caster && spell) //when casting spell
|
if(caster && spell) //when casting spell
|
||||||
{
|
{
|
||||||
//calculating spell school level
|
//calculating spell school level
|
||||||
ui8 schoolLevel = caster->getSpellSchoolLevel(spell);
|
ui8 schoolLevel = caster->getSpellSchoolLevel(spell);
|
||||||
|
|
||||||
// printing shaded hex(es)
|
// printing shaded hex(es)
|
||||||
auto shaded = spell->rangeInHexes(currentlyHoveredHex, schoolLevel, curInt->cb->battleGetMySide());
|
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);
|
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)
|
&& currentlyHoveredHex.getX() != GameConstants::BFIELD_WIDTH - 1)
|
||||||
showHighlightedHex(to, currentlyHoveredHex);
|
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);
|
std::set<BattleHex> set = curInt->cb->battleGetAttackedHexes(activeStack, currentlyHoveredHex, attackingHex);
|
||||||
for (BattleHex hex : set)
|
for(BattleHex hex : set)
|
||||||
showHighlightedHex(to, hex);
|
showHighlightedHex(to, hex);
|
||||||
|
|
||||||
// display the movement shadow of the stack at b (i.e. stack under mouse)
|
// display the movement shadow of the stack at b (i.e. stack under mouse)
|
||||||
const CStack *const shere = curInt->cb->battleGetStackByPos(currentlyHoveredHex, false);
|
const CStack * const shere = curInt->cb->battleGetStackByPos(currentlyHoveredHex, false);
|
||||||
if (shere && shere != activeStack && shere->alive())
|
if(shere && shere != activeStack && shere->alive())
|
||||||
{
|
{
|
||||||
std::vector<BattleHex> v = curInt->cb->battleGetAvailableHexes(shere, true );
|
std::vector<BattleHex> v = curInt->cb->battleGetAvailableHexes(shere, true );
|
||||||
for (BattleHex hex : v)
|
for(BattleHex hex : v)
|
||||||
showHighlightedHex(to, hex);
|
showHighlightedHex(to, hex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3321,13 +3321,15 @@ void CBattleInterface::showAliveStacks(SDL_Surface *to, std::vector<const CStack
|
|||||||
//printing amount
|
//printing amount
|
||||||
if (isAmountBoxVisible(stack))
|
if (isAmountBoxVisible(stack))
|
||||||
{
|
{
|
||||||
const BattleHex nextPos = stack->position + (stack->attackerOwned ? 1 : -1);
|
const int sideShift = stack->side == BattleSide::ATTACKER ? 1 : -1;
|
||||||
const bool edge = stack->position % GameConstants::BFIELD_WIDTH == (stack->attackerOwned ? GameConstants::BFIELD_WIDTH - 2 : 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];
|
const bool moveInside = !edge && !stackCountOutsideHexes[nextPos];
|
||||||
int xAdd = (stack->attackerOwned ? 220 : 202) +
|
int xAdd = (stack->side == BattleSide::ATTACKER ? 220 : 202) +
|
||||||
(stack->doubleWide() ? 44 : 0) *(stack->attackerOwned ? +1 : -1) +
|
(stack->doubleWide() ? 44 : 0) * sideShift +
|
||||||
(moveInside ? amountNormal->w + 10 : 0) *(stack->attackerOwned ? -1 : +1);
|
(moveInside ? amountNormal->w + 10 : 0) * reverseSideShift;
|
||||||
int yAdd = 260 + ((stack->attackerOwned || moveInside) ? 0 : -15);
|
int yAdd = 260 + ((stack->side == BattleSide::ATTACKER || moveInside) ? 0 : -15);
|
||||||
|
|
||||||
//blitting amount background box
|
//blitting amount background box
|
||||||
SDL_Surface *amountBG = amountNormal;
|
SDL_Surface *amountBG = amountNormal;
|
||||||
|
@ -384,7 +384,7 @@ CBattleResultWindow::CBattleResultWindow(const BattleResult &br, const SDL_Rect
|
|||||||
{
|
{
|
||||||
auto stacks = owner.cb->battleGetAllStacks();
|
auto stacks = owner.cb->battleGetAllStacks();
|
||||||
vstd::erase_if(stacks, [i](const CStack *stack) //erase stack of other side and not coming from garrison
|
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; });
|
auto best = vstd::maxElementByFun(stacks, [](const CStack *stack){ return stack->type->AIValue; });
|
||||||
if(best != stacks.end()) //should be always but to be safe...
|
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
|
//shifting position for double - hex creatures
|
||||||
if(stack->doubleWide())
|
if(stack->doubleWide())
|
||||||
{
|
{
|
||||||
if(stack->attackerOwned)
|
if(stack->side == BattleSide::ATTACKER)
|
||||||
{
|
{
|
||||||
if(cbi->creDir[stack->ID])
|
if(cbi->creDir[stack->ID])
|
||||||
ret.x -= 44;
|
ret.x -= 44;
|
||||||
|
@ -15,8 +15,8 @@
|
|||||||
#include "NetPacks.h"
|
#include "NetPacks.h"
|
||||||
|
|
||||||
|
|
||||||
CStack::CStack(const CStackInstance *Base, PlayerColor O, int I, bool AO, SlotID S)
|
CStack::CStack(const CStackInstance *Base, PlayerColor O, int I, ui8 Side, SlotID S)
|
||||||
: base(Base), ID(I), owner(O), slot(S), attackerOwned(AO),
|
: base(Base), ID(I), owner(O), slot(S), side(Side),
|
||||||
counterAttacksPerformed(0),counterAttacksTotalCache(0), cloneID(-1),
|
counterAttacksPerformed(0),counterAttacksTotalCache(0), cloneID(-1),
|
||||||
firstHPleft(-1), position(), shots(0), casts(0), resurrected(0)
|
firstHPleft(-1), position(), shots(0), casts(0), resurrected(0)
|
||||||
{
|
{
|
||||||
@ -30,8 +30,8 @@ CStack::CStack()
|
|||||||
init();
|
init();
|
||||||
setNodeType(STACK_BATTLE);
|
setNodeType(STACK_BATTLE);
|
||||||
}
|
}
|
||||||
CStack::CStack(const CStackBasicDescriptor *stack, PlayerColor O, int I, bool AO, SlotID S)
|
CStack::CStack(const CStackBasicDescriptor *stack, PlayerColor O, int I, ui8 Side, SlotID S)
|
||||||
: base(nullptr), ID(I), owner(O), slot(S), attackerOwned(AO),
|
: base(nullptr), ID(I), owner(O), slot(S), side(Side),
|
||||||
counterAttacksPerformed(0), counterAttacksTotalCache(0), cloneID(-1),
|
counterAttacksPerformed(0), counterAttacksTotalCache(0), cloneID(-1),
|
||||||
firstHPleft(-1), position(), shots(0), casts(0), resurrected(0)
|
firstHPleft(-1), position(), shots(0), casts(0), resurrected(0)
|
||||||
{
|
{
|
||||||
@ -49,7 +49,7 @@ void CStack::init()
|
|||||||
firstHPleft = -1;
|
firstHPleft = -1;
|
||||||
owner = PlayerColor::NEUTRAL;
|
owner = PlayerColor::NEUTRAL;
|
||||||
slot = SlotID(255);
|
slot = SlotID(255);
|
||||||
attackerOwned = false;
|
side = 1;
|
||||||
position = BattleHex();
|
position = BattleHex();
|
||||||
counterAttacksPerformed = 0;
|
counterAttacksPerformed = 0;
|
||||||
counterAttacksTotalCache = 0;
|
counterAttacksTotalCache = 0;
|
||||||
@ -145,9 +145,9 @@ BattleHex CStack::occupiedHex() const
|
|||||||
|
|
||||||
BattleHex CStack::occupiedHex(BattleHex assumedPos) const
|
BattleHex CStack::occupiedHex(BattleHex assumedPos) const
|
||||||
{
|
{
|
||||||
if (doubleWide())
|
if(doubleWide())
|
||||||
{
|
{
|
||||||
if (attackerOwned)
|
if(side == BattleSide::ATTACKER)
|
||||||
return assumedPos - 1;
|
return assumedPos - 1;
|
||||||
else
|
else
|
||||||
return assumedPos + 1;
|
return assumedPos + 1;
|
||||||
@ -165,17 +165,17 @@ std::vector<BattleHex> CStack::getHexes() const
|
|||||||
|
|
||||||
std::vector<BattleHex> CStack::getHexes(BattleHex assumedPos) 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;
|
std::vector<BattleHex> hexes;
|
||||||
hexes.push_back(assumedPos);
|
hexes.push_back(assumedPos);
|
||||||
|
|
||||||
if (twoHex)
|
if(twoHex)
|
||||||
{
|
{
|
||||||
if (AttackerOwned)
|
if(side == BattleSide::ATTACKER)
|
||||||
hexes.push_back(assumedPos - 1);
|
hexes.push_back(assumedPos - 1);
|
||||||
else
|
else
|
||||||
hexes.push_back(assumedPos + 1);
|
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
|
BattleHex hex = (attackerPos != BattleHex::INVALID) ? attackerPos : position; //use hypothetical position
|
||||||
std::vector<BattleHex> hexes;
|
std::vector<BattleHex> hexes;
|
||||||
if (doubleWide())
|
if(doubleWide())
|
||||||
{
|
{
|
||||||
const int WN = GameConstants::BFIELD_WIDTH;
|
const int WN = GameConstants::BFIELD_WIDTH;
|
||||||
if(attackerOwned)
|
if(side == BattleSide::ATTACKER)
|
||||||
{ //position is equal to front hex
|
{ //position is equal to front hex
|
||||||
BattleHex::checkAndPush(hex - ( (hex/WN)%2 ? WN+2 : WN+1 ), hexes);
|
BattleHex::checkAndPush(hex - ( (hex/WN)%2 ? WN+2 : WN+1 ), hexes);
|
||||||
BattleHex::checkAndPush(hex - ( (hex/WN)%2 ? WN+1 : WN ), 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> CStack::activeSpells() const
|
||||||
{
|
{
|
||||||
std::vector<si32> ret;
|
std::vector<si32> ret;
|
||||||
@ -382,11 +397,11 @@ bool CStack::isMeleeAttackPossible(const CStack * attacker, const CStack * defen
|
|||||||
return
|
return
|
||||||
(BattleHex::mutualPosition(attackerPos, defenderPos) >= 0) //front <=> front
|
(BattleHex::mutualPosition(attackerPos, defenderPos) >= 0) //front <=> front
|
||||||
|| (attacker->doubleWide() //back <=> 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
|
|| (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
|
|| (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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
12
lib/CStack.h
12
lib/CStack.h
@ -24,7 +24,7 @@ public:
|
|||||||
ui32 firstHPleft; //HP of first creature in stack
|
ui32 firstHPleft; //HP of first creature in stack
|
||||||
PlayerColor owner; //owner - player colour (255 for neutrals)
|
PlayerColor owner; //owner - player colour (255 for neutrals)
|
||||||
SlotID slot; //slot - position in garrison (may be 255 for neutrals/called creatures)
|
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
|
BattleHex position; //position on battlefield; -2 - keep, -3 - lower tower, -4 - upper tower
|
||||||
///how many times this stack has been counterattacked this round
|
///how many times this stack has been counterattacked this round
|
||||||
ui8 counterAttacksPerformed;
|
ui8 counterAttacksPerformed;
|
||||||
@ -39,8 +39,8 @@ public:
|
|||||||
//overrides
|
//overrides
|
||||||
const CCreature* getCreature() const {return type;}
|
const CCreature* getCreature() const {return type;}
|
||||||
|
|
||||||
CStack(const CStackInstance *base, PlayerColor O, int I, bool AO, SlotID S); //c-tor
|
CStack(const CStackInstance *base, PlayerColor O, int I, ui8 Side, SlotID S); //c-tor
|
||||||
CStack(const CStackBasicDescriptor *stack, PlayerColor O, int I, bool AO, SlotID S = SlotID(255)); //c-tor
|
CStack(const CStackBasicDescriptor *stack, PlayerColor O, int I, ui8 Side, SlotID S = SlotID(255)); //c-tor
|
||||||
CStack(); //c-tor
|
CStack(); //c-tor
|
||||||
~CStack();
|
~CStack();
|
||||||
std::string nodeName() const override;
|
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
|
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() const; //up to two occupied hexes, starting from front
|
||||||
std::vector<BattleHex> getHexes(BattleHex assumedPos) 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
|
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
|
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>
|
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
|
void prepareAttacked(BattleStackAttacked &bsa, CRandomGenerator & rand, boost::optional<int> customCount = boost::none) const; //requires bsa.damageAmout filled
|
||||||
|
|
||||||
@ -110,7 +112,7 @@ public:
|
|||||||
assert(isIndependentNode());
|
assert(isIndependentNode());
|
||||||
h & static_cast<CBonusSystemNode&>(*this);
|
h & static_cast<CBonusSystemNode&>(*this);
|
||||||
h & static_cast<CStackBasicDescriptor&>(*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;
|
& shots & casts & count & resurrected;
|
||||||
|
|
||||||
const CArmedInstance *army = (base ? base->armyObj : nullptr);
|
const CArmedInstance *army = (base ? base->armyObj : nullptr);
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "battle/BattleHex.h"
|
#include "battle/BattleHex.h"
|
||||||
|
#include "GameConstants.h"
|
||||||
#include "int3.h"
|
#include "int3.h"
|
||||||
|
|
||||||
class CGTownInstance;
|
class CGTownInstance;
|
||||||
|
@ -1628,13 +1628,13 @@ struct BattleStacksRemoved : public CPackForClient
|
|||||||
struct BattleStackAdded : public CPackForClient
|
struct BattleStackAdded : public CPackForClient
|
||||||
{
|
{
|
||||||
BattleStackAdded()
|
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);
|
DLL_LINKAGE void applyGs(CGameState *gs);
|
||||||
void applyCl(CClient *cl);
|
void applyCl(CClient *cl);
|
||||||
|
|
||||||
int attacker; // if true, stack belongs to attacker
|
ui8 side;
|
||||||
CreatureID creID;
|
CreatureID creID;
|
||||||
int amount;
|
int amount;
|
||||||
int pos;
|
int pos;
|
||||||
@ -1645,7 +1645,7 @@ struct BattleStackAdded : public CPackForClient
|
|||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
{
|
{
|
||||||
h & attacker & creID & amount & pos & summoned;
|
h & side & creID & amount & pos & summoned;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1384,7 +1384,7 @@ void BattleStackMoved::applyGs(CGameState *gs)
|
|||||||
{
|
{
|
||||||
SpellCreatedObstacle *sands = dynamic_cast<SpellCreatedObstacle*>(oi.get());
|
SpellCreatedObstacle *sands = dynamic_cast<SpellCreatedObstacle*>(oi.get());
|
||||||
assert(sands);
|
assert(sands);
|
||||||
if(sands->casterSide != !s->attackerOwned)
|
if(sands->casterSide != s->side)
|
||||||
sands->visibleForAnotherSide = true;
|
sands->visibleForAnotherSide = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1803,7 +1803,7 @@ DLL_LINKAGE void BattleStackAdded::applyGs(CGameState *gs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
CStackBasicDescriptor csbd(creID, amount);
|
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)
|
if (summoned)
|
||||||
addedStack->state.insert(EBattleStackState::SUMMONED);
|
addedStack->state.insert(EBattleStackState::SUMMONED);
|
||||||
|
|
||||||
|
@ -10,16 +10,17 @@
|
|||||||
#include "../StdInc.h"
|
#include "../StdInc.h"
|
||||||
#include "AccessibilityInfo.h"
|
#include "AccessibilityInfo.h"
|
||||||
#include "../CStack.h"
|
#include "../CStack.h"
|
||||||
|
#include "../GameConstants.h"
|
||||||
|
|
||||||
bool AccessibilityInfo::accessible(BattleHex tile, const CStack * stack) const
|
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.
|
// 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 the hex is out of range then the tile isn't accessible
|
||||||
if(!hex.isValid())
|
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
|
// If we're no defender which step on gate and the hex isn't accessible, then the tile
|
||||||
// isn't accessible
|
// isn't accessible
|
||||||
else if(at(hex) != EAccessibility::ACCESSIBLE &&
|
else if(at(hex) != EAccessibility::ACCESSIBLE &&
|
||||||
!(at(hex) == EAccessibility::GATE && !attackerOwned))
|
!(at(hex) == EAccessibility::GATE && side == BattleSide::DEFENDER))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
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;
|
|
||||||
}
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "BattleHex.h"
|
#include "BattleHex.h"
|
||||||
|
#include "../GameConstants.h"
|
||||||
|
|
||||||
class CStack;
|
class CStack;
|
||||||
|
|
||||||
@ -29,7 +30,6 @@ typedef std::array<EAccessibility, GameConstants::BFIELD_SIZE> TAccessibilityArr
|
|||||||
|
|
||||||
struct DLL_LINKAGE AccessibilityInfo : TAccessibilityArray
|
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, 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
|
||||||
};
|
};
|
||||||
|
@ -27,7 +27,7 @@ BattleAction::BattleAction():
|
|||||||
BattleAction BattleAction::makeHeal(const CStack * healer, const CStack * healed)
|
BattleAction BattleAction::makeHeal(const CStack * healer, const CStack * healed)
|
||||||
{
|
{
|
||||||
BattleAction ba;
|
BattleAction ba;
|
||||||
ba.side = !healer->attackerOwned;
|
ba.side = healer->side;
|
||||||
ba.actionType = STACK_HEAL;
|
ba.actionType = STACK_HEAL;
|
||||||
ba.stackNumber = healer->ID;
|
ba.stackNumber = healer->ID;
|
||||||
ba.destinationTile = healed->position;
|
ba.destinationTile = healed->position;
|
||||||
@ -37,7 +37,7 @@ BattleAction BattleAction::makeHeal(const CStack * healer, const CStack * healed
|
|||||||
BattleAction BattleAction::makeDefend(const CStack * stack)
|
BattleAction BattleAction::makeDefend(const CStack * stack)
|
||||||
{
|
{
|
||||||
BattleAction ba;
|
BattleAction ba;
|
||||||
ba.side = !stack->attackerOwned;
|
ba.side = stack->side;
|
||||||
ba.actionType = DEFEND;
|
ba.actionType = DEFEND;
|
||||||
ba.stackNumber = stack->ID;
|
ba.stackNumber = stack->ID;
|
||||||
return ba;
|
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 BattleAction::makeMeleeAttack(const CStack * stack, const CStack * attacked, BattleHex attackFrom /*= BattleHex::INVALID*/)
|
||||||
{
|
{
|
||||||
BattleAction ba;
|
BattleAction ba;
|
||||||
ba.side = !stack->attackerOwned;
|
ba.side = stack->side;
|
||||||
ba.actionType = WALK_AND_ATTACK;
|
ba.actionType = WALK_AND_ATTACK;
|
||||||
ba.stackNumber = stack->ID;
|
ba.stackNumber = stack->ID;
|
||||||
ba.destinationTile = attackFrom;
|
ba.destinationTile = attackFrom;
|
||||||
@ -58,7 +58,7 @@ BattleAction BattleAction::makeMeleeAttack(const CStack * stack, const CStack *
|
|||||||
BattleAction BattleAction::makeWait(const CStack * stack)
|
BattleAction BattleAction::makeWait(const CStack * stack)
|
||||||
{
|
{
|
||||||
BattleAction ba;
|
BattleAction ba;
|
||||||
ba.side = !stack->attackerOwned;
|
ba.side = stack->side;
|
||||||
ba.actionType = WAIT;
|
ba.actionType = WAIT;
|
||||||
ba.stackNumber = stack->ID;
|
ba.stackNumber = stack->ID;
|
||||||
return ba;
|
return ba;
|
||||||
@ -67,7 +67,7 @@ BattleAction BattleAction::makeWait(const CStack * stack)
|
|||||||
BattleAction BattleAction::makeShotAttack(const CStack * shooter, const CStack * target)
|
BattleAction BattleAction::makeShotAttack(const CStack * shooter, const CStack * target)
|
||||||
{
|
{
|
||||||
BattleAction ba;
|
BattleAction ba;
|
||||||
ba.side = !shooter->attackerOwned;
|
ba.side = shooter->side;
|
||||||
ba.actionType = SHOOT;
|
ba.actionType = SHOOT;
|
||||||
ba.stackNumber = shooter->ID;
|
ba.stackNumber = shooter->ID;
|
||||||
ba.destinationTile = target->position;
|
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 BattleAction::makeMove(const CStack * stack, BattleHex dest)
|
||||||
{
|
{
|
||||||
BattleAction ba;
|
BattleAction ba;
|
||||||
ba.side = !stack->attackerOwned;
|
ba.side = stack->side;
|
||||||
ba.actionType = WALK;
|
ba.actionType = WALK;
|
||||||
ba.stackNumber = stack->ID;
|
ba.stackNumber = stack->ID;
|
||||||
ba.destinationTile = dest;
|
ba.destinationTile = dest;
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "BattleHex.h"
|
#include "BattleHex.h"
|
||||||
|
#include "../GameConstants.h"
|
||||||
|
|
||||||
class CStack;
|
class CStack;
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
*/
|
*/
|
||||||
#include "../StdInc.h"
|
#include "../StdInc.h"
|
||||||
#include "BattleHex.h"
|
#include "BattleHex.h"
|
||||||
|
#include "../GameConstants.h"
|
||||||
|
|
||||||
BattleHex::BattleHex() : hex(INVALID) {}
|
BattleHex::BattleHex() : hex(INVALID) {}
|
||||||
|
|
||||||
@ -99,6 +100,8 @@ BattleHex& BattleHex::moveInDirection(EDir dir, bool hasToBeValid)
|
|||||||
case LEFT:
|
case LEFT:
|
||||||
setXY(x-1, y, hasToBeValid);
|
setXY(x-1, y, hasToBeValid);
|
||||||
break;
|
break;
|
||||||
|
case NONE:
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw std::runtime_error("Disaster: wrong direction in BattleHex::operator+=!\n");
|
throw std::runtime_error("Disaster: wrong direction in BattleHex::operator+=!\n");
|
||||||
break;
|
break;
|
||||||
@ -160,7 +163,7 @@ void BattleHex::checkAndPush(BattleHex tile, std::vector<BattleHex> & ret)
|
|||||||
ret.push_back(tile);
|
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 :(
|
std::vector<BattleHex> sortedTiles (possibilities.begin(), possibilities.end()); //set can't be sorted properly :(
|
||||||
BattleHex initialHex = BattleHex(initialPos);
|
BattleHex initialHex = BattleHex(initialPos);
|
||||||
@ -175,11 +178,11 @@ BattleHex BattleHex::getClosestTile(bool attackerOwned, BattleHex initialPos, st
|
|||||||
return closestDistance < here.getDistance (initialPos, here);
|
return closestDistance < here.getDistance (initialPos, here);
|
||||||
};
|
};
|
||||||
vstd::erase_if(sortedTiles, notClosest); //only closest tiles are interesting
|
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(left.getX() != right.getX())
|
||||||
{
|
{
|
||||||
if (attackerOwned)
|
if(side == BattleSide::ATTACKER)
|
||||||
return left.getX() > right.getX(); //find furthest right
|
return left.getX() > right.getX(); //find furthest right
|
||||||
else
|
else
|
||||||
return left.getX() < right.getX(); //find furthest left
|
return left.getX() < right.getX(); //find furthest left
|
||||||
|
@ -8,14 +8,35 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#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
|
// for battle stacks' positions
|
||||||
struct DLL_LINKAGE BattleHex //TODO: decide if this should be changed to class for better code design
|
struct DLL_LINKAGE BattleHex //TODO: decide if this should be changed to class for better code design
|
||||||
{
|
{
|
||||||
si16 hex;
|
si16 hex;
|
||||||
static const si16 INVALID = -1;
|
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();
|
||||||
BattleHex(si16 _hex);
|
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 signed char mutualPosition(BattleHex hex1, BattleHex hex2);
|
||||||
static char getDistance(BattleHex hex1, BattleHex hex2);
|
static char getDistance(BattleHex hex1, BattleHex hex2);
|
||||||
static void checkAndPush(BattleHex tile, std::vector<BattleHex> & ret);
|
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>
|
template <typename Handler>
|
||||||
void serialize(Handler &h, const int version)
|
void serialize(Handler &h, const int version)
|
||||||
|
@ -26,7 +26,7 @@ const CStack * BattleInfo::getNextStack() const
|
|||||||
return nullptr;
|
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 twoHex = VLC->creh->creatures[creID]->isDoubleWide();
|
||||||
//bool flying = VLC->creh->creatures[creID]->isFlying();
|
//bool flying = VLC->creh->creatures[creID]->isFlying();
|
||||||
@ -36,7 +36,7 @@ int BattleInfo::getAvaliableHex(CreatureID creID, bool attackerOwned, int initia
|
|||||||
pos = initialPos;
|
pos = initialPos;
|
||||||
else //summon elementals depending on player side
|
else //summon elementals depending on player side
|
||||||
{
|
{
|
||||||
if (attackerOwned)
|
if(side == BattleSide::ATTACKER)
|
||||||
pos = 0; //top left
|
pos = 0; //top left
|
||||||
else
|
else
|
||||||
pos = GameConstants::BFIELD_WIDTH - 1; //top right
|
pos = GameConstants::BFIELD_WIDTH - 1; //top right
|
||||||
@ -46,7 +46,7 @@ int BattleInfo::getAvaliableHex(CreatureID creID, bool attackerOwned, int initia
|
|||||||
|
|
||||||
std::set<BattleHex> occupyable;
|
std::set<BattleHex> occupyable;
|
||||||
for(int i = 0; i < accessibility.size(); i++)
|
for(int i = 0; i < accessibility.size(); i++)
|
||||||
if(accessibility.accessible(i, twoHex, attackerOwned))
|
if(accessibility.accessible(i, twoHex, side))
|
||||||
occupyable.insert(i);
|
occupyable.insert(i);
|
||||||
|
|
||||||
if (occupyable.empty())
|
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::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)
|
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);
|
si32 killed = (st->alive() ? (st->baseAmount - st->count + st->resurrected) : st->baseAmount);
|
||||||
vstd::amax(killed, 0);
|
vstd::amax(killed, 0);
|
||||||
if(killed)
|
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();
|
int stackID = getIdForNewStack();
|
||||||
PlayerColor owner = sides[attackerOwned ? 0 : 1].color;
|
PlayerColor owner = sides[side].color;
|
||||||
assert((owner >= PlayerColor::PLAYER_LIMIT) ||
|
assert((owner >= PlayerColor::PLAYER_LIMIT) ||
|
||||||
(base.armyObj && base.armyObj->tempOwner == owner));
|
(base.armyObj && base.armyObj->tempOwner == owner));
|
||||||
|
|
||||||
auto ret = new CStack(&base, owner, stackID, attackerOwned, slot);
|
auto ret = new CStack(&base, owner, stackID, side, slot);
|
||||||
ret->position = getAvaliableHex (base.getCreatureID(), attackerOwned, position); //TODO: what if no free tile on battlefield was found?
|
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
|
ret->state.insert(EBattleStackState::ALIVE); //alive state indication
|
||||||
return ret;
|
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();
|
int stackID = getIdForNewStack();
|
||||||
PlayerColor owner = sides[attackerOwned ? 0 : 1].color;
|
PlayerColor owner = sides[side].color;
|
||||||
auto ret = new CStack(&base, owner, stackID, attackerOwned, slot);
|
auto ret = new CStack(&base, owner, stackID, side, slot);
|
||||||
ret->position = position;
|
ret->position = position;
|
||||||
ret->state.insert(EBattleStackState::ALIVE); //alive state indication
|
ret->state.insert(EBattleStackState::ALIVE); //alive state indication
|
||||||
return ret;
|
return ret;
|
||||||
@ -155,7 +155,7 @@ void BattleInfo::localInitStack(CStack * s)
|
|||||||
}
|
}
|
||||||
else //attach directly to obj to which stack belongs and creature type
|
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);
|
s->attachTo(army);
|
||||||
assert(s->type);
|
assert(s->type);
|
||||||
s->attachTo(const_cast<CCreature*>(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())
|
if(creatureBank && i->second->type->isDoubleWide())
|
||||||
pos += side ? BattleHex::LEFT : BattleHex::RIGHT;
|
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);
|
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)
|
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]);
|
creatureBank ? commanderBank[i] : commanderField[i]);
|
||||||
stacks.push_back(stack);
|
stacks.push_back(stack);
|
||||||
}
|
}
|
||||||
@ -506,15 +506,15 @@ BattleInfo * BattleInfo::setupBattle(int3 tile, ETerrainType terrain, BFieldType
|
|||||||
if (curB->town && curB->town->fortLevel() >= CGTownInstance::CITADEL)
|
if (curB->town && curB->town->fortLevel() >= CGTownInstance::CITADEL)
|
||||||
{
|
{
|
||||||
// keep tower
|
// 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);
|
stacks.push_back(stack);
|
||||||
|
|
||||||
if (curB->town->fortLevel() >= CGTownInstance::CASTLE)
|
if (curB->town->fortLevel() >= CGTownInstance::CASTLE)
|
||||||
{
|
{
|
||||||
// lower tower + upper tower
|
// 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);
|
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);
|
stacks.push_back(stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,28 +55,17 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallb
|
|||||||
CGHeroInstance * battleGetFightingHero(ui8 side) const;
|
CGHeroInstance * battleGetFightingHero(ui8 side) const;
|
||||||
|
|
||||||
const CStack * getNextStack() const; //which stack will have turn after current one
|
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
|
int getAvaliableHex(CreatureID creID, ui8 side, int initialPos = -1) const; //find place for summon / clone effects
|
||||||
//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
|
|
||||||
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::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::shared_ptr<CObstacleInstance> getObstacleOnTile(BattleHex tile) const;
|
||||||
std::set<BattleHex> getStoppers(bool whichSidePerspective) 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)
|
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 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
|
CStack * generateNewStack(const CStackInstance &base, ui8 side, SlotID slot, BattleHex position) const; //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield
|
||||||
//std::set<CStack*> getAttackedCreatures(const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos = BattleHex::INVALID); //calculates range of multi-hex attacks
|
CStack * generateNewStack(const CStackBasicDescriptor &base, ui8 side, SlotID slot, BattleHex position) const; //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield
|
||||||
//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
|
|
||||||
int getIdForNewStack() const; //suggest a currently unused ID that'd suitable for generating a new stack
|
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
|
const CGHeroInstance * getHero(PlayerColor player) const; //returns fighting hero that belongs to given player
|
||||||
|
@ -103,10 +103,10 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastSpell(con
|
|||||||
return ESpellCastProblem::INVALID;
|
return ESpellCastProblem::INVALID;
|
||||||
}
|
}
|
||||||
const PlayerColor player = caster->getOwner();
|
const PlayerColor player = caster->getOwner();
|
||||||
const si8 side = playerToSide(player);
|
const auto side = playerToSide(player);
|
||||||
if(side < 0)
|
if(!side)
|
||||||
return ESpellCastProblem::INVALID;
|
return ESpellCastProblem::INVALID;
|
||||||
if(!battleDoWeKnowAbout(side))
|
if(!battleDoWeKnowAbout(side.get()))
|
||||||
{
|
{
|
||||||
logGlobal->warnStream() << "You can't check if enemy can cast given spell!";
|
logGlobal->warnStream() << "You can't check if enemy can cast given spell!";
|
||||||
return ESpellCastProblem::INVALID;
|
return ESpellCastProblem::INVALID;
|
||||||
@ -119,7 +119,7 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastSpell(con
|
|||||||
{
|
{
|
||||||
case ECastingMode::HERO_CASTING:
|
case ECastingMode::HERO_CASTING:
|
||||||
{
|
{
|
||||||
if(battleCastSpells(side) > 0)
|
if(battleCastSpells(side.get()) > 0)
|
||||||
return ESpellCastProblem::ALREADY_CASTED_THIS_TURN;
|
return ESpellCastProblem::ALREADY_CASTED_THIS_TURN;
|
||||||
|
|
||||||
auto hero = dynamic_cast<const CGHeroInstance *>(caster);
|
auto hero = dynamic_cast<const CGHeroInstance *>(caster);
|
||||||
@ -255,7 +255,7 @@ void CBattleInfoCallback::battleGetStackQueue(std::vector<const CStack *> &out,
|
|||||||
int bestSpeed = fastest->Speed(turn);
|
int bestSpeed = fastest->Speed(turn);
|
||||||
|
|
||||||
//FIXME: comparison between bool and integer. Logic does not makes sense either
|
//FIXME: comparison between bool and integer. Logic does not makes sense either
|
||||||
if(fastest->attackerOwned != lastMoved)
|
if(fastest->side != lastMoved)
|
||||||
{
|
{
|
||||||
ret = fastest;
|
ret = fastest;
|
||||||
}
|
}
|
||||||
@ -264,7 +264,7 @@ void CBattleInfoCallback::battleGetStackQueue(std::vector<const CStack *> &out,
|
|||||||
for(j = i + 1; j < st.size(); j++)
|
for(j = i + 1; j < st.size(); j++)
|
||||||
{
|
{
|
||||||
if(!st[j]) continue;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,7 +288,7 @@ void CBattleInfoCallback::battleGetStackQueue(std::vector<const CStack *> &out,
|
|||||||
else
|
else
|
||||||
st[j] = nullptr;
|
st[j] = nullptr;
|
||||||
|
|
||||||
lastMoved = ret->attackerOwned;
|
lastMoved = ret->side;
|
||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -362,9 +362,9 @@ void CBattleInfoCallback::battleGetStackQueue(std::vector<const CStack *> &out,
|
|||||||
{
|
{
|
||||||
//FIXME: both branches contain same code!!!
|
//FIXME: both branches contain same code!!!
|
||||||
if(out.size() && out.front() == active)
|
if(out.size() && out.front() == active)
|
||||||
lastMoved = active->attackerOwned;
|
lastMoved = active->side;
|
||||||
else
|
else
|
||||||
lastMoved = active->attackerOwned;
|
lastMoved = active->side;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -418,7 +418,7 @@ std::vector<BattleHex> CBattleInfoCallback::battleGetAvailableHexes(const CStack
|
|||||||
if(!reachability.isReachable(i))
|
if(!reachability.isReachable(i))
|
||||||
continue;
|
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
|
//Stack has to perform tactic-phase movement -> can enter any reachable tile within given range
|
||||||
if(!isInTacticRange(i))
|
if(!isInTacticRange(i))
|
||||||
@ -453,7 +453,7 @@ std::vector<BattleHex> CBattleInfoCallback::battleGetAvailableHexes(const CStack
|
|||||||
});
|
});
|
||||||
return availableNeighbor != ret.end();
|
return availableNeighbor != ret.end();
|
||||||
};
|
};
|
||||||
for(const CStack * otherSt : battleAliveStacks(stack->attackerOwned))
|
for(const CStack * otherSt : battleAliveStacks(1-stack->side))
|
||||||
{
|
{
|
||||||
if(!otherSt->isValidTarget(false))
|
if(!otherSt->isValidTarget(false))
|
||||||
continue;
|
continue;
|
||||||
@ -800,7 +800,6 @@ std::pair<ui32, ui32> CBattleInfoCallback::battleEstimateDamage(CRandomGenerator
|
|||||||
RETURN_IF_NOT_BATTLE(std::make_pair(0, 0));
|
RETURN_IF_NOT_BATTLE(std::make_pair(0, 0));
|
||||||
|
|
||||||
//const bool shooting = battleCanShoot(bai.attacker, bai.defenderPosition); //TODO handle bonus bearer
|
//const bool shooting = battleCanShoot(bai.attacker, bai.defenderPosition); //TODO handle bonus bearer
|
||||||
//const ui8 mySide = !attacker->attackerOwned;
|
|
||||||
|
|
||||||
TDmgRange ret = calculateDmgRange(bai);
|
TDmgRange ret = calculateDmgRange(bai);
|
||||||
|
|
||||||
@ -965,7 +964,7 @@ ReachabilityInfo CBattleInfoCallback::makeBFS(const AccessibilityInfo &accessibi
|
|||||||
const int costToNeighbour = ret.distances[curHex] + 1;
|
const int costToNeighbour = ret.distances[curHex] + 1;
|
||||||
for(BattleHex neighbour : curHex.neighbouringTiles())
|
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];
|
const int costFoundSoFar = ret.distances[neighbour];
|
||||||
|
|
||||||
if(accessible && costToNeighbour < costFoundSoFar)
|
if(accessible && costToNeighbour < costFoundSoFar)
|
||||||
@ -1001,7 +1000,7 @@ std::set<BattleHex> CBattleInfoCallback::getStoppers(BattlePerspective::BattlePe
|
|||||||
return ret;
|
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 reachability = getReachability(closest);
|
||||||
auto avHexes = battleGetAvailableHexes(closest, false);
|
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)
|
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)
|
for(const CStack * st : possibleStacks)
|
||||||
@ -1064,7 +1063,7 @@ ReachabilityInfo CBattleInfoCallback::getReachability(const CStack *stack) const
|
|||||||
{
|
{
|
||||||
ReachabilityInfo::Parameters params(stack);
|
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.
|
//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.
|
// 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++)
|
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.predecessors[i] = params.startPosition;
|
||||||
ret.distances[i] = BattleHex::getDistance(params.startPosition, i);
|
ret.distances[i] = BattleHex::getDistance(params.startPosition, i);
|
||||||
@ -1103,7 +1102,7 @@ AttackableTiles CBattleInfoCallback::getPotentiallyAttackableHexes (const CStack
|
|||||||
{
|
{
|
||||||
//does not return hex attacked directly
|
//does not return hex attacked directly
|
||||||
//TODO: apply rotation to two-hex attackers
|
//TODO: apply rotation to two-hex attackers
|
||||||
bool isAttacker = attacker->attackerOwned;
|
bool isAttacker = attacker->side == BattleSide::ATTACKER;
|
||||||
|
|
||||||
AttackableTiles at;
|
AttackableTiles at;
|
||||||
RETURN_IF_NOT_BATTLE(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_FIRE:
|
||||||
case SpellID::PROTECTION_FROM_WATER:
|
case SpellID::PROTECTION_FROM_WATER:
|
||||||
{
|
{
|
||||||
const ui8 enemySide = (ui8)subject->attackerOwned;
|
const ui8 enemySide = 1 - subject->side;
|
||||||
//todo: only if enemy has spellbook
|
//todo: only if enemy has spellbook
|
||||||
if (!battleHasHero(enemySide)) //only if there is enemy hero
|
if (!battleHasHero(enemySide)) //only if there is enemy hero
|
||||||
continue;
|
continue;
|
||||||
@ -1567,17 +1566,17 @@ int CBattleInfoCallback::battleGetSurrenderCost(PlayerColor Player) const
|
|||||||
if(!battleCanSurrender(Player))
|
if(!battleCanSurrender(Player))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
const si8 playerSide = playerToSide(Player);
|
const auto side = playerToSide(Player);
|
||||||
if(playerSide < 0)
|
if(!side)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
double discount = 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
|
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;
|
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);
|
discount += h->valOfBonuses(Bonus::SURRENDER_DISCOUNT);
|
||||||
|
|
||||||
ret *= (100.0 - discount) / 100.0;
|
ret *= (100.0 - discount) / 100.0;
|
||||||
@ -1616,7 +1615,7 @@ boost::optional<int> CBattleInfoCallback::battleIsFinished() const
|
|||||||
{
|
{
|
||||||
if(stack->alive() && !stack->hasBonusOfType(Bonus::SIEGE_WEAPON))
|
if(stack->alive() && !stack->hasBonusOfType(Bonus::SIEGE_WEAPON))
|
||||||
{
|
{
|
||||||
hasStack[1-stack->attackerOwned] = true;
|
hasStack[stack->side] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ public:
|
|||||||
AccessibilityInfo getAccesibility() const;
|
AccessibilityInfo getAccesibility() const;
|
||||||
AccessibilityInfo getAccesibility(const CStack *stack) const; //Hexes ocupied by stack will be marked as accessible.
|
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
|
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:
|
protected:
|
||||||
ReachabilityInfo getFlyingReachability(const ReachabilityInfo::Parameters & params) const;
|
ReachabilityInfo getFlyingReachability(const ReachabilityInfo::Parameters & params) const;
|
||||||
ReachabilityInfo makeBFS(const AccessibilityInfo & accessibility, const ReachabilityInfo::Parameters & params) const;
|
ReachabilityInfo makeBFS(const AccessibilityInfo & accessibility, const ReachabilityInfo::Parameters & params) const;
|
||||||
|
@ -67,7 +67,7 @@ bool CBattleInfoEssentials::battleHasNativeStack(ui8 side) const
|
|||||||
|
|
||||||
for(const CStack * s : battleGetAllStacks())
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,7 +102,7 @@ TStacks CBattleInfoEssentials::battleAliveStacks() const
|
|||||||
TStacks CBattleInfoEssentials::battleAliveStacks(ui8 side) const
|
TStacks CBattleInfoEssentials::battleAliveStacks(ui8 side) const
|
||||||
{
|
{
|
||||||
return battleGetStacksIf([=](const CStack * s){
|
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
|
bool CBattleInfoEssentials::battleCanFlee(PlayerColor player) const
|
||||||
{
|
{
|
||||||
RETURN_IF_NOT_BATTLE(false);
|
RETURN_IF_NOT_BATTLE(false);
|
||||||
const si8 mySide = playerToSide(player);
|
const auto side = playerToSide(player);
|
||||||
const CGHeroInstance *myHero = battleGetFightingHero(mySide);
|
if(!side)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const CGHeroInstance *myHero = battleGetFightingHero(side.get());
|
||||||
|
|
||||||
//current player have no hero
|
//current player have no hero
|
||||||
if(!myHero)
|
if(!myHero)
|
||||||
@ -249,7 +252,7 @@ bool CBattleInfoEssentials::battleCanFlee(PlayerColor player) const
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
//we are besieged defender
|
//we are besieged defender
|
||||||
if(mySide == BattleSide::DEFENDER && battleGetSiegeLevel())
|
if(side.get() == BattleSide::DEFENDER && battleGetSiegeLevel())
|
||||||
{
|
{
|
||||||
auto town = battleGetDefendedTown();
|
auto town = battleGetDefendedTown();
|
||||||
if(!town->hasBuilt(BuildingID::ESCAPE_TUNNEL, ETownType::STRONGHOLD))
|
if(!town->hasBuilt(BuildingID::ESCAPE_TUNNEL, ETownType::STRONGHOLD))
|
||||||
@ -259,23 +262,31 @@ bool CBattleInfoEssentials::battleCanFlee(PlayerColor player) const
|
|||||||
return true;
|
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; });
|
int ret = vstd::find_pos_if(getBattle()->sides, [=](const SideInBattle &side){ return side.color == player; });
|
||||||
if(ret < 0)
|
if(ret < 0)
|
||||||
logGlobal->warnStream() << "Cannot find side for player " << player;
|
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
|
bool CBattleInfoEssentials::playerHasAccessToHeroInfo(PlayerColor player, const CGHeroInstance * h) const
|
||||||
{
|
{
|
||||||
RETURN_IF_NOT_BATTLE(false);
|
RETURN_IF_NOT_BATTLE(false);
|
||||||
const si8 playerSide = playerToSide(player);
|
const auto side = playerToSide(player);
|
||||||
if (playerSide >= 0)
|
if(side)
|
||||||
{
|
{
|
||||||
if (getBattle()->sides[!playerSide].hero == h)
|
if (getBattle()->sides[otherSide(side.get())].hero == h)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -290,10 +301,12 @@ ui8 CBattleInfoEssentials::battleGetSiegeLevel() const
|
|||||||
bool CBattleInfoEssentials::battleCanSurrender(PlayerColor player) const
|
bool CBattleInfoEssentials::battleCanSurrender(PlayerColor player) const
|
||||||
{
|
{
|
||||||
RETURN_IF_NOT_BATTLE(false);
|
RETURN_IF_NOT_BATTLE(false);
|
||||||
ui8 mySide = playerToSide(player);
|
const auto side = playerToSide(player);
|
||||||
bool iAmSiegeDefender = (mySide == BattleSide::DEFENDER && battleGetSiegeLevel());
|
if(!side)
|
||||||
|
return false;
|
||||||
|
bool iAmSiegeDefender = (side.get() == BattleSide::DEFENDER && battleGetSiegeLevel());
|
||||||
//conditions like for fleeing (except escape tunnel presence) + enemy must have a hero
|
//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
|
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
|
const CGHeroInstance * CBattleInfoEssentials::battleGetOwnerHero(const CStack * stack) const
|
||||||
{
|
{
|
||||||
RETURN_IF_NOT_BATTLE(nullptr);
|
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
|
bool CBattleInfoEssentials::battleMatchOwner(const CStack * attacker, const CStack * defender, const boost::logic::tribool positivness /* = false*/) const
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "CCallbackBase.h"
|
#include "CCallbackBase.h"
|
||||||
|
#include "BattleHex.h"
|
||||||
|
|
||||||
class CGTownInstance;
|
class CGTownInstance;
|
||||||
class CGHeroInstance;
|
class CGHeroInstance;
|
||||||
@ -32,12 +33,6 @@ namespace BattlePerspective
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace BattleSide
|
|
||||||
{
|
|
||||||
enum {ATTACKER = 0, DEFENDER = 1};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class DLL_LINKAGE CBattleInfoEssentials : public virtual CCallbackBase
|
class DLL_LINKAGE CBattleInfoEssentials : public virtual CCallbackBase
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
@ -71,7 +66,8 @@ public:
|
|||||||
si8 battleGetTacticsSide() const; //returns which side is in tactics phase, undefined if none (?)
|
si8 battleGetTacticsSide() const; //returns which side is in tactics phase, undefined if none (?)
|
||||||
bool battleCanFlee(PlayerColor player) const;
|
bool battleCanFlee(PlayerColor player) const;
|
||||||
bool battleCanSurrender(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;
|
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
|
ui8 battleGetSiegeLevel() const; //returns 0 when there is no siege, 1 if fort, 2 is citadel, 3 is castle
|
||||||
bool battleHasHero(ui8 side) const;
|
bool battleHasHero(ui8 side) const;
|
||||||
|
@ -17,16 +17,17 @@ ReachabilityInfo::Parameters::Parameters()
|
|||||||
{
|
{
|
||||||
stack = nullptr;
|
stack = nullptr;
|
||||||
perspective = BattlePerspective::ALL_KNOWING;
|
perspective = BattlePerspective::ALL_KNOWING;
|
||||||
attackerOwned = doubleWide = flying = false;
|
side = 0;
|
||||||
|
doubleWide = flying = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReachabilityInfo::Parameters::Parameters(const CStack * Stack)
|
ReachabilityInfo::Parameters::Parameters(const CStack * Stack)
|
||||||
{
|
{
|
||||||
stack = Stack;
|
stack = Stack;
|
||||||
perspective = (BattlePerspective::BattlePerspective)(!Stack->attackerOwned);
|
perspective = (BattlePerspective::BattlePerspective)(Stack->side);
|
||||||
startPosition = Stack->position;
|
startPosition = Stack->position;
|
||||||
doubleWide = stack->doubleWide();
|
doubleWide = stack->doubleWide();
|
||||||
attackerOwned = stack->attackerOwned;
|
side = stack->side;
|
||||||
flying = stack->hasBonusOfType(Bonus::FLYING);
|
flying = stack->hasBonusOfType(Bonus::FLYING);
|
||||||
knownAccessible = stack->getHexes();
|
knownAccessible = stack->getHexes();
|
||||||
}
|
}
|
||||||
|
@ -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
|
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 doubleWide;
|
||||||
bool flying;
|
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)
|
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)
|
||||||
|
@ -104,7 +104,7 @@ std::vector<const CStack *> ChainLightningMechanics::calculateAffectedStacks(con
|
|||||||
}
|
}
|
||||||
if(possibleHexes.empty()) //not enough targets
|
if(possibleHexes.empty()) //not enough targets
|
||||||
break;
|
break;
|
||||||
lightningHex = BattleHex::getClosestTile(stack->attackerOwned, lightningHex, possibleHexes);
|
lightningHex = BattleHex::getClosestTile(stack->side, lightningHex, possibleHexes);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@ -121,13 +121,12 @@ void CloneMechanics::applyBattleEffects(const SpellCastEnvironment * env, const
|
|||||||
env->complain ("No target stack to clone!");
|
env->complain ("No target stack to clone!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const int attacker = !(bool)parameters.casterSide;
|
|
||||||
|
|
||||||
BattleStackAdded bsa;
|
BattleStackAdded bsa;
|
||||||
bsa.creID = clonedStack->type->idNumber;
|
bsa.creID = clonedStack->type->idNumber;
|
||||||
bsa.attacker = attacker;
|
bsa.side = parameters.casterSide;
|
||||||
bsa.summoned = true;
|
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;
|
bsa.amount = clonedStack->count;
|
||||||
env->sendAndApply(&bsa);
|
env->sendAndApply(&bsa);
|
||||||
|
|
||||||
@ -370,8 +369,11 @@ ESpellCastProblem::ESpellCastProblem EarthquakeMechanics::canBeCast(const CBattl
|
|||||||
CSpell::TargetInfo ti(owner, caster->getSpellSchoolLevel(owner));
|
CSpell::TargetInfo ti(owner, caster->getSpellSchoolLevel(owner));
|
||||||
if(ti.smart)
|
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 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;
|
return ESpellCastProblem::NO_APPROPRIATE_TARGET;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -407,13 +409,13 @@ ESpellCastProblem::ESpellCastProblem HypnotizeMechanics::isImmuneByStack(const I
|
|||||||
///ObstacleMechanics
|
///ObstacleMechanics
|
||||||
ESpellCastProblem::ESpellCastProblem ObstacleMechanics::canBeCast(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const
|
ESpellCastProblem::ESpellCastProblem ObstacleMechanics::canBeCast(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const
|
||||||
{
|
{
|
||||||
const si8 side = cb->playerToSide(ctx.caster->getOwner());
|
const auto side = cb->playerToSide(ctx.caster->getOwner());
|
||||||
if(side < 0)
|
if(!side)
|
||||||
return ESpellCastProblem::INVALID;
|
return ESpellCastProblem::INVALID;
|
||||||
|
|
||||||
bool hexesOutsideBattlefield = false;
|
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)
|
for(const BattleHex & hex : tilesThatMustBeClear)
|
||||||
if(!isHexAviable(cb, hex, ctx.ti.clearAffected))
|
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
|
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
|
//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());
|
const auto side = cb->playerToSide(caster->getOwner());
|
||||||
if(playerSide < 0)
|
if(!side)
|
||||||
return ESpellCastProblem::INVALID;
|
return ESpellCastProblem::INVALID;
|
||||||
|
|
||||||
const si8 otherSide = !playerSide;
|
const ui8 otherSide = cb->otherSide(side.get());
|
||||||
|
|
||||||
if(cb->battleHasNativeStack(otherSide))
|
if(cb->battleHasNativeStack(otherSide))
|
||||||
return ESpellCastProblem::NO_APPROPRIATE_TARGET;
|
return ESpellCastProblem::NO_APPROPRIATE_TARGET;
|
||||||
@ -887,9 +889,9 @@ void SummonMechanics::applyBattleEffects(const SpellCastEnvironment * env, const
|
|||||||
{
|
{
|
||||||
BattleStackAdded bsa;
|
BattleStackAdded bsa;
|
||||||
bsa.creID = creatureToSummon;
|
bsa.creID = creatureToSummon;
|
||||||
bsa.attacker = !(bool)parameters.casterSide;
|
bsa.side = parameters.casterSide;
|
||||||
bsa.summoned = true;
|
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
|
//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;
|
int percentBonus = parameters.casterHero ? parameters.casterHero->valOfBonuses(Bonus::SPECIFIC_SPELL_DAMAGE, owner->id.toEnum()) : 0;
|
||||||
|
@ -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
|
std::set<const CStack* > attackedCres;//std::set to exclude multiple occurrences of two hex creatures
|
||||||
|
|
||||||
const si8 playerSide = cb->playerToSide(ctx.caster->getOwner());
|
const auto side = cb->playerToSide(ctx.caster->getOwner());
|
||||||
if(playerSide < 0)
|
if(!side)
|
||||||
return std::vector<const CStack *>();
|
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
|
//hackfix for banned creature massive spells
|
||||||
if(!ctx.ti.massive && owner->getLevelInfo(ctx.schoolLvl).range == "X")
|
if(!ctx.ti.massive && owner->getLevelInfo(ctx.schoolLvl).range == "X")
|
||||||
|
@ -186,15 +186,15 @@ ESpellCastProblem::ESpellCastProblem CSpell::canBeCast(const CBattleInfoCallback
|
|||||||
return ESpellCastProblem::ADVMAP_SPELL_INSTEAD_OF_BATTLE_SPELL;
|
return ESpellCastProblem::ADVMAP_SPELL_INSTEAD_OF_BATTLE_SPELL;
|
||||||
|
|
||||||
const PlayerColor player = caster->getOwner();
|
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;
|
return ESpellCastProblem::INVALID;
|
||||||
|
|
||||||
//effect like Recanter's Cloak. Blocks also passive casting.
|
//effect like Recanter's Cloak. Blocks also passive casting.
|
||||||
//TODO: check creature abilities to block
|
//TODO: check creature abilities to block
|
||||||
//TODO: check any possible caster
|
//TODO: check any possible caster
|
||||||
if(cb->battleMaxSpellLevel(side) < level)
|
if(cb->battleMaxSpellLevel(side.get()) < level)
|
||||||
return ESpellCastProblem::SPELL_LEVEL_LIMIT_EXCEEDED;
|
return ESpellCastProblem::SPELL_LEVEL_LIMIT_EXCEEDED;
|
||||||
|
|
||||||
const ESpellCastProblem::ESpellCastProblem specificProblem = mechanics->canBeCast(cb, mode, caster);
|
const ESpellCastProblem::ESpellCastProblem specificProblem = mechanics->canBeCast(cb, mode, caster);
|
||||||
|
@ -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 x = targetPosition.getX();
|
||||||
int y = targetPosition.getY();
|
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...
|
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);
|
BattleHex::checkAndPush(targetPosition.cloneInDirection(BattleHex::EDir::RIGHT, false).cloneInDirection(BattleHex::EDir::RIGHT, false), output);
|
||||||
else
|
else
|
||||||
@ -1160,21 +1162,15 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
|
|||||||
auto accessibility = getAccesibility(curStack);
|
auto accessibility = getAccesibility(curStack);
|
||||||
|
|
||||||
//shifting destination (if we have double wide stack and we can occupy dest but not be exactly there)
|
//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)
|
BattleHex shifted = dest.cloneInDirection(curStack->destShiftDir());
|
||||||
{
|
|
||||||
if (accessibility.accessible(dest+1, curStack))
|
if(accessibility.accessible(shifted, curStack))
|
||||||
dest += BattleHex::RIGHT;
|
dest = shifted;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (accessibility.accessible(dest-1, curStack))
|
|
||||||
dest += BattleHex::LEFT;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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!");
|
complain("Given destination is not accessible!");
|
||||||
return 0;
|
return 0;
|
||||||
@ -1182,7 +1178,7 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
|
|||||||
|
|
||||||
bool canUseGate = false;
|
bool canUseGate = false;
|
||||||
auto dbState = gs->curB->si.gateState;
|
auto dbState = gs->curB->si.gateState;
|
||||||
if (battleGetSiegeLevel() > 0 && !curStack->attackerOwned &&
|
if(battleGetSiegeLevel() > 0 && curStack->side == BattleSide::DEFENDER &&
|
||||||
dbState != EGateState::DESTROYED &&
|
dbState != EGateState::DESTROYED &&
|
||||||
dbState != EGateState::BLOCKED)
|
dbState != EGateState::BLOCKED)
|
||||||
{
|
{
|
||||||
@ -3857,7 +3853,7 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
|
|||||||
|
|
||||||
if (battleTacticDist())
|
if (battleTacticDist())
|
||||||
{
|
{
|
||||||
if (stack && !stack->attackerOwned != battleGetTacticsSide())
|
if (stack && stack->side != battleGetTacticsSide())
|
||||||
{
|
{
|
||||||
complain("This is not a stack of side that has tactics!");
|
complain("This is not a stack of side that has tactics!");
|
||||||
return false;
|
return false;
|
||||||
@ -3951,10 +3947,8 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
|
|||||||
|
|
||||||
logGlobal->trace("%s will attack %s", stack->nodeName(), destinationStack->nodeName());
|
logGlobal->trace("%s will attack %s", stack->nodeName(), destinationStack->nodeName());
|
||||||
|
|
||||||
if (stack->position != ba.destinationTile //we wasn't able to reach destination tile
|
if(stack->position != ba.destinationTile //we wasn't able to reach destination tile
|
||||||
&& !(stack->doubleWide()
|
&& !(stack->doubleWide() && (stack->position == ba.destinationTile.cloneInDirection(stack->destShiftDir()))) //nor occupy specified hex
|
||||||
&& (stack->position == ba.destinationTile + (stack->attackerOwned ? +1 : -1))
|
|
||||||
) //nor occupy specified hex
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
complain("We cannot move this stack to its destination " + stack->getCreature()->namePl);
|
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!
|
CreatureID summonedType(summoner->getBonusLocalFirst(Selector::type(Bonus::DAEMON_SUMMONING))->subtype);//in case summoner can summon more than one type of monsters... scream!
|
||||||
BattleStackAdded bsa;
|
BattleStackAdded bsa;
|
||||||
bsa.attacker = summoner->attackerOwned;
|
bsa.side = summoner->side;
|
||||||
|
|
||||||
bsa.creID = summonedType;
|
bsa.creID = summonedType;
|
||||||
ui64 risedHp = summoner->count * summoner->valOfBonuses(Bonus::DAEMON_SUMMONING, bsa.creID.toEnum());
|
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.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;
|
bsa.summoned = false;
|
||||||
|
|
||||||
if (bsa.amount) //there's rare possibility single creature cannot rise desired type
|
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
|
//helper info
|
||||||
const SpellCreatedObstacle *spellObstacle = dynamic_cast<const SpellCreatedObstacle*>(&obstacle); //not nice but we may need spell params
|
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
|
const CGHeroInstance *hero = gs->curB->battleGetFightingHero(side);//FIXME: there may be no hero - landmines in Tower
|
||||||
|
|
||||||
if (obstacle.obstacleType == CObstacleInstance::MOAT)
|
if (obstacle.obstacleType == CObstacleInstance::MOAT)
|
||||||
@ -5416,6 +5410,7 @@ void CGameHandler::handleAfterAttackCasting(const BattleAttack & bat)
|
|||||||
|
|
||||||
BattleStackAdded resurrectInfo;
|
BattleStackAdded resurrectInfo;
|
||||||
resurrectInfo.pos = defender->position;
|
resurrectInfo.pos = defender->position;
|
||||||
|
resurrectInfo.side = defender->side;
|
||||||
|
|
||||||
if (bonusAdditionalInfo != -1)
|
if (bonusAdditionalInfo != -1)
|
||||||
resurrectInfo.creID = (CreatureID)bonusAdditionalInfo;
|
resurrectInfo.creID = (CreatureID)bonusAdditionalInfo;
|
||||||
@ -5515,7 +5510,7 @@ void CGameHandler::makeStackDoNothing(const CStack * next)
|
|||||||
doNothing.actionType = Battle::NO_ACTION;
|
doNothing.actionType = Battle::NO_ACTION;
|
||||||
doNothing.additionalInfo = 0;
|
doNothing.additionalInfo = 0;
|
||||||
doNothing.destinationTile = -1;
|
doNothing.destinationTile = -1;
|
||||||
doNothing.side = !next->attackerOwned;
|
doNothing.side = next->side;
|
||||||
doNothing.stackNumber = next->ID;
|
doNothing.stackNumber = next->ID;
|
||||||
|
|
||||||
makeAutomaticAction(next, doNothing);
|
makeAutomaticAction(next, doNothing);
|
||||||
@ -5708,16 +5703,16 @@ void CGameHandler::runBattle()
|
|||||||
if (!guardianIsBig)
|
if (!guardianIsBig)
|
||||||
targetHexes = stack->getSurroundingHexes();
|
targetHexes = stack->getSurroundingHexes();
|
||||||
else
|
else
|
||||||
summonGuardiansHelper(targetHexes, stack->position, stack->attackerOwned, targetIsBig);
|
summonGuardiansHelper(targetHexes, stack->position, stack->side, targetIsBig);
|
||||||
|
|
||||||
for (auto hex : targetHexes)
|
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;
|
BattleStackAdded newStack;
|
||||||
newStack.amount = std::max(1, (int)(stack->count * 0.01 * summonInfo->val));
|
newStack.amount = std::max(1, (int)(stack->count * 0.01 * summonInfo->val));
|
||||||
newStack.creID = creatureData.num;
|
newStack.creID = creatureData.num;
|
||||||
newStack.attacker = stack->attackerOwned;
|
newStack.side = stack->side;
|
||||||
newStack.summoned = true;
|
newStack.summoned = true;
|
||||||
newStack.pos = hex.hex;
|
newStack.pos = hex.hex;
|
||||||
sendAndApply(&newStack);
|
sendAndApply(&newStack);
|
||||||
@ -5808,7 +5803,7 @@ void CGameHandler::runBattle()
|
|||||||
BattleAction ba;
|
BattleAction ba;
|
||||||
ba.actionType = Battle::BAD_MORALE;
|
ba.actionType = Battle::BAD_MORALE;
|
||||||
ba.additionalInfo = 1;
|
ba.additionalInfo = 1;
|
||||||
ba.side = !next->attackerOwned;
|
ba.side = next->side;
|
||||||
ba.stackNumber = next->ID;
|
ba.stackNumber = next->ID;
|
||||||
|
|
||||||
makeAutomaticAction(next, ba);
|
makeAutomaticAction(next, ba);
|
||||||
@ -5819,12 +5814,12 @@ void CGameHandler::runBattle()
|
|||||||
if (next->hasBonusOfType(Bonus::ATTACKS_NEAREST_CREATURE)) //while in berserk
|
if (next->hasBonusOfType(Bonus::ATTACKS_NEAREST_CREATURE)) //while in berserk
|
||||||
{
|
{
|
||||||
logGlobal->debug("Handle Berserk effect");
|
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)
|
if (attackInfo.first != nullptr)
|
||||||
{
|
{
|
||||||
BattleAction attack;
|
BattleAction attack;
|
||||||
attack.actionType = Battle::WALK_AND_ATTACK;
|
attack.actionType = Battle::WALK_AND_ATTACK;
|
||||||
attack.side = !next->attackerOwned;
|
attack.side = next->side;
|
||||||
attack.stackNumber = next->ID;
|
attack.stackNumber = next->ID;
|
||||||
attack.additionalInfo = attackInfo.first->position;
|
attack.additionalInfo = attackInfo.first->position;
|
||||||
attack.destinationTile = attackInfo.second;
|
attack.destinationTile = attackInfo.second;
|
||||||
@ -5847,7 +5842,7 @@ void CGameHandler::runBattle()
|
|||||||
{
|
{
|
||||||
BattleAction attack;
|
BattleAction attack;
|
||||||
attack.actionType = Battle::SHOOT;
|
attack.actionType = Battle::SHOOT;
|
||||||
attack.side = !next->attackerOwned;
|
attack.side = next->side;
|
||||||
attack.stackNumber = next->ID;
|
attack.stackNumber = next->ID;
|
||||||
|
|
||||||
for (auto & elem : gs->curB->stacks)
|
for (auto & elem : gs->curB->stacks)
|
||||||
@ -5880,7 +5875,7 @@ void CGameHandler::runBattle()
|
|||||||
getRandomGenerator());
|
getRandomGenerator());
|
||||||
attack.actionType = Battle::CATAPULT;
|
attack.actionType = Battle::CATAPULT;
|
||||||
attack.additionalInfo = 0;
|
attack.additionalInfo = 0;
|
||||||
attack.side = !next->attackerOwned;
|
attack.side = next->side;
|
||||||
attack.stackNumber = next->ID;
|
attack.stackNumber = next->ID;
|
||||||
|
|
||||||
makeAutomaticAction(next, attack);
|
makeAutomaticAction(next, attack);
|
||||||
@ -5910,7 +5905,7 @@ void CGameHandler::runBattle()
|
|||||||
heal.actionType = Battle::STACK_HEAL;
|
heal.actionType = Battle::STACK_HEAL;
|
||||||
heal.additionalInfo = 0;
|
heal.additionalInfo = 0;
|
||||||
heal.destinationTile = toBeHealed->position;
|
heal.destinationTile = toBeHealed->position;
|
||||||
heal.side = !next->attackerOwned;
|
heal.side = next->side;
|
||||||
heal.stackNumber = next->ID;
|
heal.stackNumber = next->ID;
|
||||||
|
|
||||||
makeAutomaticAction(next, heal);
|
makeAutomaticAction(next, heal);
|
||||||
|
@ -91,16 +91,16 @@ BOOST_AUTO_TEST_CASE(getClosestTile)
|
|||||||
possibilities.insert(119);
|
possibilities.insert(119);
|
||||||
possibilities.insert(186);
|
possibilities.insert(186);
|
||||||
|
|
||||||
BOOST_TEST(mainHex.getClosestTile(true,mainHex,possibilities)==3);
|
BOOST_TEST(mainHex.getClosestTile(0,mainHex,possibilities)==3);
|
||||||
mainHex = 139;
|
mainHex = 139;
|
||||||
BOOST_TEST(mainHex.getClosestTile(false,mainHex,possibilities)==119);
|
BOOST_TEST(mainHex.getClosestTile(1,mainHex,possibilities)==119);
|
||||||
mainHex = 16;
|
mainHex = 16;
|
||||||
BOOST_TEST(mainHex.getClosestTile(false,mainHex,possibilities)==100);
|
BOOST_TEST(mainHex.getClosestTile(1,mainHex,possibilities)==100);
|
||||||
mainHex = 166;
|
mainHex = 166;
|
||||||
BOOST_TEST(mainHex.getClosestTile(true,mainHex,possibilities)==186);
|
BOOST_TEST(mainHex.getClosestTile(0,mainHex,possibilities)==186);
|
||||||
mainHex = 76;
|
mainHex = 76;
|
||||||
BOOST_TEST(mainHex.getClosestTile(false,mainHex,possibilities)==3);
|
BOOST_TEST(mainHex.getClosestTile(1,mainHex,possibilities)==3);
|
||||||
BOOST_TEST(mainHex.getClosestTile(true,mainHex,possibilities)==100);
|
BOOST_TEST(mainHex.getClosestTile(0,mainHex,possibilities)==100);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(moveEDir)
|
BOOST_AUTO_TEST_CASE(moveEDir)
|
||||||
@ -118,6 +118,8 @@ BOOST_AUTO_TEST_CASE(moveEDir)
|
|||||||
BOOST_TEST(mainHex==3);
|
BOOST_TEST(mainHex==3);
|
||||||
mainHex.moveInDirection(BattleHex::EDir::BOTTOM_LEFT);
|
mainHex.moveInDirection(BattleHex::EDir::BOTTOM_LEFT);
|
||||||
BOOST_TEST(mainHex==20);
|
BOOST_TEST(mainHex==20);
|
||||||
|
mainHex.moveInDirection(BattleHex::EDir::NONE);
|
||||||
|
BOOST_TEST(mainHex==20);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
Loading…
Reference in New Issue
Block a user