mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2026-09-12 08:57:07 +00:00
chore: align iw3,iw4,iw5 menu code (#987)
* chore: small adjustments to iw3 menu dumper * chore: align iw4 menu loader closer to iw3 * chore: align iw4 menu dumper closer to iw3 * chore: adjust iw4 menu expression dumping * chore: adjust iw4 menu expression converting * chore: align iw5 menu loader closer to iw3 * chore: align iw4 menu dumper closer to iw3 * chore: adjust iw5 menu expression dumping * chore: adjust iw5 menu expression converting * fix: not respecting reference menus when inlining menu list menus * fix: compilation on linux
This commit is contained in:
@@ -2315,7 +2315,7 @@ namespace IW4
|
|||||||
int ownerDraw;
|
int ownerDraw;
|
||||||
unsigned int ownerDrawFlags;
|
unsigned int ownerDrawFlags;
|
||||||
float borderSize;
|
float borderSize;
|
||||||
int staticFlags;
|
unsigned int staticFlags;
|
||||||
unsigned int dynamicFlags[1];
|
unsigned int dynamicFlags[1];
|
||||||
int nextTime;
|
int nextTime;
|
||||||
float foreColor[4];
|
float foreColor[4];
|
||||||
@@ -2385,14 +2385,14 @@ namespace IW4
|
|||||||
int gameMsgWindowIndex;
|
int gameMsgWindowIndex;
|
||||||
int gameMsgWindowMode;
|
int gameMsgWindowMode;
|
||||||
const char* text;
|
const char* text;
|
||||||
int itemFlags;
|
unsigned int itemFlags;
|
||||||
menuDef_t* parent;
|
menuDef_t* parent;
|
||||||
MenuEventHandlerSet* mouseEnterText;
|
MenuEventHandlerSet* mouseEnterText;
|
||||||
MenuEventHandlerSet* mouseExitText;
|
MenuEventHandlerSet* mouseExitText;
|
||||||
MenuEventHandlerSet* mouseEnter;
|
MenuEventHandlerSet* mouseEnter;
|
||||||
MenuEventHandlerSet* mouseExit;
|
MenuEventHandlerSet* mouseExit;
|
||||||
MenuEventHandlerSet* action;
|
MenuEventHandlerSet* action;
|
||||||
MenuEventHandlerSet* accept;
|
MenuEventHandlerSet* onAccept;
|
||||||
MenuEventHandlerSet* onFocus;
|
MenuEventHandlerSet* onFocus;
|
||||||
MenuEventHandlerSet* leaveFocus;
|
MenuEventHandlerSet* leaveFocus;
|
||||||
const char* dvar;
|
const char* dvar;
|
||||||
|
|||||||
@@ -3235,8 +3235,8 @@ namespace IW5
|
|||||||
int ownerDraw;
|
int ownerDraw;
|
||||||
unsigned int ownerDrawFlags;
|
unsigned int ownerDrawFlags;
|
||||||
float borderSize;
|
float borderSize;
|
||||||
int staticFlags;
|
unsigned int staticFlags;
|
||||||
int dynamicFlags[1];
|
unsigned int dynamicFlags[1];
|
||||||
int nextTime;
|
int nextTime;
|
||||||
float foreColor[4];
|
float foreColor[4];
|
||||||
float backColor[4];
|
float backColor[4];
|
||||||
@@ -3419,14 +3419,14 @@ namespace IW5
|
|||||||
int gameMsgWindowIndex;
|
int gameMsgWindowIndex;
|
||||||
int gameMsgWindowMode;
|
int gameMsgWindowMode;
|
||||||
const char* text;
|
const char* text;
|
||||||
int itemFlags;
|
unsigned int itemFlags;
|
||||||
menuDef_t* parent;
|
menuDef_t* parent;
|
||||||
MenuEventHandlerSet* mouseEnterText;
|
MenuEventHandlerSet* mouseEnterText;
|
||||||
MenuEventHandlerSet* mouseExitText;
|
MenuEventHandlerSet* mouseExitText;
|
||||||
MenuEventHandlerSet* mouseEnter;
|
MenuEventHandlerSet* mouseEnter;
|
||||||
MenuEventHandlerSet* mouseExit;
|
MenuEventHandlerSet* mouseExit;
|
||||||
MenuEventHandlerSet* action;
|
MenuEventHandlerSet* action;
|
||||||
MenuEventHandlerSet* accept;
|
MenuEventHandlerSet* onAccept;
|
||||||
MenuEventHandlerSet* onFocus;
|
MenuEventHandlerSet* onFocus;
|
||||||
MenuEventHandlerSet* hasFocus;
|
MenuEventHandlerSet* hasFocus;
|
||||||
MenuEventHandlerSet* leaveFocus;
|
MenuEventHandlerSet* leaveFocus;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
#include "LoaderMenuListIW4.h"
|
#include "LoaderMenuListIW4.h"
|
||||||
|
|
||||||
#include "Game/IW4/IW4.h"
|
|
||||||
#include "Game/IW4/Menu/MenuConversionZoneStateIW4.h"
|
#include "Game/IW4/Menu/MenuConversionZoneStateIW4.h"
|
||||||
#include "Game/IW4/Menu/MenuConverterIW4.h"
|
#include "Game/IW4/Menu/MenuConverterIW4.h"
|
||||||
#include "ObjLoading.h"
|
#include "ObjLoading.h"
|
||||||
#include "Parsing/Menu/MenuFileReader.h"
|
#include "Parsing/Menu/MenuFileReader.h"
|
||||||
#include "Utils/Logging/Log.h"
|
#include "Utils/Logging/Log.h"
|
||||||
|
|
||||||
#include <cstring>
|
#include <deque>
|
||||||
#include <format>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
using namespace IW4;
|
using namespace IW4;
|
||||||
|
|
||||||
@@ -44,7 +41,8 @@ namespace
|
|||||||
const auto menuListResult = ParseMenuFile(*file.m_stream, assetName, zoneState);
|
const auto menuListResult = ParseMenuFile(*file.m_stream, assetName, zoneState);
|
||||||
if (menuListResult)
|
if (menuListResult)
|
||||||
{
|
{
|
||||||
ProcessParsedResults(assetName, context, *menuListResult, zoneState, conversionState, menus, registration);
|
if (!ProcessParsedResults(assetName, context, *menuListResult, zoneState, conversionState, menus, registration))
|
||||||
|
return AssetCreationResult::Failure();
|
||||||
|
|
||||||
for (const auto& menuToLoad : menuListResult->m_menus_to_load)
|
for (const auto& menuToLoad : menuListResult->m_menus_to_load)
|
||||||
menuLoadQueue.emplace_back(menuToLoad);
|
menuLoadQueue.emplace_back(menuToLoad);
|
||||||
@@ -59,7 +57,8 @@ namespace
|
|||||||
{
|
{
|
||||||
const auto& menuFileToLoad = menuLoadQueue.front();
|
const auto& menuFileToLoad = menuLoadQueue.front();
|
||||||
|
|
||||||
LoadMenuFileFromQueue(menuFileToLoad, context, zoneState, conversionState, menus, registration);
|
if (!LoadMenuFileFromQueue(menuFileToLoad, context, zoneState, conversionState, menus, registration))
|
||||||
|
return AssetCreationResult::Failure();
|
||||||
|
|
||||||
menuLoadQueue.pop_front();
|
menuLoadQueue.pop_front();
|
||||||
}
|
}
|
||||||
@@ -108,7 +107,8 @@ namespace
|
|||||||
const auto menuFileResult = ParseMenuFile(*file.m_stream, menuFilePath, zoneState);
|
const auto menuFileResult = ParseMenuFile(*file.m_stream, menuFilePath, zoneState);
|
||||||
if (menuFileResult)
|
if (menuFileResult)
|
||||||
{
|
{
|
||||||
ProcessParsedResults(menuFilePath, context, *menuFileResult, zoneState, conversionState, menus, registration);
|
if (!ProcessParsedResults(menuFilePath, context, *menuFileResult, zoneState, conversionState, menus, registration))
|
||||||
|
return false;
|
||||||
if (!menuFileResult->m_menus_to_load.empty())
|
if (!menuFileResult->m_menus_to_load.empty())
|
||||||
con::warn("Menu file has menus to load even though it is not a menu list, ignoring: \"{}\"", menuFilePath);
|
con::warn("Menu file has menus to load even though it is not a menu list, ignoring: \"{}\"", menuFilePath);
|
||||||
|
|
||||||
@@ -158,8 +158,7 @@ namespace
|
|||||||
auto* menuAsset = m_memory.Alloc<menuDef_t>();
|
auto* menuAsset = m_memory.Alloc<menuDef_t>();
|
||||||
AssetRegistration<AssetMenu> menuRegistration(commonMenu->m_name, menuAsset);
|
AssetRegistration<AssetMenu> menuRegistration(commonMenu->m_name, menuAsset);
|
||||||
|
|
||||||
converter->ConvertMenu(*commonMenu, *menuAsset, menuRegistration);
|
if (!converter->ConvertMenu(*commonMenu, *menuAsset, menuRegistration))
|
||||||
if (menuAsset == nullptr)
|
|
||||||
{
|
{
|
||||||
con::error("Failed to convert menu file \"{}\"", commonMenu->m_name);
|
con::error("Failed to convert menu file \"{}\"", commonMenu->m_name);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -10,4 +10,4 @@
|
|||||||
namespace menu
|
namespace menu
|
||||||
{
|
{
|
||||||
std::unique_ptr<AssetCreator<IW4::AssetMenuList>> CreateMenuListLoaderIW4(MemoryManager& memory, ISearchPath& searchPath);
|
std::unique_ptr<AssetCreator<IW4::AssetMenuList>> CreateMenuListLoaderIW4(MemoryManager& memory, ISearchPath& searchPath);
|
||||||
} // namespace menu
|
}
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ const char* MenuConversionZoneState::AddString(const std::string& str)
|
|||||||
|
|
||||||
void MenuConversionZoneState::AddLoadedFile(std::string loadedFileName, std::vector<XAssetInfo<menuDef_t>*> menusOfFile)
|
void MenuConversionZoneState::AddLoadedFile(std::string loadedFileName, std::vector<XAssetInfo<menuDef_t>*> menusOfFile)
|
||||||
{
|
{
|
||||||
m_menus_by_filename.emplace(std::make_pair(std::move(loadedFileName), std::move(menusOfFile)));
|
m_menus_by_filename.emplace(std::move(loadedFileName), std::move(menusOfFile));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MenuConversionZoneState::FinalizeSupportingData() const
|
void MenuConversionZoneState::FinalizeSupportingData() const
|
||||||
|
|||||||
@@ -3,26 +3,15 @@
|
|||||||
#include "Asset/IZoneAssetCreationState.h"
|
#include "Asset/IZoneAssetCreationState.h"
|
||||||
#include "Game/IW4/IW4.h"
|
#include "Game/IW4/IW4.h"
|
||||||
|
|
||||||
#include <map>
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace IW4
|
namespace IW4
|
||||||
{
|
{
|
||||||
class MenuConversionZoneState final : public IZoneAssetCreationState
|
class MenuConversionZoneState final : public IZoneAssetCreationState
|
||||||
{
|
{
|
||||||
Zone* m_zone;
|
|
||||||
std::vector<Statement_s*> m_functions;
|
|
||||||
std::map<std::string, Statement_s*> m_function_by_name;
|
|
||||||
|
|
||||||
std::vector<StaticDvar*> m_static_dvars;
|
|
||||||
std::map<std::string, size_t> m_dvars_by_name;
|
|
||||||
|
|
||||||
std::vector<const char*> m_strings;
|
|
||||||
std::map<std::string, const char*> m_strings_by_value;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::map<std::string, std::vector<XAssetInfo<menuDef_t>*>> m_menus_by_filename;
|
|
||||||
ExpressionSupportingData* m_supporting_data;
|
|
||||||
|
|
||||||
MenuConversionZoneState();
|
MenuConversionZoneState();
|
||||||
void Inject(ZoneAssetCreationInjection& inject) override;
|
void Inject(ZoneAssetCreationInjection& inject) override;
|
||||||
|
|
||||||
@@ -35,5 +24,19 @@ namespace IW4
|
|||||||
void AddLoadedFile(std::string loadedFileName, std::vector<XAssetInfo<menuDef_t>*> menusOfFile);
|
void AddLoadedFile(std::string loadedFileName, std::vector<XAssetInfo<menuDef_t>*> menusOfFile);
|
||||||
|
|
||||||
void FinalizeSupportingData() const;
|
void FinalizeSupportingData() const;
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::vector<XAssetInfo<menuDef_t>*>> m_menus_by_filename;
|
||||||
|
ExpressionSupportingData* m_supporting_data;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Zone* m_zone;
|
||||||
|
std::vector<Statement_s*> m_functions;
|
||||||
|
std::unordered_map<std::string, Statement_s*> m_function_by_name;
|
||||||
|
|
||||||
|
std::vector<StaticDvar*> m_static_dvars;
|
||||||
|
std::unordered_map<std::string, size_t> m_dvars_by_name;
|
||||||
|
|
||||||
|
std::vector<const char*> m_strings;
|
||||||
|
std::unordered_map<std::string, const char*> m_strings_by_value;
|
||||||
};
|
};
|
||||||
} // namespace IW4
|
} // namespace IW4
|
||||||
|
|||||||
@@ -13,35 +13,37 @@
|
|||||||
#include "Parsing/Simple/Expression/SimpleExpressionUnaryOperation.h"
|
#include "Parsing/Simple/Expression/SimpleExpressionUnaryOperation.h"
|
||||||
#include "Utils/StringUtils.h"
|
#include "Utils/StringUtils.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
using namespace IW4;
|
using namespace IW4;
|
||||||
using namespace menu;
|
using namespace menu;
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
class MenuConverter : public AbstractMenuConverter, public IMenuConverter
|
class MenuConverter final : public AbstractMenuConverter, public IMenuConverter
|
||||||
{
|
{
|
||||||
[[nodiscard]] static rectDef_s ConvertRectDef(const CommonRect& rect)
|
[[nodiscard]] static rectDef_s ConvertRectDef(const CommonRect& rect)
|
||||||
{
|
{
|
||||||
return rectDef_s{
|
return rectDef_s{
|
||||||
static_cast<float>(rect.x),
|
.x = static_cast<float>(rect.x),
|
||||||
static_cast<float>(rect.y),
|
.y = static_cast<float>(rect.y),
|
||||||
static_cast<float>(rect.w),
|
.w = static_cast<float>(rect.w),
|
||||||
static_cast<float>(rect.h),
|
.h = static_cast<float>(rect.h),
|
||||||
static_cast<unsigned char>(rect.horizontalAlign),
|
.horzAlign = static_cast<unsigned char>(rect.horizontalAlign),
|
||||||
static_cast<unsigned char>(rect.verticalAlign),
|
.vertAlign = static_cast<unsigned char>(rect.verticalAlign),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] static rectDef_s ConvertRectDefRelativeTo(const rectDef_s& rect, const rectDef_s& rectRelativeTo)
|
[[nodiscard]] static rectDef_s ConvertRectDefRelativeTo(const rectDef_s& rect, const rectDef_s& relativeTo)
|
||||||
{
|
{
|
||||||
return rectDef_s{
|
return rectDef_s{
|
||||||
.x = rectRelativeTo.x + rect.x,
|
.x = relativeTo.x + rect.x,
|
||||||
.y = rectRelativeTo.y + rect.y,
|
.y = relativeTo.y + rect.y,
|
||||||
.w = static_cast<float>(rect.w),
|
.w = static_cast<float>(rect.w),
|
||||||
.h = static_cast<float>(rect.h),
|
.h = static_cast<float>(rect.h),
|
||||||
.horzAlign = static_cast<unsigned char>(rect.horzAlign),
|
.horzAlign = static_cast<unsigned char>(rect.horzAlign),
|
||||||
@@ -57,7 +59,7 @@ namespace
|
|||||||
output[3] = static_cast<float>(input.a);
|
output[3] = static_cast<float>(input.a);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ApplyFlag(int& flags, const bool shouldApply, const int flagValue)
|
static void ApplyFlag(unsigned& flags, const bool shouldApply, const unsigned flagValue)
|
||||||
{
|
{
|
||||||
if (!shouldApply)
|
if (!shouldApply)
|
||||||
return;
|
return;
|
||||||
@@ -65,16 +67,6 @@ namespace
|
|||||||
flags |= flagValue;
|
flags |= flagValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ConvertItemType(const int input)
|
|
||||||
{
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ConvertTextFont(const int input)
|
|
||||||
{
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] Material* ConvertMaterial(const std::string& materialName, const CommonMenuDef* menu, const CommonItemDef* item = nullptr) const
|
[[nodiscard]] Material* ConvertMaterial(const std::string& materialName, const CommonMenuDef* menu, const CommonItemDef* item = nullptr) const
|
||||||
{
|
{
|
||||||
if (materialName.empty())
|
if (materialName.empty())
|
||||||
@@ -99,181 +91,14 @@ namespace
|
|||||||
return soundDependency->Asset();
|
return soundDependency->Asset();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HandleStaticDvarFunctionCall(Statement_s* gameStatement,
|
constexpr static expressionOperatorType_e UNARY_OPERATION_MAPPING[]{
|
||||||
std::vector<expressionEntry>& entries,
|
|
||||||
const CommonExpressionBaseFunctionCall* functionCall,
|
|
||||||
const int targetFunctionIndex) const
|
|
||||||
{
|
|
||||||
if (functionCall->m_args.size() != 1)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const auto* dvarNameExpression = functionCall->m_args[0].get();
|
|
||||||
if (!dvarNameExpression->IsStatic())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const auto staticDvarNameExpressionValue = dvarNameExpression->EvaluateStatic();
|
|
||||||
if (staticDvarNameExpressionValue.m_type != SimpleExpressionValue::Type::STRING)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
expressionEntry functionEntry{};
|
|
||||||
functionEntry.type = EET_OPERATOR;
|
|
||||||
functionEntry.data.op = targetFunctionIndex;
|
|
||||||
entries.emplace_back(functionEntry);
|
|
||||||
|
|
||||||
expressionEntry staticDvarIndexEntry{};
|
|
||||||
staticDvarIndexEntry.type = EET_OPERAND;
|
|
||||||
staticDvarIndexEntry.data.operand.dataType = VAL_INT;
|
|
||||||
staticDvarIndexEntry.data.operand.internals.intVal =
|
|
||||||
static_cast<int>(m_conversion_zone_state.AddStaticDvar(*staticDvarNameExpressionValue.m_string_value));
|
|
||||||
entries.emplace_back(staticDvarIndexEntry);
|
|
||||||
|
|
||||||
expressionEntry parenRight{};
|
|
||||||
parenRight.type = EET_OPERATOR;
|
|
||||||
parenRight.data.op = OP_RIGHTPAREN;
|
|
||||||
entries.emplace_back(parenRight);
|
|
||||||
|
|
||||||
gameStatement->supportingData = m_conversion_zone_state.m_supporting_data;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HandleSpecialBaseFunctionCall(Statement_s* gameStatement,
|
|
||||||
std::vector<expressionEntry>& entries,
|
|
||||||
const CommonExpressionBaseFunctionCall* functionCall,
|
|
||||||
const CommonMenuDef* menu,
|
|
||||||
const CommonItemDef* item) const
|
|
||||||
{
|
|
||||||
switch (functionCall->m_function_index)
|
|
||||||
{
|
|
||||||
case EXP_FUNC_DVAR_INT:
|
|
||||||
return HandleStaticDvarFunctionCall(gameStatement, entries, functionCall, EXP_FUNC_STATIC_DVAR_INT);
|
|
||||||
case EXP_FUNC_DVAR_BOOL:
|
|
||||||
return HandleStaticDvarFunctionCall(gameStatement, entries, functionCall, EXP_FUNC_STATIC_DVAR_BOOL);
|
|
||||||
case EXP_FUNC_DVAR_FLOAT:
|
|
||||||
return HandleStaticDvarFunctionCall(gameStatement, entries, functionCall, EXP_FUNC_STATIC_DVAR_FLOAT);
|
|
||||||
case EXP_FUNC_DVAR_STRING:
|
|
||||||
return HandleStaticDvarFunctionCall(gameStatement, entries, functionCall, EXP_FUNC_STATIC_DVAR_STRING);
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConvertExpressionEntryBaseFunctionCall(Statement_s* gameStatement,
|
|
||||||
std::vector<expressionEntry>& entries,
|
|
||||||
const CommonExpressionBaseFunctionCall* functionCall,
|
|
||||||
const CommonMenuDef* menu,
|
|
||||||
const CommonItemDef* item) const
|
|
||||||
{
|
|
||||||
if (!HandleSpecialBaseFunctionCall(gameStatement, entries, functionCall, menu, item))
|
|
||||||
{
|
|
||||||
expressionEntry functionEntry{};
|
|
||||||
functionEntry.type = EET_OPERATOR;
|
|
||||||
functionEntry.data.op = static_cast<int>(functionCall->m_function_index);
|
|
||||||
entries.emplace_back(functionEntry);
|
|
||||||
|
|
||||||
auto firstArg = true;
|
|
||||||
for (const auto& arg : functionCall->m_args)
|
|
||||||
{
|
|
||||||
if (!firstArg)
|
|
||||||
{
|
|
||||||
expressionEntry argSeparator{};
|
|
||||||
argSeparator.type = EET_OPERATOR;
|
|
||||||
argSeparator.data.op = OP_COMMA;
|
|
||||||
entries.emplace_back(argSeparator);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
firstArg = false;
|
|
||||||
|
|
||||||
ConvertExpressionEntry(gameStatement, entries, arg.get(), menu, item);
|
|
||||||
}
|
|
||||||
|
|
||||||
expressionEntry parenRight{};
|
|
||||||
parenRight.type = EET_OPERATOR;
|
|
||||||
parenRight.data.op = OP_RIGHTPAREN;
|
|
||||||
entries.emplace_back(parenRight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConvertExpressionEntryCustomFunctionCall(Statement_s* gameStatement,
|
|
||||||
std::vector<expressionEntry>& entries,
|
|
||||||
const CommonExpressionCustomFunctionCall* functionCall,
|
|
||||||
const CommonMenuDef* menu,
|
|
||||||
const CommonItemDef* item) const
|
|
||||||
{
|
|
||||||
std::string lowerCaseFunctionName(functionCall->m_function_name);
|
|
||||||
utils::MakeStringLowerCase(lowerCaseFunctionName);
|
|
||||||
|
|
||||||
Statement_s* functionStatement = m_conversion_zone_state.FindFunction(lowerCaseFunctionName);
|
|
||||||
|
|
||||||
if (functionStatement == nullptr)
|
|
||||||
{
|
|
||||||
// Function was not converted yet: Convert it now
|
|
||||||
const auto foundCommonFunction = m_parsing_zone_state.m_functions_by_name.find(lowerCaseFunctionName);
|
|
||||||
|
|
||||||
if (foundCommonFunction == m_parsing_zone_state.m_functions_by_name.end())
|
|
||||||
throw MenuConversionException("Failed to find definition for custom function \"" + functionCall->m_function_name + "\"", menu, item);
|
|
||||||
|
|
||||||
functionStatement = ConvertExpression(foundCommonFunction->second->m_value.get(), menu, item);
|
|
||||||
functionStatement = m_conversion_zone_state.AddFunction(foundCommonFunction->second->m_name, functionStatement);
|
|
||||||
}
|
|
||||||
|
|
||||||
expressionEntry functionEntry{};
|
|
||||||
functionEntry.type = EET_OPERAND;
|
|
||||||
functionEntry.data.operand.dataType = VAL_FUNCTION;
|
|
||||||
functionEntry.data.operand.internals.function = functionStatement;
|
|
||||||
entries.emplace_back(functionEntry);
|
|
||||||
|
|
||||||
// Statement uses custom function so it needs supporting data
|
|
||||||
gameStatement->supportingData = m_conversion_zone_state.m_supporting_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr static expressionOperatorType_e UNARY_OPERATION_MAPPING[static_cast<unsigned>(SimpleUnaryOperationId::COUNT)]{
|
|
||||||
OP_NOT,
|
OP_NOT,
|
||||||
OP_BITWISENOT,
|
OP_BITWISENOT,
|
||||||
OP_SUBTRACT,
|
OP_SUBTRACT,
|
||||||
};
|
};
|
||||||
|
static_assert(std::size(UNARY_OPERATION_MAPPING) == static_cast<unsigned>(SimpleUnaryOperationId::COUNT));
|
||||||
|
|
||||||
bool IsOperation(const ISimpleExpression* expression) const
|
constexpr static expressionOperatorType_e BINARY_OPERATION_MAPPING[]{
|
||||||
{
|
|
||||||
if (!m_disable_optimizations && expression->IsStatic())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return dynamic_cast<const SimpleExpressionBinaryOperation*>(expression) || dynamic_cast<const SimpleExpressionUnaryOperation*>(expression);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConvertExpressionEntryUnaryOperation(Statement_s* gameStatement,
|
|
||||||
std::vector<expressionEntry>& entries,
|
|
||||||
const SimpleExpressionUnaryOperation* unaryOperation,
|
|
||||||
const CommonMenuDef* menu,
|
|
||||||
const CommonItemDef* item) const
|
|
||||||
{
|
|
||||||
assert(static_cast<unsigned>(unaryOperation->m_operation_type->m_id) < static_cast<unsigned>(SimpleUnaryOperationId::COUNT));
|
|
||||||
expressionEntry operation{};
|
|
||||||
operation.type = EET_OPERATOR;
|
|
||||||
operation.data.op = UNARY_OPERATION_MAPPING[static_cast<unsigned>(unaryOperation->m_operation_type->m_id)];
|
|
||||||
entries.emplace_back(operation);
|
|
||||||
|
|
||||||
if (IsOperation(unaryOperation->m_operand.get()))
|
|
||||||
{
|
|
||||||
expressionEntry parenLeft{};
|
|
||||||
parenLeft.type = EET_OPERATOR;
|
|
||||||
parenLeft.data.op = OP_LEFTPAREN;
|
|
||||||
entries.emplace_back(parenLeft);
|
|
||||||
|
|
||||||
ConvertExpressionEntry(gameStatement, entries, unaryOperation->m_operand.get(), menu, item);
|
|
||||||
|
|
||||||
expressionEntry parenRight{};
|
|
||||||
parenRight.type = EET_OPERATOR;
|
|
||||||
parenRight.data.op = OP_RIGHTPAREN;
|
|
||||||
entries.emplace_back(parenRight);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ConvertExpressionEntry(gameStatement, entries, unaryOperation->m_operand.get(), menu, item);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr static expressionOperatorType_e BINARY_OPERATION_MAPPING[static_cast<unsigned>(SimpleBinaryOperationId::COUNT)]{
|
|
||||||
OP_ADD,
|
OP_ADD,
|
||||||
OP_SUBTRACT,
|
OP_SUBTRACT,
|
||||||
OP_MULTIPLY,
|
OP_MULTIPLY,
|
||||||
@@ -292,75 +117,195 @@ namespace
|
|||||||
OP_AND,
|
OP_AND,
|
||||||
OP_OR,
|
OP_OR,
|
||||||
};
|
};
|
||||||
|
static_assert(std::size(BINARY_OPERATION_MAPPING) == static_cast<unsigned>(SimpleBinaryOperationId::COUNT));
|
||||||
|
|
||||||
|
[[nodiscard]] bool IsOperation(const ISimpleExpression* expression) const
|
||||||
|
{
|
||||||
|
if (!m_disable_optimizations && expression->IsStatic())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return dynamic_cast<const SimpleExpressionBinaryOperation*>(expression) != nullptr
|
||||||
|
|| dynamic_cast<const SimpleExpressionUnaryOperation*>(expression) != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HandleStaticDvarFunctionCall(Statement_s* gameStatement,
|
||||||
|
std::vector<expressionEntry>& entries,
|
||||||
|
const CommonExpressionBaseFunctionCall* functionCall,
|
||||||
|
const int targetFunctionIndex) const
|
||||||
|
{
|
||||||
|
if (functionCall->m_args.size() != 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const auto* dvarNameExpression = functionCall->m_args[0].get();
|
||||||
|
if (!dvarNameExpression->IsStatic())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const auto staticDvarNameExpressionValue = dvarNameExpression->EvaluateStatic();
|
||||||
|
if (staticDvarNameExpressionValue.m_type != SimpleExpressionValue::Type::STRING)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = targetFunctionIndex}});
|
||||||
|
|
||||||
|
const auto dvarIntVal = static_cast<int>(m_conversion_zone_state.AddStaticDvar(*staticDvarNameExpressionValue.m_string_value));
|
||||||
|
entries.emplace_back(expressionEntry{.type = EET_OPERAND, .data = {.operand = {.dataType = VAL_INT, .internals = {.intVal = dvarIntVal}}}});
|
||||||
|
|
||||||
|
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_RIGHTPAREN}});
|
||||||
|
|
||||||
|
gameStatement->supportingData = m_conversion_zone_state.m_supporting_data;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HandleSpecialBaseFunctionCall(Statement_s* gameStatement,
|
||||||
|
std::vector<expressionEntry>& entries,
|
||||||
|
const CommonExpressionBaseFunctionCall* baseFunction) const
|
||||||
|
{
|
||||||
|
switch (baseFunction->m_function_index)
|
||||||
|
{
|
||||||
|
case EXP_FUNC_DVAR_INT:
|
||||||
|
return HandleStaticDvarFunctionCall(gameStatement, entries, baseFunction, EXP_FUNC_STATIC_DVAR_INT);
|
||||||
|
case EXP_FUNC_DVAR_BOOL:
|
||||||
|
return HandleStaticDvarFunctionCall(gameStatement, entries, baseFunction, EXP_FUNC_STATIC_DVAR_BOOL);
|
||||||
|
case EXP_FUNC_DVAR_FLOAT:
|
||||||
|
return HandleStaticDvarFunctionCall(gameStatement, entries, baseFunction, EXP_FUNC_STATIC_DVAR_FLOAT);
|
||||||
|
case EXP_FUNC_DVAR_STRING:
|
||||||
|
return HandleStaticDvarFunctionCall(gameStatement, entries, baseFunction, EXP_FUNC_STATIC_DVAR_STRING);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConvertExpressionEntryBaseFunctionCall(Statement_s* gameStatement,
|
||||||
|
std::vector<expressionEntry>& entries,
|
||||||
|
const CommonExpressionBaseFunctionCall* baseFunction,
|
||||||
|
const CommonMenuDef* menu,
|
||||||
|
const CommonItemDef* item) const
|
||||||
|
{
|
||||||
|
if (!HandleSpecialBaseFunctionCall(gameStatement, entries, baseFunction))
|
||||||
|
{
|
||||||
|
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = static_cast<int>(baseFunction->m_function_index)}});
|
||||||
|
|
||||||
|
auto firstArg = true;
|
||||||
|
for (const auto& arg : baseFunction->m_args)
|
||||||
|
{
|
||||||
|
if (firstArg)
|
||||||
|
firstArg = false;
|
||||||
|
else
|
||||||
|
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_COMMA}});
|
||||||
|
|
||||||
|
ConvertExpressionEntry(gameStatement, entries, arg.get(), menu, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_RIGHTPAREN}});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConvertExpressionEntryCustomFunctionCall(Statement_s* gameStatement,
|
||||||
|
std::vector<expressionEntry>& entries,
|
||||||
|
const CommonExpressionCustomFunctionCall* customFunction,
|
||||||
|
const CommonMenuDef* menu,
|
||||||
|
const CommonItemDef* item) const
|
||||||
|
{
|
||||||
|
std::string lowerCaseFunctionName(customFunction->m_function_name);
|
||||||
|
utils::MakeStringLowerCase(lowerCaseFunctionName);
|
||||||
|
|
||||||
|
auto* functionStatement = m_conversion_zone_state.FindFunction(lowerCaseFunctionName);
|
||||||
|
|
||||||
|
if (!functionStatement)
|
||||||
|
{
|
||||||
|
// Function was not converted yet: Convert it now
|
||||||
|
const auto foundCommonFunction = m_parsing_zone_state.m_functions_by_name.find(lowerCaseFunctionName);
|
||||||
|
|
||||||
|
if (foundCommonFunction == m_parsing_zone_state.m_functions_by_name.end())
|
||||||
|
{
|
||||||
|
throw MenuConversionException(
|
||||||
|
std::format("Failed to find definition for custom function \"{}\"", customFunction->m_function_name), menu, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
functionStatement = ConvertExpression(foundCommonFunction->second->m_value.get(), menu, item);
|
||||||
|
functionStatement = m_conversion_zone_state.AddFunction(foundCommonFunction->second->m_name, functionStatement);
|
||||||
|
}
|
||||||
|
|
||||||
|
entries.emplace_back(expressionEntry{
|
||||||
|
.type = EET_OPERAND,
|
||||||
|
.data = {.operand = {.dataType = VAL_FUNCTION, .internals = {.function = functionStatement}}},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Statement uses custom function so it needs supporting data
|
||||||
|
gameStatement->supportingData = m_conversion_zone_state.m_supporting_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConvertExpressionEntryUnaryOperation(Statement_s* gameStatement,
|
||||||
|
std::vector<expressionEntry>& entries,
|
||||||
|
const SimpleExpressionUnaryOperation* unary,
|
||||||
|
const CommonMenuDef* menu,
|
||||||
|
const CommonItemDef* item) const
|
||||||
|
{
|
||||||
|
assert(static_cast<unsigned>(unary->m_operation_type->m_id) < static_cast<unsigned>(SimpleUnaryOperationId::COUNT));
|
||||||
|
|
||||||
|
entries.emplace_back(expressionEntry{
|
||||||
|
.type = EET_OPERATOR,
|
||||||
|
.data = {.op = UNARY_OPERATION_MAPPING[static_cast<unsigned>(unary->m_operation_type->m_id)]},
|
||||||
|
});
|
||||||
|
|
||||||
|
const auto wrapOperand = IsOperation(unary->m_operand.get());
|
||||||
|
if (wrapOperand)
|
||||||
|
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_LEFTPAREN}});
|
||||||
|
ConvertExpressionEntry(gameStatement, entries, unary->m_operand.get(), menu, item);
|
||||||
|
if (wrapOperand)
|
||||||
|
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_RIGHTPAREN}});
|
||||||
|
}
|
||||||
|
|
||||||
void ConvertExpressionEntryBinaryOperation(Statement_s* gameStatement,
|
void ConvertExpressionEntryBinaryOperation(Statement_s* gameStatement,
|
||||||
std::vector<expressionEntry>& entries,
|
std::vector<expressionEntry>& entries,
|
||||||
const SimpleExpressionBinaryOperation* binaryOperation,
|
const SimpleExpressionBinaryOperation* binary,
|
||||||
const CommonMenuDef* menu,
|
const CommonMenuDef* menu,
|
||||||
const CommonItemDef* item) const
|
const CommonItemDef* item) const
|
||||||
{
|
{
|
||||||
// Game needs all nested operations to have parenthesis
|
// Game needs all nested operations to have parenthesis
|
||||||
if (IsOperation(binaryOperation->m_operand1.get()))
|
const auto wrapLeft = IsOperation(binary->m_operand1.get());
|
||||||
{
|
if (wrapLeft)
|
||||||
expressionEntry parenLeft{};
|
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_LEFTPAREN}});
|
||||||
parenLeft.type = EET_OPERATOR;
|
ConvertExpressionEntry(gameStatement, entries, binary->m_operand1.get(), menu, item);
|
||||||
parenLeft.data.op = OP_LEFTPAREN;
|
if (wrapLeft)
|
||||||
entries.emplace_back(parenLeft);
|
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_RIGHTPAREN}});
|
||||||
|
|
||||||
ConvertExpressionEntry(gameStatement, entries, binaryOperation->m_operand1.get(), menu, item);
|
assert(static_cast<unsigned>(binary->m_operation_type->m_id) < static_cast<unsigned>(SimpleBinaryOperationId::COUNT));
|
||||||
|
entries.emplace_back(expressionEntry{
|
||||||
expressionEntry parenRight{};
|
.type = EET_OPERATOR,
|
||||||
parenRight.type = EET_OPERATOR;
|
.data = {.op = BINARY_OPERATION_MAPPING[static_cast<unsigned>(binary->m_operation_type->m_id)]},
|
||||||
parenRight.data.op = OP_RIGHTPAREN;
|
});
|
||||||
entries.emplace_back(parenRight);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ConvertExpressionEntry(gameStatement, entries, binaryOperation->m_operand1.get(), menu, item);
|
|
||||||
|
|
||||||
assert(static_cast<unsigned>(binaryOperation->m_operation_type->m_id) < static_cast<unsigned>(SimpleBinaryOperationId::COUNT));
|
|
||||||
expressionEntry operation{};
|
|
||||||
operation.type = EET_OPERATOR;
|
|
||||||
operation.data.op = BINARY_OPERATION_MAPPING[static_cast<unsigned>(binaryOperation->m_operation_type->m_id)];
|
|
||||||
entries.emplace_back(operation);
|
|
||||||
|
|
||||||
// Game needs all nested operations to have parenthesis
|
// Game needs all nested operations to have parenthesis
|
||||||
if (IsOperation(binaryOperation->m_operand2.get()))
|
const auto wrapRight = IsOperation(binary->m_operand2.get());
|
||||||
{
|
if (wrapRight)
|
||||||
expressionEntry parenLeft{};
|
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_LEFTPAREN}});
|
||||||
parenLeft.type = EET_OPERATOR;
|
ConvertExpressionEntry(gameStatement, entries, binary->m_operand2.get(), menu, item);
|
||||||
parenLeft.data.op = OP_LEFTPAREN;
|
if (wrapRight)
|
||||||
entries.emplace_back(parenLeft);
|
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_RIGHTPAREN}});
|
||||||
|
|
||||||
ConvertExpressionEntry(gameStatement, entries, binaryOperation->m_operand2.get(), menu, item);
|
|
||||||
|
|
||||||
expressionEntry parenRight{};
|
|
||||||
parenRight.type = EET_OPERATOR;
|
|
||||||
parenRight.data.op = OP_RIGHTPAREN;
|
|
||||||
entries.emplace_back(parenRight);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ConvertExpressionEntry(gameStatement, entries, binaryOperation->m_operand2.get(), menu, item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConvertExpressionEntryExpressionValue(std::vector<expressionEntry>& entries, const SimpleExpressionValue* expressionValue) const
|
void ConvertExpressionValue(std::vector<expressionEntry>& entries, const SimpleExpressionValue& value) const
|
||||||
{
|
{
|
||||||
expressionEntry entry{};
|
expressionEntry entry{};
|
||||||
entry.type = EET_OPERAND;
|
entry.type = EET_OPERAND;
|
||||||
|
|
||||||
if (expressionValue->m_type == SimpleExpressionValue::Type::INT)
|
switch (value.m_type)
|
||||||
{
|
{
|
||||||
|
case SimpleExpressionValue::Type::INT:
|
||||||
entry.data.operand.dataType = VAL_INT;
|
entry.data.operand.dataType = VAL_INT;
|
||||||
entry.data.operand.internals.intVal = expressionValue->m_int_value;
|
entry.data.operand.internals.intVal = value.m_int_value;
|
||||||
}
|
break;
|
||||||
else if (expressionValue->m_type == SimpleExpressionValue::Type::DOUBLE)
|
case SimpleExpressionValue::Type::DOUBLE:
|
||||||
{
|
|
||||||
entry.data.operand.dataType = VAL_FLOAT;
|
entry.data.operand.dataType = VAL_FLOAT;
|
||||||
entry.data.operand.internals.floatVal = static_cast<float>(expressionValue->m_double_value);
|
entry.data.operand.internals.floatVal = static_cast<float>(value.m_double_value);
|
||||||
}
|
break;
|
||||||
else if (expressionValue->m_type == SimpleExpressionValue::Type::STRING)
|
case SimpleExpressionValue::Type::STRING:
|
||||||
{
|
|
||||||
entry.data.operand.dataType = VAL_STRING;
|
entry.data.operand.dataType = VAL_STRING;
|
||||||
entry.data.operand.internals.stringVal.string = m_conversion_zone_state.AddString(*expressionValue->m_string_value);
|
entry.data.operand.internals.stringVal.string = m_conversion_zone_state.AddString(*value.m_string_value);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
entries.emplace_back(entry);
|
entries.emplace_back(entry);
|
||||||
@@ -374,28 +319,28 @@ namespace
|
|||||||
{
|
{
|
||||||
if (!m_disable_optimizations && expression->IsStatic())
|
if (!m_disable_optimizations && expression->IsStatic())
|
||||||
{
|
{
|
||||||
const auto expressionStaticValue = expression->EvaluateStatic();
|
const auto staticValue = expression->EvaluateStatic();
|
||||||
ConvertExpressionEntryExpressionValue(entries, &expressionStaticValue);
|
ConvertExpressionValue(entries, staticValue);
|
||||||
}
|
}
|
||||||
else if (const auto* expressionValue = dynamic_cast<const SimpleExpressionValue*>(expression))
|
else if (const auto* value = dynamic_cast<const SimpleExpressionValue*>(expression))
|
||||||
{
|
{
|
||||||
ConvertExpressionEntryExpressionValue(entries, expressionValue);
|
ConvertExpressionValue(entries, *value);
|
||||||
}
|
}
|
||||||
else if (const auto* binaryOperation = dynamic_cast<const SimpleExpressionBinaryOperation*>(expression))
|
else if (const auto* binary = dynamic_cast<const SimpleExpressionBinaryOperation*>(expression))
|
||||||
{
|
{
|
||||||
ConvertExpressionEntryBinaryOperation(gameStatement, entries, binaryOperation, menu, item);
|
ConvertExpressionEntryBinaryOperation(gameStatement, entries, binary, menu, item);
|
||||||
}
|
}
|
||||||
else if (const auto* unaryOperation = dynamic_cast<const SimpleExpressionUnaryOperation*>(expression))
|
else if (const auto* unary = dynamic_cast<const SimpleExpressionUnaryOperation*>(expression))
|
||||||
{
|
{
|
||||||
ConvertExpressionEntryUnaryOperation(gameStatement, entries, unaryOperation, menu, item);
|
ConvertExpressionEntryUnaryOperation(gameStatement, entries, unary, menu, item);
|
||||||
}
|
}
|
||||||
else if (const auto* baseFunctionCall = dynamic_cast<const CommonExpressionBaseFunctionCall*>(expression))
|
else if (const auto* baseFunction = dynamic_cast<const CommonExpressionBaseFunctionCall*>(expression))
|
||||||
{
|
{
|
||||||
ConvertExpressionEntryBaseFunctionCall(gameStatement, entries, baseFunctionCall, menu, item);
|
ConvertExpressionEntryBaseFunctionCall(gameStatement, entries, baseFunction, menu, item);
|
||||||
}
|
}
|
||||||
else if (const auto* customFunctionCall = dynamic_cast<const CommonExpressionCustomFunctionCall*>(expression))
|
else if (const auto* customFunction = dynamic_cast<const CommonExpressionCustomFunctionCall*>(expression))
|
||||||
{
|
{
|
||||||
ConvertExpressionEntryCustomFunctionCall(gameStatement, entries, customFunctionCall, menu, item);
|
ConvertExpressionEntryCustomFunctionCall(gameStatement, entries, customFunction, menu, item);
|
||||||
}
|
}
|
||||||
else if (dynamic_cast<const SimpleExpressionConditionalOperator*>(expression))
|
else if (dynamic_cast<const SimpleExpressionConditionalOperator*>(expression))
|
||||||
{
|
{
|
||||||
@@ -414,18 +359,14 @@ namespace
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
auto* statement = m_memory.Alloc<Statement_s>();
|
auto* statement = m_memory.Alloc<Statement_s>();
|
||||||
statement->lastResult = Operand{};
|
std::vector<expressionEntry> entries;
|
||||||
statement->lastExecuteTime = 0;
|
ConvertExpressionEntry(statement, entries, expression, menu, item);
|
||||||
statement->supportingData = nullptr; // Supporting data is set upon using it
|
|
||||||
|
|
||||||
std::vector<expressionEntry> expressionEntries;
|
auto* outEntries = m_memory.Alloc<expressionEntry>(entries.size());
|
||||||
ConvertExpressionEntry(statement, expressionEntries, expression, menu, item);
|
std::memcpy(outEntries, entries.data(), sizeof(expressionEntry) * entries.size());
|
||||||
|
|
||||||
auto* outputExpressionEntries = m_memory.Alloc<expressionEntry>(expressionEntries.size());
|
statement->numEntries = static_cast<int>(entries.size());
|
||||||
std::memcpy(outputExpressionEntries, expressionEntries.data(), sizeof(expressionEntry) * expressionEntries.size());
|
statement->entries = outEntries;
|
||||||
|
|
||||||
statement->entries = outputExpressionEntries;
|
|
||||||
statement->numEntries = static_cast<int>(expressionEntries.size());
|
|
||||||
|
|
||||||
return statement;
|
return statement;
|
||||||
}
|
}
|
||||||
@@ -435,26 +376,20 @@ namespace
|
|||||||
const CommonMenuDef* menu,
|
const CommonMenuDef* menu,
|
||||||
const CommonItemDef* item = nullptr) const
|
const CommonItemDef* item = nullptr) const
|
||||||
{
|
{
|
||||||
if (m_disable_optimizations)
|
|
||||||
return ConvertExpression(expression, menu, item);
|
|
||||||
|
|
||||||
if (!expression)
|
if (!expression)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (expression->IsStatic())
|
if (!m_disable_optimizations && expression->IsStatic())
|
||||||
{
|
{
|
||||||
const auto value = expression->EvaluateStatic();
|
const auto value = expression->EvaluateStatic();
|
||||||
switch (value.m_type)
|
|
||||||
{
|
if (value.m_type == SimpleExpressionValue::Type::INT)
|
||||||
case SimpleExpressionValue::Type::DOUBLE:
|
|
||||||
staticValue = static_cast<float>(value.m_double_value);
|
|
||||||
break;
|
|
||||||
case SimpleExpressionValue::Type::INT:
|
|
||||||
staticValue = static_cast<float>(value.m_int_value);
|
staticValue = static_cast<float>(value.m_int_value);
|
||||||
break;
|
else if (value.m_type == SimpleExpressionValue::Type::DOUBLE)
|
||||||
case SimpleExpressionValue::Type::STRING:
|
staticValue = static_cast<float>(value.m_double_value);
|
||||||
|
else
|
||||||
throw MenuConversionException("Cannot convert string expression value to floating point", menu, item);
|
throw MenuConversionException("Cannot convert string expression value to floating point", menu, item);
|
||||||
}
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -466,25 +401,17 @@ namespace
|
|||||||
const CommonMenuDef* menu,
|
const CommonMenuDef* menu,
|
||||||
const CommonItemDef* item = nullptr) const
|
const CommonItemDef* item = nullptr) const
|
||||||
{
|
{
|
||||||
if (m_disable_optimizations)
|
|
||||||
return ConvertExpression(expression, menu, item);
|
|
||||||
|
|
||||||
if (!expression)
|
if (!expression)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (expression->IsStatic())
|
if (!m_disable_optimizations && expression->IsStatic())
|
||||||
{
|
{
|
||||||
const auto value = expression->EvaluateStatic();
|
const auto value = expression->EvaluateStatic();
|
||||||
switch (value.m_type)
|
if (value.m_type != SimpleExpressionValue::Type::STRING)
|
||||||
{
|
|
||||||
case SimpleExpressionValue::Type::STRING:
|
|
||||||
staticValue = m_memory.Dup(value.m_string_value->c_str());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SimpleExpressionValue::Type::DOUBLE:
|
|
||||||
case SimpleExpressionValue::Type::INT:
|
|
||||||
throw MenuConversionException("Cannot convert numeric expression value to string", menu, item);
|
throw MenuConversionException("Cannot convert numeric expression value to string", menu, item);
|
||||||
}
|
|
||||||
|
staticValue = m_memory.Dup(value.m_string_value->c_str());
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -496,37 +423,29 @@ namespace
|
|||||||
const CommonMenuDef* menu,
|
const CommonMenuDef* menu,
|
||||||
const CommonItemDef* item = nullptr) const
|
const CommonItemDef* item = nullptr) const
|
||||||
{
|
{
|
||||||
if (m_disable_optimizations)
|
|
||||||
return ConvertExpression(expression, menu, item);
|
|
||||||
|
|
||||||
if (!expression)
|
if (!expression)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (expression->IsStatic())
|
if (!m_disable_optimizations && expression->IsStatic())
|
||||||
{
|
{
|
||||||
const auto value = expression->EvaluateStatic();
|
const auto value = expression->EvaluateStatic();
|
||||||
switch (value.m_type)
|
if (value.m_type != SimpleExpressionValue::Type::STRING)
|
||||||
{
|
throw MenuConversionException("Cannot convert numeric expression value to material", menu, item);
|
||||||
case SimpleExpressionValue::Type::STRING:
|
|
||||||
staticValue = ConvertMaterial(*value.m_string_value, menu, item);
|
staticValue = ConvertMaterial(*value.m_string_value, menu, item);
|
||||||
break;
|
|
||||||
|
|
||||||
case SimpleExpressionValue::Type::DOUBLE:
|
|
||||||
case SimpleExpressionValue::Type::INT:
|
|
||||||
throw MenuConversionException("Cannot convert numeric expression value to string", menu, item);
|
|
||||||
}
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ConvertExpression(expression, menu, item);
|
return ConvertExpression(expression, menu, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] Statement_s* ConvertVisibleExpression(windowDef_t* window,
|
[[nodiscard]] Statement_s* ConvertVisibleExpression(windowDef_t& window,
|
||||||
const ISimpleExpression* expression,
|
const ISimpleExpression* expression,
|
||||||
const CommonMenuDef* commonMenu,
|
const CommonMenuDef* commonMenu,
|
||||||
const CommonItemDef* commonItem = nullptr) const
|
const CommonItemDef* commonItem = nullptr) const
|
||||||
{
|
{
|
||||||
if (expression == nullptr)
|
if (!expression)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
bool isStatic;
|
bool isStatic;
|
||||||
@@ -547,11 +466,11 @@ namespace
|
|||||||
if (isStatic)
|
if (isStatic)
|
||||||
{
|
{
|
||||||
if (isTruthy)
|
if (isTruthy)
|
||||||
window->dynamicFlags[0] |= WINDOW_FLAG_VISIBLE;
|
window.dynamicFlags[0] |= WINDOW_FLAG_VISIBLE;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
window->dynamicFlags[0] |= WINDOW_FLAG_VISIBLE;
|
window.dynamicFlags[0] |= WINDOW_FLAG_VISIBLE;
|
||||||
return ConvertExpression(expression, commonMenu, commonItem);
|
return ConvertExpression(expression, commonMenu, commonItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -637,7 +556,7 @@ namespace
|
|||||||
outputCondition->eventExpression = ConvertExpression(condition->m_condition.get(), menu, item);
|
outputCondition->eventExpression = ConvertExpression(condition->m_condition.get(), menu, item);
|
||||||
outputCondition->eventHandlerSet = ConvertEventHandlerSet(condition->m_condition_elements.get(), menu, item);
|
outputCondition->eventHandlerSet = ConvertEventHandlerSet(condition->m_condition_elements.get(), menu, item);
|
||||||
|
|
||||||
elements.push_back(outputHandler);
|
elements.emplace_back(outputHandler);
|
||||||
|
|
||||||
if (condition->m_else_elements)
|
if (condition->m_else_elements)
|
||||||
{
|
{
|
||||||
@@ -645,7 +564,7 @@ namespace
|
|||||||
outputElseHandler->eventType = EVENT_ELSE;
|
outputElseHandler->eventType = EVENT_ELSE;
|
||||||
outputElseHandler->eventData.elseScript = ConvertEventHandlerSet(condition->m_else_elements.get(), menu, item);
|
outputElseHandler->eventData.elseScript = ConvertEventHandlerSet(condition->m_else_elements.get(), menu, item);
|
||||||
|
|
||||||
elements.push_back(outputElseHandler);
|
elements.emplace_back(outputElseHandler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1011,11 +930,11 @@ namespace
|
|||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] listBoxDef_s* ConvertListBoxFeatures(itemDef_s* item,
|
[[nodiscard]] listBoxDef_s* ConvertListBoxFeatures(itemDef_s* item,
|
||||||
CommonItemFeaturesListBox* commonListBox,
|
const CommonItemFeaturesListBox* commonListBox,
|
||||||
const CommonMenuDef& parentMenu,
|
const CommonMenuDef& parentMenu,
|
||||||
const CommonItemDef& commonItem) const
|
const CommonItemDef& commonItem) const
|
||||||
{
|
{
|
||||||
if (commonListBox == nullptr)
|
if (!commonListBox)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
auto* listBox = m_memory.Alloc<listBoxDef_s>();
|
auto* listBox = m_memory.Alloc<listBoxDef_s>();
|
||||||
@@ -1030,7 +949,7 @@ namespace
|
|||||||
ConvertColor(listBox->selectBorder, commonListBox->m_select_border);
|
ConvertColor(listBox->selectBorder, commonListBox->m_select_border);
|
||||||
listBox->selectIcon = ConvertMaterial(commonListBox->m_select_icon, &parentMenu, &commonItem);
|
listBox->selectIcon = ConvertMaterial(commonListBox->m_select_icon, &parentMenu, &commonItem);
|
||||||
|
|
||||||
listBox->numColumns = static_cast<int>(std::min(std::extent_v<decltype(listBoxDef_s::columnInfo)>, commonListBox->m_columns.size()));
|
listBox->numColumns = static_cast<int>(std::min(std::size(listBox->columnInfo), commonListBox->m_columns.size()));
|
||||||
for (auto i = 0; i < listBox->numColumns; i++)
|
for (auto i = 0; i < listBox->numColumns; i++)
|
||||||
{
|
{
|
||||||
auto& col = listBox->columnInfo[i];
|
auto& col = listBox->columnInfo[i];
|
||||||
@@ -1045,12 +964,9 @@ namespace
|
|||||||
return listBox;
|
return listBox;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] editFieldDef_s* ConvertEditFieldFeatures(itemDef_s* item,
|
[[nodiscard]] editFieldDef_s* ConvertEditFieldFeatures(itemDef_s* item, const CommonItemFeaturesEditField* commonEditField) const
|
||||||
CommonItemFeaturesEditField* commonEditField,
|
|
||||||
const CommonMenuDef& parentMenu,
|
|
||||||
const CommonItemDef& commonItem) const
|
|
||||||
{
|
{
|
||||||
if (commonEditField == nullptr)
|
if (!commonEditField)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
auto* editField = m_memory.Alloc<editFieldDef_s>();
|
auto* editField = m_memory.Alloc<editFieldDef_s>();
|
||||||
@@ -1065,16 +981,13 @@ namespace
|
|||||||
return editField;
|
return editField;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] multiDef_s* ConvertMultiValueFeatures(itemDef_s* item,
|
[[nodiscard]] multiDef_s* ConvertMultiValueFeatures(const CommonItemFeaturesMultiValue* commonMultiValue) const
|
||||||
CommonItemFeaturesMultiValue* commonMultiValue,
|
|
||||||
const CommonMenuDef& parentMenu,
|
|
||||||
const CommonItemDef& commonItem) const
|
|
||||||
{
|
{
|
||||||
if (commonMultiValue == nullptr)
|
if (!commonMultiValue)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
auto* multiValue = m_memory.Alloc<multiDef_s>();
|
auto* multiValue = m_memory.Alloc<multiDef_s>();
|
||||||
multiValue->count = static_cast<int>(std::min(std::extent_v<decltype(multiDef_s::dvarList)>, commonMultiValue->m_step_names.size()));
|
multiValue->count = static_cast<int>(std::min(std::size(multiValue->dvarList), commonMultiValue->m_step_names.size()));
|
||||||
multiValue->strDef = !commonMultiValue->m_string_values.empty() ? 1 : 0;
|
multiValue->strDef = !commonMultiValue->m_string_values.empty() ? 1 : 0;
|
||||||
|
|
||||||
for (auto i = 0; i < multiValue->count; i++)
|
for (auto i = 0; i < multiValue->count; i++)
|
||||||
@@ -1096,12 +1009,9 @@ namespace
|
|||||||
return multiValue;
|
return multiValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] newsTickerDef_s* ConvertNewsTickerFeatures(itemDef_s* item,
|
[[nodiscard]] newsTickerDef_s* ConvertNewsTickerFeatures(const CommonItemFeaturesNewsTicker* commonNewsTicker) const
|
||||||
CommonItemFeaturesNewsTicker* commonNewsTicker,
|
|
||||||
const CommonMenuDef& parentMenu,
|
|
||||||
const CommonItemDef& commonItem) const
|
|
||||||
{
|
{
|
||||||
if (commonNewsTicker == nullptr)
|
if (!commonNewsTicker)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
auto* newsTicker = m_memory.Alloc<newsTickerDef_s>();
|
auto* newsTicker = m_memory.Alloc<newsTickerDef_s>();
|
||||||
@@ -1112,7 +1022,7 @@ namespace
|
|||||||
return newsTicker;
|
return newsTicker;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] itemDef_s* ConvertItem(const CommonMenuDef& commonParentMenu, const menuDef_t& parentMenu, const CommonItemDef& commonItem) const
|
[[nodiscard]] itemDef_s* ConvertItem(const CommonMenuDef& commonParentMenu, menuDef_t& parentMenu, const CommonItemDef& commonItem) const
|
||||||
{
|
{
|
||||||
auto* item = m_memory.Alloc<itemDef_s>();
|
auto* item = m_memory.Alloc<itemDef_s>();
|
||||||
|
|
||||||
@@ -1126,11 +1036,11 @@ namespace
|
|||||||
ApplyFlag(item->window.staticFlags, commonItem.m_decoration, WINDOW_FLAG_DECORATION);
|
ApplyFlag(item->window.staticFlags, commonItem.m_decoration, WINDOW_FLAG_DECORATION);
|
||||||
ApplyFlag(item->window.staticFlags, commonItem.m_auto_wrapped, WINDOW_FLAG_AUTO_WRAPPED);
|
ApplyFlag(item->window.staticFlags, commonItem.m_auto_wrapped, WINDOW_FLAG_AUTO_WRAPPED);
|
||||||
ApplyFlag(item->window.staticFlags, commonItem.m_horizontal_scroll, WINDOW_FLAG_HORIZONTAL_SCROLL);
|
ApplyFlag(item->window.staticFlags, commonItem.m_horizontal_scroll, WINDOW_FLAG_HORIZONTAL_SCROLL);
|
||||||
item->type = ConvertItemType(commonItem.m_type);
|
item->type = commonItem.m_type;
|
||||||
item->dataType = item->type;
|
item->dataType = commonItem.m_type;
|
||||||
item->window.border = commonItem.m_border;
|
item->window.border = commonItem.m_border;
|
||||||
item->window.borderSize = static_cast<float>(commonItem.m_border_size);
|
item->window.borderSize = static_cast<float>(commonItem.m_border_size);
|
||||||
item->visibleExp = ConvertVisibleExpression(&item->window, commonItem.m_visible_expression.get(), &commonParentMenu, &commonItem);
|
item->visibleExp = ConvertVisibleExpression(item->window, commonItem.m_visible_expression.get(), &commonParentMenu, &commonItem);
|
||||||
item->disabledExp = ConvertExpression(commonItem.m_disabled_expression.get(), &commonParentMenu, &commonItem);
|
item->disabledExp = ConvertExpression(commonItem.m_disabled_expression.get(), &commonParentMenu, &commonItem);
|
||||||
item->window.ownerDraw = commonItem.m_owner_draw;
|
item->window.ownerDraw = commonItem.m_owner_draw;
|
||||||
item->window.ownerDrawFlags = commonItem.m_owner_draw_flags;
|
item->window.ownerDrawFlags = commonItem.m_owner_draw_flags;
|
||||||
@@ -1140,12 +1050,11 @@ namespace
|
|||||||
item->textaligny = static_cast<float>(commonItem.m_text_align_y);
|
item->textaligny = static_cast<float>(commonItem.m_text_align_y);
|
||||||
item->textscale = static_cast<float>(commonItem.m_text_scale);
|
item->textscale = static_cast<float>(commonItem.m_text_scale);
|
||||||
item->textStyle = commonItem.m_text_style;
|
item->textStyle = commonItem.m_text_style;
|
||||||
item->fontEnum = ConvertTextFont(commonItem.m_text_font);
|
item->fontEnum = commonItem.m_text_font;
|
||||||
ConvertColor(item->window.backColor, commonItem.m_back_color);
|
ConvertColor(item->window.backColor, commonItem.m_back_color);
|
||||||
|
|
||||||
ConvertColor(item->window.foreColor, commonItem.m_fore_color);
|
ConvertColor(item->window.foreColor, commonItem.m_fore_color);
|
||||||
if (!commonItem.m_fore_color.Equals(CommonColor(1.0, 1.0, 1.0, 1.0)))
|
ApplyFlag(item->window.dynamicFlags[0], !commonItem.m_fore_color.Equals(CommonColor(1.0, 1.0, 1.0, 1.0)), WINDOW_FLAG_NON_DEFAULT_FORECOLOR);
|
||||||
item->window.dynamicFlags[0] |= WINDOW_FLAG_NON_DEFAULT_FORECOLOR;
|
|
||||||
|
|
||||||
ConvertColor(item->window.borderColor, commonItem.m_border_color);
|
ConvertColor(item->window.borderColor, commonItem.m_border_color);
|
||||||
ConvertColor(item->window.outlineColor, commonItem.m_outline_color);
|
ConvertColor(item->window.outlineColor, commonItem.m_outline_color);
|
||||||
@@ -1159,8 +1068,9 @@ namespace
|
|||||||
item->mouseEnterText = ConvertEventHandlerSet(commonItem.m_on_mouse_enter_text.get(), &commonParentMenu, &commonItem);
|
item->mouseEnterText = ConvertEventHandlerSet(commonItem.m_on_mouse_enter_text.get(), &commonParentMenu, &commonItem);
|
||||||
item->mouseExitText = ConvertEventHandlerSet(commonItem.m_on_mouse_exit_text.get(), &commonParentMenu, &commonItem);
|
item->mouseExitText = ConvertEventHandlerSet(commonItem.m_on_mouse_exit_text.get(), &commonParentMenu, &commonItem);
|
||||||
item->action = ConvertEventHandlerSet(commonItem.m_on_action.get(), &commonParentMenu, &commonItem);
|
item->action = ConvertEventHandlerSet(commonItem.m_on_action.get(), &commonParentMenu, &commonItem);
|
||||||
item->accept = ConvertEventHandlerSet(commonItem.m_on_accept.get(), &commonParentMenu, &commonItem);
|
item->onAccept = ConvertEventHandlerSet(commonItem.m_on_accept.get(), &commonParentMenu, &commonItem);
|
||||||
item->focusSound = ConvertSound(commonItem.m_focus_sound, &commonParentMenu, &commonItem);
|
item->focusSound = ConvertSound(commonItem.m_focus_sound, &commonParentMenu, &commonItem);
|
||||||
|
item->dvar = ConvertString(commonItem.m_dvar);
|
||||||
item->dvarTest = ConvertString(commonItem.m_dvar_test);
|
item->dvarTest = ConvertString(commonItem.m_dvar_test);
|
||||||
item->enableDvar = ConvertEnableDvar(commonItem, item->dvarFlags);
|
item->enableDvar = ConvertEnableDvar(commonItem, item->dvarFlags);
|
||||||
item->onKey = ConvertKeyHandler(commonItem.m_key_handlers, &commonParentMenu, &commonItem);
|
item->onKey = ConvertKeyHandler(commonItem.m_key_handlers, &commonParentMenu, &commonItem);
|
||||||
@@ -1173,7 +1083,6 @@ namespace
|
|||||||
item->fxLetterTime = commonItem.m_fx_letter_time;
|
item->fxLetterTime = commonItem.m_fx_letter_time;
|
||||||
item->fxDecayStartTime = commonItem.m_fx_decay_start_time;
|
item->fxDecayStartTime = commonItem.m_fx_decay_start_time;
|
||||||
item->fxDecayDuration = commonItem.m_fx_decay_duration;
|
item->fxDecayDuration = commonItem.m_fx_decay_duration;
|
||||||
item->dvar = ConvertString(commonItem.m_dvar);
|
|
||||||
|
|
||||||
switch (commonItem.m_feature_type)
|
switch (commonItem.m_feature_type)
|
||||||
{
|
{
|
||||||
@@ -1182,11 +1091,11 @@ namespace
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case CommonItemFeatureType::EDIT_FIELD:
|
case CommonItemFeatureType::EDIT_FIELD:
|
||||||
item->typeData.editField = ConvertEditFieldFeatures(item, commonItem.m_edit_field_features.get(), commonParentMenu, commonItem);
|
item->typeData.editField = ConvertEditFieldFeatures(item, commonItem.m_edit_field_features.get());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CommonItemFeatureType::MULTI_VALUE:
|
case CommonItemFeatureType::MULTI_VALUE:
|
||||||
item->typeData.multi = ConvertMultiValueFeatures(item, commonItem.m_multi_value_features.get(), commonParentMenu, commonItem);
|
item->typeData.multi = ConvertMultiValueFeatures(commonItem.m_multi_value_features.get());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CommonItemFeatureType::ENUM_DVAR:
|
case CommonItemFeatureType::ENUM_DVAR:
|
||||||
@@ -1194,7 +1103,7 @@ namespace
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case CommonItemFeatureType::NEWS_TICKER:
|
case CommonItemFeatureType::NEWS_TICKER:
|
||||||
item->typeData.ticker = ConvertNewsTickerFeatures(item, commonItem.m_news_ticker_features.get(), commonParentMenu, commonItem);
|
item->typeData.ticker = ConvertNewsTickerFeatures(commonItem.m_news_ticker_features.get());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CommonItemFeatureType::NONE:
|
case CommonItemFeatureType::NONE:
|
||||||
@@ -1208,10 +1117,12 @@ namespace
|
|||||||
// Do this last so any optimizations are considered
|
// Do this last so any optimizations are considered
|
||||||
item->window.rect = ConvertRectDefRelativeTo(item->window.rectClient, parentMenu.window.rect);
|
item->window.rect = ConvertRectDefRelativeTo(item->window.rectClient, parentMenu.window.rect);
|
||||||
|
|
||||||
|
item->parent = &parentMenu;
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
itemDef_s** ConvertMenuItems(const CommonMenuDef& commonMenu, const menuDef_t& menu, int& itemCount) const
|
itemDef_s** ConvertMenuItems(const CommonMenuDef& commonMenu, menuDef_t& menu, int& itemCount) const
|
||||||
{
|
{
|
||||||
if (commonMenu.m_items.empty())
|
if (commonMenu.m_items.empty())
|
||||||
{
|
{
|
||||||
@@ -1236,15 +1147,16 @@ namespace
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConvertMenu(const menu::CommonMenuDef& commonMenu, menuDef_t& menu, AssetRegistration<AssetMenu>& registration) override
|
bool ConvertMenu(const CommonMenuDef& commonMenu, menuDef_t& menu, AssetRegistration<AssetMenu>& registration) override
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
menu.window.name = m_memory.Dup(commonMenu.m_name.c_str());
|
menu.window.name = m_memory.Dup(commonMenu.m_name.c_str());
|
||||||
menu.fullScreen = commonMenu.m_full_screen;
|
menu.fullScreen = commonMenu.m_full_screen ? 1 : 0;
|
||||||
ApplyFlag(menu.window.staticFlags, commonMenu.m_screen_space, WINDOW_FLAG_SCREEN_SPACE);
|
ApplyFlag(menu.window.staticFlags, commonMenu.m_screen_space, WINDOW_FLAG_SCREEN_SPACE);
|
||||||
ApplyFlag(menu.window.staticFlags, commonMenu.m_decoration, WINDOW_FLAG_DECORATION);
|
ApplyFlag(menu.window.staticFlags, commonMenu.m_decoration, WINDOW_FLAG_DECORATION);
|
||||||
menu.window.rect = ConvertRectDef(commonMenu.m_rect);
|
menu.window.rect = ConvertRectDef(commonMenu.m_rect);
|
||||||
|
menu.window.rectClient = menu.window.rect;
|
||||||
menu.window.style = commonMenu.m_style;
|
menu.window.style = commonMenu.m_style;
|
||||||
menu.window.border = commonMenu.m_border;
|
menu.window.border = commonMenu.m_border;
|
||||||
menu.window.borderSize = static_cast<float>(commonMenu.m_border_size);
|
menu.window.borderSize = static_cast<float>(commonMenu.m_border_size);
|
||||||
@@ -1269,7 +1181,7 @@ namespace
|
|||||||
ApplyFlag(menu.window.staticFlags, commonMenu.m_hidden_during_ui, WINDOW_FLAG_HIDDEN_DURING_UI);
|
ApplyFlag(menu.window.staticFlags, commonMenu.m_hidden_during_ui, WINDOW_FLAG_HIDDEN_DURING_UI);
|
||||||
menu.allowedBinding = ConvertString(commonMenu.m_allowed_binding);
|
menu.allowedBinding = ConvertString(commonMenu.m_allowed_binding);
|
||||||
ApplyFlag(menu.window.staticFlags, commonMenu.m_text_only_focus, WINDOW_FLAG_TEXT_ONLY_FOCUS);
|
ApplyFlag(menu.window.staticFlags, commonMenu.m_text_only_focus, WINDOW_FLAG_TEXT_ONLY_FOCUS);
|
||||||
menu.visibleExp = ConvertVisibleExpression(&menu.window, commonMenu.m_visible_expression.get(), &commonMenu);
|
menu.visibleExp = ConvertVisibleExpression(menu.window, commonMenu.m_visible_expression.get(), &commonMenu);
|
||||||
menu.rectXExp = ConvertOrApplyStatement(menu.window.rect.x, commonMenu.m_rect_x_exp.get(), &commonMenu);
|
menu.rectXExp = ConvertOrApplyStatement(menu.window.rect.x, commonMenu.m_rect_x_exp.get(), &commonMenu);
|
||||||
menu.rectYExp = ConvertOrApplyStatement(menu.window.rect.y, commonMenu.m_rect_y_exp.get(), &commonMenu);
|
menu.rectYExp = ConvertOrApplyStatement(menu.window.rect.y, commonMenu.m_rect_y_exp.get(), &commonMenu);
|
||||||
menu.rectWExp = ConvertOrApplyStatement(menu.window.rect.w, commonMenu.m_rect_w_exp.get(), &commonMenu);
|
menu.rectWExp = ConvertOrApplyStatement(menu.window.rect.w, commonMenu.m_rect_w_exp.get(), &commonMenu);
|
||||||
@@ -1287,7 +1199,10 @@ namespace
|
|||||||
catch (const MenuConversionException& e)
|
catch (const MenuConversionException& e)
|
||||||
{
|
{
|
||||||
PrintConversionExceptionDetails(e);
|
PrintConversionExceptionDetails(e);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
MenuConversionZoneState& m_conversion_zone_state;
|
MenuConversionZoneState& m_conversion_zone_state;
|
||||||
@@ -1295,7 +1210,8 @@ namespace
|
|||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
std::unique_ptr<IMenuConverter> IMenuConverter::Create(bool disableOptimizations, ISearchPath& searchPath, MemoryManager& memory, AssetCreationContext& context)
|
std::unique_ptr<IMenuConverter>
|
||||||
|
IMenuConverter::Create(const bool disableOptimizations, ISearchPath& searchPath, MemoryManager& memory, AssetCreationContext& context)
|
||||||
{
|
{
|
||||||
return std::make_unique<MenuConverter>(disableOptimizations, searchPath, memory, context);
|
return std::make_unique<MenuConverter>(disableOptimizations, searchPath, memory, context);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
#include "SearchPath/ISearchPath.h"
|
#include "SearchPath/ISearchPath.h"
|
||||||
#include "Utils/MemoryManager.h"
|
#include "Utils/MemoryManager.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace IW4
|
namespace IW4
|
||||||
{
|
{
|
||||||
class IMenuConverter
|
class IMenuConverter
|
||||||
@@ -14,7 +16,7 @@ namespace IW4
|
|||||||
IMenuConverter() = default;
|
IMenuConverter() = default;
|
||||||
virtual ~IMenuConverter() = default;
|
virtual ~IMenuConverter() = default;
|
||||||
|
|
||||||
virtual void ConvertMenu(const menu::CommonMenuDef& commonMenu, menuDef_t& menu, AssetRegistration<AssetMenu>& registration) = 0;
|
virtual bool ConvertMenu(const menu::CommonMenuDef& commonMenu, menuDef_t& menu, AssetRegistration<AssetMenu>& registration) = 0;
|
||||||
|
|
||||||
static std::unique_ptr<IMenuConverter> Create(bool disableOptimizations, ISearchPath& searchPath, MemoryManager& memory, AssetCreationContext& context);
|
static std::unique_ptr<IMenuConverter> Create(bool disableOptimizations, ISearchPath& searchPath, MemoryManager& memory, AssetCreationContext& context);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
#include "LoaderMenuListIW5.h"
|
#include "LoaderMenuListIW5.h"
|
||||||
|
|
||||||
#include "Game/IW5/IW5.h"
|
|
||||||
#include "Game/IW5/Menu/MenuConversionZoneStateIW5.h"
|
#include "Game/IW5/Menu/MenuConversionZoneStateIW5.h"
|
||||||
#include "Game/IW5/Menu/MenuConverterIW5.h"
|
#include "Game/IW5/Menu/MenuConverterIW5.h"
|
||||||
#include "ObjLoading.h"
|
#include "ObjLoading.h"
|
||||||
#include "Parsing/Menu/MenuFileReader.h"
|
#include "Parsing/Menu/MenuFileReader.h"
|
||||||
#include "Utils/Logging/Log.h"
|
#include "Utils/Logging/Log.h"
|
||||||
|
|
||||||
#include <cstring>
|
#include <deque>
|
||||||
#include <format>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
using namespace IW5;
|
using namespace IW5;
|
||||||
|
|
||||||
@@ -44,7 +41,8 @@ namespace
|
|||||||
const auto menuListResult = ParseMenuFile(*file.m_stream, assetName, zoneState);
|
const auto menuListResult = ParseMenuFile(*file.m_stream, assetName, zoneState);
|
||||||
if (menuListResult)
|
if (menuListResult)
|
||||||
{
|
{
|
||||||
ProcessParsedResults(assetName, context, *menuListResult, zoneState, conversionState, menus, registration);
|
if (!ProcessParsedResults(assetName, context, *menuListResult, zoneState, conversionState, menus, registration))
|
||||||
|
return AssetCreationResult::Failure();
|
||||||
|
|
||||||
for (const auto& menuToLoad : menuListResult->m_menus_to_load)
|
for (const auto& menuToLoad : menuListResult->m_menus_to_load)
|
||||||
menuLoadQueue.emplace_back(menuToLoad);
|
menuLoadQueue.emplace_back(menuToLoad);
|
||||||
@@ -59,7 +57,8 @@ namespace
|
|||||||
{
|
{
|
||||||
const auto& menuFileToLoad = menuLoadQueue.front();
|
const auto& menuFileToLoad = menuLoadQueue.front();
|
||||||
|
|
||||||
LoadMenuFileFromQueue(menuFileToLoad, context, zoneState, conversionState, menus, registration);
|
if (!LoadMenuFileFromQueue(menuFileToLoad, context, zoneState, conversionState, menus, registration))
|
||||||
|
return AssetCreationResult::Failure();
|
||||||
|
|
||||||
menuLoadQueue.pop_front();
|
menuLoadQueue.pop_front();
|
||||||
}
|
}
|
||||||
@@ -108,7 +107,8 @@ namespace
|
|||||||
const auto menuFileResult = ParseMenuFile(*file.m_stream, menuFilePath, zoneState);
|
const auto menuFileResult = ParseMenuFile(*file.m_stream, menuFilePath, zoneState);
|
||||||
if (menuFileResult)
|
if (menuFileResult)
|
||||||
{
|
{
|
||||||
ProcessParsedResults(menuFilePath, context, *menuFileResult, zoneState, conversionState, menus, registration);
|
if (!ProcessParsedResults(menuFilePath, context, *menuFileResult, zoneState, conversionState, menus, registration))
|
||||||
|
return false;
|
||||||
if (!menuFileResult->m_menus_to_load.empty())
|
if (!menuFileResult->m_menus_to_load.empty())
|
||||||
con::warn("Menu file has menus to load even though it is not a menu list, ignoring: \"{}\"", menuFilePath);
|
con::warn("Menu file has menus to load even though it is not a menu list, ignoring: \"{}\"", menuFilePath);
|
||||||
|
|
||||||
@@ -158,8 +158,7 @@ namespace
|
|||||||
auto* menuAsset = m_memory.Alloc<menuDef_t>();
|
auto* menuAsset = m_memory.Alloc<menuDef_t>();
|
||||||
AssetRegistration<AssetMenu> menuRegistration(commonMenu->m_name, menuAsset);
|
AssetRegistration<AssetMenu> menuRegistration(commonMenu->m_name, menuAsset);
|
||||||
|
|
||||||
converter->ConvertMenu(*commonMenu, *menuAsset, menuRegistration);
|
if (!converter->ConvertMenu(*commonMenu, *menuAsset, menuRegistration))
|
||||||
if (menuAsset == nullptr)
|
|
||||||
{
|
{
|
||||||
con::error("Failed to convert menu file \"{}\"", commonMenu->m_name);
|
con::error("Failed to convert menu file \"{}\"", commonMenu->m_name);
|
||||||
return false;
|
return false;
|
||||||
@@ -214,6 +213,7 @@ namespace
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace menu
|
namespace menu
|
||||||
|
|
||||||
{
|
{
|
||||||
std::unique_ptr<AssetCreator<AssetMenuList>> CreateMenuListLoaderIW5(MemoryManager& memory, ISearchPath& searchPath)
|
std::unique_ptr<AssetCreator<AssetMenuList>> CreateMenuListLoaderIW5(MemoryManager& memory, ISearchPath& searchPath)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,4 +10,4 @@
|
|||||||
namespace menu
|
namespace menu
|
||||||
{
|
{
|
||||||
std::unique_ptr<AssetCreator<IW5::AssetMenuList>> CreateMenuListLoaderIW5(MemoryManager& memory, ISearchPath& searchPath);
|
std::unique_ptr<AssetCreator<IW5::AssetMenuList>> CreateMenuListLoaderIW5(MemoryManager& memory, ISearchPath& searchPath);
|
||||||
} // namespace menu
|
}
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ const char* MenuConversionZoneState::AddString(const std::string& str)
|
|||||||
|
|
||||||
void MenuConversionZoneState::AddLoadedFile(std::string loadedFileName, std::vector<XAssetInfo<menuDef_t>*> menusOfFile)
|
void MenuConversionZoneState::AddLoadedFile(std::string loadedFileName, std::vector<XAssetInfo<menuDef_t>*> menusOfFile)
|
||||||
{
|
{
|
||||||
m_menus_by_filename.emplace(std::make_pair(std::move(loadedFileName), std::move(menusOfFile)));
|
m_menus_by_filename.emplace(std::move(loadedFileName), std::move(menusOfFile));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MenuConversionZoneState::FinalizeSupportingData() const
|
void MenuConversionZoneState::FinalizeSupportingData() const
|
||||||
|
|||||||
@@ -3,26 +3,15 @@
|
|||||||
#include "Asset/IZoneAssetCreationState.h"
|
#include "Asset/IZoneAssetCreationState.h"
|
||||||
#include "Game/IW5/IW5.h"
|
#include "Game/IW5/IW5.h"
|
||||||
|
|
||||||
#include <map>
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace IW5
|
namespace IW5
|
||||||
{
|
{
|
||||||
class MenuConversionZoneState final : public IZoneAssetCreationState
|
class MenuConversionZoneState final : public IZoneAssetCreationState
|
||||||
{
|
{
|
||||||
Zone* m_zone;
|
|
||||||
std::vector<Statement_s*> m_functions;
|
|
||||||
std::map<std::string, Statement_s*> m_function_by_name;
|
|
||||||
|
|
||||||
std::vector<StaticDvar*> m_static_dvars;
|
|
||||||
std::map<std::string, size_t> m_dvars_by_name;
|
|
||||||
|
|
||||||
std::vector<const char*> m_strings;
|
|
||||||
std::map<std::string, const char*> m_strings_by_value;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::map<std::string, std::vector<XAssetInfo<menuDef_t>*>> m_menus_by_filename;
|
|
||||||
ExpressionSupportingData* m_supporting_data;
|
|
||||||
|
|
||||||
MenuConversionZoneState();
|
MenuConversionZoneState();
|
||||||
void Inject(ZoneAssetCreationInjection& inject) override;
|
void Inject(ZoneAssetCreationInjection& inject) override;
|
||||||
|
|
||||||
@@ -35,5 +24,19 @@ namespace IW5
|
|||||||
void AddLoadedFile(std::string loadedFileName, std::vector<XAssetInfo<menuDef_t>*> menusOfFile);
|
void AddLoadedFile(std::string loadedFileName, std::vector<XAssetInfo<menuDef_t>*> menusOfFile);
|
||||||
|
|
||||||
void FinalizeSupportingData() const;
|
void FinalizeSupportingData() const;
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::vector<XAssetInfo<menuDef_t>*>> m_menus_by_filename;
|
||||||
|
ExpressionSupportingData* m_supporting_data;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Zone* m_zone;
|
||||||
|
std::vector<Statement_s*> m_functions;
|
||||||
|
std::unordered_map<std::string, Statement_s*> m_function_by_name;
|
||||||
|
|
||||||
|
std::vector<StaticDvar*> m_static_dvars;
|
||||||
|
std::unordered_map<std::string, size_t> m_dvars_by_name;
|
||||||
|
|
||||||
|
std::vector<const char*> m_strings;
|
||||||
|
std::unordered_map<std::string, const char*> m_strings_by_value;
|
||||||
};
|
};
|
||||||
} // namespace IW5
|
} // namespace IW5
|
||||||
|
|||||||
@@ -13,10 +13,12 @@
|
|||||||
#include "Parsing/Simple/Expression/SimpleExpressionUnaryOperation.h"
|
#include "Parsing/Simple/Expression/SimpleExpressionUnaryOperation.h"
|
||||||
#include "Utils/StringUtils.h"
|
#include "Utils/StringUtils.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
using namespace IW5;
|
using namespace IW5;
|
||||||
using namespace menu;
|
using namespace menu;
|
||||||
@@ -28,20 +30,20 @@ namespace
|
|||||||
[[nodiscard]] static rectDef_s ConvertRectDef(const CommonRect& rect)
|
[[nodiscard]] static rectDef_s ConvertRectDef(const CommonRect& rect)
|
||||||
{
|
{
|
||||||
return rectDef_s{
|
return rectDef_s{
|
||||||
static_cast<float>(rect.x),
|
.x = static_cast<float>(rect.x),
|
||||||
static_cast<float>(rect.y),
|
.y = static_cast<float>(rect.y),
|
||||||
static_cast<float>(rect.w),
|
.w = static_cast<float>(rect.w),
|
||||||
static_cast<float>(rect.h),
|
.h = static_cast<float>(rect.h),
|
||||||
static_cast<unsigned char>(rect.horizontalAlign),
|
.horzAlign = static_cast<unsigned char>(rect.horizontalAlign),
|
||||||
static_cast<unsigned char>(rect.verticalAlign),
|
.vertAlign = static_cast<unsigned char>(rect.verticalAlign),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] static rectDef_s ConvertRectDefRelativeTo(const rectDef_s& rect, const rectDef_s& rectRelativeTo)
|
[[nodiscard]] static rectDef_s ConvertRectDefRelativeTo(const rectDef_s& rect, const rectDef_s& relativeTo)
|
||||||
{
|
{
|
||||||
return rectDef_s{
|
return rectDef_s{
|
||||||
.x = rectRelativeTo.x + rect.x,
|
.x = relativeTo.x + rect.x,
|
||||||
.y = rectRelativeTo.y + rect.y,
|
.y = relativeTo.y + rect.y,
|
||||||
.w = static_cast<float>(rect.w),
|
.w = static_cast<float>(rect.w),
|
||||||
.h = static_cast<float>(rect.h),
|
.h = static_cast<float>(rect.h),
|
||||||
.horzAlign = static_cast<unsigned char>(rect.horzAlign),
|
.horzAlign = static_cast<unsigned char>(rect.horzAlign),
|
||||||
@@ -57,7 +59,7 @@ namespace
|
|||||||
output[3] = static_cast<float>(input.a);
|
output[3] = static_cast<float>(input.a);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ApplyFlag(int& flags, const bool shouldApply, const int flagValue)
|
static void ApplyFlag(unsigned& flags, const bool shouldApply, const unsigned flagValue)
|
||||||
{
|
{
|
||||||
if (!shouldApply)
|
if (!shouldApply)
|
||||||
return;
|
return;
|
||||||
@@ -65,16 +67,6 @@ namespace
|
|||||||
flags |= flagValue;
|
flags |= flagValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ConvertItemType(const int input)
|
|
||||||
{
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ConvertTextFont(const int input)
|
|
||||||
{
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] Material* ConvertMaterial(const std::string& materialName, const CommonMenuDef* menu, const CommonItemDef* item = nullptr) const
|
[[nodiscard]] Material* ConvertMaterial(const std::string& materialName, const CommonMenuDef* menu, const CommonItemDef* item = nullptr) const
|
||||||
{
|
{
|
||||||
if (materialName.empty())
|
if (materialName.empty())
|
||||||
@@ -99,181 +91,14 @@ namespace
|
|||||||
return soundDependency->Asset();
|
return soundDependency->Asset();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HandleStaticDvarFunctionCall(Statement_s* gameStatement,
|
constexpr static expressionOperatorType_e UNARY_OPERATION_MAPPING[]{
|
||||||
std::vector<expressionEntry>& entries,
|
|
||||||
const CommonExpressionBaseFunctionCall* functionCall,
|
|
||||||
const int targetFunctionIndex) const
|
|
||||||
{
|
|
||||||
if (functionCall->m_args.size() != 1)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const auto* dvarNameExpression = functionCall->m_args[0].get();
|
|
||||||
if (!dvarNameExpression->IsStatic())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const auto staticDvarNameExpressionValue = dvarNameExpression->EvaluateStatic();
|
|
||||||
if (staticDvarNameExpressionValue.m_type != SimpleExpressionValue::Type::STRING)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
expressionEntry functionEntry{};
|
|
||||||
functionEntry.type = EET_OPERATOR;
|
|
||||||
functionEntry.data.op = targetFunctionIndex;
|
|
||||||
entries.emplace_back(functionEntry);
|
|
||||||
|
|
||||||
expressionEntry staticDvarIndexEntry{};
|
|
||||||
staticDvarIndexEntry.type = EET_OPERAND;
|
|
||||||
staticDvarIndexEntry.data.operand.dataType = VAL_INT;
|
|
||||||
staticDvarIndexEntry.data.operand.internals.intVal =
|
|
||||||
static_cast<int>(m_conversion_zone_state.AddStaticDvar(*staticDvarNameExpressionValue.m_string_value));
|
|
||||||
entries.emplace_back(staticDvarIndexEntry);
|
|
||||||
|
|
||||||
expressionEntry parenRight{};
|
|
||||||
parenRight.type = EET_OPERATOR;
|
|
||||||
parenRight.data.op = OP_RIGHTPAREN;
|
|
||||||
entries.emplace_back(parenRight);
|
|
||||||
|
|
||||||
gameStatement->supportingData = m_conversion_zone_state.m_supporting_data;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HandleSpecialBaseFunctionCall(Statement_s* gameStatement,
|
|
||||||
std::vector<expressionEntry>& entries,
|
|
||||||
const CommonExpressionBaseFunctionCall* functionCall,
|
|
||||||
const CommonMenuDef* menu,
|
|
||||||
const CommonItemDef* item) const
|
|
||||||
{
|
|
||||||
switch (functionCall->m_function_index)
|
|
||||||
{
|
|
||||||
case EXP_FUNC_DVAR_INT:
|
|
||||||
return HandleStaticDvarFunctionCall(gameStatement, entries, functionCall, EXP_FUNC_STATIC_DVAR_INT);
|
|
||||||
case EXP_FUNC_DVAR_BOOL:
|
|
||||||
return HandleStaticDvarFunctionCall(gameStatement, entries, functionCall, EXP_FUNC_STATIC_DVAR_BOOL);
|
|
||||||
case EXP_FUNC_DVAR_FLOAT:
|
|
||||||
return HandleStaticDvarFunctionCall(gameStatement, entries, functionCall, EXP_FUNC_STATIC_DVAR_FLOAT);
|
|
||||||
case EXP_FUNC_DVAR_STRING:
|
|
||||||
return HandleStaticDvarFunctionCall(gameStatement, entries, functionCall, EXP_FUNC_STATIC_DVAR_STRING);
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConvertExpressionEntryBaseFunctionCall(Statement_s* gameStatement,
|
|
||||||
std::vector<expressionEntry>& entries,
|
|
||||||
const CommonExpressionBaseFunctionCall* functionCall,
|
|
||||||
const CommonMenuDef* menu,
|
|
||||||
const CommonItemDef* item) const
|
|
||||||
{
|
|
||||||
if (!HandleSpecialBaseFunctionCall(gameStatement, entries, functionCall, menu, item))
|
|
||||||
{
|
|
||||||
expressionEntry functionEntry{};
|
|
||||||
functionEntry.type = EET_OPERATOR;
|
|
||||||
functionEntry.data.op = static_cast<int>(functionCall->m_function_index);
|
|
||||||
entries.emplace_back(functionEntry);
|
|
||||||
|
|
||||||
auto firstArg = true;
|
|
||||||
for (const auto& arg : functionCall->m_args)
|
|
||||||
{
|
|
||||||
if (!firstArg)
|
|
||||||
{
|
|
||||||
expressionEntry argSeparator{};
|
|
||||||
argSeparator.type = EET_OPERATOR;
|
|
||||||
argSeparator.data.op = OP_COMMA;
|
|
||||||
entries.emplace_back(argSeparator);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
firstArg = false;
|
|
||||||
|
|
||||||
ConvertExpressionEntry(gameStatement, entries, arg.get(), menu, item);
|
|
||||||
}
|
|
||||||
|
|
||||||
expressionEntry parenRight{};
|
|
||||||
parenRight.type = EET_OPERATOR;
|
|
||||||
parenRight.data.op = OP_RIGHTPAREN;
|
|
||||||
entries.emplace_back(parenRight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConvertExpressionEntryCustomFunctionCall(Statement_s* gameStatement,
|
|
||||||
std::vector<expressionEntry>& entries,
|
|
||||||
const CommonExpressionCustomFunctionCall* functionCall,
|
|
||||||
const CommonMenuDef* menu,
|
|
||||||
const CommonItemDef* item) const
|
|
||||||
{
|
|
||||||
std::string lowerCaseFunctionName(functionCall->m_function_name);
|
|
||||||
utils::MakeStringLowerCase(lowerCaseFunctionName);
|
|
||||||
|
|
||||||
Statement_s* functionStatement = m_conversion_zone_state.FindFunction(lowerCaseFunctionName);
|
|
||||||
|
|
||||||
if (functionStatement == nullptr)
|
|
||||||
{
|
|
||||||
// Function was not converted yet: Convert it now
|
|
||||||
const auto foundCommonFunction = m_parsing_zone_state.m_functions_by_name.find(lowerCaseFunctionName);
|
|
||||||
|
|
||||||
if (foundCommonFunction == m_parsing_zone_state.m_functions_by_name.end())
|
|
||||||
throw MenuConversionException("Failed to find definition for custom function \"" + functionCall->m_function_name + "\"", menu, item);
|
|
||||||
|
|
||||||
functionStatement = ConvertExpression(foundCommonFunction->second->m_value.get(), menu, item);
|
|
||||||
functionStatement = m_conversion_zone_state.AddFunction(lowerCaseFunctionName, functionStatement);
|
|
||||||
}
|
|
||||||
|
|
||||||
expressionEntry functionEntry{};
|
|
||||||
functionEntry.type = EET_OPERAND;
|
|
||||||
functionEntry.data.operand.dataType = VAL_FUNCTION;
|
|
||||||
functionEntry.data.operand.internals.function = functionStatement;
|
|
||||||
entries.emplace_back(functionEntry);
|
|
||||||
|
|
||||||
// Statement uses custom function so it needs supporting data
|
|
||||||
gameStatement->supportingData = m_conversion_zone_state.m_supporting_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr static expressionOperatorType_e UNARY_OPERATION_MAPPING[static_cast<unsigned>(SimpleUnaryOperationId::COUNT)]{
|
|
||||||
OP_NOT,
|
OP_NOT,
|
||||||
OP_BITWISENOT,
|
OP_BITWISENOT,
|
||||||
OP_SUBTRACT,
|
OP_SUBTRACT,
|
||||||
};
|
};
|
||||||
|
static_assert(std::size(UNARY_OPERATION_MAPPING) == static_cast<unsigned>(SimpleUnaryOperationId::COUNT));
|
||||||
|
|
||||||
bool IsOperation(const ISimpleExpression* expression) const
|
constexpr static expressionOperatorType_e BINARY_OPERATION_MAPPING[]{
|
||||||
{
|
|
||||||
if (!m_disable_optimizations && expression->IsStatic())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return dynamic_cast<const SimpleExpressionBinaryOperation*>(expression) || dynamic_cast<const SimpleExpressionUnaryOperation*>(expression);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConvertExpressionEntryUnaryOperation(Statement_s* gameStatement,
|
|
||||||
std::vector<expressionEntry>& entries,
|
|
||||||
const SimpleExpressionUnaryOperation* unaryOperation,
|
|
||||||
const CommonMenuDef* menu,
|
|
||||||
const CommonItemDef* item) const
|
|
||||||
{
|
|
||||||
assert(static_cast<unsigned>(unaryOperation->m_operation_type->m_id) < static_cast<unsigned>(SimpleUnaryOperationId::COUNT));
|
|
||||||
expressionEntry operation{};
|
|
||||||
operation.type = EET_OPERATOR;
|
|
||||||
operation.data.op = UNARY_OPERATION_MAPPING[static_cast<unsigned>(unaryOperation->m_operation_type->m_id)];
|
|
||||||
entries.emplace_back(operation);
|
|
||||||
|
|
||||||
if (IsOperation(unaryOperation->m_operand.get()))
|
|
||||||
{
|
|
||||||
expressionEntry parenLeft{};
|
|
||||||
parenLeft.type = EET_OPERATOR;
|
|
||||||
parenLeft.data.op = OP_LEFTPAREN;
|
|
||||||
entries.emplace_back(parenLeft);
|
|
||||||
|
|
||||||
ConvertExpressionEntry(gameStatement, entries, unaryOperation->m_operand.get(), menu, item);
|
|
||||||
|
|
||||||
expressionEntry parenRight{};
|
|
||||||
parenRight.type = EET_OPERATOR;
|
|
||||||
parenRight.data.op = OP_RIGHTPAREN;
|
|
||||||
entries.emplace_back(parenRight);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ConvertExpressionEntry(gameStatement, entries, unaryOperation->m_operand.get(), menu, item);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr static expressionOperatorType_e BINARY_OPERATION_MAPPING[static_cast<unsigned>(SimpleBinaryOperationId::COUNT)]{
|
|
||||||
OP_ADD,
|
OP_ADD,
|
||||||
OP_SUBTRACT,
|
OP_SUBTRACT,
|
||||||
OP_MULTIPLY,
|
OP_MULTIPLY,
|
||||||
@@ -292,75 +117,195 @@ namespace
|
|||||||
OP_AND,
|
OP_AND,
|
||||||
OP_OR,
|
OP_OR,
|
||||||
};
|
};
|
||||||
|
static_assert(std::size(BINARY_OPERATION_MAPPING) == static_cast<unsigned>(SimpleBinaryOperationId::COUNT));
|
||||||
|
|
||||||
|
[[nodiscard]] bool IsOperation(const ISimpleExpression* expression) const
|
||||||
|
{
|
||||||
|
if (!m_disable_optimizations && expression->IsStatic())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return dynamic_cast<const SimpleExpressionBinaryOperation*>(expression) != nullptr
|
||||||
|
|| dynamic_cast<const SimpleExpressionUnaryOperation*>(expression) != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HandleStaticDvarFunctionCall(Statement_s* gameStatement,
|
||||||
|
std::vector<expressionEntry>& entries,
|
||||||
|
const CommonExpressionBaseFunctionCall* functionCall,
|
||||||
|
const int targetFunctionIndex) const
|
||||||
|
{
|
||||||
|
if (functionCall->m_args.size() != 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const auto* dvarNameExpression = functionCall->m_args[0].get();
|
||||||
|
if (!dvarNameExpression->IsStatic())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const auto staticDvarNameExpressionValue = dvarNameExpression->EvaluateStatic();
|
||||||
|
if (staticDvarNameExpressionValue.m_type != SimpleExpressionValue::Type::STRING)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = targetFunctionIndex}});
|
||||||
|
|
||||||
|
const auto dvarIntVal = static_cast<int>(m_conversion_zone_state.AddStaticDvar(*staticDvarNameExpressionValue.m_string_value));
|
||||||
|
entries.emplace_back(expressionEntry{.type = EET_OPERAND, .data = {.operand = {.dataType = VAL_INT, .internals = {.intVal = dvarIntVal}}}});
|
||||||
|
|
||||||
|
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_RIGHTPAREN}});
|
||||||
|
|
||||||
|
gameStatement->supportingData = m_conversion_zone_state.m_supporting_data;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HandleSpecialBaseFunctionCall(Statement_s* gameStatement,
|
||||||
|
std::vector<expressionEntry>& entries,
|
||||||
|
const CommonExpressionBaseFunctionCall* baseFunction) const
|
||||||
|
{
|
||||||
|
switch (baseFunction->m_function_index)
|
||||||
|
{
|
||||||
|
case EXP_FUNC_DVAR_INT:
|
||||||
|
return HandleStaticDvarFunctionCall(gameStatement, entries, baseFunction, EXP_FUNC_STATIC_DVAR_INT);
|
||||||
|
case EXP_FUNC_DVAR_BOOL:
|
||||||
|
return HandleStaticDvarFunctionCall(gameStatement, entries, baseFunction, EXP_FUNC_STATIC_DVAR_BOOL);
|
||||||
|
case EXP_FUNC_DVAR_FLOAT:
|
||||||
|
return HandleStaticDvarFunctionCall(gameStatement, entries, baseFunction, EXP_FUNC_STATIC_DVAR_FLOAT);
|
||||||
|
case EXP_FUNC_DVAR_STRING:
|
||||||
|
return HandleStaticDvarFunctionCall(gameStatement, entries, baseFunction, EXP_FUNC_STATIC_DVAR_STRING);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConvertExpressionEntryBaseFunctionCall(Statement_s* gameStatement,
|
||||||
|
std::vector<expressionEntry>& entries,
|
||||||
|
const CommonExpressionBaseFunctionCall* baseFunction,
|
||||||
|
const CommonMenuDef* menu,
|
||||||
|
const CommonItemDef* item) const
|
||||||
|
{
|
||||||
|
if (!HandleSpecialBaseFunctionCall(gameStatement, entries, baseFunction))
|
||||||
|
{
|
||||||
|
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = static_cast<int>(baseFunction->m_function_index)}});
|
||||||
|
|
||||||
|
auto firstArg = true;
|
||||||
|
for (const auto& arg : baseFunction->m_args)
|
||||||
|
{
|
||||||
|
if (firstArg)
|
||||||
|
firstArg = false;
|
||||||
|
else
|
||||||
|
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_COMMA}});
|
||||||
|
|
||||||
|
ConvertExpressionEntry(gameStatement, entries, arg.get(), menu, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_RIGHTPAREN}});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConvertExpressionEntryCustomFunctionCall(Statement_s* gameStatement,
|
||||||
|
std::vector<expressionEntry>& entries,
|
||||||
|
const CommonExpressionCustomFunctionCall* customFunction,
|
||||||
|
const CommonMenuDef* menu,
|
||||||
|
const CommonItemDef* item) const
|
||||||
|
{
|
||||||
|
std::string lowerCaseFunctionName(customFunction->m_function_name);
|
||||||
|
utils::MakeStringLowerCase(lowerCaseFunctionName);
|
||||||
|
|
||||||
|
auto* functionStatement = m_conversion_zone_state.FindFunction(lowerCaseFunctionName);
|
||||||
|
|
||||||
|
if (!functionStatement)
|
||||||
|
{
|
||||||
|
// Function was not converted yet: Convert it now
|
||||||
|
const auto foundCommonFunction = m_parsing_zone_state.m_functions_by_name.find(lowerCaseFunctionName);
|
||||||
|
|
||||||
|
if (foundCommonFunction == m_parsing_zone_state.m_functions_by_name.end())
|
||||||
|
{
|
||||||
|
throw MenuConversionException(
|
||||||
|
std::format("Failed to find definition for custom function \"{}\"", customFunction->m_function_name), menu, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
functionStatement = ConvertExpression(foundCommonFunction->second->m_value.get(), menu, item);
|
||||||
|
functionStatement = m_conversion_zone_state.AddFunction(lowerCaseFunctionName, functionStatement);
|
||||||
|
}
|
||||||
|
|
||||||
|
entries.emplace_back(expressionEntry{
|
||||||
|
.type = EET_OPERAND,
|
||||||
|
.data = {.operand = {.dataType = VAL_FUNCTION, .internals = {.function = functionStatement}}},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Statement uses custom function so it needs supporting data
|
||||||
|
gameStatement->supportingData = m_conversion_zone_state.m_supporting_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConvertExpressionEntryUnaryOperation(Statement_s* gameStatement,
|
||||||
|
std::vector<expressionEntry>& entries,
|
||||||
|
const SimpleExpressionUnaryOperation* unary,
|
||||||
|
const CommonMenuDef* menu,
|
||||||
|
const CommonItemDef* item) const
|
||||||
|
{
|
||||||
|
assert(static_cast<unsigned>(unary->m_operation_type->m_id) < static_cast<unsigned>(SimpleUnaryOperationId::COUNT));
|
||||||
|
|
||||||
|
entries.emplace_back(expressionEntry{
|
||||||
|
.type = EET_OPERATOR,
|
||||||
|
.data = {.op = UNARY_OPERATION_MAPPING[static_cast<unsigned>(unary->m_operation_type->m_id)]},
|
||||||
|
});
|
||||||
|
|
||||||
|
const auto wrapOperand = IsOperation(unary->m_operand.get());
|
||||||
|
if (wrapOperand)
|
||||||
|
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_LEFTPAREN}});
|
||||||
|
ConvertExpressionEntry(gameStatement, entries, unary->m_operand.get(), menu, item);
|
||||||
|
if (wrapOperand)
|
||||||
|
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_RIGHTPAREN}});
|
||||||
|
}
|
||||||
|
|
||||||
void ConvertExpressionEntryBinaryOperation(Statement_s* gameStatement,
|
void ConvertExpressionEntryBinaryOperation(Statement_s* gameStatement,
|
||||||
std::vector<expressionEntry>& entries,
|
std::vector<expressionEntry>& entries,
|
||||||
const SimpleExpressionBinaryOperation* binaryOperation,
|
const SimpleExpressionBinaryOperation* binary,
|
||||||
const CommonMenuDef* menu,
|
const CommonMenuDef* menu,
|
||||||
const CommonItemDef* item) const
|
const CommonItemDef* item) const
|
||||||
{
|
{
|
||||||
// Game needs all nested operations to have parenthesis
|
// Game needs all nested operations to have parenthesis
|
||||||
if (IsOperation(binaryOperation->m_operand1.get()))
|
const auto wrapLeft = IsOperation(binary->m_operand1.get());
|
||||||
{
|
if (wrapLeft)
|
||||||
expressionEntry parenLeft{};
|
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_LEFTPAREN}});
|
||||||
parenLeft.type = EET_OPERATOR;
|
ConvertExpressionEntry(gameStatement, entries, binary->m_operand1.get(), menu, item);
|
||||||
parenLeft.data.op = OP_LEFTPAREN;
|
if (wrapLeft)
|
||||||
entries.emplace_back(parenLeft);
|
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_RIGHTPAREN}});
|
||||||
|
|
||||||
ConvertExpressionEntry(gameStatement, entries, binaryOperation->m_operand1.get(), menu, item);
|
assert(static_cast<unsigned>(binary->m_operation_type->m_id) < static_cast<unsigned>(SimpleBinaryOperationId::COUNT));
|
||||||
|
entries.emplace_back(expressionEntry{
|
||||||
expressionEntry parenRight{};
|
.type = EET_OPERATOR,
|
||||||
parenRight.type = EET_OPERATOR;
|
.data = {.op = BINARY_OPERATION_MAPPING[static_cast<unsigned>(binary->m_operation_type->m_id)]},
|
||||||
parenRight.data.op = OP_RIGHTPAREN;
|
});
|
||||||
entries.emplace_back(parenRight);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ConvertExpressionEntry(gameStatement, entries, binaryOperation->m_operand1.get(), menu, item);
|
|
||||||
|
|
||||||
assert(static_cast<unsigned>(binaryOperation->m_operation_type->m_id) < static_cast<unsigned>(SimpleBinaryOperationId::COUNT));
|
|
||||||
expressionEntry operation{};
|
|
||||||
operation.type = EET_OPERATOR;
|
|
||||||
operation.data.op = BINARY_OPERATION_MAPPING[static_cast<unsigned>(binaryOperation->m_operation_type->m_id)];
|
|
||||||
entries.emplace_back(operation);
|
|
||||||
|
|
||||||
// Game needs all nested operations to have parenthesis
|
// Game needs all nested operations to have parenthesis
|
||||||
if (IsOperation(binaryOperation->m_operand2.get()))
|
const auto wrapRight = IsOperation(binary->m_operand2.get());
|
||||||
{
|
if (wrapRight)
|
||||||
expressionEntry parenLeft{};
|
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_LEFTPAREN}});
|
||||||
parenLeft.type = EET_OPERATOR;
|
ConvertExpressionEntry(gameStatement, entries, binary->m_operand2.get(), menu, item);
|
||||||
parenLeft.data.op = OP_LEFTPAREN;
|
if (wrapRight)
|
||||||
entries.emplace_back(parenLeft);
|
entries.emplace_back(expressionEntry{.type = EET_OPERATOR, .data = {.op = OP_RIGHTPAREN}});
|
||||||
|
|
||||||
ConvertExpressionEntry(gameStatement, entries, binaryOperation->m_operand2.get(), menu, item);
|
|
||||||
|
|
||||||
expressionEntry parenRight{};
|
|
||||||
parenRight.type = EET_OPERATOR;
|
|
||||||
parenRight.data.op = OP_RIGHTPAREN;
|
|
||||||
entries.emplace_back(parenRight);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ConvertExpressionEntry(gameStatement, entries, binaryOperation->m_operand2.get(), menu, item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConvertExpressionEntryExpressionValue(std::vector<expressionEntry>& entries, const SimpleExpressionValue* expressionValue) const
|
void ConvertExpressionValue(std::vector<expressionEntry>& entries, const SimpleExpressionValue& value) const
|
||||||
{
|
{
|
||||||
expressionEntry entry{};
|
expressionEntry entry{};
|
||||||
entry.type = EET_OPERAND;
|
entry.type = EET_OPERAND;
|
||||||
|
|
||||||
if (expressionValue->m_type == SimpleExpressionValue::Type::INT)
|
switch (value.m_type)
|
||||||
{
|
{
|
||||||
|
case SimpleExpressionValue::Type::INT:
|
||||||
entry.data.operand.dataType = VAL_INT;
|
entry.data.operand.dataType = VAL_INT;
|
||||||
entry.data.operand.internals.intVal = expressionValue->m_int_value;
|
entry.data.operand.internals.intVal = value.m_int_value;
|
||||||
}
|
break;
|
||||||
else if (expressionValue->m_type == SimpleExpressionValue::Type::DOUBLE)
|
case SimpleExpressionValue::Type::DOUBLE:
|
||||||
{
|
|
||||||
entry.data.operand.dataType = VAL_FLOAT;
|
entry.data.operand.dataType = VAL_FLOAT;
|
||||||
entry.data.operand.internals.floatVal = static_cast<float>(expressionValue->m_double_value);
|
entry.data.operand.internals.floatVal = static_cast<float>(value.m_double_value);
|
||||||
}
|
break;
|
||||||
else if (expressionValue->m_type == SimpleExpressionValue::Type::STRING)
|
case SimpleExpressionValue::Type::STRING:
|
||||||
{
|
|
||||||
entry.data.operand.dataType = VAL_STRING;
|
entry.data.operand.dataType = VAL_STRING;
|
||||||
entry.data.operand.internals.stringVal.string = m_conversion_zone_state.AddString(*expressionValue->m_string_value);
|
entry.data.operand.internals.stringVal.string = m_conversion_zone_state.AddString(*value.m_string_value);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
entries.emplace_back(entry);
|
entries.emplace_back(entry);
|
||||||
@@ -374,28 +319,28 @@ namespace
|
|||||||
{
|
{
|
||||||
if (!m_disable_optimizations && expression->IsStatic())
|
if (!m_disable_optimizations && expression->IsStatic())
|
||||||
{
|
{
|
||||||
const auto expressionStaticValue = expression->EvaluateStatic();
|
const auto staticValue = expression->EvaluateStatic();
|
||||||
ConvertExpressionEntryExpressionValue(entries, &expressionStaticValue);
|
ConvertExpressionValue(entries, staticValue);
|
||||||
}
|
}
|
||||||
else if (const auto* expressionValue = dynamic_cast<const SimpleExpressionValue*>(expression))
|
else if (const auto* value = dynamic_cast<const SimpleExpressionValue*>(expression))
|
||||||
{
|
{
|
||||||
ConvertExpressionEntryExpressionValue(entries, expressionValue);
|
ConvertExpressionValue(entries, *value);
|
||||||
}
|
}
|
||||||
else if (const auto* binaryOperation = dynamic_cast<const SimpleExpressionBinaryOperation*>(expression))
|
else if (const auto* binary = dynamic_cast<const SimpleExpressionBinaryOperation*>(expression))
|
||||||
{
|
{
|
||||||
ConvertExpressionEntryBinaryOperation(gameStatement, entries, binaryOperation, menu, item);
|
ConvertExpressionEntryBinaryOperation(gameStatement, entries, binary, menu, item);
|
||||||
}
|
}
|
||||||
else if (const auto* unaryOperation = dynamic_cast<const SimpleExpressionUnaryOperation*>(expression))
|
else if (const auto* unary = dynamic_cast<const SimpleExpressionUnaryOperation*>(expression))
|
||||||
{
|
{
|
||||||
ConvertExpressionEntryUnaryOperation(gameStatement, entries, unaryOperation, menu, item);
|
ConvertExpressionEntryUnaryOperation(gameStatement, entries, unary, menu, item);
|
||||||
}
|
}
|
||||||
else if (const auto* baseFunctionCall = dynamic_cast<const CommonExpressionBaseFunctionCall*>(expression))
|
else if (const auto* baseFunction = dynamic_cast<const CommonExpressionBaseFunctionCall*>(expression))
|
||||||
{
|
{
|
||||||
ConvertExpressionEntryBaseFunctionCall(gameStatement, entries, baseFunctionCall, menu, item);
|
ConvertExpressionEntryBaseFunctionCall(gameStatement, entries, baseFunction, menu, item);
|
||||||
}
|
}
|
||||||
else if (const auto* customFunctionCall = dynamic_cast<const CommonExpressionCustomFunctionCall*>(expression))
|
else if (const auto* customFunction = dynamic_cast<const CommonExpressionCustomFunctionCall*>(expression))
|
||||||
{
|
{
|
||||||
ConvertExpressionEntryCustomFunctionCall(gameStatement, entries, customFunctionCall, menu, item);
|
ConvertExpressionEntryCustomFunctionCall(gameStatement, entries, customFunction, menu, item);
|
||||||
}
|
}
|
||||||
else if (dynamic_cast<const SimpleExpressionConditionalOperator*>(expression))
|
else if (dynamic_cast<const SimpleExpressionConditionalOperator*>(expression))
|
||||||
{
|
{
|
||||||
@@ -414,20 +359,15 @@ namespace
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
auto* statement = m_memory.Alloc<Statement_s>();
|
auto* statement = m_memory.Alloc<Statement_s>();
|
||||||
for (auto& result : statement->persistentState.lastResult)
|
|
||||||
result = Operand{};
|
|
||||||
for (auto& lastExecutionTime : statement->persistentState.lastExecuteTime)
|
|
||||||
lastExecutionTime = 0;
|
|
||||||
statement->supportingData = nullptr; // Supporting data is set upon using it
|
|
||||||
|
|
||||||
std::vector<expressionEntry> expressionEntries;
|
std::vector<expressionEntry> entries;
|
||||||
ConvertExpressionEntry(statement, expressionEntries, expression, menu, item);
|
ConvertExpressionEntry(statement, entries, expression, menu, item);
|
||||||
|
|
||||||
auto* outputExpressionEntries = m_memory.Alloc<expressionEntry>(expressionEntries.size());
|
auto* outEntries = m_memory.Alloc<expressionEntry>(entries.size());
|
||||||
std::memcpy(outputExpressionEntries, expressionEntries.data(), sizeof(expressionEntry) * expressionEntries.size());
|
std::memcpy(outEntries, entries.data(), sizeof(expressionEntry) * entries.size());
|
||||||
|
|
||||||
statement->entries = outputExpressionEntries;
|
statement->numEntries = static_cast<int>(entries.size());
|
||||||
statement->numEntries = static_cast<int>(expressionEntries.size());
|
statement->entries = outEntries;
|
||||||
|
|
||||||
return statement;
|
return statement;
|
||||||
}
|
}
|
||||||
@@ -437,26 +377,20 @@ namespace
|
|||||||
const CommonMenuDef* menu,
|
const CommonMenuDef* menu,
|
||||||
const CommonItemDef* item = nullptr) const
|
const CommonItemDef* item = nullptr) const
|
||||||
{
|
{
|
||||||
if (m_disable_optimizations)
|
|
||||||
return ConvertExpression(expression, menu, item);
|
|
||||||
|
|
||||||
if (!expression)
|
if (!expression)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (expression->IsStatic())
|
if (!m_disable_optimizations && expression->IsStatic())
|
||||||
{
|
{
|
||||||
const auto value = expression->EvaluateStatic();
|
const auto value = expression->EvaluateStatic();
|
||||||
switch (value.m_type)
|
|
||||||
{
|
if (value.m_type == SimpleExpressionValue::Type::INT)
|
||||||
case SimpleExpressionValue::Type::DOUBLE:
|
|
||||||
staticValue = static_cast<float>(value.m_double_value);
|
|
||||||
break;
|
|
||||||
case SimpleExpressionValue::Type::INT:
|
|
||||||
staticValue = static_cast<float>(value.m_int_value);
|
staticValue = static_cast<float>(value.m_int_value);
|
||||||
break;
|
else if (value.m_type == SimpleExpressionValue::Type::DOUBLE)
|
||||||
case SimpleExpressionValue::Type::STRING:
|
staticValue = static_cast<float>(value.m_double_value);
|
||||||
|
else
|
||||||
throw MenuConversionException("Cannot convert string expression value to floating point", menu, item);
|
throw MenuConversionException("Cannot convert string expression value to floating point", menu, item);
|
||||||
}
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -468,25 +402,17 @@ namespace
|
|||||||
const CommonMenuDef* menu,
|
const CommonMenuDef* menu,
|
||||||
const CommonItemDef* item = nullptr) const
|
const CommonItemDef* item = nullptr) const
|
||||||
{
|
{
|
||||||
if (m_disable_optimizations)
|
|
||||||
return ConvertExpression(expression, menu, item);
|
|
||||||
|
|
||||||
if (!expression)
|
if (!expression)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (expression->IsStatic())
|
if (!m_disable_optimizations && expression->IsStatic())
|
||||||
{
|
{
|
||||||
const auto value = expression->EvaluateStatic();
|
const auto value = expression->EvaluateStatic();
|
||||||
switch (value.m_type)
|
if (value.m_type != SimpleExpressionValue::Type::STRING)
|
||||||
{
|
|
||||||
case SimpleExpressionValue::Type::STRING:
|
|
||||||
staticValue = m_memory.Dup(value.m_string_value->c_str());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SimpleExpressionValue::Type::DOUBLE:
|
|
||||||
case SimpleExpressionValue::Type::INT:
|
|
||||||
throw MenuConversionException("Cannot convert numeric expression value to string", menu, item);
|
throw MenuConversionException("Cannot convert numeric expression value to string", menu, item);
|
||||||
}
|
|
||||||
|
staticValue = m_memory.Dup(value.m_string_value->c_str());
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -498,37 +424,29 @@ namespace
|
|||||||
const CommonMenuDef* menu,
|
const CommonMenuDef* menu,
|
||||||
const CommonItemDef* item = nullptr) const
|
const CommonItemDef* item = nullptr) const
|
||||||
{
|
{
|
||||||
if (m_disable_optimizations)
|
|
||||||
return ConvertExpression(expression, menu, item);
|
|
||||||
|
|
||||||
if (!expression)
|
if (!expression)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (expression->IsStatic())
|
if (!m_disable_optimizations && expression->IsStatic())
|
||||||
{
|
{
|
||||||
const auto value = expression->EvaluateStatic();
|
const auto value = expression->EvaluateStatic();
|
||||||
switch (value.m_type)
|
if (value.m_type != SimpleExpressionValue::Type::STRING)
|
||||||
{
|
throw MenuConversionException("Cannot convert numeric expression value to material", menu, item);
|
||||||
case SimpleExpressionValue::Type::STRING:
|
|
||||||
staticValue = ConvertMaterial(*value.m_string_value, menu, item);
|
staticValue = ConvertMaterial(*value.m_string_value, menu, item);
|
||||||
break;
|
|
||||||
|
|
||||||
case SimpleExpressionValue::Type::DOUBLE:
|
|
||||||
case SimpleExpressionValue::Type::INT:
|
|
||||||
throw MenuConversionException("Cannot convert numeric expression value to string", menu, item);
|
|
||||||
}
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ConvertExpression(expression, menu, item);
|
return ConvertExpression(expression, menu, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] Statement_s* ConvertVisibleExpression(windowDef_t* window,
|
[[nodiscard]] Statement_s* ConvertVisibleExpression(windowDef_t& window,
|
||||||
const ISimpleExpression* expression,
|
const ISimpleExpression* expression,
|
||||||
const CommonMenuDef* commonMenu,
|
const CommonMenuDef* commonMenu,
|
||||||
const CommonItemDef* commonItem = nullptr) const
|
const CommonItemDef* commonItem = nullptr) const
|
||||||
{
|
{
|
||||||
if (expression == nullptr)
|
if (!expression)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
bool isStatic;
|
bool isStatic;
|
||||||
@@ -549,11 +467,11 @@ namespace
|
|||||||
if (isStatic)
|
if (isStatic)
|
||||||
{
|
{
|
||||||
if (isTruthy)
|
if (isTruthy)
|
||||||
window->dynamicFlags[0] |= WINDOW_FLAG_VISIBLE;
|
window.dynamicFlags[0] |= WINDOW_FLAG_VISIBLE;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
window->dynamicFlags[0] |= WINDOW_FLAG_VISIBLE;
|
window.dynamicFlags[0] |= WINDOW_FLAG_VISIBLE;
|
||||||
return ConvertExpression(expression, commonMenu, commonItem);
|
return ConvertExpression(expression, commonMenu, commonItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -639,7 +557,7 @@ namespace
|
|||||||
outputCondition->eventExpression = ConvertExpression(condition->m_condition.get(), menu, item);
|
outputCondition->eventExpression = ConvertExpression(condition->m_condition.get(), menu, item);
|
||||||
outputCondition->eventHandlerSet = ConvertEventHandlerSet(condition->m_condition_elements.get(), menu, item);
|
outputCondition->eventHandlerSet = ConvertEventHandlerSet(condition->m_condition_elements.get(), menu, item);
|
||||||
|
|
||||||
elements.push_back(outputHandler);
|
elements.emplace_back(outputHandler);
|
||||||
|
|
||||||
if (condition->m_else_elements)
|
if (condition->m_else_elements)
|
||||||
{
|
{
|
||||||
@@ -647,7 +565,7 @@ namespace
|
|||||||
outputElseHandler->eventType = EVENT_ELSE;
|
outputElseHandler->eventType = EVENT_ELSE;
|
||||||
outputElseHandler->eventData.elseScript = ConvertEventHandlerSet(condition->m_else_elements.get(), menu, item);
|
outputElseHandler->eventData.elseScript = ConvertEventHandlerSet(condition->m_else_elements.get(), menu, item);
|
||||||
|
|
||||||
elements.push_back(outputElseHandler);
|
elements.emplace_back(outputElseHandler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1013,11 +931,11 @@ namespace
|
|||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] listBoxDef_s* ConvertListBoxFeatures(itemDef_s* item,
|
[[nodiscard]] listBoxDef_s* ConvertListBoxFeatures(itemDef_s* item,
|
||||||
CommonItemFeaturesListBox* commonListBox,
|
const CommonItemFeaturesListBox* commonListBox,
|
||||||
const CommonMenuDef& parentMenu,
|
const CommonMenuDef& parentMenu,
|
||||||
const CommonItemDef& commonItem) const
|
const CommonItemDef& commonItem) const
|
||||||
{
|
{
|
||||||
if (commonListBox == nullptr)
|
if (!commonListBox)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
auto* listBox = m_memory.Alloc<listBoxDef_s>();
|
auto* listBox = m_memory.Alloc<listBoxDef_s>();
|
||||||
@@ -1034,7 +952,7 @@ namespace
|
|||||||
listBox->elementHeightExp =
|
listBox->elementHeightExp =
|
||||||
ConvertOrApplyStatement(listBox->elementHeight, commonListBox->m_element_height_expression.get(), &parentMenu, &commonItem);
|
ConvertOrApplyStatement(listBox->elementHeight, commonListBox->m_element_height_expression.get(), &parentMenu, &commonItem);
|
||||||
|
|
||||||
listBox->numColumns = static_cast<int>(std::min(std::extent_v<decltype(listBoxDef_s::columnInfo)>, commonListBox->m_columns.size()));
|
listBox->numColumns = static_cast<int>(std::min(std::size(listBox->columnInfo), commonListBox->m_columns.size()));
|
||||||
for (auto i = 0; i < listBox->numColumns; i++)
|
for (auto i = 0; i < listBox->numColumns; i++)
|
||||||
{
|
{
|
||||||
auto& col = listBox->columnInfo[i];
|
auto& col = listBox->columnInfo[i];
|
||||||
@@ -1050,12 +968,9 @@ namespace
|
|||||||
return listBox;
|
return listBox;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] editFieldDef_s* ConvertEditFieldFeatures(itemDef_s* item,
|
[[nodiscard]] editFieldDef_s* ConvertEditFieldFeatures(itemDef_s* item, const CommonItemFeaturesEditField* commonEditField) const
|
||||||
CommonItemFeaturesEditField* commonEditField,
|
|
||||||
const CommonMenuDef& parentMenu,
|
|
||||||
const CommonItemDef& commonItem) const
|
|
||||||
{
|
{
|
||||||
if (commonEditField == nullptr)
|
if (!commonEditField)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
auto* editField = m_memory.Alloc<editFieldDef_s>();
|
auto* editField = m_memory.Alloc<editFieldDef_s>();
|
||||||
@@ -1070,16 +985,13 @@ namespace
|
|||||||
return editField;
|
return editField;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] multiDef_s* ConvertMultiValueFeatures(itemDef_s* item,
|
[[nodiscard]] multiDef_s* ConvertMultiValueFeatures(const CommonItemFeaturesMultiValue* commonMultiValue) const
|
||||||
CommonItemFeaturesMultiValue* commonMultiValue,
|
|
||||||
const CommonMenuDef& parentMenu,
|
|
||||||
const CommonItemDef& commonItem) const
|
|
||||||
{
|
{
|
||||||
if (commonMultiValue == nullptr)
|
if (!commonMultiValue)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
auto* multiValue = m_memory.Alloc<multiDef_s>();
|
auto* multiValue = m_memory.Alloc<multiDef_s>();
|
||||||
multiValue->count = static_cast<int>(std::min(std::extent_v<decltype(multiDef_s::dvarList)>, commonMultiValue->m_step_names.size()));
|
multiValue->count = static_cast<int>(std::min(std::size(multiValue->dvarList), commonMultiValue->m_step_names.size()));
|
||||||
multiValue->strDef = !commonMultiValue->m_string_values.empty() ? 1 : 0;
|
multiValue->strDef = !commonMultiValue->m_string_values.empty() ? 1 : 0;
|
||||||
|
|
||||||
for (auto i = 0; i < multiValue->count; i++)
|
for (auto i = 0; i < multiValue->count; i++)
|
||||||
@@ -1101,12 +1013,9 @@ namespace
|
|||||||
return multiValue;
|
return multiValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] newsTickerDef_s* ConvertNewsTickerFeatures(itemDef_s* item,
|
[[nodiscard]] newsTickerDef_s* ConvertNewsTickerFeatures(const CommonItemFeaturesNewsTicker* commonNewsTicker) const
|
||||||
CommonItemFeaturesNewsTicker* commonNewsTicker,
|
|
||||||
const CommonMenuDef& parentMenu,
|
|
||||||
const CommonItemDef& commonItem) const
|
|
||||||
{
|
{
|
||||||
if (commonNewsTicker == nullptr)
|
if (!commonNewsTicker)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
auto* newsTicker = m_memory.Alloc<newsTickerDef_s>();
|
auto* newsTicker = m_memory.Alloc<newsTickerDef_s>();
|
||||||
@@ -1117,7 +1026,7 @@ namespace
|
|||||||
return newsTicker;
|
return newsTicker;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] itemDef_s* ConvertItem(const CommonMenuDef& commonParentMenu, const menuDef_t& parentMenu, const CommonItemDef& commonItem) const
|
[[nodiscard]] itemDef_s* ConvertItem(const CommonMenuDef& commonParentMenu, menuDef_t& parentMenu, const CommonItemDef& commonItem) const
|
||||||
{
|
{
|
||||||
auto* item = m_memory.Alloc<itemDef_s>();
|
auto* item = m_memory.Alloc<itemDef_s>();
|
||||||
memset(item, 0, sizeof(itemDef_s));
|
memset(item, 0, sizeof(itemDef_s));
|
||||||
@@ -1132,11 +1041,11 @@ namespace
|
|||||||
ApplyFlag(item->window.staticFlags, commonItem.m_decoration, WINDOW_FLAG_DECORATION);
|
ApplyFlag(item->window.staticFlags, commonItem.m_decoration, WINDOW_FLAG_DECORATION);
|
||||||
ApplyFlag(item->window.staticFlags, commonItem.m_auto_wrapped, WINDOW_FLAG_AUTO_WRAPPED);
|
ApplyFlag(item->window.staticFlags, commonItem.m_auto_wrapped, WINDOW_FLAG_AUTO_WRAPPED);
|
||||||
ApplyFlag(item->window.staticFlags, commonItem.m_horizontal_scroll, WINDOW_FLAG_HORIZONTAL_SCROLL);
|
ApplyFlag(item->window.staticFlags, commonItem.m_horizontal_scroll, WINDOW_FLAG_HORIZONTAL_SCROLL);
|
||||||
item->type = ConvertItemType(commonItem.m_type);
|
item->type = commonItem.m_type;
|
||||||
item->dataType = item->type;
|
item->dataType = commonItem.m_type;
|
||||||
item->window.border = commonItem.m_border;
|
item->window.border = commonItem.m_border;
|
||||||
item->window.borderSize = static_cast<float>(commonItem.m_border_size);
|
item->window.borderSize = static_cast<float>(commonItem.m_border_size);
|
||||||
item->visibleExp = ConvertVisibleExpression(&item->window, commonItem.m_visible_expression.get(), &commonParentMenu, &commonItem);
|
item->visibleExp = ConvertVisibleExpression(item->window, commonItem.m_visible_expression.get(), &commonParentMenu, &commonItem);
|
||||||
item->disabledExp = ConvertExpression(commonItem.m_disabled_expression.get(), &commonParentMenu, &commonItem);
|
item->disabledExp = ConvertExpression(commonItem.m_disabled_expression.get(), &commonParentMenu, &commonItem);
|
||||||
item->window.ownerDraw = commonItem.m_owner_draw;
|
item->window.ownerDraw = commonItem.m_owner_draw;
|
||||||
item->window.ownerDrawFlags = commonItem.m_owner_draw_flags;
|
item->window.ownerDrawFlags = commonItem.m_owner_draw_flags;
|
||||||
@@ -1146,12 +1055,11 @@ namespace
|
|||||||
item->textaligny = static_cast<float>(commonItem.m_text_align_y);
|
item->textaligny = static_cast<float>(commonItem.m_text_align_y);
|
||||||
item->textscale = static_cast<float>(commonItem.m_text_scale);
|
item->textscale = static_cast<float>(commonItem.m_text_scale);
|
||||||
item->textStyle = commonItem.m_text_style;
|
item->textStyle = commonItem.m_text_style;
|
||||||
item->fontEnum = ConvertTextFont(commonItem.m_text_font);
|
item->fontEnum = commonItem.m_text_font;
|
||||||
ConvertColor(item->window.backColor, commonItem.m_back_color);
|
ConvertColor(item->window.backColor, commonItem.m_back_color);
|
||||||
|
|
||||||
ConvertColor(item->window.foreColor, commonItem.m_fore_color);
|
ConvertColor(item->window.foreColor, commonItem.m_fore_color);
|
||||||
if (!commonItem.m_fore_color.Equals(CommonColor(1.0, 1.0, 1.0, 1.0)))
|
ApplyFlag(item->window.dynamicFlags[0], !commonItem.m_fore_color.Equals(CommonColor(1.0, 1.0, 1.0, 1.0)), WINDOW_FLAG_NON_DEFAULT_FORECOLOR);
|
||||||
item->window.dynamicFlags[0] |= WINDOW_FLAG_NON_DEFAULT_FORECOLOR;
|
|
||||||
|
|
||||||
ConvertColor(item->window.borderColor, commonItem.m_border_color);
|
ConvertColor(item->window.borderColor, commonItem.m_border_color);
|
||||||
ConvertColor(item->window.outlineColor, commonItem.m_outline_color);
|
ConvertColor(item->window.outlineColor, commonItem.m_outline_color);
|
||||||
@@ -1166,8 +1074,9 @@ namespace
|
|||||||
item->mouseEnterText = ConvertEventHandlerSet(commonItem.m_on_mouse_enter_text.get(), &commonParentMenu, &commonItem);
|
item->mouseEnterText = ConvertEventHandlerSet(commonItem.m_on_mouse_enter_text.get(), &commonParentMenu, &commonItem);
|
||||||
item->mouseExitText = ConvertEventHandlerSet(commonItem.m_on_mouse_exit_text.get(), &commonParentMenu, &commonItem);
|
item->mouseExitText = ConvertEventHandlerSet(commonItem.m_on_mouse_exit_text.get(), &commonParentMenu, &commonItem);
|
||||||
item->action = ConvertEventHandlerSet(commonItem.m_on_action.get(), &commonParentMenu, &commonItem);
|
item->action = ConvertEventHandlerSet(commonItem.m_on_action.get(), &commonParentMenu, &commonItem);
|
||||||
item->accept = ConvertEventHandlerSet(commonItem.m_on_accept.get(), &commonParentMenu, &commonItem);
|
item->onAccept = ConvertEventHandlerSet(commonItem.m_on_accept.get(), &commonParentMenu, &commonItem);
|
||||||
item->focusSound = ConvertSound(commonItem.m_focus_sound, &commonParentMenu, &commonItem);
|
item->focusSound = ConvertSound(commonItem.m_focus_sound, &commonParentMenu, &commonItem);
|
||||||
|
item->dvar = ConvertString(commonItem.m_dvar);
|
||||||
item->dvarTest = ConvertString(commonItem.m_dvar_test);
|
item->dvarTest = ConvertString(commonItem.m_dvar_test);
|
||||||
item->enableDvar = ConvertEnableDvar(commonItem, item->dvarFlags);
|
item->enableDvar = ConvertEnableDvar(commonItem, item->dvarFlags);
|
||||||
item->onKey = ConvertKeyHandler(commonItem.m_key_handlers, &commonParentMenu, &commonItem);
|
item->onKey = ConvertKeyHandler(commonItem.m_key_handlers, &commonParentMenu, &commonItem);
|
||||||
@@ -1181,7 +1090,6 @@ namespace
|
|||||||
item->fxLetterTime = commonItem.m_fx_letter_time;
|
item->fxLetterTime = commonItem.m_fx_letter_time;
|
||||||
item->fxDecayStartTime = commonItem.m_fx_decay_start_time;
|
item->fxDecayStartTime = commonItem.m_fx_decay_start_time;
|
||||||
item->fxDecayDuration = commonItem.m_fx_decay_duration;
|
item->fxDecayDuration = commonItem.m_fx_decay_duration;
|
||||||
item->dvar = ConvertString(commonItem.m_dvar);
|
|
||||||
|
|
||||||
switch (commonItem.m_feature_type)
|
switch (commonItem.m_feature_type)
|
||||||
{
|
{
|
||||||
@@ -1190,11 +1098,11 @@ namespace
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case CommonItemFeatureType::EDIT_FIELD:
|
case CommonItemFeatureType::EDIT_FIELD:
|
||||||
item->typeData.editField = ConvertEditFieldFeatures(item, commonItem.m_edit_field_features.get(), commonParentMenu, commonItem);
|
item->typeData.editField = ConvertEditFieldFeatures(item, commonItem.m_edit_field_features.get());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CommonItemFeatureType::MULTI_VALUE:
|
case CommonItemFeatureType::MULTI_VALUE:
|
||||||
item->typeData.multi = ConvertMultiValueFeatures(item, commonItem.m_multi_value_features.get(), commonParentMenu, commonItem);
|
item->typeData.multi = ConvertMultiValueFeatures(commonItem.m_multi_value_features.get());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CommonItemFeatureType::ENUM_DVAR:
|
case CommonItemFeatureType::ENUM_DVAR:
|
||||||
@@ -1202,7 +1110,7 @@ namespace
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case CommonItemFeatureType::NEWS_TICKER:
|
case CommonItemFeatureType::NEWS_TICKER:
|
||||||
item->typeData.ticker = ConvertNewsTickerFeatures(item, commonItem.m_news_ticker_features.get(), commonParentMenu, commonItem);
|
item->typeData.ticker = ConvertNewsTickerFeatures(commonItem.m_news_ticker_features.get());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CommonItemFeatureType::NONE:
|
case CommonItemFeatureType::NONE:
|
||||||
@@ -1216,10 +1124,12 @@ namespace
|
|||||||
// Do this last so any optimizations are considered
|
// Do this last so any optimizations are considered
|
||||||
item->window.rect = ConvertRectDefRelativeTo(item->window.rectClient, parentMenu.window.rect);
|
item->window.rect = ConvertRectDefRelativeTo(item->window.rectClient, parentMenu.window.rect);
|
||||||
|
|
||||||
|
item->parent = &parentMenu;
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
itemDef_s** ConvertMenuItems(const CommonMenuDef& commonMenu, const menuDef_t& menu, int& itemCount) const
|
itemDef_s** ConvertMenuItems(const CommonMenuDef& commonMenu, menuDef_t& menu, int& itemCount) const
|
||||||
{
|
{
|
||||||
if (commonMenu.m_items.empty())
|
if (commonMenu.m_items.empty())
|
||||||
{
|
{
|
||||||
@@ -1244,7 +1154,7 @@ namespace
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConvertMenu(const menu::CommonMenuDef& commonMenu, menuDef_t& menu, AssetRegistration<AssetMenu>& registration) override
|
bool ConvertMenu(const CommonMenuDef& commonMenu, menuDef_t& menu, AssetRegistration<AssetMenu>& registration) override
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -1252,10 +1162,11 @@ namespace
|
|||||||
|
|
||||||
menu.data = menuData;
|
menu.data = menuData;
|
||||||
menu.window.name = m_memory.Dup(commonMenu.m_name.c_str());
|
menu.window.name = m_memory.Dup(commonMenu.m_name.c_str());
|
||||||
menuData->fullScreen = commonMenu.m_full_screen;
|
menuData->fullScreen = commonMenu.m_full_screen ? 1 : 0;
|
||||||
ApplyFlag(menu.window.staticFlags, commonMenu.m_screen_space, WINDOW_FLAG_SCREEN_SPACE);
|
ApplyFlag(menu.window.staticFlags, commonMenu.m_screen_space, WINDOW_FLAG_SCREEN_SPACE);
|
||||||
ApplyFlag(menu.window.staticFlags, commonMenu.m_decoration, WINDOW_FLAG_DECORATION);
|
ApplyFlag(menu.window.staticFlags, commonMenu.m_decoration, WINDOW_FLAG_DECORATION);
|
||||||
menu.window.rect = ConvertRectDef(commonMenu.m_rect);
|
menu.window.rect = ConvertRectDef(commonMenu.m_rect);
|
||||||
|
menu.window.rectClient = menu.window.rect;
|
||||||
menu.window.style = commonMenu.m_style;
|
menu.window.style = commonMenu.m_style;
|
||||||
menu.window.border = commonMenu.m_border;
|
menu.window.border = commonMenu.m_border;
|
||||||
menu.window.borderSize = static_cast<float>(commonMenu.m_border_size);
|
menu.window.borderSize = static_cast<float>(commonMenu.m_border_size);
|
||||||
@@ -1280,7 +1191,7 @@ namespace
|
|||||||
ApplyFlag(menu.window.staticFlags, commonMenu.m_hidden_during_ui, WINDOW_FLAG_HIDDEN_DURING_UI);
|
ApplyFlag(menu.window.staticFlags, commonMenu.m_hidden_during_ui, WINDOW_FLAG_HIDDEN_DURING_UI);
|
||||||
menuData->allowedBinding = ConvertString(commonMenu.m_allowed_binding);
|
menuData->allowedBinding = ConvertString(commonMenu.m_allowed_binding);
|
||||||
ApplyFlag(menu.window.staticFlags, commonMenu.m_text_only_focus, WINDOW_FLAG_TEXT_ONLY_FOCUS);
|
ApplyFlag(menu.window.staticFlags, commonMenu.m_text_only_focus, WINDOW_FLAG_TEXT_ONLY_FOCUS);
|
||||||
menuData->visibleExp = ConvertVisibleExpression(&menu.window, commonMenu.m_visible_expression.get(), &commonMenu);
|
menuData->visibleExp = ConvertVisibleExpression(menu.window, commonMenu.m_visible_expression.get(), &commonMenu);
|
||||||
menuData->rectXExp = ConvertOrApplyStatement(menu.window.rect.x, commonMenu.m_rect_x_exp.get(), &commonMenu);
|
menuData->rectXExp = ConvertOrApplyStatement(menu.window.rect.x, commonMenu.m_rect_x_exp.get(), &commonMenu);
|
||||||
menuData->rectYExp = ConvertOrApplyStatement(menu.window.rect.y, commonMenu.m_rect_y_exp.get(), &commonMenu);
|
menuData->rectYExp = ConvertOrApplyStatement(menu.window.rect.y, commonMenu.m_rect_y_exp.get(), &commonMenu);
|
||||||
menuData->rectWExp = ConvertOrApplyStatement(menu.window.rect.w, commonMenu.m_rect_w_exp.get(), &commonMenu);
|
menuData->rectWExp = ConvertOrApplyStatement(menu.window.rect.w, commonMenu.m_rect_w_exp.get(), &commonMenu);
|
||||||
@@ -1299,7 +1210,10 @@ namespace
|
|||||||
catch (const MenuConversionException& e)
|
catch (const MenuConversionException& e)
|
||||||
{
|
{
|
||||||
PrintConversionExceptionDetails(e);
|
PrintConversionExceptionDetails(e);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
MenuConversionZoneState& m_conversion_zone_state;
|
MenuConversionZoneState& m_conversion_zone_state;
|
||||||
@@ -1307,7 +1221,8 @@ namespace
|
|||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
std::unique_ptr<IMenuConverter> IMenuConverter::Create(bool disableOptimizations, ISearchPath& searchPath, MemoryManager& memory, AssetCreationContext& context)
|
std::unique_ptr<IMenuConverter>
|
||||||
|
IMenuConverter::Create(const bool disableOptimizations, ISearchPath& searchPath, MemoryManager& memory, AssetCreationContext& context)
|
||||||
{
|
{
|
||||||
return std::make_unique<MenuConverter>(disableOptimizations, searchPath, memory, context);
|
return std::make_unique<MenuConverter>(disableOptimizations, searchPath, memory, context);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
#include "SearchPath/ISearchPath.h"
|
#include "SearchPath/ISearchPath.h"
|
||||||
#include "Utils/MemoryManager.h"
|
#include "Utils/MemoryManager.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace IW5
|
namespace IW5
|
||||||
{
|
{
|
||||||
class IMenuConverter
|
class IMenuConverter
|
||||||
@@ -14,7 +16,7 @@ namespace IW5
|
|||||||
IMenuConverter() = default;
|
IMenuConverter() = default;
|
||||||
virtual ~IMenuConverter() = default;
|
virtual ~IMenuConverter() = default;
|
||||||
|
|
||||||
virtual void ConvertMenu(const ::menu::CommonMenuDef& commonMenu, menuDef_t& menu, AssetRegistration<AssetMenu>& registration) = 0;
|
virtual bool ConvertMenu(const ::menu::CommonMenuDef& commonMenu, menuDef_t& menu, AssetRegistration<AssetMenu>& registration) = 0;
|
||||||
|
|
||||||
static std::unique_ptr<IMenuConverter> Create(bool disableOptimizations, ISearchPath& searchPath, MemoryManager& memory, AssetCreationContext& context);
|
static std::unique_ptr<IMenuConverter> Create(bool disableOptimizations, ISearchPath& searchPath, MemoryManager& memory, AssetCreationContext& context);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "MenuWriterIW3.h"
|
#include "MenuWriterIW3.h"
|
||||||
#include "ObjWriting.h"
|
#include "ObjWriting.h"
|
||||||
|
|
||||||
|
#include <format>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
using namespace IW3;
|
using namespace IW3;
|
||||||
@@ -15,7 +16,7 @@ namespace
|
|||||||
const auto menuDumpingState = zoneState->m_menu_dumping_state_map.find(asset.Asset());
|
const auto menuDumpingState = zoneState->m_menu_dumping_state_map.find(asset.Asset());
|
||||||
|
|
||||||
if (menuDumpingState == zoneState->m_menu_dumping_state_map.end())
|
if (menuDumpingState == zoneState->m_menu_dumping_state_map.end())
|
||||||
return "ui_mp/" + std::string(asset.Asset()->window.name) + ".menu";
|
return std::format("ui_mp/{}.menu", asset.Asset()->window.name);
|
||||||
|
|
||||||
return menuDumpingState->second.m_path;
|
return menuDumpingState->second.m_path;
|
||||||
}
|
}
|
||||||
@@ -31,7 +32,7 @@ namespace menu
|
|||||||
if (!ObjWriting::ShouldHandleAssetType(ASSET_TYPE_MENULIST))
|
if (!ObjWriting::ShouldHandleAssetType(ASSET_TYPE_MENULIST))
|
||||||
{
|
{
|
||||||
// Make sure menu paths based on menu lists are created
|
// Make sure menu paths based on menu lists are created
|
||||||
auto menuListAssets = context.m_zone.m_pools.PoolAssets<AssetMenuList>();
|
const auto menuListAssets = context.m_zone.m_pools.PoolAssets<AssetMenuList>();
|
||||||
for (auto* menuListAsset : menuListAssets)
|
for (auto* menuListAsset : menuListAssets)
|
||||||
CreateDumpingStateForMenuListIW3(zoneState, menuListAsset->Asset());
|
CreateDumpingStateForMenuListIW3(zoneState, menuListAsset->Asset());
|
||||||
}
|
}
|
||||||
@@ -42,7 +43,7 @@ namespace menu
|
|||||||
if (!assetFile)
|
if (!assetFile)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto menuWriter = CreateMenuWriterIW3(*assetFile);
|
const auto menuWriter = CreateMenuWriterIW3(*assetFile);
|
||||||
|
|
||||||
menuWriter->Start();
|
menuWriter->Start();
|
||||||
menuWriter->WriteMenu(*menu);
|
menuWriter->WriteMenu(*menu);
|
||||||
|
|||||||
@@ -26,8 +26,11 @@ namespace
|
|||||||
if (menuDumpingState == zoneState->m_menu_dumping_state_map.end())
|
if (menuDumpingState == zoneState->m_menu_dumping_state_map.end())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
const auto* menuAssetName = menu->window.name;
|
||||||
|
const auto isReference = menuAssetName && menuAssetName[0] == ',';
|
||||||
|
|
||||||
// If the menu was embedded directly as menu list write its data in the menu list file
|
// If the menu was embedded directly as menu list write its data in the menu list file
|
||||||
if (menuDumpingState->second.m_alias_menu_list == menuList)
|
if (!isReference && menuDumpingState->second.m_alias_menu_list == menuList)
|
||||||
menuDumper.WriteMenu(*menu);
|
menuDumper.WriteMenu(*menu);
|
||||||
else
|
else
|
||||||
menuDumper.IncludeMenu(menuDumpingState->second.m_path);
|
menuDumper.IncludeMenu(menuDumpingState->second.m_path);
|
||||||
@@ -111,7 +114,7 @@ namespace menu
|
|||||||
{
|
{
|
||||||
auto* zoneState = context.GetZoneAssetDumperState<MenuDumpingZoneState>();
|
auto* zoneState = context.GetZoneAssetDumperState<MenuDumpingZoneState>();
|
||||||
|
|
||||||
auto menuListAssets = context.m_zone.m_pools.PoolAssets<AssetMenuList>();
|
const auto menuListAssets = context.m_zone.m_pools.PoolAssets<AssetMenuList>();
|
||||||
for (const auto* asset : menuListAssets)
|
for (const auto* asset : menuListAssets)
|
||||||
CreateDumpingStateForMenuListIW3(zoneState, asset->Asset());
|
CreateDumpingStateForMenuListIW3(zoneState, asset->Asset());
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#include "MenuWriterIW4.h"
|
#include "MenuWriterIW4.h"
|
||||||
#include "ObjWriting.h"
|
#include "ObjWriting.h"
|
||||||
|
|
||||||
#include <filesystem>
|
#include <format>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
using namespace IW4;
|
using namespace IW4;
|
||||||
@@ -16,7 +16,7 @@ namespace
|
|||||||
const auto menuDumpingState = zoneState->m_menu_dumping_state_map.find(asset.Asset());
|
const auto menuDumpingState = zoneState->m_menu_dumping_state_map.find(asset.Asset());
|
||||||
|
|
||||||
if (menuDumpingState == zoneState->m_menu_dumping_state_map.end())
|
if (menuDumpingState == zoneState->m_menu_dumping_state_map.end())
|
||||||
return "ui_mp/" + std::string(asset.Asset()->window.name) + ".menu";
|
return std::format("ui_mp/{}.menu", asset.Asset()->window.name);
|
||||||
|
|
||||||
return menuDumpingState->second.m_path;
|
return menuDumpingState->second.m_path;
|
||||||
}
|
}
|
||||||
@@ -32,7 +32,7 @@ namespace menu
|
|||||||
if (!ObjWriting::ShouldHandleAssetType(ASSET_TYPE_MENULIST))
|
if (!ObjWriting::ShouldHandleAssetType(ASSET_TYPE_MENULIST))
|
||||||
{
|
{
|
||||||
// Make sure menu paths based on menu lists are created
|
// Make sure menu paths based on menu lists are created
|
||||||
auto menuListAssets = context.m_zone.m_pools.PoolAssets<AssetMenuList>();
|
const auto menuListAssets = context.m_zone.m_pools.PoolAssets<AssetMenuList>();
|
||||||
for (auto* menuListAsset : menuListAssets)
|
for (auto* menuListAsset : menuListAssets)
|
||||||
CreateDumpingStateForMenuListIW4(zoneState, menuListAsset->Asset());
|
CreateDumpingStateForMenuListIW4(zoneState, menuListAsset->Asset());
|
||||||
}
|
}
|
||||||
@@ -43,7 +43,7 @@ namespace menu
|
|||||||
if (!assetFile)
|
if (!assetFile)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto menuWriter = CreateMenuWriterIW4(*assetFile);
|
const auto menuWriter = CreateMenuWriterIW4(*assetFile);
|
||||||
|
|
||||||
menuWriter->Start();
|
menuWriter->Start();
|
||||||
menuWriter->WriteMenu(*menu);
|
menuWriter->WriteMenu(*menu);
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <set>
|
#include <format>
|
||||||
#include <sstream>
|
#include <unordered_set>
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ namespace
|
|||||||
std::vector<const ExpressionSupportingData*> GetAllUniqueExpressionSupportingData(const MenuList* menuList)
|
std::vector<const ExpressionSupportingData*> GetAllUniqueExpressionSupportingData(const MenuList* menuList)
|
||||||
{
|
{
|
||||||
std::vector<const ExpressionSupportingData*> result;
|
std::vector<const ExpressionSupportingData*> result;
|
||||||
std::set<const ExpressionSupportingData*> alreadyAddedSupportingData;
|
std::unordered_set<const ExpressionSupportingData*> alreadyAddedSupportingData;
|
||||||
|
|
||||||
if (menuList->menus == nullptr)
|
if (menuList->menus == nullptr)
|
||||||
return result;
|
return result;
|
||||||
@@ -34,9 +34,9 @@ namespace
|
|||||||
if (menu->expressionData == nullptr)
|
if (menu->expressionData == nullptr)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (alreadyAddedSupportingData.find(menu->expressionData) == alreadyAddedSupportingData.end())
|
if (!alreadyAddedSupportingData.contains(menu->expressionData))
|
||||||
{
|
{
|
||||||
result.push_back(menu->expressionData);
|
result.emplace_back(menu->expressionData);
|
||||||
alreadyAddedSupportingData.emplace(menu->expressionData);
|
alreadyAddedSupportingData.emplace(menu->expressionData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -59,13 +59,10 @@ namespace
|
|||||||
for (auto i = 0; i < supportingData->uifunctions.totalFunctions; i++)
|
for (auto i = 0; i < supportingData->uifunctions.totalFunctions; i++)
|
||||||
{
|
{
|
||||||
const auto* function = supportingData->uifunctions.functions[i];
|
const auto* function = supportingData->uifunctions.functions[i];
|
||||||
if (function != nullptr)
|
if (!function)
|
||||||
{
|
continue;
|
||||||
std::stringstream ss;
|
|
||||||
ss << "FUNC_" << functionIndex;
|
|
||||||
|
|
||||||
menuDumper.WriteFunctionDef(ss.str(), function);
|
menuDumper.WriteFunctionDef(std::format("FUNC_{}", functionIndex), function);
|
||||||
}
|
|
||||||
|
|
||||||
functionIndex++;
|
functionIndex++;
|
||||||
}
|
}
|
||||||
@@ -77,13 +74,18 @@ namespace
|
|||||||
for (auto menuNum = 0; menuNum < menuList->menuCount; menuNum++)
|
for (auto menuNum = 0; menuNum < menuList->menuCount; menuNum++)
|
||||||
{
|
{
|
||||||
const auto* menu = menuList->menus[menuNum];
|
const auto* menu = menuList->menus[menuNum];
|
||||||
|
if (!menu)
|
||||||
|
continue;
|
||||||
|
|
||||||
const auto menuDumpingState = zoneState->m_menu_dumping_state_map.find(menu);
|
const auto menuDumpingState = zoneState->m_menu_dumping_state_map.find(menu);
|
||||||
if (menuDumpingState == zoneState->m_menu_dumping_state_map.end())
|
if (menuDumpingState == zoneState->m_menu_dumping_state_map.end())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
const auto* menuAssetName = menu->window.name;
|
||||||
|
const auto isReference = menuAssetName && menuAssetName[0] == ',';
|
||||||
|
|
||||||
// If the menu was embedded directly as menu list write its data in the menu list file
|
// If the menu was embedded directly as menu list write its data in the menu list file
|
||||||
if (menuDumpingState->second.m_alias_menu_list == menuList)
|
if (!isReference && menuDumpingState->second.m_alias_menu_list == menuList)
|
||||||
menuDumper.WriteMenu(*menu);
|
menuDumper.WriteMenu(*menu);
|
||||||
else
|
else
|
||||||
menuDumper.IncludeMenu(menuDumpingState->second.m_path);
|
menuDumper.IncludeMenu(menuDumpingState->second.m_path);
|
||||||
@@ -95,15 +97,12 @@ namespace
|
|||||||
const auto* menuAssetName = menu->window.name;
|
const auto* menuAssetName = menu->window.name;
|
||||||
|
|
||||||
if (!menuAssetName)
|
if (!menuAssetName)
|
||||||
return "";
|
return {};
|
||||||
|
|
||||||
if (menuAssetName[0] == ',')
|
if (menuAssetName[0] == ',')
|
||||||
menuAssetName = &menuAssetName[1];
|
menuAssetName = &menuAssetName[1];
|
||||||
|
|
||||||
std::ostringstream ss;
|
return std::format("{}{}.menu", menuListParentPath, menuAssetName);
|
||||||
ss << menuListParentPath << menuAssetName << ".menu";
|
|
||||||
|
|
||||||
return ss.str();
|
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@@ -111,32 +110,34 @@ namespace menu
|
|||||||
{
|
{
|
||||||
void CreateDumpingStateForMenuListIW4(MenuDumpingZoneState* zoneState, const MenuList* menuList)
|
void CreateDumpingStateForMenuListIW4(MenuDumpingZoneState* zoneState, const MenuList* menuList)
|
||||||
{
|
{
|
||||||
if (menuList->menuCount <= 0 || menuList->menus == nullptr || menuList->name == nullptr)
|
if (!menuList || menuList->menuCount <= 0 || !menuList->menus || !menuList->name)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const std::string menuListName(menuList->name);
|
const std::string menuListName(menuList->name);
|
||||||
const fs::path p(menuListName);
|
const fs::path p(menuListName);
|
||||||
std::string parentPath;
|
std::string parentPath;
|
||||||
if (p.has_parent_path())
|
if (p.has_parent_path())
|
||||||
parentPath = p.parent_path().string() + "/";
|
parentPath = p.parent_path().generic_string() + "/";
|
||||||
|
|
||||||
for (auto i = 0; i < menuList->menuCount; i++)
|
for (auto i = 0; i < menuList->menuCount; i++)
|
||||||
{
|
{
|
||||||
auto* menu = menuList->menus[i];
|
const auto* menu = menuList->menus[i];
|
||||||
|
|
||||||
if (menu == nullptr)
|
if (!menu)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto menuPath = PathForMenu(parentPath, menu);
|
||||||
|
if (menuPath.empty())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto existingState = zoneState->m_menu_dumping_state_map.find(menu);
|
auto existingState = zoneState->m_menu_dumping_state_map.find(menu);
|
||||||
if (existingState == zoneState->m_menu_dumping_state_map.end())
|
if (existingState == zoneState->m_menu_dumping_state_map.end())
|
||||||
{
|
{
|
||||||
auto menuPath = PathForMenu(parentPath, menu);
|
|
||||||
const auto isTheSameAsMenuList = menuPath == menuListName;
|
const auto isTheSameAsMenuList = menuPath == menuListName;
|
||||||
zoneState->CreateMenuDumpingState(menu, std::move(menuPath), isTheSameAsMenuList ? menuList : nullptr);
|
zoneState->CreateMenuDumpingState(menu, std::move(menuPath), isTheSameAsMenuList ? menuList : nullptr);
|
||||||
}
|
}
|
||||||
else if (existingState->second.m_alias_menu_list == nullptr)
|
else if (!existingState->second.m_alias_menu_list)
|
||||||
{
|
{
|
||||||
auto menuPath = PathForMenu(parentPath, menu);
|
|
||||||
const auto isTheSameAsMenuList = menuPath == menuListName;
|
const auto isTheSameAsMenuList = menuPath == menuListName;
|
||||||
if (isTheSameAsMenuList)
|
if (isTheSameAsMenuList)
|
||||||
{
|
{
|
||||||
@@ -157,15 +158,12 @@ namespace menu
|
|||||||
|
|
||||||
auto* zoneState = context.GetZoneAssetDumperState<MenuDumpingZoneState>();
|
auto* zoneState = context.GetZoneAssetDumperState<MenuDumpingZoneState>();
|
||||||
|
|
||||||
auto menuWriter = CreateMenuWriterIW4(*assetFile);
|
const auto menuWriter = CreateMenuWriterIW4(*assetFile);
|
||||||
|
|
||||||
menuWriter->Start();
|
menuWriter->Start();
|
||||||
|
|
||||||
if (!ObjWriting::Configuration.MenuLegacyMode)
|
if (!ObjWriting::Configuration.MenuLegacyMode)
|
||||||
DumpFunctions(*menuWriter, menuList);
|
DumpFunctions(*menuWriter, menuList);
|
||||||
|
|
||||||
DumpMenus(*menuWriter, zoneState, menuList);
|
DumpMenus(*menuWriter, zoneState, menuList);
|
||||||
|
|
||||||
menuWriter->End();
|
menuWriter->End();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,7 +171,7 @@ namespace menu
|
|||||||
{
|
{
|
||||||
auto* zoneState = context.GetZoneAssetDumperState<MenuDumpingZoneState>();
|
auto* zoneState = context.GetZoneAssetDumperState<MenuDumpingZoneState>();
|
||||||
|
|
||||||
auto menuListAssets = context.m_zone.m_pools.PoolAssets<AssetMenuList>();
|
const auto menuListAssets = context.m_zone.m_pools.PoolAssets<AssetMenuList>();
|
||||||
for (const auto* asset : menuListAssets)
|
for (const auto* asset : menuListAssets)
|
||||||
CreateDumpingStateForMenuListIW4(zoneState, asset->Asset());
|
CreateDumpingStateForMenuListIW4(zoneState, asset->Asset());
|
||||||
|
|
||||||
|
|||||||
@@ -6,34 +6,29 @@
|
|||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <limits>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
using namespace IW4;
|
using namespace IW4;
|
||||||
|
|
||||||
// Uncomment this macro to skip interpretative expression dumping
|
|
||||||
// #define DUMP_NAIVE
|
|
||||||
|
|
||||||
#ifdef DUMP_NAIVE
|
|
||||||
#define DUMP_FUNC WriteStatementNaive
|
|
||||||
#else
|
|
||||||
#define DUMP_FUNC WriteStatementSkipInitialUnnecessaryParenthesis
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
size_t FindStatementClosingParenthesis(const Statement_s* statement, const size_t openingParenthesisPosition)
|
// Set this to true to skip interpretative expression dumping
|
||||||
{
|
constexpr auto DUMP_NAIVE = false;
|
||||||
assert(statement->numEntries >= 0);
|
|
||||||
assert(openingParenthesisPosition < static_cast<size_t>(statement->numEntries));
|
|
||||||
|
|
||||||
const auto statementEnd = static_cast<size_t>(statement->numEntries);
|
size_t FindStatementClosingParenthesis(const Statement_s& statement, const size_t openingParenthesisPosition)
|
||||||
|
{
|
||||||
|
assert(statement.numEntries >= 0);
|
||||||
|
assert(openingParenthesisPosition < static_cast<size_t>(statement.numEntries));
|
||||||
|
|
||||||
|
const auto statementEnd = static_cast<size_t>(statement.numEntries);
|
||||||
|
|
||||||
// The openingParenthesisPosition does not necessarily point to an actual opening parenthesis operator. That's fine though.
|
// The openingParenthesisPosition does not necessarily point to an actual opening parenthesis operator. That's fine though.
|
||||||
// We will pretend it does since the game does sometimes leave out opening parenthesis from the entries.
|
// We will pretend it does since the game does sometimes leave out opening parenthesis from the entries.
|
||||||
auto currentParenthesisDepth = 1;
|
auto currentParenthesisDepth = 1;
|
||||||
for (auto currentSearchPosition = openingParenthesisPosition + 1; currentSearchPosition < statementEnd; currentSearchPosition++)
|
for (auto currentSearchPosition = openingParenthesisPosition + 1; currentSearchPosition < statementEnd; currentSearchPosition++)
|
||||||
{
|
{
|
||||||
const auto& expEntry = statement->entries[currentSearchPosition];
|
const auto& expEntry = statement.entries[currentSearchPosition];
|
||||||
if (expEntry.type != EET_OPERATOR)
|
if (expEntry.type != EET_OPERATOR)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -54,7 +49,7 @@ namespace
|
|||||||
return statementEnd;
|
return statementEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
class MenuWriter final : public ::menu::AbstractBaseWriter, public menu::IWriterIW4
|
class MenuWriter final : public menu::AbstractBaseWriter, public menu::IWriterIW4
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit MenuWriter(std::ostream& stream)
|
explicit MenuWriter(std::ostream& stream)
|
||||||
@@ -75,9 +70,7 @@ namespace
|
|||||||
void WriteMenu(const menuDef_t& menu) override
|
void WriteMenu(const menuDef_t& menu) override
|
||||||
{
|
{
|
||||||
StartMenuDefScope();
|
StartMenuDefScope();
|
||||||
|
WriteMenuData(menu);
|
||||||
WriteMenuData(&menu);
|
|
||||||
|
|
||||||
EndScope();
|
EndScope();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,17 +90,22 @@ namespace
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void WriteStatementNaive(const Statement_s* statement) const
|
static bool HasStatement(const Statement_s* statement)
|
||||||
{
|
{
|
||||||
const auto entryCount = static_cast<size_t>(statement->numEntries);
|
return statement && statement->numEntries > 0 && statement->entries;
|
||||||
|
}
|
||||||
|
|
||||||
const auto missingClosingParenthesis = statement->numEntries > 0 && statement->entries[0].type == EET_OPERATOR
|
void WriteStatementNaive(const Statement_s& statement) const
|
||||||
&& statement->entries[0].data.op == OP_LEFTPAREN
|
{
|
||||||
&& FindStatementClosingParenthesis(statement, 0) >= static_cast<size_t>(statement->numEntries);
|
const auto entryCount = static_cast<size_t>(statement.numEntries);
|
||||||
|
|
||||||
|
const auto missingClosingParenthesis = statement.numEntries > 0 && statement.entries[0].type == EET_OPERATOR
|
||||||
|
&& statement.entries[0].data.op == OP_LEFTPAREN
|
||||||
|
&& FindStatementClosingParenthesis(statement, 0) >= static_cast<size_t>(statement.numEntries);
|
||||||
|
|
||||||
for (auto i = 0uz; i < entryCount; i++)
|
for (auto i = 0uz; i < entryCount; i++)
|
||||||
{
|
{
|
||||||
const auto& entry = statement->entries[i];
|
const auto& entry = statement.entries[i];
|
||||||
if (entry.type == EET_OPERAND)
|
if (entry.type == EET_OPERAND)
|
||||||
{
|
{
|
||||||
size_t pos = i;
|
size_t pos = i;
|
||||||
@@ -144,14 +142,14 @@ namespace
|
|||||||
|
|
||||||
if (closingParenPos - i + 1u >= 1u)
|
if (closingParenPos - i + 1u >= 1u)
|
||||||
{
|
{
|
||||||
const auto& staticDvarEntry = statement->entries[i + 1];
|
const auto& staticDvarEntry = statement.entries[i + 1];
|
||||||
if (staticDvarEntry.type == EET_OPERAND && staticDvarEntry.data.operand.dataType == VAL_INT)
|
if (staticDvarEntry.type == EET_OPERAND && staticDvarEntry.data.operand.dataType == VAL_INT)
|
||||||
{
|
{
|
||||||
if (statement->supportingData && statement->supportingData->staticDvarList.staticDvars
|
if (statement.supportingData && statement.supportingData->staticDvarList.staticDvars
|
||||||
&& staticDvarEntry.data.operand.internals.intVal >= 0
|
&& staticDvarEntry.data.operand.internals.intVal >= 0
|
||||||
&& staticDvarEntry.data.operand.internals.intVal < statement->supportingData->staticDvarList.numStaticDvars)
|
&& staticDvarEntry.data.operand.internals.intVal < statement.supportingData->staticDvarList.numStaticDvars)
|
||||||
{
|
{
|
||||||
const auto* staticDvar = statement->supportingData->staticDvarList.staticDvars[staticDvarEntry.data.operand.internals.intVal];
|
const auto* staticDvar = statement.supportingData->staticDvarList.staticDvars[staticDvarEntry.data.operand.internals.intVal];
|
||||||
if (staticDvar && staticDvar->dvarName)
|
if (staticDvar && staticDvar->dvarName)
|
||||||
m_stream << staticDvar->dvarName;
|
m_stream << staticDvar->dvarName;
|
||||||
}
|
}
|
||||||
@@ -183,9 +181,9 @@ namespace
|
|||||||
m_stream << ")";
|
m_stream << ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteStatementOperator(const Statement_s* statement, size_t& currentPos, bool& spaceNext) const
|
void WriteStatementOperator(const Statement_s& statement, size_t& currentPos, bool& spaceNext) const
|
||||||
{
|
{
|
||||||
const auto& expEntry = statement->entries[currentPos];
|
const auto& expEntry = statement.entries[currentPos];
|
||||||
|
|
||||||
if (spaceNext && expEntry.data.op != OP_COMMA)
|
if (spaceNext && expEntry.data.op != OP_COMMA)
|
||||||
m_stream << " ";
|
m_stream << " ";
|
||||||
@@ -230,14 +228,14 @@ namespace
|
|||||||
|
|
||||||
if (closingParenPos - currentPos + 1 >= 1)
|
if (closingParenPos - currentPos + 1 >= 1)
|
||||||
{
|
{
|
||||||
const auto& staticDvarEntry = statement->entries[currentPos + 1];
|
const auto& staticDvarEntry = statement.entries[currentPos + 1];
|
||||||
if (staticDvarEntry.type == EET_OPERAND && staticDvarEntry.data.operand.dataType == VAL_INT)
|
if (staticDvarEntry.type == EET_OPERAND && staticDvarEntry.data.operand.dataType == VAL_INT)
|
||||||
{
|
{
|
||||||
if (statement->supportingData && statement->supportingData->staticDvarList.staticDvars
|
if (statement.supportingData && statement.supportingData->staticDvarList.staticDvars
|
||||||
&& staticDvarEntry.data.operand.internals.intVal >= 0
|
&& staticDvarEntry.data.operand.internals.intVal >= 0
|
||||||
&& staticDvarEntry.data.operand.internals.intVal < statement->supportingData->staticDvarList.numStaticDvars)
|
&& staticDvarEntry.data.operand.internals.intVal < statement.supportingData->staticDvarList.numStaticDvars)
|
||||||
{
|
{
|
||||||
const auto* staticDvar = statement->supportingData->staticDvarList.staticDvars[staticDvarEntry.data.operand.internals.intVal];
|
const auto* staticDvar = statement.supportingData->staticDvarList.staticDvars[staticDvarEntry.data.operand.internals.intVal];
|
||||||
if (staticDvar && staticDvar->dvarName)
|
if (staticDvar && staticDvar->dvarName)
|
||||||
m_stream << staticDvar->dvarName;
|
m_stream << staticDvar->dvarName;
|
||||||
}
|
}
|
||||||
@@ -277,22 +275,22 @@ namespace
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteStatementOperandFunction(const Statement_s* statement, size_t currentPos) const
|
void WriteStatementOperandFunction(const Statement_s& statement, const size_t currentPos) const
|
||||||
{
|
{
|
||||||
const auto& operand = statement->entries[currentPos].data.operand;
|
const auto& operand = statement.entries[currentPos].data.operand;
|
||||||
|
|
||||||
if (operand.internals.function == nullptr)
|
if (!operand.internals.function)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!ObjWriting::Configuration.MenuLegacyMode)
|
if (!ObjWriting::Configuration.MenuLegacyMode)
|
||||||
{
|
{
|
||||||
int functionIndex = -1;
|
int functionIndex = -1;
|
||||||
if (statement->supportingData && statement->supportingData->uifunctions.functions)
|
if (statement.supportingData && statement.supportingData->uifunctions.functions)
|
||||||
{
|
{
|
||||||
for (auto supportingFunctionIndex = 0; supportingFunctionIndex < statement->supportingData->uifunctions.totalFunctions;
|
for (auto supportingFunctionIndex = 0; supportingFunctionIndex < statement.supportingData->uifunctions.totalFunctions;
|
||||||
supportingFunctionIndex++)
|
supportingFunctionIndex++)
|
||||||
{
|
{
|
||||||
if (statement->supportingData->uifunctions.functions[supportingFunctionIndex] == operand.internals.function)
|
if (statement.supportingData->uifunctions.functions[supportingFunctionIndex] == operand.internals.function)
|
||||||
{
|
{
|
||||||
functionIndex = supportingFunctionIndex;
|
functionIndex = supportingFunctionIndex;
|
||||||
break;
|
break;
|
||||||
@@ -309,14 +307,14 @@ namespace
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_stream << "(";
|
m_stream << "(";
|
||||||
WriteStatementSkipInitialUnnecessaryParenthesis(operand.internals.function);
|
WriteStatementSkipInitialUnnecessaryParenthesis(*operand.internals.function);
|
||||||
m_stream << ")";
|
m_stream << ")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteStatementOperand(const Statement_s* statement, size_t& currentPos, bool& spaceNext) const
|
void WriteStatementOperand(const Statement_s& statement, size_t& currentPos, bool& spaceNext) const
|
||||||
{
|
{
|
||||||
const auto& expEntry = statement->entries[currentPos];
|
const auto& expEntry = statement.entries[currentPos];
|
||||||
|
|
||||||
if (spaceNext)
|
if (spaceNext)
|
||||||
m_stream << " ";
|
m_stream << " ";
|
||||||
@@ -349,16 +347,16 @@ namespace
|
|||||||
spaceNext = true;
|
spaceNext = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteStatementEntryRange(const Statement_s* statement, size_t startOffset, size_t endOffset) const
|
void WriteStatementEntryRange(const Statement_s& statement, const size_t startOffset, const size_t endOffset) const
|
||||||
{
|
{
|
||||||
assert(startOffset <= endOffset);
|
assert(startOffset <= endOffset);
|
||||||
assert(endOffset <= static_cast<size_t>(statement->numEntries));
|
assert(endOffset <= static_cast<size_t>(statement.numEntries));
|
||||||
|
|
||||||
auto currentPos = startOffset;
|
auto currentPos = startOffset;
|
||||||
auto spaceNext = false;
|
auto spaceNext = false;
|
||||||
while (currentPos < endOffset)
|
while (currentPos < endOffset)
|
||||||
{
|
{
|
||||||
const auto& expEntry = statement->entries[currentPos];
|
const auto& expEntry = statement.entries[currentPos];
|
||||||
|
|
||||||
if (expEntry.type == EET_OPERATOR)
|
if (expEntry.type == EET_OPERATOR)
|
||||||
{
|
{
|
||||||
@@ -371,41 +369,41 @@ namespace
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteStatement(const Statement_s* statement) const
|
void WriteStatement(const Statement_s& statement) const
|
||||||
{
|
{
|
||||||
if (statement == nullptr || statement->numEntries < 0)
|
if (!statement.entries || statement.numEntries < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
WriteStatementEntryRange(statement, 0, static_cast<size_t>(statement->numEntries));
|
WriteStatementEntryRange(statement, 0, static_cast<size_t>(statement.numEntries));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteStatementSkipInitialUnnecessaryParenthesis(const Statement_s* statementValue) const
|
void WriteStatementSkipInitialUnnecessaryParenthesis(const Statement_s& statement) const
|
||||||
{
|
{
|
||||||
if (statementValue == nullptr || statementValue->numEntries < 0)
|
if (!statement.entries || statement.numEntries < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const auto statementEnd = static_cast<size_t>(statementValue->numEntries);
|
const auto statementEnd = static_cast<size_t>(statement.numEntries);
|
||||||
|
|
||||||
if (statementValue->numEntries >= 1 && statementValue->entries[0].type == EET_OPERATOR && statementValue->entries[0].data.op == OP_LEFTPAREN)
|
if (statement.numEntries >= 1 && statement.entries[0].type == EET_OPERATOR && statement.entries[0].data.op == OP_LEFTPAREN)
|
||||||
{
|
{
|
||||||
const auto parenthesisEnd = FindStatementClosingParenthesis(statementValue, 0);
|
const auto parenthesisEnd = FindStatementClosingParenthesis(statement, 0);
|
||||||
|
|
||||||
if (parenthesisEnd >= statementEnd)
|
if (parenthesisEnd >= statementEnd)
|
||||||
WriteStatementEntryRange(statementValue, 1, statementEnd);
|
WriteStatementEntryRange(statement, 1, statementEnd);
|
||||||
else if (parenthesisEnd == statementEnd - 1)
|
else if (parenthesisEnd == statementEnd - 1)
|
||||||
WriteStatementEntryRange(statementValue, 1, statementEnd - 1);
|
WriteStatementEntryRange(statement, 1, statementEnd - 1);
|
||||||
else
|
else
|
||||||
WriteStatementEntryRange(statementValue, 0, statementEnd);
|
WriteStatementEntryRange(statement, 0, statementEnd);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WriteStatementEntryRange(statementValue, 0, statementEnd);
|
WriteStatementEntryRange(statement, 0, statementEnd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteStatementProperty(const std::string& propertyKey, const Statement_s* statementValue, bool isBooleanStatement) const
|
void WriteStatementProperty(const std::string& propertyKey, const Statement_s* statement, const bool isBooleanStatement) const
|
||||||
{
|
{
|
||||||
if (statementValue == nullptr || statementValue->numEntries < 0)
|
if (!HasStatement(statement))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Indent();
|
Indent();
|
||||||
@@ -414,24 +412,30 @@ namespace
|
|||||||
if (isBooleanStatement)
|
if (isBooleanStatement)
|
||||||
{
|
{
|
||||||
m_stream << "when(";
|
m_stream << "when(";
|
||||||
DUMP_FUNC(statementValue);
|
if constexpr (DUMP_NAIVE)
|
||||||
|
WriteStatementNaive(*statement);
|
||||||
|
else
|
||||||
|
WriteStatementSkipInitialUnnecessaryParenthesis(*statement);
|
||||||
m_stream << ");\n";
|
m_stream << ");\n";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DUMP_FUNC(statementValue);
|
if constexpr (DUMP_NAIVE)
|
||||||
|
WriteStatementNaive(*statement);
|
||||||
|
else
|
||||||
|
WriteStatement(*statement);
|
||||||
m_stream << ";\n";
|
m_stream << ";\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteSetLocalVarData(const std::string& setFunction, const SetLocalVarData* setLocalVarData) const
|
void WriteSetLocalVarData(const std::string& setFunction, const SetLocalVarData* setLocalVarData) const
|
||||||
{
|
{
|
||||||
if (setLocalVarData == nullptr)
|
if (!setLocalVarData || !setLocalVarData->expression)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Indent();
|
Indent();
|
||||||
m_stream << setFunction << " " << setLocalVarData->localVarName << " ";
|
m_stream << setFunction << " " << setLocalVarData->localVarName << " ";
|
||||||
WriteStatement(setLocalVarData->expression);
|
WriteStatement(*setLocalVarData->expression);
|
||||||
m_stream << ";\n";
|
m_stream << ";\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -453,7 +457,6 @@ namespace
|
|||||||
{
|
{
|
||||||
if (token == ";")
|
if (token == ";")
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Indent();
|
Indent();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -470,7 +473,7 @@ namespace
|
|||||||
isNewStatement = false;
|
isNewStatement = false;
|
||||||
|
|
||||||
if (DoesTokenNeedQuotationMarks(token))
|
if (DoesTokenNeedQuotationMarks(token))
|
||||||
m_stream << "\"" << token << "\"";
|
WriteEscapedString(token);
|
||||||
else
|
else
|
||||||
m_stream << token;
|
m_stream << token;
|
||||||
}
|
}
|
||||||
@@ -485,10 +488,10 @@ namespace
|
|||||||
m_stream << "{\n";
|
m_stream << "{\n";
|
||||||
IncIndent();
|
IncIndent();
|
||||||
|
|
||||||
for (auto i = 0; i < eventHandlerSet->eventHandlerCount; i++)
|
for (auto eventHandlerIndex = 0; eventHandlerIndex < eventHandlerSet->eventHandlerCount; eventHandlerIndex++)
|
||||||
{
|
{
|
||||||
const auto* eventHandler = eventHandlerSet->eventHandlers[i];
|
const auto* eventHandler = eventHandlerSet->eventHandlers[eventHandlerIndex];
|
||||||
if (eventHandler == nullptr)
|
if (!eventHandler)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
switch (eventHandler->eventType)
|
switch (eventHandler->eventType)
|
||||||
@@ -498,21 +501,21 @@ namespace
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case EVENT_IF:
|
case EVENT_IF:
|
||||||
if (eventHandler->eventData.conditionalScript == nullptr || eventHandler->eventData.conditionalScript->eventExpression == nullptr
|
if (!eventHandler->eventData.conditionalScript || !eventHandler->eventData.conditionalScript->eventExpression
|
||||||
|| eventHandler->eventData.conditionalScript->eventHandlerSet == nullptr)
|
|| !eventHandler->eventData.conditionalScript->eventHandlerSet)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Indent();
|
Indent();
|
||||||
m_stream << "if (";
|
m_stream << "if (";
|
||||||
WriteStatementSkipInitialUnnecessaryParenthesis(eventHandler->eventData.conditionalScript->eventExpression);
|
WriteStatementSkipInitialUnnecessaryParenthesis(*eventHandler->eventData.conditionalScript->eventExpression);
|
||||||
m_stream << ")\n";
|
m_stream << ")\n";
|
||||||
WriteMenuEventHandlerSet(eventHandler->eventData.conditionalScript->eventHandlerSet);
|
WriteMenuEventHandlerSet(eventHandler->eventData.conditionalScript->eventHandlerSet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EVENT_ELSE:
|
case EVENT_ELSE:
|
||||||
if (eventHandler->eventData.elseScript == nullptr)
|
if (!eventHandler->eventData.elseScript)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Indent();
|
Indent();
|
||||||
@@ -548,7 +551,7 @@ namespace
|
|||||||
|
|
||||||
void WriteMenuEventHandlerSetProperty(const std::string& propertyKey, const MenuEventHandlerSet* eventHandlerSetValue)
|
void WriteMenuEventHandlerSetProperty(const std::string& propertyKey, const MenuEventHandlerSet* eventHandlerSetValue)
|
||||||
{
|
{
|
||||||
if (eventHandlerSetValue == nullptr)
|
if (!eventHandlerSetValue)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Indent();
|
Indent();
|
||||||
@@ -564,51 +567,44 @@ namespace
|
|||||||
<< static_cast<int>(rect.vertAlign) << "\n";
|
<< static_cast<int>(rect.vertAlign) << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteMaterialProperty(const std::string& propertyKey, const Material* materialValue) const
|
void WriteMaterialProperty(const std::string& propertyKey, const Material* material) const
|
||||||
{
|
{
|
||||||
if (materialValue == nullptr || materialValue->info.name == nullptr)
|
if (!material || !material->info.name)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (materialValue->info.name[0] == ',')
|
const auto* materialName = material->info.name;
|
||||||
WriteStringProperty(propertyKey, &materialValue->info.name[1]);
|
if (materialName[0] == ',')
|
||||||
else
|
materialName++;
|
||||||
WriteStringProperty(propertyKey, materialValue->info.name);
|
WriteStringProperty(propertyKey, materialName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteSoundAliasProperty(const std::string& propertyKey, const snd_alias_list_t* soundAliasValue) const
|
void WriteSoundAliasProperty(const std::string& propertyKey, const snd_alias_list_t* soundAlias) const
|
||||||
{
|
{
|
||||||
if (soundAliasValue == nullptr)
|
if (soundAlias)
|
||||||
return;
|
WriteStringProperty(propertyKey, soundAlias->aliasName);
|
||||||
|
|
||||||
WriteStringProperty(propertyKey, soundAliasValue->aliasName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteDecodeEffectProperty(const std::string& propertyKey, const itemDef_s* item) const
|
void WriteDecodeEffectProperty(const std::string& propertyKey, const itemDef_s& item) const
|
||||||
{
|
{
|
||||||
if (!item->decayActive)
|
if (!item.decayActive)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Indent();
|
Indent();
|
||||||
WriteKey(propertyKey);
|
WriteKey(propertyKey);
|
||||||
m_stream << item->fxLetterTime << " " << item->fxDecayStartTime << " " << item->fxDecayDuration << "\n";
|
m_stream << item.fxLetterTime << " " << item.fxDecayStartTime << " " << item.fxDecayDuration << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteItemKeyHandlerProperty(const ItemKeyHandler* itemKeyHandlerValue)
|
void WriteItemKeyHandlers(const ItemKeyHandler* handler)
|
||||||
{
|
{
|
||||||
for (const auto* currentHandler = itemKeyHandlerValue; currentHandler; currentHandler = currentHandler->next)
|
for (const auto* current = handler; current; current = current->next)
|
||||||
{
|
{
|
||||||
if (currentHandler->key >= '!' && currentHandler->key <= '~' && currentHandler->key != '"')
|
std::string key;
|
||||||
{
|
if (current->key >= '!' && current->key <= '~' && current->key != '"')
|
||||||
std::ostringstream ss;
|
key = std::format("execKey \"{}\"", static_cast<char>(current->key));
|
||||||
ss << "execKey \"" << static_cast<char>(currentHandler->key) << "\"";
|
|
||||||
WriteMenuEventHandlerSetProperty(ss.str(), currentHandler->action);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
key = std::format("execKeyInt {}", current->key);
|
||||||
std::ostringstream ss;
|
|
||||||
ss << "execKeyInt " << currentHandler->key;
|
WriteMenuEventHandlerSetProperty(key, current->action);
|
||||||
WriteMenuEventHandlerSetProperty(ss.str(), currentHandler->action);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -619,18 +615,18 @@ namespace
|
|||||||
|
|
||||||
Indent();
|
Indent();
|
||||||
WriteKey(propertyKey);
|
WriteKey(propertyKey);
|
||||||
|
m_stream << "{ ";
|
||||||
|
|
||||||
const auto tokenList = CreateScriptTokenList(value);
|
const auto tokenList = CreateScriptTokenList(value);
|
||||||
|
|
||||||
auto firstToken = true;
|
auto firstToken = true;
|
||||||
m_stream << "{ ";
|
|
||||||
for (const auto& token : tokenList)
|
for (const auto& token : tokenList)
|
||||||
{
|
{
|
||||||
if (firstToken)
|
if (firstToken)
|
||||||
firstToken = false;
|
firstToken = false;
|
||||||
else
|
else
|
||||||
m_stream << ";";
|
m_stream << ";";
|
||||||
m_stream << "\"" << token << "\"";
|
|
||||||
|
WriteEscapedString(token);
|
||||||
}
|
}
|
||||||
if (!firstToken)
|
if (!firstToken)
|
||||||
m_stream << " ";
|
m_stream << " ";
|
||||||
@@ -656,58 +652,61 @@ namespace
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteColumnProperty(const std::string& propertyKey, const listBoxDef_s* listBox) const
|
void WriteColumnProperty(const listBoxDef_s& listBox) const
|
||||||
{
|
{
|
||||||
if (listBox->numColumns <= 0)
|
if (listBox.numColumns <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Indent();
|
Indent();
|
||||||
WriteKey(propertyKey);
|
WriteKey("columns");
|
||||||
m_stream << listBox->numColumns << "\n";
|
m_stream << listBox.numColumns << "\n";
|
||||||
|
|
||||||
for (auto col = 0; col < listBox->numColumns; col++)
|
const auto columnCount = std::min<size_t>(listBox.numColumns, std::size(listBox.columnInfo));
|
||||||
|
for (size_t columnIndex = 0u; columnIndex < columnCount; columnIndex++)
|
||||||
{
|
{
|
||||||
|
const auto& column = listBox.columnInfo[columnIndex];
|
||||||
|
|
||||||
Indent();
|
Indent();
|
||||||
for (auto i = 0u; i < MENU_KEY_SPACING; i++)
|
for (auto i = 0u; i < MENU_KEY_SPACING; i++)
|
||||||
m_stream << " ";
|
m_stream << " ";
|
||||||
|
|
||||||
m_stream << listBox->columnInfo[col].pos << " " << listBox->columnInfo[col].width << " " << listBox->columnInfo[col].maxChars << " "
|
m_stream << column.pos << " " << column.width << " " << column.maxChars << " " << column.alignment << "\n";
|
||||||
<< listBox->columnInfo[col].alignment << "\n";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteListBoxProperties(const itemDef_s* item)
|
void WriteListBoxProperties(const itemDef_s& item)
|
||||||
{
|
{
|
||||||
if (item->type != ITEM_TYPE_LISTBOX || item->typeData.listBox == nullptr)
|
if (item.type != ITEM_TYPE_LISTBOX || !item.typeData.listBox)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const auto* listBox = item->typeData.listBox;
|
const auto& listBox = *item.typeData.listBox;
|
||||||
WriteKeywordProperty("notselectable", listBox->notselectable != 0);
|
WriteKeywordProperty("notselectable", listBox.notselectable != 0);
|
||||||
WriteKeywordProperty("noscrollbars", listBox->noScrollBars != 0);
|
WriteKeywordProperty("noscrollbars", listBox.noScrollBars != 0);
|
||||||
WriteKeywordProperty("usepaging", listBox->usePaging != 0);
|
WriteKeywordProperty("usepaging", listBox.usePaging != 0);
|
||||||
WriteFloatProperty("elementwidth", listBox->elementWidth, 0.0f);
|
WriteFloatProperty("elementwidth", listBox.elementWidth, 0.0f);
|
||||||
WriteFloatProperty("elementheight", listBox->elementHeight, 0.0f);
|
WriteFloatProperty("elementheight", listBox.elementHeight, 0.0f);
|
||||||
WriteFloatProperty("feeder", item->special, 0.0f);
|
WriteFloatProperty("feeder", item.special, 0.0f);
|
||||||
WriteIntProperty("elementtype", listBox->elementStyle, 0);
|
WriteIntProperty("elementtype", listBox.elementStyle, 0);
|
||||||
WriteColumnProperty("columns", listBox);
|
WriteColumnProperty(listBox);
|
||||||
WriteMenuEventHandlerSetProperty("doubleclick", listBox->onDoubleClick);
|
WriteMenuEventHandlerSetProperty("doubleclick", listBox.onDoubleClick);
|
||||||
WriteColorProperty("selectBorder", listBox->selectBorder, COLOR_0000);
|
WriteColorProperty("selectBorder", listBox.selectBorder, COLOR_0000);
|
||||||
WriteMaterialProperty("selectIcon", listBox->selectIcon);
|
WriteMaterialProperty("selectIcon", listBox.selectIcon);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteDvarFloatProperty(const std::string& propertyKey, const itemDef_s* item, const editFieldDef_s* editField) const
|
void WriteDvarFloatProperty(const itemDef_s& item, const editFieldDef_s& editField) const
|
||||||
{
|
{
|
||||||
if (item->dvar == nullptr)
|
if (!item.dvar)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Indent();
|
Indent();
|
||||||
WriteKey(propertyKey);
|
WriteKey("dvarFloat");
|
||||||
m_stream << "\"" << item->dvar << "\" " << editField->defVal << " " << editField->minVal << " " << editField->maxVal << "\n";
|
WriteEscapedString(item.dvar);
|
||||||
|
m_stream << " " << editField.defVal << " " << editField.minVal << " " << editField.maxVal << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteEditFieldProperties(const itemDef_s* item) const
|
void WriteEditFieldProperties(const itemDef_s& item) const
|
||||||
{
|
{
|
||||||
switch (item->type)
|
switch (item.type)
|
||||||
{
|
{
|
||||||
case ITEM_TYPE_TEXT:
|
case ITEM_TYPE_TEXT:
|
||||||
case ITEM_TYPE_EDITFIELD:
|
case ITEM_TYPE_EDITFIELD:
|
||||||
@@ -726,153 +725,161 @@ namespace
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item->typeData.editField == nullptr)
|
if (!item.typeData.editField)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const auto* editField = item->typeData.editField;
|
const auto& editField = *item.typeData.editField;
|
||||||
if (std::fabs(-1.0f - editField->defVal) >= std::numeric_limits<float>::epsilon()
|
if (std::fabs(-1.0f - editField.defVal) >= std::numeric_limits<float>::epsilon()
|
||||||
|| std::fabs(-1.0f - editField->minVal) >= std::numeric_limits<float>::epsilon()
|
|| std::fabs(-1.0f - editField.minVal) >= std::numeric_limits<float>::epsilon()
|
||||||
|| std::fabs(-1.0f - editField->maxVal) >= std::numeric_limits<float>::epsilon())
|
|| std::fabs(-1.0f - editField.maxVal) >= std::numeric_limits<float>::epsilon())
|
||||||
{
|
{
|
||||||
WriteDvarFloatProperty("dvarFloat", item, editField);
|
WriteDvarFloatProperty(item, editField);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WriteStringProperty("dvar", item->dvar);
|
WriteStringProperty("dvar", item.dvar);
|
||||||
}
|
}
|
||||||
WriteStringProperty("localvar", item->localVar);
|
WriteStringProperty("localvar", item.localVar);
|
||||||
WriteIntProperty("maxChars", editField->maxChars, 0);
|
WriteIntProperty("maxChars", editField.maxChars, 0);
|
||||||
WriteKeywordProperty("maxCharsGotoNext", editField->maxCharsGotoNext != 0);
|
WriteKeywordProperty("maxCharsGotoNext", editField.maxCharsGotoNext != 0);
|
||||||
WriteIntProperty("maxPaintChars", editField->maxPaintChars, 0);
|
WriteIntProperty("maxPaintChars", editField.maxPaintChars, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteMultiValueProperty(const multiDef_s* multiDef) const
|
void WriteMultiValueProperty(const multiDef_s& multi) const
|
||||||
{
|
{
|
||||||
Indent();
|
if (multi.count <= 0)
|
||||||
if (multiDef->strDef)
|
return;
|
||||||
WriteKey("dvarStrList");
|
|
||||||
else
|
|
||||||
WriteKey("dvarFloatList");
|
|
||||||
|
|
||||||
|
Indent();
|
||||||
|
WriteKey(multi.strDef ? "dvarStrList" : "dvarFloatList");
|
||||||
m_stream << "{";
|
m_stream << "{";
|
||||||
for (auto i = 0; i < multiDef->count; i++)
|
const auto valueCount = std::min<size_t>(multi.count, std::size(multi.dvarValue));
|
||||||
|
for (size_t valueIndex = 0u; valueIndex < valueCount; valueIndex++)
|
||||||
{
|
{
|
||||||
if (multiDef->dvarList[i] == nullptr || multiDef->strDef && multiDef->dvarStr[i] == nullptr)
|
if (!multi.dvarList[valueIndex] || (multi.strDef && !multi.dvarStr[valueIndex]))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
m_stream << " \"" << multiDef->dvarList[i] << "\"";
|
m_stream << " ";
|
||||||
|
WriteEscapedString(multi.dvarList[valueIndex]);
|
||||||
if (multiDef->strDef)
|
m_stream << " ";
|
||||||
m_stream << " \"" << multiDef->dvarStr[i] << "\"";
|
if (multi.strDef)
|
||||||
|
WriteEscapedString(multi.dvarStr[valueIndex]);
|
||||||
else
|
else
|
||||||
m_stream << " " << multiDef->dvarValue[i] << "";
|
m_stream << multi.dvarValue[valueIndex];
|
||||||
}
|
}
|
||||||
m_stream << " }\n";
|
m_stream << " }\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteMultiProperties(const itemDef_s* item) const
|
void WriteMultiProperties(const itemDef_s& item) const
|
||||||
{
|
{
|
||||||
if (item->type != ITEM_TYPE_MULTI || item->typeData.multi == nullptr)
|
if (item.type != ITEM_TYPE_MULTI || !item.typeData.multi)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const auto* multiDef = item->typeData.multi;
|
WriteStringProperty("dvar", item.dvar);
|
||||||
|
WriteStringProperty("localvar", item.localVar);
|
||||||
if (multiDef->count <= 0)
|
WriteMultiValueProperty(*item.typeData.multi);
|
||||||
return;
|
|
||||||
|
|
||||||
WriteStringProperty("dvar", item->dvar);
|
|
||||||
WriteStringProperty("localvar", item->localVar);
|
|
||||||
WriteMultiValueProperty(multiDef);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteEnumDvarProperties(const itemDef_s* item) const
|
void WriteEnumDvarProperties(const itemDef_s& item) const
|
||||||
{
|
{
|
||||||
if (item->type != ITEM_TYPE_DVARENUM)
|
if (item.type != ITEM_TYPE_DVARENUM)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
WriteStringProperty("dvar", item->dvar);
|
WriteStringProperty("dvar", item.dvar);
|
||||||
WriteStringProperty("localvar", item->localVar);
|
WriteStringProperty("localvar", item.localVar);
|
||||||
WriteStringProperty("dvarEnumList", item->typeData.enumDvarName);
|
WriteStringProperty("dvarEnumList", item.typeData.enumDvarName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteTickerProperties(const itemDef_s* item) const
|
void WriteTickerProperties(const itemDef_s& item) const
|
||||||
{
|
{
|
||||||
if (item->type != ITEM_TYPE_NEWS_TICKER || item->typeData.ticker == nullptr)
|
if (item.type != ITEM_TYPE_NEWS_TICKER || item.typeData.ticker == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const auto* newsTickerDef = item->typeData.ticker;
|
const auto* newsTickerDef = item.typeData.ticker;
|
||||||
WriteIntProperty("spacing", newsTickerDef->spacing, 0);
|
WriteIntProperty("spacing", newsTickerDef->spacing, 0);
|
||||||
WriteIntProperty("speed", newsTickerDef->speed, 0);
|
WriteIntProperty("speed", newsTickerDef->speed, 0);
|
||||||
WriteIntProperty("newsfeed", newsTickerDef->feedId, 0);
|
WriteIntProperty("newsfeed", newsTickerDef->feedId, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteItemData(const itemDef_s* item)
|
void WriteItemTextProperty(const char* text) const
|
||||||
{
|
{
|
||||||
WriteStringProperty("name", item->window.name);
|
// This distinguishes explicitly empty text from null text, which falls back to the item's dvar.
|
||||||
WriteStringProperty("text", item->text);
|
if (!text)
|
||||||
WriteKeywordProperty("textsavegame", item->itemFlags & ITEM_FLAG_SAVE_GAME_INFO);
|
return;
|
||||||
WriteKeywordProperty("textcinematicsubtitle", item->itemFlags & ITEM_FLAG_CINEMATIC_SUBTITLE);
|
|
||||||
WriteStringProperty("group", item->window.group);
|
|
||||||
WriteRectProperty("rect", item->window.rectClient);
|
|
||||||
WriteIntProperty("style", item->window.style, 0);
|
|
||||||
WriteKeywordProperty("decoration", item->window.staticFlags & WINDOW_FLAG_DECORATION);
|
|
||||||
WriteKeywordProperty("autowrapped", item->window.staticFlags & WINDOW_FLAG_AUTO_WRAPPED);
|
|
||||||
WriteKeywordProperty("horizontalscroll", item->window.staticFlags & WINDOW_FLAG_HORIZONTAL_SCROLL);
|
|
||||||
WriteIntProperty("type", item->type, ITEM_TYPE_TEXT);
|
|
||||||
WriteIntProperty("border", item->window.border, 0);
|
|
||||||
WriteFloatProperty("borderSize", item->window.borderSize, 0.0f);
|
|
||||||
|
|
||||||
if (item->visibleExp)
|
Indent();
|
||||||
WriteStatementProperty("visible", item->visibleExp, true);
|
WriteKey("text");
|
||||||
else if (item->window.dynamicFlags[0] & WINDOW_FLAG_VISIBLE)
|
WriteEscapedString(text);
|
||||||
|
m_stream << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteItemData(const itemDef_s& item)
|
||||||
|
{
|
||||||
|
WriteStringProperty("name", item.window.name);
|
||||||
|
WriteItemTextProperty(item.text);
|
||||||
|
WriteKeywordProperty("textsavegame", item.itemFlags & ITEM_FLAG_SAVE_GAME_INFO);
|
||||||
|
WriteKeywordProperty("textcinematicsubtitle", item.itemFlags & ITEM_FLAG_CINEMATIC_SUBTITLE);
|
||||||
|
WriteStringProperty("group", item.window.group);
|
||||||
|
WriteRectProperty("rect", item.window.rectClient);
|
||||||
|
WriteIntProperty("style", item.window.style, 0);
|
||||||
|
WriteKeywordProperty("decoration", item.window.staticFlags & WINDOW_FLAG_DECORATION);
|
||||||
|
WriteKeywordProperty("autowrapped", item.window.staticFlags & WINDOW_FLAG_AUTO_WRAPPED);
|
||||||
|
WriteKeywordProperty("horizontalscroll", item.window.staticFlags & WINDOW_FLAG_HORIZONTAL_SCROLL);
|
||||||
|
WriteIntProperty("type", item.type, ITEM_TYPE_TEXT);
|
||||||
|
WriteIntProperty("border", item.window.border, 0);
|
||||||
|
WriteFloatProperty("borderSize", item.window.borderSize, 0.0f);
|
||||||
|
|
||||||
|
if (HasStatement(item.visibleExp))
|
||||||
|
WriteStatementProperty("visible", item.visibleExp, true);
|
||||||
|
else if (item.window.dynamicFlags[0] & WINDOW_FLAG_VISIBLE)
|
||||||
WriteIntProperty("visible", 1, 0);
|
WriteIntProperty("visible", 1, 0);
|
||||||
|
|
||||||
WriteStatementProperty("disabled", item->disabledExp, true);
|
WriteStatementProperty("disabled", item.disabledExp, true);
|
||||||
WriteIntProperty("ownerdraw", item->window.ownerDraw, 0);
|
WriteIntProperty("ownerdraw", item.window.ownerDraw, 0);
|
||||||
WriteFlagsProperty("ownerdrawFlag", item->window.ownerDrawFlags);
|
WriteFlagsProperty("ownerdrawFlag", item.window.ownerDrawFlags);
|
||||||
WriteIntProperty("align", item->alignment, 0);
|
WriteIntProperty("align", item.alignment, 0);
|
||||||
WriteIntProperty("textalign", item->textAlignMode, 0);
|
WriteIntProperty("textalign", item.textAlignMode, 0);
|
||||||
WriteFloatProperty("textalignx", item->textalignx, 0.0f);
|
WriteFloatProperty("textalignx", item.textalignx, 0.0f);
|
||||||
WriteFloatProperty("textaligny", item->textaligny, 0.0f);
|
WriteFloatProperty("textaligny", item.textaligny, 0.0f);
|
||||||
WriteFloatProperty("textscale", item->textscale, 0.0f);
|
WriteFloatProperty("textscale", item.textscale, 0.0f);
|
||||||
WriteIntProperty("textstyle", item->textStyle, 0);
|
WriteIntProperty("textstyle", item.textStyle, 0);
|
||||||
WriteIntProperty("textfont", item->fontEnum, 0);
|
WriteIntProperty("textfont", item.fontEnum, 0);
|
||||||
WriteColorProperty("backcolor", item->window.backColor, COLOR_0000);
|
WriteColorProperty("backcolor", item.window.backColor, COLOR_0000);
|
||||||
WriteColorProperty("forecolor", item->window.foreColor, COLOR_1111);
|
WriteColorProperty("forecolor", item.window.foreColor, COLOR_1111);
|
||||||
WriteColorProperty("bordercolor", item->window.borderColor, COLOR_0000);
|
WriteColorProperty("bordercolor", item.window.borderColor, COLOR_0000);
|
||||||
WriteColorProperty("outlinecolor", item->window.outlineColor, COLOR_0000);
|
WriteColorProperty("outlinecolor", item.window.outlineColor, COLOR_0000);
|
||||||
WriteColorProperty("disablecolor", item->window.disableColor, COLOR_0000);
|
WriteColorProperty("disablecolor", item.window.disableColor, COLOR_0000);
|
||||||
WriteColorProperty("glowcolor", item->glowColor, COLOR_0000);
|
WriteColorProperty("glowcolor", item.glowColor, COLOR_0000);
|
||||||
WriteMaterialProperty("background", item->window.background);
|
WriteMaterialProperty("background", item.window.background);
|
||||||
WriteMenuEventHandlerSetProperty("onFocus", item->onFocus);
|
WriteMenuEventHandlerSetProperty("onFocus", item.onFocus);
|
||||||
WriteMenuEventHandlerSetProperty("leaveFocus", item->leaveFocus);
|
WriteMenuEventHandlerSetProperty("leaveFocus", item.leaveFocus);
|
||||||
WriteMenuEventHandlerSetProperty("mouseEnter", item->mouseEnter);
|
WriteMenuEventHandlerSetProperty("mouseEnter", item.mouseEnter);
|
||||||
WriteMenuEventHandlerSetProperty("mouseExit", item->mouseExit);
|
WriteMenuEventHandlerSetProperty("mouseExit", item.mouseExit);
|
||||||
WriteMenuEventHandlerSetProperty("mouseEnterText", item->mouseEnterText);
|
WriteMenuEventHandlerSetProperty("mouseEnterText", item.mouseEnterText);
|
||||||
WriteMenuEventHandlerSetProperty("mouseExitText", item->mouseExitText);
|
WriteMenuEventHandlerSetProperty("mouseExitText", item.mouseExitText);
|
||||||
WriteMenuEventHandlerSetProperty("action", item->action);
|
WriteMenuEventHandlerSetProperty("action", item.action);
|
||||||
WriteMenuEventHandlerSetProperty("accept", item->accept);
|
WriteMenuEventHandlerSetProperty("accept", item.onAccept);
|
||||||
// WriteFloatProperty("special", item->special, 0.0f);
|
// WriteFloatProperty("special", item.special, 0.0f);
|
||||||
WriteSoundAliasProperty("focusSound", item->focusSound);
|
WriteSoundAliasProperty("focusSound", item.focusSound);
|
||||||
WriteStringProperty("dvarTest", item->dvarTest);
|
WriteStringProperty("dvarTest", item.dvarTest);
|
||||||
|
|
||||||
if (item->dvarFlags & ITEM_DVAR_FLAG_ENABLE)
|
if (item.dvarFlags & ITEM_DVAR_FLAG_ENABLE)
|
||||||
WriteMultiTokenStringProperty("enableDvar", item->enableDvar);
|
WriteMultiTokenStringProperty("enableDvar", item.enableDvar);
|
||||||
else if (item->dvarFlags & ITEM_DVAR_FLAG_DISABLE)
|
else if (item.dvarFlags & ITEM_DVAR_FLAG_DISABLE)
|
||||||
WriteMultiTokenStringProperty("disableDvar", item->enableDvar);
|
WriteMultiTokenStringProperty("disableDvar", item.enableDvar);
|
||||||
else if (item->dvarFlags & ITEM_DVAR_FLAG_SHOW)
|
else if (item.dvarFlags & ITEM_DVAR_FLAG_SHOW)
|
||||||
WriteMultiTokenStringProperty("showDvar", item->enableDvar);
|
WriteMultiTokenStringProperty("showDvar", item.enableDvar);
|
||||||
else if (item->dvarFlags & ITEM_DVAR_FLAG_HIDE)
|
else if (item.dvarFlags & ITEM_DVAR_FLAG_HIDE)
|
||||||
WriteMultiTokenStringProperty("hideDvar", item->enableDvar);
|
WriteMultiTokenStringProperty("hideDvar", item.enableDvar);
|
||||||
else if (item->dvarFlags & ITEM_DVAR_FLAG_FOCUS)
|
else if (item.dvarFlags & ITEM_DVAR_FLAG_FOCUS)
|
||||||
WriteMultiTokenStringProperty("focusDvar", item->enableDvar);
|
WriteMultiTokenStringProperty("focusDvar", item.enableDvar);
|
||||||
|
|
||||||
WriteItemKeyHandlerProperty(item->onKey);
|
WriteItemKeyHandlers(item.onKey);
|
||||||
WriteStatementProperty("exp text", item->textExp, false);
|
WriteStatementProperty("exp text", item.textExp, false);
|
||||||
WriteStatementProperty("exp material", item->materialExp, false);
|
WriteStatementProperty("exp material", item.materialExp, false);
|
||||||
WriteFloatExpressionsProperty(item->floatExpressions, item->floatExpressionCount);
|
WriteFloatExpressionsProperty(item.floatExpressions, item.floatExpressionCount);
|
||||||
WriteIntProperty("gamemsgwindowindex", item->gameMsgWindowIndex, 0);
|
WriteIntProperty("gamemsgwindowindex", item.gameMsgWindowIndex, 0);
|
||||||
WriteIntProperty("gamemsgwindowmode", item->gameMsgWindowMode, 0);
|
WriteIntProperty("gamemsgwindowmode", item.gameMsgWindowMode, 0);
|
||||||
WriteDecodeEffectProperty("decodeEffect", item);
|
WriteDecodeEffectProperty("decodeEffect", item);
|
||||||
|
|
||||||
WriteListBoxProperties(item);
|
WriteListBoxProperties(item);
|
||||||
@@ -882,68 +889,73 @@ namespace
|
|||||||
WriteTickerProperties(item);
|
WriteTickerProperties(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteItemDefs(const itemDef_s* const* itemDefs, size_t itemCount)
|
void WriteItemDefs(const itemDef_s* const* items, const size_t itemCount)
|
||||||
{
|
{
|
||||||
for (auto i = 0u; i < itemCount; i++)
|
if (!items || itemCount <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (size_t itemIndex = 0u; itemIndex < itemCount; itemIndex++)
|
||||||
{
|
{
|
||||||
|
const auto* item = items[itemIndex];
|
||||||
|
if (!item)
|
||||||
|
continue;
|
||||||
|
|
||||||
StartItemDefScope();
|
StartItemDefScope();
|
||||||
|
WriteItemData(*item);
|
||||||
WriteItemData(itemDefs[i]);
|
|
||||||
|
|
||||||
EndScope();
|
EndScope();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteMenuData(const menuDef_t* menu)
|
void WriteMenuData(const menuDef_t& menu)
|
||||||
{
|
{
|
||||||
WriteStringProperty("name", menu->window.name);
|
WriteStringProperty("name", menu.window.name);
|
||||||
WriteBoolProperty("fullscreen", menu->fullScreen, false);
|
WriteBoolProperty("fullscreen", menu.fullScreen, false);
|
||||||
WriteKeywordProperty("screenSpace", menu->window.staticFlags & WINDOW_FLAG_SCREEN_SPACE);
|
WriteKeywordProperty("screenSpace", menu.window.staticFlags & WINDOW_FLAG_SCREEN_SPACE);
|
||||||
WriteKeywordProperty("decoration", menu->window.staticFlags & WINDOW_FLAG_DECORATION);
|
WriteKeywordProperty("decoration", menu.window.staticFlags & WINDOW_FLAG_DECORATION);
|
||||||
WriteRectProperty("rect", menu->window.rect);
|
WriteRectProperty("rect", menu.window.rect);
|
||||||
WriteIntProperty("style", menu->window.style, 0);
|
WriteIntProperty("style", menu.window.style, 0);
|
||||||
WriteIntProperty("border", menu->window.border, 0);
|
WriteIntProperty("border", menu.window.border, 0);
|
||||||
WriteFloatProperty("borderSize", menu->window.borderSize, 0.0f);
|
WriteFloatProperty("borderSize", menu.window.borderSize, 0.0f);
|
||||||
WriteColorProperty("backcolor", menu->window.backColor, COLOR_0000);
|
WriteColorProperty("backcolor", menu.window.backColor, COLOR_0000);
|
||||||
WriteColorProperty("forecolor", menu->window.foreColor, COLOR_1111);
|
WriteColorProperty("forecolor", menu.window.foreColor, COLOR_1111);
|
||||||
WriteColorProperty("bordercolor", menu->window.borderColor, COLOR_0000);
|
WriteColorProperty("bordercolor", menu.window.borderColor, COLOR_0000);
|
||||||
WriteColorProperty("focuscolor", menu->focusColor, COLOR_0000);
|
WriteColorProperty("focuscolor", menu.focusColor, COLOR_0000);
|
||||||
WriteColorProperty("outlinecolor", menu->window.outlineColor, COLOR_0000);
|
WriteColorProperty("outlinecolor", menu.window.outlineColor, COLOR_0000);
|
||||||
WriteMaterialProperty("background", menu->window.background);
|
WriteMaterialProperty("background", menu.window.background);
|
||||||
WriteIntProperty("ownerdraw", menu->window.ownerDraw, 0);
|
WriteIntProperty("ownerdraw", menu.window.ownerDraw, 0);
|
||||||
WriteFlagsProperty("ownerdrawFlag", menu->window.ownerDrawFlags);
|
WriteFlagsProperty("ownerdrawFlag", menu.window.ownerDrawFlags);
|
||||||
WriteKeywordProperty("outOfBoundsClick", menu->window.staticFlags & WINDOW_FLAG_OUT_OF_BOUNDS_CLICK);
|
WriteKeywordProperty("outOfBoundsClick", menu.window.staticFlags & WINDOW_FLAG_OUT_OF_BOUNDS_CLICK);
|
||||||
WriteStringProperty("soundLoop", menu->soundName);
|
WriteStringProperty("soundLoop", menu.soundName);
|
||||||
WriteKeywordProperty("popup", menu->window.staticFlags & WINDOW_FLAG_POPUP);
|
WriteKeywordProperty("popup", menu.window.staticFlags & WINDOW_FLAG_POPUP);
|
||||||
WriteFloatProperty("fadeClamp", menu->fadeClamp, 0.0f);
|
WriteFloatProperty("fadeClamp", menu.fadeClamp, 0.0f);
|
||||||
WriteIntProperty("fadeCycle", menu->fadeCycle, 0);
|
WriteIntProperty("fadeCycle", menu.fadeCycle, 0);
|
||||||
WriteFloatProperty("fadeAmount", menu->fadeAmount, 0.0f);
|
WriteFloatProperty("fadeAmount", menu.fadeAmount, 0.0f);
|
||||||
WriteFloatProperty("fadeInAmount", menu->fadeInAmount, 0.0f);
|
WriteFloatProperty("fadeInAmount", menu.fadeInAmount, 0.0f);
|
||||||
WriteFloatProperty("blurWorld", menu->blurRadius, 0.0f);
|
WriteFloatProperty("blurWorld", menu.blurRadius, 0.0f);
|
||||||
WriteKeywordProperty("legacySplitScreenScale", menu->window.staticFlags & WINDOW_FLAG_LEGACY_SPLIT_SCREEN_SCALE);
|
WriteKeywordProperty("legacySplitScreenScale", menu.window.staticFlags & WINDOW_FLAG_LEGACY_SPLIT_SCREEN_SCALE);
|
||||||
WriteKeywordProperty("hiddenDuringScope", menu->window.staticFlags & WINDOW_FLAG_HIDDEN_DURING_SCOPE);
|
WriteKeywordProperty("hiddenDuringScope", menu.window.staticFlags & WINDOW_FLAG_HIDDEN_DURING_SCOPE);
|
||||||
WriteKeywordProperty("hiddenDuringFlashbang", menu->window.staticFlags & WINDOW_FLAG_HIDDEN_DURING_FLASH_BANG);
|
WriteKeywordProperty("hiddenDuringFlashbang", menu.window.staticFlags & WINDOW_FLAG_HIDDEN_DURING_FLASH_BANG);
|
||||||
WriteKeywordProperty("hiddenDuringUI", menu->window.staticFlags & WINDOW_FLAG_HIDDEN_DURING_UI);
|
WriteKeywordProperty("hiddenDuringUI", menu.window.staticFlags & WINDOW_FLAG_HIDDEN_DURING_UI);
|
||||||
WriteStringProperty("allowedBinding", menu->allowedBinding);
|
WriteStringProperty("allowedBinding", menu.allowedBinding);
|
||||||
WriteKeywordProperty("textOnlyFocus", menu->window.staticFlags & WINDOW_FLAG_TEXT_ONLY_FOCUS);
|
WriteKeywordProperty("textOnlyFocus", menu.window.staticFlags & WINDOW_FLAG_TEXT_ONLY_FOCUS);
|
||||||
|
|
||||||
if (menu->visibleExp)
|
if (HasStatement(menu.visibleExp))
|
||||||
WriteStatementProperty("visible", menu->visibleExp, true);
|
WriteStatementProperty("visible", menu.visibleExp, true);
|
||||||
else if (menu->window.dynamicFlags[0] & WINDOW_FLAG_VISIBLE)
|
else if (menu.window.dynamicFlags[0] & WINDOW_FLAG_VISIBLE)
|
||||||
WriteIntProperty("visible", 1, 0);
|
WriteIntProperty("visible", 1, 0);
|
||||||
|
|
||||||
WriteStatementProperty("exp rect X", menu->rectXExp, false);
|
WriteStatementProperty("exp rect X", menu.rectXExp, false);
|
||||||
WriteStatementProperty("exp rect Y", menu->rectYExp, false);
|
WriteStatementProperty("exp rect Y", menu.rectYExp, false);
|
||||||
WriteStatementProperty("exp rect W", menu->rectWExp, false);
|
WriteStatementProperty("exp rect W", menu.rectWExp, false);
|
||||||
WriteStatementProperty("exp rect H", menu->rectHExp, false);
|
WriteStatementProperty("exp rect H", menu.rectHExp, false);
|
||||||
WriteStatementProperty("exp openSound", menu->openSoundExp, false);
|
WriteStatementProperty("exp openSound", menu.openSoundExp, false);
|
||||||
WriteStatementProperty("exp closeSound", menu->closeSoundExp, false);
|
WriteStatementProperty("exp closeSound", menu.closeSoundExp, false);
|
||||||
WriteMenuEventHandlerSetProperty("onOpen", menu->onOpen);
|
WriteMenuEventHandlerSetProperty("onOpen", menu.onOpen);
|
||||||
WriteMenuEventHandlerSetProperty("onClose", menu->onClose);
|
WriteMenuEventHandlerSetProperty("onClose", menu.onClose);
|
||||||
WriteMenuEventHandlerSetProperty("onRequestClose", menu->onCloseRequest);
|
WriteMenuEventHandlerSetProperty("onRequestClose", menu.onCloseRequest);
|
||||||
WriteMenuEventHandlerSetProperty("onESC", menu->onESC);
|
WriteMenuEventHandlerSetProperty("onESC", menu.onESC);
|
||||||
WriteItemKeyHandlerProperty(menu->onKey);
|
WriteItemKeyHandlers(menu.onKey);
|
||||||
WriteItemDefs(menu->items, menu->itemCount);
|
WriteItemDefs(menu.items, menu.itemCount);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@@ -1,49 +1,24 @@
|
|||||||
#include "MenuDumperIW5.h"
|
#include "MenuDumperIW5.h"
|
||||||
|
|
||||||
|
#include "MenuListDumperIW5.h"
|
||||||
#include "MenuWriterIW5.h"
|
#include "MenuWriterIW5.h"
|
||||||
#include "ObjWriting.h"
|
#include "ObjWriting.h"
|
||||||
|
|
||||||
#include <filesystem>
|
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
|
||||||
|
|
||||||
using namespace IW5;
|
using namespace IW5;
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
const MenuList* GetParentMenuList(const XAssetInfo<menuDef_t>& asset)
|
std::string GetPathForMenu(menu::MenuDumpingZoneState* zoneState, const XAssetInfo<menuDef_t>& asset)
|
||||||
{
|
{
|
||||||
const auto* menu = asset.Asset();
|
const auto menuDumpingState = zoneState->m_menu_dumping_state_map.find(asset.Asset());
|
||||||
auto zoneMenuListPool = asset.m_zone->m_pools.PoolAssets<AssetMenuList>();
|
|
||||||
for (const auto* menuList : zoneMenuListPool)
|
|
||||||
{
|
|
||||||
const auto* menuListAsset = menuList->Asset();
|
|
||||||
|
|
||||||
for (auto menuIndex = 0; menuIndex < menuListAsset->menuCount; menuIndex++)
|
if (menuDumpingState == zoneState->m_menu_dumping_state_map.end())
|
||||||
{
|
|
||||||
if (menuListAsset->menus[menuIndex] == menu)
|
|
||||||
return menuListAsset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string GetPathForMenu(const XAssetInfo<menuDef_t>& asset)
|
|
||||||
{
|
|
||||||
const auto* list = GetParentMenuList(asset);
|
|
||||||
|
|
||||||
if (!list)
|
|
||||||
return std::format("ui_mp/{}.menu", asset.Asset()->window.name);
|
return std::format("ui_mp/{}.menu", asset.Asset()->window.name);
|
||||||
|
|
||||||
const fs::path p(list->name);
|
return menuDumpingState->second.m_path;
|
||||||
std::string parentPath;
|
|
||||||
if (p.has_parent_path())
|
|
||||||
parentPath = p.parent_path().string() + "/";
|
|
||||||
|
|
||||||
return std::format("{}{}.menu", parentPath, asset.Asset()->window.name);
|
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@@ -52,22 +27,23 @@ namespace menu
|
|||||||
void MenuDumperIW5::DumpAsset(AssetDumpingContext& context, const XAssetInfo<AssetMenu::Type>& asset)
|
void MenuDumperIW5::DumpAsset(AssetDumpingContext& context, const XAssetInfo<AssetMenu::Type>& asset)
|
||||||
{
|
{
|
||||||
const auto* menu = asset.Asset();
|
const auto* menu = asset.Asset();
|
||||||
const auto menuFilePath = GetPathForMenu(asset);
|
auto* zoneState = context.GetZoneAssetDumperState<MenuDumpingZoneState>();
|
||||||
|
|
||||||
if (ObjWriting::ShouldHandleAssetType(ASSET_TYPE_MENULIST))
|
if (ObjWriting::ShouldHandleAssetType(ASSET_TYPE_MENULIST))
|
||||||
{
|
{
|
||||||
// Don't dump menu file separately if the name matches the menu list
|
// Make sure menu paths based on menu lists are created
|
||||||
const auto* menuListParent = GetParentMenuList(asset);
|
const auto menuListAssets = context.m_zone.m_pools.PoolAssets<AssetMenuList>();
|
||||||
if (menuListParent && menuFilePath == menuListParent->name)
|
for (auto* menuListAsset : menuListAssets)
|
||||||
return;
|
CreateDumpingStateForMenuListIW5(zoneState, menuListAsset->Asset());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto menuFilePath = GetPathForMenu(zoneState, asset);
|
||||||
const auto assetFile = context.OpenAssetFile(menuFilePath);
|
const auto assetFile = context.OpenAssetFile(menuFilePath);
|
||||||
|
|
||||||
if (!assetFile)
|
if (!assetFile)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto menuWriter = CreateMenuWriterIW5(*assetFile);
|
const auto menuWriter = CreateMenuWriterIW5(*assetFile);
|
||||||
|
|
||||||
menuWriter->Start();
|
menuWriter->Start();
|
||||||
menuWriter->WriteMenu(*menu);
|
menuWriter->WriteMenu(*menu);
|
||||||
|
|||||||
@@ -8,8 +8,7 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <set>
|
#include <unordered_set>
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
@@ -20,24 +19,24 @@ namespace
|
|||||||
std::vector<const ExpressionSupportingData*> GetAllUniqueExpressionSupportingData(const MenuList* menuList)
|
std::vector<const ExpressionSupportingData*> GetAllUniqueExpressionSupportingData(const MenuList* menuList)
|
||||||
{
|
{
|
||||||
std::vector<const ExpressionSupportingData*> result;
|
std::vector<const ExpressionSupportingData*> result;
|
||||||
std::set<const ExpressionSupportingData*> alreadyAddedSupportingData;
|
std::unordered_set<const ExpressionSupportingData*> alreadyAddedSupportingData;
|
||||||
|
|
||||||
if (menuList->menus == nullptr)
|
if (!menuList->menus)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
for (auto i = 0; i < menuList->menuCount; i++)
|
for (auto i = 0; i < menuList->menuCount; i++)
|
||||||
{
|
{
|
||||||
if (menuList->menus[i] == nullptr)
|
if (!menuList->menus[i])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const auto* menu = menuList->menus[i];
|
const auto* menu = menuList->menus[i];
|
||||||
|
|
||||||
if (menu->data == nullptr || menu->data->expressionData == nullptr)
|
if (!menu->data || !menu->data->expressionData)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (alreadyAddedSupportingData.find(menu->data->expressionData) == alreadyAddedSupportingData.end())
|
if (!alreadyAddedSupportingData.contains(menu->data->expressionData))
|
||||||
{
|
{
|
||||||
result.push_back(menu->data->expressionData);
|
result.emplace_back(menu->data->expressionData);
|
||||||
alreadyAddedSupportingData.emplace(menu->data->expressionData);
|
alreadyAddedSupportingData.emplace(menu->data->expressionData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -60,7 +59,7 @@ namespace
|
|||||||
for (auto i = 0; i < supportingData->uifunctions.totalFunctions; i++)
|
for (auto i = 0; i < supportingData->uifunctions.totalFunctions; i++)
|
||||||
{
|
{
|
||||||
const auto* function = supportingData->uifunctions.functions[i];
|
const auto* function = supportingData->uifunctions.functions[i];
|
||||||
if (function == nullptr)
|
if (!function)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
menuDumper.WriteFunctionDef(std::format("FUNC_{}", functionIndex), function);
|
menuDumper.WriteFunctionDef(std::format("FUNC_{}", functionIndex), function);
|
||||||
@@ -70,42 +69,85 @@ namespace
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DumpMenus(menu::IWriterIW5& menuDumper, const MenuList* menuList)
|
void DumpMenus(menu::IWriterIW5& menuDumper, menu::MenuDumpingZoneState* zoneState, const MenuList* menuList)
|
||||||
{
|
{
|
||||||
const fs::path p(menuList->name);
|
|
||||||
|
|
||||||
std::string parentPath;
|
|
||||||
if (p.has_parent_path())
|
|
||||||
parentPath = p.parent_path().string() + "/";
|
|
||||||
|
|
||||||
for (auto menuNum = 0; menuNum < menuList->menuCount; menuNum++)
|
for (auto menuNum = 0; menuNum < menuList->menuCount; menuNum++)
|
||||||
{
|
{
|
||||||
const auto* menu = menuList->menus[menuNum];
|
const auto* menu = menuList->menus[menuNum];
|
||||||
|
if (!menu)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const auto menuDumpingState = zoneState->m_menu_dumping_state_map.find(menu);
|
||||||
|
if (menuDumpingState == zoneState->m_menu_dumping_state_map.end())
|
||||||
|
continue;
|
||||||
|
|
||||||
const auto* menuAssetName = menu->window.name;
|
const auto* menuAssetName = menu->window.name;
|
||||||
|
const auto isReference = menuAssetName && menuAssetName[0] == ',';
|
||||||
bool isReference = false;
|
|
||||||
if (menuAssetName && menuAssetName[0] == ',')
|
|
||||||
{
|
|
||||||
menuAssetName = &menuAssetName[1];
|
|
||||||
isReference = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss << parentPath << menuAssetName << ".menu";
|
|
||||||
|
|
||||||
const auto menuName = ss.str();
|
|
||||||
|
|
||||||
// If the menu was embedded directly as menu list write its data in the menu list file
|
// If the menu was embedded directly as menu list write its data in the menu list file
|
||||||
if (!isReference && menuName == menuList->name)
|
if (!isReference && menuDumpingState->second.m_alias_menu_list == menuList)
|
||||||
menuDumper.WriteMenu(*menu);
|
menuDumper.WriteMenu(*menu);
|
||||||
else
|
else
|
||||||
menuDumper.IncludeMenu(ss.str());
|
menuDumper.IncludeMenu(menuDumpingState->second.m_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string PathForMenu(const std::string& menuListParentPath, const menuDef_t* menu)
|
||||||
|
{
|
||||||
|
const auto* menuAssetName = menu->window.name;
|
||||||
|
|
||||||
|
if (!menuAssetName)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (menuAssetName[0] == ',')
|
||||||
|
menuAssetName = &menuAssetName[1];
|
||||||
|
|
||||||
|
return std::format("{}{}.menu", menuListParentPath, menuAssetName);
|
||||||
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace menu
|
namespace menu
|
||||||
{
|
{
|
||||||
|
void CreateDumpingStateForMenuListIW5(MenuDumpingZoneState* zoneState, const MenuList* menuList)
|
||||||
|
{
|
||||||
|
if (!menuList || menuList->menuCount <= 0 || !menuList->menus || !menuList->name)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const std::string menuListName(menuList->name);
|
||||||
|
const fs::path p(menuListName);
|
||||||
|
std::string parentPath;
|
||||||
|
if (p.has_parent_path())
|
||||||
|
parentPath = p.parent_path().generic_string() + "/";
|
||||||
|
|
||||||
|
for (auto i = 0; i < menuList->menuCount; i++)
|
||||||
|
{
|
||||||
|
const auto* menu = menuList->menus[i];
|
||||||
|
|
||||||
|
if (!menu)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto menuPath = PathForMenu(parentPath, menu);
|
||||||
|
if (menuPath.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto existingState = zoneState->m_menu_dumping_state_map.find(menu);
|
||||||
|
if (existingState == zoneState->m_menu_dumping_state_map.end())
|
||||||
|
{
|
||||||
|
const auto isTheSameAsMenuList = menuPath == menuListName;
|
||||||
|
zoneState->CreateMenuDumpingState(menu, std::move(menuPath), isTheSameAsMenuList ? menuList : nullptr);
|
||||||
|
}
|
||||||
|
else if (!existingState->second.m_alias_menu_list)
|
||||||
|
{
|
||||||
|
const auto isTheSameAsMenuList = menuPath == menuListName;
|
||||||
|
if (isTheSameAsMenuList)
|
||||||
|
{
|
||||||
|
existingState->second.m_alias_menu_list = menuList;
|
||||||
|
existingState->second.m_path = std::move(menuPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MenuListDumperIW5::DumpAsset(AssetDumpingContext& context, const XAssetInfo<AssetMenuList::Type>& asset)
|
void MenuListDumperIW5::DumpAsset(AssetDumpingContext& context, const XAssetInfo<AssetMenuList::Type>& asset)
|
||||||
{
|
{
|
||||||
const auto* menuList = asset.Asset();
|
const auto* menuList = asset.Asset();
|
||||||
@@ -114,15 +156,25 @@ namespace menu
|
|||||||
if (!assetFile)
|
if (!assetFile)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto menuWriter = CreateMenuWriterIW5(*assetFile);
|
auto* zoneState = context.GetZoneAssetDumperState<MenuDumpingZoneState>();
|
||||||
|
|
||||||
|
const auto menuWriter = CreateMenuWriterIW5(*assetFile);
|
||||||
|
|
||||||
menuWriter->Start();
|
menuWriter->Start();
|
||||||
|
|
||||||
if (!ObjWriting::Configuration.MenuLegacyMode)
|
if (!ObjWriting::Configuration.MenuLegacyMode)
|
||||||
DumpFunctions(*menuWriter, menuList);
|
DumpFunctions(*menuWriter, menuList);
|
||||||
|
DumpMenus(*menuWriter, zoneState, menuList);
|
||||||
DumpMenus(*menuWriter, menuList);
|
|
||||||
|
|
||||||
menuWriter->End();
|
menuWriter->End();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MenuListDumperIW5::Dump(AssetDumpingContext& context)
|
||||||
|
{
|
||||||
|
auto* zoneState = context.GetZoneAssetDumperState<MenuDumpingZoneState>();
|
||||||
|
|
||||||
|
const auto menuListAssets = context.m_zone.m_pools.PoolAssets<AssetMenuList>();
|
||||||
|
for (const auto* asset : menuListAssets)
|
||||||
|
CreateDumpingStateForMenuListIW5(zoneState, asset->Asset());
|
||||||
|
|
||||||
|
AbstractAssetDumper::Dump(context);
|
||||||
|
}
|
||||||
} // namespace menu
|
} // namespace menu
|
||||||
|
|||||||
@@ -2,11 +2,17 @@
|
|||||||
|
|
||||||
#include "Dumping/AbstractAssetDumper.h"
|
#include "Dumping/AbstractAssetDumper.h"
|
||||||
#include "Game/IW5/IW5.h"
|
#include "Game/IW5/IW5.h"
|
||||||
|
#include "Menu/MenuDumpingZoneState.h"
|
||||||
|
|
||||||
namespace menu
|
namespace menu
|
||||||
{
|
{
|
||||||
|
void CreateDumpingStateForMenuListIW5(MenuDumpingZoneState* zoneState, const IW5::MenuList* menuList);
|
||||||
|
|
||||||
class MenuListDumperIW5 final : public AbstractAssetDumper<IW5::AssetMenuList>
|
class MenuListDumperIW5 final : public AbstractAssetDumper<IW5::AssetMenuList>
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
void Dump(AssetDumpingContext& context) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void DumpAsset(AssetDumpingContext& context, const XAssetInfo<IW5::AssetMenuList::Type>& asset) override;
|
void DumpAsset(AssetDumpingContext& context, const XAssetInfo<IW5::AssetMenuList::Type>& asset) override;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,34 +6,29 @@
|
|||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <limits>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
using namespace IW5;
|
using namespace IW5;
|
||||||
|
|
||||||
// Uncomment this macro to skip interpretative expression dumping
|
|
||||||
// #define DUMP_NAIVE
|
|
||||||
|
|
||||||
#ifdef DUMP_NAIVE
|
|
||||||
#define DUMP_FUNC WriteStatementNaive
|
|
||||||
#else
|
|
||||||
#define DUMP_FUNC WriteStatementSkipInitialUnnecessaryParenthesis
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
size_t FindStatementClosingParenthesis(const Statement_s* statement, const size_t openingParenthesisPosition)
|
// Set this to true to skip interpretative expression dumping
|
||||||
{
|
constexpr auto DUMP_NAIVE = false;
|
||||||
assert(statement->numEntries >= 0);
|
|
||||||
assert(openingParenthesisPosition < static_cast<size_t>(statement->numEntries));
|
|
||||||
|
|
||||||
const auto statementEnd = static_cast<size_t>(statement->numEntries);
|
size_t FindStatementClosingParenthesis(const Statement_s& statement, const size_t openingParenthesisPosition)
|
||||||
|
{
|
||||||
|
assert(statement.numEntries >= 0);
|
||||||
|
assert(openingParenthesisPosition < static_cast<size_t>(statement.numEntries));
|
||||||
|
|
||||||
|
const auto statementEnd = static_cast<size_t>(statement.numEntries);
|
||||||
|
|
||||||
// The openingParenthesisPosition does not necessarily point to an actual opening parenthesis operator. That's fine though.
|
// The openingParenthesisPosition does not necessarily point to an actual opening parenthesis operator. That's fine though.
|
||||||
// We will pretend it does since the game does sometimes leave out opening parenthesis from the entries.
|
// We will pretend it does since the game does sometimes leave out opening parenthesis from the entries.
|
||||||
auto currentParenthesisDepth = 1;
|
auto currentParenthesisDepth = 1;
|
||||||
for (auto currentSearchPosition = openingParenthesisPosition + 1; currentSearchPosition < statementEnd; currentSearchPosition++)
|
for (auto currentSearchPosition = openingParenthesisPosition + 1; currentSearchPosition < statementEnd; currentSearchPosition++)
|
||||||
{
|
{
|
||||||
const auto& expEntry = statement->entries[currentSearchPosition];
|
const auto& expEntry = statement.entries[currentSearchPosition];
|
||||||
if (expEntry.type != EET_OPERATOR)
|
if (expEntry.type != EET_OPERATOR)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -78,9 +73,7 @@ namespace
|
|||||||
void WriteMenu(const menuDef_t& menu) override
|
void WriteMenu(const menuDef_t& menu) override
|
||||||
{
|
{
|
||||||
StartMenuDefScope();
|
StartMenuDefScope();
|
||||||
|
WriteMenuData(menu);
|
||||||
WriteMenuData(&menu);
|
|
||||||
|
|
||||||
EndScope();
|
EndScope();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,12 +93,22 @@ namespace
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void WriteStatementNaive(const Statement_s* statement) const
|
static bool HasStatement(const Statement_s* statement)
|
||||||
{
|
{
|
||||||
const auto entryCount = static_cast<unsigned>(statement->numEntries);
|
return statement && statement->numEntries > 0 && statement->entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteStatementNaive(const Statement_s& statement) const
|
||||||
|
{
|
||||||
|
const auto entryCount = static_cast<unsigned>(statement.numEntries);
|
||||||
|
|
||||||
|
const auto missingClosingParenthesis = statement.numEntries > 0 && statement.entries[0].type == EET_OPERATOR
|
||||||
|
&& statement.entries[0].data.op == OP_LEFTPAREN
|
||||||
|
&& FindStatementClosingParenthesis(statement, 0) >= static_cast<size_t>(statement.numEntries);
|
||||||
|
|
||||||
for (auto i = 0uz; i < entryCount; i++)
|
for (auto i = 0uz; i < entryCount; i++)
|
||||||
{
|
{
|
||||||
const auto& entry = statement->entries[i];
|
const auto& entry = statement.entries[i];
|
||||||
if (entry.type == EET_OPERAND)
|
if (entry.type == EET_OPERAND)
|
||||||
{
|
{
|
||||||
size_t pos = i;
|
size_t pos = i;
|
||||||
@@ -142,14 +145,14 @@ namespace
|
|||||||
|
|
||||||
if (closingParenPos - i + 1u >= 1u)
|
if (closingParenPos - i + 1u >= 1u)
|
||||||
{
|
{
|
||||||
const auto& staticDvarEntry = statement->entries[i + 1u];
|
const auto& staticDvarEntry = statement.entries[i + 1u];
|
||||||
if (staticDvarEntry.type == EET_OPERAND && staticDvarEntry.data.operand.dataType == VAL_INT)
|
if (staticDvarEntry.type == EET_OPERAND && staticDvarEntry.data.operand.dataType == VAL_INT)
|
||||||
{
|
{
|
||||||
if (statement->supportingData && statement->supportingData->staticDvarList.staticDvars
|
if (statement.supportingData && statement.supportingData->staticDvarList.staticDvars
|
||||||
&& staticDvarEntry.data.operand.internals.intVal >= 0
|
&& staticDvarEntry.data.operand.internals.intVal >= 0
|
||||||
&& staticDvarEntry.data.operand.internals.intVal < statement->supportingData->staticDvarList.numStaticDvars)
|
&& staticDvarEntry.data.operand.internals.intVal < statement.supportingData->staticDvarList.numStaticDvars)
|
||||||
{
|
{
|
||||||
const auto* staticDvar = statement->supportingData->staticDvarList.staticDvars[staticDvarEntry.data.operand.internals.intVal];
|
const auto* staticDvar = statement.supportingData->staticDvarList.staticDvars[staticDvarEntry.data.operand.internals.intVal];
|
||||||
if (staticDvar && staticDvar->dvarName)
|
if (staticDvar && staticDvar->dvarName)
|
||||||
m_stream << staticDvar->dvarName;
|
m_stream << staticDvar->dvarName;
|
||||||
}
|
}
|
||||||
@@ -178,9 +181,9 @@ namespace
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteStatementOperator(const Statement_s* statement, size_t& currentPos, bool& spaceNext) const
|
void WriteStatementOperator(const Statement_s& statement, size_t& currentPos, bool& spaceNext) const
|
||||||
{
|
{
|
||||||
const auto& expEntry = statement->entries[currentPos];
|
const auto& expEntry = statement.entries[currentPos];
|
||||||
|
|
||||||
if (spaceNext && expEntry.data.op != OP_COMMA)
|
if (spaceNext && expEntry.data.op != OP_COMMA)
|
||||||
m_stream << " ";
|
m_stream << " ";
|
||||||
@@ -225,14 +228,14 @@ namespace
|
|||||||
|
|
||||||
if (closingParenPos - currentPos + 1 >= 1)
|
if (closingParenPos - currentPos + 1 >= 1)
|
||||||
{
|
{
|
||||||
const auto& staticDvarEntry = statement->entries[currentPos + 1];
|
const auto& staticDvarEntry = statement.entries[currentPos + 1];
|
||||||
if (staticDvarEntry.type == EET_OPERAND && staticDvarEntry.data.operand.dataType == VAL_INT)
|
if (staticDvarEntry.type == EET_OPERAND && staticDvarEntry.data.operand.dataType == VAL_INT)
|
||||||
{
|
{
|
||||||
if (statement->supportingData && statement->supportingData->staticDvarList.staticDvars
|
if (statement.supportingData && statement.supportingData->staticDvarList.staticDvars
|
||||||
&& staticDvarEntry.data.operand.internals.intVal >= 0
|
&& staticDvarEntry.data.operand.internals.intVal >= 0
|
||||||
&& staticDvarEntry.data.operand.internals.intVal < statement->supportingData->staticDvarList.numStaticDvars)
|
&& staticDvarEntry.data.operand.internals.intVal < statement.supportingData->staticDvarList.numStaticDvars)
|
||||||
{
|
{
|
||||||
const auto* staticDvar = statement->supportingData->staticDvarList.staticDvars[staticDvarEntry.data.operand.internals.intVal];
|
const auto* staticDvar = statement.supportingData->staticDvarList.staticDvars[staticDvarEntry.data.operand.internals.intVal];
|
||||||
if (staticDvar && staticDvar->dvarName)
|
if (staticDvar && staticDvar->dvarName)
|
||||||
m_stream << staticDvar->dvarName;
|
m_stream << staticDvar->dvarName;
|
||||||
}
|
}
|
||||||
@@ -272,22 +275,22 @@ namespace
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteStatementOperandFunction(const Statement_s* statement, size_t currentPos) const
|
void WriteStatementOperandFunction(const Statement_s& statement, const size_t currentPos) const
|
||||||
{
|
{
|
||||||
const auto& operand = statement->entries[currentPos].data.operand;
|
const auto& operand = statement.entries[currentPos].data.operand;
|
||||||
|
|
||||||
if (operand.internals.function == nullptr)
|
if (!operand.internals.function)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!ObjWriting::Configuration.MenuLegacyMode)
|
if (!ObjWriting::Configuration.MenuLegacyMode)
|
||||||
{
|
{
|
||||||
int functionIndex = -1;
|
int functionIndex = -1;
|
||||||
if (statement->supportingData && statement->supportingData->uifunctions.functions)
|
if (statement.supportingData && statement.supportingData->uifunctions.functions)
|
||||||
{
|
{
|
||||||
for (auto supportingFunctionIndex = 0; supportingFunctionIndex < statement->supportingData->uifunctions.totalFunctions;
|
for (auto supportingFunctionIndex = 0; supportingFunctionIndex < statement.supportingData->uifunctions.totalFunctions;
|
||||||
supportingFunctionIndex++)
|
supportingFunctionIndex++)
|
||||||
{
|
{
|
||||||
if (statement->supportingData->uifunctions.functions[supportingFunctionIndex] == operand.internals.function)
|
if (statement.supportingData->uifunctions.functions[supportingFunctionIndex] == operand.internals.function)
|
||||||
{
|
{
|
||||||
functionIndex = supportingFunctionIndex;
|
functionIndex = supportingFunctionIndex;
|
||||||
break;
|
break;
|
||||||
@@ -304,14 +307,14 @@ namespace
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_stream << "(";
|
m_stream << "(";
|
||||||
WriteStatementSkipInitialUnnecessaryParenthesis(operand.internals.function);
|
WriteStatementSkipInitialUnnecessaryParenthesis(*operand.internals.function);
|
||||||
m_stream << ")";
|
m_stream << ")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteStatementOperand(const Statement_s* statement, size_t& currentPos, bool& spaceNext) const
|
void WriteStatementOperand(const Statement_s& statement, size_t& currentPos, bool& spaceNext) const
|
||||||
{
|
{
|
||||||
const auto& expEntry = statement->entries[currentPos];
|
const auto& expEntry = statement.entries[currentPos];
|
||||||
|
|
||||||
if (spaceNext)
|
if (spaceNext)
|
||||||
m_stream << " ";
|
m_stream << " ";
|
||||||
@@ -344,16 +347,16 @@ namespace
|
|||||||
spaceNext = true;
|
spaceNext = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteStatementEntryRange(const Statement_s* statement, size_t startOffset, size_t endOffset) const
|
void WriteStatementEntryRange(const Statement_s& statement, const size_t startOffset, const size_t endOffset) const
|
||||||
{
|
{
|
||||||
assert(startOffset <= endOffset);
|
assert(startOffset <= endOffset);
|
||||||
assert(endOffset <= static_cast<size_t>(statement->numEntries));
|
assert(endOffset <= static_cast<size_t>(statement.numEntries));
|
||||||
|
|
||||||
auto currentPos = startOffset;
|
auto currentPos = startOffset;
|
||||||
auto spaceNext = false;
|
auto spaceNext = false;
|
||||||
while (currentPos < endOffset)
|
while (currentPos < endOffset)
|
||||||
{
|
{
|
||||||
const auto& expEntry = statement->entries[currentPos];
|
const auto& expEntry = statement.entries[currentPos];
|
||||||
|
|
||||||
if (expEntry.type == EET_OPERATOR)
|
if (expEntry.type == EET_OPERATOR)
|
||||||
{
|
{
|
||||||
@@ -366,41 +369,41 @@ namespace
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteStatement(const Statement_s* statement) const
|
void WriteStatement(const Statement_s& statement) const
|
||||||
{
|
{
|
||||||
if (statement == nullptr || statement->numEntries < 0)
|
if (!statement.entries || statement.numEntries < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
WriteStatementEntryRange(statement, 0, static_cast<size_t>(statement->numEntries));
|
WriteStatementEntryRange(statement, 0, static_cast<size_t>(statement.numEntries));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteStatementSkipInitialUnnecessaryParenthesis(const Statement_s* statementValue) const
|
void WriteStatementSkipInitialUnnecessaryParenthesis(const Statement_s& statement) const
|
||||||
{
|
{
|
||||||
if (statementValue == nullptr || statementValue->numEntries < 0)
|
if (!statement.entries || statement.numEntries < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const auto statementEnd = static_cast<size_t>(statementValue->numEntries);
|
const auto statementEnd = static_cast<size_t>(statement.numEntries);
|
||||||
|
|
||||||
if (statementValue->numEntries >= 1 && statementValue->entries[0].type == EET_OPERATOR && statementValue->entries[0].data.op == OP_LEFTPAREN)
|
if (statement.numEntries >= 1 && statement.entries[0].type == EET_OPERATOR && statement.entries[0].data.op == OP_LEFTPAREN)
|
||||||
{
|
{
|
||||||
const auto parenthesisEnd = FindStatementClosingParenthesis(statementValue, 0);
|
const auto parenthesisEnd = FindStatementClosingParenthesis(statement, 0);
|
||||||
|
|
||||||
if (parenthesisEnd >= statementEnd)
|
if (parenthesisEnd >= statementEnd)
|
||||||
WriteStatementEntryRange(statementValue, 1, statementEnd);
|
WriteStatementEntryRange(statement, 1, statementEnd);
|
||||||
else if (parenthesisEnd == statementEnd - 1)
|
else if (parenthesisEnd == statementEnd - 1)
|
||||||
WriteStatementEntryRange(statementValue, 1, statementEnd - 1);
|
WriteStatementEntryRange(statement, 1, statementEnd - 1);
|
||||||
else
|
else
|
||||||
WriteStatementEntryRange(statementValue, 0, statementEnd);
|
WriteStatementEntryRange(statement, 0, statementEnd);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WriteStatementEntryRange(statementValue, 0, statementEnd);
|
WriteStatementEntryRange(statement, 0, statementEnd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteStatementProperty(const std::string& propertyKey, const Statement_s* statementValue, bool isBooleanStatement) const
|
void WriteStatementProperty(const std::string& propertyKey, const Statement_s* statement, const bool isBooleanStatement) const
|
||||||
{
|
{
|
||||||
if (statementValue == nullptr || statementValue->numEntries < 0)
|
if (!HasStatement(statement))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Indent();
|
Indent();
|
||||||
@@ -409,24 +412,30 @@ namespace
|
|||||||
if (isBooleanStatement)
|
if (isBooleanStatement)
|
||||||
{
|
{
|
||||||
m_stream << "when(";
|
m_stream << "when(";
|
||||||
DUMP_FUNC(statementValue);
|
if constexpr (DUMP_NAIVE)
|
||||||
|
WriteStatementNaive(*statement);
|
||||||
|
else
|
||||||
|
WriteStatementSkipInitialUnnecessaryParenthesis(*statement);
|
||||||
m_stream << ");\n";
|
m_stream << ");\n";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DUMP_FUNC(statementValue);
|
if constexpr (DUMP_NAIVE)
|
||||||
|
WriteStatementNaive(*statement);
|
||||||
|
else
|
||||||
|
WriteStatement(*statement);
|
||||||
m_stream << ";\n";
|
m_stream << ";\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteSetLocalVarData(const std::string& setFunction, const SetLocalVarData* setLocalVarData) const
|
void WriteSetLocalVarData(const std::string& setFunction, const SetLocalVarData* setLocalVarData) const
|
||||||
{
|
{
|
||||||
if (setLocalVarData == nullptr)
|
if (!setLocalVarData || !setLocalVarData->expression)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Indent();
|
Indent();
|
||||||
m_stream << setFunction << " " << setLocalVarData->localVarName << " ";
|
m_stream << setFunction << " " << setLocalVarData->localVarName << " ";
|
||||||
WriteStatement(setLocalVarData->expression);
|
WriteStatement(*setLocalVarData->expression);
|
||||||
m_stream << ";\n";
|
m_stream << ";\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -448,7 +457,6 @@ namespace
|
|||||||
{
|
{
|
||||||
if (token == ";")
|
if (token == ";")
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Indent();
|
Indent();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -465,7 +473,7 @@ namespace
|
|||||||
isNewStatement = false;
|
isNewStatement = false;
|
||||||
|
|
||||||
if (DoesTokenNeedQuotationMarks(token))
|
if (DoesTokenNeedQuotationMarks(token))
|
||||||
m_stream << "\"" << token << "\"";
|
WriteEscapedString(token);
|
||||||
else
|
else
|
||||||
m_stream << token;
|
m_stream << token;
|
||||||
}
|
}
|
||||||
@@ -480,10 +488,10 @@ namespace
|
|||||||
m_stream << "{\n";
|
m_stream << "{\n";
|
||||||
IncIndent();
|
IncIndent();
|
||||||
|
|
||||||
for (auto i = 0; i < eventHandlerSet->eventHandlerCount; i++)
|
for (auto eventHandlerIndex = 0; eventHandlerIndex < eventHandlerSet->eventHandlerCount; eventHandlerIndex++)
|
||||||
{
|
{
|
||||||
const auto* eventHandler = eventHandlerSet->eventHandlers[i];
|
const auto* eventHandler = eventHandlerSet->eventHandlers[eventHandlerIndex];
|
||||||
if (eventHandler == nullptr)
|
if (!eventHandler)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
switch (eventHandler->eventType)
|
switch (eventHandler->eventType)
|
||||||
@@ -493,21 +501,21 @@ namespace
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case EVENT_IF:
|
case EVENT_IF:
|
||||||
if (eventHandler->eventData.conditionalScript == nullptr || eventHandler->eventData.conditionalScript->eventExpression == nullptr
|
if (!eventHandler->eventData.conditionalScript || !eventHandler->eventData.conditionalScript->eventExpression
|
||||||
|| eventHandler->eventData.conditionalScript->eventHandlerSet == nullptr)
|
|| !eventHandler->eventData.conditionalScript->eventHandlerSet)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Indent();
|
Indent();
|
||||||
m_stream << "if (";
|
m_stream << "if (";
|
||||||
WriteStatementSkipInitialUnnecessaryParenthesis(eventHandler->eventData.conditionalScript->eventExpression);
|
WriteStatementSkipInitialUnnecessaryParenthesis(*eventHandler->eventData.conditionalScript->eventExpression);
|
||||||
m_stream << ")\n";
|
m_stream << ")\n";
|
||||||
WriteMenuEventHandlerSet(eventHandler->eventData.conditionalScript->eventHandlerSet);
|
WriteMenuEventHandlerSet(eventHandler->eventData.conditionalScript->eventHandlerSet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EVENT_ELSE:
|
case EVENT_ELSE:
|
||||||
if (eventHandler->eventData.elseScript == nullptr)
|
if (!eventHandler->eventData.elseScript)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Indent();
|
Indent();
|
||||||
@@ -543,7 +551,7 @@ namespace
|
|||||||
|
|
||||||
void WriteMenuEventHandlerSetProperty(const std::string& propertyKey, const MenuEventHandlerSet* eventHandlerSetValue)
|
void WriteMenuEventHandlerSetProperty(const std::string& propertyKey, const MenuEventHandlerSet* eventHandlerSetValue)
|
||||||
{
|
{
|
||||||
if (eventHandlerSetValue == nullptr)
|
if (!eventHandlerSetValue)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Indent();
|
Indent();
|
||||||
@@ -559,51 +567,44 @@ namespace
|
|||||||
<< static_cast<int>(rect.vertAlign) << "\n";
|
<< static_cast<int>(rect.vertAlign) << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteMaterialProperty(const std::string& propertyKey, const Material* materialValue) const
|
void WriteMaterialProperty(const std::string& propertyKey, const Material* material) const
|
||||||
{
|
{
|
||||||
if (materialValue == nullptr || materialValue->info.name == nullptr)
|
if (!material || !material->info.name)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (materialValue->info.name[0] == ',')
|
const auto* materialName = material->info.name;
|
||||||
WriteStringProperty(propertyKey, &materialValue->info.name[1]);
|
if (materialName[0] == ',')
|
||||||
else
|
materialName++;
|
||||||
WriteStringProperty(propertyKey, materialValue->info.name);
|
WriteStringProperty(propertyKey, materialName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteSoundAliasProperty(const std::string& propertyKey, const snd_alias_list_t* soundAliasValue) const
|
void WriteSoundAliasProperty(const std::string& propertyKey, const snd_alias_list_t* soundAlias) const
|
||||||
{
|
{
|
||||||
if (soundAliasValue == nullptr)
|
if (soundAlias)
|
||||||
return;
|
WriteStringProperty(propertyKey, soundAlias->aliasName);
|
||||||
|
|
||||||
WriteStringProperty(propertyKey, soundAliasValue->aliasName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteDecodeEffectProperty(const std::string& propertyKey, const itemDef_s* item) const
|
void WriteDecodeEffectProperty(const std::string& propertyKey, const itemDef_s& item) const
|
||||||
{
|
{
|
||||||
if (!item->decayActive)
|
if (!item.decayActive)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Indent();
|
Indent();
|
||||||
WriteKey(propertyKey);
|
WriteKey(propertyKey);
|
||||||
m_stream << item->fxLetterTime << " " << item->fxDecayStartTime << " " << item->fxDecayDuration << "\n";
|
m_stream << item.fxLetterTime << " " << item.fxDecayStartTime << " " << item.fxDecayDuration << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteItemKeyHandlerProperty(const ItemKeyHandler* itemKeyHandlerValue)
|
void WriteItemKeyHandlers(const ItemKeyHandler* handler)
|
||||||
{
|
{
|
||||||
for (const auto* currentHandler = itemKeyHandlerValue; currentHandler; currentHandler = currentHandler->next)
|
for (const auto* current = handler; current; current = current->next)
|
||||||
{
|
{
|
||||||
if (currentHandler->key >= '!' && currentHandler->key <= '~' && currentHandler->key != '"')
|
std::string key;
|
||||||
{
|
if (current->key >= '!' && current->key <= '~' && current->key != '"')
|
||||||
std::ostringstream ss;
|
key = std::format("execKey \"{}\"", static_cast<char>(current->key));
|
||||||
ss << "execKey \"" << static_cast<char>(currentHandler->key) << "\"";
|
|
||||||
WriteMenuEventHandlerSetProperty(ss.str(), currentHandler->action);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
key = std::format("execKeyInt {}", current->key);
|
||||||
std::ostringstream ss;
|
|
||||||
ss << "execKeyInt " << currentHandler->key;
|
WriteMenuEventHandlerSetProperty(key, current->action);
|
||||||
WriteMenuEventHandlerSetProperty(ss.str(), currentHandler->action);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -614,18 +615,18 @@ namespace
|
|||||||
|
|
||||||
Indent();
|
Indent();
|
||||||
WriteKey(propertyKey);
|
WriteKey(propertyKey);
|
||||||
|
m_stream << "{ ";
|
||||||
|
|
||||||
const auto tokenList = CreateScriptTokenList(value);
|
const auto tokenList = CreateScriptTokenList(value);
|
||||||
|
|
||||||
auto firstToken = true;
|
auto firstToken = true;
|
||||||
m_stream << "{ ";
|
|
||||||
for (const auto& token : tokenList)
|
for (const auto& token : tokenList)
|
||||||
{
|
{
|
||||||
if (firstToken)
|
if (firstToken)
|
||||||
firstToken = false;
|
firstToken = false;
|
||||||
else
|
else
|
||||||
m_stream << ";";
|
m_stream << ";";
|
||||||
m_stream << "\"" << token << "\"";
|
|
||||||
|
WriteEscapedString(token);
|
||||||
}
|
}
|
||||||
if (!firstToken)
|
if (!firstToken)
|
||||||
m_stream << " ";
|
m_stream << " ";
|
||||||
@@ -651,59 +652,63 @@ namespace
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteColumnProperty(const std::string& propertyKey, const listBoxDef_s* listBox) const
|
void WriteColumnProperty(const listBoxDef_s& listBox) const
|
||||||
{
|
{
|
||||||
if (listBox->numColumns <= 0)
|
if (listBox.numColumns <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Indent();
|
Indent();
|
||||||
WriteKey(propertyKey);
|
WriteKey("columns");
|
||||||
m_stream << listBox->numColumns << "\n";
|
m_stream << listBox.numColumns << "\n";
|
||||||
|
|
||||||
for (auto col = 0; col < listBox->numColumns; col++)
|
const auto columnCount = std::min<size_t>(listBox.numColumns, std::size(listBox.columnInfo));
|
||||||
|
for (size_t columnIndex = 0u; columnIndex < columnCount; columnIndex++)
|
||||||
{
|
{
|
||||||
|
const auto& column = listBox.columnInfo[columnIndex];
|
||||||
|
|
||||||
Indent();
|
Indent();
|
||||||
for (auto i = 0u; i < MENU_KEY_SPACING; i++)
|
for (auto i = 0u; i < MENU_KEY_SPACING; i++)
|
||||||
m_stream << " ";
|
m_stream << " ";
|
||||||
|
|
||||||
m_stream << listBox->columnInfo[col].xpos << " " << listBox->columnInfo[col].ypos << " " << listBox->columnInfo[col].width << " "
|
m_stream << column.xpos << " " << column.ypos << " " << column.width << " " << column.height << " " << column.maxChars << " "
|
||||||
<< listBox->columnInfo[col].height << " " << listBox->columnInfo[col].maxChars << " " << listBox->columnInfo[col].alignment << "\n";
|
<< column.alignment << "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteListBoxProperties(const itemDef_s* item)
|
void WriteListBoxProperties(const itemDef_s& item)
|
||||||
{
|
{
|
||||||
if (item->type != ITEM_TYPE_LISTBOX || item->typeData.listBox == nullptr)
|
if (item.type != ITEM_TYPE_LISTBOX || !item.typeData.listBox)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const auto* listBox = item->typeData.listBox;
|
const auto& listBox = *item.typeData.listBox;
|
||||||
WriteKeywordProperty("notselectable", listBox->notselectable != 0);
|
WriteKeywordProperty("notselectable", listBox.notselectable != 0);
|
||||||
WriteKeywordProperty("noscrollbars", listBox->noScrollBars != 0);
|
WriteKeywordProperty("noscrollbars", listBox.noScrollBars != 0);
|
||||||
WriteKeywordProperty("usepaging", listBox->usePaging != 0);
|
WriteKeywordProperty("usepaging", listBox.usePaging != 0);
|
||||||
WriteFloatProperty("elementwidth", listBox->elementWidth, 0.0f);
|
WriteFloatProperty("elementwidth", listBox.elementWidth, 0.0f);
|
||||||
WriteFloatProperty("elementheight", listBox->elementHeight, 0.0f);
|
WriteFloatProperty("elementheight", listBox.elementHeight, 0.0f);
|
||||||
WriteFloatProperty("feeder", item->special, 0.0f);
|
WriteFloatProperty("feeder", item.special, 0.0f);
|
||||||
WriteIntProperty("elementtype", listBox->elementStyle, 0);
|
WriteIntProperty("elementtype", listBox.elementStyle, 0);
|
||||||
WriteColumnProperty("columns", listBox);
|
WriteColumnProperty(listBox);
|
||||||
WriteMenuEventHandlerSetProperty("doubleclick", listBox->onDoubleClick);
|
WriteMenuEventHandlerSetProperty("doubleclick", listBox.onDoubleClick);
|
||||||
WriteColorProperty("selectBorder", listBox->selectBorder, COLOR_0000);
|
WriteColorProperty("selectBorder", listBox.selectBorder, COLOR_0000);
|
||||||
WriteMaterialProperty("selectIcon", listBox->selectIcon);
|
WriteMaterialProperty("selectIcon", listBox.selectIcon);
|
||||||
WriteStatementProperty("exp elementheight", listBox->elementHeightExp, false);
|
WriteStatementProperty("exp elementheight", listBox.elementHeightExp, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteDvarFloatProperty(const std::string& propertyKey, const itemDef_s* item, const editFieldDef_s* editField) const
|
void WriteDvarFloatProperty(const itemDef_s& item, const editFieldDef_s& editField) const
|
||||||
{
|
{
|
||||||
if (item->dvar == nullptr)
|
if (!item.dvar)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Indent();
|
Indent();
|
||||||
WriteKey(propertyKey);
|
WriteKey("dvarFloat");
|
||||||
m_stream << "\"" << item->dvar << "\" " << editField->stepVal << " " << editField->minVal << " " << editField->maxVal << "\n";
|
WriteEscapedString(item.dvar);
|
||||||
|
m_stream << " " << editField.stepVal << " " << editField.minVal << " " << editField.maxVal << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteEditFieldProperties(const itemDef_s* item) const
|
void WriteEditFieldProperties(const itemDef_s& item) const
|
||||||
{
|
{
|
||||||
switch (item->type)
|
switch (item.type)
|
||||||
{
|
{
|
||||||
case ITEM_TYPE_TEXT:
|
case ITEM_TYPE_TEXT:
|
||||||
case ITEM_TYPE_EDITFIELD:
|
case ITEM_TYPE_EDITFIELD:
|
||||||
@@ -722,155 +727,160 @@ namespace
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item->typeData.editField == nullptr)
|
if (!item.typeData.editField)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const auto* editField = item->typeData.editField;
|
const auto& editField = *item.typeData.editField;
|
||||||
if (std::fabs(-1.0f - editField->stepVal) >= std::numeric_limits<float>::epsilon()
|
if (std::fabs(-1.0f - editField.stepVal) >= std::numeric_limits<float>::epsilon()
|
||||||
|| std::fabs(-1.0f - editField->minVal) >= std::numeric_limits<float>::epsilon()
|
|| std::fabs(-1.0f - editField.minVal) >= std::numeric_limits<float>::epsilon()
|
||||||
|| std::fabs(-1.0f - editField->maxVal) >= std::numeric_limits<float>::epsilon())
|
|| std::fabs(-1.0f - editField.maxVal) >= std::numeric_limits<float>::epsilon())
|
||||||
{
|
{
|
||||||
WriteDvarFloatProperty("dvarFloat", item, editField);
|
WriteDvarFloatProperty(item, editField);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WriteStringProperty("dvar", item->dvar);
|
WriteStringProperty("dvar", item.dvar);
|
||||||
}
|
}
|
||||||
WriteStringProperty("localvar", item->localVar);
|
WriteStringProperty("localvar", item.localVar);
|
||||||
WriteIntProperty("maxChars", editField->maxChars, 0);
|
WriteIntProperty("maxChars", editField.maxChars, 0);
|
||||||
WriteKeywordProperty("maxCharsGotoNext", editField->maxCharsGotoNext != 0);
|
WriteKeywordProperty("maxCharsGotoNext", editField.maxCharsGotoNext != 0);
|
||||||
WriteIntProperty("maxPaintChars", editField->maxPaintChars, 0);
|
WriteIntProperty("maxPaintChars", editField.maxPaintChars, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteMultiValueProperty(const multiDef_s* multiDef) const
|
void WriteMultiValueProperty(const multiDef_s& multi) const
|
||||||
{
|
{
|
||||||
Indent();
|
Indent();
|
||||||
if (multiDef->strDef)
|
WriteKey(multi.strDef ? "dvarStrList" : "dvarFloatList");
|
||||||
WriteKey("dvarStrList");
|
|
||||||
else
|
|
||||||
WriteKey("dvarFloatList");
|
|
||||||
|
|
||||||
m_stream << "{";
|
m_stream << "{";
|
||||||
for (auto i = 0; i < multiDef->count; i++)
|
const auto valueCount = std::min<size_t>(multi.count, std::size(multi.dvarValue));
|
||||||
|
for (size_t valueIndex = 0u; valueIndex < valueCount; valueIndex++)
|
||||||
{
|
{
|
||||||
if (multiDef->dvarList[i] == nullptr || multiDef->strDef && multiDef->dvarStr[i] == nullptr)
|
if (!multi.dvarList[valueIndex] || (multi.strDef && !multi.dvarStr[valueIndex]))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
m_stream << " \"" << multiDef->dvarList[i] << "\"";
|
m_stream << " ";
|
||||||
|
WriteEscapedString(multi.dvarList[valueIndex]);
|
||||||
if (multiDef->strDef)
|
m_stream << " ";
|
||||||
m_stream << " \"" << multiDef->dvarStr[i] << "\"";
|
if (multi.strDef)
|
||||||
|
WriteEscapedString(multi.dvarStr[valueIndex]);
|
||||||
else
|
else
|
||||||
m_stream << " " << multiDef->dvarValue[i] << "";
|
m_stream << multi.dvarValue[valueIndex];
|
||||||
}
|
}
|
||||||
m_stream << " }\n";
|
m_stream << " }\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteMultiProperties(const itemDef_s* item) const
|
void WriteMultiProperties(const itemDef_s& item) const
|
||||||
{
|
{
|
||||||
if (item->type != ITEM_TYPE_MULTI || item->typeData.multi == nullptr)
|
if (item.type != ITEM_TYPE_MULTI || !item.typeData.multi)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const auto* multiDef = item->typeData.multi;
|
WriteStringProperty("dvar", item.dvar);
|
||||||
|
WriteStringProperty("localvar", item.localVar);
|
||||||
if (multiDef->count <= 0)
|
WriteMultiValueProperty(*item.typeData.multi);
|
||||||
return;
|
|
||||||
|
|
||||||
WriteStringProperty("dvar", item->dvar);
|
|
||||||
WriteStringProperty("localvar", item->localVar);
|
|
||||||
WriteMultiValueProperty(multiDef);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteEnumDvarProperties(const itemDef_s* item) const
|
void WriteEnumDvarProperties(const itemDef_s& item) const
|
||||||
{
|
{
|
||||||
if (item->type != ITEM_TYPE_DVARENUM)
|
if (item.type != ITEM_TYPE_DVARENUM)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
WriteStringProperty("dvar", item->dvar);
|
WriteStringProperty("dvar", item.dvar);
|
||||||
WriteStringProperty("localvar", item->localVar);
|
WriteStringProperty("localvar", item.localVar);
|
||||||
WriteStringProperty("dvarEnumList", item->typeData.enumDvarName);
|
WriteStringProperty("dvarEnumList", item.typeData.enumDvarName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteTickerProperties(const itemDef_s* item) const
|
void WriteTickerProperties(const itemDef_s& item) const
|
||||||
{
|
{
|
||||||
if (item->type != ITEM_TYPE_NEWS_TICKER || item->typeData.ticker == nullptr)
|
if (item.type != ITEM_TYPE_NEWS_TICKER || !item.typeData.ticker)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const auto* newsTickerDef = item->typeData.ticker;
|
const auto* newsTickerDef = item.typeData.ticker;
|
||||||
WriteIntProperty("spacing", newsTickerDef->spacing, 0);
|
WriteIntProperty("spacing", newsTickerDef->spacing, 0);
|
||||||
WriteIntProperty("speed", newsTickerDef->speed, 0);
|
WriteIntProperty("speed", newsTickerDef->speed, 0);
|
||||||
WriteIntProperty("newsfeed", newsTickerDef->feedId, 0);
|
WriteIntProperty("newsfeed", newsTickerDef->feedId, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteItemData(const itemDef_s* item)
|
void WriteItemTextProperty(const char* text) const
|
||||||
{
|
{
|
||||||
WriteStringProperty("name", item->window.name);
|
// This distinguishes explicitly empty text from null text, which falls back to the item's dvar.
|
||||||
WriteStringProperty("text", item->text);
|
if (!text)
|
||||||
WriteKeywordProperty("textsavegame", item->itemFlags & ITEM_FLAG_SAVE_GAME_INFO);
|
return;
|
||||||
WriteKeywordProperty("textcinematicsubtitle", item->itemFlags & ITEM_FLAG_CINEMATIC_SUBTITLE);
|
|
||||||
WriteStringProperty("group", item->window.group);
|
|
||||||
WriteRectProperty("rect", item->window.rectClient);
|
|
||||||
WriteIntProperty("style", item->window.style, 0);
|
|
||||||
WriteKeywordProperty("decoration", item->window.staticFlags & WINDOW_FLAG_DECORATION);
|
|
||||||
WriteKeywordProperty("autowrapped", item->window.staticFlags & WINDOW_FLAG_AUTO_WRAPPED);
|
|
||||||
WriteKeywordProperty("horizontalscroll", item->window.staticFlags & WINDOW_FLAG_HORIZONTAL_SCROLL);
|
|
||||||
WriteIntProperty("type", item->type, ITEM_TYPE_TEXT);
|
|
||||||
WriteIntProperty("border", item->window.border, 0);
|
|
||||||
WriteFloatProperty("borderSize", item->window.borderSize, 0.0f);
|
|
||||||
|
|
||||||
if (item->visibleExp)
|
Indent();
|
||||||
WriteStatementProperty("visible", item->visibleExp, true);
|
WriteKey("text");
|
||||||
else if (item->window.dynamicFlags[0] & WINDOW_FLAG_VISIBLE)
|
WriteEscapedString(text);
|
||||||
|
m_stream << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteItemData(const itemDef_s& item)
|
||||||
|
{
|
||||||
|
WriteStringProperty("name", item.window.name);
|
||||||
|
WriteItemTextProperty(item.text);
|
||||||
|
WriteKeywordProperty("textsavegame", item.itemFlags & ITEM_FLAG_SAVE_GAME_INFO);
|
||||||
|
WriteKeywordProperty("textcinematicsubtitle", item.itemFlags & ITEM_FLAG_CINEMATIC_SUBTITLE);
|
||||||
|
WriteStringProperty("group", item.window.group);
|
||||||
|
WriteRectProperty("rect", item.window.rectClient);
|
||||||
|
WriteIntProperty("style", item.window.style, 0);
|
||||||
|
WriteKeywordProperty("decoration", item.window.staticFlags & WINDOW_FLAG_DECORATION);
|
||||||
|
WriteKeywordProperty("autowrapped", item.window.staticFlags & WINDOW_FLAG_AUTO_WRAPPED);
|
||||||
|
WriteKeywordProperty("horizontalscroll", item.window.staticFlags & WINDOW_FLAG_HORIZONTAL_SCROLL);
|
||||||
|
WriteIntProperty("type", item.type, ITEM_TYPE_TEXT);
|
||||||
|
WriteIntProperty("border", item.window.border, 0);
|
||||||
|
WriteFloatProperty("borderSize", item.window.borderSize, 0.0f);
|
||||||
|
|
||||||
|
if (HasStatement(item.visibleExp))
|
||||||
|
WriteStatementProperty("visible", item.visibleExp, true);
|
||||||
|
else if (item.window.dynamicFlags[0] & WINDOW_FLAG_VISIBLE)
|
||||||
WriteIntProperty("visible", 1, 0);
|
WriteIntProperty("visible", 1, 0);
|
||||||
|
|
||||||
WriteStatementProperty("disabled", item->disabledExp, true);
|
WriteStatementProperty("disabled", item.disabledExp, true);
|
||||||
WriteIntProperty("ownerdraw", item->window.ownerDraw, 0);
|
WriteIntProperty("ownerdraw", item.window.ownerDraw, 0);
|
||||||
WriteFlagsProperty("ownerdrawFlag", item->window.ownerDrawFlags);
|
WriteFlagsProperty("ownerdrawFlag", item.window.ownerDrawFlags);
|
||||||
WriteIntProperty("align", item->alignment, 0);
|
WriteIntProperty("align", item.alignment, 0);
|
||||||
WriteIntProperty("textalign", item->textAlignMode, 0);
|
WriteIntProperty("textalign", item.textAlignMode, 0);
|
||||||
WriteFloatProperty("textalignx", item->textalignx, 0.0f);
|
WriteFloatProperty("textalignx", item.textalignx, 0.0f);
|
||||||
WriteFloatProperty("textaligny", item->textaligny, 0.0f);
|
WriteFloatProperty("textaligny", item.textaligny, 0.0f);
|
||||||
WriteFloatProperty("textscale", item->textscale, 0.0f);
|
WriteFloatProperty("textscale", item.textscale, 0.0f);
|
||||||
WriteIntProperty("textstyle", item->textStyle, 0);
|
WriteIntProperty("textstyle", item.textStyle, 0);
|
||||||
WriteIntProperty("textfont", item->fontEnum, 0);
|
WriteIntProperty("textfont", item.fontEnum, 0);
|
||||||
WriteColorProperty("backcolor", item->window.backColor, COLOR_0000);
|
WriteColorProperty("backcolor", item.window.backColor, COLOR_0000);
|
||||||
WriteColorProperty("forecolor", item->window.foreColor, COLOR_1111);
|
WriteColorProperty("forecolor", item.window.foreColor, COLOR_1111);
|
||||||
WriteColorProperty("bordercolor", item->window.borderColor, COLOR_0000);
|
WriteColorProperty("bordercolor", item.window.borderColor, COLOR_0000);
|
||||||
WriteColorProperty("outlinecolor", item->window.outlineColor, COLOR_0000);
|
WriteColorProperty("outlinecolor", item.window.outlineColor, COLOR_0000);
|
||||||
WriteColorProperty("disablecolor", item->window.disableColor, COLOR_0000);
|
WriteColorProperty("disablecolor", item.window.disableColor, COLOR_0000);
|
||||||
WriteColorProperty("glowcolor", item->glowColor, COLOR_0000);
|
WriteColorProperty("glowcolor", item.glowColor, COLOR_0000);
|
||||||
WriteMaterialProperty("background", item->window.background);
|
WriteMaterialProperty("background", item.window.background);
|
||||||
WriteMenuEventHandlerSetProperty("onFocus", item->onFocus);
|
WriteMenuEventHandlerSetProperty("onFocus", item.onFocus);
|
||||||
WriteMenuEventHandlerSetProperty("hasFocus", item->hasFocus);
|
WriteMenuEventHandlerSetProperty("hasFocus", item.hasFocus);
|
||||||
WriteMenuEventHandlerSetProperty("leaveFocus", item->leaveFocus);
|
WriteMenuEventHandlerSetProperty("leaveFocus", item.leaveFocus);
|
||||||
WriteMenuEventHandlerSetProperty("mouseEnter", item->mouseEnter);
|
WriteMenuEventHandlerSetProperty("mouseEnter", item.mouseEnter);
|
||||||
WriteMenuEventHandlerSetProperty("mouseExit", item->mouseExit);
|
WriteMenuEventHandlerSetProperty("mouseExit", item.mouseExit);
|
||||||
WriteMenuEventHandlerSetProperty("mouseEnterText", item->mouseEnterText);
|
WriteMenuEventHandlerSetProperty("mouseEnterText", item.mouseEnterText);
|
||||||
WriteMenuEventHandlerSetProperty("mouseExitText", item->mouseExitText);
|
WriteMenuEventHandlerSetProperty("mouseExitText", item.mouseExitText);
|
||||||
WriteMenuEventHandlerSetProperty("action", item->action);
|
WriteMenuEventHandlerSetProperty("action", item.action);
|
||||||
WriteMenuEventHandlerSetProperty("accept", item->accept);
|
WriteMenuEventHandlerSetProperty("accept", item.onAccept);
|
||||||
// WriteFloatProperty("special", item->special, 0.0f);
|
// WriteFloatProperty("special", item.special, 0.0f);
|
||||||
WriteSoundAliasProperty("focusSound", item->focusSound);
|
WriteSoundAliasProperty("focusSound", item.focusSound);
|
||||||
WriteStringProperty("dvarTest", item->dvarTest);
|
WriteStringProperty("dvarTest", item.dvarTest);
|
||||||
|
|
||||||
if (item->dvarFlags & ITEM_DVAR_FLAG_ENABLE)
|
if (item.dvarFlags & ITEM_DVAR_FLAG_ENABLE)
|
||||||
WriteMultiTokenStringProperty("enableDvar", item->enableDvar);
|
WriteMultiTokenStringProperty("enableDvar", item.enableDvar);
|
||||||
else if (item->dvarFlags & ITEM_DVAR_FLAG_DISABLE)
|
else if (item.dvarFlags & ITEM_DVAR_FLAG_DISABLE)
|
||||||
WriteMultiTokenStringProperty("disableDvar", item->enableDvar);
|
WriteMultiTokenStringProperty("disableDvar", item.enableDvar);
|
||||||
else if (item->dvarFlags & ITEM_DVAR_FLAG_SHOW)
|
else if (item.dvarFlags & ITEM_DVAR_FLAG_SHOW)
|
||||||
WriteMultiTokenStringProperty("showDvar", item->enableDvar);
|
WriteMultiTokenStringProperty("showDvar", item.enableDvar);
|
||||||
else if (item->dvarFlags & ITEM_DVAR_FLAG_HIDE)
|
else if (item.dvarFlags & ITEM_DVAR_FLAG_HIDE)
|
||||||
WriteMultiTokenStringProperty("hideDvar", item->enableDvar);
|
WriteMultiTokenStringProperty("hideDvar", item.enableDvar);
|
||||||
else if (item->dvarFlags & ITEM_DVAR_FLAG_FOCUS)
|
else if (item.dvarFlags & ITEM_DVAR_FLAG_FOCUS)
|
||||||
WriteMultiTokenStringProperty("focusDvar", item->enableDvar);
|
WriteMultiTokenStringProperty("focusDvar", item.enableDvar);
|
||||||
|
|
||||||
WriteItemKeyHandlerProperty(item->onKey);
|
WriteItemKeyHandlers(item.onKey);
|
||||||
WriteStatementProperty("exp text", item->textExp, false);
|
WriteStatementProperty("exp text", item.textExp, false);
|
||||||
WriteStatementProperty("exp textaligny", item->textAlignYExp, false);
|
WriteStatementProperty("exp textaligny", item.textAlignYExp, false);
|
||||||
WriteStatementProperty("exp material", item->materialExp, false);
|
WriteStatementProperty("exp material", item.materialExp, false);
|
||||||
WriteFloatExpressionsProperty(item->floatExpressions, item->floatExpressionCount);
|
WriteFloatExpressionsProperty(item.floatExpressions, item.floatExpressionCount);
|
||||||
WriteIntProperty("gamemsgwindowindex", item->gameMsgWindowIndex, 0);
|
WriteIntProperty("gamemsgwindowindex", item.gameMsgWindowIndex, 0);
|
||||||
WriteIntProperty("gamemsgwindowmode", item->gameMsgWindowMode, 0);
|
WriteIntProperty("gamemsgwindowmode", item.gameMsgWindowMode, 0);
|
||||||
WriteDecodeEffectProperty("decodeEffect", item);
|
WriteDecodeEffectProperty("decodeEffect", item);
|
||||||
|
|
||||||
WriteListBoxProperties(item);
|
WriteListBoxProperties(item);
|
||||||
@@ -880,70 +890,75 @@ namespace
|
|||||||
WriteTickerProperties(item);
|
WriteTickerProperties(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteItemDefs(const itemDef_s* const* itemDefs, size_t itemCount)
|
void WriteItemDefs(const itemDef_s* const* items, const size_t itemCount)
|
||||||
{
|
{
|
||||||
for (auto i = 0u; i < itemCount; i++)
|
if (!items || itemCount <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (size_t itemIndex = 0u; itemIndex < itemCount; itemIndex++)
|
||||||
{
|
{
|
||||||
|
const auto* item = items[itemIndex];
|
||||||
|
if (!item)
|
||||||
|
continue;
|
||||||
|
|
||||||
StartItemDefScope();
|
StartItemDefScope();
|
||||||
|
WriteItemData(*item);
|
||||||
WriteItemData(itemDefs[i]);
|
|
||||||
|
|
||||||
EndScope();
|
EndScope();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteMenuData(const menuDef_t* menu)
|
void WriteMenuData(const menuDef_t& menu)
|
||||||
{
|
{
|
||||||
WriteStringProperty("name", menu->window.name);
|
WriteStringProperty("name", menu.window.name);
|
||||||
WriteBoolProperty("fullscreen", menu->data->fullScreen, false);
|
WriteBoolProperty("fullscreen", menu.data->fullScreen, false);
|
||||||
WriteKeywordProperty("screenSpace", menu->window.staticFlags & WINDOW_FLAG_SCREEN_SPACE);
|
WriteKeywordProperty("screenSpace", menu.window.staticFlags & WINDOW_FLAG_SCREEN_SPACE);
|
||||||
WriteKeywordProperty("decoration", menu->window.staticFlags & WINDOW_FLAG_DECORATION);
|
WriteKeywordProperty("decoration", menu.window.staticFlags & WINDOW_FLAG_DECORATION);
|
||||||
WriteRectProperty("rect", menu->window.rect);
|
WriteRectProperty("rect", menu.window.rect);
|
||||||
WriteIntProperty("style", menu->window.style, 0);
|
WriteIntProperty("style", menu.window.style, 0);
|
||||||
WriteIntProperty("border", menu->window.border, 0);
|
WriteIntProperty("border", menu.window.border, 0);
|
||||||
WriteFloatProperty("borderSize", menu->window.borderSize, 0.0f);
|
WriteFloatProperty("borderSize", menu.window.borderSize, 0.0f);
|
||||||
WriteColorProperty("backcolor", menu->window.backColor, COLOR_0000);
|
WriteColorProperty("backcolor", menu.window.backColor, COLOR_0000);
|
||||||
WriteColorProperty("forecolor", menu->window.foreColor, COLOR_1111);
|
WriteColorProperty("forecolor", menu.window.foreColor, COLOR_1111);
|
||||||
WriteColorProperty("bordercolor", menu->window.borderColor, COLOR_0000);
|
WriteColorProperty("bordercolor", menu.window.borderColor, COLOR_0000);
|
||||||
WriteColorProperty("focuscolor", menu->data->focusColor, COLOR_0000);
|
WriteColorProperty("focuscolor", menu.data->focusColor, COLOR_0000);
|
||||||
WriteColorProperty("outlinecolor", menu->window.outlineColor, COLOR_0000);
|
WriteColorProperty("outlinecolor", menu.window.outlineColor, COLOR_0000);
|
||||||
WriteMaterialProperty("background", menu->window.background);
|
WriteMaterialProperty("background", menu.window.background);
|
||||||
WriteIntProperty("ownerdraw", menu->window.ownerDraw, 0);
|
WriteIntProperty("ownerdraw", menu.window.ownerDraw, 0);
|
||||||
WriteFlagsProperty("ownerdrawFlag", menu->window.ownerDrawFlags);
|
WriteFlagsProperty("ownerdrawFlag", menu.window.ownerDrawFlags);
|
||||||
WriteKeywordProperty("outOfBoundsClick", menu->window.staticFlags & WINDOW_FLAG_OUT_OF_BOUNDS_CLICK);
|
WriteKeywordProperty("outOfBoundsClick", menu.window.staticFlags & WINDOW_FLAG_OUT_OF_BOUNDS_CLICK);
|
||||||
WriteStringProperty("soundLoop", menu->data->soundName);
|
WriteStringProperty("soundLoop", menu.data->soundName);
|
||||||
WriteKeywordProperty("popup", menu->window.staticFlags & WINDOW_FLAG_POPUP);
|
WriteKeywordProperty("popup", menu.window.staticFlags & WINDOW_FLAG_POPUP);
|
||||||
WriteFloatProperty("fadeClamp", menu->data->fadeClamp, 0.0f);
|
WriteFloatProperty("fadeClamp", menu.data->fadeClamp, 0.0f);
|
||||||
WriteIntProperty("fadeCycle", menu->data->fadeCycle, 0);
|
WriteIntProperty("fadeCycle", menu.data->fadeCycle, 0);
|
||||||
WriteFloatProperty("fadeAmount", menu->data->fadeAmount, 0.0f);
|
WriteFloatProperty("fadeAmount", menu.data->fadeAmount, 0.0f);
|
||||||
WriteFloatProperty("fadeInAmount", menu->data->fadeInAmount, 0.0f);
|
WriteFloatProperty("fadeInAmount", menu.data->fadeInAmount, 0.0f);
|
||||||
WriteFloatProperty("blurWorld", menu->data->blurRadius, 0.0f);
|
WriteFloatProperty("blurWorld", menu.data->blurRadius, 0.0f);
|
||||||
WriteKeywordProperty("legacySplitScreenScale", menu->window.staticFlags & WINDOW_FLAG_LEGACY_SPLIT_SCREEN_SCALE);
|
WriteKeywordProperty("legacySplitScreenScale", menu.window.staticFlags & WINDOW_FLAG_LEGACY_SPLIT_SCREEN_SCALE);
|
||||||
WriteKeywordProperty("hiddenDuringScope", menu->window.staticFlags & WINDOW_FLAG_HIDDEN_DURING_SCOPE);
|
WriteKeywordProperty("hiddenDuringScope", menu.window.staticFlags & WINDOW_FLAG_HIDDEN_DURING_SCOPE);
|
||||||
WriteKeywordProperty("hiddenDuringFlashbang", menu->window.staticFlags & WINDOW_FLAG_HIDDEN_DURING_FLASH_BANG);
|
WriteKeywordProperty("hiddenDuringFlashbang", menu.window.staticFlags & WINDOW_FLAG_HIDDEN_DURING_FLASH_BANG);
|
||||||
WriteKeywordProperty("hiddenDuringUI", menu->window.staticFlags & WINDOW_FLAG_HIDDEN_DURING_UI);
|
WriteKeywordProperty("hiddenDuringUI", menu.window.staticFlags & WINDOW_FLAG_HIDDEN_DURING_UI);
|
||||||
WriteStringProperty("allowedBinding", menu->data->allowedBinding);
|
WriteStringProperty("allowedBinding", menu.data->allowedBinding);
|
||||||
WriteKeywordProperty("textOnlyFocus", menu->window.staticFlags & WINDOW_FLAG_TEXT_ONLY_FOCUS);
|
WriteKeywordProperty("textOnlyFocus", menu.window.staticFlags & WINDOW_FLAG_TEXT_ONLY_FOCUS);
|
||||||
|
|
||||||
if (menu->data->visibleExp)
|
if (HasStatement(menu.data->visibleExp))
|
||||||
WriteStatementProperty("visible", menu->data->visibleExp, true);
|
WriteStatementProperty("visible", menu.data->visibleExp, true);
|
||||||
else if (menu->window.dynamicFlags[0] & WINDOW_FLAG_VISIBLE)
|
else if (menu.window.dynamicFlags[0] & WINDOW_FLAG_VISIBLE)
|
||||||
WriteIntProperty("visible", 1, 0);
|
WriteIntProperty("visible", 1, 0);
|
||||||
|
|
||||||
WriteStatementProperty("exp rect X", menu->data->rectXExp, false);
|
WriteStatementProperty("exp rect X", menu.data->rectXExp, false);
|
||||||
WriteStatementProperty("exp rect Y", menu->data->rectYExp, false);
|
WriteStatementProperty("exp rect Y", menu.data->rectYExp, false);
|
||||||
WriteStatementProperty("exp rect W", menu->data->rectWExp, false);
|
WriteStatementProperty("exp rect W", menu.data->rectWExp, false);
|
||||||
WriteStatementProperty("exp rect H", menu->data->rectHExp, false);
|
WriteStatementProperty("exp rect H", menu.data->rectHExp, false);
|
||||||
WriteStatementProperty("exp openSound", menu->data->openSoundExp, false);
|
WriteStatementProperty("exp openSound", menu.data->openSoundExp, false);
|
||||||
WriteStatementProperty("exp closeSound", menu->data->closeSoundExp, false);
|
WriteStatementProperty("exp closeSound", menu.data->closeSoundExp, false);
|
||||||
WriteStatementProperty("exp soundLoop", menu->data->soundLoopExp, false);
|
WriteStatementProperty("exp soundLoop", menu.data->soundLoopExp, false);
|
||||||
WriteMenuEventHandlerSetProperty("onOpen", menu->data->onOpen);
|
WriteMenuEventHandlerSetProperty("onOpen", menu.data->onOpen);
|
||||||
WriteMenuEventHandlerSetProperty("onClose", menu->data->onClose);
|
WriteMenuEventHandlerSetProperty("onClose", menu.data->onClose);
|
||||||
WriteMenuEventHandlerSetProperty("onRequestClose", menu->data->onCloseRequest);
|
WriteMenuEventHandlerSetProperty("onRequestClose", menu.data->onCloseRequest);
|
||||||
WriteMenuEventHandlerSetProperty("onESC", menu->data->onESC);
|
WriteMenuEventHandlerSetProperty("onESC", menu.data->onESC);
|
||||||
WriteMenuEventHandlerSetProperty("onFocusDueToClose", menu->data->onFocusDueToClose);
|
WriteMenuEventHandlerSetProperty("onFocusDueToClose", menu.data->onFocusDueToClose);
|
||||||
WriteItemKeyHandlerProperty(menu->data->onKey);
|
WriteItemKeyHandlers(menu.data->onKey);
|
||||||
WriteItemDefs(menu->items, menu->itemCount);
|
WriteItemDefs(menu.items, menu.itemCount);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
Reference in New Issue
Block a user