mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-12 02:28:11 +02:00
Fix 2160 dismissing a VIP hero
This commit is contained in:
parent
4483c45905
commit
9f3313524e
@ -28,6 +28,7 @@
|
||||
#include "../lib/CHeroHandler.h"
|
||||
#include "../lib/mapObjects/CGHeroInstance.h"
|
||||
#include "../lib/NetPacksBase.h"
|
||||
#include "../mapHandler.h"
|
||||
|
||||
/*
|
||||
* CHeroWindow.cpp, part of VCMI engine
|
||||
@ -275,6 +276,9 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded /*= fals
|
||||
if(!LOCPLINT->cb->howManyTowns() && LOCPLINT->cb->howManyHeroes() == 1)
|
||||
noDismiss = true;
|
||||
|
||||
if(curHero->isMissionCritical())
|
||||
noDismiss = true;
|
||||
|
||||
dismissButton->block(!!curHero->visitedTown || noDismiss);
|
||||
|
||||
if(curHero->getSecSkillLevel(SecondarySkill::TACTICS) == 0)
|
||||
@ -343,10 +347,10 @@ void CHeroWindow::commanderWindow()
|
||||
void CHeroWindow::showAll(SDL_Surface * to)
|
||||
{
|
||||
CIntObject::showAll(to);
|
||||
|
||||
|
||||
//printing hero's name
|
||||
printAtMiddleLoc(curHero->name, 190, 38, FONT_BIG, Colors::YELLOW, to);
|
||||
|
||||
|
||||
//printing hero's level
|
||||
std::string secondLine= CGI->generaltexth->allTexts[342];
|
||||
boost::algorithm::replace_first(secondLine,"%d",boost::lexical_cast<std::string>(curHero->level));
|
||||
@ -360,14 +364,14 @@ void CHeroWindow::showAll(SDL_Surface * to)
|
||||
primarySkill << primSkillAreas[m]->bonusValue;
|
||||
printAtMiddleLoc(primarySkill.str(), 53 + 70 * m, 166, FONT_SMALL, Colors::WHITE, to);
|
||||
}
|
||||
|
||||
|
||||
//secondary skills
|
||||
for(size_t v=0; v<std::min(secSkillAreas.size(), curHero->secSkills.size()); ++v)
|
||||
{
|
||||
printAtLoc(CGI->generaltexth->levels[curHero->secSkills[v].second-1], (v%2) ? 212 : 68, 280 + 48 * (v/2), FONT_SMALL, Colors::WHITE, to);
|
||||
printAtLoc(CGI->generaltexth->skillName[curHero->secSkills[v].first], (v%2) ? 212 : 68, 300 + 48 * (v/2), FONT_SMALL, Colors::WHITE, to);
|
||||
}
|
||||
|
||||
|
||||
//printing special ability
|
||||
printAtLoc(curHero->type->specName, 69, 205, FONT_SMALL, Colors::WHITE, to);
|
||||
std::ostringstream expstr;
|
||||
|
@ -66,6 +66,10 @@ const PlayerState * CGameInfoCallback::getPlayer(PlayerColor color, bool verbose
|
||||
{
|
||||
//funtion written from scratch since it's accessed A LOT by AI
|
||||
|
||||
if(!color.isValidPlayer())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
auto player = gs->players.find(color);
|
||||
if (player != gs->players.end())
|
||||
{
|
||||
@ -229,13 +233,13 @@ bool CGameInfoCallback::getTownInfo(const CGObjectInstance * town, InfoAboutTown
|
||||
{
|
||||
if(!detailed && nullptr != selectedObject)
|
||||
{
|
||||
const CGHeroInstance * selectedHero = dynamic_cast<const CGHeroInstance *>(selectedObject);
|
||||
const CGHeroInstance * selectedHero = dynamic_cast<const CGHeroInstance *>(selectedObject);
|
||||
if(nullptr != selectedHero)
|
||||
detailed = selectedHero->hasVisions(town, 1);
|
||||
detailed = selectedHero->hasVisions(town, 1);
|
||||
}
|
||||
|
||||
|
||||
dest.initFromTown(static_cast<const CGTownInstance *>(town), detailed);
|
||||
}
|
||||
}
|
||||
else if(town->ID == Obj::GARRISON || town->ID == Obj::GARRISON2)
|
||||
dest.initFromArmy(static_cast<const CArmedInstance *>(town), detailed);
|
||||
else
|
||||
@ -268,28 +272,28 @@ bool CGameInfoCallback::getHeroInfo(const CGObjectInstance * hero, InfoAboutHero
|
||||
ERROR_RET_VAL_IF(!isVisible(h->getPosition(false)), "That hero is not visible!", false);
|
||||
|
||||
bool accessFlag = hasAccess(h->tempOwner);
|
||||
|
||||
|
||||
if(!accessFlag && nullptr != selectedObject)
|
||||
{
|
||||
const CGHeroInstance * selectedHero = dynamic_cast<const CGHeroInstance *>(selectedObject);
|
||||
const CGHeroInstance * selectedHero = dynamic_cast<const CGHeroInstance *>(selectedObject);
|
||||
if(nullptr != selectedHero)
|
||||
accessFlag = selectedHero->hasVisions(hero, 1);
|
||||
accessFlag = selectedHero->hasVisions(hero, 1);
|
||||
}
|
||||
|
||||
|
||||
dest.initFromHero(h, accessFlag);
|
||||
|
||||
|
||||
//DISGUISED bonus implementation
|
||||
|
||||
|
||||
if(getPlayerRelations(getLocalPlayer(), hero->tempOwner) == PlayerRelations::ENEMIES)
|
||||
{
|
||||
//todo: bonus cashing
|
||||
//todo: bonus cashing
|
||||
int disguiseLevel = h->valOfBonuses(Selector::typeSubtype(Bonus::DISGUISED, 0));
|
||||
|
||||
auto doBasicDisguise = [disguiseLevel](InfoAboutHero & info)
|
||||
|
||||
auto doBasicDisguise = [disguiseLevel](InfoAboutHero & info)
|
||||
{
|
||||
int maxAIValue = 0;
|
||||
const CCreature * mostStrong = nullptr;
|
||||
|
||||
|
||||
for(auto & elem : info.army)
|
||||
{
|
||||
if(elem.second.type->AIValue > maxAIValue)
|
||||
@ -298,7 +302,7 @@ bool CGameInfoCallback::getHeroInfo(const CGObjectInstance * hero, InfoAboutHero
|
||||
mostStrong = elem.second.type;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(nullptr == mostStrong)//just in case
|
||||
logGlobal->errorStream() << "CGameInfoCallback::getHeroInfo: Unable to select most strong stack" << disguiseLevel;
|
||||
else
|
||||
@ -307,25 +311,25 @@ bool CGameInfoCallback::getHeroInfo(const CGObjectInstance * hero, InfoAboutHero
|
||||
elem.second.type = mostStrong;
|
||||
}
|
||||
};
|
||||
|
||||
auto doAdvancedDisguise = [accessFlag, &doBasicDisguise](InfoAboutHero & info)
|
||||
|
||||
auto doAdvancedDisguise = [accessFlag, &doBasicDisguise](InfoAboutHero & info)
|
||||
{
|
||||
doBasicDisguise(info);
|
||||
|
||||
|
||||
for(auto & elem : info.army)
|
||||
elem.second.count = 0;
|
||||
};
|
||||
|
||||
auto doExpertDisguise = [this,h](InfoAboutHero & info)
|
||||
|
||||
auto doExpertDisguise = [this,h](InfoAboutHero & info)
|
||||
{
|
||||
for(auto & elem : info.army)
|
||||
elem.second.count = 0;
|
||||
|
||||
|
||||
const auto factionIndex = getStartInfo(false)->playerInfos.at(h->tempOwner).castle;
|
||||
|
||||
|
||||
int maxAIValue = 0;
|
||||
const CCreature * mostStrong = nullptr;
|
||||
|
||||
|
||||
for(auto creature : VLC->creh->creatures)
|
||||
{
|
||||
if(creature->faction == factionIndex && creature->AIValue > maxAIValue)
|
||||
@ -334,35 +338,35 @@ bool CGameInfoCallback::getHeroInfo(const CGObjectInstance * hero, InfoAboutHero
|
||||
mostStrong = creature;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(nullptr != mostStrong) //possible, faction may have no creatures at all
|
||||
for(auto & elem : info.army)
|
||||
elem.second.type = mostStrong;
|
||||
};
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
switch (disguiseLevel)
|
||||
{
|
||||
case 0:
|
||||
//no bonus at all - do nothing
|
||||
break;
|
||||
break;
|
||||
case 1:
|
||||
doBasicDisguise(dest);
|
||||
break;
|
||||
break;
|
||||
case 2:
|
||||
doAdvancedDisguise(dest);
|
||||
break;
|
||||
break;
|
||||
case 3:
|
||||
doExpertDisguise(dest);
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
//invalid value
|
||||
logGlobal->errorStream() << "CGameInfoCallback::getHeroInfo: Invalid DISGUISED bonus value " << disguiseLevel;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -486,7 +490,7 @@ std::shared_ptr<boost::multi_array<TerrainTile*, 3>> CGameInfoCallback::getAllVi
|
||||
|
||||
|
||||
boost::multi_array<TerrainTile*, 3> tileArray(boost::extents[width][height][levels]);
|
||||
|
||||
|
||||
for (size_t x = 0; x < width; x++)
|
||||
for (size_t y = 0; y < height; y++)
|
||||
for (size_t z = 0; z < levels; z++)
|
||||
@ -964,4 +968,3 @@ void IGameEventRealizer::setObjProperty(ObjectInstanceID objid, int prop, si64 v
|
||||
sob.val = static_cast<ui32>(val);
|
||||
commitPackage(&sob);
|
||||
}
|
||||
|
||||
|
@ -2268,7 +2268,7 @@ EVictoryLossCheckResult CGameState::checkForVictoryAndLoss(PlayerColor player) c
|
||||
|
||||
for (const TriggeredEvent & event : map->triggeredEvents)
|
||||
{
|
||||
if ((event.trigger.test(evaluateEvent)))
|
||||
if (event.trigger.test(evaluateEvent))
|
||||
{
|
||||
if (event.effect.type == EventEffect::VICTORY)
|
||||
return EVictoryLossCheckResult::victory(event.onFulfill, event.effect.toOtherMessage);
|
||||
@ -2285,7 +2285,7 @@ EVictoryLossCheckResult CGameState::checkForVictoryAndLoss(PlayerColor player) c
|
||||
return EVictoryLossCheckResult();
|
||||
}
|
||||
|
||||
bool CGameState::checkForVictory( PlayerColor player, const EventCondition & condition ) const
|
||||
bool CGameState::checkForVictory(PlayerColor player, const EventCondition & condition) const
|
||||
{
|
||||
const PlayerState *p = CGameInfoCallback::getPlayer(player);
|
||||
switch (condition.condition)
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "../CCreatureHandler.h"
|
||||
#include "../BattleState.h"
|
||||
#include "../CTownHandler.h"
|
||||
#include "../mapping/CMap.h"
|
||||
#include "CGTownInstance.h"
|
||||
|
||||
///helpers
|
||||
@ -1454,3 +1455,27 @@ bool CGHeroInstance::hasVisions(const CGObjectInstance * target, const int subty
|
||||
|
||||
return (distance < visionsRange) && (target->pos.z == pos.z);
|
||||
}
|
||||
|
||||
bool CGHeroInstance::isMissionCritical() const
|
||||
{
|
||||
for(const TriggeredEvent & event : IObjectInterface::cb->getMapHeader()->triggeredEvents)
|
||||
{
|
||||
if(event.trigger.test([&](const EventCondition & condition)
|
||||
{
|
||||
if (condition.condition == EventCondition::CONTROL && condition.object)
|
||||
{
|
||||
auto hero = dynamic_cast<const CGHeroInstance*>(condition.object);
|
||||
return (hero != this);
|
||||
}
|
||||
else if(condition.condition == EventCondition::IS_HUMAN)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -20,6 +20,7 @@
|
||||
class CHero;
|
||||
class CGBoat;
|
||||
class CGTownInstance;
|
||||
class CMap;
|
||||
struct TerrainTile;
|
||||
struct TurnInfo;
|
||||
|
||||
@ -211,6 +212,8 @@ public:
|
||||
void updateSkill(SecondarySkill which, int val);
|
||||
|
||||
bool hasVisions(const CGObjectInstance * target, const int subtype) const;
|
||||
/// If this hero perishes, the scenario is failed
|
||||
bool isMissionCritical() const;
|
||||
|
||||
CGHeroInstance();
|
||||
virtual ~CGHeroInstance();
|
||||
|
Loading…
Reference in New Issue
Block a user