diff --git a/Global.h b/Global.h index 2eb54db45..1ba7846e4 100644 --- a/Global.h +++ b/Global.h @@ -475,6 +475,19 @@ namespace vstd } } + template + void erase_if(std::unordered_set &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 void erase_if(std::map &container, Predicate pred) diff --git a/client/NetPacksClient.cpp b/client/NetPacksClient.cpp index 0af992ec6..affbdf49e 100644 --- a/client/NetPacksClient.cpp +++ b/client/NetPacksClient.cpp @@ -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); diff --git a/config/objects/generic.json b/config/objects/generic.json index 0060d02e2..a2c188ed1 100644 --- a/config/objects/generic.json +++ b/config/objects/generic.json @@ -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", diff --git a/config/objects/moddables.json b/config/objects/moddables.json index da0b7e793..2a2b31371 100644 --- a/config/objects/moddables.json +++ b/config/objects/moddables.json @@ -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, diff --git a/config/objects/rewardableGeneric.json b/config/objects/rewardableGeneric.json index 5c48c25b4..cd36c3aac 100644 --- a/config/objects/rewardableGeneric.json +++ b/config/objects/rewardableGeneric.json @@ -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 + } + } + } } \ No newline at end of file diff --git a/lib/CGameInfoCallback.cpp b/lib/CGameInfoCallback.cpp index 077f862c5..45b72a8b4 100644 --- a/lib/CGameInfoCallback.cpp +++ b/lib/CGameInfoCallback.cpp @@ -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 } diff --git a/lib/IGameCallback.cpp b/lib/IGameCallback.cpp index 503d1a8d7..55ceaf9cd 100644 --- a/lib/IGameCallback.cpp +++ b/lib/IGameCallback.cpp @@ -88,7 +88,7 @@ void CPrivilegedInfoCallback::getTilesInRange(std::unordered_set & 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 & tiles, } } -void CPrivilegedInfoCallback::getAllTiles(std::unordered_set & tiles, std::optional Player, int level, MapTerrainFilterMode tileFilterMode) const +void CPrivilegedInfoCallback::getAllTiles(std::unordered_set & tiles, std::optional Player, int level, std::function filter) const { if(!!Player && !Player->isValidPlayer()) { @@ -137,29 +137,9 @@ void CPrivilegedInfoCallback::getAllTiles(std::unordered_set & 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); } } } diff --git a/lib/IGameCallback.h b/lib/IGameCallback.h index 03e96dbeb..e1f82f87c 100644 --- a/lib/IGameCallback.h +++ b/lib/IGameCallback.h @@ -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 &tiles, std::optional player = std::optional(), - int level = -1, MapTerrainFilterMode tileFilterMode = MapTerrainFilterMode::NONE) const; + void getAllTiles(std::unordered_set &tiles, std::optional player, int level, std::function filter) const; //gives 3 treasures, 3 minors, 1 major -> used by Black Market and Artifact Merchant void pickAllowedArtsSet(std::vector & out, CRandomGenerator & rand) const; diff --git a/lib/NetPacks.h b/lib/NetPacks.h index 2992e7be6..017cc0118 100644 --- a/lib/NetPacks.h +++ b/lib/NetPacks.h @@ -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 tiles; PlayerColor player; - ui8 mode = 0; //mode==0 - hide, mode==1 - reveal + Mode mode; bool waitForDialogs = false; virtual void visitTyped(ICPackVisitor & visitor) override; diff --git a/lib/NetPacksLib.cpp b/lib/NetPacksLib.cpp index c56928a3c..65d4878af 100644 --- a/lib/NetPacksLib.cpp +++ b/lib/NetPacksLib.cpp @@ -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 tilesRevealed; for (auto & elem : gs->map->objects) diff --git a/lib/TerrainHandler.cpp b/lib/TerrainHandler.cpp index 2c33519d1..f7a3eb96f 100644 --- a/lib/TerrainHandler.cpp +++ b/lib/TerrainHandler.cpp @@ -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; diff --git a/lib/TerrainHandler.h b/lib/TerrainHandler.h index 60d649d3c..b94e4427d 100644 --- a/lib/TerrainHandler.h +++ b/lib/TerrainHandler.h @@ -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 void serialize(Handler &h, const int version) { diff --git a/lib/mapObjectConstructors/CObjectClassesHandler.cpp b/lib/mapObjectConstructors/CObjectClassesHandler.cpp index b157667d4..9b8b5ecff 100644 --- a/lib/mapObjectConstructors/CObjectClassesHandler.cpp +++ b/lib/mapObjectConstructors/CObjectClassesHandler.cpp @@ -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); diff --git a/lib/mapObjects/CGTownInstance.cpp b/lib/mapObjects/CGTownInstance.cpp index 7c9d97a7b..78c4399ba 100644 --- a/lib/mapObjects/CGTownInstance.cpp +++ b/lib/mapObjects/CGTownInstance.cpp @@ -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); } diff --git a/lib/mapObjects/CRewardableObject.h b/lib/mapObjects/CRewardableObject.h index 3e8bc6a7e..fe41428c1 100644 --- a/lib/mapObjects/CRewardableObject.h +++ b/lib/mapObjects/CRewardableObject.h @@ -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 diff --git a/lib/mapObjects/MiscObjects.cpp b/lib/mapObjects/MiscObjects.cpp index bf370d858..36f7fd91a 100644 --- a/lib/mapObjects/MiscObjects.cpp +++ b/lib/mapObjects/MiscObjects.cpp @@ -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); diff --git a/lib/mapObjects/MiscObjects.h b/lib/mapObjects/MiscObjects.h index 8b68c4dab..ce7e7fcb2 100644 --- a/lib/mapObjects/MiscObjects.h +++ b/lib/mapObjects/MiscObjects.h @@ -314,17 +314,6 @@ public: } }; -class DLL_LINKAGE CGObservatory : public CGObjectInstance //Redwood observatory -{ -public: - void onHeroVisit(const CGHeroInstance * h) const override; - - template void serialize(Handler &h, const int version) - { - h & static_cast(*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 void serialize(Handler &h, const int version) - { - h & static_cast(*this); - } -}; - class DLL_LINKAGE CGDenOfthieves : public CGObjectInstance { void onHeroVisit(const CGHeroInstance * h) const override; diff --git a/lib/registerTypes/RegisterTypes.h b/lib/registerTypes/RegisterTypes.h index e431b9dd3..e8ed5239e 100644 --- a/lib/registerTypes/RegisterTypes.h +++ b/lib/registerTypes/RegisterTypes.h @@ -56,7 +56,6 @@ void registerTypesMapObjects1(Serializer &s) s.template registerType(); s.template registerType(); s.template registerType(); - s.template registerType(); s.template registerType(); s.template registerType(); s.template registerType(); s.template registerType(); @@ -112,7 +111,6 @@ void registerTypesMapObjectTypes(Serializer &s) #define REGISTER_GENERIC_HANDLER(TYPENAME) s.template registerType >() 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(); s.template registerType(); - s.template registerType(); s.template registerType(); //s.template registerType(); diff --git a/lib/rewardable/Info.cpp b/lib/rewardable/Info.cpp index b842254ad..a7d63a1b9 100644 --- a/lib/rewardable/Info.cpp +++ b/lib/rewardable/Info.cpp @@ -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()); diff --git a/lib/rewardable/Interface.cpp b/lib/rewardable/Interface.cpp index 84cfdc8e3..f13a4a5a5 100644 --- a/lib/rewardable/Interface.cpp +++ b/lib/rewardable/Interface.cpp @@ -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); diff --git a/lib/rewardable/Reward.cpp b/lib/rewardable/Reward.cpp index bbdbf3cdc..dad53105a 100644 --- a/lib/rewardable/Reward.cpp +++ b/lib/rewardable/Reward.cpp @@ -18,6 +18,11 @@ VCMI_LIB_NAMESPACE_BEGIN +void Rewardable::RewardRevealTiles::serializeJson(JsonSerializeFormat & handler) +{ + // TODO +} + Rewardable::Reward::Reward() : heroExperience(0) , heroLevel(0) diff --git a/lib/rewardable/Reward.h b/lib/rewardable/Reward.h index 9493083f1..b842e5929 100644 --- a/lib/rewardable/Reward.h +++ b/lib/rewardable/Reward.h @@ -27,6 +27,34 @@ namespace Rewardable struct Reward; using RewardsList = std::vector>; +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 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 extraComponents; + std::optional 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); diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 27412a5e2..8653120b0 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -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 &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); } diff --git a/server/processors/PlayerMessageProcessor.cpp b/server/processors/PlayerMessageProcessor.cpp index 7cadfda29..7df0a3cb9 100644 --- a/server/processors/PlayerMessageProcessor.cpp +++ b/server/processors/PlayerMessageProcessor.cpp @@ -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);