From 2809f51ba6ea14f1fc4f175c6c5f5e06983ced9a Mon Sep 17 00:00:00 2001 From: momo5502 Date: Thu, 24 Dec 2015 03:26:46 +0100 Subject: [PATCH] Menu loading code. --- iw4/Components/AssetHandler.cpp | 4 +- iw4/Components/Dvar.cpp | 3 + iw4/Components/FastFiles.cpp | 74 ++++ iw4/Components/FastFiles.hpp | 17 + iw4/Components/FileSystem.cpp | 30 ++ iw4/Components/FileSystem.hpp | 27 ++ iw4/Components/Loader.cpp | 2 + iw4/Components/Loader.hpp | 2 + iw4/Components/Materials.hpp | 1 + iw4/Components/Menus.cpp | 237 +++++++++++- iw4/Components/Menus.hpp | 23 ++ iw4/Components/MusicalTalent.cpp | 8 +- iw4/Components/MusicalTalent.hpp | 1 + iw4/Components/QuickPatch.cpp | 6 + iw4/Game/Functions.cpp | 17 + iw4/Game/Functions.hpp | 30 ++ iw4/Game/Structs.hpp | 597 ++++++++++++++++++++++++++++++- iw4/iw4.vcxproj | 4 + iw4/iw4.vcxproj.filters | 12 + 19 files changed, 1081 insertions(+), 14 deletions(-) create mode 100644 iw4/Components/FastFiles.cpp create mode 100644 iw4/Components/FastFiles.hpp create mode 100644 iw4/Components/FileSystem.cpp create mode 100644 iw4/Components/FileSystem.hpp diff --git a/iw4/Components/AssetHandler.cpp b/iw4/Components/AssetHandler.cpp index 1403b8f4..c4a47d70 100644 --- a/iw4/Components/AssetHandler.cpp +++ b/iw4/Components/AssetHandler.cpp @@ -7,8 +7,9 @@ namespace Components Game::XAssetHeader AssetHandler::FindAsset(Game::XAssetType type, const char* filename) { - Game::XAssetHeader header = nullptr; + Game::XAssetHeader header = { 0 }; + // Allow call DB_FindXAssetHeader within the hook AssetHandler::BypassState = true; if (AssetHandler::TypeCallbacks.find(type) != AssetHandler::TypeCallbacks.end()) @@ -16,6 +17,7 @@ namespace Components header = AssetHandler::TypeCallbacks[type](type, filename); } + // Disallow calling DB_FindXAssetHeader ;) AssetHandler::BypassState = false; return header; diff --git a/iw4/Components/Dvar.cpp b/iw4/Components/Dvar.cpp index 7b556098..f9bc396d 100644 --- a/iw4/Components/Dvar.cpp +++ b/iw4/Components/Dvar.cpp @@ -122,6 +122,9 @@ namespace Components // un-cheat cg_fov and add archive flags Utils::Hook::Xor(0x4F8E35, Game::dvar_flag::DVAR_FLAG_CHEAT | Game::dvar_flag::DVAR_FLAG_SAVED); + // set flags of cg_drawFPS to archive + Utils::Hook::Or(0x4F8F69, Game::dvar_flag::DVAR_FLAG_SAVED); + // set cg_fov max to 90.0 static float cgFov90 = 90.0f; Utils::Hook::Set(0x4F8E28, &cgFov90); diff --git a/iw4/Components/FastFiles.cpp b/iw4/Components/FastFiles.cpp new file mode 100644 index 00000000..380459eb --- /dev/null +++ b/iw4/Components/FastFiles.cpp @@ -0,0 +1,74 @@ +#include "..\STDInclude.hpp" + +namespace Components +{ + std::vector FastFiles::ZonePaths; + + void FastFiles::LoadDLCUIZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync) + { + Game::XZoneInfo* data = new Game::XZoneInfo[zoneCount + 2]; + memcpy(data, zoneInfo, sizeof(Game::XZoneInfo) * zoneCount); + + data[zoneCount].name = "dlc1_ui_mp"; + data[zoneCount].allocFlags = 2; + data[zoneCount].freeFlags = 0; + zoneCount++; + + data[zoneCount].name = "dlc2_ui_mp"; + data[zoneCount].allocFlags = 2; + data[zoneCount].freeFlags = 0; + zoneCount++; + + Game::DB_LoadXAssets(data, zoneCount, sync); + + delete[] data; + } + + const char* FastFiles::GetZoneLocation(const char* file) + { + const char* dir = Dvar::Var("fs_basepath").Get(); + + for (auto &path : FastFiles::ZonePaths) + { + std::string absoluteFile = Utils::VA("%s\\%s%s", dir, path.data(), file); + + // No ".ff" appended, append it manually + if (strstr(file, ".ff") != (file + strlen(file) - 3)) + { + absoluteFile.append(".ff"); + } + + // Check if FastFile exists + if (GetFileAttributes(absoluteFile.data()) != INVALID_FILE_ATTRIBUTES) + { + return Utils::VA("%s", path.data()); + } + } + + return Utils::VA("zone\\%s\\", Game::Win_GetLanguage()); + } + + void FastFiles::AddZonePath(std::string path) + { + FastFiles::ZonePaths.push_back(path); + } + + FastFiles::FastFiles() + { + // Redirect zone paths + Utils::Hook(0x44DA90, FastFiles::GetZoneLocation, HOOK_JUMP).Install()->Quick(); + + // Allow dlc ui zone loading + Utils::Hook(0x506BC7, FastFiles::LoadDLCUIZones, HOOK_CALL).Install()->Quick(); + Utils::Hook(0x60B4AC, FastFiles::LoadDLCUIZones, HOOK_CALL).Install()->Quick(); + + // Add custom zone paths + FastFiles::AddZonePath("zone\\patch\\"); + FastFiles::AddZonePath("zone\\dlc\\"); + } + + FastFiles::~FastFiles() + { + FastFiles::ZonePaths.clear(); + } +} diff --git a/iw4/Components/FastFiles.hpp b/iw4/Components/FastFiles.hpp new file mode 100644 index 00000000..c8e62ece --- /dev/null +++ b/iw4/Components/FastFiles.hpp @@ -0,0 +1,17 @@ +namespace Components +{ + class FastFiles : public Component + { + public: + FastFiles(); + ~FastFiles(); + const char* GetName() { return "FastFiles"; }; + + static void AddZonePath(std::string path); + + private: + static std::vector ZonePaths; + static const char* GetZoneLocation(const char* file); + static void LoadDLCUIZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync); + }; +} diff --git a/iw4/Components/FileSystem.cpp b/iw4/Components/FileSystem.cpp new file mode 100644 index 00000000..d061d6fa --- /dev/null +++ b/iw4/Components/FileSystem.cpp @@ -0,0 +1,30 @@ +#include "..\STDInclude.hpp" + +namespace Components +{ + void FileSystem::File::Read() + { + char* buffer = nullptr; + int size = Game::FS_ReadFile(this->FilePath.data(), &buffer); + + this->Buffer.clear(); + + if (size < 0) + { + if (buffer) + { + Game::FS_FreeFile(buffer); + } + } + else + { + this->Buffer.append(buffer, size); + Game::FS_FreeFile(buffer); + } + } + + FileSystem::FileSystem() + { + + } +} diff --git a/iw4/Components/FileSystem.hpp b/iw4/Components/FileSystem.hpp new file mode 100644 index 00000000..6ed33dff --- /dev/null +++ b/iw4/Components/FileSystem.hpp @@ -0,0 +1,27 @@ +namespace Components +{ + class FileSystem : public Component + { + public: + + class File + { + public: + //File() {}; + File(std::string file) : FilePath(file) { this->Read(); }; + + bool Exists() { return this->Buffer.size() > 0; }; + std::string GetName() { return this->FilePath; }; + std::string& GetBuffer() { return this->Buffer; }; + + private: + std::string FilePath; + std::string Buffer; + + void Read(); + }; + + FileSystem(); + const char* GetName() { return "FileSystem"; }; + }; +} diff --git a/iw4/Components/Loader.cpp b/iw4/Components/Loader.cpp index c9c5fe54..4a6e7516 100644 --- a/iw4/Components/Loader.cpp +++ b/iw4/Components/Loader.cpp @@ -15,7 +15,9 @@ namespace Components Loader::Register(new Console()); Loader::Register(new RawFiles()); Loader::Register(new Renderer()); + Loader::Register(new FastFiles()); Loader::Register(new Materials()); + Loader::Register(new FileSystem()); Loader::Register(new QuickPatch()); Loader::Register(new AssetHandler()); Loader::Register(new MusicalTalent()); diff --git a/iw4/Components/Loader.hpp b/iw4/Components/Loader.hpp index c5770462..44e18840 100644 --- a/iw4/Components/Loader.hpp +++ b/iw4/Components/Loader.hpp @@ -29,7 +29,9 @@ namespace Components #include "Console.hpp" #include "RawFiles.hpp" #include "Renderer.hpp" +#include "FastFiles.hpp" #include "Materials.hpp" +#include "FileSystem.hpp" #include "QuickPatch.hpp" #include "AssetHandler.hpp" #include "MusicalTalent.hpp" diff --git a/iw4/Components/Materials.hpp b/iw4/Components/Materials.hpp index 0cb374ed..5bab38a4 100644 --- a/iw4/Components/Materials.hpp +++ b/iw4/Components/Materials.hpp @@ -7,6 +7,7 @@ namespace Components ~Materials(); const char* GetName() { return "Materials"; }; + private: static Utils::Hook ImageVersionCheckHook; static void ImageVersionCheck(); }; diff --git a/iw4/Components/Menus.cpp b/iw4/Components/Menus.cpp index 7d99f06e..05d48cd8 100644 --- a/iw4/Components/Menus.cpp +++ b/iw4/Components/Menus.cpp @@ -2,8 +2,226 @@ namespace Components { + std::vector Menus::MenuList; + std::vector Menus::MenuListList; + + int Menus::ReserveSourceHandle() + { + // Check if a free slot is available + int i = 1; + for (; i < MAX_SOURCEFILES; i++) + { + if (!Game::sourceFiles[i]) + break; + } + + if (i >= MAX_SOURCEFILES) + return 0; + + // Reserve it, if yes + Game::sourceFiles[i] = (Game::source_t*)1; + + return i; + } + + Game::script_t* Menus::LoadMenuScript(std::string buffer) + { + Game::script_t* script = Game::Script_Alloc(sizeof(Game::script_t) + 1 + buffer.length()); + + strcpy_s(script->filename, sizeof(script->filename), "script_t"); + script->buffer = (char*)(script + 1); + + *((char*)(script + 1) + buffer.length()) = '\0'; + + script->script_p = script->buffer; + script->lastscript_p = script->buffer; + script->length = buffer.length(); + script->end_p = &script->buffer[buffer.length()]; + script->line = 1; + script->lastline = 1; + script->tokenavailable = 0; + + Game::Script_SetupTokens(script, (void*)0x797F80); + script->punctuations = (Game::punctuation_t*)0x797F80; + + strcpy(script->buffer, buffer.data()); + + script->length = Game::Script_CleanString(script->buffer); + + return script; + } + + int Menus::LoadMenuSource(std::string buffer) + { + int handle = Menus::ReserveSourceHandle(); + if (!handle) return 0; // No free source slot! + + Game::source_t *source = nullptr; + Game::script_t *script = Menus::LoadMenuScript(buffer); + + if (!script) + { + Game::sourceFiles[handle] = nullptr; // Free reserved slot + return 0; + } + + script->next = NULL; + + source = (Game::source_t *)calloc(1, sizeof(Game::source_t)); + + strncpy(source->filename, "string", 64); + source->scriptstack = script; + source->tokens = NULL; + source->defines = NULL; + source->indentstack = NULL; + source->skip = 0; + source->definehash = (Game::define_t**)calloc(1, 4096); + + Game::sourceFiles[handle] = source; + + return handle; + } + + Game::menuDef_t* Menus::LoadMenu(Game::menuDef_t* menudef) + { + FileSystem::File menuFile(Utils::VA("ui_mp\\%s.menu", menudef->window.name)); + + if (menuFile.Exists()) + { + int handle = Menus::LoadMenuSource(menuFile.GetBuffer()); + + // TODO: Parse menu! + + Menus::FreeMenuSource(handle); + } + + return menudef; + } + + Game::MenuList* Menus::LoadMenuList(Game::MenuList* menuList) + { + bool NewMenuLoaded = false; + + Game::MenuList* newList = (Game::MenuList*)calloc(1, sizeof(Game::MenuList)); + newList->name = _strdup(menuList->name); + newList->menus = (Game::menuDef_t **)calloc(menuList->menuCount, sizeof(Game::menuDef_t *)); + newList->menuCount = menuList->menuCount; + + Menus::MenuListList.push_back(newList); + + for (int i = 0; i < newList->menuCount; i++) + { + newList->menus[i] = Menus::LoadMenu(menuList->menus[i]); + } + + return newList; + } + + void Menus::FreeMenuScript(Game::script_t* script) + { + Game::FreeMemory(script); + } + + void Menus::FreeMenuSource(int handle) + { + if (!Game::sourceFiles[handle]) return; + + Game::script_t *script; +// Game::token_t *token; +// Game::define_t *define; + Game::indent_t *indent; + Game::source_t *source = Game::sourceFiles[handle]; + + while (source->scriptstack) + { + script = source->scriptstack; + source->scriptstack = source->scriptstack->next; + Menus::FreeMenuScript(script); + } + + while (source->indentstack) + { + indent = source->indentstack; + source->indentstack = source->indentstack->next; + free(indent); + } + + if (source->definehash) free(source->definehash); + + free(source); + + Game::sourceFiles[handle] = nullptr; + } + + void Menus::FreeMenu(Game::menuDef_t* menudef) + { + // + } + + void Menus::FreeMenuList(Game::MenuList* menuList) + { + if (menuList) + { + if (menuList->name) + { + free((void*)menuList->name); + } + + if (menuList->menus) + { + free(menuList->menus); + } + + free(menuList); + } + } + + void Menus::FreeEverything() + { + for (auto menu : Menus::MenuList) + { + Menus::FreeMenu(menu); + } + + Menus::MenuList.clear(); + + for (auto menuList : Menus::MenuListList) + { + Menus::FreeMenuList(menuList); + } + + Menus::MenuListList.clear(); + } + + Game::XAssetHeader Menus::MenuFileLoad(Game::XAssetType type, const char* filename) + { + Game::XAssetHeader header = { 0 }; + + // Check if we already loaded it + for (auto menuList : Menus::MenuListList) + { + if (!strcmp(menuList->name, filename)) + { + header.menuList = menuList; + return header; + } + } + + Game::MenuList* menuList = Game::DB_FindXAssetHeader(type, filename).menuList; + header.menuList = menuList; + + if (menuList) + { + header.menuList = Menus::LoadMenuList(menuList); + } + + return header; + } + Menus::Menus() { + AssetHandler::On(Game::XAssetType::ASSET_TYPE_MENUFILE, Menus::MenuFileLoad); + Command::Add("openmenu", [] (Command::Params params) { if (params.Length() != 2) @@ -12,15 +230,18 @@ namespace Components return; } - char* menu = params[1]; + Game::Menus_OpenByName(0x62E2858, params[1]); + }); - __asm - { - push menu - push 62E2858h - mov eax, 4CCE60h - call eax - } + Command::Add("reloadmenus", [] (Command::Params params) + { + Menus::FreeEverything(); + // TODO: Refresh ui context? }); } + + Menus::~Menus() + { + Menus::FreeEverything(); + } } diff --git a/iw4/Components/Menus.hpp b/iw4/Components/Menus.hpp index b54472d9..391e93fc 100644 --- a/iw4/Components/Menus.hpp +++ b/iw4/Components/Menus.hpp @@ -1,9 +1,32 @@ +#define MAX_SOURCEFILES 64 + namespace Components { class Menus : public Component { public: Menus(); + ~Menus(); const char* GetName() { return "Menus"; }; + + private: + static std::vector MenuList; + static std::vector MenuListList; + + static Game::XAssetHeader MenuFileLoad(Game::XAssetType type, const char* filename); + static Game::MenuList* LoadMenuList(Game::MenuList* menuList); + static Game::menuDef_t* LoadMenu(Game::menuDef_t* menudef); + + static Game::script_t* LoadMenuScript(std::string buffer); + static int LoadMenuSource(std::string buffer); + static int ReserveSourceHandle(); + + static void FreeMenuScript(Game::script_t* script); + static void FreeMenuSource(int handle); + + static void FreeMenuList(Game::MenuList* menuList); + static void FreeMenu(Game::menuDef_t* menudef); + + static void FreeEverything(); }; } diff --git a/iw4/Components/MusicalTalent.cpp b/iw4/Components/MusicalTalent.cpp index 4af85982..dfc88cf6 100644 --- a/iw4/Components/MusicalTalent.cpp +++ b/iw4/Components/MusicalTalent.cpp @@ -11,9 +11,11 @@ namespace Components Game::XAssetHeader MusicalTalent::ManipulateAliases(Game::XAssetType type, const char* filename) { + Game::XAssetHeader header = { 0 }; + if (MusicalTalent::SoundAliasList.find(Utils::StrToLower(filename)) != MusicalTalent::SoundAliasList.end()) { - Game::snd_alias_list_t* aliases = (Game::snd_alias_list_t*)Game::DB_FindXAssetHeader(type, filename); + Game::snd_alias_list_t* aliases = Game::DB_FindXAssetHeader(type, filename).aliasList; if (aliases) { @@ -22,11 +24,11 @@ namespace Components aliases->aliases->stream->file = MusicalTalent::SoundAliasList[Utils::StrToLower(filename)]; } - return aliases; + header.aliasList = aliases; } } - return NULL; + return header; } MusicalTalent::MusicalTalent() diff --git a/iw4/Components/MusicalTalent.hpp b/iw4/Components/MusicalTalent.hpp index aece4968..a8943a86 100644 --- a/iw4/Components/MusicalTalent.hpp +++ b/iw4/Components/MusicalTalent.hpp @@ -5,6 +5,7 @@ namespace Components public: MusicalTalent(); ~MusicalTalent(); + const char* GetName() { return "MusicalTalent"; }; static void Replace(std::string sound, const char* file); diff --git a/iw4/Components/QuickPatch.cpp b/iw4/Components/QuickPatch.cpp index 50d40c96..e269a21a 100644 --- a/iw4/Components/QuickPatch.cpp +++ b/iw4/Components/QuickPatch.cpp @@ -38,6 +38,9 @@ namespace Components // fs_basegame Utils::Hook::Set(0x6431D1, "data"); + // remove limit on IWD file loading + Utils::Hook::Set(0x642BF3, 0xEB); + // Disable UPNP Utils::Hook::Nop(0x60BE24, 5); @@ -48,6 +51,9 @@ namespace Components Utils::Hook::Set(0x6832BA, 0xEB); Utils::Hook::Set(0x4BD190, 0xC3); + // default sv_pure to 0 + Utils::Hook::Set(0x4D3A74, 0); + // Why? Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_WEAPON, 2400); } diff --git a/iw4/Game/Functions.cpp b/iw4/Game/Functions.cpp index 44415e90..c49aa5ba 100644 --- a/iw4/Game/Functions.cpp +++ b/iw4/Game/Functions.cpp @@ -10,6 +10,7 @@ namespace Game DB_FindXAssetHeader_t DB_FindXAssetHeader = (DB_FindXAssetHeader_t)0x407930; DB_GetXAssetSizeHandler_t* DB_GetXAssetSizeHandlers = (DB_GetXAssetSizeHandler_t*)0x799488; + DB_LoadXAssets_t DB_LoadXAssets = (DB_LoadXAssets_t)0x4E5930; Dvar_RegisterBool_t Dvar_RegisterBool = (Dvar_RegisterBool_t)0x4CE1A0; Dvar_RegisterFloat_t Dvar_RegisterFloat = (Dvar_RegisterFloat_t)0x648440; @@ -26,8 +27,21 @@ namespace Game Field_Clear_t Field_Clear = (Field_Clear_t)0x437EB0; + FreeMemory_t FreeMemory = (FreeMemory_t)0x4D6640; + + FS_FreeFile_t FS_FreeFile = (FS_FreeFile_t)0x4416B0; + FS_ReadFile_t FS_ReadFile = (FS_ReadFile_t)0x4F4B90; + + Menus_OpenByName_t Menus_OpenByName = (Menus_OpenByName_t)0x4CCE60; + LoadModdableRawfile_t LoadModdableRawfile = (LoadModdableRawfile_t)0x61ABC0; + Script_Alloc_t Script_Alloc = (Script_Alloc_t)0x422E70; + Script_SetupTokens_t Script_SetupTokens = (Script_SetupTokens_t)0x4E6950; + Script_CleanString_t Script_CleanString = (Script_CleanString_t)0x498220; + + Win_GetLanguage_t Win_GetLanguage = (Win_GetLanguage_t)0x45CBA0; + void** DB_XAssetPool = (void**)0x7998A8; unsigned int* g_poolSize = (unsigned int*)0x7995E8; @@ -35,6 +49,9 @@ namespace Game DWORD* cmd_argc = (DWORD*)0x1AAC614; char*** cmd_argv = (char***)0x1AAC634; + source_t **sourceFiles = (source_t **)0x7C4A98; + keywordHash_t **menuParseKeywordHash = (keywordHash_t **)0x63AE928; + void* ReallocateAssetPool(XAssetType type, unsigned int newSize) { int elSize = DB_GetXAssetSizeHandlers[type](); diff --git a/iw4/Game/Functions.hpp b/iw4/Game/Functions.hpp index 1ca8f247..524ab083 100644 --- a/iw4/Game/Functions.hpp +++ b/iw4/Game/Functions.hpp @@ -18,6 +18,9 @@ namespace Game typedef int(__cdecl * DB_GetXAssetSizeHandler_t)(); extern DB_GetXAssetSizeHandler_t* DB_GetXAssetSizeHandlers; + typedef void(*DB_LoadXAssets_t)(XZoneInfo *zoneInfo, unsigned int zoneCount, int sync); + extern DB_LoadXAssets_t DB_LoadXAssets; + typedef dvar_t* (__cdecl * Dvar_RegisterBool_t)(const char* name, bool default, int flags, const char* description); extern Dvar_RegisterBool_t Dvar_RegisterBool; @@ -54,9 +57,33 @@ namespace Game typedef void(__cdecl * Field_Clear_t)(void* field); extern Field_Clear_t Field_Clear; + typedef void(__cdecl * FreeMemory_t)(void* buffer); + extern FreeMemory_t FreeMemory; + + typedef void(__cdecl * FS_FreeFile_t)(void* buffer); + extern FS_FreeFile_t FS_FreeFile; + + typedef int(__cdecl * FS_ReadFile_t)(const char* path, char** buffer); + extern FS_ReadFile_t FS_ReadFile; + + typedef int(__cdecl * Menus_OpenByName_t)(/*UiContext **/int dc, const char *p); + extern Menus_OpenByName_t Menus_OpenByName; + typedef void* (__cdecl * LoadModdableRawfile_t)(int a1, const char* filename); extern LoadModdableRawfile_t LoadModdableRawfile; + typedef script_t* (__cdecl * Script_Alloc_t)(int length); + extern Script_Alloc_t Script_Alloc; + + typedef void(__cdecl * Script_SetupTokens_t)(script_t* script, void* tokens); + extern Script_SetupTokens_t Script_SetupTokens; + + typedef int(__cdecl * Script_CleanString_t)(char* buffer); + extern Script_CleanString_t Script_CleanString; + + typedef const char * (__cdecl * Win_GetLanguage_t)(); + extern Win_GetLanguage_t Win_GetLanguage; + extern void** DB_XAssetPool; extern unsigned int* g_poolSize; @@ -64,5 +91,8 @@ namespace Game extern DWORD* cmd_argc; extern char*** cmd_argv; + extern source_t **sourceFiles; + extern keywordHash_t **menuParseKeywordHash; + void* ReallocateAssetPool(XAssetType type, unsigned int newSize); } diff --git a/iw4/Game/Structs.hpp b/iw4/Game/Structs.hpp index e6b995b8..0d3ecfa6 100644 --- a/iw4/Game/Structs.hpp +++ b/iw4/Game/Structs.hpp @@ -48,8 +48,6 @@ namespace Game ASSET_TYPE_MAX = 43 } XAssetType; - typedef void *XAssetHeader; // Temporary - typedef enum { DVAR_FLAG_NONE = 0x0, //no flags @@ -144,4 +142,599 @@ namespace Game snd_alias_t* aliases; int numAliases; } snd_alias_list_t; + + typedef struct + { + const char *name; + int allocFlags; + int freeFlags; + } XZoneInfo; + + + + typedef float vec_t; + typedef vec_t vec4_t[4]; + struct expression_s; + struct statement_s; + struct menuDef_t; + enum operationEnum; + + struct Material + { + const char *name; + }; + + struct keyname_t + { + const char *name; + int keynum; + }; + + struct ItemFloatExpressionEntry + { + int target; + const char *s1; + const char *s2; + }; + +#define ITEM_TYPE_TEXT 0 // simple text +#define ITEM_TYPE_BUTTON 1 // button, basically text with a border +#define ITEM_TYPE_RADIOBUTTON 2 // toggle button, may be grouped +#define ITEM_TYPE_CHECKBOX 3 // check box +#define ITEM_TYPE_EDITFIELD 4 // editable text, associated with a dvar +#define ITEM_TYPE_COMBO 5 // drop down list +#define ITEM_TYPE_LISTBOX 6 // scrollable list +#define ITEM_TYPE_MODEL 7 // model +#define ITEM_TYPE_OWNERDRAW 8 // owner draw, name specs what it is +#define ITEM_TYPE_NUMERICFIELD 9 // editable text, associated with a dvar +#define ITEM_TYPE_SLIDER 10 // mouse speed, volume, etc. +#define ITEM_TYPE_YESNO 11 // yes no dvar setting +#define ITEM_TYPE_MULTI 12 // multiple list setting, enumerated +#define ITEM_TYPE_DVARENUM 13 // multiple list setting, enumerated from a dvar +#define ITEM_TYPE_BIND 14 // bind +#define ITEM_TYPE_MENUMODEL 15 // special menu model +#define ITEM_TYPE_VALIDFILEFIELD 16 // text must be valid for use in a dos filename +#define ITEM_TYPE_DECIMALFIELD 17 // editable text, associated with a dvar, which allows decimal input +#define ITEM_TYPE_UPREDITFIELD 18 // editable text, associated with a dvar +#define ITEM_TYPE_GAME_MESSAGE_WINDOW 19 // game message window +#define ITEM_TYPE_NEWSTICKER 20 // horizontal scrollbox +#define ITEM_TYPE_TEXTSCROLL 21 // vertical scrollbox +#define ITEM_TYPE_EMAILFIELD 22 +#define ITEM_TYPE_PASSWORDFIELD 23 + + struct MenuEventHandlerSet; + struct Statement_s; + + struct UIFunctionList + { + int totalFunctions; + Statement_s **functions; + }; + + struct StaticDvar + { + /*dvar_t*/ + void *dvar; + char *dvarName; + }; + + struct StaticDvarList + { + int numStaticDvars; + StaticDvar **staticDvars; + }; + + struct StringList + { + int totalStrings; + const char **strings; + }; + + struct ExpressionSupportingData + { + UIFunctionList uifunctions; + StaticDvarList staticDvarList; + StringList uiStrings; + }; + + enum expDataType : int + { + VAL_INT = 0x0, + VAL_FLOAT = 0x1, + VAL_STRING = 0x2, + VAL_FUNCTION = 0x3, + }; + + struct ExpressionString + { + const char *string; + }; + + union operandInternalDataUnion + { + int intVal; + float floatVal; + ExpressionString stringVal; + Statement_s *function; + }; + + struct Operand + { + expDataType dataType; + operandInternalDataUnion internals; + }; + + union entryInternalData + { + operationEnum op; + Operand operand; + }; + + /* expressionEntry->type */ +#define OPERATOR 0 +#define OPERAND 1 + + struct expressionEntry // 0xC + { + int type; + entryInternalData data; + }; + + struct Statement_s // 0x18 + { + int numEntries; + expressionEntry *entries; + ExpressionSupportingData *supportingData; + char unknown[0xC]; // ? + }; + + struct SetLocalVarData + { + const char *localVarName; + Statement_s *expression; + }; + + struct ConditionalScript + { + MenuEventHandlerSet *eventHandlerSet; + Statement_s *eventExpression; // loads this first + }; + + union EventData + { + const char *unconditionalScript; + ConditionalScript *conditionalScript; + MenuEventHandlerSet *elseScript; + SetLocalVarData *setLocalVarData; + }; + + enum EventType + { + EVENT_UNCONDITIONAL = 0x0, + EVENT_IF = 0x1, + EVENT_ELSE = 0x2, + EVENT_SET_LOCAL_VAR_BOOL = 0x3, + EVENT_SET_LOCAL_VAR_INT = 0x4, + EVENT_SET_LOCAL_VAR_FLOAT = 0x5, + EVENT_SET_LOCAL_VAR_STRING = 0x6, + EVENT_COUNT = 0x7, + }; + + struct MenuEventHandler + { + EventData eventData; + EventType eventType; + }; + + struct MenuEventHandlerSet + { + int eventHandlerCount; + MenuEventHandler **eventHandlers; + }; + + struct ItemKeyHandler + { + int key; + MenuEventHandlerSet *action; + ItemKeyHandler *next; + }; + +#pragma pack(push, 4) + struct rectDef_s + { + float x; + float y; + float w; + float h; + char horzAlign; + char vertAlign; + }; +#pragma pack(pop) + + /* windowDef_t->dynamicFlags */ + // 0x1 +#define WINDOWDYNAMIC_HASFOCUS 0x00000002 +#define WINDOWDYNAMIC_VISIBLE 0x00000004 +#define WINDOWDYNAMIC_FADEOUT 0x00000010 +#define WINDOWDYNAMIC_FADEIN 0x00000020 + // 0x40 + // 0x80 +#define WINDOWDYNAMIC_CLOSED 0x00000800 + // 0x2000 +#define WINDOWDYNAMIC_BACKCOLOR 0x00008000 +#define WINDOWDYNAMIC_FORECOLOR 0x00010000 + + /* windowDef_t->staticFlags */ +#define WINDOWSTATIC_DECORATION 0x00100000 +#define WINDOWSTATIC_HORIZONTALSCROLL 0x00200000 +#define WINDOWSTATIC_SCREENSPACE 0x00400000 +#define WINDOWSTATIC_AUTOWRAPPED 0x00800000 +#define WINDOWSTATIC_POPUP 0x01000000 +#define WINDOWSTATIC_OUTOFBOUNDSCLICK 0x02000000 +#define WINDOWSTATIC_LEGACYSPLITSCREENSCALE 0x04000000 +#define WINDOWSTATIC_HIDDENDURINGFLASH 0x10000000 +#define WINDOWSTATIC_HIDDENDURINGSCOPE 0x20000000 +#define WINDOWSTATIC_HIDDENDURINGUI 0x40000000 +#define WINDOWSTATIC_TEXTONLYFOCUS 0x80000000 + + struct windowDef_t // 0xA4 + { + const char *name; // 0x00 + rectDef_s rect; + rectDef_s rectClient; + char *group; // 0x2C + int style; // 0x30 + int border; // 0x34 + int ownerDraw; // 0x38 + int ownerDrawFlags; // 0x3C + float borderSize; // 0x40 + int staticFlags; // 0x44 + int dynamicFlags; // 0x48 + int nextTime; // 0x4C + float foreColor[4]; // 0x50 + float backColor[4]; // 0x60 + float borderColor[4];// 0x70 + float outlineColor[4];// 0x80 + float disableColor[4];// 0x90 + Material *background; // 0xA0 + }; + + enum ItemFloatExpressionTarget + { + ITEM_FLOATEXP_TGT_RECT_X = 0x0, + ITEM_FLOATEXP_TGT_RECT_Y = 0x1, + ITEM_FLOATEXP_TGT_RECT_W = 0x2, + ITEM_FLOATEXP_TGT_RECT_H = 0x3, + ITEM_FLOATEXP_TGT_FORECOLOR_R = 0x4, + ITEM_FLOATEXP_TGT_FORECOLOR_G = 0x5, + ITEM_FLOATEXP_TGT_FORECOLOR_B = 0x6, + ITEM_FLOATEXP_TGT_FORECOLOR_RGB = 0x7, + ITEM_FLOATEXP_TGT_FORECOLOR_A = 0x8, + ITEM_FLOATEXP_TGT_GLOWCOLOR_R = 0x9, + ITEM_FLOATEXP_TGT_GLOWCOLOR_G = 0xA, + ITEM_FLOATEXP_TGT_GLOWCOLOR_B = 0xB, + ITEM_FLOATEXP_TGT_GLOWCOLOR_RGB = 0xC, + ITEM_FLOATEXP_TGT_GLOWCOLOR_A = 0xD, + ITEM_FLOATEXP_TGT_BACKCOLOR_R = 0xE, + ITEM_FLOATEXP_TGT_BACKCOLOR_G = 0xF, + ITEM_FLOATEXP_TGT_BACKCOLOR_B = 0x10, + ITEM_FLOATEXP_TGT_BACKCOLOR_RGB = 0x11, + ITEM_FLOATEXP_TGT_BACKCOLOR_A = 0x12, + ITEM_FLOATEXP_TGT__COUNT = 0x13, + }; + + struct ItemFloatExpression + { + ItemFloatExpressionTarget target; + Statement_s *expression; + }; + + struct editFieldDef_s + { + float minVal; + float maxVal; + float defVal; + float range; + int maxChars; + int maxCharsGotoNext; + int maxPaintChars; + int paintOffset; + }; + + struct multiDef_s // 0x188 + { + const char *dvarList[32]; + const char *dvarStr[32]; + float dvarValue[32]; + int count; + int strDef; + }; + + struct columnInfo_s + { + int xpos; + int width; + int maxChars; + int alignment; + }; + + struct listBoxDef_s // 0x144 + { + // somethings not right here + int startPos[2]; + int endPos[2]; + float elementWidth; + float elementHeight; + int elementStyle; + int numColumns; + columnInfo_s columnInfo[16]; + MenuEventHandlerSet *doubleClick; // 0xC8 + int notselectable; + int noscrollbars; + int usepaging; + float selectBorder[4]; + Material *selectIcon; + }; + + struct newsTickerDef_s + { + int feedId; + int speed; + int spacing; + }; + + struct textScrollDef_s + { + int startTime; + }; + + union itemDefData_t + { + listBoxDef_s *listBox; + editFieldDef_s *editField; + newsTickerDef_s *ticker; + multiDef_s *multiDef; + const char *enumDvarName; + textScrollDef_s *scroll; + void *data; + }; + + struct itemDef_t + { + windowDef_t window; + rectDef_s textRect; + int type; + int dataType; + int alignment; + int fontEnum; + int textAlignMode; + float textAlignX; + float textAlignY; + float textScale; + int textStyle; + int gameMsgWindowIndex; + int gameMsgWindowMode; + const char *text; + int textSaveGameInfo; + int parent; + MenuEventHandlerSet *mouseEnterText; + MenuEventHandlerSet *mouseExitText; + MenuEventHandlerSet *mouseEnter; + MenuEventHandlerSet *mouseExit; + MenuEventHandlerSet *action; + MenuEventHandlerSet *accept; + MenuEventHandlerSet *onFocus; + MenuEventHandlerSet *leaveFocus; + const char *dvar; + const char *dvarTest; + ItemKeyHandler *onKey; + const char *enableDvar; + const char *localVar; + int dvarFlags; + const char *focusSound; + float special; + int cursorPos; + itemDefData_t typeData; + int imageTrack; + int floatExpressionCount; + ItemFloatExpression *floatExpressions; + Statement_s *visibleExp; + Statement_s *disabledExp; + Statement_s *textExp; + Statement_s *materialExp; + float glowColor[4]; + bool decayActive; + int fxBirthTime; + int fxLetterTime; + int fxDecayStartTime; + int fxDecayDuration; + int lastSoundPlayedTime; + }; + + struct menuTransition // 0x18 + { + int transitionType; + int startTime; + float startVal; + float endVal; + float time; + int endTriggerType; + }; + + struct menuDef_t + { + windowDef_t window; + int font; + int fullscreen; + int itemCount; + int fontIndex; + int cursorItems; + int fadeCycle; + float fadeClamp; + float fadeAmount; + float fadeInAmount; + float blurRadius; + MenuEventHandlerSet *onOpen; + MenuEventHandlerSet *onRequestClose; + MenuEventHandlerSet *onClose; + MenuEventHandlerSet *onEsc; + ItemKeyHandler *onKey; + Statement_s *visibleExp; + const char *allowedBinding; + const char *soundLoop; + int imageTrack; + float focusColor[4]; + Statement_s *rectXExp; + Statement_s *rectYExp; + Statement_s *rectHExp; + Statement_s *rectWExp; + Statement_s *openSoundExp; + Statement_s *closeSoundExp; + itemDef_t **items; + char unknown[112]; + ExpressionSupportingData *expressionData; + }; + + struct MenuList + { + const char *name; + int menuCount; + menuDef_t **menus; + }; + + // Q3TA precompiler code + + //undef if binary numbers of the form 0b... or 0B... are not allowed +#define BINARYNUMBERS + //undef if not using the token.intvalue and token.floatvalue +#define NUMBERVALUE + //use dollar sign also as punctuation +#define DOLLAR + + //maximum token length +#define MAX_TOKEN 1024 + + //punctuation + typedef struct punctuation_s + { + char *p; //punctuation character(s) + int n; //punctuation indication + struct punctuation_s *next; //next punctuation + } punctuation_t; + + //token + typedef struct token_s + { + char string[MAX_TOKEN]; //available token + int type; //last read token type + int subtype; //last read token sub type +#ifdef NUMBERVALUE + unsigned long int intvalue; //integer value + long double floatvalue; //floating point value +#endif //NUMBERVALUE + char *whitespace_p; //start of white space before token + char *endwhitespace_p; //start of white space before token + int line; //line the token was on + int linescrossed; //lines crossed in white space + struct token_s *next; //next token in chain + } token_t; + + //script file + typedef struct script_s + { + char filename[64]; //file name of the script + char *buffer; //buffer containing the script + char *script_p; //current pointer in the script + char *end_p; //pointer to the end of the script + char *lastscript_p; //script pointer before reading token + char *whitespace_p; //begin of the white space + char *endwhitespace_p; //end of the white space + int length; //length of the script in bytes + int line; //current line in script + int lastline; //line before reading token + int tokenavailable; //set by UnreadLastToken + int flags; //several script flags + punctuation_t *punctuations; //the punctuations used in the script + punctuation_t **punctuationtable; + token_t token; //available token + struct script_s *next; //next script in a chain + } script_t; + + //macro definitions + typedef struct define_s + { + char *name; //define name + int flags; //define flags + int builtin; // > 0 if builtin define + int numparms; //number of define parameters + token_t *parms; //define parameters + token_t *tokens; //macro tokens (possibly containing parm tokens) + struct define_s *next; //next defined macro in a list + struct define_s *hashnext; //next define in the hash chain + } define_t; + + //indents + //used for conditional compilation directives: + //#if, #else, #elif, #ifdef, #ifndef + typedef struct indent_s + { + int type; //indent type + int skip; //true if skipping current indent + script_t *script; //script the indent was in + struct indent_s *next; //next indent on the indent stack + } indent_t; + + //source file + typedef struct source_s + { + char filename[64]; //file name of the script + char includepath[64]; //path to include files + punctuation_t *punctuations; //punctuations to use + script_t *scriptstack; //stack with scripts of the source + token_t *tokens; //tokens to read first + define_t *defines; //list with macro definitions + define_t **definehash; //hash chain with defines + indent_t *indentstack; //stack with indents + int skip; // > 0 if skipping conditional code + token_t token; //last read token + } source_t; + +#define MAX_TOKENLENGTH 1024 + + typedef struct pc_token_s + { + int type; + int subtype; + int intvalue; + float floatvalue; + char string[MAX_TOKENLENGTH]; + } pc_token_t; + + //token types +#define TT_STRING 1 // string +#define TT_LITERAL 2 // literal +#define TT_NUMBER 3 // number +#define TT_NAME 4 // name +#define TT_PUNCTUATION 5 // punctuation + + //typedef int menuDef_t; + //typedef int itemDef_t; + +#define KEYWORDHASH_SIZE 512 + + typedef struct keywordHash_s + { + char *keyword; + bool(*func)(itemDef_t *item, int handle); + //struct keywordHash_s *next; + } keywordHash_t; + + union XAssetHeader + { + void *data; + MenuList *menuList; + menuDef_t *menu; + Material *material; + snd_alias_list_t *aliasList; + }; } diff --git a/iw4/iw4.vcxproj b/iw4/iw4.vcxproj index 8de06f3f..ac9ac8eb 100644 --- a/iw4/iw4.vcxproj +++ b/iw4/iw4.vcxproj @@ -56,6 +56,8 @@ + + @@ -86,6 +88,8 @@ + + diff --git a/iw4/iw4.vcxproj.filters b/iw4/iw4.vcxproj.filters index b22b9700..bfea3d4c 100644 --- a/iw4/iw4.vcxproj.filters +++ b/iw4/iw4.vcxproj.filters @@ -110,6 +110,12 @@ Source\Components\Modules + + Source\Components\Modules + + + Source\Components\Modules + @@ -196,5 +202,11 @@ Source\Components\Modules + + Source\Components\Modules + + + Source\Components\Modules + \ No newline at end of file