diff --git a/client/lobby/BattleOnlyMode.cpp b/client/lobby/BattleOnlyMode.cpp index 50601766d..0c719362a 100644 --- a/client/lobby/BattleOnlyMode.cpp +++ b/client/lobby/BattleOnlyMode.cpp @@ -58,6 +58,8 @@ void BattleOnlyMode::openBattleWindow() { + if(GAME->server().isGuest()) + return; GAME->server().sendGuiAction(LobbyGuiAction::BATTLE_MODE); ENGINE->windows().createAndPushWindow(); } @@ -118,54 +120,43 @@ BattleOnlyModeWindow::BattleOnlyModeWindow() if(terrains.size() > index) { startInfo->selectedTerrain = terrains[index]->getId(); - startInfo->selectedTown = FactionID::NONE; + startInfo->selectedTown = std::nullopt; } else { - startInfo->selectedTerrain = TerrainId::NONE; + startInfo->selectedTerrain = std::nullopt; auto it = std::next(factions.begin(), index - terrains.size()); if (it != factions.end()) startInfo->selectedTown = *it; } - setTerrainButtonText(); - setOkButtonEnabled(); - }, (startInfo->selectedTerrain != TerrainId::NONE ? static_cast(startInfo->selectedTerrain) : static_cast(startInfo->selectedTown + terrains.size())), images, true, true); + onChange(); + }, (startInfo->selectedTerrain ? static_cast(*startInfo->selectedTerrain) : static_cast(*startInfo->selectedTown + terrains.size())), images, true, true); }); battlefieldSelector->block(GAME->server().isGuest()); buttonReset = std::make_shared(Point(289, 174), AnimationPath::builtin("GSPButtonClear"), CButton::tooltip(), [this](){ if(GAME->server().isHost()) { startInfo->selectedTerrain = TerrainId::DIRT; - startInfo->selectedTown = FactionID::NONE; - } - setTerrainButtonText(); - setOkButtonEnabled(); - if(GAME->server().isHost()) - { - startInfo->selectedHero[0].reset(); + startInfo->selectedTown = std::nullopt; + startInfo->selectedHero[0] = std::nullopt; startInfo->selectedArmy[0]->clearSlots(); for(size_t i=0; iselectedArmyInput.at(i)->setText("1"); - heroSelector1->setHeroIcon(); - heroSelector1->setCreatureIcons(); } - startInfo->selectedHero[1].reset(); + startInfo->selectedHero[1] = std::nullopt; startInfo->selectedArmy[1]->clearSlots(); for(size_t i=0; iselectedArmyInput.at(i)->setText("1"); - heroSelector2->setHeroIcon(); - heroSelector2->setCreatureIcons(); - redraw(); + onChange(); }); buttonReset->setTextOverlay(LIBRARY->generaltexth->translate("vcmi.lobby.battleOnlyModeReset"), EFonts::FONT_SMALL, Colors::WHITE); - setTerrainButtonText(); - setOkButtonEnabled(); - heroSelector1 = std::make_shared(0, *this, Point(0, 40)); heroSelector2 = std::make_shared(1, *this, Point(260, 40)); heroSelector1->setInputEnabled(GAME->server().isHost()); + + onChange(); } void BattleOnlyModeWindow::init() @@ -180,8 +171,6 @@ void BattleOnlyModeWindow::init() map->name = MetaString::createFromTextID("vcmi.lobby.battleOnlyMode"); cb = std::make_unique(map.get()); - - onChange(); } void BattleOnlyModeWindow::onChange() @@ -189,20 +178,33 @@ void BattleOnlyModeWindow::onChange() GAME->server().setBattleOnlyModeStartInfo(startInfo); } +void BattleOnlyModeWindow::update() +{ + setTerrainButtonText(); + setOkButtonEnabled(); + + heroSelector1->setHeroIcon(); + heroSelector1->setCreatureIcons(); + heroSelector2->setHeroIcon(); + heroSelector2->setCreatureIcons(); + redraw(); +} + void BattleOnlyModeWindow::applyStartInfo(std::shared_ptr si) { - + startInfo = si; + update(); } void BattleOnlyModeWindow::setTerrainButtonText() { - battlefieldSelector->setTextOverlay(LIBRARY->generaltexth->translate("vcmi.lobby.battleOnlyModeBattlefield") + ": " + (startInfo->selectedTerrain != TerrainId::NONE ? startInfo->selectedTerrain.toEntity(LIBRARY)->getNameTranslated() : startInfo->selectedTown.toEntity(LIBRARY)->getNameTranslated()), EFonts::FONT_SMALL, Colors::WHITE); + battlefieldSelector->setTextOverlay(LIBRARY->generaltexth->translate("vcmi.lobby.battleOnlyModeBattlefield") + ": " + (startInfo->selectedTerrain ? (*startInfo->selectedTerrain).toEntity(LIBRARY)->getNameTranslated() : (*startInfo->selectedTown).toEntity(LIBRARY)->getNameTranslated()), EFonts::FONT_SMALL, Colors::WHITE); } void BattleOnlyModeWindow::setOkButtonEnabled() { - bool canStart = (startInfo->selectedTerrain != TerrainId::NONE || startInfo->selectedTown != FactionID::NONE); - canStart &= (startInfo->selectedHero[0] && ((startInfo->selectedHero[1]) || (startInfo->selectedTown != FactionID::NONE && startInfo->selectedArmy[1]->stacksCount()))); + bool canStart = (startInfo->selectedTerrain || startInfo->selectedTown); + canStart &= (startInfo->selectedHero[0] && ((startInfo->selectedHero[1]) || (startInfo->selectedTown && startInfo->selectedArmy[1]->stacksCount()))); buttonOk->block(!canStart || GAME->server().isGuest()); buttonAbort->block(GAME->server().isGuest()); } @@ -238,6 +240,7 @@ BattleOnlyModeHeroSelector::BattleOnlyModeHeroSelector(int id, BattleOnlyModeWin primSkillsInput.back()->setText("0"); primSkillsInput.back()->setCallback([this, i, id](const std::string & text){ parent.startInfo->primSkillLevel[id][i] = std::stoi(primSkillsInput[i]->getText()); + parent.onChange(); }); } @@ -249,7 +252,10 @@ BattleOnlyModeHeroSelector::BattleOnlyModeHeroSelector(int id, BattleOnlyModeWin selectedArmyInput.back()->setText("1"); selectedArmyInput.back()->setCallback([this, i, id](const std::string & text){ if(!parent.startInfo->selectedArmy[id]->slotEmpty(SlotID(i))) + { parent.startInfo->selectedArmy[id]->setCreature(SlotID(i), parent.startInfo->selectedArmy[id]->getCreature(SlotID(i))->getId(), TextOperations::parseMetric(text)); + parent.onChange(); + } }); } @@ -310,7 +316,7 @@ void BattleOnlyModeHeroSelector::setHeroIcon() if(index == 0) { parent.startInfo->selectedHero[id].reset(); - setHeroIcon(); + parent.onChange(); return; } index--; @@ -325,8 +331,7 @@ void BattleOnlyModeHeroSelector::setHeroIcon() for(size_t i=0; iprimSkillLevel[id][i] = 0; - setHeroIcon(); - parent.setOkButtonEnabled(); + parent.onChange(); }, selectedIndex, images, true, true); window->onPopup = [heroes](int index) { if(index == 0) @@ -395,7 +400,7 @@ void BattleOnlyModeHeroSelector::setCreatureIcons() { if(!parent.startInfo->selectedArmy[id]->slotEmpty(SlotID(i))) parent.startInfo->selectedArmy[id]->eraseStack(SlotID(i)); - setCreatureIcons(); + parent.onChange(); return; } index--; @@ -403,7 +408,7 @@ void BattleOnlyModeHeroSelector::setCreatureIcons() auto creature = creatures.at(index).toCreature(); parent.startInfo->selectedArmy[id]->setCreature(SlotID(i), creature->getId(), 100); selectedArmyInput[SlotID(i)]->setText("100"); - setCreatureIcons(); + parent.onChange(); }, selectedIndex, images, true, true); window->onPopup = [creatures](int index) { if(index == 0) @@ -432,7 +437,7 @@ void BattleOnlyModeWindow::startBattle() map->getEditManager()->clearTerrain(rng); map->getEditManager()->getTerrainSelection().selectAll(); - map->getEditManager()->drawTerrain(startInfo->selectedTerrain == TerrainId::NONE ? TerrainId::DIRT : startInfo->selectedTerrain, 0, rng); + map->getEditManager()->drawTerrain(!startInfo->selectedTerrain ? TerrainId::DIRT : *startInfo->selectedTerrain, 0, rng); map->players[0].canComputerPlay = true; map->players[0].canHumanPlay = true; @@ -454,11 +459,11 @@ void BattleOnlyModeWindow::startBattle() }; addHero(0, PlayerColor(0), int3(5, 6, 0)); - if(startInfo->selectedTown == FactionID::NONE) + if(startInfo->selectedTown) addHero(1, PlayerColor(1), int3(5, 5, 0)); else { - auto factory = LIBRARY->objtypeh->getHandlerFor(Obj::TOWN, startInfo->selectedTown); + auto factory = LIBRARY->objtypeh->getHandlerFor(Obj::TOWN, *startInfo->selectedTown); auto templates = factory->getTemplates(); auto obj = factory->create(cb.get(), templates.front()); auto townObj = std::dynamic_pointer_cast(obj); diff --git a/client/lobby/BattleOnlyMode.h b/client/lobby/BattleOnlyMode.h index 5003ed4c4..86615bf2e 100644 --- a/client/lobby/BattleOnlyMode.h +++ b/client/lobby/BattleOnlyMode.h @@ -80,6 +80,7 @@ private: void init(); void onChange(); + void update(); void setTerrainButtonText(); void setOkButtonEnabled(); void startBattle(); diff --git a/client/lobby/SelectionTab.cpp b/client/lobby/SelectionTab.cpp index 40b53cd6f..47ef38567 100644 --- a/client/lobby/SelectionTab.cpp +++ b/client/lobby/SelectionTab.cpp @@ -247,7 +247,6 @@ SelectionTab::SelectionTab(ESelectionScreen Type) buttonBattleOnlyMode = std::make_shared(Point(23, 18), AnimationPath::builtin("lobby/battleButton"), CButton::tooltip("", LIBRARY->generaltexth->translate("vcmi.lobby.battleOnlyMode")), [tabTitle, tabTitleDelete](){ BattleOnlyMode::openBattleWindow(); }); - //buttonBattleOnlyMode->block(GAME->server().isGuest()); } if(tabType == ESelectionScreen::loadGame || tabType == ESelectionScreen::newGame) diff --git a/lib/StartInfo.cpp b/lib/StartInfo.cpp index eb2440047..f93edd959 100644 --- a/lib/StartInfo.cpp +++ b/lib/StartInfo.cpp @@ -244,7 +244,7 @@ TeamID LobbyInfo::getPlayerTeamId(const PlayerColor & color) BattleOnlyModeStartInfo::BattleOnlyModeStartInfo() : selectedTerrain(TerrainId::DIRT) - , selectedTown(FactionID::NONE) + , selectedTown(std::nullopt) { for(auto & element : selectedArmy) element = std::make_shared(); diff --git a/lib/StartInfo.h b/lib/StartInfo.h index 994ae1526..fe00d81c1 100644 --- a/lib/StartInfo.h +++ b/lib/StartInfo.h @@ -244,8 +244,8 @@ struct DLL_LINKAGE LobbyInfo : public LobbyState class DLL_LINKAGE BattleOnlyModeStartInfo : public Serializeable { public: - TerrainId selectedTerrain; - FactionID selectedTown; + std::optional selectedTerrain; + std::optional selectedTown; std::array, 2> selectedHero; std::array, 2> selectedArmy; diff --git a/server/LobbyNetPackVisitors.h b/server/LobbyNetPackVisitors.h index 51a04aa97..e2721eb21 100644 --- a/server/LobbyNetPackVisitors.h +++ b/server/LobbyNetPackVisitors.h @@ -47,6 +47,7 @@ public: void visitLobbyGuiAction(LobbyGuiAction & pack) override; void visitLobbyPvPAction(LobbyPvPAction & pack) override; void visitLobbyDelete(LobbyDelete & pack) override; + void visitLobbySetBattleOnlyModeStartInfo(LobbySetBattleOnlyModeStartInfo & pack) override; }; class ApplyOnServerAfterAnnounceNetPackVisitor : public VCMI_LIB_WRAP_NAMESPACE(ICPackVisitor) diff --git a/server/NetPacksLobbyServer.cpp b/server/NetPacksLobbyServer.cpp index 15b0cd352..5411a2e4d 100644 --- a/server/NetPacksLobbyServer.cpp +++ b/server/NetPacksLobbyServer.cpp @@ -385,12 +385,16 @@ void ApplyOnServerNetPackVisitor::visitLobbyPvPAction(LobbyPvPAction & pack) result = true; } - void ClientPermissionsCheckerNetPackVisitor::visitLobbyDelete(LobbyDelete & pack) { result = srv.isClientHost(connection->connectionID); } +void ClientPermissionsCheckerNetPackVisitor::visitLobbySetBattleOnlyModeStartInfo(LobbySetBattleOnlyModeStartInfo & pack) +{ + result = true; +} + void ApplyOnServerNetPackVisitor::visitLobbyDelete(LobbyDelete & pack) { if(pack.type == LobbyDelete::EType::SAVEGAME || pack.type == LobbyDelete::EType::RANDOMMAP)