From 11e4d84749095a2796927dd312e6b784d6e2c893 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 21 Feb 2023 14:38:08 +0200 Subject: [PATCH] Implemented View Earth / View Air spells --- AI/Nullkiller/AIGateway.cpp | 2 +- AI/Nullkiller/AIGateway.h | 2 +- AI/VCAI/VCAI.cpp | 2 +- AI/VCAI/VCAI.h | 2 +- client/CPlayerInterface.cpp | 18 +---- client/CPlayerInterface.h | 2 +- client/NetPacksClient.cpp | 2 +- client/adventureMap/CAdvMapInt.cpp | 91 ++++++++++------------- client/adventureMap/CAdvMapInt.h | 23 +++--- client/adventureMap/CAdventureOptions.cpp | 2 +- client/adventureMap/CTerrainRect.cpp | 11 +++ client/adventureMap/CTerrainRect.h | 4 + client/mapRenderer/IMapRendererContext.h | 5 +- client/mapRenderer/MapRenderer.cpp | 4 +- client/mapRenderer/MapRendererContext.cpp | 78 ++++++++++++++++++- client/mapRenderer/MapRendererContext.h | 39 +++++++++- client/mapRenderer/MapViewCache.cpp | 51 ++++--------- client/mapRenderer/MapViewCache.h | 27 ------- client/mapRenderer/MapViewController.cpp | 12 +++ client/mapRenderer/MapViewController.h | 6 ++ lib/CGameInterface.h | 2 +- lib/NetPacks.h | 2 + lib/spells/AdventureSpellMechanics.cpp | 10 +++ lib/spells/AdventureSpellMechanics.h | 3 + 24 files changed, 243 insertions(+), 157 deletions(-) diff --git a/AI/Nullkiller/AIGateway.cpp b/AI/Nullkiller/AIGateway.cpp index 21dc1061c..f63e8f6e8 100644 --- a/AI/Nullkiller/AIGateway.cpp +++ b/AI/Nullkiller/AIGateway.cpp @@ -489,7 +489,7 @@ void AIGateway::showMarketWindow(const IMarket * market, const CGHeroInstance * NET_EVENT_HANDLER; } -void AIGateway::showWorldViewEx(const std::vector & objectPositions) +void AIGateway::showWorldViewEx(const std::vector & objectPositions, bool showTerrain) { //TODO: AI support for ViewXXX spell LOG_TRACE(logAi); diff --git a/AI/Nullkiller/AIGateway.h b/AI/Nullkiller/AIGateway.h index df98bfaca..98b0fca8b 100644 --- a/AI/Nullkiller/AIGateway.h +++ b/AI/Nullkiller/AIGateway.h @@ -165,7 +165,7 @@ public: void buildChanged(const CGTownInstance * town, BuildingID buildingID, int what) override; void heroBonusChanged(const CGHeroInstance * hero, const Bonus & bonus, bool gain) override; void showMarketWindow(const IMarket * market, const CGHeroInstance * visitor) override; - void showWorldViewEx(const std::vector & objectPositions) override; + void showWorldViewEx(const std::vector & objectPositions, bool showTerrain) override; boost::optional makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) override; void battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side) override; diff --git a/AI/VCAI/VCAI.cpp b/AI/VCAI/VCAI.cpp index ab669343a..da7eced29 100644 --- a/AI/VCAI/VCAI.cpp +++ b/AI/VCAI/VCAI.cpp @@ -572,7 +572,7 @@ void VCAI::showMarketWindow(const IMarket * market, const CGHeroInstance * visit NET_EVENT_HANDLER; } -void VCAI::showWorldViewEx(const std::vector & objectPositions) +void VCAI::showWorldViewEx(const std::vector & objectPositions, bool showTerrain) { //TODO: AI support for ViewXXX spell LOG_TRACE(logAi); diff --git a/AI/VCAI/VCAI.h b/AI/VCAI/VCAI.h index 328eb1cb0..5ea900961 100644 --- a/AI/VCAI/VCAI.h +++ b/AI/VCAI/VCAI.h @@ -198,7 +198,7 @@ public: void buildChanged(const CGTownInstance * town, BuildingID buildingID, int what) override; void heroBonusChanged(const CGHeroInstance * hero, const Bonus & bonus, bool gain) override; void showMarketWindow(const IMarket * market, const CGHeroInstance * visitor) override; - void showWorldViewEx(const std::vector & objectPositions) override; + void showWorldViewEx(const std::vector & objectPositions, bool showTerrain) override; void battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side) override; void battleEnd(const BattleResult * br) override; diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index 5e0f49929..7c3031436 100644 --- a/client/CPlayerInterface.cpp +++ b/client/CPlayerInterface.cpp @@ -1829,7 +1829,7 @@ void CPlayerInterface::showPuzzleMap() void CPlayerInterface::viewWorldMap() { - adventureInt->changeMode(EAdvMapMode::WORLD_VIEW); + adventureInt->openWorldView(); } void CPlayerInterface::advmapSpellCast(const CGHeroInstance * caster, int spellID) @@ -1843,14 +1843,6 @@ void CPlayerInterface::advmapSpellCast(const CGHeroInstance * caster, int spellI paths.erasePath(caster); const spells::Spell * spell = CGI->spells()->getByIndex(spellID); - - if(spellID == SpellID::VIEW_EARTH) - { - //TODO: implement on server side - const auto level = caster->getSpellSchoolLevel(spell); - adventureInt->worldViewOptions.showAllTerrain = (level > 2); - } - auto castSoundPath = spell->getCastSound(); if(!castSoundPath.empty()) CCS->soundh->playSound(castSoundPath); @@ -2369,14 +2361,10 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance * h, CGPath path) setMovementStatus(false); } -void CPlayerInterface::showWorldViewEx(const std::vector& objectPositions) +void CPlayerInterface::showWorldViewEx(const std::vector& objectPositions, bool showTerrain) { EVENT_HANDLER_CALLED_BY_CLIENT; - //TODO: showWorldViewEx - - std::copy(objectPositions.begin(), objectPositions.end(), std::back_inserter(adventureInt->worldViewOptions.iconPositions)); - - viewWorldMap(); + adventureInt->openWorldView(objectPositions, showTerrain ); } void CPlayerInterface::updateAmbientSounds(bool resetAll) diff --git a/client/CPlayerInterface.h b/client/CPlayerInterface.h index fe4bf1842..d3526cd85 100644 --- a/client/CPlayerInterface.h +++ b/client/CPlayerInterface.h @@ -210,7 +210,7 @@ public: void showComp(const Component &comp, std::string message) override; //display component in the advmapint infobox void saveGame(BinarySerializer & h, const int version) override; //saving void loadGame(BinaryDeserializer & h, const int version) override; //loading - void showWorldViewEx(const std::vector & objectPositions) override; + void showWorldViewEx(const std::vector & objectPositions, bool showTerrain) override; //for battles void actionFinished(const BattleAction& action) override;//occurs AFTER action taken by active stack or by the hero diff --git a/client/NetPacksClient.cpp b/client/NetPacksClient.cpp index 5d8ba8bd8..20e2e4c4d 100644 --- a/client/NetPacksClient.cpp +++ b/client/NetPacksClient.cpp @@ -883,7 +883,7 @@ void ApplyClientNetPackVisitor::visitAdvmapSpellCast(AdvmapSpellCast & pack) void ApplyClientNetPackVisitor::visitShowWorldViewEx(ShowWorldViewEx & pack) { - callOnlyThatInterface(cl, pack.player, &CGameInterface::showWorldViewEx, pack.objectPositions); + callOnlyThatInterface(cl, pack.player, &CGameInterface::showWorldViewEx, pack.objectPositions, pack.showTerrain); } void ApplyClientNetPackVisitor::visitOpenWindow(OpenWindow & pack) diff --git a/client/adventureMap/CAdvMapInt.cpp b/client/adventureMap/CAdvMapInt.cpp index 659b91d91..dd5609bdb 100644 --- a/client/adventureMap/CAdvMapInt.cpp +++ b/client/adventureMap/CAdvMapInt.cpp @@ -236,7 +236,7 @@ CAdvMapInt::CAdvMapInt(): activeMapPanel = panelMain; - changeMode(EAdvMapMode::NORMAL); + exitWorldView(); underground->block(!CGI->mh->getMap()->twoLevel); questlog->block(!CGI->mh->getMap()->quests.size()); @@ -252,7 +252,7 @@ void CAdvMapInt::fshowOverview() void CAdvMapInt::fworldViewBack() { - changeMode(EAdvMapMode::NORMAL); + exitWorldView(); auto hero = curHero(); if (hero) @@ -262,17 +262,17 @@ void CAdvMapInt::fworldViewBack() void CAdvMapInt::fworldViewScale1x() { // TODO set corresponding scale button to "selected" mode - changeMode(EAdvMapMode::WORLD_VIEW, 7); // 7 pixels per tile + openWorldView(7); } void CAdvMapInt::fworldViewScale2x() { - changeMode(EAdvMapMode::WORLD_VIEW, 11); // 11 pixels per tile + openWorldView(11); } void CAdvMapInt::fworldViewScale4x() { - changeMode(EAdvMapMode::WORLD_VIEW, 16); // 16 pixels per tile + openWorldView(16); } void CAdvMapInt::fswitchLevel() @@ -666,7 +666,7 @@ void CAdvMapInt::centerOn(const CGObjectInstance * obj, bool fade) void CAdvMapInt::keyReleased(const SDL_Keycode &key) { - if (mode == EAdvMapMode::WORLD_VIEW) + if (mode != EAdvMapMode::NORMAL) return; switch (key) @@ -694,7 +694,7 @@ void CAdvMapInt::keyReleased(const SDL_Keycode &key) void CAdvMapInt::keyPressed(const SDL_Keycode & key) { - if (mode == EAdvMapMode::WORLD_VIEW) + if (mode != EAdvMapMode::NORMAL) return; const CGHeroInstance *h = curHero(); //selected hero @@ -1460,62 +1460,49 @@ void CAdvMapInt::quickCombatUnlock() activate(); } -void CAdvMapInt::changeMode(EAdvMapMode newMode) +void CAdvMapInt::exitWorldView() { - changeMode(newMode, 11); + mode = EAdvMapMode::NORMAL; + + panelMain->activate(); + panelWorldView->deactivate(); + activeMapPanel = panelMain; + + townList->activate(); + heroList->activate(); + infoBar->activate(); + + redraw(); + terrain->setTileSize(32); + terrain->setTerrainVisibility(false); + terrain->setOverlayVisibility({}); } -void CAdvMapInt::changeMode(EAdvMapMode newMode, int tileSize) +void CAdvMapInt::openWorldView(int tileSize) { - if (mode != newMode) - { - mode = newMode; + mode = EAdvMapMode::WORLD_VIEW; + panelMain->deactivate(); + panelWorldView->activate(); - switch (mode) - { - case EAdvMapMode::NORMAL: - panelMain->activate(); - panelWorldView->deactivate(); - activeMapPanel = panelMain; + activeMapPanel = panelWorldView; - townList->activate(); - heroList->activate(); - infoBar->activate(); + townList->deactivate(); + heroList->deactivate(); + infoBar->showSelection(); // to prevent new day animation interfering world view mode + infoBar->deactivate(); - worldViewOptions.clear(); - - break; - case EAdvMapMode::WORLD_VIEW: - panelMain->deactivate(); - panelWorldView->activate(); - - activeMapPanel = panelWorldView; - - townList->deactivate(); - heroList->deactivate(); - infoBar->showSelection(); // to prevent new day animation interfering world view mode - infoBar->deactivate(); - - - break; - } - redraw(); - } - - if(mode == EAdvMapMode::NORMAL) - terrain->setTileSize(32); - if(mode == EAdvMapMode::WORLD_VIEW) - terrain->setTileSize(tileSize); + redraw(); + terrain->setTileSize(tileSize); } -CAdvMapInt::WorldViewOptions::WorldViewOptions() +void CAdvMapInt::openWorldView() { - clear(); + openWorldView(11); } -void CAdvMapInt::WorldViewOptions::clear() +void CAdvMapInt::openWorldView(const std::vector& objectPositions, bool showTerrain) { - showAllTerrain = false; - - iconPositions.clear(); + openWorldView(11); + terrain->setTerrainVisibility(showTerrain); + terrain->setOverlayVisibility(objectPositions); } diff --git a/client/adventureMap/CAdvMapInt.h b/client/adventureMap/CAdvMapInt.h index 5bc7fa8d7..cb3169cf5 100644 --- a/client/adventureMap/CAdvMapInt.h +++ b/client/adventureMap/CAdvMapInt.h @@ -61,21 +61,12 @@ private: enum EDirections {LEFT=1, RIGHT=2, UP=4, DOWN=8}; enum EGameStates {NA, INGAME, WAITING}; - struct WorldViewOptions - { - bool showAllTerrain; //for expert viewEarth - std::vector iconPositions; - WorldViewOptions(); - void clear(); - }; - bool swipeEnabled; bool swipeMovementRequested; Point swipeTargetPosition; EGameStates state; EAdvMapMode mode; - WorldViewOptions worldViewOptions; /// Currently selected object, can be town, hero or null const CArmedInstance *selection; @@ -211,9 +202,17 @@ public: /// returs visible section of game map, in tiles Rect terrainAreaTiles() const; - /// changes current adventure map mode; used to switch between default view and world view; scale is ignored if EAdvMapMode == NORMAL - void changeMode(EAdvMapMode newMode); - void changeMode(EAdvMapMode newMode, int tileSize); + /// exits currently opened world view mode and returns to normal map + void exitWorldView(); + + /// opens world view at default scale + void openWorldView(); + + /// opens world view at specific scale + void openWorldView(int tileSize); + + /// opens world view with specific info, e.g. after View Earth/Air is shown + void openWorldView(const std::vector& objectPositions, bool showTerrain); }; extern std::shared_ptr adventureInt; diff --git a/client/adventureMap/CAdventureOptions.cpp b/client/adventureMap/CAdventureOptions.cpp index 7e96ac4b0..a53512e6e 100644 --- a/client/adventureMap/CAdventureOptions.cpp +++ b/client/adventureMap/CAdventureOptions.cpp @@ -29,7 +29,7 @@ CAdventureOptions::CAdventureOptions() OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); viewWorld = std::make_shared(Point(24, 23), "ADVVIEW.DEF", CButton::tooltip(), [&](){ close(); }, SDLK_v); - viewWorld->addCallback(std::bind(&CPlayerInterface::viewWorldMap, LOCPLINT)); + viewWorld->addCallback( [] { LOCPLINT->viewWorldMap(); }); exit = std::make_shared(Point(204, 313), "IOK6432.DEF", CButton::tooltip(), std::bind(&CAdventureOptions::close, this), SDLK_RETURN); exit->assignedKeys.insert(SDLK_ESCAPE); diff --git a/client/adventureMap/CTerrainRect.cpp b/client/adventureMap/CTerrainRect.cpp index 88893f51b..ed46aae7b 100644 --- a/client/adventureMap/CTerrainRect.cpp +++ b/client/adventureMap/CTerrainRect.cpp @@ -240,3 +240,14 @@ void CTerrainRect::setTileSize(int sizePixels) { renderer->getController()->setTileSize(Point(sizePixels, sizePixels)); } + + +void CTerrainRect::setTerrainVisibility(bool showAllTerrain) +{ + renderer->getController()->setTerrainVisibility(showAllTerrain); +} + +void CTerrainRect::setOverlayVisibility(const std::vector & objectPositions) +{ + renderer->getController()->setOverlayVisibility(objectPositions); +} diff --git a/client/adventureMap/CTerrainRect.h b/client/adventureMap/CTerrainRect.h index 814fd15b8..5c53ba1bd 100644 --- a/client/adventureMap/CTerrainRect.h +++ b/client/adventureMap/CTerrainRect.h @@ -14,6 +14,7 @@ VCMI_LIB_NAMESPACE_BEGIN struct CGPath; +struct ObjectPosInfo; VCMI_LIB_NAMESPACE_END class MapView; @@ -51,6 +52,9 @@ public: void setLevel(int level); void setTileSize(int sizePixels); + void setTerrainVisibility(bool showAllTerrain); + void setOverlayVisibility(const std::vector & objectPositions); + Point getViewCenter(); int getLevel(); diff --git a/client/mapRenderer/IMapRendererContext.h b/client/mapRenderer/IMapRendererContext.h index d3c856971..d7a8cbbed 100644 --- a/client/mapRenderer/IMapRendererContext.h +++ b/client/mapRenderer/IMapRendererContext.h @@ -53,11 +53,14 @@ public: virtual Point objectImageOffset(ObjectInstanceID objectID, const int3 & coordinates) const = 0; /// returns object animation transparency. IF set to 0, object will not be visible - virtual double objectTransparency(ObjectInstanceID objectID) const = 0; + virtual double objectTransparency(ObjectInstanceID objectID, const int3 &coordinates) const = 0; /// returns animation frame for selected object virtual size_t objectImageIndex(ObjectInstanceID objectID, size_t groupSize) const = 0; + /// returns index of image for overlay on specific tile, or numeric_limits::max if none + virtual size_t overlayImageIndex(const int3 & coordinates) const = 0; + /// returns animation frame for terrain virtual size_t terrainImageIndex(size_t groupSize) const = 0; diff --git a/client/mapRenderer/MapRenderer.cpp b/client/mapRenderer/MapRenderer.cpp index 4caa4d4a1..2b6cf216c 100644 --- a/client/mapRenderer/MapRenderer.cpp +++ b/client/mapRenderer/MapRenderer.cpp @@ -444,7 +444,7 @@ void MapRendererObjects::renderImage(const IMapRendererContext & context, Canvas if(!image) return; - auto transparency = static_cast(std::round(255 * context.objectTransparency(object->id))); + auto transparency = static_cast(std::round(255 * context.objectTransparency(object->id, coordinates))); if (transparency == 0) return; @@ -507,7 +507,7 @@ void MapRendererDebug::renderTile(const IMapRendererContext & context, Canvas & { const auto * object = context.getObject(objectID); - if (context.objectTransparency(objectID) > 0) + if (context.objectTransparency(objectID, coordinates) > 0) { visitable |= object->visitableAt(coordinates.x, coordinates.y); blockable |= object->blockingAt(coordinates.x, coordinates.y); diff --git a/client/mapRenderer/MapRendererContext.cpp b/client/mapRenderer/MapRendererContext.cpp index 5f2c651db..37d1421af 100644 --- a/client/mapRenderer/MapRendererContext.cpp +++ b/client/mapRenderer/MapRendererContext.cpp @@ -66,6 +66,8 @@ const CGObjectInstance * MapRendererContext::getObject(ObjectInstanceID objectID bool MapRendererContext::isVisible(const int3 & coordinates) const { + if (showAllTerrain) + return LOCPLINT->cb->isInTheMap(coordinates); return LOCPLINT->cb->isVisible(coordinates) || settings["session"]["spectate"].Bool(); } @@ -253,11 +255,11 @@ Point MapRendererContext::objectImageOffset(ObjectInstanceID objectID, const int return Point(offsetTiles) * Point(32, 32); } -double MapRendererContext::objectTransparency(ObjectInstanceID objectID) const +double MapRendererContext::objectTransparency(ObjectInstanceID objectID, const int3 & coordinates) const { const CGObjectInstance * object = getObject(objectID); - if(object && object->ID == Obj::HERO) + if(object->ID == Obj::HERO) { const auto * hero = dynamic_cast(object); @@ -268,6 +270,12 @@ double MapRendererContext::objectTransparency(ObjectInstanceID objectID) const return 0; } + if(showAllTerrain) + { + if(object->isVisitable() && !LOCPLINT->cb->isVisible(coordinates)) + return 0; + } + if(fadeOutAnimation && objectID == fadeOutAnimation->target) return 1.0 - fadeOutAnimation->progress; @@ -276,3 +284,69 @@ double MapRendererContext::objectTransparency(ObjectInstanceID objectID) const return 1.0; } + +size_t MapRendererContext::selectOverlayImageForObject(const ObjectPosInfo & object) const +{ + size_t ownerIndex = PlayerColor::PLAYER_LIMIT.getNum() * static_cast(EWorldViewIcon::ICONS_PER_PLAYER); + + if(object.owner.isValidPlayer()) + ownerIndex = object.owner.getNum() * static_cast(EWorldViewIcon::ICONS_PER_PLAYER); + + switch(object.id) + { + case Obj::MONOLITH_ONE_WAY_ENTRANCE: + case Obj::MONOLITH_ONE_WAY_EXIT: + case Obj::MONOLITH_TWO_WAY: + return ownerIndex + static_cast(EWorldViewIcon::TELEPORT); + case Obj::SUBTERRANEAN_GATE: + return ownerIndex + static_cast(EWorldViewIcon::GATE); + case Obj::ARTIFACT: + return ownerIndex + static_cast(EWorldViewIcon::ARTIFACT); + case Obj::TOWN: + return ownerIndex + static_cast(EWorldViewIcon::TOWN); + case Obj::HERO: + return ownerIndex + static_cast(EWorldViewIcon::HERO); + case Obj::MINE: + return ownerIndex + static_cast(EWorldViewIcon::MINE_WOOD) + object.subId; + case Obj::RESOURCE: + return ownerIndex + static_cast(EWorldViewIcon::RES_WOOD) + object.subId; + } + return std::numeric_limits::max(); +} + +size_t MapRendererContext::overlayImageIndex(const int3 & coordinates) const +{ + for(const auto & entry : additionalOverlayIcons) + { + if(entry.pos != coordinates) + continue; + + size_t iconIndex = selectOverlayImageForObject(entry); + + if(iconIndex != std::numeric_limits::max()) + return iconIndex; + } + + if(!isVisible(coordinates)) + return std::numeric_limits::max(); + + for(const auto & objectID : getObjects(coordinates)) + { + const auto * object = getObject(objectID); + + if(!object->visitableAt(coordinates.x, coordinates.y)) + continue; + + ObjectPosInfo info; + info.pos = coordinates; + info.id = object->ID; + info.subId = object->subID; + info.owner = object->tempOwner; + + size_t iconIndex = selectOverlayImageForObject(info); + + if(iconIndex != std::numeric_limits::max()) + return iconIndex; + } + return std::numeric_limits::max(); +} diff --git a/client/mapRenderer/MapRendererContext.h b/client/mapRenderer/MapRendererContext.h index 6802a6cfd..06ac24053 100644 --- a/client/mapRenderer/MapRendererContext.h +++ b/client/mapRenderer/MapRendererContext.h @@ -14,6 +14,10 @@ #include "../lib/int3.h" #include "../lib/GameConstants.h" +VCMI_LIB_NAMESPACE_BEGIN +struct ObjectPosInfo; +VCMI_LIB_NAMESPACE_END + class MapObjectsSorter { const IMapRendererContext & context; @@ -39,6 +43,33 @@ struct FadingAnimationState double progress; }; +// from VwSymbol.def +enum class EWorldViewIcon +{ + TOWN = 0, + HERO = 1, + ARTIFACT = 2, + TELEPORT = 3, + GATE = 4, + MINE_WOOD = 5, + MINE_MERCURY = 6, + MINE_STONE = 7, + MINE_SULFUR = 8, + MINE_CRYSTAL = 9, + MINE_GEM = 10, + MINE_GOLD = 11, + RES_WOOD = 12, + RES_MERCURY = 13, + RES_STONE = 14, + RES_SULFUR = 15, + RES_CRYSTAL = 16, + RES_GEM = 17, + RES_GOLD = 18, + + ICONS_PER_PLAYER = 19, + ICONS_TOTAL = 19 * 9 // 8 players + neutral set at the end +}; + class MapRendererContext : public IMapRendererContext { friend class MapViewController; @@ -54,7 +85,12 @@ class MapRendererContext : public IMapRendererContext boost::optional fadeOutAnimation; boost::optional fadeInAnimation; + std::vector additionalOverlayIcons; + bool worldViewModeActive = false; + bool showAllTerrain = false; + + size_t selectOverlayImageForObject(const ObjectPosInfo & objectID) const; public: MapRendererContext(); @@ -74,9 +110,10 @@ public: size_t objectGroupIndex(ObjectInstanceID objectID) const override; Point objectImageOffset(ObjectInstanceID objectID, const int3 & coordinates) const override; - double objectTransparency(ObjectInstanceID objectID) const override; + double objectTransparency(ObjectInstanceID objectID, const int3 &coordinates) const override; size_t objectImageIndex(ObjectInstanceID objectID, size_t groupSize) const override; size_t terrainImageIndex(size_t groupSize) const override; + size_t overlayImageIndex(const int3 & coordinates) const override; // Point getTileSize() const override; bool showOverlay() const override; diff --git a/client/mapRenderer/MapViewCache.cpp b/client/mapRenderer/MapViewCache.cpp index 9676c74a7..c9bd268bc 100644 --- a/client/mapRenderer/MapViewCache.cpp +++ b/client/mapRenderer/MapViewCache.cpp @@ -26,13 +26,12 @@ MapViewCache::MapViewCache(const std::shared_ptr & model) : model(model) , mapRenderer(new MapRenderer()) , iconsStorage(new CAnimation("VwSymbol")) - , intermediate(new Canvas(Point(32,32))) + , intermediate(new Canvas(Point(32, 32))) , terrain(new Canvas(model->getCacheDimensionsPixels())) { iconsStorage->preload(); - for (size_t i = 0; i < iconsStorage->size(); ++i) + for(size_t i = 0; i < iconsStorage->size(); ++i) iconsStorage->getImage(i)->setBlitMode(EImageBlitMode::COLORKEY); - } Canvas MapViewCache::getTile(const int3 & coordinates) @@ -42,40 +41,10 @@ Canvas MapViewCache::getTile(const int3 & coordinates) std::shared_ptr MapViewCache::getOverlayImageForTile(const std::shared_ptr & context, const int3 & coordinates) { - if (!context->isVisible(coordinates)) - return nullptr; + size_t imageIndex = context->overlayImageIndex(coordinates); - for(const auto & objectID : context->getObjects(coordinates)) - { - const auto * object = context->getObject(objectID); - - if (!object->visitableAt(coordinates.x, coordinates.y)) - continue; - - size_t ownerIndex = PlayerColor::PLAYER_LIMIT.getNum() * static_cast(EWorldViewIcon::ICONS_PER_PLAYER); - if (object->tempOwner.isValidPlayer()) - ownerIndex = object->tempOwner.getNum() * static_cast(EWorldViewIcon::ICONS_PER_PLAYER); - - switch (object->ID) - { - case Obj::MONOLITH_ONE_WAY_ENTRANCE: - case Obj::MONOLITH_ONE_WAY_EXIT: - case Obj::MONOLITH_TWO_WAY: - return iconsStorage->getImage(ownerIndex + static_cast(EWorldViewIcon::TELEPORT)); - case Obj::SUBTERRANEAN_GATE: - return iconsStorage->getImage(ownerIndex + static_cast(EWorldViewIcon::GATE)); - case Obj::ARTIFACT: - return iconsStorage->getImage(ownerIndex + static_cast(EWorldViewIcon::ARTIFACT)); - case Obj::TOWN: - return iconsStorage->getImage(ownerIndex + static_cast(EWorldViewIcon::TOWN)); - case Obj::HERO: - return iconsStorage->getImage(ownerIndex + static_cast(EWorldViewIcon::HERO)); - case Obj::MINE: - return iconsStorage->getImage(ownerIndex + static_cast(EWorldViewIcon::MINE_WOOD) + object->subID); - case Obj::RESOURCE: - return iconsStorage->getImage(ownerIndex + static_cast(EWorldViewIcon::RES_WOOD) + object->subID); - } - } + if(imageIndex < iconsStorage->size()) + return iconsStorage->getImage(imageIndex); return nullptr; } @@ -115,9 +84,17 @@ void MapViewCache::render(const std::shared_ptr & context, C Canvas source = getTile(tile); Rect targetRect = model->getTargetTileArea(tile); target.draw(source, targetRect.topLeft()); + } + } - if (context->showOverlay()) + if (context->showOverlay()) + { + for(int y = dimensions.top(); y < dimensions.bottom(); ++y) + { + for(int x = dimensions.left(); x < dimensions.right(); ++x) { + int3 tile(x, y, model->getLevel()); + Rect targetRect = model->getTargetTileArea(tile); auto overlay = getOverlayImageForTile(context, tile); if (overlay) diff --git a/client/mapRenderer/MapViewCache.h b/client/mapRenderer/MapViewCache.h index 1b2234ec1..55ec02d39 100644 --- a/client/mapRenderer/MapViewCache.h +++ b/client/mapRenderer/MapViewCache.h @@ -21,33 +21,6 @@ class MapRendererContext; //class MapViewController; class MapViewModel; -// from VwSymbol.def -enum class EWorldViewIcon -{ - TOWN = 0, - HERO = 1, - ARTIFACT = 2, - TELEPORT = 3, - GATE = 4, - MINE_WOOD = 5, - MINE_MERCURY = 6, - MINE_STONE = 7, - MINE_SULFUR = 8, - MINE_CRYSTAL = 9, - MINE_GEM = 10, - MINE_GOLD = 11, - RES_WOOD = 12, - RES_MERCURY = 13, - RES_STONE = 14, - RES_SULFUR = 15, - RES_CRYSTAL = 16, - RES_GEM = 17, - RES_GOLD = 18, - - ICONS_PER_PLAYER = 19, - ICONS_TOTAL = 19 * 9 // 8 players + neutral set at the end -}; - /// Class responsible for rendering of entire map view /// uses rendering parameters provided by owner class class MapViewCache diff --git a/client/mapRenderer/MapViewController.cpp b/client/mapRenderer/MapViewController.cpp index c612d51cf..d8d8ff31b 100644 --- a/client/mapRenderer/MapViewController.cpp +++ b/client/mapRenderer/MapViewController.cpp @@ -17,6 +17,7 @@ #include "../../lib/CConfigHandler.h" #include "../../lib/mapObjects/CGHeroInstance.h" #include "../../lib/mapObjects/MiscObjects.h" +#include "../../lib/spells/ViewSpellInt.h" void MapViewController::setViewCenter(const int3 & position) { @@ -185,3 +186,14 @@ bool MapViewController::hasOngoingAnimations() return false; } + +void MapViewController::setTerrainVisibility(bool showAllTerrain) +{ + context->showAllTerrain = showAllTerrain; +} + +void MapViewController::setOverlayVisibility(const std::vector & objectPositions) +{ + context->additionalOverlayIcons = objectPositions; +} + diff --git a/client/mapRenderer/MapViewController.h b/client/mapRenderer/MapViewController.h index 39eb3fe0f..b5494c566 100644 --- a/client/mapRenderer/MapViewController.h +++ b/client/mapRenderer/MapViewController.h @@ -13,7 +13,9 @@ VCMI_LIB_NAMESPACE_BEGIN class Point; +struct ObjectPosInfo; VCMI_LIB_NAMESPACE_END + class MapViewModel; class MapRendererContext; @@ -42,4 +44,8 @@ public: void setViewCenter(const Point & position, int level); void setTileSize(const Point & tileSize); void update(uint32_t timeDelta); + + void setTerrainVisibility(bool showAllTerrain); + void setOverlayVisibility(const std::vector & objectPositions); + }; diff --git a/lib/CGameInterface.h b/lib/CGameInterface.h index f07a9548a..154c3058f 100644 --- a/lib/CGameInterface.h +++ b/lib/CGameInterface.h @@ -107,7 +107,7 @@ public: virtual void showMapObjectSelectDialog(QueryID askID, const Component & icon, const MetaString & title, const MetaString & description, const std::vector & objects) = 0; virtual void finish(){}; //if for some reason we want to end - virtual void showWorldViewEx(const std::vector & objectPositions){}; + virtual void showWorldViewEx(const std::vector & objectPositions, bool showTerrain){}; virtual boost::optional makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) { diff --git a/lib/NetPacks.h b/lib/NetPacks.h index 1e13d437c..a0e3aa87d 100644 --- a/lib/NetPacks.h +++ b/lib/NetPacks.h @@ -1908,12 +1908,14 @@ protected: struct DLL_LINKAGE ShowWorldViewEx : public CPackForClient { PlayerColor player; + bool showTerrain; // TODO: send terrain state std::vector objectPositions; template void serialize(Handler & h, const int version) { h & player; + h & showTerrain; h & objectPositions; } diff --git a/lib/spells/AdventureSpellMechanics.cpp b/lib/spells/AdventureSpellMechanics.cpp index 98fe28ad5..5bc687075 100644 --- a/lib/spells/AdventureSpellMechanics.cpp +++ b/lib/spells/AdventureSpellMechanics.cpp @@ -585,6 +585,7 @@ ESpellCastResult ViewMechanics::applyAdventureEffects(SpellCastEnvironment * env pack.objectPositions.push_back(posInfo); } } + pack.showTerrain = showTerrain(spellLevel); env->apply(&pack); @@ -602,6 +603,11 @@ bool ViewAirMechanics::filterObject(const CGObjectInstance * obj, const int32_t return (obj->ID == Obj::ARTIFACT) || (spellLevel > 1 && obj->ID == Obj::HERO) || (spellLevel > 2 && obj->ID == Obj::TOWN); } +bool ViewAirMechanics::showTerrain(const int32_t spellLevel) const +{ + return false; +} + ///ViewEarthMechanics ViewEarthMechanics::ViewEarthMechanics(const CSpell * s): ViewMechanics(s) @@ -613,5 +619,9 @@ bool ViewEarthMechanics::filterObject(const CGObjectInstance * obj, const int32_ return (obj->ID == Obj::RESOURCE) || (spellLevel > 1 && obj->ID == Obj::MINE); } +bool ViewEarthMechanics::showTerrain(const int32_t spellLevel) const +{ + return spellLevel > 2; +} VCMI_LIB_NAMESPACE_END diff --git a/lib/spells/AdventureSpellMechanics.h b/lib/spells/AdventureSpellMechanics.h index 9b6a5cf63..8fd6ac6c4 100644 --- a/lib/spells/AdventureSpellMechanics.h +++ b/lib/spells/AdventureSpellMechanics.h @@ -82,6 +82,7 @@ public: protected: ESpellCastResult applyAdventureEffects(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const override; virtual bool filterObject(const CGObjectInstance * obj, const int32_t spellLevel) const = 0; + virtual bool showTerrain(const int32_t spellLevel) const = 0; }; class DLL_LINKAGE ViewAirMechanics : public ViewMechanics @@ -90,6 +91,7 @@ public: ViewAirMechanics(const CSpell * s); protected: bool filterObject(const CGObjectInstance * obj, const int32_t spellLevel) const override; + bool showTerrain(const int32_t spellLevel) const override; }; class DLL_LINKAGE ViewEarthMechanics : public ViewMechanics @@ -98,6 +100,7 @@ public: ViewEarthMechanics(const CSpell * s); protected: bool filterObject(const CGObjectInstance * obj, const int32_t spellLevel) const override; + bool showTerrain(const int32_t spellLevel) const override; };