/* =========================================================================== Copyright (C) 2023 the OpenMoHAA team This file is part of OpenMoHAA source code. OpenMoHAA source code is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. OpenMoHAA source code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenMoHAA source code; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ #include "cl_ui.h" #include "../qcommon/localization.h" class MpMapPickerItem : public UIListCtrlItem { str m_string; // Added in 2.0 str m_directory; public: MpMapPickerItem(const str& string, const str& directory); int getListItemValue(int which) const override; griditemtype_t getListItemType(int which) const override; str getListItemString(int which) const override; void DrawListItem(int iColumn, const UIRect2D& drawRect, bool bSelected, UIFont *pFont) override; qboolean IsHeaderEntry() const override; }; CLASS_DECLARATION(USignal, MpMapPickerClass, NULL) { {&EV_UIListBase_ItemSelected, &MpMapPickerClass::FileSelected }, {&EV_UIListBase_ItemDoubleClicked, &MpMapPickerClass::FileChosen }, {&W_Deactivated, &MpMapPickerClass::OnDeactivated}, {NULL, NULL } }; MpMapPickerClass::MpMapPickerClass() { window = new UIFloatingWindow(); window->Create( NULL, UIRect2D((uid.vidWidth - 300) / 2, (uid.vidHeight - 200) / 2, 300, 200), "Select a Map", UColor(0.15f, 0.195f, 0.278f), UHudColor ); window->setFont("facfont-20"); window->PassEventToWidget("closebutton", new Event(EV_Widget_Disable)); window->PassEventToWidget("minimizebutton", new Event(EV_Widget_Disable)); window->Connect(this, W_Deactivated, W_Deactivated); listbox = new UIListCtrl(); listbox->InitFrame(window->getChildSpace(), window->getChildSpace()->getClientFrame(), 0); listbox->SetDrawHeader(false); listbox->setFont("facfont-20"); listbox->FrameInitialized(); listbox->AddColumn(Sys_LV_CL_ConvertString("Select a Map"), 0, 400, false, false); listbox->Connect(this, EV_UIListBase_ItemDoubleClicked, EV_UIListBase_ItemDoubleClicked); listbox->Connect(this, EV_UIListBase_ItemSelected, EV_UIListBase_ItemSelected); listbox->AllowActivate(true); // Added in 2.0 // Don't localize elements listbox->SetDontLocalize(); } MpMapPickerClass::~MpMapPickerClass() { if (listbox) { delete listbox; listbox = NULL; } if (window) { delete window; window = NULL; } } void MpMapPickerClass::Setup(const char *root_directory, const char *current_directory, const char *game_type) { Initialize(root_directory, current_directory, game_type); } void MpMapPickerClass::Initialize(const char *root_directory, const char *current_directory, const char *game_type) { rootDirectory = root_directory; if (rootDirectory.length() > 1 && rootDirectory[rootDirectory.length() - 1] != '/') { rootDirectory += "/"; } currentDirectory = current_directory; if (currentDirectory.length() > 1 && currentDirectory[currentDirectory.length() - 1] != '/') { currentDirectory += "/"; } if (game_type) { gameType = game_type; } SetupFiles(); } void MpMapPickerClass::GotoParentDirectory(void) { uintptr_t i; if (currentDirectory == rootDirectory) { return; } for (i = currentDirectory.length() - 2; i > 0; i--) { if (currentDirectory[i] == '/') { break; } } if (currentDirectory[i] == '/') { i++; } currentDirectory = str(currentDirectory, 0, i); // refresh files SetupFiles(); } void MpMapPickerClass::GotoSubDirectory(str subdir) { currentDirectory += subdir + "/"; // refresh files SetupFiles(); } void MpMapPickerClass::SetupFiles(void) { char **filenames; int numfiles; int i; char mapname[128]; bool bTugOfWar = false, bObjective = false, bLiberation = false; listbox->DeleteAllItems(); if (gameType == "tow") { bTugOfWar = true; } else if (gameType == "obj") { bObjective = true; } else if (gameType == "lib") { bLiberation = true; } else { // retrieve directories filenames = FS_ListFiles(rootDirectory, ".bsp", qfalse, &numfiles); for (i = 0; i < numfiles; i++) { const char *filename = filenames[i]; strcpy(mapname, filename); mapname[strlen(mapname) - 4] = 0; if (COM_IsMapValid(mapname)) { listbox->AddItem(new MpMapPickerItem(mapname, rootDirectory)); } } FS_FreeFileList(filenames); } if (com_target_game->integer > target_game_e::TG_MOH) { if (currentDirectory.length()) { if (currentDirectory == "maps/-/") { SetupSecondaryFiles(currentDirectory, bTugOfWar, bObjective, bLiberation); } else { SetupSecondaryFiles("maps/obj/", bTugOfWar, bObjective, bLiberation); SetupSecondaryFiles("maps/lib/", bTugOfWar, bObjective, bLiberation); } } } listbox->SortByColumn(0); } void MpMapPickerClass::SetupSecondaryFiles(const char *path, bool bTugOfWar, bool bObjective, bool bLiberation) { char **filenames; int numfiles; int i; char mapname[128]; char string[1024]; filenames = FS_ListFiles(path, ".bsp", qfalse, &numfiles); for (i = 0; i < numfiles; i++) { const char *filename = filenames[i]; const char *token; strcpy(mapname, filename); mapname[strlen(mapname) - 4] = 0; if (!COM_IsMapValid(mapname)) { continue; } if (bTugOfWar || bObjective || bLiberation) { bool bHasMP = false, bHasTOW = false, bHasLib = false; strcpy(string, mapname); for (token = strtok(string, "_"); token; token = strtok(NULL, "_")) { if (bObjective) { if (!Q_stricmp(token, "obj")) { listbox->AddItem(new MpMapPickerItem(mapname, path)); } else if (!Q_stricmp(token, "ship")) { listbox->AddItem(new MpMapPickerItem(mapname, path)); } } if (bTugOfWar) { if (!Q_stricmp(token, "MP")) { bHasMP = true; } if (!Q_stricmp(token, "TOW")) { bHasTOW = true; } if (bHasMP && bHasTOW) { listbox->AddItem(new MpMapPickerItem(mapname, path)); } } if (bLiberation) { if (!Q_stricmp(token, "MP")) { bHasMP = true; } if (!Q_stricmp(token, "LIB")) { bHasLib = true; } if (bHasMP && bHasLib) { listbox->AddItem(new MpMapPickerItem(mapname, path)); } } } } else { if (!Q_stricmp(mapname, "obj_team2") || !Q_stricmp(mapname, "obj_team4")) { continue; } listbox->AddItem(new MpMapPickerItem(mapname, path)); } } FS_FreeFileList(filenames); } void MpMapPickerClass::FileSelected(const str& currentDirectory, const str& partialName, const str& fullname) { FileChosen(currentDirectory, partialName, fullname); } void MpMapPickerClass::FileSelected(Event *ev) { if (!listbox->getCurrentItem()) { return; } uii.Snd_PlaySound("sound/menu/apply.wav"); UIListCtrlItem *item = listbox->GetItem(listbox->getCurrentItem()); str name = item->getListItemString(0); str directory = item->getListItemString(1); FileSelected(directory, name, directory + name); } void MpMapPickerClass::FileChosen(const str& currentDirectory, const str& partialName, const str& fullname) { const char *pszFilename; str sCommand; pszFilename = fullname.c_str(); sCommand = va("ui_dmmap %s\n", pszFilename + 5); Cbuf_AddText(sCommand); CloseWindow(); } void MpMapPickerClass::FileChosen(Event *ev) { if (!listbox->getCurrentItem()) { return; } uii.Snd_PlaySound("sound/menu/apply.wav"); UIListCtrlItem *item = listbox->GetItem(listbox->getCurrentItem()); str name = item->getListItemString(0); str directory = item->getListItemString(1); FileSelected(directory, name, directory + name); } void MpMapPickerClass::CloseWindow(void) { PostEvent(EV_Remove, 0); } void MpMapPickerClass::OnDeactivated(Event *ev) { CloseWindow(); } MpMapPickerItem::MpMapPickerItem(const str& string, const str& directory) { m_string = string; m_directory = directory; } int MpMapPickerItem::getListItemValue(int which) const { return atoi(m_string); } griditemtype_t MpMapPickerItem::getListItemType(int which) const { return griditemtype_t::TYPE_STRING; } str MpMapPickerItem::getListItemString(int which) const { switch (which) { default: case 0: return m_string; case 1: return m_directory; } } void MpMapPickerItem::DrawListItem(int iColumn, const UIRect2D& drawRect, bool bSelected, UIFont *pFont) {} qboolean MpMapPickerItem::IsHeaderEntry() const { return qfalse; }