1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-08-13 19:54:17 +02:00

Merge pull request #176 from vmarkovtsev/issue/2160

Fix 2160 dismissing a VIP hero.
This commit is contained in:
Alexander Shishkin
2016-01-27 18:28:57 +03:00
5 changed files with 76 additions and 41 deletions

View File

@@ -28,6 +28,7 @@
#include "../lib/CHeroHandler.h" #include "../lib/CHeroHandler.h"
#include "../lib/mapObjects/CGHeroInstance.h" #include "../lib/mapObjects/CGHeroInstance.h"
#include "../lib/NetPacksBase.h" #include "../lib/NetPacksBase.h"
#include "../mapHandler.h"
/* /*
* CHeroWindow.cpp, part of VCMI engine * 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) if(!LOCPLINT->cb->howManyTowns() && LOCPLINT->cb->howManyHeroes() == 1)
noDismiss = true; noDismiss = true;
if(curHero->isMissionCritical())
noDismiss = true;
dismissButton->block(!!curHero->visitedTown || noDismiss); dismissButton->block(!!curHero->visitedTown || noDismiss);
if(curHero->getSecSkillLevel(SecondarySkill::TACTICS) == 0) if(curHero->getSecSkillLevel(SecondarySkill::TACTICS) == 0)
@@ -343,10 +347,10 @@ void CHeroWindow::commanderWindow()
void CHeroWindow::showAll(SDL_Surface * to) void CHeroWindow::showAll(SDL_Surface * to)
{ {
CIntObject::showAll(to); CIntObject::showAll(to);
//printing hero's name //printing hero's name
printAtMiddleLoc(curHero->name, 190, 38, FONT_BIG, Colors::YELLOW, to); printAtMiddleLoc(curHero->name, 190, 38, FONT_BIG, Colors::YELLOW, to);
//printing hero's level //printing hero's level
std::string secondLine= CGI->generaltexth->allTexts[342]; std::string secondLine= CGI->generaltexth->allTexts[342];
boost::algorithm::replace_first(secondLine,"%d",boost::lexical_cast<std::string>(curHero->level)); 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; primarySkill << primSkillAreas[m]->bonusValue;
printAtMiddleLoc(primarySkill.str(), 53 + 70 * m, 166, FONT_SMALL, Colors::WHITE, to); printAtMiddleLoc(primarySkill.str(), 53 + 70 * m, 166, FONT_SMALL, Colors::WHITE, to);
} }
//secondary skills //secondary skills
for(size_t v=0; v<std::min(secSkillAreas.size(), curHero->secSkills.size()); ++v) 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->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); printAtLoc(CGI->generaltexth->skillName[curHero->secSkills[v].first], (v%2) ? 212 : 68, 300 + 48 * (v/2), FONT_SMALL, Colors::WHITE, to);
} }
//printing special ability //printing special ability
printAtLoc(curHero->type->specName, 69, 205, FONT_SMALL, Colors::WHITE, to); printAtLoc(curHero->type->specName, 69, 205, FONT_SMALL, Colors::WHITE, to);
std::ostringstream expstr; std::ostringstream expstr;

View File

@@ -66,6 +66,10 @@ const PlayerState * CGameInfoCallback::getPlayer(PlayerColor color, bool verbose
{ {
//funtion written from scratch since it's accessed A LOT by AI //funtion written from scratch since it's accessed A LOT by AI
if(!color.isValidPlayer())
{
return nullptr;
}
auto player = gs->players.find(color); auto player = gs->players.find(color);
if (player != gs->players.end()) if (player != gs->players.end())
{ {
@@ -229,13 +233,13 @@ bool CGameInfoCallback::getTownInfo(const CGObjectInstance * town, InfoAboutTown
{ {
if(!detailed && nullptr != selectedObject) if(!detailed && nullptr != selectedObject)
{ {
const CGHeroInstance * selectedHero = dynamic_cast<const CGHeroInstance *>(selectedObject); const CGHeroInstance * selectedHero = dynamic_cast<const CGHeroInstance *>(selectedObject);
if(nullptr != selectedHero) if(nullptr != selectedHero)
detailed = selectedHero->hasVisions(town, 1); detailed = selectedHero->hasVisions(town, 1);
} }
dest.initFromTown(static_cast<const CGTownInstance *>(town), detailed); dest.initFromTown(static_cast<const CGTownInstance *>(town), detailed);
} }
else if(town->ID == Obj::GARRISON || town->ID == Obj::GARRISON2) else if(town->ID == Obj::GARRISON || town->ID == Obj::GARRISON2)
dest.initFromArmy(static_cast<const CArmedInstance *>(town), detailed); dest.initFromArmy(static_cast<const CArmedInstance *>(town), detailed);
else 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); ERROR_RET_VAL_IF(!isVisible(h->getPosition(false)), "That hero is not visible!", false);
bool accessFlag = hasAccess(h->tempOwner); bool accessFlag = hasAccess(h->tempOwner);
if(!accessFlag && nullptr != selectedObject) if(!accessFlag && nullptr != selectedObject)
{ {
const CGHeroInstance * selectedHero = dynamic_cast<const CGHeroInstance *>(selectedObject); const CGHeroInstance * selectedHero = dynamic_cast<const CGHeroInstance *>(selectedObject);
if(nullptr != selectedHero) if(nullptr != selectedHero)
accessFlag = selectedHero->hasVisions(hero, 1); accessFlag = selectedHero->hasVisions(hero, 1);
} }
dest.initFromHero(h, accessFlag); dest.initFromHero(h, accessFlag);
//DISGUISED bonus implementation //DISGUISED bonus implementation
if(getPlayerRelations(getLocalPlayer(), hero->tempOwner) == PlayerRelations::ENEMIES) if(getPlayerRelations(getLocalPlayer(), hero->tempOwner) == PlayerRelations::ENEMIES)
{ {
//todo: bonus cashing //todo: bonus cashing
int disguiseLevel = h->valOfBonuses(Selector::typeSubtype(Bonus::DISGUISED, 0)); int disguiseLevel = h->valOfBonuses(Selector::typeSubtype(Bonus::DISGUISED, 0));
auto doBasicDisguise = [disguiseLevel](InfoAboutHero & info) auto doBasicDisguise = [disguiseLevel](InfoAboutHero & info)
{ {
int maxAIValue = 0; int maxAIValue = 0;
const CCreature * mostStrong = nullptr; const CCreature * mostStrong = nullptr;
for(auto & elem : info.army) for(auto & elem : info.army)
{ {
if(elem.second.type->AIValue > maxAIValue) if(elem.second.type->AIValue > maxAIValue)
@@ -298,7 +302,7 @@ bool CGameInfoCallback::getHeroInfo(const CGObjectInstance * hero, InfoAboutHero
mostStrong = elem.second.type; mostStrong = elem.second.type;
} }
} }
if(nullptr == mostStrong)//just in case if(nullptr == mostStrong)//just in case
logGlobal->errorStream() << "CGameInfoCallback::getHeroInfo: Unable to select most strong stack" << disguiseLevel; logGlobal->errorStream() << "CGameInfoCallback::getHeroInfo: Unable to select most strong stack" << disguiseLevel;
else else
@@ -307,25 +311,25 @@ bool CGameInfoCallback::getHeroInfo(const CGObjectInstance * hero, InfoAboutHero
elem.second.type = mostStrong; elem.second.type = mostStrong;
} }
}; };
auto doAdvancedDisguise = [accessFlag, &doBasicDisguise](InfoAboutHero & info) auto doAdvancedDisguise = [accessFlag, &doBasicDisguise](InfoAboutHero & info)
{ {
doBasicDisguise(info); doBasicDisguise(info);
for(auto & elem : info.army) for(auto & elem : info.army)
elem.second.count = 0; elem.second.count = 0;
}; };
auto doExpertDisguise = [this,h](InfoAboutHero & info) auto doExpertDisguise = [this,h](InfoAboutHero & info)
{ {
for(auto & elem : info.army) for(auto & elem : info.army)
elem.second.count = 0; elem.second.count = 0;
const auto factionIndex = getStartInfo(false)->playerInfos.at(h->tempOwner).castle; const auto factionIndex = getStartInfo(false)->playerInfos.at(h->tempOwner).castle;
int maxAIValue = 0; int maxAIValue = 0;
const CCreature * mostStrong = nullptr; const CCreature * mostStrong = nullptr;
for(auto creature : VLC->creh->creatures) for(auto creature : VLC->creh->creatures)
{ {
if(creature->faction == factionIndex && creature->AIValue > maxAIValue) if(creature->faction == factionIndex && creature->AIValue > maxAIValue)
@@ -334,35 +338,35 @@ bool CGameInfoCallback::getHeroInfo(const CGObjectInstance * hero, InfoAboutHero
mostStrong = creature; mostStrong = creature;
} }
} }
if(nullptr != mostStrong) //possible, faction may have no creatures at all if(nullptr != mostStrong) //possible, faction may have no creatures at all
for(auto & elem : info.army) for(auto & elem : info.army)
elem.second.type = mostStrong; elem.second.type = mostStrong;
}; };
switch (disguiseLevel) switch (disguiseLevel)
{ {
case 0: case 0:
//no bonus at all - do nothing //no bonus at all - do nothing
break; break;
case 1: case 1:
doBasicDisguise(dest); doBasicDisguise(dest);
break; break;
case 2: case 2:
doAdvancedDisguise(dest); doAdvancedDisguise(dest);
break; break;
case 3: case 3:
doExpertDisguise(dest); doExpertDisguise(dest);
break; break;
default: default:
//invalid value //invalid value
logGlobal->errorStream() << "CGameInfoCallback::getHeroInfo: Invalid DISGUISED bonus value " << disguiseLevel; logGlobal->errorStream() << "CGameInfoCallback::getHeroInfo: Invalid DISGUISED bonus value " << disguiseLevel;
break; break;
} }
} }
return true; 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]); boost::multi_array<TerrainTile*, 3> tileArray(boost::extents[width][height][levels]);
for (size_t x = 0; x < width; x++) for (size_t x = 0; x < width; x++)
for (size_t y = 0; y < height; y++) for (size_t y = 0; y < height; y++)
for (size_t z = 0; z < levels; z++) 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); sob.val = static_cast<ui32>(val);
commitPackage(&sob); commitPackage(&sob);
} }

View File

@@ -2268,7 +2268,7 @@ EVictoryLossCheckResult CGameState::checkForVictoryAndLoss(PlayerColor player) c
for (const TriggeredEvent & event : map->triggeredEvents) for (const TriggeredEvent & event : map->triggeredEvents)
{ {
if ((event.trigger.test(evaluateEvent))) if (event.trigger.test(evaluateEvent))
{ {
if (event.effect.type == EventEffect::VICTORY) if (event.effect.type == EventEffect::VICTORY)
return EVictoryLossCheckResult::victory(event.onFulfill, event.effect.toOtherMessage); return EVictoryLossCheckResult::victory(event.onFulfill, event.effect.toOtherMessage);
@@ -2285,7 +2285,7 @@ EVictoryLossCheckResult CGameState::checkForVictoryAndLoss(PlayerColor player) c
return EVictoryLossCheckResult(); 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); const PlayerState *p = CGameInfoCallback::getPlayer(player);
switch (condition.condition) switch (condition.condition)

View File

@@ -23,6 +23,7 @@
#include "../CCreatureHandler.h" #include "../CCreatureHandler.h"
#include "../BattleState.h" #include "../BattleState.h"
#include "../CTownHandler.h" #include "../CTownHandler.h"
#include "../mapping/CMap.h"
#include "CGTownInstance.h" #include "CGTownInstance.h"
///helpers ///helpers
@@ -1454,3 +1455,27 @@ bool CGHeroInstance::hasVisions(const CGObjectInstance * target, const int subty
return (distance < visionsRange) && (target->pos.z == pos.z); 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;
}

View File

@@ -20,6 +20,7 @@
class CHero; class CHero;
class CGBoat; class CGBoat;
class CGTownInstance; class CGTownInstance;
class CMap;
struct TerrainTile; struct TerrainTile;
struct TurnInfo; struct TurnInfo;
@@ -211,6 +212,8 @@ public:
void updateSkill(SecondarySkill which, int val); void updateSkill(SecondarySkill which, int val);
bool hasVisions(const CGObjectInstance * target, const int subtype) const; bool hasVisions(const CGObjectInstance * target, const int subtype) const;
/// If this hero perishes, the scenario is failed
bool isMissionCritical() const;
CGHeroInstance(); CGHeroInstance();
virtual ~CGHeroInstance(); virtual ~CGHeroInstance();