Jump to content

Scripting a time-difference event?


Recommended Posts

Posted (edited)

I've made a script for a fireplace where the fire grows when firewood is added, but gets smaller as time passes, eventually becoming just a pile of ashes:

Spoiler
Scriptname KHDFireplaceActivatorALIAS extends ReferenceAlias  

Quest Property FirewoodStage1 Auto
MiscObject Property Firewood Auto
Message Property NoFirewoodMessage Auto
Message Property KHDDontNeedFirewood Auto
int Property StageToSet0 auto
int Property StageToSet1 auto
int Property StageToSet2 auto
int Property StageToSet3 auto
int Property StageToSet4 auto
int Property StageToSet5 auto
GlobalVariable Property KHDFireplaceTemp auto
Int Property pHoursToWait Auto

	EVENT OnActivate (objectReference triggerRef)

Int pGlobal = KHDFireplaceTemp.GetValueInt()



if pGlobal == 5
		KHDDontNeedFirewood.Show()
	
elseif game.GetPlayer().GetItemCount(Firewood) == 0
		NoFirewoodMessage.Show()
			

elseif pGlobal == 0
		game.GetPlayer().RemoveItem(Firewood, 1)
		FirewoodStage1.SetStage(stageToSet1)
		KHDFireplaceTemp.SetValue(1)
		RegisterForSingleUpdateGameTime(pHourstoWait)

elseif pGlobal == 1
		game.GetPlayer().RemoveItem(Firewood, 1)
		FirewoodStage1.SetStage(stageToSet2)
		KHDFireplaceTemp.SetValue(2)
		RegisterForSingleUpdateGameTime(pHourstoWait)

elseif pGlobal == 2
		game.GetPlayer().RemoveItem(Firewood, 1)
		FirewoodStage1.SetStage(stageToSet3)
		KHDFireplaceTemp.SetValue(3)
		RegisterForSingleUpdateGameTime(pHourstoWait)

elseif pGlobal == 3
		game.GetPlayer().RemoveItem(Firewood, 1)
		FirewoodStage1.SetStage(stageToSet4)
		KHDFireplaceTemp.SetValue(4)
		RegisterForSingleUpdateGameTime(pHourstoWait)

elseif pGlobal == 4
		game.GetPlayer().RemoveItem(Firewood, 1)
		FirewoodStage1.SetStage(stageToSet5)
		KHDFireplaceTemp.SetValue(5)
		RegisterForSingleUpdateGameTime(pHourstoWait)
			

endif
	EndEvent


Event OnUpdateGameTime()

Int pGlobal = KHDFireplaceTemp.GetValueInt()

if pGlobal == 5
		FirewoodStage1.SetStage(stageToSet4)
		KHDFireplaceTemp.SetValue(4)
		RegisterForSingleUpdateGameTime(pHourstoWait)

elseif pGlobal == 4
		FirewoodStage1.SetStage(stageToSet3)
		KHDFireplaceTemp.SetValue(3)
		RegisterForSingleUpdateGameTime(pHourstoWait)

elseif pGlobal == 3
		FirewoodStage1.SetStage(stageToSet2)
		KHDFireplaceTemp.SetValue(2)
		RegisterForSingleUpdateGameTime(pHourstoWait)

elseif pGlobal == 2
		FirewoodStage1.SetStage(stageToSet1)
		KHDFireplaceTemp.SetValue(1)
		RegisterForSingleUpdateGameTime(pHourstoWait)

elseif pGlobal == 1
		FirewoodStage1.SetStage(stageToSet0)
		KHDFireplaceTemp.SetValue(0)

endif
EndEvent

 

 

but there's a problem:

As you can see in the code, the fire goes from stage 5 to stage 0 incrementally every hour. So if you press the wait button and wait one hour a few times, or just don't do anything and literally wait, you'll see it happen.

However, if I wait and select a chunk of time, e.g. 8 hours when I go to bed, when I get up, the fire will only have gone down 1 stage, presumably because the script only works once per wait.

How can I get round this?

 

I was thinking I'd need to create a timer where the "Current Time" is compared to a "Start Time" value which was set upon adding the firewood.

So because 5 is the maximum and I can't add more wood at that level,  sleeping for 6 hours would mean the hour different between the StartTime and CurrentTime is greater than 5 so the fire will be at Stage 0 upon waking up.

Is that possible? If so how would I go about writing the code?

 

EDIT: Just realized the Survival Mode has similar time-based stuff (I think), I'll check it out

Edited by KhajitDave
Remembered something
Link to comment
Share on other sites

When you register for the update, store the current time in a script wide local variable. Say ST for start time.

Then in the update event after assigning the pGlobal variable insert the following (needs tested).

Float StagesPassed = Math.Floor(((Utility.GetCurrentGameTime() - ST) * 24) / pHourstoWait)
If (pGlobal - StagesPassed) > 0
  pGlobal = CurrentStage - StagesPassed
Else
  pGlobal = 0
EndIf

The above should take the difference between the current time and the start, break it down to hours, and divide it by the number of hours to wait.  Then round that down to the nearest whole number (this should be the number of stages that should have passed).  If the current stage value less the result, is greater than zero assign the new value otherwise assign zero and proceed with the rest of the update event.

 

 

Link to comment
Share on other sites

I guess I've stored the CurrentTime as a local variable with this:

float GetCurrentTime = ST

 

However, the next part is giving me some error messages:

variable CurrentStage is undefined
cannot subtract a none from a float (cast missing or types unrelated)
type mismatch while assigning to a int (cast missing or types unrelated)

Link to comment
Share on other sites

Posted (edited)
float ST ; somewhere in the preamble of your script

ST = Game.getCurrentGameTime() ; when you start your timed delay

The trick is to do it at the point where you start your timed delay... "when you register for update" in Ishara's reply.

Edited by xkkmEl
Link to comment
Share on other sites

Yeah that's what I've done, at least I think I have.

Is this corrrect?

Spoiler
	EVENT OnActivate (objectReference triggerRef)

Int pGlobal = KHDFireplaceTemp.GetValueInt()


if pGlobal == 5
		KHDDontNeedFirewood.Show()
	
elseif game.GetPlayer().GetItemCount(Firewood) == 0
		NoFirewoodMessage.Show()
			

elseif pGlobal == 0
		game.GetPlayer().RemoveItem(Firewood, 1)
		FirewoodStage1.SetStage(stageToSet1)
		KHDFireplaceTemp.SetValue(1)
		RegisterForSingleUpdateGameTime(pHourstoWait)
		float GetCurrentTime = ST

elseif pGlobal == 1
		game.GetPlayer().RemoveItem(Firewood, 1)
		FirewoodStage1.SetStage(stageToSet2)
		KHDFireplaceTemp.SetValue(2)
		RegisterForSingleUpdateGameTime(pHourstoWait)
		float GetCurrentTime = ST

elseif pGlobal == 2
		game.GetPlayer().RemoveItem(Firewood, 1)
		FirewoodStage1.SetStage(stageToSet3)
		KHDFireplaceTemp.SetValue(3)
		RegisterForSingleUpdateGameTime(pHourstoWait)
		float GetCurrentTime = ST

elseif pGlobal == 3
		game.GetPlayer().RemoveItem(Firewood, 1)
		FirewoodStage1.SetStage(stageToSet4)
		KHDFireplaceTemp.SetValue(4)
		RegisterForSingleUpdateGameTime(pHourstoWait)
		float GetCurrentTime = ST

elseif pGlobal == 4
		game.GetPlayer().RemoveItem(Firewood, 1)
		FirewoodStage1.SetStage(stageToSet5)
		KHDFireplaceTemp.SetValue(5)
		RegisterForSingleUpdateGameTime(pHourstoWait)
		float GetCurrentTime = ST
	

endif
	EndEvent

 

 

Link to comment
Share on other sites

A local script variable is one that is defined in the empty state but whose value can be changed as needed throughout the script.

A local event / function variable is one that is defined inside of an event or function and used exclusively within that event or function.

Your empty state should have:  Float ST

And at each update registration you should have:  ST = Utility.GetCurrentGameTime()

As far as the CurrentStage thing, that was a mistake.  I had tried a couple different approaches before realizing I was making things too complicated.  It was a forgotten leftover.  Replace it with pGlobal and it should work as intended.

 

Link to comment
Share on other sites

Oh I see. Thanks very much for taking the time to help out with this.

You mentioned "empty state" but my script doesn't have any states set. I figured I didn't need them.

 

If you wouldn't mind, could you take a look at how I have the current script and tell me what needs to be changed?

I'm having the following error: "type mismatch while assigning to a int (cast missing or types unrelated)", perhaps because I don't have any states set up?

Here's the script:

Spoiler
Scriptname KHDFireplaceActivatorALIASNEW extends ReferenceAlias  


Quest Property FirewoodStage1 Auto
MiscObject Property Firewood Auto
Message Property NoFirewoodMessage Auto
Message Property KHDDontNeedFirewood Auto
int Property StageToSet0 auto
int Property StageToSet1 auto
int Property StageToSet2 auto
int Property StageToSet3 auto
int Property StageToSet4 auto
int Property StageToSet5 auto
GlobalVariable Property KHDFireplaceTemp auto
Int Property pHoursToWait Auto
float property ST Auto
float property CurrentStage Auto


	EVENT OnActivate (objectReference triggerRef)

Int pGlobal = KHDFireplaceTemp.GetValueInt()


if pGlobal == 5
		KHDDontNeedFirewood.Show()
	
elseif game.GetPlayer().GetItemCount(Firewood) == 0
		NoFirewoodMessage.Show()
			

elseif pGlobal == 0
		game.GetPlayer().RemoveItem(Firewood, 1)
		FirewoodStage1.SetStage(stageToSet1)
		KHDFireplaceTemp.SetValue(1)
		RegisterForSingleUpdateGameTime(pHourstoWait)
		ST = Utility.GetCurrentGameTime()

elseif pGlobal == 1
		game.GetPlayer().RemoveItem(Firewood, 1)
		FirewoodStage1.SetStage(stageToSet2)
		KHDFireplaceTemp.SetValue(2)
		RegisterForSingleUpdateGameTime(pHourstoWait)
		ST = Utility.GetCurrentGameTime()

elseif pGlobal == 2
		game.GetPlayer().RemoveItem(Firewood, 1)
		FirewoodStage1.SetStage(stageToSet3)
		KHDFireplaceTemp.SetValue(3)
		RegisterForSingleUpdateGameTime(pHourstoWait)
		ST = Utility.GetCurrentGameTime()

elseif pGlobal == 3
		game.GetPlayer().RemoveItem(Firewood, 1)
		FirewoodStage1.SetStage(stageToSet4)
		KHDFireplaceTemp.SetValue(4)
		RegisterForSingleUpdateGameTime(pHourstoWait)
		ST = Utility.GetCurrentGameTime()

elseif pGlobal == 4
		game.GetPlayer().RemoveItem(Firewood, 1)
		FirewoodStage1.SetStage(stageToSet5)
		KHDFireplaceTemp.SetValue(5)
		RegisterForSingleUpdateGameTime(pHourstoWait)
		ST = Utility.GetCurrentGameTime()
	

endif
	EndEvent


Event OnUpdateGameTime()

Int pGlobal = KHDFireplaceTemp.GetValueInt()
Float StagesPassed = Math.Floor(((Utility.GetCurrentGameTime() - ST) * 24) / pHourstoWait)
If (pGlobal - StagesPassed) > 0
  pGlobal = pGlobal - StagesPassed
Else
  pGlobal = 0
EndIf


if pGlobal == 5
		FirewoodStage1.SetStage(stageToSet4)
		KHDFireplaceTemp.SetValue(4)
		RegisterForSingleUpdateGameTime(pHourstoWait)

elseif pGlobal == 4
		FirewoodStage1.SetStage(stageToSet3)
		KHDFireplaceTemp.SetValue(3)
		RegisterForSingleUpdateGameTime(pHourstoWait)

elseif pGlobal == 3
		FirewoodStage1.SetStage(stageToSet2)
		KHDFireplaceTemp.SetValue(2)
		RegisterForSingleUpdateGameTime(pHourstoWait)

elseif pGlobal == 2
		FirewoodStage1.SetStage(stageToSet1)
		KHDFireplaceTemp.SetValue(1)
		RegisterForSingleUpdateGameTime(pHourstoWait)

elseif pGlobal == 1
		FirewoodStage1.SetStage(stageToSet0)
		KHDFireplaceTemp.SetValue(0)

endif
EndEvent

 

 

Link to comment
Share on other sites

Change

pGlobal = pGlobal - StagesPassed

to

pGlobal = (pGlobal - StagesPassed) as Int

The reason for this is that pGlobal is defined as an integer.  But up until this point we have been working with floats.  The end result being assigned to the pGlobal variable needs to be cast into an integer.  A simple oversight.

As far as the empty state, that is what any area outside of defined states would be called.  So if a script does not have any defined states, that script is completely in the empty state.  Should someone state that a variable declaration needs to be in the empty state, it means that it belongs outside of any state definitions, events or functions. Typically where properties reside.

You can also change 

float property ST Auto

into

Float ST

Only two reasons to make a variable a property:

  1. The variable cannot be defined within the script itself and instead must be assigned something with the Creation Kit.
  2. The variable needs to be accessed by another script.
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...