Jump to content

[LE] Noob papyrus questions


candlepin

Recommended Posts

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 1

Scriptname PRKF_Gourd_SwapPerk_01001827 Extends Perk Hidden

 

;BEGIN FRAGMENT Fragment_0

Function Fragment_0(ObjectReference akTargetRef, Actor akActor)

;BEGIN CODE

akTargetRef.disable()

akTargetRef.delete()

akActor.addItem(Gourd)

;END CODE

EndFunction

;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 auto

Ingredient property IngredientGourd auto

ObjectReference 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

  • Replies 89
  • Created
  • Last Reply

Top Posters In This Topic

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
EndEvent

Making 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

@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

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_Objects

https://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

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

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 Gibberish

https://forums.nexusmods.com/index.php?/topic/5370805-need-some-help-with-a-custom-spell/

 

Reality

https://forums.nexusmods.com/index.php?/topic/5306120-will-this-script-work-as-intended/

Edited by Masterofnet
Link to comment
Share on other sites

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

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 Gibberish

https://forums.nexus...a-custom-spell/

 

Reality

https://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 by Masterofnet
Link to comment
Share on other sites

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 & Masterofnet

Regarding 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

  • Recently Browsing   0 members

    • No registered users viewing this page.

×
×
  • Create New...