994 lines
24 KiB
C++
994 lines
24 KiB
C++
// ======================= ZoneTool =======================
|
|
// zonetool, a fastfile linker for various
|
|
// Call of Duty titles.
|
|
//
|
|
// Project: https://github.com/ZoneTool/zonetool
|
|
// Author: aerosoul (https://github.com/aerosoul94)
|
|
// License: GNU GPL v3.0
|
|
// ========================================================
|
|
#include "stdafx.hpp"
|
|
|
|
namespace ZoneTool
|
|
{
|
|
namespace IW4
|
|
{
|
|
void IMenuDef::init(const std::string& name, ZoneMemory* mem)
|
|
{
|
|
this->name_ = name;
|
|
this->asset_ = DB_FindXAssetHeader(this->type(), this->name().data()).menu;
|
|
}
|
|
|
|
std::string IMenuDef::name()
|
|
{
|
|
return this->name_;
|
|
}
|
|
|
|
std::int32_t IMenuDef::type()
|
|
{
|
|
return menu;
|
|
}
|
|
|
|
int IMenuDef::indentCounter = 0;
|
|
FILE* IMenuDef::fp = nullptr;
|
|
|
|
static const char* g_expOperatorNames[]
|
|
{
|
|
"NOOP",
|
|
")",
|
|
"*",
|
|
"/",
|
|
"%",
|
|
"+",
|
|
"-",
|
|
"!",
|
|
"<",
|
|
"<=",
|
|
">",
|
|
">=",
|
|
"==",
|
|
"!=",
|
|
"&&",
|
|
"||",
|
|
"(",
|
|
",",
|
|
"&",
|
|
"|",
|
|
"~",
|
|
"<<",
|
|
">>",
|
|
"dvarint(static)",
|
|
"dvarbool(static)",
|
|
"dvarfloat(static)",
|
|
"dvarstring(static)",
|
|
"int",
|
|
"string",
|
|
"float",
|
|
"sin",
|
|
"cos",
|
|
"min",
|
|
"max",
|
|
"milliseconds",
|
|
"dvarint",
|
|
"dvarbool",
|
|
"dvarfloat",
|
|
"dvarstring",
|
|
"stat",
|
|
"ui_active",
|
|
"flashbanged",
|
|
"usingvehicle",
|
|
"missilecam",
|
|
"scoped",
|
|
"scopedthermal",
|
|
"scoreboard_visible",
|
|
"inkillcam",
|
|
"inkillcamnpc",
|
|
"player",
|
|
"getperk",
|
|
"selecting_location",
|
|
"selecting_direction",
|
|
"team",
|
|
"otherteam",
|
|
"marinesfield",
|
|
"opforfield",
|
|
"menuisopen",
|
|
"writingdata",
|
|
"inlobby",
|
|
"inprivateparty",
|
|
"privatepartyhost",
|
|
"privatepartyhostinlobby",
|
|
"aloneinparty",
|
|
"adsjavelin",
|
|
"weaplockblink",
|
|
"weapattacktop",
|
|
"weapattackdirect",
|
|
"weaplocking",
|
|
"weaplocked",
|
|
"weaplocktooclose",
|
|
"weaplockscreenposx",
|
|
"weaplockscreenposy",
|
|
"secondsastime",
|
|
"tablelookup",
|
|
"tablelookupbyrow",
|
|
"tablegetrownum",
|
|
"locstring",
|
|
"localvarint",
|
|
"localvarbool",
|
|
"localvarfloat",
|
|
"localvarstring",
|
|
"timeleft",
|
|
"secondsascountdown",
|
|
"gamemsgwndactive",
|
|
"gametypename",
|
|
"gametype",
|
|
"gametypedescription",
|
|
"scoreatrank",
|
|
"friendsonline",
|
|
"spectatingclient",
|
|
"spectatingfree",
|
|
"statrangeanybitsset",
|
|
"keybinding",
|
|
"actionslotusable",
|
|
"hudfade",
|
|
"maxrecommendedplayers",
|
|
"acceptinginvite",
|
|
"isintermission",
|
|
"gamehost",
|
|
"partyismissingmappack",
|
|
"partymissingmappackerror",
|
|
"anynewmappacks",
|
|
"amiselected",
|
|
"partystatusstring",
|
|
"attachedcontrollercount",
|
|
"issplitscreenonlinepossible",
|
|
"splitscreenplayercount",
|
|
"getplayerdata",
|
|
"getplayerdatasplitscreen",
|
|
"experienceforlevel",
|
|
"levelforexperience",
|
|
"isitemunlocked",
|
|
"isitemunlockedsplitscreen",
|
|
"debugprint",
|
|
"getplayerdataanybooltrue",
|
|
"weaponclassnew",
|
|
"weaponname",
|
|
"isreloading",
|
|
"savegameavailable",
|
|
"unlockeditemcount",
|
|
"unlockeditemcountsplitscreen",
|
|
"unlockeditem",
|
|
"unlockeditemsplitscreen",
|
|
"mailsubject",
|
|
"mailfrom",
|
|
"mailreceived",
|
|
"mailbody",
|
|
"maillootlocalized",
|
|
"mailgivesloot",
|
|
"anynewmail",
|
|
"mailtimetofollowup",
|
|
"mailloottype",
|
|
"mailranlottery",
|
|
"lotterylootlocalized",
|
|
"radarisjammed",
|
|
"radarjamintensity",
|
|
"radarisenabled",
|
|
"isempjammed",
|
|
"playerads",
|
|
"weaponheatactive",
|
|
"weaponheatvalue",
|
|
"weaponheatoverheated",
|
|
"getsplashtext",
|
|
"getsplashdescription",
|
|
"getsplashmaterial",
|
|
"splashhasicon",
|
|
"splashrownum",
|
|
"getfocuseditemname",
|
|
"getfocuseditemx",
|
|
"getfocuseditemy",
|
|
"getfocuseditemwidth",
|
|
"getfocuseditemheight",
|
|
"getitemx",
|
|
"getitemy",
|
|
"getitemwidth",
|
|
"getitemheight",
|
|
"playlist",
|
|
"scoreboardexternalmutenotice",
|
|
"getclientmatchdata",
|
|
"getclientmatchdatadef",
|
|
"getmapname",
|
|
"getmapimage",
|
|
"getmapcustom",
|
|
"getmigrationstatus",
|
|
"getplayercardinfo",
|
|
"isofflineprofileselected",
|
|
"coopplayer",
|
|
"iscoop",
|
|
"getpartystatus",
|
|
"getsearchparams",
|
|
"gettimeplayed",
|
|
"isselectedplayerfriend",
|
|
"getcharbyindex",
|
|
"getprofiledata",
|
|
"isprofilesignedin",
|
|
"getwaitpopupstatus",
|
|
"getnattype",
|
|
"getlocalizednattype",
|
|
"getadjustedsafeareahorizontal",
|
|
"getadjustedsafeareavertical",
|
|
"connectioninfo",
|
|
"offlineprofilecansave",
|
|
"allsplitscreenprofilescansave",
|
|
"allsplitscreenprofilesaresignedin",
|
|
"coopready"
|
|
};
|
|
|
|
const char* g_commandList[] =
|
|
{
|
|
"fadein",
|
|
"fadeout",
|
|
"show",
|
|
"hide",
|
|
"showMenu",
|
|
"hideMenu",
|
|
"setcolor",
|
|
"open",
|
|
"close",
|
|
"closeForAllPlayers",
|
|
"ingameopen",
|
|
"ingameclose",
|
|
"setbackground",
|
|
"setItemColor",
|
|
"focusfirst",
|
|
"setfocus",
|
|
"setfocusbydvar",
|
|
"setdvar",
|
|
"exec",
|
|
"execnow",
|
|
"execOnDvarStringValue",
|
|
"execOnDvarIntValue",
|
|
"execOnDvarFloatValue",
|
|
"execNowOnDvarStringValue",
|
|
"execNowOnDvarIntValue",
|
|
"execNowOnDvarFloatValue",
|
|
"play",
|
|
"scriptmenuresponse",
|
|
"scriptMenuRespondOnDvarStringValue",
|
|
"scriptMenuRespondOnDvarIntValue",
|
|
"scriptMenuRespondOnDvarFloatValue",
|
|
"setPlayerData",
|
|
"setPlayerDataSplitscreen",
|
|
"updateMail",
|
|
"openMail",
|
|
"deleteMail",
|
|
"doMailLottery",
|
|
"resetStatsConfirm",
|
|
"resetStatsCancel",
|
|
"setGameMode",
|
|
"setLocalVarBool",
|
|
"setLocalVarInt",
|
|
"setLocalVarFloat",
|
|
"setLocalVarString",
|
|
"feederTop",
|
|
"feederBottom",
|
|
"showGamerCard",
|
|
"openforgametype",
|
|
"closeforgametype",
|
|
"statclearperknew",
|
|
"statsetusingtable",
|
|
"statclearbitmask",
|
|
"kickPlayer",
|
|
"getKickPlayerQuestion",
|
|
"partyUpdateMissingMapPackDvar",
|
|
"getHostMigrateQuestion",
|
|
"makehost",
|
|
"togglePlayerMute",
|
|
"addFriendFromId",
|
|
"resolveError",
|
|
"lerp",
|
|
// added by me
|
|
"uiScript"
|
|
};
|
|
|
|
struct ItemFloatExpressionEntry
|
|
{
|
|
int target;
|
|
const char* s1;
|
|
const char* s2;
|
|
};
|
|
|
|
ItemFloatExpressionEntry g_itemFloatExpressions[19] =
|
|
{
|
|
{ 0, "rect", "x" },
|
|
{ 1, "rect", "y" },
|
|
{ 2, "rect", "w" },
|
|
{ 3, "rect", "h" },
|
|
{ 4, "forecolor", "r" },
|
|
{ 5, "forecolor", "g" },
|
|
{ 6, "forecolor", "b" },
|
|
{ 7, "forecolor", "rgb" },
|
|
{ 8, "forecolor", "a" },
|
|
{ 9, "glowcolor", "r" },
|
|
{ 10, "glowcolor", "g" },
|
|
{ 11, "glowcolor", "b" },
|
|
{ 12, "glowcolor", "rgb" },
|
|
{ 13, "glowcolor", "a" },
|
|
{ 14, "backcolor", "r" },
|
|
{ 15, "backcolor", "g" },
|
|
{ 16, "backcolor", "b" },
|
|
{ 17, "backcolor", "rgb" },
|
|
{ 18, "backcolor", "a" }
|
|
};
|
|
|
|
void IMenuDef::dump(menuDef_t* asset)
|
|
{
|
|
ZONETOOL_INFO("Dumping menu %s", asset->window.name);
|
|
|
|
fp = FileSystem::FileOpen("menus\\"s + asset->window.name + ".menu"s, "w");
|
|
indentCounter = 1;
|
|
|
|
if (fp)
|
|
{
|
|
emit_menu_def(asset);
|
|
}
|
|
|
|
FileSystem::FileClose(fp);
|
|
}
|
|
|
|
void IMenuDef::emit_open_brace()
|
|
{
|
|
fprintf(fp, "%s{\n", get_tabs());
|
|
}
|
|
|
|
void IMenuDef::emit_closing_brace()
|
|
{
|
|
fprintf(fp, "%s}\n", get_tabs());
|
|
}
|
|
|
|
void IMenuDef::push_indent()
|
|
{
|
|
emit_open_brace();
|
|
IMenuDef::indentCounter++;
|
|
}
|
|
|
|
void IMenuDef::pop_indent()
|
|
{
|
|
IMenuDef::indentCounter--;
|
|
emit_closing_brace();
|
|
}
|
|
|
|
void IMenuDef::emit_menu_def(menuDef_t* asset)
|
|
{
|
|
fputs("{\n\tmenuDef\n", fp);
|
|
push_indent();
|
|
|
|
emit_window_def(&asset->window, false);
|
|
emit_color("focuscolor", asset->focusColor);
|
|
emit_int("fullscreen", asset->fullscreen);
|
|
emit_float("fadeCycle", asset->fadeCycle);
|
|
emit_float("fadeClamp", asset->fadeClamp);
|
|
emit_float("fadeAmount", asset->fadeAmount);
|
|
emit_float("fadeInAmount", asset->fadeInAmount);
|
|
emit_float("blurWorld", asset->blurRadius);
|
|
emit_string("allowedBinding", asset->allowedBinding);
|
|
emit_statement("visible when", asset->visibleExp);
|
|
emit_statement("exp rect x", asset->rectXExp);
|
|
emit_statement("exp rect y", asset->rectYExp);
|
|
emit_statement("exp rect h", asset->rectHExp);
|
|
emit_statement("exp rect w", asset->rectWExp);
|
|
emit_statement("exp openSound", asset->openSoundExp);
|
|
emit_statement("exp closeSound", asset->closeSoundExp);
|
|
emit_item_key_handler("execKeyInt", asset->onKey);
|
|
emit_menu_event_handler_set("onOpen", asset->onOpen);
|
|
emit_menu_event_handler_set("onRequestClose", asset->onRequestClose);
|
|
emit_menu_event_handler_set("onClose", asset->onClose);
|
|
emit_menu_event_handler_set("onEsc", asset->onEsc);
|
|
|
|
for (auto i = 0; i < asset->itemCount; i++)
|
|
{
|
|
emit_item_def(asset->items[i]);
|
|
}
|
|
|
|
pop_indent();
|
|
fputs("}\n", fp);
|
|
}
|
|
|
|
void IMenuDef::emit_item_def(itemDef_t* item)
|
|
{
|
|
fputs("\t\titemDef\n", fp);
|
|
push_indent();
|
|
|
|
emit_window_def(&item->window, true);
|
|
emit_int("type", item->type);
|
|
emit_int("align", item->alignment);
|
|
emit_int("textfont", item->fontEnum);
|
|
emit_int("textalign", item->textAlignMode);
|
|
emit_float("textalignx", item->textAlignX);
|
|
emit_float("textaligny", item->textAlignY);
|
|
emit_float("textscale", item->textScale);
|
|
emit_color("glowColor", item->glowColor);
|
|
emit_bool("decodeEffect", item->decayActive);
|
|
|
|
if (item->type == ITEM_TYPE_GAME_MESSAGE_WINDOW)
|
|
{
|
|
emit_int("gamemsgwindowindex", item->gameMsgWindowIndex);
|
|
emit_int("gamemsgwindowmode", item->gameMsgWindowMode);
|
|
}
|
|
|
|
emit_string("text", item->text);
|
|
emit_bool("textsavegame", item->textSaveGameInfo & 1);
|
|
emit_bool("textcinematicsubtitle", item->textSaveGameInfo & 2);
|
|
emit_float("feeder", item->special);
|
|
emit_string("focusSound", item->focusSound);
|
|
|
|
if (item->type != ITEM_TYPE_SLIDER && item->type != ITEM_TYPE_DVARENUM)
|
|
{
|
|
emit_string("dvar", item->dvar);
|
|
emit_item_def_data(&item->typeData, item->type);
|
|
}
|
|
else
|
|
{
|
|
emit_item_def_data(&item->typeData, item->type);
|
|
}
|
|
|
|
emit_dvar_flags(item->dvarFlags, item->dvarTest, item->enableDvar);
|
|
emit_item_float_expressions(item->floatExpressions, item->floatExpressionCount);
|
|
emit_statement("visible when", item->visibleExp);
|
|
emit_statement("disabled when", item->disabledExp);
|
|
emit_statement("exp text", item->textExp);
|
|
emit_statement("exp material", item->materialExp);
|
|
emit_item_key_handler("execKeyInt", item->onKey);
|
|
emit_menu_event_handler_set("mouseEnterText", item->mouseEnterText);
|
|
emit_menu_event_handler_set("mouseExitText", item->mouseExitText);
|
|
emit_menu_event_handler_set("mouseEnter", item->mouseEnter);
|
|
emit_menu_event_handler_set("mouseExit", item->mouseExit);
|
|
emit_menu_event_handler_set("action", item->action);
|
|
emit_menu_event_handler_set("accept", item->accept);
|
|
emit_menu_event_handler_set("onFocus", item->onFocus);
|
|
emit_menu_event_handler_set("leaveFocus", item->leaveFocus);
|
|
|
|
pop_indent();
|
|
}
|
|
|
|
void IMenuDef::emit_window_def(windowDef_t* window, bool is_item)
|
|
{
|
|
emit_string("name", window->name);
|
|
if (is_item)
|
|
{
|
|
emit_rect("rect", window->rectClient);
|
|
}
|
|
else
|
|
{
|
|
emit_rect("rect", window->rect);
|
|
}
|
|
emit_static_flags(window->staticFlags);
|
|
emit_dynamic_flags(window->dynamicFlags);
|
|
emit_string("group", window->group);
|
|
emit_int("style", window->style);
|
|
emit_int("border", window->border);
|
|
emit_float("borderSize", window->borderSize);
|
|
emit_int("ownerdraw", window->ownerDraw);
|
|
emit_int("ownerdrawFlag", window->ownerDrawFlags);
|
|
emit_color("forecolor", window->foreColor);
|
|
emit_color("backcolor", window->backColor);
|
|
emit_color("bordercolor", window->borderColor);
|
|
emit_color("outlinecolor", window->outlineColor);
|
|
emit_color("disablecolor", window->disableColor);
|
|
|
|
if (window->background)
|
|
{
|
|
emit_string("background", window->background->name);
|
|
}
|
|
}
|
|
|
|
void IMenuDef::emit_set_local_var_data(SetLocalVarData* data, EventType type)
|
|
{
|
|
if (data)
|
|
{
|
|
std::string cmd;
|
|
switch (type)
|
|
{
|
|
case EVENT_SET_LOCAL_VAR_BOOL:
|
|
cmd = "setLocalVarBool";
|
|
break;
|
|
case EVENT_SET_LOCAL_VAR_INT:
|
|
cmd = "setLocalVarInt";
|
|
break;
|
|
case EVENT_SET_LOCAL_VAR_FLOAT:
|
|
cmd = "setLocalVarFloat";
|
|
break;
|
|
case EVENT_SET_LOCAL_VAR_STRING:
|
|
cmd = "setLocalVarString";
|
|
break;
|
|
}
|
|
|
|
fprintf(fp, "%s%s \"%s\"", get_tabs(), cmd.c_str(), data->localVarName);
|
|
emit_statement(nullptr, data->expression, true);
|
|
}
|
|
}
|
|
|
|
void IMenuDef::emit_dynamic_flags(int flags)
|
|
{
|
|
emit_bool("visible 1", flags & WINDOWDYNAMIC_VISIBLE);
|
|
}
|
|
|
|
void IMenuDef::emit_static_flags(int flags)
|
|
{
|
|
emit_bool("decoration", flags & WINDOWSTATIC_DECORATION);
|
|
emit_bool("horizontalscroll", flags & WINDOWSTATIC_HORIZONTALSCROLL);
|
|
emit_bool("screenSpace", flags & WINDOWSTATIC_SCREENSPACE);
|
|
emit_bool("autowrapped", flags & WINDOWSTATIC_AUTOWRAPPED);
|
|
emit_bool("popup", flags & WINDOWSTATIC_POPUP);
|
|
emit_bool("outOfBoundsClick", flags & WINDOWSTATIC_OUTOFBOUNDSCLICK);
|
|
emit_bool("legacySplitScreenScale", flags & WINDOWSTATIC_LEGACYSPLITSCREENSCALE);
|
|
emit_bool("hiddenDuringFlashbang", flags & WINDOWSTATIC_HIDDENDURINGFLASH);
|
|
emit_bool("hiddenDuringScope", flags & WINDOWSTATIC_HIDDENDURINGSCOPE);
|
|
emit_bool("hiddenDuringUI", flags & WINDOWSTATIC_HIDDENDURINGUI);
|
|
emit_bool("textOnlyFocus", flags & WINDOWSTATIC_TEXTONLYFOCUS);
|
|
}
|
|
|
|
void IMenuDef::emit_dvar_flags(int dvarFlags, const char* dvarTest, const char* enableDvar)
|
|
{
|
|
std::string command;
|
|
switch (dvarFlags)
|
|
{
|
|
case 0x01:
|
|
command = "enableDvar";
|
|
break;
|
|
case 0x02:
|
|
command = "disableDvar";
|
|
break;
|
|
case 0x04:
|
|
command = "showDvar";
|
|
break;
|
|
case 0x08:
|
|
command = "hideDvar";
|
|
break;
|
|
case 0x10:
|
|
command = "focusDvar";
|
|
break;
|
|
}
|
|
|
|
emit_string("dvarTest", dvarTest);
|
|
|
|
if (enableDvar)
|
|
{
|
|
fprintf(fp, "%s%s { %s}\n", get_tabs(), command.c_str(), enableDvar);
|
|
}
|
|
}
|
|
|
|
void IMenuDef::emit_item_def_data(itemDefData_t* data, int type)
|
|
{
|
|
if (data->data)
|
|
{
|
|
switch (type)
|
|
{
|
|
case ITEM_TYPE_LISTBOX:
|
|
emit_list_box(data->listBox);
|
|
break;
|
|
case ITEM_TYPE_MULTI:
|
|
emit_multi_def(data->multiDef);
|
|
break;
|
|
case ITEM_TYPE_DVARENUM:
|
|
fprintf(fp, "%s%s %s %s", get_tabs(), "dvar", "dvarEnumList", data->enumDvarName);
|
|
break;
|
|
case ITEM_TYPE_NEWSTICKER:
|
|
emit_int("newsfeed", data->ticker->feedId);
|
|
emit_int("speed", data->ticker->speed);
|
|
emit_int("spacing", data->ticker->spacing);
|
|
break;
|
|
case ITEM_TYPE_EDITFIELD:
|
|
case ITEM_TYPE_NUMERICFIELD:
|
|
case ITEM_TYPE_VALIDFILEFIELD:
|
|
case ITEM_TYPE_UPREDITFIELD:
|
|
case ITEM_TYPE_YESNO:
|
|
case ITEM_TYPE_BIND:
|
|
case ITEM_TYPE_TEXT:
|
|
case ITEM_TYPE_DECIMALFIELD:
|
|
case ITEM_TYPE_EMAILFIELD:
|
|
case ITEM_TYPE_PASSWORDFIELD:
|
|
emit_int("maxChars", data->editField->maxChars);
|
|
emit_int("maxCharsGotoNext", data->editField->maxCharsGotoNext);
|
|
emit_int("maxPaintChars", data->editField->maxPaintChars);
|
|
break;
|
|
case ITEM_TYPE_TEXTSCROLL:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void IMenuDef::emit_multi_def(multiDef_s* multiDef)
|
|
{
|
|
if (multiDef->strDef)
|
|
{
|
|
fprintf(fp, "%s%s {", get_tabs(), "dvarStrList");
|
|
}
|
|
else
|
|
{
|
|
fprintf(fp, "%s%s {", get_tabs(), "dvarFloatList");
|
|
}
|
|
|
|
for (auto i = 0; i < multiDef->count; i++)
|
|
{
|
|
fprintf(fp, " \"%s\"", multiDef->dvarList[i]);
|
|
if (multiDef->strDef)
|
|
{
|
|
fprintf(fp, " \"%s\"", multiDef->dvarStr[i]);
|
|
}
|
|
else
|
|
{
|
|
fprintf(fp, " %g", multiDef->dvarValue[i]);
|
|
}
|
|
}
|
|
|
|
fputs(" }\n", fp);
|
|
}
|
|
|
|
void IMenuDef::emit_list_box(listBoxDef_s* listBox)
|
|
{
|
|
emit_color("selectBorder", listBox->selectBorder);
|
|
|
|
if (listBox->selectIcon)
|
|
{
|
|
emit_string("selectIcon", listBox->selectIcon->name);
|
|
}
|
|
|
|
emit_float("elementWidth", listBox->elementWidth);
|
|
emit_float("elementHeight", listBox->elementHeight);
|
|
emit_int("elementtype", listBox->elementStyle);
|
|
emit_column_info(listBox->columnInfo, listBox->numColumns);
|
|
emit_bool("noscrollbars", listBox->noscrollbars);
|
|
emit_bool("notselectable", listBox->notselectable);
|
|
emit_bool("usepaging", listBox->usepaging);
|
|
emit_menu_event_handler_set("doubleClick", listBox->doubleClick);
|
|
}
|
|
|
|
void IMenuDef::emit_column_info(columnInfo_s* columns, int count)
|
|
{
|
|
fprintf(fp, "//%snumcol\t\t\txpos\txwidth\ttextlen\t alignment\n", get_tabs());
|
|
fprintf(fp, "%s%s %i\t\t%i\t\t%i\t\t%i\t\t %i\n", get_tabs(), "columns", count, columns[0].xpos, columns[0].width, columns[0].maxChars, columns[0].alignment);
|
|
for (int i = 1; i < count; i++)
|
|
{
|
|
fprintf(fp, "%s\t\t\t\t%i\t\t%i\t\t%i\t\t %i\n", get_tabs(), columns[i].xpos, columns[i].width, columns[i].maxChars, columns[i].alignment);
|
|
}
|
|
}
|
|
|
|
void IMenuDef::emit_item_float_expressions(ItemFloatExpression* expressions, int count)
|
|
{
|
|
if (expressions)
|
|
{
|
|
for (auto i = 0; i < count; i++)
|
|
{
|
|
std::string name;
|
|
name = "exp ";
|
|
name += g_itemFloatExpressions[expressions[i].target].s1;
|
|
name += " ";
|
|
name += g_itemFloatExpressions[expressions[i].target].s2;
|
|
emit_statement(name.c_str(), expressions[i].expression);
|
|
}
|
|
}
|
|
}
|
|
|
|
void IMenuDef::emit_item_key_handler(const char* name, ItemKeyHandler* handler)
|
|
{
|
|
if (handler)
|
|
{
|
|
emit_menu_event_handler_set("", handler->action);
|
|
emit_item_key_handler("execKeyInt", handler->next);
|
|
}
|
|
}
|
|
|
|
void IMenuDef::emit_menu_event_handler_set(const char* name, MenuEventHandlerSet* set)
|
|
{
|
|
if (set)
|
|
{
|
|
const bool formatStatement = true;
|
|
|
|
if (name)
|
|
{
|
|
fprintf(fp, "%s%s\n", get_tabs(), name);
|
|
push_indent();
|
|
}
|
|
|
|
for (auto i = 0; i < set->eventHandlerCount; i++)
|
|
{
|
|
switch (set->eventHandlers[i]->eventType)
|
|
{
|
|
case EVENT_UNCONDITIONAL:
|
|
fprintf(fp, "%s%s", get_tabs(), format_script(set->eventHandlers[i]->eventData.unconditionalScript).c_str());
|
|
break;
|
|
case EVENT_IF:
|
|
emit_conditional_script(set->eventHandlers[i]->eventData.conditionalScript);
|
|
break;
|
|
case EVENT_ELSE:
|
|
emit_menu_event_handler_set("else", set->eventHandlers[i]->eventData.elseScript);
|
|
break;
|
|
case EVENT_SET_LOCAL_VAR_BOOL:
|
|
case EVENT_SET_LOCAL_VAR_INT:
|
|
case EVENT_SET_LOCAL_VAR_FLOAT:
|
|
case EVENT_SET_LOCAL_VAR_STRING:
|
|
emit_set_local_var_data(set->eventHandlers[i]->eventData.setLocalVarData, set->eventHandlers[i]->eventType);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (name)
|
|
{
|
|
pop_indent();
|
|
}
|
|
}
|
|
}
|
|
|
|
void IMenuDef::emit_conditional_script(ConditionalScript* script)
|
|
{
|
|
if (script)
|
|
{
|
|
fprintf(fp, "%sif", get_tabs());
|
|
emit_statement(nullptr, script->eventExpression);
|
|
push_indent();
|
|
emit_menu_event_handler_set(nullptr, script->eventHandlerSet);
|
|
pop_indent();
|
|
}
|
|
}
|
|
|
|
void IMenuDef::emit_statement(const char* name, Statement_s* statement, bool semiColon)
|
|
{
|
|
if (statement)
|
|
{
|
|
const bool clean_statements = true;
|
|
bool needs_closing_parenthesis = false;
|
|
|
|
if (name)
|
|
{
|
|
fprintf(fp, "%s%s", get_tabs(), name);
|
|
}
|
|
|
|
if (clean_statements)
|
|
{
|
|
if (statement->entries[0].data.op != OP_LEFTPAREN)
|
|
{
|
|
fputs(" (", fp);
|
|
}
|
|
}
|
|
|
|
for (auto i = 0; i < statement->numEntries; i++)
|
|
{
|
|
int type = statement->entries[i].type;
|
|
if (type == OPERATOR)
|
|
{
|
|
needs_closing_parenthesis = true;
|
|
auto op = statement->entries[i].data.op;
|
|
if (op < OP_FIRSTFUNCTIONCALL)
|
|
{
|
|
if (statement->entries[i - 1].data.op == OP_RIGHTPAREN && op == OP_LEFTPAREN)
|
|
{
|
|
++i;
|
|
continue;
|
|
}
|
|
|
|
if (statement->entries[i - 1].data.op == OP_NOT)
|
|
{
|
|
fprintf(fp, "%s", g_expOperatorNames[op]);
|
|
}
|
|
else
|
|
{
|
|
fprintf(fp, " %s", g_expOperatorNames[op]);
|
|
}
|
|
}
|
|
else if (op >= OP_STATICDVARINT && op <= OP_STATICDVARSTRING)
|
|
{
|
|
i++;
|
|
|
|
std::string command;
|
|
switch (op)
|
|
{
|
|
case OP_STATICDVARINT:
|
|
command = "dvarstring";
|
|
break;
|
|
case OP_STATICDVARBOOL:
|
|
command = "dvarbool";
|
|
break;
|
|
case OP_STATICDVARFLOAT:
|
|
command = "dvarfloat";
|
|
break;
|
|
case OP_STATICDVARSTRING:
|
|
command = "dvarstring";
|
|
break;
|
|
}
|
|
|
|
command += "( \"";
|
|
command += statement->supportingData->staticDvarList.staticDvars[statement->entries[i].data.operand.internals.intVal]->dvarName;
|
|
command += "\" )";
|
|
|
|
if (statement->entries[i - 2].data.op == OP_NOT)
|
|
{
|
|
fprintf(fp, "%s", command.c_str());
|
|
}
|
|
else
|
|
{
|
|
fprintf(fp, " %s", command.c_str());
|
|
}
|
|
|
|
i++;
|
|
}
|
|
else
|
|
{
|
|
if (statement->entries[i - 1].data.op == OP_NOT)
|
|
fprintf(fp, "%s(", g_expOperatorNames[op]);
|
|
else
|
|
fprintf(fp, " %s(", g_expOperatorNames[op]);
|
|
}
|
|
}
|
|
else if (type == OPERAND)
|
|
{
|
|
switch (statement->entries[i].data.operand.dataType)
|
|
{
|
|
case VAL_INT:
|
|
fprintf(fp, " %i", statement->entries[i].data.operand.internals.intVal);
|
|
break;
|
|
case VAL_FLOAT:
|
|
fprintf(fp, " %g", statement->entries[i].data.operand.internals.floatVal);
|
|
break;
|
|
case VAL_STRING:
|
|
fprintf(fp, " \"%s\"", escape_string(statement->entries[i].data.operand.internals.stringVal.string).c_str());
|
|
break;
|
|
case VAL_FUNCTION:
|
|
emit_statement(nullptr, statement->entries[i].data.operand.internals.function);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (clean_statements)
|
|
{
|
|
if (needs_closing_parenthesis)
|
|
{
|
|
fputs(" )", fp);
|
|
}
|
|
|
|
if (statement->entries[0].data.op != OP_LEFTPAREN)
|
|
{
|
|
fputs(" )", fp);
|
|
}
|
|
|
|
if (semiColon)
|
|
{
|
|
fputs(";", fp);
|
|
}
|
|
}
|
|
|
|
fputs("\n", fp);
|
|
}
|
|
}
|
|
|
|
void IMenuDef::emit_string(const char* name, const char* value)
|
|
{
|
|
if (value && *value)
|
|
{
|
|
fprintf(fp, "%s%s \"%s\"\n", get_tabs(), name, value);
|
|
}
|
|
}
|
|
|
|
void IMenuDef::emit_bool(const char* name, bool value)
|
|
{
|
|
if (value)
|
|
{
|
|
fprintf(fp, "%s%s\n", get_tabs(), name);
|
|
}
|
|
}
|
|
|
|
void IMenuDef::emit_int(const char* name, int value)
|
|
{
|
|
if (value)
|
|
{
|
|
fprintf(fp, "%s%s %i\n", get_tabs(), name, value);
|
|
}
|
|
}
|
|
|
|
void IMenuDef::emit_float(const char* name, float value)
|
|
{
|
|
if (value)
|
|
{
|
|
fprintf(fp, "%s%s %g\n", get_tabs(), name, value);
|
|
}
|
|
}
|
|
|
|
void IMenuDef::emit_rect(const char* name, rectDef_s& rect)
|
|
{
|
|
// TODO: Some pre-processing may be needed
|
|
fprintf(fp, "%s%s %g %g %g %g %i %i\n", get_tabs(), name, rect.x, rect.y, rect.w, rect.h, rect.horzAlign, rect.vertAlign);
|
|
}
|
|
|
|
void IMenuDef::emit_color(const char* name, vec4_t& color)
|
|
{
|
|
if (color[0] > 0.0f || color[1] > 0.0f || color[2] > 0.0f || color[3] > 0.0f)
|
|
{
|
|
fprintf(fp, "%s%s %g %g %g %g\n", get_tabs(), name, color[0], color[1], color[2], color[3]);
|
|
}
|
|
}
|
|
|
|
const char* IMenuDef::get_tabs()
|
|
{
|
|
static char tabs[10];
|
|
|
|
for (auto i = 0; i < indentCounter && i < 10; i++)
|
|
{
|
|
tabs[i] = '\t';
|
|
}
|
|
|
|
tabs[indentCounter] = 0;
|
|
return tabs;
|
|
}
|
|
|
|
void IMenuDef::replace_all(std::string& str, std::string from, std::string to, bool case_insensitive)
|
|
{
|
|
if (case_insensitive)
|
|
{
|
|
auto replace = [&](std::string from, std::string to) -> bool
|
|
{
|
|
std::string lowered(str);
|
|
std::transform(str.begin(), str.end(), lowered.begin(), ::tolower);
|
|
|
|
auto pos = lowered.find(from);
|
|
if (pos == std::string::npos)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
str.replace(pos, from.length(), to);
|
|
return true;
|
|
};
|
|
|
|
std::transform(from.begin(), from.end(), from.begin(), ::tolower);
|
|
while (replace(from, to));
|
|
}
|
|
else
|
|
{
|
|
std::size_t pos = 0;
|
|
while ((pos = str.find(from, pos)) != std::string::npos)
|
|
{
|
|
str.replace(pos, from.length(), to);
|
|
pos += to.length();
|
|
}
|
|
}
|
|
}
|
|
|
|
std::string IMenuDef::escape_string(const char* value)
|
|
{
|
|
std::string out(value);
|
|
replace_all(out, "\t", "\\t");
|
|
replace_all(out, "\n", "\\n");
|
|
return out;
|
|
}
|
|
|
|
std::string IMenuDef::format_script(const char* value)
|
|
{
|
|
std::string out = escape_string(value);
|
|
const std::string tabs = get_tabs();
|
|
|
|
// clean indentation and semi colons
|
|
out += "\n";
|
|
replace_all(out, "\t;", "\t");
|
|
replace_all(out, tabs + "\n", "");
|
|
replace_all(out, " ; \n", ";\n");
|
|
replace_all(out, " \n", ";\n");
|
|
replace_all(out, " ; ", ";\n" + tabs);
|
|
replace_all(out, "; ", ";\n" + tabs);
|
|
|
|
// remove quotes from keywords
|
|
replace_all(out, "\"self\"", "self");
|
|
replace_all(out, "\"forecolor\"", "forecolor");
|
|
replace_all(out, "\"backcolor\"", "backcolor");
|
|
replace_all(out, "\"bordercolor\"", "bordercolor");
|
|
|
|
// remove quotes from commands
|
|
for (auto i = 0; i < 62; i++)
|
|
{
|
|
replace_all(out, "\""s + g_commandList[i] + "\""s, g_commandList[i], true);
|
|
}
|
|
|
|
return out;
|
|
}
|
|
}
|
|
} |