Bucket Mouse
Active member
From the very beginning, NESMaker's UI has been designed for a day-night cycle. Two sets of four palettes are assigned to every screen, as well as four possible monster configurations (day, night, day triggered, and night triggered). But even though this stuff is there, you can't actually do anything with it. The game will ignore any commands related to "night" colors or monsters, even though it compiles data for them into the ROM anyway.
The reason it doesn't work is because it's only half-finished. Most of the variables and scripts to run this feature are already in the game -- they're just not hooked up. There is one key ingredient that's missing, but we'll get to it. Follow these directions and you can have a day and night cycle in your Adventure module game within minutes.
DOLOADSCREENDATA
In your Subroutines folder you can find a script called doLoadScreenData.asm. Make a copy of it. Then open the copy and find the line "GetScreenTriggerInfo." Higlight everything from that point up to the line that says "triggeredStateInfoIsLoaded." Then delete all that, and replace it with this:
Once you've done that, make a variable called "nightbyte." I tried many versions of this without an extra variable, but to no avail. Can't get around it.
Scroll down a bit until you find the line "JSR LoadMonster_1". Right above it, put this in:
Yes, that's all it takes. The script from this point onward is already prepped to handle night monster information. It just needs to be loaded with the correct variable in X. screenState is that variable, and it already exists -- it just wasn't written in. It offers four possibilities:
#$00 = day
#$01 = night
#$02 = day triggered
#$03 = night triggered
The current version of NESMaker uses screenState, but only loads it with #$00 or #$02. #$01 and#$03 wouldn't have done anything until now. We've patched in the extra lines to connect those functions and now your monsters will appear in their Night states and colors when the screen is triggered to do so.
To make sure the music also changes, make THIS alteration near the bottom, right where you see these lines:
LDY #178
LDA (collisionPointer),y
178 is the point where the music data for the day screen is stored. The night screen data is stored at #180, the triggered at #179 and the night + triggered at #181, so:
Now for the background palettes -- they have to change too. You can find doLoadBackgroundPalette.asm in your Subroutines folder. Make a copy of it and open the copy. This is actually sort of a macro, but it's not in the macro folder for some reason. Point is, you can patch in the commands to look up the unused night palettes with this. Delete everything in there and use this instead:
Time to attach your modified scripts to your game! It's gonna be a bit different this time. In NESMaker, go to Project Settings > Script Settings, go to the top of the list, find "Load Subroutines" and click Edit. Instead of being editable directly, the addresses for doLoadScreenData.asm and doLoadBackgroundPalette.asm are stored HERE. You will have to directly edit the addresses to redirect them to your modified files...sorry, I'm not the one who designed it this way.
Alternately you could just make a copy of NESMaker entirely and directly edit those two files instead of using copies of them...which for some people might be easier.
All that's needed now is a timer to command the screenState flag to night after a certain period of time, and then back to day. All timer programs are usually placed inside doHandleGameTimer.asm. Search for it and bring it up. Then paste all this into it:
Foertunately doHandleGameTimer has an address that you can change from Script Settings. Do that once you've made the changes to the copy.
HOW TO USE THE TIMER
The timer uses two time-related variables that already exist in NESMaker and are there for your timekeeping pleasure. It's possible that you might be using them already for something else. If this is the case, make up two new variables and use them in place of gameTimerHi and gameTimerLo...or you'll have problems.
A variable on the NES can only count to 255, and 255 frames isn't a very long time for a day-and-night cycle. So we use two, as an "hour" and "minute" hand. The minutes count down, subtract one of the hours and count down a new set of minutes. You get the idea.
gameTimerHi will load itself with the number 80. This means both day and night will last a minute (or precisely one minute and four seconds). If you want the time to last longer than that (you probably do), adjust the designated point in the script to 160 (two minutes) or 240 (three minutes). We're about to hit the 255 limit again, so we can't go higher, but three minutes is longer than you think. An average day in Ocarina of Time, from sunrise to sunset, is two minutes and thirty seconds.
You can also write your own timer script if this one isn't sufficient. By using a third variable, you could make the nights super-long.
IF YOU WANT TIME TO STOP IN SOME AREAS
If you want time to freeze under certain conditions -- like when you visit a town, or when you're in a cutscene -- use a Screen Flag. Put this at the beginning of your timer script:
Then flag the screens you want time to stop in.
IF YOU WANT THE NIGHT TO COME INSTANTANEOUSLY
Once day shifts to night, the change will happen upon your next screen load. But if you want the colors onscreen to instantly change when it hits night, I gave you a way to do that. Just uncomment the two instances of "LoadBackgroundPalettes" in the timer script. Poof, it's night! However the monsters will not change until you visit the next screen.
IF YOU WANT TO COMMAND THE NIGHT MANUALLY
Just don't use the timer. Skip that step and change screenState to #$01 another way -- via a tile, a monster AI, or whatever. You can also skip the palette-changing part and use the night function a different way, gaining two extra monster configurations for every screen. Then change them as events in your story shape the world!
The reason it doesn't work is because it's only half-finished. Most of the variables and scripts to run this feature are already in the game -- they're just not hooked up. There is one key ingredient that's missing, but we'll get to it. Follow these directions and you can have a day and night cycle in your Adventure module game within minutes.
DOLOADSCREENDATA
In your Subroutines folder you can find a script called doLoadScreenData.asm. Make a copy of it. Then open the copy and find the line "GetScreenTriggerInfo." Higlight everything from that point up to the line that says "triggeredStateInfoIsLoaded." Then delete all that, and replace it with this:
Code:
GetScreenTriggerInfo:
JSR doClearAllMonsters
;;;;; MONSTERS
;;; constants for banks
GetTrigger
;; result of screenType trigger stored in temp3 and also in accum
;; x and y restored.
BEQ thisScreenIsNotTriggered
;; this screen IS triggered
LDA nightbyte
CMP #$01
BNE isTriggeredDay
;; triggered and night
LDA #$03
STA screenState
JMP triggeredStateInfoIsLoaded
isTriggeredDay
; triggered and day
LDA #$02
STA screenState
JMP triggeredStateInfoIsLoaded
;;=================================
thisScreenIsNotTriggered
LDA nightbyte
CMP #$01
BNE isNormalDay
;; normal and night
LDA #$01
STA screenState
isNormalDay:
; normal and day
LDA #$00
STA screenState
triggeredStateInfoIsLoaded:
LDX screenState ;; activates night text group
Once you've done that, make a variable called "nightbyte." I tried many versions of this without an extra variable, but to no avail. Can't get around it.
Scroll down a bit until you find the line "JSR LoadMonster_1". Right above it, put this in:
Code:
LDX screenState ;; activates night placements for monsters
Yes, that's all it takes. The script from this point onward is already prepped to handle night monster information. It just needs to be loaded with the correct variable in X. screenState is that variable, and it already exists -- it just wasn't written in. It offers four possibilities:
#$00 = day
#$01 = night
#$02 = day triggered
#$03 = night triggered
The current version of NESMaker uses screenState, but only loads it with #$00 or #$02. #$01 and#$03 wouldn't have done anything until now. We've patched in the extra lines to connect those functions and now your monsters will appear in their Night states and colors when the screen is triggered to do so.
To make sure the music also changes, make THIS alteration near the bottom, right where you see these lines:
LDY #178
LDA (collisionPointer),y
178 is the point where the music data for the day screen is stored. The night screen data is stored at #180, the triggered at #179 and the night + triggered at #181, so:
Code:
LDA screenState
CMP #$01
BEQ +night
CMP #$02
BEQ +triggered
CMP #$03
BEQ +nighttriggered
LDY #178 ; normal music
JMP +
+night:
LDY #180 ; night music
JMP +
+triggered:
LDY #179 ; triggered music
JMP +
nighttriggered:
LDY #181 ; night triggered music
+
LDA (collisionPointer),y
Now for the background palettes -- they have to change too. You can find doLoadBackgroundPalette.asm in your Subroutines folder. Make a copy of it and open the copy. This is actually sort of a macro, but it's not in the macro folder for some reason. Point is, you can patch in the commands to look up the unused night palettes with this. Delete everything in there and use this instead:
Code:
doLoadBackgroundPalettes:
;; This is tied to the macro LoadBackgroundPalettes.
;; It uses bank and 16 bit label.
TXA
PHA
TYA
PHA
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Get Palette Label based on INDEX
SwitchBank #$16
LDY arg0_hold
LDA GameBckPalLo,y
STA temp16
LDA GameBckPalHi,y
STA temp16+1
LDA screenState
CMP #$00 ; not night
BEQ +
CMP #$02 ; not night either
BEQ +
LDY #$20 ; to load the night palettes, Y must be shifted forward by 32 (20 in hex)
JMP +night
+
LDY #$20 ; to load the night palettes, Y must be shifted forward by 32 (20 in hex)
JMP +night
+
LDY #$00
+night
LDX #$00
loop_LoadBackgroundPalette:
LDA (temp16),y
STA bckPal,x
INY
INX
CPX #$10
BNE loop_LoadBackgroundPalette
;;;; end of loop.
LDA updateScreenData
ORA #%00000001 ;; palette
STA updateScreenData
ReturnBank
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
PLA
TAY
PLA
TAX
RTS
Time to attach your modified scripts to your game! It's gonna be a bit different this time. In NESMaker, go to Project Settings > Script Settings, go to the top of the list, find "Load Subroutines" and click Edit. Instead of being editable directly, the addresses for doLoadScreenData.asm and doLoadBackgroundPalette.asm are stored HERE. You will have to directly edit the addresses to redirect them to your modified files...sorry, I'm not the one who designed it this way.
Alternately you could just make a copy of NESMaker entirely and directly edit those two files instead of using copies of them...which for some people might be easier.
All that's needed now is a timer to command the screenState flag to night after a certain period of time, and then back to day. All timer programs are usually placed inside doHandleGameTimer.asm. Search for it and bring it up. Then paste all this into it:
Code:
LDA gameTimerHi
BEQ +resethi
CMP #40 ; this should be exactly half of your total time
BEQ +hihalfway
LDA gameTimerLo
BEQ +resetlo ; if lo number reaches zero, this decreases hi number
DEC gameTimerLo ; otherwise, it decreases the lo digit then cycles again
JMP +
+resetlo:
DEC gameTimerHi
LDA #100 ; the low mumber counts this number of frames, then decreases the high number by 1
STA gameTimerLo
JMP +
+resethi
LDA #80 ; enter the amount of time you want between night and day here
STA gameTimerHi
LDA #$00
STA screenState
; LoadBackgroundPalettes newPal
LDA #$01
STA updateScreenData
JMP +
+hihalfway
DEC gameTimerHi
LDA #$01
STA screenState
; LoadBackgroundPalettes newPal
LDA #$01
STA updateScreenData
+
Foertunately doHandleGameTimer has an address that you can change from Script Settings. Do that once you've made the changes to the copy.
HOW TO USE THE TIMER
The timer uses two time-related variables that already exist in NESMaker and are there for your timekeeping pleasure. It's possible that you might be using them already for something else. If this is the case, make up two new variables and use them in place of gameTimerHi and gameTimerLo...or you'll have problems.
A variable on the NES can only count to 255, and 255 frames isn't a very long time for a day-and-night cycle. So we use two, as an "hour" and "minute" hand. The minutes count down, subtract one of the hours and count down a new set of minutes. You get the idea.
gameTimerHi will load itself with the number 80. This means both day and night will last a minute (or precisely one minute and four seconds). If you want the time to last longer than that (you probably do), adjust the designated point in the script to 160 (two minutes) or 240 (three minutes). We're about to hit the 255 limit again, so we can't go higher, but three minutes is longer than you think. An average day in Ocarina of Time, from sunrise to sunset, is two minutes and thirty seconds.
You can also write your own timer script if this one isn't sufficient. By using a third variable, you could make the nights super-long.
IF YOU WANT TIME TO STOP IN SOME AREAS
If you want time to freeze under certain conditions -- like when you visit a town, or when you're in a cutscene -- use a Screen Flag. Put this at the beginning of your timer script:
Code:
LDA ScreenFlags00 ; change to 01 if your first row of screen flags is taken up
AND #%01000000 ; the 1 in this row will correspond to the flag you want to use -- change as desired
BEQ +notflagged
JMP +
+notflagged
Then flag the screens you want time to stop in.
IF YOU WANT THE NIGHT TO COME INSTANTANEOUSLY
Once day shifts to night, the change will happen upon your next screen load. But if you want the colors onscreen to instantly change when it hits night, I gave you a way to do that. Just uncomment the two instances of "LoadBackgroundPalettes" in the timer script. Poof, it's night! However the monsters will not change until you visit the next screen.
IF YOU WANT TO COMMAND THE NIGHT MANUALLY
Just don't use the timer. Skip that step and change screenState to #$01 another way -- via a tile, a monster AI, or whatever. You can also skip the palette-changing part and use the night function a different way, gaining two extra monster configurations for every screen. Then change them as events in your story shape the world!
Last edited: