diff --git a/client/windows/InfoWindows.cpp b/client/windows/InfoWindows.cpp index ffafc8e38..dcc6a3137 100644 --- a/client/windows/InfoWindows.cpp +++ b/client/windows/InfoWindows.cpp @@ -411,7 +411,7 @@ CInfoBoxPopup::CInfoBoxPopup(Point position, const CGTownInstance * town): CWindowObject(RCLICK_POPUP | PLAYER_COLORED, "TOWNQVBK", toScreen(position)) { InfoAboutTown iah; - LOCPLINT->cb->getTownInfo(town, iah); + LOCPLINT->cb->getTownInfo(town, iah, adventureInt->selection); //todo: should this be nearest hero? OBJ_CONSTRUCTION_CAPTURING_ALL; new CTownTooltip(Point(9, 10), iah); @@ -421,7 +421,7 @@ CInfoBoxPopup::CInfoBoxPopup(Point position, const CGHeroInstance * hero): CWindowObject(RCLICK_POPUP | PLAYER_COLORED, "HEROQVBK", toScreen(position)) { InfoAboutHero iah; - LOCPLINT->cb->getHeroInfo(hero, iah); + LOCPLINT->cb->getHeroInfo(hero, iah, adventureInt->selection);//todo: should this be nearest hero? OBJ_CONSTRUCTION_CAPTURING_ALL; new CHeroTooltip(Point(9, 10), iah); diff --git a/config/spells/adventure.json b/config/spells/adventure.json index 3aef7c4cc..f6614eb3c 100644 --- a/config/spells/adventure.json +++ b/config/spells/adventure.json @@ -55,13 +55,35 @@ "effects" : { "visionsMonsters" : { "val" : 2 + }, + "visionsHeroes" :{ + "type" : "VISIONS", + "subtype" : 1, + "duration" : "ONE_DAY", + "val" : 2, + "valueType" : "INDEPENDENT_MAX" } + } }, "expert":{ "effects" : { "visionsMonsters" : { "val" : 3 + }, + "visionsHeroes" :{ + "type" : "VISIONS", + "subtype" : 1, + "duration" : "ONE_DAY", + "val" : 3, + "valueType" : "INDEPENDENT_MAX" + }, + "visionsTowns" :{ + "type" : "VISIONS", + "subtype" : 2, + "duration" : "ONE_DAY", + "val" : 3, + "valueType" : "INDEPENDENT_MAX" } } } diff --git a/lib/CGameInfoCallback.cpp b/lib/CGameInfoCallback.cpp index fe3ce7e99..da84f8642 100644 --- a/lib/CGameInfoCallback.cpp +++ b/lib/CGameInfoCallback.cpp @@ -201,14 +201,23 @@ int CGameInfoCallback::howManyTowns(PlayerColor Player) const return gs->players[Player].towns.size(); } -bool CGameInfoCallback::getTownInfo( const CGObjectInstance *town, InfoAboutTown &dest ) const +bool CGameInfoCallback::getTownInfo(const CGObjectInstance * town, InfoAboutTown & dest, const CGObjectInstance * selectedObject/* = nullptr*/) const { ERROR_RET_VAL_IF(!isVisible(town, player), "Town is not visible!", false); //it's not a town or it's not visible for layer bool detailed = hasAccess(town->tempOwner); //TODO vision support if(town->ID == Obj::TOWN) + { + if(!detailed && nullptr != selectedObject) + { + const CGHeroInstance * selectedHero = dynamic_cast(selectedObject); + if(nullptr != selectedHero) + detailed = selectedHero->hasVisions(town, 1); + } + dest.initFromTown(static_cast(town), detailed); + } else if(town->ID == Obj::GARRISON || town->ID == Obj::GARRISON2) dest.initFromArmy(static_cast(town), detailed); else @@ -233,15 +242,23 @@ std::vector CGameInfoCallback::getGuardingCreatures (in return ret; } -bool CGameInfoCallback::getHeroInfo( const CGObjectInstance *hero, InfoAboutHero &dest ) const +bool CGameInfoCallback::getHeroInfo(const CGObjectInstance * hero, InfoAboutHero & dest, const CGObjectInstance * selectedObject/* = nullptr*/) const { const CGHeroInstance *h = dynamic_cast(hero); ERROR_RET_VAL_IF(!h, "That's not a hero!", false); ERROR_RET_VAL_IF(!isVisible(h->getPosition(false)), "That hero is not visible!", false); - //TODO vision support - dest.initFromHero(h, hasAccess(h->tempOwner)); + bool accessFlag = hasAccess(h->tempOwner); + + if(!accessFlag && nullptr != selectedObject) + { + const CGHeroInstance * selectedHero = dynamic_cast(selectedObject); + if(nullptr != selectedHero) + accessFlag = selectedHero->hasVisions(hero, 1); + } + + dest.initFromHero(h, accessFlag); return true; } diff --git a/lib/CGameInfoCallback.h b/lib/CGameInfoCallback.h index 1daf4fb50..8a5c3689e 100644 --- a/lib/CGameInfoCallback.h +++ b/lib/CGameInfoCallback.h @@ -69,7 +69,7 @@ public: const CGHeroInstance* getHero(ObjectInstanceID objid) const; const CGHeroInstance* getHeroWithSubid(int subid) const; int getHeroCount(PlayerColor player, bool includeGarrisoned) const; - bool getHeroInfo(const CGObjectInstance *hero, InfoAboutHero &dest) const; + bool getHeroInfo(const CGObjectInstance * hero, InfoAboutHero & dest, const CGObjectInstance * selectedObject = nullptr) const; int getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const; //when called during battle, takes into account creatures' spell cost reduction int estimateSpellDamage(const CSpell * sp, const CGHeroInstance * hero) const; //estimates damage of given spell; returns 0 if spell causes no dmg const CArtifactInstance * getArtInstance(ArtifactInstanceID aid) const; @@ -99,7 +99,7 @@ public: std::vector getAvailableHeroes(const CGObjectInstance * townOrTavern) const; //heroes that can be recruited std::string getTavernGossip(const CGObjectInstance * townOrTavern) const; EBuildingState::EBuildingState canBuildStructure(const CGTownInstance *t, BuildingID ID);//// 0 - no more than one capitol, 1 - lack of water, 2 - forbidden, 3 - Add another level to Mage Guild, 4 - already built, 5 - cannot build, 6 - cannot afford, 7 - build, 8 - lack of requirements - virtual bool getTownInfo(const CGObjectInstance *town, InfoAboutTown &dest) const; + virtual bool getTownInfo(const CGObjectInstance * town, InfoAboutTown & dest, const CGObjectInstance * selectedObject = nullptr) const; const CTown *getNativeTown(PlayerColor color) const; //from gs diff --git a/lib/mapObjects/CGHeroInstance.cpp b/lib/mapObjects/CGHeroInstance.cpp index b30d3810e..8f0f2db66 100644 --- a/lib/mapObjects/CGHeroInstance.cpp +++ b/lib/mapObjects/CGHeroInstance.cpp @@ -1343,3 +1343,24 @@ void CGHeroInstance::levelUpAutomatically() levelUp(proposedSecondarySkills); } } + +bool CGHeroInstance::hasVisions(const CGObjectInstance * target, const int subtype) const +{ + //VISIONS spell support + + const std::string cached = boost::to_string((boost::format("type_%d__subtype_%d") % Bonus::VISIONS % subtype)); + + const int visionsMultiplier = valOfBonuses(Selector::typeSubtype(Bonus::VISIONS,subtype), cached); + + int visionsRange = visionsMultiplier * getPrimSkillLevel(PrimarySkill::SPELL_POWER); + + if (visionsMultiplier > 0) + vstd::amax(visionsRange, 3); //minimum range is 3 tiles, but only if VISIONS bonus present + + const int distance = target->pos.dist2d(getPosition(false)); + + logGlobal->debug(boost::to_string(boost::format("Visions: dist %d, mult %d, range %d") % distance % visionsMultiplier % visionsRange)); + + return (distance < visionsRange) && (target->pos.z == pos.z); +} + diff --git a/lib/mapObjects/CGHeroInstance.h b/lib/mapObjects/CGHeroInstance.h index 69c65cd06..eb8723a91 100644 --- a/lib/mapObjects/CGHeroInstance.h +++ b/lib/mapObjects/CGHeroInstance.h @@ -193,6 +193,8 @@ public: void Updatespecialty(); void recreateSecondarySkillsBonuses(); void updateSkill(SecondarySkill which, int val); + + bool hasVisions(const CGObjectInstance * target, const int subtype) const; CGHeroInstance(); virtual ~CGHeroInstance(); diff --git a/lib/mapObjects/MiscObjects.cpp b/lib/mapObjects/MiscObjects.cpp index 5a3d7bf06..e67e3a372 100644 --- a/lib/mapObjects/MiscObjects.cpp +++ b/lib/mapObjects/MiscObjects.cpp @@ -101,22 +101,8 @@ std::string CGCreature::getHoverText(PlayerColor player) const std::string CGCreature::getHoverText(const CGHeroInstance * hero) const { - //VISIONS spell support - - static const std::string cached = boost::to_string((boost::format("type_%d__subtype_0") % Bonus::VISIONS)); - std::string hoverName; - - const int visionsMultiplier = hero->valOfBonuses(Selector::typeSubtype(Bonus::VISIONS,0), cached); - - int visionsRadius = visionsMultiplier * hero->getPrimSkillLevel(PrimarySkill::SPELL_POWER); - - if (visionsMultiplier > 0) - vstd::amin(visionsRadius, 3); //minimum range is 3 tiles, but only if VISIONS bonus present - - const bool inVisionsRange = (pos.dist2d(hero->pos) < visionsRadius) && (pos.z == hero->pos.z); - - if(inVisionsRange) + if(hero->hasVisions(this, 0)) { MetaString ms; ms << stacks.begin()->second->count;