Resource:Light Effects Tutorial

= Overview = This resource will allow you to add mist, spots, and beams to your light meshes as well as prevent the vanilla bug where activator style lights randomly go dark even when on. There are two parts to using this resource: a script to attach to your activator light in the Creation Kit and changes in the mesh (nif) file itself.

See "Stained Glass Workshop Mod - Unicorn Farts and Godrays" for a live example of what these light effects do.



How to Use
If your only interest is preventing the vanilla light bug you can skip adding the spot, beam, and mist nodes to your nif file and add the REF_ATTACH_NODE only. Otherwise add the aspects you wish to use.


 * Backup your nif somewhere safely
 * Open nif in Nifskope and add two entries: One is a NiNode called REF_ATTACH_NODE. It doesn't have a position or value, just needs to be present, it keeps the light sources moving with the lamp when you pick it up in workshop mode.
 * Second entry: SpotNode01 where and at the angle you want your light source to appear.


 * The light script will put whatever you want at the following nodes (In light green) if present and the properties are filled in at the entry:
 * So, you can put up to 6 things in that nif. So put in SpotNode01. Probably the same place you had your addon node.
 * The rest is handled either by altering the script itself (like changing the scale of the mist, or what happens when you activate it) or filling in properties in CK.
 * Don't worry about filling in all 6 or putting all 6 nodes in the nif. It will ignore the ones not present.
 * Anyway, that's the nif part. On to the script part.
 * I'm going to assume you've set the light source entry up with the hemi gobo already.
 * Open your activator in CK. Add script:
 * Add light script:
 * This entry will pop up.
 * Double click on SpotBaseForm (in black), go to the right pane, form type: light, then choose your light entry. Hit OK
 * Click yes anyway.
 * Click OK to close the activator entry, save, and start to play with position and light entry settings in your nif until you like how it looks in game.

Source code
ScriptName YOURNAMESPACE:LightScriptFullControl extends ObjectReference

Form Property SpotBaseForm Auto Const Form Property SpotBaseForm2 Auto Const Form Property BeamBaseForm Auto Const Form Property BeamBaseForm2 Auto Const Form Property MistBaseForm Auto Const Form Property MistBaseForm2 Auto Const string Property spotNode = "SpotNode01" Auto conditional string Property spotNode2 = "SpotNode02" Auto conditional string Property beamNode = "BeamNode01" Auto conditional string Property beamNode2 = "BeamNode02" Auto conditional string Property mistNode = "MistNode01" Auto conditional string Property mistNode2 = "MistNode02" Auto conditional
 * -- Properties --

ObjectReference mistRef2 bool IsSparkly ObjectReference spotRef2 ObjectReference mistRef ObjectReference spotRef ObjectReference beamRef ObjectReference beamRef2
 * -- Variables ---


 * -- Functions ---

Function MoveStainedGlassExtraParts Self.DestroyStainedGlassExtraParts Utility.Wait(0.1) Self.PlaceStainedGlassExtraParts EndFunction

Function PlaceStainedGlassExtraParts ; niston @ 2022-08-29 ; do not execute this if 3D isn't loaded - PlaceAtNode wouldn't work anyways If (!Is3DLoaded) Return EndIf IsSparkly = True ; niston @ 2022-08-29 ; added none checks to prevent excessive log spam If (SpotBaseForm != none) spotRef = Self.PlaceAtNode(spotNode, SpotBaseForm, 1, False, False, False, True) EndIf If (SpotBaseForm2 != none) spotRef2 = Self.PlaceAtNode(spotNode2, SpotBaseForm2, 1, False, False, False, True) EndIf If (BeamBaseForm != none) beamRef = Self.PlaceAtNode(beamNode, BeamBaseForm, 1, False, False, False, True) Endif If (beamRef != none) beamRef.SetScale(1) EndIf If (BeamBaseForm2 != none) beamRef2 = Self.PlaceAtNode(beamNode2, BeamBaseForm2, 1, False, False, False, True) EndIf If (beamRef2 != none) beamRef2.SetScale(1) EndIf If (MistBaseForm != none) mistRef = Self.PlaceAtNode(mistNode, MistBaseForm, 1, False, True, False, True) EndIf If (mistRef != none) mistRef.SetScale(1) mistRef.enable(False) EndIf If (MistBaseForm2 != none) mistRef2 = Self.PlaceAtNode(mistNode2, MistBaseForm2, 1, False, True, False, True) EndIf If (mistRef2 != none) mistRef2.WaitFor3DLoad mistRef2.SetScale(1) mistRef2.enable(False) EndIf EndFunction

Function DestroyStainedGlassExtraParts ; niston @ 2022-08-29 ; modified to prevent log spam when object to be deleted doesn't exist IsSparkly = False If (spotRef) spotRef.Delete EndIf If (spotRef2) spotRef2.Delete EndIf If (beamRef) beamRef.Delete EndIf If (beamRef2) beamRef2.Delete EndIf If (mistRef) mistRef.Delete EndIf If (mistRef2) mistRef2.Delete EndIf EndFunction

Auto State On
 * -- State ---

Event OnWorkshopObjectDestroyed(ObjectReference akActionRef) If (IsSparkly) Self.DestroyStainedGlassExtraParts EndIf EndEvent

Event OnActivate(ObjectReference akActionRef) If (Self.Ispowered == True) Self.DestroyStainedGlassExtraParts Self.GoToState("off") Else Self.DestroyStainedGlassExtraParts EndIf EndEvent

Event OnPowerOff If (IsSparkly) Self.DestroyStainedGlassExtraParts EndIf EndEvent

Event OnPowerOn(ObjectReference akPowerGenerator) If (!IsSparkly) Self.PlaceStainedGlassExtraParts EndIf EndEvent

Event OnWorkshopObjectPlaced(ObjectReference akReference) If (Self.Ispowered == True) If (!IsSparkly) Self.PlaceStainedGlassExtraParts EndIf ElseIf (IsSparkly) Self.DestroyStainedGlassExtraParts EndIf EndEvent

Event OnWorkshopObjectMoved(ObjectReference akReference) If (Self.Ispowered == True) If (IsSparkly) Self.MoveStainedGlassExtraParts EndIf ElseIf (IsSparkly) Self.DestroyStainedGlassExtraParts EndIf EndEvent EndState

State off
 * -- State ---

Event OnWorkshopObjectDestroyed(ObjectReference akActionRef) If (IsSparkly) Self.DestroyStainedGlassExtraParts EndIf EndEvent

Event OnActivate(ObjectReference akActionRef) If (Self.Ispowered == True) If (!IsSparkly) Self.PlaceStainedGlassExtraParts EndIf Self.GoToState("On") ElseIf (IsSparkly) Self.DestroyStainedGlassExtraParts EndIf EndEvent

Event OnPowerOff If (IsSparkly) Self.DestroyStainedGlassExtraParts EndIf EndEvent EndState

Credits

 * MunkySpunk for the primary work and scripting.
 * Niston for some script editing.
 * Damanding/Crayonkit for tutorial publishing with permission of both MunkySpunk and Niston.

License
This tutorial is under Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)