// ======================= 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 w", asset->rectWExp); emit_statement("exp rect h", asset->rectHExp); 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) { std::string keyName = std::string(name) + " "s + std::to_string(handler->key); emit_menu_event_handler_set(keyName.c_str(), 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, "\"", ""); // Remove all quotes 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; } } }