[4.5.9] ChangeTileAtPosition macro

dale_coop

Moderator
Staff member
Here's one "ChangeTileAtPosition" macro I use.... to change a tile (graphics and collision) at a specific spot on your screen.
I thought it might be useful for some of you.

Code:
MACRO ChangeTileAtPosition arg0, arg1, arg2, arg3, arg4
    ; arg0 = the X tile position (0-15)
    ; arg1 = the Y tile position (0-14)
    ; arg2 = metatile to change into
    ; arg3 = collision to change into.
    ; arg4 = nametable (0, 1)
    
    LDA arg1   
    ASL
    ASL
    ASL
    ASL           
    AND #%11110000               
    STA tempz               
    LDA arg0           
    ; LSR
    ; LSR
    ; LSR
    ; LSR
    ORA tempz
    TAY   
    LDA arg4
    BEQ +isEvenCt
        ;; is an odd ct, so looking in collisionTable2
        LDA arg3
        STA collisionTable2,y
        JMP +doneWithTileUpdate
    +isEvenCt
        LDA arg3
        STA collisionTable,y
        
    +doneWithTileUpdate

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;   
;;;; This part will actually update the tile with tile 0 in the tile set.
;;; ys is carried over from above.

;;; GET THE HIGH BYTE OF THE TILE TO CHANGE
    LDA arg4
    BEQ +isEvenNt
        ;; is odd nt
        LDA #$24
        JMP +gotNt
    +isEvenNt
        ;; is even nt
        LDA #$20
    +gotNt
        STA temp1
;;; GET THE LOW BYTE OF THE TILE TO CHANGE
        TYA
        STA temp
        LSR
        LSR
        LSR
        LSR
        LSR
        LSR
        clc
        ADC temp1
        STA temp2 ;;;temp16+1
        TYA
        AND #%11110000
        ASL
        ASL
        STA tempz
        TYA
        AND #%00001111
        ASL
        ORA tempz
        STA temp3 ;temp16
        
;;; SET THE TILE NUMBER TO CHANGE TO.   
    LDA arg2 ;; the tile to change.
            ;;; this is in tiles, so if you wanted the second "metatile",
            ;;; use 2, not 1.  If you wanted the tile in the next row,
            ;;; use #$20, not #$10.  Etc.
    STA tempA
    CLC
    ADC #$01
    STA tempB
    CLC
    ADC #$0F
    STA tempC
    CLC
    ADC #$01
    STA tempD
    
    
    LDY #$00
        LDA temp2
        STA scrollUpdateRam,y
        INY
        LDA temp3
        STA scrollUpdateRam,y
        INY
        LDA tempA
        STA scrollUpdateRam,y
        INY
        
        LDA temp2
        STA scrollUpdateRam,y
        INY
        LDA temp3
        CLC
        ADC #$01
        STA scrollUpdateRam,y
        INY
        LDA tempB
        STA scrollUpdateRam,y
        INY
        
            LDA temp3
            CLC
            ADC #$20
            STA temp3
            LDA temp2
            ADC #$00
            STA temp2
        
        LDA temp2
        STA scrollUpdateRam,y
        INY
        LDA temp3
        STA scrollUpdateRam,y
        INY
        LDA tempC
        STA scrollUpdateRam,y
        INY
        
        LDA temp2
        STA scrollUpdateRam,y
        INY
        LDA temp3
        CLC
        ADC #$01
        STA scrollUpdateRam,y
        INY
        LDA tempD
        STA scrollUpdateRam,y
        INY
    
    TYA
    STA maxScrollOffsetCounter
    
    
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Turn on update screen on next frame.
        LDA updateScreenData
        ORA #%0000100
        STA updateScreenData
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ENDM

Installation:
Save that script as "ChangeTileAtPosition.asm" in your "GameEngineData\Routines\BASE_4_5\System\Macros\" folder.

Usage:
Code:
  ChangeTileAtPosition <X tile position>, <Y tile position>, <new gfx tile>, <new collision tile>, <nametable>
Example:
Code:
  ChangeTileAtPosition #$03, #$0D, #$02, #$00, camScreen
 

baardbi

Well-known member
This macro is amazing. I found that using JSR doWaitFrame after the macro can help in some cases if the screen doesn't update as expected.

ChangeTileAtPosition #$03, #$0D, #$02, #$00, camScreen
JSR doWaitFrame
 

baardbi

Well-known member
I found that adding a little piece of code before using the macro makes sure that there's no mismatch with the current nametable. So far this little trick seems to work every time. Before doing this I only got the expected result if I explicitly used #0 or #1 for arg4.

LDA currentNametable
AND #%00000001
STA temp

ChangeTileAtPosition #$03, #$0D, #$02, #$00, temp
 

dale_coop

Moderator
Staff member
I found that adding a little piece of code before using the macro makes sure that there's no mismatch with the current nametable. So far this little trick seems to work every time. Before doing this I only got the expected result if I explicitly used #0 or #1 for arg4.
Yes it can be used like that but for NON scrolling screens.
Else it's safer to use Obejct_screen,x or camScreen
 

lasanderos

New member
Hey, thanks for a useful macro! What should I do if I wanted to change nine tiles instead of just one? I can get changing just one background tile to work, but if I try using this more than once in a row, not even the first tile changes anymore.
 

lasanderos

New member
I still don't seem to get it to go through all nine times, it stops after the first one even if I'm using "JSR doWaitFrame" in between. I have the following code as part of my hurt monster -script, this specific part runs when all "lesser monsters" are destroyed. Creating the boss object works fine and the first tile gets changed, but then the code stops running. I also tried moving the createObject after the tile changes, but then the object did not get created at all and again only the first tile got changed. What am I doing wrong?
spawnBoss:

CreateObjectOnScreen tempA, tempB, #38, #$00, tempD

;let's hide Kehno from the background
LDA currentNametable
AND #%00000001
STA temp

ChangeTileAtPosition #$06, #$0A, #$42, #$00, temp
JSR doWaitFrame
ChangeTileAtPosition #$07, #$0A, #$42, #$00, temp
JSR doWaitFrame
ChangeTileAtPosition #$08, #$0A, #$42, #$00, temp
JSR doWaitFrame
ChangeTileAtPosition #$06, #$0B, #$42, #$00, temp
JSR doWaitFrame
ChangeTileAtPosition #$07, #$0B, #$42, #$00, temp
JSR doWaitFrame
ChangeTileAtPosition #$08, #$0B, #$42, #$00, temp
JSR doWaitFrame
ChangeTileAtPosition #$06, #$0C, #$42, #$00, temp
JSR doWaitFrame
ChangeTileAtPosition #$07, #$0C, #$42, #$00, temp
JSR doWaitFrame
ChangeTileAtPosition #$08, #$0C, #$42, #$00, temp
JSR doWaitFrame

JMP +doSkipHurtingThisObject
 

kevin81

Well-known member
My first guess would be that because the `temp` variable is being overwritten within the macro, after the first `ChangeTileAtPosition` the wrong nametable value is being used. You could fix this by using a different variable, for example `temp4`, or even add your own in the Zero Page variables to make sure it's not being clobbered by the macro.
 

lasanderos

New member
My first guess would be that because the `temp` variable is being overwritten within the macro, after the first `ChangeTileAtPosition` the wrong nametable value is being used. You could fix this by using a different variable, for example `temp4`, or even add your own in the Zero Page variables to make sure it's not being clobbered by the macro.
That did the trick, thank you!
 
Top Bottom