Expose races to Lua

fix-osga-rotate-wildly
Evil Eye 10 months ago
parent b9fc9f0827
commit cd118ee263

@ -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

@ -21,6 +21,10 @@ namespace sol
struct is_automagical<MWWorld::Store<ESM::BirthSign>> : std::false_type
{
};
template <>
struct is_automagical<ESM::SpellList> : std::false_type
{
};
}
namespace MWLua
@ -43,12 +47,19 @@ namespace MWLua
signT["texture"] = sol::readonly_property([vfs](const ESM::BirthSign& rec) -> std::string {
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;
});
signT["spells"]
= sol::readonly_property([](const ESM::BirthSign& rec) -> const ESM::SpellList* { return &rec.mPowers; });
auto spellListT = lua.new_usertype<ESM::SpellList>("ESM3_SpellList");
spellListT[sol::meta_function::length] = [](const ESM::SpellList& list) { return list.mList.size(); };
spellListT[sol::meta_function::index]
= [](const ESM::SpellList& list, size_t index) -> sol::optional<std::string> {
if (index == 0 || index > list.mList.size())
return sol::nullopt;
return list.mList[index - 1].serializeText(); // Translate from Lua's 1-based indexing.
};
spellListT[sol::meta_function::pairs] = lua["ipairsForArray"].template get<sol::function>();
spellListT[sol::meta_function::ipairs] = lua["ipairsForArray"].template get<sol::function>();
return LuaUtil::makeReadOnly(birthSigns);
}

@ -0,0 +1,120 @@
#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 "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<MWWorld::Store<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) -> const ESM::SpellList* { return &rec.mPowers; });
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);
}
}

@ -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,35 @@
-- @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 #map<#string, #number> height A read-only table with male and female fields
-- @field #map<#string, #number> weight A read-only table with male and female fields
-- @field #map<#string, #map<#string, #number>> attributes A read-only table of attribute ID to male and female base values
-- @usage -- Get base strength for men
-- strength = types.NPC.races.records[1].attributes.strength.male
---
-- @type NpcRecord
-- @field #string id The record ID of the NPC

Loading…
Cancel
Save