1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2026-01-04 03:43:08 +00:00

Merge branch 'dialoguefilters' into 'master'

Expose info conditions to Lua

Closes #8076

See merge request OpenMW/openmw!5045
This commit is contained in:
Alexei Kotov 2025-12-19 04:33:39 +03:00
commit 7ca6fbb952
7 changed files with 275 additions and 8 deletions

View file

@ -82,7 +82,7 @@ message(STATUS "Configuring OpenMW...")
set(OPENMW_VERSION_MAJOR 0)
set(OPENMW_VERSION_MINOR 51)
set(OPENMW_VERSION_RELEASE 0)
set(OPENMW_LUA_API_REVISION 109)
set(OPENMW_LUA_API_REVISION 110)
set(OPENMW_POSTPROCESSING_API_REVISION 4)
set(OPENMW_VERSION_COMMITHASH "")

View file

@ -42,7 +42,7 @@ const char* CSMWorld::ConstInfoSelectWrapper::FunctionEnumStrings[] = {
"PC Light Armor",
"PC Short Blade",
"PC Marksman",
"PC Merchantile",
"PC Mercantile",
"PC Speechcraft",
"PC Hand to Hand",
"PC Sex",
@ -297,7 +297,7 @@ void CSMWorld::ConstInfoSelectWrapper::updateComparisonType()
case ESM::DialogueCondition::Function_PcLightArmor:
case ESM::DialogueCondition::Function_PcShortBlade:
case ESM::DialogueCondition::Function_PcMarksman:
case ESM::DialogueCondition::Function_PcMerchantile:
case ESM::DialogueCondition::Function_PcMercantile:
case ESM::DialogueCondition::Function_PcSpeechcraft:
case ESM::DialogueCondition::Function_PcHandToHand:
case ESM::DialogueCondition::Function_PcGender:
@ -485,7 +485,7 @@ std::pair<int, int> CSMWorld::ConstInfoSelectWrapper::getValidIntRange() const
case ESM::DialogueCondition::Function_PcLightArmor:
case ESM::DialogueCondition::Function_PcShortBlade:
case ESM::DialogueCondition::Function_PcMarksman:
case ESM::DialogueCondition::Function_PcMerchantile:
case ESM::DialogueCondition::Function_PcMercantile:
case ESM::DialogueCondition::Function_PcSpeechcraft:
case ESM::DialogueCondition::Function_PcHandToHand:
case ESM::DialogueCondition::Function_PcClothingModifier:

View file

@ -426,7 +426,7 @@ int MWDialogue::Filter::getSelectStructInteger(const SelectWrapper& select) cons
case ESM::DialogueCondition::Function_PcLightArmor:
case ESM::DialogueCondition::Function_PcShortBlade:
case ESM::DialogueCondition::Function_PcMarksman:
case ESM::DialogueCondition::Function_PcMerchantile:
case ESM::DialogueCondition::Function_PcMercantile:
case ESM::DialogueCondition::Function_PcSpeechcraft:
case ESM::DialogueCondition::Function_PcHandToHand:
{

View file

@ -130,7 +130,7 @@ int MWDialogue::SelectWrapper::getArgument() const
return 22;
case ESM::DialogueCondition::Function_PcMarksman:
return 23;
case ESM::DialogueCondition::Function_PcMerchantile:
case ESM::DialogueCondition::Function_PcMercantile:
return 24;
case ESM::DialogueCondition::Function_PcSpeechcraft:
return 25;
@ -193,7 +193,7 @@ MWDialogue::SelectWrapper::Type MWDialogue::SelectWrapper::getType() const
case ESM::DialogueCondition::Function_PcLightArmor:
case ESM::DialogueCondition::Function_PcShortBlade:
case ESM::DialogueCondition::Function_PcMarksman:
case ESM::DialogueCondition::Function_PcMerchantile:
case ESM::DialogueCondition::Function_PcMercantile:
case ESM::DialogueCondition::Function_PcSpeechcraft:
case ESM::DialogueCondition::Function_PcHandToHand:
case ESM::DialogueCondition::Function_FriendHit:

View file

@ -283,6 +283,61 @@ namespace
}
return sol::optional<std::string_view>(rec.mResultScript);
});
recordInfoBindingsClass["conditions"]
= sol::readonly_property([lua = lua.lua_state()](const ESM::DialInfo& rec) -> sol::object {
if (rec.mData.mType == ESM::Dialogue::Type::Journal)
return sol::nil;
sol::table res(lua, sol::create);
for (const ESM::DialogueCondition& condition : rec.mSelects)
res.add(&condition);
return res;
});
}
void prepareBindingsForDialogueConditions(sol::state_view& lua)
{
auto conditionBindingsClass = lua.new_usertype<ESM::DialogueCondition>("ESM3_Dialogue_Info_Condition");
conditionBindingsClass["type"] = sol::readonly_property(
[](const ESM::DialogueCondition& condition) -> int { return condition.mFunction; });
conditionBindingsClass["operator"] = sol::readonly_property(
[](const ESM::DialogueCondition& condition) -> int { return condition.mComparison; });
conditionBindingsClass["value"] = sol::readonly_property([](const ESM::DialogueCondition& condition) -> double {
return std::visit([](auto value) -> double { return value; }, condition.mValue);
});
conditionBindingsClass["recordId"]
= sol::readonly_property([](const ESM::DialogueCondition& condition) -> ESM::RefId {
switch (condition.mFunction)
{
case ESM::DialogueCondition::Function::Function_Journal:
case ESM::DialogueCondition::Function::Function_Item:
case ESM::DialogueCondition::Function::Function_Dead:
case ESM::DialogueCondition::Function::Function_NotId:
case ESM::DialogueCondition::Function::Function_NotFaction:
case ESM::DialogueCondition::Function::Function_NotClass:
case ESM::DialogueCondition::Function::Function_NotRace:
return ESM::StringRefId(condition.mVariable);
default:
return {};
}
});
conditionBindingsClass["variableName"]
= sol::readonly_property([](const ESM::DialogueCondition& condition) -> std::optional<std::string> {
switch (condition.mFunction)
{
case ESM::DialogueCondition::Function::Function_Global:
case ESM::DialogueCondition::Function::Function_Local:
case ESM::DialogueCondition::Function::Function_NotLocal:
return Misc::StringUtils::lowerCase(condition.mVariable);
default:
return {};
}
});
conditionBindingsClass["cellName"]
= sol::readonly_property([](const ESM::DialogueCondition& condition) -> std::optional<std::string_view> {
if (condition.mFunction == ESM::DialogueCondition::Function::Function_NotCell)
return condition.mVariable;
return {};
});
}
void prepareBindingsForDialogueRecords(sol::state_view& lua)
@ -290,6 +345,7 @@ namespace
prepareBindingsForDialogueRecord(lua);
prepareBindingsForDialogueRecordInfoList(lua);
prepareBindingsForDialogueRecordInfoListElement(lua);
prepareBindingsForDialogueConditions(lua);
}
}
@ -311,6 +367,10 @@ namespace sol
struct is_automagical<ESM::DialInfo> : std::false_type
{
};
template <>
struct is_automagical<ESM::DialogueCondition> : std::false_type
{
};
}
namespace MWLua
@ -338,6 +398,96 @@ namespace MWLua
prepareBindingsForDialogueRecords(lua);
api["CONDITION_OPERATOR"] = LuaUtil::makeStrictReadOnly(
lua.create_table_with("Equal", ESM::DialogueCondition::Comparison::Comp_Eq, "NotEqual",
ESM::DialogueCondition::Comparison::Comp_Ne, "Greater", ESM::DialogueCondition::Comparison::Comp_Gt,
"GreaterEqual", ESM::DialogueCondition::Comparison::Comp_Ge, "Less",
ESM::DialogueCondition::Comparison::Comp_Ls, "LessEqual", ESM::DialogueCondition::Comparison::Comp_Le));
api["CONDITION_TYPE"] = LuaUtil::makeStrictReadOnly(lua.create_table_with("FacReactionLowest",
ESM::DialogueCondition::Function::Function_FacReactionLowest, "FacReactionHighest",
ESM::DialogueCondition::Function::Function_FacReactionHighest, "RankRequirement",
ESM::DialogueCondition::Function::Function_RankRequirement, "Reputation",
ESM::DialogueCondition::Function::Function_Reputation, "HealthPercent",
ESM::DialogueCondition::Function::Function_Health_Percent, "PcReputation",
ESM::DialogueCondition::Function::Function_PcReputation, "PcLevel",
ESM::DialogueCondition::Function::Function_PcLevel, "PcHealthPercent",
ESM::DialogueCondition::Function::Function_PcHealthPercent, "PcMagicka",
ESM::DialogueCondition::Function::Function_PcMagicka, "PcFatigue",
ESM::DialogueCondition::Function::Function_PcFatigue, "PcStrength",
ESM::DialogueCondition::Function::Function_PcStrength, "PcBlock",
ESM::DialogueCondition::Function::Function_PcBlock, "PcArmorer",
ESM::DialogueCondition::Function::Function_PcArmorer, "PcMediumArmor",
ESM::DialogueCondition::Function::Function_PcMediumArmor, "PcHeavyArmor",
ESM::DialogueCondition::Function::Function_PcHeavyArmor, "PcBluntWeapon",
ESM::DialogueCondition::Function::Function_PcBluntWeapon, "PcLongBlade",
ESM::DialogueCondition::Function::Function_PcLongBlade, "PcAxe",
ESM::DialogueCondition::Function::Function_PcAxe, "PcSpear",
ESM::DialogueCondition::Function::Function_PcSpear, "PcAthletics",
ESM::DialogueCondition::Function::Function_PcAthletics, "PcEnchant",
ESM::DialogueCondition::Function::Function_PcEnchant, "PcDestruction",
ESM::DialogueCondition::Function::Function_PcDestruction, "PcAlteration",
ESM::DialogueCondition::Function::Function_PcAlteration, "PcIllusion",
ESM::DialogueCondition::Function::Function_PcIllusion, "PcConjuration",
ESM::DialogueCondition::Function::Function_PcConjuration, "PcMysticism",
ESM::DialogueCondition::Function::Function_PcMysticism, "PcRestoration",
ESM::DialogueCondition::Function::Function_PcRestoration, "PcAlchemy",
ESM::DialogueCondition::Function::Function_PcAlchemy, "PcUnarmored",
ESM::DialogueCondition::Function::Function_PcUnarmored, "PcSecurity",
ESM::DialogueCondition::Function::Function_PcSecurity, "PcSneak",
ESM::DialogueCondition::Function::Function_PcSneak, "PcAcrobatics",
ESM::DialogueCondition::Function::Function_PcAcrobatics, "PcLightArmor",
ESM::DialogueCondition::Function::Function_PcLightArmor, "PcShortBlade",
ESM::DialogueCondition::Function::Function_PcShortBlade, "PcMarksman",
ESM::DialogueCondition::Function::Function_PcMarksman, "PcMercantile",
ESM::DialogueCondition::Function::Function_PcMercantile, "PcSpeechcraft",
ESM::DialogueCondition::Function::Function_PcSpeechcraft, "PcHandToHand",
ESM::DialogueCondition::Function::Function_PcHandToHand, "PcGender",
ESM::DialogueCondition::Function::Function_PcGender, "PcExpelled",
ESM::DialogueCondition::Function::Function_PcExpelled, "PcCommonDisease",
ESM::DialogueCondition::Function::Function_PcCommonDisease, "PcBlightDisease",
ESM::DialogueCondition::Function::Function_PcBlightDisease, "PcClothingModifier",
ESM::DialogueCondition::Function::Function_PcClothingModifier, "PcCrimeLevel",
ESM::DialogueCondition::Function::Function_PcCrimeLevel, "SameGender",
ESM::DialogueCondition::Function::Function_SameSex, "SameRace",
ESM::DialogueCondition::Function::Function_SameRace, "SameFaction",
ESM::DialogueCondition::Function::Function_SameFaction, "FactionRankDifference",
ESM::DialogueCondition::Function::Function_FactionRankDifference, "Detected",
ESM::DialogueCondition::Function::Function_Detected, "Alarmed",
ESM::DialogueCondition::Function::Function_Alarmed, "Choice",
ESM::DialogueCondition::Function::Function_Choice, "PcIntelligence",
ESM::DialogueCondition::Function::Function_PcIntelligence, "PcWillpower",
ESM::DialogueCondition::Function::Function_PcWillpower, "PcAgility",
ESM::DialogueCondition::Function::Function_PcAgility, "PcSpeed",
ESM::DialogueCondition::Function::Function_PcSpeed, "PcEndurance",
ESM::DialogueCondition::Function::Function_PcEndurance, "PcPersonality",
ESM::DialogueCondition::Function::Function_PcPersonality, "PcLuck",
ESM::DialogueCondition::Function::Function_PcLuck, "PcCorprus",
ESM::DialogueCondition::Function::Function_PcCorprus, "Weather",
ESM::DialogueCondition::Function::Function_Weather, "PcVampire",
ESM::DialogueCondition::Function::Function_PcVampire, "Level",
ESM::DialogueCondition::Function::Function_Level, "Attacked",
ESM::DialogueCondition::Function::Function_Attacked, "TalkedToPc",
ESM::DialogueCondition::Function::Function_TalkedToPc, "PcHealth",
ESM::DialogueCondition::Function::Function_PcHealth, "CreatureTarget",
ESM::DialogueCondition::Function::Function_CreatureTarget, "FriendHit",
ESM::DialogueCondition::Function::Function_FriendHit, "Fight",
ESM::DialogueCondition::Function::Function_Fight, "Hello", ESM::DialogueCondition::Function::Function_Hello,
"Alarm", ESM::DialogueCondition::Function::Function_Alarm, "Flee",
ESM::DialogueCondition::Function::Function_Flee, "ShouldAttack",
ESM::DialogueCondition::Function::Function_ShouldAttack, "Werewolf",
ESM::DialogueCondition::Function::Function_Werewolf, "PcWerewolfKills",
ESM::DialogueCondition::Function::Function_PcWerewolfKills, "Global",
ESM::DialogueCondition::Function::Function_Global, "Local",
ESM::DialogueCondition::Function::Function_Local, "Journal",
ESM::DialogueCondition::Function::Function_Journal, "Item", ESM::DialogueCondition::Function::Function_Item,
"Dead", ESM::DialogueCondition::Function::Function_Dead, "NotId",
ESM::DialogueCondition::Function::Function_NotId, "NotFaction",
ESM::DialogueCondition::Function::Function_NotFaction, "NotClass",
ESM::DialogueCondition::Function::Function_NotClass, "NotRace",
ESM::DialogueCondition::Function::Function_NotRace, "NotCell",
ESM::DialogueCondition::Function::Function_NotCell, "NotLocal",
ESM::DialogueCondition::Function::Function_NotLocal));
return LuaUtil::makeReadOnly(api);
}
}

View file

@ -52,7 +52,7 @@ namespace ESM
Function_PcLightArmor,
Function_PcShortBlade,
Function_PcMarksman,
Function_PcMerchantile,
Function_PcMercantile,
Function_PcSpeechcraft,
Function_PcHandToHand,
Function_PcGender,

View file

@ -1165,6 +1165,123 @@
-- Always nil for journal records or if there is no value set.
-- @field [parent=#DialogueRecordInfo] #string resultScript
---
-- A read-only list of @{#DialogueInfoCondition}s.
-- Always nil for journal records.
-- @field [parent=#DialogueRecordInfo] #list<#DialogueInfoCondition> conditions
---
-- @type DialogueInfoCondition
-- @field #DialogueConditionOperator operator The #{#DialogueConditionOperator} to use in the comparison
-- @field #DialogueConditionType type The condition's @{#DialogueConditionType}
-- @field #number value The value to compare to
-- @field #string recordId The record ID to use in the comparison
-- @field #string variableName The name of the global or local mwscript variable to compare to
-- @field #string cellName The cell name to compare to
--- Possible @{#DialogueConditionOperator} values
-- @field [parent=#Dialogue] #DialogueConditionOperator CONDITION_OPERATOR
--- `core.dialogue.CONDITION_OPERATOR`
-- @type DialogueConditionOperator
-- @field #number Equal ==
-- @field #number NotEqual !=
-- @field #number Greater >
-- @field #number GreaterEqual >=
-- @field #number Less <
-- @field #number LessEqual <=
--- Possible @{#DialogueConditionType} values
-- @field [parent=#Dialogue] #DialogueConditionType CONDITION_TYPE
--- `core.dialogue.CONDITION_TYPE`
-- @type DialogueConditionType
-- @field #number FacReactionLowest Lowest faction reaction from the speaker's primary faction to the player's factions
-- @field #number FacReactionHighest Highest faction reaction from the speaker's primary faction to the player's factions
-- @field #number RankRequirement Check whether the player can advance in the speaker's primary faction
-- @field #number Reputation The speaker's reputation
-- @field #number HealthPercent The speaker's health percentage
-- @field #number PcReputation The player's reputation
-- @field #number PcLevel The player's level
-- @field #number PcHealthPercent The player's health percentage
-- @field #number PcMagicka The player's current magicka
-- @field #number PcFatigue The player's current fatigue
-- @field #number PcStrength The player's current strength
-- @field #number PcBlock The player's current block
-- @field #number PcArmorer The player's current armorer
-- @field #number PcMediumArmor The player's current medium armor
-- @field #number PcHeavyArmor The player's current heavy armor
-- @field #number PcBluntWeapon The player's current blunt weapon
-- @field #number PcLongBlade The player's current long blade
-- @field #number PcAxe The player's current axe
-- @field #number PcSpear The player's current spear
-- @field #number PcAthletics The player's current athletics
-- @field #number PcEnchant The player's current enchant
-- @field #number PcDestruction The player's current destruction
-- @field #number PcAlteration The player's current alteration
-- @field #number PcIllusion The player's current illusion
-- @field #number PcConjuration The player's current conjuration
-- @field #number PcMysticism The player's current mysticism
-- @field #number PcRestoration The player's current restoration
-- @field #number PcAlchemy The player's current alchemy
-- @field #number PcUnarmored The player's current unarmored
-- @field #number PcSecurity The player's current security
-- @field #number PcSneak The player's current sneak
-- @field #number PcAcrobatics The player's current acrobatics
-- @field #number PcLightArmor The player's current light armor
-- @field #number PcShortBlade The player's current short blade
-- @field #number PcMarksman The player's current marksman
-- @field #number PcMercantile The player's current mercantile
-- @field #number PcSpeechcraft The player's current speechcraft
-- @field #number PcHandToHand The player's current hand to hand
-- @field #number PcGender The player's gender
-- @field #number PcExpelled Check whether the player has been expelled from the speaker's primary faction
-- @field #number PcCommonDisease Check if the player has a common disease
-- @field #number PcBlightDisease Check if the player has a blight disease
-- @field #number PcClothingModifier Check the combined value of the player's outfit
-- @field #number PcCrimeLevel The player's bounty
-- @field #number SameGender Check if the speaker's gender matches the player's
-- @field #number SameRace Check if the speaker's race matches the player's
-- @field #number SameFaction Check if the player is a member of the speaker's primary faction
-- @field #number FactionRankDifference The difference between the player's rank in the speaker's primary faction and the speaker's
-- @field #number Detected Whether the speaker has detected the player
-- @field #number Alarmed Whether the speaker was alarmed by the player's crime
-- @field #number Choice The choice index
-- @field #number PcIntelligence The player's current intelligence
-- @field #number PcWillpower The player's current willpower
-- @field #number PcAgility The player's current agility
-- @field #number PcSpeed The player's current speed
-- @field #number PcEndurance The player's current endurance
-- @field #number PcPersonality The player's current personality
-- @field #number PcLuck The player's current luck
-- @field #number PcCorprus Whether the player is affected by the Corprus magic effect
-- @field #number Weather Checks the scriptId of the weather in the player's cell
-- @field #number PcVampire Whether the player is affected by the Vampirism magic effect
-- @field #number Level The speaker's level
-- @field #number Attacked Whether the speaker was attacked
-- @field #number TalkedToPc Whether the speaker has talked to the player before
-- @field #number PcHealth The player's current health
-- @field #number CreatureTarget Whether the speaker is targeting a creature
-- @field #number FriendHit The number of times the player has hit the speaker follower
-- @field #number Fight The speaker's current fight
-- @field #number Hello The speaker's current hello
-- @field #number Alarm The speaker's current alarm
-- @field #number Flee The speaker's current flee
-- @field #number ShouldAttack Whether the speaker would start combat with the player
-- @field #number Werewolf Whether the speaker is in werewolf form
-- @field #number PcWerewolfKills The number of werewolves killed by the player
-- @field #number Global A comparison to the @{#DialogueInfoCondition.variableName} global variable
-- @field #number Local A comparison to the speaker's @{#DialogueInfoCondition.variableName} local variable
-- @field #number Journal A comparison to the player's @{#DialogueInfoCondition.recordId} journal index
-- @field #number Item The number of copies of @{#DialogueInfoCondition.recordId} the player is carrying
-- @field #number Dead The number of dead actors of the given @{#DialogueInfoCondition.recordId}
-- @field #number NotId The speaker's recordId should not match @{#DialogueInfoCondition.recordId}
-- @field #number NotFaction The speaker's faction ID should not match @{#DialogueInfoCondition.recordId}
-- @field #number NotClass The speaker's class should not match @{#DialogueInfoCondition.recordId}
-- @field #number NotRace The speaker's race should not match @{#DialogueInfoCondition.recordId}
-- @field #number NotCell The player's cell name should not start with @{#DialogueInfoCondition.cellName}
-- @field #number NotLocal A comparison to the speaker's @{#DialogueInfoCondition.variableName} local variable
--- @{#Regions}: Regions
-- @field [parent=#core] #Regions regions