Jump to content

DOWNLOAD MODS

Are you looking for something shiny for your load order? We have many exclusive mods and resources you won't find anywhere else. Start your search now...

LEARN MODDING

Ready to try your hand at making your own mod creations? Visit the Enclave, the original ES/FO modding school, and learn the tricks of the trade from veteran modders...

JOIN THE ALLIANCE

Membership is free and registering unlocks image galleries, project hosting, live chat, unlimited downloads, & more...

Need a little help.


thefinn
 Share

Recommended Posts

I'm kind of a newb at scripting, and worse for skyrim, I learn best by looking through examples - and sometimes the exact example you need you just can't find. ;)

 

I currently have made an NPC who I wish to have sell various items. He works just fine and has his container works fine also.

 

However, in order to not have to use master files, I decided to go with detecting mods that are installed and thereby changing the contents of his container based upon what mods the player has.

 

So for instance if Midas magic were installed, perhaps he sells some spells from that mod.

If Jaysus Swords are installed, perhaps he sells some daggers or whatever.

(No I'm not really using these, it's just for the exercise).

 

I am using as an example chesko's frostfall where he detects various armour packages to make them compatible and it seems fairly straight forward.

 

The one issue I seem to have is finding a good example of an activator script for the container itself and how to add items to it (I am a little iffy on how to reference the container as the target of the created object).

 

Or should the activator be on the actor, so that the container will change whenever someone talks to him?

 

Perhaps someone has a new perk in destruction magic, and thus a few more spellbooks might need to be added to the container at that point. Perhaps something is already bought, and needs to be replaced, etc..

(I'd like to avoid any papyrus lag doing that - I'm not sure of the best way).

 

I'm certainly not asking anyone to do it for me, however, any examples you might point me to would be great.

 

Any help appreciated.

Edited by thefinn
Link to comment
Share on other sites

I did this by placing a 'trigger zone' that surrounds the entire area around the chest.

So on trigger enter by the player, I check the mods that are installed, and based on that, I add the objects from that mod. (I did this for the DLC instead of other mods, but the concept is the exact same.)

 

So the script only runs once every time the player 'enters' the trigger zone.

Link to comment
Share on other sites

Hrm, that's not gonna work here. The NPC is a roaming salesman - the container in question is just his "shop container".

 

I might be able to put an activator on him, I'm just not entirely sure how.

ScriptName addShopitems Extends ObjectReference

Event OnActivate(ObjectReference akActionRef)

Something like that might be what I'm after...?

 

I figure I can do the check for mods at first load and set some flags for what is or isn't there. Then run something like this each time the NPC is spoken to..

 

Would just like a little bit of affirmation from someone who has done it or knows how.

Reason being that under the CK example I got this from is written -

To make this script work: Attach this script to an activator such as a button, lever, or container.

 

Doesn't say NPC ;) I guess I will try it later.

Edited by thefinn
Link to comment
Share on other sites

You can certainly attach a script to the base actor object. I did this so that when the player activates the merchant, I check the merchant and merchant container to see how much gold there is. Then I add gold based on that calculation to both the merchant and container. (32K in each, since that is the bug limit in Skyrim.)

 

You could do the same thing.

 

Here is my 'replenish gold' script that you can use and adjust to your needs.

If the player is sneaking when they active the merchant, it allows them to change the max amount of gold the merchant will have.

Scriptname LevelersActorSheanna extends ObjectReference  
{Gold on Sheanna}

ObjectReference Property LevelersChestSheannaREF  Auto  

miscobject Property gold001  Auto  

Message Property LevelersActorMaxGoldMSG  Auto  
Message Property LevelersActorMaxGoldSetMSG  Auto  

GlobalVariable Property LevelersActorMaxGoldGBL  Auto  

int MaxGold
int SheannaGold
int ChestGold
int button
int npcdead

Function CheckGold()
	if npcdead == true
		MaxGold = 0
		RemoveItem(Gold001, (SheannaGold - MaxGold))
	else
		MaxGold = LevelersActorMaxGoldGBL.GetValue() as int
		SheannaGold = GetItemCount(Gold001)
		ChestGold = LevelersChestSheannaREF.GetItemCount(Gold001)
		if SheannaGold < MaxGold
			AddItem(Gold001, (MaxGold - SheannaGold))
		elseif SheannaGold > MaxGold
			RemoveItem(Gold001, (SheannaGold - MaxGold))
		endif
		if ChestGold < MaxGold
			LevelersChestSheannaREF.AddItem(Gold001, (MaxGold - ChestGold))
		elseif ChestGold > MaxGold
			LevelersChestSheannaREF.RemoveItem(Gold001, (ChestGold - MaxGold))
		endif
	endif
EndFunction

Event OnInit()
	CheckGold()
EndEvent

Event OnActivate(ObjectReference akActionRef)
	If akActionRef == Game.GetPlayer()
		if Game.GetPlayer().IsSneaking()
			if npcdead == 1
				MaxGold = 0
				RemoveAllItems()
			else
				MaxGold = LevelersActorMaxGoldGBL.GetValue() as int
				button = LevelersActorMaxGoldMSG.Show(MaxGold)
				if button == 0
					MaxGold = 5000
				elseif button == 1
					MaxGold = 32000
				elseif button == 2
					MaxGold = 50000
				elseif button == 3
					MaxGold = 100000
				elseif button == 4
;					RemoveAllItems()
					LevelersChestSheannaREF.RemoveAllItems()
				endif
				LevelersActorMaxGoldGBL.SetValue(MaxGold)
				LevelersActorMaxGoldSetMSG.Show(MaxGold)
			endif
		endif
		CheckGold()
	endif
EndEvent

Event OnDeath(Actor akKiller)
	npcdead = 1
EndEvent

Link to comment
Share on other sites

This is what I have so far... I'll be testing this soon, I don't have a test character, have to do the cart ride :\

Scriptname MagarActivator extends ObjectReference  

ObjectReference Property MagarsChestRef  Auto  

;Supported Mods
bool isOpOutfitsLoaded    ;Opulent Outfits

Event onLoad()
    isOPOutfitsLoaded = Game.GetFormFromFile(0x008A2F, "OmageReplacerPack.esp")
    if isOPOutfitsLoaded
        MagarsChestRef.AddItem(Game.GetFormFromFile(0x008A2F, "OmageReplacerPack.esp"))
    endif
endEvent

Event onActivate(ObjectReference TriggerRef)
    debug.Trace(self + " has been activated by " + TriggerRef)
endEvent

The OnActivate I can deal with no worries - your example in fact showed me that I CAN treat an NPC just like any other object and apply that normal activator - that I guess was what I was asking - badly ;)

 

Edit: yeah that script was exactly what I needed, thank you so much. I can see the objectreference to the chest as well, easy-mode from here :)

 

I am a coder from way back, but I've not dealt with the CK in depth, this has actually been one of the better experiences of learning the script->CK interaction I've had. So thanks!

Edited by thefinn
Link to comment
Share on other sites

Hey, glad to help.

 

But remember, (there is always a 'but', isn't there?) the OnLoad does not execute very often. Only when the player 'enters' the cell the NPC is in. If they load a saved game from the same place the NPC is, the block will NOT execute. Perhaps also not if you leave the cell and re-enter the cell either, since the NPC would still be loaded in memory.

 

I think there may be some other problems with it but I don't recall at the moment.

 

That is why I used the 'onActivate' block instead. Unless you don't want it to happen 'every single time' the player activates the NPC. (In most cases, this should only be once per visit.)

 

I also will not run the script if the NPC is dead. You don't want the stuff spawning after they have died. And you know players, they love to kill your precious mod added NPC's.

Link to comment
Share on other sites

No worries, I will likely try and look the event up I'm actually after and that is just when he loads into the game the first time - set the variables for which mods are loaded then. Noone is going to be able to change the mods mid-game... That's the only thing that will go there.

 

The Activation will deal with what is in the chest at any given time, that script above is merely for testing the whole thing, then I will continue ;)

Link to comment
Share on other sites

If I could ask another question here. When exactly does the OnInit event run?

 

When I leave and enter the cell ? when he is totally unloaded and reloaded ?

 

I'm trying to work out when the stuff will appear (I have a working script for OnActivator but there are several things wrong with that method).

Link to comment
Share on other sites

yeah that didn't really explain it (I do read this kinda thing before asking ;))

 

Event called when the script has been created and all its properties have been initialized.<- this doesn't explain anything.

 

It's as good as saying "Oh this stuff will run when the game engine tells it to, and when that is... we'll leave you to guess."

 

Actually, what I've been after before I went to bed last night was a good example mod where someone adds their items into leveled lists via script - that will give me what I need as they have to do all of that at the same time I need to do my stuff. So it should have the quest stuff for running things at the start of game and when the game loads from a save. (I work better with examples ;)).

 

Can you think of a mod doing that ? I thought Jaysus swords did it but I forgot how it was needed for bashed patches when I used to use it.

Link to comment
Share on other sites

When the object the script is attached to is initialized. When that is depends on what object you attached the script to.

 

I am pretty sure I did this with a quest in Levelers Tower for Skyrim. Its been a while though.

 

Mostly, you create a new quest and check the box for run on game start. Attach your script to the quest, and your pretty much done.

The OnInit will then run at game start, because that is when the quest is told to 'initialize'. (remember the check box?)

Link to comment
Share on other sites

I just got this compiled, am about to test it.

 

I haven't QUITE worked out how to do the same thing via save game load, but I will get there.

; This script will put certain items in Magar's inventory depending upon mods loaded.

Scriptname MagarActivator extends Quest

LeveledItem Property MagarList Auto
;Supported Mods

bool isOpOutfitsLoaded                                                                                                    ;Opulent Outfits - Mages of Winterhold - Replacer Version.

Int[] Robes


event OnInit()
    debug.Trace("Magar Initializing.")
    isOPOutfitsLoaded = Game.GetFormFromFile(0x008A2F, "OmageReplacerPack.esp")
    if isOPOutfitsLoaded
        debug.Trace("Opulent Outfits Detected.")
        OpulentOutfits()
    endif
endEvent

Function OpulentOutfits()
            Robes = new int[15]                                                                                ; Array with Robe ID's
            Robes[0] = 0x0028A6
            debug.Trace("Adding Opulent Robes, Hoods and Boots to Inventory.")
            MagarList.AddForm(Game.GetFormFromFile(Robes[0], "OmageReplacerPack.esp"), 1, 1)                            ; Novice Hood of Alteration

;            MagarsChestRef.AddForm(Game.GetFormFromFile(0x0028A6, "OmageReplacerPack.esp"))                             ; Novice Hood of Alteration
;            MagarsChestRef.AddItem(Game.GetFormFromFile(0x002E35, "OmageReplacerPack.esp"))                             ; Novice Hood of Conjuration
;            MagarsChestRef.AddItem(Game.GetFormFromFile(0x002E39, "OmageReplacerPack.esp"))                            ; Novice Hood of Destruction
;            MagarsChestRef.AddItem(Game.GetFormFromFile(0x002E3D, "OmageReplacerPack.esp"))                             ; Novice Hood of Illusion
;            MagarsChestRef.AddItem(Game.GetFormFromFile(0x002E41, "OmageReplacerPack.esp"))                             ; Novice Hood of Restoration
;            MagarsChestRef.AddItem(Game.GetFormFromFile(0x0028A7, "OmageReplacerPack.esp"))                             ; Apprentice Boots of Alteration
;            MagarsChestRef.AddItem(Game.GetFormFromFile(0x002E33, "OmageReplacerPack.esp"))                             ; Apprentice Boots of Conjuration
;            MagarsChestRef.AddItem(Game.GetFormFromFile(0x002E37, "OmageReplacerPack.esp"))                             ; Apprentice Boots of Destruction
;            MagarsChestRef.AddItem(Game.GetFormFromFile(0x002E3B, "OmageReplacerPack.esp"))                             ; Apprentice Boots of Illusion
;            MagarsChestRef.AddItem(Game.GetFormFromFile(0x002E3F, "OmageReplacerPack.esp"))                             ; Apprentice Boots of Restoration
;            MagarsChestRef.AddItem(Game.GetFormFromFile(0x10D669, "Skyrim.esm"))                                        ; Novice Robes of Alteration
;            MagarsChestRef.AddItem(Game.GetFormFromFile(0x10D66A, "Skyrim.esm"))                                         ; Novice Robes of Conjuration
;            MagarsChestRef.AddItem(Game.GetFormFromFile(0x10D668, "Skyrim.esm"))                                         ; Novice Robes of Destruction
;            MagarsChestRef.AddItem(Game.GetFormFromFile(0x10D671, "Skyrim.esm"))                                         ; Novice Robes of Illusion
;            MagarsChestRef.AddItem(Game.GetFormFromFile(0x10D66B, "Skyrim.esm"))                                        ; Novice Robes of Restoration
endFunction
Edited by thefinn
Link to comment
Share on other sites

It didn't but after much reading on Player Reference Alias Quests (rolls eyes), I got it all working.

 

One final question if I can however, when declaring the Array, is it possible to define ALL of the array elements on a single line?

 

Or even multi-line.. ?

 

Like

 

Array[] = 1,

2,

3,

10, ; etc

15, ; comment

22  ; comment

 

or is that somehow not allowed?

 

I'll put the final scripts up in a minute - something to note - I had dragonborn, hf and DG all as masters because of the earlier way I was doing things.

 

When trying to add the player reference it was crashing over and over when I tried to click "ok" - perhaps the CK ran out of memory ? I dunno.

 

I took the masters out with TESVEdit and had no issues after that, was incredibly annoying for a while though.

Edited by thefinn
Link to comment
Share on other sites

I'd still like a way to decare the array elements on a single line if possible, however, this all works perfectly now.

 

This script detects mods installed, and adds items defined by their object ID into the leveled list of this shopkeeper.

Sorry the editor keeps ripping all the tabs out :\

; This script will put certain items in Magar's inventory depending upon mods loaded.

Scriptname THEFINNMagarActivator extends Quest

LeveledItem Property MagarList Auto ; Point this at Magar's Leveled List in CK

;Supported Mods
bool isSkyrimThere ;I wonder if skyrim is there ?
bool isOpOutfitsLoaded ;Opulent Outfits - Mages of Winterhold - Replacer Version.
int i
int[] Robes ;Integer Array holding the item id's.

event OnInit() ;Run once On New Game Start
debug.Trace("========== Magar Initializing.")
StartShop()
endEvent

Function StartShop() ; This is also run once by player reference alias script on savegame LOAD.
isSkyrimThere = Game.GetFormFromFile(0x06B46C, "Skyrim.esm") ; check for skyrim.
isOPOutfitsLoaded = Game.GetFormFromFile(0x008A2F, "OmageReplacerPack.esp") ; check for opulent outfits.
if isOpOutfitsLoaded
OpulentOutfits()
endIf
if isSkyrimThere
VanillaMageRobes()
endif
endFunction

Function OpulentOutfits()
debug.Trace("========== Adding Opulent Robes, Hoods and Boots to Inventory.")
Robes = new int[10] ; Reset Array for new Items.
Robes[0] = 0x0028A6 ; Novice Hood of Alteration
Robes[1] = 0x002E35 ; Novice Hood of Conjuration
Robes[2] = 0x002E39 ; Novice Hood of Destruction
Robes[3] = 0x002E3D ; Novice Hood of Illusion
Robes[4] = 0x002E41 ; Novice Hood of Restoration
Robes[5] = 0x0028A7 ; Apprentice Boots of Alteration
Robes[6] = 0x002E33 ; Apprentice Boots of Conjuration
Robes[7] = 0x002E37 ; Apprentice Boots of Destruction
Robes[8] = 0x002E3B ; Apprentice Boots of Illusion
Robes[9] = 0x002E3F ; Apprentice Boots of Restoration
i = 0 ; set i back to zero to begin.
while i < Robes.Length
AddSomeItems("OmageReplacerPack.esp", Robes[i]) ; Step through the Array.
i += 1
endwhile

endFunction

Function VanillaMageRobes()
debug.Trace("========== Adding Vanilla Skyrim Mage Robes to Inventory.")
Robes = new int[8] ; Reset Array for new items.
Robes[0] = 0x06B46C ; Novice Boots
Robes[1] = 0x10DD3A ; Novice Hood
Robes[2] = 0x10D667 ; Novice Robes
Robes[3] = 0x10D669 ; Novice Robes of Alteration
Robes[4] = 0x10D66A ; Novice Robes of Conjuration
Robes[5] = 0x10D668 ; Novice Robes of Destruction
Robes[6] = 0x10D671 ; Novice Robes of Illusion
Robes[7] = 0x10D66B ; Novice Robes of Restoration
i = 0 ; set i back to zero to begin.
while i < Robes.Length
AddSomeItems("Skyrim.esm", Robes[i]) ; Step through the array adding each item.
i += 1
endWhile
endFunction

Function AddSomeItems(string Filetocall, int arg)
MagarList.AddForm(Game.GetFormFromFile(arg, Filetocall),1,1) ; Get the read item ID from the parent esm/esp and add it to the leveled list.
endFunction
Edited by thefinn
Link to comment
Share on other sites

Unlike Willie, I have found several excuses to use arrays, but Papyrus is not really very array-friendly even though it has the basic capability. I would give a pretty penny for a one-line assignment myself, but it just isn't there, any more than arrays that can be dimensioned at runtime are there, or array properties that can be given an initial list of values, or ... :)

 

Just quickly off the top of my head, can't you pre-define the robes as an FLST and then just cast that to Int when you assign it to your Robes array? You wouldn't be able to comment the individual values that way, but I don't see why that is really necessary. You'll know what they are when you populate the FLST.

Link to comment
Share on other sites

To be honest, I have seen a bunch of bugs regard casts and types not matching (or whatever it said) but really have very little clue regarding what it's referring to - I know they are generally referring to variables being set to int when they don't contain an integer but in terms of the array as a whole... I don't get your meaning ;)

 

I'm not very used to skyrim coding yet.

 

I also have a papyrus error here that perhaps someone can shed some light on:

[10/15/2013 - 05:13:01AM] Error: Unable to bind script THEFINNMagarResetPerLoad to THEFINNPlayerRefQuest (8D05A48C) because their base types do not match
 

It doesn't seem to be interferring at all however (I don't think anyhow).

Link to comment
Share on other sites

A FormList is basically a pre-defined array of form IDs.  Looking more closely at your code, though, I see that won't work for you, since you have to use GetFormFromFile.

 

The other option is to define your robes as array properties, so the information is filled in before the script ever runs. This will make your script a little leaner and more efficient, since you don't need the initialization code at all. Something like:

Int[] Property RobesOpulent Auto
Int[] Property RobesVanilla Auto

<other code>

Function OpulentOutfits()

    debug.Trace("========== Adding Opulent Robes, Hoods and Boots to Inventory.")

    i = 0 ; set i back to zero to begin.

    while i < RobesOpulent.Length
        AddSomeItems("OmageReplacerPack.esp", RobesOpulent[i]) ; Step through the Array.
        i += 1
    endwhile

endFunction

Function VanillaMageRobes()

    debug.Trace("========== Adding Vanilla Skyrim Mage Robes to Inventory.")

    i = 0 ; set i back to zero to begin.

    while i < RobesVanilla.Length
        AddSomeItems("OmageReplacerPack.esp", RobesVanilla[i]) ; Step through the Array.
    i += 1
    endwhile

endFunction

See how much cleaner and easier to read that is? When you add your script to the merchant and edit the properties, the Properties Editor will give you a special dialog for an array property allowing you to fill in as many or as few elements as needed. If Opulent Robes ever adds new robes, you don't need to change your script at all! Just add the new ones to the list in the Property and you're good to go.

 

In fact, you could make it even simpler by combining the two functions into one. The calling program could simply pass in the name of the property containing the proper robe list as an argument, so the script has less redundant code.

 

The main disadvantage, of course, is that you don't have your nice list of comments telling what each integer is referring to. But, if you can live with that, I think this might be the best way to get the job done.

Edited by BrettM
Link to comment
Share on other sites

Doesn't this require the robes mod be a master file ?

 

The whole point of the original script was to only have Skyrim.esm and Update.esm as masters, and detect all the mods I want to make compatible.

 

Edit: Nevermind, I see the part where you are still calling the filename.

 

Hrm I will experiment and see how it goes - I really DO want to tidy that part up.. idk, it's nice to have it documented so you can see if say a pair of boots or something small goes missing - I intend on putting in quite a lot of compatibility too, so it might be better to keep it documented.

 

That's so much easier on the eyes though. *shrug*

Edited by thefinn
Link to comment
Share on other sites

I agree that documenting "magic numbers" is a really, really good thing to do. FormLists are very nice for that, since you can see the names of all the stuff you added to them, so it's really a shame they won't work for you. If the properties could somehow be made so that you could fill them from a pick-list of names, that would solve the problem, but I can't think of a way to do that offhand. If one occurs to me, I'll sure let you know!

 

OTOH, if you're going to be including a lot of refs to other mods, then your script is going to turn into a real maze of functions and calls to them, and all the code to initialize all the arrays of the things you want to add is going to suck up processor time. Of course, that matters less when your code is of the "run once" variety rather than something that needs to run every time the player speaks to the merchant.

Link to comment
Share on other sites

Yeah run once only. I am very aware of what I am actually asking of the processor and even more scared of the papyrus runtime engine - let's face it - anything could happen lol

 

Just on this - I actually would've been WAY more scared of that, but then I saw frostfall, and it dispelled any notion that *I* would be the one to reach the limits ;)

Edited by thefinn
Link to comment
Share on other sites

Perk Property SpringheelJakPerk auto

 

Is there a way of setting up the equivalent to a Perk Property without the CK ?

 

Or at least setting a variable to be read by HasPerk ?

 

 

        isAlterationNovice = Game.GetPlayer().HasPerk(f2ca6)
 

Obviously the wrong type there. I'm not sure what it's expecting, the CK website is of little help.

 

I'm sure I could make it with GetFormFromFile but that doesn't seem very elegant ;)

 

Actually those were integers, I might try that. I'd really rather not declare it at all and just throw it in, can it not handle that ?!

Edited by thefinn
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...