Lua: Add missing light flags, allow creating light record via world.createRecord

i-have-no-land-and-i-must-scream
Zackhasacat 8 months ago committed by psi29a
parent f595015ffc
commit c63c1e69cf

@ -15,6 +15,65 @@ namespace sol
}; };
} }
namespace
{
void setRecordFlag(const sol::table& rec, const std::string& key, int flag, ESM::Light& record)
{
if (auto luaFlag = rec[key]; luaFlag != sol::nil)
{
if (luaFlag)
{
record.mData.mFlags |= flag;
}
else
{
record.mData.mFlags &= ~flag;
}
}
}
// Populates a light struct from a Lua table.
ESM::Light tableToLight(const sol::table& rec)
{
ESM::Light light;
if (rec["template"] != sol::nil)
light = LuaUtil::cast<ESM::Light>(rec["template"]);
else
light.blank();
if (rec["name"] != sol::nil)
light.mName = rec["name"];
if (rec["model"] != sol::nil)
light.mModel = Misc::ResourceHelpers::meshPathForESM3(rec["model"].get<std::string_view>());
if (rec["icon"] != sol::nil)
light.mIcon = rec["icon"];
if (rec["mwscript"] != sol::nil)
{
std::string_view scriptId = rec["mwscript"].get<std::string_view>();
light.mScript = ESM::RefId::deserializeText(scriptId);
}
if (rec["weight"] != sol::nil)
light.mData.mWeight = rec["weight"];
if (rec["value"] != sol::nil)
light.mData.mValue = rec["value"];
if (rec["duration"] != sol::nil)
light.mData.mTime = rec["duration"];
if (rec["radius"] != sol::nil)
light.mData.mRadius = rec["radius"];
if (rec["color"] != sol::nil)
light.mData.mColor = rec["color"];
setRecordFlag(rec, "isCarriable", ESM::Light::Carry, light);
setRecordFlag(rec, "isDynamic", ESM::Light::Dynamic, light);
setRecordFlag(rec, "isFire", ESM::Light::Fire, light);
setRecordFlag(rec, "isFlicker", ESM::Light::Flicker, light);
setRecordFlag(rec, "isFlickerSlow", ESM::Light::FlickerSlow, light);
setRecordFlag(rec, "isNegative", ESM::Light::Negative, light);
setRecordFlag(rec, "isOffByDefault", ESM::Light::OffDefault, light);
setRecordFlag(rec, "isPulse", ESM::Light::Pulse, light);
setRecordFlag(rec, "isPulseSlow", ESM::Light::PulseSlow, light);
return light;
}
}
namespace MWLua namespace MWLua
{ {
void addLightBindings(sol::table light, const Context& context) void addLightBindings(sol::table light, const Context& context)
@ -22,6 +81,7 @@ namespace MWLua
auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS();
addRecordFunctionBinding<ESM::Light>(light, context); addRecordFunctionBinding<ESM::Light>(light, context);
light["createRecordDraft"] = tableToLight;
sol::usertype<ESM::Light> record = context.mLua->sol().new_usertype<ESM::Light>("ESM3_Light"); sol::usertype<ESM::Light> record = context.mLua->sol().new_usertype<ESM::Light>("ESM3_Light");
record[sol::meta_function::to_string] record[sol::meta_function::to_string]
@ -45,5 +105,21 @@ namespace MWLua
record["color"] = sol::readonly_property([](const ESM::Light& rec) -> int { return rec.mData.mColor; }); record["color"] = sol::readonly_property([](const ESM::Light& rec) -> int { return rec.mData.mColor; });
record["isCarriable"] = sol::readonly_property( record["isCarriable"] = sol::readonly_property(
[](const ESM::Light& rec) -> bool { return rec.mData.mFlags & ESM::Light::Carry; }); [](const ESM::Light& rec) -> bool { return rec.mData.mFlags & ESM::Light::Carry; });
record["isDynamic"] = sol::readonly_property(
[](const ESM::Light& rec) -> bool { return rec.mData.mFlags & ESM::Light::Dynamic; });
record["isFire"]
= sol::readonly_property([](const ESM::Light& rec) -> bool { return rec.mData.mFlags & ESM::Light::Fire; });
record["isFlicker"] = sol::readonly_property(
[](const ESM::Light& rec) -> bool { return rec.mData.mFlags & ESM::Light::Flicker; });
record["isFlickerSlow"] = sol::readonly_property(
[](const ESM::Light& rec) -> bool { return rec.mData.mFlags & ESM::Light::FlickerSlow; });
record["isNegative"] = sol::readonly_property(
[](const ESM::Light& rec) -> bool { return rec.mData.mFlags & ESM::Light::Negative; });
record["isOffByDefault"] = sol::readonly_property(
[](const ESM::Light& rec) -> bool { return rec.mData.mFlags & ESM::Light::OffDefault; });
record["isPulse"] = sol::readonly_property(
[](const ESM::Light& rec) -> bool { return rec.mData.mFlags & ESM::Light::Pulse; });
record["isPulseSlow"] = sol::readonly_property(
[](const ESM::Light& rec) -> bool { return rec.mData.mFlags & ESM::Light::PulseSlow; });
} }
} }

@ -5,6 +5,7 @@
#include <components/esm3/loadarmo.hpp> #include <components/esm3/loadarmo.hpp>
#include <components/esm3/loadbook.hpp> #include <components/esm3/loadbook.hpp>
#include <components/esm3/loadclot.hpp> #include <components/esm3/loadclot.hpp>
#include <components/esm3/loadligh.hpp>
#include <components/esm3/loadmisc.hpp> #include <components/esm3/loadmisc.hpp>
#include <components/esm3/loadskil.hpp> #include <components/esm3/loadskil.hpp>
#include <components/esm3/loadweap.hpp> #include <components/esm3/loadweap.hpp>
@ -181,6 +182,10 @@ namespace MWLua
[lua = context.mLua](const ESM::Weapon& weapon) -> const ESM::Weapon* { [lua = context.mLua](const ESM::Weapon& weapon) -> const ESM::Weapon* {
checkGameInitialized(lua); checkGameInitialized(lua);
return MWBase::Environment::get().getESMStore()->insert(weapon); return MWBase::Environment::get().getESMStore()->insert(weapon);
},
[lua = context.mLua](const ESM::Light& light) -> const ESM::Light* {
checkGameInitialized(lua);
return MWBase::Environment::get().getESMStore()->insert(light);
}); });
api["_runStandardActivationAction"] = [context](const GObject& object, const GObject& actor) { api["_runStandardActivationAction"] = [context](const GObject& object, const GObject& actor) {

@ -540,6 +540,7 @@ void MWState::StateManager::loadGame(const Character* character, const std::file
case ESM::REC_ENAB: case ESM::REC_ENAB:
case ESM::REC_LEVC: case ESM::REC_LEVC:
case ESM::REC_LEVI: case ESM::REC_LEVI:
case ESM::REC_LIGH:
case ESM::REC_CREA: case ESM::REC_CREA:
case ESM::REC_CONT: case ESM::REC_CONT:
case ESM::REC_RAND: case ESM::REC_RAND:

@ -689,7 +689,7 @@ namespace MWWorld
+ get<ESM::Activator>().getDynamicSize() + get<ESM::Miscellaneous>().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() + get<ESM::Light>().getDynamicSize();
} }
void ESMStore::write(ESM::ESMWriter& writer, Loading::Listener& progress) const void ESMStore::write(ESM::ESMWriter& writer, Loading::Listener& progress) const
@ -715,6 +715,7 @@ namespace MWWorld
get<ESM::ItemLevList>().write(writer, progress); get<ESM::ItemLevList>().write(writer, progress);
get<ESM::Creature>().write(writer, progress); get<ESM::Creature>().write(writer, progress);
get<ESM::Container>().write(writer, progress); get<ESM::Container>().write(writer, progress);
get<ESM::Light>().write(writer, progress);
} }
bool ESMStore::readRecord(ESM::ESMReader& reader, uint32_t type_id) bool ESMStore::readRecord(ESM::ESMReader& reader, uint32_t type_id)
@ -734,6 +735,7 @@ namespace MWWorld
case ESM::REC_WEAP: case ESM::REC_WEAP:
case ESM::REC_LEVI: case ESM::REC_LEVI:
case ESM::REC_LEVC: case ESM::REC_LEVC:
case ESM::REC_LIGH:
mStoreImp->mRecNameToStore[type]->read(reader); mStoreImp->mRecNameToStore[type]->read(reader);
return true; return true;
case ESM::REC_NPC_: case ESM::REC_NPC_:

@ -1589,6 +1589,13 @@
-- @param openmw.core#GameObject object -- @param openmw.core#GameObject object
-- @return #boolean -- @return #boolean
---
-- Creates a @{#LightRecord} without adding it to the world database.
-- Use @{openmw_world#(world).createRecord} to add the record to the world.
-- @function [parent=#Light] createRecordDraft
-- @param #LightRecord light A Lua table with the fields of a LightRecord, with an optional field `template` that accepts a @{#LightRecord} as a base.
-- @return #LightRecord A strongly typed Light record.
--- ---
-- Returns the read-only @{#LightRecord} of a Light -- Returns the read-only @{#LightRecord} of a Light
-- @function [parent=#Light] record -- @function [parent=#Light] record
@ -1608,7 +1615,15 @@
-- @field #number duration -- @field #number duration
-- @field #number radius -- @field #number radius
-- @field #number color -- @field #number color
-- @field #boolean isCarriable -- @field #boolean isCarriable True if the light can be carried by actors and appears up in their inventory.
-- @field #boolean isDynamic If true, the light will apply to actors and other moving objects
-- @field #boolean isFire True if the light acts like a fire.
-- @field #boolean isFlicker
-- @field #boolean isFlickerSlow
-- @field #boolean isNegative If true, the light will reduce light instead of increasing it.
-- @field #boolean isOffByDefault If true, the light will not emit any light or sound while placed in the world. It will still work in the inventory.
-- @field #boolean isPulse
-- @field #boolean isPulseSlow

@ -172,7 +172,8 @@
-- * @{openmw.types#MiscellaneousRecord}, -- * @{openmw.types#MiscellaneousRecord},
-- * @{openmw.types#ClothingRecord}, -- * @{openmw.types#ClothingRecord},
-- * @{openmw.types#WeaponRecord}, -- * @{openmw.types#WeaponRecord},
-- * @{openmw.types#ActivatorRecord} -- * @{openmw.types#ActivatorRecord},
-- * @{openmw.types#LightRecord}
-- @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.

@ -126,7 +126,30 @@ local function testRecordStores()
testRecordStore(types.NPC.races,"races") testRecordStore(types.NPC.races,"races")
testRecordStore(types.Player.birthSigns,"birthSigns") testRecordStore(types.Player.birthSigns,"birthSigns")
end end
local function testRecordCreation()
local newLight = {
isCarriable = true,
isDynamic = true,
isFire =false,
isFlicker = false,
isFlickerSlow = false,
isNegative = false,
isOffByDefault = false,
isPulse = false,
weight = 1,
value = 10,
duration = 12,
radius = 30,
color = 5,
name = "TestLight",
model = "meshes\\marker_door.dae"
}
local draft = types.Light.createRecordDraft(newLight)
local record = world.createRecord(draft)
for key, value in pairs(newLight) do
testing.expectEqual(record[key],value)
end
end
local function initPlayer() local function initPlayer()
player:teleport('', util.vector3(4096, 4096, 867.237), util.transform.identity) player:teleport('', util.vector3(4096, 4096, 867.237), util.transform.identity)
coroutine.yield() coroutine.yield()
@ -165,6 +188,7 @@ tests = {
{'teleport', testTeleport}, {'teleport', testTeleport},
{'getGMST', testGetGMST}, {'getGMST', testGetGMST},
{'recordStores', testRecordStores}, {'recordStores', testRecordStores},
{'recordCreation', testRecordCreation},
{'mwscript', testMWScript}, {'mwscript', testMWScript},
} }

Loading…
Cancel
Save