mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-15 22:49:48 +00:00
Merge branch 'raciallybound' into 'master'
Expose races to Lua See merge request OpenMW/openmw!3863
This commit is contained in:
commit
d168466034
@ -64,7 +64,7 @@ add_openmw_dir (mwlua
|
||||
context menuscripts globalscripts localscripts playerscripts luabindings objectbindings cellbindings
|
||||
mwscriptbindings camerabindings vfsbindings uibindings soundbindings inputbindings nearbybindings
|
||||
postprocessingbindings stats debugbindings corebindings worldbindings worker magicbindings factionbindings
|
||||
classbindings itemdata inputprocessor animationbindings birthsignbindings
|
||||
classbindings itemdata inputprocessor animationbindings birthsignbindings racebindings
|
||||
types/types types/door types/item types/actor types/container types/lockable types/weapon types/npc
|
||||
types/creature types/player types/activator types/book types/lockpick types/probe types/apparatus
|
||||
types/potion types/ingredient types/misc types/repair types/armor types/light types/static
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "birthsignbindings.hpp"
|
||||
#include "idcollectionbindings.hpp"
|
||||
#include "luamanagerimp.hpp"
|
||||
#include "types/types.hpp"
|
||||
|
||||
@ -17,10 +18,6 @@ namespace sol
|
||||
struct is_automagical<ESM::BirthSign> : std::false_type
|
||||
{
|
||||
};
|
||||
template <>
|
||||
struct is_automagical<MWWorld::Store<ESM::BirthSign>> : std::false_type
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
namespace MWLua
|
||||
@ -44,10 +41,7 @@ namespace MWLua
|
||||
return Misc::ResourceHelpers::correctTexturePath(rec.mTexture, vfs);
|
||||
});
|
||||
signT["spells"] = sol::readonly_property([lua](const ESM::BirthSign& rec) -> sol::table {
|
||||
sol::table res(lua, sol::create);
|
||||
for (size_t i = 0; i < rec.mPowers.mList.size(); ++i)
|
||||
res[i + 1] = rec.mPowers.mList[i].serializeText();
|
||||
return res;
|
||||
return createReadOnlyRefIdTable(lua, rec.mPowers.mList);
|
||||
});
|
||||
|
||||
return LuaUtil::makeReadOnly(birthSigns);
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "classbindings.hpp"
|
||||
#include "idcollectionbindings.hpp"
|
||||
#include "luamanagerimp.hpp"
|
||||
#include "stats.hpp"
|
||||
#include "types/types.hpp"
|
||||
@ -16,10 +17,6 @@ namespace sol
|
||||
struct is_automagical<ESM::Class> : std::false_type
|
||||
{
|
||||
};
|
||||
template <>
|
||||
struct is_automagical<MWWorld::Store<ESM::Class>> : std::false_type
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
namespace MWLua
|
||||
@ -40,34 +37,15 @@ namespace MWLua
|
||||
= sol::readonly_property([](const ESM::Class& rec) -> std::string_view { return rec.mDescription; });
|
||||
|
||||
classT["attributes"] = sol::readonly_property([lua](const ESM::Class& rec) -> sol::table {
|
||||
sol::table res(lua, sol::create);
|
||||
auto attribute = rec.mData.mAttribute;
|
||||
for (size_t i = 0; i < attribute.size(); ++i)
|
||||
{
|
||||
ESM::RefId attributeId = ESM::Attribute::indexToRefId(attribute[i]);
|
||||
res[i + 1] = attributeId.serializeText();
|
||||
}
|
||||
return res;
|
||||
return createReadOnlyRefIdTable(lua, rec.mData.mAttribute, ESM::Attribute::indexToRefId);
|
||||
});
|
||||
classT["majorSkills"] = sol::readonly_property([lua](const ESM::Class& rec) -> sol::table {
|
||||
sol::table res(lua, sol::create);
|
||||
auto skills = rec.mData.mSkills;
|
||||
for (size_t i = 0; i < skills.size(); ++i)
|
||||
{
|
||||
ESM::RefId skillId = ESM::Skill::indexToRefId(skills[i][1]);
|
||||
res[i + 1] = skillId.serializeText();
|
||||
}
|
||||
return res;
|
||||
return createReadOnlyRefIdTable(
|
||||
lua, rec.mData.mSkills, [](const auto& pair) { return ESM::Skill::indexToRefId(pair[1]); });
|
||||
});
|
||||
classT["minorSkills"] = sol::readonly_property([lua](const ESM::Class& rec) -> sol::table {
|
||||
sol::table res(lua, sol::create);
|
||||
auto skills = rec.mData.mSkills;
|
||||
for (size_t i = 0; i < skills.size(); ++i)
|
||||
{
|
||||
ESM::RefId skillId = ESM::Skill::indexToRefId(skills[i][0]);
|
||||
res[i + 1] = skillId.serializeText();
|
||||
}
|
||||
return res;
|
||||
return createReadOnlyRefIdTable(
|
||||
lua, rec.mData.mSkills, [](const auto& pair) { return ESM::Skill::indexToRefId(pair[0]); });
|
||||
});
|
||||
|
||||
classT["specialization"] = sol::readonly_property([](const ESM::Class& rec) -> std::string_view {
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "../mwmechanics/npcstats.hpp"
|
||||
|
||||
#include "idcollectionbindings.hpp"
|
||||
#include "luamanagerimp.hpp"
|
||||
|
||||
namespace
|
||||
@ -96,26 +97,10 @@ namespace MWLua
|
||||
return res;
|
||||
});
|
||||
factionT["attributes"] = sol::readonly_property([&lua](const ESM::Faction& rec) {
|
||||
sol::table res(lua, sol::create);
|
||||
for (auto attributeIndex : rec.mData.mAttribute)
|
||||
{
|
||||
ESM::RefId id = ESM::Attribute::indexToRefId(attributeIndex);
|
||||
if (!id.empty())
|
||||
res.add(id.serializeText());
|
||||
}
|
||||
|
||||
return res;
|
||||
return createReadOnlyRefIdTable(lua, rec.mData.mAttribute, ESM::Attribute::indexToRefId);
|
||||
});
|
||||
factionT["skills"] = sol::readonly_property([&lua](const ESM::Faction& rec) {
|
||||
sol::table res(lua, sol::create);
|
||||
for (auto skillIndex : rec.mData.mSkills)
|
||||
{
|
||||
ESM::RefId id = ESM::Skill::indexToRefId(skillIndex);
|
||||
if (!id.empty())
|
||||
res.add(id.serializeText());
|
||||
}
|
||||
|
||||
return res;
|
||||
return createReadOnlyRefIdTable(lua, rec.mData.mSkills, ESM::Skill::indexToRefId);
|
||||
});
|
||||
auto rankT = lua.new_usertype<FactionRank>("ESM3_FactionRank");
|
||||
rankT[sol::meta_function::to_string] = [](const FactionRank& rec) -> std::string {
|
||||
|
25
apps/openmw/mwlua/idcollectionbindings.hpp
Normal file
25
apps/openmw/mwlua/idcollectionbindings.hpp
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef MWLUA_IDCOLLECTIONBINDINGS_H
|
||||
#define MWLUA_IDCOLLECTIONBINDINGS_H
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <components/esm/refid.hpp>
|
||||
#include <components/lua/luastate.hpp>
|
||||
|
||||
namespace MWLua
|
||||
{
|
||||
template <class C, class P = std::identity>
|
||||
sol::table createReadOnlyRefIdTable(const sol::state_view& lua, const C& container, P projection = {})
|
||||
{
|
||||
sol::table res(lua, sol::create);
|
||||
for (const auto& element : container)
|
||||
{
|
||||
ESM::RefId id = projection(element);
|
||||
if (!id.empty())
|
||||
res.add(id.serializeText());
|
||||
}
|
||||
return LuaUtil::makeReadOnly(res);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
117
apps/openmw/mwlua/racebindings.cpp
Normal file
117
apps/openmw/mwlua/racebindings.cpp
Normal file
@ -0,0 +1,117 @@
|
||||
#include <components/esm/attr.hpp>
|
||||
#include <components/esm3/loadrace.hpp>
|
||||
#include <components/lua/luastate.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "idcollectionbindings.hpp"
|
||||
#include "luamanagerimp.hpp"
|
||||
#include "racebindings.hpp"
|
||||
#include "types/types.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
struct RaceAttributes
|
||||
{
|
||||
const ESM::Race& mRace;
|
||||
const sol::state_view mLua;
|
||||
|
||||
sol::table getAttribute(ESM::RefId id) const
|
||||
{
|
||||
sol::table res(mLua, sol::create);
|
||||
res["male"] = mRace.mData.getAttribute(id, true);
|
||||
res["female"] = mRace.mData.getAttribute(id, false);
|
||||
return LuaUtil::makeReadOnly(res);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace sol
|
||||
{
|
||||
template <>
|
||||
struct is_automagical<ESM::Race> : std::false_type
|
||||
{
|
||||
};
|
||||
template <>
|
||||
struct is_automagical<RaceAttributes> : std::false_type
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
namespace MWLua
|
||||
{
|
||||
sol::table initRaceRecordBindings(const Context& context)
|
||||
{
|
||||
sol::state_view& lua = context.mLua->sol();
|
||||
sol::table races(context.mLua->sol(), sol::create);
|
||||
addRecordFunctionBinding<ESM::Race>(races, context);
|
||||
|
||||
auto raceT = lua.new_usertype<ESM::Race>("ESM3_Race");
|
||||
raceT[sol::meta_function::to_string]
|
||||
= [](const ESM::Race& rec) -> std::string { return "ESM3_Race[" + rec.mId.toDebugString() + "]"; };
|
||||
raceT["id"] = sol::readonly_property([](const ESM::Race& rec) { return rec.mId.serializeText(); });
|
||||
raceT["name"] = sol::readonly_property([](const ESM::Race& rec) -> std::string_view { return rec.mName; });
|
||||
raceT["description"]
|
||||
= sol::readonly_property([](const ESM::Race& rec) -> std::string_view { return rec.mDescription; });
|
||||
raceT["spells"] = sol::readonly_property(
|
||||
[lua](const ESM::Race& rec) -> sol::table { return createReadOnlyRefIdTable(lua, rec.mPowers.mList); });
|
||||
raceT["skills"] = sol::readonly_property([lua](const ESM::Race& rec) -> sol::table {
|
||||
sol::table res(lua, sol::create);
|
||||
for (const auto& skillBonus : rec.mData.mBonus)
|
||||
{
|
||||
ESM::RefId skill = ESM::Skill::indexToRefId(skillBonus.mSkill);
|
||||
if (!skill.empty())
|
||||
res[skill.serializeText()] = skillBonus.mBonus;
|
||||
}
|
||||
return res;
|
||||
});
|
||||
raceT["isPlayable"] = sol::readonly_property(
|
||||
[](const ESM::Race& rec) -> bool { return rec.mData.mFlags & ESM::Race::Playable; });
|
||||
raceT["isBeast"]
|
||||
= sol::readonly_property([](const ESM::Race& rec) -> bool { return rec.mData.mFlags & ESM::Race::Beast; });
|
||||
raceT["height"] = sol::readonly_property([lua](const ESM::Race& rec) -> sol::table {
|
||||
sol::table res(lua, sol::create);
|
||||
res["male"] = rec.mData.mMaleHeight;
|
||||
res["female"] = rec.mData.mFemaleHeight;
|
||||
return LuaUtil::makeReadOnly(res);
|
||||
});
|
||||
raceT["weight"] = sol::readonly_property([lua](const ESM::Race& rec) -> sol::table {
|
||||
sol::table res(lua, sol::create);
|
||||
res["male"] = rec.mData.mMaleWeight;
|
||||
res["female"] = rec.mData.mFemaleWeight;
|
||||
return LuaUtil::makeReadOnly(res);
|
||||
});
|
||||
|
||||
raceT["attributes"] = sol::readonly_property([lua](const ESM::Race& rec) -> RaceAttributes {
|
||||
return { rec, lua };
|
||||
});
|
||||
|
||||
auto attributesT = lua.new_usertype<RaceAttributes>("ESM3_RaceAttributes");
|
||||
const auto& store = MWBase::Environment::get().getESMStore()->get<ESM::Attribute>();
|
||||
attributesT[sol::meta_function::index]
|
||||
= [&](const RaceAttributes& attributes, std::string_view stringId) -> sol::optional<sol::table> {
|
||||
ESM::RefId id = ESM::RefId::deserializeText(stringId);
|
||||
if (!store.search(id))
|
||||
return sol::nullopt;
|
||||
return attributes.getAttribute(id);
|
||||
};
|
||||
attributesT[sol::meta_function::pairs] = [&](sol::this_state ts, RaceAttributes& attributes) {
|
||||
auto iterator = store.begin();
|
||||
return sol::as_function(
|
||||
[iterator, attributes,
|
||||
&store]() mutable -> std::pair<sol::optional<std::string>, sol::optional<sol::table>> {
|
||||
if (iterator != store.end())
|
||||
{
|
||||
ESM::RefId id = iterator->mId;
|
||||
++iterator;
|
||||
return { id.serializeText(), attributes.getAttribute(id) };
|
||||
}
|
||||
return { sol::nullopt, sol::nullopt };
|
||||
});
|
||||
};
|
||||
|
||||
return LuaUtil::makeReadOnly(races);
|
||||
}
|
||||
}
|
13
apps/openmw/mwlua/racebindings.hpp
Normal file
13
apps/openmw/mwlua/racebindings.hpp
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef MWLUA_RACEBINDINGS_H
|
||||
#define MWLUA_RACEBINDINGS_H
|
||||
|
||||
#include <sol/forward.hpp>
|
||||
|
||||
#include "context.hpp"
|
||||
|
||||
namespace MWLua
|
||||
{
|
||||
sol::table initRaceRecordBindings(const Context& context);
|
||||
}
|
||||
|
||||
#endif // MWLUA_RACEBINDINGS_H
|
@ -15,6 +15,7 @@
|
||||
|
||||
#include "../classbindings.hpp"
|
||||
#include "../localscripts.hpp"
|
||||
#include "../racebindings.hpp"
|
||||
#include "../stats.hpp"
|
||||
|
||||
namespace sol
|
||||
@ -86,6 +87,7 @@ namespace MWLua
|
||||
addActorServicesBindings<ESM::NPC>(record, context);
|
||||
|
||||
npc["classes"] = initClassRecordBindings(context);
|
||||
npc["races"] = initRaceRecordBindings(context);
|
||||
|
||||
// This function is game-specific, in future we should replace it with something more universal.
|
||||
npc["isWerewolf"] = [](const Object& o) {
|
||||
|
@ -958,6 +958,40 @@
|
||||
-- @param #any objectOrRecordId
|
||||
-- @return #NpcRecord
|
||||
|
||||
--- @{#Races}: Race data
|
||||
-- @field [parent=#NPC] #Races races
|
||||
|
||||
---
|
||||
-- A read-only list of all @{#RaceRecord}s in the world database.
|
||||
-- @field [parent=#Races] #list<#RaceRecord> records
|
||||
|
||||
---
|
||||
-- Returns a read-only @{#RaceRecord}
|
||||
-- @function [parent=#Races] record
|
||||
-- @param #string recordId
|
||||
-- @return #RaceRecord
|
||||
|
||||
---
|
||||
-- Race data record
|
||||
-- @type RaceRecord
|
||||
-- @field #string id Race id
|
||||
-- @field #string name Race name
|
||||
-- @field #string description Race description
|
||||
-- @field #map<#string, #number> skills A map of bonus skill points by skill ID
|
||||
-- @field #list<#string> spells A read-only list containing the ids of all spells inherent to the race
|
||||
-- @field #bool isPlayable True if the player can pick this race in character generation
|
||||
-- @field #bool isBeast True if this race is a beast race
|
||||
-- @field #GenderedNumber height Height values
|
||||
-- @field #GenderedNumber weight Weight values
|
||||
-- @field #map<#string, #GenderedNumber> attributes A read-only table of attribute ID to base value
|
||||
-- @usage -- Get base strength for men
|
||||
-- strength = types.NPC.races.records[1].attributes.strength.male
|
||||
|
||||
---
|
||||
-- @type GenderedNumber
|
||||
-- @field #number male Male value
|
||||
-- @field #number female Female value
|
||||
|
||||
---
|
||||
-- @type NpcRecord
|
||||
-- @field #string id The record ID of the NPC
|
||||
|
Loading…
Reference in New Issue
Block a user