(Solved) Is there a table for pickup/object spawn location?

m8si

Active member
I'm wondering if there is a table containing the spawn location info of the object that has been placed via the editor?

Came up this idea that maybe after collecting a pickup it would be possible to set the pickup's spawn location to let's say 0,0

Then when entering the same screen again the pickup would be spawned on that new location 0,0 and after that there would be a check that if any object is at position 0,0 it would be destroyed.
 

SciNEStist

Well-known member
if your goal is to allow pickups to only happen once, there is another way. triggered and untriggered screens spawn objects differently, so if you trigger the screen you are on when the pickup is grabbed, it cant be picked up again.
 

m8si

Active member
If I understand it correctly. When there is more than one pickup on the screen it doesn't help, I can't assume player has collected all the pickups if one has been picked. :)
 
Last edited:

JamesNES

Well-known member
I did something like this for my byte off game, it'll take one byte of ram for every two screens though. And it wouldn't work for scrolling games. I can post it if that'll help.

It was to stop enemies respawning after you kill them, so same thing but picking up pickups.
 

m8si

Active member
I would love to see what you have made. My game is a scroller, but maybe there is some way to get it working.
 

m8si

Active member
Looked through all of the files in my project but couldn't find anything related to object table. I hope I just missed it and there is a table somwhere...
 

JamesNES

Well-known member
Pickups are just stored like monsters in that screen's .col file, that's where the spawn locations are too. So they're in rom and can't be changed, they'll always have to spawn in the same spot from that.

Permakilling enemies on a single screen game was simpler as they were always spawned in in the same order, so they had the same object ID in the list. Using a variable for each screen I could flip a bit that said if that monster had been killed, and then not spawn it on the next screen load.

I thought about how you could do it for scrolling, and it's definitely doable, but you'd need one byte of ram for every screen that had pickups placed on it, which could get costly. That'd let you have 8 different pickups. If you only had 4 you could do one byte per two screens.

Then use one of NES Maker's screen bytes to tell it which byte of ram that screen uses, like an extension of the screen triggers function.

You'd really need to look at how much ram you'd have to use to see if it's worth doing. The screen byte would just stay in rom so that wouldn't matter, but yeah, if you had a lot of screens with pickups that'd be a lot of ram.
 

m8si

Active member
Ok.. So locations are read only. :( I was a bit afraid that it would be the case. Thanks for posting it seems like a good solution. So the sprite order is different if I scroll to a screen left or right?

I also thought something similar in case the locations were in rom. Maybe I need my own table for object placement. Then I can check from that table if the pickup has been collected or not by changing the coords to 0,0

However I am going to need a lot of room for my game and I know at some point I may be at a point where I have to cut out some things Maybe it would be wiser to change to tile pickups instead or maybe design the levels in a way that I need to check only a few screens for pickups.
 
Ok.. So locations are read only. :( I was a bit afraid that it would be the case. Thanks for posting it seems like a good solution. So the sprite order is different if I scroll to a screen left or right?

I also thought something similar in case the locations were in rom. Maybe I need my own table for object placement. Then I can check from that table if the pickup has been collected or not by changing the coords to 0,0

However I am going to need a lot of room for my game and I know at some point I may be at a point where I have to cut out some things Maybe it would be wiser to change to tile pickups instead or maybe design the levels in a way that I need to check only a few screens for pickups.
Ran into a similar issue with movable tiles... even though it was hard for me this way it should be easier for you I recommend either addressing this in your scrolling asm file or if you are willing to compromise how this works: postscreenload.asm? Granted that would make it so you would have to compromise a lot on how this works...
 

m8si

Active member
Thanks! I tried to mess a bit with doUpdateCamera.asm but I think the whole thing just might be too difficult for me at this point. Got some strange artifacts to appear on screen and the game started to lag and I got some screen tearing issues. :( And the only thing I managed to do was to hide the coins placed in the editor. xD

I'll concentrate on some other things for now, but maybe return to this issue later.
 

m8si

Active member
As @JamesNES said there is a table for pickups and it can be found from GameEngineData\ScreenData\CollisionTables. Table is Read Only so it doesn't help much but in case someone needs it for something here is the answer :)

Code:
;; Byte 12: Monster 1 Origin Day Normal (yyyyxxxx) if not placed then (111100xx) where x is: 01=random 10=edgespawn 11=disabled
    .db #$c9
;; Byte 13: Monster 2 Origin Day Normal (yyyyxxxx) if not placed then (111100xx) where x is: 01=random 10=edgespawn 11=disabled
    .db #$7d
;; Byte 14: Monster 3 Origin Day Normal (yyyyxxxx) if not placed then (111100xx) where x is: 01=random 10=edgespawn 11=disabled
    .db #$f3
;; Byte 15: Monster 1 Origin Night Normal (yyyyxxxx) if not placed then (111100xx) where x is: 01=random 10=edgespawn 11=disabled
    .db #$f3
;; Byte 16: Monster 2 Origin Night Normal (yyyyxxxx) if not placed then (111100xx) where x is: 01=random 10=edgespawn 11=disabled
    .db #$f3
;; Byte 17: Monster 3 Origin Night Normal (yyyyxxxx) if not placed then (111100xx) where x is: 01=random 10=edgespawn 11=disabled
    .db #$f3
;; Byte 18: Monster 1 Origin Day Triggered (yyyyxxxx) if not placed then (111100xx) where x is: 01=random 10=edgespawn 11=disabled
    .db #$f3
;; Byte 19: Monster 2 Origin Day Triggered (yyyyxxxx) if not placed then (111100xx) where x is: 01=random 10=edgespawn 11=disabled
    .db #$f3
;; Byte 20: Monster 3 Origin Day Triggered (yyyyxxxx) if not placed then (111100xx) where x is: 01=random 10=edgespawn 11=disabled
    .db #$f3
;; Byte 21: Monster 1 Origin Night Triggered (yyyyxxxx) if not placed then (111100xx) where x is: 01=random 10=edgespawn 11=disabled
    .db #$f3
;; Byte 22: Monster 2 Origin Night Triggered (yyyyxxxx) if not placed then (111100xx) where x is: 01=random 10=edgespawn 11=disabled
    .db #$f3
;; Byte 23: Monster 3 Origin Night Triggered (yyyyxxxx) if not placed then (111100xx) where x is: 01=random 10=edgespawn 11=disabled
    .db #$f3
 

JamesNES

Well-known member
Was having fun thinking about how to do this. If your game is gonna be made of levels rather than a big open vania type thing, I'd do it like this:

-have (eg) ten bytes of ram, allowing ten screens in the level to have pickups
-have 8 possible pickups, ordered in NES Maker's game objects at slots 8 to 15
-have a screenbyte (doesn't need to be in ram) that tells each pickup screen which byte of ram to check
-when an item is picked up, subtract 8 from its object ID and flip the corresponding bit in that screen's assigned item pickup ram
-then when scrolling onto that screen again, check that same bit to decide whether to spawn it or not

This will work! And it'd be easier than trying to do the same thing with tile-based pickups. Then when the player goes to the next level, zero all those variables out again. One caveat would be that you could only have one type of each pickup on that screen, unless you duplicated game objects.

When you're running low on spare ram check out the default zero page and overflow ram lists, there's quite a lot of stuff in there that's assigned but literally never used.

A handy table NES Maker includes for stuff like this is in ToggleTables.asm:

Code:
ValToBitTable_inverse:
    .db #%00000001, #%00000010, #%000000100, #%00001000, #%00010000, #%00100000, #%01000000, #%10000000

It took me way too long to realise what this was for. So if you wanted to flip the bit for the pickup that's object ID #15:

Code:
LDA Object_type,x ;;#15
SEC 
SBC #$08
TAX  ;;#07 now
LDA ValToBitTable_inverse,x    ;; #%10000000
ORA pickupRam,y
STA pickupRam,y
;;y would have to have been set up already with the current screen's pickupRam index, from the screen byte

And then when the scrolling engine hits the point where it's loading that pickup on that screen, you'd check whether it was flagged already or not with AND, and branch around the object creation.

Hope this helps get the gears turning.
 

m8si

Active member
Great, thank you very much! I'll experiment with it and will let you know how it goes once I have more time.

But yea. It seems to be a solid idea. I don't have any plans to include other sprite pickups so making a duplicate and having 4 per screen would be more than enough. And yes! Only a few screens per level will need a pickup.
 

m8si

Active member
Had little time to look at it. Having a good feeling about this. But I don't understand what should be put in AND to make the object vanish.

I put your code in pickup script

Code:
LDA Object_type,x ;; coin is #05
        SEC
        SBC #$08
        TAX  ;;#07 now
        LDA ValToBitTable_inverse,x    ;; #%10000000
        LDY #$01
        ORA pickupRam,y
        STA pickupRam,y
        ;;y would have to have been set up already with the current screen's pickupRam index, from the screen byte

Then I found out that placing this code at the end of doUpdateCamera makes it so that if any pickup is collected ALL the upcoming monsters will vanish. Not sure about that AND #%00000100 and how should it be.

Code:
LDY #$01
                LDA pickupRam,y   
                AND #%00000100
                BNE ++
                    CreateObjectOnScreen temp2, temp1, tempD, #$00, scrollUpdateScreen
                ++
 

m8si

Active member
I think I may have a working system now!!

Thank you very much to @JamesNES for helping me out with the code.



First create a 10 byte variable called pickupRam
Then you will need 4 identical pickup objects stored in your Game Objects. When placing the objects on screens remember that you can place only one of the unique objects per scrolling area. That won't break anything, if you place more than just one, but they just won't spawn if the corresponding object with the same #number has been picked already.

Here is the code. I haven't tested it much and I am still a bit confused about how some of the things work. xD


This goes to pickup script
Code:
    LDA Object_type,x
        STA temp
        SEC
        SBC #$08
        TAX  ;;#07 now
        LDA ValToBitTable_inverse,x    ;; #%10000000
        LDY temp ; Current object is stored in y
        ORA pickupRam,y
        STA pickupRam,y

And this goes to doUpdateCamera script. At the end After BEQ +noMonsterToLoadInThisColumn

Code:
                LDY tempD
                LDA pickupRam,y  
                AND #%00001111
                BNE ++
                   JMP +createMonster
                ++
                JMP +noMonsterToLoadInThisColumn
               
                +createMonster:
                 CreateObjectOnScreen temp2, temp1, tempD, #$00, scrollUpdateScreen
               
               
               
            +noMonsterToLoadInThisColumn:
           

           
    RTS

After entering to another scrollable area you need to also set pickupRam variables to zero. Maybe in a warp script or Screen Load script etc...


And here you can see it in action:
 
Last edited:

JamesNES

Well-known member
Wow nice work, I thought it was gonna be a longer road than that!

Looks like you went with a bit of a different way to mine but if it works, hey!
 

m8si

Active member
It works, but having some bugs that may be related to other things. :)

Is it correct to reset the variables like this? The code is on my PostScreenLoad and I think in my code I am writing only to places 5-8 because my objects are on those slots.

Code:
LDA #$00
    STA pickupRam

    LDX #$05
    STA pickupRam,x
    LDX #$06
    STA pickupRam,x
    LDX #$07
    STA pickupRam,x
    LDX #$08
    STA pickupRam,x
 

JamesNES

Well-known member
My original idea was around multiple screens in a level with multiple instances of the same pickup, which was way more complicated. If you're only having one of each item in a level, you only need the one byte of ram. Hold out a bit and I'll write both parts up later today
 

m8si

Active member
This is a bit offtopic...
I do have multiple screens, but I realised maybe it would be fair to give the player a chance to "farm" the coins by leaving and re-entering the area. It is also a difficulty factor. Coins are life in this game. :) Maybe more experienced players don't need to farm the coins this way, idk... Anyways it is always fun if you as a player can find a way to exploit the game somehow. xD
 

JamesNES

Well-known member
Every time I play Faxanadu there's a substantial amount of coin farming, but I find it more relaxing than repetitive!

Here's what I came up with for making pickups stay away. This is in the pickup script:

Code:
STX tempx
LDA Object_type,x 
SEC 
SBC #$05
TAX 
LDA ValToBitTable_inverse,x 
ORA pickupRam
STA pickupRam 
LDX tempx

Which can go at the end of the pickup script so it applies to everything that's flagged as a pickup, or just for individual types.

And in doUpdateCamera this is the new seam monster loading subroutine:

Code:
checkSeamForMonsterPosition:
    ;; y is loaded before subroutine.
    
            ;;first, check if it's a pickup 
            LDA tempD 
            CMP #$05
            BCS +maybePickup
                JMP +notPickup            
            +maybePickup 
            CMP #$09
            BCC +isPickup
                JMP +notPickup             
            +isPickup
            
            ;;check if it's been picked up already 
            STX tempx 
            LDA tempD 
            SEC 
            SBC #$05
            TAX 
            
            LDA ValToBitTable_inverse,x 
            AND pickupRam
            BEQ +spawn 
                LDX tempx  
                JMP +noMonsterToLoadInThisColumn
            +spawn 
            LDX tempx 
            
            
            +notPickup
            LDA (pointer6),y
            STA temp
            ASL
            ASL
            ASL
            ASL
            STA temp2
            LDA scrollUpdateColumn
            AND #%11110000
            CMP temp2
            BNE +noMonsterToLoadInThisColumn
                LDA temp
                AND #%11110000
                STA temp1
                CMP #%11110000
                BEQ +noMonsterToLoadInThisColumn
                    CreateObjectOnScreen temp2, temp1, tempD, #$00, scrollUpdateScreen
            +noMonsterToLoadInThisColumn:
    RTS

I haven't really done anything with NES Maker's scrolling modules, but I had an install going to mess around with, gave this a go and it looks like it's working fine. So the pickups will be objects 05-08 only.
 
Top Bottom