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

simplify_debugging
Zackhasacat 12 months ago committed by Petr Mikheev
parent 38823cb983
commit ef004e5eba

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

@ -570,6 +570,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
@ -640,6 +641,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
@ -711,7 +718,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
@ -750,6 +762,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
@ -864,6 +883,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
@ -986,7 +1012,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
@ -1156,6 +1187,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…
Cancel
Save