2026-04-13T02:57:22 I am lookign for an example of a textbox that uses wordwrap and multiline. does anyonew have a mod with those parameters I can look at. 2026-04-13T03:04:18 I 'm 90% sure those properties just don't work together 2026-04-13T04:14:31 so it was working but something was causing it to insert the newline at a weird place. I ended writing a function that does the wrap based on text size. Not really a perfect solution as letters are diff size on the font i want but it was good enough for what I am doing. I dont recommend anyone do it this way but here is the code if your curious local function wrapWords(text, maxLen) -- split on space or any words 2026-04-13T04:14:31 longer than MaxLen. make an exception to not split if the remaining part is 2 characters or less to avoid orphaned letters. local words = {} for w in text:gmatch("%S+") do while #w > maxLen do local part = w:sub(1, maxLen - 1) w = w:sub(maxLen) if #w <= 2 then part = part .. w w = "" else part = part .. "-" end 2026-04-13T04:14:32 table.insert(words, part) end table.insert(words, w) end -- POP array and build lines local result = {} local line = "" while #words > 0 do local word = table.remove(words, 1) if line == "" then line = word elseif #line + 1 + #word <= maxLen then line = line .. " " .. word else table.insert(result, line) line = word 2026-04-13T04:14:32 end end -- push last line if line ~= "" then table.insert(result, line) end return table.concat(result, "\n") end 2026-04-13T07:53:53 Is weather dehardcoding at the point where you can change what weather's play in certain regions? I recall seeing that in an MR but can't remember which or if it's been merged. 2026-04-13T11:59:25 I believe you're looking for this, which is not currently merged: https://gitlab.com/OpenMW/openmw/-/merge_requests/5242 2026-04-13T12:18:08 anyone know how I could intercept opening the repair menu when the player equips a repair hammer? 2026-04-13T12:48:05 https://openmw.readthedocs.io/en/latest/reference/lua-scripting/interface_ui.html##(UI).registerWindow 2026-04-13T18:02:49 Hi @nox7 . Is angles ui officialy released yet? Anyway, I saw a github release and gave it a try 😃 When I tried to create a first example, I found that there is an unnecessary require/or missing file: module not found: scripts.Nox.Utils.TableUtils I commented out this require and it seems to work so far. 2026-04-13T18:04:39 Ah, good find. That was a debug library I must have accidentally included. It has a release, yes, and you're welcome to try using it. I decided not to announce the release or put it on Nexus I've swapped my focus to tackling these things before returning to it: https://discord.com/channels/260439894298460160/1493251518894309586/1493251521519943690 My belief is that there are things the Lua API needs to natively support before I 2026-04-13T18:04:39 can have a more streamlined and efficient UI framework built on top of it. 2026-04-13T18:05:02 Ah, hmm... I really wish it hadn't done that 2026-04-13T18:06:49 Either way, it'll work exactly as described in the https://anglesui.com docs 2026-04-13T18:06:52 <.arrean> https://tenor.com/view/textwall-division-2-spoxehub-gif-12483842339964756186 2026-04-13T18:07:00 <.arrean> Appreciated text wall though 2026-04-13T18:08:24 Cool, thanks. I think I have a good usecase to try it out, since I need to implement an inventory select menu from mwse. Resizing it is not a primary concern. 2026-04-13T18:09:23 Awesome, I hope it goes well and is simple with the library. So long as OpenMW doesn't plan on making the Lua API backwards-incomputable then any UIs made with it will work forever 2026-04-13T18:26:42 Can anybody give me some hints how to create a proper rotation object from a serialized table? I have this: local util = require("openmw.util") local RavenloftData = { position = util.vector3(4888.00, 4225.00, 13370.60), rotation = util.vector3(-2.0, 0.0, 0.0), cell = { name = "Ravenloft: Quarters", isExterior = false, gridX = nil, gridY = nil } } return { RavenloftData 2026-04-13T18:26:42 = RavenloftData } But loading the rotation data fails. Im pretty sure I just need the correct function. Because when I use a saved location via self.rotation in the player script everything is loaded correctly. Im really new to lua scripting and how to handle the different "data types" confuses me. Any hints how to do this properly would be much appreciated. 2026-04-13T18:36:08 You need a transformation. I'm not 100% on the exact syntax, but the object is lua local transform = util.transform Which you then perform operations on like lua transform.rotateX(angle) transform.rotateY(angle) transform.rotateZ(angle) it doesn't have a way to apply to all 3 angles (that I can see in the docs). 2026-04-13T18:45:11 > Im really new to lua scripting and how to handle the different "data types" confuses me. > Any hints how to do this properly would be much appreciated. Yeah, I get this. Check out the properties you're assigning to, in the docs, and what they expect + return types. They'll be listed next to the functions or to the right of the properties in the docs. 2026-04-13T18:49:04 I'm sorry I can't follow. Does that mean there is no way to serialize the current rotation of the player, save it to a string (via output in the console) and then later load it for self:teleport? For reference here is the actual function that does the teleport (Which works with data I saved directly in the engine): ocal function teleportPlayerEvent(data) print("Teleport event triggered in global script") local 2026-04-13T18:49:04 location = data local player = world.players[1] if not player then print("No player found to teleport!") return end local cell if location.cell.isExterior then cell = world.getExteriorCell(location.cell.gridX, location.cell.gridY) else cell = world.getCellByName(location.cell.name) end if not cell then print("Failed to resolve saved cell for teleport") return 2026-04-13T18:49:05 end player:teleport(cell, location.position, location.rotation) print("Player teleported to saved location!") helper.printLocation(location) end I will try the documentation again, but it's really confusing for me to read. I'm used to Python and VBA maybe that why I struggle with the structure. In any case thanks for pointing me in the right direction already. 2026-04-13T18:53:44 > Does that mean there is no way to serialize the current rotation of the player, save it to a string (via output in the console) and then later load it for self:teleport? Not at all. Data serialization is a pretty straight forward process that you have control over. If we follow what you'e doing in your previous post: lua local RavenloftData = { position = util.vector3(4888.00, 4225.00, 13370.60), rotation = 2026-04-13T18:53:45 util.vector3(-2.0, 0.0, 0.0), cell = { name = "Ravenloft: Quarters", isExterior = false, gridX = nil, gridY = nil } } We can just use that rotation's x,y,z properties in a transformation when re-applying it. lua local data = ? -- Load your RavenloftData local rotationTransform = util.transform.rotateX(data.rotation.x) * util.transform.rotateY(data.rotation.y) * util.transform.rotateX(data.rotation.z) 2026-04-13T18:55:15 For the rotation specifically (on how to read the docs), I just found it on GameObject and checked what it expected on the left-side (which you can click to learn about) 2026-04-13T18:55:16 https://cdn.discordapp.com/attachments/854806553310920714/1493323702303981708/image.png?ex=69de8d93&is=69dd3c13&hm=208999cf806c4b61b5414db3abc28512b75806b31af6dcb489ee1c248c86f7ab& 2026-04-13T18:55:51 <.arrean> Do you need to save rotation data as x/y/z angles? self.position on a player returns "transform" object, in globl space. I think you can do transform.apply(V) where V is a vector of the new position 2026-04-13T19:07:14 I just want to save the current players rotation (as in the direction I'm looking at) and call that from a hardcoded table. I'm not sure what the vector of the new position is. Is it just the coordinates from the position variable in the table? How would it know the rotation then? 2026-04-13T19:12:11 You just need to build a transformation, that's all. 2026-04-13T19:22:24 Can you tell me how i would call it? I tried multiple things: rotation = util.Transform:apply(-2.0, 0.0, 0.0) Does not work. I don't understand how to correctly address the method? Also what the difference between the "Type TRANSFORM" and "Type Transform" notation in the documentation? 2026-04-13T19:23:04 :apply() doesn't actually return a Transform. AFAIK you need to use the methods I described above (multiplying the angles against each other for composition). 2026-04-13T19:23:51 And as fair as the naming goes, I can only assume it's just docs inconsistency and there is no difference; but if you link me to them I can explain it better (if they are different) 2026-04-13T19:28:31 To make it simple, your code would look like this lua player:teleport( cell, location.position, util.transform.rotateX(location.rotation.x) * util.transform.rotateY(location.rotation.y) * util.transform.rotateZ(location.rotation.z) ) 2026-04-13T19:29:30 Sorry I missed you post up there. I will try to understand that first. Regarding the documentation: Here "Type TRANSFORM" starts and the next segment is "Type Transform" I'm just confused. Maybe I'm missing some common knowledge on documentation standards? To compare it with Python: I would have expected Transform to be a class in the module openmw.utils. Are there now 2 "classes", one capitalized and the other not? Or is 2026-04-13T19:29:31 this just a segmentation technique in the documentation? And what would that imply? 2026-04-13T19:31:10 Ah, yeah 😅 That's an unfortunate situation of the API/docs. In this case, the TRANSFORM is the functions/keys/values of util.transform and Transform is a single instance of a transformation (its members and methods) 2026-04-13T19:43:47 Thank you very much. It works now (Had to reverse XYZ with ZYX thought: local util = require("openmw.util") local RavenloftData = { position = util.vector3(4888.00, 4225.00, 13370.60), -- rotation = util.vector3(-2.0, 0.0, 0.0), -- rotation = TransformQ{ rotation(angle=0.916335, axis=(-0.368326, -0.166157, 0.914728)) } ,, rotation = util.transform.rotateZ(-1.54) * util.transform.rotateY( 0.17) * 2026-04-13T19:43:47 util.transform.rotateX( 0.00), cell = { name = "Ravenloft: Quarters", isExterior = false, gridX = nil, gridY = nil } } return { RavenloftData = RavenloftData } This correctly loads the serialzed data. Never hoped this will work today. Now I only have to bind it to an inventory object OnUse 😄 Currently I'm using keypresses. But how hard could that be right 😉 2026-04-13T19:44:19 Glad to hear it. Don't hesistate to ask here if something else stumps you up, of course. 2026-04-13T19:46:12 Will do 🙂 2026-04-13T20:10:35 There are three things involved: Transform - the type of things that can apply tovectors, util.transform - the table of helper methods to construct Transform, and TRANSFORM - the type of util.transform 2026-04-13T20:10:52 Similar logic applies to most of the confusing duplicate names in the API 2026-04-13T20:11:10 It's basically a side effect of how the documentation tool works 2026-04-13T20:11:48 Ok I'm confused by the documentation again. Is there a event that I can grab of the object that the players tries to equip? So similar to OnPCEquip? I found ItemUsage.addHandlerForObject(obj, handler) but I'm not really sure how use it. Is "handler" just any function and the function(armor, actor) (in the example for ItemUsage.addHandlerForType(type, handler)) is just returning both the armor and actor object? 2026-04-13T20:12:55 If I'm not mistaken, your best bet is still checking the equipment table in onUpdate 2026-04-13T20:13:50 <.arrean> there's an event, but it misses a bunch of stuff. E.g. it doesn't fire when you equip via hotkeys or next/previous weapon keys 2026-04-13T20:14:03 <.arrean> if your item is not something that can be hotkeyed and not a weapon 2026-04-13T20:14:06 <.arrean> you should be fine 2026-04-13T20:16:30 <.arrean> for ItemUsage.addHandlerForObject(obj, handler) it's lua local I = require("openmw.interfaces") --and then just I.ItemUsage.addHandlerForObject(obj, function() if object.recordId == "something" then --do stuff end end) 2026-04-13T20:16:56 <.arrean> so whenever an object is used, this handler will be entered, and if the object's ID matches what you want - you can do stuff 2026-04-13T20:19:35 <.arrean> the armor/actor part is present in "latest" docs though, and not in "stable", so not sure if ItemUsage was updated, or just the docs :P 2026-04-13T20:19:37 <.arrean> https://openmw.readthedocs.io/en/latest/reference/lua-scripting/interface_item_usage.html 2026-04-13T20:29:07 Just for context what I want to to in the end: - When Player tries to equip do two things: - Save current location to memory (works currently with on keypress already) - Teleport the player to a hardcoded location (works currently with on keypress already) - When the player uses the amulet in specific cells (e.g. Ravenloft) return him to the previously saved position It does not 2026-04-13T20:29:08 necessarily have to be an amulet, but reacting to hotkeys would be nice for easy usage if possible. 2026-04-13T20:29:53 <.arrean> yeah, then it's onFrame/onUpdate 2026-04-13T20:30:05 <.arrean> check the slot your items equips into 2026-04-13T20:31:09 <.arrean> types.Actor.getEquipment(self,types.Actor.EQUIPMENT_SLOT.Amulet)) 2026-04-13T20:31:43 <.arrean> can throttle it, so checks don't happen on pause, and can check e.g. once a second, instead of every frame 2026-04-13T20:31:53 <.arrean> but that's the most reliable way at the time 2026-04-13T20:33:03 <.arrean> what you can do is save value of "getEquipment" - if it's not your amulet - do nothing, if it wasn't your amulet and now is - do your thing. 2026-04-13T20:35:24 <.arrean> so that it doesn't happen continously. I have something similar for "equip changes" Here's a cut down example, let me know if it helps: lua function ParryController.updateEquippedIfChanged(self) local changesDetected = false local rightEquipped = getEquipment(self.defendant, types.Actor.EQUIPMENT_SLOT.CarriedRight) if rightEquipped == nil or self:isItemBroken(rightEquipped) then ---@diagnostic 2026-04-13T20:35:25 disable-next-line: missing-fields rightEquipped = { recordId = "None", id = "none" } end if (self.currentEquippedR.id ~= rightEquipped.id) or not self.recordEquippedR then changesDetected = true self.currentEquippedR = rightEquipped self.recordEquippedR = getWeaponRecord(rightEquipped.recordId) or Constants.HandToHandRecordStub end if changesDetected == true then self:tryLowerGuard() 2026-04-13T20:35:25 end end this gets called in the player's onFrame 2026-04-13T21:40:27 Hi, I can't really get it to work. But it's really late and I will try again tomorrow. Thanks for the hints to all of you guys. Have a good night 🙂 2026-04-13T21:40:57 <.arrean> Get some rest 2026-04-13T21:51:02 <.arrean> however, if I understood correctly what you want to do: here's a version without my bullshit that should be easier to understand lua local I = require("openmw.interfaces") local self = require("openmw.self") local core = require("openmw.core") local types = require("openmw.types") local currentEquippedR = { recordId = "None", id = "none" } local targetId = "ID OF YOUR AMULET" local lastCheckTime = nil local function 2026-04-13T21:51:02 lookForAmulet(self) local amulet = types.Actor.getEquipment(self, types.Actor.EQUIPMENT_SLOT.Amulet) if amulet == nil then amulet = { recordId = "None", id = "none" } end if (currentEquippedR.id ~= amulet.id) then currentEquippedR = amulet if amulet.recordId == targetId then doStuff() end end end local function onFrame(dT) if core.isWorldPaused() then return end 2026-04-13T21:51:03 currentTime = core.getRealTime() if lastCheckTime == nil or (lastCheckTime ~= nil and( currentTime - lastCheckTime >= 1)) then lastCheckTime = currentTime lookForAmulet() end end return{ engineHandlers = { onFrame = onFrame, }, }