mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-08-03 23:36:59 -04:00
Merge branch 'createnewpeople' into 'master'
Allow creating new NPC records via lua See merge request OpenMW/openmw!4825
This commit is contained in:
commit
a25c88c1e0
@ -29,6 +29,110 @@ 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<ESM::NPC>(rec["template"]);
|
||||||
|
else
|
||||||
|
npc.blank();
|
||||||
|
|
||||||
|
if (npc.mId == ESM::RefId::deserializeText("Player"))
|
||||||
|
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<std::string_view>());
|
||||||
|
if (rec["mwscript"] != sol::nil)
|
||||||
|
npc.mScript = ESM::RefId::deserializeText(rec["mwscript"].get<std::string_view>());
|
||||||
|
if (rec["race"] != sol::nil)
|
||||||
|
npc.mRace = ESM::RefId::deserializeText(rec["race"].get<std::string_view>());
|
||||||
|
if (rec["class"] != sol::nil)
|
||||||
|
npc.mClass = ESM::RefId::deserializeText(rec["class"].get<std::string_view>());
|
||||||
|
if (rec["head"] != sol::nil)
|
||||||
|
npc.mHead = ESM::RefId::deserializeText(rec["head"].get<std::string_view>());
|
||||||
|
if (rec["hair"] != sol::nil)
|
||||||
|
npc.mHair = ESM::RefId::deserializeText(rec["hair"].get<std::string_view>());
|
||||||
|
|
||||||
|
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 = rec["baseDisposition"].get<int>();
|
||||||
|
|
||||||
|
if (rec["baseGold"] != sol::nil)
|
||||||
|
npc.mNpdt.mGold = rec["baseGold"].get<int>();
|
||||||
|
|
||||||
|
if (rec["bloodType"] != sol::nil)
|
||||||
|
npc.mBloodType = rec["bloodType"].get<int>();
|
||||||
|
|
||||||
|
// Services offered
|
||||||
|
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);
|
||||||
|
|
||||||
|
npc.mAiData.mServices = flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
return npc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
size_t getValidRanksCount(const ESM::Faction* faction)
|
size_t getValidRanksCount(const ESM::Faction* faction)
|
||||||
@ -152,6 +256,7 @@ namespace MWLua
|
|||||||
stats.setBaseDisposition(stats.getBaseDisposition() + value);
|
stats.setBaseDisposition(stats.getBaseDisposition() + value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
npc["createRecordDraft"] = tableToNPC;
|
||||||
npc["getFactionRank"] = [](const Object& actor, std::string_view faction) -> size_t {
|
npc["getFactionRank"] = [](const Object& actor, std::string_view faction) -> size_t {
|
||||||
const MWWorld::Ptr ptr = actor.ptr();
|
const MWWorld::Ptr ptr = actor.ptr();
|
||||||
ESM::RefId factionId = parseFactionId(faction);
|
ESM::RefId factionId = parseFactionId(faction);
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include <components/esm3/loadclot.hpp>
|
#include <components/esm3/loadclot.hpp>
|
||||||
#include <components/esm3/loadligh.hpp>
|
#include <components/esm3/loadligh.hpp>
|
||||||
#include <components/esm3/loadmisc.hpp>
|
#include <components/esm3/loadmisc.hpp>
|
||||||
|
#include <components/esm3/loadnpc.hpp>
|
||||||
#include <components/esm3/loadskil.hpp>
|
#include <components/esm3/loadskil.hpp>
|
||||||
#include <components/esm3/loadweap.hpp>
|
#include <components/esm3/loadweap.hpp>
|
||||||
#include <components/lua/luastate.hpp>
|
#include <components/lua/luastate.hpp>
|
||||||
@ -188,6 +189,10 @@ namespace MWLua
|
|||||||
checkGameInitialized(lua);
|
checkGameInitialized(lua);
|
||||||
return MWBase::Environment::get().getESMStore()->insert(potion);
|
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* {
|
[lua = context.mLua](const ESM::Weapon& weapon) -> const ESM::Weapon* {
|
||||||
checkGameInitialized(lua);
|
checkGameInitialized(lua);
|
||||||
return MWBase::Environment::get().getESMStore()->insert(weapon);
|
return MWBase::Environment::get().getESMStore()->insert(weapon);
|
||||||
|
@ -726,8 +726,6 @@ namespace MWWorld
|
|||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case ESM::REC_ALCH:
|
case ESM::REC_ALCH:
|
||||||
case ESM::REC_MISC:
|
|
||||||
case ESM::REC_ACTI:
|
|
||||||
case ESM::REC_ARMO:
|
case ESM::REC_ARMO:
|
||||||
case ESM::REC_BOOK:
|
case ESM::REC_BOOK:
|
||||||
case ESM::REC_CLAS:
|
case ESM::REC_CLAS:
|
||||||
@ -735,14 +733,16 @@ namespace MWWorld
|
|||||||
case ESM::REC_ENCH:
|
case ESM::REC_ENCH:
|
||||||
case ESM::REC_SPEL:
|
case ESM::REC_SPEL:
|
||||||
case ESM::REC_WEAP:
|
case ESM::REC_WEAP:
|
||||||
case ESM::REC_LEVI:
|
|
||||||
case ESM::REC_LEVC:
|
|
||||||
case ESM::REC_LIGH:
|
|
||||||
mStoreImp->mRecNameToStore[type]->read(reader);
|
mStoreImp->mRecNameToStore[type]->read(reader);
|
||||||
return true;
|
return true;
|
||||||
case ESM::REC_NPC_:
|
case ESM::REC_NPC_:
|
||||||
case ESM::REC_CREA:
|
case ESM::REC_CREA:
|
||||||
case ESM::REC_CONT:
|
case ESM::REC_CONT:
|
||||||
|
case ESM::REC_MISC:
|
||||||
|
case ESM::REC_ACTI:
|
||||||
|
case ESM::REC_LEVI:
|
||||||
|
case ESM::REC_LEVC:
|
||||||
|
case ESM::REC_LIGH:
|
||||||
mStoreImp->mRecNameToStore[type]->read(reader, true);
|
mStoreImp->mRecNameToStore[type]->read(reader, true);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -269,13 +269,29 @@ namespace MWWorld
|
|||||||
list.push_back((*it)->mId);
|
list.push_back((*it)->mId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
template <class IdType, class StaticMap>
|
||||||
|
inline bool shouldInsert(const IdType& id, const StaticMap& map)
|
||||||
|
{
|
||||||
|
auto it = map.find(id);
|
||||||
|
return it != map.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class StaticMap>
|
||||||
|
inline bool shouldInsert(const ESM::RefId& id, const StaticMap& map)
|
||||||
|
{
|
||||||
|
if (!id.template is<ESM::GeneratedRefId>())
|
||||||
|
{
|
||||||
|
auto it = map.find(id);
|
||||||
|
return it != map.end();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
template <class T, class Id>
|
template <class T, class Id>
|
||||||
T* TypedDynamicStore<T, Id>::insert(const T& item, bool overrideOnly)
|
T* TypedDynamicStore<T, Id>::insert(const T& item, bool overrideOnly)
|
||||||
{
|
{
|
||||||
if (overrideOnly)
|
if (overrideOnly)
|
||||||
{
|
{
|
||||||
auto it = mStatic.find(item.mId);
|
if (!shouldInsert(item.mId, mStatic))
|
||||||
if (it == mStatic.end())
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
std::pair<typename Dynamic::iterator, bool> result = mDynamic.insert_or_assign(item.mId, item);
|
std::pair<typename Dynamic::iterator, bool> result = mDynamic.insert_or_assign(item.mId, item);
|
||||||
|
@ -875,6 +875,13 @@
|
|||||||
-- @field #Actor baseType @{#Actor}
|
-- @field #Actor baseType @{#Actor}
|
||||||
-- @field [parent=#NPC] #NpcStats stats
|
-- @field [parent=#NPC] #NpcStats stats
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Creates a @{#NpcRecord} without adding it to the world database.
|
||||||
|
-- Use @{openmw_world#(world).createRecord} to add the record to the world.
|
||||||
|
-- @function [parent=#NPC] createRecordDraft
|
||||||
|
-- @param #NpcRecord book A Lua table with the fields of a NpcRecord, with an optional field `template` that accepts a @{#NpcRecord} as a base.
|
||||||
|
-- @return #NpcRecord A strongly typed NPC record.
|
||||||
|
|
||||||
---
|
---
|
||||||
-- A read-only list of all @{#NpcRecord}s in the world database, may be indexed by recordId.
|
-- A read-only list of all @{#NpcRecord}s in the world database, may be indexed by recordId.
|
||||||
-- Implements [iterables#List](iterables.html#List) of #NpcRecord.
|
-- Implements [iterables#List](iterables.html#List) of #NpcRecord.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user