mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-26 03:52:01 +02:00
commit
b2f5042942
@ -78,6 +78,11 @@ void BattleObstacleController::obstaclePlaced(const std::vector<std::shared_ptr<
|
||||
{
|
||||
for (auto const & oi : obstacles)
|
||||
{
|
||||
auto side = owner.curInt->cb->playerToSide(owner.curInt->playerID);
|
||||
|
||||
if(!oi->visibleForSide(side.get(),owner.curInt->cb->battleHasNativeStack(side.get())))
|
||||
continue;
|
||||
|
||||
auto spellObstacle = dynamic_cast<const SpellCreatedObstacle*>(oi.get());
|
||||
|
||||
if (!spellObstacle)
|
||||
|
@ -335,7 +335,7 @@
|
||||
},
|
||||
"playerAI" : {
|
||||
"type" : "string",
|
||||
"default" : "VCAI"
|
||||
"default" : "Nullkiller"
|
||||
},
|
||||
"friendlyAI" : {
|
||||
"type" : "string",
|
||||
|
@ -90,8 +90,7 @@
|
||||
"damage":{
|
||||
"type":"core:damage",
|
||||
"optional":false,
|
||||
"indirect":true,
|
||||
"customEffectId" : 82
|
||||
"indirect":true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -249,8 +249,8 @@ public:
|
||||
}
|
||||
|
||||
bool operator == (const Identifier & b) const { return num == b.num; }
|
||||
bool operator <= (const Identifier & b) const { return num >= b.num; }
|
||||
bool operator >= (const Identifier & b) const { return num <= b.num; }
|
||||
bool operator <= (const Identifier & b) const { return num <= b.num; }
|
||||
bool operator >= (const Identifier & b) const { return num >= b.num; }
|
||||
bool operator != (const Identifier & b) const { return num != b.num; }
|
||||
bool operator < (const Identifier & b) const { return num < b.num; }
|
||||
bool operator > (const Identifier & b) const { return num > b.num; }
|
||||
|
@ -308,8 +308,6 @@ public:
|
||||
RESET_STATE,
|
||||
UPDATE,
|
||||
REMOVE,
|
||||
ACTIVATE_AND_UPDATE,
|
||||
ACTIVATE_AND_REMOVE
|
||||
};
|
||||
|
||||
JsonNode data;
|
||||
|
@ -2402,7 +2402,6 @@ void BattleObstaclesChanged::applyBattle(IBattleState * battleState)
|
||||
case BattleChanges::EOperation::ADD:
|
||||
battleState->addObstacle(change);
|
||||
break;
|
||||
case BattleChanges::EOperation::ACTIVATE_AND_UPDATE:
|
||||
case BattleChanges::EOperation::UPDATE:
|
||||
battleState->updateObstacle(change);
|
||||
break;
|
||||
|
@ -346,7 +346,7 @@ std::vector<bfs::path> VCMIDirsWIN32::dataPaths() const
|
||||
}
|
||||
|
||||
bfs::path VCMIDirsWIN32::clientPath() const { return binaryPath() / "VCMI_client.exe"; }
|
||||
bfs::path VCMIDirsWIN32::mapEditorPath() const { return binaryPath() / "VCMI_editor.exe"; }
|
||||
bfs::path VCMIDirsWIN32::mapEditorPath() const { return binaryPath() / "VCMI_mapeditor.exe"; }
|
||||
bfs::path VCMIDirsWIN32::serverPath() const { return binaryPath() / "VCMI_server.exe"; }
|
||||
|
||||
bfs::path VCMIDirsWIN32::libraryPath() const { return "."; }
|
||||
|
@ -798,18 +798,20 @@ std::vector<std::shared_ptr<const CObstacleInstance>> CBattleInfoCallback::battl
|
||||
return obstacles;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<const CObstacleInstance>> CBattleInfoCallback::getAllAffectedObstaclesByStack(const battle::Unit * unit) const
|
||||
std::vector<std::shared_ptr<const CObstacleInstance>> CBattleInfoCallback::getAllAffectedObstaclesByStack(const battle::Unit * unit, const std::set<BattleHex> & passed) const
|
||||
{
|
||||
std::vector<std::shared_ptr<const CObstacleInstance>> affectedObstacles = std::vector<std::shared_ptr<const CObstacleInstance>>();
|
||||
auto affectedObstacles = std::vector<std::shared_ptr<const CObstacleInstance>>();
|
||||
RETURN_IF_NOT_BATTLE(affectedObstacles);
|
||||
if(unit->alive())
|
||||
{
|
||||
if(!passed.count(unit->getPosition()))
|
||||
affectedObstacles = battleGetAllObstaclesOnPos(unit->getPosition(), false);
|
||||
if(unit->doubleWide())
|
||||
{
|
||||
BattleHex otherHex = unit->occupiedHex(unit->getPosition());
|
||||
if(otherHex.isValid())
|
||||
BattleHex otherHex = unit->occupiedHex();
|
||||
if(otherHex.isValid() && !passed.count(otherHex))
|
||||
for(auto & i : battleGetAllObstaclesOnPos(otherHex, false))
|
||||
if(!vstd::contains(affectedObstacles, i))
|
||||
affectedObstacles.push_back(i);
|
||||
}
|
||||
for(auto hex : unit->getHexes())
|
||||
@ -932,6 +934,8 @@ ReachabilityInfo CBattleInfoCallback::makeBFS(const AccessibilityInfo &accessibi
|
||||
return ret;
|
||||
|
||||
const std::set<BattleHex> obstacles = getStoppers(params.perspective);
|
||||
auto checkParams = params;
|
||||
checkParams.ignoreKnownAccessible = true; //Ignore starting hexes obstacles
|
||||
|
||||
std::queue<BattleHex> hexq; //bfs queue
|
||||
|
||||
@ -949,7 +953,7 @@ ReachabilityInfo CBattleInfoCallback::makeBFS(const AccessibilityInfo &accessibi
|
||||
hexq.pop();
|
||||
|
||||
//walking stack can't step past the obstacles
|
||||
if(curHex != params.startPosition && isInObstacle(curHex, obstacles, params))
|
||||
if(isInObstacle(curHex, obstacles, checkParams))
|
||||
continue;
|
||||
|
||||
const int costToNeighbour = ret.distances[curHex.hex] + 1;
|
||||
@ -982,6 +986,9 @@ bool CBattleInfoCallback::isInObstacle(
|
||||
|
||||
for(auto occupiedHex : occupiedHexes)
|
||||
{
|
||||
if(params.ignoreKnownAccessible && vstd::contains(params.knownAccessible, occupiedHex))
|
||||
continue;
|
||||
|
||||
if(vstd::contains(obstacles, occupiedHex))
|
||||
{
|
||||
if(occupiedHex == ESiegeHex::GATE_BRIDGE)
|
||||
|
@ -60,7 +60,7 @@ public:
|
||||
boost::optional<int> battleIsFinished() const override; //return none if battle is ongoing; otherwise the victorious side (0/1) or 2 if it is a draw
|
||||
|
||||
std::vector<std::shared_ptr<const CObstacleInstance>> battleGetAllObstaclesOnPos(BattleHex tile, bool onlyBlocking = true) const override;
|
||||
std::vector<std::shared_ptr<const CObstacleInstance>> getAllAffectedObstaclesByStack(const battle::Unit * unit) const override;
|
||||
std::vector<std::shared_ptr<const CObstacleInstance>> getAllAffectedObstaclesByStack(const battle::Unit * unit, const std::set<BattleHex> & passed) const override;
|
||||
|
||||
const CStack * battleGetStackByPos(BattleHex pos, bool onlyAlive = true) const;
|
||||
|
||||
|
@ -47,10 +47,7 @@ std::vector<std::shared_ptr<const CObstacleInstance>> CBattleInfoEssentials::bat
|
||||
else
|
||||
{
|
||||
if(!!player && *perspective != battleGetMySide())
|
||||
{
|
||||
logGlobal->error("Unauthorized obstacles access attempt!");
|
||||
return ret;
|
||||
}
|
||||
logGlobal->warn("Unauthorized obstacles access attempt, assuming massive spell");
|
||||
}
|
||||
|
||||
for(const auto & obstacle : getBattle()->getAllObstacles())
|
||||
|
@ -72,7 +72,7 @@ public:
|
||||
|
||||
//blocking obstacles makes tile inaccessible, others cause special effects (like Land Mines, Moat, Quicksands)
|
||||
virtual std::vector<std::shared_ptr<const CObstacleInstance>> battleGetAllObstaclesOnPos(BattleHex tile, bool onlyBlocking = true) const = 0;
|
||||
virtual std::vector<std::shared_ptr<const CObstacleInstance>> getAllAffectedObstaclesByStack(const battle::Unit * unit) const = 0;
|
||||
virtual std::vector<std::shared_ptr<const CObstacleInstance>> getAllAffectedObstaclesByStack(const battle::Unit * unit, const std::set<BattleHex> & passed) const = 0;
|
||||
};
|
||||
|
||||
|
||||
|
@ -28,6 +28,7 @@ struct DLL_LINKAGE ReachabilityInfo
|
||||
ui8 side = 0;
|
||||
bool doubleWide = false;
|
||||
bool flying = false;
|
||||
bool ignoreKnownAccessible = false; //Ignore obstacles if it is in accessible hexes
|
||||
std::vector<BattleHex> knownAccessible; //hexes that will be treated as accessible, even if they're occupied by stack (by default - tiles occupied by stack we do reachability for, so it doesn't block itself)
|
||||
|
||||
BattleHex startPosition; //assumed position of stack
|
||||
|
@ -130,7 +130,17 @@ void initTerrainType(Zone & zone, CMapGenerator & gen)
|
||||
{
|
||||
if(zone.isMatchTerrainToTown() && zone.getTownType() != ETownType::NEUTRAL)
|
||||
{
|
||||
zone.setTerrainType((*VLC->townh)[zone.getTownType()]->nativeTerrain);
|
||||
auto terrainType = (*VLC->townh)[zone.getTownType()]->nativeTerrain;
|
||||
|
||||
if (terrainType <= ETerrainId::NONE)
|
||||
{
|
||||
logGlobal->warn("Town %s has invalid terrain type: %d", zone.getTownType(), terrainType);
|
||||
zone.setTerrainType(ETerrainId::DIRT);
|
||||
}
|
||||
else
|
||||
{
|
||||
zone.setTerrainType(terrainType);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -121,6 +121,9 @@ void Obstacle::adjustAffectedHexes(std::set<BattleHex> & hexes, const Mechanics
|
||||
|
||||
bool Obstacle::applicable(Problem & problem, const Mechanics * m) const
|
||||
{
|
||||
if(hidden && m->battle()->battleHasNativeStack(m->battle()->otherSide(m->casterSide)))
|
||||
return m->adaptProblem(ESpellCastProblem::NO_APPROPRIATE_TARGET, problem);
|
||||
|
||||
return LocationEffect::applicable(problem, m);
|
||||
}
|
||||
|
||||
@ -270,12 +273,7 @@ void Obstacle::placeObstacles(ServerCallback * server, const Mechanics * m, cons
|
||||
|
||||
BattleObstaclesChanged pack;
|
||||
|
||||
boost::optional<BattlePerspective::BattlePerspective> perspective;
|
||||
|
||||
if(!m->battle()->getPlayerID())
|
||||
perspective = boost::make_optional(BattlePerspective::ALL_KNOWING);
|
||||
|
||||
auto all = m->battle()->battleGetAllObstacles(perspective);
|
||||
auto all = m->battle()->battleGetAllObstacles(BattlePerspective::ALL_KNOWING);
|
||||
|
||||
int obstacleIdToGive = 1;
|
||||
for(auto & one : all)
|
||||
|
@ -72,7 +72,7 @@ bool RemoveObstacle::canRemove(const CObstacleInstance * obstacle) const
|
||||
return true;
|
||||
const auto *spellObstacle = dynamic_cast<const SpellCreatedObstacle *>(obstacle);
|
||||
|
||||
if(removeAllSpells && spellObstacle)
|
||||
if(removeAllSpells && obstacle->obstacleType == CObstacleInstance::SPELL_CREATED)
|
||||
return true;
|
||||
|
||||
if(spellObstacle && !removeSpells.empty())
|
||||
@ -89,7 +89,7 @@ std::set<const CObstacleInstance *> RemoveObstacle::getTargets(const Mechanics *
|
||||
std::set<const CObstacleInstance *> possibleTargets;
|
||||
if(m->isMassive() || alwaysMassive)
|
||||
{
|
||||
for(const auto & obstacle : m->battle()->battleGetAllObstacles())
|
||||
for(const auto & obstacle : m->battle()->battleGetAllObstacles(BattlePerspective::ALL_KNOWING))
|
||||
if(canRemove(obstacle.get()))
|
||||
possibleTargets.insert(obstacle.get());
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ bool UnitEffect::applicable(Problem & problem, const Mechanics * m) const
|
||||
{
|
||||
//stack effect is applicable in general if there is at least one smart target
|
||||
|
||||
auto mainFilter = std::bind(&UnitEffect::getStackFilter, this, m, true, _1);
|
||||
auto mainFilter = std::bind(&UnitEffect::getStackFilter, this, m, false, _1);
|
||||
auto predicate = std::bind(&UnitEffect::eraseByImmunityFilter, this, m, _1);
|
||||
|
||||
auto targets = m->battle()->battleGetUnitsIf(mainFilter);
|
||||
@ -53,12 +53,12 @@ bool UnitEffect::applicable(Problem & problem, const Mechanics * m) const
|
||||
|
||||
bool UnitEffect::applicable(Problem & problem, const Mechanics * m, const EffectTarget & target) const
|
||||
{
|
||||
//stack effect is applicable if it affects at least one smart target
|
||||
//assume target correctly transformed, just reapply smart filter
|
||||
//stack effect is applicable if it affects at least one target (smartness should not be checked)
|
||||
//assume target correctly transformed, just reapply filter
|
||||
|
||||
for(const auto & item : target)
|
||||
if(item.unitValue)
|
||||
if(getStackFilter(m, true, item.unitValue))
|
||||
if(getStackFilter(m, false, item.unitValue))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
@ -1401,6 +1401,11 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
|
||||
|
||||
//initing necessary tables
|
||||
auto accessibility = getAccesibility(curStack);
|
||||
std::set<BattleHex> passed;
|
||||
//Ignore obstacles on starting position
|
||||
passed.insert(curStack->getPosition());
|
||||
if(curStack->doubleWide())
|
||||
passed.insert(curStack->occupiedHex());
|
||||
|
||||
//shifting destination (if we have double wide stack and we can occupy dest but not be exactly there)
|
||||
if(!stackAtEnd && curStack->doubleWide() && !accessibility.accessible(dest, curStack))
|
||||
@ -1593,10 +1598,12 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
|
||||
if(otherHex.isValid() && !obstacle2.empty())
|
||||
obstacleHit = true;
|
||||
}
|
||||
if(!obstacleHit)
|
||||
passed.insert(hex);
|
||||
}
|
||||
}
|
||||
|
||||
if (tiles.size() > 0)
|
||||
if (!tiles.empty())
|
||||
{
|
||||
//commit movement
|
||||
BattleStackMoved sm;
|
||||
@ -1612,7 +1619,12 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
|
||||
if (curStack->getPosition() != dest)
|
||||
{
|
||||
if(stackIsMoving && start != curStack->getPosition())
|
||||
stackIsMoving = handleDamageFromObstacle(curStack, stackIsMoving);
|
||||
{
|
||||
stackIsMoving = handleDamageFromObstacle(curStack, stackIsMoving, passed);
|
||||
passed.insert(curStack->getPosition());
|
||||
if(curStack->doubleWide())
|
||||
passed.insert(curStack->occupiedHex());
|
||||
}
|
||||
if (gateStateChanging)
|
||||
{
|
||||
if (curStack->getPosition() == openGateAtHex)
|
||||
@ -1640,7 +1652,7 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
|
||||
}
|
||||
|
||||
//handling obstacle on the final field (separate, because it affects both flying and walking stacks)
|
||||
handleDamageFromObstacle(curStack);
|
||||
handleDamageFromObstacle(curStack, false, passed);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -5301,13 +5313,13 @@ void CGameHandler::stackTurnTrigger(const CStack *st)
|
||||
}
|
||||
}
|
||||
|
||||
bool CGameHandler::handleDamageFromObstacle(const CStack * curStack, bool stackIsMoving)
|
||||
bool CGameHandler::handleDamageFromObstacle(const CStack * curStack, bool stackIsMoving, const std::set<BattleHex> & passed)
|
||||
{
|
||||
if(!curStack->alive())
|
||||
return false;
|
||||
bool containDamageFromMoat = false;
|
||||
bool movementStoped = false;
|
||||
for(auto & obstacle : getAllAffectedObstaclesByStack(curStack))
|
||||
bool movementStopped = false;
|
||||
for(auto & obstacle : getAllAffectedObstaclesByStack(curStack, passed))
|
||||
{
|
||||
if(obstacle->obstacleType == CObstacleInstance::SPELL_CREATED)
|
||||
{
|
||||
@ -5318,7 +5330,7 @@ bool CGameHandler::handleDamageFromObstacle(const CStack * curStack, bool stackI
|
||||
if(!spellObstacle)
|
||||
COMPLAIN_RET("Invalid obstacle instance");
|
||||
|
||||
if(spellObstacle->trigger)
|
||||
if(spellObstacle->triggersEffects())
|
||||
{
|
||||
const bool oneTimeObstacle = spellObstacle->removeOnTrigger;
|
||||
|
||||
@ -5336,9 +5348,9 @@ bool CGameHandler::handleDamageFromObstacle(const CStack * curStack, bool stackI
|
||||
ObstacleChanges changeInfo;
|
||||
changeInfo.id = spellObstacle->uniqueID;
|
||||
if (oneTimeObstacle)
|
||||
changeInfo.operation = ObstacleChanges::EOperation::ACTIVATE_AND_REMOVE;
|
||||
changeInfo.operation = ObstacleChanges::EOperation::REMOVE;
|
||||
else
|
||||
changeInfo.operation = ObstacleChanges::EOperation::ACTIVATE_AND_UPDATE;
|
||||
changeInfo.operation = ObstacleChanges::EOperation::UPDATE;
|
||||
|
||||
SpellCreatedObstacle changedObstacle;
|
||||
changedObstacle.uniqueID = spellObstacle->uniqueID;
|
||||
@ -5382,12 +5394,12 @@ bool CGameHandler::handleDamageFromObstacle(const CStack * curStack, bool stackI
|
||||
return false;
|
||||
|
||||
if((obstacle->stopsMovement() && stackIsMoving))
|
||||
movementStoped = true;
|
||||
movementStopped = true;
|
||||
}
|
||||
|
||||
if(stackIsMoving)
|
||||
return curStack->alive() && !movementStoped;
|
||||
else
|
||||
return curStack->alive() && !movementStopped;
|
||||
|
||||
return curStack->alive();
|
||||
}
|
||||
|
||||
|
@ -231,7 +231,7 @@ public:
|
||||
bool makeCustomAction(BattleAction &ba);
|
||||
void stackEnchantedTrigger(const CStack * stack);
|
||||
void stackTurnTrigger(const CStack *stack);
|
||||
bool handleDamageFromObstacle(const CStack * curStack, bool stackIsMoving = false); //checks if obstacle is land mine and handles possible consequences
|
||||
bool handleDamageFromObstacle(const CStack * curStack, bool stackIsMoving = false, const std::set<BattleHex> & passed = {}); //checks if obstacle is land mine and handles possible consequences
|
||||
|
||||
void removeObstacle(const CObstacleInstance &obstacle);
|
||||
bool queryReply( QueryID qid, const JsonNode & answer, PlayerColor player );
|
||||
|
Loading…
x
Reference in New Issue
Block a user