[4.5.9] Adding zapper support

kevin81

Active member
Here's a way to add NES Zapper support to your NESmaker game.
It's more or less a proof of concept which may or may not need to be improved, but at least it'll give you a working starting point.


1) Add a variable called zapped (1 byte) to Zero Page RAM.

2) Add a variable called palBackup (17 bytes) to Overflow RAM

3) Add a constant ZAP_WHITE_TILE with a value of 126* to User Constants.

4) Draw an 8x8 blue square in GameObjectTiles.bmp in the next-to-last tile*.
1699575226965.png

5) Download the attached txt script file, rename it to nm_zapper.asm, and put it somewhere in the GameEngineData/Routines folder.

6) In Script Settings, add a script define.
Name: Zapper handler (or whatever name you find suiting)
Define: SCR_ZAPPER
Script: Routines\nm_zapper.asm (or wherever you saved it after downloading)

7) In Project Labels, under Monster Bits, edit the value of Bit-7 and change it into Zappable (this is optional, but makes things more clear UI-wise).

8) In Routines\BASE_4_5\Game\MainGameLoop.asm, find the line that says dontSkipNormalGameLoop:, and directly below, add:
Code:
ifdef ZAP_WHITE_TILE
    .include SCR_ZAPPER
endif

9) In Routines\BASE_4_5\System\NMI.asm, find the lines that say...
Code:
doPaletteUpdates:
    .include SCR_LOAD_PALETTES
    JMP skipScreenUpdates
+
...and remove the JMP skipScreenUpdates line (or add a semicolon in front).

10) In Routines\BASE_4_5\Game\LoadAllSubroutines.asm, at the very end, add...
Code:
MonsterBits:
   .include "ScreenData\ObjectData\MonsterBits.dat"
ifdef ZAP_WHITE_TILE
    doHandleZap:
        JMP RESET
        RTS
endif
...and replace JMP RESET with whatever you want a successful zap to do. Destroy the object, add points to your score, warp to a winner screen... anything goes.

11) From the Monster Graphics Banks, open the monster you want to zap, click Object Details, click the Details tab, and select the checkbox that says Zappable (or Bit-7 if you skipped step 7).
1699575358236.png

12) Build and test the ROM. In Mesen, go to Options > Input and select Zapper for Player 2.

Happy zapping!


* 126 (or $7E) corresponds with the next-to-last tile in GameObjectTiles.bmp. If you cannot use this tile (e.g. because it is already in use), you can pick a different tile, and then count/calculate the corresponding tile number, or look it up in Mesen's PPU viewer.
 

Attachments

  • nm_zapper.asm.txt
    9.3 KB · Views: 13
just FYI for anyone wondering why the black shooting screen isn't working take a look at this tutorial:
 

baardbi

Active member
Here's a way to add NES Zapper support to your NESmaker game.
It's more or less a proof of concept which may or may not need to be improved, but at least it'll give you a working starting point.


1) Add a variable called zapped (1 byte) to Zero Page RAM.

2) Add a variable called palBackup (17 bytes) to Overflow RAM

3) Add a constant ZAP_WHITE_TILE with a value of 126* to User Constants.

4) Draw an 8x8 blue square in GameObjectTiles.bmp in the next-to-last tile*.
View attachment 7656

5) Download the attached txt script file, rename it to nm_zapper.asm, and put it somewhere in the GameEngineData/Routines folder.

6) In Script Settings, add a script define.
Name: Zapper handler (or whatever name you find suiting)
Define: SCR_ZAPPER
Script: Routines\nm_zapper.asm (or wherever you saved it after downloading)

7) In Project Labels, under Monster Bits, edit the value of Bit-7 and change it into Zappable (this is optional, but makes things more clear UI-wise).

8) In Routines\BASE_4_5\Game\MainGameLoop.asm, find the line that says dontSkipNormalGameLoop:, and directly below, add:
Code:
ifdef ZAP_WHITE_TILE
    .include SCR_ZAPPER
endif

9) In Routines\BASE_4_5\System\NMI.asm, find the lines that say...
Code:
doPaletteUpdates:
    .include SCR_LOAD_PALETTES
    JMP skipScreenUpdates
+
...and remove the JMP skipScreenUpdates line (or add a semicolon in front).

10) In Routines\BASE_4_5\Game\LoadAllSubroutines.asm, at the very end, add...
Code:
MonsterBits:
   .include "ScreenData\ObjectData\MonsterBits.dat"
ifdef ZAP_WHITE_TILE
    doHandleZap:
        JMP RESET
        RTS
endif
...and replace JMP RESET with whatever you want a successful zap to do. Destroy the object, add points to your score, warp to a winner screen... anything goes.

11) From the Monster Graphics Banks, open the monster you want to zap, click Object Details, click the Details tab, and select the checkbox that says Zappable (or Bit-7 if you skipped step 7).
View attachment 7657

12) Build and test the ROM. In Mesen, go to Options > Input and select Zapper for Player 2.

Happy zapping!


* 126 (or $7E) corresponds with the next-to-last tile in GameObjectTiles.bmp. If you cannot use this tile (e.g. because it is already in use), you can pick a different tile, and then count/calculate the corresponding tile number, or look it up in Mesen's PPU viewer.
Wow! This is insanely cool. I'll definitely try this out in the near future. Very very nice work!!!
 
working on making menus... is there a way if you shoot one menu white flash to destroy the rest before warping? because even after I warp the white boxes are still there
granted you only need to pull the zapper to go back to a screen in the credits & instructions menu... but for the main menu... again having trouble destroying the object before warping
 

kevin81

Active member
working on making menus... is there a way if you shoot one menu white flash to destroy the rest before warping? because even after I warp the white boxes are still there
granted you only need to pull the zapper to go back to a screen in the credits & instructions menu... but for the main menu... again having trouble destroying the object before warping

My first guess would be that it has to do with the zapper code not accounting for objects being active yet. You could try to edit the script as follows.

Go to line #126, where the -zap_objLoop: starts, and add the following lines:

Code:
    LDA Object_status,x     ; Get the current object's status
    AND #%10000000          ; Check if it is active (i.e. Bit 7 = 1)
    BNE +                   ;
        JMP +zap_next       ; If it is inactive, go to step 6
    +

I'm not 100% sure, but I hope this solves the issue. At least it won't hurt anyway (and probably is a good idea even) to add in this snippet.
 
My first guess would be that it has to do with the zapper code not accounting for objects being active yet. You could try to edit the script as follows.

Go to line #126, where the -zap_objLoop: starts, and add the following lines:

Code:
    LDA Object_status,x     ; Get the current object's status
    AND #%10000000          ; Check if it is active (i.e. Bit 7 = 1)
    BNE +                   ;
        JMP +zap_next       ; If it is inactive, go to step 6
    +

I'm not 100% sure, but I hope this solves the issue. At least it won't hurt anyway (and probably is a good idea even) to add in this snippet.
Fixed it! Thanks my dude!
 
Top Bottom