chronicleroflegends
Member
Hello everyone!
I have seen a lot of people starting to running out of the limited space they have available for code in bank 14.
I ran into this issue as well, but thanks to a huge amount of help from Kasumi I have an extremely effective workaround.
Warning: this is a long read and an advanced topic.
You might use this if you want:
More complicated code for player movement and controls
More complicated / varied monster AI
You keep running into overflow on bank 14 and you need a bit more space.
This method will get you a -TON- more space. An entire extra 16kb bank full at minimum.
It will cost a small amount of space in the static bank for every subroutine created.
Before you go further though, understand a few things:
-This is going to be an advanced look at nesmaker scripting, and you will be modifying where nesmaker stores things. Before continuing please make sure you understand how to
make and use a subroutine. PLEASE PLEASE make a backup, because this can break your entire project if you get something wrong.
-I'm hesitant to share this so close to the release of the new version of Nesmaker, because some of this won't be
valid anymore. This tutorial is strictly for games using the 4.1.5 version of Nesmaker. It is intended to help those
not planning to update to finish their games.
Ok, with that out of the way, a quick primer on the concept of what is happening:
Our Nesmaker games have their data stored in various banks. Some have gameplay logic code, some have graphics, some have text, etc.
At any one time, we have two of these banks loaded into memory: The static bank, and the swappable bank. The static bank contains
code that must be accessible at -all- times and as such is always loaded into memory. To access the rest of the memory, the swappable
bank is constantly being changed.
Most of the scripting you guys have been doing, with character movement and monster ai is all limited to bank 14, which contains most
of the game code. In order to have more space than just bank 14 you need to swap out of bank 14 to another bank. But here is where the
difficulty happens. Everything runs linearly on the NES. If you try and swap to another bank from bank 14, all you are going to do is
crash the game. This means that any code that moves from one bank to another one -must- be in the static bank.
Whats more, the way bank swapping is done, only the previous bank visited can be remembered. If you bank swap more than once without
returning to the original bank, you will lose the data you need to get back to where you started and the game will crash.
Almost all issues you will run into when tinkering with this is that the path back to the correct bank will be lost.
So how do you move over into the static bank from where you are in bank 14, and how do you make sure you can get back to the bank you started from?
I used a method that I called 'bank boomerangs'.
It combines using subroutines and bank switching to reach out to another bank, execute a block of code, and return right back to where you left from.
Here comes the actual tutorial:
==== Step 1 ====
Create a new script in GameEngineData>Routines>YourModule>InitializationScripts called
'bankBoomerangs.asm'
replace 'YourModule' with the actual module you are using.
Copy and paste this code into the script:
You are done with that one for now. It won't do anything yet but it gives you a framework
to work with.
Now go to the nesmaker editor> project settings>script settings and add a new script define:
Name: Bank Boomerangs
Define: SCR_BANK_BOOMERANGS
Script: Routines\YourModule\InitializationScripts\bankBoomerangs.asm
- replace YourModule with the actual module you are using.
This will let you edit the script from within nesmaker.
==== Step 2 ====
Now open up this script:
GameEngineData>Routines>YourModule>MainASM.asm
-replace YourModule with the actual module you are using.
This script is the main game loop, and the code that is loaded in the static bank.
This is where you are going to link the new script you created.
Scroll down or search for this line: '.include "GameData\HUD_DEFINES.dat"'
add one line here:
==== Step 3 ====
Ok, now you have the tools necessary to access other banks from your code bank.
Now we need to actually get some stuff in the other banks!
I recommend using bank 18, because it is completely empty! Pick wherever you want (as long as there isn't already something there), but the rest of this tutorial will be assuming you are using bank 18.
First you will need something to put there. Lets create a script that simply resets
the game.
Create a new script somewhere, I have a 'custom' folder inside my routines folder.
name it 'test.asm'
inside the script make this simple subroutine:
Now go to the nesmaker editor> project settings>script settings and add a new script define:
Name: Test Subroutine
Define: SCR_TEST_SUBROUTINE
Script: PATHTOYOURTESTSCRIPT\test.asm
- replace PATHTOYOURTESTSCRIPT with the actual address to your script.
We need the script defined in order to put it in bank 18.
Go to GameEndineData>Routines>YourModule>BankData and open the script Bank18.asm
it should be empty. If for some reason it isn't you may want to find one that is.
anyways add this line:
Ok, now you actually have something in Bank 18!
Now how to actually call that code from over in bank 14?
You need to go back and edit your bankBoomerangs.asm script one more time.
Add this block of code after ;; === ADD BOOMERANGS HERE ===
What this does is creates a link between bank 14 and bank 18 through the static bank.
Now, in bank 14 you can call:
'JSR boomerang_test'
and it will run testSubroutine_reset in bank 18.
Congratulations! You now have all the tools in place that you will need.
From here, what should you do to take advantage of this?
-You can get rid of the script for test.asm and the code to access it, it was just
to teach you how to use it.
-Add any scripts that you want to bank 18 in the same way you added test.asm
-I included the template at the top of bankBoomerangs.asm so that you can easily copy and paste it when you need access. You will need to create a separate 'boomerang' in this file for each subroutine you want to access in bank 18.
-Scripts you add in this way ABSOLUTELY MUST be designed as subroutines. This is because
it depends on using RTS to get back to the static bank when you have finished. You can
create and call new subroutines inside of bank 18 as long as they always return correctly.
If you have any further questions I will try and answer them.
I have seen a lot of people starting to running out of the limited space they have available for code in bank 14.
I ran into this issue as well, but thanks to a huge amount of help from Kasumi I have an extremely effective workaround.
Warning: this is a long read and an advanced topic.
You might use this if you want:
More complicated code for player movement and controls
More complicated / varied monster AI
You keep running into overflow on bank 14 and you need a bit more space.
This method will get you a -TON- more space. An entire extra 16kb bank full at minimum.
It will cost a small amount of space in the static bank for every subroutine created.
Before you go further though, understand a few things:
-This is going to be an advanced look at nesmaker scripting, and you will be modifying where nesmaker stores things. Before continuing please make sure you understand how to
make and use a subroutine. PLEASE PLEASE make a backup, because this can break your entire project if you get something wrong.
-I'm hesitant to share this so close to the release of the new version of Nesmaker, because some of this won't be
valid anymore. This tutorial is strictly for games using the 4.1.5 version of Nesmaker. It is intended to help those
not planning to update to finish their games.
Ok, with that out of the way, a quick primer on the concept of what is happening:
Our Nesmaker games have their data stored in various banks. Some have gameplay logic code, some have graphics, some have text, etc.
At any one time, we have two of these banks loaded into memory: The static bank, and the swappable bank. The static bank contains
code that must be accessible at -all- times and as such is always loaded into memory. To access the rest of the memory, the swappable
bank is constantly being changed.
Most of the scripting you guys have been doing, with character movement and monster ai is all limited to bank 14, which contains most
of the game code. In order to have more space than just bank 14 you need to swap out of bank 14 to another bank. But here is where the
difficulty happens. Everything runs linearly on the NES. If you try and swap to another bank from bank 14, all you are going to do is
crash the game. This means that any code that moves from one bank to another one -must- be in the static bank.
Whats more, the way bank swapping is done, only the previous bank visited can be remembered. If you bank swap more than once without
returning to the original bank, you will lose the data you need to get back to where you started and the game will crash.
Almost all issues you will run into when tinkering with this is that the path back to the correct bank will be lost.
So how do you move over into the static bank from where you are in bank 14, and how do you make sure you can get back to the bank you started from?
I used a method that I called 'bank boomerangs'.
It combines using subroutines and bank switching to reach out to another bank, execute a block of code, and return right back to where you left from.
Here comes the actual tutorial:
==== Step 1 ====
Create a new script in GameEngineData>Routines>YourModule>InitializationScripts called
'bankBoomerangs.asm'
replace 'YourModule' with the actual module you are using.
Copy and paste this code into the script:
Code:
;; Boomerang template: ---------------------
;;boomerang_subroutineName:
;;; Change to bank BANKNUM
;LDA currentBank
;STA prevBank
;LDY #$BANKNUM ;; Bank to use
;JSR bankswitchY
;;; Call the subroutine
;JSR subroutineName
;;; Return to the previous bank
;LDY prevBank ;; Bank we came from
;JSR bankswitchY
;RTS
;; ----------------------------------------
JMP skipBoomerangs ;; Make the subroutines callable.
;; === ADD BOOMERANGS HERE ===
;; ===========================
skipBoomerangs: ;; end of script
You are done with that one for now. It won't do anything yet but it gives you a framework
to work with.
Now go to the nesmaker editor> project settings>script settings and add a new script define:
Name: Bank Boomerangs
Define: SCR_BANK_BOOMERANGS
Script: Routines\YourModule\InitializationScripts\bankBoomerangs.asm
- replace YourModule with the actual module you are using.
This will let you edit the script from within nesmaker.
==== Step 2 ====
Now open up this script:
GameEngineData>Routines>YourModule>MainASM.asm
-replace YourModule with the actual module you are using.
This script is the main game loop, and the code that is loaded in the static bank.
This is where you are going to link the new script you created.
Scroll down or search for this line: '.include "GameData\HUD_DEFINES.dat"'
add one line here:
Code:
.include ROOT\InitializationScripts\bankBoomerangs.asm
==== Step 3 ====
Ok, now you have the tools necessary to access other banks from your code bank.
Now we need to actually get some stuff in the other banks!
I recommend using bank 18, because it is completely empty! Pick wherever you want (as long as there isn't already something there), but the rest of this tutorial will be assuming you are using bank 18.
First you will need something to put there. Lets create a script that simply resets
the game.
Create a new script somewhere, I have a 'custom' folder inside my routines folder.
name it 'test.asm'
inside the script make this simple subroutine:
Code:
testSubroutine_reset:
JMP RESET
RTS
Now go to the nesmaker editor> project settings>script settings and add a new script define:
Name: Test Subroutine
Define: SCR_TEST_SUBROUTINE
Script: PATHTOYOURTESTSCRIPT\test.asm
- replace PATHTOYOURTESTSCRIPT with the actual address to your script.
We need the script defined in order to put it in bank 18.
Go to GameEndineData>Routines>YourModule>BankData and open the script Bank18.asm
it should be empty. If for some reason it isn't you may want to find one that is.
anyways add this line:
Code:
.include SCR_TEST_SUBROUTINE
Ok, now you actually have something in Bank 18!
Now how to actually call that code from over in bank 14?
You need to go back and edit your bankBoomerangs.asm script one more time.
Add this block of code after ;; === ADD BOOMERANGS HERE ===
Code:
boomerang_test:
;;; Change to bank 18
LDA currentBank
STA prevBank
LDY #$18 ;; Bank to use
JSR bankswitchY
;;; Call the subroutine
JSR testSubroutine_reset
;;; Return to the previous bank
LDY prevBank ;; Bank we came from
JSR bankswitchY
RTS
What this does is creates a link between bank 14 and bank 18 through the static bank.
Now, in bank 14 you can call:
'JSR boomerang_test'
and it will run testSubroutine_reset in bank 18.
Congratulations! You now have all the tools in place that you will need.
From here, what should you do to take advantage of this?
-You can get rid of the script for test.asm and the code to access it, it was just
to teach you how to use it.
-Add any scripts that you want to bank 18 in the same way you added test.asm
-I included the template at the top of bankBoomerangs.asm so that you can easily copy and paste it when you need access. You will need to create a separate 'boomerang' in this file for each subroutine you want to access in bank 18.
-Scripts you add in this way ABSOLUTELY MUST be designed as subroutines. This is because
it depends on using RTS to get back to the static bank when you have finished. You can
create and call new subroutines inside of bank 18 as long as they always return correctly.
If you have any further questions I will try and answer them.