1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-03-17 20:58:07 +02:00

Cartographer/Observatory is now configurable object

This commit is contained in:
Ivan Savenko 2023-10-04 14:11:13 +03:00
parent f3ed589e35
commit 98fd939ed6
24 changed files with 353 additions and 282 deletions

View File

@ -475,6 +475,19 @@ namespace vstd
}
}
template<typename Elem, typename Predicate>
void erase_if(std::unordered_set<Elem> &setContainer, Predicate pred)
{
auto itr = setContainer.begin();
auto endItr = setContainer.end();
while(itr != endItr)
{
auto tmpItr = itr++;
if(pred(*tmpItr))
setContainer.erase(tmpItr);
}
}
//works for map and std::map, maybe something else
template<typename Key, typename Val, typename Predicate>
void erase_if(std::map<Key, Val> &container, Predicate pred)

View File

@ -177,7 +177,7 @@ void ApplyClientNetPackVisitor::visitFoWChange(FoWChange & pack)
}
if(cl.getPlayerRelations(i.first, pack.player) != PlayerRelations::ENEMIES)
{
if(pack.mode)
if(pack.mode == FoWChange::Mode::REVEAL)
i.second->tileRevealed(pack.tiles);
else
i.second->tileHidden(pack.tiles);

View File

@ -156,70 +156,6 @@
}
},
"redwoodObservatory" : {
"index" :58,
"handler" : "observatory",
"base" : {
"sounds" : {
"visit" : ["LIGHTHOUSE"]
}
},
"types" : {
"object" : {
"index" : 0,
"aiValue" : 750,
"templates" :
{
"base" : { "animation" : "avxredw.def", "visitableFrom" : [ "---", "+++", "+++" ], "mask" : [ "VV", "VV", "VA"], "allowedTerrains":["grass", "swamp", "dirt", "sand", "lava", "rough"] },
"snow" : { "animation" : "avxreds0.def", "visitableFrom" : [ "---", "+++", "+++" ], "mask" : [ "VV", "VV", "VA"], "allowedTerrains":["snow"] }
},
"rmg" : {
"zoneLimit" : 1,
"value" : 750,
"rarity" : 100
}
}
}
},
"pillarOfFire" : {
"index" :60,
"handler" : "observatory",
"base" : {
"sounds" : {
"ambient" : ["LOOPFIRE"],
"visit" : ["LIGHTHOUSE"]
}
},
"types" : {
"object" : {
"index" : 0,
"aiValue" : 750,
"rmg" : {
"zoneLimit" : 1,
"value" : 750,
"rarity" : 100
}
}
}
},
"coverOfDarkness" : {
"index" :15,
"handler" : "observatory",
"base" : {
"sounds" : {
"visit" : ["LIGHTHOUSE"]
}
},
"types" : {
"object" : {
"index" : 0,
"aiValue" : 100,
"rmg" : {
}
}
}
},
"whirlpool" : {
"index" :111,
"handler" : "whirlpool",

View File

@ -255,23 +255,6 @@
}
},
// subtype: different revealed areas
"cartographer" : {
"index" :13,
"handler": "cartographer",
"lastReservedIndex" : 2,
"base" : {
"sounds" : {
"visit" : ["LIGHTHOUSE"]
}
},
"types" : {
"water" : { "index" : 0, "aiValue" : 5000, "rmg" : { "zoneLimit" : 1, "value" : 5000, "rarity" : 20 } },
"land" : { "index" : 1, "aiValue": 10000, "rmg" : { "zoneLimit" : 1, "value" : 10000, "rarity" : 20 } },
"subterra" : { "index" : 2, "aiValue" : 7500, "rmg" : { "zoneLimit" : 1, "value" : 7500, "rarity" : 20 } }
}
},
// subtype: resource ID
"mine" : {
"index" :53,

View File

@ -66,4 +66,212 @@
}
}
},
"redwoodObservatory" : {
"index" :58,
"handler" : "configurable",
"base" : {
"sounds" : {
"visit" : ["LIGHTHOUSE"]
}
},
"types" : {
"redwoodObservatory" : {
"index" : 0,
"aiValue" : 750,
"templates" :
{
"base" : { "animation" : "avxredw.def", "visitableFrom" : [ "---", "+++", "+++" ], "mask" : [ "VV", "VV", "VA"], "allowedTerrains":["grass", "swamp", "dirt", "sand", "lava", "rough"] },
"snow" : { "animation" : "avxreds0.def", "visitableFrom" : [ "---", "+++", "+++" ], "mask" : [ "VV", "VV", "VA"], "allowedTerrains":["snow"] }
},
"rmg" : {
"zoneLimit" : 1,
"value" : 750,
"rarity" : 100
},
"compatibilityIdentifiers" : [ "object" ],
"visitMode" : "unlimited",
"rewards" : [
{
"message" : 98,
"revealTiles" : {
"radius" : 20,
"surface" : 1,
"subterra" : 1,
"water" : 1,
"rock" : 1
}
}
]
}
}
},
"pillarOfFire" : {
"index" :60,
"handler" : "configurable",
"base" : {
"sounds" : {
"ambient" : ["LOOPFIRE"],
"visit" : ["LIGHTHOUSE"]
}
},
"types" : {
"pillarOfFire" : {
"index" : 0,
"aiValue" : 750,
"rmg" : {
"zoneLimit" : 1,
"value" : 750,
"rarity" : 100
},
"compatibilityIdentifiers" : [ "object" ],
"visitMode" : "unlimited",
"rewards" : [
{
"message" : 99,
"revealTiles" : {
"radius" : 20,
"surface" : 1,
"subterra" : 1,
"water" : 1,
"rock" : 1
}
}
]
}
}
},
"coverOfDarkness" : {
"index" :15,
"handler" : "configurable",
"base" : {
"sounds" : {
"visit" : ["LIGHTHOUSE"]
}
},
"types" : {
"coverOfDarkness" : {
"index" : 0,
"aiValue" : 100,
"rmg" : {
},
"compatibilityIdentifiers" : [ "object" ],
"visitMode" : "unlimited",
"rewards" : [
{
"message" : 31,
"revealTiles" : {
"radius" : 20,
"surface" : 1,
"subterra" : 1,
"water" : 1,
"rock" : 1,
"hide" : true
}
}
]
}
}
},
"cartographer" : {
"index" :13,
"handler": "configurable",
"lastReservedIndex" : 2,
"base" : {
"sounds" : {
"visit" : ["LIGHTHOUSE"]
}
},
"types" : {
"cartographerWater" : {
"index" : 0,
"aiValue" : 5000,
"rmg" : {
"zoneLimit" : 1,
"value" : 5000,
"rarity" : 20
},
"compatibilityIdentifiers" : [ "water" ],
"visitMode" : "unlimited",
"canRefuse" : true,
"rewards" : [
{
"limiter" : { "resources" : { "gold" : 1000 } },
"message" : 25,
"resources" : {
"gold" : -1000
},
"revealTiles" : {
"water" : 1
}
}
],
"onEmptyMessage" : 28,
"onVisitedMessage" : 24
},
"cartographerLand" : {
"index" : 1,
"aiValue": 10000,
"rmg" : {
"zoneLimit" : 1,
"value" : 10000,
"rarity" : 2
},
"compatibilityIdentifiers" : [ "land" ],
"visitMode" : "unlimited",
"canRefuse" : true,
"rewards" : [
{
"limiter" : { "resources" : { "gold" : 1000 } },
"message" : 26,
"resources" : {
"gold" : -1000
},
"revealTiles" : {
"surface" : 1,
"water" : -1,
"rock" : -1
}
}
],
"onEmptyMessage" : 28,
"onVisitedMessage" : 24
},
"cartographerSubterranean" : {
"index" : 2,
"aiValue" : 7500,
"rmg" : {
"zoneLimit" : 1,
"value" : 7500,
"rarity" : 20
},
"compatibilityIdentifiers" : [ "subterra" ],
"visitMode" : "unlimited",
"canRefuse" : true,
"rewards" : [
{
"limiter" : { "resources" : { "gold" : 1000 } },
"message" : 27,
"resources" : {
"gold" : -1000
},
"revealTiles" : {
"subterra" : 1,
"water" : -1,
"rock" : -1,
"surface" : -1
}
}
],
"onEmptyMessage" : 28,
"onVisitedMessage" : 24
}
}
}
}

View File

@ -607,7 +607,7 @@ EBuildingState CGameInfoCallback::canBuildStructure( const CGTownInstance *t, Bu
{
const TerrainTile *tile = getTile(t->bestLocation(), false);
if(!tile || tile->terType->isLand())
if(!tile || !tile->terType->isWater())
return EBuildingState::NO_WATER; //lack of water
}

View File

@ -88,7 +88,7 @@ void CPrivilegedInfoCallback::getTilesInRange(std::unordered_set<int3> & tiles,
return;
}
if(radious == CBuilding::HEIGHT_SKYSHIP) //reveal entire map
getAllTiles (tiles, player, -1, MapTerrainFilterMode::NONE);
getAllTiles (tiles, player, -1, [](auto * tile){return true;});
else
{
const TeamState * team = !player ? nullptr : gs->getPlayerTeam(*player);
@ -112,7 +112,7 @@ void CPrivilegedInfoCallback::getTilesInRange(std::unordered_set<int3> & tiles,
}
}
void CPrivilegedInfoCallback::getAllTiles(std::unordered_set<int3> & tiles, std::optional<PlayerColor> Player, int level, MapTerrainFilterMode tileFilterMode) const
void CPrivilegedInfoCallback::getAllTiles(std::unordered_set<int3> & tiles, std::optional<PlayerColor> Player, int level, std::function<bool(const TerrainTile *)> filter) const
{
if(!!Player && !Player->isValidPlayer())
{
@ -137,29 +137,9 @@ void CPrivilegedInfoCallback::getAllTiles(std::unordered_set<int3> & tiles, std:
{
for(int yd = 0; yd < gs->map->height; yd++)
{
bool isTileEligible = false;
switch(tileFilterMode)
{
case MapTerrainFilterMode::NONE:
isTileEligible = true;
break;
case MapTerrainFilterMode::WATER:
isTileEligible = getTile(int3(xd, yd, zd))->terType->isWater();
break;
case MapTerrainFilterMode::LAND:
isTileEligible = getTile(int3(xd, yd, zd))->terType->isLand();
break;
case MapTerrainFilterMode::LAND_CARTOGRAPHER:
isTileEligible = getTile(int3(xd, yd, zd))->terType->isSurfaceCartographerCompatible();
break;
case MapTerrainFilterMode::UNDERGROUND_CARTOGRAPHER:
isTileEligible = getTile(int3(xd, yd, zd))->terType->isUndergroundCartographerCompatible();
break;
}
if(isTileEligible)
tiles.insert(int3(xd, yd, zd));
int3 coordinates(xd, yd, zd);
if (filter(getTile(coordinates)))
tiles.insert(coordinates);
}
}
}

View File

@ -43,15 +43,6 @@ namespace scripting
class DLL_LINKAGE CPrivilegedInfoCallback : public CGameInfoCallback
{
public:
enum class MapTerrainFilterMode
{
NONE = 0,
LAND = 1,
WATER = 2,
LAND_CARTOGRAPHER = 3,
UNDERGROUND_CARTOGRAPHER = 4
};
CGameState *gameState();
//used for random spawns
@ -66,8 +57,7 @@ public:
int3::EDistanceFormula formula = int3::DIST_2D) const;
//returns all tiles on given level (-1 - both levels, otherwise number of level)
void getAllTiles(std::unordered_set<int3> &tiles, std::optional<PlayerColor> player = std::optional<PlayerColor>(),
int level = -1, MapTerrainFilterMode tileFilterMode = MapTerrainFilterMode::NONE) const;
void getAllTiles(std::unordered_set<int3> &tiles, std::optional<PlayerColor> player, int level, std::function<bool(const TerrainTile *)> filter) const;
//gives 3 treasures, 3 minors, 1 major -> used by Black Market and Artifact Merchant
void pickAllowedArtsSet(std::vector<const CArtifact *> & out, CRandomGenerator & rand) const;

View File

@ -344,11 +344,17 @@ struct DLL_LINKAGE SetMovePoints : public CPackForClient
struct DLL_LINKAGE FoWChange : public CPackForClient
{
enum class Mode : uint8_t
{
HIDE,
REVEAL
};
void applyGs(CGameState * gs);
std::unordered_set<int3> tiles;
PlayerColor player;
ui8 mode = 0; //mode==0 - hide, mode==1 - reveal
Mode mode;
bool waitForDialogs = false;
virtual void visitTyped(ICPackVisitor & visitor) override;

View File

@ -924,8 +924,9 @@ void FoWChange::applyGs(CGameState *gs)
TeamState * team = gs->getPlayerTeam(player);
auto fogOfWarMap = team->fogOfWarMap;
for(const int3 & t : tiles)
(*fogOfWarMap)[t.z][t.x][t.y] = mode;
if (mode == 0) //do not hide too much
(*fogOfWarMap)[t.z][t.x][t.y] = mode != Mode::HIDE;
if (mode == Mode::HIDE) //do not hide too much
{
std::unordered_set<int3> tilesRevealed;
for (auto & elem : gs->map->objects)

View File

@ -155,9 +155,14 @@ bool TerrainType::isWater() const
return passabilityType & PassabilityType::WATER;
}
bool TerrainType::isRock() const
{
return passabilityType & PassabilityType::ROCK;
}
bool TerrainType::isPassable() const
{
return !(passabilityType & PassabilityType::ROCK);
return !isRock();
}
bool TerrainType::isSurface() const
@ -170,16 +175,6 @@ bool TerrainType::isUnderground() const
return passabilityType & PassabilityType::SUBTERRANEAN;
}
bool TerrainType::isSurfaceCartographerCompatible() const
{
return isSurface();
}
bool TerrainType::isUndergroundCartographerCompatible() const
{
return isLand() && isPassable() && !isSurface();
}
bool TerrainType::isTransitionRequired() const
{
return transitionRequired;

View File

@ -84,12 +84,13 @@ public:
bool isLand() const;
bool isWater() const;
bool isRock() const;
bool isPassable() const;
bool isSurface() const;
bool isUnderground() const;
bool isTransitionRequired() const;
bool isSurfaceCartographerCompatible() const;
bool isUndergroundCartographerCompatible() const;
template <typename Handler> void serialize(Handler &h, const int version)
{

View File

@ -71,7 +71,6 @@ CObjectClassesHandler::CObjectClassesHandler()
SET_HANDLER("randomDwelling", CGDwelling);
SET_HANDLER("generic", CGObjectInstance);
SET_HANDLER("cartographer", CCartographer);
SET_HANDLER("artifact", CGArtifact);
SET_HANDLER("borderGate", CGBorderGate);
SET_HANDLER("borderGuard", CGBorderGuard);
@ -84,7 +83,6 @@ CObjectClassesHandler::CObjectClassesHandler()
SET_HANDLER("magi", CGMagi);
SET_HANDLER("mine", CGMine);
SET_HANDLER("obelisk", CGObelisk);
SET_HANDLER("observatory", CGObservatory);
SET_HANDLER("pandora", CGPandoraBox);
SET_HANDLER("prison", CGHeroInstance);
SET_HANDLER("questGuard", CGQuestGuard);

View File

@ -1068,7 +1068,7 @@ void CGTownInstance::onTownCaptured(const PlayerColor & winner) const
setOwner(winner);
FoWChange fw;
fw.player = winner;
fw.mode = 1;
fw.mode = FoWChange::Mode::REVEAL;
cb->getTilesInRange(fw.tiles, getSightCenter(), getSightRadius(), winner, 1);
cb->sendAndApply(& fw);
}

View File

@ -90,6 +90,5 @@ public:
// POSSIBLE
// class DLL_LINKAGE CGSignBottle : public CGObjectInstance //signs and ocean bottles
// class DLL_LINKAGE CGScholar : public CGObjectInstance
VCMI_LIB_NAMESPACE_END

View File

@ -842,40 +842,6 @@ void CGArtifact::serializeJsonOptions(JsonSerializeFormat& handler)
}
}
void CGObservatory::onHeroVisit( const CGHeroInstance * h ) const
{
InfoWindow iw;
iw.type = EInfoWindowMode::AUTO;
iw.player = h->tempOwner;
switch (ID)
{
case Obj::REDWOOD_OBSERVATORY:
case Obj::PILLAR_OF_FIRE:
{
iw.text.appendLocalString(EMetaText::ADVOB_TXT,98 + (ID==Obj::PILLAR_OF_FIRE));
FoWChange fw;
fw.player = h->tempOwner;
fw.mode = 1;
cb->getTilesInRange (fw.tiles, pos, 20, h->tempOwner, 1);
cb->sendAndApply (&fw);
break;
}
case Obj::COVER_OF_DARKNESS:
{
iw.text.appendLocalString (EMetaText::ADVOB_TXT, 31);
for (auto & player : cb->gameState()->players)
{
if (cb->getPlayerStatus(player.first) == EPlayerStatus::INGAME &&
cb->getPlayerRelations(player.first, h->tempOwner) == PlayerRelations::ENEMIES)
cb->changeFogOfWar(visitablePos(), 20, player.first, true);
}
break;
}
}
cb->showInfoDialog(&iw);
}
void CGShrine::onHeroVisit( const CGHeroInstance * h ) const
{
if(spell == SpellID::NONE)
@ -1175,7 +1141,7 @@ void CGMagi::onHeroVisit(const CGHeroInstance * h) const
FoWChange fw;
fw.player = h->tempOwner;
fw.mode = 1;
fw.mode = FoWChange::Mode::REVEAL;
fw.waitForDialogs = true;
for(const auto & it : eyelist[subID])
@ -1321,79 +1287,6 @@ BoatId CGShipyard::getBoatType() const
return createdBoat;
}
void CCartographer::onHeroVisit( const CGHeroInstance * h ) const
{
//if player has not bought map of this subtype yet and underground exist for stalagmite cartographer
if (!wasVisited(h->getOwner()) && (subID != 2 || cb->gameState()->map->twoLevel))
{
if (cb->getResource(h->tempOwner, EGameResID::GOLD) >= 1000) //if he can afford a map
{
//ask if he wants to buy one
int text=0;
switch (subID)
{
case 0:
text = 25;
break;
case 1:
text = 26;
break;
case 2:
text = 27;
break;
default:
logGlobal->warn("Unrecognized subtype of cartographer");
}
assert(text);
BlockingDialog bd (true, false);
bd.player = h->getOwner();
bd.text.appendLocalString (EMetaText::ADVOB_TXT, text);
cb->showBlockingDialog (&bd);
}
else //if he cannot afford
{
h->showInfoDialog(28);
}
}
else //if he already visited carographer
{
h->showInfoDialog(24);
}
}
void CCartographer::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const
{
if(answer) //if hero wants to buy map
{
cb->giveResource(hero->tempOwner, EGameResID::GOLD, -1000);
FoWChange fw;
fw.mode = 1;
fw.player = hero->tempOwner;
//subIDs of different types of cartographers:
//water = 0; land = 1; underground = 2;
IGameCallback::MapTerrainFilterMode tileFilterMode = IGameCallback::MapTerrainFilterMode::NONE;
switch(subID)
{
case 0:
tileFilterMode = CPrivilegedInfoCallback::MapTerrainFilterMode::WATER;
break;
case 1:
tileFilterMode = CPrivilegedInfoCallback::MapTerrainFilterMode::LAND_CARTOGRAPHER;
break;
case 2:
tileFilterMode = CPrivilegedInfoCallback::MapTerrainFilterMode::UNDERGROUND_CARTOGRAPHER;
break;
}
cb->getAllTiles(fw.tiles, hero->tempOwner, -1, tileFilterMode); //reveal appropriate tiles
cb->sendAndApply(&fw);
cb->setObjProperty(id, CCartographer::OBJPROP_VISITED, hero->tempOwner.getNum());
}
}
void CGDenOfthieves::onHeroVisit (const CGHeroInstance * h) const
{
cb->showObjectWindow(this, EOpenWindowMode::THIEVES_GUILD, h, false);

View File

@ -314,17 +314,6 @@ public:
}
};
class DLL_LINKAGE CGObservatory : public CGObjectInstance //Redwood observatory
{
public:
void onHeroVisit(const CGHeroInstance * h) const override;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CGObjectInstance&>(*this);
}
};
class DLL_LINKAGE CGBoat : public CGObjectInstance, public CBonusSystemNode
{
public:
@ -396,19 +385,6 @@ public:
}
};
class DLL_LINKAGE CCartographer : public CTeamVisited
{
///behaviour varies depending on surface and floor
public:
void onHeroVisit(const CGHeroInstance * h) const override;
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CTeamVisited&>(*this);
}
};
class DLL_LINKAGE CGDenOfthieves : public CGObjectInstance
{
void onHeroVisit(const CGHeroInstance * h) const override;

View File

@ -56,7 +56,6 @@ void registerTypesMapObjects1(Serializer &s)
s.template registerType<CGMonolith, CGWhirlpool>();
s.template registerType<CGObjectInstance, CGSignBottle>();
s.template registerType<CGObjectInstance, CGScholar>();
s.template registerType<CGObjectInstance, CGObservatory>();
s.template registerType<CGObjectInstance, CGKeys>();
s.template registerType<CGKeys, CGKeymasterTent>();
s.template registerType<CGKeys, CGBorderGuard>(); s.template registerType<IQuestObject, CGBorderGuard>();
@ -112,7 +111,6 @@ void registerTypesMapObjectTypes(Serializer &s)
#define REGISTER_GENERIC_HANDLER(TYPENAME) s.template registerType<AObjectTypeHandler, CDefaultObjectTypeHandler<TYPENAME> >()
REGISTER_GENERIC_HANDLER(CGObjectInstance);
REGISTER_GENERIC_HANDLER(CCartographer);
REGISTER_GENERIC_HANDLER(CGArtifact);
REGISTER_GENERIC_HANDLER(CGBlackMarket);
REGISTER_GENERIC_HANDLER(CGBoat);
@ -132,7 +130,6 @@ void registerTypesMapObjectTypes(Serializer &s)
REGISTER_GENERIC_HANDLER(CGMarket);
REGISTER_GENERIC_HANDLER(CGMine);
REGISTER_GENERIC_HANDLER(CGObelisk);
REGISTER_GENERIC_HANDLER(CGObservatory);
REGISTER_GENERIC_HANDLER(CGPandoraBox);
REGISTER_GENERIC_HANDLER(CGQuestGuard);
REGISTER_GENERIC_HANDLER(CGResource);
@ -177,7 +174,6 @@ void registerTypesMapObjects2(Serializer &s)
s.template registerType<CGObjectInstance, CTeamVisited>();
s.template registerType<CTeamVisited, CGShrine>();
s.template registerType<CTeamVisited, CCartographer>();
s.template registerType<CTeamVisited, CGObelisk>();
//s.template registerType<CQuest>();

View File

@ -161,6 +161,20 @@ void Rewardable::Info::configureReward(Rewardable::Configuration & object, CRand
reward.spellCast.second = source["spellCast"]["schoolLevel"].Integer();
}
if (!source["revealTiles"].isNull())
{
auto const & entry = source["revealTiles"];
reward.revealTiles = RewardRevealTiles();
reward.revealTiles->radius = JsonRandom::loadValue(entry["radius"], rng, variables);
reward.revealTiles->hide = entry["hide"].Bool();
reward.revealTiles->scoreSurface = JsonRandom::loadValue(entry["surface"], rng, variables);
reward.revealTiles->scoreSubterra = JsonRandom::loadValue(entry["subterra"], rng, variables);
reward.revealTiles->scoreWater = JsonRandom::loadValue(entry["water"], rng, variables);
reward.revealTiles->scoreRock = JsonRandom::loadValue(entry["rock"], rng, variables);
}
for ( auto node : source["changeCreatures"].Struct() )
{
CreatureID from(VLC->identifiers()->getIdentifier(node.second.meta, "creature", node.first).value());

View File

@ -12,6 +12,7 @@
#include "Interface.h"
#include "../CHeroHandler.h"
#include "../TerrainHandler.h"
#include "../CSoundBase.h"
#include "../NetPacks.h"
#include "../spells/CSpellHandler.h"
@ -46,6 +47,52 @@ void Rewardable::Interface::grantRewardBeforeLevelup(IGameCallback * cb, const R
cb->giveResources(hero->tempOwner, info.reward.resources);
if (info.reward.revealTiles)
{
auto const & props = *info.reward.revealTiles;
FoWChange fw;
if (props.hide)
fw.mode = FoWChange::Mode::HIDE;
else
fw.mode = FoWChange::Mode::REVEAL;
fw.player = hero->tempOwner;
auto const functor = [&props](const TerrainTile * tile)
{
int score = 0;
if (tile->terType->isSurface())
score += props.scoreSurface;
if (tile->terType->isUnderground())
score += props.scoreSubterra;
if (tile->terType->isWater())
score += props.scoreWater;
if (tile->terType->isRock())
score += props.scoreRock;
return score > 0;
};
if (props.radius > 0)
{
cb->getTilesInRange(fw.tiles, hero->getSightCenter(), props.radius, hero->tempOwner, 1);
vstd::erase_if(fw.tiles, [&](const int3 & coord){
return functor(cb->getTile(coord));
});
}
else
{
cb->getAllTiles(fw.tiles, hero->tempOwner, -1, functor);
}
cb->sendAndApply(&fw);
}
for(const auto & entry : info.reward.secondary)
{
int current = hero->getSecSkillLevel(entry.first);

View File

@ -18,6 +18,11 @@
VCMI_LIB_NAMESPACE_BEGIN
void Rewardable::RewardRevealTiles::serializeJson(JsonSerializeFormat & handler)
{
// TODO
}
Rewardable::Reward::Reward()
: heroExperience(0)
, heroLevel(0)

View File

@ -27,6 +27,34 @@ namespace Rewardable
struct Reward;
using RewardsList = std::vector<std::shared_ptr<Rewardable::Reward>>;
struct RewardRevealTiles
{
/// Reveal distance, if not positive - reveal entire map
int radius;
/// Reveal score of terrains with "surface" flag set
int scoreSurface;
/// Reveal score of terrains with "subterra" flag set
int scoreSubterra;
/// Reveal score of terrains with "water" flag set
int scoreWater;
/// Reveal score of terrains with "rock" flag set
int scoreRock;
/// If set, then terrain will be instead hidden for all enemies (Cover of Darkness)
bool hide;
void serializeJson(JsonSerializeFormat & handler);
template <typename Handler> void serialize(Handler &h, const int version)
{
h & radius;
h & scoreSurface;
h & scoreSubterra;
h & scoreWater;
h & scoreRock;
h & hide;
}
};
/// Reward that can be granted to a hero
/// NOTE: eventually should replace seer hut rewards and events/pandoras
struct DLL_LINKAGE Reward final
@ -74,6 +102,8 @@ struct DLL_LINKAGE Reward final
/// list of components that will be added to reward description. First entry in list will override displayed component
std::vector<Component> extraComponents;
std::optional<RewardRevealTiles> revealTiles;
/// if set to true, object will be removed after granting reward
bool removeObject;
@ -107,8 +137,8 @@ struct DLL_LINKAGE Reward final
h & spells;
h & creatures;
h & creaturesChange;
if(version >= 821)
h & spellCast;
h & revealTiles;
h & spellCast;
}
void serializeJson(JsonSerializeFormat & handler);

View File

@ -858,7 +858,7 @@ void CGameHandler::onNewTurn()
if (player != PlayerColor::NEUTRAL) //do not reveal fow for neutral player
{
FoWChange fw;
fw.mode = 1;
fw.mode = FoWChange::Mode::REVEAL;
fw.player = player;
// find all hidden tiles
const auto fow = getPlayerTeam(player)->fogOfWarMap;
@ -2389,7 +2389,7 @@ bool CGameHandler::buildStructure(ObjectInstanceID tid, BuildingID requestedID,
// now when everything is built - reveal tiles for lookout tower
FoWChange fw;
fw.player = t->tempOwner;
fw.mode = 1;
fw.mode = FoWChange::Mode::REVEAL;
getTilesInRange(fw.tiles, t->getSightCenter(), t->getSightRadius(), t->tempOwner, 1);
sendAndApply(&fw);
@ -4135,7 +4135,7 @@ void CGameHandler::changeFogOfWar(std::unordered_set<int3> &tiles, PlayerColor p
FoWChange fow;
fow.tiles = tiles;
fow.player = player;
fow.mode = hide? 0 : 1;
fow.mode = hide ? FoWChange::Mode::HIDE : FoWChange::Mode::REVEAL;
sendAndApply(&fow);
}

View File

@ -346,7 +346,7 @@ void PlayerMessageProcessor::cheatDefeat(PlayerColor player)
void PlayerMessageProcessor::cheatMapReveal(PlayerColor player, bool reveal)
{
FoWChange fc;
fc.mode = reveal;
fc.mode = reveal ? FoWChange::Mode::REVEAL : FoWChange::Mode::HIDE;
fc.player = player;
const auto & fowMap = gameHandler->gameState()->getPlayerTeam(player)->fogOfWarMap;
const auto & mapSize = gameHandler->gameState()->getMapSize();
@ -356,7 +356,7 @@ void PlayerMessageProcessor::cheatMapReveal(PlayerColor player, bool reveal)
for(int z = 0; z < mapSize.z; z++)
for(int x = 0; x < mapSize.x; x++)
for(int y = 0; y < mapSize.y; y++)
if(!(*fowMap)[z][x][y] || !fc.mode)
if(!(*fowMap)[z][x][y] || fc.mode == FoWChange::Mode::HIDE)
hlp_tab[lastUnc++] = int3(x, y, z);
fc.tiles.insert(hlp_tab, hlp_tab + lastUnc);