Bucket Mouse
Active member
In version 4.1 I had a game fill up the bank for monster AI before I got close with anything else. So with 4.5.6 I'm trying to think of a way that I could possibly store action step data in a separate bank if it came to it. In version 4.5.6, AI data is stored in bank 1C.
I made a copy of my NESMaker folder, so as not to alter anything important, and got to monkeying with the engine.
There are several parts in doHandleObjects that grab AI data from bank 1C. And Bank 1D appears to be completely empty. So.......what if I took half the sprite address data, and copied it into 1D, like this?
BANK 1C ALTERATIONS
BANK 1D ALTERATIONS
Note that I cut it in half at Object 25, but you don't have to cut it exactly there. If you do cut it a different way, be sure to change every instance of #$26 in the following code to the number you picked.
NESMaker won't know where to find the latter half of the object data if I don't tell it where I just put it. So open doDrawSprites.asm and find this comment line:
;; Next, we have to do a few indirect look ups to get the actual correct table read.
We're going to make these changes to it....
Next, I opened doHandleObjects and made the following alteration where the script first switches to 1C (stuff shifted to the left is what I added)...
I did a search and found ten places overall where a call is made to switch to Bank 1C. Five of them are in doHandleObjects, and the other five appear in:
doCreateState_addExtraVariables_AdventureBase
doUpdateActionTimer
doClearAllMonsters
DoObjectAction
doHandleObjectCollisions
This is just for the Adventure module. If you're using Platform, there are several more. If you're unsure where to find them all, just open BASE 4.5 and do a Control-F search for 1C. They will all pop up.
I copy-pasted my SwitchBank workaround script into all of them, numbering the variables with each copy (that's how I knew I did it ten times). Then I hit "compile" and waited for the mess of errors.
I got none! The game went through! Rarely ever happens to me. The game is fully functional, and NES Space Tool shows that data is now stored in 1D, so as far as I know, this works. (Don't hold me to that -- it's fresh barely tested code, I won't be shocked if it causes a problem down the line).
The method I've used here could also be used to store other data in separate banks. Not this exact code, but the basic thinking behind it. If you've got a bank in danger of overflowing, and it is NOT the static bank, search for every instance of that bank being used and see if you can split it with an empty bank as I've done.
I made a copy of my NESMaker folder, so as not to alter anything important, and got to monkeying with the engine.
There are several parts in doHandleObjects that grab AI data from bank 1C. And Bank 1D appears to be completely empty. So.......what if I took half the sprite address data, and copied it into 1D, like this?
BANK 1C ALTERATIONS
Code:
ObjectLoSpriteAddressLo:
.db #<GameItem0_Lo, #<GameItem1_Lo, #<GameItem2_Lo, #<GameItem3_Lo, #<GameItem4_Lo, #<GameItem5_Lo, #<GameItem6_Lo, #<GameItem7_Lo
.db #<GameItem8_Lo, #<GameItem9_Lo,#<GameItem10_Lo,#<GameItem11_Lo,#<GameItem12_Lo,#<GameItem13_Lo,#<GameItem14_Lo,#<GameItem15_Lo
.db #<Object0_Lo,#<Object1_Lo,#<Object2_Lo,#<Object3_Lo,#<Object4_Lo,#<Object5_Lo,#<Object6_Lo,#<Object7_Lo
.db #<Object8_Lo,#<Object9_Lo,#<Object10_Lo,#<Object11_Lo,#<Object12_Lo,#<Object13_Lo,#<Object14_Lo,#<Object15_Lo
.db #<Object16_Lo,#<Object17_Lo,#<Object18_Lo,#<Object19_Lo,#<Object20_Lo,#<Object21_Lo,#<Object22_Lo,#<Object23_Lo
.db #<Object24_Lo,#<Object25_Lo
ObjectLoSpriteAddressHi:
.db #>GameItem0_Lo, #>GameItem1_Lo, #>GameItem2_Lo, #>GameItem3_Lo, #>GameItem4_Lo, #>GameItem5_Lo, #>GameItem6_Lo, #>GameItem7_Lo
.db #>GameItem8_Lo, #>GameItem9_Lo,#>GameItem10_Lo,#>GameItem11_Lo,#>GameItem12_Lo,#>GameItem13_Lo,#>GameItem14_Lo,#>GameItem15_Lo
.db #>Object0_Lo,#>Object1_Lo,#>Object2_Lo,#>Object3_Lo,#>Object4_Lo,#>Object5_Lo,#>Object6_Lo,#>Object7_Lo
.db #>Object8_Lo,#>Object9_Lo,#>Object10_Lo,#>Object11_Lo,#>Object12_Lo,#>Object13_Lo,#>Object14_Lo,#>Object15_Lo
.db #>Object16_Lo,#>Object17_Lo,#>Object18_Lo,#>Object19_Lo,#>Object20_Lo,#>Object21_Lo,#>Object22_Lo,#>Object23_Lo
.db #>Object24_Lo,#>Object25_Lo
ObjectHiSpriteAddressLo:
.db #<GameItem0_Hi, #<GameItem1_Hi, #<GameItem2_Hi, #<GameItem3_Hi, #<GameItem4_Hi, #<GameItem5_Hi, #<GameItem6_Hi, #<GameItem7_Hi
.db #<GameItem8_Hi, #<GameItem9_Hi,#<GameItem10_Hi,#<GameItem11_Hi,#<GameItem12_Hi,#<GameItem13_Hi,#<GameItem14_Hi,#<GameItem15_Hi
.db #<Object0_Hi,#<Object1_Hi,#<Object2_Hi,#<Object3_Hi,#<Object4_Hi,#<Object5_Hi,#<Object6_Hi,#<Object7_Hi
.db #<Object8_Hi,#<Object9_Hi,#<Object10_Hi,#<Object11_Hi,#<Object12_Hi,#<Object13_Hi,#<Object14_Hi,#<Object15_Hi
.db #<Object16_Hi,#<Object17_Hi,#<Object18_Hi,#<Object19_Hi,#<Object20_Hi,#<Object21_Hi,#<Object22_Hi,#<Object23_Hi
.db #<Object24_Hi,#<Object25_Hi
ObjectHiSpriteAddressHi:
.db #>GameItem0_Hi, #>GameItem1_Hi, #>GameItem2_Hi, #>GameItem3_Hi, #>GameItem4_Hi, #>GameItem5_Hi, #>GameItem6_Hi, #>GameItem7_Hi
.db #>GameItem8_Hi, #>GameItem9_Hi,#>GameItem10_Hi,#>GameItem11_Hi,#>GameItem12_Hi,#>GameItem13_Hi,#>GameItem14_Hi,#>GameItem15_Hi
.db #>Object0_Hi,#>Object1_Hi,#>Object2_Hi,#>Object3_Hi,#>Object4_Hi,#>Object5_Hi,#>Object6_Hi,#>Object7_Hi
.db #>Object8_Hi,#>Object9_Hi,#>Object10_Hi,#>Object11_Hi,#>Object12_Hi,#>Object13_Hi,#>Object14_Hi,#>Object15_Hi
.db #>Object16_Hi,#>Object17_Hi,#>Object18_Hi,#>Object19_Hi,#>Object20_Hi,#>Object21_Hi,#>Object22_Hi,#>Object23_Hi
.db #>Object24_Hi,#>Object25_Hi
BANK 1D ALTERATIONS
Code:
ObjectLoSpriteAddressLo2:
.db #<Object26_Lo,#<Object27_Lo,#<Object28_Lo,#<Object29_Lo,#<Object30_Lo,#<Object31_Lo
.db #<Object32_Lo,#<Object33_Lo,#<Object34_Lo,#<Object35_Lo,#<Object36_Lo,#<Object37_Lo,#<Object38_Lo,#<Object39_Lo
.db #<Object40_Lo,#<Object41_Lo,#<Object42_Lo,#<Object43_Lo,#<Object44_Lo,#<Object45_Lo,#<Object46_Lo,#<Object47_Lo
.db #<Object48_Lo,#<Object49_Lo,#<Object50_Lo,#<Object51_Lo,#<Object52_Lo,#<Object53_Lo,#<Object54_Lo,#<Object55_Lo
.db #<Object56_Lo,#<Object57_Lo,#<Object58_Lo,#<Object59_Lo,#<Object60_Lo,#<Object61_Lo,#<Object62_Lo,#<Object63_Lo
ObjectLoSpriteAddressHi2:
.db #>Object26_Lo,#>Object27_Lo,#>Object28_Lo,#>Object29_Lo,#>Object30_Lo,#>Object31_Lo
.db #>Object32_Lo,#>Object33_Lo,#>Object34_Lo,#>Object35_Lo,#>Object36_Lo,#>Object37_Lo,#>Object38_Lo,#>Object39_Lo
.db #>Object40_Lo,#>Object41_Lo,#>Object42_Lo,#>Object43_Lo,#>Object44_Lo,#>Object45_Lo,#>Object46_Lo,#>Object47_Lo
.db #>Object48_Lo,#>Object49_Lo,#>Object50_Lo,#>Object51_Lo,#>Object52_Lo,#>Object53_Lo,#>Object54_Lo,#>Object55_Lo
.db #>Object56_Lo,#>Object57_Lo,#>Object58_Lo,#>Object59_Lo,#>Object60_Lo,#>Object61_Lo,#>Object62_Lo,#>Object63_Lo
ObjectHiSpriteAddressLo2:
.db #<Object26_Hi,#<Object27_Hi,#<Object28_Hi,#<Object29_Hi,#<Object30_Hi,#<Object31_Hi
.db #<Object32_Hi,#<Object33_Hi,#<Object34_Hi,#<Object35_Hi,#<Object36_Hi,#<Object37_Hi,#<Object38_Hi,#<Object39_Hi
.db #<Object40_Hi,#<Object41_Hi,#<Object42_Hi,#<Object43_Hi,#<Object44_Hi,#<Object45_Hi,#<Object46_Hi,#<Object47_Hi
.db #<Object48_Hi,#<Object49_Hi,#<Object50_Hi,#<Object51_Hi,#<Object52_Hi,#<Object53_Hi,#<Object54_Hi,#<Object55_Hi
.db #<Object56_Hi,#<Object57_Hi,#<Object58_Hi,#<Object59_Hi,#<Object60_Hi,#<Object61_Hi,#<Object62_Hi,#<Object63_Hi
ObjectHiSpriteAddressHi2:
.db #>Object26_Hi,#>Object27_Hi,#>Object28_Hi,#>Object29_Hi,#>Object30_Hi,#>Object31_Hi
.db #>Object32_Hi,#>Object33_Hi,#>Object34_Hi,#>Object35_Hi,#>Object36_Hi,#>Object37_Hi,#>Object38_Hi,#>Object39_Hi
.db #>Object40_Hi,#>Object41_Hi,#>Object42_Hi,#>Object43_Hi,#>Object44_Hi,#>Object45_Hi,#>Object46_Hi,#>Object47_Hi
.db #>Object48_Hi,#>Object49_Hi,#>Object50_Hi,#>Object51_Hi,#>Object52_Hi,#>Object53_Hi,#>Object54_Hi,#>Object55_Hi
.db #>Object56_Hi,#>Object57_Hi,#>Object58_Hi,#>Object59_Hi,#>Object60_Hi,#>Object61_Hi,#>Object62_Hi,#>Object63_Hi
Note that I cut it in half at Object 25, but you don't have to cut it exactly there. If you do cut it a different way, be sure to change every instance of #$26 in the following code to the number you picked.
NESMaker won't know where to find the latter half of the object data if I don't tell it where I just put it. So open doDrawSprites.asm and find this comment line:
;; Next, we have to do a few indirect look ups to get the actual correct table read.
We're going to make these changes to it....
Code:
LDA Object_type,x
CMP #$26
BCS +
;; Next, we have to do a few indirect look ups to get the actual correct table read.
LDY Object_type,x
LDA ObjectLoSpriteAddressLo,y
STA tempPointer_lo
LDA ObjectLoSpriteAddressHi,y
STA tempPointer_lo+1
LDA ObjectHiSpriteAddressLo,y
STA tempPointer_hi
LDA ObjectHiSpriteAddressHi,y
STA tempPointer_hi+1
JMP ++
+
;; Next, we have to do a few indirect look ups to get the actual correct table read.
LDY Object_type,x
LDA ObjectLoSpriteAddressLo2,y
STA tempPointer_lo
LDA ObjectLoSpriteAddressHi2,y
STA tempPointer_lo+1
LDA ObjectHiSpriteAddressLo2,y
STA tempPointer_hi
LDA ObjectHiSpriteAddressHi2,y
STA tempPointer_hi+1
++
Next, I opened doHandleObjects and made the following alteration where the script first switches to 1C (stuff shifted to the left is what I added)...
Code:
JSR doHandleCreateState
LDA Object_type,x
CMP #$33
BCS laterobjects
SwitchBank #$1C
JMP earlierobjects
laterobjects:
SwitchBank #$1D
earlierobjects:
LDY Object_type,x
LDA ObjectFlags,y
STA Object_flags,x
ReturnBank
I did a search and found ten places overall where a call is made to switch to Bank 1C. Five of them are in doHandleObjects, and the other five appear in:
doCreateState_addExtraVariables_AdventureBase
doUpdateActionTimer
doClearAllMonsters
DoObjectAction
doHandleObjectCollisions
This is just for the Adventure module. If you're using Platform, there are several more. If you're unsure where to find them all, just open BASE 4.5 and do a Control-F search for 1C. They will all pop up.
I copy-pasted my SwitchBank workaround script into all of them, numbering the variables with each copy (that's how I knew I did it ten times). Then I hit "compile" and waited for the mess of errors.
I got none! The game went through! Rarely ever happens to me. The game is fully functional, and NES Space Tool shows that data is now stored in 1D, so as far as I know, this works. (Don't hold me to that -- it's fresh barely tested code, I won't be shocked if it causes a problem down the line).
The method I've used here could also be used to store other data in separate banks. Not this exact code, but the basic thinking behind it. If you've got a bank in danger of overflowing, and it is NOT the static bank, search for every instance of that bank being used and see if you can split it with an empty bank as I've done.