mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-12 02:28:11 +02:00
Merge remote-tracking branch 'remotes/origin/develop' into feature/VCMIMapFormat1
This commit is contained in:
commit
150fcc9422
@ -108,7 +108,7 @@ BattleAction CStupidAI::activeStack( const CStack * stack )
|
||||
if(stack->type->idNumber == CreatureID::CATAPULT)
|
||||
{
|
||||
BattleAction attack;
|
||||
static const std::vector<int> wallHexes = {50, 183, 182, 130, 62, 29, 12, 95};
|
||||
static const std::vector<int> wallHexes = {50, 183, 182, 130, 78, 29, 12, 95};
|
||||
|
||||
attack.destinationTile = *RandomGeneratorUtil::nextItem(wallHexes, CRandomGenerator::getDefault());
|
||||
attack.actionType = Battle::CATAPULT;
|
||||
|
@ -11,6 +11,9 @@ GENERAL:
|
||||
* New cheat code:
|
||||
- vcmiglaurung - gives 5000 crystal dragons into each slot
|
||||
|
||||
BATTLES:
|
||||
* Drawbridge mechanics implemented (animation still missing)
|
||||
|
||||
ADVETURE AI:
|
||||
* Fixed AI trying to go through underground rock
|
||||
* Fixed several cases causing AI wandering aimlessly
|
||||
|
@ -1012,6 +1012,14 @@ void CPlayerInterface::battleObstaclePlaced(const CObstacleInstance &obstacle)
|
||||
battleInt->obstaclePlaced(obstacle);
|
||||
}
|
||||
|
||||
void CPlayerInterface::battleGateStateChanged(const EGateState state)
|
||||
{
|
||||
EVENT_HANDLER_CALLED_BY_CLIENT;
|
||||
BATTLE_EVENT_POSSIBLE_RETURN;
|
||||
|
||||
battleInt->gateStateChanged(state);
|
||||
}
|
||||
|
||||
void CPlayerInterface::yourTacticPhase(int distance)
|
||||
{
|
||||
THREAD_CREATED_BY_CLIENT;
|
||||
|
@ -220,6 +220,7 @@ public:
|
||||
void battleCatapultAttacked(const CatapultAttack & ca) override; //called when catapult makes an attack
|
||||
void battleStacksRemoved(const BattleStacksRemoved & bsr) override; //called when certain stack is completely removed from battlefield
|
||||
void battleObstaclePlaced(const CObstacleInstance &obstacle) override;
|
||||
void battleGateStateChanged(const EGateState state) override;
|
||||
void yourTacticPhase(int distance) override;
|
||||
|
||||
//-------------//
|
||||
|
@ -658,6 +658,11 @@ void BattleObstaclePlaced::applyCl(CClient * cl)
|
||||
BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(battleObstaclePlaced, *obstacle);
|
||||
}
|
||||
|
||||
void BattleUpdateGateState::applyFirstCl(CClient * cl)
|
||||
{
|
||||
BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(battleGateStateChanged, state);
|
||||
}
|
||||
|
||||
void BattleResult::applyFirstCl( CClient *cl )
|
||||
{
|
||||
BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(battleEnd,this);
|
||||
|
@ -1218,9 +1218,14 @@ void CBattleInterface::stackIsCatapulting(const CatapultAttack & ca)
|
||||
|
||||
for(auto attackInfo : ca.attackedParts)
|
||||
{
|
||||
SDL_FreeSurface(siegeH->walls[attackInfo.attackedPart + 2]);
|
||||
siegeH->walls[attackInfo.attackedPart + 2] = BitmapHandler::loadBitmap(
|
||||
siegeH->getSiegeName(attackInfo.attackedPart + 2, curInt->cb->battleGetWallState(attackInfo.attackedPart)));
|
||||
int wallId = attackInfo.attackedPart + 2;
|
||||
//gate state changing handled separately
|
||||
if(wallId == SiegeHelper::GATE)
|
||||
continue;
|
||||
|
||||
SDL_FreeSurface(siegeH->walls[wallId]);
|
||||
siegeH->walls[wallId] = BitmapHandler::loadBitmap(
|
||||
siegeH->getSiegeName(wallId, curInt->cb->battleGetWallState(attackInfo.attackedPart)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -2735,6 +2740,37 @@ void CBattleInterface::obstaclePlaced(const CObstacleInstance & oi)
|
||||
//CCS->soundh->playSound(sound);
|
||||
}
|
||||
|
||||
void CBattleInterface::gateStateChanged(const EGateState state)
|
||||
{
|
||||
auto oldState = curInt->cb->battleGetGateState();
|
||||
bool playSound = false;
|
||||
int stateId = EWallState::NONE;
|
||||
switch(state)
|
||||
{
|
||||
case EGateState::CLOSED:
|
||||
if(oldState != EGateState::BLOCKED)
|
||||
playSound = true;
|
||||
break;
|
||||
case EGateState::BLOCKED:
|
||||
if(oldState != EGateState::CLOSED)
|
||||
playSound = true;
|
||||
break;
|
||||
case EGateState::OPENED:
|
||||
playSound = true;
|
||||
stateId = EWallState::DAMAGED;
|
||||
break;
|
||||
case EGateState::DESTROYED:
|
||||
stateId = EWallState::DESTROYED;
|
||||
break;
|
||||
}
|
||||
|
||||
SDL_FreeSurface(siegeH->walls[SiegeHelper::GATE]);
|
||||
if(stateId != EWallState::NONE)
|
||||
siegeH->walls[SiegeHelper::GATE] = BitmapHandler::loadBitmap(siegeH->getSiegeName(SiegeHelper::GATE, stateId));
|
||||
if(playSound)
|
||||
CCS->soundh->playSound(soundBase::DRAWBRG);
|
||||
}
|
||||
|
||||
const CGHeroInstance * CBattleInterface::currentHero() const
|
||||
{
|
||||
if(attackingHeroInstance->tempOwner == curInt->playerID)
|
||||
@ -2791,11 +2827,11 @@ void CBattleInterface::requestAutofightingAIToTakeAction()
|
||||
}
|
||||
|
||||
CBattleInterface::SiegeHelper::SiegeHelper(const CGTownInstance *siegeTown, const CBattleInterface * _owner)
|
||||
: owner(_owner), town(siegeTown)
|
||||
: owner(_owner), town(siegeTown)
|
||||
{
|
||||
for(int g = 0; g < ARRAY_COUNT(walls); ++g)
|
||||
{
|
||||
walls[g] = BitmapHandler::loadBitmap( getSiegeName(g) );
|
||||
walls[g] = BitmapHandler::loadBitmap(getSiegeName(g));
|
||||
}
|
||||
}
|
||||
|
||||
@ -2834,75 +2870,83 @@ std::string CBattleInterface::SiegeHelper::getSiegeName(ui16 what, int state) co
|
||||
|
||||
switch(what)
|
||||
{
|
||||
case 0: //background
|
||||
case SiegeHelper::BACKGROUND:
|
||||
return prefix + "BACK.BMP";
|
||||
case 1: //background wall
|
||||
case SiegeHelper::BACKGROUND_WALL:
|
||||
{
|
||||
switch(town->town->faction->index)
|
||||
{
|
||||
case 5: case 4: case 1: case 6:
|
||||
case ETownType::RAMPART:
|
||||
case ETownType::NECROPOLIS:
|
||||
case ETownType::DUNGEON:
|
||||
case ETownType::STRONGHOLD:
|
||||
return prefix + "TPW1.BMP";
|
||||
default:
|
||||
return prefix + "TPWL.BMP";
|
||||
}
|
||||
}
|
||||
case 2: //keep
|
||||
case SiegeHelper::KEEP:
|
||||
return prefix + "MAN" + addit + ".BMP";
|
||||
case 3: //bottom tower
|
||||
case SiegeHelper::BOTTOM_TOWER:
|
||||
return prefix + "TW1" + addit + ".BMP";
|
||||
case 4: //bottom wall
|
||||
case SiegeHelper::BOTTOM_WALL:
|
||||
return prefix + "WA1" + addit + ".BMP";
|
||||
case 5: //below gate
|
||||
case SiegeHelper::WALL_BELLOW_GATE:
|
||||
return prefix + "WA3" + addit + ".BMP";
|
||||
case 6: //over gate
|
||||
case SiegeHelper::WALL_OVER_GATE:
|
||||
return prefix + "WA4" + addit + ".BMP";
|
||||
case 7: //upper wall
|
||||
case SiegeHelper::UPPER_WALL:
|
||||
return prefix + "WA6" + addit + ".BMP";
|
||||
case 8: //upper tower
|
||||
case SiegeHelper::UPPER_TOWER:
|
||||
return prefix + "TW2" + addit + ".BMP";
|
||||
case 9: //gate
|
||||
case SiegeHelper::GATE:
|
||||
return prefix + "DRW" + addit + ".BMP";
|
||||
case 10: //gate arch
|
||||
case SiegeHelper::GATE_ARCH:
|
||||
return prefix + "ARCH.BMP";
|
||||
case 11: //bottom static wall
|
||||
case SiegeHelper::BOTTOM_STATIC_WALL:
|
||||
return prefix + "WA2.BMP";
|
||||
case 12: //upper static wall
|
||||
case SiegeHelper::UPPER_STATIC_WALL:
|
||||
return prefix + "WA5.BMP";
|
||||
case 13: //moat
|
||||
case SiegeHelper::MOAT:
|
||||
return prefix + "MOAT.BMP";
|
||||
case 14: //mlip
|
||||
case SiegeHelper::BACKGROUND_MOAT:
|
||||
return prefix + "MLIP.BMP";
|
||||
case 15: //keep creature cover
|
||||
case SiegeHelper::KEEP_BATTLEMENT:
|
||||
return prefix + "MANC.BMP";
|
||||
case 16: //bottom turret creature cover
|
||||
case SiegeHelper::BOTTOM_BATTLEMENT:
|
||||
return prefix + "TW1C.BMP";
|
||||
case 17: //upper turret creature cover
|
||||
case SiegeHelper::UPPER_BATTLEMENT:
|
||||
return prefix + "TW2C.BMP";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/// What: 1. background wall, 2. keep, 3. bottom tower, 4. bottom wall, 5. wall below gate,
|
||||
/// 6. wall over gate, 7. upper wall, 8. upper tower, 9. gate, 10. gate arch, 11. bottom static wall, 12. upper static wall, 13. moat, 14. mlip,
|
||||
/// 15. keep turret cover, 16. lower turret cover, 17. upper turret cover
|
||||
void CBattleInterface::SiegeHelper::printPartOfWall(SDL_Surface * to, int what)
|
||||
{
|
||||
Point pos = Point(-1, -1);
|
||||
auto & ci = owner->siegeH->town->town->clientInfo;
|
||||
auto & ci = town->town->clientInfo;
|
||||
|
||||
if (what >= 1 && what <= 17)
|
||||
if (vstd::iswithin(what, 1, 17))
|
||||
{
|
||||
pos.x = ci.siegePositions[what].x + owner->pos.x;
|
||||
pos.y = ci.siegePositions[what].y + owner->pos.y;
|
||||
}
|
||||
|
||||
if (town->town->faction->index == ETownType::TOWER
|
||||
&& (what == 13 || what == 14))
|
||||
&& (what == SiegeHelper::MOAT || what == SiegeHelper::BACKGROUND_MOAT))
|
||||
return; // no moat in Tower. TODO: remove hardcode somehow?
|
||||
|
||||
if(pos.x != -1)
|
||||
{
|
||||
//gate have no displayed bitmap when drawbridge is raised
|
||||
if(what == SiegeHelper::GATE)
|
||||
{
|
||||
auto gateState = owner->curInt->cb->battleGetGateState();
|
||||
if(gateState != EGateState::OPENED && gateState != EGateState::DESTROYED)
|
||||
return;
|
||||
}
|
||||
|
||||
blitAt(walls[what], pos.x, pos.y, to);
|
||||
}
|
||||
}
|
||||
@ -3004,7 +3048,7 @@ void CBattleInterface::showAbsoluteObstacles(SDL_Surface * to)
|
||||
blitAt(getObstacleImage(*oi), pos.x + oi->getInfo().width, pos.y + oi->getInfo().height, to);
|
||||
|
||||
if (siegeH && siegeH->town->hasBuilt(BuildingID::CITADEL))
|
||||
siegeH->printPartOfWall(to, 14); // show moat background
|
||||
siegeH->printPartOfWall(to, SiegeHelper::BACKGROUND_MOAT);
|
||||
}
|
||||
|
||||
void CBattleInterface::showHighlightedHexes(SDL_Surface * to)
|
||||
@ -3415,29 +3459,29 @@ BattleObjectsByHex CBattleInterface::sortObjectsByHex()
|
||||
// Sort wall parts
|
||||
if (siegeH)
|
||||
{
|
||||
sorted.beforeAll.walls.push_back(1); // 1. background wall
|
||||
sorted.hex[135].walls.push_back(2); // 2. keep
|
||||
sorted.afterAll.walls.push_back(3); // 3. bottom tower
|
||||
sorted.hex[182].walls.push_back(4); // 4. bottom wall
|
||||
sorted.hex[130].walls.push_back(5); // 5. wall below gate,
|
||||
sorted.hex[62].walls.push_back(6); // 6. wall over gate
|
||||
sorted.hex[12].walls.push_back(7); // 7. upper wall
|
||||
sorted.beforeAll.walls.push_back(8); // 8. upper tower
|
||||
//sorted.hex[94].walls.push_back(9); // 9. gate // Not implemented it seems
|
||||
sorted.hex[112].walls.push_back(10); // 10. gate arch
|
||||
sorted.hex[165].walls.push_back(11); // 11. bottom static wall
|
||||
sorted.hex[45].walls.push_back(12); // 12. upper static wall
|
||||
sorted.beforeAll.walls.push_back(SiegeHelper::BACKGROUND_WALL);
|
||||
sorted.hex[135].walls.push_back(SiegeHelper::KEEP);
|
||||
sorted.afterAll.walls.push_back(SiegeHelper::BOTTOM_TOWER);
|
||||
sorted.hex[182].walls.push_back(SiegeHelper::BOTTOM_WALL);
|
||||
sorted.hex[130].walls.push_back(SiegeHelper::WALL_BELLOW_GATE);
|
||||
sorted.hex[78].walls.push_back(SiegeHelper::WALL_OVER_GATE);
|
||||
sorted.hex[12].walls.push_back(SiegeHelper::UPPER_WALL);
|
||||
sorted.beforeAll.walls.push_back(SiegeHelper::UPPER_TOWER);
|
||||
sorted.hex[94].walls.push_back(SiegeHelper::GATE);
|
||||
sorted.hex[112].walls.push_back(SiegeHelper::GATE_ARCH);
|
||||
sorted.hex[165].walls.push_back(SiegeHelper::BOTTOM_STATIC_WALL);
|
||||
sorted.hex[45].walls.push_back(SiegeHelper::UPPER_STATIC_WALL);
|
||||
|
||||
if (siegeH && siegeH->town->hasBuilt(BuildingID::CITADEL))
|
||||
{
|
||||
sorted.beforeAll.walls.push_back(13); // 13. moat
|
||||
//sorted.beforeAll.walls.push_back(14); // 14. mlip (moat background terrain), blit as absolute obstacle
|
||||
sorted.hex[135].walls.push_back(15); // 15. keep turret cover
|
||||
sorted.beforeAll.walls.push_back(SiegeHelper::MOAT);
|
||||
//sorted.beforeAll.walls.push_back(SiegeHelper::BACKGROUND_MOAT); // blit as absolute obstacle
|
||||
sorted.hex[135].walls.push_back(SiegeHelper::KEEP_BATTLEMENT);
|
||||
}
|
||||
if (siegeH && siegeH->town->hasBuilt(BuildingID::CASTLE))
|
||||
{
|
||||
sorted.afterAll.walls.push_back(16); // 16. lower turret cover
|
||||
sorted.beforeAll.walls.push_back(17); // 17. upper turret cover
|
||||
sorted.afterAll.walls.push_back(SiegeHelper::BOTTOM_BATTLEMENT);
|
||||
sorted.beforeAll.walls.push_back(SiegeHelper::UPPER_BATTLEMENT);
|
||||
}
|
||||
}
|
||||
return sorted;
|
||||
|
@ -148,7 +148,7 @@ private:
|
||||
void activateStack(); //sets activeStack to stackToActivate etc. //FIXME: No, it's not clear at all
|
||||
std::vector<BattleHex> occupyableHexes, //hexes available for active stack
|
||||
attackableHexes; //hexes attackable by active stack
|
||||
bool stackCountOutsideHexes[GameConstants::BFIELD_SIZE]; // hexes that when in front of a unit cause it's amount box to move back
|
||||
bool stackCountOutsideHexes[GameConstants::BFIELD_SIZE]; // hexes that when in front of a unit cause it's amount box to move back
|
||||
BattleHex previouslyHoveredHex; //number of hex that was hovered by the cursor a while ago
|
||||
BattleHex currentlyHoveredHex; //number of hex that is supposed to be hovered (for a while it may be inappropriately set, but will be renewed soon)
|
||||
int attackingHex; //hex from which the stack would perform attack with current cursor
|
||||
@ -198,16 +198,32 @@ private:
|
||||
SiegeHelper(const CGTownInstance * siegeTown, const CBattleInterface * _owner); //c-tor
|
||||
~SiegeHelper(); //d-tor
|
||||
|
||||
//filename getters
|
||||
//what: 0 - background, 1 - background wall, 2 - keep, 3 - bottom tower, 4 - bottom wall,
|
||||
// 5 - below gate, 6 - over gate, 7 - upper wall, 8 - upper tower, 9 - gate,
|
||||
// 10 - gate arch, 11 - bottom static 12 - upper static, 13 - moat, 14 - moat background,
|
||||
// 15 - keep battlement, 16 - bottom battlement, 17 - upper battlement;
|
||||
// state uses EWallState enum
|
||||
std::string getSiegeName(ui16 what) const;
|
||||
std::string getSiegeName(ui16 what, int state) const;
|
||||
std::string getSiegeName(ui16 what, int state) const; // state uses EWallState enum
|
||||
|
||||
void printPartOfWall(SDL_Surface * to, int what);//what: 1 - background wall, 2 - keep, 3 - bottom tower, 4 - bottom wall, 5 - below gate, 6 - over gate, 7 - upper wall, 8 - uppert tower, 9 - gate, 10 - gate arch, 11 - bottom static wall, 12 - upper static wall, 15 - keep creature cover, 16 - bottom turret creature cover, 17 - upper turret creature cover
|
||||
void printPartOfWall(SDL_Surface * to, int what);
|
||||
|
||||
enum EWallVisual
|
||||
{
|
||||
BACKGROUND = 0,
|
||||
BACKGROUND_WALL = 1,
|
||||
KEEP,
|
||||
BOTTOM_TOWER,
|
||||
BOTTOM_WALL,
|
||||
WALL_BELLOW_GATE,
|
||||
WALL_OVER_GATE,
|
||||
UPPER_WALL,
|
||||
UPPER_TOWER,
|
||||
GATE,
|
||||
GATE_ARCH,
|
||||
BOTTOM_STATIC_WALL,
|
||||
UPPER_STATIC_WALL,
|
||||
MOAT,
|
||||
BACKGROUND_MOAT,
|
||||
KEEP_BATTLEMENT,
|
||||
BOTTOM_BATTLEMENT,
|
||||
UPPER_BATTLEMENT
|
||||
};
|
||||
|
||||
friend class CBattleInterface;
|
||||
} * siegeH;
|
||||
@ -341,6 +357,8 @@ public:
|
||||
BattleHex fromWhichHexAttack(BattleHex myNumber);
|
||||
void obstaclePlaced(const CObstacleInstance & oi);
|
||||
|
||||
void gateStateChanged(const EGateState state);
|
||||
|
||||
const CGHeroInstance * currentHero() const;
|
||||
InfoAboutHero enemyHero() const;
|
||||
|
||||
|
@ -327,6 +327,8 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, ETerrainType terrain, BFieldTyp
|
||||
//setting up siege obstacles
|
||||
if (town && town->hasFort())
|
||||
{
|
||||
curB->si.gateState = EGateState::CLOSED;
|
||||
|
||||
for (int b = 0; b < curB->si.wallState.size(); ++b)
|
||||
{
|
||||
curB->si.wallState[b] = EWallState::INTACT;
|
||||
|
@ -33,6 +33,7 @@ class CRandomGenerator;
|
||||
struct DLL_LINKAGE SiegeInfo
|
||||
{
|
||||
std::array<si8, EWallPart::PARTS_COUNT> wallState;
|
||||
EGateState gateState;
|
||||
|
||||
// return EWallState decreased by value of damage points
|
||||
static EWallState::EWallState applyDamage(EWallState::EWallState state, unsigned int value)
|
||||
@ -51,7 +52,7 @@ struct DLL_LINKAGE SiegeInfo
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & wallState;
|
||||
h & wallState & gateState;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -62,13 +62,13 @@ namespace SiegeStuffThatShouldBeMovedToHandlers // <=== TODO
|
||||
std::make_pair(183, EWallPart::BOTTOM_TOWER),
|
||||
std::make_pair(182, EWallPart::BOTTOM_WALL),
|
||||
std::make_pair(130, EWallPart::BELOW_GATE),
|
||||
std::make_pair(62, EWallPart::OVER_GATE),
|
||||
std::make_pair(78, EWallPart::OVER_GATE),
|
||||
std::make_pair(29, EWallPart::UPPER_WALL),
|
||||
std::make_pair(12, EWallPart::UPPER_TOWER),
|
||||
std::make_pair(95, EWallPart::INDESTRUCTIBLE_PART_OF_GATE),
|
||||
std::make_pair(96, EWallPart::GATE),
|
||||
std::make_pair(45, EWallPart::INDESTRUCTIBLE_PART),
|
||||
std::make_pair(78, EWallPart::INDESTRUCTIBLE_PART),
|
||||
std::make_pair(62, EWallPart::INDESTRUCTIBLE_PART),
|
||||
std::make_pair(112, EWallPart::INDESTRUCTIBLE_PART),
|
||||
std::make_pair(147, EWallPart::INDESTRUCTIBLE_PART)
|
||||
};
|
||||
@ -442,6 +442,15 @@ si8 CBattleInfoEssentials::battleGetWallState(int partOfWall) const
|
||||
return getBattle()->si.wallState[partOfWall];
|
||||
}
|
||||
|
||||
EGateState CBattleInfoEssentials::battleGetGateState() const
|
||||
{
|
||||
RETURN_IF_NOT_BATTLE(EGateState::NONE);
|
||||
if(getBattle()->town == nullptr || getBattle()->town->fortLevel() == CGTownInstance::NONE)
|
||||
return EGateState::NONE;
|
||||
|
||||
return getBattle()->si.gateState;
|
||||
}
|
||||
|
||||
si8 CBattleInfoCallback::battleHasWallPenalty( const CStack * stack, BattleHex destHex ) const
|
||||
{
|
||||
return battleHasWallPenalty(stack, stack->position, destHex);
|
||||
@ -1134,9 +1143,20 @@ AccessibilityInfo CBattleInfoCallback::getAccesibility() const
|
||||
}
|
||||
|
||||
//gate -> should be before stacks
|
||||
if(battleGetSiegeLevel() > 0 && battleGetWallState(EWallPart::GATE) != EWallState::DESTROYED)
|
||||
if(battleGetSiegeLevel() > 0)
|
||||
{
|
||||
ret[95] = ret[96] = EAccessibility::GATE; //block gate's hexes
|
||||
EAccessibility::EAccessibility accessability = EAccessibility::ACCESSIBLE;
|
||||
switch(battleGetGateState())
|
||||
{
|
||||
case EGateState::CLOSED:
|
||||
accessability = EAccessibility::GATE;
|
||||
break;
|
||||
|
||||
case EGateState::BLOCKED:
|
||||
accessability = EAccessibility::UNAVAILABLE;
|
||||
break;
|
||||
}
|
||||
ret[ESiegeHex::GATE_OUTER] = ret[ESiegeHex::GATE_INNER] = accessability;
|
||||
}
|
||||
|
||||
//tiles occupied by standing stacks
|
||||
@ -1157,14 +1177,19 @@ AccessibilityInfo CBattleInfoCallback::getAccesibility() const
|
||||
//walls
|
||||
if(battleGetSiegeLevel() > 0)
|
||||
{
|
||||
static const int permanentlyLocked[] = {12, 45, 78, 112, 147, 165};
|
||||
static const int permanentlyLocked[] = {12, 45, 62, 112, 147, 165};
|
||||
for(auto hex : permanentlyLocked)
|
||||
ret[hex] = EAccessibility::UNAVAILABLE;
|
||||
|
||||
//TODO likely duplicated logic
|
||||
static const std::pair<int, BattleHex> lockedIfNotDestroyed[] = //(which part of wall, which hex is blocked if this part of wall is not destroyed
|
||||
{std::make_pair(2, BattleHex(182)), std::make_pair(3, BattleHex(130)),
|
||||
std::make_pair(4, BattleHex(62)), std::make_pair(5, BattleHex(29))};
|
||||
static const std::pair<int, BattleHex> lockedIfNotDestroyed[] =
|
||||
{
|
||||
//which part of wall, which hex is blocked if this part of wall is not destroyed
|
||||
std::make_pair(2, BattleHex(ESiegeHex::DESTRUCTIBLE_WALL_4)),
|
||||
std::make_pair(3, BattleHex(ESiegeHex::DESTRUCTIBLE_WALL_3)),
|
||||
std::make_pair(4, BattleHex(ESiegeHex::DESTRUCTIBLE_WALL_2)),
|
||||
std::make_pair(5, BattleHex(ESiegeHex::DESTRUCTIBLE_WALL_1))
|
||||
};
|
||||
|
||||
for(auto & elem : lockedIfNotDestroyed)
|
||||
{
|
||||
|
@ -199,6 +199,7 @@ public:
|
||||
// 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
|
||||
si8 battleGetWallState(int partOfWall) const;
|
||||
EGateState battleGetGateState() const;
|
||||
|
||||
//helpers
|
||||
///returns all stacks, alive or dead or undead or mechanical :)
|
||||
|
@ -513,6 +513,29 @@ namespace EWallState
|
||||
};
|
||||
}
|
||||
|
||||
enum class EGateState : ui8
|
||||
{
|
||||
NONE,
|
||||
CLOSED,
|
||||
BLOCKED, //dead or alive stack blocking from outside
|
||||
OPENED,
|
||||
DESTROYED
|
||||
};
|
||||
|
||||
namespace ESiegeHex
|
||||
{
|
||||
enum ESiegeHex : si16
|
||||
{
|
||||
DESTRUCTIBLE_WALL_1 = 29,
|
||||
DESTRUCTIBLE_WALL_2 = 78,
|
||||
DESTRUCTIBLE_WALL_3 = 130,
|
||||
DESTRUCTIBLE_WALL_4 = 182,
|
||||
GATE_BRIDGE = 94,
|
||||
GATE_OUTER = 95,
|
||||
GATE_INNER = 96
|
||||
};
|
||||
}
|
||||
|
||||
namespace ETileType
|
||||
{
|
||||
enum ETileType
|
||||
|
@ -69,6 +69,7 @@ public:
|
||||
virtual void battleCatapultAttacked(const CatapultAttack & ca){}; //called when catapult makes an attack
|
||||
virtual void battleStacksRemoved(const BattleStacksRemoved & bsr){}; //called when certain stack is completely removed from battlefield
|
||||
virtual void battleObstaclePlaced(const CObstacleInstance &obstacle){};
|
||||
virtual void battleGateStateChanged(const EGateState state){};
|
||||
};
|
||||
|
||||
class DLL_LINKAGE IGameEventsReceiver
|
||||
|
@ -1689,6 +1689,21 @@ struct BattleObstaclePlaced : public CPackForClient //3020
|
||||
}
|
||||
};
|
||||
|
||||
struct BattleUpdateGateState : public CPackForClient//3021
|
||||
{
|
||||
BattleUpdateGateState(){type = 3021;};
|
||||
|
||||
void applyFirstCl(CClient *cl);
|
||||
|
||||
DLL_LINKAGE void applyGs(CGameState *gs);
|
||||
|
||||
EGateState state;
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & state;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct ShowInInfobox : public CPackForClient //107
|
||||
{
|
||||
|
@ -1225,6 +1225,12 @@ DLL_LINKAGE void BattleObstaclePlaced::applyGs( CGameState *gs )
|
||||
gs->curB->obstacles.push_back(obstacle);
|
||||
}
|
||||
|
||||
DLL_LINKAGE void BattleUpdateGateState::applyGs(CGameState *gs)
|
||||
{
|
||||
if(gs->curB)
|
||||
gs->curB->si.gateState = state;
|
||||
}
|
||||
|
||||
void BattleResult::applyGs( CGameState *gs )
|
||||
{
|
||||
for (CStack *s : gs->curB->stacks)
|
||||
|
@ -270,6 +270,7 @@ void registerTypesClientPacks2(Serializer &s)
|
||||
s.template registerType<CPackForClient, SetStackEffect>();
|
||||
s.template registerType<CPackForClient, BattleTriggerEffect>();
|
||||
s.template registerType<CPackForClient, BattleObstaclePlaced>();
|
||||
s.template registerType<CPackForClient, BattleUpdateGateState>();
|
||||
s.template registerType<CPackForClient, BattleSetStackProperty>();
|
||||
s.template registerType<CPackForClient, StacksInjured>();
|
||||
s.template registerType<CPackForClient, BattleResultsApplied>();
|
||||
|
@ -339,7 +339,7 @@ void CMapGenOptions::updateCompOnlyPlayers()
|
||||
|
||||
// Add some comp only players if necessary
|
||||
int compOnlyPlayersToAdd = getPlayerCount() - players.size();
|
||||
|
||||
|
||||
if (compOnlyPlayersToAdd < 0)
|
||||
{
|
||||
logGlobal->errorStream() << boost::format("Incorrect number of players to add. Requested players %d, current players %d") % playerCount % players.size();
|
||||
|
@ -55,7 +55,7 @@ public:
|
||||
~CMapGenerator(); // required due to std::unique_ptr
|
||||
|
||||
std::unique_ptr<CMap> generate(CMapGenOptions * mapGenOptions, int RandomSeed = std::time(nullptr));
|
||||
|
||||
|
||||
CMapGenOptions * mapGenOptions;
|
||||
std::unique_ptr<CMap> map;
|
||||
CRandomGenerator rand;
|
||||
@ -74,14 +74,14 @@ public:
|
||||
bool isFree(const int3 &tile) const;
|
||||
bool isUsed(const int3 &tile) const;
|
||||
bool isRoad(const int3 &tile) const;
|
||||
|
||||
|
||||
void setOccupied(const int3 &tile, ETileType::ETileType state);
|
||||
void setRoad(const int3 &tile, ERoadType::ERoadType roadType);
|
||||
|
||||
|
||||
CTileInfo getTile(const int3 & tile) const;
|
||||
bool isAllowedSpell(SpellID sid) const;
|
||||
|
||||
float getNearestObjectDistance(const int3 &tile) const;
|
||||
float getNearestObjectDistance(const int3 &tile) const;
|
||||
void setNearestObjectDistance(int3 &tile, float value);
|
||||
|
||||
int getNextMonlithIndex();
|
||||
|
@ -196,7 +196,7 @@ void CRmgTemplateStorage::loadObject(std::string scope, std::string name, const
|
||||
{
|
||||
zone->setMinesAmount (mineInfo.first, mineInfo.second);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -239,8 +239,8 @@ CRmgTemplate::CSize CRmgTemplateStorage::parseMapTemplateSize(const std::string
|
||||
|
||||
std::vector<std::string> parts;
|
||||
boost::split(parts, text, boost::is_any_of("+"));
|
||||
static const std::map<std::string, int> mapSizeMapping =
|
||||
{
|
||||
static const std::map<std::string, int> mapSizeMapping =
|
||||
{
|
||||
{"s", CMapHeader::MAP_SIZE_SMALL},
|
||||
{"m", CMapHeader::MAP_SIZE_MIDDLE},
|
||||
{"l", CMapHeader::MAP_SIZE_LARGE},
|
||||
@ -269,12 +269,12 @@ CRmgTemplate::CSize CRmgTemplateStorage::parseMapTemplateSize(const std::string
|
||||
|
||||
ETemplateZoneType::ETemplateZoneType CRmgTemplateStorage::parseZoneType(const std::string & type) const
|
||||
{
|
||||
static const std::map<std::string, ETemplateZoneType::ETemplateZoneType> zoneTypeMapping =
|
||||
static const std::map<std::string, ETemplateZoneType::ETemplateZoneType> zoneTypeMapping =
|
||||
{
|
||||
{"playerStart", ETemplateZoneType::PLAYER_START},
|
||||
{"cpuStart", ETemplateZoneType::CPU_START},
|
||||
{"treasure", ETemplateZoneType::TREASURE},
|
||||
{"junction", ETemplateZoneType::JUNCTION},
|
||||
{"junction", ETemplateZoneType::JUNCTION},
|
||||
};
|
||||
auto it = zoneTypeMapping.find(type);
|
||||
if(it == zoneTypeMapping.end()) throw std::runtime_error("Zone type unknown.");
|
||||
|
@ -47,12 +47,12 @@ public:
|
||||
bool isPossible() const;
|
||||
bool isFree() const;
|
||||
bool isUsed() const;
|
||||
bool isRoad() const;
|
||||
bool isRoad() const;
|
||||
void setOccupied(ETileType::ETileType value);
|
||||
ETerrainType getTerrainType() const;
|
||||
ETileType::ETileType getTileType() const;
|
||||
void setTerrainType(ETerrainType value);
|
||||
|
||||
|
||||
void setRoadType(ERoadType::ERoadType value);
|
||||
private:
|
||||
float nearestObjectDistance;
|
||||
@ -175,7 +175,7 @@ public:
|
||||
bool crunchPath(CMapGenerator* gen, const int3 &src, const int3 &dst, bool onlyStraight, std::set<int3>* clearedTiles = nullptr);
|
||||
bool connectPath(CMapGenerator* gen, const int3& src, bool onlyStraight);
|
||||
bool connectWithCenter(CMapGenerator* gen, const int3& src, bool onlyStraight);
|
||||
|
||||
|
||||
std::vector<int3> getAccessibleOffsets (CMapGenerator* gen, CGObjectInstance* object);
|
||||
|
||||
void addConnection(TRmgTemplateZoneId otherZone);
|
||||
@ -229,11 +229,11 @@ private:
|
||||
std::set<int3> possibleTiles; //optimization purposes for treasure generation
|
||||
std::vector<TRmgTemplateZoneId> connections; //list of adjacent zones
|
||||
std::set<int3> freePaths; //core paths of free tiles that all other objects will be linked to
|
||||
|
||||
|
||||
std::set<int3> roadNodes; //tiles to be connected with roads
|
||||
std::set<int3> roads; //all tiles with roads
|
||||
std::set<int3> tilesToConnectLater; //will be connected after paths are fractalized
|
||||
|
||||
|
||||
bool createRoad(CMapGenerator* gen, const int3 &src, const int3 &dst);
|
||||
void drawRoads(CMapGenerator * gen); //actually updates tiles
|
||||
|
||||
|
@ -206,9 +206,9 @@ ESpellCastResult TownPortalMechanics::applyAdventureEffects(const SpellCastEnvir
|
||||
}
|
||||
|
||||
CGTownInstance * town = static_cast<CGTownInstance*>(tile.visitableObjects.back());
|
||||
|
||||
|
||||
const auto relations = env->getCb()->getPlayerRelations(town->tempOwner, parameters.caster->tempOwner);
|
||||
|
||||
|
||||
if(relations == PlayerRelations::ENEMIES)
|
||||
{
|
||||
env->complain("Can't teleport to enemy!");
|
||||
@ -241,21 +241,21 @@ ESpellCastResult TownPortalMechanics::applyAdventureEffects(const SpellCastEnvir
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
const int movementCost = GameConstants::BASE_MOVEMENT_COST * ((parameters.caster->getSpellSchoolLevel(owner) >= 3) ? 2 : 3);
|
||||
|
||||
|
||||
if(parameters.caster->movement < movementCost)
|
||||
{
|
||||
env->complain("This hero has not enough movement points!");
|
||||
return ESpellCastResult::ERROR;
|
||||
return ESpellCastResult::ERROR;
|
||||
}
|
||||
|
||||
|
||||
if(env->moveHero(parameters.caster->id, town->visitablePos() + parameters.caster->getVisitableOffset() ,1))
|
||||
{
|
||||
SetMovePoints smp;
|
||||
smp.hid = parameters.caster->id;
|
||||
smp.val = std::max<ui32>(0, parameters.caster->movement - movementCost);
|
||||
env->sendAndApply(&smp);
|
||||
env->sendAndApply(&smp);
|
||||
}
|
||||
return ESpellCastResult::OK;
|
||||
}
|
||||
@ -271,7 +271,7 @@ ESpellCastResult ViewMechanics::applyAdventureEffects(const SpellCastEnvironment
|
||||
for(const CGObjectInstance * obj : env->getMap()->objects)
|
||||
{
|
||||
//todo:we need to send only not visible objects
|
||||
|
||||
|
||||
if(obj)//for some reason deleted object remain as empty pointer
|
||||
if(filterObject(obj, spellLevel))
|
||||
pack.objectPositions.push_back(ObjectPosInfo(obj));
|
||||
|
@ -29,7 +29,7 @@ void HealingSpellMechanics::applyBattleEffects(const SpellCastEnvironment * env,
|
||||
for(auto & attackedCre : ctx.attackedCres)
|
||||
{
|
||||
StacksHealedOrResurrected::HealInfo hi;
|
||||
hi.stackID = (attackedCre)->ID;
|
||||
hi.stackID = (attackedCre)->ID;
|
||||
int stackHPgained = parameters.caster->getSpellBonus(owner, hpGained, attackedCre);
|
||||
hi.healedHP = attackedCre->calculateHealedHealthPoints(stackHPgained, resurrect);
|
||||
hi.lowLevelResurrection = (healLevel == EHealLevel::RESURRECT);
|
||||
@ -54,11 +54,11 @@ void AntimagicMechanics::applyBattle(BattleInfo * battle, const BattleSpellCast
|
||||
doDispell(battle, packet, [this](const Bonus * b) -> bool
|
||||
{
|
||||
if(b->source == Bonus::SPELL_EFFECT)
|
||||
{
|
||||
{
|
||||
return b->sid != owner->id; //effect from this spell
|
||||
}
|
||||
return false; //not a spell effect
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
///ChainLightningMechanics
|
||||
@ -125,12 +125,12 @@ void CloneMechanics::applyBattleEffects(const SpellCastEnvironment * env, const
|
||||
ssp.val = 0;
|
||||
ssp.absolute = 1;
|
||||
env->sendAndApply(&ssp);
|
||||
|
||||
|
||||
ssp.stackID = clonedStack->ID;
|
||||
ssp.which = BattleSetStackProperty::HAS_CLONE;
|
||||
ssp.val = bsa.newStackID;
|
||||
ssp.absolute = 1;
|
||||
env->sendAndApply(&ssp);
|
||||
env->sendAndApply(&ssp);
|
||||
}
|
||||
|
||||
ESpellCastProblem::ESpellCastProblem CloneMechanics::isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const
|
||||
@ -172,7 +172,7 @@ void CureMechanics::applyBattle(BattleInfo * battle, const BattleSpellCast * pac
|
||||
CSpell * sp = SpellID(b->sid).toSpell();
|
||||
return sp->isNegative();
|
||||
}
|
||||
return false; //not a spell effect
|
||||
return false; //not a spell effect
|
||||
});
|
||||
}
|
||||
|
||||
@ -193,9 +193,9 @@ ESpellCastProblem::ESpellCastProblem DispellMechanics::isImmuneByStack(const ISp
|
||||
{
|
||||
//just in case
|
||||
if(!obj->alive())
|
||||
return ESpellCastProblem::WRONG_SPELL_TARGET;
|
||||
return ESpellCastProblem::WRONG_SPELL_TARGET;
|
||||
}
|
||||
//DISPELL ignores all immunities, except specific absolute immunity
|
||||
//DISPELL ignores all immunities, except specific absolute immunity
|
||||
{
|
||||
//SPELL_IMMUNITY absolute case
|
||||
std::stringstream cachingStr;
|
||||
@ -210,7 +210,7 @@ ESpellCastProblem::ESpellCastProblem DispellMechanics::isImmuneByStack(const ISp
|
||||
if(obj->hasBonus(Selector::sourceType(Bonus::SPELL_EFFECT), cachingStr.str()))
|
||||
{
|
||||
return ESpellCastProblem::OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ESpellCastProblem::WRONG_SPELL_TARGET;
|
||||
//any other immunities are ignored - do not execute default algorithm
|
||||
@ -337,7 +337,7 @@ ESpellCastProblem::ESpellCastProblem EarthquakeMechanics::canBeCast(const CBattl
|
||||
{
|
||||
return ESpellCastProblem::NO_APPROPRIATE_TARGET;
|
||||
}
|
||||
|
||||
|
||||
CSpell::TargetInfo ti(owner, 0);//TODO: use real spell level
|
||||
if(ti.smart)
|
||||
{
|
||||
@ -353,7 +353,7 @@ ESpellCastProblem::ESpellCastProblem EarthquakeMechanics::canBeCast(const CBattl
|
||||
ESpellCastProblem::ESpellCastProblem HypnotizeMechanics::isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const
|
||||
{
|
||||
//todo: maybe do not resist on passive cast
|
||||
if(nullptr != caster)
|
||||
if(nullptr != caster)
|
||||
{
|
||||
//TODO: what with other creatures casting hypnotize, Faerie Dragons style?
|
||||
ui64 subjectHealth = (obj->count - 1) * obj->MaxHealth() + obj->firstHPleft;
|
||||
@ -521,7 +521,7 @@ HealingSpellMechanics::EHealLevel RisingSpellMechanics::getHealLevel(int effectL
|
||||
//this may be even distinct class
|
||||
if((effectLevel <= 1) && (owner->id == SpellID::RESURRECTION))
|
||||
return EHealLevel::RESURRECT;
|
||||
|
||||
|
||||
return EHealLevel::TRUE_RESURRECT;
|
||||
}
|
||||
|
||||
@ -532,9 +532,9 @@ ESpellCastProblem::ESpellCastProblem SacrificeMechanics::canBeCast(const CBattle
|
||||
|
||||
bool targetExists = false;
|
||||
bool targetToSacrificeExists = false;
|
||||
|
||||
|
||||
const CGHeroInstance * caster = nullptr; //todo: use ISpellCaster
|
||||
|
||||
|
||||
if(cb->battleHasHero(cb->playerToSide(player)))
|
||||
caster = cb->battleGetFightingHero(cb->playerToSide(player));
|
||||
|
||||
@ -624,7 +624,7 @@ ESpellCastProblem::ESpellCastProblem SpecialRisingSpellMechanics::isImmuneByStac
|
||||
return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
|
||||
|
||||
//FIXME: Archangels can cast immune stack and this should be applied for them and not hero
|
||||
// if(caster)
|
||||
// if(caster)
|
||||
// {
|
||||
// auto maxHealth = calculateHealedHP(caster, obj, nullptr);
|
||||
// if (maxHealth < obj->MaxHealth()) //must be able to rise at least one full creature
|
||||
@ -640,16 +640,16 @@ ESpellCastProblem::ESpellCastProblem SummonMechanics::canBeCast(const CBattleInf
|
||||
const ui8 side = cb->playerToSide(player);
|
||||
|
||||
//check if there are summoned elementals of other type
|
||||
|
||||
|
||||
auto otherSummoned = cb->battleGetStacksIf([side, this](const CStack * st)
|
||||
{
|
||||
return (st->attackerOwned == !side)
|
||||
&& (vstd::contains(st->state, EBattleStackState::SUMMONED))
|
||||
&& (st->getCreature()->idNumber != creatureToSummon);
|
||||
});
|
||||
|
||||
|
||||
if(!otherSummoned.empty())
|
||||
return ESpellCastProblem::ANOTHER_ELEMENTAL_SUMMONED;
|
||||
return ESpellCastProblem::ANOTHER_ELEMENTAL_SUMMONED;
|
||||
|
||||
return ESpellCastProblem::OK;
|
||||
}
|
||||
@ -692,7 +692,7 @@ void TeleportMechanics::applyBattleEffects(const SpellCastEnvironment * env, con
|
||||
if(!destination.isValid())
|
||||
{
|
||||
env->complain("TeleportMechanics: invalid teleport destination");
|
||||
return;
|
||||
return;
|
||||
}
|
||||
BattleStackMoved bsm;
|
||||
bsm.distance = -1;
|
||||
@ -701,7 +701,7 @@ void TeleportMechanics::applyBattleEffects(const SpellCastEnvironment * env, con
|
||||
tiles.push_back(destination);
|
||||
bsm.tilesToMove = tiles;
|
||||
bsm.teleporting = true;
|
||||
env->sendAndApply(&bsm);
|
||||
env->sendAndApply(&bsm);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -714,7 +714,7 @@ void TeleportMechanics::applyBattleEffects(const SpellCastEnvironment * env, con
|
||||
bsm.tilesToMove = tiles;
|
||||
bsm.teleporting = true;
|
||||
env->sendAndApply(&bsm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -15,14 +15,14 @@
|
||||
class DLL_LINKAGE HealingSpellMechanics : public DefaultSpellMechanics
|
||||
{
|
||||
public:
|
||||
enum class EHealLevel
|
||||
enum class EHealLevel
|
||||
{
|
||||
HEAL,
|
||||
RESURRECT,
|
||||
TRUE_RESURRECT
|
||||
};
|
||||
|
||||
HealingSpellMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
HealingSpellMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
protected:
|
||||
void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
|
||||
virtual int calculateHealedHP(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const;
|
||||
@ -32,9 +32,9 @@ protected:
|
||||
class DLL_LINKAGE AntimagicMechanics : public DefaultSpellMechanics
|
||||
{
|
||||
public:
|
||||
AntimagicMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
|
||||
void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const override final;
|
||||
AntimagicMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
|
||||
void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const override final;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE ChainLightningMechanics : public DefaultSpellMechanics
|
||||
@ -59,7 +59,7 @@ public:
|
||||
CureMechanics(CSpell * s): HealingSpellMechanics(s){};
|
||||
|
||||
void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const override final;
|
||||
|
||||
|
||||
EHealLevel getHealLevel(int effectLevel) const override final;
|
||||
};
|
||||
|
||||
@ -130,7 +130,7 @@ public:
|
||||
ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, PlayerColor player) const override;
|
||||
protected:
|
||||
void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
|
||||
int calculateHealedHP(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
|
||||
int calculateHealedHP(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
|
||||
};
|
||||
|
||||
///all rising spells but SACRIFICE
|
||||
|
@ -19,7 +19,7 @@ class StacksInjured;
|
||||
struct SpellCastContext
|
||||
{
|
||||
SpellCastContext(std::vector<const CStack *> & attackedCres, BattleSpellCast & sc, StacksInjured & si):
|
||||
attackedCres(attackedCres), sc(sc), si(si)
|
||||
attackedCres(attackedCres), sc(sc), si(si)
|
||||
{
|
||||
};
|
||||
std::vector<const CStack *> & attackedCres;
|
||||
@ -43,21 +43,21 @@ public:
|
||||
std::set<const CStack *> getAffectedStacks(SpellTargetingContext & ctx) const override;
|
||||
|
||||
ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, PlayerColor player) const override;
|
||||
|
||||
|
||||
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const override;
|
||||
|
||||
virtual void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const override;
|
||||
bool adventureCast(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override final;
|
||||
void battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const override final;
|
||||
|
||||
void battleLogSingleTarget(std::vector<std::string> & logLines, const BattleSpellCast * packet,
|
||||
const std::string & casterName, const CStack * attackedStack, bool & displayDamage) const override;
|
||||
void battleLogSingleTarget(std::vector<std::string> & logLines, const BattleSpellCast * packet,
|
||||
const std::string & casterName, const CStack * attackedStack, bool & displayDamage) const override;
|
||||
protected:
|
||||
virtual void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const;
|
||||
|
||||
///actual adventure cast implementation
|
||||
virtual ESpellCastResult applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const;
|
||||
|
||||
|
||||
void doDispell(BattleInfo * battle, const BattleSpellCast * packet, const CSelector & selector) const;
|
||||
private:
|
||||
void castMagicMirror(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const;
|
||||
|
@ -68,7 +68,7 @@ public:
|
||||
{
|
||||
std::string resourceName;
|
||||
VerticalPosition verticalPosition;
|
||||
int pause;
|
||||
int pause;
|
||||
|
||||
AnimationItem();
|
||||
|
||||
@ -78,7 +78,7 @@ public:
|
||||
if(version >= 754) //save format backward compatibility
|
||||
{
|
||||
h & pause;
|
||||
}
|
||||
}
|
||||
else if(!h.saving)
|
||||
{
|
||||
pause = 0;
|
||||
@ -128,8 +128,8 @@ public:
|
||||
std::string range;
|
||||
|
||||
std::vector<Bonus> effects;
|
||||
|
||||
std::vector<Bonus *> effectsTmp; //TODO: this should replace effects
|
||||
|
||||
std::vector<Bonus *> effectsTmp; //TODO: this should replace effects
|
||||
|
||||
LevelInfo();
|
||||
~LevelInfo();
|
||||
@ -265,13 +265,13 @@ public:
|
||||
friend class Graphics;
|
||||
public:
|
||||
///internal interface (for callbacks)
|
||||
|
||||
|
||||
///Checks general but spell-specific problems for all casting modes. Use only during battle.
|
||||
ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, PlayerColor player) const;
|
||||
|
||||
///checks for creature immunity / anything that prevent casting *at given hex* - doesn't take into account general problems such as not having spellbook or mana points etc.
|
||||
ESpellCastProblem::ESpellCastProblem isImmuneAt(const CBattleInfoCallback * cb, const ISpellCaster * caster, ECastingMode::ECastingMode mode, BattleHex destination) const;
|
||||
|
||||
|
||||
///checks for creature immunity / anything that prevent casting *at given target* - doesn't take into account general problems such as not having spellbook or mana points etc.
|
||||
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const;
|
||||
public:
|
||||
@ -295,7 +295,7 @@ public://internal, for use only by Mechanics classes
|
||||
///applies caster`s secondary skills and affectedCreature`s to raw damage
|
||||
int adjustRawDamage(const ISpellCaster * caster, const CStack * affectedCreature, int rawDamage) const;
|
||||
///returns raw damage or healed HP
|
||||
int calculateRawEffectValue(int effectLevel, int effectPower) const;
|
||||
int calculateRawEffectValue(int effectLevel, int effectPower) const;
|
||||
///generic immunity calculation
|
||||
ESpellCastProblem::ESpellCastProblem internalIsImmune(const ISpellCaster * caster, const CStack *obj) const;
|
||||
|
||||
|
@ -48,7 +48,7 @@ void DeathStareMechanics::applyBattleEffects(const SpellCastEnvironment * env, c
|
||||
BattleStackAttacked bsa;
|
||||
bsa.flags |= BattleStackAttacked::SPELL_EFFECT;
|
||||
bsa.spellID = owner->id;
|
||||
bsa.damageAmount = parameters.effectPower * (attackedCre)->valOfBonuses(Bonus::STACK_HEALTH);//todo: move here all DeathStare calculation
|
||||
bsa.damageAmount = parameters.effectPower * (attackedCre)->valOfBonuses(Bonus::STACK_HEALTH);//todo: move here all DeathStare calculation
|
||||
bsa.stackAttacked = (attackedCre)->ID;
|
||||
bsa.attackerID = -1;
|
||||
(attackedCre)->prepareAttacked(bsa, env->getRandomGenerator());
|
||||
@ -60,8 +60,8 @@ void DeathStareMechanics::applyBattleEffects(const SpellCastEnvironment * env, c
|
||||
void DispellHelpfulMechanics::applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const
|
||||
{
|
||||
DefaultSpellMechanics::applyBattle(battle, packet);
|
||||
|
||||
doDispell(battle, packet, Selector::positiveSpellEffects);
|
||||
|
||||
doDispell(battle, packet, Selector::positiveSpellEffects);
|
||||
}
|
||||
|
||||
ESpellCastProblem::ESpellCastProblem DispellHelpfulMechanics::isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const
|
||||
|
@ -24,14 +24,14 @@ BattleSpellCastParameters::Destination::Destination(const CStack * destination):
|
||||
stackValue(destination),
|
||||
hexValue(destination->position)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
BattleSpellCastParameters::Destination::Destination(const BattleHex & destination):
|
||||
stackValue(nullptr),
|
||||
hexValue(destination)
|
||||
hexValue(destination)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
BattleSpellCastParameters::BattleSpellCastParameters(const BattleInfo * cb, const ISpellCaster * caster, const CSpell * spell)
|
||||
@ -68,10 +68,10 @@ void BattleSpellCastParameters::prepare(const CSpell * spell)
|
||||
effectPower = caster->getEffectPower(spell);
|
||||
effectValue = caster->getEffectValue(spell);
|
||||
enchantPower = caster->getEnchantPower(spell);
|
||||
|
||||
|
||||
vstd::amax(spellLvl, 0);
|
||||
vstd::amax(effectLevel, 0);
|
||||
vstd::amax(enchantPower, 0);
|
||||
vstd::amax(enchantPower, 0);
|
||||
vstd::amax(enchantPower, 0);
|
||||
vstd::amax(effectValue, 0);
|
||||
}
|
||||
@ -118,11 +118,11 @@ ISpellMechanics * ISpellMechanics::createMechanics(CSpell * s)
|
||||
case SpellID::SACRIFICE:
|
||||
return new SacrificeMechanics(s);
|
||||
case SpellID::SUMMON_FIRE_ELEMENTAL:
|
||||
return new SummonMechanics(s, CreatureID::FIRE_ELEMENTAL);
|
||||
return new SummonMechanics(s, CreatureID::FIRE_ELEMENTAL);
|
||||
case SpellID::SUMMON_EARTH_ELEMENTAL:
|
||||
return new SummonMechanics(s, CreatureID::EARTH_ELEMENTAL);
|
||||
return new SummonMechanics(s, CreatureID::EARTH_ELEMENTAL);
|
||||
case SpellID::SUMMON_WATER_ELEMENTAL:
|
||||
return new SummonMechanics(s, CreatureID::WATER_ELEMENTAL);
|
||||
return new SummonMechanics(s, CreatureID::WATER_ELEMENTAL);
|
||||
case SpellID::SUMMON_AIR_ELEMENTAL:
|
||||
return new SummonMechanics(s, CreatureID::AIR_ELEMENTAL);
|
||||
case SpellID::TELEPORT:
|
||||
@ -151,4 +151,4 @@ ISpellMechanics * ISpellMechanics::createMechanics(CSpell * s)
|
||||
return new DefaultSpellMechanics(s);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -34,13 +34,13 @@ public:
|
||||
struct DLL_LINKAGE BattleSpellCastParameters
|
||||
{
|
||||
public:
|
||||
///Single spell destination.
|
||||
///Single spell destination.
|
||||
/// (assumes that anything but battle stack can share same hex)
|
||||
struct DLL_LINKAGE Destination
|
||||
{
|
||||
explicit Destination(const CStack * destination);
|
||||
explicit Destination(const CStack * destination);
|
||||
explicit Destination(const BattleHex & destination);
|
||||
|
||||
|
||||
const CStack * stackValue;
|
||||
const BattleHex hexValue;
|
||||
};
|
||||
@ -49,10 +49,10 @@ public:
|
||||
void aimToHex(const BattleHex & destination);
|
||||
void aimToStack(const CStack * destination);
|
||||
BattleHex getFirstDestinationHex() const;
|
||||
|
||||
|
||||
const BattleInfo * cb;
|
||||
const ISpellCaster * caster;
|
||||
const PlayerColor casterColor;
|
||||
const PlayerColor casterColor;
|
||||
const ui8 casterSide;
|
||||
|
||||
std::vector<Destination> destinations;
|
||||
@ -63,7 +63,7 @@ public:
|
||||
const CStack * selectedStack;//deprecated
|
||||
|
||||
///spell school level
|
||||
int spellLvl;
|
||||
int spellLvl;
|
||||
///spell school level to use for effects
|
||||
int effectLevel;
|
||||
///actual spell-power affecting effect values
|
||||
@ -72,7 +72,7 @@ public:
|
||||
int enchantPower;
|
||||
///for Archangel-like casting
|
||||
int effectValue;
|
||||
private:
|
||||
private:
|
||||
void prepare(const CSpell * spell);
|
||||
};
|
||||
|
||||
@ -105,18 +105,18 @@ public:
|
||||
|
||||
virtual std::vector<BattleHex> rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool * outDroppedHexes = nullptr) const = 0;
|
||||
virtual std::set<const CStack *> getAffectedStacks(SpellTargetingContext & ctx) const = 0;
|
||||
|
||||
|
||||
virtual ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, PlayerColor player) const = 0;
|
||||
|
||||
|
||||
virtual ESpellCastProblem::ESpellCastProblem isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const = 0;
|
||||
|
||||
|
||||
virtual void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const = 0;
|
||||
virtual bool adventureCast(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const = 0;
|
||||
virtual void battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const = 0;
|
||||
|
||||
virtual void battleLogSingleTarget(std::vector<std::string> & logLines, const BattleSpellCast * packet,
|
||||
virtual void battleLogSingleTarget(std::vector<std::string> & logLines, const BattleSpellCast * packet,
|
||||
const std::string & casterName, const CStack * attackedStack, bool & displayDamage) const = 0;
|
||||
|
||||
|
||||
static ISpellMechanics * createMechanics(CSpell * s);
|
||||
protected:
|
||||
CSpell * owner;
|
||||
|
@ -23,15 +23,15 @@ class DLL_LINKAGE ISpellCaster
|
||||
{
|
||||
public:
|
||||
virtual ~ISpellCaster(){};
|
||||
|
||||
|
||||
/// returns level on which given spell would be cast by this(0 - none, 1 - basic etc);
|
||||
/// caster may not know this spell at all
|
||||
/// caster may not know this spell at all
|
||||
/// optionally returns number of selected school by arg - 0 - air magic, 1 - fire magic, 2 - water magic, 3 - earth magic
|
||||
virtual ui8 getSpellSchoolLevel(const CSpell * spell, int *outSelectedSchool = nullptr) const = 0;
|
||||
virtual ui8 getSpellSchoolLevel(const CSpell * spell, int *outSelectedSchool = nullptr) const = 0;
|
||||
|
||||
///applying sorcery secondary skill etc
|
||||
virtual ui32 getSpellBonus(const CSpell * spell, ui32 base, const CStack * affectedStack) const = 0;
|
||||
|
||||
|
||||
///default spell school level for effect calculation
|
||||
virtual int getEffectLevel(const CSpell * spell) const = 0;
|
||||
|
||||
@ -43,6 +43,6 @@ public:
|
||||
|
||||
///damage/heal override(ignores spell configuration, effect level and effect power)
|
||||
virtual int getEffectValue(const CSpell * spell) const = 0;
|
||||
|
||||
|
||||
virtual const PlayerColor getOwner() const = 0;
|
||||
};
|
||||
|
@ -1005,7 +1005,8 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
|
||||
assert(gs->curB->isInTacticRange(dest));
|
||||
}
|
||||
|
||||
if(curStack->position == dest)
|
||||
auto start = curStack->position;
|
||||
if(start == dest)
|
||||
return 0;
|
||||
|
||||
//initing necessary tables
|
||||
@ -1032,16 +1033,60 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::pair< std::vector<BattleHex>, int > path = gs->curB->getPath(curStack->position, dest, curStack);
|
||||
bool canUseGate = false;
|
||||
auto dbState = gs->curB->si.gateState;
|
||||
if(battleGetSiegeLevel() > 0 && !curStack->attackerOwned &&
|
||||
dbState != EGateState::DESTROYED &&
|
||||
dbState != EGateState::BLOCKED)
|
||||
{
|
||||
canUseGate = true;
|
||||
}
|
||||
|
||||
std::pair< std::vector<BattleHex>, int > path = gs->curB->getPath(start, dest, curStack);
|
||||
|
||||
ret = path.second;
|
||||
|
||||
int creSpeed = gs->curB->tacticDistance ? GameConstants::BFIELD_SIZE : curStack->Speed();
|
||||
|
||||
auto isGateDrawbridgeHex = [&](BattleHex hex) -> bool
|
||||
{
|
||||
if(gs->curB->town->subID == ETownType::FORTRESS && hex == ESiegeHex::GATE_BRIDGE)
|
||||
return true;
|
||||
if(hex == ESiegeHex::GATE_OUTER)
|
||||
return true;
|
||||
if(hex == ESiegeHex::GATE_INNER)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
auto occupyGateDrawbridgeHex = [&](BattleHex hex) -> bool
|
||||
{
|
||||
if(isGateDrawbridgeHex(hex))
|
||||
return true;
|
||||
|
||||
if(curStack->doubleWide())
|
||||
{
|
||||
BattleHex otherHex = curStack->occupiedHex(hex);
|
||||
if(otherHex.isValid() && isGateDrawbridgeHex(otherHex))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
if(curStack->hasBonusOfType(Bonus::FLYING))
|
||||
{
|
||||
if(path.second <= creSpeed && path.first.size() > 0)
|
||||
{
|
||||
if(canUseGate && dbState != EGateState::OPENED &&
|
||||
occupyGateDrawbridgeHex(dest))
|
||||
{
|
||||
BattleUpdateGateState db;
|
||||
db.state = EGateState::OPENED;
|
||||
sendAndApply(&db);
|
||||
}
|
||||
|
||||
//inform clients about move
|
||||
BattleStackMoved sm;
|
||||
sm.stack = curStack->ID;
|
||||
@ -1059,6 +1104,72 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
|
||||
std::vector<BattleHex> tiles;
|
||||
const int tilesToMove = std::max((int)(path.first.size() - creSpeed), 0);
|
||||
int v = path.first.size()-1;
|
||||
path.first.push_back(start);
|
||||
|
||||
// check if gate need to be open or closed at some point
|
||||
BattleHex openGateAtHex, gateMayCloseAtHex;
|
||||
if(canUseGate)
|
||||
{
|
||||
for(int i = path.first.size()-1; i >= 0; i--)
|
||||
{
|
||||
auto needOpenGates = [&](BattleHex hex) -> bool
|
||||
{
|
||||
if(gs->curB->town->subID == ETownType::FORTRESS && hex == ESiegeHex::GATE_BRIDGE)
|
||||
return true;
|
||||
if(hex == ESiegeHex::GATE_BRIDGE && i-1 >= 0 && path.first[i-1] == ESiegeHex::GATE_OUTER)
|
||||
return true;
|
||||
else if(hex == ESiegeHex::GATE_OUTER || hex == ESiegeHex::GATE_INNER)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
auto hex = path.first[i];
|
||||
if(!openGateAtHex.isValid() && dbState != EGateState::OPENED)
|
||||
{
|
||||
if(needOpenGates(hex))
|
||||
openGateAtHex = path.first[i+1];
|
||||
|
||||
//TODO we need find batter way to handle double-wide stacks
|
||||
//currently if only second occupied stack part is standing on gate / bridge hex then stack will start to wait for bridge to lower before it's needed. Though this is just a visual bug.
|
||||
if(curStack->doubleWide())
|
||||
{
|
||||
BattleHex otherHex = curStack->occupiedHex(hex);
|
||||
if(otherHex.isValid() && needOpenGates(otherHex))
|
||||
openGateAtHex = path.first[i+2];
|
||||
}
|
||||
|
||||
//gate may be opened and then closed during stack movement, but not other way around
|
||||
if(openGateAtHex.isValid())
|
||||
dbState = EGateState::OPENED;
|
||||
}
|
||||
|
||||
if(!gateMayCloseAtHex.isValid() && dbState != EGateState::CLOSED)
|
||||
{
|
||||
if(hex == ESiegeHex::GATE_INNER && i-1 >= 0 && path.first[i-1] != ESiegeHex::GATE_OUTER)
|
||||
{
|
||||
gateMayCloseAtHex = path.first[i-1];
|
||||
}
|
||||
if(gs->curB->town->subID == ETownType::FORTRESS)
|
||||
{
|
||||
if(hex == ESiegeHex::GATE_BRIDGE && i-1 >= 0 && path.first[i-1] != ESiegeHex::GATE_OUTER)
|
||||
{
|
||||
gateMayCloseAtHex = path.first[i-1];
|
||||
}
|
||||
else if(hex == ESiegeHex::GATE_OUTER && i-1 >= 0 &&
|
||||
path.first[i-1] != ESiegeHex::GATE_INNER &&
|
||||
path.first[i-1] != ESiegeHex::GATE_BRIDGE)
|
||||
{
|
||||
gateMayCloseAtHex = path.first[i-1];
|
||||
}
|
||||
}
|
||||
else if(hex == ESiegeHex::GATE_OUTER && i-1 >= 0 && path.first[i-1] != ESiegeHex::GATE_INNER)
|
||||
{
|
||||
gateMayCloseAtHex = path.first[i-1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool stackIsMoving = true;
|
||||
|
||||
@ -1070,22 +1181,35 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
|
||||
break;
|
||||
}
|
||||
|
||||
for(bool obstacleHit = false; (!obstacleHit) && (v >= tilesToMove); --v)
|
||||
bool gateStateChanging = false;
|
||||
//special handling for opening gate on from starting hex
|
||||
if(openGateAtHex.isValid() && openGateAtHex == start)
|
||||
gateStateChanging = true;
|
||||
else
|
||||
{
|
||||
BattleHex hex = path.first[v];
|
||||
tiles.push_back(hex);
|
||||
|
||||
//if we walked onto something, finalize this portion of stack movement check into obstacle
|
||||
if((obstacle = battleGetObstacleOnPos(hex, false)))
|
||||
obstacleHit = true;
|
||||
|
||||
if(curStack->doubleWide())
|
||||
for(bool obstacleHit = false; (!obstacleHit) && (!gateStateChanging) && (v >= tilesToMove); --v)
|
||||
{
|
||||
BattleHex otherHex = curStack->occupiedHex(hex);
|
||||
BattleHex hex = path.first[v];
|
||||
tiles.push_back(hex);
|
||||
|
||||
//two hex creature hit obstacle by backside
|
||||
if(otherHex.isValid() && ((obstacle2 = battleGetObstacleOnPos(otherHex, false))))
|
||||
if((openGateAtHex.isValid() && openGateAtHex == hex) ||
|
||||
(gateMayCloseAtHex.isValid() && gateMayCloseAtHex == hex))
|
||||
{
|
||||
gateStateChanging = true;
|
||||
}
|
||||
|
||||
//if we walked onto something, finalize this portion of stack movement check into obstacle
|
||||
if((obstacle = battleGetObstacleOnPos(hex, false)))
|
||||
obstacleHit = true;
|
||||
|
||||
if(curStack->doubleWide())
|
||||
{
|
||||
BattleHex otherHex = curStack->occupiedHex(hex);
|
||||
|
||||
//two hex creature hit obstacle by backside
|
||||
if(otherHex.isValid() && ((obstacle2 = battleGetObstacleOnPos(otherHex, false))))
|
||||
obstacleHit = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1121,6 +1245,26 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
|
||||
processObstacle(obstacle);
|
||||
if(curStack->alive())
|
||||
processObstacle(obstacle2);
|
||||
|
||||
if(gateStateChanging)
|
||||
{
|
||||
if(curStack->position == openGateAtHex)
|
||||
{
|
||||
openGateAtHex = BattleHex();
|
||||
//only open gate if stack is still alive
|
||||
if(curStack->alive())
|
||||
{
|
||||
BattleUpdateGateState db;
|
||||
db.state = EGateState::OPENED;
|
||||
sendAndApply(&db);
|
||||
}
|
||||
}
|
||||
else if(curStack->position == gateMayCloseAtHex)
|
||||
{
|
||||
gateMayCloseAtHex = BattleHex();
|
||||
updateGateState();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
//movement finished normally: we reached destination
|
||||
@ -1731,8 +1875,13 @@ void CGameHandler::setupBattle( int3 tile, const CArmedInstance *armies[2], cons
|
||||
sendAndApply(&bs);
|
||||
}
|
||||
|
||||
void CGameHandler::checkForBattleEnd()
|
||||
void CGameHandler::checkBattleStateChanges()
|
||||
{
|
||||
//check if drawbridge state need to be changes
|
||||
if(battleGetSiegeLevel() > 0)
|
||||
updateGateState();
|
||||
|
||||
//check if battle ended
|
||||
if(auto result = battleIsFinished())
|
||||
{
|
||||
setBattleResult(BattleResult::NORMAL, *result);
|
||||
@ -3466,6 +3615,39 @@ bool CGameHandler::queryReply(QueryID qid, ui32 answer, PlayerColor player)
|
||||
|
||||
static EndAction end_action;
|
||||
|
||||
void CGameHandler::updateGateState()
|
||||
{
|
||||
BattleUpdateGateState db;
|
||||
db.state = gs->curB->si.gateState;
|
||||
if(gs->curB->si.wallState[EWallPart::GATE] == EWallState::DESTROYED)
|
||||
{
|
||||
db.state = EGateState::DESTROYED;
|
||||
}
|
||||
else if(db.state == EGateState::OPENED)
|
||||
{
|
||||
if(!gs->curB->battleGetStackByPos(BattleHex(ESiegeHex::GATE_OUTER), false) &&
|
||||
!gs->curB->battleGetStackByPos(BattleHex(ESiegeHex::GATE_INNER), false))
|
||||
{
|
||||
if(gs->curB->town->subID == ETownType::FORTRESS)
|
||||
{
|
||||
if(!gs->curB->battleGetStackByPos(BattleHex(ESiegeHex::GATE_BRIDGE), false))
|
||||
db.state = EGateState::CLOSED;
|
||||
}
|
||||
else if(gs->curB->battleGetStackByPos(BattleHex(ESiegeHex::GATE_BRIDGE)))
|
||||
db.state = EGateState::BLOCKED;
|
||||
else
|
||||
db.state = EGateState::CLOSED;
|
||||
}
|
||||
}
|
||||
else if(gs->curB->battleGetStackByPos(BattleHex(ESiegeHex::GATE_BRIDGE), false))
|
||||
db.state = EGateState::BLOCKED;
|
||||
else
|
||||
db.state = EGateState::CLOSED;
|
||||
|
||||
if(db.state != gs->curB->si.gateState)
|
||||
sendAndApply(&db);
|
||||
}
|
||||
|
||||
bool CGameHandler::makeBattleAction( BattleAction &ba )
|
||||
{
|
||||
bool ok = true;
|
||||
@ -4218,7 +4400,7 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
|
||||
{
|
||||
battleMadeAction.setn(true);
|
||||
}
|
||||
checkForBattleEnd();
|
||||
checkBattleStateChanges();
|
||||
if(battleResult.get())
|
||||
{
|
||||
battleMadeAction.setn(true);
|
||||
@ -5605,7 +5787,7 @@ void CGameHandler::runBattle()
|
||||
break;
|
||||
}
|
||||
//we're after action, all results applied
|
||||
checkForBattleEnd(); //check if this action ended the battle
|
||||
checkBattleStateChanges(); //check if this action ended the battle
|
||||
|
||||
if(next != nullptr)
|
||||
{
|
||||
@ -5657,7 +5839,7 @@ bool CGameHandler::makeAutomaticAction(const CStack *stack, BattleAction &ba)
|
||||
sendAndApply(&bsa);
|
||||
|
||||
bool ret = makeBattleAction(ba);
|
||||
checkForBattleEnd();
|
||||
checkBattleStateChanges();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -115,7 +115,7 @@ public:
|
||||
void endBattle(int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2); //ends battle
|
||||
void prepareAttack(BattleAttack &bat, const CStack *att, const CStack *def, int distance, int targetHex); //distance - number of hexes travelled before attacking
|
||||
void applyBattleEffects(BattleAttack &bat, const CStack *att, const CStack *def, int distance, bool secondary); //damage, drain life & fire shield
|
||||
void checkForBattleEnd();
|
||||
void checkBattleStateChanges();
|
||||
void setupBattle(int3 tile, const CArmedInstance *armies[2], const CGHeroInstance *heroes[2], bool creatureBank, const CGTownInstance *town);
|
||||
void setBattleResult(BattleResult::EResult resultType, int victoriusSide);
|
||||
void duelFinished();
|
||||
@ -203,6 +203,7 @@ public:
|
||||
PlayerColor getPlayerAt(CConnection *c) const;
|
||||
|
||||
void playerMessage( PlayerColor player, const std::string &message, ObjectInstanceID currObj);
|
||||
void updateGateState();
|
||||
bool makeBattleAction(BattleAction &ba);
|
||||
bool makeAutomaticAction(const CStack *stack, BattleAction &ba); //used when action is taken by stack without volition of player (eg. unguided catapult attack)
|
||||
bool makeCustomAction(BattleAction &ba);
|
||||
|
Loading…
Reference in New Issue
Block a user