mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-22 22:13:35 +02:00
Fix battle setup for sieges without forts
- Update the if statement in BattleProcessor::SetupBattle to allow obstacles in battlefields during sieges without forts. - Ensure towns without forts use the native battlegrounds. - Refactor variable name from curB to currentBattle for clarity.
This commit is contained in:
parent
52e0899d6f
commit
c576438a95
@ -161,54 +161,45 @@ struct RangeGenerator
|
|||||||
BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const BattleField & battlefieldType, BattleSideArray<const CArmedInstance *> armies, BattleSideArray<const CGHeroInstance *> heroes, const BattleLayout & layout, const CGTownInstance * town)
|
BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const BattleField & battlefieldType, BattleSideArray<const CArmedInstance *> armies, BattleSideArray<const CGHeroInstance *> heroes, const BattleLayout & layout, const CGTownInstance * town)
|
||||||
{
|
{
|
||||||
CMP_stack cmpst;
|
CMP_stack cmpst;
|
||||||
auto * curB = new BattleInfo(layout);
|
auto * currentBattle = new BattleInfo(layout);
|
||||||
|
|
||||||
for(auto i : { BattleSide::LEFT_SIDE, BattleSide::RIGHT_SIDE})
|
for(auto i : { BattleSide::LEFT_SIDE, BattleSide::RIGHT_SIDE})
|
||||||
curB->sides[i].init(heroes[i], armies[i]);
|
currentBattle->sides[i].init(heroes[i], armies[i]);
|
||||||
|
|
||||||
std::vector<CStack*> & stacks = (curB->stacks);
|
std::vector<CStack*> & stacks = (currentBattle->stacks);
|
||||||
|
|
||||||
curB->tile = tile;
|
currentBattle->tile = tile;
|
||||||
curB->battlefieldType = battlefieldType;
|
currentBattle->terrainType = terrain;
|
||||||
curB->round = -2;
|
currentBattle->battlefieldType = battlefieldType;
|
||||||
curB->activeStack = -1;
|
currentBattle->round = -2;
|
||||||
curB->replayAllowed = false;
|
currentBattle->activeStack = -1;
|
||||||
|
currentBattle->replayAllowed = false;
|
||||||
if(town)
|
currentBattle->town = town;
|
||||||
{
|
|
||||||
curB->town = town;
|
|
||||||
curB->terrainType = town->getNativeTerrain();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
curB->town = nullptr;
|
|
||||||
curB->terrainType = terrain;
|
|
||||||
}
|
|
||||||
|
|
||||||
//setting up siege obstacles
|
//setting up siege obstacles
|
||||||
if (town && town->fortificationsLevel().wallsHealth != 0)
|
if (town && town->fortificationsLevel().wallsHealth != 0)
|
||||||
{
|
{
|
||||||
auto fortification = town->fortificationsLevel();
|
auto fortification = town->fortificationsLevel();
|
||||||
|
|
||||||
curB->si.gateState = EGateState::CLOSED;
|
currentBattle->si.gateState = EGateState::CLOSED;
|
||||||
|
|
||||||
curB->si.wallState[EWallPart::GATE] = EWallState::INTACT;
|
currentBattle->si.wallState[EWallPart::GATE] = EWallState::INTACT;
|
||||||
|
|
||||||
for(const auto wall : {EWallPart::BOTTOM_WALL, EWallPart::BELOW_GATE, EWallPart::OVER_GATE, EWallPart::UPPER_WALL})
|
for(const auto wall : {EWallPart::BOTTOM_WALL, EWallPart::BELOW_GATE, EWallPart::OVER_GATE, EWallPart::UPPER_WALL})
|
||||||
curB->si.wallState[wall] = static_cast<EWallState>(fortification.wallsHealth);
|
currentBattle->si.wallState[wall] = static_cast<EWallState>(fortification.wallsHealth);
|
||||||
|
|
||||||
if (fortification.citadelHealth != 0)
|
if (fortification.citadelHealth != 0)
|
||||||
curB->si.wallState[EWallPart::KEEP] = static_cast<EWallState>(fortification.citadelHealth);
|
currentBattle->si.wallState[EWallPart::KEEP] = static_cast<EWallState>(fortification.citadelHealth);
|
||||||
|
|
||||||
if (fortification.upperTowerHealth != 0)
|
if (fortification.upperTowerHealth != 0)
|
||||||
curB->si.wallState[EWallPart::UPPER_TOWER] = static_cast<EWallState>(fortification.upperTowerHealth);
|
currentBattle->si.wallState[EWallPart::UPPER_TOWER] = static_cast<EWallState>(fortification.upperTowerHealth);
|
||||||
|
|
||||||
if (fortification.lowerTowerHealth != 0)
|
if (fortification.lowerTowerHealth != 0)
|
||||||
curB->si.wallState[EWallPart::BOTTOM_TOWER] = static_cast<EWallState>(fortification.lowerTowerHealth);
|
currentBattle->si.wallState[EWallPart::BOTTOM_TOWER] = static_cast<EWallState>(fortification.lowerTowerHealth);
|
||||||
}
|
}
|
||||||
|
|
||||||
//randomize obstacles
|
//randomize obstacles
|
||||||
if (layout.obstaclesAllowed && !town)
|
if (layout.obstaclesAllowed && (!town || !town->hasFort()))
|
||||||
{
|
{
|
||||||
RandGen r{};
|
RandGen r{};
|
||||||
auto ourRand = [&](){ return r.rand(); };
|
auto ourRand = [&](){ return r.rand(); };
|
||||||
@ -221,12 +212,12 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
|
|||||||
auto appropriateAbsoluteObstacle = [&](int id)
|
auto appropriateAbsoluteObstacle = [&](int id)
|
||||||
{
|
{
|
||||||
const auto * info = Obstacle(id).getInfo();
|
const auto * info = Obstacle(id).getInfo();
|
||||||
return info && info->isAbsoluteObstacle && info->isAppropriate(curB->terrainType, battlefieldType);
|
return info && info->isAbsoluteObstacle && info->isAppropriate(currentBattle->terrainType, battlefieldType);
|
||||||
};
|
};
|
||||||
auto appropriateUsualObstacle = [&](int id)
|
auto appropriateUsualObstacle = [&](int id)
|
||||||
{
|
{
|
||||||
const auto * info = Obstacle(id).getInfo();
|
const auto * info = Obstacle(id).getInfo();
|
||||||
return info && !info->isAbsoluteObstacle && info->isAppropriate(curB->terrainType, battlefieldType);
|
return info && !info->isAbsoluteObstacle && info->isAppropriate(currentBattle->terrainType, battlefieldType);
|
||||||
};
|
};
|
||||||
|
|
||||||
if(r.rand(1,100) <= 40) //put cliff-like obstacle
|
if(r.rand(1,100) <= 40) //put cliff-like obstacle
|
||||||
@ -237,8 +228,8 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
|
|||||||
auto obstPtr = std::make_shared<CObstacleInstance>();
|
auto obstPtr = std::make_shared<CObstacleInstance>();
|
||||||
obstPtr->obstacleType = CObstacleInstance::ABSOLUTE_OBSTACLE;
|
obstPtr->obstacleType = CObstacleInstance::ABSOLUTE_OBSTACLE;
|
||||||
obstPtr->ID = obidgen.getSuchNumber(appropriateAbsoluteObstacle);
|
obstPtr->ID = obidgen.getSuchNumber(appropriateAbsoluteObstacle);
|
||||||
obstPtr->uniqueID = static_cast<si32>(curB->obstacles.size());
|
obstPtr->uniqueID = static_cast<si32>(currentBattle->obstacles.size());
|
||||||
curB->obstacles.push_back(obstPtr);
|
currentBattle->obstacles.push_back(obstPtr);
|
||||||
|
|
||||||
for(BattleHex blocked : obstPtr->getBlockedTiles())
|
for(BattleHex blocked : obstPtr->getBlockedTiles())
|
||||||
blockedTiles.push_back(blocked);
|
blockedTiles.push_back(blocked);
|
||||||
@ -256,7 +247,7 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
|
|||||||
while(tilesToBlock > 0)
|
while(tilesToBlock > 0)
|
||||||
{
|
{
|
||||||
RangeGenerator obidgen(0, VLC->obstacleHandler->size() - 1, ourRand);
|
RangeGenerator obidgen(0, VLC->obstacleHandler->size() - 1, ourRand);
|
||||||
auto tileAccessibility = curB->getAccessibility();
|
auto tileAccessibility = currentBattle->getAccessibility();
|
||||||
const int obid = obidgen.getSuchNumber(appropriateUsualObstacle);
|
const int obid = obidgen.getSuchNumber(appropriateUsualObstacle);
|
||||||
const ObstacleInfo &obi = *Obstacle(obid).getInfo();
|
const ObstacleInfo &obi = *Obstacle(obid).getInfo();
|
||||||
|
|
||||||
@ -290,8 +281,8 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
|
|||||||
auto obstPtr = std::make_shared<CObstacleInstance>();
|
auto obstPtr = std::make_shared<CObstacleInstance>();
|
||||||
obstPtr->ID = obid;
|
obstPtr->ID = obid;
|
||||||
obstPtr->pos = posgenerator.getSuchNumber(validPosition);
|
obstPtr->pos = posgenerator.getSuchNumber(validPosition);
|
||||||
obstPtr->uniqueID = static_cast<si32>(curB->obstacles.size());
|
obstPtr->uniqueID = static_cast<si32>(currentBattle->obstacles.size());
|
||||||
curB->obstacles.push_back(obstPtr);
|
currentBattle->obstacles.push_back(obstPtr);
|
||||||
|
|
||||||
for(BattleHex blocked : obstPtr->getBlockedTiles())
|
for(BattleHex blocked : obstPtr->getBlockedTiles())
|
||||||
blockedTiles.push_back(blocked);
|
blockedTiles.push_back(blocked);
|
||||||
@ -315,7 +306,7 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
|
|||||||
CreatureID cre = warMachineArt->artType->getWarMachine();
|
CreatureID cre = warMachineArt->artType->getWarMachine();
|
||||||
|
|
||||||
if(cre != CreatureID::NONE)
|
if(cre != CreatureID::NONE)
|
||||||
curB->generateNewStack(curB->nextUnitId(), CStackBasicDescriptor(cre, 1), side, SlotID::WAR_MACHINES_SLOT, hex);
|
currentBattle->generateNewStack(currentBattle->nextUnitId(), CStackBasicDescriptor(cre, 1), side, SlotID::WAR_MACHINES_SLOT, hex);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -353,7 +344,7 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
|
|||||||
const BattleHex & pos = layout.units.at(side).at(k);
|
const BattleHex & pos = layout.units.at(side).at(k);
|
||||||
|
|
||||||
if (pos.isValid())
|
if (pos.isValid())
|
||||||
curB->generateNewStack(curB->nextUnitId(), *i->second, side, i->first, pos);
|
currentBattle->generateNewStack(currentBattle->nextUnitId(), *i->second, side, i->first, pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -362,20 +353,20 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
|
|||||||
{
|
{
|
||||||
if (heroes[i] && heroes[i]->commander && heroes[i]->commander->alive)
|
if (heroes[i] && heroes[i]->commander && heroes[i]->commander->alive)
|
||||||
{
|
{
|
||||||
curB->generateNewStack(curB->nextUnitId(), *heroes[i]->commander, i, SlotID::COMMANDER_SLOT_PLACEHOLDER, layout.commanders.at(i));
|
currentBattle->generateNewStack(currentBattle->nextUnitId(), *heroes[i]->commander, i, SlotID::COMMANDER_SLOT_PLACEHOLDER, layout.commanders.at(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (curB->town)
|
if (currentBattle->town)
|
||||||
{
|
{
|
||||||
if (curB->town->fortificationsLevel().citadelHealth != 0)
|
if (currentBattle->town->fortificationsLevel().citadelHealth != 0)
|
||||||
curB->generateNewStack(curB->nextUnitId(), CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), BattleSide::DEFENDER, SlotID::ARROW_TOWERS_SLOT, BattleHex::CASTLE_CENTRAL_TOWER);
|
currentBattle->generateNewStack(currentBattle->nextUnitId(), CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), BattleSide::DEFENDER, SlotID::ARROW_TOWERS_SLOT, BattleHex::CASTLE_CENTRAL_TOWER);
|
||||||
|
|
||||||
if (curB->town->fortificationsLevel().upperTowerHealth != 0)
|
if (currentBattle->town->fortificationsLevel().upperTowerHealth != 0)
|
||||||
curB->generateNewStack(curB->nextUnitId(), CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), BattleSide::DEFENDER, SlotID::ARROW_TOWERS_SLOT, BattleHex::CASTLE_UPPER_TOWER);
|
currentBattle->generateNewStack(currentBattle->nextUnitId(), CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), BattleSide::DEFENDER, SlotID::ARROW_TOWERS_SLOT, BattleHex::CASTLE_UPPER_TOWER);
|
||||||
|
|
||||||
if (curB->town->fortificationsLevel().lowerTowerHealth != 0)
|
if (currentBattle->town->fortificationsLevel().lowerTowerHealth != 0)
|
||||||
curB->generateNewStack(curB->nextUnitId(), CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), BattleSide::DEFENDER, SlotID::ARROW_TOWERS_SLOT, BattleHex::CASTLE_BOTTOM_TOWER);
|
currentBattle->generateNewStack(currentBattle->nextUnitId(), CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), BattleSide::DEFENDER, SlotID::ARROW_TOWERS_SLOT, BattleHex::CASTLE_BOTTOM_TOWER);
|
||||||
|
|
||||||
//Moat generating is done on server
|
//Moat generating is done on server
|
||||||
}
|
}
|
||||||
@ -390,15 +381,15 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
|
|||||||
|
|
||||||
for(const std::shared_ptr<Bonus> & bonus : bgInfo->bonuses)
|
for(const std::shared_ptr<Bonus> & bonus : bgInfo->bonuses)
|
||||||
{
|
{
|
||||||
curB->addNewBonus(bonus);
|
currentBattle->addNewBonus(bonus);
|
||||||
}
|
}
|
||||||
|
|
||||||
//native terrain bonuses
|
//native terrain bonuses
|
||||||
auto nativeTerrain = std::make_shared<CreatureTerrainLimiter>();
|
auto nativeTerrain = std::make_shared<CreatureTerrainLimiter>();
|
||||||
|
|
||||||
curB->addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::STACKS_SPEED, BonusSource::TERRAIN_NATIVE, 1, BonusSourceID())->addLimiter(nativeTerrain));
|
currentBattle->addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::STACKS_SPEED, BonusSource::TERRAIN_NATIVE, 1, BonusSourceID())->addLimiter(nativeTerrain));
|
||||||
curB->addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::PRIMARY_SKILL, BonusSource::TERRAIN_NATIVE, 1, BonusSourceID(), BonusSubtypeID(PrimarySkill::ATTACK))->addLimiter(nativeTerrain));
|
currentBattle->addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::PRIMARY_SKILL, BonusSource::TERRAIN_NATIVE, 1, BonusSourceID(), BonusSubtypeID(PrimarySkill::ATTACK))->addLimiter(nativeTerrain));
|
||||||
curB->addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::PRIMARY_SKILL, BonusSource::TERRAIN_NATIVE, 1, BonusSourceID(), BonusSubtypeID(PrimarySkill::DEFENSE))->addLimiter(nativeTerrain));
|
currentBattle->addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::PRIMARY_SKILL, BonusSource::TERRAIN_NATIVE, 1, BonusSourceID(), BonusSubtypeID(PrimarySkill::DEFENSE))->addLimiter(nativeTerrain));
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
//tactics
|
//tactics
|
||||||
@ -428,21 +419,21 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
|
|||||||
logGlobal->warn("Double tactics is not implemented, only attacker will have tactics!");
|
logGlobal->warn("Double tactics is not implemented, only attacker will have tactics!");
|
||||||
if(tacticsSkillDiffAttacker > 0)
|
if(tacticsSkillDiffAttacker > 0)
|
||||||
{
|
{
|
||||||
curB->tacticsSide = BattleSide::ATTACKER;
|
currentBattle->tacticsSide = BattleSide::ATTACKER;
|
||||||
//bonus specifies distance you can move beyond base row; this allows 100% compatibility with HMM3 mechanics
|
//bonus specifies distance you can move beyond base row; this allows 100% compatibility with HMM3 mechanics
|
||||||
curB->tacticDistance = 1 + tacticsSkillDiffAttacker;
|
currentBattle->tacticDistance = 1 + tacticsSkillDiffAttacker;
|
||||||
}
|
}
|
||||||
else if(tacticsSkillDiffDefender > 0)
|
else if(tacticsSkillDiffDefender > 0)
|
||||||
{
|
{
|
||||||
curB->tacticsSide = BattleSide::DEFENDER;
|
currentBattle->tacticsSide = BattleSide::DEFENDER;
|
||||||
//bonus specifies distance you can move beyond base row; this allows 100% compatibility with HMM3 mechanics
|
//bonus specifies distance you can move beyond base row; this allows 100% compatibility with HMM3 mechanics
|
||||||
curB->tacticDistance = 1 + tacticsSkillDiffDefender;
|
currentBattle->tacticDistance = 1 + tacticsSkillDiffDefender;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
curB->tacticDistance = 0;
|
currentBattle->tacticDistance = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return curB;
|
return currentBattle;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CGHeroInstance * BattleInfo::getHero(const PlayerColor & player) const
|
const CGHeroInstance * BattleInfo::getHero(const PlayerColor & player) const
|
||||||
|
@ -28,10 +28,12 @@
|
|||||||
#include "../../lib/gameState/CGameState.h"
|
#include "../../lib/gameState/CGameState.h"
|
||||||
#include "../../lib/mapping/CMap.h"
|
#include "../../lib/mapping/CMap.h"
|
||||||
#include "../../lib/mapObjects/CGHeroInstance.h"
|
#include "../../lib/mapObjects/CGHeroInstance.h"
|
||||||
|
#include "../../lib/mapObjects/CGTownInstance.h"
|
||||||
#include "../../lib/modding/IdentifierStorage.h"
|
#include "../../lib/modding/IdentifierStorage.h"
|
||||||
#include "../../lib/networkPacks/PacksForClient.h"
|
#include "../../lib/networkPacks/PacksForClient.h"
|
||||||
#include "../../lib/networkPacks/PacksForClientBattle.h"
|
#include "../../lib/networkPacks/PacksForClientBattle.h"
|
||||||
#include "../../lib/CPlayerState.h"
|
#include "../../lib/CPlayerState.h"
|
||||||
|
#include "vstd/RNG.h"
|
||||||
|
|
||||||
BattleProcessor::BattleProcessor(CGameHandler * gameHandler)
|
BattleProcessor::BattleProcessor(CGameHandler * gameHandler)
|
||||||
: gameHandler(gameHandler)
|
: gameHandler(gameHandler)
|
||||||
@ -156,16 +158,24 @@ BattleID BattleProcessor::setupBattle(int3 tile, BattleSideArray<const CArmedIns
|
|||||||
{
|
{
|
||||||
const auto & t = *gameHandler->getTile(tile);
|
const auto & t = *gameHandler->getTile(tile);
|
||||||
TerrainId terrain = t.terType->getId();
|
TerrainId terrain = t.terType->getId();
|
||||||
if (gameHandler->gameState()->map->isCoastalTile(tile)) //coastal tile is always ground
|
if (town)
|
||||||
|
terrain = town->getNativeTerrain();
|
||||||
|
else if (gameHandler->gameState()->map->isCoastalTile(tile)) //coastal tile is always ground
|
||||||
terrain = ETerrainId::SAND;
|
terrain = ETerrainId::SAND;
|
||||||
|
|
||||||
BattleField terType = gameHandler->gameState()->battleGetBattlefieldType(tile, gameHandler->getRandomGenerator());
|
BattleField battlefieldType = gameHandler->gameState()->battleGetBattlefieldType(tile, gameHandler->getRandomGenerator());
|
||||||
if (heroes[BattleSide::ATTACKER] && heroes[BattleSide::ATTACKER]->boat && heroes[BattleSide::DEFENDER] && heroes[BattleSide::DEFENDER]->boat)
|
|
||||||
terType = BattleField(*VLC->identifiers()->getIdentifier("core", "battlefield.ship_to_ship"));
|
if (town)
|
||||||
|
{
|
||||||
|
const TerrainType* terrainData = VLC->terrainTypeHandler->getById(terrain);
|
||||||
|
battlefieldType = BattleField(*RandomGeneratorUtil::nextItem(terrainData->battleFields, gameHandler->getRandomGenerator()));
|
||||||
|
}
|
||||||
|
else if (heroes[BattleSide::ATTACKER] && heroes[BattleSide::ATTACKER]->boat && heroes[BattleSide::DEFENDER] && heroes[BattleSide::DEFENDER]->boat)
|
||||||
|
battlefieldType = BattleField(*VLC->identifiers()->getIdentifier("core", "battlefield.ship_to_ship"));
|
||||||
|
|
||||||
//send info about battles
|
//send info about battles
|
||||||
BattleStart bs;
|
BattleStart bs;
|
||||||
bs.info = BattleInfo::setupBattle(tile, terrain, terType, armies, heroes, layout, town);
|
bs.info = BattleInfo::setupBattle(tile, terrain, battlefieldType, armies, heroes, layout, town);
|
||||||
bs.battleID = gameHandler->gameState()->nextBattleID;
|
bs.battleID = gameHandler->gameState()->nextBattleID;
|
||||||
|
|
||||||
engageIntoBattle(bs.info->getSide(BattleSide::ATTACKER).color);
|
engageIntoBattle(bs.info->getSide(BattleSide::ATTACKER).color);
|
||||||
|
Loading…
Reference in New Issue
Block a user