1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

Merge pull request #2005 from IvanSavenko/advmap_refactor

Refactoring of adventure map interface
This commit is contained in:
Ivan Savenko 2023-04-24 17:19:22 +03:00 committed by GitHub
commit 48abf46824
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 1158 additions and 1135 deletions

View File

@ -256,7 +256,7 @@ void AIGateway::heroVisitsTown(const CGHeroInstance * hero, const CGTownInstance
NET_EVENT_HANDLER;
}
void AIGateway::tileHidden(const std::unordered_set<int3, ShashInt3> & pos)
void AIGateway::tileHidden(const std::unordered_set<int3> & pos)
{
LOG_TRACE(logAi);
NET_EVENT_HANDLER;
@ -264,7 +264,7 @@ void AIGateway::tileHidden(const std::unordered_set<int3, ShashInt3> & pos)
nullkiller->memory->removeInvisibleObjects(myCb.get());
}
void AIGateway::tileRevealed(const std::unordered_set<int3, ShashInt3> & pos)
void AIGateway::tileRevealed(const std::unordered_set<int3> & pos)
{
LOG_TRACE(logAi);
NET_EVENT_HANDLER;

View File

@ -127,7 +127,7 @@ public:
void heroMoved(const TryMoveHero & details, bool verbose = true) override;
void heroInGarrisonChange(const CGTownInstance * town) override;
void centerView(int3 pos, int focusTime) override;
void tileHidden(const std::unordered_set<int3, ShashInt3> & pos) override;
void tileHidden(const std::unordered_set<int3> & pos) override;
void artifactMoved(const ArtifactLocation & src, const ArtifactLocation & dst) override;
void artifactAssembled(const ArtifactLocation & al) override;
void showTavernWindow(const CGObjectInstance * townOrTavern) override;
@ -142,7 +142,7 @@ public:
void heroVisit(const CGHeroInstance * visitor, const CGObjectInstance * visitedObj, bool start) override;
void availableArtifactsChanged(const CGBlackMarket * bm = nullptr) override;
void heroVisitsTown(const CGHeroInstance * hero, const CGTownInstance * town) override;
void tileRevealed(const std::unordered_set<int3, ShashInt3> & pos) override;
void tileRevealed(const std::unordered_set<int3> & pos) override;
void heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2, QueryID query) override;
void heroPrimarySkillChanged(const CGHeroInstance * hero, int which, si64 val) override;
void showRecruitmentDialog(const CGDwelling * dwelling, const CArmedInstance * dst, int level) override;

View File

@ -268,7 +268,7 @@ void VCAI::heroVisitsTown(const CGHeroInstance * hero, const CGTownInstance * to
//moveCreaturesToHero(town);
}
void VCAI::tileHidden(const std::unordered_set<int3, ShashInt3> & pos)
void VCAI::tileHidden(const std::unordered_set<int3> & pos)
{
LOG_TRACE(logAi);
NET_EVENT_HANDLER;
@ -277,7 +277,7 @@ void VCAI::tileHidden(const std::unordered_set<int3, ShashInt3> & pos)
clearPathsInfo();
}
void VCAI::tileRevealed(const std::unordered_set<int3, ShashInt3> & pos)
void VCAI::tileRevealed(const std::unordered_set<int3> & pos)
{
LOG_TRACE(logAi);
NET_EVENT_HANDLER;

View File

@ -160,7 +160,7 @@ public:
void heroMoved(const TryMoveHero & details, bool verbose = true) override;
void heroInGarrisonChange(const CGTownInstance * town) override;
void centerView(int3 pos, int focusTime) override;
void tileHidden(const std::unordered_set<int3, ShashInt3> & pos) override;
void tileHidden(const std::unordered_set<int3> & pos) override;
void artifactMoved(const ArtifactLocation & src, const ArtifactLocation & dst) override;
void artifactAssembled(const ArtifactLocation & al) override;
void showTavernWindow(const CGObjectInstance * townOrTavern) override;
@ -175,7 +175,7 @@ public:
void heroVisit(const CGHeroInstance * visitor, const CGObjectInstance * visitedObj, bool start) override;
void availableArtifactsChanged(const CGBlackMarket * bm = nullptr) override;
void heroVisitsTown(const CGHeroInstance * hero, const CGTownInstance * town) override;
void tileRevealed(const std::unordered_set<int3, ShashInt3> & pos) override;
void tileRevealed(const std::unordered_set<int3> & pos) override;
void heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2, QueryID query) override;
void heroPrimarySkillChanged(const CGHeroInstance * hero, int which, si64 val) override;
void showRecruitmentDialog(const CGDwelling * dwelling, const CArmedInstance * dst, int level) override;

View File

@ -3,7 +3,7 @@ set(client_SRCS
../CCallback.cpp
adventureMap/CAdvMapPanel.cpp
adventureMap/CAdvMapInt.cpp
adventureMap/CAdventureMapInterface.cpp
adventureMap/CAdventureOptions.cpp
adventureMap/CInGameConsole.cpp
adventureMap/CInfoBar.cpp
@ -110,6 +110,7 @@ set(client_SRCS
CMT.cpp
CMusicHandler.cpp
CPlayerInterface.cpp
PlayerLocalState.cpp
CServerHandler.cpp
CVideoHandler.cpp
Client.cpp
@ -122,7 +123,7 @@ set(client_HEADERS
StdInc.h
adventureMap/CAdvMapPanel.h
adventureMap/CAdvMapInt.h
adventureMap/CAdventureMapInterface.h
adventureMap/CAdventureOptions.h
adventureMap/CInGameConsole.h
adventureMap/CInfoBar.h
@ -238,6 +239,7 @@ set(client_HEADERS
CMT.h
CMusicHandler.h
CPlayerInterface.h
PlayerLocalState.h
CServerHandler.h
CVideoHandler.h
Client.h

View File

@ -8,14 +8,14 @@
*
*/
#include "StdInc.h"
#include "CPlayerInterface.h"
#include <vcmi/Artifact.h>
#include "adventureMap/CAdvMapInt.h"
#include "adventureMap/CAdventureMapInterface.h"
#include "mapView/mapHandler.h"
#include "adventureMap/CList.h"
#include "adventureMap/CInfoBar.h"
#include "adventureMap/CMinimap.h"
#include "battle/BattleInterface.h"
#include "battle/BattleEffectsController.h"
#include "battle/BattleFieldController.h"
@ -26,12 +26,12 @@
#include "gui/CursorHandler.h"
#include "windows/CKingdomInterface.h"
#include "CGameInfo.h"
#include "PlayerLocalState.h"
#include "CMT.h"
#include "windows/CHeroWindow.h"
#include "windows/CCreatureWindow.h"
#include "windows/CQuestLog.h"
#include "windows/CPuzzleWindow.h"
#include "CPlayerInterface.h"
#include "widgets/CComponent.h"
#include "widgets/Buttons.h"
#include "windows/CTradeWindow.h"
@ -115,97 +115,8 @@ struct HeroObjectRetriever
}
};
HeroPathStorage::HeroPathStorage(CPlayerInterface & owner):
owner(owner)
{
}
void HeroPathStorage::setPath(const CGHeroInstance *h, const CGPath & path)
{
paths[h] = path;
}
const CGPath & HeroPathStorage::getPath(const CGHeroInstance *h) const
{
assert(hasPath(h));
return paths.at(h);
}
bool HeroPathStorage::hasPath(const CGHeroInstance *h) const
{
return paths.count(h) > 0;
}
bool HeroPathStorage::setPath(const CGHeroInstance *h, const int3 & destination)
{
CGPath path;
if (!owner.cb->getPathsInfo(h)->getPath(path, destination))
return false;
setPath(h, path);
return true;
}
void HeroPathStorage::removeLastNode(const CGHeroInstance *h)
{
assert(hasPath(h));
if (!hasPath(h))
return;
auto & path = paths[h];
path.nodes.pop_back();
if (path.nodes.size() < 2) //if it was the last one, remove entire path and path with only one tile is not a real path
erasePath(h);
}
void HeroPathStorage::erasePath(const CGHeroInstance *h)
{
paths.erase(h);
adventureInt->updateMoveHero(h, false);
}
void HeroPathStorage::verifyPath(const CGHeroInstance *h)
{
if (!hasPath(h))
return;
setPath(h, getPath(h).endPos());
}
template<typename Handler>
void HeroPathStorage::serialize(Handler & h, int version)
{
std::map<const CGHeroInstance *, int3> pathsMap; //hero -> dest
if (h.saving)
{
for (auto &p : paths)
{
if (p.second.nodes.size())
pathsMap[p.first] = p.second.endPos();
else
logGlobal->debug("%s has assigned an empty path! Ignoring it...", p.first->getNameTranslated());
}
h & pathsMap;
}
else
{
h & pathsMap;
if (owner.cb)
{
for (auto &p : pathsMap)
{
CGPath path;
owner.cb->getPathsInfo(p.first)->getPath(path, p.second);
paths[p.first] = path;
logGlobal->trace("Restored path for hero %s leading to %s with %d nodes", p.first->nodeName(), p.second.toString(), path.nodes.size());
}
}
}
}
CPlayerInterface::CPlayerInterface(PlayerColor Player):
paths(*this)
localState(std::make_unique<PlayerLocalState>(*this))
{
logGlobal->trace("\tHuman player interface for player %s being constructed", Player.getStr());
destinationTeleport = ObjectInstanceID();
@ -248,8 +159,53 @@ void CPlayerInterface::initGameInterface(std::shared_ptr<Environment> ENV, std::
initializeHeroTownList();
// always recreate advmap interface to avoid possible memory-corruption bugs
adventureInt.reset(new CAdvMapInt());
adventureInt.reset(new CAdventureMapInterface());
}
void CPlayerInterface::playerStartsTurn(PlayerColor player)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
if (!vstd::contains (GH.listInt, adventureInt))
{
// after map load - remove all active windows and replace them with adventure map
GH.popInts ((int)GH.listInt.size());
GH.pushInt (adventureInt);
}
// remove all dialogs that do not expect query answer
while (GH.listInt.front() != adventureInt && !dynamic_cast<CInfoWindow*>(GH.listInt.front().get()))
GH.popInts(1);
if (player != playerID && LOCPLINT == this)
{
waitWhileDialog();
adventureInt->onEnemyTurnStarted(player);
}
}
void CPlayerInterface::performAutosave()
{
std::string prefix = settings["session"]["saveprefix"].String();
int frequency = static_cast<int>(settings["general"]["saveFrequency"].Integer());
if(firstCall)
{
autosaveCount = getLastIndex(prefix + "Autosave_");
if(firstCall > 0) //new game, not loaded
{
int index = getLastIndex(prefix + "Newgame_");
index %= SAVES_COUNT;
cb->save("Saves/" + prefix + "Newgame_Autosave_" + std::to_string(index + 1));
}
firstCall = 0;
}
else if(frequency > 0 && cb->getDate() % frequency == 0)
{
LOCPLINT->cb->save("Saves/" + prefix + "Autosave_" + std::to_string(autosaveCount++ + 1));
autosaveCount %= 5;
}
}
void CPlayerInterface::yourTurn()
{
EVENT_HANDLER_CALLED_BY_CLIENT;
@ -258,38 +214,13 @@ void CPlayerInterface::yourTurn()
LOCPLINT = this;
GH.curInt = this;
adventureInt->selection = nullptr;
NotificationHandler::notify("Your turn");
std::string prefix = settings["session"]["saveprefix"].String();
int frequency = static_cast<int>(settings["general"]["saveFrequency"].Integer());
if (firstCall)
{
if(CSH->howManyPlayerInterfaces() == 1)
adventureInt->setPlayer(playerID);
autosaveCount = getLastIndex(prefix + "Autosave_");
if (firstCall > 0) //new game, not loaded
{
int index = getLastIndex(prefix + "Newgame_");
index %= SAVES_COUNT;
cb->save("Saves/" + prefix + "Newgame_Autosave_" + std::to_string(index + 1));
}
firstCall = 0;
}
else if(frequency > 0 && cb->getDate() % frequency == 0)
{
LOCPLINT->cb->save("Saves/" + prefix + "Autosave_" + std::to_string(autosaveCount++ + 1));
autosaveCount %= 5;
}
adventureInt->setPlayer(playerID);
performAutosave();
if (CSH->howManyPlayerInterfaces() > 1) //hot seat message
{
adventureInt->startHotSeatWait(playerID);
adventureInt->onHotseatWaitStarted(playerID);
makingTurn = true;
std::string msg = CGI->generaltexth->allTexts[13];
@ -301,13 +232,60 @@ void CPlayerInterface::yourTurn()
else
{
makingTurn = true;
adventureInt->startTurn();
adventureInt->onPlayerTurnStarted(playerID);
}
}
acceptTurn();
}
void CPlayerInterface::acceptTurn()
{
if (settings["session"]["autoSkip"].Bool())
{
while(CInfoWindow *iw = dynamic_cast<CInfoWindow *>(GH.topInt().get()))
iw->close();
}
if(CSH->howManyPlayerInterfaces() > 1)
{
waitWhileDialog(); // wait for player to accept turn in hot-seat mode
adventureInt->onPlayerTurnStarted(playerID);
}
// warn player if he has no town
if (cb->howManyTowns() == 0)
{
auto playerColor = *cb->getPlayerID();
std::vector<Component> components;
components.emplace_back(Component::EComponentType::FLAG, playerColor.getNum(), 0, 0);
MetaString text;
const auto & optDaysWithoutCastle = cb->getPlayerState(playerColor)->daysWithoutCastle;
if(optDaysWithoutCastle)
{
auto daysWithoutCastle = optDaysWithoutCastle.value();
if (daysWithoutCastle < 6)
{
text.addTxt(MetaString::ARRAY_TXT,128); //%s, you only have %d days left to capture a town or you will be banished from this land.
text.addReplacement(MetaString::COLOR, playerColor.getNum());
text.addReplacement(7 - daysWithoutCastle);
}
else if (daysWithoutCastle == 6)
{
text.addTxt(MetaString::ARRAY_TXT,129); //%s, this is your last day to capture a town or you will be banished from this land.
text.addReplacement(MetaString::COLOR, playerColor.getNum());
}
showInfoDialogAndWait(components, text);
}
else
logGlobal->warn("Player has no towns, but daysWithoutCastle is not set");
}
}
void CPlayerInterface::heroMoved(const TryMoveHero & details, bool verbose)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
@ -324,37 +302,40 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details, bool verbose)
if (!hero)
return;
adventureInt->infoBar->requestPopAll();
if (details.result == TryMoveHero::EMBARK || details.result == TryMoveHero::DISEMBARK)
{
if(hero->getRemovalSound() && hero->tempOwner == playerID)
CCS->soundh->playSound(hero->getRemovalSound().value());
}
adventureInt->minimap->updateTile(hero->convertToVisitablePos(details.start));
adventureInt->minimap->updateTile(hero->convertToVisitablePos(details.end));
std::unordered_set<int3> changedTiles {
hero->convertToVisitablePos(details.start),
hero->convertToVisitablePos(details.end)
};
adventureInt->onMapTilesChanged(changedTiles);
adventureInt->onHeroMovementStarted(hero);
bool directlyAttackingCreature = details.attackedFrom && paths.hasPath(hero) && paths.getPath(hero).endPos() == *details.attackedFrom;
bool directlyAttackingCreature = details.attackedFrom && localState->hasPath(hero) && localState->getPath(hero).endPos() == *details.attackedFrom;
if(makingTurn && hero->tempOwner == playerID) //we are moving our hero - we may need to update assigned path
{
if(details.result == TryMoveHero::TELEPORTATION)
{
if(paths.hasPath(hero))
if(localState->hasPath(hero))
{
assert(paths.getPath(hero).nodes.size() >= 2);
auto nodesIt = paths.getPath(hero).nodes.end() - 1;
assert(localState->getPath(hero).nodes.size() >= 2);
auto nodesIt = localState->getPath(hero).nodes.end() - 1;
if((nodesIt)->coord == hero->convertToVisitablePos(details.start)
&& (nodesIt - 1)->coord == hero->convertToVisitablePos(details.end))
{
//path was between entrance and exit of teleport -> OK, erase node as usual
paths.removeLastNode(hero);
localState->removeLastNode(hero);
}
else
{
//teleport was not along current path, it'll now be invalid (hero is somewhere else)
paths.erasePath(hero);
localState->erasePath(hero);
}
}
@ -363,28 +344,26 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details, bool verbose)
if(hero->pos != details.end //hero didn't change tile but visit succeeded
|| directlyAttackingCreature) // or creature was attacked from endangering tile.
{
paths.erasePath(hero);
localState->erasePath(hero);
}
else if(paths.hasPath(hero) && hero->pos == details.end) //&& hero is moving
else if(localState->hasPath(hero) && hero->pos == details.end) //&& hero is moving
{
if(details.start != details.end) //so we don't touch path when revisiting with spacebar
paths.removeLastNode(hero);
localState->removeLastNode(hero);
}
}
if(details.stopMovement()) //hero failed to move
{
stillMoveHero.setn(STOP_MOVE);
adventureInt->heroList->update(hero);
adventureInt->onHeroChanged(hero);
return;
}
adventureInt->heroList->redraw();
CGI->mh->waitForOngoingAnimations();
//move finished
adventureInt->heroList->update(hero);
adventureInt->onHeroChanged(hero);
//check if user cancelled movement
{
@ -428,33 +407,9 @@ void CPlayerInterface::heroKilled(const CGHeroInstance* hero)
EVENT_HANDLER_CALLED_BY_CLIENT;
LOG_TRACE_PARAMS(logGlobal, "Hero %s killed handler for player %s", hero->getNameTranslated() % playerID);
const CArmedInstance *newSelection = nullptr;
if (makingTurn)
{
//find new object for selection: either hero
int next = adventureInt->getNextHeroIndex(vstd::find_pos(wanderingHeroes, hero));
if (next >= 0)
newSelection = wanderingHeroes[next];
//or town
if (!newSelection || newSelection == hero)
{
if (towns.empty())
newSelection = nullptr;
else
newSelection = towns.front();
}
}
wanderingHeroes -= hero;
adventureInt->heroList->update(hero);
if (makingTurn && newSelection)
adventureInt->select(newSelection, true);
else if (adventureInt->selection == hero)
adventureInt->selection = nullptr;
paths.erasePath(hero);
localState->removeWanderingHero(hero);
adventureInt->onHeroChanged(hero);
localState->erasePath(hero);
}
void CPlayerInterface::heroVisit(const CGHeroInstance * visitor, const CGObjectInstance * visitedObj, bool start)
@ -470,8 +425,8 @@ void CPlayerInterface::heroVisit(const CGHeroInstance * visitor, const CGObjectI
void CPlayerInterface::heroCreated(const CGHeroInstance * hero)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
wanderingHeroes.push_back(hero);
adventureInt->heroList->update(hero);
localState->addWanderingHero(hero);
adventureInt->onHeroChanged(hero);
}
void CPlayerInterface::openTownWindow(const CGTownInstance * town)
{
@ -484,13 +439,6 @@ void CPlayerInterface::openTownWindow(const CGTownInstance * town)
GH.pushInt(newCastleInt);
}
void CPlayerInterface::activateForSpectator()
{
adventureInt->state = CAdvMapInt::INGAME;
adventureInt->activate();
adventureInt->minimap->activate();
}
void CPlayerInterface::heroPrimarySkillChanged(const CGHeroInstance * hero, int which, si64 val)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
@ -499,8 +447,8 @@ void CPlayerInterface::heroPrimarySkillChanged(const CGHeroInstance * hero, int
if (CAltarWindow *ctw = dynamic_cast<CAltarWindow *>(GH.topInt().get()))
ctw->setExpToLevel();
}
else if (which < GameConstants::PRIMARY_SKILLS) //no need to redraw infowin if this is experience (exp is treated as prim skill with id==4)
updateInfo(hero);
else
adventureInt->onHeroChanged(hero);
}
void CPlayerInterface::heroSecondarySkillChanged(const CGHeroInstance * hero, int which, int val)
@ -516,15 +464,15 @@ void CPlayerInterface::heroSecondarySkillChanged(const CGHeroInstance * hero, in
void CPlayerInterface::heroManaPointsChanged(const CGHeroInstance * hero)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
updateInfo(hero);
adventureInt->onHeroChanged(hero);
if (makingTurn && hero->tempOwner == playerID)
adventureInt->heroList->update(hero);
adventureInt->onHeroChanged(hero);
}
void CPlayerInterface::heroMovePointsChanged(const CGHeroInstance * hero)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
if (makingTurn && hero->tempOwner == playerID)
adventureInt->heroList->update(hero);
adventureInt->onHeroChanged(hero);
}
void CPlayerInterface::receivedResource()
{
@ -560,21 +508,22 @@ void CPlayerInterface::commanderGotLevel (const CCommanderInstance * commander,
void CPlayerInterface::heroInGarrisonChange(const CGTownInstance *town)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
updateInfo(town);
if (town->garrisonHero) //wandering hero moved to the garrison
if(town->garrisonHero) //wandering hero moved to the garrison
{
if (town->garrisonHero->tempOwner == playerID && vstd::contains(wanderingHeroes,town->garrisonHero)) // our hero
wanderingHeroes -= town->garrisonHero;
// This method also gets called on hero recruitment -> garrisoned hero is already in garrison
if(town->garrisonHero->tempOwner == playerID && !vstd::contains(localState->getWanderingHeroes(), town->visitingHero))
localState->removeWanderingHero(town->garrisonHero);
}
if (town->visitingHero) //hero leaves garrison
if(town->visitingHero) //hero leaves garrison
{
if (town->visitingHero->tempOwner == playerID && !vstd::contains(wanderingHeroes,town->visitingHero)) // our hero
wanderingHeroes.push_back(town->visitingHero);
// This method also gets called on hero recruitment -> wandering heroes already contains new hero
if(town->visitingHero->tempOwner == playerID && !vstd::contains(localState->getWanderingHeroes(), town->visitingHero))
localState->addWanderingHero(town->visitingHero);
}
adventureInt->heroList->update();
adventureInt->updateNextHero(nullptr);
adventureInt->onHeroChanged(nullptr);
adventureInt->onTownChanged(town);
if(castleInt)
{
@ -627,7 +576,15 @@ void CPlayerInterface::garrisonsChanged(std::vector<const CGObjectInstance *> ob
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
for (auto object : objs)
updateInfo(object);
{
auto * hero = dynamic_cast<const CGHeroInstance*>(object);
auto * town = dynamic_cast<const CGTownInstance*>(object);
if (hero)
adventureInt->onHeroChanged(hero);
if (town)
adventureInt->onTownChanged(town);
}
for (auto & elem : GH.listInt)
{
@ -645,23 +602,9 @@ void CPlayerInterface::garrisonsChanged(std::vector<const CGObjectInstance *> ob
GH.totalRedraw();
}
void CPlayerInterface::garrisonChanged( const CGObjectInstance * obj)
{
garrisonsChanged(std::vector<const CGObjectInstance *>(1, obj));
}
void CPlayerInterface::buildChanged(const CGTownInstance *town, BuildingID buildingID, int what) //what: 1 - built, 2 - demolished
{
EVENT_HANDLER_CALLED_BY_CLIENT;
switch (buildingID)
{
case BuildingID::FORT: case BuildingID::CITADEL: case BuildingID::CASTLE:
case BuildingID::VILLAGE_HALL: case BuildingID::TOWN_HALL: case BuildingID::CITY_HALL: case BuildingID::CAPITOL:
case BuildingID::RESOURCE_SILO:
updateInfo(town);
break;
}
if (castleInt)
{
castleInt->townlist->update(town);
@ -680,7 +623,7 @@ void CPlayerInterface::buildChanged(const CGTownInstance *town, BuildingID build
}
}
}
adventureInt->townList->update(town);
adventureInt->onTownChanged(town);
}
void CPlayerInterface::battleStartBefore(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2)
@ -709,7 +652,6 @@ void CPlayerInterface::battleStart(const CCreatureSet *army1, const CCreatureSet
isAutoFightOn = true;
cb->registerBattleInterface(autofightingAI);
// Player shouldn't be able to move on adventure map if quick combat is going
adventureInt->quickCombatLock();
allowBattleReplay = true;
}
@ -920,7 +862,6 @@ void CPlayerInterface::battleEnd(const BattleResult *br, QueryID queryID)
// #1490 - during AI turn when quick combat is on, we need to display the message and wait for user to close it.
// Otherwise NewTurn causes freeze.
waitWhileDialog();
adventureInt->quickCombatUnlock();
return;
}
}
@ -928,7 +869,6 @@ void CPlayerInterface::battleEnd(const BattleResult *br, QueryID queryID)
BATTLE_EVENT_POSSIBLE_RETURN;
battleInt->battleFinished(*br, queryID);
adventureInt->quickCombatUnlock();
}
void CPlayerInterface::battleLogMessage(const std::vector<MetaString> & lines)
@ -1070,7 +1010,7 @@ void CPlayerInterface::showInfoDialog(EInfoWindowMode type, const std::string &t
if(autoTryHover || type == EInfoWindowMode::INFO)
{
waitWhileDialog(); //Fix for mantis #98
adventureInt->infoBar->pushComponents(components, text, timer);
adventureInt->showInfoBoxMessage(components, text, timer);
if (makingTurn && GH.listInt.size() && LOCPLINT == this)
CCS->soundh->playSound(static_cast<soundBase::soundID>(soundID));
@ -1230,19 +1170,17 @@ void CPlayerInterface::showMapObjectSelectDialog(QueryID askID, const Component
GH.pushInt(wnd);
}
void CPlayerInterface::tileRevealed(const std::unordered_set<int3, ShashInt3> &pos)
void CPlayerInterface::tileRevealed(const std::unordered_set<int3> &pos)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
//FIXME: wait for dialog? Magi hut/eye would benefit from this but may break other areas
for (auto & po : pos)
adventureInt->minimap->updateTile(po);
adventureInt->onMapTilesChanged(pos);
}
void CPlayerInterface::tileHidden(const std::unordered_set<int3, ShashInt3> &pos)
void CPlayerInterface::tileHidden(const std::unordered_set<int3> &pos)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
for (auto & po : pos)
adventureInt->minimap->updateTile(po);
adventureInt->onMapTilesChanged(pos);
}
void CPlayerInterface::openHeroWindow(const CGHeroInstance *hero)
@ -1286,33 +1224,24 @@ void CPlayerInterface::heroBonusChanged( const CGHeroInstance *hero, const Bonus
if (bonus.type == Bonus::NONE)
return;
updateInfo(hero);
adventureInt->onHeroChanged(hero);
if ((bonus.type == Bonus::FLYING_MOVEMENT || bonus.type == Bonus::WATER_WALKING) && !gain)
{
//recalculate paths because hero has lost bonus influencing pathfinding
paths.erasePath(hero);
localState->erasePath(hero);
}
}
template <typename Handler> void CPlayerInterface::serializeTempl( Handler &h, const int version )
{
h & wanderingHeroes;
h & towns;
h & sleepingHeroes;
h & paths;
h & spellbookSettings;
}
void CPlayerInterface::saveGame( BinarySerializer & h, const int version )
{
EVENT_HANDLER_CALLED_BY_CLIENT;
serializeTempl(h,version);
localState->serialize(h, version);
}
void CPlayerInterface::loadGame( BinaryDeserializer & h, const int version )
{
EVENT_HANDLER_CALLED_BY_CLIENT;
serializeTempl(h,version);
localState->serialize(h, version);
firstCall = -1;
}
@ -1330,14 +1259,8 @@ void CPlayerInterface::moveHero( const CGHeroInstance *h, const CGPath& path )
setMovementStatus(true);
if (adventureInt && adventureInt->isHeroSleeping(h))
{
adventureInt->sleepWake->clickLeft(true, false);
adventureInt->sleepWake->clickLeft(false, true);
//could've just called
//adventureInt->fsleepWake();
//but no authentic button click/sound ;-)
}
if (localState->isHeroSleeping(h))
localState->setHeroAwaken(h);
boost::thread moveHeroTask(std::bind(&CPlayerInterface::doMoveHero,this,h,path));
}
@ -1347,7 +1270,7 @@ void CPlayerInterface::showGarrisonDialog( const CArmedInstance *up, const CGHer
EVENT_HANDLER_CALLED_BY_CLIENT;
auto onEnd = [=](){ cb->selectionMade(0, queryID); };
if (stillMoveHero.get() == DURING_MOVE && paths.hasPath(down) && paths.getPath(down).nodes.size() > 1) //to ignore calls on passing through garrisons
if (stillMoveHero.get() == DURING_MOVE && localState->hasPath(down) && localState->getPath(down).nodes.size() > 1) //to ignore calls on passing through garrisons
{
onEnd();
return;
@ -1406,6 +1329,12 @@ void CPlayerInterface::requestRealized( PackageApplied *pa )
}
}
void CPlayerInterface::showHeroExchange(ObjectInstanceID hero1, ObjectInstanceID hero2)
{
heroExchangeStarted(hero1, hero2, QueryID(-1));
}
void CPlayerInterface::heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2, QueryID query)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
@ -1415,48 +1344,51 @@ void CPlayerInterface::heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanc
void CPlayerInterface::objectPropertyChanged(const SetObjectProperty * sop)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
//redraw minimap if owner changed
if (sop->what == ObjProperty::OWNER)
{
const CGObjectInstance * obj = cb->getObj(sop->id);
std::set<int3> pos = obj->getBlockedPos();
for(auto & po : pos)
{
if(cb->isVisible(po))
adventureInt->minimap->updateTile(po);
}
if(obj->ID == Obj::TOWN)
{
if(obj->tempOwner == playerID)
towns.push_back(static_cast<const CGTownInstance *>(obj));
else
towns -= obj;
auto town = static_cast<const CGTownInstance *>(obj);
adventureInt->townList->update();
adventureInt->minimap->update();
if(obj->tempOwner == playerID)
localState->addOwnedTown(town);
else
localState->removeOwnedTown(town);
adventureInt->onTownChanged(town);
}
assert(cb->getTownsInfo().size() == towns.size());
std::set<int3> pos = obj->getBlockedPos();
std::unordered_set<int3> upos(pos.begin(), pos.end());
adventureInt->onMapTilesChanged(upos);
assert(cb->getTownsInfo().size() == localState->getOwnedTowns().size());
}
}
void CPlayerInterface::initializeHeroTownList()
{
if(!wanderingHeroes.size())
if(localState->getWanderingHeroes().empty())
{
std::vector<const CGHeroInstance*> heroes = cb->getHeroesInfo();
for(auto & hero : heroes)
for(auto & hero : cb->getHeroesInfo())
{
if(!hero->inTownGarrison)
wanderingHeroes.push_back(hero);
localState->addWanderingHero(hero);
}
}
if(!towns.size())
towns = cb->getTownsInfo();
if(localState->getOwnedTowns().empty())
{
for(auto & town : cb->getTownsInfo())
localState->addOwnedTown(town);
}
if(adventureInt)
adventureInt->updateNextHero(nullptr);
adventureInt->onHeroChanged(nullptr);
}
void CPlayerInterface::showRecruitmentDialog(const CGDwelling *dwelling, const CArmedInstance *dst, int level)
@ -1545,7 +1477,7 @@ void CPlayerInterface::objectRemoved(const CGObjectInstance * obj)
void CPlayerInterface::objectRemovedAfter()
{
EVENT_HANDLER_CALLED_BY_CLIENT;
adventureInt->minimap->update();
adventureInt->onMapTilesChanged(boost::none);
}
void CPlayerInterface::playerBlocked(int reason, bool start)
@ -1558,8 +1490,7 @@ void CPlayerInterface::playerBlocked(int reason, bool start)
boost::unique_lock<boost::mutex> lock(eventsM); //TODO: copied from yourTurn, no idea if it's needed
LOCPLINT = this;
GH.curInt = this;
adventureInt->selection = nullptr;
adventureInt->setPlayer(playerID);
adventureInt->onCurrentPlayerChanged(playerID);
std::string msg = CGI->generaltexth->translate("vcmi.adventureMap.playerAttacked");
boost::replace_first(msg, "%s", cb->getStartInfo()->playerInfos.find(playerID)->second.name);
std::vector<std::shared_ptr<CComponent>> cmp;
@ -1636,10 +1567,12 @@ void CPlayerInterface::gameOver(PlayerColor player, const EVictoryLossCheckResul
if (victoryLossCheckResult.loss())
showInfoDialog(CGI->generaltexth->allTexts[95]);
//we assume GH.curInt == LOCPLINT
assert(GH.curInt == LOCPLINT);
auto previousInterface = LOCPLINT; //without multiple player interfaces some of lines below are useless, but for hotseat we wanna swap player interface temporarily
LOCPLINT = this; //this is needed for dialog to show and avoid freeze, dialog showing logic should be reworked someday
GH.curInt = this; //waiting for dialogs requires this to get events
if(!makingTurn)
{
makingTurn = true; //also needed for dialog to show with current implementation
@ -1657,9 +1590,7 @@ void CPlayerInterface::gameOver(PlayerColor player, const EVictoryLossCheckResul
if(adventureInt)
{
GH.terminate_cond->setn(true);
adventureInt->deactivate();
if (GH.topInt() == adventureInt)
GH.popInt(adventureInt);
GH.popInts(GH.listInt.size());
adventureInt.reset();
}
}
@ -1677,7 +1608,8 @@ void CPlayerInterface::gameOver(PlayerColor player, const EVictoryLossCheckResul
requestReturningToMainMenu(false);
}
if (GH.curInt == this) GH.curInt = nullptr;
if (GH.curInt == this)
GH.curInt = nullptr;
}
else
{
@ -1720,7 +1652,7 @@ void CPlayerInterface::advmapSpellCast(const CGHeroInstance * caster, int spellI
GH.popInts(1);
if(spellID == SpellID::FLY || spellID == SpellID::WATER_WALK)
paths.erasePath(caster);
localState->erasePath(caster);
const spells::Spell * spell = CGI->spells()->getByIndex(spellID);
auto castSoundPath = spell->getCastSound();
@ -1728,56 +1660,6 @@ void CPlayerInterface::advmapSpellCast(const CGHeroInstance * caster, int spellI
CCS->soundh->playSound(castSoundPath);
}
void CPlayerInterface::acceptTurn()
{
if (settings["session"]["autoSkip"].Bool())
{
while(CInfoWindow *iw = dynamic_cast<CInfoWindow *>(GH.topInt().get()))
iw->close();
}
if(CSH->howManyPlayerInterfaces() > 1)
{
waitWhileDialog(); // wait for player to accept turn in hot-seat mode
adventureInt->startTurn();
}
adventureInt->initializeNewTurn();
// warn player if he has no town
if (cb->howManyTowns() == 0)
{
auto playerColor = *cb->getPlayerID();
std::vector<Component> components;
components.emplace_back(Component::EComponentType::FLAG, playerColor.getNum(), 0, 0);
MetaString text;
const auto & optDaysWithoutCastle = cb->getPlayerState(playerColor)->daysWithoutCastle;
if(optDaysWithoutCastle)
{
auto daysWithoutCastle = optDaysWithoutCastle.value();
if (daysWithoutCastle < 6)
{
text.addTxt(MetaString::ARRAY_TXT,128); //%s, you only have %d days left to capture a town or you will be banished from this land.
text.addReplacement(MetaString::COLOR, playerColor.getNum());
text.addReplacement(7 - daysWithoutCastle);
}
else if (daysWithoutCastle == 6)
{
text.addTxt(MetaString::ARRAY_TXT,129); //%s, this is your last day to capture a town or you will be banished from this land.
text.addReplacement(MetaString::COLOR, playerColor.getNum());
}
showInfoDialogAndWait(components, text);
}
else
logGlobal->warn("Player has no towns, but daysWithoutCastle is not set");
}
}
void CPlayerInterface::tryDiggging(const CGHeroInstance * h)
{
int msgToShow = -1;
@ -1810,21 +1692,6 @@ void CPlayerInterface::tryDiggging(const CGHeroInstance * h)
showInfoDialog(CGI->generaltexth->allTexts[msgToShow]);
}
void CPlayerInterface::updateInfo(const CGObjectInstance * specific)
{
bool isHero = dynamic_cast<const CGHeroInstance *>(specific) != nullptr;
bool changedHero = dynamic_cast<const CGHeroInstance *>(specific) != adventureInt->curHero();
bool isTown = dynamic_cast<const CGTownInstance *>(specific) != nullptr;
bool update = (isHero && changedHero) || (isTown);
// If infobar is showing components and we request an update to hero
// do not force infobar tick here, it will prevents us to show components just picked up
if(adventureInt->infoBar->showingComponents() && !update)
return;
adventureInt->infoBar->showSelection();
}
void CPlayerInterface::battleNewRoundFirst( int round )
{
EVENT_HANDLER_CALLED_BY_CLIENT;
@ -1933,14 +1800,14 @@ void CPlayerInterface::artifactPut(const ArtifactLocation &al)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
auto hero = std::visit(HeroObjectRetriever(), al.artHolder);
updateInfo(hero);
adventureInt->onHeroChanged(hero);
}
void CPlayerInterface::artifactRemoved(const ArtifactLocation &al)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
auto hero = std::visit(HeroObjectRetriever(), al.artHolder);
updateInfo(hero);
adventureInt->onHeroChanged(hero);
for(auto isa : GH.listInt)
{
auto artWin = dynamic_cast<CArtifactHolder*>(isa.get());
@ -1955,7 +1822,7 @@ void CPlayerInterface::artifactMoved(const ArtifactLocation &src, const Artifact
{
EVENT_HANDLER_CALLED_BY_CLIENT;
auto hero = std::visit(HeroObjectRetriever(), dst.artHolder);
updateInfo(hero);
adventureInt->onHeroChanged(hero);
bool redraw = true;
// If a bulk transfer has arrived, then redrawing only the last art movement.
@ -1984,7 +1851,7 @@ void CPlayerInterface::artifactAssembled(const ArtifactLocation &al)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
auto hero = std::visit(HeroObjectRetriever(), al.artHolder);
updateInfo(hero);
adventureInt->onHeroChanged(hero);
for(auto isa : GH.listInt)
{
auto artWin = dynamic_cast<CArtifactHolder*>(isa.get());
@ -1997,7 +1864,7 @@ void CPlayerInterface::artifactDisassembled(const ArtifactLocation &al)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
auto hero = std::visit(HeroObjectRetriever(), al.artHolder);
updateInfo(hero);
adventureInt->onHeroChanged(hero);
for(auto isa : GH.listInt)
{
auto artWin = dynamic_cast<CArtifactHolder*>(isa.get());
@ -2006,34 +1873,6 @@ void CPlayerInterface::artifactDisassembled(const ArtifactLocation &al)
}
}
void CPlayerInterface::playerStartsTurn(PlayerColor player)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
if (!vstd::contains (GH.listInt, adventureInt))
{
GH.popInts ((int)GH.listInt.size()); //after map load - remove everything else
GH.pushInt (adventureInt);
}
else
{
if (player == playerID)
adventureInt->infoBar->showSelection();
while (GH.listInt.front() != adventureInt && !dynamic_cast<CInfoWindow*>(GH.listInt.front().get())) //don't remove dialogs that expect query answer
GH.popInts(1);
}
if(CSH->howManyPlayerInterfaces() == 1)
{
GH.curInt = this;
adventureInt->startTurn();
}
if (player != playerID && this == LOCPLINT)
{
waitWhileDialog();
adventureInt->aiTurnStarted();
}
}
void CPlayerInterface::waitForAllDialogs(bool unlockPim)
{
while(!dialogs.empty())
@ -2049,15 +1888,9 @@ void CPlayerInterface::proposeLoadingGame()
showYesNoDialog(CGI->generaltexth->allTexts[68], [](){ GH.pushUserEvent(EUserEvent::RETURN_TO_MENU_LOAD); }, nullptr);
}
CPlayerInterface::SpellbookLastSetting::SpellbookLastSetting()
{
spellbookLastPageBattle = spellbokLastPageAdvmap = 0;
spellbookLastTabBattle = spellbookLastTabAdvmap = 4;
}
bool CPlayerInterface::capturedAllEvents()
{
if (duringMovement)
if(duringMovement)
{
//just inform that we are capturing events. they will be processed by heroMoved() in client thread.
return true;
@ -2065,7 +1898,7 @@ bool CPlayerInterface::capturedAllEvents()
bool needToLockAdventureMap = adventureInt && adventureInt->active && CGI->mh->hasOngoingAnimations();
if (ignoreEvents || needToLockAdventureMap)
if (ignoreEvents || needToLockAdventureMap || isAutoFightOn)
{
boost::unique_lock<boost::mutex> un(eventsM);
while(!SDLEventsQueue.empty())
@ -2245,15 +2078,6 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance * h, CGPath path)
if (!showingDialog->get())
GH.fakeMouseMove();
//todo: this should be in main thread
if (adventureInt)
{
// (i == 0) means hero went through all the path
adventureInt->updateMoveHero(h, (i != 0));
adventureInt->updateNextHero(h);
}
CGI->mh->waitForOngoingAnimations();
setMovementStatus(false);
}

View File

@ -9,16 +9,10 @@
*/
#pragma once
#include "../lib/FunctionList.h"
#include "../lib/CGameInterface.h"
#include "../lib/NetPacksBase.h"
#include "gui/CIntObject.h"
#ifdef __GNUC__
#define sprintf_s snprintf
#endif
VCMI_LIB_NAMESPACE_BEGIN
class Artifact;
@ -37,7 +31,7 @@ struct CPathsInfo;
VCMI_LIB_NAMESPACE_END
class CButton;
class CAdvMapInt;
class CAdventureMapInterface;
class CCastleInterface;
class BattleInterface;
class CComponent;
@ -51,103 +45,63 @@ class ClickableR;
class Hoverable;
class KeyInterested;
class MotionInterested;
class PlayerLocalState;
class TimeInterested;
class IShowable;
struct SDL_Surface;
union SDL_Event;
namespace boost
{
class mutex;
class recursive_mutex;
}
class CPlayerInterface;
class HeroPathStorage
{
CPlayerInterface & owner;
std::map<const CGHeroInstance *, CGPath> paths; //maps hero => selected path in adventure map
public:
explicit HeroPathStorage(CPlayerInterface &owner);
void setPath(const CGHeroInstance *h, const CGPath & path);
bool setPath(const CGHeroInstance *h, const int3 & destination);
const CGPath & getPath(const CGHeroInstance *h) const;
bool hasPath(const CGHeroInstance *h) const;
void removeLastNode(const CGHeroInstance *h);
void erasePath(const CGHeroInstance *h);
void verifyPath(const CGHeroInstance *h);
template <typename Handler>
void serialize( Handler &h, int version );
};
/// Central class for managing user interface logic
class CPlayerInterface : public CGameInterface, public IUpdateable
{
public:
HeroPathStorage paths;
bool duringMovement;
bool ignoreEvents;
size_t numOfMovedArts;
// -1 - just loaded game; 1 - just started game; 0 otherwise
int firstCall;
int autosaveCount;
static const int SAVES_COUNT = 5;
std::pair<const CCreatureSet *, const CCreatureSet *> lastBattleArmies;
bool allowBattleReplay = false;
std::list<std::shared_ptr<CInfoWindow>> dialogs; //queue of dialogs awaiting to be shown (not currently shown!)
const BattleAction *curAction; //during the battle - action currently performed by active stack (or nullptr)
std::shared_ptr<Environment> env;
ObjectInstanceID destinationTeleport; //contain -1 or object id if teleportation
int3 destinationTeleportPos;
public: // TODO: make private
std::shared_ptr<Environment> env;
std::unique_ptr<PlayerLocalState> localState;
//minor interfaces
CondSh<bool> *showingDialog; //indicates if dialog box is displayed
static boost::recursive_mutex *pim;
bool makingTurn; //if player is already making his turn
int firstCall; // -1 - just loaded game; 1 - just started game; 0 otherwise
int autosaveCount;
static const int SAVES_COUNT = 5;
CCastleInterface * castleInt; //nullptr if castle window isn't opened
static std::shared_ptr<BattleInterface> battleInt; //nullptr if no battle
CInGameConsole * cingconsole;
std::shared_ptr<CCallback> cb; //to communicate with engine
const BattleAction *curAction; //during the battle - action currently performed by active stack (or nullptr)
std::list<std::shared_ptr<CInfoWindow>> dialogs; //queue of dialogs awaiting to be shown (not currently shown!)
std::vector<const CGHeroInstance *> wanderingHeroes; //our heroes on the adventure map (not the garrisoned ones)
std::vector<const CGTownInstance *> towns; //our towns on the adventure map
std::vector<const CGHeroInstance *> sleepingHeroes; //if hero is in here, he's sleeping
//During battle is quick combat mode is used
std::shared_ptr<CBattleGameInterface> autofightingAI; //AI that makes decisions
bool isAutoFightOn; //Flag, switch it to stop quick combat. Don't touch if there is no battle interface.
bool allowBattleReplay = false;
std::pair<const CCreatureSet *, const CCreatureSet *> lastBattleArmies;
struct SpellbookLastSetting
{
int spellbookLastPageBattle, spellbokLastPageAdvmap; //on which page we left spellbook
int spellbookLastTabBattle, spellbookLastTabAdvmap; //on which page we left spellbook
SpellbookLastSetting();
template <typename Handler> void serialize( Handler &h, const int version )
{
h & spellbookLastPageBattle;
h & spellbokLastPageAdvmap;
h & spellbookLastTabBattle;
h & spellbookLastTabAdvmap;
}
} spellbookSettings;
protected: // Call-ins from server, should not be called directly, but only via GameInterface
void update() override;
void initializeHeroTownList();
int getLastIndex(std::string namePrefix);
void initGameInterface(std::shared_ptr<Environment> ENV, std::shared_ptr<CCallback> CB) override;
//overridden funcs from CGameInterface
void garrisonsChanged(ObjectInstanceID id1, ObjectInstanceID id2) override;
void buildChanged(const CGTownInstance *town, BuildingID buildingID, int what) override; //what: 1 - built, 2 - demolished
void artifactPut(const ArtifactLocation &al) override;
@ -172,22 +126,16 @@ public:
void receivedResource() override;
void showInfoDialog(EInfoWindowMode type, const std::string & text, const std::vector<Component> & components, int soundID) override;
void showRecruitmentDialog(const CGDwelling *dwelling, const CArmedInstance *dst, int level) override;
void showShipyardDialog(const IShipyard *obj) override; //obj may be town or shipyard;
void showBlockingDialog(const std::string &text, const std::vector<Component> &components, QueryID askID, const int soundID, bool selection, bool cancel) override; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID.
void showTeleportDialog(TeleportChannelID channel, TTeleportExitsList exits, bool impassable, QueryID askID) override;
void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, QueryID queryID) override;
void showMapObjectSelectDialog(QueryID askID, const Component & icon, const MetaString & title, const MetaString & description, const std::vector<ObjectInstanceID> & objects) override;
void showPuzzleMap() override;
void viewWorldMap() override;
void showMarketWindow(const IMarket *market, const CGHeroInstance *visitor) override;
void showUniversityWindow(const IMarket *market, const CGHeroInstance *visitor) override;
void showHillFortWindow(const CGObjectInstance *object, const CGHeroInstance *visitor) override;
void showTavernWindow(const CGObjectInstance *townOrTavern) override;
void showThievesGuildWindow (const CGObjectInstance * obj) override;
void showQuestLog() override;
void advmapSpellCast(const CGHeroInstance * caster, int spellID) override; //called when a hero casts a spell
void tileHidden(const std::unordered_set<int3, ShashInt3> &pos) override; //called when given tiles become hidden under fog of war
void tileRevealed(const std::unordered_set<int3, ShashInt3> &pos) override; //called when fog of war disappears from given tiles
void tileHidden(const std::unordered_set<int3> &pos) override; //called when given tiles become hidden under fog of war
void tileRevealed(const std::unordered_set<int3> &pos) override; //called when fog of war disappears from given tiles
void newObject(const CGObjectInstance * obj) override;
void availableArtifactsChanged(const CGBlackMarket *bm = nullptr) override; //bm may be nullptr, then artifacts are changed in the global pool (used by merchants in towns)
void yourTurn() override;
@ -230,21 +178,23 @@ public:
void yourTacticPhase(int distance) override;
void forceEndTacticPhase() override;
//-------------//
public: // public interface for use by client via LOCPLINT access
// part of GameInterface that is also used by client code
void showPuzzleMap() override;
void viewWorldMap() override;
void showQuestLog() override;
void showThievesGuildWindow (const CGObjectInstance * obj) override;
void showTavernWindow(const CGObjectInstance *townOrTavern) override;
void showShipyardDialog(const IShipyard *obj) override; //obj may be town or shipyard;
void showHeroExchange(ObjectInstanceID hero1, ObjectInstanceID hero2);
void showArtifactAssemblyDialog(const Artifact * artifact, const Artifact * assembledArtifact, CFunctionList<bool()> onYes);
void garrisonsChanged(std::vector<const CGObjectInstance *> objs);
void garrisonChanged(const CGObjectInstance * obj);
void heroKilled(const CGHeroInstance* hero);
void waitWhileDialog(bool unlockPim = true);
void waitForAllDialogs(bool unlockPim = true);
void redrawHeroWin(const CGHeroInstance * hero);
void openTownWindow(const CGTownInstance * town); //shows townscreen
void openHeroWindow(const CGHeroInstance * hero); //shows hero window with given hero
void updateInfo(const CGObjectInstance * specific);
void initGameInterface(std::shared_ptr<Environment> ENV, std::shared_ptr<CCallback> CB) override;
void activateForSpectator(); // TODO: spectator probably need own player interface class
// show dialogs
void showInfoDialog(const std::string &text, std::shared_ptr<CComponent> component);
void showInfoDialog(const std::string &text, const std::vector<std::shared_ptr<CComponent>> & components = std::vector<std::shared_ptr<CComponent>>(), int soundID = 0);
void showInfoDialogAndWait(std::vector<Component> & components, const MetaString & text);
@ -253,10 +203,8 @@ public:
void stopMovement();
void moveHero(const CGHeroInstance *h, const CGPath& path);
void acceptTurn(); //used during hot seat after your turn message is close
void tryDiggging(const CGHeroInstance *h);
void showShipyardDialogOrProblemPopup(const IShipyard *obj); //obj may be town or shipyard;
void requestReturningToMainMenu(bool won);
void proposeLoadingGame();
///returns true if all events are processed internally
@ -266,11 +214,6 @@ public:
~CPlayerInterface();
private:
template <typename Handler> void serializeTempl(Handler &h, const int version);
private:
struct IgnoreEvents
{
CPlayerInterface & owner;
@ -285,14 +228,18 @@ private:
};
bool duringMovement;
bool ignoreEvents;
size_t numOfMovedArts;
void heroKilled(const CGHeroInstance* hero);
void garrisonsChanged(std::vector<const CGObjectInstance *> objs);
void requestReturningToMainMenu(bool won);
void acceptTurn(); //used during hot seat after your turn message is close
void initializeHeroTownList();
int getLastIndex(std::string namePrefix);
void doMoveHero(const CGHeroInstance *h, CGPath path);
void setMovementStatus(bool value);
/// Performs autosave, if needed according to settings
void performAutosave();
};
/// Provides global access to instance of interface of currently active player
extern CPlayerInterface * LOCPLINT;

View File

@ -15,7 +15,7 @@
#include "CPlayerInterface.h"
#include "CServerHandler.h"
#include "ClientNetPackVisitors.h"
#include "adventureMap/CAdvMapInt.h"
#include "adventureMap/CAdventureMapInterface.h"
#include "battle/BattleInterface.h"
#include "gui/CGuiHandler.h"
#include "mapView/mapHandler.h"

View File

@ -235,7 +235,7 @@ public:
void castSpell(const spells::Caster * caster, SpellID spellID, const int3 &pos) override {};
void changeFogOfWar(int3 center, ui32 radius, PlayerColor player, bool hide) override {}
void changeFogOfWar(std::unordered_set<int3, ShashInt3> & tiles, PlayerColor player, bool hide) override {}
void changeFogOfWar(std::unordered_set<int3> & tiles, PlayerColor player, bool hide) override {}
void setObjProperty(ObjectInstanceID objid, int prop, si64 val) override {}

View File

@ -8,13 +8,12 @@
*
*/
#include "StdInc.h"
#include "ClientCommandManager.h"
#include "Client.h"
#include "adventureMap/CInGameConsole.h"
#include "adventureMap/CAdvMapInt.h"
#include "CPlayerInterface.h"
#include "PlayerLocalState.h"
#include "CServerHandler.h"
#include "gui/CGuiHandler.h"
#include "../lib/NetPacks.h"
@ -387,12 +386,12 @@ void ClientCommandManager::handleBonusesCommand(std::istringstream & singleWordB
ss << b;
return ss.str();
};
printCommandMessage("Bonuses of " + adventureInt->curArmy()->getObjectName() + "\n");
printCommandMessage(format(adventureInt->curArmy()->getBonusList()) + "\n");
printCommandMessage("Bonuses of " + LOCPLINT->localState->getCurrentArmy()->getObjectName() + "\n");
printCommandMessage(format(LOCPLINT->localState->getCurrentArmy()->getBonusList()) + "\n");
printCommandMessage("\nInherited bonuses:\n");
TCNodes parents;
adventureInt->curArmy()->getParents(parents);
LOCPLINT->localState->getCurrentArmy()->getParents(parents);
for(const CBonusSystemNode *parent : parents)
{
printCommandMessage(std::string("\nBonuses from ") + typeid(*parent).name() + "\n" + format(*parent->getAllBonuses(Selector::all, Selector::all)) + "\n");
@ -416,7 +415,7 @@ void ClientCommandManager::handleTellCommand(std::istringstream& singleWordBuffe
void ClientCommandManager::handleMpCommand()
{
if(const CGHeroInstance* h = adventureInt->curHero())
if(const CGHeroInstance* h = LOCPLINT->localState->getCurrentHero())
printCommandMessage(std::to_string(h->movement) + "; max: " + std::to_string(h->maxMovePoints(true)) + "/" + std::to_string(h->maxMovePoints(false)) + "\n");
}
@ -602,7 +601,7 @@ void ClientCommandManager::processCommand(const std::string & message, bool call
else if(commandName == "tell")
handleTellCommand(singleWordBuffer);
else if(commandName == "mp" && adventureInt)
else if(commandName == "mp" && LOCPLINT)
handleMpCommand();
else if (commandName == "set")

268
client/PlayerLocalState.cpp Normal file
View File

@ -0,0 +1,268 @@
/*
* PlayerLocalState.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "PlayerLocalState.h"
#include "../CCallback.h"
#include "../lib/CPathfinder.h"
#include "../lib/mapObjects/CGHeroInstance.h"
#include "../lib/mapObjects/CGTownInstance.h"
#include "CPlayerInterface.h"
#include "adventureMap/CAdventureMapInterface.h"
PlayerLocalState::PlayerLocalState(CPlayerInterface & owner)
: owner(owner)
, currentSelection(nullptr)
{
}
void PlayerLocalState::saveHeroPaths(std::map<const CGHeroInstance *, int3> & pathsMap)
{
for(auto & p : paths)
{
if(p.second.nodes.size())
pathsMap[p.first] = p.second.endPos();
else
logGlobal->debug("%s has assigned an empty path! Ignoring it...", p.first->getNameTranslated());
}
}
void PlayerLocalState::loadHeroPaths(std::map<const CGHeroInstance *, int3> & pathsMap)
{
if(owner.cb)
{
for(auto & p : pathsMap)
{
CGPath path;
owner.cb->getPathsInfo(p.first)->getPath(path, p.second);
paths[p.first] = path;
logGlobal->trace("Restored path for hero %s leading to %s with %d nodes", p.first->nodeName(), p.second.toString(), path.nodes.size());
}
}
}
void PlayerLocalState::setPath(const CGHeroInstance * h, const CGPath & path)
{
paths[h] = path;
}
const CGPath & PlayerLocalState::getPath(const CGHeroInstance * h) const
{
assert(hasPath(h));
return paths.at(h);
}
bool PlayerLocalState::hasPath(const CGHeroInstance * h) const
{
return paths.count(h) > 0;
}
bool PlayerLocalState::setPath(const CGHeroInstance * h, const int3 & destination)
{
CGPath path;
if(!owner.cb->getPathsInfo(h)->getPath(path, destination))
return false;
setPath(h, path);
return true;
}
void PlayerLocalState::removeLastNode(const CGHeroInstance * h)
{
assert(hasPath(h));
if(!hasPath(h))
return;
auto & path = paths[h];
path.nodes.pop_back();
if(path.nodes.size() < 2) //if it was the last one, remove entire path and path with only one tile is not a real path
erasePath(h);
}
void PlayerLocalState::erasePath(const CGHeroInstance * h)
{
paths.erase(h);
adventureInt->onHeroChanged(h);
}
void PlayerLocalState::verifyPath(const CGHeroInstance * h)
{
if(!hasPath(h))
return;
setPath(h, getPath(h).endPos());
}
const CGHeroInstance * PlayerLocalState::getCurrentHero() const
{
if(currentSelection && currentSelection->ID == Obj::HERO)
return dynamic_cast<const CGHeroInstance *>(currentSelection);
else
return nullptr;
}
const CGHeroInstance * PlayerLocalState::getNextWanderingHero(const CGHeroInstance * currentHero)
{
bool currentHeroFound = false;
const CGHeroInstance * firstSuitable = nullptr;
const CGHeroInstance * nextSuitable = nullptr;
for(const auto * hero : getWanderingHeroes())
{
if (hero == currentHero)
{
currentHeroFound = true;
continue;
}
if (isHeroSleeping(hero))
continue;
if (hero->movement == 0)
continue;
if (!firstSuitable)
firstSuitable = hero;
if (!nextSuitable && currentHeroFound)
nextSuitable = hero;
}
// if we found suitable hero after currently selected hero -> return this hero
if (nextSuitable)
return nextSuitable;
// othervice -> loop over and return first suitable hero in the list (or null if none)
return firstSuitable;
}
const CGTownInstance * PlayerLocalState::getCurrentTown() const
{
if(currentSelection && currentSelection->ID == Obj::TOWN)
return dynamic_cast<const CGTownInstance *>(currentSelection);
else
return nullptr;
}
const CArmedInstance * PlayerLocalState::getCurrentArmy() const
{
if(currentSelection)
return dynamic_cast<const CArmedInstance *>(currentSelection);
else
return nullptr;
}
void PlayerLocalState::setSelection(const CArmedInstance * selection)
{
if (currentSelection == selection)
return;
currentSelection = selection;
if (selection)
adventureInt->onSelectionChanged(selection);
}
bool PlayerLocalState::isHeroSleeping(const CGHeroInstance * hero) const
{
return vstd::contains(sleepingHeroes, hero);
}
void PlayerLocalState::setHeroAsleep(const CGHeroInstance * hero)
{
assert(hero);
assert(vstd::contains(wanderingHeroes, hero));
assert(!vstd::contains(sleepingHeroes, hero));
sleepingHeroes.push_back(hero);
}
void PlayerLocalState::setHeroAwaken(const CGHeroInstance * hero)
{
assert(hero);
assert(vstd::contains(wanderingHeroes, hero));
assert(vstd::contains(sleepingHeroes, hero));
vstd::erase(sleepingHeroes, hero);
}
const std::vector<const CGHeroInstance *> & PlayerLocalState::getWanderingHeroes()
{
return wanderingHeroes;
}
const CGHeroInstance * PlayerLocalState::getWanderingHero(size_t index)
{
if(index < wanderingHeroes.size())
return wanderingHeroes[index];
return nullptr;
}
void PlayerLocalState::addWanderingHero(const CGHeroInstance * hero)
{
assert(hero);
assert(!vstd::contains(wanderingHeroes, hero));
wanderingHeroes.push_back(hero);
}
void PlayerLocalState::removeWanderingHero(const CGHeroInstance * hero)
{
assert(hero);
assert(vstd::contains(wanderingHeroes, hero));
if (hero == currentSelection)
{
auto const * nextHero = getNextWanderingHero(hero);
setSelection(nextHero);
}
vstd::erase(wanderingHeroes, hero);
vstd::erase(sleepingHeroes, hero);
if (currentSelection == nullptr && !wanderingHeroes.empty())
setSelection(wanderingHeroes.front());
if (currentSelection == nullptr && !ownedTowns.empty())
setSelection(ownedTowns.front());
}
const std::vector<const CGTownInstance *> & PlayerLocalState::getOwnedTowns()
{
return ownedTowns;
}
const CGTownInstance * PlayerLocalState::getOwnedTown(size_t index)
{
if(index < ownedTowns.size())
return ownedTowns[index];
return nullptr;
}
void PlayerLocalState::addOwnedTown(const CGTownInstance * town)
{
assert(town);
assert(!vstd::contains(ownedTowns, town));
ownedTowns.push_back(town);
}
void PlayerLocalState::removeOwnedTown(const CGTownInstance * town)
{
assert(town);
assert(vstd::contains(ownedTowns, town));
vstd::erase(ownedTowns, town);
if (town == currentSelection)
setSelection(nullptr);
if (currentSelection == nullptr && !wanderingHeroes.empty())
setSelection(wanderingHeroes.front());
if (currentSelection == nullptr && !ownedTowns.empty())
setSelection(ownedTowns.front());
}

111
client/PlayerLocalState.h Normal file
View File

@ -0,0 +1,111 @@
/*
* PlayerLocalState.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
VCMI_LIB_NAMESPACE_BEGIN
class CGHeroInstance;
class CGTownInstance;
class CArmedInstance;
struct CGPath;
class int3;
VCMI_LIB_NAMESPACE_END
class CPlayerInterface;
/// Class that contains potentially serializeable state of a local player
class PlayerLocalState
{
CPlayerInterface & owner;
/// Currently selected object, can be town, hero or null
const CArmedInstance * currentSelection;
std::map<const CGHeroInstance *, CGPath> paths; //maps hero => selected path in adventure map
std::vector<const CGHeroInstance *> sleepingHeroes; //if hero is in here, he's sleeping
std::vector<const CGHeroInstance *> wanderingHeroes; //our heroes on the adventure map (not the garrisoned ones)
std::vector<const CGTownInstance *> ownedTowns; //our towns on the adventure map
void saveHeroPaths(std::map<const CGHeroInstance *, int3> & paths);
void loadHeroPaths(std::map<const CGHeroInstance *, int3> & paths);
public:
struct SpellbookLastSetting
{
//on which page we left spellbook
int spellbookLastPageBattle = 0;
int spellbokLastPageAdvmap = 0;
int spellbookLastTabBattle = 4;
int spellbookLastTabAdvmap = 4;
template<typename Handler>
void serialize(Handler & h, const int version)
{
h & spellbookLastPageBattle;
h & spellbokLastPageAdvmap;
h & spellbookLastTabBattle;
h & spellbookLastTabAdvmap;
}
} spellbookSettings;
explicit PlayerLocalState(CPlayerInterface & owner);
bool isHeroSleeping(const CGHeroInstance * hero) const;
void setHeroAsleep(const CGHeroInstance * hero);
void setHeroAwaken(const CGHeroInstance * hero);
const std::vector<const CGTownInstance *> & getOwnedTowns();
const CGTownInstance * getOwnedTown(size_t index);
void addOwnedTown(const CGTownInstance * hero);
void removeOwnedTown(const CGTownInstance * hero);
const std::vector<const CGHeroInstance *> & getWanderingHeroes();
const CGHeroInstance * getWanderingHero(size_t index);
const CGHeroInstance * getNextWanderingHero(const CGHeroInstance * hero);
void addWanderingHero(const CGHeroInstance * hero);
void removeWanderingHero(const CGHeroInstance * hero);
void setPath(const CGHeroInstance * h, const CGPath & path);
bool setPath(const CGHeroInstance * h, const int3 & destination);
const CGPath & getPath(const CGHeroInstance * h) const;
bool hasPath(const CGHeroInstance * h) const;
void removeLastNode(const CGHeroInstance * h);
void erasePath(const CGHeroInstance * h);
void verifyPath(const CGHeroInstance * h);
/// Returns currently selected object
const CGHeroInstance * getCurrentHero() const;
const CGTownInstance * getCurrentTown() const;
const CArmedInstance * getCurrentArmy() const;
/// Changes currently selected object
void setSelection(const CArmedInstance *sel);
template<typename Handler>
void serialize(Handler & h, int version)
{
//WARNING: this code is broken and not used. See CClient::loadGame
std::map<const CGHeroInstance *, int3> pathsMap; //hero -> dest
if(h.saving)
saveHeroPaths(pathsMap);
h & pathsMap;
if(!h.saving)
loadHeroPaths(pathsMap);
h & ownedTowns;
h & wanderingHeroes;
h & sleepingHeroes;
}
};

View File

@ -11,9 +11,6 @@
#include "../gui/CIntObject.h"
#include "../../lib/int3.h"
#include "../../lib/GameConstants.h"
VCMI_LIB_NAMESPACE_BEGIN
class CGObjectInstance;
@ -23,6 +20,8 @@ class CArmedInstance;
class IShipyard;
struct CGPathNode;
struct ObjectPosInfo;
struct Component;
class int3;
VCMI_LIB_NAMESPACE_END
@ -43,38 +42,28 @@ class MapAudioPlayer;
struct MapDrawingInfo;
enum class EAdvMapMode
{
NORMAL,
WORLD_VIEW
};
/// That's a huge class which handles general adventure map actions and
/// shows the right menu(questlog, spellbook, end turn,..) from where you
/// can get to the towns and heroes.
class CAdvMapInt : public CIntObject
class CAdventureMapInterface : public CIntObject
{
//TODO: remove
friend class CPlayerInterface;
private:
enum EDirections {LEFT=1, RIGHT=2, UP=4, DOWN=8};
enum EGameStates {NA, INGAME, WAITING};
enum class EGameState
{
NOT_INITIALIZED,
HOTSEAT_WAIT,
MAKING_TURN,
ENEMY_TURN,
WORLD_VIEW
};
EGameStates state;
EAdvMapMode mode;
/// Currently selected object, can be town, hero or null
const CArmedInstance *selection;
EGameState state;
/// currently acting player
PlayerColor player;
bool duringAITurn;
PlayerColor currentPlayerID;
/// uses EDirections enum
ui8 scrollingDir;
bool scrollingState;
bool scrollingCursorSet;
const CSpell *spellBeingCasted; //nullptr if none
@ -127,15 +116,13 @@ private:
void fnextHero();
void fendTurn();
void setScrollingCursor(ui8 direction) const;
void selectionChanged();
bool isActive();
void adjustActiveness(bool aiTurnStart); //should be called every time at AI/human turn transition; blocks GUI during AI turn
const IShipyard * ourInaccessibleShipyard(const CGObjectInstance *obj) const; //checks if obj is our ashipyard and cursor is 0,0 -> returns shipyard or nullptr else
//button updates
void updateSleepWake(const CGHeroInstance *h);
void updateSpellbook(const CGHeroInstance *h);
// update locked state of buttons
void updateButtons();
void handleMapScrollingUpdate();
@ -145,9 +132,15 @@ private:
std::optional<Point> keyToMoveDirection(const SDL_Keycode & key);
public:
CAdvMapInt();
void endingTurn();
/// exits currently opened world view mode and returns to normal map
void exitWorldView();
void exitCastingMode();
void leaveCastingMode(const int3 & castTarget);
void abortCastingMode();
protected:
// CIntObject interface implementation
void activate() override;
@ -157,58 +150,69 @@ public:
void showAll(SDL_Surface * to) override;
void keyPressed(const SDL_Keycode & key) override;
void keyReleased(const SDL_Keycode & key) override;
void mouseMoved (const Point & cursorPosition) override;
// public interface
public:
CAdventureMapInterface();
/// called by MapView whenever currently visible area changes
/// visibleArea describen now visible map section measured in tiles
void onMapViewMoved(const Rect & visibleArea, int mapLevel);
/// Called by PlayerInterface when specified player is ready to start his turn
void onHotseatWaitStarted(PlayerColor playerID);
/// Called when map audio should be paused, e.g. on combat or town scren access
/// Called by PlayerInterface when AI or remote human player starts his turn
void onEnemyTurnStarted(PlayerColor playerID);
/// Called by PlayerInterface when local human player starts his turn
void onPlayerTurnStarted(PlayerColor playerID);
/// Called by PlayerInterface when interface should be switched to specified player without starting turn
void onCurrentPlayerChanged(PlayerColor playerID);
/// Called by PlayerInterface when specific map tile changed and must be updated on minimap
void onMapTilesChanged(boost::optional<std::unordered_set<int3>> positions);
/// Called by PlayerInterface when hero starts movement
void onHeroMovementStarted(const CGHeroInstance * hero);
/// Called by PlayerInterface when hero state changed and hero list must be updated
void onHeroChanged(const CGHeroInstance * hero);
/// Called by PlayerInterface when town state changed and town list must be updated
void onTownChanged(const CGTownInstance * town);
/// Called when currently selected object changes
void onSelectionChanged(const CArmedInstance *sel);
/// Called when map audio should be paused, e.g. on combat or town screen access
void onAudioPaused();
/// Called when map audio should be resume, opposite to onPaused
void onAudioResumed();
void select(const CArmedInstance *sel, bool centerView = true);
/// Requests to display provided information inside infobox
void showInfoBoxMessage(const std::vector<Component> & components, std::string message, int timer);
/// Changes position on map to center selected location
void centerOnTile(int3 on);
void centerOnObject(const CGObjectInstance *obj);
bool isHeroSleeping(const CGHeroInstance *hero);
void setHeroSleeping(const CGHeroInstance *hero, bool sleep);
int getNextHeroIndex(int startIndex); //for Next Hero button - cycles awake heroes with movement only
void setPlayer(PlayerColor Player);
void startHotSeatWait(PlayerColor Player);
void startTurn();
void initializeNewTurn();
void endingTurn();
void aiTurnStarted();
void quickCombatLock(); //should be called when quick battle started
void quickCombatUnlock();
/// called by MapView whenever currently visible area changes
/// visibleArea describes now visible map section measured in tiles
void onMapViewMoved(const Rect & visibleArea, int mapLevel);
/// called by MapView whenever tile is clicked
void onTileLeftClicked(const int3 & mapPos);
/// called by MapView whenever tile is hovered
void onTileHovered(const int3 & mapPos);
/// called by MapView whenever tile is clicked
void onTileRightClicked(const int3 & mapPos);
/// called by spell window when spell to cast has been selected
void enterCastingMode(const CSpell * sp);
void leaveCastingMode(bool cast = false, int3 dest = int3(-1, -1, -1));
const CGHeroInstance * curHero() const;
const CGTownInstance * curTown() const;
const CArmedInstance * curArmy() const;
void updateMoveHero(const CGHeroInstance *h, tribool hasPath = boost::logic::indeterminate);
void updateNextHero(const CGHeroInstance *h);
/// returns area of screen covered by terrain (main game area)
Rect terrainAreaPixels() const;
/// exits currently opened world view mode and returns to normal map
void exitWorldView();
/// opens world view at default scale
void openWorldView();
@ -219,4 +223,4 @@ public:
void openWorldView(const std::vector<ObjectPosInfo>& objectPositions, bool showTerrain);
};
extern std::shared_ptr<CAdvMapInt> adventureInt;
extern std::shared_ptr<CAdventureMapInterface> adventureInt;

View File

@ -11,10 +11,9 @@
#include "StdInc.h"
#include "CAdventureOptions.h"
#include "CAdvMapInt.h"
#include "../CGameInfo.h"
#include "../CPlayerInterface.h"
#include "../PlayerLocalState.h"
#include "../lobby/CCampaignInfoScreen.h"
#include "../lobby/CScenarioInfoScreen.h"
#include "../gui/CGuiHandler.h"
@ -41,7 +40,7 @@ CAdventureOptions::CAdventureOptions()
puzzle->addCallback(std::bind(&CPlayerInterface::showPuzzleMap, LOCPLINT));
dig = std::make_shared<CButton>(Point(24, 139), "ADVDIG.DEF", CButton::tooltip(), [&](){ close(); }, SDLK_d);
if(const CGHeroInstance *h = adventureInt->curHero())
if(const CGHeroInstance *h = LOCPLINT->localState->getCurrentHero())
dig->addCallback(std::bind(&CPlayerInterface::tryDiggging, LOCPLINT, h));
else
dig->block(true);

View File

@ -14,8 +14,8 @@
#include "../CGameInfo.h"
#include "../CMusicHandler.h"
#include "../CPlayerInterface.h"
#include "../PlayerLocalState.h"
#include "../ClientCommandManager.h"
#include "../adventureMap/CAdvMapInt.h"
#include "../gui/CGuiHandler.h"
#include "../render/Colors.h"
@ -259,7 +259,7 @@ void CInGameConsole::endEnteringText(bool processEnteredText)
clientCommandThread.detach();
}
else
LOCPLINT->cb->sendMessage(txt, adventureInt->curArmy());
LOCPLINT->cb->sendMessage(txt, LOCPLINT->localState->getCurrentArmy());
}
enteredText.clear();

View File

@ -11,7 +11,7 @@
#include "StdInc.h"
#include "CInfoBar.h"
#include "CAdvMapInt.h"
#include "CAdventureMapInterface.h"
#include "../widgets/CComponent.h"
#include "../widgets/Images.h"
@ -22,6 +22,7 @@
#include "../CGameInfo.h"
#include "../CMusicHandler.h"
#include "../CPlayerInterface.h"
#include "../PlayerLocalState.h"
#include "../gui/CGuiHandler.h"
#include "../../CCallback.h"
@ -114,7 +115,7 @@ CInfoBar::VisibleGameStatusInfo::VisibleGameStatusInfo()
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
//get amount of halls of each level
std::vector<int> halls(4, 0);
for(auto town : LOCPLINT->towns)
for(auto town : LOCPLINT->localState->getOwnedTowns())
{
int hallLevel = town->hallLevel();
//negative value means no village hall, unlikely but possible
@ -237,15 +238,15 @@ void CInfoBar::reset()
void CInfoBar::showSelection()
{
OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE);
if(adventureInt->curHero())
if(LOCPLINT->localState->getCurrentHero())
{
showHeroSelection(adventureInt->curHero());
showHeroSelection(LOCPLINT->localState->getCurrentHero());
return;
}
if(adventureInt->curTown())
if(LOCPLINT->localState->getCurrentTown())
{
showTownSelection(adventureInt->curTown());
showTownSelection(LOCPLINT->localState->getCurrentTown());
return;
}

View File

@ -11,13 +11,14 @@
#include "StdInc.h"
#include "CList.h"
#include "CAdvMapInt.h"
#include "CAdventureMapInterface.h"
#include "../widgets/Images.h"
#include "../widgets/Buttons.h"
#include "../windows/InfoWindows.h"
#include "../CGameInfo.h"
#include "../CPlayerInterface.h"
#include "../PlayerLocalState.h"
#include "../gui/CGuiHandler.h"
#include "../../lib/CGeneralTextHandler.h"
@ -203,8 +204,8 @@ std::shared_ptr<CIntObject> CHeroList::CHeroItem::genSelection()
void CHeroList::CHeroItem::select(bool on)
{
if(on && adventureInt->curHero() != hero)
adventureInt->select(hero);
if(on)
LOCPLINT->localState->setSelection(hero);
}
void CHeroList::CHeroItem::open()
@ -224,19 +225,19 @@ std::string CHeroList::CHeroItem::getHoverText()
std::shared_ptr<CIntObject> CHeroList::createHeroItem(size_t index)
{
if (LOCPLINT->wanderingHeroes.size() > index)
return std::make_shared<CHeroItem>(this, LOCPLINT->wanderingHeroes[index]);
if (LOCPLINT->localState->getWanderingHeroes().size() > index)
return std::make_shared<CHeroItem>(this, LOCPLINT->localState->getWanderingHero(index));
return std::make_shared<CEmptyHeroItem>();
}
CHeroList::CHeroList(int size, Point position, std::string btnUp, std::string btnDown):
CList(size, position, btnUp, btnDown, LOCPLINT->wanderingHeroes.size(), 303, 304, std::bind(&CHeroList::createHeroItem, this, _1))
CList(size, position, btnUp, btnDown, LOCPLINT->localState->getWanderingHeroes().size(), 303, 304, std::bind(&CHeroList::createHeroItem, this, _1))
{
}
void CHeroList::select(const CGHeroInstance * hero)
{
selectIndex(vstd::find_pos(LOCPLINT->wanderingHeroes, hero));
selectIndex(vstd::find_pos(LOCPLINT->localState->getWanderingHeroes(), hero));
}
void CHeroList::update(const CGHeroInstance * hero)
@ -245,7 +246,7 @@ void CHeroList::update(const CGHeroInstance * hero)
for(auto & elem : listBox->getItems())
{
auto item = std::dynamic_pointer_cast<CHeroItem>(elem);
if(item && item->hero == hero && vstd::contains(LOCPLINT->wanderingHeroes, hero))
if(item && item->hero == hero && vstd::contains(LOCPLINT->localState->getWanderingHeroes(), hero))
{
item->update();
return;
@ -253,17 +254,17 @@ void CHeroList::update(const CGHeroInstance * hero)
}
//simplest solution for now: reset list and restore selection
listBox->resize(LOCPLINT->wanderingHeroes.size());
if (adventureInt->curHero())
select(adventureInt->curHero());
listBox->resize(LOCPLINT->localState->getWanderingHeroes().size());
if (LOCPLINT->localState->getCurrentHero())
select(LOCPLINT->localState->getCurrentHero());
CList::update();
}
std::shared_ptr<CIntObject> CTownList::createTownItem(size_t index)
{
if (LOCPLINT->towns.size() > index)
return std::make_shared<CTownItem>(this, LOCPLINT->towns[index]);
if (LOCPLINT->localState->getOwnedTowns().size() > index)
return std::make_shared<CTownItem>(this, LOCPLINT->localState->getOwnedTown(index));
return std::make_shared<CAnimImage>("ITPA", 0);
}
@ -292,8 +293,8 @@ void CTownList::CTownItem::update()
void CTownList::CTownItem::select(bool on)
{
if (on && adventureInt->curTown() != town)
adventureInt->select(town);
if(on)
LOCPLINT->localState->setSelection(town);
}
void CTownList::CTownItem::open()
@ -312,22 +313,22 @@ std::string CTownList::CTownItem::getHoverText()
}
CTownList::CTownList(int size, Point position, std::string btnUp, std::string btnDown):
CList(size, position, btnUp, btnDown, LOCPLINT->towns.size(), 306, 307, std::bind(&CTownList::createTownItem, this, _1))
CList(size, position, btnUp, btnDown, LOCPLINT->localState->getOwnedTowns().size(), 306, 307, std::bind(&CTownList::createTownItem, this, _1))
{
}
void CTownList::select(const CGTownInstance * town)
{
selectIndex(vstd::find_pos(LOCPLINT->towns, town));
selectIndex(vstd::find_pos(LOCPLINT->localState->getOwnedTowns(), town));
}
void CTownList::update(const CGTownInstance *)
{
//simplest solution for now: reset list and restore selection
listBox->resize(LOCPLINT->towns.size());
if (adventureInt->curTown())
select(adventureInt->curTown());
listBox->resize(LOCPLINT->localState->getOwnedTowns().size());
if (LOCPLINT->localState->getCurrentTown())
select(LOCPLINT->localState->getCurrentTown());
CList::update();
}

View File

@ -11,14 +11,15 @@
#include "StdInc.h"
#include "CMinimap.h"
#include "CAdvMapInt.h"
#include "CAdventureMapInterface.h"
#include "../widgets/Images.h"
#include "../CGameInfo.h"
#include "../CPlayerInterface.h"
#include "../gui/CGuiHandler.h"
#include "../render/Colors.h"
#include "../renderSDL/SDL_PixelAccess.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../render/Canvas.h"
#include "../windows/InfoWindows.h"
#include "../../CCallback.h"
@ -27,6 +28,8 @@
#include "../../lib/mapObjects/CGHeroInstance.h"
#include "../../lib/mapping/CMapDefines.h"
#include <SDL_pixels.h>
ColorRGBA CMinimapInstance::getTileColor(const int3 & pos) const
{
const TerrainTile * tile = LOCPLINT->cb->getTile(pos, false);
@ -225,10 +228,13 @@ void CMinimap::setAIRadar(bool on)
redraw();
}
void CMinimap::updateTile(const int3 &pos)
void CMinimap::updateTiles(std::unordered_set<int3> positions)
{
if(minimap)
minimap->refreshTile(pos);
{
for (auto const & tile : positions)
minimap->refreshTile(tile);
}
redraw();
}

View File

@ -10,13 +10,12 @@
#pragma once
#include "../gui/CIntObject.h"
#include "../../lib/GameConstants.h"
#include "../render/Canvas.h"
VCMI_LIB_NAMESPACE_BEGIN
class ColorRGBA;
VCMI_LIB_NAMESPACE_END
class Canvas;
class CMinimap;
class CMinimapInstance : public CIntObject
@ -68,6 +67,6 @@ public:
void showAll(SDL_Surface * to) override;
void updateTile(const int3 &pos);
void updateTiles(std::unordered_set<int3> positions);
};

View File

@ -157,7 +157,7 @@ void MapAudioPlayer::updateAmbientSounds()
};
int3 pos = currentSelection->getSightCenter();
std::unordered_set<int3, ShashInt3> tiles;
std::unordered_set<int3> tiles;
LOCPLINT->cb->getVisibleTilesInRange(tiles, pos, CCS->soundh->ambientGetRange(), int3::DIST_CHEBYSHEV);
for(int3 tile : tiles)
{

View File

@ -29,7 +29,7 @@
#include "../gui/CursorHandler.h"
#include "../gui/CGuiHandler.h"
#include "../render/Canvas.h"
#include "../adventureMap/CAdvMapInt.h"
#include "../adventureMap/CAdventureMapInterface.h"
#include "../../CCallback.h"
#include "../../lib/CStack.h"

View File

@ -246,14 +246,6 @@ void BattleStacksController::setActiveStack(const CStack *stack)
bool BattleStacksController::stackNeedsAmountBox(const CStack * stack) const
{
BattleHex currentActionTarget;
if(owner.curInt->curAction)
{
auto target = owner.curInt->curAction->getTarget(owner.curInt->cb.get());
if(!target.empty())
currentActionTarget = target.at(0).hexValue;
}
//do not show box for singular war machines, stacked war machines with box shown are supported as extension feature
if(stack->hasBonusOfType(Bonus::SIEGE_WEAPON) && stack->getCount() == 1)
return false;

View File

@ -17,7 +17,7 @@
#include "../../CCallback.h"
#include "../CGameInfo.h"
#include "../CPlayerInterface.h"
#include "../adventureMap/CAdvMapInt.h"
#include "../PlayerLocalState.h"
#include "../../lib/CPathfinder.h"
#include "../../lib/Point.h"
@ -73,9 +73,9 @@ bool MapRendererBaseContext::isActiveHero(const CGObjectInstance * obj) const
if(obj->ID == Obj::HERO)
{
assert(dynamic_cast<const CGHeroInstance *>(obj) != nullptr);
if(adventureInt->curHero() != nullptr)
if(LOCPLINT->localState->getCurrentHero() != nullptr)
{
if(obj->id == adventureInt->curHero()->id)
if(obj->id == LOCPLINT->localState->getCurrentHero()->id)
return true;
}
}
@ -206,15 +206,15 @@ MapRendererAdventureContext::MapRendererAdventureContext(const MapRendererContex
const CGPath * MapRendererAdventureContext::currentPath() const
{
const auto * hero = adventureInt->curHero();
const auto * hero = LOCPLINT->localState->getCurrentHero();
if(!hero)
return nullptr;
if(!LOCPLINT->paths.hasPath(hero))
if(!LOCPLINT->localState->hasPath(hero))
return nullptr;
return &LOCPLINT->paths.getPath(hero);
return &LOCPLINT->localState->getPath(hero);
}
size_t MapRendererAdventureContext::objectImageIndex(ObjectInstanceID objectID, size_t groupSize) const

View File

@ -17,7 +17,7 @@
#include "../../CCallback.h"
#include "../CGameInfo.h"
#include "../CPlayerInterface.h"
#include "../adventureMap/CAdvMapInt.h"
#include "../adventureMap/CAdventureMapInterface.h"
#include "../../lib/mapObjects/CGHeroInstance.h"
#include "../../lib/mapping/CMap.h"

View File

@ -19,7 +19,7 @@
#include "../CGameInfo.h"
#include "../CPlayerInterface.h"
#include "../adventureMap/CAdvMapInt.h"
#include "../adventureMap/CAdventureMapInterface.h"
#include "../gui/CGuiHandler.h"
#include "../render/CAnimation.h"
#include "../render/Canvas.h"

View File

@ -15,7 +15,7 @@
#include "MapViewModel.h"
#include "../CGameInfo.h"
#include "../adventureMap/CAdvMapInt.h"
#include "../adventureMap/CAdventureMapInterface.h"
#include "../gui/CGuiHandler.h"
#include "../gui/CursorHandler.h"

View File

@ -17,7 +17,7 @@
#include "MapViewModel.h"
#include "../CPlayerInterface.h"
#include "../adventureMap/CAdvMapInt.h"
#include "../adventureMap/CAdventureMapInterface.h"
#include "../gui/CGuiHandler.h"
#include "../../lib/CConfigHandler.h"

View File

@ -19,6 +19,7 @@
#include "../CGameInfo.h"
#include "../CMusicHandler.h"
#include "../CPlayerInterface.h"
#include "../PlayerLocalState.h"
#include "../gui/CGuiHandler.h"
#include "../widgets/MiscWidgets.h"
#include "../widgets/CComponent.h"
@ -27,7 +28,7 @@
#include "../renderSDL/SDL_Extensions.h"
#include "../render/IImage.h"
#include "../render/ColorFilter.h"
#include "../adventureMap/CAdvMapInt.h"
#include "../adventureMap/CAdventureMapInterface.h"
#include "../adventureMap/CList.h"
#include "../adventureMap/CResDataBar.h"
@ -495,7 +496,7 @@ void HeroSlots::splitClicked()
{
if(!!town->visitingHero && town->garrisonHero && (visitingHero->isSelected() || garrisonedHero->isSelected()))
{
LOCPLINT->heroExchangeStarted(town->visitingHero->id, town->garrisonHero->id, QueryID(-1));
LOCPLINT->showHeroExchange(town->visitingHero->id, town->garrisonHero->id);
}
}
@ -1229,9 +1230,9 @@ void CCastleInterface::close()
if(town->tempOwner == LOCPLINT->playerID) //we may have opened window for an allied town
{
if(town->visitingHero && town->visitingHero->tempOwner == LOCPLINT->playerID)
adventureInt->select(town->visitingHero);
LOCPLINT->localState->setSelection(town->visitingHero);
else
adventureInt->select(town);
LOCPLINT->localState->setSelection(town);
}
CWindowObject::close();
}
@ -1239,15 +1240,15 @@ void CCastleInterface::close()
void CCastleInterface::castleTeleport(int where)
{
const CGTownInstance * dest = LOCPLINT->cb->getTown(ObjectInstanceID(where));
adventureInt->select(town->visitingHero);//according to assert(ho == adventureInt->selection) in the eraseCurrentPathOf
LOCPLINT->localState->setSelection(town->visitingHero);//according to assert(ho == adventureInt->selection) in the eraseCurrentPathOf
LOCPLINT->cb->teleportHero(town->visitingHero, dest);
LOCPLINT->paths.erasePath(town->visitingHero);
LOCPLINT->localState->erasePath(town->visitingHero);
}
void CCastleInterface::townChange()
{
//TODO: do not recreate window
const CGTownInstance * dest = LOCPLINT->towns[townlist->getSelectedIndex()];
const CGTownInstance * dest = LOCPLINT->localState->getOwnedTown(townlist->getSelectedIndex());
const CGTownInstance * town = this->town;// "this" is going to be deleted
if ( dest == town )
return;

View File

@ -15,7 +15,7 @@
#include "../gui/CGuiHandler.h"
#include "../widgets/CComponent.h"
#include "../adventureMap/CAdvMapInt.h"
#include "../adventureMap/CAdventureMapInterface.h"
#include "../widgets/Buttons.h"
#include "../adventureMap/CMinimap.h"
#include "../renderSDL/SDL_Extensions.h"

View File

@ -18,6 +18,7 @@
#include "../CGameInfo.h"
#include "../CPlayerInterface.h"
#include "../PlayerLocalState.h"
#include "../CVideoHandler.h"
#include "../battle/BattleInterface.h"
@ -25,7 +26,7 @@
#include "../widgets/MiscWidgets.h"
#include "../widgets/CComponent.h"
#include "../widgets/TextControls.h"
#include "../adventureMap/CAdvMapInt.h"
#include "../adventureMap/CAdventureMapInterface.h"
#include "../render/CAnimation.h"
#include "../renderSDL/SDL_Extensions.h"
@ -221,9 +222,9 @@ CSpellWindow::CSpellWindow(const CGHeroInstance * _myHero, CPlayerInterface * _m
}
}
selectedTab = battleSpellsOnly ? myInt->spellbookSettings.spellbookLastTabBattle : myInt->spellbookSettings.spellbookLastTabAdvmap;
selectedTab = battleSpellsOnly ? myInt->localState->spellbookSettings.spellbookLastTabBattle : myInt->localState->spellbookSettings.spellbookLastTabAdvmap;
schoolTab->setFrame(selectedTab, 0);
int cp = battleSpellsOnly ? myInt->spellbookSettings.spellbookLastPageBattle : myInt->spellbookSettings.spellbokLastPageAdvmap;
int cp = battleSpellsOnly ? myInt->localState->spellbookSettings.spellbookLastPageBattle : myInt->localState->spellbookSettings.spellbokLastPageAdvmap;
// spellbook last page battle index is not reset after battle, so this needs to stay here
vstd::abetween(cp, 0, std::max(0, pagesWithinCurrentTab() - 1));
setCurrentPage(cp);
@ -237,8 +238,8 @@ CSpellWindow::~CSpellWindow()
void CSpellWindow::fexitb()
{
(myInt->battleInt ? myInt->spellbookSettings.spellbookLastTabBattle : myInt->spellbookSettings.spellbookLastTabAdvmap) = selectedTab;
(myInt->battleInt ? myInt->spellbookSettings.spellbookLastPageBattle : myInt->spellbookSettings.spellbokLastPageAdvmap) = currentPage;
(myInt->battleInt ? myInt->localState->spellbookSettings.spellbookLastTabBattle : myInt->localState->spellbookSettings.spellbookLastTabAdvmap) = selectedTab;
(myInt->battleInt ? myInt->localState->spellbookSettings.spellbookLastPageBattle : myInt->localState->spellbookSettings.spellbokLastPageAdvmap) = currentPage;
close();
}
@ -556,8 +557,8 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
auto guard = vstd::makeScopeGuard([this]()
{
owner->myInt->spellbookSettings.spellbookLastTabAdvmap = owner->selectedTab;
owner->myInt->spellbookSettings.spellbokLastPageAdvmap = owner->currentPage;
owner->myInt->localState->spellbookSettings.spellbookLastTabAdvmap = owner->selectedTab;
owner->myInt->localState->spellbookSettings.spellbokLastPageAdvmap = owner->currentPage;
});
if(mySpell->getTargetType() == spells::AimType::LOCATION)

View File

@ -11,6 +11,7 @@
#include "InfoWindows.h"
#include "../CGameInfo.h"
#include "../PlayerLocalState.h"
#include "../CPlayerInterface.h"
#include "../CMusicHandler.h"
@ -21,7 +22,7 @@
#include "../gui/CGuiHandler.h"
#include "../battle/BattleInterface.h"
#include "../battle/BattleInterfaceClasses.h"
#include "../adventureMap/CAdvMapInt.h"
#include "../adventureMap/CAdventureMapInterface.h"
#include "../windows/CMessage.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../gui/CursorHandler.h"
@ -332,8 +333,8 @@ void CRClickPopup::createAndPush(const CGObjectInstance * obj, const Point & p,
}
else
{
if(adventureInt->curHero())
CRClickPopup::createAndPush(obj->getHoverText(adventureInt->curHero()));
if(LOCPLINT->localState->getCurrentHero())
CRClickPopup::createAndPush(obj->getHoverText(LOCPLINT->localState->getCurrentHero()));
else
CRClickPopup::createAndPush(obj->getHoverText(LOCPLINT->playerID));
}
@ -376,7 +377,7 @@ CInfoBoxPopup::CInfoBoxPopup(Point position, const CGTownInstance * town)
: CWindowObject(RCLICK_POPUP | PLAYER_COLORED, "TOWNQVBK", toScreen(position))
{
InfoAboutTown iah;
LOCPLINT->cb->getTownInfo(town, iah, adventureInt->curTown()); //todo: should this be nearest hero?
LOCPLINT->cb->getTownInfo(town, iah, LOCPLINT->localState->getCurrentTown()); //todo: should this be nearest hero?
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
tooltip = std::make_shared<CTownTooltip>(Point(9, 10), iah);
@ -386,7 +387,7 @@ CInfoBoxPopup::CInfoBoxPopup(Point position, const CGHeroInstance * hero)
: CWindowObject(RCLICK_POPUP | PLAYER_COLORED, "HEROQVBK", toScreen(position))
{
InfoAboutHero iah;
LOCPLINT->cb->getHeroInfo(hero, iah, adventureInt->curHero());//todo: should this be nearest hero?
LOCPLINT->cb->getHeroInfo(hero, iah, LOCPLINT->localState->getCurrentHero());//todo: should this be nearest hero?
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
tooltip = std::make_shared<CHeroTooltip>(Point(9, 10), iah);
@ -405,7 +406,7 @@ CInfoBoxPopup::CInfoBoxPopup(Point position, const CGGarrison * garr)
std::shared_ptr<WindowBase> CRClickPopup::createInfoWin(Point position, const CGObjectInstance * specific) //specific=0 => draws info about selected town/hero
{
if(nullptr == specific)
specific = adventureInt->curArmy();
specific = LOCPLINT->localState->getCurrentArmy();
if(nullptr == specific)
{

View File

@ -935,7 +935,7 @@ bool CGameInfoCallback::isInTheMap(const int3 &pos) const
return gs->map->isInTheMap(pos);
}
void CGameInfoCallback::getVisibleTilesInRange(std::unordered_set<int3, ShashInt3> &tiles, int3 pos, int radious, int3::EDistanceFormula distanceFormula) const
void CGameInfoCallback::getVisibleTilesInRange(std::unordered_set<int3> &tiles, int3 pos, int radious, int3::EDistanceFormula distanceFormula) const
{
gs->getTilesInRange(tiles, pos, radious, getLocalPlayer(), -1, distanceFormula);
}

View File

@ -35,7 +35,6 @@ struct SThievesGuildInfo;
class CMapHeader;
struct TeamState;
struct QuestInfo;
struct ShashInt3;
class CGameState;
class PathfinderConfig;
@ -99,7 +98,7 @@ public:
// const TerrainTile * getTile(int3 tile, bool verbose = true) const;
// std::shared_ptr<boost::multi_array<TerrainTile*, 3>> getAllVisibleTiles() const;
// bool isInTheMap(const int3 &pos) const;
// void getVisibleTilesInRange(std::unordered_set<int3, ShashInt3> &tiles, int3 pos, int radious, int3::EDistanceFormula distanceFormula = int3::DIST_2D) const;
// void getVisibleTilesInRange(std::unordered_set<int3> &tiles, int3 pos, int radious, int3::EDistanceFormula distanceFormula = int3::DIST_2D) const;
//town
// const CGTownInstance* getTown(ObjectInstanceID objid) const;
@ -194,7 +193,7 @@ public:
virtual const TerrainTile * getTile(int3 tile, bool verbose = true) const;
virtual std::shared_ptr<const boost::multi_array<TerrainTile*, 3>> getAllVisibleTiles() const;
virtual bool isInTheMap(const int3 &pos) const;
virtual void getVisibleTilesInRange(std::unordered_set<int3, ShashInt3> &tiles, int3 pos, int radious, int3::EDistanceFormula distanceFormula = int3::DIST_2D) const;
virtual void getVisibleTilesInRange(std::unordered_set<int3> &tiles, int3 pos, int radious, int3::EDistanceFormula distanceFormula = int3::DIST_2D) const;
virtual void calculatePaths(const std::shared_ptr<PathfinderConfig> & config);
virtual void calculatePaths(const CGHeroInstance *hero, CPathsInfo &out);
virtual EDiggingStatus getTileDigStatus(int3 tile, bool verbose = true) const;

View File

@ -1641,7 +1641,7 @@ void CGameState::initFogOfWar()
{
if(!obj || !vstd::contains(elem.second.players, obj->tempOwner)) continue; //not a flagged object
std::unordered_set<int3, ShashInt3> tiles;
std::unordered_set<int3> tiles;
getTilesInRange(tiles, obj->getSightCenter(), obj->getSightRadius(), obj->tempOwner, 1);
for(const int3 & tile : tiles)
{

View File

@ -548,7 +548,7 @@ public:
PATROL_LOCKED = 1,
PATROL_RADIUS
} patrolState;
std::unordered_set<int3, ShashInt3> patrolTiles;
std::unordered_set<int3> patrolTiles;
int turn;
PlayerColor owner;

View File

@ -63,7 +63,7 @@ void CPrivilegedInfoCallback::getFreeTiles(std::vector<int3> & tiles) const
}
}
void CPrivilegedInfoCallback::getTilesInRange(std::unordered_set<int3, ShashInt3> & tiles,
void CPrivilegedInfoCallback::getTilesInRange(std::unordered_set<int3> & tiles,
const int3 & pos,
int radious,
std::optional<PlayerColor> player,
@ -100,7 +100,7 @@ void CPrivilegedInfoCallback::getTilesInRange(std::unordered_set<int3, ShashInt3
}
}
void CPrivilegedInfoCallback::getAllTiles(std::unordered_set<int3, ShashInt3> & tiles, std::optional<PlayerColor> Player, int level, MapTerrainFilterMode tileFilterMode) const
void CPrivilegedInfoCallback::getAllTiles(std::unordered_set<int3> & tiles, std::optional<PlayerColor> Player, int level, MapTerrainFilterMode tileFilterMode) const
{
if(!!Player && *Player >= PlayerColor::PLAYER_LIMIT)
{

View File

@ -26,7 +26,6 @@ struct ArtifactLocation;
class CCreatureSet;
class CStackBasicDescriptor;
class CGCreature;
struct ShashInt3;
namespace spells
{
@ -59,7 +58,7 @@ public:
void getFreeTiles(std::vector<int3> &tiles) const;
//mode 1 - only unrevealed tiles; mode 0 - all, mode -1 - only revealed
void getTilesInRange(std::unordered_set<int3, ShashInt3> & tiles,
void getTilesInRange(std::unordered_set<int3> & tiles,
const int3 & pos,
int radious,
std::optional<PlayerColor> player = std::optional<PlayerColor>(),
@ -67,7 +66,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<int3, ShashInt3> &tiles, std::optional<PlayerColor> player = std::optional<PlayerColor>(),
void getAllTiles(std::unordered_set<int3> &tiles, std::optional<PlayerColor> player = std::optional<PlayerColor>(),
int level = -1, MapTerrainFilterMode tileFilterMode = MapTerrainFilterMode::NONE) const;
//gives 3 treasures, 3 minors, 1 major -> used by Black Market and Artifact Merchant
@ -136,7 +135,7 @@ public:
virtual void sendAndApply(CPackForClient * pack) = 0;
virtual void heroExchange(ObjectInstanceID hero1, ObjectInstanceID hero2)=0; //when two heroes meet on adventure map
virtual void changeFogOfWar(int3 center, ui32 radius, PlayerColor player, bool hide) = 0;
virtual void changeFogOfWar(std::unordered_set<int3, ShashInt3> &tiles, PlayerColor player, bool hide) = 0;
virtual void changeFogOfWar(std::unordered_set<int3> &tiles, PlayerColor player, bool hide) = 0;
virtual void castSpell(const spells::Caster * caster, SpellID spellID, const int3 &pos) = 0;
};

View File

@ -117,8 +117,8 @@ public:
virtual void showThievesGuildWindow (const CGObjectInstance * obj){};
virtual void showQuestLog(){};
virtual void advmapSpellCast(const CGHeroInstance * caster, int spellID){}; //called when a hero casts a spell
virtual void tileHidden(const std::unordered_set<int3, ShashInt3> &pos){};
virtual void tileRevealed(const std::unordered_set<int3, ShashInt3> &pos){};
virtual void tileHidden(const std::unordered_set<int3> &pos){};
virtual void tileRevealed(const std::unordered_set<int3> &pos){};
virtual void newObject(const CGObjectInstance * obj){}; //eg. ship built in shipyard
virtual void availableArtifactsChanged(const CGBlackMarket *bm = nullptr){}; //bm may be nullptr, then artifacts are changed in the global pool (used by merchants in towns)
virtual void centerView (int3 pos, int focusTime){};

View File

@ -308,7 +308,7 @@ struct DLL_LINKAGE FoWChange : public CPackForClient
{
void applyGs(CGameState * gs);
std::unordered_set<int3, struct ShashInt3 > tiles;
std::unordered_set<int3> tiles;
PlayerColor player;
ui8 mode = 0; //mode==0 - hide, mode==1 - reveal
bool waitForDialogs = false;
@ -590,7 +590,7 @@ struct DLL_LINKAGE TryMoveHero : public CPackForClient
ui32 movePoints = 0;
EResult result = FAILED; //uses EResult
int3 start, end; //h3m format
std::unordered_set<int3, ShashInt3> fowRevealed; //revealed tiles
std::unordered_set<int3> fowRevealed; //revealed tiles
std::optional<int3> attackedFrom; // Set when stepping into endangered tile.
virtual void visitTyped(ICPackVisitor & visitor) override;

View File

@ -915,7 +915,7 @@ void FoWChange::applyGs(CGameState *gs)
(*fogOfWarMap)[t.z][t.x][t.y] = mode;
if (mode == 0) //do not hide too much
{
std::unordered_set<int3, ShashInt3> tilesRevealed;
std::unordered_set<int3> tilesRevealed;
for (auto & elem : gs->map->objects)
{
const CGObjectInstance *o = elem;
@ -1918,7 +1918,7 @@ void AssembledArtifact::applyGs(CGameState *gs)
[[maybe_unused]] const CArtifactInstance *transformedArt = al.getArt();
assert(transformedArt);
bool combineEquipped = !ArtifactUtils::isSlotBackpack(al.slot);
assert(vstd::contains_if(transformedArt->assemblyPossibilities(artSet, combineEquipped), [=](const CArtifact * art)->bool
assert(vstd::contains_if(ArtifactUtils::assemblyPossibilities(artSet, transformedArt->artType->getId(), combineEquipped), [=](const CArtifact * art)->bool
{
return art->getId() == builtArt->getId();
}));

View File

@ -182,18 +182,6 @@ public:
}
};
//Why not normal function?
struct ShashInt3
{
size_t operator()(int3 const& pos) const
{
size_t ret = std::hash<int>()(pos.x);
vstd::hash_combine(ret, pos.y);
vstd::hash_combine(ret, pos.z);
return ret;
}
};
template<typename Container>
int3 findClosestTile (Container & container, int3 dest)
{
@ -215,3 +203,15 @@ int3 findClosestTile (Container & container, int3 dest)
}
VCMI_LIB_NAMESPACE_END
template<>
struct std::hash<VCMI_LIB_WRAP_NAMESPACE(int3)> {
size_t operator()(VCMI_LIB_WRAP_NAMESPACE(int3) const& pos) const
{
size_t ret = std::hash<int>()(pos.x);
VCMI_LIB_WRAP_NAMESPACE(vstd)::hash_combine(ret, pos.y);
VCMI_LIB_WRAP_NAMESPACE(vstd)::hash_combine(ret, pos.z);
return ret;
}
};

View File

@ -7136,11 +7136,11 @@ void CGameHandler::removeAfterVisit(const CGObjectInstance *object)
void CGameHandler::changeFogOfWar(int3 center, ui32 radius, PlayerColor player, bool hide)
{
std::unordered_set<int3, ShashInt3> tiles;
std::unordered_set<int3> tiles;
getTilesInRange(tiles, center, radius, player, hide? -1 : 1);
if (hide)
{
std::unordered_set<int3, ShashInt3> observedTiles; //do not hide tiles observed by heroes. May lead to disastrous AI problems
std::unordered_set<int3> observedTiles; //do not hide tiles observed by heroes. May lead to disastrous AI problems
auto p = getPlayerState(player);
for (auto h : p->heroes)
{
@ -7156,7 +7156,7 @@ void CGameHandler::changeFogOfWar(int3 center, ui32 radius, PlayerColor player,
changeFogOfWar(tiles, player, hide);
}
void CGameHandler::changeFogOfWar(std::unordered_set<int3, ShashInt3> &tiles, PlayerColor player, bool hide)
void CGameHandler::changeFogOfWar(std::unordered_set<int3> &tiles, PlayerColor player, bool hide)
{
FoWChange fow;
fow.tiles = tiles;

View File

@ -200,7 +200,7 @@ public:
void heroExchange(ObjectInstanceID hero1, ObjectInstanceID hero2) override;
void changeFogOfWar(int3 center, ui32 radius, PlayerColor player, bool hide) override;
void changeFogOfWar(std::unordered_set<int3, ShashInt3> &tiles, PlayerColor player, bool hide) override;
void changeFogOfWar(std::unordered_set<int3> &tiles, PlayerColor player, bool hide) override;
void castSpell(const spells::Caster * caster, SpellID spellID, const int3 &pos) override;