Difference between revisions of "Light Switch"

From the CreationKit Wiki
Jump to navigation Jump to search
imported>Jostrus
(Add logic check for OnInit and Update Timers to validate the swap is necessary. In case of player sleep past trigger times.)
imported>Jostrus
(Information change regarding previous code change.)
Line 89: Line 89:


bool Function ShouldLightsBeOff()
bool Function ShouldLightsBeOff()
{Validate the light state based on current time of day}


float CurrentTime = GetCurrentHourOfDay()
float CurrentTime = GetCurrentHourOfDay()
Line 110: Line 111:


So, for example, if I were to pass 7.0 as its parameter, then the next time it's 7:00 am in Skyrim, this object will have the native event [[OnUpdateGameTime_-_Form|OnUpdateGameTime]] called on it.
So, for example, if I were to pass 7.0 as its parameter, then the next time it's 7:00 am in Skyrim, this object will have the native event [[OnUpdateGameTime_-_Form|OnUpdateGameTime]] called on it.
==ShouldLightsBeOff==
This function validates that the current time of day is within the turn off or turn on range. It presumes that your turn off time is before the turn on time. This used by the [[OnInit]] and the [[OnUpdateGameTime_-_Form|OnUpdateGameTime]] events. It is necessary in case the player does a sleep or wait which causes the game to pass the current and next trigger time. Upon resuming the game will trigger the update and it needs to only switch state if the time is appropriate.


===OnInit===
===OnInit===
Line 119: Line 123:
The two states are nearly identical, and work sort of like mirror images of one another. Each state, when it begins, changes the enable state of the marker or master light (and therefore all other lights), and registers for a single update in game time at the time at which the state needs to change, as set by the two properties of this script.
The two states are nearly identical, and work sort of like mirror images of one another. Each state, when it begins, changes the enable state of the marker or master light (and therefore all other lights), and registers for a single update in game time at the time at which the state needs to change, as set by the two properties of this script.


When that time is reached, the OnUpdateGameTime event is called, which switches the script to the other state, and its OnBeginState event will run.
When that time is reached, the OnUpdateGameTime event is called, validates that the then current time of day requires a state switch, then if so switches the script to the other state, and its OnBeginState event will run.


==Extending This Script==
==Extending This Script==

Revision as of 03:54, 1 October 2018


Setup

The script on this page can be used to automatically turn a set of lights on or off depending on the time of day. It contains 2 properties, which have default values but are configurable in the Creation Kit

  1. LightsOffTime
    • The time at which lights should be turned off. Set to 7:00 am by default.
  2. LightsOnTime
    • The time at which lights should be turned on. Set to 6:00 pm by default.

In order to set this script up to be used, you'll need to either create a marker or select one of the lights to be the "master", and set it to be the enable parent of all the other lights. Then, just attach the script below to that marker or master light. If you don't want to use the default values, then either alter them in the script or override them in the Creation Kit.

Script

ScriptName TimedLightSwitch extends ObjectReference
{Controls a set of lights with a master enable parent marker with this
script attached to turn on and off at the times of the day specified
by the properties LightsOffTime and LightsOnTime}

float Property LightsOffTime = 7.0 auto
{The time at which lights should be turned off}
float Property LightsOnTime = 18.0 auto
{The time at which lights should be turned on}

float Function GetCurrentHourOfDay() global
{Returns the current time of day in hours since midnight}

	float Time = Utility.GetCurrentGameTime()
	Time -= Math.Floor(Time) ; Remove "previous in-game days passed" bit
	Time *= 24 ; Convert from fraction of a day to number of hours
	Return Time

EndFunction

Function RegisterForSingleUpdateGameTimeAt(float GameTime)
{Registers for a single UpdateGameTime event at the next occurrence
of the specified GameTime (in hours since midnight)}

	float CurrentTime = GetCurrentHourOfDay()
	If (GameTime < CurrentTime)
		GameTime += 24
	EndIf

	RegisterForSingleUpdateGameTime(GameTime - CurrentTime)

EndFunction

Event OnInit()

	If (ShouldLightsBeOff())
		GoToState("LightsOff")
	Else
		GoToState("LightsOn")
	EndIf

EndEvent

State LightsOff

	Event OnBeginState()
		Disable()
		RegisterForSingleUpdateGameTimeAt(LightsOnTime)
	EndEvent

	Event OnUpdateGameTime()
		If (ShouldLightsBeOff())
			RegisterForSingleUpdateGameTimeAt(LightsOnTime)
		Else
			GoToState("LightsOn")
		EndIf
	EndEvent

EndState

State LightsOn

	Event OnBeginState()
		Enable()
		RegisterForSingleUpdateGameTimeAt(LightsOffTime)
	EndEvent

	Event OnUpdateGameTime()
		If (ShouldLightsBeOff())
			GoToState("LightsOff")
		Else
			RegisterForSingleUpdateGameTimeAt(LightsOffTime)
		EndIf
	EndEvent

EndState

bool Function ShouldLightsBeOff()
{Validate the light state based on current time of day}

		float CurrentTime = GetCurrentHourOfDay()
		If (CurrentTime >= LightsOffTime) && (CurrentTime < LightsOnTime)
			return true
		Else
			return false
		EndIf

EndFunction

Script Explanation

This script consists of 2 custom functions, one OnInit event, and two states, each with their own OnBeginState and OnUpdateGameTime events.

The functions are documented within the script, but just in case they're not clear:

GetCurrentHourOfDay

This function uses the Utility script's global function, GetCurrentGameTime, and some mathematical manipulation, to get the current time of the current day as a number between 0.0 and 24.0

RegisterForSingleUpdateGameTimeAt

This function works as a variation of RegisterForSingleUpdateGameTime. The twist is that, while RegisterForSingleUpdateGameTime takes a duration as its parameter, this custom function takes the time at which the update should take place as its parameter.

So, for example, if I were to pass 7.0 as its parameter, then the next time it's 7:00 am in Skyrim, this object will have the native event OnUpdateGameTime called on it.

ShouldLightsBeOff

This function validates that the current time of day is within the turn off or turn on range. It presumes that your turn off time is before the turn on time. This used by the OnInit and the OnUpdateGameTime events. It is necessary in case the player does a sleep or wait which causes the game to pass the current and next trigger time. Upon resuming the game will trigger the update and it needs to only switch state if the time is appropriate.

OnInit

This event should pretty much always be used to set up your script in whatever ways are required that cannot be done when initialising properties or variables. All that's required here is that the correct state is selected depending on the current time in-game when this event runs.

If the lights should be off, then the script enters the "LightsOff" state, whereas if they should be on, then the script enters the "LightsOn" state.

States

The two states are nearly identical, and work sort of like mirror images of one another. Each state, when it begins, changes the enable state of the marker or master light (and therefore all other lights), and registers for a single update in game time at the time at which the state needs to change, as set by the two properties of this script.

When that time is reached, the OnUpdateGameTime event is called, validates that the then current time of day requires a state switch, then if so switches the script to the other state, and its OnBeginState event will run.

Extending This Script

The key functionality in this script is in the states. Specifically, that they both use the OnBeginState native event to set everything that needs to be set, so that the lights can be turned on or off simply by changing the state of the script. By taking advantage of this, it wouldn't be particularly difficult to, say, change the script so that the lights' state is toggled when the scripted object is activated:

Manual Light Switch

ScriptName ManualLightSwitch extends ObjectReference
{Controls a set of lights with a master enable parent
marker (EnableMarker) and a switch with this script
attached to turn on and off when the switch is activated}

ObjectReference Property EnableMarker auto
{The marker set as the enable parent of all the lights}

Event OnInit()

	If (EnableMarker.IsDisabled())
		GoToState("LightsOff")
	Else
		GoToState("LightsOn")
	EndIf

EndEvent

State LightsOff

	Event OnBeginState()
		EnableMarker.Disable()
	EndEvent

	Event OnActivate(ObjectReference akActionRef)
		GoToState("LightsOn")
	EndEvent

EndState

State LightsOn

	Event OnBeginState()
		EnableMarker.Enable()
	EndEvent

	Event OnActivate(ObjectReference akActionRef)
		GoToState("LightsOff")
	EndEvent

EndState