mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-22 22:13:35 +02:00
Merge pull request #4790 from kodobi/bugfix/fix-incorrect-battlefield-while-attacking-town-without-fort
Fix battle setup for sieges without forts
This commit is contained in:
commit
59a15c5ff0
@ -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)
|
||||
{
|
||||
CMP_stack cmpst;
|
||||
auto * curB = new BattleInfo(layout);
|
||||
auto * currentBattle = new BattleInfo(layout);
|
||||
|
||||
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;
|
||||
curB->battlefieldType = battlefieldType;
|
||||
curB->round = -2;
|
||||
curB->activeStack = -1;
|
||||
curB->replayAllowed = false;
|
||||
|
||||
if(town)
|
||||
{
|
||||
curB->town = town;
|
||||
curB->terrainType = town->getNativeTerrain();
|
||||
}
|
||||
else
|
||||
{
|
||||
curB->town = nullptr;
|
||||
curB->terrainType = terrain;
|
||||
}
|
||||
currentBattle->tile = tile;
|
||||
currentBattle->terrainType = terrain;
|
||||
currentBattle->battlefieldType = battlefieldType;
|
||||
currentBattle->round = -2;
|
||||
currentBattle->activeStack = -1;
|
||||
currentBattle->replayAllowed = false;
|
||||
currentBattle->town = town;
|
||||
|
||||
//setting up siege obstacles
|
||||
if (town && town->fortificationsLevel().wallsHealth != 0)
|
||||
{
|
||||
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})
|
||||
curB->si.wallState[wall] = static_cast<EWallState>(fortification.wallsHealth);
|
||||
currentBattle->si.wallState[wall] = static_cast<EWallState>(fortification.wallsHealth);
|
||||
|
||||
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)
|
||||
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)
|
||||
curB->si.wallState[EWallPart::BOTTOM_TOWER] = static_cast<EWallState>(fortification.lowerTowerHealth);
|
||||
currentBattle->si.wallState[EWallPart::BOTTOM_TOWER] = static_cast<EWallState>(fortification.lowerTowerHealth);
|
||||
}
|
||||
|
||||
//randomize obstacles
|
||||
if (layout.obstaclesAllowed && !town)
|
||||
if (layout.obstaclesAllowed && (!town || !town->hasFort()))
|
||||
{
|
||||
RandGen r{};
|
||||
auto ourRand = [&](){ return r.rand(); };
|
||||
@ -221,12 +212,12 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
|
||||
auto appropriateAbsoluteObstacle = [&](int id)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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
|
||||
@ -237,8 +228,8 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
|
||||
auto obstPtr = std::make_shared<CObstacleInstance>();
|
||||
obstPtr->obstacleType = CObstacleInstance::ABSOLUTE_OBSTACLE;
|
||||
obstPtr->ID = obidgen.getSuchNumber(appropriateAbsoluteObstacle);
|
||||
obstPtr->uniqueID = static_cast<si32>(curB->obstacles.size());
|
||||
curB->obstacles.push_back(obstPtr);
|
||||
obstPtr->uniqueID = static_cast<si32>(currentBattle->obstacles.size());
|
||||
currentBattle->obstacles.push_back(obstPtr);
|
||||
|
||||
for(BattleHex blocked : obstPtr->getBlockedTiles())
|
||||
blockedTiles.push_back(blocked);
|
||||
@ -256,7 +247,7 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
|
||||
while(tilesToBlock > 0)
|
||||
{
|
||||
RangeGenerator obidgen(0, VLC->obstacleHandler->size() - 1, ourRand);
|
||||
auto tileAccessibility = curB->getAccessibility();
|
||||
auto tileAccessibility = currentBattle->getAccessibility();
|
||||
const int obid = obidgen.getSuchNumber(appropriateUsualObstacle);
|
||||
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>();
|
||||
obstPtr->ID = obid;
|
||||
obstPtr->pos = posgenerator.getSuchNumber(validPosition);
|
||||
obstPtr->uniqueID = static_cast<si32>(curB->obstacles.size());
|
||||
curB->obstacles.push_back(obstPtr);
|
||||
obstPtr->uniqueID = static_cast<si32>(currentBattle->obstacles.size());
|
||||
currentBattle->obstacles.push_back(obstPtr);
|
||||
|
||||
for(BattleHex blocked : obstPtr->getBlockedTiles())
|
||||
blockedTiles.push_back(blocked);
|
||||
@ -315,7 +306,7 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
|
||||
CreatureID cre = warMachineArt->artType->getWarMachine();
|
||||
|
||||
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);
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
curB->generateNewStack(curB->nextUnitId(), CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), BattleSide::DEFENDER, SlotID::ARROW_TOWERS_SLOT, BattleHex::CASTLE_CENTRAL_TOWER);
|
||||
if (currentBattle->town->fortificationsLevel().citadelHealth != 0)
|
||||
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)
|
||||
curB->generateNewStack(curB->nextUnitId(), CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), BattleSide::DEFENDER, SlotID::ARROW_TOWERS_SLOT, BattleHex::CASTLE_UPPER_TOWER);
|
||||
if (currentBattle->town->fortificationsLevel().upperTowerHealth != 0)
|
||||
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)
|
||||
curB->generateNewStack(curB->nextUnitId(), CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), BattleSide::DEFENDER, SlotID::ARROW_TOWERS_SLOT, BattleHex::CASTLE_BOTTOM_TOWER);
|
||||
if (currentBattle->town->fortificationsLevel().lowerTowerHealth != 0)
|
||||
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
|
||||
}
|
||||
@ -390,15 +381,15 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
|
||||
|
||||
for(const std::shared_ptr<Bonus> & bonus : bgInfo->bonuses)
|
||||
{
|
||||
curB->addNewBonus(bonus);
|
||||
currentBattle->addNewBonus(bonus);
|
||||
}
|
||||
|
||||
//native terrain bonuses
|
||||
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));
|
||||
curB->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::STACKS_SPEED, BonusSource::TERRAIN_NATIVE, 1, BonusSourceID())->addLimiter(nativeTerrain));
|
||||
currentBattle->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::DEFENSE))->addLimiter(nativeTerrain));
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//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!");
|
||||
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
|
||||
curB->tacticDistance = 1 + tacticsSkillDiffAttacker;
|
||||
currentBattle->tacticDistance = 1 + tacticsSkillDiffAttacker;
|
||||
}
|
||||
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
|
||||
curB->tacticDistance = 1 + tacticsSkillDiffDefender;
|
||||
currentBattle->tacticDistance = 1 + tacticsSkillDiffDefender;
|
||||
}
|
||||
else
|
||||
curB->tacticDistance = 0;
|
||||
currentBattle->tacticDistance = 0;
|
||||
}
|
||||
|
||||
return curB;
|
||||
return currentBattle;
|
||||
}
|
||||
|
||||
const CGHeroInstance * BattleInfo::getHero(const PlayerColor & player) const
|
||||
|
@ -28,10 +28,12 @@
|
||||
#include "../../lib/gameState/CGameState.h"
|
||||
#include "../../lib/mapping/CMap.h"
|
||||
#include "../../lib/mapObjects/CGHeroInstance.h"
|
||||
#include "../../lib/mapObjects/CGTownInstance.h"
|
||||
#include "../../lib/modding/IdentifierStorage.h"
|
||||
#include "../../lib/networkPacks/PacksForClient.h"
|
||||
#include "../../lib/networkPacks/PacksForClientBattle.h"
|
||||
#include "../../lib/CPlayerState.h"
|
||||
#include <vstd/RNG.h>
|
||||
|
||||
BattleProcessor::BattleProcessor(CGameHandler * gameHandler)
|
||||
: gameHandler(gameHandler)
|
||||
@ -156,16 +158,24 @@ BattleID BattleProcessor::setupBattle(int3 tile, BattleSideArray<const CArmedIns
|
||||
{
|
||||
const auto & t = *gameHandler->getTile(tile);
|
||||
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;
|
||||
|
||||
BattleField terType = 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"));
|
||||
BattleField battlefieldType = gameHandler->gameState()->battleGetBattlefieldType(tile, gameHandler->getRandomGenerator());
|
||||
|
||||
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
|
||||
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;
|
||||
|
||||
engageIntoBattle(bs.info->getSide(BattleSide::ATTACKER).color);
|
||||
|
Loading…
Reference in New Issue
Block a user