Talk:Complete Example Scripts

From the CreationKit Wiki
Revision as of 09:17, 9 December 2014 by imported>Terra Nova2 (→‎Enabling ReferenceAliases using an array)
Jump to navigation Jump to search

Standards

I'd like to make sure that the example scripts contained on this page are ones that are likely to be useful to readers. In my opinion there are a few things that are particularly likely to make a script useful in this way. For example:

  • Demonstrating a solution to a common problem
  • Demonstrating an advanced technique
  • Demonstrating usage of a difficult function

A lot of the time, though, such scripts would be more useful in other places. For example, if a script demonstrates well how a difficult function could be used, then it would probably be better suited on the documentation page for that function.

I think scripts included in this page should be ones that are:

  • Simple
    Ideally scripts on this page should be kept short and only perform a single function. Perhaps they should be something that could be used as a starting point for a more complex script.
  • Well documented
    • Both on this page and in their comments and variable/custom function names. If people are going to use these scripts, it's important that they're easy to understand and have good self documentation.
    • I think it would be best if the behaviour of a script is documented internally, and any setup required in the Creation Kit is documented on this page.
  • Reusable
    • In Papyrus, we can use properties to define behaviour without referring to any content in the data file itself. For example, the script used for Skyrim's "Transmute" spell is written such that it could be reused on another spell that transmutes a different set of items. Scripts on this page should be set up so that they apply to a generic situation.

When writing a script, there are basically two things that have to be done:

  • Detect an event
  • Do something

Because I'd like to keep scripts on this page as simple as possible, I think it would be best if each example it mainly about one of these things - it should either show how to capture a certain event or how to do something.

If the script is detecting a certain event, then the "do something" bit of the script should be kept separate if possible. Instead of putting some example code in there, I'd recommend a comment, like this:

ScriptName OnPlayerActivateScript extends ObjectReference
{This script detects when the object to which it is
attached is activated by the player, then does something}

Event OnActivate(ObjectReference akActionRef)
	if (akActionRef == Game.GetPlayer())
		; Do something
	endif
EndEvent

Likewise, when a script is mainly about "doing something", if at all possible a very simple event should be used, such as OnActivate, so as not to complicate the script any further.

If it's not possible to separate the event detection from the script's action, then it's probably worth reconsidering whether the script would be useful to have on this page.


In order to prevent this page from containing hundreds or thousands of scripts, only particularly useful scripts should be here. There will be many examples that meet the standards I've defined here, but if we put them all on this page it will become too difficult to find anything. Ideally, the examples here would be simple examples that are commonly sought after.

Currently, I don't think the examples on this page fit the standards I have in mind for it. Before I go about "cleaning it up", does anyone have any objections, criticisms or other comments on the standards that I've laid out here?

-- Cipscis 20:43, 15 February 2012 (EST)

Thinking a bit more about this, it seems to me that these standards would work quite well for another page, but "Complete Example Scripts" implies something else that is also useful.
-- Cipscis 17:57, 27 February 2012 (EST)
Perhaps if this were split into a series of helpful catagory subpages, like "Scripts for Activators", "Scripts for Sounds", "Scripts for Moving Things", and so on, it would help a user narrow down his search to the exact sort of script he or she is looking for. Otherwise it will most likely eventually be a horde of random scripts in no particular order. RedwoodElf 23:06, 8 March 2012 (EST)
That certainly sounds like a good idea to me. There's a Skyrim Script Repository on TESAlliance that's organised like this, perhaps those categories would be good starting points?
-- Cipscis 23:08, 8 March 2012 (EST)
I think having categories would be a good idea. Maybe also adding a full list at the bottom for those that could be in one place or another... I am still confused about what to put in here though. What about examples that people uses to ask about like for example having a spell place an item and getting its coordinates? That would need 3 scripts at least. Would that fit in here?
Shana 02:31, 9 March 2012 (EST)
Yes that fits here. If you want to write a complete tutorial for than it would go in Tutorials instead, otherwise here's fine. But make a new page for it. I think it's a good idea to put each example on its own page and make this a category.
--Qazaaq 06:20, 9 March 2012 (EST)

Container Script

Thanks fg for streamlining my container script. Though there may be a problem with it now. I havent tested it but it looks like the script will destroy any item not on the formlist. I think the item must be removed from the container and returned to the player. Thoughts? —The preceding unsigned comment was added by [[User:{{{2}}}|{{{2}}}]] ([[User talk:{{{2}}}|talk]] • [[Special:Contributions/{{{2}}}|contribs]]) 14:45, 12 May 2012‎ Scrivener07

Actually, it was JustinOther who optimized it. I just corrected the spelling for "Invalid". And yes, it's scripted so that any item not in the formlist is returned (silently) to its previous container. --Fg109 16:34, 12 May 2012 (EDT)

Advancing the Quest Stage When The Player Collides with a Trigger Box

This script, which is attached to a trigger box, advances the quest stage to 99 once if the stage is less than 99 when the player, and only when the player, bumps into it:

Scriptname AAMyTriggerBoxAdvanceQuestToStage99 extends ObjectReference  
 
Event OnTriggerEnter(ObjectReference akActionRef)
	if(akActionRef == Game.GetPlayer()) 
		If AAMyQuest.GetStage()<99
			AAMyQuest.SetStage (99)
		EndIf
	endif
EndEvent

Quest Property AAMyQuest  Auto

--David Brasher 19:21, 12 May 2012 (EDT)

--Scrivener07 03:08, 16 May 2012 (EDT) Seems very specific to a certain quest. Ill take a shot at making it more vague :) Same script with variables.

Event OnTriggerEnter(ObjectReference akActionRef)
	if(akActionRef == Game.GetPlayer()) 
		If AdvQuest.GetStage()< PreReqStage
			AdvQuest.SetStage(AdvStageTo)
		EndIf
	endif
EndEvent
Quest Property AdvQuest Auto
Int Property PreReqStage Auto
Int Property AdvStageTo Auto


Example scripts are only useful when they are very specific and the reader can clearly see what the parts are that need to be changed to apply to his or her mod. Most of the example scripts on this wiki are too vague and general to be used by non-professionals who just work with computers as a hobby. You are welcome to add all the example scripts in your format that you want to the wiki pages and discussion pages, put please do not edit any of my scripts I post in discussion pages. They are designed for laymen like myself and are more readable for them.--David Brasher 21:02, 24 May 2012 (EDT)

You two may want to take a look at the defaultSetStageTrigSCRIPT. --Fg109 04:01, 16 May 2012 (EDT)

Didn't work when I tried to use it. It would have taken more research and development time to get it operational in my mod than making this script did.--David Brasher 21:02, 24 May 2012 (EDT)

Disabling an Actor with a Trigger Box after a Certain Quest Stage

This script disables the questgiver if his quest is finished (if it is at stage 99.) It is placed on a trigger zone at the city gate which is out of sight of the questgiver, so that he won't vanish in front of your eyes.

Scriptname AAMyQuestgiverDisableSCRIPT extends ObjectReference  

Event OnTriggerEnter(ObjectReference akActionRef)
	if(akActionRef == Game.GetPlayer()) 
		If AAMyQuest.GetStage()==99
			AAMyQuestgiver.Disable()
		EndIf
	endif
EndEvent

Actor Property AAMyQuestgiver  Auto  

Quest Property AAMyQuest  Auto

--David Brasher 19:55, 12 May 2012 (EDT)

Missing script?

Hello, there are several pages linking to this one, referring to a FormList script example: "Disabling/enabling a large quantity of objects easily". Where is that script? I know, it's easy to figure out that a marker enabling parent would be a good strategy, as is used in home cells during the furniture buying process, but I wonder if the referred script just does that or if it exposes another way (it should be the case since it refers to Formlists usage)... --HawkFest (talk) 23:54, 26 July 2012 (EDT)

Suggestion

You know what would be really useful, I think? An example of a script that would run on a weapon attack. I'm trying to make a new weapon, but just can't quite figure out a couple of the basics, being new to Papyrus. --Starfyredragon (talk) 16:25, 12 August 2012 (EDT)

You should attach the script to one of the magic effects of an enchantment applied to the weapon. That script would then use the OnEffectStart and OnEffectFinish events, where the akTarget parameter is the target of the weapon hit. --HawkFest (talk) 2013-01-28T10:51:34 (EST)

Question

Is it possible to write a script that checks for the player forging a weapon (any weapon) of a particular new material as part of a quest stage?

The idea is that once he has learned the secret arts from the book he has access to the recipes, and then he has to forge a weapon and then temper it as part of the mini-quest.

I can add the quest stages to the journal, but how would I script it so that when he forges a weapon as directed the quest stage completes, and when he tempers that weapon the next quest stage completes and the Quest is successfully over?

Cheers!

~

After looking into the tutorial for blacksmithing in the CK, I still can't figure out how they did it wih the iron dagger. One way you might be able to do it (but this is just a guess, I haven't done anything like it) would be add a no-hit, invisible cloak to the player. Have the cloak check the player's distance to the nearest forge. While they are near a forge, keep track of the number of items you're looking for. When the number increases while they're right next to a forge, you could assume (with moderate reliability) that they forged the item. Xander9009 (talk) 2013-05-13T15:37:20 (EDT)
Make a Story Managed quest (CraftItem) and insert this script:
Event OnStoryCraftItem(ObjectReference akBench, Location akLocation, Form akCreatedItem)
if akCreatedItem == YourItemForm
;do some stuff
endif
endEvent
Templar-von-Midgard (talk)

Show Gift Inventory?

ok, I guess this would be attached to some actor/alias, and then another script could call the FeedCompanion function on the actor property pointing the actor to which it is attached? --HawkFest (talk) 2013-01-28T11:09:58 (EST)

Quest Mod: Check Whether Prerequisite Quest is Completed on Install

I'm making a quest mod that adds a quest to the game which follows up on one of the vanilla quest lines. If the player hasn't yet completed that quest, then my quest should trigger when they do; but I figured that a nice bit of functionality to add would be to check whether the prerequisite quest is already completed upon mod install, and then start my quest if it is. I thought this problem might be similar to the Maintenance Code example on this page, and wrote it like so:

ScriptName MyQuest Extends Quest Hidden

;***fragments and stuff***

Quest Property PrereqQuestA Auto

Quest Property PrereqQuestB Auto

;run the following code on first load
Event OnInit()
	Debug.Notification("My Mod installed successfully.")
	if PrereqQuestA.getStage() == *shut down stage* || PrereqQuestB.getStage() == *shut down stage*
		Debug.Notification("Prereq Quest already completed: starting My Mod Quest.")
		;***and then either...***
		SetStage(0) ;stage 0 is an empty start up stage
		;***OR***
		Start()
		;***both were tested***
	endif
endEvent

The OnInit() event is firing, and the prerequisite quest check works correctly, as both Debug notifications appear on the screen. The quest, however, does not start. In fact, it is broken: no "quest started" notification appears, and the quest is not in the journal, AND using setstage from the console to try to start the quest doesn't cause the notification to appear or the quest to start in the journal - although sqs at the console does mark the stage just set as completed. The quest will only begin to proceed as it should when the player interacts with one of the quest NPCs and uses a dialogue option that calls GetOwningQuest().SetStage(), at which point the journal entry appears in the player journal, minus any objectives that were given before the stage just set. Removing the above code allows the quest to be launched with "setstage MyModQuest 0" from the console, and it works normally.

The quest is not Start Game Enabled, and is ticked to Run Once. The OnInit() page suggests that the script won't receive events during its OnInit(), but Start() and SetStage() aren't events, are they? --Geekofalltrades (talk) 2013-12-13T19:18:08 (EST)

Enable/Disable an object on a schedule?

Based on my experience in the current Creation Kit (October 2014), the player cannot gain Line of Sight (LOS) on a disabled object- please confirm.

The script that works in my case is this:

Bool Property bEnableStuff Auto
Float Property fHourToDisable Auto ; Desired enable time/18.0 for example's sake
Float Property fHourToEnable Auto ; Desired enable time/6.0 for example's sake
Float Property fUpdateInterval Auto ; 15.0 works well and isn't too frantic.
GlobalVariable Property GameHour Auto
ObjectReference Property kYourObject Auto

Event OnInit()
	RegisterForSingleUpdate(fUpdateInterval)
	bEnableStuff = !kYourObject.IsDisabled()
	ToggleEnableStateIfApplicable()
EndEvent
 
Event OnUpdate()
	ToggleEnableStateIfApplicable()
	RegisterForSingleUpdate(fUpdateInterval)
EndEvent
 
Function ToggleEnableStateIfApplicable()
	Float fTime = GameHour.GetValue()
	If bEnableStuff != (fTime > fHourToEnable && fTime < fHourToDisable)
		bEnableStuff = !bEnableStuff
		If bEnableStuff
			kYourObject.Enable()
		Else
			kYourObject.Disable()
		EndIf
	EndIf
EndFunction


Enabling ReferenceAliases using an array

Int i = 0
Int MyArrayLength = myAliasArray.length

While i < MyArrayLength
	myAliasArray[i].GetReference().Enable()
	i += 1
	debug.trace("Iterating:" + i)
EndWhile

Why?

After each loop cycle, the condition has to be re-evaluated to decide on whether to continue looping or to bail out. To evaluate "i < myAliasArray.length", the length of the array will have to be determined and that value will have to be compared to i. However, the length of the array is not going to change while the loop runs and evaluating it after each cycle is entirely superfluous. Evaluate it once, store the result in a local variable and then compare i to that value. This halves the number of operations to be carried out for checking the loop condition and thus saves performance. --Sclerocephalus (talk) 2014-12-08T18:48:14 (EST)

I had made that function. Thanks for the correction but you did not have to remove all the other bits, as those were necessary for learning purposes. I removed my incorrect portion. Unfortunately I don't have the original function anymore. No harm no foul. --Terra Nova2 (talk) 2014-12-09T09:17:05 (EST)