Jump to content

[LE] Some scripting Tips? Making a auto sell stuff mod...


Recommended Posts

I have been modding since 2004, doing everything from 2D, 3D, scripting, well you name it. I mainly mod Oblivion and I done this lately in Oblivion and I will soon release an Oblivion version of the Legacy of the Dragonborn, called The legacy of the Champion. What I ask here now, I have it all working in Oblivion and it works perfect.

 

So I want a mod that autosell some specific items from my inventory. In Oblivion, an object has the stats from CS, lets say we put 20 damage at a sword and a value of 1000, that is what the object inside the inventory will have, as it is the base objects we see in the inventory and as soon as we pull it out, it will become a reference, starting with FFxxxxxx. So We can check that item and also get the actual value from it, if it is enchanted that is.

 

What I want to make is 2 containers. I want to put all items that I wish to autosell in container 1 and get the gold to container 2. I want to check every item in container 1 and compare it with my inventory, get the ID for it and also the value and the number of items with ObjectID.getitemcount. Why I will store the items inside a container is as it seems the arrays in Papyrus are limited to max index 128? In OBSE, there is no known limit to the array index as far as I know. and I am up to 600 now in some scripts in game that do exactly what I want them to do, check each index with my inventory and sell the crap per auto. :smile:

 

So in Skyrim, we can modify everything at a weapon and armor with the Workbench and Grind Stone, adding the values up many times, like 3-4 times the base value. That should mean that it is no longer the base object we have inside the inventory right? How would I check a value of a specific item inside my inventory with a script? How does Skyrim see the objects in containers and inventory? Still as the base objects or new references? The modified items never stack it seems, even if they have the same values, not even after a reboot of the game. Player made Potions stacks after a restart, but weapons or armor seems not to stack? If the weapon or armor gets an unique reference number, I cannot see any way to make this work in Skyrim really... I hope you can tell me what is what really... Any tip will be helpful.

Edited by Pellape
Link to comment
Share on other sites

  • Replies 82
  • Created
  • Last Reply

Top Posters In This Topic

Skyrim has GetGoldValue which can be used on a specific object instance and obtain that item's specific base value.

 

However, there are problems when it comes to enchanted gear. If the object is pre-enchanted (i.e. the base form is enchanted) it will obtain the correct base value. But if the object is player enchanted it can only obtain the non-enchanted base value. Furthermore, GetGoldValue cannot obtain the final value based on any modifiers (perks, etc). There are mathematical ways of getting close if one wants to delve into that. Despite its limitations it is still worth using to see how it will work for your needs.

 

Instead of trying to get the items from the player inventory, why not have the player add the items they want to "sell / junk" to a specific container? Use a script on that container that uses the OnItemAdded event to obtain the gold value.

 

You will find that mods which try to do something similar will usually not worry about getting the exact appropriate amount as would be obtained at a merchant but rather claim the missing amount as a "fee for service".

 

For learning purposes:

To scan items in the player's inventory and do something with them (Requires SKSE)

Here is a working example that scans the player inventory for ammo (arrows / bolts) already in inventory

 

Function GetPlayerAmmo(Bool TFbolt = false)
  Int Z = PlayerRef.GetNumItems()
  Int Y = 0
  While Y < Z
    If PlayerRef.GetNthForm(Y) as Ammo
      Ammo Entry = PlayerRef.GetNthForm(Y) as Ammo
      If Entry != Game.GetFormFromFile(0x0010B0A7, "Skyrim.esm") && Entry != Game.GetFormFromFile(0x000CAB52,"Skyrim.esm") ;don't process bound arrows or practice arrows.
        If TFBolt == false
          If !(ArrowMaster.HasForm(Entry)) && Entry.IsBolt() == false
            ArrowMaster.AddForm(Entry)
          EndIf
        Else
          If !(BoltMaster.HasForm(Entry)) && Entry.IsBolt() == true
            BoltMaster.AddForm(Entry)
          EndIf
        EndIf
      EndIf
    EndIf
    Y += 1
  EndWhile
EndFunction 

Note: ArrowMaster and BoltMaster are Formlist property variables. PlayerRef is an Actor property variable.

 

Formlists are similar to arrays. However, they can hold any type of form in the game and they can exceed 128 entries. One could consider a formlist to be a type of "container".

Unless persistent, Items have no reference ID while being held in a container or inventory. Once dropped into the game world, they will obtain a reference ID. Thus most work done while an item is held in an inventory or container will utilize data from the base form. Mileage may vary based on the functions in use. Always test for end results before tossing out an idea.

Link to comment
Share on other sites

Thanks a lot IsharaMeradin for the input.

 

I will make some tests, next Saturday. If I fail to get the new gold value from a player modded items, I can always skip making the items better honestly and only use the base values from CK as I am a bit tired of open and fiddle with the inventory, spending so much time at the vendors and it is therefor I want a mod like this, that allow me to focus at the fun stuff and spending time at vendors is not very fun really and if i get 20 or 80 gold from a Steel Dagger does not matter much as I have more gold than I will ever need now anyway. I do not need a function though, as I plan to make a button, in the other hand, I do need a function really when I think about it. I could add 3 scripts. One at an activator, a button, one at a spell, both will call for the same function.

 

I did took a peek at formlists and it might be exactly what I want or need really. When it comes to loops, I usually start from the behind in the inventory and count down instead of doing as it is done in that script, starting from 0 and I will explain why.

 

Lets say we come to Y = 3 and we move the 3rd item from the inventory, the loop will miss to check number 4 as the 4th item is now suddenly the 3rd item and that one will not be checked at all. If we start from getNumItem(Top) and go down, not a single item will be missed to be checked and end the loop with Y -= 1 instead and stop the loop when Y = 0, so while y > 0, will be most proper in this case. Well now comes the part on Saturday where I need to learn the basics of Skyrim scripting as there is a lot of stuff that is pure no sense for me as I am an Oblivion scripter.

 

But lets make an Oblivion example and you try to translate it to an Skyrim example? Oblivion scripts are very very easy to read I guess but the Skyrim ones confused me some so far but I will examine some activator scripts at Saturday from the Skyrim.esm, to see if I can get any wiser really. I use this function for moving stuff from my inventory to a container called PekResourcesChest as soon as I done a dungeon, where I add every resource for a crafting mod that I use:

scn PekSortbasicStuff04Fun


array_var ObjectArr

Ref MyItem

Short Turns
Short NumberOfItems
Short ObjectNumber

Begin Function {}

Message "Sorting 04 Started"

	Set Turns to 0
	Let ObjectArr := ar_Construct Array


	Let ObjectArr[0] := MiddleMetalTankard001
	Let ObjectArr[1] := MiddleMetalTankard002
	Let ObjectArr[2] := MiddleMetalTankard003

	Let ObjectNumber := ar_Size ObjectArr

	While ( Turns < ObjectNumber )
		Let MyItem := ObjectArr[Turns]
		Set NumberOfItems to player.GetItemCount MyItem
		
		If ( NumberOfItems > 0 )
			Player.Removeitem MyItem NumberOfItems
			PekResourcesChest.AddItem MyItem NumberOfItems
			
			PrintC "Varv %.0f - Flyttat %.0f st %n", Turns, NumberOfItems, MyItem 
		EndIf
		Let Turns += 1
	Loop

	

	Message "Sorting 04 Done"
	
End     ;   scn PekSortbasicStuff04Fun

I did only included 3 items in the array, as the lists is MUCH longer than this. In this example, I use a static list as my dynamic scripts not always works as I want them too, sometimes the references are just ignored.

 

So Int is Short right? Just like in C++?

But how do we initiate references like Ref?

Do we call the functions with call <function>?

 

I do start at 0 in the loop and count up, as the arrays are static... :wink: I could do that with a chest as well really or a formlist as it will be the number of items in the chest or formlist that counts, not the number of items that the player has in its inventory. I do start from the top, searching for soul gems and moving them... :wink:

 

You did mention SKSE? Do we start CK in the same way as we start CS with OBSE?

SKSE64_Launcher /Editor

? Or how do we start CK to get SKSE included?

 

Where can I find the SKSE specific functions and commands? When i Googled it, the only thing I did find was how to make DLL's with C++ and that is not what I want really as I only want to make simple scripts inside CK, not DLL's as SKSE plugins... In Oblivion, we have all OBSE and every function available here: https://cs.elderscrolls.com/index.php?title=List_of_Functions and even Pluggy scripting is included. Pluggy is a script expander, rarely used as most of those functions are also available from OBSE anyway. It seems like it was some competition between the OBSE team and Pluggy team fora period... :wink:

Edited by Pellape
Link to comment
Share on other sites

Prolly a repo somewhere with all SKSE commands but really, just look at the scripts themselves. They are all documented there directly. It can also be useful to sift through them manually since you will also stumble on a lot of non-SKSE calls too, that you dont see mentioned often but could be very useful

 

For your purposes def look at the ObjectReference script. GetContainerForms() and quite a few others are likely to be handy for your goals

Link to comment
Share on other sites

Unlike Oblivion's scripting system, Papyrus is independent of Skyrim's plugins. This means that you can write and even compile your scripts outside of the Creation Kit if a third party tool like Sublime Text or Notepad++ is properly set up. The Creation Kit is only needed to assign the scripts to the intended objects and to assign the correct data to any property variables. While it is possible to create a script from scratch inside the Creation Kit, there are some limitations when it comes to length. The built-in editor has a max character limit, yet papyrus scripts can be much much larger if necessary. In fact, many scripts used for MCM menus will exceed the character limit for the built-in editor.

 

As far as a list of SKSE functions, this is a good start but it is not up-to-date. The best thing to do is to take a look at the source files provided by SKSE.

 

And yes, if you were to remove items from an inventory or container while looping the contents, it is best to start at the highest index value rather than 0. The example was more a demonstration of what was needed. Direction of looping is up to intended purpose.

Link to comment
Share on other sites

Oblivion did have such a limit as well. I remember I reached the limit around 2008 when i made scripts for remaking stuff to arrows, long before I found out of OBSE scripting, so no functions, no loops, no arrays, just static boring coding, so much no optimised code, waste of space really. The limit is gone with CSE and my current Oblivion scripts are HUGE, even if I use arrays and loops. CSE script editor has a small ball that fills up, so you can see how much more code you can add before finding the limit and my biggest script today, fills that ball to 3/4, and it is over 3000 lines long... OBSE can also be used to make scripts outside CS and used for DLL's. I do use Notepad ++ and TES4 scripting plugin, which makes it easy and nice to make nice and good looking scripts.

 

Thanks a lot for the help so far. I cannot make any tests until Saturday and if I had access to Skyrim right now, I would not sit here typing. Then I had started to test this right away. At my GF's flat, I can only play Oblivion as there is no space left for Skyrim on this computer. I do not even know if it can handle it with ATI R5 GF card? I have Nvidia in my flat and a lot of space. Well Saturday it is... :wink: In one way it is good, as then I do not get tired of Skyrim so fast but I really miss it right now. I wanna play it. :wink: Oblivion will have to do right now and it is not bad at all really, just that I played it and modded it 2 years straight and I need a break from it... :D

 

I will start to peek at how Bethesda made their scripts, to learn the basics of how to structure Papyrus. What I seen, there is a lot of differences between Skyrim and oblivion. I can type oblivion scripts in my sleep, but the Skyrim ones looks a bit different what I seen so far. Many or almost all functions are the same, but the structure is not, like initiating variables and the odd stuff added after the scriptnames at line 1. I will figure it out really. I should spend some time in Youtube as well, best source for anyone. I did learn Blender from Youtube 2005 and still use it.

Edited by Pellape
Link to comment
Share on other sites

I find this (https://www.creationkit.com/index.php?title=Category:Papyrus) to be an invaluable source of information. Links on the right lead to informative pages and tutorials. Links below lead to more information about the base game functions / events as well as some provided by SKSE.

 

Please do not accidentally get confused by the Fallout 4 pages when using a search engine. I have seen that happen a lot. Pay attention to the wiki's URL. If it contains "creationkit.com/fallout4", do not use it for Skyrim.

Link to comment
Share on other sites

Agreed, the wiki is super helpful, but it doesn't list all of the functions, and doesn't include functions from PapyrusUtil and Papyrus Extender mods. In addition, I use GrepWin: https://tools.stefankueng.com/grepWin.html which can search text in multiple files in a folder, and can include sub folders.

 

For compiling scripts I use SSEScript https://www.nexusmods.com/skyrimspecialedition/mods/43691/ but as IsharaMeradin said there are many editors to choose from.

Link to comment
Share on other sites

Okay, I managed to pull this script together but I cannot test it until tomorrow. Correct me if I am wrong but is not GetNthForm (GetInventoryObject in OBSE) an SKSE function and if so, I must have SKSE loaded in CK to be able to compile this? I was thinking of adding this script to an activator but also add an even ScriptEffectStart, well in a separate script to be able to add this to a spell right? I cannot test this until late tomorrow evening, nor test to start CK and include SKSE.

 

The question is: Have i done right or is it something I need to correct, add or edit? The Stuff that i will compare with the player will be added to the PekContainerREF

ScriptName PekSellAllThisStuff

Int PekNumberOfItemsinStack
Int PekFormIndex
Int PekGoldValue
Form PekForm

Event OnActivate (ObjectReference PekHandle)
	
	PekFormIndex = PekContainerREF.GetNumItems()

	While PekFormIndex > 0 
		
		PekFormIndex -= 1

		PekForm = Player.GetNthForm(PekFormIndex)
		PekNumberOfItemsinStack = Player.GetItemCount(PekForm)
		PekGoldValue = PekForm.GetGoldValue()
		
		PekGoldValue = PekGoldValue * PekNumberOfItemsinStack 

		Player.RemoveItem(PekForm, PekNumberOfItemsinStack ) 
		Player.Additem(GoldBase, PekGoldValue)
	EndWhile

endEvent
Edited by Pellape
Link to comment
Share on other sites

I wanted a animal companion for this Enderal playthrough that doesnt do much damage but does kinda cheese the inventory system where I hand him heavy stuff and then once in a while tell him to go sell everything he has. He has one item I want to exclude so I handle that in the array. Uses that GetContainerForms() call I mentioned which IMO is one of the better ways to orchestrate this

  Actor MeTheFollower = Self as Actor; Just clarity. My script simply casts as self
  Form[] Things = MeTheFollower.GetContainerForms()
  Int Counter
  Int Digit
  While Digit < Things.Length
   Bool CanSell = Things[Digit].GetName() != "Night Light"
   If CanSell
    Int Total = MeTheFollower.GetItemCount(Things[Digit])
    Counter += Things[Digit].GetGoldValue() * Total
    MeTheFollower.RemoveItem(Things[Digit],Total)
   EndIf
   Digit += 1
  EndWhile
  ;RefreshFol(); Just my routine to port back to me when done
  Debug.Notification("Items were sold for " + Counter as String + " pennies")
  (Game.GetForm(0x14) as ObjectReference).AddItem(Game.GetForm(0xF),Counter,True)
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.

×
×
  • Create New...