2016-03-27 11:49:47 +02:00
|
|
|
/*
|
|
|
|
===========================================================================
|
2023-12-29 14:25:35 +01:00
|
|
|
Copyright (C) 2023 the OpenMoHAA team
|
2016-03-27 11:49:47 +02:00
|
|
|
|
|
|
|
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"
|
|
|
|
|
2023-12-29 14:25:35 +01:00
|
|
|
class PMPickerItem : public UIListCtrlItem
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-12-29 14:25:35 +01:00
|
|
|
str m_string;
|
|
|
|
|
|
|
|
public:
|
2023-12-30 16:54:57 +01:00
|
|
|
PMPickerItem(const str& string);
|
|
|
|
|
2023-12-29 14:25:35 +01:00
|
|
|
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;
|
|
|
|
};
|
|
|
|
|
2023-12-30 14:09:32 +01:00
|
|
|
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 }
|
|
|
|
};
|
|
|
|
|
|
|
|
static 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static 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;
|
|
|
|
}
|
|
|
|
|
2023-12-29 14:25:35 +01:00
|
|
|
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 }
|
2016-03-27 11:49:47 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
PlayerModelPickerClass::PlayerModelPickerClass()
|
|
|
|
{
|
2023-12-30 16:54:57 +01:00
|
|
|
window = new UIFloatingWindow();
|
|
|
|
window->Create(
|
|
|
|
NULL,
|
|
|
|
UIRect2D((cls.glconfig.vidWidth - 400) / 2, (cls.glconfig.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;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
PlayerModelPickerClass::~PlayerModelPickerClass()
|
|
|
|
{
|
2023-12-30 16:54:57 +01:00
|
|
|
if (listbox) {
|
|
|
|
delete listbox;
|
|
|
|
listbox = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (window) {
|
|
|
|
delete window;
|
|
|
|
window = NULL;
|
|
|
|
}
|
2023-12-29 14:25:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void PlayerModelPickerClass::Setup(const char *root_directory, const char *current_directory, qboolean bGermanModels)
|
|
|
|
{
|
2023-12-30 16:54:57 +01:00
|
|
|
Initialize(root_directory, current_directory, bGermanModels);
|
2023-12-29 14:25:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void PlayerModelPickerClass::Initialize(
|
|
|
|
const char *root_directory, const char *current_directory, qboolean bGermanModels
|
|
|
|
)
|
|
|
|
{
|
2023-12-30 16:54:57 +01:00
|
|
|
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();
|
2023-12-29 14:25:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void PlayerModelPickerClass::SetupFiles(void)
|
|
|
|
{
|
2023-12-30 16:54:57 +01:00
|
|
|
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);
|
2023-12-29 14:25:35 +01:00
|
|
|
}
|
|
|
|
|
2023-12-30 02:22:41 +01:00
|
|
|
void PlayerModelPickerClass::FileSelected(
|
|
|
|
const str& name, const str& currentDirectory, const str& partialName, const str& fullname
|
|
|
|
)
|
2023-12-29 14:25:35 +01:00
|
|
|
{
|
2023-12-30 16:54:57 +01:00
|
|
|
FileChosen(name, currentDirectory, partialName, fullname);
|
2023-12-29 14:25:35 +01:00
|
|
|
}
|
|
|
|
|
2023-12-30 02:22:41 +01:00
|
|
|
void PlayerModelPickerClass::FileSelected(Event *ev)
|
2023-12-29 14:25:35 +01:00
|
|
|
{
|
2023-12-30 16:54:57 +01:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
|
|
|
FileSelected(name, currentDirectory, fullname, currentDirectory + donotshowssindeorfr);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-12-30 02:22:41 +01:00
|
|
|
void PlayerModelPickerClass::FileChosen(
|
|
|
|
const str& name, const str& currentDirectory, const str& partialName, const str& fullname
|
|
|
|
)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-12-30 16:54:57 +01:00
|
|
|
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();
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-12-29 14:25:35 +01:00
|
|
|
void PlayerModelPickerClass::FileChosen(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-12-30 16:54:57 +01:00
|
|
|
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);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-12-29 14:25:35 +01:00
|
|
|
void PlayerModelPickerClass::CloseWindow(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-12-30 16:54:57 +01:00
|
|
|
PostEvent(EV_Remove, 0);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-12-29 14:25:35 +01:00
|
|
|
void PlayerModelPickerClass::OnDeactivated(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-12-30 16:54:57 +01:00
|
|
|
CloseWindow();
|
|
|
|
}
|
|
|
|
|
|
|
|
PMPickerItem::PMPickerItem(const str& string)
|
|
|
|
{
|
|
|
|
m_string = string;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-12-29 14:25:35 +01:00
|
|
|
int PMPickerItem::getListItemValue(int which) const
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-12-30 02:22:41 +01:00
|
|
|
return atoi(m_string);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-12-29 14:25:35 +01:00
|
|
|
griditemtype_t PMPickerItem::getListItemType(int which) const
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-12-29 14:25:35 +01:00
|
|
|
return griditemtype_t::TYPE_STRING;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-12-29 14:25:35 +01:00
|
|
|
str PMPickerItem::getListItemString(int which) const
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-12-30 02:22:41 +01:00
|
|
|
return m_string;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-12-30 02:22:41 +01:00
|
|
|
void PMPickerItem::DrawListItem(int iColumn, const UIRect2D& drawRect, bool bSelected, UIFont *pFont) {}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-12-29 14:25:35 +01:00
|
|
|
qboolean PMPickerItem::IsHeaderEntry() const
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-12-29 14:25:35 +01:00
|
|
|
return qfalse;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|