KhajitDave Posted May 3 Share Posted May 3 (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 May 3 by KhajitDave Remembered something Link to comment Share on other sites More sharing options...
IsharaMeradin Posted May 3 Share Posted May 3 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 More sharing options...
KhajitDave Posted May 5 Author Share Posted May 5 Thanks for your help! When you say "store the current time....", how do I do that? I'm a beginner at papyrus scripting Link to comment Share on other sites More sharing options...
KhajitDave Posted May 5 Author Share Posted May 5 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 More sharing options...
xkkmEl Posted May 5 Share Posted May 5 (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 May 5 by xkkmEl Link to comment Share on other sites More sharing options...
KhajitDave Posted May 5 Author Share Posted May 5 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 More sharing options...
KhajitDave Posted May 5 Author Share Posted May 5 I've set "float property CurrentStage auto" But I'm getting this error: type mismatch while assigning to a int (cast missing or types unrelated) Link to comment Share on other sites More sharing options...
IsharaMeradin Posted May 5 Share Posted May 5 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 More sharing options...
KhajitDave Posted May 5 Author Share Posted May 5 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 More sharing options...
IsharaMeradin Posted May 5 Share Posted May 5 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: The variable cannot be defined within the script itself and instead must be assigned something with the Creation Kit. The variable needs to be accessed by another script. Link to comment Share on other sites More sharing options...
Recommended Posts