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

Initial refactoring to encapsulate adventure map

This commit is contained in:
Ivan Savenko 2023-04-20 22:03:28 +03:00
parent ee12685748
commit f1902ab247
13 changed files with 215 additions and 236 deletions

View File

@ -15,7 +15,6 @@
#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"
@ -161,8 +160,7 @@ void HeroPathStorage::removeLastNode(const CGHeroInstance *h)
void HeroPathStorage::erasePath(const CGHeroInstance *h)
{
paths.erase(h);
adventureInt->updateMoveHero(h, false);
adventureInt->onHeroChanged(h);
}
void HeroPathStorage::verifyPath(const CGHeroInstance *h)
@ -258,7 +256,6 @@ void CPlayerInterface::yourTurn()
LOCPLINT = this;
GH.curInt = this;
adventureInt->selection = nullptr;
NotificationHandler::notify("Your turn");
@ -267,7 +264,7 @@ void CPlayerInterface::yourTurn()
if (firstCall)
{
if(CSH->howManyPlayerInterfaces() == 1)
adventureInt->setPlayer(playerID);
adventureInt->onCurrentPlayerChanged(playerID);
autosaveCount = getLastIndex(prefix + "Autosave_");
@ -285,7 +282,7 @@ void CPlayerInterface::yourTurn()
autosaveCount %= 5;
}
adventureInt->setPlayer(playerID);
adventureInt->onCurrentPlayerChanged(playerID);
if (CSH->howManyPlayerInterfaces() > 1) //hot seat message
{
@ -324,15 +321,15 @@ 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));
adventureInt->onMapTileChanged(hero->convertToVisitablePos(details.start));
adventureInt->onMapTileChanged(hero->convertToVisitablePos(details.end));
bool directlyAttackingCreature = details.attackedFrom && paths.hasPath(hero) && paths.getPath(hero).endPos() == *details.attackedFrom;
@ -375,16 +372,14 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details, bool verbose)
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
{
@ -427,33 +422,8 @@ 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;
adventureInt->onHeroChanged(hero);
paths.erasePath(hero);
}
@ -471,7 +441,7 @@ void CPlayerInterface::heroCreated(const CGHeroInstance * hero)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
wanderingHeroes.push_back(hero);
adventureInt->heroList->update(hero);
adventureInt->onHeroChanged(hero);
}
void CPlayerInterface::openTownWindow(const CGTownInstance * town)
{
@ -486,9 +456,7 @@ void CPlayerInterface::openTownWindow(const CGTownInstance * town)
void CPlayerInterface::activateForSpectator()
{
adventureInt->state = CAdvMapInt::INGAME;
adventureInt->activate();
adventureInt->minimap->activate();
}
void CPlayerInterface::heroPrimarySkillChanged(const CGHeroInstance * hero, int which, si64 val)
@ -499,8 +467,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 +484,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,7 +528,6 @@ 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
{
@ -573,8 +540,8 @@ void CPlayerInterface::heroInGarrisonChange(const CGTownInstance *town)
if (town->visitingHero->tempOwner == playerID && !vstd::contains(wanderingHeroes,town->visitingHero)) // our hero
wanderingHeroes.push_back(town->visitingHero);
}
adventureInt->heroList->update();
adventureInt->updateNextHero(nullptr);
adventureInt->onHeroChanged(nullptr);
adventureInt->onTownChanged(town);
if(castleInt)
{
@ -627,7 +594,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)
{
@ -653,15 +628,6 @@ void CPlayerInterface::garrisonChanged( const CGObjectInstance * 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 +646,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 +675,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 +885,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 +892,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 +1033,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));
@ -1235,14 +1198,14 @@ void CPlayerInterface::tileRevealed(const std::unordered_set<int3, ShashInt3> &p
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->onMapTileChanged(po);
}
void CPlayerInterface::tileHidden(const std::unordered_set<int3, ShashInt3> &pos)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
for (auto & po : pos)
adventureInt->minimap->updateTile(po);
adventureInt->onMapTileChanged(po);
}
void CPlayerInterface::openHeroWindow(const CGHeroInstance *hero)
@ -1286,7 +1249,7 @@ 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
@ -1330,14 +1293,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 (adventureInt)
adventureInt->onHeroWokeUp(h);
boost::thread moveHeroTask(std::bind(&CPlayerInterface::doMoveHero,this,h,path));
}
@ -1415,6 +1372,7 @@ 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)
{
@ -1424,17 +1382,19 @@ void CPlayerInterface::objectPropertyChanged(const SetObjectProperty * sop)
for(auto & po : pos)
{
if(cb->isVisible(po))
adventureInt->minimap->updateTile(po);
adventureInt->onMapTileChanged(po);
}
if(obj->ID == Obj::TOWN)
{
auto town = static_cast<const CGTownInstance *>(obj);
if(obj->tempOwner == playerID)
towns.push_back(static_cast<const CGTownInstance *>(obj));
towns.push_back(town);
else
towns -= obj;
adventureInt->townList->update();
adventureInt->minimap->update();
adventureInt->onTownChanged(town);
adventureInt->onMapTilesChanged();
}
assert(cb->getTownsInfo().size() == towns.size());
}
@ -1456,7 +1416,7 @@ void CPlayerInterface::initializeHeroTownList()
towns = cb->getTownsInfo();
if(adventureInt)
adventureInt->updateNextHero(nullptr);
adventureInt->onHeroChanged(nullptr);
}
void CPlayerInterface::showRecruitmentDialog(const CGDwelling *dwelling, const CArmedInstance *dst, int level)
@ -1545,7 +1505,7 @@ void CPlayerInterface::objectRemoved(const CGObjectInstance * obj)
void CPlayerInterface::objectRemovedAfter()
{
EVENT_HANDLER_CALLED_BY_CLIENT;
adventureInt->minimap->update();
adventureInt->onMapTilesChanged();
}
void CPlayerInterface::playerBlocked(int reason, bool start)
@ -1558,8 +1518,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;
@ -1810,21 +1769,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 +1877,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 +1899,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 +1928,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 +1941,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());
@ -2016,8 +1960,6 @@ void CPlayerInterface::playerStartsTurn(PlayerColor player)
}
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);
}
@ -2057,7 +1999,7 @@ CPlayerInterface::SpellbookLastSetting::SpellbookLastSetting()
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 +2007,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 +2187,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

@ -240,7 +240,6 @@ public:
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

View File

@ -387,12 +387,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 " + adventureInt->getCurrentArmy()->getObjectName() + "\n");
printCommandMessage(format(adventureInt->getCurrentArmy()->getBonusList()) + "\n");
printCommandMessage("\nInherited bonuses:\n");
TCNodes parents;
adventureInt->curArmy()->getParents(parents);
adventureInt->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 +416,7 @@ void ClientCommandManager::handleTellCommand(std::istringstream& singleWordBuffe
void ClientCommandManager::handleMpCommand()
{
if(const CGHeroInstance* h = adventureInt->curHero())
if(const CGHeroInstance* h = adventureInt->getCurrentHero())
printCommandMessage(std::to_string(h->movement) + "; max: " + std::to_string(h->maxMovePoints(true)) + "/" + std::to_string(h->maxMovePoints(false)) + "\n");
}

View File

@ -91,7 +91,7 @@ CAdvMapInt::CAdvMapInt():
resdatabar(new CResDataBar),
mapAudio(new MapAudioPlayer()),
terrain(new MapView(Point(ADVOPT.advmapX, ADVOPT.advmapY), Point(ADVOPT.advmapW, ADVOPT.advmapH))),
state(NA),
state(EGameStates::NA),
spellBeingCasted(nullptr),
selection(nullptr),
activeMapPanel(nullptr),
@ -216,7 +216,7 @@ CAdvMapInt::CAdvMapInt():
worldViewUnderground = makeButton(294, std::bind(&CAdvMapInt::fswitchLevel,this), worldViewUndergroundConfig, SDLK_u);
panelWorldView->addChildColorableButton(worldViewUnderground);
setPlayer(LOCPLINT->playerID);
onCurrentPlayerChanged(LOCPLINT->playerID);
int iconColorMultiplier = player.getNum() * 19;
int wvLeft = heroList->pos.x - 2; // TODO correct drawing position
@ -259,7 +259,7 @@ void CAdvMapInt::fworldViewBack()
{
exitWorldView();
auto hero = curHero();
auto hero = getCurrentHero();
if (hero)
centerOnObject(hero);
}
@ -318,7 +318,7 @@ void CAdvMapInt::fshowQuestlog()
void CAdvMapInt::fsleepWake()
{
const CGHeroInstance *h = curHero();
const CGHeroInstance *h = getCurrentHero();
if (!h)
return;
bool newSleep = !isHeroSleeping(h);
@ -339,7 +339,7 @@ void CAdvMapInt::fsleepWake()
void CAdvMapInt::fmoveHero()
{
const CGHeroInstance *h = curHero();
const CGHeroInstance *h = getCurrentHero();
if (!h || !LOCPLINT->paths.hasPath(h) || CGI->mh->hasOngoingAnimations())
return;
@ -348,12 +348,12 @@ void CAdvMapInt::fmoveHero()
void CAdvMapInt::fshowSpellbok()
{
if (!curHero()) //checking necessary values
if (!getCurrentHero()) //checking necessary values
return;
centerOnObject(selection);
GH.pushIntT<CSpellWindow>(curHero(), LOCPLINT, false);
GH.pushIntT<CSpellWindow>(getCurrentHero(), LOCPLINT, false);
}
void CAdvMapInt::fadventureOPtions()
@ -372,7 +372,7 @@ void CAdvMapInt::fnextHero()
int next = getNextHeroIndex(vstd::find_pos(LOCPLINT->wanderingHeroes, hero));
if (next < 0)
return;
select(LOCPLINT->wanderingHeroes[next], true);
setSelection(LOCPLINT->wanderingHeroes[next], true);
}
void CAdvMapInt::fendTurn()
@ -420,20 +420,6 @@ void CAdvMapInt::updateSleepWake(const CGHeroInstance *h)
sleepWake->assignedKeys.insert(state ? SDLK_w : SDLK_z);
}
void CAdvMapInt::updateMoveHero(const CGHeroInstance *h, tribool hasPath)
{
if(!h)
{
moveHero->block(true);
return;
}
//default value is for everywhere but CPlayerInterface::moveHero, because paths are not updated from there immediately
if(boost::logic::indeterminate(hasPath))
hasPath = LOCPLINT->paths.hasPath(h);
moveHero->block(!(bool)hasPath || (h->movement == 0));
}
void CAdvMapInt::updateSpellbook(const CGHeroInstance *h)
{
spellbook->block(!h);
@ -460,8 +446,13 @@ int CAdvMapInt::getNextHeroIndex(int startIndex)
return -1;
}
void CAdvMapInt::updateNextHero(const CGHeroInstance *h)
void CAdvMapInt::onHeroChanged(const CGHeroInstance *h)
{
heroList->update(h);
if (h == getCurrentHero())
adventureInt->infoBar->showSelection();
int start = vstd::find_pos(LOCPLINT->wanderingHeroes, h);
int next = getNextHeroIndex(start);
if (next < 0)
@ -472,6 +463,27 @@ void CAdvMapInt::updateNextHero(const CGHeroInstance *h)
const CGHeroInstance *nextH = LOCPLINT->wanderingHeroes[next];
bool noActiveHeroes = (next == start) && ((nextH->movement == 0) || isHeroSleeping(nextH));
nextHero->block(noActiveHeroes);
if(!h)
{
moveHero->block(true);
return;
}
//default value is for everywhere but CPlayerInterface::moveHero, because paths are not updated from there immediately
bool hasPath = LOCPLINT->paths.hasPath(h);
moveHero->block(!(bool)hasPath || (h->movement == 0));
}
void CAdvMapInt::onTownChanged(const CGTownInstance * town)
{
townList->update(town);
adventureInt->infoBar->showSelection();
}
void CAdvMapInt::showInfoBoxMessage(const std::vector<Component> & components, std::string message, int timer)
{
infoBar->pushComponents(components, message, timer);
}
void CAdvMapInt::activate()
@ -532,7 +544,7 @@ void CAdvMapInt::showAll(SDL_Surface * to)
{
bg->draw(to, 0, 0);
if(state != INGAME)
if(state != EGameStates::INGAME)
return;
switch (mode)
@ -565,18 +577,30 @@ bool CAdvMapInt::isHeroSleeping(const CGHeroInstance *hero)
return vstd::contains(LOCPLINT->sleepingHeroes, hero);
}
void CAdvMapInt::onHeroWokeUp(const CGHeroInstance * hero)
{
if (!isHeroSleeping(hero))
return;
sleepWake->clickLeft(true, false);
sleepWake->clickLeft(false, true);
//could've just called
//adventureInt->fsleepWake();
//but no authentic button click/sound ;-)
}
void CAdvMapInt::setHeroSleeping(const CGHeroInstance *hero, bool sleep)
{
if (sleep)
LOCPLINT->sleepingHeroes.push_back(hero); //FIXME: should we check for existence?
else
LOCPLINT->sleepingHeroes -= hero;
updateNextHero(nullptr);
onHeroChanged(nullptr);
}
void CAdvMapInt::show(SDL_Surface * to)
{
if(state != INGAME)
if(state != EGameStates::INGAME)
return;
handleMapScrollingUpdate();
@ -636,7 +660,7 @@ void CAdvMapInt::selectionChanged()
{
const CGTownInstance *to = LOCPLINT->towns[townList->getSelectedIndex()];
if (selection != to)
select(to);
setSelection(to);
}
void CAdvMapInt::centerOnTile(int3 on)
@ -682,8 +706,8 @@ void CAdvMapInt::keyPressed(const SDL_Keycode & key)
if (mode != EAdvMapMode::NORMAL)
return;
const CGHeroInstance *h = curHero(); //selected hero
const CGTownInstance *t = curTown(); //selected town
const CGHeroInstance *h = getCurrentHero(); //selected hero
const CGTownInstance *t = getCurrentTown(); //selected town
switch(key)
{
@ -843,7 +867,7 @@ void CAdvMapInt::keyPressed(const SDL_Keycode & key)
const CGPath & path = LOCPLINT->paths.getPath(h);
if (path.nodes.size() > 2)
updateMoveHero(h);
onHeroChanged(h);
else
if(!path.nodes[0].turns)
LOCPLINT->moveHero(h, path);
@ -874,7 +898,7 @@ std::optional<Point> CAdvMapInt::keyToMoveDirection(const SDL_Keycode & key)
return std::nullopt;
}
void CAdvMapInt::select(const CArmedInstance *sel, bool centerView)
void CAdvMapInt::setSelection(const CArmedInstance *sel, bool centerView)
{
assert(sel);
if(selection != sel)
@ -893,7 +917,7 @@ void CAdvMapInt::select(const CArmedInstance *sel, bool centerView)
heroList->select(nullptr);
updateSleepWake(nullptr);
updateMoveHero(nullptr);
onHeroChanged(nullptr);
updateSpellbook(nullptr);
}
else //hero selected
@ -907,7 +931,7 @@ void CAdvMapInt::select(const CArmedInstance *sel, bool centerView)
LOCPLINT->paths.verifyPath(hero);
updateSleepWake(hero);
updateMoveHero(hero);
onHeroChanged(hero);
updateSpellbook(hero);
}
townList->redraw();
@ -962,11 +986,23 @@ bool CAdvMapInt::isActive()
void CAdvMapInt::startHotSeatWait(PlayerColor Player)
{
state = WAITING;
state = EGameStates::WAITING;
}
void CAdvMapInt::setPlayer(PlayerColor Player)
void CAdvMapInt::onMapTileChanged(const int3 & mapPosition)
{
minimap->updateTile(mapPosition);
}
void CAdvMapInt::onMapTilesChanged()
{
minimap->update();
}
void CAdvMapInt::onCurrentPlayerChanged(PlayerColor Player)
{
selection = nullptr;
if (Player == player)
return;
@ -981,12 +1017,13 @@ void CAdvMapInt::setPlayer(PlayerColor Player)
void CAdvMapInt::startTurn()
{
state = INGAME;
state = EGameStates::INGAME;
if(LOCPLINT->cb->getCurrentPlayer() == LOCPLINT->playerID
|| settings["session"]["spectate"].Bool())
{
adjustActiveness(false);
minimap->setAIRadar(false);
infoBar->showSelection();
}
}
@ -1012,17 +1049,17 @@ void CAdvMapInt::initializeNewTurn()
//select first hero if available.
if (heroToSelect != nullptr)
{
select(heroToSelect, centerView);
setSelection(heroToSelect, centerView);
}
else if (LOCPLINT->towns.size())
select(LOCPLINT->towns.front(), centerView);
setSelection(LOCPLINT->towns.front(), centerView);
else
select(LOCPLINT->wanderingHeroes.front());
setSelection(LOCPLINT->wanderingHeroes.front());
//show new day animation and sound on infobar
infoBar->showDate();
updateNextHero(nullptr);
onHeroChanged(nullptr);
showAll(screen);
mapAudio->onPlayerTurnStarted();
@ -1103,9 +1140,9 @@ void CAdvMapInt::onTileLeftClicked(const int3 &mapPos)
if(selection == topBlocking) //selected town clicked
LOCPLINT->openTownWindow(static_cast<const CGTownInstance*>(topBlocking));
else if(canSelect)
select(static_cast<const CArmedInstance*>(topBlocking), false);
setSelection(static_cast<const CArmedInstance*>(topBlocking), false);
}
else if(const CGHeroInstance * currentHero = curHero()) //hero is selected
else if(const CGHeroInstance * currentHero = getCurrentHero()) //hero is selected
{
isHero = true;
@ -1117,7 +1154,7 @@ void CAdvMapInt::onTileLeftClicked(const int3 &mapPos)
}
else if(canSelect && pn->turns == 255 ) //selectable object at inaccessible tile
{
select(static_cast<const CArmedInstance*>(topBlocking), false);
setSelection(static_cast<const CArmedInstance*>(topBlocking), false);
return;
}
else //still here? we need to move hero if we clicked end of already selected path or calculate a new path otherwise
@ -1132,7 +1169,7 @@ void CAdvMapInt::onTileLeftClicked(const int3 &mapPos)
else //remove old path and find a new one if we clicked on accessible tile
{
LOCPLINT->paths.setPath(currentHero, mapPos);
updateMoveHero(currentHero);
onHeroChanged(currentHero);
}
}
} //end of hero is selected "case"
@ -1164,7 +1201,7 @@ void CAdvMapInt::onTileHovered(const int3 &mapPos)
if(objAtTile)
{
objRelations = LOCPLINT->cb->getPlayerRelations(LOCPLINT->playerID, objAtTile->tempOwner);
std::string text = curHero() ? objAtTile->getHoverText(curHero()) : objAtTile->getHoverText(LOCPLINT->playerID);
std::string text = getCurrentHero() ? objAtTile->getHoverText(getCurrentHero()) : objAtTile->getHoverText(LOCPLINT->playerID);
boost::replace_all(text,"\n"," ");
statusbar->write(text);
}
@ -1211,7 +1248,7 @@ void CAdvMapInt::onTileHovered(const int3 &mapPos)
else
CCS->curh->set(Cursor::Map::POINTER);
}
else if(const CGHeroInstance * hero = curHero())
else if(const CGHeroInstance * hero = getCurrentHero())
{
std::array<Cursor::Map, 4> cursorMove = { Cursor::Map::T1_MOVE, Cursor::Map::T2_MOVE, Cursor::Map::T3_MOVE, Cursor::Map::T4_MOVE, };
std::array<Cursor::Map, 4> cursorAttack = { Cursor::Map::T1_ATTACK, Cursor::Map::T2_ATTACK, Cursor::Map::T3_ATTACK, Cursor::Map::T4_ATTACK, };
@ -1357,12 +1394,12 @@ void CAdvMapInt::leaveCastingMode(bool cast, int3 dest)
activate();
if(cast)
LOCPLINT->cb->castSpell(curHero(), id, dest);
LOCPLINT->cb->castSpell(getCurrentHero(), id, dest);
else
LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[731]); //Spell cancelled
}
const CGHeroInstance * CAdvMapInt::curHero() const
const CGHeroInstance * CAdvMapInt::getCurrentHero() const
{
if(selection && selection->ID == Obj::HERO)
return dynamic_cast<const CGHeroInstance *>(selection);
@ -1370,7 +1407,7 @@ const CGHeroInstance * CAdvMapInt::curHero() const
return nullptr;
}
const CGTownInstance * CAdvMapInt::curTown() const
const CGTownInstance * CAdvMapInt::getCurrentTown() const
{
if(selection && selection->ID == Obj::TOWN)
return dynamic_cast<const CGTownInstance *>(selection);
@ -1378,7 +1415,7 @@ const CGTownInstance * CAdvMapInt::curTown() const
return nullptr;
}
const CArmedInstance * CAdvMapInt::curArmy() const
const CArmedInstance * CAdvMapInt::getCurrentArmy() const
{
if (selection)
return dynamic_cast<const CArmedInstance *>(selection);
@ -1427,18 +1464,6 @@ void CAdvMapInt::adjustActiveness(bool aiTurnStart)
activate();
}
void CAdvMapInt::quickCombatLock()
{
if(!duringAITurn)
deactivate();
}
void CAdvMapInt::quickCombatUnlock()
{
if(!duringAITurn)
activate();
}
void CAdvMapInt::exitWorldView()
{
mode = EAdvMapMode::NORMAL;

View File

@ -23,6 +23,7 @@ class CArmedInstance;
class IShipyard;
struct CGPathNode;
struct ObjectPosInfo;
struct Component;
VCMI_LIB_NAMESPACE_END
@ -54,12 +55,9 @@ enum class EAdvMapMode
/// can get to the towns and heroes.
class CAdvMapInt : 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 EGameStates {NA, INGAME, WAITING};
EGameStates state;
EAdvMapMode mode;
@ -145,6 +143,11 @@ private:
std::optional<Point> keyToMoveDirection(const SDL_Keycode & key);
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 endingTurn();
public:
CAdvMapInt();
@ -162,9 +165,28 @@ public:
// public interface
/// called by MapView whenever currently visible area changes
/// visibleArea describen now visible map section measured in tiles
void onMapViewMoved(const Rect & visibleArea, int mapLevel);
void startHotSeatWait(PlayerColor Player);
void startTurn();
void initializeNewTurn();
void aiTurnStarted();
/// Called by PlayerInterface when hero is forced to wake up, e.g. on moving sleeping hero
void onHeroWokeUp(const CGHeroInstance * hero);
/// Called by PlayerInterface when current player changes in hotseat
void onCurrentPlayerChanged(PlayerColor Player);
/// Called by PlayerInterface when specific map tile changed and must be updated on minimap
void onMapTileChanged(const int3 & mapPosition);
/// Called by PlayerInterface when unknown number of tiles changed and minimap should redraw
void onMapTilesChanged();
/// 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 map audio should be paused, e.g. on combat or town scren access
void onAudioPaused();
@ -172,36 +194,35 @@ public:
/// 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 currently selected object
void setSelection(const CArmedInstance *sel, bool centerView = true);
/// 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);
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);
const CGHeroInstance * getCurrentHero() const;
const CGTownInstance * getCurrentTown() const;
const CArmedInstance * getCurrentArmy() const;
/// returns area of screen covered by terrain (main game area)
Rect terrainAreaPixels() const;
@ -217,6 +238,7 @@ public:
/// opens world view with specific info, e.g. after View Earth/Air is shown
void openWorldView(const std::vector<ObjectPosInfo>& objectPositions, bool showTerrain);
};
extern std::shared_ptr<CAdvMapInt> adventureInt;

View File

@ -41,7 +41,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 = adventureInt->getCurrentHero())
dig->addCallback(std::bind(&CPlayerInterface::tryDiggging, LOCPLINT, h));
else
dig->block(true);

View File

@ -259,7 +259,7 @@ void CInGameConsole::endEnteringText(bool processEnteredText)
clientCommandThread.detach();
}
else
LOCPLINT->cb->sendMessage(txt, adventureInt->curArmy());
LOCPLINT->cb->sendMessage(txt, adventureInt->getCurrentArmy());
}
enteredText.clear();

View File

@ -237,15 +237,15 @@ void CInfoBar::reset()
void CInfoBar::showSelection()
{
OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE);
if(adventureInt->curHero())
if(adventureInt->getCurrentHero())
{
showHeroSelection(adventureInt->curHero());
showHeroSelection(adventureInt->getCurrentHero());
return;
}
if(adventureInt->curTown())
if(adventureInt->getCurrentTown())
{
showTownSelection(adventureInt->curTown());
showTownSelection(adventureInt->getCurrentTown());
return;
}

View File

@ -203,8 +203,8 @@ std::shared_ptr<CIntObject> CHeroList::CHeroItem::genSelection()
void CHeroList::CHeroItem::select(bool on)
{
if(on && adventureInt->curHero() != hero)
adventureInt->select(hero);
if(on && adventureInt->getCurrentHero() != hero)
adventureInt->setSelection(hero);
}
void CHeroList::CHeroItem::open()
@ -254,8 +254,8 @@ 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());
if (adventureInt->getCurrentHero())
select(adventureInt->getCurrentHero());
CList::update();
}
@ -292,8 +292,8 @@ void CTownList::CTownItem::update()
void CTownList::CTownItem::select(bool on)
{
if (on && adventureInt->curTown() != town)
adventureInt->select(town);
if (on && adventureInt->getCurrentTown() != town)
adventureInt->setSelection(town);
}
void CTownList::CTownItem::open()
@ -326,8 +326,8 @@ 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());
if (adventureInt->getCurrentTown())
select(adventureInt->getCurrentTown());
CList::update();
}

View File

@ -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(adventureInt->getCurrentHero() != nullptr)
{
if(obj->id == adventureInt->curHero()->id)
if(obj->id == adventureInt->getCurrentHero()->id)
return true;
}
}
@ -206,7 +206,7 @@ MapRendererAdventureContext::MapRendererAdventureContext(const MapRendererContex
const CGPath * MapRendererAdventureContext::currentPath() const
{
const auto * hero = adventureInt->curHero();
const auto * hero = adventureInt->getCurrentHero();
if(!hero)
return nullptr;

View File

@ -1229,9 +1229,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);
adventureInt->setSelection(town->visitingHero);
else
adventureInt->select(town);
adventureInt->setSelection(town);
}
CWindowObject::close();
}
@ -1239,7 +1239,7 @@ 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
adventureInt->setSelection(town->visitingHero);//according to assert(ho == adventureInt->selection) in the eraseCurrentPathOf
LOCPLINT->cb->teleportHero(town->visitingHero, dest);
LOCPLINT->paths.erasePath(town->visitingHero);
}

View File

@ -332,8 +332,8 @@ void CRClickPopup::createAndPush(const CGObjectInstance * obj, const Point & p,
}
else
{
if(adventureInt->curHero())
CRClickPopup::createAndPush(obj->getHoverText(adventureInt->curHero()));
if(adventureInt->getCurrentHero())
CRClickPopup::createAndPush(obj->getHoverText(adventureInt->getCurrentHero()));
else
CRClickPopup::createAndPush(obj->getHoverText(LOCPLINT->playerID));
}
@ -376,7 +376,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, adventureInt->getCurrentTown()); //todo: should this be nearest hero?
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
tooltip = std::make_shared<CTownTooltip>(Point(9, 10), iah);
@ -386,7 +386,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, adventureInt->getCurrentHero());//todo: should this be nearest hero?
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
tooltip = std::make_shared<CHeroTooltip>(Point(9, 10), iah);
@ -405,7 +405,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 = adventureInt->getCurrentArmy();
if(nullptr == specific)
{

View File

@ -1915,7 +1915,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();
}));