diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c99b8029d..9fadb8c82a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 "") diff --git a/apps/opencs/model/world/infoselectwrapper.cpp b/apps/opencs/model/world/infoselectwrapper.cpp index c22ae19d94..bdc7a7c3b4 100644 --- a/apps/opencs/model/world/infoselectwrapper.cpp +++ b/apps/opencs/model/world/infoselectwrapper.cpp @@ -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 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: diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 95c38671db..1389f443ab 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -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: { diff --git a/apps/openmw/mwdialogue/selectwrapper.cpp b/apps/openmw/mwdialogue/selectwrapper.cpp index f9469bf9a9..20d91237ee 100644 --- a/apps/openmw/mwdialogue/selectwrapper.cpp +++ b/apps/openmw/mwdialogue/selectwrapper.cpp @@ -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: diff --git a/apps/openmw/mwlua/dialoguebindings.cpp b/apps/openmw/mwlua/dialoguebindings.cpp index 6028d0e1b2..d2c9cbff23 100644 --- a/apps/openmw/mwlua/dialoguebindings.cpp +++ b/apps/openmw/mwlua/dialoguebindings.cpp @@ -283,6 +283,61 @@ namespace } return sol::optional(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("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 { + 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 { + 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 : std::false_type { }; + template <> + struct is_automagical : 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); } } diff --git a/components/esm3/dialoguecondition.hpp b/components/esm3/dialoguecondition.hpp index c06d50b601..c4069e01c1 100644 --- a/components/esm3/dialoguecondition.hpp +++ b/components/esm3/dialoguecondition.hpp @@ -52,7 +52,7 @@ namespace ESM Function_PcLightArmor, Function_PcShortBlade, Function_PcMarksman, - Function_PcMerchantile, + Function_PcMercantile, Function_PcSpeechcraft, Function_PcHandToHand, Function_PcGender, diff --git a/files/lua_api/openmw/core.lua b/files/lua_api/openmw/core.lua index 91d064a9b5..d7e8b7fe33 100644 --- a/files/lua_api/openmw/core.lua +++ b/files/lua_api/openmw/core.lua @@ -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