niston Posted February 25, 2021 Share Posted February 25, 2021 Is it just me, or is RemoveComponents() the probably most useless function in all of papyrus?It has no return value and offers no output container parameter. How'd you even know if it found suitable item(s) to scrap? Link to comment Share on other sites More sharing options...
NoCashNoExp Posted February 25, 2021 Share Posted February 25, 2021 (edited) I am going to offer my 2 cents here. This is the best I can come up with. Maybe you can improve this script. Replace player with your container's ObjectReference. Scriptname TestScript extends Quest FormList Property CA_JunkItems Auto Const Mandatory ; A Formlist that contains all junk items in FO4. I found this one already made in CK but I am not sure if it has all the junk items. Component Property c_Steel Auto Const Mandatory Struct ConsumedItem Form baseForm int count EndStruct ConsumedItem[] items Event OnInit() AddInventoryEventFilter(CA_JunkItems) RegisterForRemoteEvent(Game.GetPlayer(), "OnItemRemoved") EndEvent Event ObjectReference.OnItemRemoved(ObjectReference akSender, Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akDestContainer) Debug.Trace("[TestScript] OnItemRemoved() Removed " + aiItemCount + " of item: " + akBaseItem) ConsumedItem cItem = new ConsumedItem cItem.baseForm= akBaseItem cItem.count = aiItemCount items.Add(cItem) EndEvent Function removeComps() items = None items = new ConsumedItem[0] Game.GetPlayer().RemoveComponents(c_steel, 20) Debug.Trace("[TestScript] removeComps() finished") EndFunction ; When to call this?? Function onRemoveComponentsDone() int i = 0 While i < items.length Debug.Trace("[TestScript] Item: " + items[i].baseForm + ", Count: " + items[i].count) i = i + 1 EndWhile EndFunction The problem is I don't know how to detect when RemoveComponents() has done its work. removeComps() finishes before all the events are even fired. Maybe you could find a workaround for this one using timers or something. I honestly don't know Edited February 25, 2021 by NoCashNoExp Link to comment Share on other sites More sharing options...
niston Posted February 25, 2021 Author Share Posted February 25, 2021 Same problem there though, how'd you know that RemoveComponents() in fact removed 20 steel?I think it'll have to be combined with GetComponentCount(). Do you plan on using ConsumedItem[] items as sort of a queue?If so, you could add a timer processing the queue in blocks, for as long as there's something in the queue. Link to comment Share on other sites More sharing options...
Zorkaz Posted February 25, 2021 Share Posted February 25, 2021 Really depends on what you want to do. E.g. for my working generators I used a mix between get and remove. Scriptname FVFireScrWoodandOil extends ObjectReference Component Property c_Wood Auto Component Property c_oil Auto ObjectReference Property FVWarmTrigger Auto Int Property Into Auto Int Property Into2 Auto Event OnLoad() While Self.isenabled() Utility.wait(10) Into = Self.GetComponentCount (c_wood) Into2 = Self.GetComponentCount (c_oil) If (Into+Into2 > 2) If Self.GetComponentCount(c_wood) > 2 Self.RemoveComponents(c_Wood, 3) FVWarmTrigger.enable() Utility.wait(180) Elseif Self.GetComponentCount(c_oil) > 2 Self.RemoveComponents(c_oil, 3) FVWarmTrigger.enable() Utility.wait(180) Elseif (Self.GetComponentCount(c_wood) > 1) && (Self.GetComponentCount(c_oil) > 1) Self.RemoveComponents(c_Wood, 2) Self.RemoveComponents(c_oil, 1) FVWarmTrigger.enable() Utility.wait(180) Elseif (Self.GetComponentCount(c_wood) > 0) && (Self.GetComponentCount(c_oil) > 1) Self.RemoveComponents(c_Wood, 1) Self.RemoveComponents(c_oil, 2) FVWarmTrigger.enable() Utility.wait(180) Elseif (Self.GetComponentCount(c_wood) > 1) && (Self.GetComponentCount(c_oil) > 0) Self.RemoveComponents(c_Wood, 2) Self.RemoveComponents(c_oil, 1) FVWarmTrigger.enable() Utility.wait(180) Else FVWarmTrigger.disable() Endif Endif Endwhile EndEvent And yes I should have used a timer instead of utility.wait... Link to comment Share on other sites More sharing options...
SKKmods Posted February 25, 2021 Share Posted February 25, 2021 Yes if you are manually scripting crafting conditions then you need to validate the source has GetComponentCount() before RemoveComponents() or a fail path. Edit: which is where you can log the latency across those transative workshop provisioner supply networks getting component counts from piles of crap in 30 workshops. Yay ! lets add *more* workshops to that then cry when it all falls over /salty. Link to comment Share on other sites More sharing options...
NoCashNoExp Posted February 25, 2021 Share Posted February 25, 2021 (edited) Same problem there though, how'd you know that RemoveComponents() in fact removed 20 steel?I think it'll have to be combined with GetComponentCount(). Do you plan on using ConsumedItem[] items as sort of a queue?If so, you could add a timer processing the queue in blocks, for as long as there's something in the queue. Well, the items array currently has base form junk items that the game decided to use up. This means we can copy those in another separate container and count them to make sure. This is untested and I am not sure if it will return correct numbers. It's more conceptual really. The problem is again how would you know that the game is done with RemoveComponents(). Scriptname TestScript extends Quest FormList Property CA_JunkItems Auto Const Mandatory ; A Formlist that contains all junk items in FO4. I found this one already made in CK but I am not sure if it has all the junk items. Component Property c_Steel Auto Const Mandatory Container Property TempContainer Auto Const Mandatory ; Temp Container Property Struct ConsumedItem Form baseForm int count EndStruct ConsumedItem[] items Event OnInit() AddInventoryEventFilter(CA_JunkItems) RegisterForRemoteEvent(Game.GetPlayer(), "OnItemRemoved") EndEvent Event ObjectReference.OnItemRemoved(ObjectReference akSender, Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akDestContainer) Debug.Trace("[TestScript] OnItemRemoved() Removed " + aiItemCount + " of item: " + akBaseItem) ConsumedItem cItem = new ConsumedItem cItem.baseForm= akBaseItem cItem.count = aiItemCount items.Add(cItem) EndEvent Function removeComps() items = None items = new ConsumedItem[0] Game.GetPlayer().RemoveComponents(c_steel, 20) Debug.Trace("[TestScript] removeComps() finished") EndFunction ; When to call this?? Function onRemoveComponentsDone() ObjectReference cont = Game.GetPlayer().PlaceAtMe(TempContainer) int i = 0 While i < items.length cont.AddItem(items[i].baseForm, items[i].count, true) i = i + 1 EndWhile Debug.Trace("The game consumed (" + cont.GetComponentCount(c_steel) +") steel components from player") cont.DisableNoWait() cont.Delete() EndFunction Edit: I've just realised, this is such a roundabout way for this problem. Why not just call GetComponentCount() before even calling RemoveComponents() to make sure whether the container has 20 steel or not. Edited February 25, 2021 by NoCashNoExp Link to comment Share on other sites More sharing options...
niston Posted February 25, 2021 Author Share Posted February 25, 2021 @SKK: I'm at 108 workshops. And I plan to add many more, now that the array limit has been squashed (I set mine to 512 elements). *muahahah* Link to comment Share on other sites More sharing options...
SKKmods Posted February 25, 2021 Share Posted February 25, 2021 Le nettoyeur doesn't do tears :sweat: Link to comment Share on other sites More sharing options...
niston Posted February 25, 2021 Author Share Posted February 25, 2021 Edit: I've just realised, this is such a roundabout way for this problem. Why not just call GetComponentCount() before even calling RemoveComponents() to make sure whether the container has 20 steel or not. That's what I'm thinking, yes.Since RemoveComponents() doesn't tell you anything, you'll have to check for the required components to be present beforehand. Link to comment Share on other sites More sharing options...
niston Posted February 26, 2021 Author Share Posted February 26, 2021 I've got this. Didn't get around to test it yet, but I expect it just works. Scriptname F4MS:F4MS_ComponentScrapAgent extends ObjectReference ; F4MS component scrapping agent ; custom scripting by niston Int Function ScrapItems(Int componentCountRequested, Component componentToScrapFor, ObjectReference sourceContainer, ObjectReference targetContainer) ; get available component count for source container Int numberOfComponentsScrapped = sourceContainer.GetComponentCount(componentToScrapFor) ; container has requested component in it? If (numberOfComponentsScrapped > 0) ; component count supplied? If (componentCountRequested > 0) ; limit scrapped count to requested amount If (numberOfComponentsScrapped > componentCountRequested) numberOfComponentsScrapped = componentCountRequested EndIf EndIf ; perform scrapping on source container sourceContainer.RemoveComponents(componentToScrapFor, numberOfComponentsScrapped, abSilent = true) ; add scrapped components to target container targetContainer.AddItem(componentToScrapFor, numberOfComponentsScrapped, abSilent = true) Else ; nothing to scrap for in this container numberOfComponentsScrapped = 0 EndIf ; return amount of scrapped components moved to target container Return numberOfComponentsScrapped EndFunction If ScrapItems() is called with a componentCountRequested of < 1, it'll scrap for the entire lot of the requested component that it can find in sourceContainer. Once can obviously not call it with a Formlist, for no one ever could know which components from the list RemoveComponents() actually scrapped for. But if you want FormList processing, you'll simply call ScrapItems() for each entry in your Formlist. @NoCashNoExp: Regarding the problem of knowing when RemoveComponents() is done, I think you can't. I don't personally face that problem in my application, but perhaps you could call GetComponentCount() again and it would block until RemoveComponents is done? Pure speculation on my part, but it might just work as well. BTW: It appears that ObjectReference already has a function Scrap() on it. But I can't find any documentation about it. Is it added by F4SE, perhaps? Link to comment Share on other sites More sharing options...
Recommended Posts