Files
OpenAssetTools/src/ObjLoading/Parsing/Menu/Sequence/EventHandlerSetScopeSequences.cpp
T
moandJan Laupetin 4da55a351a feat: add T4 menu dumping and loading (#986)
* feat: add T4 menu dumping

* chore: align with latest changes

* feat: add T4 menu loading

Load T4 menulists and menu files through the shared menu parser.

Preserve T4-specific menu and listbox fields and cover loading, dumping, linking, and round-trip behaviour.

* chore: make flag fields unsigned

* chore: rename `expOperationEnum` -> `operationEnum`

* chore: use default enum numeration for T4 operationEnum

* chore: remove unused members of operationEnum

* chore: remove redundant op from operationEnum

* refactor: align T4 expression operand names with IW3

* chore: small adjustment to iw3,t4 types

---------

Co-authored-by: Jan Laupetin <[email protected]>
2026-09-03 23:19:03 +02:00

1964 lines
83 KiB
C++

#include "EventHandlerSetScopeSequences.h"
#include "Generic/GenericStringPropertySequence.h"
#include "Parsing/Menu/Domain/EventHandler/CommonEventHandlerScript.h"
#include "Parsing/Menu/Domain/EventHandler/CommonEventHandlerSetLocalVar.h"
#include "Parsing/Menu/Matcher/MenuExpressionMatchers.h"
#include "Parsing/Menu/Matcher/MenuMatcherFactory.h"
#include "Parsing/Menu/Matcher/MenuMatcherScriptInt.h"
#include "Parsing/Menu/Matcher/MenuMatcherScriptNumeric.h"
#include <initializer_list>
#include <memory>
#include <sstream>
using namespace menu;
namespace
{
enum class ExpectedScriptToken
{
NUMERIC,
INT,
TEXT
};
class ScriptMatcherFactory final : public MenuMatcherFactory
{
public:
explicit ScriptMatcherFactory(const IMatcherForLabelSupplier<SimpleParserValue>* labelSupplier)
: MenuMatcherFactory(labelSupplier)
{
}
[[nodiscard]] MatcherFactoryWrapper<SimpleParserValue> ScriptStrictNumeric() const
{
return And({
MatcherFactoryWrapper<SimpleParserValue>(std::make_unique<MenuMatcherScriptNumeric>())
.Transform(
[](const token_list_t& tokens) -> SimpleParserValue
{
const auto& firstToken = tokens[0].get();
if (firstToken.m_type == SimpleParserValueType::CHARACTER)
{
const auto& secondToken = tokens[1].get();
if (secondToken.m_type == SimpleParserValueType::INTEGER)
return SimpleParserValue::String(firstToken.GetPos(), new std::string(std::to_string(-secondToken.IntegerValue())));
std::ostringstream ss;
ss << std::noshowpoint << -firstToken.FloatingPointValue();
return SimpleParserValue::String(firstToken.GetPos(), new std::string(ss.str()));
}
if (firstToken.m_type == SimpleParserValueType::INTEGER)
return SimpleParserValue::String(firstToken.GetPos(), new std::string(std::to_string(firstToken.IntegerValue())));
if (firstToken.m_type == SimpleParserValueType::FLOATING_POINT)
{
std::ostringstream ss;
ss << std::noshowpoint << firstToken.FloatingPointValue();
return SimpleParserValue::String(firstToken.GetPos(), new std::string(ss.str()));
}
return SimpleParserValue::String(firstToken.GetPos(), new std::string(firstToken.StringValue()));
}),
});
}
[[nodiscard]] MatcherFactoryWrapper<SimpleParserValue> ScriptNumeric() const
{
return Or({
ScriptStrictNumeric(),
Or({
Type(SimpleParserValueType::CHARACTER),
Type(SimpleParserValueType::STRING),
Type(SimpleParserValueType::IDENTIFIER),
})
.Transform(
[](const token_list_t& tokens) -> SimpleParserValue
{
return SimpleParserValue::Integer(tokens[0].get().GetPos(), static_cast<int>(ExpectedScriptToken::NUMERIC));
}),
});
}
[[nodiscard]] MatcherFactoryWrapper<SimpleParserValue> ScriptStrictInt() const
{
return And({
MatcherFactoryWrapper<SimpleParserValue>(std::make_unique<MenuMatcherScriptInt>())
.Transform(
[](const token_list_t& tokens) -> SimpleParserValue
{
const auto& firstToken = tokens[0].get();
if (firstToken.m_type == SimpleParserValueType::CHARACTER)
return SimpleParserValue::String(firstToken.GetPos(), new std::string(std::to_string(-tokens[1].get().IntegerValue())));
if (firstToken.m_type == SimpleParserValueType::INTEGER)
return SimpleParserValue::String(firstToken.GetPos(), new std::string(std::to_string(firstToken.IntegerValue())));
return SimpleParserValue::String(firstToken.GetPos(), new std::string(firstToken.StringValue()));
}),
});
}
[[nodiscard]] MatcherFactoryWrapper<SimpleParserValue> ScriptChar(const char c) const
{
return Or({
Char(c),
Or({
Type(SimpleParserValueType::INTEGER),
Type(SimpleParserValueType::FLOATING_POINT),
Type(SimpleParserValueType::STRING),
Type(SimpleParserValueType::IDENTIFIER),
})
.Transform(
[](const token_list_t& tokens) -> SimpleParserValue
{
return SimpleParserValue::Integer(tokens[0].get().GetPos(), static_cast<int>(ExpectedScriptToken::INT));
}),
});
}
[[nodiscard]] MatcherFactoryWrapper<SimpleParserValue> ScriptInt() const
{
return Or({
ScriptStrictInt(),
Or({
Type(SimpleParserValueType::CHARACTER),
Type(SimpleParserValueType::FLOATING_POINT),
Type(SimpleParserValueType::STRING),
Type(SimpleParserValueType::IDENTIFIER),
})
.Transform(
[](const token_list_t& tokens) -> SimpleParserValue
{
return SimpleParserValue::Integer(tokens[0].get().GetPos(), static_cast<int>(ExpectedScriptToken::INT));
}),
});
}
[[nodiscard]] MatcherFactoryWrapper<SimpleParserValue> ScriptText() const
{
return Or({
Type(SimpleParserValueType::STRING),
Type(SimpleParserValueType::IDENTIFIER),
Or({
Type(SimpleParserValueType::CHARACTER),
Type(SimpleParserValueType::FLOATING_POINT),
Type(SimpleParserValueType::INTEGER),
})
.Transform(
[](const token_list_t& tokens) -> SimpleParserValue
{
return SimpleParserValue::Integer(tokens[0].get().GetPos(), static_cast<int>(ExpectedScriptToken::TEXT));
}),
});
}
[[nodiscard]] MatcherFactoryWrapper<SimpleParserValue> ScriptKeyword(std::string keyword) const
{
return KeywordIgnoreCase(std::move(keyword));
}
[[nodiscard]] MatcherFactoryWrapper<SimpleParserValue> ScriptColor() const
{
return And({
ScriptStrictNumeric(),
Optional(ScriptStrictNumeric()),
Optional(ScriptStrictNumeric()),
Optional(ScriptStrictNumeric()),
});
}
[[nodiscard]] MatcherFactoryWrapper<SimpleParserValue> ScriptLocalVarIntOrLiteral() const
{
return Or({
And({
ScriptKeyword("localVarInt"),
Char('('),
ScriptText(),
Char(')'),
}),
ScriptStrictInt(),
});
}
[[nodiscard]] MatcherFactoryWrapper<SimpleParserValue> ScriptLocalVarBoolOrLiteral() const
{
return Or({
And({
ScriptKeyword("localVarBool"),
Char('('),
ScriptText(),
Char(')'),
}),
ScriptStrictInt(),
});
}
};
class SequenceCloseBlock final : public MenuFileParser::sequence_t
{
public:
SequenceCloseBlock()
{
const MenuMatcherFactory create(this);
AddMatchers({
create.Char('}'),
});
}
protected:
void ProcessMatch(MenuFileParserState* state, SequenceResult<SimpleParserValue>& result) const override
{
auto remainingScript = state->m_current_script.str();
if (!remainingScript.empty())
state->m_current_nested_event_handler_set->m_elements.emplace_back(std::make_unique<CommonEventHandlerScript>(std::move(remainingScript)));
state->m_current_script.str(std::string());
bool conditionWasAutoSkip;
do
{
conditionWasAutoSkip = false;
if (!state->m_condition_stack.empty())
{
conditionWasAutoSkip = state->m_condition_stack.top().m_auto_skip;
state->m_condition_stack.pop();
if (!state->m_condition_stack.empty())
{
const auto& newConditionState = state->m_condition_stack.top();
if (newConditionState.m_in_condition_elements)
state->m_current_nested_event_handler_set = newConditionState.m_condition->m_condition_elements.get();
else
state->m_current_nested_event_handler_set = newConditionState.m_condition->m_else_elements.get();
}
else
state->m_current_nested_event_handler_set = state->m_current_event_handler_set;
}
else
{
state->m_current_event_handler_set = nullptr;
state->m_current_nested_event_handler_set = nullptr;
}
} while (conditionWasAutoSkip);
}
};
class SequenceSkipEmptyStatements final : public MenuFileParser::sequence_t
{
public:
SequenceSkipEmptyStatements()
{
const MenuMatcherFactory create(this);
AddMatchers({
create.Char(';'),
});
}
protected:
void ProcessMatch(MenuFileParserState* state, SequenceResult<SimpleParserValue>& result) const override
{
if (!state->m_current_script_statement_terminated)
{
state->m_current_script << "; ";
state->m_current_script_statement_terminated = true;
}
}
};
class SequenceSkipScriptToken final : public MenuFileParser::sequence_t
{
static constexpr auto CAPTURE_SCRIPT_TOKEN = 1;
public:
SequenceSkipScriptToken()
{
const ScriptMatcherFactory create(this);
AddMatchers({
create
.Or({
create.ScriptStrictNumeric(),
create.String(),
create.Identifier(),
create.Type(SimpleParserValueType::CHARACTER),
})
.Capture(CAPTURE_SCRIPT_TOKEN),
});
}
protected:
void ProcessMatch(MenuFileParserState* state, SequenceResult<SimpleParserValue>& result) const override
{
const auto& capture = result.NextCapture(CAPTURE_SCRIPT_TOKEN);
switch (capture.m_type)
{
case SimpleParserValueType::STRING:
state->m_current_script << "\"" << capture.StringValue() << "\" ";
break;
case SimpleParserValueType::IDENTIFIER:
state->m_current_script << "\"" << capture.IdentifierValue() << "\" ";
break;
case SimpleParserValueType::INTEGER:
state->m_current_script << "\"" << capture.IntegerValue() << "\" ";
break;
case SimpleParserValueType::CHARACTER:
state->m_current_script << capture.CharacterValue() << " ";
break;
case SimpleParserValueType::FLOATING_POINT:
state->m_current_script << "\"" << capture.FloatingPointValue() << "\" ";
break;
default:
throw ParsingException(capture.GetPos(), "Invalid script token type for skipping");
}
state->m_current_script_statement_terminated = false;
}
};
class SequenceGenericScriptStatement : public MenuFileParser::sequence_t
{
protected:
static constexpr auto CAPTURE_SCRIPT_TOKEN = 1;
SequenceGenericScriptStatement() = default;
public:
explicit SequenceGenericScriptStatement(std::initializer_list<Movable<std::unique_ptr<AbstractMatcher<SimpleParserValue>>>> matchers)
{
const MenuMatcherFactory create(this);
AddMatchers({
create.And(matchers).Capture(CAPTURE_SCRIPT_TOKEN),
create.Optional(create.Char(';')),
});
}
static std::unique_ptr<SequenceGenericScriptStatement>
Create(std::initializer_list<Movable<std::unique_ptr<AbstractMatcher<SimpleParserValue>>>> matchers)
{
return std::make_unique<SequenceGenericScriptStatement>(matchers);
}
private:
static std::string ScriptTokenTypeToString(int tokenType)
{
switch (static_cast<ExpectedScriptToken>(tokenType))
{
case ExpectedScriptToken::INT:
return "INT";
case ExpectedScriptToken::NUMERIC:
return "NUMERIC";
case ExpectedScriptToken::TEXT:
return "TEXT";
default:
return "UNKNOWN";
}
}
protected:
void ProcessMatch(MenuFileParserState* state, SequenceResult<SimpleParserValue>& result) const override
{
while (result.HasNextCapture(CAPTURE_SCRIPT_TOKEN))
{
const auto& capture = result.NextCapture(CAPTURE_SCRIPT_TOKEN);
if (capture.m_type == SimpleParserValueType::IDENTIFIER)
{
state->m_current_script << "\"" << capture.IdentifierValue() << "\" ";
}
else if (capture.m_type == SimpleParserValueType::STRING)
{
state->m_current_script << "\"" << capture.StringValue() << "\" ";
}
else if (capture.m_type == SimpleParserValueType::CHARACTER)
{
state->m_current_script << capture.CharacterValue() << " ";
}
else if (capture.m_type == SimpleParserValueType::INTEGER)
{
std::ostringstream ss;
ss << "Invalid script token. Expected " << ScriptTokenTypeToString(capture.IntegerValue()) << ".";
throw ParsingException(capture.GetPos(), ss.str());
}
else
throw ParsingException(capture.GetPos(), "Invalid script capture");
}
state->m_current_script << "; ";
}
};
class SequenceUiScriptStatement final : public SequenceGenericScriptStatement
{
public:
explicit SequenceUiScriptStatement(std::initializer_list<Movable<std::unique_ptr<AbstractMatcher<SimpleParserValue>>>> matchers)
: SequenceGenericScriptStatement()
{
const ScriptMatcherFactory create(this);
AddMatchers({
create
.And({
create.ScriptKeyword("uiScript"),
create.And(matchers),
})
.Capture(CAPTURE_SCRIPT_TOKEN),
create.Optional(create.Char(';')),
});
}
static std::unique_ptr<SequenceUiScriptStatement> Create(std::initializer_list<Movable<std::unique_ptr<AbstractMatcher<SimpleParserValue>>>> matchers)
{
return std::make_unique<SequenceUiScriptStatement>(matchers);
}
};
class AbstractSequenceWithPlayerData : public SequenceGenericScriptStatement
{
protected:
static constexpr auto LABEL_PLAYER_DATA_PATH_ELEMENT = 1;
static std::unique_ptr<matcher_t> PlayerDataPathMatchers(const ScriptMatcherFactory& create)
{
return create.Or({
create.ScriptKeyword("false"),
create.ScriptKeyword("true"),
create.And({
create.Or({
create.ScriptKeyword("localvarstring"),
create.ScriptKeyword("localvarint"),
create.ScriptKeyword("localvarfloat"),
create.ScriptKeyword("localvarbool"),
}),
create.ScriptChar('('),
create.ScriptText(),
create.ScriptChar(')'),
}),
create.ScriptStrictInt(),
create.ScriptText(),
});
}
};
class SequenceSetPlayerData final : public AbstractSequenceWithPlayerData
{
public:
explicit SequenceSetPlayerData()
{
const ScriptMatcherFactory create(this);
AddLabeledMatchers(PlayerDataPathMatchers(create), LABEL_PLAYER_DATA_PATH_ELEMENT);
AddMatchers({
create
.And({
create.ScriptKeyword("setPlayerData"),
create.ScriptChar('('),
create.Label(LABEL_PLAYER_DATA_PATH_ELEMENT),
create.Loop(create.And({
create.ScriptChar(','),
create.Label(LABEL_PLAYER_DATA_PATH_ELEMENT),
})),
create.ScriptChar(')'),
})
.Capture(CAPTURE_SCRIPT_TOKEN),
create.Optional(create.Char(';')),
});
}
};
class SequenceSetPlayerDataSplitscreen final : public AbstractSequenceWithPlayerData
{
public:
explicit SequenceSetPlayerDataSplitscreen()
{
const ScriptMatcherFactory create(this);
AddLabeledMatchers(PlayerDataPathMatchers(create), LABEL_PLAYER_DATA_PATH_ELEMENT);
AddMatchers({
create
.And({
create.ScriptKeyword("setPlayerDataSplitscreen"),
create.ScriptChar('('),
create.ScriptInt(),
create.ScriptChar(','),
create.Label(LABEL_PLAYER_DATA_PATH_ELEMENT),
create.Loop(create.And({
create.ScriptChar(','),
create.Label(LABEL_PLAYER_DATA_PATH_ELEMENT),
})),
create.ScriptChar(')'),
})
.Capture(CAPTURE_SCRIPT_TOKEN),
create.Optional(create.Char(';')),
});
}
};
class SequenceLerp final : public SequenceGenericScriptStatement
{
public:
explicit SequenceLerp()
{
const ScriptMatcherFactory create(this);
AddMatchers({
create
.And({
create.ScriptKeyword("lerp"),
create.Or({
create.ScriptKeyword("scale"),
create.ScriptKeyword("alpha"),
create.ScriptKeyword("x"),
create.ScriptKeyword("y"),
}),
create.ScriptKeyword("from"),
create.ScriptNumeric(),
create.ScriptKeyword("to"),
create.ScriptNumeric(),
create.ScriptKeyword("over"),
create.ScriptNumeric(),
})
.Capture(CAPTURE_SCRIPT_TOKEN),
create.Optional(create.Char(';')),
});
}
};
class SequenceSetLocalVar final : public MenuFileParser::sequence_t
{
static constexpr auto TAG_BOOL = static_cast<int>(SetLocalVarType::BOOL);
static constexpr auto TAG_INT = static_cast<int>(SetLocalVarType::INT);
static constexpr auto TAG_FLOAT = static_cast<int>(SetLocalVarType::FLOAT);
static constexpr auto TAG_STRING = static_cast<int>(SetLocalVarType::STRING);
static constexpr auto CAPTURE_VAR_NAME = 1;
public:
SequenceSetLocalVar()
{
const ScriptMatcherFactory create(this);
const MenuExpressionMatchers expressionMatchers;
AddLabeledMatchers(expressionMatchers.Expression(this), MenuExpressionMatchers::LABEL_EXPRESSION);
AddMatchers({
create.Or({
create.ScriptKeyword("setLocalVarBool").Tag(TAG_BOOL),
create.ScriptKeyword("setLocalVarInt").Tag(TAG_INT),
create.ScriptKeyword("setLocalVarFloat").Tag(TAG_FLOAT),
create.ScriptKeyword("setLocalVarString").Tag(TAG_STRING),
}),
create.ScriptText().Capture(CAPTURE_VAR_NAME),
create.Or({
create.And({
create.Label(MenuExpressionMatchers::LABEL_EXPRESSION),
create.Optional(create.Char(';')),
}),
// The game seems to accept setLocalVar expressions without value as setting the var to the default value
// This only applies to the menu parser though and not to the script parser so we need to separately parse this
create.Char(';'),
}),
});
}
private:
static std::string ScriptKeywordForType(const SetLocalVarType type)
{
switch (type)
{
case SetLocalVarType::BOOL:
return "setLocalVarBool";
case SetLocalVarType::INT:
return "setLocalVarInt";
case SetLocalVarType::FLOAT:
return "setLocalVarFloat";
case SetLocalVarType::STRING:
return "setLocalVarString";
default:
return "unknown";
}
}
static void EmitStaticValue(MenuFileParserState* state, const SimpleExpressionValue& value)
{
switch (value.m_type)
{
case SimpleExpressionValue::Type::DOUBLE:
state->m_current_script << value.m_double_value;
break;
case SimpleExpressionValue::Type::INT:
state->m_current_script << value.m_int_value;
break;
case SimpleExpressionValue::Type::STRING:
state->m_current_script << *value.m_string_value;
break;
}
}
static void CheckStaticValueType(const TokenPos& pos, const SetLocalVarType type, const SimpleExpressionValue& staticValue)
{
switch (type)
{
case SetLocalVarType::BOOL:
if (staticValue.m_type != SimpleExpressionValue::Type::INT)
throw ParsingException(pos, "Static value must be BOOL");
break;
case SetLocalVarType::INT:
if (staticValue.m_type != SimpleExpressionValue::Type::INT)
throw ParsingException(pos, "Static value must be INT");
break;
case SetLocalVarType::FLOAT:
if (staticValue.m_type != SimpleExpressionValue::Type::DOUBLE && staticValue.m_type != SimpleExpressionValue::Type::INT)
throw ParsingException(pos, "Static value must be FLOAT");
break;
case SetLocalVarType::STRING:
default:
break;
}
}
static void EmitStaticSetLocalVar(MenuFileParserState* state,
const TokenPos& pos,
const SetLocalVarType type,
const std::string& varName,
std::unique_ptr<ISimpleExpression> expression)
{
state->m_current_script << "\"" << ScriptKeywordForType(type) << "\" \"" << varName << "\" \"";
const auto staticValue = expression->EvaluateStatic();
CheckStaticValueType(pos, type, staticValue);
EmitStaticValue(state, staticValue);
state->m_current_script << "\" ; ";
}
static void EmitDynamicSetLocalVar(MenuFileParserState* state,
const SetLocalVarType type,
const std::string& varName,
std::unique_ptr<ISimpleExpression> expression)
{
auto remainingScript = state->m_current_script.str();
if (!remainingScript.empty())
state->m_current_nested_event_handler_set->m_elements.emplace_back(std::make_unique<CommonEventHandlerScript>(std::move(remainingScript)));
state->m_current_script.str(std::string());
state->m_current_nested_event_handler_set->m_elements.emplace_back(
std::make_unique<CommonEventHandlerSetLocalVar>(type, varName, std::move(expression)));
}
static std::unique_ptr<ISimpleExpression> DefaultExpressionForType(const SetLocalVarType type)
{
switch (type)
{
case SetLocalVarType::INT:
case SetLocalVarType::BOOL:
return std::make_unique<SimpleExpressionValue>(0);
case SetLocalVarType::FLOAT:
return std::make_unique<SimpleExpressionValue>(0.0);
case SetLocalVarType::STRING:
return std::make_unique<SimpleExpressionValue>(std::string());
default:
assert(false);
return nullptr;
}
}
protected:
void ProcessMatch(MenuFileParserState* state, SequenceResult<SimpleParserValue>& result) const override
{
const MenuExpressionMatchers expressionMatchers(state);
const auto typeTag = static_cast<SetLocalVarType>(result.NextTag());
const auto& varNameToken = result.NextCapture(CAPTURE_VAR_NAME);
const auto& varName = MenuMatcherFactory::TokenTextValue(varNameToken);
auto expression = expressionMatchers.ProcessExpression(result);
if (expression)
{
if (expression->IsStatic())
EmitStaticSetLocalVar(state, varNameToken.GetPos(), typeTag, varName, std::move(expression));
else
EmitDynamicSetLocalVar(state, typeTag, varName, std::move(expression));
}
else
EmitStaticSetLocalVar(state, varNameToken.GetPos(), typeTag, varName, DefaultExpressionForType(typeTag));
}
};
class SequenceIf final : public MenuFileParser::sequence_t
{
static constexpr auto CAPTURE_KEYWORD = 1;
public:
SequenceIf()
{
const ScriptMatcherFactory create(this);
const MenuExpressionMatchers expressionMatchers;
AddLabeledMatchers(expressionMatchers.Expression(this), MenuExpressionMatchers::LABEL_EXPRESSION);
AddMatchers({
create.Keyword("if").Capture(CAPTURE_KEYWORD),
create.Char('('),
create.Label(MenuExpressionMatchers::LABEL_EXPRESSION),
create.Char(')'),
create.Char('{'),
});
}
protected:
void ProcessMatch(MenuFileParserState* state, SequenceResult<SimpleParserValue>& result) const override
{
const MenuExpressionMatchers expressionMatchers(state);
auto expression = expressionMatchers.ProcessExpression(result);
if (!expression)
throw ParsingException(result.NextCapture(CAPTURE_KEYWORD).GetPos(), "Could not parse expression");
auto remainingScript = state->m_current_script.str();
if (!remainingScript.empty())
state->m_current_nested_event_handler_set->m_elements.emplace_back(std::make_unique<CommonEventHandlerScript>(std::move(remainingScript)));
state->m_current_script.str(std::string());
auto newCondition = std::make_unique<CommonEventHandlerCondition>(std::move(expression), std::make_unique<CommonEventHandlerSet>(), nullptr);
auto* newConditionPtr = newCondition.get();
state->m_current_nested_event_handler_set->m_elements.emplace_back(std::move(newCondition));
state->m_condition_stack.emplace(newConditionPtr);
state->m_current_nested_event_handler_set = newConditionPtr->m_condition_elements.get();
}
};
class SequenceElseIf final : public MenuFileParser::sequence_t
{
static constexpr auto CAPTURE_KEYWORD = 1;
public:
SequenceElseIf()
{
const ScriptMatcherFactory create(this);
const MenuExpressionMatchers expressionMatchers;
AddLabeledMatchers(expressionMatchers.Expression(this), MenuExpressionMatchers::LABEL_EXPRESSION);
AddMatchers({
create.Char('}'),
create.Keyword("elseif").Capture(CAPTURE_KEYWORD),
create.Char('('),
create.Label(MenuExpressionMatchers::LABEL_EXPRESSION),
create.Char(')'),
create.Char('{'),
});
}
protected:
void ProcessMatch(MenuFileParserState* state, SequenceResult<SimpleParserValue>& result) const override
{
const MenuExpressionMatchers expressionMatchers(state);
auto expression = expressionMatchers.ProcessExpression(result);
if (!expression)
throw ParsingException(result.NextCapture(CAPTURE_KEYWORD).GetPos(), "Could not parse expression");
if (state->m_condition_stack.empty())
throw ParsingException(result.NextCapture(CAPTURE_KEYWORD).GetPos(), "Not in an if statement");
auto remainingScript = state->m_current_script.str();
if (!remainingScript.empty())
state->m_current_nested_event_handler_set->m_elements.emplace_back(std::make_unique<CommonEventHandlerScript>(std::move(remainingScript)));
state->m_current_script.str(std::string());
auto& currentCondition = state->m_condition_stack.top();
assert(currentCondition.m_in_condition_elements == (currentCondition.m_condition->m_else_elements == nullptr));
if (!currentCondition.m_in_condition_elements)
throw ParsingException(result.NextCapture(CAPTURE_KEYWORD).GetPos(), "Cannot specify elseif after else");
currentCondition.m_in_condition_elements = false;
auto newCondition = std::make_unique<CommonEventHandlerCondition>(std::move(expression), std::make_unique<CommonEventHandlerSet>(), nullptr);
auto* newConditionPtr = newCondition.get();
currentCondition.m_condition->m_else_elements = std::make_unique<CommonEventHandlerSet>();
currentCondition.m_condition->m_else_elements->m_elements.emplace_back(std::move(newCondition));
state->m_condition_stack.emplace(newConditionPtr, true);
state->m_current_nested_event_handler_set = newConditionPtr->m_condition_elements.get();
}
};
class SequenceElse final : public MenuFileParser::sequence_t
{
static constexpr auto CAPTURE_KEYWORD = 1;
public:
SequenceElse()
{
const ScriptMatcherFactory create(this);
const MenuExpressionMatchers expressionMatchers;
AddMatchers({
create.Char('}'),
create.Keyword("else").Capture(CAPTURE_KEYWORD),
create.Char('{'),
});
}
protected:
void ProcessMatch(MenuFileParserState* state, SequenceResult<SimpleParserValue>& result) const override
{
if (state->m_condition_stack.empty())
throw ParsingException(result.NextCapture(CAPTURE_KEYWORD).GetPos(), "Not in an if statement");
auto& currentCondition = state->m_condition_stack.top();
assert(currentCondition.m_in_condition_elements == (currentCondition.m_condition->m_else_elements == nullptr));
if (!currentCondition.m_in_condition_elements)
throw ParsingException(result.NextCapture(CAPTURE_KEYWORD).GetPos(), "Cannot specify second else block");
auto remainingScript = state->m_current_script.str();
if (!remainingScript.empty())
state->m_current_nested_event_handler_set->m_elements.emplace_back(std::make_unique<CommonEventHandlerScript>(std::move(remainingScript)));
state->m_current_script.str(std::string());
currentCondition.m_in_condition_elements = false;
currentCondition.m_condition->m_else_elements = std::make_unique<CommonEventHandlerSet>();
state->m_current_nested_event_handler_set = currentCondition.m_condition->m_else_elements.get();
}
};
class SequenceOnlineVault final : public SequenceGenericScriptStatement
{
static constexpr auto LABEL_OPEN = 1;
static constexpr auto LABEL_PARADIGM = 2;
static constexpr auto LABEL_PLATFORM = 3;
static constexpr auto LABEL_FILE_CATEGORY = 4;
public:
explicit SequenceOnlineVault()
{
const ScriptMatcherFactory create(this);
AddLabeledMatchers(create.Or({
create.ScriptKeyword("Browse"),
create.ScriptKeyword("Load"),
create.ScriptKeyword("Save"),
create.ScriptKeyword("Copy"),
}),
LABEL_PARADIGM);
AddLabeledMatchers(create.Or({
create.ScriptKeyword("Fb"),
create.ScriptKeyword("Elite"),
create.ScriptKeyword("Live"),
}),
LABEL_PLATFORM);
AddLabeledMatchers(create.Or({
create.ScriptKeyword("All"),
create.ScriptKeyword("Film"),
create.ScriptKeyword("Clip"),
create.ScriptKeyword("Screenshot"),
create.ScriptKeyword("Avi"),
create.ScriptKeyword("Cgm"),
create.ScriptKeyword("Rcu"),
}),
LABEL_FILE_CATEGORY);
AddLabeledMatchers(create.And({
create.ScriptKeyword("open"),
create.Label(LABEL_PARADIGM),
create.Optional(create.Label(LABEL_PLATFORM)),
create.Optional(create.Label(LABEL_FILE_CATEGORY)),
create.ScriptText(),
}),
LABEL_OPEN);
AddMatchers({
create
.And({
create.ScriptKeyword("uiScript"),
create.ScriptKeyword("OnlineVault"),
create.Or({
create.Label(LABEL_OPEN),
create.ScriptKeyword("Pop"),
create.ScriptKeyword("CloseAll"),
create.ScriptKeyword("Load"),
create.ScriptKeyword("LoadAndRenderMovie"),
create.ScriptKeyword("TrySave"),
create.ScriptKeyword("Save"),
create.ScriptKeyword("Rename"),
create.ScriptKeyword("Delete"),
create.ScriptKeyword("Abort"),
create.ScriptKeyword("FacebookUploadPhoto"),
create.ScriptKeyword("FacebookUploadVideo"),
}),
})
.Capture(CAPTURE_SCRIPT_TOKEN),
create.Optional(create.Char(';')),
});
}
};
} // namespace
EventHandlerSetScopeSequences::EventHandlerSetScopeSequences(std::vector<std::unique_ptr<MenuFileParser::sequence_t>>& allSequences,
std::vector<MenuFileParser::sequence_t*>& scopeSequences)
: AbstractScopeSequenceHolder(allSequences, scopeSequences)
{
}
void EventHandlerSetScopeSequences::AddSequences(const FeatureLevel featureLevel, const bool permissive) const
{
AddSequence(std::make_unique<SequenceSkipEmptyStatements>());
// IW3 and T4 store event handlers as opaque script strings rather than structured handlers.
if (featureLevel == FeatureLevel::IW3 || featureLevel == FeatureLevel::T4)
{
AddSequence(std::make_unique<SequenceCloseBlock>());
AddSequence(std::make_unique<SequenceSkipScriptToken>());
return;
}
// If else and stuff
// Creating factory with no label supplier. Cannot use labels with it.
const ScriptMatcherFactory create(nullptr);
if (!permissive)
{
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("fadeIn"),
create.ScriptText(),
})); // fadeIn <item group name>
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("fadeOut"),
create.ScriptText(),
})); // fadeOut <item group name>
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("show"),
create.ScriptText(),
})); // show <item group name>
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("hide"),
create.ScriptText(),
})); // hide <item group name>
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("showMenu"),
create.ScriptText(),
})); // showMenu <menu name>
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("hideMenu"),
create.ScriptText(),
})); // hideMenu <menu name>
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("setColor"),
create.Or({
create.ScriptKeyword("backColor"),
create.ScriptKeyword("foreColor"),
create.ScriptKeyword("borderColor"),
}),
create.ScriptColor(),
})); // setColor ("backColor" | "foreColor" | "borderColor") <r> [<g>] [<b>] [<a>]
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("open"),
create.ScriptText(),
})); // open <menu name>
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("close"),
create.ScriptText(),
})); // close ("self" | <menu name>)
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("escape"),
create.ScriptText(),
})); // escape ("self" | <menu name>)
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("closeForAllPlayers"),
create.ScriptText(),
})); // closeForAllPlayers <menu name>
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("ingameOpen"),
create.ScriptText(),
})); // ingameOpen <menu name>
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("ingameClose"),
create.ScriptText(),
})); // ingameClose <menu name>
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("setBackground"),
create.ScriptText(),
})); // setBackground <material name>
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("setItemColor"),
create.ScriptText(),
create.Or({
create.ScriptKeyword("backColor"),
create.ScriptKeyword("foreColor"),
create.ScriptKeyword("borderColor"),
create.ScriptKeyword("disableColor"),
}),
create.ScriptColor(),
})); // setItemColor <item group name> (backColor | foreColor | borderColor | disableColor) <r> [<g>] [<b>] [<a>]
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("focusFirst"),
}));
// setFocus game specific
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("setFocusByDvar"),
create.ScriptText(),
})); // setFocusByDvar <dvar name>
// setDvar game specific
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("exec"),
create.ScriptText(),
})); // exec <command>
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("execNow"),
create.ScriptText(),
})); // execNow <command>
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("execOnDvarStringValue"),
create.ScriptText(),
create.ScriptText(),
create.ScriptText(),
})); // execOnDvarStringValue <dvar name> <value> <command>
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("execOnDvarIntValue"),
create.ScriptText(),
create.ScriptInt(),
create.ScriptText(),
})); // execOnDvarIntValue <dvar name> <value> <command>
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("execOnDvarFloatValue"),
create.ScriptText(),
create.ScriptNumeric(),
create.ScriptText(),
})); // execOnDvarFloatValue <dvar name> <value> <command>
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("execNowOnDvarStringValue"),
create.ScriptText(),
create.ScriptText(),
create.ScriptText(),
})); // execNowOnDvarStringValue <dvar name> <value> <command>
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("execNowOnDvarIntValue"),
create.ScriptText(),
create.ScriptInt(),
create.ScriptText(),
})); // execNowOnDvarIntValue <dvar name> <value> <command>
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("execNowOnDvarFloatValue"),
create.ScriptText(),
create.ScriptNumeric(),
create.ScriptText(),
})); // execNowOnDvarFloatValue <dvar name> <value> <command>
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("play"),
create.ScriptText(),
})); // play <sound name>
// scriptMenuResponse game specific
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("scriptMenuRespondOnDvarStringValue"),
create.ScriptText(),
create.ScriptText(),
create.ScriptText(),
})); // scriptMenuRespondOnDvarStringValue <dvar name> <value> <response value>
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("scriptMenuRespondOnDvarIntValue"),
create.ScriptText(),
create.ScriptInt(),
create.ScriptText(),
})); // scriptMenuRespondOnDvarIntValue <dvar name> <value> <response value>
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("scriptMenuRespondOnDvarFloatValue"),
create.ScriptText(),
create.ScriptNumeric(),
create.ScriptText(),
})); // scriptMenuRespondOnDvarFloatValue <dvar name> <value> <response value>
AddSequence(std::make_unique<SequenceSetPlayerData>());
AddSequence(std::make_unique<SequenceSetPlayerDataSplitscreen>());
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("resetStatsConfirm"),
}));
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("resetStatsCancel"),
}));
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("setGameMode"),
create.ScriptText(),
})); // setGameMode <mode name>
// feederTop / feederBottom game specific
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("showGamerCard"),
}));
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("openForGameType"),
create.ScriptText(),
}));
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("closeForGameType"),
create.ScriptText(),
}));
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("kickPlayer"),
}));
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("getKickPlayerQuestion"),
}));
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("partyUpdateMissingMapPackDvar"),
}));
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("togglePlayerMute"),
}));
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("resolveError"),
}));
AddSequence(std::make_unique<SequenceLerp>());
// UiScripts
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("StartServer"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("loadArenas"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("loadGameInfo"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("clearError"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("Quit"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("Controls"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("Leave"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("closeingame"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("update"),
create.ScriptText(),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("startSingleplayer"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("startMultiplayer"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("getLanguage"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("verifyLanguage"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("updateLanguage"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("mutePlayer"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("openMenuOnDvar"),
create.ScriptText(),
create.Or({
create.ScriptStrictNumeric(),
create.ScriptText(),
}),
create.ScriptText(),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("openMenuOnDvarNot"),
create.ScriptText(),
create.Or({
create.ScriptStrictNumeric(),
create.ScriptText(),
}),
create.ScriptText(),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("closeMenuOnDvar"),
create.ScriptText(),
create.Or({
create.ScriptStrictNumeric(),
create.ScriptText(),
}),
create.ScriptText(),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("closeMenuOnDvarNot"),
create.ScriptText(),
create.Or({
create.ScriptStrictNumeric(),
create.ScriptText(),
}),
create.ScriptText(),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("setRecommended"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("clearLoadErrorsSummary"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("clearClientMatchData"),
}));
if (featureLevel == FeatureLevel::IW4)
{
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("setFocus"),
create.ScriptText(),
})); // setFocus <item name>
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("setDvar"),
create.ScriptText(),
create.Or({
create.ScriptStrictNumeric(),
create.ScriptText(),
}),
})); // setDvar <dvar name> <dvar value>
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("scriptMenuResponse"),
create.ScriptText(),
})); // scriptMenuResponse <response value>
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("updateMail"),
}));
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("openMail"),
}));
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("deleteMail"),
}));
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("doMailLottery"),
}));
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("feederTop"),
}));
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("feederBottom"),
}));
// statClearPerkNew // TODO
// statSetUsingTable // TODO
// statClearBitMask // TODO
// IW4x UiScripts
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("LoadMods"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("RunMod"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("ClearMods"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("security_increase_cancel"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("mod_download_cancel"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("LoadFriends"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("JoinFriend"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("downloadDLC"),
create.ScriptInt(),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("checkFirstLaunch"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("visitWebsite"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("visitWiki"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("visitDiscord"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("updateui_mousePitch"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("ServerStatus"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("UpdateFilter"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("RefreshFilter"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("RefreshServers"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("JoinServer"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("ServerSort"),
create.ScriptInt(),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("CreateListFavorite"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("CreateFavorite"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("CreateCurrentServerFavorite"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("DeleteFavorite"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("nextStartupMessage"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("UpdateClasses"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("loadDemos"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("launchDemo"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("deleteDemo"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("ApplyMap"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("ApplyInitialMap"),
}));
}
if (featureLevel == FeatureLevel::IW5)
{
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("forceClose"),
create.ScriptText(),
})); // forceClose ("self" | <menu name>)
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("setFocus"),
create.Or({
create.And({
create.ScriptKeyword("localVarString"),
create.Char('('),
create.ScriptText(),
create.Char(')'),
}),
create.ScriptText(),
}),
})); // setFocus ((localVarString '(' <var name> ')') | <item name>)
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("setDvar"),
create.ScriptText(),
create.Or({
create.And({
create.ScriptKeyword("localVarString"),
create.Char('('),
create.ScriptText(),
create.Char(')'),
}),
create.ScriptStrictNumeric(),
create.ScriptText(),
}),
})); // setDvar <dvar name> ((localVarString '(' <var name> ')') | <dvar value>)
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("execFirstClient"),
create.ScriptText(),
})); // execFirstClient <command>
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("execKeyPress"),
create.Or({
create.ScriptStrictNumeric(),
create.ScriptText(),
}),
})); // execKeyPress <key number>
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("scriptMenuResponse"),
create.Or({
create.And({
create.Or({
create.ScriptKeyword("localVarInt"),
create.ScriptKeyword("localVarFloat"),
create.ScriptKeyword("localVarBool"),
create.ScriptKeyword("localVarString"),
}),
create.Char('('),
create.ScriptText(),
create.Char(')'),
}),
create.ScriptStrictInt(),
create.ScriptText(),
}),
})); // scriptMenuResponse (((localVarInt | localVarFloat | localVarBool | localVarString) '(' <var name> ')') | <response value>)
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("deleteEliteCacFile"),
}));
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("integrateEliteCacFile"),
}));
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("setMatchRulesData"),
})); // unknown parameters
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("loadMatchRulesDataFromPlayer"),
})); // unknown parameters
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("saveMatchRulesDataToPlayer"),
})); // unknown parameters
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("loadMatchRulesDataFromHistory"),
})); // unknown parameters
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("loadMatchRulesDataDefaults"),
})); // unknown parameters
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("setUsingMatchRulesData"),
})); // unknown parameters
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("saveMatchRulesDedicatedServer"),
})); // unknown parameters
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("loadMatchRulesDedicatedServer"),
})); // unknown parameters
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("onlineVaultEditMetadata"),
})); // unknown parameters
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("includeInMapRotation"),
})); // unknown parameters
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("useCustomMapRotation"),
})); // unknown parameters
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("useIntermissionTimer"),
})); // unknown parameters
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("stopIntermissionTimer"),
})); // unknown parameters
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("feederTop"),
create.Optional(create.Text()),
})); // feederTop [<var name>]
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("feederBottom"),
create.Optional(create.Text()),
})); // feederBottom [<var name>]
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("feederPageUp"),
create.Optional(create.Text()),
})); // feederPageUp [<var name>]
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("feederPageDown"),
create.Optional(create.Text()),
})); // feederPageDown [<var name>]
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("showCoopGamerCard"),
})); // unknown parameters
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("showSplitscreenGamerCard"),
})); // unknown parameters
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("reportPlayerOffensive"),
}));
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("reportPlayerExploiting"),
}));
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("reportPlayerCheating"),
}));
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("reportPlayerBoosting"),
}));
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("setCardIcon"),
create.Char('('),
create.ScriptLocalVarIntOrLiteral(),
create.Char(')'),
})); // setCardIcon '(' ((localVarInt '(' <var name> ')') | <card icon index>) ')'
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("setCardTitle"),
create.Char('('),
create.ScriptLocalVarIntOrLiteral(),
create.Char(')'),
})); // setCardTitle '(' ((localVarInt '(' <var name> ')') | <card title index>) ')'
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("setCardIconNew"),
create.Char('('),
create.ScriptLocalVarIntOrLiteral(),
create.Char(','),
create.Or({
create.ScriptLocalVarIntOrLiteral(),
// This is wrong and the game does not even understand it. But because it's not a number it evaluates to 0...
// The game's menus do it and i don't want to fix it everywhere
create.ScriptKeyword("false"),
}),
create.Char(')'),
})); // setCardIconNew '(' ((localVarInt '(' <var name> ')') | <card icon index>) ',' ((localVarInt '(' <var name> ')') | <is new>) ')'
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("setCardTitleNew"),
create.Char('('),
create.ScriptLocalVarIntOrLiteral(),
create.Char(','),
create.Or({
create.ScriptLocalVarIntOrLiteral(),
// This is a hack (see setCardIconNew for details)
create.ScriptKeyword("false"),
}),
create.Char(')'),
})); // setCardTitleNew '(' ((localVarInt '(' <var name> ')') | <card icon index>) ',' ((localVarInt '(' <var name> ')') | <is new>) ')'
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("setCardIconSplitScreen"),
})); // unknown
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("setCardTitleSplitScreen"),
})); // unknown
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("setCardIconNewSplitScreen"),
})); // unknown
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("setCardTitleNewSplitScreen"),
})); // unknown
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("purchasePrestigeTitle"),
create.Char('('),
create.ScriptText(),
create.Char(')'),
})); // purchasePrestigeTitle '(' <title name> ')'
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("setProfileItemNew"),
create.Char('('),
create.ScriptText(),
create.Char(','),
create.ScriptLocalVarIntOrLiteral(),
create.Char(')'),
})); // setProfileItemNew '(' <item name> ',' (0|1|(localVarInt '(' <var name> ')')) ')'
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("setProfileItemNewSplitScreen"),
})); // unknown
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("storePopupXuid"),
}));
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("getHostMigrateQuestion"),
}));
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("makeHost"),
}));
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("saveGameHide"),
})); // saveGameHide <item name>
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("saveGameShow"),
})); // saveGameShow <item name>
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("saveGameSetLocalBool"),
create.ScriptText(),
})); // saveGameSetLocalBool <var name>
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("saveDelay"),
}));
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("writeSave"),
}));
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("setSaveExecOnSuccess"),
create.ScriptText(),
})); // setSaveExecOnSuccess <command>
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("nextLevel"),
}));
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("disablePause"),
}));
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("enablePause"),
}));
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("runCompletionResolve"),
}));
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("clearCompletionResolve"),
}));
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("execWithResolve"),
create.ScriptText(),
}));
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("playMenuVideo"),
create.Char('('),
create.ScriptText(),
create.Char(','),
create.ScriptLocalVarIntOrLiteral(),
create.Char(','),
create.ScriptLocalVarBoolOrLiteral(),
create.Char(')'),
})); // playMenuVideo '(' <video name> ',' ((localVarInt '(' <var name> ')') | <offset>) ',' ((localVarBool '(' <var name> ')') |
// <maybe_looping_bool>) ')'
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("setBackgroundVideo"),
create.Char('('),
create.ScriptText(),
create.Char(')'),
})); // setBackgroundVideo '(' <video name or empty string> ')'
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("clearEntitlementNew"),
create.ScriptText(),
})); // clearEntitlementNew <entitlement name>
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("setPastTitleRank"),
})); // unknown
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("setPastTitlePrestige"),
})); // unknown
AddSequence(SequenceGenericScriptStatement::Create({
create.ScriptKeyword("anticheat_bancheck"),
create.ScriptStrictNumeric(),
})); // anticheat_bancheck <num>
// UiScripts
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("LoadSaveGames"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("LoadGame"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("SaveGame"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("ForceSave"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("DelSaveGame"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("SaveGameSort"),
create.ScriptStrictInt(),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("playerStart"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("saveComplete"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("saveRevert"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("resetvscroll"),
create.ScriptText(),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("RefreshLeaderboards"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("ViewGamerCard"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("OpenLeaderboard"),
create.ScriptText(),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("OpenLeaderboardExt"),
create.ScriptText(),
create.Optional(create.Text()),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("ClearLeaderboard"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("FriendStoreXUID"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("FriendClearXUID"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("FriendInvite"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("FriendJoin"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("FriendGamerCard"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("FriendReportOffensive"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("FriendReportExploiter"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("FriendReportCheater"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("FriendReportBooster"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("RecentPlayerStoreXUID"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("RecentPlayerClearXUID"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("RecentPlayerGamerCard"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("RecentPlayerFriendRequest"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("RecentPlayerShowGroups"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("RecentPlayerJoin"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("RecentPlayerInvite"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("RecentPlayerReportOffensive"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("RecentPlayerReportExploiter"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("RecentPlayerReportCheater"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("RecentPlayerReportBooster"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("FacebookStoreXUID"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("FacebookClearXUID"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("FacebookGamerCard"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("FacebookFriendRequest"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("FacebookPageRight"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("FacebookPageLeft"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("FacebookJoin"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("FacebookInvite"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("FacebookReportOffensive"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("FacebookReportExploiter"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("FacebookReportCheater"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("FacebookReportBooster"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("EliteClanStoreXUID"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("EliteClanClearXUID"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("EliteClanGamerCard"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("EliteClanFriendRequest"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("EliteClanJoin"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("EliteClanInvite"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("EliteClanReportOffensive"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("EliteClanReportExploiter"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("EliteClanReportCheater"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("EliteClanReportBooster"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("coopPlayerShowGroups"),
create.ScriptStrictInt(),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("simulateKeyPress"),
create.ScriptStrictInt(),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("commerceShowStore"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("voteTypeMap"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("voteMap"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("voteGame"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("RefreshServers"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("RefreshFilter"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("closeJoin"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("StopRefresh"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("TrimRecipeName"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("ResetRecipeList"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("SelectServer"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("ShowCurrentServerTooltip"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("voteTempBan"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("addFavorite"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("deleteFavorite"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("PlayDemo"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("SwitchSegmentTransition"),
create.ScriptStrictInt(),
create.ScriptStrictInt(),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("PreviewSegment"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("MoveSegment"),
create.ScriptStrictInt(),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("DeleteSegment"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("SetFocusOnSegmentButton"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("PopulateLocalDemoFileInformation"),
}));
AddSequence(std::make_unique<SequenceOnlineVault>());
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("Playlist"),
create.Or({
create.And({
create.ScriptKeyword("Open"),
create.ScriptStrictInt(),
}),
create.ScriptKeyword("DoAction"),
create.ScriptKeyword("Close"),
create.ScriptKeyword("CloseAll"),
}),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("UpdateArenas"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("SortChallengesTop"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("xlaunchelitesearch"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("xlaunchelitelaunch"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("xlaunchelitestore"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("LobbyShowGroups"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("addPlayerProfiles"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("createPlayerProfile"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("deletePlayerProfile"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("loadPlayerProfile"),
}));
AddSequence(SequenceUiScriptStatement::Create({
create.ScriptKeyword("selectActivePlayerProfile"),
}));
}
}
AddSequence(std::make_unique<SequenceSetLocalVar>());
AddSequence(std::make_unique<SequenceIf>());
AddSequence(std::make_unique<SequenceElseIf>());
AddSequence(std::make_unique<SequenceElse>());
AddSequence(std::make_unique<SequenceCloseBlock>());
if (permissive)
{
AddSequence(std::make_unique<SequenceSkipScriptToken>());
}
}