senterpat Posted November 22, 2023 Share Posted November 22, 2023 (edited) So I'm trying to work on something, but for some reason the data menu close only seems to trigger when I close the menu with the "hold to exit" option. Opening the datamenu with tab allows the debug message to show, but if I close the menu it only fires the debug message once another menu, or the data menu has opened. Upon opening the data menu a second time, I first see the debug message for closing, and then the open debug message is right underneath. The end goal of what I'm doing is to add a keyword when the menu is open to an armor item, and remove it when it closes. Is there a better way to accomplish this? Below is my current script, trying to get the framework in place: Keyword Property KeywordToRemove Auto Const Event OnInit() Self.RegisterForMenuOpenCloseEvent("DataMenu") Self.RegisterForMenuOpenCloseEvent("InventoryMenu") EndEvent Event OnMenuOpenCloseEvent(String asMenuName, Bool abOpening) If asMenuName == "DataMenu" && abOpening == True If Game.GetPlayer().WornHasKeyword(KeywordToRemove) debug.messagebox("haskeyword data open") Self.RegisterForMenuOpenCloseEvent("DataMenu") Self.unRegisterForMenuOpenCloseEvent("InventoryMenu") endif elseIf asMenuName == "DataMenu" && abOpening == False debug.messagebox(" haskeyword data close") Self.RegisterForMenuOpenCloseEvent("DataMenu") Self.RegisterForMenuOpenCloseEvent("InventoryMenu") elseIf asMenuName == "InventoryMenu" && abOpening == True If Game.GetPlayer().WornHasKeyword(KeywordToRemove) debug.messagebox("haskeyword inventory open") Self.RegisterForMenuOpenCloseEvent("DataMenu") Self.unRegisterForMenuOpenCloseEvent("InventoryMenu") endif elseIf asMenuName == "InventoryMenu" && abOpening == False debug.messagebox("haskeyword inventory close") Self.RegisterForMenuOpenCloseEvent("DataMenu") Self.RegisterForMenuOpenCloseEvent("InventoryMenu") endif EndEvent Edited November 22, 2023 by senterpat Link to comment Share on other sites More sharing options...
LarannKiar Posted November 23, 2023 Share Posted November 23, 2023 Here's a quick script that might give you some ideas. I haven't tested it but it should work... maybe with some further development.. Keyword Property myKeyword Auto Const Armor Property myArmor Auto Const ObjectMod Property theOMOD Auto Const {This OMOD should apply the keyword to the InstanceData of armor instances upon being attached to them.} Event OnInit() ; generally, you shouldn't register for two possible overlapping menus without storing their opened states ( i.e., something like IsMenuOpen() with a script variable ) to avoid possible conflicts ; but of course it depends on testing how the two interacts for you usecase ; I'd stay away from editing the content of an inventory while it is open or there's a change the script is still processing when it opens so... DataMenu. ; You can also try use FaderMenu, that loads quite frequently in this game.. Self.RegisterForMenuOpenCloseEvent("DataMenu") EndEvent Event OnMenuOpenCloseEvent(String asMenuName, bool abOpening) If abOpening If asMenuName == "DataMenu" || asMenuName == "InventoryMenu" ; conditions are not necessary if the script is only registered for the events of these two Menus only TryToAttachKeywordToForm(True, myArmor, myKeyword) EndIf Else TryToAttachKeywordToForm(False, myArmor, myKeyword) EndIf EndEvent Bool Function TryToAttachKeywordToForm(bool abAttach, Armor akArmor, Keyword akKeyword) If akArmor != None && akKeyword != None ; some failsafe check to prevent Papyrus log errors if one of appears to be None Actor PlayerRef = Game.GetPlayer() ; optimization If abAttach == True ; akArmor not equipped, can be dropped for a very short time ; the RemoveItem sound is played and it's not an "elegant" or nice way to do this but it's an option If PlayerRef.IsEquipped(akArmor) == 0 ObjectReference ArmorRef = PlayerRef.DropObject(akArmor) If ArmorRef If ArmorRef.HasKeyword(myKeyword) == False ArmorRef.AddKeyword(myKeyword) EndIf PlayerRef.AddItem(ArmorRef) EndIf ; I'd rather try to add keyword this way; only reliable if PlayerRef has only one item from akArmor in their inventory otherwise you can't know which one "receives" it ; Use WornHaskeyword only if you know this keyword is surely not attached to an another equipped item ElseIf PlayerRef.WornHasKeyword(myKeyword) == 0 PlayerRef.AttachModToInventoryItem(akArmor, theOMOD) EndIf Else ; something similar EndIf EndIf EndFunction Link to comment Share on other sites More sharing options...
senterpat Posted November 24, 2023 Author Share Posted November 24, 2023 Thanks so much! I already tried the OMOD method, sadly when I attach the keyword using that the armors model disappears. I tried doing the reverse and having it start with the keyword and having the OMOD remove it, but that didn't work at all. I never even got to the scripting process when I switched to this method, as I could never get the OMOD on without the armor disappearing, but using a different keyword worked fine. It's likely due to it being hardcoded, I can manipulate other keywords the same way in testing, but the Armor keyword I was removing let's you hide your space suit whenever the mask would be hidden, but doing so made the inventory really act up, so I wanted to add it back in the menus. Using Add/RemoveKeyword was working, but the triggers were unreliably firing. I'll keep messing with it but I'm not holding my breath. Link to comment Share on other sites More sharing options...
SKKmods Posted November 25, 2023 Share Posted November 25, 2023 When you say "DataMenu" which actual object are you using: Message.Show(), Terminal.TerminalMenu.Activate(), or something else ? Link to comment Share on other sites More sharing options...
LarannKiar Posted November 28, 2023 Share Posted November 28, 2023 (edited) On 11/23/2023 at 5:10 PM, senterpat said: Thanks so much! I already tried the OMOD method, sadly when I attach the keyword using that the armors model disappears. Make sure you only have one item of the same type in the inventory. You can use DropObject() or DropFirstObject() for this. AttachModToInventoryItem(), in some cases, appears to break item instance data if the inventory contains multiple items of the same base object. The VM should log an error, something like "error: singular items are supported" but the function might not exit and break the item. Practically, it can remove all ObjectMods. If you drop the item from the inventory afterward, the item's 3D is reinitialized but the lost ObjectMods won't "reappear". That part of the instance data seems to be unrecoverable. On 11/23/2023 at 5:10 PM, senterpat said: It's likely due to it being hardcoded, I can manipulate other keywords the same way in testing, but the Armor keyword I was removing let's you hide your space suit whenever the mask would be hidden, but doing so made the inventory really act up, so I wanted to add it back in the menus. Using Add/RemoveKeyword was working, but the triggers were unreliably firing. Armors and Weapon have InstanceData that makes the inventory system treat them quite differently. The system relies on events which aren't exposed to Papyrus and calling functions on the items is generally difficult because one needs to find the "right time" to edit their data to avoid issues like that.. I recently finished testing Transfer Inventories (TIN), a new mod I've been working on for a while that will let players export and import any inventories between save games (readable "blueprint files"). I had to decompile the ObjectMod data from reference data and well.. there are quite a few anomalies in the system that's for sure... Manipulating references by only editing their inventory item data alone wasn't perfect in Fallout 4 either but "badly" called functions in FO4 could only result in minor 3D glitches and not in a full ObjectMod data purge.. Starfield seems to be a bit worse in this regard.. it really requires making the engine create 3D for the item to handle it safely. Finally, if you choose to drop the item, make sure to wait until the item's scriptobject (the ItemRef that DropObject() returns) and its 3D are initialized. (Either a simple "If ItemRef != None, then" should do it with some error handling of course). DropObject() should be reliable until you need to process thousands or even millions of items which requires handling stacked items. Edited November 28, 2023 by LarannKiar Link to comment Share on other sites More sharing options...
Recommended Posts