mirror of
https://github.com/OpenMW/openmw.git
synced 2025-02-21 07:09:42 +00:00
Merge branch 'create_record_types' into 'master'
Allow creating Activator, Armor, Clothing, Misc, Weapon records via lua See merge request OpenMW/openmw!2944
This commit is contained in:
commit
4ed283bb15
13 changed files with 253 additions and 12 deletions
|
@ -225,7 +225,7 @@ Programmers
|
|||
tlmullis
|
||||
tri4ng1e
|
||||
Thoronador
|
||||
Tobias Tribble (zackogenic)
|
||||
Tobias Tribble (zackhasacat)
|
||||
Tom Lowe (Vulpen)
|
||||
Tom Mason (wheybags)
|
||||
Torben Leif Carrington (TorbenC)
|
||||
|
|
|
@ -3,9 +3,14 @@
|
|||
#include <chrono>
|
||||
|
||||
#include <components/esm/attr.hpp>
|
||||
#include <components/esm3/loadacti.hpp>
|
||||
#include <components/esm3/loadalch.hpp>
|
||||
#include <components/esm3/loadarmo.hpp>
|
||||
#include <components/esm3/loadbook.hpp>
|
||||
#include <components/esm3/loadclot.hpp>
|
||||
#include <components/esm3/loadmisc.hpp>
|
||||
#include <components/esm3/loadskil.hpp>
|
||||
|
||||
#include <components/esm3/loadweap.hpp>
|
||||
#include <components/lua/l10n.hpp>
|
||||
#include <components/lua/luastate.hpp>
|
||||
#include <components/lua/utilpackage.hpp>
|
||||
|
@ -186,11 +191,28 @@ namespace MWLua
|
|||
};
|
||||
|
||||
// Creates a new record in the world database.
|
||||
api["createRecord"] = sol::overload([](const ESM::Potion& potion) -> const ESM::Potion* {
|
||||
return MWBase::Environment::get().getESMStore()->insert(potion);
|
||||
}
|
||||
// TODO: add here overloads for other records
|
||||
);
|
||||
api["createRecord"] = sol::overload(
|
||||
[](const ESM::Activator& activator) -> const ESM::Activator* {
|
||||
return MWBase::Environment::get().getESMStore()->insert(activator);
|
||||
},
|
||||
[](const ESM::Armor& armor) -> const ESM::Armor* {
|
||||
return MWBase::Environment::get().getESMStore()->insert(armor);
|
||||
},
|
||||
[](const ESM::Clothing& clothing) -> const ESM::Clothing* {
|
||||
return MWBase::Environment::get().getESMStore()->insert(clothing);
|
||||
},
|
||||
[](const ESM::Book& book) -> const ESM::Book* {
|
||||
return MWBase::Environment::get().getESMStore()->insert(book);
|
||||
},
|
||||
[](const ESM::Miscellaneous& misc) -> const ESM::Miscellaneous* {
|
||||
return MWBase::Environment::get().getESMStore()->insert(misc);
|
||||
},
|
||||
[](const ESM::Potion& potion) -> const ESM::Potion* {
|
||||
return MWBase::Environment::get().getESMStore()->insert(potion);
|
||||
},
|
||||
[](const ESM::Weapon& weapon) -> const ESM::Weapon* {
|
||||
return MWBase::Environment::get().getESMStore()->insert(weapon);
|
||||
});
|
||||
|
||||
api["_runStandardActivationAction"] = [context](const GObject& object, const GObject& actor) {
|
||||
context.mLuaManager->addAction(
|
||||
|
|
|
@ -16,6 +16,19 @@ namespace sol
|
|||
{
|
||||
};
|
||||
}
|
||||
namespace
|
||||
{
|
||||
// Populates a activator struct from a Lua table.
|
||||
ESM::Activator tableToActivator(const sol::table& rec)
|
||||
{
|
||||
ESM::Activator activator;
|
||||
activator.mName = rec["name"];
|
||||
activator.mModel = rec["model"];
|
||||
std::string_view scriptId = rec["mwscript"].get<std::string_view>();
|
||||
activator.mScript = ESM::RefId::deserializeText(scriptId);
|
||||
return activator;
|
||||
}
|
||||
}
|
||||
|
||||
namespace MWLua
|
||||
{
|
||||
|
@ -23,6 +36,7 @@ namespace MWLua
|
|||
{
|
||||
auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS();
|
||||
|
||||
activator["createRecordDraft"] = tableToActivator;
|
||||
addRecordFunctionBinding<ESM::Activator>(activator, context);
|
||||
|
||||
sol::usertype<ESM::Activator> record = context.mLua->sol().new_usertype<ESM::Activator>("ESM3_Activator");
|
||||
|
|
|
@ -16,6 +16,34 @@ namespace sol
|
|||
{
|
||||
};
|
||||
}
|
||||
namespace
|
||||
{
|
||||
// Populates an armor struct from a Lua table.
|
||||
ESM::Armor tableToArmor(const sol::table& rec)
|
||||
{
|
||||
ESM::Armor armor;
|
||||
armor.mName = rec["name"];
|
||||
armor.mModel = rec["model"];
|
||||
armor.mIcon = rec["icon"];
|
||||
std::string_view enchantId = rec["enchant"].get<std::string_view>();
|
||||
armor.mEnchant = ESM::RefId::deserializeText(enchantId);
|
||||
std::string_view scriptId = rec["mwscript"].get<std::string_view>();
|
||||
armor.mScript = ESM::RefId::deserializeText(scriptId);
|
||||
|
||||
armor.mData.mWeight = rec["weight"];
|
||||
armor.mData.mValue = rec["value"];
|
||||
int armorType = rec["type"].get<int>();
|
||||
if (armorType >= 0 && armorType <= ESM::Armor::RBracer)
|
||||
armor.mData.mType = armorType;
|
||||
else
|
||||
throw std::runtime_error("Invalid Armor Type provided: " + std::to_string(armorType));
|
||||
armor.mData.mHealth = rec["health"];
|
||||
armor.mData.mArmor = rec["baseArmor"];
|
||||
armor.mData.mEnchant = std::round(rec["enchantCapacity"].get<float>() * 10);
|
||||
|
||||
return armor;
|
||||
}
|
||||
}
|
||||
|
||||
namespace MWLua
|
||||
{
|
||||
|
@ -39,6 +67,7 @@ namespace MWLua
|
|||
|
||||
addRecordFunctionBinding<ESM::Armor>(armor, context);
|
||||
|
||||
armor["createRecordDraft"] = tableToArmor;
|
||||
sol::usertype<ESM::Armor> record = context.mLua->sol().new_usertype<ESM::Armor>("ESM3_Armor");
|
||||
record[sol::meta_function::to_string]
|
||||
= [](const ESM::Armor& rec) -> std::string { return "ESM3_Armor[" + rec.mId.toDebugString() + "]"; };
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
#include "types.hpp"
|
||||
|
||||
#include <components/misc/strings/algorithm.hpp>
|
||||
#include <components/misc/strings/lower.hpp>
|
||||
|
||||
#include <components/esm3/loadbook.hpp>
|
||||
#include <components/lua/luastate.hpp>
|
||||
#include <components/misc/resourcehelpers.hpp>
|
||||
|
@ -18,6 +21,43 @@ namespace sol
|
|||
};
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
// Populates a book struct from a Lua table.
|
||||
ESM::Book tableToBook(const sol::table& rec)
|
||||
{
|
||||
ESM::Book book;
|
||||
book.mName = rec["name"];
|
||||
book.mModel = rec["model"];
|
||||
book.mIcon = rec["icon"];
|
||||
book.mText = rec["text"];
|
||||
std::string_view enchantId = rec["enchant"].get<std::string_view>();
|
||||
book.mEnchant = ESM::RefId::deserializeText(enchantId);
|
||||
|
||||
book.mData.mEnchant = std::round(rec["enchantCapacity"].get<float>() * 10);
|
||||
std::string_view scriptId = rec["mwscript"].get<std::string_view>();
|
||||
book.mScript = ESM::RefId::deserializeText(scriptId);
|
||||
book.mData.mWeight = rec["weight"];
|
||||
book.mData.mValue = rec["value"];
|
||||
book.mData.mIsScroll = rec["isScroll"];
|
||||
|
||||
std::string_view skill = rec["skill"].get<std::string_view>();
|
||||
|
||||
book.mData.mSkillId = -1;
|
||||
if (skill.length() > 0)
|
||||
{
|
||||
for (std::size_t i = 0; i < std::size(ESM::Skill::sSkillNames); ++i)
|
||||
{
|
||||
if (Misc::StringUtils::ciEqual(ESM::Skill::sSkillNames[i], skill))
|
||||
book.mData.mSkillId = i;
|
||||
}
|
||||
if (book.mData.mSkillId == -1)
|
||||
throw std::runtime_error("Incorrect skill: " + std::string(skill));
|
||||
}
|
||||
return book;
|
||||
}
|
||||
}
|
||||
|
||||
namespace MWLua
|
||||
{
|
||||
void addBookBindings(sol::table book, const Context& context)
|
||||
|
@ -26,6 +66,7 @@ namespace MWLua
|
|||
// TODO: Remove book.SKILL after branching 0.49
|
||||
sol::table skill(context.mLua->sol(), sol::create);
|
||||
book["SKILL"] = LuaUtil::makeStrictReadOnly(skill);
|
||||
book["createRecordDraft"] = tableToBook;
|
||||
for (int id = ESM::Skill::Block; id < ESM::Skill::Length; ++id)
|
||||
{
|
||||
std::string skillName = Misc::StringUtils::lowerCase(ESM::Skill::sSkillNames[id]);
|
||||
|
|
|
@ -16,11 +16,36 @@ namespace sol
|
|||
{
|
||||
};
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
// Populates a clothing struct from a Lua table.
|
||||
ESM::Clothing tableToClothing(const sol::table& rec)
|
||||
{
|
||||
ESM::Clothing clothing;
|
||||
clothing.mName = rec["name"];
|
||||
clothing.mModel = rec["model"];
|
||||
clothing.mIcon = rec["icon"];
|
||||
std::string_view scriptId = rec["mwscript"].get<std::string_view>();
|
||||
clothing.mScript = ESM::RefId::deserializeText(scriptId);
|
||||
clothing.mData.mEnchant = std::round(rec["enchantCapacity"].get<float>() * 10);
|
||||
std::string_view enchantId = rec["enchant"].get<std::string_view>();
|
||||
clothing.mEnchant = ESM::RefId::deserializeText(enchantId);
|
||||
clothing.mData.mWeight = rec["weight"];
|
||||
clothing.mData.mValue = rec["value"];
|
||||
int clothingType = rec["type"].get<int>();
|
||||
if (clothingType >= 0 && clothingType <= ESM::Clothing::Amulet)
|
||||
clothing.mData.mType = clothingType;
|
||||
else
|
||||
throw std::runtime_error("Invalid Clothing Type provided: " + std::to_string(clothingType));
|
||||
return clothing;
|
||||
}
|
||||
}
|
||||
namespace MWLua
|
||||
{
|
||||
void addClothingBindings(sol::table clothing, const Context& context)
|
||||
{
|
||||
clothing["createRecordDraft"] = tableToClothing;
|
||||
|
||||
clothing["TYPE"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, int>({
|
||||
{ "Amulet", ESM::Clothing::Amulet },
|
||||
{ "Belt", ESM::Clothing::Belt },
|
||||
|
|
|
@ -18,6 +18,23 @@ namespace sol
|
|||
};
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
// Populates a misc struct from a Lua table.
|
||||
ESM::Miscellaneous tableToMisc(const sol::table& rec)
|
||||
{
|
||||
ESM::Miscellaneous misc;
|
||||
misc.mName = rec["name"];
|
||||
misc.mModel = rec["model"];
|
||||
misc.mIcon = rec["icon"];
|
||||
std::string_view scriptId = rec["mwscript"].get<std::string_view>();
|
||||
misc.mScript = ESM::RefId::deserializeText(scriptId);
|
||||
misc.mData.mWeight = rec["weight"];
|
||||
misc.mData.mValue = rec["value"];
|
||||
return misc;
|
||||
}
|
||||
}
|
||||
|
||||
namespace MWLua
|
||||
{
|
||||
void addMiscellaneousBindings(sol::table miscellaneous, const Context& context)
|
||||
|
@ -25,6 +42,7 @@ namespace MWLua
|
|||
auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS();
|
||||
|
||||
addRecordFunctionBinding<ESM::Miscellaneous>(miscellaneous, context);
|
||||
miscellaneous["createRecordDraft"] = tableToMisc;
|
||||
|
||||
miscellaneous["setSoul"] = [](const GObject& object, std::string_view soulId) {
|
||||
ESM::RefId creature = ESM::RefId::deserializeText(soulId);
|
||||
|
|
|
@ -43,6 +43,7 @@ namespace MWLua
|
|||
= sol::readonly_property([](const ESM::NPC& rec) -> std::string { return rec.mHair.serializeText(); });
|
||||
record["head"]
|
||||
= sol::readonly_property([](const ESM::NPC& rec) -> std::string { return rec.mHead.serializeText(); });
|
||||
record["isMale"] = sol::readonly_property([](const ESM::NPC& rec) -> bool { return rec.isMale(); });
|
||||
|
||||
// This function is game-specific, in future we should replace it with something more universal.
|
||||
npc["isWerewolf"] = [](const Object& o) {
|
||||
|
|
|
@ -17,6 +17,48 @@ namespace sol
|
|||
};
|
||||
}
|
||||
#include <components/resource/resourcesystem.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
// Populates a weapon struct from a Lua table.
|
||||
ESM::Weapon tableToWeapon(const sol::table& rec)
|
||||
{
|
||||
ESM::Weapon weapon;
|
||||
weapon.mName = rec["name"];
|
||||
weapon.mModel = rec["model"];
|
||||
weapon.mIcon = rec["icon"];
|
||||
std::string_view enchantId = rec["enchant"].get<std::string_view>();
|
||||
weapon.mEnchant = ESM::RefId::deserializeText(enchantId);
|
||||
std::string_view scriptId = rec["mwscript"].get<std::string_view>();
|
||||
weapon.mScript = ESM::RefId::deserializeText(scriptId);
|
||||
weapon.mData.mFlags = 0;
|
||||
if (rec["isMagical"])
|
||||
weapon.mData.mFlags |= ESM::Weapon::Magical;
|
||||
if (rec["isSilver"])
|
||||
weapon.mData.mFlags |= ESM::Weapon::Silver;
|
||||
int weaponType = rec["type"].get<int>();
|
||||
if (weaponType >= 0 && weaponType <= ESM::Weapon::MarksmanThrown)
|
||||
weapon.mData.mType = weaponType;
|
||||
else
|
||||
throw std::runtime_error("Invalid Weapon Type provided: " + std::to_string(weaponType));
|
||||
|
||||
weapon.mData.mWeight = rec["weight"];
|
||||
weapon.mData.mValue = rec["value"];
|
||||
weapon.mData.mHealth = rec["health"];
|
||||
weapon.mData.mSpeed = rec["speed"];
|
||||
weapon.mData.mReach = rec["reach"];
|
||||
weapon.mData.mEnchant = std::round(rec["enchantCapacity"].get<float>() * 10);
|
||||
weapon.mData.mChop[0] = rec["chopMinDamage"];
|
||||
weapon.mData.mChop[1] = rec["chopMaxDamage"];
|
||||
weapon.mData.mSlash[0] = rec["slashMinDamage"];
|
||||
weapon.mData.mSlash[1] = rec["slashMaxDamage"];
|
||||
weapon.mData.mThrust[0] = rec["thrustMinDamage"];
|
||||
weapon.mData.mThrust[1] = rec["thrustMaxDamage"];
|
||||
|
||||
return weapon;
|
||||
}
|
||||
}
|
||||
|
||||
namespace MWLua
|
||||
{
|
||||
void addWeaponBindings(sol::table weapon, const Context& context)
|
||||
|
@ -41,6 +83,7 @@ namespace MWLua
|
|||
auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS();
|
||||
|
||||
addRecordFunctionBinding<ESM::Weapon>(weapon, context);
|
||||
weapon["createRecordDraft"] = tableToWeapon;
|
||||
|
||||
sol::usertype<ESM::Weapon> record = context.mLua->sol().new_usertype<ESM::Weapon>("ESM3_Weapon");
|
||||
record[sol::meta_function::to_string]
|
||||
|
|
|
@ -461,6 +461,8 @@ void MWState::StateManager::loadGame(const Character* character, const std::file
|
|||
break;
|
||||
|
||||
case ESM::REC_ALCH:
|
||||
case ESM::REC_MISC:
|
||||
case ESM::REC_ACTI:
|
||||
case ESM::REC_ARMO:
|
||||
case ESM::REC_BOOK:
|
||||
case ESM::REC_CLAS:
|
||||
|
|
|
@ -631,6 +631,7 @@ namespace MWWorld
|
|||
+ get<ESM::Book>().getDynamicSize() + get<ESM::Class>().getDynamicSize()
|
||||
+ get<ESM::Clothing>().getDynamicSize() + get<ESM::Enchantment>().getDynamicSize()
|
||||
+ get<ESM::NPC>().getDynamicSize() + get<ESM::Spell>().getDynamicSize()
|
||||
+ get<ESM::Activator>().getDynamicSize() + get<ESM::Miscellaneous>().getDynamicSize()
|
||||
+ get<ESM::Weapon>().getDynamicSize() + get<ESM::CreatureLevList>().getDynamicSize()
|
||||
+ get<ESM::ItemLevList>().getDynamicSize() + get<ESM::Creature>().getDynamicSize()
|
||||
+ get<ESM::Container>().getDynamicSize();
|
||||
|
@ -651,6 +652,8 @@ namespace MWWorld
|
|||
get<ESM::Clothing>().write(writer, progress);
|
||||
get<ESM::Enchantment>().write(writer, progress);
|
||||
get<ESM::NPC>().write(writer, progress);
|
||||
get<ESM::Miscellaneous>().write(writer, progress);
|
||||
get<ESM::Activator>().write(writer, progress);
|
||||
get<ESM::Spell>().write(writer, progress);
|
||||
get<ESM::Weapon>().write(writer, progress);
|
||||
get<ESM::CreatureLevList>().write(writer, progress);
|
||||
|
@ -665,6 +668,8 @@ namespace MWWorld
|
|||
switch (type)
|
||||
{
|
||||
case ESM::REC_ALCH:
|
||||
case ESM::REC_MISC:
|
||||
case ESM::REC_ACTI:
|
||||
case ESM::REC_ARMO:
|
||||
case ESM::REC_BOOK:
|
||||
case ESM::REC_CLAS:
|
||||
|
|
|
@ -631,6 +631,7 @@
|
|||
-- @field #string mwscript MWScript that is attached to this NPC
|
||||
-- @field #string hair Path to the hair body part model
|
||||
-- @field #string head Path to the head body part model
|
||||
-- @field #bool isMale The gender setting of the NPC
|
||||
|
||||
--- @{#Player} functions
|
||||
-- @field [parent=#types] #Player Player
|
||||
|
@ -701,6 +702,12 @@
|
|||
-- @field #number baseArmor The base armor rating of this armor
|
||||
-- @field #number enchantCapacity
|
||||
|
||||
---
|
||||
-- Creates a @{#ArmorRecord} without adding it to the world database.
|
||||
-- Use @{openmw_world#(world).createRecord} to add the record to the world.
|
||||
-- @function [parent=#Armor] createRecordDraft
|
||||
-- @param #ArmorRecord armor A Lua table with the fields of a ArmorRecord.
|
||||
-- @return #ArmorRecord A strongly typed Armor record.
|
||||
|
||||
|
||||
--- @{#Book} functions
|
||||
|
@ -772,7 +779,12 @@
|
|||
-- @field #boolean isScroll
|
||||
-- @field #number enchantCapacity
|
||||
|
||||
|
||||
---
|
||||
-- Creates a @{#BookRecord} without adding it to the world database.
|
||||
-- Use @{openmw_world#(world).createRecord} to add the record to the world.
|
||||
-- @function [parent=#Book] createRecordDraft
|
||||
-- @param #BookRecord book A Lua table with the fields of a BookRecord.
|
||||
-- @return #BookRecord A strongly typed Book record.
|
||||
|
||||
--- @{#Clothing} functions
|
||||
-- @field [parent=#types] #Clothing Clothing
|
||||
|
@ -811,6 +823,13 @@
|
|||
-- @param #any objectOrRecordId
|
||||
-- @return #ClothingRecord
|
||||
|
||||
---
|
||||
-- Creates a @{#ClothingRecord} without adding it to the world database.
|
||||
-- Use @{openmw_world#(world).createRecord} to add the record to the world.
|
||||
-- @function [parent=#Clothing] createRecordDraft
|
||||
-- @param #ClothingRecord clothing A Lua table with the fields of a ClothingRecord.
|
||||
-- @return #ClothingRecord A strongly typed clothing record.
|
||||
|
||||
---
|
||||
-- @type ClothingRecord
|
||||
-- @field #string id Record id
|
||||
|
@ -925,6 +944,13 @@
|
|||
-- @param openmw.core#GameObject object
|
||||
-- @return #string
|
||||
|
||||
---
|
||||
-- Creates a @{#MiscellaneousRecord} without adding it to the world database.
|
||||
-- Use @{openmw_world#(world).createRecord} to add the record to the world.
|
||||
-- @function [parent=#Miscellaneous] createRecordDraft
|
||||
-- @param #MiscellaneousRecord miscellaneous A Lua table with the fields of a MiscellaneousRecord.
|
||||
-- @return #MiscellaneousRecord A strongly typed Miscellaneous record.
|
||||
|
||||
---
|
||||
-- Sets the soul of a miscellaneous item, intended for soul gem objects; Must be used in a global script.
|
||||
-- @function [parent=#Miscellaneous] setSoul
|
||||
|
@ -1047,7 +1073,12 @@
|
|||
-- @field #number thrustMinDamage
|
||||
-- @field #number thrustMaxDamage
|
||||
|
||||
|
||||
---
|
||||
-- Creates a @{#WeaponRecord} without adding it to the world database.
|
||||
-- Use @{openmw_world#(world).createRecord} to add the record to the world.
|
||||
-- @function [parent=#Weapon] createRecordDraft
|
||||
-- @param #WeaponRecord weapon A Lua table with the fields of a WeaponRecord.
|
||||
-- @return #WeaponRecord A strongly typed Weapon record.
|
||||
|
||||
--- @{#Apparatus} functions
|
||||
-- @field [parent=#types] #Apparatus Apparatus
|
||||
|
@ -1217,6 +1248,13 @@
|
|||
-- @field #string model VFS path to the model
|
||||
-- @field #string mwscript MWScript on this activator (can be empty)
|
||||
|
||||
---
|
||||
-- Creates a @{#ActivatorRecord} without adding it to the world database.
|
||||
-- Use @{openmw_world#(world).createRecord} to add the record to the world.
|
||||
-- @function [parent=#Activator] createRecordDraft
|
||||
-- @param #ActivatorRecord activator A Lua table with the fields of a ActivatorRecord.
|
||||
-- @return #ActivatorRecord A strongly typed Activator record.
|
||||
|
||||
--- @{#Container} functions
|
||||
-- @field [parent=#types] #Container Container
|
||||
|
||||
|
|
|
@ -83,10 +83,13 @@
|
|||
-- Creates a custom record in the world database.
|
||||
-- Eventually meant to support all records, but the current
|
||||
-- set of supported types is limited to:
|
||||
-- * @{openmw.types#PotionRecord}
|
||||
-- * @{openmw.types#PotionRecord},
|
||||
-- * @{openmw.types#ArmorRecord},
|
||||
-- * @{openmw.types#BookRecord},
|
||||
-- * @{openmw.types#MiscellaneousRecord},
|
||||
-- * @{openmw.types#ActivatorRecord}
|
||||
-- @function [parent=#world] createRecord
|
||||
-- @param #any record A record to be registered in the database. Must be one of the supported types.
|
||||
-- @return #any A new record added to the database. The type is the same as the input's.
|
||||
|
||||
return nil
|
||||
|
||||
|
|
Loading…
Reference in a new issue