From 99ae52e94ca1443bee0bb16d918de164cd5e620f Mon Sep 17 00:00:00 2001 From: SkyHasACat Date: Sun, 3 Aug 2025 13:42:04 -0700 Subject: [PATCH] Add fields to record --- apps/openmw/mwlua/types/actor.hpp | 13 ++--- apps/openmw/mwlua/types/npc.cpp | 56 ++++++++++++--------- apps/openmw/mwlua/types/servicesoffered.hpp | 26 ++++++++++ files/lua_api/openmw/types.lua | 3 ++ 4 files changed, 64 insertions(+), 34 deletions(-) create mode 100644 apps/openmw/mwlua/types/servicesoffered.hpp diff --git a/apps/openmw/mwlua/types/actor.hpp b/apps/openmw/mwlua/types/actor.hpp index 425e44451b..f55089c5a4 100644 --- a/apps/openmw/mwlua/types/actor.hpp +++ b/apps/openmw/mwlua/types/actor.hpp @@ -16,6 +16,7 @@ #include "../context.hpp" +#include "servicesoffered.hpp" namespace MWLua { @@ -25,15 +26,6 @@ namespace MWLua record["servicesOffered"] = sol::readonly_property([context](const T& rec) -> sol::table { sol::state_view lua = context.sol(); sol::table providedServices(lua, sol::create); - constexpr std::array, 19> serviceNames = { { { ESM::NPC::Spells, - "Spells" }, - { ESM::NPC::Spellmaking, "Spellmaking" }, { ESM::NPC::Enchanting, "Enchanting" }, - { ESM::NPC::Training, "Training" }, { ESM::NPC::Repair, "Repair" }, { ESM::NPC::AllItems, "Barter" }, - { ESM::NPC::Weapon, "Weapon" }, { ESM::NPC::Armor, "Armor" }, { ESM::NPC::Clothing, "Clothing" }, - { ESM::NPC::Books, "Books" }, { ESM::NPC::Ingredients, "Ingredients" }, { ESM::NPC::Picks, "Picks" }, - { ESM::NPC::Probes, "Probes" }, { ESM::NPC::Lights, "Lights" }, { ESM::NPC::Apparatus, "Apparatus" }, - { ESM::NPC::RepairItem, "RepairItem" }, { ESM::NPC::Misc, "Misc" }, { ESM::NPC::Potions, "Potions" }, - { ESM::NPC::MagicItems, "MagicItems" } } }; int services = rec.mAiData.mServices; if constexpr (std::is_same_v) @@ -42,10 +34,11 @@ namespace MWLua services = MWBase::Environment::get().getESMStore()->get().find(rec.mClass)->mData.mServices; } - for (const auto& [flag, name] : serviceNames) + for (const auto& [flag, name] : ServiceNames) { providedServices[name] = (services & flag) != 0; } + providedServices["Travel"] = !rec.getTransport().empty(); return LuaUtil::makeReadOnly(providedServices); }); diff --git a/apps/openmw/mwlua/types/npc.cpp b/apps/openmw/mwlua/types/npc.cpp index 2f6b0fa0ba..c0ffce9402 100644 --- a/apps/openmw/mwlua/types/npc.cpp +++ b/apps/openmw/mwlua/types/npc.cpp @@ -2,6 +2,7 @@ #include "actor.hpp" #include "modelproperty.hpp" +#include "servicesoffered.hpp" #include #include @@ -58,6 +59,8 @@ namespace npc.mHead = ESM::RefId::deserializeText(rec["head"].get()); if (rec["hair"] != sol::nil) npc.mHair = ESM::RefId::deserializeText(rec["hair"].get()); + if (rec["primaryFaction"] != sol::nil) + npc.mFaction = ESM::RefId::deserializeText(rec["primaryFaction"].get()); if (rec["isMale"] != sol::nil) { @@ -77,6 +80,15 @@ namespace npc.mFlags &= ~ESM::NPC::Essential; } + if (rec["autocalc"] != sol::nil) + { + bool respawn = rec["autocalc"]; + if (respawn) + npc.mFlags |= ESM::NPC::Autocalc; + else + npc.mFlags &= ~ESM::NPC::Autocalc; + } + if (rec["isRespawning"] != sol::nil) { bool respawn = rec["isRespawning"]; @@ -95,35 +107,20 @@ namespace if (rec["bloodType"] != sol::nil) npc.mBloodType = rec["bloodType"].get(); - // Services offered + if (rec["primaryFactionRank"] != sol::nil) + npc.mNpdt.mRank = rec["primaryFactionRank"].get(); + if (rec["servicesOffered"] != sol::nil) { const sol::table services = rec["servicesOffered"]; int flags = 0; - auto setFlag = [&](std::string_view key, int mask) { - if (services[key] != sol::nil && services[key]) - flags |= mask; - }; - setFlag("Spells", ESM::NPC::Spells); - setFlag("Spellmaking", ESM::NPC::Spellmaking); - setFlag("Enchanting", ESM::NPC::Enchanting); - setFlag("Training", ESM::NPC::Training); - setFlag("Repair", ESM::NPC::Repair); - setFlag("Barter", ESM::NPC::AllItems); - setFlag("Weapon", ESM::NPC::Weapon); - setFlag("Armor", ESM::NPC::Armor); - setFlag("Clothing", ESM::NPC::Clothing); - setFlag("Books", ESM::NPC::Books); - setFlag("Ingredients", ESM::NPC::Ingredients); - setFlag("Picks", ESM::NPC::Picks); - setFlag("Probes", ESM::NPC::Probes); - setFlag("Lights", ESM::NPC::Lights); - setFlag("Apparatus", ESM::NPC::Apparatus); - setFlag("RepairItem", ESM::NPC::RepairItem); - setFlag("Misc", ESM::NPC::Misc); - setFlag("Potions", ESM::NPC::Potions); - setFlag("MagicItems", ESM::NPC::MagicItems); + for (const auto& [mask, key] : ServiceNames) + { + sol::object value = services[key]; + if (value != sol::nil && value.as()) + flags |= mask; + } npc.mAiData.mServices = flags; } @@ -198,9 +195,20 @@ namespace MWLua = sol::readonly_property([](const ESM::NPC& rec) -> int { return (int)rec.mNpdt.mDisposition; }); record["head"] = sol::readonly_property([](const ESM::NPC& rec) -> std::string { return rec.mHead.serializeText(); }); + record["primaryFaction"] = sol::readonly_property( + [](const ESM::NPC& rec) -> sol::optional { return LuaUtil::serializeRefId(rec.mFaction); }); + record["primaryFactionRank"] + = sol::readonly_property([](const ESM::NPC& rec, sol::this_state s) -> sol::object { + sol::state_view lua(s); + if (rec.mFaction.empty()) + return sol::make_object(lua, sol::nil); // return nil + return sol::make_object(lua, rec.mNpdt.mRank); // return the rank as a number + }); addModelProperty(record); record["isEssential"] = sol::readonly_property([](const ESM::NPC& rec) -> bool { return rec.mFlags & ESM::NPC::Essential; }); + record["autocalc"] + = sol::readonly_property([](const ESM::NPC& rec) -> bool { return rec.mFlags & ESM::NPC::Autocalc; }); record["isMale"] = sol::readonly_property([](const ESM::NPC& rec) -> bool { return rec.isMale(); }); record["isRespawning"] = sol::readonly_property([](const ESM::NPC& rec) -> bool { return rec.mFlags & ESM::NPC::Respawn; }); diff --git a/apps/openmw/mwlua/types/servicesoffered.hpp b/apps/openmw/mwlua/types/servicesoffered.hpp new file mode 100644 index 0000000000..c854baca4d --- /dev/null +++ b/apps/openmw/mwlua/types/servicesoffered.hpp @@ -0,0 +1,26 @@ +#pragma once +#include +#include +#include // for ESM::NPC constants + +inline constexpr std::array, 19> ServiceNames = {{ + { ESM::NPC::Spells, "Spells" }, + { ESM::NPC::Spellmaking, "Spellmaking" }, + { ESM::NPC::Enchanting, "Enchanting" }, + { ESM::NPC::Training, "Training" }, + { ESM::NPC::Repair, "Repair" }, + { ESM::NPC::AllItems, "Barter" }, + { ESM::NPC::Weapon, "Weapon" }, + { ESM::NPC::Armor, "Armor" }, + { ESM::NPC::Clothing, "Clothing" }, + { ESM::NPC::Books, "Books" }, + { ESM::NPC::Ingredients, "Ingredients" }, + { ESM::NPC::Picks, "Picks" }, + { ESM::NPC::Probes, "Probes" }, + { ESM::NPC::Lights, "Lights" }, + { ESM::NPC::Apparatus, "Apparatus" }, + { ESM::NPC::RepairItem, "RepairItem" }, + { ESM::NPC::Misc, "Misc" }, + { ESM::NPC::Potions, "Potions" }, + { ESM::NPC::MagicItems, "MagicItems" } +}}; \ No newline at end of file diff --git a/files/lua_api/openmw/types.lua b/files/lua_api/openmw/types.lua index 6e1bee5ab4..5f78467bdc 100644 --- a/files/lua_api/openmw/types.lua +++ b/files/lua_api/openmw/types.lua @@ -861,6 +861,9 @@ -- @field #boolean canWalk whether the creature can walk -- @field #boolean canUseWeapons whether the creature can use weapons and shields -- @field #boolean isBiped whether the creature is a biped +-- @field #boolean autocalc If true, the actors stats will be automatically calculated based on level and class. +-- @field #string primaryFaction Faction ID of the NPCs default faction. Nil if no faction +-- @field #number primaryFactionRank Faction rank of the NPCs default faction. Nil if no faction -- @field #boolean isEssential whether the creature is essential -- @field #boolean isRespawning whether the creature respawns after death -- @field #number bloodType integer representing the blood type of the Creature. Used to generate the correct blood vfx.