diff --git a/gframe/game.cpp b/gframe/game.cpp index 74f25d48b..97dde382d 100644 --- a/gframe/game.cpp +++ b/gframe/game.cpp @@ -313,6 +313,7 @@ void Game::Initialize() { btnCreateHost->setEnabled(coreloaded); PopulateGameHostWindows(); + PopulateAIBotWindow(); //img wCardImg = env->addStaticText(L"", Scale(1, 1, 1 + CARD_IMG_WRAPPER_WIDTH, 1 + CARD_IMG_WRAPPER_HEIGHT), true, false, 0, -1, true); @@ -1346,21 +1347,6 @@ void Game::PopulateGameHostWindows() { chkHostPrepReady[i] = env->addCheckBox(false, Scale(250, 65 + i * 25, 270, 85 + i * 25), wHostPrepare, CHECKBOX_HP_READY, L""); chkHostPrepReady[i]->setEnabled(false); } - gBot.window = env->addWindow(Scale(750, 120, 960, 420), false, gDataManager->GetSysString(2051).data()); - defaultStrings.emplace_back(gBot.window, 2051); - gBot.window->getCloseButton()->setVisible(false); - gBot.window->setVisible(false); - gBot.deckProperties = env->addStaticText(L"", Scale(10, 25, 200, 100), true, true, gBot.window); - gBot.chkThrowRock = env->addCheckBox(gGameConfig->botThrowRock, Scale(10, 105, 200, 130), gBot.window, -1, gDataManager->GetSysString(2052).data()); - defaultStrings.emplace_back(gBot.chkThrowRock, 2052); - gBot.chkMute = env->addCheckBox(gGameConfig->botMute, Scale(10, 135, 200, 160), gBot.window, -1, gDataManager->GetSysString(2053).data()); - defaultStrings.emplace_back(gBot.chkMute, 2053); - gBot.cbBotDeck = AddComboBox(env, Scale(10, 165, 200, 190), gBot.window, COMBOBOX_BOT_DECK); - gBot.stBotEngine = env->addStaticText(gDataManager->GetSysString(2082).data(), Scale(10, 195, 200, 220), false, false, gBot.window); - defaultStrings.emplace_back(gBot.stBotEngine, 2082); - gBot.cbBotEngine = AddComboBox(env, Scale(10, 225, 200, 250), gBot.window, COMBOBOX_BOT_ENGINE); - gBot.btnAdd = env->addButton(Scale(10, 260, 200, 285), gBot.window, BUTTON_BOT_ADD, gDataManager->GetSysString(2054).data()); - defaultStrings.emplace_back(gBot.btnAdd, 2054); btnHostPrepOB = env->addButton(Scale(10, 180, 110, 205), wHostPrepare, BUTTON_HP_OBSERVER, gDataManager->GetSysString(1252).data()); defaultStrings.emplace_back(btnHostPrepOB, 1252); stHostPrepOB = env->addStaticText(epro::format(L"{} 0", gDataManager->GetSysString(1253)).data(), Scale(10, 210, 270, 230), false, false, wHostPrepare); @@ -1382,6 +1368,33 @@ void Game::PopulateGameHostWindows() { defaultStrings.emplace_back(btnHostPrepCancel, 1210); } +void Game::PopulateAIBotWindow() { +#if !defined(__ANDROID__) && !defined(EDOPRO_IOS) + static constexpr bool showWindbotArgs = true; +#else + static constexpr bool showWindbotArgs = false; +#endif + gBot.window = env->addWindow(Scale(750, 120, 960, showWindbotArgs ? 455 : 420), false, gDataManager->GetSysString(2051).data()); + defaultStrings.emplace_back(gBot.window, 2051); + gBot.window->getCloseButton()->setVisible(false); + gBot.window->setVisible(false); + gBot.deckProperties = env->addStaticText(L"", Scale(10, 25, 200, 100), true, true, gBot.window); + gBot.chkThrowRock = env->addCheckBox(gGameConfig->botThrowRock, Scale(10, 105, 200, 130), gBot.window, -1, gDataManager->GetSysString(2052).data()); + defaultStrings.emplace_back(gBot.chkThrowRock, 2052); + gBot.chkMute = env->addCheckBox(gGameConfig->botMute, Scale(10, 135, 200, 160), gBot.window, -1, gDataManager->GetSysString(2053).data()); + defaultStrings.emplace_back(gBot.chkMute, 2053); + gBot.cbBotDeck = AddComboBox(env, Scale(10, 165, 200, 190), gBot.window, COMBOBOX_BOT_DECK); + gBot.stBotEngine = env->addStaticText(gDataManager->GetSysString(2082).data(), Scale(10, 195, 200, 220), false, false, gBot.window); + defaultStrings.emplace_back(gBot.stBotEngine, 2082); + gBot.cbBotEngine = AddComboBox(env, Scale(10, 225, 200, 250), gBot.window, COMBOBOX_BOT_ENGINE); + gBot.btnAdd = env->addButton(Scale(10, 260, 200, 285), gBot.window, BUTTON_BOT_ADD, gDataManager->GetSysString(2054).data()); + defaultStrings.emplace_back(gBot.btnAdd, 2054); + if(showWindbotArgs) { + gBot.btnCommand = env->addButton(Scale(10, 295, 200, 320), gBot.window, BUTTON_BOT_COPY_COMMAND, gDataManager->GetSysString(12120).data()); + defaultStrings.emplace_back(gBot.btnCommand, 12120); + } +} + void Game::PopulateTabSettingsWindow() { //tab infosExpanded = 0; diff --git a/gframe/game.h b/gframe/game.h index a2b2c083b..c98771172 100644 --- a/gframe/game.h +++ b/gframe/game.h @@ -377,6 +377,7 @@ class Game { irr::gui::IGUIButton* btnTabShowSettings; void PopulateGameHostWindows(); + void PopulateAIBotWindow(); void PopulateTabSettingsWindow(); void PopulateSettingsWindow(); SettingsWindow gSettings; diff --git a/gframe/menu_handler.cpp b/gframe/menu_handler.cpp index bb549af0f..d024009c5 100644 --- a/gframe/menu_handler.cpp +++ b/gframe/menu_handler.cpp @@ -442,7 +442,19 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) { if(mainGame->gBot.LaunchSelected(port, mainGame->dInfo.secret.pass)) break; } catch(...) {} - mainGame->PopupMessage(L"Failed to launch windbot"); + mainGame->PopupMessage(gDataManager->GetSysString(12122).data()); + break; + } + case BUTTON_BOT_COPY_COMMAND: { + try { + int port = std::stoi(gGameConfig->serverport); + const auto params = mainGame->gBot.GetParameters(port, mainGame->dInfo.secret.pass); + if(params.size()) { + Utils::OSOperator->copyToClipboard(mainGame->gBot.GetParameters(port, mainGame->dInfo.secret.pass).data()); + mainGame->stACMessage->setText(gDataManager->GetSysString(12121).data()); + mainGame->PopupElement(mainGame->wACMessage, 20); + } + } catch(...) {} break; } case BUTTON_EXPORT_DECK: { diff --git a/gframe/menu_handler.h b/gframe/menu_handler.h index f1cdcaf3d..b554bc288 100644 --- a/gframe/menu_handler.h +++ b/gframe/menu_handler.h @@ -49,6 +49,7 @@ enum GUI { EDITBOX_NUMERIC, BUTTON_HP_AI_TOGGLE, BUTTON_BOT_ADD, + BUTTON_BOT_COPY_COMMAND, EDITBOX_CHAT, EDITBOX_PORT_BOX, COMBOBOX_BOT_DECK, diff --git a/gframe/windbot.cpp b/gframe/windbot.cpp index 2400e0710..af1527d95 100644 --- a/gframe/windbot.cpp +++ b/gframe/windbot.cpp @@ -102,6 +102,20 @@ WindBot::launch_ret_t WindBot::Launch(int port, epro::wstringview pass, bool cha #endif } +std::wstring WindBot::GetLaunchParameters(int port, epro::wstringview pass, bool chat, int hand, const wchar_t* overridedeck) const { +#ifndef __ANDROID__ + if(!serialized) { + serialized = true; + serialized_databases = base64_encode(databases.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace)); + } +#endif + const auto assets_path = Utils::GetAbsolutePath(EPRO_TEXT("./WindBot"_sv)); + const auto override_deck = overridedeck ? epro::format(L" DeckFile=\"{}\"", overridedeck) : L""; + return epro::format( + L"HostInfo=\"{}\" Deck=\"{}\" Port={} Version={} name=\"[AI] {}\" Chat={} Hand={} DbPaths={}{} AssetPath=\"{}\"", + pass, deck, port, version, name, chat, hand, Utils::ToUnicodeIfNeeded(serialized_databases), override_deck, Utils::ToUnicodeIfNeeded(assets_path)); +} + void WindBot::AddDatabase(epro::path_stringview database) { #ifdef __ANDROID__ porting::addWindbotDatabase(Utils::GetAbsolutePath(database)); diff --git a/gframe/windbot.h b/gframe/windbot.h index 37548ab0e..53dca3bc2 100644 --- a/gframe/windbot.h +++ b/gframe/windbot.h @@ -28,6 +28,7 @@ struct WindBot { static epro::path_string executablePath; #endif launch_ret_t Launch(int port, epro::wstringview pass, bool chat, int hand, const wchar_t* overridedeck) const; + std::wstring GetLaunchParameters(int port, epro::wstringview pass, bool chat, int hand, const wchar_t* overridedeck) const; #ifndef __ANDROID__ static nlohmann::ordered_json databases; diff --git a/gframe/windbot_panel.cpp b/gframe/windbot_panel.cpp index cafae1e2d..11f3edafc 100644 --- a/gframe/windbot_panel.cpp +++ b/gframe/windbot_panel.cpp @@ -116,4 +116,23 @@ bool WindBotPanel::LaunchSelected(int port, epro::wstringview pass) { return res; } +std::wstring WindBotPanel::GetParameters(int port, epro::wstringview pass) { + int index = CurrentIndex(); + int engine = CurrentEngine(); + if(index < 0 || engine < 0) return {}; + const wchar_t* overridedeck = nullptr; + std::wstring tmpdeck{}; + const auto maxsize = (int)(bots.size() - (genericEngine != nullptr)); + if(engine != index || index >= maxsize) { + if(index >= maxsize) { + tmpdeck = epro::format(L"{}/{}.ydk", absolute_deck_path, cbBotDeck->getItem(cbBotDeck->getSelected())); + overridedeck = tmpdeck.data(); + } else { + overridedeck = bots[index].deckfile.data(); + } + } + // 1 = scissors, 2 = rock, 3 = paper + return bots[engine].GetLaunchParameters(port, pass, !chkMute->isChecked(), chkThrowRock->isChecked() * 2, overridedeck); +} + } diff --git a/gframe/windbot_panel.h b/gframe/windbot_panel.h index 066282db2..6be711f75 100644 --- a/gframe/windbot_panel.h +++ b/gframe/windbot_panel.h @@ -36,6 +36,7 @@ struct WindBotPanel { irr::gui::IGUIStaticText* stBotEngine; irr::gui::IGUIStaticText* deckProperties; irr::gui::IGUIButton* btnAdd; + irr::gui::IGUIButton* btnCommand; int CurrentIndex(); int CurrentEngine(); @@ -43,6 +44,7 @@ struct WindBotPanel { void UpdateDescription(); void UpdateEngine(); bool LaunchSelected(int port, epro::wstringview pass); + std::wstring GetParameters(int port, epro::wstringview pass); private: int genericEngineIdx; };