Skip to content

Commit

Permalink
Merge branch 'factions' into 'master'
Browse files Browse the repository at this point in the history
Implement Lua API for factions

See merge request OpenMW/openmw!3405
  • Loading branch information
psi29a committed Sep 12, 2023
2 parents 42b7734 + 02dcf1f commit 090da90
Show file tree
Hide file tree
Showing 14 changed files with 556 additions and 11 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
Feature #7194: Ori to show texture paths
Feature #7214: Searching in the in-game console
Feature #7284: Searching in the console with regex and toggleable case-sensitivity
Feature #7468: Factions API for Lua
Feature #7477: NegativeLight Magic Effect flag
Feature #7499: OpenMW-CS: Generate record filters by drag & dropping cell content to the filters field
Feature #7546: Start the game on Fredas
Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ message(STATUS "Configuring OpenMW...")
set(OPENMW_VERSION_MAJOR 0)
set(OPENMW_VERSION_MINOR 49)
set(OPENMW_VERSION_RELEASE 0)
set(OPENMW_LUA_API_REVISION 46)
set(OPENMW_LUA_API_REVISION 47)

set(OPENMW_VERSION_COMMITHASH "")
set(OPENMW_VERSION_TAGHASH "")
Expand Down
2 changes: 1 addition & 1 deletion apps/openmw/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ add_openmw_dir (mwlua
context globalscripts localscripts playerscripts luabindings objectbindings cellbindings mwscriptbindings
camerabindings vfsbindings uibindings soundbindings inputbindings nearbybindings postprocessingbindings stats debugbindings
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 types/clothing types/levelledlist types/terminal
worker magicbindings
worker magicbindings factionbindings
)

add_openmw_dir (mwsound
Expand Down
135 changes: 135 additions & 0 deletions apps/openmw/mwlua/factionbindings.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
#include "factionbindings.hpp"

#include <components/esm3/loadfact.hpp>
#include <components/lua/luastate.hpp>

#include "../mwbase/environment.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/esmstore.hpp"

#include "../mwmechanics/npcstats.hpp"

#include "luamanagerimp.hpp"

namespace
{
struct FactionRank : ESM::RankData
{
std::string mRankName;
ESM::RefId mFactionId;
size_t mRankIndex;

FactionRank(const ESM::RefId& factionId, const ESM::RankData& data, std::string_view rankName, size_t rankIndex)
: ESM::RankData(data)
, mRankName(rankName)
, mFactionId(factionId)
{
}
};
}

namespace sol
{
template <>
struct is_automagical<ESM::Faction> : std::false_type
{
};
template <>
struct is_automagical<MWWorld::Store<ESM::Faction>> : std::false_type
{
};
template <>
struct is_automagical<MWWorld::Store<FactionRank>> : std::false_type
{
};
}

namespace MWLua
{
using FactionStore = MWWorld::Store<ESM::Faction>;

void initCoreFactionBindings(const Context& context)
{
sol::state_view& lua = context.mLua->sol();
sol::usertype<FactionStore> factionStoreT = lua.new_usertype<FactionStore>("ESM3_FactionStore");
factionStoreT[sol::meta_function::to_string] = [](const FactionStore& store) {
return "ESM3_FactionStore{" + std::to_string(store.getSize()) + " factions}";
};
factionStoreT[sol::meta_function::length] = [](const FactionStore& store) { return store.getSize(); };
factionStoreT[sol::meta_function::index] = sol::overload(
[](const FactionStore& store, size_t index) -> const ESM::Faction* {
if (index == 0 || index > store.getSize())
return nullptr;
return store.at(index - 1);
},
[](const FactionStore& store, std::string_view factionId) -> const ESM::Faction* {
return store.search(ESM::RefId::deserializeText(factionId));
});
factionStoreT[sol::meta_function::pairs] = lua["ipairsForArray"].template get<sol::function>();
factionStoreT[sol::meta_function::ipairs] = lua["ipairsForArray"].template get<sol::function>();
// Faction record
auto factionT = lua.new_usertype<ESM::Faction>("ESM3_Faction");
factionT[sol::meta_function::to_string]
= [](const ESM::Faction& rec) -> std::string { return "ESM3_Faction[" + rec.mId.toDebugString() + "]"; };
factionT["id"] = sol::readonly_property([](const ESM::Faction& rec) { return rec.mId.serializeText(); });
factionT["name"]
= sol::readonly_property([](const ESM::Faction& rec) -> std::string_view { return rec.mName; });
factionT["hidden"]
= sol::readonly_property([](const ESM::Faction& rec) -> bool { return rec.mData.mIsHidden; });
factionT["ranks"] = sol::readonly_property([&lua](const ESM::Faction& rec) {
sol::table res(lua, sol::create);
for (size_t i = 0; i < rec.mRanks.size() && i < rec.mData.mRankData.size(); i++)
{
if (rec.mRanks[i].empty())
break;

res.add(FactionRank(rec.mId, rec.mData.mRankData[i], rec.mRanks[i], i));
}

return res;
});
factionT["reactions"] = sol::readonly_property([&lua](const ESM::Faction& rec) {
sol::table res(lua, sol::create);
for (const auto& [factionId, reaction] : rec.mReactions)
res[factionId.serializeText()] = reaction;
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;
});
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;
});
auto rankT = lua.new_usertype<FactionRank>("ESM3_FactionRank");
rankT[sol::meta_function::to_string] = [](const FactionRank& rec) -> std::string {
return "ESM3_FactionRank[" + rec.mFactionId.toDebugString() + ", " + std::to_string(rec.mRankIndex + 1)
+ "]";
};
rankT["name"] = sol::readonly_property([](const FactionRank& rec) { return rec.mRankName; });
rankT["primarySkillValue"] = sol::readonly_property([](const FactionRank& rec) { return rec.mPrimarySkill; });
rankT["favouredSkillValue"] = sol::readonly_property([](const FactionRank& rec) { return rec.mFavouredSkill; });
rankT["factionReaction"] = sol::readonly_property([](const FactionRank& rec) { return rec.mFactReaction; });
rankT["attributeValues"] = sol::readonly_property([&lua](const FactionRank& rec) {
sol::table res(lua, sol::create);
res.add(rec.mAttribute1);
res.add(rec.mAttribute2);
return res;
});
}
}
13 changes: 13 additions & 0 deletions apps/openmw/mwlua/factionbindings.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#ifndef MWLUA_FACTIONBINDINGS_H
#define MWLUA_FACTIONBINDINGS_H

#include <sol/forward.hpp>

#include "context.hpp"

namespace MWLua
{
void initCoreFactionBindings(const Context& context);
}

#endif // MWLUA_FACTIONBINDINGS_H
6 changes: 6 additions & 0 deletions apps/openmw/mwlua/luabindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <components/esm3/loadarmo.hpp>
#include <components/esm3/loadbook.hpp>
#include <components/esm3/loadclot.hpp>
#include <components/esm3/loadfact.hpp>
#include <components/esm3/loadmisc.hpp>
#include <components/esm3/loadskil.hpp>
#include <components/esm3/loadweap.hpp>
Expand Down Expand Up @@ -36,6 +37,7 @@
#include "camerabindings.hpp"
#include "cellbindings.hpp"
#include "debugbindings.hpp"
#include "factionbindings.hpp"
#include "inputbindings.hpp"
#include "magicbindings.hpp"
#include "nearbybindings.hpp"
Expand Down Expand Up @@ -153,6 +155,10 @@ namespace MWLua
addTimeBindings(api, context, false);
api["magic"] = initCoreMagicBindings(context);
api["stats"] = initCoreStatsBindings(context);

initCoreFactionBindings(context);
api["factions"] = &MWBase::Environment::get().getWorld()->getStore().get<ESM::Faction>();

api["l10n"] = LuaUtil::initL10nLoader(lua->sol(), MWBase::Environment::get().getL10nManager());
const MWWorld::Store<ESM::GameSetting>* gmstStore
= &MWBase::Environment::get().getESMStore()->get<ESM::GameSetting>();
Expand Down
Loading

0 comments on commit 090da90

Please sign in to comment.