mirror of
https://github.com/vcmi/vcmi.git
synced 2025-11-25 22:42:04 +02:00
Reworked & fixed DARKNESS bonuses and lookout tower / skyship logic
This commit is contained in:
@@ -171,7 +171,12 @@
|
||||
"special1": { "requires" : [ "marketplace" ], "marketModes" : ["resource-artifact", "artifact-resource"] },
|
||||
"horde1": { "id" : 18, "upgrades" : "dwellingLvl2" },
|
||||
"horde1Upgr": { "id" : 19, "upgrades" : "dwellingUpLvl2", "requires" : [ "horde1" ], "mode" : "auto" },
|
||||
"special2": { "height" : "high", "requires" : [ "fort" ] },
|
||||
"special2": {
|
||||
"requires" : [ "fort" ],
|
||||
"bonuses": [
|
||||
{ "type": "SIGHT_RADIUS", "val": 15 }, // 5 base + 15 bonus = 20 tiles range
|
||||
]
|
||||
},
|
||||
"special3": { "type" : "library", "requires" : [ "mageGuild1" ] },
|
||||
"special4": {
|
||||
"requires" : [ "mageGuild1" ],
|
||||
@@ -185,7 +190,13 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"grail": { "height" : "skyship", "produce" : { "gold": 5000 }, "bonuses": [ { "type": "PRIMARY_SKILL", "subtype": "primarySkill.knowledge", "val": 15 } ] },
|
||||
"grail": {
|
||||
"produce" : { "gold": 5000 },
|
||||
"bonuses": [
|
||||
{ "type": "PRIMARY_SKILL", "subtype": "primarySkill.knowledge", "val": 15 },
|
||||
{ "type": "FULL_MAP_SCOUTING" }
|
||||
]
|
||||
},
|
||||
|
||||
"dwellingLvl1": { "id" : 30, "requires" : [ "fort" ] },
|
||||
"dwellingLvl2": { "id" : 31, "requires" : [ "dwellingLvl1" ] },
|
||||
|
||||
@@ -314,6 +314,9 @@
|
||||
"movementPointsLand" : [ 1500, 1500, 1500, 1500, 1560, 1630, 1700, 1760, 1830, 1900, 1960, 2000 ],
|
||||
/// movement points hero can get on start of the turn when on sea, depending on speed of slowest creature (0-based list)
|
||||
"movementPointsSea" : [ 1500 ]
|
||||
|
||||
/// Base scouting range for hero without any range modifiers
|
||||
"baseScoutingRange" : 5,
|
||||
},
|
||||
|
||||
"towns":
|
||||
@@ -335,7 +338,10 @@
|
||||
// How much researchs/skips per day are possible? (array index is spell tier)
|
||||
"spellResearchPerDay": [ 2, 2, 2, 2, 1 ],
|
||||
// Exponent for increasing cost for each research (factor 1 disables this; array index is spell tier)
|
||||
"spellResearchCostExponentPerResearch": [ 1.25, 1.25, 1.25, 1.25, 1.25 ]
|
||||
"spellResearchCostExponentPerResearch": [ 1.25, 1.25, 1.25, 1.25, 1.25 ],
|
||||
|
||||
// Base scouting range for town without any range modifiers
|
||||
"baseScoutingRange" : 5,
|
||||
},
|
||||
|
||||
"combat":
|
||||
@@ -581,12 +587,6 @@
|
||||
"val" : 1,
|
||||
"valueType" : "BASE_NUMBER"
|
||||
},
|
||||
"sightRadius" :
|
||||
{
|
||||
"type" : "SIGHT_RADIUS", //default sight radius
|
||||
"val" : 5,
|
||||
"valueType" : "BASE_NUMBER"
|
||||
},
|
||||
"experienceGain" :
|
||||
{
|
||||
"type" : "HERO_EXPERIENCE_GAIN_PERCENT", //default hero xp
|
||||
|
||||
@@ -44,11 +44,6 @@
|
||||
"enum" : [ "normal", "auto", "special", "grail" ],
|
||||
"description" : "Mode in which this building will be built"
|
||||
},
|
||||
"height" : {
|
||||
"type" : "string",
|
||||
"enum" : [ "skyship", "high", "average", "low"],
|
||||
"description" : "Height for lookout towers and some grails"
|
||||
},
|
||||
"requires" : {
|
||||
"$ref" : "#/definitions/buildingRequirement",
|
||||
"description" : "List of town buildings that must be built before this one"
|
||||
|
||||
@@ -27,12 +27,6 @@ Changes mastery level of spells of affected heroes and units. Examples are magic
|
||||
- subtype: school of magic
|
||||
- val: level
|
||||
|
||||
### DARKNESS
|
||||
|
||||
On each turn, hides area in fog of war around affected town for all players other than town owner. Currently does not work for any entities other than towns.
|
||||
|
||||
- val: radius in tiles
|
||||
|
||||
## Player bonuses
|
||||
|
||||
Intended to be setup as global effect, AI cheat etc.
|
||||
@@ -99,6 +93,27 @@ Reveal area of fog of war around affected heroes when hero is recruited or moves
|
||||
|
||||
- val: radius in tiles
|
||||
|
||||
### DARKNESS
|
||||
|
||||
On each turn, hides area in fog of war around affected objects for all players other than town owner. Areas within scouting range of owned objects are not affected
|
||||
|
||||
NOTE: when used by heroes, effect would still activate only on new turn, and not on every hero movement
|
||||
|
||||
- val: radius in tiles
|
||||
- addInfo: optional, activation period (e.g. 7 = weekly, 28 = monthly)
|
||||
|
||||
### FULL_MAP_SCOUTING
|
||||
|
||||
On each turn, reveals entire map for owner of the bonus
|
||||
|
||||
- addInfo: optional, activation period (e.g. 7 = weekly, 28 = monthly)
|
||||
|
||||
### FULL_MAP_DARKNESS
|
||||
|
||||
On each turn, hides entire map in fog of war for all players other than town owner. Areas within scouting range of owned objects are not affected
|
||||
|
||||
- addInfo: optional, activation period (e.g. 7 = weekly, 28 = monthly)
|
||||
|
||||
### MANA_REGENERATION
|
||||
|
||||
Restores specific amount of mana points for affected heroes on new turn
|
||||
|
||||
@@ -151,15 +151,6 @@ These are just a couple of examples of what can be done in VCMI. See vcmi config
|
||||
// See 'List of unique town buildings' section below for detailed description of this field
|
||||
"type" : "",
|
||||
|
||||
// If set, building will have Lookout Tower logic - extend sight radius of a town.
|
||||
// Possible values:
|
||||
// low - increases town sight radius by 5 tiles
|
||||
// average - sight radius extended by 15 tiles
|
||||
// high - sight radius extended by 20 tiles
|
||||
// skyship - entire map will be revealed
|
||||
// If not set, building will not affect sight radius of a town
|
||||
"height" : "average"
|
||||
|
||||
// Resources produced each day by this building
|
||||
"produce" : {
|
||||
"sulfur" : 1,
|
||||
|
||||
@@ -77,6 +77,7 @@ const std::vector<GameSettings::SettingOption> GameSettings::settingProperties =
|
||||
{EGameSettings::DWELLINGS_ACCUMULATE_WHEN_OWNED, "dwellings", "accumulateWhenOwned" },
|
||||
{EGameSettings::DWELLINGS_MERGE_ON_RECRUIT, "dwellings", "mergeOnRecruit" },
|
||||
{EGameSettings::HEROES_BACKPACK_CAP, "heroes", "backpackSize" },
|
||||
{EGameSettings::HEROES_BASE_SCOUNTING_RANGE, "heroes", "baseScoutingRange" },
|
||||
{EGameSettings::HEROES_MINIMAL_PRIMARY_SKILLS, "heroes", "minimalPrimarySkills" },
|
||||
{EGameSettings::HEROES_PER_PLAYER_ON_MAP_CAP, "heroes", "perPlayerOnMapCap" },
|
||||
{EGameSettings::HEROES_PER_PLAYER_TOTAL_CAP, "heroes", "perPlayerTotalCap" },
|
||||
@@ -116,6 +117,7 @@ const std::vector<GameSettings::SettingOption> GameSettings::settingProperties =
|
||||
{EGameSettings::TEXTS_ROAD, "textData", "road" },
|
||||
{EGameSettings::TEXTS_SPELL, "textData", "spell" },
|
||||
{EGameSettings::TEXTS_TERRAIN, "textData", "terrain" },
|
||||
{EGameSettings::TOWNS_BASE_SCOUNTING_RANGE, "towns", "baseScoutingRange" },
|
||||
{EGameSettings::TOWNS_BUILDINGS_PER_TURN_CAP, "towns", "buildingsPerTurnCap" },
|
||||
{EGameSettings::TOWNS_STARTING_DWELLING_CHANCES, "towns", "startingDwellingChances" },
|
||||
{EGameSettings::TOWNS_SPELL_RESEARCH, "towns", "spellResearch" },
|
||||
|
||||
@@ -50,6 +50,7 @@ enum class EGameSettings
|
||||
DWELLINGS_ACCUMULATE_WHEN_OWNED,
|
||||
DWELLINGS_MERGE_ON_RECRUIT,
|
||||
HEROES_BACKPACK_CAP,
|
||||
HEROES_BASE_SCOUNTING_RANGE,
|
||||
HEROES_MINIMAL_PRIMARY_SKILLS,
|
||||
HEROES_PER_PLAYER_ON_MAP_CAP,
|
||||
HEROES_PER_PLAYER_TOTAL_CAP,
|
||||
@@ -59,6 +60,7 @@ enum class EGameSettings
|
||||
HEROES_MOVEMENT_COST_BASE,
|
||||
HEROES_MOVEMENT_POINTS_LAND,
|
||||
HEROES_MOVEMENT_POINTS_SEA,
|
||||
INTERFACE_PLAYER_COLORED_BACKGROUND,
|
||||
MAP_FORMAT_ARMAGEDDONS_BLADE,
|
||||
MAP_FORMAT_CHRONICLES,
|
||||
MAP_FORMAT_HORN_OF_THE_ABYSS,
|
||||
@@ -91,14 +93,13 @@ enum class EGameSettings
|
||||
TEXTS_TERRAIN,
|
||||
TOWNS_BUILDINGS_PER_TURN_CAP,
|
||||
TOWNS_STARTING_DWELLING_CHANCES,
|
||||
INTERFACE_PLAYER_COLORED_BACKGROUND,
|
||||
TOWNS_BASE_SCOUNTING_RANGE,
|
||||
TOWNS_SPELL_RESEARCH,
|
||||
TOWNS_SPELL_RESEARCH_COST,
|
||||
TOWNS_SPELL_RESEARCH_PER_DAY,
|
||||
TOWNS_SPELL_RESEARCH_COST_EXPONENT_PER_RESEARCH,
|
||||
|
||||
OPTIONS_COUNT,
|
||||
OPTIONS_BEGIN = BONUSES_GLOBAL
|
||||
OPTIONS_COUNT
|
||||
};
|
||||
|
||||
class DLL_LINKAGE IGameSettings
|
||||
|
||||
@@ -190,6 +190,8 @@ class JsonNode;
|
||||
BONUS_NAME(MULTIHEX_ANIMATION) /*eg. dragons*/ \
|
||||
BONUS_NAME(STACK_EXPERIENCE_GAIN_PERCENT) /*modifies all stack experience gains*/\
|
||||
BONUS_NAME(VULNERABLE_FROM_BACK) /*bonus damage for attacks from behind*/\
|
||||
BONUS_NAME(FULL_MAP_SCOUTING) /*Skyship*/\
|
||||
BONUS_NAME(FULL_MAP_DARKNESS) /*opposite to Skyship*/\
|
||||
/* end of list */
|
||||
|
||||
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
int IBonusBearer::valOfBonuses(const CSelector &selector, const std::string &cachingStr) const
|
||||
int IBonusBearer::valOfBonuses(const CSelector &selector, const std::string &cachingStr, int baseValue) const
|
||||
{
|
||||
TConstBonusListPtr hlp = getAllBonuses(selector, nullptr, cachingStr);
|
||||
return hlp->totalValue();
|
||||
return hlp->totalValue(baseValue);
|
||||
}
|
||||
|
||||
bool IBonusBearer::hasBonus(const CSelector &selector, const std::string &cachingStr) const
|
||||
@@ -63,14 +63,17 @@ TConstBonusListPtr IBonusBearer::getBonusesOfType(BonusType type, BonusSubtypeID
|
||||
return getBonuses(s, cachingStr);
|
||||
}
|
||||
|
||||
int IBonusBearer::valOfBonuses(BonusType type) const
|
||||
int IBonusBearer::applyBonuses(BonusType type, int baseValue) const
|
||||
{
|
||||
//This part is performance-critical
|
||||
std::string cachingStr = "type_" + std::to_string(static_cast<int>(type));
|
||||
|
||||
CSelector s = Selector::type()(type);
|
||||
return valOfBonuses(s, cachingStr, baseValue);
|
||||
}
|
||||
|
||||
return valOfBonuses(s, cachingStr);
|
||||
int IBonusBearer::valOfBonuses(BonusType type) const
|
||||
{
|
||||
return applyBonuses(type, 0);
|
||||
}
|
||||
|
||||
bool IBonusBearer::hasBonusOfType(BonusType type) const
|
||||
|
||||
@@ -21,7 +21,7 @@ public:
|
||||
IBonusBearer() = default;
|
||||
virtual ~IBonusBearer() = default;
|
||||
virtual TConstBonusListPtr getAllBonuses(const CSelector &selector, const CSelector &limit, const std::string &cachingStr = {}) const = 0;
|
||||
int valOfBonuses(const CSelector &selector, const std::string &cachingStr = {}) const;
|
||||
int valOfBonuses(const CSelector &selector, const std::string &cachingStr = {}, int baseValue = 0) const;
|
||||
bool hasBonus(const CSelector &selector, const std::string &cachingStr = {}) const;
|
||||
bool hasBonus(const CSelector &selector, const CSelector &limit, const std::string &cachingStr = {}) const;
|
||||
TConstBonusListPtr getBonuses(const CSelector &selector, const CSelector &limit, const std::string &cachingStr = {}) const;
|
||||
@@ -30,6 +30,7 @@ public:
|
||||
std::shared_ptr<const Bonus> getBonus(const CSelector &selector) const; //returns any bonus visible on node that matches (or nullptr if none matches)
|
||||
|
||||
//Optimized interface (with auto-caching)
|
||||
int applyBonuses(BonusType type, int baseValue) const; //subtype -> subtype of bonus;
|
||||
int valOfBonuses(BonusType type) const; //subtype -> subtype of bonus;
|
||||
bool hasBonusOfType(BonusType type) const;//determines if hero has a bonus of given type (and optionally subtype)
|
||||
int valOfBonuses(BonusType type, BonusSubtypeID subtype) const; //subtype -> subtype of bonus;
|
||||
|
||||
@@ -903,7 +903,7 @@ void CGameInfoCallback::getTilesInRange(std::unordered_set<int3> & tiles,
|
||||
logGlobal->error("Illegal call to getTilesInRange!");
|
||||
return;
|
||||
}
|
||||
if(radious == CBuilding::HEIGHT_SKYSHIP) //reveal entire map
|
||||
if(radious == GameConstants::FULL_MAP_RANGE)
|
||||
getAllTiles (tiles, player, -1, [](auto * tile){return true;});
|
||||
else
|
||||
{
|
||||
|
||||
@@ -54,6 +54,8 @@ namespace GameConstants
|
||||
constexpr int TOURNAMENT_RULES_DD_MAP_TILES_THRESHOLD = 144*144*2; //map tiles count threshold for 2 dimension door casts with tournament rules
|
||||
constexpr int KINGDOM_WINDOW_HEROES_SLOTS = 4;
|
||||
constexpr int INFO_WINDOW_ARTIFACTS_MAX_ITEMS = 14;
|
||||
|
||||
constexpr int FULL_MAP_RANGE = std::numeric_limits<int>::max();
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
@@ -25,14 +25,6 @@ const std::map<std::string, CBuilding::EBuildMode> CBuilding::MODES =
|
||||
{ "grail", CBuilding::BUILD_GRAIL }
|
||||
};
|
||||
|
||||
const std::map<std::string, CBuilding::ETowerHeight> CBuilding::TOWER_TYPES =
|
||||
{
|
||||
{ "low", CBuilding::HEIGHT_LOW },
|
||||
{ "average", CBuilding::HEIGHT_AVERAGE },
|
||||
{ "high", CBuilding::HEIGHT_HIGH },
|
||||
{ "skyship", CBuilding::HEIGHT_SKYSHIP }
|
||||
};
|
||||
|
||||
BuildingTypeUniqueID CBuilding::getUniqueTypeID() const
|
||||
{
|
||||
return BuildingTypeUniqueID(town->faction->getId(), bid);
|
||||
|
||||
@@ -60,17 +60,7 @@ public:
|
||||
BUILD_GRAIL // 3 - grail - building requires grail to be built
|
||||
} mode;
|
||||
|
||||
enum ETowerHeight // for lookup towers and some grails
|
||||
{
|
||||
HEIGHT_NO_TOWER = 5, // building has not 'lookout tower' ability
|
||||
HEIGHT_LOW = 10, // low lookout tower, but castle without lookout tower gives radius 5
|
||||
HEIGHT_AVERAGE = 15,
|
||||
HEIGHT_HIGH = 20, // such tower is in the Tower town
|
||||
HEIGHT_SKYSHIP = std::numeric_limits<int>::max() // grail, open entire map
|
||||
} height;
|
||||
|
||||
static const std::map<std::string, CBuilding::EBuildMode> MODES;
|
||||
static const std::map<std::string, CBuilding::ETowerHeight> TOWER_TYPES;
|
||||
|
||||
CBuilding() : town(nullptr), mode(BUILD_NORMAL) {};
|
||||
|
||||
|
||||
@@ -283,8 +283,6 @@ void CTownHandler::loadBuilding(CTown * town, const std::string & stringID, cons
|
||||
? CBuilding::BUILD_GRAIL
|
||||
: vstd::find_or(CBuilding::MODES, source["mode"].String(), CBuilding::BUILD_NORMAL);
|
||||
|
||||
ret->height = vstd::find_or(CBuilding::TOWER_TYPES, source["height"].String(), CBuilding::HEIGHT_NO_TOWER);
|
||||
|
||||
ret->identifier = stringID;
|
||||
ret->modScope = source.getModScope();
|
||||
ret->town = town;
|
||||
|
||||
@@ -220,6 +220,9 @@ static void loadBonusAddInfo(CAddInfo & var, BonusType type, const JsonNode & no
|
||||
case BonusType::PRIMARY_SKILL:
|
||||
case BonusType::ENCHANTER:
|
||||
case BonusType::SPECIAL_PECULIAR_ENCHANT:
|
||||
case BonusType::DARKNESS:
|
||||
case BonusType::FULL_MAP_SCOUTING:
|
||||
case BonusType::FULL_MAP_DARKNESS:
|
||||
// 1 number
|
||||
var = getFirstValue(value).Integer();
|
||||
break;
|
||||
|
||||
@@ -1062,7 +1062,8 @@ CStackBasicDescriptor CGHeroInstance::calculateNecromancy (const BattleResult &b
|
||||
|
||||
int CGHeroInstance::getSightRadius() const
|
||||
{
|
||||
return valOfBonuses(BonusType::SIGHT_RADIUS); // scouting gives SIGHT_RADIUS bonus
|
||||
int baseValue = LIBRARY->engineSettings()->getInteger(EGameSettings::HEROES_BASE_SCOUNTING_RANGE);
|
||||
return applyBonuses(BonusType::SIGHT_RADIUS, baseValue);
|
||||
}
|
||||
|
||||
si32 CGHeroInstance::manaRegain() const
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "StdInc.h"
|
||||
#include "CGTownInstance.h"
|
||||
|
||||
#include "IGameSettings.h"
|
||||
#include "TownBuildingInstance.h"
|
||||
#include "../spells/CSpellHandler.h"
|
||||
#include "../bonuses/Bonus.h"
|
||||
@@ -42,17 +43,10 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
int CGTownInstance::getSightRadius() const //returns sight distance
|
||||
int CGTownInstance::getSightRadius() const
|
||||
{
|
||||
auto ret = CBuilding::HEIGHT_NO_TOWER;
|
||||
|
||||
for(const auto & bid : builtBuildings)
|
||||
{
|
||||
auto height = getTown()->buildings.at(bid)->height;
|
||||
if(ret < height)
|
||||
ret = height;
|
||||
}
|
||||
return ret;
|
||||
int baseValue = LIBRARY->engineSettings()->getInteger(EGameSettings::TOWNS_BASE_SCOUNTING_RANGE);
|
||||
return applyBonuses(BonusType::SIGHT_RADIUS, baseValue);
|
||||
}
|
||||
|
||||
void CGTownInstance::setPropertyDer(ObjProperty what, ObjPropertyID identifier)
|
||||
|
||||
@@ -654,6 +654,19 @@ void CGameHandler::onNewTurn()
|
||||
addStatistics(*statistics); // write at end of turn
|
||||
}
|
||||
|
||||
const auto & currentDaySelector = [day = gameState().day+1](const Bonus * bonus)
|
||||
{
|
||||
if (bonus->additionalInfo[0] <= 0)
|
||||
return true;
|
||||
if ((day % bonus->additionalInfo[0]) == 0)
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
const auto & fullMapScoutingSelector = Selector::type()(BonusType::FULL_MAP_SCOUTING).And(currentDaySelector);
|
||||
const auto & fullMapDarknessSelector = Selector::type()(BonusType::FULL_MAP_DARKNESS).And(currentDaySelector);
|
||||
const auto & darknessSelector = Selector::type()(BonusType::DARKNESS).And(currentDaySelector);
|
||||
|
||||
for (const auto & townID : gameState().getMap().getAllTowns())
|
||||
{
|
||||
const auto * t = gameState().getTown(townID);
|
||||
@@ -661,25 +674,27 @@ void CGameHandler::onNewTurn()
|
||||
|
||||
// Skyship, probably easier to handle same as Veil of darkness
|
||||
// do it every new day before veils
|
||||
if(t->hasBuilt(BuildingID::GRAIL)
|
||||
&& player.isValidPlayer()
|
||||
&& t->getTown()->buildings.at(BuildingID::GRAIL)->height == CBuilding::HEIGHT_SKYSHIP)
|
||||
{
|
||||
changeFogOfWar(t->getSightCenter(), t->getSightRadius(), player, ETileVisibility::REVEALED);
|
||||
}
|
||||
if(t->hasBonus(fullMapScoutingSelector) && player.isValidPlayer())
|
||||
changeFogOfWar(t->getSightCenter(), GameConstants::FULL_MAP_RANGE, player, ETileVisibility::REVEALED);
|
||||
}
|
||||
|
||||
for (const auto & townID : gameState().getMap().getAllTowns())
|
||||
{
|
||||
const auto * t = gameState().getTown(townID);
|
||||
if(t->hasBonusOfType(BonusType::DARKNESS))
|
||||
for (const auto & object : gameState().getMap().getObjects<CArmedInstance>())
|
||||
{
|
||||
if(!object->hasBonus(darknessSelector) && !object->hasBonus(fullMapDarknessSelector))
|
||||
continue;
|
||||
|
||||
for(const auto & player : gameState().players)
|
||||
{
|
||||
if (gameInfo().getPlayerStatus(player.first) == EPlayerStatus::INGAME &&
|
||||
gameInfo().getPlayerRelations(player.first, t->tempOwner) == PlayerRelations::ENEMIES)
|
||||
changeFogOfWar(t->getSightCenter(), t->valOfBonuses(BonusType::DARKNESS), player.first, ETileVisibility::HIDDEN);
|
||||
}
|
||||
if (gameInfo().getPlayerStatus(player.first) != EPlayerStatus::INGAME)
|
||||
continue;
|
||||
|
||||
if (gameInfo().getPlayerRelations(player.first, object->getOwner()) != PlayerRelations::ENEMIES)
|
||||
continue;
|
||||
|
||||
if (object->hasBonus(fullMapDarknessSelector))
|
||||
changeFogOfWar(object->getSightCenter(), GameConstants::FULL_MAP_RANGE, player.first, ETileVisibility::HIDDEN);
|
||||
else
|
||||
changeFogOfWar(object->getSightCenter(), object->valOfBonuses(darknessSelector), player.first, ETileVisibility::HIDDEN);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4146,7 +4161,6 @@ void CGameHandler::changeFogOfWar(const std::unordered_set<int3> &tiles, PlayerC
|
||||
if (mode == ETileVisibility::HIDDEN)
|
||||
{
|
||||
// do not hide tiles observed by owned objects. May lead to disastrous AI problems
|
||||
// FIXME: this leads to a bug - shroud of darkness from Necropolis does can not override Skyship from Tower
|
||||
std::unordered_set<int3> observedTiles;
|
||||
const auto * p = gameInfo().getPlayerState(player);
|
||||
for (const auto * obj : p->getOwnedObjects())
|
||||
|
||||
Reference in New Issue
Block a user