Countdown Timer WORKING

Retrobuster

New member
Hey everyone,

This is the updated and fully working version of the script needed to make a mario style countdown timer in your HUD that ticks once a second (or whatever rate you want it to), spawns the PlayerDeath object instead of simply resetting the game, AND resets inbetween screens. I used this for a single screen maze game so I don't know how it'd work on a scrolling game or an adventure game, but it works perfectly for this purpose.

Firstly, though, I need to shout out to Justin Francoeur, Dale Coop, Kevin Skeen, Mugi, and whoever else may've been involved with the making of this process. I pretty much did nothing but ask for a bunch of help. They all figured this out and I compiled it from a few threads from this forum and from Facebook. So give them a big round of applause for figuring all this out!

Step 1: Create a new HandleGameTimer.asm script from this code and load it into your project through the Script Settings.

Code:
;; create a variable in your HUD called myTimer 
;; set the initial value for myTimer from your HUD 
;; myTimer needs to have a max value of 3
;; this script was used for NESMAKER 4.1.1 and calls the SubtractValue macro
;; make sure that SubtractValue is the *proper* version
;; This script wouldn't be possible without Kevin Skeen's Timer_Tick.asm script
;; Thank you for everything, Kevin Skeen!


HandleGameTimer:

DEC gameTimer ;decrement memory by one


BNE dontUpdateGameTimer ;if gameTimer = 0, don't update
LDA gameTimerLo ;load gameTimerLo into accumulator
CLC ;clear the carry flag
ADC #$01 ;add 01 to acumulator with carry
STA gameTimerLo ;store to the accumlator
LDA gameTimerHi ;load gameTimerHi into accumulator
ADC #$00 ;add 00 to acumulator with carry
STA gameTimerHi ;store to the accumlator
;;;;;;;;;;;;;;;;;;;;;;;;;;; 
;; DO WHATEVER READS OF THE GAMETIMER YOU MIGHT WANT HERE.
LDA #DayNightSpeed
STA gameTimer


LDX #$02 ;;Checking Hundreds
LDA myTimer,x ;;Load Hundreds Digit
BNE SubtractTime ;;If not 0, we have more than 000
DEX ;;Checking Tens -- Decrease x so x is 1
LDA myTimer,x ;;Load Tens Digit
BNE SubtractTime ;;If not 0, we have more than 000
DEX ;;Checking Tens 
LDA myTimer,x ;;Load Ones Digit
BNE SubtractTime
JMP RESET


;;;;;;;;;;;;;;;;;;;;;;;;;;;



dontUpdateGameTimer:
RTS


SubtractTime:

SubtractValue #$03, myTimer, #$01, #$00 ;;Subtract 1 from the Ones digit


;;Update HUD
LDA #$03 ;; your timer can only have max 3 numbers
STA hudElementTilesToLoad
LDA DrawHudBytes
ORA #HUD_myTimer
STA DrawHudBytes
RTS



DoAlarm:

;;; we're going to edge-load monsters one at a time if they are of edge type and are not active.
LDX #$00
doLoadMonsterOnTimerLoop:

LDA edgeLoaderInCue
BEQ noEdgeMonstersInCue
LDA currentBank
STA prevBank
LDY #$1C ;; data bank
JSR bankswitchY
JSR CreateTimedEdgeSpawner
DEC edgeLoaderInCue
LDY prevBank
JSR bankswitchY

noEdgeMonstersInCue
RTS

Step 2: Go to Project->Info and change the Day/Night Cycle Speed to 60 to make it tick once every second. This is where you can control how often the timer ticks.

Step 3: Modify your HandleScreenLoads.asm script by inserting this code near the beginning just after the ";;;;;;;;;;;; SET SCREENS RELATIVE TO THE SCREEN TO BE LOADED" comment.
Code:
 ;; reset my timer;
  LDA #$06
  STA myTimer+1
  LDA #$00
  STA myTimer

That should do it!
 

Mugi

Member
this is exaclt why i keep telling everyone that facebook is not a place for game development....

well anyway, this was posted on facebook and got lost in the shit just like everything else in facebook... fortunately i still had the link.

I dont know who wrote it, if someone does, please credit them accordingly.

Code:
;; create a variable in your HUD called myTimer 
;; set the initial value for myTimer from your HUD 
;; myTimer needs to have a max value of 3
;; this script was used for NESMAKER 4.1.1 and calls the SubtractValue macro
;; make sure that SubtractValue is the *proper* version
;; This script wouldn't be possible without Kevin Skeen's Timer_Tick.asm script
;; Thank you for everything, Kevin Skeen!


HandleGameTimer:
    
    DEC gameTimer           ;decrement memory by one
    
    
    BNE dontUpdateGameTimer ;if gameTimer = 0, don't update
    LDA gameTimerLo         ;load gameTimerLo into accumulator
    CLC                     ;clear the carry flag
    ADC #$01                ;add 01 to acumulator with carry
    STA gameTimerLo         ;store to the accumlator
    LDA gameTimerHi         ;load gameTimerHi into accumulator
    ADC #$00                ;add 00 to acumulator with carry
    STA gameTimerHi         ;store to the accumlator
;;;;;;;;;;;;;;;;;;;;;;;;;;; 
    ;; DO WHATEVER READS OF THE GAMETIMER YOU MIGHT WANT HERE.
    LDA #DayNightSpeed
    STA gameTimer
    
    clc
    lda mySeconds
    jsr SubtractSeconds
    
    ;;do the same for minutes
    ;;kinda wasteful but dunno how to do it better.
    ;ldx #$01
    ;JMP RESET            ;;this is what happens when the time is zero
    
   
    
;;;;;;;;;;;;;;;;;;;;;;;;;;;
    

    
    dontUpdateGameTimer:
    RTS
    
    
SubtractSeconds:
sbc #1
sta mySeconds
bcs SubtractMinutes
UpdateHud mySeconds
rts

SubtractMinutes:
clc
lda #59
sta mySeconds
clc
lda myMinutes
sbc #1
bcs RESET ; resets the game if time goes to 0
sta myMinutes
UpdateHud mySeconds
UpdateHud myMinutes
rts
    
DoAlarm:
    
    ;;; we're going to edge-load monsters one at a time if they are of edge type and are not active.
    LDX #$00
doLoadMonsterOnTimerLoop:

    LDA edgeLoaderInCue
    BEQ noEdgeMonstersInCue
    LDA currentBank
    STA prevBank
    LDY #$1C ;; data bank
    JSR bankswitchY
    JSR CreateTimedEdgeSpawner
    DEC edgeLoaderInCue
    LDY prevBank
    JSR bankswitchY

noEdgeMonstersInCue
    RTS
 

Retrobuster

New member
Great! Thank you so much! I agree, some thing like this - a finished script - should be posted into the forums! Thanks Mugi! I changed the subject line to remove the "?" so people know this script is in here.
 

dale_coop

Moderator
Staff member
Agree with Mugi, on that!!!! I hate Facebook for that, we always loose everything. I keep saying post on the forum, ask on the forum, share on the forum...
I hate FB >_<

Anyway... another version of the same script, posted on FB:

Code:
;; create a variable in your HUD called myTimer 
;; set the initial value for myTimer from your HUD 
;; myTimer needs to have a max value of 3
;; this script was used for NESMAKER 4.1.1 and calls the SubtractValue macro
;; make sure that SubtractValue is the *proper* version
;; This script wouldn't be possible without Kevin Skeen's Timer_Tick.asm script
;; Thank you for everything, Kevin Skeen!


HandleGameTimer:
    
    DEC gameTimer           ;decrement memory by one
    
    
    BNE dontUpdateGameTimer ;if gameTimer = 0, don't update
    LDA gameTimerLo         ;load gameTimerLo into accumulator
    CLC                     ;clear the carry flag
    ADC #$01                ;add 01 to acumulator with carry
    STA gameTimerLo         ;store to the accumlator
    LDA gameTimerHi         ;load gameTimerHi into accumulator
    ADC #$00                ;add 00 to acumulator with carry
    STA gameTimerHi         ;store to the accumlator
;;;;;;;;;;;;;;;;;;;;;;;;;;; 
    ;; DO WHATEVER READS OF THE GAMETIMER YOU MIGHT WANT HERE.
    
    
    
    LDX #$02                ;;Checking Hundreds
    LDA myTimer,x           ;;Load Hundreds Digit
    BNE SubtractTime        ;;If not 0, we have more than 000
    DEX                     ;;Checking Tens -- Decrease x so x is 1
    LDA myTimer,x           ;;Load Tens Digit
    BNE SubtractTime        ;;If not 0, we have more than 000
    DEX         	    ;;Checking Tens 
    LDA myTimer,x           ;;Load Ones Digit
    BNE SubtractTime
    JMP RESET            ;;this is what happens when the time is zero
    
   
    
;;;;;;;;;;;;;;;;;;;;;;;;;;;
    LDA #DayNightSpeed
    STA gameTimer

    
    dontUpdateGameTimer:
    RTS
    
    
SubtractTime:

SubtractValue #$03, myTimer, #$01, #$00 ;;Subtract 1 from the Ones digit
    

    ;;Update HUD
    LDA #$03                    ;; your timer can only have max 3 numbers
    STA hudElementTilesToLoad
    LDA DrawHudBytes
    ORA #HUD_myTimer
    STA DrawHudBytes
    RTS


    
DoAlarm:
    
    ;;; we're going to edge-load monsters one at a time if they are of edge type and are not active.
    LDX #$00
doLoadMonsterOnTimerLoop:

    LDA edgeLoaderInCue
    BEQ noEdgeMonstersInCue
    LDA currentBank
    STA prevBank
    LDY #$1C ;; data bank
    JSR bankswitchY
    JSR CreateTimedEdgeSpawner
    DEC edgeLoaderInCue
    LDY prevBank
    JSR bankswitchY

noEdgeMonstersInCue
    RTS
 

Retrobuster

New member
So this works, but like a previous script I found, it only ticks every 5 or so seconds. Is there a way to speed that up to be in real time? As a workaround, I just set the amount it subtracts by to 5 so that it evens out for the most part, but I'd prefer it ticking every second. Any advice?

Also, in a single screen, maze game - how would I go about resetting the timer after completing each screen?
 

Retrobuster

New member
NEVERMIND! Found the post on Facebook and the solution was already there. The correct code is:

;; create a variable in your HUD called myTimer
;; set the initial value for myTimer from your HUD
;; myTimer needs to have a max value of 3
;; this script was used for NESMAKER 4.1.1 and calls the SubtractValue macro
;; make sure that SubtractValue is the *proper* version
;; This script wouldn't be possible without Kevin Skeen's Timer_Tick.asm script
;; Thank you for everything, Kevin Skeen!


HandleGameTimer:

DEC gameTimer ;decrement memory by one


BNE dontUpdateGameTimer ;if gameTimer = 0, don't update
LDA gameTimerLo ;load gameTimerLo into accumulator
CLC ;clear the carry flag
ADC #$01 ;add 01 to acumulator with carry
STA gameTimerLo ;store to the accumlator
LDA gameTimerHi ;load gameTimerHi into accumulator
ADC #$00 ;add 00 to acumulator with carry
STA gameTimerHi ;store to the accumlator
;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; DO WHATEVER READS OF THE GAMETIMER YOU MIGHT WANT HERE.
LDA #DayNightSpeed
STA gameTimer


LDX #$02 ;;Checking Hundreds
LDA myTimer,x ;;Load Hundreds Digit
BNE SubtractTime ;;If not 0, we have more than 000
DEX ;;Checking Tens -- Decrease x so x is 1
LDA myTimer,x ;;Load Tens Digit
BNE SubtractTime ;;If not 0, we have more than 000
DEX ;;Checking Tens
LDA myTimer,x ;;Load Ones Digit
BNE SubtractTime
JMP RESET


;;;;;;;;;;;;;;;;;;;;;;;;;;;



dontUpdateGameTimer:
RTS


SubtractTime:

SubtractValue #$03, myTimer, #$01, #$00 ;;Subtract 1 from the Ones digit


;;Update HUD
LDA #$03 ;; your timer can only have max 3 numbers
STA hudElementTilesToLoad
LDA DrawHudBytes
ORA #HUD_myTimer
STA DrawHudBytes
RTS



DoAlarm:

;;; we're going to edge-load monsters one at a time if they are of edge type and are not active.
LDX #$00
doLoadMonsterOnTimerLoop:

LDA edgeLoaderInCue
BEQ noEdgeMonstersInCue
LDA currentBank
STA prevBank
LDY #$1C ;; data bank
JSR bankswitchY
JSR CreateTimedEdgeSpawner
DEC edgeLoaderInCue
LDY prevBank
JSR bankswitchY

noEdgeMonstersInCue
RTS

THEN, you go to Project->Info and change the Day/Night Cycle Speed to 60 and it ticks once every second! I still haven't figured out how to get the timer to reset in between screens though. Hmmm...
 
Having it reset between screens seems like a cool option. I have an idea for a game that I might pursue (don't want to get too sidetracked though) that could definitely make use of this feature.
 

Retrobuster

New member
Dale's helping me with that feature. To me, that seems like a necessity. If you're going to have a timer in your HUD, it's got to be able to be reset in between levels. He's already figured out how to make the script call the PlayerDeath object instead of just immediately resetting the game which was an easy fix that has actually taught me something important about how the code works overall. Just replace the JMP RESET with JMP HandlePlayerDeath.

Once the resetting timer thing gets fixed, I'm going to delete this thread and post a new one with that code and how to implement it into a game since it'll feel pretty complete at that point.
 
Can this code be manipulated to work as a metroid timer that once you get the end end you win or timer expires yiu die rest from check point. But can this be done out resetting everytime you go to a new screen if used in an adventure base game? O the timer would only need to be trigger on Certain screens
 

Retrobuster

New member
If I understand what you're asking, as of now, that timer doesn't reset when going to a new screen. So, I could set the timer to 999 seconds and it will keep counting down no matter what screen you're on. 999 seconds is roughly 16.5 minutes though so wouldn't make for a very long game. :)
 

Bucket Mouse

Active member
Retrobuster said:
Hey everyone,

This is the updated and fully working version of the script needed to make a mario style countdown timer in your HUD that ticks once a second (or whatever rate you want it to), spawns the PlayerDeath object instead of simply resetting the game, AND resets inbetween screens.

This code does NOT make the player lose a life when it goes to zero. It simply resets.

The main problem is the JMP RESET at the end of this part:

Code:
LDX #$02 ;;Checking Hundreds
LDA myTimer,x ;;Load Hundreds Digit
BNE SubtractTime ;;If not 0, we have more than 000
DEX ;;Checking Tens -- Decrease x so x is 1
LDA myTimer,x ;;Load Tens Digit
BNE SubtractTime ;;If not 0, we have more than 000
DEX ;;Checking Tens 
LDA myTimer,x ;;Load Ones Digit
BNE SubtractTime
JMP RESET

I changed it to JSR PlayerLoseLife and added a tag to the front of that script, and then a "RTS" at the end of it.....but that just made the player instantly die the second the next screen loaded, and on until all the lives were gone.

How do I fix this?
 

dale_coop

Moderator
Staff member
Like you said, I would just replace the "JMP RESET" line with a "JSR PlayerLoseLife" :

Code:
;; create a variable in your HUD called myTimer 
;; set the initial value for myTimer from your HUD 
;; myTimer needs to have a max value of 3
;; this script was used for NESMAKER 4.1.1 and calls the SubtractValue macro
;; make sure that SubtractValue is the *proper* version
;; This script wouldn't be possible without Kevin Skeen's Timer_Tick.asm script
;; Thank you for everything, Kevin Skeen!


HandleGameTimer:

DEC gameTimer ;decrement memory by one


BNE dontUpdateGameTimer ;if gameTimer = 0, don't update
LDA gameTimerLo ;load gameTimerLo into accumulator
CLC ;clear the carry flag
ADC #$01 ;add 01 to acumulator with carry
STA gameTimerLo ;store to the accumlator
LDA gameTimerHi ;load gameTimerHi into accumulator
ADC #$00 ;add 00 to acumulator with carry
STA gameTimerHi ;store to the accumlator
;;;;;;;;;;;;;;;;;;;;;;;;;;; 
;; DO WHATEVER READS OF THE GAMETIMER YOU MIGHT WANT HERE.
LDA #DayNightSpeed
STA gameTimer


LDX #$02 ;;Checking Hundreds
LDA myTimer,x ;;Load Hundreds Digit
BNE SubtractTime ;;If not 0, we have more than 000
DEX ;;Checking Tens -- Decrease x so x is 1
LDA myTimer,x ;;Load Tens Digit
BNE SubtractTime ;;If not 0, we have more than 000
DEX ;;Checking Tens 
LDA myTimer,x ;;Load Ones Digit
BNE SubtractTime
JSR PlayerLoseLife


;;;;;;;;;;;;;;;;;;;;;;;;;;;



dontUpdateGameTimer:
RTS


SubtractTime:

SubtractValue #$03, myTimer, #$01, #$00 ;;Subtract 1 from the Ones digit


;;Update HUD
LDA #$03 ;; your timer can only have max 3 numbers
STA hudElementTilesToLoad
LDA DrawHudBytes
ORA #HUD_myTimer
STA DrawHudBytes
RTS



DoAlarm:

;;; we're going to edge-load monsters one at a time if they are of edge type and are not active.
LDX #$00
doLoadMonsterOnTimerLoop:

LDA edgeLoaderInCue
BEQ noEdgeMonstersInCue
LDA currentBank
STA prevBank
LDY #$1C ;; data bank
JSR bankswitchY
JSR CreateTimedEdgeSpawner
DEC edgeLoaderInCue
LDY prevBank
JSR bankswitchY

noEdgeMonstersInCue
RTS


And (here might be your current issue) don't forget the Step 3 on the original post (to reset 60 seconds to your timer when a screen is loaded).
 

Bucket Mouse

Active member
dale_coop said:
And (here might be your current issue) don't forget the Step 3 on the original post (to reset 60 seconds to your timer when a screen is loaded).

You were correct.....I forgot that third step. Now there are no issues....except for the fact that Step 3 actually overwrites the value you set in the HUD menu. So if you set the value to 50 seconds (like I did) and the code here is wired for 60 seconds (like it is) then 60 seconds is what you'll get.

It's not THAT huge a problem.....I just have to change the timer manually now. LDA #$05 puts it back at 50; LDA #$08 gives you eighty seconds, etc.
 

Bucket Mouse

Active member
dale_coop said:
Yep exactly... on the OP the script was for 60 seconds ;)

Here's a new bug...the timer just keeps going no matter what happens, even when a text box is on screen, or the sprite is doing its victory animation. Imagine beating a screen only to have the time run out while the animation is playing, causing you to lose a life. This has to be fixed.

I put this at the beginning of HandleGameTimer, but it does not work:

Code:
        LDA textboxHandler
        CMP #%10000000 ; checks to see if the text box is on
        BNE dontUpdateGameTimer
        
        LDA player1_object
        CMP #$10 ; compares to tenth Game Object, which is the Victory animation
        BNE dontUpdateGameTimer

I thought this was right for sure, but it just prevents the timer from working at all. Changing the BNE to BEQ isn't the solution either -- that's like doing nothing; the timer continues to run.
Someday I'll be good enough to write my own code but today isn't the day. What am I missing?
 

dale_coop

Moderator
Staff member
It's not a bug... more a design issue.
You are on the right path... your code is almost correct, you could try this:

Code:
	; checks to see if the text box is on	
	LDA gameHandler
	AND #%00100000
	BNE dontUpdateGameTimer
	
        LDA player1_object
        CMP #$FF ; player is no more... because destroyed and been replaced by the tenth Game Object, which is the Victory animation
        BEQ dontUpdateGameTimer
 

Bucket Mouse

Active member
Okay, that stops the timer during the text.....but it's still going during Victory. I don't know why FF is what we're comparing player1 to...what does FF represent?

If it's checking to see if the player isn't there, shouldn't the number be 00 instead? Of course, that doesn't work either.
 
Top Bottom