diff --git a/apps/openmw/mwlua/objectbindings.cpp b/apps/openmw/mwlua/objectbindings.cpp index 3508fdcd44..708792fa51 100644 --- a/apps/openmw/mwlua/objectbindings.cpp +++ b/apps/openmw/mwlua/objectbindings.cpp @@ -388,7 +388,7 @@ namespace MWLua objectT["setScale"] = [context](const GObject& object, float scale) { context.mLuaManager->addAction( [object, scale] { MWBase::Environment::get().getWorld()->scaleObject(object.ptr(), scale); }); - }; + };--adjustScale objectT["addScript"] = [context](const GObject& object, std::string_view path, sol::object initData) { const LuaUtil::ScriptsConfiguration& cfg = context.mLua->getConfiguration(); std::optional scriptId = cfg.findId(VFS::Path::Normalized(path)); diff --git a/apps/openmw/mwlua/types/npc.cpp b/apps/openmw/mwlua/types/npc.cpp index 380a2d1e9b..60f6325ea2 100644 --- a/apps/openmw/mwlua/types/npc.cpp +++ b/apps/openmw/mwlua/types/npc.cpp @@ -29,6 +29,138 @@ namespace sol }; } +namespace +{ +ESM::NPC tableToNPC(const sol::table& rec) +{ + ESM::NPC npc; + + // Start from template if provided + if (rec["template"] != sol::nil) + npc = LuaUtil::cast(rec["template"]); + else + npc.blank(); + + // Force dummy ID + npc.mId = ESM::RefId::deserializeText("blank"); + + // Basic fields + if (rec["name"] != sol::nil) + npc.mName = rec["name"]; + if (rec["model"] != sol::nil) + npc.mModel = Misc::ResourceHelpers::meshPathForESM3(rec["model"].get()); + if (rec["mwscript"] != sol::nil) + npc.mScript = ESM::RefId::deserializeText(rec["mwscript"].get()); + if (rec["race"] != sol::nil) + npc.mRace = ESM::RefId::deserializeText(rec["race"].get()); + if (rec["class"] != sol::nil) + npc.mClass = ESM::RefId::deserializeText(rec["class"].get()); + if (rec["head"] != sol::nil) + npc.mHead = ESM::RefId::deserializeText(rec["head"].get()); + if (rec["hair"] != sol::nil) + npc.mHair = ESM::RefId::deserializeText(rec["hair"].get()); + + if (rec["isMale"] != sol::nil) + { + bool male = rec["isMale"]; + if (male) + npc.mFlags &= ~ESM::NPC::Female; + else + npc.mFlags |= ESM::NPC::Female; + } + + if (rec["isEssential"] != sol::nil) + { + bool essential = rec["isEssential"]; + if (essential) + npc.mFlags |= ESM::NPC::Essential; + else + npc.mFlags &= ~ESM::NPC::Essential; + } + + if (rec["isRespawning"] != sol::nil) + { + bool respawn = rec["isRespawning"]; + if (respawn) + npc.mFlags |= ESM::NPC::Respawn; + else + npc.mFlags &= ~ESM::NPC::Respawn; + } + + if (rec["baseDisposition"] != sol::nil) + npc.mNpdt.mDisposition = static_cast(rec["baseDisposition"]); + + if (rec["baseGold"] != sol::nil) + npc.mNpdt.mGold = static_cast(rec["baseGold"]); + + if (rec["bloodType"] != sol::nil) + npc.mBloodType = static_cast(rec["bloodType"]); + + // Services offered + if (rec["servicesOffered"] != sol::nil) + { + const sol::table services = rec["servicesOffered"]; + int flags = 0; + auto setFlag = [&](const char* 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); + + npc.mAiData.mServices = flags; + } + + // Travel destinations + if (rec["travelDestinations"] != sol::nil) + { + const sol::table travelDests = rec["travelDestinations"]; + npc.mTransport.clear(); + for (std::size_t i = 1; i <= travelDests.size(); ++i) + { + sol::table t = travelDests[i]; + ESM::Transport destination; + + // Position + destination.mPos.pos = t["position"]; + destination.mPos.rot = Misc::Convert::toRotation(LuaUtil::fromTransform(t["rotation"])); + + // Cell + std::string cellId = t["cellId"]; + destination.mCellName = cellId; // If empty, it will be handled as exterior + + npc.mTransport.push_back(destination); + } + } + + return npc; +} + // Blood type + if (rec["bloodType"] != sol::nil) + npc.mBloodType = static_cast(rec["bloodType"]); + + return npc; + } +} + namespace { size_t getValidRanksCount(const ESM::Faction* faction) @@ -151,7 +283,7 @@ namespace MWLua auto& stats = cls.getNpcStats(o.ptr()); stats.setBaseDisposition(stats.getBaseDisposition() + value); }; - + npc["createRecordDraft"] = tableToNPC; npc["getFactionRank"] = [](const Object& actor, std::string_view faction) -> size_t { const MWWorld::Ptr ptr = actor.ptr(); ESM::RefId factionId = parseFactionId(faction); diff --git a/apps/openmw/mwlua/worldbindings.cpp b/apps/openmw/mwlua/worldbindings.cpp index c02bad3bd3..de8eec3710 100644 --- a/apps/openmw/mwlua/worldbindings.cpp +++ b/apps/openmw/mwlua/worldbindings.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -155,6 +156,11 @@ namespace MWLua MWWorld::Ptr newPtr = ptr.getClass().copyToCell(ptr, cell, count.value_or(1)); return GObject(newPtr); }; + api["advanceTime"] = [context](double hours, bool incremental) { + context.mLuaManager->addAction([ hours, incremental] { + MWBase::Environment::get().getWorld()->advanceTime(hours, incremental); + }); + }; api["getObjectByFormId"] = [](std::string_view formIdStr) -> GObject { ESM::RefId refId = ESM::RefId::deserializeText(formIdStr); if (!refId.is()) @@ -188,6 +194,10 @@ namespace MWLua checkGameInitialized(lua); return MWBase::Environment::get().getESMStore()->insert(potion); }, + [lua = context.mLua](const ESM::NPC& npc) -> const ESM::NPC* { + checkGameInitialized(lua); + return MWBase::Environment::get().getESMStore()->insert(npc); + }, [lua = context.mLua](const ESM::Weapon& weapon) -> const ESM::Weapon* { checkGameInitialized(lua); return MWBase::Environment::get().getESMStore()->insert(weapon);