mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-16 15:29:55 +00:00
Implement Lua API for factions (feature 7468)
This commit is contained in:
parent
9d3eb1a901
commit
6ee86dea82
14 changed files with 509 additions and 11 deletions
|
@ -94,6 +94,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
|
||||
|
|
|
@ -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 "")
|
||||
|
|
|
@ -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
|
||||
|
|
135
apps/openmw/mwlua/factionbindings.cpp
Normal file
135
apps/openmw/mwlua/factionbindings.cpp
Normal file
|
@ -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
apps/openmw/mwlua/factionbindings.hpp
Normal file
13
apps/openmw/mwlua/factionbindings.hpp
Normal file
|
@ -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
|
|
@ -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>
|
||||
|
@ -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"
|
||||
|
@ -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>();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "actor.hpp"
|
||||
#include "types.hpp"
|
||||
|
||||
#include <components/esm3/loadfact.hpp>
|
||||
#include <components/esm3/loadnpc.hpp>
|
||||
#include <components/lua/luastate.hpp>
|
||||
|
||||
|
@ -11,6 +12,7 @@
|
|||
#include <apps/openmw/mwworld/class.hpp>
|
||||
#include <apps/openmw/mwworld/esmstore.hpp>
|
||||
|
||||
#include "../localscripts.hpp"
|
||||
#include "../stats.hpp"
|
||||
|
||||
namespace sol
|
||||
|
@ -21,6 +23,32 @@ namespace sol
|
|||
};
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
size_t getValidRanksCount(const ESM::Faction* faction)
|
||||
{
|
||||
if (!faction)
|
||||
return 0;
|
||||
|
||||
for (size_t i = 0; i < faction->mRanks.size(); i++)
|
||||
{
|
||||
if (faction->mRanks[i].empty())
|
||||
return i;
|
||||
}
|
||||
|
||||
return faction->mRanks.size();
|
||||
}
|
||||
|
||||
ESM::RefId parseFactionId(std::string_view faction)
|
||||
{
|
||||
ESM::RefId id = ESM::RefId::deserializeText(faction);
|
||||
const MWWorld::ESMStore* store = MWBase::Environment::get().getESMStore();
|
||||
if (!store->get<ESM::Faction>().search(id))
|
||||
throw std::runtime_error("Faction '" + std::string(faction) + "' does not exist");
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
namespace MWLua
|
||||
{
|
||||
void addNpcBindings(sol::table npc, const Context& context)
|
||||
|
@ -29,7 +57,9 @@ namespace MWLua
|
|||
|
||||
addRecordFunctionBinding<ESM::NPC>(npc, context);
|
||||
|
||||
sol::usertype<ESM::NPC> record = context.mLua->sol().new_usertype<ESM::NPC>("ESM3_NPC");
|
||||
sol::state_view& lua = context.mLua->sol();
|
||||
|
||||
sol::usertype<ESM::NPC> record = lua.new_usertype<ESM::NPC>("ESM3_NPC");
|
||||
record[sol::meta_function::to_string]
|
||||
= [](const ESM::NPC& rec) { return "ESM3_NPC[" + rec.mId.toDebugString() + "]"; };
|
||||
record["id"]
|
||||
|
@ -68,5 +98,182 @@ namespace MWLua
|
|||
throw std::runtime_error("NPC expected");
|
||||
return MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(o.ptr());
|
||||
};
|
||||
|
||||
npc["getFactionRank"] = [](const Object& actor, std::string_view faction) {
|
||||
const MWWorld::Ptr ptr = actor.ptr();
|
||||
ESM::RefId factionId = parseFactionId(faction);
|
||||
|
||||
const MWMechanics::NpcStats& npcStats = ptr.getClass().getNpcStats(ptr);
|
||||
|
||||
int factionRank = npcStats.getFactionRank(factionId);
|
||||
if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr())
|
||||
{
|
||||
if (npcStats.isInFaction(factionId))
|
||||
return factionRank + 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ESM::RefId primaryFactionId = ptr.getClass().getPrimaryFaction(ptr);
|
||||
if (factionId == primaryFactionId && factionRank == -1)
|
||||
return ptr.getClass().getPrimaryFactionRank(ptr);
|
||||
else if (primaryFactionId == factionId)
|
||||
return factionRank + 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
npc["setFactionRank"] = [](Object& actor, std::string_view faction, int value) {
|
||||
if (dynamic_cast<LObject*>(&actor) && !dynamic_cast<SelfObject*>(&actor))
|
||||
throw std::runtime_error("Local scripts can modify only self");
|
||||
|
||||
const MWWorld::Ptr ptr = actor.ptr();
|
||||
ESM::RefId factionId = parseFactionId(faction);
|
||||
|
||||
const ESM::Faction* factionPtr
|
||||
= MWBase::Environment::get().getESMStore()->get<ESM::Faction>().find(factionId);
|
||||
|
||||
auto ranksCount = static_cast<int>(getValidRanksCount(factionPtr));
|
||||
|
||||
if (ptr != MWBase::Environment::get().getWorld()->getPlayerPtr())
|
||||
{
|
||||
ESM::RefId primaryFactionId = ptr.getClass().getPrimaryFaction(ptr);
|
||||
if (value <= 0 || factionId != primaryFactionId)
|
||||
return;
|
||||
}
|
||||
|
||||
MWMechanics::NpcStats& npcStats = ptr.getClass().getNpcStats(ptr);
|
||||
|
||||
if (!npcStats.isInFaction(factionId) && value > 0)
|
||||
npcStats.joinFaction(factionId);
|
||||
|
||||
npcStats.setFactionRank(factionId, std::min(value - 1, ranksCount - 1));
|
||||
};
|
||||
|
||||
npc["modifyFactionRank"] = [](Object& actor, std::string_view faction, int value) {
|
||||
if (dynamic_cast<LObject*>(&actor) && !dynamic_cast<SelfObject*>(&actor))
|
||||
throw std::runtime_error("Local scripts can modify only self");
|
||||
|
||||
if (value == 0)
|
||||
return;
|
||||
|
||||
const MWWorld::Ptr ptr = actor.ptr();
|
||||
ESM::RefId factionId = parseFactionId(faction);
|
||||
|
||||
const ESM::Faction* factionPtr
|
||||
= MWBase::Environment::get().getESMStore()->get<ESM::Faction>().search(factionId);
|
||||
if (!factionPtr)
|
||||
return;
|
||||
|
||||
auto ranksCount = static_cast<int>(getValidRanksCount(factionPtr));
|
||||
|
||||
MWMechanics::NpcStats& npcStats = ptr.getClass().getNpcStats(ptr);
|
||||
|
||||
if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr())
|
||||
{
|
||||
int currentRank = npcStats.getFactionRank(factionId);
|
||||
if (currentRank >= 0)
|
||||
{
|
||||
npcStats.setFactionRank(factionId, currentRank + value);
|
||||
}
|
||||
else if (value > 0)
|
||||
{
|
||||
npcStats.joinFaction(factionId);
|
||||
npcStats.setFactionRank(factionId, std::min(value - 1, ranksCount - 1));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ESM::RefId primaryFactionId = ptr.getClass().getPrimaryFaction(ptr);
|
||||
if (factionId != primaryFactionId)
|
||||
return;
|
||||
|
||||
// If we already changed rank for this NPC, modify current rank in the NPC stats.
|
||||
// Otherwise take rank from base NPC record, adjust it and put it to NPC data.
|
||||
int currentRank = npcStats.getFactionRank(factionId);
|
||||
if (currentRank < 0)
|
||||
{
|
||||
int rank = ptr.getClass().getPrimaryFactionRank(ptr);
|
||||
npcStats.joinFaction(factionId);
|
||||
npcStats.setFactionRank(factionId, std::clamp(0, rank + value, ranksCount - 1));
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
npcStats.setFactionRank(factionId, std::clamp(0, currentRank + value, ranksCount - 1));
|
||||
};
|
||||
|
||||
npc["getFactionReputation"] = [](const Object& actor, std::string_view faction) {
|
||||
const MWWorld::Ptr ptr = actor.ptr();
|
||||
ESM::RefId factionId = parseFactionId(faction);
|
||||
|
||||
return ptr.getClass().getNpcStats(ptr).getFactionReputation(factionId);
|
||||
};
|
||||
|
||||
npc["setFactionReputation"] = [](Object& actor, std::string_view faction, int value) {
|
||||
if (dynamic_cast<LObject*>(&actor) && !dynamic_cast<SelfObject*>(&actor))
|
||||
throw std::runtime_error("Local scripts can modify only self");
|
||||
|
||||
const MWWorld::Ptr ptr = actor.ptr();
|
||||
ESM::RefId factionId = parseFactionId(faction);
|
||||
|
||||
ptr.getClass().getNpcStats(ptr).setFactionReputation(factionId, value);
|
||||
};
|
||||
|
||||
npc["modifyFactionReputation"] = [](Object& actor, std::string_view faction, int value) {
|
||||
if (dynamic_cast<LObject*>(&actor) && !dynamic_cast<SelfObject*>(&actor))
|
||||
throw std::runtime_error("Local scripts can modify only self");
|
||||
|
||||
const MWWorld::Ptr ptr = actor.ptr();
|
||||
ESM::RefId factionId = parseFactionId(faction);
|
||||
|
||||
MWMechanics::NpcStats& npcStats = ptr.getClass().getNpcStats(ptr);
|
||||
int existingReputation = npcStats.getFactionReputation(factionId);
|
||||
npcStats.setFactionReputation(factionId, existingReputation + value);
|
||||
};
|
||||
|
||||
npc["expell"] = [](Object& actor, std::string_view faction) {
|
||||
if (dynamic_cast<LObject*>(&actor) && !dynamic_cast<SelfObject*>(&actor))
|
||||
throw std::runtime_error("Local scripts can modify only self");
|
||||
|
||||
const MWWorld::Ptr ptr = actor.ptr();
|
||||
ESM::RefId factionId = parseFactionId(faction);
|
||||
ptr.getClass().getNpcStats(ptr).expell(factionId, false);
|
||||
};
|
||||
npc["clearExpelled"] = [](Object& actor, std::string_view faction) {
|
||||
if (dynamic_cast<LObject*>(&actor) && !dynamic_cast<SelfObject*>(&actor))
|
||||
throw std::runtime_error("Local scripts can modify only self");
|
||||
|
||||
const MWWorld::Ptr ptr = actor.ptr();
|
||||
ESM::RefId factionId = parseFactionId(faction);
|
||||
ptr.getClass().getNpcStats(ptr).clearExpelled(factionId);
|
||||
};
|
||||
npc["isExpelled"] = [](const Object& actor, std::string_view faction) {
|
||||
const MWWorld::Ptr ptr = actor.ptr();
|
||||
ESM::RefId factionId = parseFactionId(faction);
|
||||
return ptr.getClass().getNpcStats(ptr).getExpelled(factionId);
|
||||
};
|
||||
npc["getFactions"] = [&lua](const Object& actor) {
|
||||
const MWWorld::Ptr ptr = actor.ptr();
|
||||
MWMechanics::NpcStats& npcStats = ptr.getClass().getNpcStats(ptr);
|
||||
sol::table res(lua, sol::create);
|
||||
if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr())
|
||||
{
|
||||
for (const auto& [factionId, _] : npcStats.getFactionRanks())
|
||||
res.add(factionId.serializeText());
|
||||
return res;
|
||||
}
|
||||
|
||||
ESM::RefId primaryFactionId = ptr.getClass().getPrimaryFaction(ptr);
|
||||
if (primaryFactionId.empty())
|
||||
return res;
|
||||
|
||||
res.add(primaryFactionId.serializeText());
|
||||
|
||||
return res;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1364,7 +1364,7 @@ namespace MWMechanics
|
|||
const std::map<ESM::RefId, int>& playerRanks = player.getClass().getNpcStats(player).getFactionRanks();
|
||||
if (playerRanks.find(factionID) != playerRanks.end())
|
||||
{
|
||||
player.getClass().getNpcStats(player).expell(factionID);
|
||||
player.getClass().getNpcStats(player).expell(factionID, true);
|
||||
}
|
||||
}
|
||||
else if (!factionId.empty())
|
||||
|
@ -1372,7 +1372,7 @@ namespace MWMechanics
|
|||
const std::map<ESM::RefId, int>& playerRanks = player.getClass().getNpcStats(player).getFactionRanks();
|
||||
if (playerRanks.find(factionId) != playerRanks.end())
|
||||
{
|
||||
player.getClass().getNpcStats(player).expell(factionId);
|
||||
player.getClass().getNpcStats(player).expell(factionId, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -112,14 +112,17 @@ bool MWMechanics::NpcStats::getExpelled(const ESM::RefId& factionID) const
|
|||
return mExpelled.find(factionID) != mExpelled.end();
|
||||
}
|
||||
|
||||
void MWMechanics::NpcStats::expell(const ESM::RefId& factionID)
|
||||
void MWMechanics::NpcStats::expell(const ESM::RefId& factionID, bool printMessage)
|
||||
{
|
||||
if (mExpelled.find(factionID) == mExpelled.end())
|
||||
{
|
||||
mExpelled.insert(factionID);
|
||||
if (!printMessage)
|
||||
return;
|
||||
|
||||
std::string message = "#{sExpelledMessage}";
|
||||
message += MWBase::Environment::get().getESMStore()->get<ESM::Faction>().find(factionID)->mName;
|
||||
MWBase::Environment::get().getWindowManager()->messageBox(message);
|
||||
mExpelled.insert(factionID);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ namespace MWMechanics
|
|||
|
||||
const std::set<ESM::RefId>& getExpelled() const { return mExpelled; }
|
||||
bool getExpelled(const ESM::RefId& factionID) const;
|
||||
void expell(const ESM::RefId& factionID);
|
||||
void expell(const ESM::RefId& factionID, bool printMessage);
|
||||
void clearExpelled(const ESM::RefId& factionID);
|
||||
|
||||
bool isInFaction(const ESM::RefId& faction) const;
|
||||
|
|
|
@ -938,7 +938,7 @@ namespace MWScript
|
|||
MWWorld::Ptr player = MWMechanics::getPlayer();
|
||||
if (!factionID.empty())
|
||||
{
|
||||
player.getClass().getNpcStats(player).expell(factionID);
|
||||
player.getClass().getNpcStats(player).expell(factionID, true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -68,7 +68,7 @@ namespace ESM
|
|||
std::map<ESM::RefId, int> mReactions;
|
||||
|
||||
// Name of faction ranks (may be empty for NPC factions)
|
||||
std::string mRanks[10];
|
||||
std::array<std::string, 10> mRanks;
|
||||
|
||||
void load(ESMReader& esm, bool& isDeleted);
|
||||
void save(ESMWriter& esm, bool isDeleted = false) const;
|
||||
|
|
|
@ -10,6 +10,10 @@
|
|||
-- The revision of OpenMW Lua API. It is an integer that is incremented every time the API is changed. See the actual value at the top of the page.
|
||||
-- @field [parent=#core] #number API_REVISION
|
||||
|
||||
---
|
||||
-- A read-only list of all @{#FactionRecord}s in the world database.
|
||||
-- @field [parent=#core] #list<#FactionRecord> factions
|
||||
|
||||
---
|
||||
-- Terminates the game and quits to the OS. Should be used only for testing purposes.
|
||||
-- @function [parent=#core] quit
|
||||
|
@ -868,7 +872,6 @@
|
|||
-- print(sound.fileName)
|
||||
-- end
|
||||
|
||||
|
||||
--- @{#Stats}: stats
|
||||
-- @field [parent=#core] #Stats stats
|
||||
|
||||
|
@ -920,4 +923,23 @@
|
|||
-- @field #string failureSound VFS path to the failure sound
|
||||
-- @field #string hitSound VFS path to the hit sound
|
||||
|
||||
---
|
||||
-- Faction data record
|
||||
-- @type FactionRecord
|
||||
-- @field #string id Faction id
|
||||
-- @field #string name Faction name
|
||||
-- @field #list<#FactionRank> ranks A read-only list containing data for all ranks in the faction, in order.
|
||||
-- @field #map<#string, #number> reactions A read-only map containing reactions of other factions to this faction.
|
||||
-- @field #list<#string> attributes A read-only list containing IDs of attributes to advance ranks in the faction.
|
||||
-- @field #list<#string> skills A read-only list containing IDs of skills to advance ranks in the faction.
|
||||
|
||||
---
|
||||
-- Faction rank data record
|
||||
-- @type FactionRank
|
||||
-- @field #string name Faction name Rank display name
|
||||
-- @field #list<#number> attributeValues Attributes values required to get this rank.
|
||||
-- @field #number primarySkillValue Primary skill value required to get this rank.
|
||||
-- @field #number favouredSkillValue Secondary skill value required to get this rank.
|
||||
-- @field #number factionReaction Reaction of faction members if player is in this faction.
|
||||
|
||||
return nil
|
||||
|
|
|
@ -720,6 +720,117 @@
|
|||
-- @param openmw.core#GameObject object
|
||||
-- @return #boolean
|
||||
|
||||
---
|
||||
-- Get all factions in which NPC has a membership.
|
||||
-- Note: this function does not take in account an expelling state.
|
||||
-- @function [parent=#NPC] getFactions
|
||||
-- @param openmw.core#GameObject actor NPC object
|
||||
-- @return #list<#string> factionIds List of faction IDs.
|
||||
-- @usage local NPC = require('openmw.types').NPC;
|
||||
-- for _, factionId in pairs(types.NPC.getFactions(actor)) do
|
||||
-- print(factionId);
|
||||
-- end
|
||||
|
||||
---
|
||||
-- Get rank of given NPC in given faction.
|
||||
-- Throws an exception if there is no such faction.
|
||||
-- Note: this function does not take in account an expelling state.
|
||||
-- @function [parent=#NPC] getFactionRank
|
||||
-- @param openmw.core#GameObject actor NPC object
|
||||
-- @param #string faction Faction ID
|
||||
-- @return #number rank Rank index (from 1), 0 if NPC is not in faction.
|
||||
-- @usage local NPC = require('openmw.types').NPC;
|
||||
-- print(NPC.getFactionRank(player, "mages guild");
|
||||
|
||||
---
|
||||
-- Set rank of given NPC in given faction.
|
||||
-- Throws an exception if there is no such faction.
|
||||
-- For NPCs faction should be an NPC's primary faction.
|
||||
-- Notes:
|
||||
--
|
||||
-- * "value" <= 0 does nothing for NPCs and make the player character to leave the faction (purge his rank and reputation in faction).
|
||||
-- * "value" > 0 set rank to given value if rank is valid (name is not empty), and to the highest valid rank otherwise.
|
||||
-- @function [parent=#NPC] setFactionRank
|
||||
-- @param openmw.core#GameObject actor NPC object
|
||||
-- @param #string faction Faction ID
|
||||
-- @param #number value Rank index (from 1).
|
||||
-- @usage local NPC = require('openmw.types').NPC;
|
||||
-- NPC.setFactionRank(player, "mages guild", 6);
|
||||
|
||||
---
|
||||
-- Adjust rank of given NPC in given faction.
|
||||
-- For NPCs faction should be an NPC's primary faction.
|
||||
-- Throws an exception if there is no such faction.
|
||||
-- Notes:
|
||||
--
|
||||
-- * If rank should become <= 0 after modification, function does nothing for NPCs and makes the player character to leave the faction (purge his rank and reputation in faction).
|
||||
-- * If rank should become > 0 after modification, function set rank to given value if rank is valid (name is not empty), and to the highest valid rank otherwise.
|
||||
-- @function [parent=#NPC] modifyFactionRank
|
||||
-- @param openmw.core#GameObject actor NPC object
|
||||
-- @param #string faction Faction ID
|
||||
-- @param #number value Rank index (from 1) modifier. If rank reaches 0 for player character, he leaves the faction.
|
||||
-- @usage local NPC = require('openmw.types').NPC;
|
||||
-- NPC.modifyFactionRank(player, "mages guild", 1);
|
||||
|
||||
---
|
||||
-- Get reputation of given actor in given faction.
|
||||
-- Throws an exception if there is no such faction.
|
||||
-- @function [parent=#NPC] getFactionReputation
|
||||
-- @param openmw.core#GameObject actor NPC object
|
||||
-- @param #string faction Faction ID
|
||||
-- @return #number reputation Reputation level, 0 if NPC is not in faction.
|
||||
-- @usage local NPC = require('openmw.types').NPC;
|
||||
-- print(NPC.getFactionReputation(player, "mages guild"));
|
||||
|
||||
---
|
||||
-- Set reputation of given actor in given faction.
|
||||
-- Throws an exception if there is no such faction.
|
||||
-- @function [parent=#NPC] setFactionReputation
|
||||
-- @param openmw.core#GameObject actor NPC object
|
||||
-- @param #string faction Faction ID
|
||||
-- @param #number value Reputation value
|
||||
-- @usage local NPC = require('openmw.types').NPC;
|
||||
-- NPC.setFactionReputation(player, "mages guild", 100);
|
||||
|
||||
---
|
||||
-- Adjust reputation of given actor in given faction.
|
||||
-- Throws an exception if there is no such faction.
|
||||
-- @function [parent=#NPC] modifyFactionReputation
|
||||
-- @param openmw.core#GameObject actor NPC object
|
||||
-- @param #string faction Faction ID
|
||||
-- @param #number value Reputation modifier value
|
||||
-- @usage local NPC = require('openmw.types').NPC;
|
||||
-- NPC.modifyFactionReputation(player, "mages guild", 5);
|
||||
|
||||
---
|
||||
-- Expell NPC from given faction.
|
||||
-- Throws an exception if there is no such faction.
|
||||
-- Note: expelled NPC still keeps his rank and reputation in faction, he just get an additonal flag for given faction.
|
||||
-- @function [parent=#NPC] expell
|
||||
-- @param openmw.core#GameObject actor NPC object
|
||||
-- @param #string faction Faction ID
|
||||
-- @usage local NPC = require('openmw.types').NPC;
|
||||
-- NPC.expell(player, "mages guild");
|
||||
|
||||
---
|
||||
-- Clear expelling of NPC from given faction.
|
||||
-- Throws an exception if there is no such faction.
|
||||
-- @function [parent=#NPC] clearExpelled
|
||||
-- @param openmw.core#GameObject actor NPC object
|
||||
-- @param #string faction Faction ID
|
||||
-- @usage local NPC = require('openmw.types').NPC;
|
||||
-- NPC.clearExpell(player, "mages guild");
|
||||
|
||||
---
|
||||
-- Check if NPC is expelled from given faction.
|
||||
-- Throws an exception if there is no such faction.
|
||||
-- @function [parent=#NPC] isExpelled
|
||||
-- @param openmw.core#GameObject actor NPC object
|
||||
-- @param #string faction Faction ID
|
||||
-- @return #bool isExpelled True if NPC is expelled from the faction.
|
||||
-- @usage local NPC = require('openmw.types').NPC;
|
||||
-- local result = NPC.isExpelled(player, "mages guild");
|
||||
|
||||
---
|
||||
-- Returns the current disposition of the provided NPC. This is their derived disposition, after modifiers such as personality and faction relations are taken into account.
|
||||
-- @function [parent=#NPC] getDisposition
|
||||
|
|
Loading…
Reference in a new issue