mirror of
https://github.com/vcmi/vcmi.git
synced 2024-11-28 08:48:48 +02:00
* some progress in StupidAI
* refactoring of battle handling WARNING: strange crash on entering battle
This commit is contained in:
parent
401b364ad7
commit
957f1764d7
@ -485,7 +485,7 @@ BattleAction CBattleLogic::MakeAttack(int attackerID, int destinationID)
|
||||
return BattleAction::makeDefend(attackerStack);
|
||||
}
|
||||
|
||||
if (m_cb->battleCanShoot(attackerID, m_cb->battleGetPos(destinationID))) // shoot
|
||||
if (m_cb->battleCanShoot(attackerStack, destinationStack->position)) // shoot
|
||||
{
|
||||
return BattleAction::makeShotAttack(attackerStack, destinationStack);
|
||||
}
|
||||
@ -519,7 +519,7 @@ BattleAction CBattleLogic::MakeAttack(int attackerID, int destinationID)
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<int> fields = m_cb->battleGetAvailableHexes(attackerID, false);
|
||||
std::vector<THex> fields = m_cb->battleGetAvailableHexes(m_cb->battleGetStackByID(attackerID), false);
|
||||
|
||||
if(fields.size() == 0)
|
||||
{
|
||||
@ -533,11 +533,11 @@ BattleAction CBattleLogic::MakeAttack(int attackerID, int destinationID)
|
||||
ba.destinationTile = static_cast<ui16>(dest_tile);
|
||||
//simplified checking for possibility of attack (previous was too simplified)
|
||||
int destStackPos = m_cb->battleGetPos(destinationID);
|
||||
if(BattleInfo::mutualPosition(dest_tile, destStackPos) != -1)
|
||||
if(THex::mutualPosition(dest_tile, destStackPos) != -1)
|
||||
ba.additionalInfo = destStackPos;
|
||||
else if(BattleInfo::mutualPosition(dest_tile, destStackPos+1) != -1)
|
||||
else if(THex::mutualPosition(dest_tile, destStackPos+1) != -1)
|
||||
ba.additionalInfo = destStackPos+1;
|
||||
else if(BattleInfo::mutualPosition(dest_tile, destStackPos-1) != -1)
|
||||
else if(THex::mutualPosition(dest_tile, destStackPos-1) != -1)
|
||||
ba.additionalInfo = destStackPos-1;
|
||||
else
|
||||
return BattleAction::makeDefend(attackerStack);
|
||||
@ -574,7 +574,7 @@ BattleAction CBattleLogic::MakeAttack(int attackerID, int destinationID)
|
||||
}
|
||||
}
|
||||
|
||||
for (std::vector<int>::const_iterator it = fields.begin(); it != fields.end(); ++it)
|
||||
for (std::vector<THex>::const_iterator it = fields.begin(); it != fields.end(); ++it)
|
||||
{
|
||||
if (*it == dest_tile)
|
||||
{
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "stdafx.h"
|
||||
#include "StupidAI.h"
|
||||
#include "../../lib/BattleState.h"
|
||||
#include "../../CCallback.h"
|
||||
|
||||
CStupidAI::CStupidAI(void)
|
||||
: side(-1), cb(NULL)
|
||||
@ -33,12 +34,38 @@ void CStupidAI::actionStarted( const BattleAction *action )
|
||||
BattleAction CStupidAI::activeStack( const CStack * stack )
|
||||
{
|
||||
print("activeStack called");
|
||||
std::vector<THex> avHexes = cb->battleGetAvailableHexes(stack, false);
|
||||
std::vector<const CStack *> avEnemies;
|
||||
for(int g=0; g<avHexes.size(); ++g)
|
||||
{
|
||||
const CStack * enemy = cb->battleGetStackByPos(avHexes[g]);
|
||||
if (enemy)
|
||||
{
|
||||
avEnemies.push_back(enemy);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(stack->position % 17 < 5) //move army little towards enemy
|
||||
{
|
||||
THex dest = stack->position + !side*2 - 1;
|
||||
print(stack->nodeName() + "will be moved to " + boost::lexical_cast<std::string>(dest));
|
||||
return BattleAction::makeMove(stack, dest);
|
||||
}
|
||||
|
||||
if(avEnemies.size())
|
||||
{
|
||||
const CStack * enemy = avEnemies[0];
|
||||
//shooting
|
||||
if (cb->battleCanShoot(stack, enemy->position))
|
||||
{
|
||||
return BattleAction::makeShotAttack(stack, enemy);
|
||||
}
|
||||
|
||||
//melee
|
||||
return BattleAction::makeMeleeAttack(stack, enemy, avHexes);
|
||||
}
|
||||
|
||||
return BattleAction::makeDefend(stack);
|
||||
}
|
||||
|
||||
|
@ -517,10 +517,10 @@ int CBattleCallback::battleMakeAction(BattleAction* action)
|
||||
return 0;
|
||||
}
|
||||
|
||||
const CStack* CBattleCallback::battleGetStackByPos(int pos, bool onlyAlive)
|
||||
const CStack* CBattleCallback::battleGetStackByPos(THex pos, bool onlyAlive)
|
||||
{
|
||||
boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
||||
return battleGetStackByID(gs->battleGetStack(pos, onlyAlive), onlyAlive);
|
||||
return gs->curB->battleGetStack(pos, onlyAlive);
|
||||
}
|
||||
|
||||
int CBattleCallback::battleGetPos(int stack)
|
||||
@ -565,25 +565,25 @@ void CBattleCallback::getStackQueue( std::vector<const CStack *> &out, int howMa
|
||||
gs->curB->getStackQueue(out, howMany);
|
||||
}
|
||||
|
||||
std::vector<int> CBattleCallback::battleGetAvailableHexes(int ID, bool addOccupiable)
|
||||
std::vector<THex> CBattleCallback::battleGetAvailableHexes(const CStack * stack, bool addOccupiable)
|
||||
{
|
||||
boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
||||
if(!gs->curB)
|
||||
{
|
||||
tlog2<<"battleGetAvailableHexes called when there is no battle!"<<std::endl;
|
||||
return std::vector<int>();
|
||||
return std::vector<THex>();
|
||||
}
|
||||
return gs->curB->getAccessibility(ID, addOccupiable);
|
||||
return gs->curB->getAccessibility(stack, addOccupiable);
|
||||
//return gs->battleGetRange(ID);
|
||||
}
|
||||
|
||||
bool CBattleCallback::battleCanShoot(int ID, int dest)
|
||||
bool CBattleCallback::battleCanShoot(const CStack * stack, THex dest)
|
||||
{
|
||||
boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
||||
|
||||
if(!gs->curB) return false;
|
||||
|
||||
return gs->battleCanShoot(ID, dest);
|
||||
return gs->curB->battleCanShoot(stack, dest);
|
||||
}
|
||||
|
||||
bool CBattleCallback::battleCanCastSpell()
|
||||
@ -599,15 +599,15 @@ bool CBattleCallback::battleCanCastSpell()
|
||||
|
||||
bool CBattleCallback::battleCanFlee()
|
||||
{
|
||||
return gs->battleCanFlee(player);
|
||||
return gs->curB->battleCanFlee(player);
|
||||
}
|
||||
|
||||
const CGTownInstance *CBattleCallback::battleGetDefendedTown()
|
||||
{
|
||||
if(!gs->curB || gs->curB->tid == -1)
|
||||
if(!gs->curB || gs->curB->town == NULL)
|
||||
return NULL;
|
||||
|
||||
return static_cast<const CGTownInstance *>(gs->map->objects[gs->curB->tid].get());
|
||||
return gs->curB->town;
|
||||
}
|
||||
|
||||
ui8 CBattleCallback::battleGetWallState(int partOfWall)
|
||||
@ -649,7 +649,7 @@ std::pair<ui32, ui32> CBattleCallback::battleEstimateDamage(int attackerID, int
|
||||
const CStack * attacker = gs->curB->getStack(attackerID, false),
|
||||
* defender = gs->curB->getStack(defenderID);
|
||||
|
||||
return gs->curB->calculateDmgRange(attacker, defender, attackerHero, defenderHero, battleCanShoot(attacker->ID, defender->position), 0, false);
|
||||
return gs->curB->calculateDmgRange(attacker, defender, attackerHero, defenderHero, battleCanShoot(attacker, defender->position), 0, false);
|
||||
}
|
||||
|
||||
ui8 CBattleCallback::battleGetSiegeLevel()
|
||||
@ -917,19 +917,19 @@ bool CCallback::hasAccess(int playerId) const
|
||||
return gs->getPlayerRelations( playerId, player ) || player < 0;
|
||||
}
|
||||
|
||||
si8 CBattleCallback::battleHasDistancePenalty( int stackID, int destHex )
|
||||
si8 CBattleCallback::battleHasDistancePenalty( const CStack * stack, THex destHex )
|
||||
{
|
||||
return gs->curB->hasDistancePenalty(stackID, destHex);
|
||||
return gs->curB->hasDistancePenalty(stack, destHex);
|
||||
}
|
||||
|
||||
si8 CBattleCallback::battleHasWallPenalty( int stackID, int destHex )
|
||||
si8 CBattleCallback::battleHasWallPenalty( const CStack * stack, THex destHex )
|
||||
{
|
||||
return gs->curB->hasWallPenalty(stackID, destHex);
|
||||
return gs->curB->hasWallPenalty(stack, destHex);
|
||||
}
|
||||
|
||||
si8 CBattleCallback::battleCanTeleportTo(int stackID, int destHex, int telportLevel)
|
||||
si8 CBattleCallback::battleCanTeleportTo(const CStack * stack, THex destHex, int telportLevel)
|
||||
{
|
||||
return gs->curB->canTeleportTo(stackID, destHex, telportLevel);
|
||||
return gs->curB->canTeleportTo(stack, destHex, telportLevel);
|
||||
}
|
||||
|
||||
int CCallback::getPlayerStatus(int player) const
|
||||
|
55
CCallback.h
55
CCallback.h
@ -79,13 +79,13 @@ public:
|
||||
virtual int battleGetObstaclesAtTile(THex tile)=0; //returns bitfield
|
||||
virtual std::vector<CObstacleInstance> battleGetAllObstacles()=0; //returns all obstacles on the battlefield
|
||||
virtual const CStack * battleGetStackByID(int ID, bool onlyAlive = true)=0; //returns stack info by given ID
|
||||
virtual const CStack * battleGetStackByPos(int pos, bool onlyAlive = true)=0; //returns stack info by given pos
|
||||
virtual const CStack * battleGetStackByPos(THex pos, bool onlyAlive = true)=0; //returns stack info by given pos
|
||||
virtual int battleGetPos(int stack)=0; //returns position (tile ID) of stack
|
||||
virtual int battleMakeAction(BattleAction* action)=0;//for casting spells by hero - DO NOT use it for moving active stack
|
||||
virtual std::vector<const CStack*> battleGetStacks()=0; //returns stacks on battlefield
|
||||
virtual void getStackQueue( std::vector<const CStack *> &out, int howMany )=0; //returns vector of stack in order of their move sequence
|
||||
virtual std::vector<int> battleGetAvailableHexes(int ID, bool addOccupiable)=0; //returns numbers of hexes reachable by creature with id ID
|
||||
virtual bool battleCanShoot(int ID, int dest)=0; //returns true if unit with id ID can shoot to dest
|
||||
virtual std::vector<THex> battleGetAvailableHexes(const CStack * stack, bool addOccupiable)=0; //returns numbers of hexes reachable by creature with id ID
|
||||
virtual bool battleCanShoot(const CStack * stack, THex dest)=0; //returns true if unit with id ID can shoot to dest
|
||||
virtual bool battleCanCastSpell()=0; //returns true, if caller can cast a spell
|
||||
virtual bool battleCanFlee()=0; //returns true if caller can flee from the battle
|
||||
virtual const CGTownInstance * battleGetDefendedTown()=0; //returns defended town if current battle is a siege, NULL instead
|
||||
@ -94,8 +94,9 @@ public:
|
||||
virtual std::pair<ui32, ui32> battleEstimateDamage(int attackerID, int defenderID)=0; //estimates damage dealt by attacker to defender; it may be not precise especially when stack has randomly working bonuses; returns pair <min dmg, max dmg>
|
||||
virtual ui8 battleGetSiegeLevel()=0; //returns 0 when there is no siege, 1 if fort, 2 is citadel, 3 is castle
|
||||
virtual const CGHeroInstance * battleGetFightingHero(ui8 side) const =0; //returns hero corresponding to given side (0 - attacker, 1 - defender)
|
||||
virtual si8 battleHasDistancePenalty(int stackID, int destHex) =0; //checks if given stack has distance penalty
|
||||
virtual si8 battleHasWallPenalty(int stackID, int destHex) =0; //checks if given stack has wall penalty
|
||||
virtual si8 battleHasDistancePenalty(const CStack * stack, THex destHex) =0; //checks if given stack has distance penalty
|
||||
virtual si8 battleHasWallPenalty(const CStack * stack, THex destHex) =0; //checks if given stack has wall penalty
|
||||
virtual si8 battleCanTeleportTo(const CStack * stack, THex destHex, int telportLevel) =0; //checks if teleportation of given stack to given position can take place
|
||||
};
|
||||
|
||||
class ICallback : public virtual IBattleCallback
|
||||
@ -201,28 +202,28 @@ protected:
|
||||
|
||||
public:
|
||||
//battle
|
||||
int battleGetBattlefieldType(); // 1. sand/shore 2. sand/mesas 3. dirt/birches 4. dirt/hills 5. dirt/pines 6. grass/hills 7. grass/pines 8. lava 9. magic plains 10. snow/mountains 11. snow/trees 12. subterranean 13. swamp/trees 14. fiery fields 15. rock lands 16. magic clouds 17. lucid pools 18. holy ground 19. clover field 20. evil fog 21. "favourable winds" text on magic plains background 22. cursed ground 23. rough 24. ship to ship 25. ship
|
||||
int battleGetObstaclesAtTile(THex tile); //returns bitfield
|
||||
std::vector<CObstacleInstance> battleGetAllObstacles(); //returns all obstacles on the battlefield
|
||||
const CStack * battleGetStackByID(int ID, bool onlyAlive = true); //returns stack info by given ID
|
||||
const CStack * battleGetStackByPos(int pos, bool onlyAlive = true); //returns stack info by given pos
|
||||
int battleGetPos(int stack); //returns position (tile ID) of stack
|
||||
int battleMakeAction(BattleAction* action);//for casting spells by hero - DO NOT use it for moving active stack
|
||||
std::vector<const CStack*> battleGetStacks(); //returns stacks on battlefield
|
||||
void getStackQueue( std::vector<const CStack *> &out, int howMany ); //returns vector of stack in order of their move sequence
|
||||
std::vector<int> battleGetAvailableHexes(int ID, bool addOccupiable); //reutrns numbers of hexes reachable by creature with id ID
|
||||
bool battleCanShoot(int ID, int dest); //returns true if unit with id ID can shoot to dest
|
||||
bool battleCanCastSpell(); //returns true, if caller can cast a spell
|
||||
bool battleCanFlee(); //returns true if caller can flee from the battle
|
||||
const CGTownInstance * battleGetDefendedTown(); //returns defended town if current battle is a siege, NULL instead
|
||||
ui8 battleGetWallState(int partOfWall); //for determining state of a part of the wall; format: parameter [0] - keep, [1] - bottom tower, [2] - bottom wall, [3] - below gate, [4] - over gate, [5] - upper wall, [6] - uppert tower, [7] - gate; returned value: 1 - intact, 2 - damaged, 3 - destroyed; 0 - no battle
|
||||
int battleGetWallUnderHex(int hex); //returns part of destructible wall / gate / keep under given hex or -1 if not found
|
||||
std::pair<ui32, ui32> battleEstimateDamage(int attackerID, int defenderID); //estimates damage dealt by attacker to defender; it may be not precise especially when stack has randomly working bonuses; returns pair <min dmg, max dmg>
|
||||
ui8 battleGetSiegeLevel(); //returns 0 when there is no siege, 1 if fort, 2 is citadel, 3 is castle
|
||||
const CGHeroInstance * battleGetFightingHero(ui8 side) const; //returns hero corresponding ot given side (0 - attacker, 1 - defender)
|
||||
si8 battleHasDistancePenalty(int stackID, int destHex); //checks if given stack has distance penalty
|
||||
si8 battleHasWallPenalty(int stackID, int destHex); //checks if given stack has wall penalty
|
||||
si8 battleCanTeleportTo(int stackID, int destHex, int telportLevel); //checks if teleportation of given stack to given position can take place
|
||||
int battleGetBattlefieldType() OVERRIDE; // 1. sand/shore 2. sand/mesas 3. dirt/birches 4. dirt/hills 5. dirt/pines 6. grass/hills 7. grass/pines 8. lava 9. magic plains 10. snow/mountains 11. snow/trees 12. subterranean 13. swamp/trees 14. fiery fields 15. rock lands 16. magic clouds 17. lucid pools 18. holy ground 19. clover field 20. evil fog 21. "favourable winds" text on magic plains background 22. cursed ground 23. rough 24. ship to ship 25. ship
|
||||
int battleGetObstaclesAtTile(THex tile) OVERRIDE; //returns bitfield
|
||||
std::vector<CObstacleInstance> battleGetAllObstacles() OVERRIDE; //returns all obstacles on the battlefield
|
||||
const CStack * battleGetStackByID(int ID, bool onlyAlive = true) OVERRIDE; //returns stack info by given ID
|
||||
const CStack * battleGetStackByPos(THex pos, bool onlyAlive = true) OVERRIDE; //returns stack info by given pos
|
||||
int battleGetPos(int stack) OVERRIDE; //returns position (tile ID) of stack
|
||||
int battleMakeAction(BattleAction* action) OVERRIDE;//for casting spells by hero - DO NOT use it for moving active stack
|
||||
std::vector<const CStack*> battleGetStacks() OVERRIDE; //returns stacks on battlefield
|
||||
void getStackQueue( std::vector<const CStack *> &out, int howMany ) OVERRIDE; //returns vector of stack in order of their move sequence
|
||||
std::vector<THex> battleGetAvailableHexes(const CStack * stack, bool addOccupiable) OVERRIDE; //reutrns numbers of hexes reachable by creature with id ID
|
||||
bool battleCanShoot(const CStack * stack, THex dest) OVERRIDE; //returns true if unit with id ID can shoot to dest
|
||||
bool battleCanCastSpell() OVERRIDE; //returns true, if caller can cast a spell
|
||||
bool battleCanFlee() OVERRIDE; //returns true if caller can flee from the battle
|
||||
const CGTownInstance * battleGetDefendedTown() OVERRIDE; //returns defended town if current battle is a siege, NULL instead
|
||||
ui8 battleGetWallState(int partOfWall) OVERRIDE; //for determining state of a part of the wall; format: parameter [0] - keep, [1] - bottom tower, [2] - bottom wall, [3] - below gate, [4] - over gate, [5] - upper wall, [6] - uppert tower, [7] - gate; returned value: 1 - intact, 2 - damaged, 3 - destroyed; 0 - no battle
|
||||
int battleGetWallUnderHex(int hex) OVERRIDE; //returns part of destructible wall / gate / keep under given hex or -1 if not found
|
||||
std::pair<ui32, ui32> battleEstimateDamage(int attackerID, int defenderID) OVERRIDE; //estimates damage dealt by attacker to defender; it may be not precise especially when stack has randomly working bonuses; returns pair <min dmg, max dmg>
|
||||
ui8 battleGetSiegeLevel() OVERRIDE; //returns 0 when there is no siege, 1 if fort, 2 is citadel, 3 is castle
|
||||
const CGHeroInstance * battleGetFightingHero(ui8 side) const OVERRIDE; //returns hero corresponding ot given side (0 - attacker, 1 - defender)
|
||||
si8 battleHasDistancePenalty(const CStack * stack, THex destHex) OVERRIDE; //checks if given stack has distance penalty
|
||||
si8 battleHasWallPenalty(const CStack * stack, THex destHex) OVERRIDE; //checks if given stack has wall penalty
|
||||
si8 battleCanTeleportTo(const CStack * stack, THex destHex, int telportLevel) OVERRIDE; //checks if teleportation of given stack to given position can take place
|
||||
|
||||
friend CCallback;
|
||||
friend CClient;
|
||||
|
@ -603,7 +603,7 @@ bool CBattleStackMoved::init()
|
||||
Point begPosition = CBattleHex::getXYUnitAnim(curStackPos, movedStack->attackerOwned, movedStack, owner);
|
||||
Point endPosition = CBattleHex::getXYUnitAnim(destHex, movedStack->attackerOwned, movedStack, owner);
|
||||
|
||||
int mutPos = BattleInfo::mutualPosition(curStackPos, destHex);
|
||||
int mutPos = THex::mutualPosition(curStackPos, destHex);
|
||||
|
||||
//reverse unit if necessary
|
||||
if((begPosition.x > endPosition.x) && owner->creDir[stack->ID] == true)
|
||||
@ -879,9 +879,9 @@ bool CMeleeAttack::init()
|
||||
int reversedShift = 0; //shift of attacking stack's position due to reversing
|
||||
if(attackingStack->attackerOwned)
|
||||
{
|
||||
if(attackingStack->doubleWide() && BattleInfo::mutualPosition(attackingStackPosBeforeReturn, dest) == -1)
|
||||
if(attackingStack->doubleWide() && THex::mutualPosition(attackingStackPosBeforeReturn, dest) == -1)
|
||||
{
|
||||
if(BattleInfo::mutualPosition(attackingStackPosBeforeReturn + (attackingStack->attackerOwned ? -1 : 1), dest) >= 0) //if reversing stack will make its position adjacent to dest
|
||||
if(THex::mutualPosition(attackingStackPosBeforeReturn + (attackingStack->attackerOwned ? -1 : 1), dest) >= 0) //if reversing stack will make its position adjacent to dest
|
||||
{
|
||||
reversedShift = (attackingStack->attackerOwned ? -1 : 1);
|
||||
}
|
||||
@ -889,9 +889,9 @@ bool CMeleeAttack::init()
|
||||
}
|
||||
else //if(astack->attackerOwned)
|
||||
{
|
||||
if(attackingStack->doubleWide() && BattleInfo::mutualPosition(attackingStackPosBeforeReturn, dest) == -1)
|
||||
if(attackingStack->doubleWide() && THex::mutualPosition(attackingStackPosBeforeReturn, dest) == -1)
|
||||
{
|
||||
if(BattleInfo::mutualPosition(attackingStackPosBeforeReturn + (attackingStack->attackerOwned ? -1 : 1), dest) >= 0) //if reversing stack will make its position adjacent to dest
|
||||
if(THex::mutualPosition(attackingStackPosBeforeReturn + (attackingStack->attackerOwned ? -1 : 1), dest) >= 0) //if reversing stack will make its position adjacent to dest
|
||||
{
|
||||
reversedShift = (attackingStack->attackerOwned ? -1 : 1);
|
||||
}
|
||||
@ -912,7 +912,7 @@ bool CMeleeAttack::init()
|
||||
|
||||
static const int mutPosToGroup[] = {11, 11, 12, 13, 13, 12};
|
||||
|
||||
int mutPos = BattleInfo::mutualPosition(attackingStackPosBeforeReturn + reversedShift, dest);
|
||||
int mutPos = THex::mutualPosition(attackingStackPosBeforeReturn + reversedShift, dest);
|
||||
switch(mutPos) //attack direction
|
||||
{
|
||||
case 0: case 1: case 2: case 3: case 4: case 5:
|
||||
@ -1792,10 +1792,10 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent)
|
||||
}
|
||||
|
||||
}
|
||||
else if(curInt->cb->battleCanShoot(activeStack->ID,myNumber)) //we can shoot enemy
|
||||
else if(curInt->cb->battleCanShoot(activeStack,myNumber)) //we can shoot enemy
|
||||
{
|
||||
if(curInt->cb->battleHasDistancePenalty(activeStack->ID, myNumber) ||
|
||||
curInt->cb->battleHasWallPenalty(activeStack->ID, myNumber))
|
||||
if(curInt->cb->battleHasDistancePenalty(activeStack, myNumber) ||
|
||||
curInt->cb->battleHasWallPenalty(activeStack, myNumber))
|
||||
{
|
||||
CCS->curh->changeGraphic(1,15);
|
||||
}
|
||||
@ -2336,7 +2336,7 @@ bool CBattleInterface::isTileAttackable(const int & number) const
|
||||
{
|
||||
for(size_t b=0; b<shadedHexes.size(); ++b)
|
||||
{
|
||||
if(BattleInfo::mutualPosition(shadedHexes[b], number) != -1 || shadedHexes[b] == number)
|
||||
if(THex::mutualPosition(shadedHexes[b], number) != -1 || shadedHexes[b] == number)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -2417,7 +2417,7 @@ void CBattleInterface::hexLclicked(int whichOne)
|
||||
case 5: //teleport
|
||||
const CSpell *s = CGI->spellh->spells[spellToCast->additionalInfo];
|
||||
ui8 skill = getActiveHero()->getSpellSchoolLevel(s); //skill level
|
||||
if (!curInt->cb->battleCanTeleportTo(activeStack->ID, whichOne, skill))
|
||||
if (!curInt->cb->battleCanTeleportTo(activeStack, whichOne, skill))
|
||||
{
|
||||
allowCasting = false;
|
||||
}
|
||||
@ -2441,7 +2441,7 @@ void CBattleInterface::hexLclicked(int whichOne)
|
||||
CCS->curh->changeGraphic(1, 6); //cursor should be changed
|
||||
if(activeStack->doubleWide())
|
||||
{
|
||||
std::vector<int> acc = curInt->cb->battleGetAvailableHexes(activeStack->ID, false);
|
||||
std::vector<THex> acc = curInt->cb->battleGetAvailableHexes(activeStack, false);
|
||||
int shiftedDest = whichOne + (activeStack->attackerOwned ? 1 : -1);
|
||||
if(vstd::contains(acc, whichOne))
|
||||
giveCommand(2,whichOne,activeStack->ID);
|
||||
@ -2459,7 +2459,7 @@ void CBattleInterface::hexLclicked(int whichOne)
|
||||
}
|
||||
}
|
||||
else if(dest->owner != actSt->owner
|
||||
&& curInt->cb->battleCanShoot(activeStack->ID, whichOne) ) //shooting
|
||||
&& curInt->cb->battleCanShoot(activeStack, whichOne) ) //shooting
|
||||
{
|
||||
CCS->curh->changeGraphic(1, 6); //cursor should be changed
|
||||
giveCommand(7,whichOne,activeStack->ID);
|
||||
@ -2510,7 +2510,7 @@ void CBattleInterface::hexLclicked(int whichOne)
|
||||
{
|
||||
if(actStack->doubleWide() && !actStack->attackerOwned)
|
||||
{
|
||||
std::vector<int> acc = curInt->cb->battleGetAvailableHexes(activeStack->ID, false);
|
||||
std::vector<THex> acc = curInt->cb->battleGetAvailableHexes(activeStack, false);
|
||||
if(vstd::contains(acc, whichOne))
|
||||
attackFromHex = whichOne - 1;
|
||||
else
|
||||
@ -2562,7 +2562,7 @@ void CBattleInterface::hexLclicked(int whichOne)
|
||||
{
|
||||
if(actStack->doubleWide() && actStack->attackerOwned)
|
||||
{
|
||||
std::vector<int> acc = curInt->cb->battleGetAvailableHexes(activeStack->ID, false);
|
||||
std::vector<THex> acc = curInt->cb->battleGetAvailableHexes(activeStack, false);
|
||||
if(vstd::contains(acc, whichOne))
|
||||
attackFromHex = whichOne + 1;
|
||||
else
|
||||
@ -3120,7 +3120,7 @@ void CBattleInterface::showPieceOfWall(SDL_Surface * to, int hex, const std::vec
|
||||
|
||||
void CBattleInterface::redrawBackgroundWithHexes(const CStack * activeStack)
|
||||
{
|
||||
shadedHexes = curInt->cb->battleGetAvailableHexes(activeStack->ID, true);
|
||||
shadedHexes = curInt->cb->battleGetAvailableHexes(activeStack, true);
|
||||
|
||||
//preparating background graphic with hexes and shaded hexes
|
||||
blitAt(background, 0, 0, backgroundWithHexes);
|
||||
|
@ -394,7 +394,7 @@ private:
|
||||
const CStack * stackToActivate; //when animation is playing, we should wait till the end to make the next stack active; NULL of none
|
||||
void activateStack(); //sets activeStack to stackToActivate etc.
|
||||
int mouseHoveredStack; //stack hovered by mouse; if -1 -> none
|
||||
std::vector<int> shadedHexes; //hexes available for active stack
|
||||
std::vector<THex> shadedHexes; //hexes available for active stack
|
||||
int previouslyHoveredHex; //number of hex that was hovered by the cursor a while ago
|
||||
int currentlyHoveredHex; //number of hex that is supposed to be hovered (for a while it may be inappropriately set, but will be renewed soon)
|
||||
float getAnimSpeedMultiplier() const; //returns multiplier for number of frames in a group
|
||||
|
@ -834,10 +834,10 @@ void CPlayerInterface::battleAttack(const BattleAttack *ba)
|
||||
else
|
||||
{//WARNING: does not support multiple attacked creatures
|
||||
int shift = 0;
|
||||
if(ba->counter() && BattleInfo::mutualPosition(curAction->destinationTile, attacker->position) < 0)
|
||||
if(ba->counter() && THex::mutualPosition(curAction->destinationTile, attacker->position) < 0)
|
||||
{
|
||||
int distp = BattleInfo::getDistance(curAction->destinationTile + 1, attacker->position);
|
||||
int distm = BattleInfo::getDistance(curAction->destinationTile - 1, attacker->position);
|
||||
int distp = THex::getDistance(curAction->destinationTile + 1, attacker->position);
|
||||
int distm = THex::getDistance(curAction->destinationTile - 1, attacker->position);
|
||||
|
||||
if( distp < distm )
|
||||
shift = 1;
|
||||
|
159
global.h
159
global.h
@ -7,6 +7,7 @@
|
||||
#include <boost/logic/tribool.hpp>
|
||||
using boost::logic::tribool;
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <assert.h>
|
||||
typedef boost::uint64_t ui64; //unsigned int 64 bits (8 bytes)
|
||||
typedef boost::uint32_t ui32; //unsigned int 32 bits (4 bytes)
|
||||
typedef boost::uint16_t ui16; //unsigned int 16 bits (2 bytes)
|
||||
@ -17,7 +18,8 @@ typedef boost::int16_t si16; //signed int 16 bits (2 bytes)
|
||||
typedef boost::int8_t si8; //signed int 8 bits (1 byte)
|
||||
typedef si64 expType;
|
||||
typedef ui16 spelltype;
|
||||
typedef ui16 THex; //for battle stacks' positions
|
||||
|
||||
|
||||
#include "int3.h"
|
||||
#include <map>
|
||||
#include <vector>
|
||||
@ -126,6 +128,161 @@ const int BFIELD_SIZE = BFIELD_WIDTH * BFIELD_HEIGHT;
|
||||
|
||||
const int SPELLBOOK_GOLD_COST = 500;
|
||||
|
||||
|
||||
//for battle stacks' positions
|
||||
struct THex
|
||||
{
|
||||
enum EDir{RIGHT, BOTTOM_RIGHT, BOTTOM_LEFT, LEFT, TOP_LEFT, TOP_RIGHT};
|
||||
|
||||
si16 hex;
|
||||
|
||||
THex() : hex(-1) {}
|
||||
THex(si16 _hex) : hex(_hex)
|
||||
{
|
||||
assert(hex >= 0 && hex < BFIELD_SIZE);
|
||||
}
|
||||
operator si16() const
|
||||
{
|
||||
return hex;
|
||||
}
|
||||
|
||||
template<typename inttype>
|
||||
THex(inttype x, inttype y)
|
||||
{
|
||||
setXY(x, y);
|
||||
}
|
||||
|
||||
template<typename inttype>
|
||||
THex(std::pair<inttype, inttype> xy)
|
||||
{
|
||||
setXY(xy);
|
||||
}
|
||||
|
||||
template<typename inttype>
|
||||
void setX(inttype x)
|
||||
{
|
||||
setXY(x, getY());
|
||||
}
|
||||
|
||||
template<typename inttype>
|
||||
void setY(inttype y)
|
||||
{
|
||||
setXY(getX(), y);
|
||||
}
|
||||
|
||||
void setXY(si16 x, si16 y)
|
||||
{
|
||||
assert(x >= 0 && x < BFIELD_WIDTH && y >= 0 && y < BFIELD_HEIGHT);
|
||||
hex = x + y * BFIELD_WIDTH;
|
||||
}
|
||||
|
||||
template<typename inttype>
|
||||
void setXY(std::pair<inttype, inttype> xy)
|
||||
{
|
||||
setXY(xy.first, xy.second);
|
||||
}
|
||||
|
||||
si16 getY() const
|
||||
{
|
||||
return hex/BFIELD_WIDTH;
|
||||
}
|
||||
|
||||
si16 getX() const
|
||||
{
|
||||
int pos = hex - getY() * BFIELD_WIDTH;
|
||||
return pos;
|
||||
}
|
||||
|
||||
std::pair<si16, si16> getXY() const
|
||||
{
|
||||
return std::make_pair(getX(), getY());
|
||||
}
|
||||
|
||||
//moving to direction
|
||||
void operator+=(EDir dir)
|
||||
{
|
||||
si16 x = getX(),
|
||||
y = getY();
|
||||
|
||||
switch(dir)
|
||||
{
|
||||
case TOP_LEFT:
|
||||
setXY(y%2 ? x-1 : x, y-1);
|
||||
case TOP_RIGHT:
|
||||
setXY(y%2 ? x : x+1, y-1);
|
||||
case RIGHT:
|
||||
setXY(x+1, y);
|
||||
case BOTTOM_RIGHT:
|
||||
setXY(y%2 ? x : x+1, y+1);
|
||||
case BOTTOM_LEFT:
|
||||
setXY(y%2 ? x-1 : x, y+1);
|
||||
case LEFT:
|
||||
setXY(x-1, y);
|
||||
default:
|
||||
throw std::string("Disaster: wrong direction in THex::operator+=!\n");
|
||||
}
|
||||
}
|
||||
|
||||
//generates new THex moved by given dir
|
||||
THex operator+(EDir dir) const
|
||||
{
|
||||
THex ret(*this);
|
||||
ret += dir;
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<THex> neighbouringTiles() const
|
||||
{
|
||||
std::vector<THex> ret;
|
||||
const int WN = BFIELD_WIDTH;
|
||||
checkAndPush(hex - ( (hex/WN)%2 ? WN+1 : WN ), ret);
|
||||
checkAndPush(hex - ( (hex/WN)%2 ? WN : WN-1 ), ret);
|
||||
checkAndPush(hex - 1, ret);
|
||||
checkAndPush(hex + 1, ret);
|
||||
checkAndPush(hex + ( (hex/WN)%2 ? WN-1 : WN ), ret);
|
||||
checkAndPush(hex + ( (hex/WN)%2 ? WN : WN+1 ), ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//returns info about mutual position of given hexes (-1 - they're distant, 0 - left top, 1 - right top, 2 - right, 3 - right bottom, 4 - left bottom, 5 - left)
|
||||
static signed char mutualPosition(THex hex1, THex hex2)
|
||||
{
|
||||
if(hex2 == hex1 - ( (hex1/17)%2 ? 18 : 17 )) //top left
|
||||
return 0;
|
||||
if(hex2 == hex1 - ( (hex1/17)%2 ? 17 : 16 )) //top right
|
||||
return 1;
|
||||
if(hex2 == hex1 - 1 && hex1%17 != 0) //left
|
||||
return 5;
|
||||
if(hex2 == hex1 + 1 && hex1%17 != 16) //right
|
||||
return 2;
|
||||
if(hex2 == hex1 + ( (hex1/17)%2 ? 16 : 17 )) //bottom left
|
||||
return 4;
|
||||
if(hex2 == hex1 + ( (hex1/17)%2 ? 17 : 18 )) //bottom right
|
||||
return 3;
|
||||
return -1;
|
||||
}
|
||||
//returns distance between given hexes
|
||||
static si8 getDistance(THex hex1, THex hex2)
|
||||
{
|
||||
int xDst = std::abs(hex1 % BFIELD_WIDTH - hex2 % BFIELD_WIDTH),
|
||||
yDst = std::abs(hex1 / BFIELD_WIDTH - hex2 / BFIELD_WIDTH);
|
||||
return std::max(xDst, yDst) + std::min(xDst, yDst) - (yDst + 1)/2;
|
||||
}
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & hex;
|
||||
}
|
||||
private:
|
||||
static void checkAndPush(int tile, std::vector<THex> & ret)
|
||||
{
|
||||
if( tile>=0 && tile<BFIELD_SIZE && (tile%BFIELD_WIDTH != (BFIELD_WIDTH - 1)) && (tile%BFIELD_WIDTH != 0) )
|
||||
ret.push_back(THex(tile));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
enum EMarketMode
|
||||
{
|
||||
RESOURCE_RESOURCE, RESOURCE_PLAYER, CREATURE_RESOURCE, RESOURCE_ARTIFACT,
|
||||
|
@ -30,12 +30,31 @@ BattleAction BattleAction::makeDefend(const CStack *stack)
|
||||
return ba;
|
||||
}
|
||||
|
||||
BattleAction BattleAction::makeMeleeAttack(const CStack *stack) /*WARNING: stacks must be neighbouring! */
|
||||
BattleAction BattleAction::makeMeleeAttack( const CStack *stack, const CStack * attacked, std::vector<THex> reachableByAttacker )
|
||||
{
|
||||
BattleAction ba;
|
||||
ba.side = !stack->attackerOwned;
|
||||
ba.actionType = WAIT;
|
||||
ba.actionType = WALK_AND_ATTACK;
|
||||
ba.stackNumber = stack->ID;
|
||||
ba.destinationTile = -1;
|
||||
for (int g=0; g<reachableByAttacker.size(); ++g)
|
||||
{
|
||||
if (THex::mutualPosition(reachableByAttacker[g], attacked->position) >= 0 )
|
||||
{
|
||||
ba.destinationTile = reachableByAttacker[g];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ba.destinationTile == -1)
|
||||
{
|
||||
//we couldn't determine appropriate pos
|
||||
//TODO: should we throw an exception?
|
||||
return makeDefend(stack);
|
||||
}
|
||||
|
||||
ba.additionalInfo = attacked->position;
|
||||
|
||||
return ba;
|
||||
}
|
||||
|
||||
|
@ -23,8 +23,7 @@ struct DLL_EXPORT BattleAction
|
||||
{
|
||||
INVALID = -1, NO_ACTION = 0, HERO_SPELL, WALK, DEFEND, RETREAT, SURRENDER, WALK_AND_ATTACK, SHOOT, WAIT, CATAPULT, MONSTER_SPELL, BAD_MORALE, STACK_HEAL
|
||||
};
|
||||
ui8 actionType; // 0 = No action; 1 = Hero cast a spell 2 = Walk 3 = Defend 4 = Retreat from the battle
|
||||
//5 = Surrender 6 = Walk and Attack 7 = Shoot 8 = Wait 9 = Catapult
|
||||
ui8 actionType; //use ActionType enum for values
|
||||
//10 = Monster casts a spell (i.e. Faerie Dragons) 11 - Bad morale freeze 12 - stacks heals another stack
|
||||
ui16 destinationTile;
|
||||
si32 additionalInfo; // e.g. spell number if type is 1 || 10; tile to attack if type is 6
|
||||
@ -37,7 +36,7 @@ struct DLL_EXPORT BattleAction
|
||||
|
||||
static BattleAction makeDefend(const CStack *stack);
|
||||
static BattleAction makeWait(const CStack *stack);
|
||||
static BattleAction makeMeleeAttack(const CStack *stack); //WARNING: stacks must be neighbouring!;
|
||||
static BattleAction makeMeleeAttack(const CStack *stack, const CStack * attacked, std::vector<THex> reachableByAttacker);
|
||||
static BattleAction makeShotAttack(const CStack *shooter, const CStack *target);
|
||||
static BattleAction makeMove(const CStack *stack, THex dest);
|
||||
};
|
||||
|
@ -129,7 +129,7 @@ const CStack * BattleInfo::getStackT(THex tileID, bool onlyAlive) const
|
||||
return const_cast<BattleInfo * const>(this)->getStackT(tileID, onlyAlive);
|
||||
}
|
||||
|
||||
void BattleInfo::getAccessibilityMap(bool *accessibility, bool twoHex, bool attackerOwned, bool addOccupiable, std::set<int> & occupyable, bool flying, int stackToOmmit) const
|
||||
void BattleInfo::getAccessibilityMap(bool *accessibility, bool twoHex, bool attackerOwned, bool addOccupiable, std::set<THex> & occupyable, bool flying, const CStack * stackToOmmit) const
|
||||
{
|
||||
memset(accessibility, 1, BFIELD_SIZE); //initialize array with trues
|
||||
|
||||
@ -142,7 +142,7 @@ void BattleInfo::getAccessibilityMap(bool *accessibility, bool twoHex, bool atta
|
||||
|
||||
for(unsigned int g=0; g<stacks.size(); ++g)
|
||||
{
|
||||
if(!stacks[g]->alive() || stacks[g]->ID==stackToOmmit || stacks[g]->position < 0) //we don't want to lock position of this stack (eg. if it's a turret)
|
||||
if(!stacks[g]->alive() || stacks[g]->ID==stackToOmmit->ID || stacks[g]->position < 0) //we don't want to lock position of this stack (eg. if it's a turret)
|
||||
continue;
|
||||
|
||||
accessibility[stacks[g]->position] = false;
|
||||
@ -174,8 +174,9 @@ void BattleInfo::getAccessibilityMap(bool *accessibility, bool twoHex, bool atta
|
||||
accessibility[permanentlyLocked[b]] = false;
|
||||
}
|
||||
|
||||
static const std::pair<int, int> lockedIfNotDestroyed[] = //(which part of wall, which hex is blocked if this part of wall is not destroyed
|
||||
{std::make_pair(2, 182), std::make_pair(3, 130), std::make_pair(4, 62), std::make_pair(5, 29)};
|
||||
static const std::pair<int, THex> lockedIfNotDestroyed[] = //(which part of wall, which hex is blocked if this part of wall is not destroyed
|
||||
{std::make_pair(2, THex(182)), std::make_pair(3, THex(130)),
|
||||
std::make_pair(4, THex(62)), std::make_pair(5, THex(29))};
|
||||
for(int b=0; b<ARRAY_COUNT(lockedIfNotDestroyed); ++b)
|
||||
{
|
||||
if(si.wallState[lockedIfNotDestroyed[b].first] < 3)
|
||||
@ -194,12 +195,12 @@ void BattleInfo::getAccessibilityMap(bool *accessibility, bool twoHex, bool atta
|
||||
//occupyability
|
||||
if(addOccupiable && twoHex)
|
||||
{
|
||||
std::set<int> rem; //tiles to unlock
|
||||
std::set<THex> rem; //tiles to unlock
|
||||
for(int h=0; h<BFIELD_HEIGHT; ++h)
|
||||
{
|
||||
for(int w=1; w<BFIELD_WIDTH-1; ++w)
|
||||
{
|
||||
int hex = h * BFIELD_WIDTH + w;
|
||||
THex hex(w, h);
|
||||
if(!isAccessible(hex, accessibility, twoHex, attackerOwned, flying, true)
|
||||
&& (attackerOwned ? isAccessible(hex+1, accessibility, twoHex, attackerOwned, flying, true) : isAccessible(hex-1, accessibility, twoHex, attackerOwned, flying, true) )
|
||||
)
|
||||
@ -230,7 +231,7 @@ bool BattleInfo::isAccessible(int hex, bool * accessibility, bool twoHex, bool a
|
||||
}
|
||||
}
|
||||
|
||||
void BattleInfo::makeBFS(int start, bool *accessibility, int *predecessor, int *dists, bool twoHex, bool attackerOwned, bool flying, bool fillPredecessors) const //both pointers must point to the at least 187-elements int arrays
|
||||
void BattleInfo::makeBFS(THex start, bool *accessibility, int *predecessor, int *dists, bool twoHex, bool attackerOwned, bool flying, bool fillPredecessors) const //both pointers must point to the at least 187-elements int arrays
|
||||
{
|
||||
//inits
|
||||
for(int b=0; b<BFIELD_SIZE; ++b)
|
||||
@ -238,14 +239,14 @@ void BattleInfo::makeBFS(int start, bool *accessibility, int *predecessor, int *
|
||||
for(int g=0; g<BFIELD_SIZE; ++g)
|
||||
dists[g] = 100000000;
|
||||
|
||||
std::queue< std::pair<int, bool> > hexq; //bfs queue <hex, accessible> (second filed used only if fillPredecessors is true)
|
||||
std::queue< std::pair<THex, bool> > hexq; //bfs queue <hex, accessible> (second filed used only if fillPredecessors is true)
|
||||
hexq.push(std::make_pair(start, true));
|
||||
dists[hexq.front().first] = 0;
|
||||
int curNext = -1; //for bfs loop only (helper var)
|
||||
while(!hexq.empty()) //bfs loop
|
||||
{
|
||||
std::pair<int, bool> curHex = hexq.front();
|
||||
std::vector<int> neighbours = neighbouringTiles(curHex.first);
|
||||
std::pair<THex, bool> curHex = hexq.front();
|
||||
std::vector<THex> neighbours = curHex.first.neighbouringTiles();
|
||||
hexq.pop();
|
||||
for(unsigned int nr=0; nr<neighbours.size(); nr++)
|
||||
{
|
||||
@ -268,34 +269,33 @@ void BattleInfo::makeBFS(int start, bool *accessibility, int *predecessor, int *
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<int> BattleInfo::getAccessibility(int stackID, bool addOccupiable) const
|
||||
std::vector<THex> BattleInfo::getAccessibility(const CStack * stack, bool addOccupiable) const
|
||||
{
|
||||
std::vector<int> ret;
|
||||
std::vector<THex> ret;
|
||||
bool ac[BFIELD_SIZE];
|
||||
const CStack *s = getStack(stackID, false); //this function is called from healedOrResurrected, so our stack can be dead
|
||||
|
||||
if(s->position < 0) //turrets
|
||||
return std::vector<int>();
|
||||
if(stack->position < 0) //turrets
|
||||
return std::vector<THex>();
|
||||
|
||||
std::set<int> occupyable;
|
||||
std::set<THex> occupyable;
|
||||
|
||||
getAccessibilityMap(ac, s->doubleWide(), s->attackerOwned, addOccupiable, occupyable, s->hasBonusOfType(Bonus::FLYING), stackID);
|
||||
getAccessibilityMap(ac, stack->doubleWide(), stack->attackerOwned, addOccupiable, occupyable, stack->hasBonusOfType(Bonus::FLYING), stack);
|
||||
|
||||
int pr[BFIELD_SIZE], dist[BFIELD_SIZE];
|
||||
makeBFS(s->position, ac, pr, dist, s->doubleWide(), s->attackerOwned, s->hasBonusOfType(Bonus::FLYING), false);
|
||||
makeBFS(stack->position, ac, pr, dist, stack->doubleWide(), stack->attackerOwned, stack->hasBonusOfType(Bonus::FLYING), false);
|
||||
|
||||
if(s->doubleWide())
|
||||
if(stack->doubleWide())
|
||||
{
|
||||
if(!addOccupiable)
|
||||
{
|
||||
std::vector<int> rem;
|
||||
std::vector<THex> rem;
|
||||
for(int b=0; b<BFIELD_SIZE; ++b)
|
||||
{
|
||||
//don't take into account most left and most right columns of hexes
|
||||
if( b % BFIELD_WIDTH == 0 || b % BFIELD_WIDTH == BFIELD_WIDTH - 1 )
|
||||
continue;
|
||||
|
||||
if( ac[b] && !(s->attackerOwned ? ac[b-1] : ac[b+1]) )
|
||||
if( ac[b] && !(stack->attackerOwned ? ac[b-1] : ac[b+1]) )
|
||||
{
|
||||
rem.push_back(b);
|
||||
}
|
||||
@ -308,16 +308,16 @@ std::vector<int> BattleInfo::getAccessibility(int stackID, bool addOccupiable) c
|
||||
|
||||
//removing accessibility for side hexes
|
||||
for(int v=0; v<BFIELD_SIZE; ++v)
|
||||
if(s->attackerOwned ? (v%BFIELD_WIDTH)==1 : (v%BFIELD_WIDTH)==(BFIELD_WIDTH - 2))
|
||||
if(stack->attackerOwned ? (v%BFIELD_WIDTH)==1 : (v%BFIELD_WIDTH)==(BFIELD_WIDTH - 2))
|
||||
ac[v] = false;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0; i < BFIELD_SIZE ; ++i) {
|
||||
if(
|
||||
( ( !addOccupiable && dist[i] <= s->Speed() && ac[i] ) || ( addOccupiable && dist[i] <= s->Speed() && isAccessible(i, ac, s->doubleWide(), s->attackerOwned, s->hasBonusOfType(Bonus::FLYING), true) ) )//we can reach it
|
||||
|| (vstd::contains(occupyable, i) && ( dist[ i + (s->attackerOwned ? 1 : -1 ) ] <= s->Speed() ) &&
|
||||
ac[i + (s->attackerOwned ? 1 : -1 )] ) //it's occupyable and we can reach adjacent hex
|
||||
( ( !addOccupiable && dist[i] <= stack->Speed() && ac[i] ) || ( addOccupiable && dist[i] <= stack->Speed() && isAccessible(i, ac, stack->doubleWide(), stack->attackerOwned, stack->hasBonusOfType(Bonus::FLYING), true) ) )//we can reach it
|
||||
|| (vstd::contains(occupyable, i) && ( dist[ i + (stack->attackerOwned ? 1 : -1 ) ] <= stack->Speed() ) &&
|
||||
ac[i + (stack->attackerOwned ? 1 : -1 )] ) //it's occupyable and we can reach adjacent hex
|
||||
)
|
||||
{
|
||||
ret.push_back(i);
|
||||
@ -326,65 +326,35 @@ std::vector<int> BattleInfo::getAccessibility(int stackID, bool addOccupiable) c
|
||||
|
||||
return ret;
|
||||
}
|
||||
bool BattleInfo::isStackBlocked(int ID)
|
||||
bool BattleInfo::isStackBlocked(const CStack * stack)
|
||||
{
|
||||
CStack *our = getStack(ID);
|
||||
if(our->hasBonusOfType(Bonus::SIEGE_WEAPON)) //siege weapons cannot be blocked
|
||||
if(stack->hasBonusOfType(Bonus::SIEGE_WEAPON)) //siege weapons cannot be blocked
|
||||
return false;
|
||||
|
||||
for(unsigned int i=0; i<stacks.size();i++)
|
||||
{
|
||||
if( !stacks[i]->alive()
|
||||
|| stacks[i]->owner==our->owner
|
||||
|| stacks[i]->owner==stack->owner
|
||||
)
|
||||
continue; //we omit dead and allied stacks
|
||||
if(stacks[i]->doubleWide())
|
||||
{
|
||||
if( mutualPosition(stacks[i]->position, our->position) >= 0
|
||||
|| mutualPosition(stacks[i]->position + (stacks[i]->attackerOwned ? -1 : 1), our->position) >= 0)
|
||||
if( THex::mutualPosition(stacks[i]->position, stack->position) >= 0
|
||||
|| THex::mutualPosition(stacks[i]->position + (stacks[i]->attackerOwned ? -1 : 1), stack->position) >= 0)
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( mutualPosition(stacks[i]->position, our->position) >= 0 )
|
||||
if( THex::mutualPosition(stacks[i]->position, stack->position) >= 0 )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
signed char BattleInfo::mutualPosition(THex hex1, THex hex2)
|
||||
{
|
||||
if(hex2 == hex1 - ( (hex1/17)%2 ? 18 : 17 )) //top left
|
||||
return 0;
|
||||
if(hex2 == hex1 - ( (hex1/17)%2 ? 17 : 16 )) //top right
|
||||
return 1;
|
||||
if(hex2 == hex1 - 1 && hex1%17 != 0) //left
|
||||
return 5;
|
||||
if(hex2 == hex1 + 1 && hex1%17 != 16) //right
|
||||
return 2;
|
||||
if(hex2 == hex1 + ( (hex1/17)%2 ? 16 : 17 )) //bottom left
|
||||
return 4;
|
||||
if(hex2 == hex1 + ( (hex1/17)%2 ? 17 : 18 )) //bottom right
|
||||
return 3;
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::vector<int> BattleInfo::neighbouringTiles(int hex)
|
||||
{
|
||||
#define CHECK_AND_PUSH(tile) {int hlp = (tile); if(hlp>=0 && hlp<BFIELD_SIZE && (hlp%BFIELD_WIDTH!=16) && hlp%BFIELD_WIDTH) ret.push_back(hlp);}
|
||||
std::vector<int> ret;
|
||||
CHECK_AND_PUSH(hex - ( (hex/17)%2 ? 18 : 17 ));
|
||||
CHECK_AND_PUSH(hex - ( (hex/17)%2 ? 17 : 16 ));
|
||||
CHECK_AND_PUSH(hex - 1);
|
||||
CHECK_AND_PUSH(hex + 1);
|
||||
CHECK_AND_PUSH(hex + ( (hex/17)%2 ? 16 : 17 ));
|
||||
CHECK_AND_PUSH(hex + ( (hex/17)%2 ? 17 : 18 ));
|
||||
#undef CHECK_AND_PUSH
|
||||
return ret;
|
||||
}
|
||||
std::pair< std::vector<int>, int > BattleInfo::getPath(int start, int dest, bool*accessibility, bool flyingCreature, bool twoHex, bool attackerOwned)
|
||||
{
|
||||
{
|
||||
int predecessor[BFIELD_SIZE]; //for getting the Path
|
||||
int dist[BFIELD_SIZE]; //calculated distances
|
||||
|
||||
@ -585,7 +555,7 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, con
|
||||
|
||||
//wall / distance penalty + advanced air shield
|
||||
if (shooting && !NBonus::hasOfType(attackerHero, Bonus::NO_SHOTING_PENALTY) && (
|
||||
hasDistancePenalty(attacker->ID, defender->position) || hasWallPenalty(attacker->ID, defender->position) ||
|
||||
hasDistancePenalty(attacker, defender->position) || hasWallPenalty(attacker, defender->position) ||
|
||||
HLP::hasAdvancedAirShield(defender) )
|
||||
)
|
||||
{
|
||||
@ -780,7 +750,7 @@ ui32 BattleInfo::getSpellCost(const CSpell * sp, const CGHeroInstance * caster)
|
||||
return ret + manaReduction + manaIncrease;
|
||||
}
|
||||
|
||||
int BattleInfo::hexToWallPart(int hex) const
|
||||
int BattleInfo::hexToWallPart(THex hex) const
|
||||
{
|
||||
if(siege == 0) //there is no battle!
|
||||
return -1;
|
||||
@ -808,9 +778,9 @@ int BattleInfo::lineToWallHex( int line ) const
|
||||
std::pair<const CStack *, int> BattleInfo::getNearestStack(const CStack * closest, boost::logic::tribool attackerOwned) const
|
||||
{
|
||||
bool ac[BFIELD_SIZE];
|
||||
std::set<int> occupyable;
|
||||
std::set<THex> occupyable;
|
||||
|
||||
getAccessibilityMap(ac, closest->doubleWide(), closest->attackerOwned, false, occupyable, closest->hasBonusOfType(Bonus::FLYING), closest->ID);
|
||||
getAccessibilityMap(ac, closest->doubleWide(), closest->attackerOwned, false, occupyable, closest->hasBonusOfType(Bonus::FLYING), closest);
|
||||
|
||||
int predecessor[BFIELD_SIZE], dist[BFIELD_SIZE];
|
||||
makeBFS(closest->position, ac, predecessor, dist, closest->doubleWide(), closest->attackerOwned, closest->hasBonusOfType(Bonus::FLYING), true);
|
||||
@ -1051,15 +1021,13 @@ void BattleInfo::getStackQueue( std::vector<const CStack *> &out, int howMany, i
|
||||
}
|
||||
}
|
||||
|
||||
si8 BattleInfo::hasDistancePenalty( int stackID, int destHex )
|
||||
si8 BattleInfo::hasDistancePenalty( const CStack * stack, THex destHex )
|
||||
{
|
||||
const CStack * stack = getStack(stackID);
|
||||
|
||||
struct HLP
|
||||
{
|
||||
static bool lowerAnalyze(const CStack * stack, int hex)
|
||||
static bool lowerAnalyze(const CStack * stack, THex hex)
|
||||
{
|
||||
int distance = BattleInfo::getDistance(hex, stack->position);
|
||||
int distance = THex::getDistance(hex, stack->position);
|
||||
|
||||
//I hope it's approximately correct
|
||||
return distance > 10 && !stack->hasBonusOfType(Bonus::NO_DISTANCE_PENALTY);
|
||||
@ -1085,13 +1053,12 @@ si8 BattleInfo::sameSideOfWall(int pos1, int pos2)
|
||||
return stackLeft != destLeft;
|
||||
}
|
||||
|
||||
si8 BattleInfo::hasWallPenalty( int stackID, int destHex )
|
||||
si8 BattleInfo::hasWallPenalty( const CStack* stack, THex destHex )
|
||||
{
|
||||
if (siege == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const CStack * stack = getStack(stackID);
|
||||
if (stack->hasBonusOfType(Bonus::NO_WALL_PENALTY))
|
||||
{
|
||||
return false;
|
||||
@ -1100,18 +1067,17 @@ si8 BattleInfo::hasWallPenalty( int stackID, int destHex )
|
||||
return !sameSideOfWall(stack->position, destHex);
|
||||
}
|
||||
|
||||
si8 BattleInfo::canTeleportTo(int stackID, int destHex, int telportLevel)
|
||||
si8 BattleInfo::canTeleportTo(const CStack * stack, THex destHex, int telportLevel)
|
||||
{
|
||||
bool ac[BFIELD_SIZE];
|
||||
const CStack *s = getStack(stackID, false); //this function is called from healedOrResurrected, so our stack can be dead
|
||||
|
||||
std::set<int> occupyable;
|
||||
std::set<THex> occupyable;
|
||||
|
||||
getAccessibilityMap(ac, s->doubleWide(), s->attackerOwned, false, occupyable, s->hasBonusOfType(Bonus::FLYING), stackID);
|
||||
getAccessibilityMap(ac, stack->doubleWide(), stack->attackerOwned, false, occupyable, stack->hasBonusOfType(Bonus::FLYING), stack);
|
||||
|
||||
if (siege && telportLevel < 2) //check for wall
|
||||
{
|
||||
return ac[destHex] && sameSideOfWall(s->position, destHex);
|
||||
return ac[destHex] && sameSideOfWall(stack->position, destHex);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1141,11 +1107,103 @@ si8 BattleInfo::canTeleportTo(int stackID, int destHex, int telportLevel)
|
||||
// }
|
||||
// }
|
||||
|
||||
si8 BattleInfo::getDistance( THex hex1, THex hex2 )
|
||||
bool BattleInfo::battleCanShoot(const CStack * stack, THex dest)
|
||||
{
|
||||
int xDst = std::abs(hex1 % BFIELD_WIDTH - hex2 % BFIELD_WIDTH),
|
||||
yDst = std::abs(hex1 / BFIELD_WIDTH - hex2 / BFIELD_WIDTH);
|
||||
return std::max(xDst, yDst) + std::min(xDst, yDst) - (yDst + 1)/2;
|
||||
const CStack *dst = getStackT(dest);
|
||||
|
||||
if(!stack || !dst) return false;
|
||||
|
||||
const CGHeroInstance * stackHero = battleGetOwner(stack);
|
||||
|
||||
if(stack->hasBonusOfType(Bonus::FORGETFULL)) //forgetfulness
|
||||
return false;
|
||||
|
||||
if(stack->getCreature()->idNumber == 145 && dst) //catapult cannot attack creatures
|
||||
return false;
|
||||
|
||||
if(stack->hasBonusOfType(Bonus::SHOOTER)//it's shooter
|
||||
&& stack->owner != dst->owner
|
||||
&& dst->alive()
|
||||
&& (!isStackBlocked(stack) || NBonus::hasOfType(stackHero, Bonus::FREE_SHOOTING))
|
||||
&& stack->shots
|
||||
)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BattleInfo::battleCanFlee(int player)
|
||||
{
|
||||
if (player == side1)
|
||||
{
|
||||
if (!heroes[0])
|
||||
return false;//current player have no hero
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!heroes[1])
|
||||
return false;
|
||||
}
|
||||
|
||||
if( ( heroes[0] && heroes[0]->hasBonusOfType(Bonus::ENEMY_CANT_ESCAPE) ) //eg. one of heroes is wearing shakles of war
|
||||
|| ( heroes[1] && heroes[1]->hasBonusOfType(Bonus::ENEMY_CANT_ESCAPE)))
|
||||
return false;
|
||||
|
||||
if (player == side2 && siege //defender in siege
|
||||
&& !(town->subID == 6 && vstd::contains(town->builtBuildings, 17)))//without escape tunnel
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const CStack * BattleInfo::battleGetStack(THex pos, bool onlyAlive)
|
||||
{
|
||||
for(unsigned int g=0; g<stacks.size(); ++g)
|
||||
{
|
||||
if((stacks[g]->position == pos
|
||||
|| (stacks[g]->doubleWide()
|
||||
&&( (stacks[g]->attackerOwned && stacks[g]->position-1 == pos)
|
||||
|| (!stacks[g]->attackerOwned && stacks[g]->position+1 == pos) )
|
||||
))
|
||||
&& (!onlyAlive || stacks[g]->alive())
|
||||
)
|
||||
return stacks[g];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const CGHeroInstance * BattleInfo::battleGetOwner(const CStack * stack)
|
||||
{
|
||||
return heroes[!stack->attackerOwned];
|
||||
}
|
||||
|
||||
si8 BattleInfo::battleMaxSpellLevel()
|
||||
{
|
||||
// if(!curB) //there is not battle
|
||||
// {
|
||||
// tlog1 << "si8 CGameState::maxSpellLevel() call when there is no battle!" << std::endl;
|
||||
// throw "si8 CGameState::maxSpellLevel() call when there is no battle!";
|
||||
// }
|
||||
|
||||
si8 levelLimit = SPELL_LEVELS;
|
||||
|
||||
const CGHeroInstance *h1 = heroes[0];
|
||||
if(h1)
|
||||
{
|
||||
BOOST_FOREACH(const Bonus *i, h1->bonuses)
|
||||
if(i->type == Bonus::BLOCK_SPELLS_ABOVE_LEVEL)
|
||||
amin(levelLimit, i->val);
|
||||
}
|
||||
|
||||
const CGHeroInstance *h2 = heroes[1];
|
||||
if(h2)
|
||||
{
|
||||
|
||||
BOOST_FOREACH(const Bonus *i, h2->bonuses)
|
||||
if(i->type == Bonus::BLOCK_SPELLS_ABOVE_LEVEL)
|
||||
amin(levelLimit, i->val);
|
||||
}
|
||||
|
||||
return levelLimit;
|
||||
}
|
||||
|
||||
void BattleInfo::localInit()
|
||||
@ -1210,12 +1268,12 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int terType, const
|
||||
|
||||
if(town)
|
||||
{
|
||||
curB->tid = town->id;
|
||||
curB->town = town;
|
||||
curB->siege = town->fortLevel();
|
||||
}
|
||||
else
|
||||
{
|
||||
curB->tid = -1;
|
||||
curB->town = NULL;
|
||||
curB->siege = 0;
|
||||
}
|
||||
|
||||
@ -1279,11 +1337,11 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int terType, const
|
||||
{
|
||||
if((stacks[g]->position%17)==1 && stacks[g]->doubleWide() && stacks[g]->attackerOwned)
|
||||
{
|
||||
stacks[g]->position += 1;
|
||||
stacks[g]->position += THex::RIGHT;
|
||||
}
|
||||
else if((stacks[g]->position%17)==15 && stacks[g]->doubleWide() && !stacks[g]->attackerOwned)
|
||||
{
|
||||
stacks[g]->position -= 1;
|
||||
stacks[g]->position += THex::LEFT;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1527,7 +1585,7 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int terType, const
|
||||
|
||||
|
||||
CStack::CStack(const CStackInstance *Base, int O, int I, bool AO, int S)
|
||||
: base(Base), ID(I), owner(O), slot(S), attackerOwned(AO), position(-1),
|
||||
: base(Base), ID(I), owner(O), slot(S), attackerOwned(AO),
|
||||
counterAttacks(1)
|
||||
{
|
||||
assert(base);
|
||||
@ -1541,7 +1599,7 @@ CStack::CStack()
|
||||
}
|
||||
|
||||
CStack::CStack(const CStackBasicDescriptor *stack, int O, int I, bool AO, int S)
|
||||
: base(NULL), ID(I), owner(O), slot(S), attackerOwned(AO), position(-1), counterAttacks(1)
|
||||
: base(NULL), ID(I), owner(O), slot(S), attackerOwned(AO), counterAttacks(1)
|
||||
{
|
||||
type = stack->type;
|
||||
count = baseAmount = stack->count;
|
||||
@ -1557,7 +1615,7 @@ void CStack::init()
|
||||
owner = 255;
|
||||
slot = 255;
|
||||
attackerOwned = false;
|
||||
position = -1;
|
||||
position = THex();
|
||||
counterAttacks = -1;
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,7 @@ struct DLL_EXPORT BattleInfo : public CBonusSystemNode
|
||||
ui8 side1, side2; //side1 - attacker, side2 - defender
|
||||
si32 round, activeStack;
|
||||
ui8 siege; // = 0 ordinary battle = 1 a siege with a Fort = 2 a siege with a Citadel = 3 a siege with a Castle
|
||||
si32 tid; //used during town siege - id of attacked town; -1 if not town defence
|
||||
const CGTownInstance * town; //used during town siege - id of attacked town; -1 if not town defence
|
||||
int3 tile; //for background and bonuses
|
||||
CGHeroInstance *heroes[2];
|
||||
CArmedInstance *belligerents[2]; //may be same as heroes
|
||||
@ -62,7 +62,7 @@ struct DLL_EXPORT BattleInfo : public CBonusSystemNode
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & side1 & side2 & round & activeStack & siege & tid & tile & stacks & belligerents & obstacles
|
||||
h & side1 & side2 & round & activeStack & siege & town & tile & stacks & belligerents & obstacles
|
||||
& castSpells & si & battlefieldType;
|
||||
h & heroes;
|
||||
h & static_cast<CBonusSystemNode&>(*this);
|
||||
@ -78,16 +78,14 @@ struct DLL_EXPORT BattleInfo : public CBonusSystemNode
|
||||
const CStack * getStack(int stackID, bool onlyAlive = true) const;
|
||||
CStack * getStackT(THex tileID, bool onlyAlive = true);
|
||||
const CStack * getStackT(THex tileID, bool onlyAlive = true) const;
|
||||
void getAccessibilityMap(bool *accessibility, bool twoHex, bool attackerOwned, bool addOccupiable, std::set<int> & occupyable, bool flying, int stackToOmmit=-1) const; //send pointer to at least 187 allocated bytes
|
||||
void getAccessibilityMap(bool *accessibility, bool twoHex, bool attackerOwned, bool addOccupiable, std::set<THex> & occupyable, bool flying, const CStack* stackToOmmit = NULL) const; //send pointer to at least 187 allocated bytes
|
||||
static bool isAccessible(int hex, bool * accessibility, bool twoHex, bool attackerOwned, bool flying, bool lastPos); //helper for makeBFS
|
||||
void makeBFS(int start, bool*accessibility, int *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
|
||||
void makeBFS(THex start, bool*accessibility, int *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<int>, int > getPath(int start, int dest, bool*accessibility, bool flyingCreature, bool twoHex, bool attackerOwned); //returned value: pair<path, length>; length may be different than number of elements in path since flying vreatures jump between distant hexes
|
||||
std::vector<int> getAccessibility(int stackID, bool addOccupiable) const; //returns vector of accessible tiles (taking into account the creature range)
|
||||
std::vector<THex> getAccessibility(const CStack * stack, bool addOccupiable) const; //returns vector of accessible tiles (taking into account the creature range)
|
||||
|
||||
bool isStackBlocked(const CStack * stack); //returns true if there is neighboring enemy stack
|
||||
|
||||
bool isStackBlocked(int ID); //returns true if there is neighboring enemy stack
|
||||
static signed char mutualPosition(THex hex1, THex hex2); //returns info about mutual position of given hexes (-1 - they're distant, 0 - left top, 1 - right top, 2 - right, 3 - right bottom, 4 - left bottom, 5 - left)
|
||||
static std::vector<int> neighbouringTiles(int hex);
|
||||
static si8 getDistance(THex hex1, THex hex2); //returns distance between given hexes
|
||||
ui32 calculateDmg(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge, bool lucky); //charge - number of hexes travelled before attack (for champion's jousting)
|
||||
std::pair<ui32, ui32> calculateDmgRange(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge, bool lucky); //charge - number of hexes travelled before attack (for champion's jousting); returns pair <min dmg, max dmg>
|
||||
void calculateCasualties(std::map<ui32,si32> *casualties) const; //casualties are array of maps size 2 (attacker, defeneder), maps are (crid => amount)
|
||||
@ -96,16 +94,22 @@ struct DLL_EXPORT BattleInfo : public CBonusSystemNode
|
||||
CStack * generateNewStack(const CStackInstance &base, int stackID, bool attackerOwned, int slot, int position) const; //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield
|
||||
CStack * generateNewStack(const CStackBasicDescriptor &base, int stackID, bool attackerOwned, int slot, int position) const; //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield
|
||||
ui32 getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const; //returns cost of given spell
|
||||
int hexToWallPart(int hex) const; //returns part of destructible wall / gate / keep under given hex or -1 if not found
|
||||
int hexToWallPart(THex hex) const; //returns part of destructible wall / gate / keep under given hex or -1 if not found
|
||||
int lineToWallHex(int line) const; //returns hex with wall in given line
|
||||
std::pair<const CStack *, int> getNearestStack(const CStack * closest, boost::logic::tribool attackerOwned) const; //if attackerOwned is indetermnate, returened stack is of any owner; hex is the number of hex we should be looking from; returns (nerarest creature, predecessorHex)
|
||||
ui32 calculateSpellBonus(ui32 baseDamage, const CSpell * sp, const CGHeroInstance * caster, const CStack * affectedCreature) const;
|
||||
ui32 calculateSpellDmg(const CSpell * sp, const CGHeroInstance * caster, const CStack * affectedCreature, int spellSchoolLevel, int usedSpellPower) const; //calculates damage inflicted by spell
|
||||
ui32 calculateHealedHP(const CGHeroInstance * caster, const CSpell * spell, const CStack * stack) const;
|
||||
si8 hasDistancePenalty(int stackID, int destHex); //determines if given stack has distance penalty shooting given pos
|
||||
si8 hasDistancePenalty(const CStack * stackID, THex destHex); //determines if given stack has distance penalty shooting given pos
|
||||
si8 sameSideOfWall(int pos1, int pos2); //determines if given positions are on the same side of wall
|
||||
si8 hasWallPenalty(int stackID, int destHex); //determines if given stack has wall penalty shooting given pos
|
||||
si8 canTeleportTo(int stackID, int destHex, int telportLevel); //determines if given stack can teleport to given place
|
||||
si8 hasWallPenalty(const CStack * stack, THex destHex); //determines if given stack has wall penalty shooting given pos
|
||||
si8 canTeleportTo(const CStack * stack, THex destHex, int telportLevel); //determines if given stack can teleport to given place
|
||||
bool battleCanShoot(const CStack * stack, THex dest); //determines if stack with given ID shoot at the selected destination
|
||||
|
||||
bool battleCanFlee(int player); //returns true if player can flee from the battle
|
||||
const CStack * battleGetStack(THex pos, bool onlyAlive); //returns stack at given tile
|
||||
const CGHeroInstance * battleGetOwner(const CStack * stack); //returns hero that owns given stack; NULL if none
|
||||
si8 battleMaxSpellLevel(); //calculates maximum spell level possible to be cast on battlefield - takes into account artifacts of both heroes; if no effects are set, SPELL_LEVELS is returned
|
||||
void localInit();
|
||||
static BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int terType, const CArmedInstance *armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance *town );
|
||||
};
|
||||
|
@ -1542,51 +1542,6 @@ void CGameState::init( StartInfo * si, ui32 checksum, int Seed )
|
||||
CGTeleport::postInit(); //pairing subterranean gates
|
||||
}
|
||||
|
||||
bool CGameState::battleCanFlee(int player)
|
||||
{
|
||||
if(!curB) //there is no battle
|
||||
return false;
|
||||
|
||||
if (player == curB->side1)
|
||||
{
|
||||
if (!curB->heroes[0])
|
||||
return false;//current player have no hero
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!curB->heroes[1])
|
||||
return false;
|
||||
}
|
||||
|
||||
if( ( curB->heroes[0] && curB->heroes[0]->hasBonusOfType(Bonus::ENEMY_CANT_ESCAPE) ) //eg. one of heroes is wearing shakles of war
|
||||
|| ( curB->heroes[1] && curB->heroes[1]->hasBonusOfType(Bonus::ENEMY_CANT_ESCAPE)))
|
||||
return false;
|
||||
|
||||
if (player == curB->side2 && curB->siege //defender in siege
|
||||
&& !(getTown(curB->tid)->subID == 6 && vstd::contains(getTown(curB->tid)->builtBuildings, 17)))//without escape tunnel
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int CGameState::battleGetStack(int pos, bool onlyAlive)
|
||||
{
|
||||
if(!curB)
|
||||
return -1;
|
||||
for(unsigned int g=0; g<curB->stacks.size(); ++g)
|
||||
{
|
||||
if((curB->stacks[g]->position == pos
|
||||
|| (curB->stacks[g]->doubleWide()
|
||||
&&( (curB->stacks[g]->attackerOwned && curB->stacks[g]->position-1 == pos)
|
||||
|| (!curB->stacks[g]->attackerOwned && curB->stacks[g]->position+1 == pos) )
|
||||
))
|
||||
&& (!onlyAlive || curB->stacks[g]->alive())
|
||||
)
|
||||
return curB->stacks[g]->ID;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int CGameState::battleGetBattlefieldType(int3 tile)
|
||||
{
|
||||
if(tile==int3() && curB)
|
||||
@ -1659,14 +1614,6 @@ int CGameState::battleGetBattlefieldType(int3 tile)
|
||||
}
|
||||
}
|
||||
|
||||
const CGHeroInstance * CGameState::battleGetOwner(int stackID)
|
||||
{
|
||||
if(!curB)
|
||||
return NULL;
|
||||
|
||||
return curB->heroes[!curB->getStack(stackID)->attackerOwned];
|
||||
}
|
||||
|
||||
std::set<std::pair<int, int> > costDiff(const std::vector<ui32> &a, const std::vector<ui32> &b, const int modifier = 100) //modifer %
|
||||
{
|
||||
std::set<std::pair<int, int> > ret;
|
||||
@ -2503,63 +2450,7 @@ bool CGameState::checkForVisitableDir( const int3 & src, const TerrainTile *pom,
|
||||
}
|
||||
return true;
|
||||
}
|
||||
si8 CGameState::battleMaxSpellLevel()
|
||||
{
|
||||
if(!curB) //there is not battle
|
||||
{
|
||||
tlog1 << "si8 CGameState::maxSpellLevel() call when there is no battle!" << std::endl;
|
||||
throw "si8 CGameState::maxSpellLevel() call when there is no battle!";
|
||||
}
|
||||
|
||||
si8 levelLimit = SPELL_LEVELS;
|
||||
|
||||
const CGHeroInstance *h1 = curB->heroes[0];
|
||||
if(h1)
|
||||
{
|
||||
BOOST_FOREACH(const Bonus *i, h1->bonuses)
|
||||
if(i->type == Bonus::BLOCK_SPELLS_ABOVE_LEVEL)
|
||||
amin(levelLimit, i->val);
|
||||
}
|
||||
|
||||
const CGHeroInstance *h2 = curB->heroes[1];
|
||||
if(h2)
|
||||
{
|
||||
|
||||
BOOST_FOREACH(const Bonus *i, h2->bonuses)
|
||||
if(i->type == Bonus::BLOCK_SPELLS_ABOVE_LEVEL)
|
||||
amin(levelLimit, i->val);
|
||||
}
|
||||
|
||||
return levelLimit;
|
||||
}
|
||||
|
||||
bool CGameState::battleCanShoot(int ID, int dest)
|
||||
{
|
||||
if(!curB)
|
||||
return false;
|
||||
|
||||
const CStack *our = curB->getStack(ID),
|
||||
*dst = curB->getStackT(dest);
|
||||
|
||||
if(!our || !dst) return false;
|
||||
|
||||
const CGHeroInstance * ourHero = battleGetOwner(our->ID);
|
||||
|
||||
if(our->hasBonusOfType(Bonus::FORGETFULL)) //forgetfulness
|
||||
return false;
|
||||
|
||||
if(our->getCreature()->idNumber == 145 && dst) //catapult cannot attack creatures
|
||||
return false;
|
||||
|
||||
if(our->hasBonusOfType(Bonus::SHOOTER)//it's shooter
|
||||
&& our->owner != dst->owner
|
||||
&& dst->alive()
|
||||
&& (!curB->isStackBlocked(ID) || NBonus::hasOfType(ourHero, Bonus::FREE_SHOOTING))
|
||||
&& our->shots
|
||||
)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
int CGameState::victoryCheck( ui8 player ) const
|
||||
{
|
||||
|
@ -295,12 +295,7 @@ public:
|
||||
CGTownInstance *getTown(int objid);
|
||||
const CGHeroInstance *getHero(int objid) const;
|
||||
const CGTownInstance *getTown(int objid) const;
|
||||
bool battleCanFlee(int player); //returns true if player can flee from the battle
|
||||
int battleGetStack(int pos, bool onlyAlive); //returns ID of stack at given tile
|
||||
int battleGetBattlefieldType(int3 tile = int3());// 1. sand/shore 2. sand/mesas 3. dirt/birches 4. dirt/hills 5. dirt/pines 6. grass/hills 7. grass/pines 8. lava 9. magic plains 10. snow/mountains 11. snow/trees 12. subterranean 13. swamp/trees 14. fiery fields 15. rock lands 16. magic clouds 17. lucid pools 18. holy ground 19. clover field 20. evil fog 21. "favourable winds" text on magic plains background 22. cursed ground 23. rough 24. ship to ship 25. ship
|
||||
const CGHeroInstance * battleGetOwner(int stackID); //returns hero that owns given stack; NULL if none
|
||||
si8 battleMaxSpellLevel(); //calculates maximum spell level possible to be cast on battlefield - takes into account artifacts of both heroes; if no effects are set, SPELL_LEVELS is returned
|
||||
bool battleCanShoot(int ID, int dest); //determines if stack with given ID shoot at the selected destination
|
||||
UpgradeInfo getUpgradeInfo(const CStackInstance &stack);
|
||||
int getPlayerRelations(ui8 color1, ui8 color2);// 0 = enemy, 1 = ally, 2 = same player
|
||||
//float getMarketEfficiency(int player, int mode=0);
|
||||
|
@ -615,6 +615,7 @@ DLL_EXPORT const CArtifactInstance *ArtifactLocation::getArt() const
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DLL_EXPORT CArtifactInstance *ArtifactLocation::getArt()
|
||||
@ -1105,7 +1106,7 @@ DLL_EXPORT void BattleSpellCast::applyGs( CGameState *gs )
|
||||
int pos; //position of stack on the battlefield - to be calculated
|
||||
|
||||
bool ac[BFIELD_SIZE];
|
||||
std::set<int> occupyable;
|
||||
std::set<THex> occupyable;
|
||||
bool twoHex = VLC->creh->creatures[creID]->isDoubleWide();
|
||||
bool flying = VLC->creh->creatures[creID]->isFlying();// vstd::contains(VLC->creh->creatures[creID]->bonuses, Bonus::FLYING);
|
||||
gs->curB->getAccessibilityMap(ac, twoHex, !side, true, occupyable, flying);
|
||||
@ -1194,7 +1195,7 @@ DLL_EXPORT void StacksHealedOrResurrected::applyGs( CGameState *gs )
|
||||
CStack * changedStack = gs->curB->getStack(healedStacks[g].stackID, false);
|
||||
|
||||
//checking if we resurrect a stack that is under a living stack
|
||||
std::vector<int> access = gs->curB->getAccessibility(changedStack->ID, true);
|
||||
std::vector<THex> access = gs->curB->getAccessibility(changedStack, true);
|
||||
bool acc[BFIELD_SIZE];
|
||||
for(int h=0; h<BFIELD_SIZE; ++h)
|
||||
acc[h] = false;
|
||||
|
@ -476,7 +476,7 @@ void CGameHandler::prepareAttack(BattleAttack &bat, const CStack *att, const CSt
|
||||
bat.flags |= 4;
|
||||
}
|
||||
|
||||
bsa->damageAmount = gs->curB->calculateDmg(att, def, gs->battleGetOwner(att->ID), gs->battleGetOwner(def->ID), bat.shot(), distance, bat.lucky());//counting dealt damage
|
||||
bsa->damageAmount = gs->curB->calculateDmg(att, def, gs->curB->battleGetOwner(att), gs->curB->battleGetOwner(def), bat.shot(), distance, bat.lucky());//counting dealt damage
|
||||
|
||||
|
||||
int dmg = bsa->damageAmount;
|
||||
@ -584,7 +584,7 @@ int CGameHandler::moveStack(int stack, int dest)
|
||||
|
||||
//initing necessary tables
|
||||
bool accessibility[BFIELD_SIZE];
|
||||
std::vector<int> accessible = gs->curB->getAccessibility(curStack->ID, false);
|
||||
std::vector<THex> accessible = gs->curB->getAccessibility(curStack, false);
|
||||
for(int b=0; b<BFIELD_SIZE; ++b)
|
||||
{
|
||||
accessibility[b] = false;
|
||||
@ -613,7 +613,7 @@ int CGameHandler::moveStack(int stack, int dest)
|
||||
return 0;
|
||||
|
||||
bool accessibilityWithOccupyable[BFIELD_SIZE];
|
||||
std::vector<int> accOc = gs->curB->getAccessibility(curStack->ID, true);
|
||||
std::vector<THex> accOc = gs->curB->getAccessibility(curStack, true);
|
||||
for(int b=0; b<BFIELD_SIZE; ++b)
|
||||
{
|
||||
accessibilityWithOccupyable[b] = false;
|
||||
@ -3042,7 +3042,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
||||
}
|
||||
case 4: //retreat/flee
|
||||
{
|
||||
if( !gs->battleCanFlee(ba.side ? gs->curB->side2 : gs->curB->side1) )
|
||||
if( !gs->curB->battleCanFlee(ba.side ? gs->curB->side2 : gs->curB->side1) )
|
||||
break;
|
||||
//TODO: remove retreating hero from map and place it in recruitment list
|
||||
BattleResult *br = new BattleResult;
|
||||
@ -3097,13 +3097,13 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
||||
|
||||
|
||||
if( !(
|
||||
(BattleInfo::mutualPosition(curpos, enemypos) >= 0) //front <=> front
|
||||
(THex::mutualPosition(curpos, enemypos) >= 0) //front <=> front
|
||||
|| (curStack->doubleWide() //back <=> front
|
||||
&& BattleInfo::mutualPosition(curpos + (curStack->attackerOwned ? -1 : 1), enemypos) >= 0)
|
||||
&& THex::mutualPosition(curpos + (curStack->attackerOwned ? -1 : 1), enemypos) >= 0)
|
||||
|| (stackAtEnd->doubleWide() //front <=> back
|
||||
&& BattleInfo::mutualPosition(curpos, enemypos + (stackAtEnd->attackerOwned ? -1 : 1)) >= 0)
|
||||
&& THex::mutualPosition(curpos, enemypos + (stackAtEnd->attackerOwned ? -1 : 1)) >= 0)
|
||||
|| (stackAtEnd->doubleWide() && curStack->doubleWide()//back <=> back
|
||||
&& BattleInfo::mutualPosition(curpos + (curStack->attackerOwned ? -1 : 1), enemypos + (stackAtEnd->attackerOwned ? -1 : 1)) >= 0)
|
||||
&& THex::mutualPosition(curpos + (curStack->attackerOwned ? -1 : 1), enemypos + (stackAtEnd->attackerOwned ? -1 : 1)) >= 0)
|
||||
)
|
||||
)
|
||||
{
|
||||
@ -3156,7 +3156,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
||||
{
|
||||
CStack *curStack = gs->curB->getStack(ba.stackNumber),
|
||||
*destStack= gs->curB->getStackT(ba.destinationTile);
|
||||
if( !gs->battleCanShoot(ba.stackNumber, ba.destinationTile) )
|
||||
if( !gs->curB->battleCanShoot(curStack, ba.destinationTile) )
|
||||
break;
|
||||
|
||||
sendAndApply(&StartAction(ba)); //start shooting
|
||||
@ -3742,7 +3742,7 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
|
||||
|| (ba.additionalInfo < 10) //it's adventure spell (not combat)
|
||||
|| (gs->curB->castSpells[ba.side]) //spell has been cast
|
||||
|| (NBonus::hasOfType(secondHero, Bonus::SPELL_IMMUNITY, s->id)) //non - casting hero provides immunity for this spell
|
||||
|| (gs->battleMaxSpellLevel() < s->level) //non - casting hero stops caster from casting this spell
|
||||
|| (gs->curB->battleMaxSpellLevel() < s->level) //non - casting hero stops caster from casting this spell
|
||||
)
|
||||
{
|
||||
tlog2 << "Spell cannot be cast!\n";
|
||||
@ -4821,7 +4821,7 @@ void CGameHandler::runBattle()
|
||||
continue;
|
||||
}
|
||||
|
||||
const CGHeroInstance * curOwner = gs->battleGetOwner(next->ID);
|
||||
const CGHeroInstance * curOwner = gs->curB->battleGetOwner(next);
|
||||
|
||||
if( (next->position < 0 && (!curOwner || curOwner->getSecSkillLevel(CGHeroInstance::BALLISTICS) == 0)) //arrow turret, hero has no ballistics
|
||||
|| (next->getCreature()->idNumber == 146 && (!curOwner || curOwner->getSecSkillLevel(CGHeroInstance::ARTILLERY) == 0))) //ballista, hero has no artillery
|
||||
|
Loading…
Reference in New Issue
Block a user