Jump to content

[LE] Scripted Endings Based on Days Spent Completing Quest


Recommended Posts

I have attached a script to my quest that should track the days spent in completing the quest. It is as follows:

 

 

 

Scriptname CV2_EndingCountdownTimer extends Quest  

GlobalVariable Property GlobalDays auto ;initial days to complete
GlobalVariable Property GlobalTime auto ;counter for hours left
Quest Property CV2_MQ auto ;the quest (I used two scripts on same quest while cause I modified a vanilla one)
 
Float endTime1
Float endTime2
Float endTime3

ObjectReference Property Ending1Trig Auto
ObjectReference Property Ending2Trig Auto
ObjectReference Property Ending3Trig Auto

Event OnInit()

        GlobalTime.SetValue(GlobalDays.GetValue() * 24)
        endTime1 = Utility.GetCurrentGameTime() + GlobalDays.GetValue() * 96
        endTime2 = Utility.GetCurrentGameTime() + GlobalDays.GetValue() * 144
        endTime3 = Utility.GetCurrentGameTime() + GlobalDays.GetValue() * 192
        CV2_MQ.UpdateCurrentInstanceGlobal(GlobalTime)
        RegisterForUpdateGameTime(0.50)

EndEvent

Event OnUpdateGameTime()

    If Utility.GetCurrentGameTime() < endTime2
        Ending1Trig.Enable()
        UnregisterForUpdateGameTime()
        RegisterForUpdateGameTime(0.50)
    ElseIf Utility.GetCurrentGameTime() >= endTime2 && Utility.GetCurrentGameTime() < endTime3
        Ending2Trig.Enable()
        Ending1Trig.Disable()
        UnregisterForUpdateGameTime()
        RegisterForUpdateGameTime(0.50)
    ElseIf Utility.GetCurrentGameTime() >= endTime3
        Ending3Trig.Enable()
        Ending2Trig.Disable()
        UnregisterForUpdateGameTime()
    EndIf

EndEvent

 

 

 

The problem I am having is that the only ending trigger that calls is the last one (the "bad" ending), which is only supposed to call when 8 in-game days have passed. The best ending is supposed to be 4 days and the good ending is supposed to be 6 days.

 

Would anyone help me with this script? Thanks in advance.

Link to comment
Share on other sites

Just some thoughts, take it all with a grain of salt, pepper, sugar or whatever. :unsure:

 

First off, in the OnInit block, I'd assign the result of GetCurrentGameTime to a local variable and use that as the base for all three end timings. If you call it three separate times, each timer will have a different start. You want one start with three separate possible endings.

Example:

Float CurrentTime = Utility.GetCurrentGameTime()
endtime1 = CurrentTime + GlobalDays.GetValue()

The second thing is that GetCurrentGameTime returns the DAYS passed rather than the HOURS. This is why you had to multiply by 24 for GlobalTime as that is supposed to store the hours remaining in the quest. But to extend the current time to the desired ending time you should only need to add the desired number of days.

 

Example:

Float CurrentTime = Utility.GetCurrentGameTime()
endtime1 = CurrentTime + 4

But you have the property GlobalDays which based on the comment text (even tho it is a direct copy from an example script on the wiki) leads me to believe that its value is 4 already as that should be the initial amount of time to complete the quest within.

Thus:

Float CurrentTime = Utility.GetCurrentGameTime()
endtime1 = CurrentTime + GlobalDays.GetValue() ;stored value is four days
endtime2 = CurrentTime + GlobalDays.GetValue() + 2.0 ;add two more to get six days total
endtime3 = CurrentTime + GlobalDays.GetValue() + 4.0 ;add four more to get eight days total

*************************************

As far as your update loop goes:

 

You are un-registering for the update after each enabling and re-registering within the first two updates. I am not sure why. Perhaps because you want to make sure that you can get to the 8th day if needed. You need some additional check to make sure this looping stops at the appropriate time and leaves the correct trigger enabled. Perhaps there is a quest stage that can be checked along with the timer? I cannot really make a suggestion as I do not know what else you have at your disposal within this quest. It may be a moot issue as the update will be unregistered automatically when the quest is stopped and whatever status the objects are in at that time should stick. But at first glance it does seem to want to keep going forever until the worst possible ending is achieved.

Link to comment
Share on other sites

Thanks, Ishara. I have been scripting using this register/unregister method to prevent game bloating and slow down from multiple loops running concurrently. At least that's how I thought it worked, but I'm not much of a scripter so I don't know for sure lol. You were correct in saying that this is how I am getting the script to loop continually in order for it to keep checking the conditions to make sure it is all up-to-date.

 

I'm going to be testing this after applying your suggestions and so far it is looking good. I got the "good" ending to show and all that was showing before was the "bad" ending no matter how many days passed. Thanks so much.

Link to comment
Share on other sites

like IsharaMeradin posted:

Utility.GetCurrentGameTime()

you could also use a formlist instead of three objectReference

 

CV2_EndingTimerQuestScript

 

Scriptname CV2_EndingTimerQuestScript extends Quest         ; CV2_EndingCountdownTimer
{should track the days spent in completing the quest}
; https://forums.nexusmods.com/index.php?/topic/7616318-scripted-endings-based-on-days-spent-completing-quest/
; jucoking wrote: "only ending trigger that calls is the last one (the "bad" ending), which is only supposed to call when 8 in-game days have passed."

  GlobalVariable PROPERTY GlobalDays  auto    ; initial days to complete
  FormList       PROPERTY TriggerList auto    ; Ending1Trig, Ending2Trig, Ending3Trig

  Float PROPERTY fTimer auto Hidden


; -- EVENTs -- 1 + "InitQuest" + "Waiting"

EVENT OnInit()
    gotoState("InitQuest")            ; ### STATE ###
    RegisterForSingleUpdateGameTime(0.0)
ENDEVENT


;===================================
state InitQuest
;==============
EVENT OnUpdateGameTime()
    myF_Init()
    gotoState("Waiting")            ; ### STATE ###
    RegisterForSingleUpdateGameTime(0.5)
ENDEVENT
;=======
endState


;===================================
state Waiting
;============
EVENT OnUpdateGameTime()
    myF_Update()
ENDEVENT
;=======
endState


; -- FUNCTIONs -- 2

;------------------
FUNCTION myF_Init()
;------------------
    ; 4 days minimum
    fTimer = GlobalDays.GetValue() + Utility.GetCurrentGameTime()        ; init the endTimer
ENDFUNCTION


;--------------------
FUNCTION myF_Update()
;--------------------
    float f = Utility.GetCurrentGameTime()
    int T

;IF    (f <= fTimer)                 ; 0 .. 4 days
;    T = -1

IF     (f <= fTimer + 2.0)           ; 0 .. 6 days
    T = 0                            ; Ending1Trig

ELSEIF (f <= fTimer + 4.0)           ; >6 .. 8 days
    T = 1                            ; Ending2Trig

ELSE                                 ; >8 days
    T = 2                            ; Ending3Trig
ENDIF
;    --------------------
    objectReference oRef

    int i = TriggerList.GetSize()
    WHILE (i)
        i = i - 1
        oRef = TriggerList.GetAt(i) as ObjectReference
        If (oRef) && !oRef.IsDisabled()
            oRef.Disable()                ; disable every trigger point, if needed
        ENDIF
    ENDWHILE
;    ---------------------
;IF (T >= 0)
    oRef = TriggerList.GetAt(T) as ObjectReference    ; We assume the first formlist entry is "Ending1Trig"!
    IF ( oRef )
        oRef.Enable()                    ; enable the current trigger after disabling anything
    ENDIF
;ENDIF
;    ---------------------
    IF (T < 2) && self.IsRunning()
        RegisterForSingleUpdateGameTime(0.5)
    ENDIF
ENDFUNCTION

 

 

Link to comment
Share on other sites

like IsharaMeradin posted:

Utility.GetCurrentGameTime()

you could also use a formlist instead of three objectReference

 

CV2_EndingTimerQuestScript

 

Scriptname CV2_EndingTimerQuestScript extends Quest         ; CV2_EndingCountdownTimer
{should track the days spent in completing the quest}
; https://forums.nexusmods.com/index.php?/topic/7616318-scripted-endings-based-on-days-spent-completing-quest/
; jucoking wrote: "only ending trigger that calls is the last one (the "bad" ending), which is only supposed to call when 8 in-game days have passed."

  GlobalVariable PROPERTY GlobalDays  auto    ; initial days to complete
  FormList       PROPERTY TriggerList auto    ; Ending1Trig, Ending2Trig, Ending3Trig

  Float PROPERTY fTimer auto Hidden


; -- EVENTs -- 1 + "InitQuest" + "Waiting"

EVENT OnInit()
    gotoState("InitQuest")            ; ### STATE ###
    RegisterForSingleUpdateGameTime(0.0)
ENDEVENT


;===================================
state InitQuest
;==============
EVENT OnUpdateGameTime()
    myF_Init()
    gotoState("Waiting")            ; ### STATE ###
    RegisterForSingleUpdateGameTime(0.5)
ENDEVENT
;=======
endState


;===================================
state Waiting
;============
EVENT OnUpdateGameTime()
    myF_Update()
ENDEVENT
;=======
endState


; -- FUNCTIONs -- 2

;------------------
FUNCTION myF_Init()
;------------------
    ; 4 days minimum
    fTimer = GlobalDays.GetValue() + Utility.GetCurrentGameTime()        ; init the endTimer
ENDFUNCTION


;--------------------
FUNCTION myF_Update()
;--------------------
    float f = Utility.GetCurrentGameTime()
    int T

;IF    (f <= fTimer)                 ; 0 .. 4 days
;    T = -1

IF     (f <= fTimer + 2.0)           ; 0 .. 6 days
    T = 0                            ; Ending1Trig

ELSEIF (f <= fTimer + 4.0)           ; >6 .. 8 days
    T = 1                            ; Ending2Trig

ELSE                                 ; >8 days
    T = 2                            ; Ending3Trig
ENDIF
;    --------------------
    objectReference oRef

    int i = TriggerList.GetSize()
    WHILE (i)
        i = i - 1
        oRef = TriggerList.GetAt(i) as ObjectReference
        If (oRef) && !oRef.IsDisabled()
            oRef.Disable()                ; disable every trigger point, if needed
        ENDIF
    ENDWHILE
;    ---------------------
;IF (T >= 0)
    oRef = TriggerList.GetAt(T) as ObjectReference    ; We assume the first formlist entry is "Ending1Trig"!
    IF ( oRef )
        oRef.Enable()                    ; enable the current trigger after disabling anything
    ENDIF
;ENDIF
;    ---------------------
    IF (T < 2) && self.IsRunning()
        RegisterForSingleUpdateGameTime(0.5)
    ENDIF
ENDFUNCTION

 

 

Ingenious, as usual, ReDragon. I do have one question about this script, though. To test, I am not able to use the "wait" function in-game because it messes with the timer. If I use your script and the FormList, would I be able to "wait" in-game in order to test for the different endings?

Link to comment
Share on other sites

  • Recently Browsing   0 members

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