/* =========================================================================== 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" class PMPickerItem : public UIListCtrlItem { str m_string; public: PMPickerItem(const str& string); 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; }; typedef struct { const char *fileName; const char *displayName; } PMPickerModel_t; static const PMPickerModel_t pickerModels[] = { // 2.0 skins {"allied_101st_captain", "US - 101st Airborne Captain" }, {"allied_101st_infantry", "US - 101st Airborne Private 1" }, {"allied_101st_scout", "US - 101st Airborne Private 2" }, {"allied_501st_pir_scout", "US - 501st Paratrooper 1" }, {"allied_501st_pir_soldier", "US - 501st Paratrooper 2" }, // 1.0 skins {"allied_airborne", "US - 501st Paratrooper 3" }, // Readded in OPM (was removed in 2.0) {"allied_manon", "US - Manon" }, // 2.0 skins {"allied_british_6th_airborne_captain", "UK - 6th Airborne Captain" }, {"allied_british_6th_airborne_paratrooper", "UK - 6th Airborne Paratrooper" }, // 1.0 skins {"allied_pilot", "US - Army Pilot" }, // 2.0 skins {"allied_russian_corporal", "RA - Corporal" }, {"allied_russian_crazy_boris", "RA - Crazy Boris" }, {"allied_russian_recon_scout", "RA - Junior Lieutenant" }, {"allied_russian_recon_soldier", "RA - Black Sea Petty Officer" }, // 1.0 skins {"allied_sas", "UK - SAS Officer" }, {"american_army", "US - Soldier" }, {"american_ranger", "US - Ranger" }, // 1.0 skins {"german_afrika_officer", "DE - Afrika Officer" }, {"german_afrika_private", "DE - Afrika Private" }, // 2.0 skins {"german_ardennes_artillery_commander", "DE - Artillery Commander" }, {"german_dday_colonel", "DE - Normandy Colonel" }, // 1.0 skins {"german_elite_officer", "DE - Elite Officer" }, {"german_elite_sentry", "DE - Elite Sentry" }, {"german_kradshutzen", "DE - Kradshutzen" }, {"german_panzer_grenadier", "DE - Panzer Grenadier" }, {"german_panzer_obershutze", "DE - Panzer Obershutze" }, {"german_panzer_shutze", "DE - Panzer Shutze" }, {"german_panzer_tankcommander", "DE - Panzer Tank Commander" }, {"german_scientist", "DE - German Scientist" }, // Those skins were superseded by german_waffenss {"german_waffen_officer", "DE - Waffen Officer" }, {"german_waffen_shutze", "DE - Waffen Shutze" }, // 1.0 skins {"german_waffenss_officer", "DE - Waffen Officer" }, {"german_waffenss_shutze", "DE - Waffen Shutze" }, {"german_wehrmacht_officer", "DE - Wehrmacht Officer" }, {"german_wehrmacht_soldier", "DE - Wehrmacht Soldier" }, {"german_winter_1", "DE - Winter Infantry 1" }, {"german_winter_2", "DE - Winter Infantry 2" }, {"german_worker", "DE - German Mechanic" }, // 2.11 skins {"allied_british_tank_corporal", "UK - 6th Royal Tank Regiment" }, {"allied_russian_seaman", "RA - Red Navy Seaman" }, {"german_Panzer_Corporal", "DE - 1st Panzer Regiment" }, {"allied_technician", "US - Air Force Technician" }, {"german_stukageschwader", "DE - Stukageschwader" }, // 2.30 skins {"It_AX_Ital_Vol", "IT - 10th Army XXI Corps" }, {"SC_AX_Ital_Inf", "IT - 6th Army 202nd Coastal Div"}, {"SC_AX_Ital_Inf2", "IT - 114th Inf Regiment" }, {"SC_AX_ITAL_PARA", "IT - Paracadutista Militare" }, // 2.40 skins {"allied_Wheathers", "US - General Wheathers" }, {"allied_US_Tank", "US - II Corps Tank Commander" }, {"allied_US_Mask", "US - II Corps Infantry" }, {"allied_british_Cmd", "UK - 10th Corps" }, {"allied_british_Tank", "UK - 8th Army" }, {NULL, NULL } }; const char *PM_FilenameToDisplayname(const char *fileName) { int i; for (i = 0; pickerModels[i].fileName; i++) { const PMPickerModel_t& model = pickerModels[i]; if (!Q_stricmp(model.fileName, fileName)) { return model.displayName; } } return fileName; } const char *PM_DisplaynameToFilename(const char *displayName) { int i; for (i = 0; pickerModels[i].fileName; i++) { const PMPickerModel_t& model = pickerModels[i]; if (!Q_stricmp(model.displayName, displayName)) { return model.fileName; } } return displayName; } CLASS_DECLARATION(USignal, PlayerModelPickerClass, NULL) { {&EV_UIListBase_ItemSelected, &PlayerModelPickerClass::FileSelected }, {&EV_UIListBase_ItemDoubleClicked, &PlayerModelPickerClass::FileChosen }, {&UIFloatingWindow::W_ClosePressed, &PlayerModelPickerClass::OnDeactivated}, {&W_Deactivated, &PlayerModelPickerClass::OnDeactivated}, {NULL, NULL } }; PlayerModelPickerClass::PlayerModelPickerClass() { window = new UIFloatingWindow(); window->Create( NULL, UIRect2D((uid.vidWidth - 400) / 2, (uid.vidHeight - 300) / 2, 400, 300), "Player Model Select...", 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("Player Model", 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(); m_bGermanModels = false; } PlayerModelPickerClass::~PlayerModelPickerClass() { if (listbox) { delete listbox; listbox = NULL; } if (window) { delete window; window = NULL; } } void PlayerModelPickerClass::Setup(const char *root_directory, const char *current_directory, qboolean bGermanModels) { Initialize(root_directory, current_directory, bGermanModels); } void PlayerModelPickerClass::Initialize( const char *root_directory, const char *current_directory, qboolean bGermanModels ) { rootDirectory = root_directory; m_bGermanModels = bGermanModels; if (rootDirectory.length() > 1 && rootDirectory[rootDirectory.length() - 1] != '/') { rootDirectory += "/"; } currentDirectory = current_directory; if (currentDirectory.length() > 1 && currentDirectory[currentDirectory.length() - 1] != '/') { currentDirectory += "/"; } SetupFiles(); } void PlayerModelPickerClass::SetupFiles(void) { str mappath; char work[128]; char **filenames; const char *displayName; int numfiles; int i; int iLen; qboolean bIsGerman; // cleanup listbox->DeleteAllItems(); if (m_bGermanModels) { window->setTitle("Select Your Axis Player Model"); } else { window->setTitle("Select Your Allied Player Model"); } filenames = FS_ListFiles(currentDirectory, ".tik", qfalse, &numfiles); for (i = 0; i < numfiles; i++) { Q_strncpyz(work, filenames[i], sizeof(work)); if (strstr(work, "_fps")) { // ignore view models continue; } if (work[0] == '_') { // ignore hidden models continue; } // allied_manon readded in OPM //if (!Q_stricmpn(work, "allied_manon")) { // continue; //} bIsGerman = !Q_stricmpn(work, "german", 6u) || !Q_stricmpn(work, "axis", 4u) || !Q_stricmpn(work, "it", 2u) || !Q_stricmpn(work, "sc", 2u); if (m_bGermanModels != bIsGerman) { continue; } // strip the extension work[strlen(work) - 4] = 0; displayName = PM_FilenameToDisplayname(work); listbox->AddItem(new PMPickerItem(displayName)); } FS_FreeFileList(filenames); listbox->SortByColumn(0); } void PlayerModelPickerClass::FileSelected( const str& name, const str& currentDirectory, const str& partialName, const str& fullname ) { FileChosen(name, currentDirectory, partialName, fullname); } void PlayerModelPickerClass::FileSelected(Event *ev) { str name; char donotshowssindeorfr[64]; str fullname; name = listbox->GetItem(listbox->getCurrentItem())->getListItemString(0); fullname = PM_DisplaynameToFilename(name); if (!Q_stricmpn(fullname, "german_waffen_", 14)) { Q_strncpyz(donotshowssindeorfr, "german_waffenss_", sizeof(donotshowssindeorfr)); Q_strcat(donotshowssindeorfr, sizeof(donotshowssindeorfr), fullname.c_str() + 14); } else { Q_strncpyz(donotshowssindeorfr, fullname, sizeof(donotshowssindeorfr)); } FileSelected(name, currentDirectory, fullname, currentDirectory + donotshowssindeorfr); } void PlayerModelPickerClass::FileChosen( const str& name, const str& currentDirectory, const str& partialName, const str& fullname ) { str sCommand; if (m_bGermanModels) { sCommand += "ui_dm_playergermanmodel \"" + name; sCommand += "\" ; ui_dm_playergermanmodel_set " + partialName; sCommand += " ; ui_disp_playergermanmodel " + fullname + ".tik"; } else { sCommand += "ui_dm_playermodel \"" + name; sCommand += "\" ; ui_dm_playermodel_set " + partialName; sCommand += " ; ui_disp_playermodel " + fullname + ".tik"; } sCommand += "\n"; Cbuf_AddText(sCommand); CloseWindow(); } void PlayerModelPickerClass::FileChosen(Event *ev) { str name; char donotshowssindeorfr[64]; str fullname; name = listbox->GetItem(listbox->getCurrentItem())->getListItemString(0); fullname = PM_DisplaynameToFilename(name); if (!Q_stricmpn(fullname, "german_waffen_", 14)) { Q_strncpyz(donotshowssindeorfr, "german_waffen_", sizeof(donotshowssindeorfr)); Q_strcat(donotshowssindeorfr, sizeof(donotshowssindeorfr), fullname.c_str() + 14); } else { Q_strncpyz(donotshowssindeorfr, fullname, sizeof(donotshowssindeorfr)); } FileChosen(name, currentDirectory, fullname, currentDirectory + donotshowssindeorfr); } void PlayerModelPickerClass::CloseWindow(void) { PostEvent(EV_Remove, 0); } void PlayerModelPickerClass::OnDeactivated(Event *ev) { CloseWindow(); } PMPickerItem::PMPickerItem(const str& string) { m_string = string; } int PMPickerItem::getListItemValue(int which) const { return atoi(m_string); } griditemtype_t PMPickerItem::getListItemType(int which) const { return griditemtype_t::TYPE_STRING; } str PMPickerItem::getListItemString(int which) const { return m_string; } void PMPickerItem::DrawListItem(int iColumn, const UIRect2D& drawRect, bool bSelected, UIFont *pFont) {} qboolean PMPickerItem::IsHeaderEntry() const { return qfalse; }