[SM] Preventing an air shot block from ever respawning (even on room reload)

Started by Munchy, December 22, 2018, 11:34:50 AM

Previous topic - Next topic

Munchy

Darnit. I thought I had this nailed  :razz:

So I have - to all intents and purposes - created air blocks that store their room ID in RAM (for cross referencing elsewhere) and I'd very much like them to disappear forever once they've been shot.

this is the logic that stores the shot being fired to RAM:

[SPOILER]

!PROJ = $7FF006
!MAX = $7FF016 ; 8 events available

!ROOM = $7E079B

org $949E55 ; (Air) Shot Reaction main routine
  JMP $B300

org $94B300
print pc
LDX #$0000
LDA #$FFFF
STA !MAX
JMP FIND_SPACE

FIND_SPACE:
LDA !PROJ, X
CMP !ROOM : BEQ RETURN ; do we already have the room stored?
CMP #$5555 : BEQ STORE_EVENT ; is the RAM space empty?
CMP #$FFFF : BNE IPLUSPLUS ; did we hit max?
SEC ; set carry because we hit max, too many!
BRA RETURN

IPLUSPLUS:
  INX : INX
JMP FIND_SPACE

STORE_EVENT:
LDA !ROOM
STA !PROJ, x
BRA RETURN

RETURN:
LDX $0DC4 ; runs the opcode we hijacked
JMP $9E58

[/SPOILER]

and I go on to hijack $84CE6B which, according to the disassembly, is the setup routine for the block.

here it is in the RAM MAP

[SPOILER]

$84CE6B BE 87 1C    LDX $1C87,y[$7E:1CCD] ; shotblock initilises rendering
$84CE6E BF 02 00 7F LDA $7F0002,x[$7F:018E]
$84CE72 29 00 F0    AND #$F000
$84CE75 09 52 00    ORA #$0052
$84CE78 99 17 1E    STA $1E17,y[$7E:1E5D]
$84CE7B 29 FF 8F    AND #$8FFF
$84CE7E 9F 02 00 7F STA $7F0002,x[$7F:018E]
$84CE82 60          RTS

[/SPOILER]

and the full disassembly notes:

[SPOILER]

SetupCE6B:  ;Set block type to solid, store type and new graphic to 1E17
LDX $1C87, Y
LDA $7F0002, X
AND #$F000
ORA #$0052
STA $1E17, Y
AND #$8FFF
STA $7F0002, X
RTS

[/SPOILER]

and here is my code (using the variables from my code earlier) that attempts to bypass the setup if the switch has been shot.

[SPOILER]

org $84CE6B                                      ; shotblock rendering routine
  JMP $EFE0

org $84EFE0                                      ; free space bank $84
print pc
  PHX                                               ; push X to stack since the routine uses it.
  LDA !MAX
  CMP #$FFFF : BNE RETURN_PLM_LOAD ; no switch has ever been fired
LDX #$0000

FIND_ROOM: ; check if Room's switch has been triggered
LDA !PROJ, X
CMP !ROOM : BEQ BYPASS_PLM_LOAD    ; room found! don't render the block!
CMP #$5555 : BEQ RETURN_PLM_LOAD   ; is the RAM space empty, room isn't in the list.
CMP #$FFFF : BNE JPLUSPLUS               ; did we hit max?
BRA RETURN_PLM_LOAD

JPLUSPLUS:
  INX : INX
  JMP FIND_ROOM

BYPASS_PLM_LOAD:
  PLX        ; get X back from stack
  JMP $CE82

RETURN_PLM_LOAD:
  PLX                ; get X back from stack
  LDX $1C87,y    ; load in the command we hijacked
  BRA $CE6E       ; perform PLM routine as normal

[/SPOILER]

I can see the injection in HEXD, it's definitely supposed to be there but when I run it, it never hits my breakpoints.  Have I missed something super obvious? What am I doing wrong?

Smiley

Taking a quick look, your code might not be working because you don't have a lorom specifier at the start of your asm; that'll cause xkas to not properly know where it's supposed to write. Now, regarding what you actually want to do...
It really sounds like a job for a PLM. This would even be really easy to do with a PLM. You should learn how to use PLMs.
The game has collision systems in place for things like this, so all you have to do is use them to your advantage:

[spoiler]
lorom
org $84EFE0 ;Free space in $84

EventAirShotPLM:
  DW Init, Main  ;PLM Header
print pc         ;The last 4 bytes will be the PLM you want to use (default $EFE0)

;Free space in $84

Init:
  LDA $1DC7,y        ;PLM Room argument
  JSR $80818E        ;X byte index, $05E7 bitmask
  LDA $7ED820,x      ;Event bit array
  AND $05E7 : BNE +  ;Check event bit defined by room argument

;If event is not set, ie. block was not shot yet
  LDX $1C87,y             ;PLM location
  LDA #$4044 : JSR $82B4  ;Tiletype/BTS for projectile detection (#$C044 for solid shootable)
  RTS

+ ;If event is set, ie. block has been shot before
  LDA #$0000 : STA $1C27,y ;Deletes PLM
  RTS

Main:
  DW $8A24, SetEvent            ;Goto instruction when hit by projectile
  DW $86C1, ProjectileDetection ;Set PLM pre-instruction to test for projectiles
  DW $86B4                      ;Wait

SetEvent:
  DW SetEventBit                ;Sets the event defined by room argument
  DW $8724, $CBB7               ;Goto instruction $CBB7 (1x1 shot block breaking animation)


;Code for PLM
ProjectileDetection:
  LDA $1D77,x ;Projectile type
  BNE + : RTS ;If not a projectile
+             ;If projectile (any)
  LDA $7EDEBC,x : STA $1D27,x ;Sets addresss from $7E:DEBC as next instruction (SetEvent)
  LDA #$0001 : STA $7EDE1C,x  ;Reset instruction timer
  RTS

SetEventBit:
  LDA $1DC7,x : JSL $8081FA   ;Set event defined by room argument
  RTS
 
[/spoiler]

So the way this works, all you need to do is place PLM $EFE0 wherever you need a disappearing air shot block, and give it an event value. And voila, that's it!

Munchy

I omitted the lorom from my snippets here. Not really sure why haha. Thanks for the stub. I'll take a look this evening! I'm not dodging the Plms :) just trying to use what's there if I can!

Munchy

Quote from: SMILEuser96 on December 22, 2018, 05:14:33 PM
The game has collision systems in place for things like this, so all you have to do is use them to your advantage:
ahhh, now I see what you mean after looking through your code. Thanks for this! That's ace how many little bits and pieces you can farm off to the game! Guess that's the kind of stuff that comes with time and experience :)

What will the texture of the PLM be? I'd like to have a custom graphic, do i just put the PLM on top of whichever tile (like Kejardon's disappearing/reappearing tiles)?

Smiley

The plm doesn't draw anything by itself, except the block breaking animation. So you can place it on whatever tile you want and it'll be that graphic.