Allow creating Activator, Armor, Clothing, Misc, Weapon records via lua

simplify_debugging
Zackhasacat 1 year ago committed by Petr Mikheev
parent 38823cb983
commit ef004e5eba

@ -225,7 +225,7 @@ Programmers
tlmullis tlmullis
tri4ng1e tri4ng1e
Thoronador Thoronador
Tobias Tribble (zackogenic) Tobias Tribble (zackhasacat)
Tom Lowe (Vulpen) Tom Lowe (Vulpen)
Tom Mason (wheybags) Tom Mason (wheybags)
Torben Leif Carrington (TorbenC) Torben Leif Carrington (TorbenC)

@ -3,9 +3,14 @@
#include <chrono> #include <chrono>
#include <components/esm/attr.hpp> #include <components/esm/attr.hpp>
#include <components/esm3/loadacti.hpp>
#include <components/esm3/loadalch.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/loadskil.hpp>
#include <components/esm3/loadweap.hpp>
#include <components/lua/l10n.hpp> #include <components/lua/l10n.hpp>
#include <components/lua/luastate.hpp> #include <components/lua/luastate.hpp>
#include <components/lua/utilpackage.hpp> #include <components/lua/utilpackage.hpp>
@ -186,11 +191,28 @@ namespace MWLua
}; };
// Creates a new record in the world database. // Creates a new record in the world database.
api["createRecord"] = sol::overload([](const ESM::Potion& potion) -> const ESM::Potion* { api["createRecord"] = sol::overload(
return MWBase::Environment::get().getESMStore()->insert(potion); [](const ESM::Activator& activator) -> const ESM::Activator* {
} return MWBase::Environment::get().getESMStore()->insert(activator);
// TODO: add here overloads for other records },
); [](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) { api["_runStandardActivationAction"] = [context](const GObject& object, const GObject& actor) {
context.mLuaManager->addAction( 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 namespace MWLua
{ {
@ -23,6 +36,7 @@ namespace MWLua
{ {
auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS();
activator["createRecordDraft"] = tableToActivator;
addRecordFunctionBinding<ESM::Activator>(activator, context); addRecordFunctionBinding<ESM::Activator>(activator, context);
sol::usertype<ESM::Activator> record = context.mLua->sol().new_usertype<ESM::Activator>("ESM3_Activator"); 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 namespace MWLua
{ {
@ -39,6 +67,7 @@ namespace MWLua
addRecordFunctionBinding<ESM::Armor>(armor, context); addRecordFunctionBinding<ESM::Armor>(armor, context);
armor["createRecordDraft"] = tableToArmor;
sol::usertype<ESM::Armor> record = context.mLua->sol().new_usertype<ESM::Armor>("ESM3_Armor"); sol::usertype<ESM::Armor> record = context.mLua->sol().new_usertype<ESM::Armor>("ESM3_Armor");
record[sol::meta_function::to_string] record[sol::meta_function::to_string]
= [](const ESM::Armor& rec) -> std::string { return "ESM3_Armor[" + rec.mId.toDebugString() + "]"; }; = [](const ESM::Armor& rec) -> std::string { return "ESM3_Armor[" + rec.mId.toDebugString() + "]"; };

@ -1,5 +1,8 @@
#include "types.hpp" #include "types.hpp"
#include <components/misc/strings/algorithm.hpp>
#include <components/misc/strings/lower.hpp>
#include <components/esm3/loadbook.hpp> #include <components/esm3/loadbook.hpp>
#include <components/lua/luastate.hpp> #include <components/lua/luastate.hpp>
#include <components/misc/resourcehelpers.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 namespace MWLua
{ {
void addBookBindings(sol::table book, const Context& context) void addBookBindings(sol::table book, const Context& context)
@ -26,6 +66,7 @@ namespace MWLua
// TODO: Remove book.SKILL after branching 0.49 // TODO: Remove book.SKILL after branching 0.49
sol::table skill(context.mLua->sol(), sol::create); sol::table skill(context.mLua->sol(), sol::create);
book["SKILL"] = LuaUtil::makeStrictReadOnly(skill); book["SKILL"] = LuaUtil::makeStrictReadOnly(skill);
book["createRecordDraft"] = tableToBook;
for (int id = ESM::Skill::Block; id < ESM::Skill::Length; ++id) for (int id = ESM::Skill::Block; id < ESM::Skill::Length; ++id)
{ {
std::string skillName = Misc::StringUtils::lowerCase(ESM::Skill::sSkillNames[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 namespace MWLua
{ {
void addClothingBindings(sol::table clothing, const Context& context) void addClothingBindings(sol::table clothing, const Context& context)
{ {
clothing["createRecordDraft"] = tableToClothing;
clothing["TYPE"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, int>({ clothing["TYPE"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, int>({
{ "Amulet", ESM::Clothing::Amulet }, { "Amulet", ESM::Clothing::Amulet },
{ "Belt", ESM::Clothing::Belt }, { "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 namespace MWLua
{ {
void addMiscellaneousBindings(sol::table miscellaneous, const Context& context) void addMiscellaneousBindings(sol::table miscellaneous, const Context& context)
@ -25,6 +42,7 @@ namespace MWLua
auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS();
addRecordFunctionBinding<ESM::Miscellaneous>(miscellaneous, context); addRecordFunctionBinding<ESM::Miscellaneous>(miscellaneous, context);
miscellaneous["createRecordDraft"] = tableToMisc;
miscellaneous["setSoul"] = [](const GObject& object, std::string_view soulId) { miscellaneous["setSoul"] = [](const GObject& object, std::string_view soulId) {
ESM::RefId creature = ESM::RefId::deserializeText(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(); }); = sol::readonly_property([](const ESM::NPC& rec) -> std::string { return rec.mHair.serializeText(); });
record["head"] record["head"]
= sol::readonly_property([](const ESM::NPC& rec) -> std::string { return rec.mHead.serializeText(); }); = 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. // This function is game-specific, in future we should replace it with something more universal.
npc["isWerewolf"] = [](const Object& o) { npc["isWerewolf"] = [](const Object& o) {

@ -17,6 +17,48 @@ namespace sol
}; };
} }
#include <components/resource/resourcesystem.hpp> #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 namespace MWLua
{ {
void addWeaponBindings(sol::table weapon, const Context& context) void addWeaponBindings(sol::table weapon, const Context& context)
@ -41,6 +83,7 @@ namespace MWLua
auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS();
addRecordFunctionBinding<ESM::Weapon>(weapon, context); addRecordFunctionBinding<ESM::Weapon>(weapon, context);
weapon["createRecordDraft"] = tableToWeapon;
sol::usertype<ESM::Weapon> record = context.mLua->sol().new_usertype<ESM::Weapon>("ESM3_Weapon"); sol::usertype<ESM::Weapon> record = context.mLua->sol().new_usertype<ESM::Weapon>("ESM3_Weapon");
record[sol::meta_function::to_string] record[sol::meta_function::to_string]

@ -461,6 +461,8 @@ void MWState::StateManager::loadGame(const Character* character, const std::file
break; break;
case ESM::REC_ALCH: case ESM::REC_ALCH:
case ESM::REC_MISC:
case ESM::REC_ACTI:
case ESM::REC_ARMO: case ESM::REC_ARMO:
case ESM::REC_BOOK: case ESM::REC_BOOK:
case ESM::REC_CLAS: case ESM::REC_CLAS:

@ -631,6 +631,7 @@ namespace MWWorld
+ get<ESM::Book>().getDynamicSize() + get<ESM::Class>().getDynamicSize() + get<ESM::Book>().getDynamicSize() + get<ESM::Class>().getDynamicSize()
+ get<ESM::Clothing>().getDynamicSize() + get<ESM::Enchantment>().getDynamicSize() + get<ESM::Clothing>().getDynamicSize() + get<ESM::Enchantment>().getDynamicSize()
+ get<ESM::NPC>().getDynamicSize() + get<ESM::Spell>().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::Weapon>().getDynamicSize() + get<ESM::CreatureLevList>().getDynamicSize()
+ get<ESM::ItemLevList>().getDynamicSize() + get<ESM::Creature>().getDynamicSize() + get<ESM::ItemLevList>().getDynamicSize() + get<ESM::Creature>().getDynamicSize()
+ get<ESM::Container>().getDynamicSize(); + get<ESM::Container>().getDynamicSize();
@ -651,6 +652,8 @@ namespace MWWorld
get<ESM::Clothing>().write(writer, progress); get<ESM::Clothing>().write(writer, progress);
get<ESM::Enchantment>().write(writer, progress); get<ESM::Enchantment>().write(writer, progress);
get<ESM::NPC>().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::Spell>().write(writer, progress);
get<ESM::Weapon>().write(writer, progress); get<ESM::Weapon>().write(writer, progress);
get<ESM::CreatureLevList>().write(writer, progress); get<ESM::CreatureLevList>().write(writer, progress);
@ -665,6 +668,8 @@ namespace MWWorld
switch (type) switch (type)
{ {
case ESM::REC_ALCH: case ESM::REC_ALCH:
case ESM::REC_MISC:
case ESM::REC_ACTI:
case ESM::REC_ARMO: case ESM::REC_ARMO:
case ESM::REC_BOOK: case ESM::REC_BOOK:
case ESM::REC_CLAS: case ESM::REC_CLAS:

@ -570,6 +570,7 @@
-- @field #string mwscript MWScript that is attached to this NPC -- @field #string mwscript MWScript that is attached to this NPC
-- @field #string hair Path to the hair body part model -- @field #string hair Path to the hair body part model
-- @field #string head Path to the head body part model -- @field #string head Path to the head body part model
-- @field #bool isMale The gender setting of the NPC
--- @{#Player} functions --- @{#Player} functions
-- @field [parent=#types] #Player Player -- @field [parent=#types] #Player Player
@ -640,6 +641,12 @@
-- @field #number baseArmor The base armor rating of this armor -- @field #number baseArmor The base armor rating of this armor
-- @field #number enchantCapacity -- @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 --- @{#Book} functions
@ -711,7 +718,12 @@
-- @field #boolean isScroll -- @field #boolean isScroll
-- @field #number enchantCapacity -- @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 --- @{#Clothing} functions
-- @field [parent=#types] #Clothing Clothing -- @field [parent=#types] #Clothing Clothing
@ -750,6 +762,13 @@
-- @param #any objectOrRecordId -- @param #any objectOrRecordId
-- @return #ClothingRecord -- @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 -- @type ClothingRecord
-- @field #string id Record id -- @field #string id Record id
@ -864,6 +883,13 @@
-- @param openmw.core#GameObject object -- @param openmw.core#GameObject object
-- @return #string -- @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. -- Sets the soul of a miscellaneous item, intended for soul gem objects; Must be used in a global script.
-- @function [parent=#Miscellaneous] setSoul -- @function [parent=#Miscellaneous] setSoul
@ -986,7 +1012,12 @@
-- @field #number thrustMinDamage -- @field #number thrustMinDamage
-- @field #number thrustMaxDamage -- @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 --- @{#Apparatus} functions
-- @field [parent=#types] #Apparatus Apparatus -- @field [parent=#types] #Apparatus Apparatus
@ -1156,6 +1187,13 @@
-- @field #string model VFS path to the model -- @field #string model VFS path to the model
-- @field #string mwscript MWScript on this activator (can be empty) -- @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 --- @{#Container} functions
-- @field [parent=#types] #Container Container -- @field [parent=#types] #Container Container

@ -83,10 +83,13 @@
-- Creates a custom record in the world database. -- Creates a custom record in the world database.
-- Eventually meant to support all records, but the current -- Eventually meant to support all records, but the current
-- set of supported types is limited to: -- 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 -- @function [parent=#world] createRecord
-- @param #any record A record to be registered in the database. Must be one of the supported types. -- @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 #any A new record added to the database. The type is the same as the input's.
return nil return nil

Loading…
Cancel
Save