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

Further refactoring to cleanup code of advmap and locplint

This commit is contained in:
Ivan Savenko
2023-04-17 01:09:25 +03:00
parent 20de44d4a5
commit 4a169972f0
7 changed files with 237 additions and 337 deletions

View File

@@ -254,24 +254,42 @@ 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
// after map load - remove all active windows and replace them with adventure map
GH.popInts ((int)GH.listInt.size());
GH.pushInt (adventureInt);
}
else
{
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)
// 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->aiTurnStarted();
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;
}
}
@@ -285,35 +303,11 @@ void CPlayerInterface::yourTurn()
GH.curInt = this;
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->onCurrentPlayerChanged(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->onCurrentPlayerChanged(playerID);
performAutosave();
if (CSH->howManyPlayerInterfaces() > 1) //hot seat message
{
adventureInt->startHotSeatWait(playerID);
adventureInt->onHotseatWaitStarted(playerID);
makingTurn = true;
std::string msg = CGI->generaltexth->allTexts[13];
@@ -325,7 +319,7 @@ void CPlayerInterface::yourTurn()
else
{
makingTurn = true;
adventureInt->startTurn();
adventureInt->onPlayerTurnStarted(playerID);
}
}
acceptTurn();
@@ -343,11 +337,9 @@ void CPlayerInterface::acceptTurn()
{
waitWhileDialog(); // wait for player to accept turn in hot-seat mode
adventureInt->startTurn();
adventureInt->onPlayerTurnStarted(playerID);
}
adventureInt->initializeNewTurn();
// warn player if he has no town
if (cb->howManyTowns() == 0)
{
@@ -532,11 +524,6 @@ void CPlayerInterface::openTownWindow(const CGTownInstance * town)
GH.pushInt(newCastleInt);
}
void CPlayerInterface::activateForSpectator()
{
adventureInt->activate();
}
void CPlayerInterface::heroPrimarySkillChanged(const CGHeroInstance * hero, int which, si64 val)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
@@ -698,11 +685,6 @@ 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;
@@ -1669,10 +1651,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
@@ -1690,9 +1674,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();
}
}
@@ -1710,7 +1692,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
{

View File

@@ -91,30 +91,35 @@ public:
/// Central class for managing user interface logic
class CPlayerInterface : public CGameInterface, public IUpdateable
{
public:
HeroPathStorage paths;
// -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;
HeroPathStorage paths;
//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
@@ -123,8 +128,6 @@ public:
//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
{
@@ -141,6 +144,7 @@ public:
}
} spellbookSettings;
public:
void update() override;
void initializeHeroTownList();
int getLastIndex(std::string namePrefix);
@@ -233,7 +237,6 @@ public:
//-------------//
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);
@@ -241,7 +244,6 @@ public:
void openTownWindow(const CGTownInstance * town); //shows townscreen
void openHeroWindow(const CGHeroInstance * hero); //shows hero window with given hero
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);
@@ -265,11 +267,8 @@ public:
~CPlayerInterface();
private:
template <typename Handler> void serializeTempl(Handler &h, const int version);
private:
struct IgnoreEvents
{
CPlayerInterface & owner;
@@ -284,14 +283,15 @@ private:
};
bool duringMovement;
bool ignoreEvents;
size_t numOfMovedArts;
void doMoveHero(const CGHeroInstance *h, CGPath path);
void setMovementStatus(bool value);
/// Performs autosave, if needed according to settings
void performAutosave();
};
extern CPlayerInterface * LOCPLINT;

View File

@@ -55,34 +55,7 @@
std::shared_ptr<CAdventureMapInterface> adventureInt;
void CAdventureMapInterface::setScrollingCursor(ui8 direction) const
{
if(direction & CAdventureMapInterface::RIGHT)
{
if(direction & CAdventureMapInterface::UP)
CCS->curh->set(Cursor::Map::SCROLL_NORTHEAST);
else if(direction & CAdventureMapInterface::DOWN)
CCS->curh->set(Cursor::Map::SCROLL_SOUTHEAST);
else
CCS->curh->set(Cursor::Map::SCROLL_EAST);
}
else if(direction & CAdventureMapInterface::LEFT)
{
if(direction & CAdventureMapInterface::UP)
CCS->curh->set(Cursor::Map::SCROLL_NORTHWEST);
else if(direction & CAdventureMapInterface::DOWN)
CCS->curh->set(Cursor::Map::SCROLL_SOUTHWEST);
else
CCS->curh->set(Cursor::Map::SCROLL_WEST);
}
else if(direction & CAdventureMapInterface::UP)
CCS->curh->set(Cursor::Map::SCROLL_NORTH);
else if(direction & CAdventureMapInterface::DOWN)
CCS->curh->set(Cursor::Map::SCROLL_SOUTH);
}
CAdventureMapInterface::CAdventureMapInterface():
mode(EAdvMapMode::NORMAL),
minimap(new CMinimap(Rect(ADVOPT.minimapX, ADVOPT.minimapY, ADVOPT.minimapW, ADVOPT.minimapH))),
statusbar(CGStatusBar::create(ADVOPT.statusbarX,ADVOPT.statusbarY,ADVOPT.statusbarG)),
heroList(new CHeroList(ADVOPT.hlistSize, Point(ADVOPT.hlistX, ADVOPT.hlistY), ADVOPT.hlistAU, ADVOPT.hlistAD)),
@@ -91,13 +64,11 @@ CAdventureMapInterface::CAdventureMapInterface():
resdatabar(new CResDataBar),
mapAudio(new MapAudioPlayer()),
terrain(new MapView(Point(ADVOPT.advmapX, ADVOPT.advmapY), Point(ADVOPT.advmapW, ADVOPT.advmapH))),
state(EGameStates::NA),
state(EGameState::NOT_INITIALIZED),
spellBeingCasted(nullptr),
selection(nullptr),
currentSelection(nullptr),
activeMapPanel(nullptr),
duringAITurn(false),
scrollingDir(0),
scrollingState(false)
scrollingCursorSet(false)
{
pos.x = pos.y = 0;
pos.w = GH.screenDimensions().x;
@@ -218,7 +189,7 @@ CAdventureMapInterface::CAdventureMapInterface():
onCurrentPlayerChanged(LOCPLINT->playerID);
int iconColorMultiplier = player.getNum() * 19;
int iconColorMultiplier = currentPlayerID.getNum() * 19;
int wvLeft = heroList->pos.x - 2; // TODO correct drawing position
//int wvTop = 195;
for (int i = 0; i < 5; ++i)
@@ -246,8 +217,6 @@ CAdventureMapInterface::CAdventureMapInterface():
underground->block(!CGI->mh->getMap()->twoLevel);
questlog->block(!CGI->mh->getMap()->quests.size());
worldViewUnderground->block(!CGI->mh->getMap()->twoLevel);
addUsedEvents(MOVE);
}
void CAdventureMapInterface::fshowOverview()
@@ -351,7 +320,7 @@ void CAdventureMapInterface::fshowSpellbok()
if (!getCurrentHero()) //checking necessary values
return;
centerOnObject(selection);
centerOnObject(currentSelection);
GH.pushIntT<CSpellWindow>(getCurrentHero(), LOCPLINT, false);
}
@@ -368,7 +337,7 @@ void CAdventureMapInterface::fsystemOptions()
void CAdventureMapInterface::fnextHero()
{
auto hero = dynamic_cast<const CGHeroInstance*>(selection);
auto hero = dynamic_cast<const CGHeroInstance*>(currentSelection);
int next = getNextHeroIndex(vstd::find_pos(LOCPLINT->wanderingHeroes, hero));
if (next < 0)
return;
@@ -451,7 +420,7 @@ void CAdventureMapInterface::onHeroChanged(const CGHeroInstance *h)
heroList->update(h);
if (h == getCurrentHero())
adventureInt->infoBar->showSelection();
infoBar->showSelection();
int start = vstd::find_pos(LOCPLINT->wanderingHeroes, h);
int next = getNextHeroIndex(start);
@@ -478,7 +447,7 @@ void CAdventureMapInterface::onHeroChanged(const CGHeroInstance *h)
void CAdventureMapInterface::onTownChanged(const CGTownInstance * town)
{
townList->update(town);
adventureInt->infoBar->showSelection();
infoBar->showSelection();
}
void CAdventureMapInterface::showInfoBoxMessage(const std::vector<Component> & components, std::string message, int timer)
@@ -501,10 +470,12 @@ void CAdventureMapInterface::activate()
LOCPLINT->cingconsole->pos = this->pos;
}
if(!duringAITurn)
if(state != EGameState::ENEMY_TURN)
{
assert(state == EGameState::MAKING_TURN);
activeMapPanel->activate();
if (mode == EAdvMapMode::NORMAL)
if (state == EGameState::MAKING_TURN)
{
heroList->activate();
townList->activate();
@@ -522,13 +493,13 @@ void CAdventureMapInterface::deactivate()
{
CIntObject::deactivate();
if(!duringAITurn)
if(state != EGameState::ENEMY_TURN)
{
scrollingDir = 0;
assert(state == EGameState::MAKING_TURN);
CCS->curh->set(Cursor::Map::POINTER);
activeMapPanel->deactivate();
if (mode == EAdvMapMode::NORMAL)
if (state == EGameState::MAKING_TURN)
{
heroList->deactivate();
townList->deactivate();
@@ -544,20 +515,13 @@ void CAdventureMapInterface::showAll(SDL_Surface * to)
{
bg->draw(to, 0, 0);
if(state != EGameStates::INGAME)
if(state != EGameState::MAKING_TURN)
return;
switch (mode)
{
case EAdvMapMode::NORMAL:
heroList->showAll(to);
townList->showAll(to);
infoBar->showAll(to);
break;
case EAdvMapMode::WORLD_VIEW:
break;
}
activeMapPanel->showAll(to);
minimap->showAll(to);
@@ -585,7 +549,7 @@ void CAdventureMapInterface::onHeroWokeUp(const CGHeroInstance * hero)
sleepWake->clickLeft(true, false);
sleepWake->clickLeft(false, true);
//could've just called
//adventureInt->fsleepWake();
//fsleepWake();
//but no authentic button click/sound ;-)
}
@@ -595,12 +559,13 @@ void CAdventureMapInterface::setHeroSleeping(const CGHeroInstance *hero, bool sl
LOCPLINT->sleepingHeroes.push_back(hero); //FIXME: should we check for existence?
else
LOCPLINT->sleepingHeroes -= hero;
onHeroChanged(nullptr);
onHeroChanged(hero);
}
void CAdventureMapInterface::show(SDL_Surface * to)
{
if(state != EGameStates::INGAME)
if(state != EGameState::MAKING_TURN)
return;
handleMapScrollingUpdate();
@@ -628,38 +593,69 @@ void CAdventureMapInterface::show(SDL_Surface * to)
void CAdventureMapInterface::handleMapScrollingUpdate()
{
uint32_t timePassed = GH.mainFPSmng->getElapsedMilliseconds();
double scrollSpeedPixels = settings["adventure"]["scrollSpeedPixels"].Float();
int32_t scrollDistance = static_cast<int32_t>(scrollSpeedPixels * timePassed / 1000);
//if advmap needs updating AND (no dialog is shown OR ctrl is pressed)
uint32_t scrollSpeedPixels = settings["adventure"]["scrollSpeedPixels"].Float();
uint32_t scrollDistance = scrollSpeedPixels * timePassed / 1000;
if(scrollingDir & LEFT)
terrain->onMapScrolled(Point(-scrollDistance, 0));
bool scrollingActive = !GH.isKeyboardCtrlDown() && isActive() && state == EGameState::MAKING_TURN;
if(scrollingDir & RIGHT)
terrain->onMapScrolled(Point(+scrollDistance, 0));
Point cursorPosition = GH.getCursorPosition();
Point scrollDirection;
if(scrollingDir & UP)
terrain->onMapScrolled(Point(0, -scrollDistance));
if (cursorPosition.x < 15)
scrollDirection.x = -1;
if(scrollingDir & DOWN)
terrain->onMapScrolled(Point(0, +scrollDistance));
if (cursorPosition.x > GH.screenDimensions().x - 15)
scrollDirection.x = +1;
if(scrollingDir)
if (cursorPosition.y < 15)
scrollDirection.y = -1;
if (cursorPosition.y > GH.screenDimensions().y - 15)
scrollDirection.y = +1;
Point scrollDelta = scrollDirection * scrollDistance;
if (scrollingActive && scrollDelta != Point(0,0))
terrain->onMapScrolled(scrollDelta);
if (scrollDelta == Point(0,0) && !scrollingCursorSet)
return;
if(scrollDelta.x > 0)
{
setScrollingCursor(scrollingDir);
scrollingState = true;
if(scrollDelta.y < 0)
CCS->curh->set(Cursor::Map::SCROLL_NORTHEAST);
if(scrollDelta.y > 0)
CCS->curh->set(Cursor::Map::SCROLL_SOUTHEAST);
if(scrollDelta.y == 0)
CCS->curh->set(Cursor::Map::SCROLL_EAST);
}
else if(scrollingState)
if(scrollDelta.x < 0)
{
if(scrollDelta.y < 0)
CCS->curh->set(Cursor::Map::SCROLL_NORTHWEST);
if(scrollDelta.y > 0)
CCS->curh->set(Cursor::Map::SCROLL_SOUTHWEST);
if(scrollDelta.y == 0)
CCS->curh->set(Cursor::Map::SCROLL_WEST);
}
if (scrollDelta.x == 0)
{
if(scrollDelta.y < 0)
CCS->curh->set(Cursor::Map::SCROLL_NORTH);
if(scrollDelta.y > 0)
CCS->curh->set(Cursor::Map::SCROLL_SOUTH);
if(scrollDelta.y == 0)
CCS->curh->set(Cursor::Map::POINTER);
scrollingState = false;
}
}
void CAdventureMapInterface::selectionChanged()
{
const CGTownInstance *to = LOCPLINT->towns[townList->getSelectedIndex()];
if (selection != to)
if (currentSelection != to)
setSelection(to);
}
@@ -673,37 +669,9 @@ void CAdventureMapInterface::centerOnObject(const CGObjectInstance * obj)
terrain->onCenteredObject(obj);
}
void CAdventureMapInterface::keyReleased(const SDL_Keycode &key)
{
if (mode != EAdvMapMode::NORMAL)
return;
switch (key)
{
case SDLK_s:
if(isActive())
GH.pushIntT<CSavingScreen>();
return;
default:
{
auto direction = keyToMoveDirection(key);
if (!direction)
return;
ui8 Dir = (direction->x<0 ? LEFT : 0) |
(direction->x>0 ? RIGHT : 0) |
(direction->y<0 ? UP : 0) |
(direction->y>0 ? DOWN : 0) ;
scrollingDir &= ~Dir;
}
}
}
void CAdventureMapInterface::keyPressed(const SDL_Keycode & key)
{
if (mode != EAdvMapMode::NORMAL)
if (state != EGameState::MAKING_TURN)
return;
const CGHeroInstance *h = getCurrentHero(); //selected hero
@@ -732,6 +700,10 @@ void CAdventureMapInterface::keyPressed(const SDL_Keycode & key)
if(isActive())
CAdventureOptions::showScenarioInfo();
return;
case SDLK_s:
if(isActive())
GH.pushIntT<CSavingScreen>();
return;
case SDLK_l:
if(isActive())
LOCPLINT->proposeLoadingGame();
@@ -769,7 +741,7 @@ void CAdventureMapInterface::keyPressed(const SDL_Keycode & key)
return;
case SDLK_RETURN:
{
if(!isActive() || !selection)
if(!isActive() || !currentSelection)
return;
if(h)
LOCPLINT->openHeroWindow(h);
@@ -783,7 +755,7 @@ void CAdventureMapInterface::keyPressed(const SDL_Keycode & key)
if(!isActive() || GH.topInt().get() != this || !spellBeingCasted)
return;
leaveCastingMode();
abortCastingMode();
return;
}
case SDLK_t:
@@ -830,20 +802,6 @@ void CAdventureMapInterface::keyPressed(const SDL_Keycode & key)
if (!direction)
return;
ui8 Dir = (direction->x<0 ? LEFT : 0) |
(direction->x>0 ? RIGHT : 0) |
(direction->y<0 ? UP : 0) |
(direction->y>0 ? DOWN : 0) ;
//ctrl makes arrow move screen, not hero
if(GH.isKeyboardCtrlDown())
{
scrollingDir |= Dir;
return;
}
if(!h || !isActive())
return;
@@ -872,7 +830,6 @@ void CAdventureMapInterface::keyPressed(const SDL_Keycode & key)
if(!path.nodes[0].turns)
LOCPLINT->moveHero(h, path);
}
return;
}
}
@@ -901,9 +858,9 @@ std::optional<Point> CAdventureMapInterface::keyToMoveDirection(const SDL_Keycod
void CAdventureMapInterface::setSelection(const CArmedInstance *sel, bool centerView)
{
assert(sel);
if(selection != sel)
if(currentSelection != sel)
infoBar->popAll();
selection = sel;
currentSelection = sel;
mapAudio->onSelectionChanged(sel);
if(centerView)
centerOnObject(sel);
@@ -938,47 +895,6 @@ void CAdventureMapInterface::setSelection(const CArmedInstance *sel, bool center
heroList->redraw();
}
void CAdventureMapInterface::mouseMoved( const Point & cursorPosition )
{
// adventure map scrolling with mouse
// currently disabled in world view mode (as it is in OH3), but should work correctly if mode check is removed
if(!GH.isKeyboardCtrlDown() && isActive() && mode == EAdvMapMode::NORMAL)
{
if(cursorPosition.x<15)
{
scrollingDir |= LEFT;
}
else
{
scrollingDir &= ~LEFT;
}
if(cursorPosition.x > GH.screenDimensions().x - 15)
{
scrollingDir |= RIGHT;
}
else
{
scrollingDir &= ~RIGHT;
}
if(cursorPosition.y<15)
{
scrollingDir |= UP;
}
else
{
scrollingDir &= ~UP;
}
if(cursorPosition.y > GH.screenDimensions().y - 15)
{
scrollingDir |= DOWN;
}
else
{
scrollingDir &= ~DOWN;
}
}
}
bool CAdventureMapInterface::isActive()
{
return active & ~CIntObject::KEYBOARD;
@@ -992,22 +908,23 @@ void CAdventureMapInterface::onMapTilesChanged(boost::optional<std::unordered_se
minimap->update();
}
void CAdventureMapInterface::startHotSeatWait(PlayerColor Player)
void CAdventureMapInterface::onHotseatWaitStarted(PlayerColor playerID)
{
state = EGameStates::WAITING;
onCurrentPlayerChanged(playerID);
state = EGameState::HOTSEAT_WAIT;
}
void CAdventureMapInterface::aiTurnStarted()
void CAdventureMapInterface::onEnemyTurnStarted(PlayerColor playerID)
{
if(settings["session"]["spectate"].Bool())
return;
adjustActiveness(true);
mapAudio->onEnemyTurnStarted();
adventureInt->minimap->setAIRadar(true);
adventureInt->infoBar->startEnemyTurn(LOCPLINT->cb->getCurrentPlayer());
adventureInt->minimap->showAll(screen);//force refresh on inactive object
adventureInt->infoBar->showAll(screen);//force refresh on inactive object
minimap->setAIRadar(true);
infoBar->startEnemyTurn(LOCPLINT->cb->getCurrentPlayer());
minimap->showAll(screen);//force refresh on inactive object
infoBar->showAll(screen);//force refresh on inactive object
}
void CAdventureMapInterface::adjustActiveness(bool aiTurnStart)
@@ -1016,30 +933,37 @@ void CAdventureMapInterface::adjustActiveness(bool aiTurnStart)
if(wasActive)
deactivate();
adventureInt->duringAITurn = aiTurnStart;
if (aiTurnStart)
state = EGameState::ENEMY_TURN;
else
state = EGameState::MAKING_TURN;
if(wasActive)
activate();
}
void CAdventureMapInterface::onCurrentPlayerChanged(PlayerColor Player)
void CAdventureMapInterface::onCurrentPlayerChanged(PlayerColor playerID)
{
selection = nullptr;
currentSelection = nullptr;
if (Player == player)
if (playerID == currentPlayerID)
return;
player = Player;
bg->playerColored(player);
currentPlayerID = playerID;
bg->playerColored(currentPlayerID);
panelMain->setPlayerColor(player);
panelWorldView->setPlayerColor(player);
panelWorldView->recolorIcons(player, player.getNum() * 19);
resdatabar->colorize(player);
panelMain->setPlayerColor(currentPlayerID);
panelWorldView->setPlayerColor(currentPlayerID);
panelWorldView->recolorIcons(currentPlayerID, currentPlayerID.getNum() * 19);
resdatabar->colorize(currentPlayerID);
}
void CAdventureMapInterface::startTurn()
void CAdventureMapInterface::onPlayerTurnStarted(PlayerColor playerID)
{
state = EGameStates::INGAME;
onCurrentPlayerChanged(playerID);
state = EGameState::MAKING_TURN;
if(LOCPLINT->cb->getCurrentPlayer() == LOCPLINT->playerID
|| settings["session"]["spectate"].Bool())
{
@@ -1047,10 +971,7 @@ void CAdventureMapInterface::startTurn()
minimap->setAIRadar(false);
infoBar->showSelection();
}
}
void CAdventureMapInterface::initializeNewTurn()
{
heroList->update();
townList->update();
@@ -1121,7 +1042,7 @@ const CGObjectInstance* CAdventureMapInterface::getActiveObject(const int3 &mapP
void CAdventureMapInterface::onTileLeftClicked(const int3 &mapPos)
{
if(mode != EAdvMapMode::NORMAL)
if(state != EGameState::MAKING_TURN)
return;
//FIXME: this line breaks H3 behavior for Dimension Door
@@ -1134,7 +1055,7 @@ void CAdventureMapInterface::onTileLeftClicked(const int3 &mapPos)
const CGObjectInstance *topBlocking = getActiveObject(mapPos);
int3 selPos = selection->getSightCenter();
int3 selPos = currentSelection->getSightCenter();
if(spellBeingCasted && isInScreenRange(selPos, mapPos))
{
const TerrainTile *heroTile = LOCPLINT->cb->getTile(selPos);
@@ -1143,11 +1064,11 @@ void CAdventureMapInterface::onTileLeftClicked(const int3 &mapPos)
{
case SpellID::SCUTTLE_BOAT: //Scuttle Boat
if(topBlocking && topBlocking->ID == Obj::BOAT)
leaveCastingMode(true, mapPos);
leaveCastingMode(mapPos);
break;
case SpellID::DIMENSION_DOOR:
if(!tile || tile->isClear(heroTile))
leaveCastingMode(true, mapPos);
leaveCastingMode(mapPos);
break;
}
return;
@@ -1157,9 +1078,9 @@ void CAdventureMapInterface::onTileLeftClicked(const int3 &mapPos)
canSelect |= topBlocking && topBlocking->ID == Obj::TOWN && LOCPLINT->cb->getPlayerRelations(LOCPLINT->playerID, topBlocking->tempOwner);
bool isHero = false;
if(selection->ID != Obj::HERO) //hero is not selected (presumably town)
if(currentSelection->ID != Obj::HERO) //hero is not selected (presumably town)
{
if(selection == topBlocking) //selected town clicked
if(currentSelection == topBlocking) //selected town clicked
LOCPLINT->openTownWindow(static_cast<const CGTownInstance*>(topBlocking));
else if(canSelect)
setSelection(static_cast<const CArmedInstance*>(topBlocking), false);
@@ -1209,9 +1130,12 @@ void CAdventureMapInterface::onTileLeftClicked(const int3 &mapPos)
void CAdventureMapInterface::onTileHovered(const int3 &mapPos)
{
if(mode != EAdvMapMode::NORMAL //disable in world view
|| !selection) //may occur just at the start of game (fake move before full intiialization)
if(state == EGameState::MAKING_TURN)
return;
if(!currentSelection) //may occur just at the start of game (fake move before full intiialization)
return;
if(!LOCPLINT->cb->isVisible(mapPos))
{
CCS->curh->set(Cursor::Map::POINTER);
@@ -1246,7 +1170,7 @@ void CAdventureMapInterface::onTileHovered(const int3 &mapPos)
case SpellID::DIMENSION_DOOR:
{
const TerrainTile * t = LOCPLINT->cb->getTile(mapPos, false);
int3 hpos = selection->getSightCenter();
int3 hpos = currentSelection->getSightCenter();
if((!t || t->isClear(LOCPLINT->cb->getTile(hpos))) && isInScreenRange(hpos, mapPos))
CCS->curh->set(Cursor::Map::TELEPORT);
else
@@ -1256,7 +1180,7 @@ void CAdventureMapInterface::onTileHovered(const int3 &mapPos)
}
}
if(selection->ID == Obj::TOWN)
if(currentSelection->ID == Obj::TOWN)
{
if(objAtTile)
{
@@ -1305,7 +1229,7 @@ void CAdventureMapInterface::onTileHovered(const int3 &mapPos)
case CGPathNode::TELEPORT_BLOCKING_VISIT:
if(objAtTile && objAtTile->ID == Obj::HERO)
{
if(selection == objAtTile)
if(currentSelection == objAtTile)
CCS->curh->set(Cursor::Map::HERO);
else
CCS->curh->set(cursorExchange[turns]);
@@ -1368,13 +1292,15 @@ void CAdventureMapInterface::showMoveDetailsInStatusbar(const CGHeroInstance & h
void CAdventureMapInterface::onTileRightClicked(const int3 &mapPos)
{
if(mode != EAdvMapMode::NORMAL)
if(state != EGameState::MAKING_TURN)
return;
if(spellBeingCasted)
{
leaveCastingMode();
abortCastingMode();
return;
}
if(!LOCPLINT->cb->isVisible(mapPos))
{
CRClickPopup::createAndPush(VLC->generaltexth->allTexts[61]); //Uncharted Territory
@@ -1407,40 +1333,45 @@ void CAdventureMapInterface::enterCastingMode(const CSpell * sp)
GH.fakeMouseMove();
}
void CAdventureMapInterface::leaveCastingMode(bool cast, int3 dest)
void CAdventureMapInterface::abortCastingMode()
{
assert(spellBeingCasted);
SpellID id = spellBeingCasted->id;
spellBeingCasted = nullptr;
terrain->deactivate();
activate();
}
if(cast)
void CAdventureMapInterface::leaveCastingMode(const int3 & dest)
{
SpellID id = spellBeingCasted->id;
abortCastingMode();
// if(cast)
LOCPLINT->cb->castSpell(getCurrentHero(), id, dest);
else
LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[731]); //Spell cancelled
// else
// LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[731]); //Spell cancelled
}
const CGHeroInstance * CAdventureMapInterface::getCurrentHero() const
{
if(selection && selection->ID == Obj::HERO)
return dynamic_cast<const CGHeroInstance *>(selection);
if(currentSelection && currentSelection->ID == Obj::HERO)
return dynamic_cast<const CGHeroInstance *>(currentSelection);
else
return nullptr;
}
const CGTownInstance * CAdventureMapInterface::getCurrentTown() const
{
if(selection && selection->ID == Obj::TOWN)
return dynamic_cast<const CGTownInstance *>(selection);
if(currentSelection && currentSelection->ID == Obj::TOWN)
return dynamic_cast<const CGTownInstance *>(currentSelection);
else
return nullptr;
}
const CArmedInstance * CAdventureMapInterface::getCurrentArmy() const
{
if (selection)
return dynamic_cast<const CArmedInstance *>(selection);
if (currentSelection)
return dynamic_cast<const CArmedInstance *>(currentSelection);
else
return nullptr;
}
@@ -1455,7 +1386,7 @@ const IShipyard * CAdventureMapInterface::ourInaccessibleShipyard(const CGObject
const IShipyard *ret = IShipyard::castFrom(obj);
if(!ret ||
obj->tempOwner != player ||
obj->tempOwner != currentPlayerID ||
(CCS->curh->get<Cursor::Map>() != Cursor::Map::T1_SAIL && CCS->curh->get<Cursor::Map>() != Cursor::Map::POINTER))
return nullptr;
@@ -1464,7 +1395,7 @@ const IShipyard * CAdventureMapInterface::ourInaccessibleShipyard(const CGObject
void CAdventureMapInterface::exitWorldView()
{
mode = EAdvMapMode::NORMAL;
state = EGameState::MAKING_TURN;
panelMain->activate();
panelWorldView->deactivate();
@@ -1480,7 +1411,7 @@ void CAdventureMapInterface::exitWorldView()
void CAdventureMapInterface::openWorldView(int tileSize)
{
mode = EAdvMapMode::WORLD_VIEW;
state = EGameState::WORLD_VIEW;
panelMain->deactivate();
panelWorldView->activate();

View File

@@ -11,9 +11,6 @@
#include "../gui/CIntObject.h"
#include "../../lib/int3.h"
#include "../../lib/GameConstants.h"
VCMI_LIB_NAMESPACE_BEGIN
class CGObjectInstance;
@@ -24,6 +21,7 @@ class IShipyard;
struct CGPathNode;
struct ObjectPosInfo;
struct Component;
class int3;
VCMI_LIB_NAMESPACE_END
@@ -44,35 +42,31 @@ 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 CAdventureMapInterface : public CIntObject
{
private:
enum EDirections {LEFT=1, RIGHT=2, UP=4, DOWN=8};
enum class EGameStates {NA, INGAME, WAITING};
enum class EGameState
{
NOT_INITIALIZED,
HOTSEAT_WAIT,
MAKING_TURN,
ENEMY_TURN,
WORLD_VIEW
};
EGameStates state;
EAdvMapMode mode;
EGameState state;
/// Currently selected object, can be town, hero or null
const CArmedInstance *selection;
const CArmedInstance *currentSelection;
/// currently acting player
PlayerColor player;
bool duringAITurn;
PlayerColor currentPlayerID;
/// uses EDirections enum
ui8 scrollingDir;
bool scrollingState;
bool scrollingCursorSet;
const CSpell *spellBeingCasted; //nullptr if none
@@ -125,7 +119,6 @@ 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
@@ -148,9 +141,10 @@ private:
int getNextHeroIndex(int startIndex); //for Next Hero button - cycles awake heroes with movement only
void endingTurn();
public:
CAdventureMapInterface();
/// exits currently opened world view mode and returns to normal map
void exitWorldView();
protected:
// CIntObject interface implementation
void activate() override;
@@ -160,22 +154,25 @@ 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();
void startHotSeatWait(PlayerColor Player);
void startTurn();
void initializeNewTurn();
void aiTurnStarted();
/// Called by PlayerInterface when specified player is ready to start his turn
void onHotseatWaitStarted(PlayerColor playerID);
/// 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 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 onMapTilesChanged( boost::optional<std::unordered_set<int3> > positions);
@@ -215,7 +212,8 @@ public:
void onTileRightClicked(const int3 & mapPos);
void enterCastingMode(const CSpell * sp);
void leaveCastingMode(bool cast = false, int3 dest = int3(-1, -1, -1));
void leaveCastingMode(const int3 & castTarget);
void abortCastingMode();
const CGHeroInstance * getCurrentHero() const;
const CGTownInstance * getCurrentTown() const;
@@ -224,9 +222,6 @@ public:
/// 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();
@@ -235,7 +230,6 @@ 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<CAdventureMapInterface> adventureInt;

View File

@@ -19,6 +19,7 @@
#include "../gui/CGuiHandler.h"
#include "../render/Colors.h"
#include "../renderSDL/SDL_PixelAccess.h"
#include "../render/Canvas.h"
#include "../windows/InfoWindows.h"
#include "../../CCallback.h"

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

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;