candlepin Posted February 23, 2017 Share Posted February 23, 2017 Hello fellow Skyrim modders! As the title implies, I have some noobish questions about a mod I'm trying to make. I've dabbled a bit in Skyrim modding, but this is my first foray into papyrus scripting. What I'd like my mod to do: replace vanilla items with new custom items (different item type). How I initially did it: do a search-and-replace. Simple.Problem: This is really messy as it alters a TON of cells. How I think it should be done: via a hidden perk script. I found a mod, GourdIngredients by egocarib, that basically does what I’d like to do but for one item only. Therefore, I’ve been trying to reverse-engineer this mod to see how egocarib got the mod to work. What I’ve deduced (correct, hopefully): egocarib uses a hidden perk and associated scripted magic effect to swap out the items. Using BSAopt below are the scripts I found associated with the mod (at the end of the post). Questions I have: -Is this (hidden perk with associated magic effect) the best way to accomplish my goal?-Could someone briefly explain these two scripts for me?-Is there a better way to script this?-Ideally, I’d like to make my mod reversible (be able to switch the vanilla items to new items and back again). I’ve thought of two ways to accomplish this: either via spells (a bit immersion-breaking and perhaps tedious) or via perks which can be toggled (via MCM? Not even sure this is possible). Thoughts? Script to swap out items: ;BEGIN FRAGMENT CODE - Do not edit anything between this and the end comment;NEXT FRAGMENT INDEX 1Scriptname PRKF_Gourd_SwapPerk_01001827 Extends Perk Hidden ;BEGIN FRAGMENT Fragment_0Function Fragment_0(ObjectReference akTargetRef, Actor akActor);BEGIN CODEakTargetRef.disable()akTargetRef.delete()akActor.addItem(Gourd);END CODEEndFunction;END FRAGMENT ;END FRAGMENT CODE - Do not edit anything between this and the begin comment Ingredient Property Gourd Auto Script for compatibility with other mods:Scriptname GourdIngredientSwap extends ReferenceAlias ;This script isn't even really necessary, since the activate perk will already swap any gourds for;the ingredient version. However, this is included for compatibility reasons, if the user has a mod that;adds gourds to any merchant or NPC inventories, this will detect and replace those as well. Potion property FoodGourd autoIngredient property IngredientGourd autoObjectReference property PlayerRef auto Event OnInit()AddInventoryEventFilter(FoodGourd)EndEvent Event OnItemAdded(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akSourceContainer)PlayerRef.RemoveItem(akBaseItem, aiItemCount, true)PlayerRef.AddItem(IngredientGourd, aiItemCount, true)EndEvent Link to comment Share on other sites More sharing options...
FrankFamily Posted February 23, 2017 Share Posted February 23, 2017 The perk script replaces normal activation of gourds (conditioned on the perk) with deleting the old and adding the new, instead of just taking the old. The script on the player alias fires when an old gourd (filtered oninit) enters your inventory, removes it and adds the ingredient version, for the cases in which you aquire one by any means not involving taking them from thw world. Having more than one item doesn't really complicate it, just make a couple matched formlists for your old and new items. Can it be made better? who knows, i would have done it this way: Scriptname ItemReplacer extends ReferenceAlias {Script on a player alias, OldItems and NewItems must be matched by index, i.e. The 5th item on one is replaced by 5th in the other and so on.} FormList property OldItems auto FormList property NewItems auto ObjectReference property PlayerRef auto Event OnInit() If PlayerRef.GetItemCount(OldItems) Int i = OldItems.GetSize() while i i -= 1 Form OldForm = OldItems.GetAt(i) As Form int Count = PlayerRef.GetItemCount(OldForm) If Count Form NewForm = NewItems.GetAt(i) As Form PlayerRef.RemoveItem(OldForm, Count, True) PlayerRef.AddItem(NewForm, Count, True) Endif EndWhile EndIf AddInventoryEventFilter(OldItems) EndEvent Event OnItemAdded(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akSourceContainer) Int i = OldItems.Find(akBaseItem) If i > -1 Form NewForm = NewItems.GetAt(i) As Form PlayerRef.RemoveItem(akBaseItem, aiItemCount, true) PlayerRef.AddItem(NewForm, aiItemCount, true) Endif EndEventMaking it reversible should be possible, can't help with the MCM, no experience, but the script could be easily modified to swap the formlists and do the item swaping the other way around. Link to comment Share on other sites More sharing options...
IsharaMeradin Posted February 23, 2017 Share Posted February 23, 2017 @FrankFamily, I would have gone with the formlist approach too. As far as reversible it is possible. If you make the MCM option a toggle and use it to set a global variable you could do something like the following: Scriptname ItemReplacer extends ReferenceAlias {Script on a player alias, OldItems and NewItems must be matched by index, i.e. The 5th item on one is replaced by 5th in the other and so on.} FormList property OldItems auto FormList property NewItems auto ObjectReference property PlayerRef auto GlobalVariable Property SwapGV auto ;0=old->new 1=new->old Bool Swap = false Event OnInit() If SwapGV.GetValue() == 0 && Swap == false Swap = true RemoveInventoryEventFilter(NewItems) AddInventoryEventFilter(OldItems) SwapItemMaint(OldItems,NewItems) ElseIf SwapGV.GetValue() == 1 && Swap == true Swap = false RemoveInventoryEventFilter(OldItems) AddInventoryEventFilter(NewItems) SwapItemMaint(NewItems,OldItems) EndIf EndEvent Event OnItemAdded(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akSourceContainer) If SwapGV.GetValue() == 0 If Swap == false Swap = true RemoveInventoryEventFilter(NewItems) AddInventoryEventFilter(OldItems) SwapItemMaint(OldItems,NewItems) EndIf SwapItem(akBaseItem, aiItemCount, OldItems, NewItems) ElseIf SwapGV.GetValue() == 1 If Swap == true Swap = false RemoveInventoryEventFilter(OldItems) AddInventoryEventFilter(NewItems) SwapItemMaint(NewItems,OldItems) EndIf SwapItem(akBaseItem, aiItemCount, NewItems, OldItems) EndIf EndEvent Function SwapItem(Form TheItem, Int Num, FormList OldList, FormList NewList) Int i = OldList.Find(TheItem) If i > -1 Form NewForm = NewList.GetAt(i) As Form PlayerRef.RemoveItem(TheItem, Num, true) PlayerRef.AddItem(NewForm, Num, true) Endif EndFunction Function SwapItemMaint(FormList OldList, FormList NewList) If PlayerRef.GetItemCount(OldList) Int i = OldList.GetSize() while i i -= 1 Form OldForm = OldList.GetAt(i) As Form int Count = PlayerRef.GetItemCount(OldForm) If Count Form NewForm = NewList.GetAt(i) As Form PlayerRef.RemoveItem(OldForm, Count, True) PlayerRef.AddItem(NewForm, Count, True) Endif EndWhile EndIf EndFunction This is the exact same approach as FrankFamily. The main code work was moved into functions so that they could be reused rather than rewritten with slight differences. The global variable tells the script which formlist to use in the filter and removes the previous one. It also dictates which order the lists are used when swapping items as they are obtained.The OnInit event includes ability to set up filters depending upon the value of the global variable, this gives flexibility in starting the quest containing the alias both before or after the player makes their choice in the MCM menu.The filter swap in the OnItemAdded event does have a drawback in that the reverse won't take effect right away. Instead it will wait until the next instance of an item on the current list is added and then the lists will be swapped and current inventory reversed. However, this shouldn't be too much of an issue.The Swap bool is included in order to prevent some unnecessary processing. There is no need to set filters and convert all items every time a single item on the list is added. All this said, the formlist approach only works if you want to swap an entire group of items. If you wish to make each individual item swap-able on its own without changing any other item, then that will have to be done differently. It is not impossible, just handled in a different manner. Link to comment Share on other sites More sharing options...
Masterofnet Posted February 23, 2017 Share Posted February 23, 2017 candlepin 1. Please post scripts like this it makes it much easier to read. 2. Did you get the Mod Authors permission to use their work? 3. This is a very big undertaking, it may be better to do it one function at a time. You are going to need to get a much better grasp of Papyrus. These pages are a good place to start. https://www.creationkit.com/index.php?title=Category:Script_Objectshttps://www.creationkit.com/index.php?title=While When you have a better grasp of what you are going to do and can provide some more detailed information I will return and help. Hopefully others will also. For starters if a script is on a player alias Scriptname GourdIngredientSwap extends ReferenceAlias Potion property FoodGourd auto Ingredient property IngredientGourd auto ;ObjectReference property PlayerRef auto - Do not define properties outside on an event unless you have to. Event OnInit() ; This will not work properly unless the Quest is start game enabled. AddInventoryEventFilter(FoodGourd) EndEvent Event OnItemAdded(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akSourceContainer) OjectReference PlayerRef = GetReference() ; This refalias script is on the player just use GetReference() PlayerRef.RemoveItem(akBaseItem, aiItemCount, true) PlayerRef.AddItem(IngredientGourd, aiItemCount, true) EndEvent Link to comment Share on other sites More sharing options...
FrankFamily Posted February 23, 2017 Share Posted February 23, 2017 Can you define a property within an event? First time i hear that. Afaik, the playerref property is the most eficient method to reference the player and in any case you'd better call that getreference on the oninit event once, not every single time an item is added. Those two links are unlikely to help much someone who doesn't know papyrus as always, you'd better link one of the many papyrus beginner tutorials or stuff like that. Still, imo the best way to learn is to start making stuff. Link to comment Share on other sites More sharing options...
lofgren Posted February 23, 2017 Share Posted February 23, 2017 For compatibility reasons, I would say ditch the perk and just use the script. It might be helpful to give at least an example of the type of switch you are trying to make, too. Link to comment Share on other sites More sharing options...
Masterofnet Posted February 23, 2017 Share Posted February 23, 2017 (edited) Freaky Frank ( As you call yourself ) What? Are you OK? ( You are not going to tell me what I am going to post here. ) - Frank removed hat from his post. Get a grip and stop with your gibberish. Franks Gibberishhttps://forums.nexusmods.com/index.php?/topic/5370805-need-some-help-with-a-custom-spell/ Realityhttps://forums.nexusmods.com/index.php?/topic/5306120-will-this-script-work-as-intended/ Edited February 23, 2017 by Masterofnet Link to comment Share on other sites More sharing options...
FrankFamily Posted February 23, 2017 Share Posted February 23, 2017 Im just giving you some advice! Here's more: engage your brain before your tongue. Oh jesus man, so resentful, give up already. You have already made 3 mistakes in a single comment in this thread. Nobody wants this childish tantrum, all i see in that post is you spending time thinking like crazy over something that took 5 minutes and talking with yourself, please stop derailing people's threads. Link to comment Share on other sites More sharing options...
Masterofnet Posted February 23, 2017 Share Posted February 23, 2017 (edited) Im just giving you some advice! Here's more: engage your brain before your tongue. Oh jesus man, so resentful, give up already. You have already made 3 mistakes in a single comment in this thread. Nobody wants this childish tantrum, all i see in that post is you spending time rethinking something that took 5 minutes like crazy and talking with yourself. Frank, That is completely incoherent. Just like this.Franks Gibberishhttps://forums.nexus...a-custom-spell/ Realityhttps://forums.nexus...rk-as-intended/ Can you define a property within an event? First time i hear that. Come down to earth Frank. I have had it with your wacko nonsense. Do not destroy another thread with it. Edited February 23, 2017 by Masterofnet Link to comment Share on other sites More sharing options...
IsharaMeradin Posted February 23, 2017 Share Posted February 23, 2017 To answer FrankFamily's question: Can you define a property within an event? First time i hear that. Afaik, the playerref property is the most eficient method to reference the player and in any case you'd better call that getreference on the oninit event once, not every single time an item is added. Those two links are unlikely to help much someone who doesn't know papyrus as always, you'd better link one of the many papyrus beginner tutorials or stuff like that. Still, imo the best way to learn is to start making stuff. Storing the PLAYER as a property is much more efficient than any other method (ask cdcooley, I've learned to trust him on this one). The player is already a persistent object and so no need to worry about any persistence issues caused by assigning them to a property. And no, you cannot define a property within an event. At least not without first defining it outside of an event with a default value. However, Masterofnet used a local variable instead of a property. He commented out the property line. Regarding this, it would be better to set up the local variable outside of the events and assign the value in the OnInit event rather than in the OnItemAdded event. No need to waste that extra bit of processing reassigning the PlayerRef variable every time an item is added. I also did not notice earlier that ObjectReference was being used for the PlayerRef, Actor will work just as well in this particular scenario. @FrankFamily & MasterofnetRegarding the bickering that the two of you seem be to be doing, please don't get another person's thread locked. Can you two resolve whatever your issue is via private message or something? There is no need for it to bleed over into every post. It makes it difficult for the rest of us who do wish to try and assist. Thank you. Link to comment Share on other sites More sharing options...
Recommended Posts