Jump to content
IGNORED

Defender II Hack Attempt - Trying to find 2 portions of code


Recommended Posts

After a week digging I thought I would post. I disassembled stargate and made some of the improvements from the Defender II hack that was done years ago. I'm also trying to do a number of other things. I'm fairly confident I've isolated a handful of portions of the code doing certain things (particularly scoring, graphics are not that hard).

 

What I am trying to find now are two things that I am falling flat on:

1) I am trying to find the routine (supposing it is timer based) that uses multiple graphics to rotate for the enemies. There are enemies that have 3 graphics each and seem to rotate through on a strict timer interval

2) I am trying to figure out where the mountains are generated to start playing with that as well. I thought these would be a predetermined set of "graphics too" but I think I am wrong.

 

Putting up the set of assemblies just in case someone can offer some assistance.

defender-arcade_1.asm

defender-arcade_2.asm

Link to comment
Share on other sites

1) Do you mean the framecounter? To speed things along, the game uses 2 variations of the counter ($81) in various routines...$F8 which is the counter divided by 4 and trimmed to values 0-3, and $F9 which is the counter divided by 8 and trimmed to values 0-3:

 

 

LF1DC: LDX    #$01    ;2
       LDA    $A2     ;3
       BEQ    LF255   ;2
       LDA    $81     ;3
       LSR            ;2
       LSR            ;2
       TAY            ;2
       AND    #$03    ;2
       STA    $F8     ;3
       TYA            ;2
       LSR            ;2
       AND    #$03    ;2
       STA    $F9     ;3

 

Just track down those variables in your disassembly, you can remove them in the routines which they appear in to be able to tell which bit of code does what. You can edit them right from Stella's debugger, rather than assembling the coded each time.

 

2) Within the display code itself. You'll find many instances of ENAM1 followed by ENABL. This is what produces the hills. The M1 and Ball sprites both start at the same horizontal location. The missile is given a horizontal motion value 3 pixels left, the ball is given 3 pixels right. HMOVE is drawn on every scanline, so they move apart as the screen is drawn downward. Kind of a neat solution to draw Defender's hillside (rather than use a playfield cityscape like the original did). Not so good if you are looking to change it into something different, tho.

Link to comment
Share on other sites

Ok, I haven't started the cityscape work yet. Will leave that for last. I was hoping for some other questions someone might be able to help me figure out.

 

Question 1:

it seems that $F8 and $F9 do different things as far as the frame counter. Seems that F9 rotates most of the ships like the landers. F8 rotates other ships (like firebomber) and is also used for some reason on the end of wave screen. So I can hard code F9 to 0x01 to get the ship images to stop rotating without impact (but not 0x00). Further, I cannot set F8 to anything other than rotating 0x00 to 0x03 without it affecting the end of wave screen.

 

Less a question and more an observation I guess.

 

Question 2:

Where are the enemy graphics actually loaded? I can see the bit where the enemy ship index positions are used from 9d and 9e but I cannot tell where it actually loads the base addresses to use with the index registers. Debugging is really baffling me to try and figure out.

 

Question 3:

This is to do with colors. So for instance, Lander IMage 1 is FF94 to FF4E. but the colors defined at FF9E to FFA5 are for the mutant. And this is similar to other lander images (the other 4). The mutant is defined alone without colors right after the image and the lander colors themselves are FFD5 to FFDC! How in the world are the graphics referenced since they don't seem to be uniform addresses spaces away from each other, and especially where the colors definitions are scattered everywhere. Is there are reference table somewhere i have not found?

 

Cause it's like the bombers are defined differently and the baiters are even more different.

 

Question 4:

Take the lander definition:

; .byte $92 ; |X X X | $FF96 original
; .byte $54 ; | X X X | $FF97
; .byte $54 ; | X X X | $FF98
; .byte $7C ; | XXXXX | $FF99
; .byte $EE ; |XXX XXX | $FF9A
; .byte $EE ; |XXX XXX | $FF9B
; .byte $7C ; | XXXXX | $FF9C
; .byte $38 ; | XXX | $FF9D
This is the defined lander. If I change line FFD9 to $00 (blank) then the image does not show. I cannot find a stripping of graphics if the top/bottom defined is not non-zero.
Maybe I am getting assembly tunnel vision....
Link to comment
Share on other sites

Been awhile since I looked at Defender2 (I made the portable version), but did you see the data table $FA3B to $FA98? Looks to be holding the 16 bit addresses of most.

 

Yes sir, I saw that referenced in an older post when PacManPlus was working on Defender Arcade. But thank you for passing it along just in case.

 

That table seems to be reference addresses for "screen" content of the title and end of wave screens. It doesn't seem to be used for game play, that's why I am a bit baffled at how the these other graphics bits are pulled in

Link to comment
Share on other sites

Base addresses appear to be built (in-program) using bits culled from data tables LFB00 and LFB50...the final values take the scanline count of where they should appear onscreen into consideration. So you might be forced to use a trace file to discover how they arrive at the values. Everytime I think I see a connection, one or two of the values in the tables throw me off :(

 

Makes sense now why Defender Arcade eliminated characters rather than repurpose them.

Link to comment
Share on other sites

 

LF948:
       .byte $08 ; |    X   | $F948 00
       .byte $0C ; |    XX  | $F949 04
       .byte $08 ; |    X   | $F94A 08
       .byte $0B ; |    X XX| $F94B 0C
       .byte $0F ; |    XXXX| $F94C 10
       .byte $0C ; |    XX  | $F94D 14
       .byte $09 ; |    X  X| $F94E 18
       .byte $09 ; |    X  X| $F94F 1C
       .byte $09 ; |    X  X| $F950 20
       .byte $0F ; |    XXXX| $F951 24 lander page $FF
       .byte $0D ; |    XX X| $F952 28
       .byte $0B ; |    X XX| $F953 2C
       .byte $0A ; |    X X | $F954 30
       .byte $08 ; |    X   | $F955 34
       .byte $08 ; |    X   | $F956 38
       .byte $08 ; |    X   | $F957 3C
       .byte $09 ; |    X  X| $F958 40
       .byte $0D ; |    XX X| $F959 44
       .byte $0D ; |    XX X| $F95A 48
       .byte $08 ; |    X   | $F95B 4C

Above table holds the low nybble of the MSB (the high nybble #$F is added by the kernel).

 

Table LFB00 holds the LSB of objects (grouped in bunches of 4)...which point just beyond the sprite definintions. The lander pointers are these...

 

       .byte $9E ; |X  XXXX | $FB24
       .byte $B2 ; |X XX  X | $FB25
       .byte $C7 ; |XX   XXX| $FB26
       .byte $D3 ; |XX X  XX| $FB27

 

Table LFB50 holds the LSB of just beyond the color definitions. The lander colors:

 

       .byte $DD ; |XX XXX X| $FB74
       .byte $DD ; |XX XXX X| $FB75
       .byte $DD ; |XX XXX X| $FB76
       .byte $DD ; |XX XXX X| $FB77

 

This matches perfectly for what exists for the lander at page $FF.

 

Table LFA00 holds which animation rate to use. 0=ram_F8, 1=ram_F9. The lander's is at $FA09.

 

Just need to find the table which defines sprite height.

Link to comment
Share on other sites

Nevermind...the kernel just displays bitmap values (going upward in Rom) until a zero is reached. No size variable.

 

I found that the hard way. I wanted to change some bitmaps but center them, but the bitmaps have to have a non-zero first and the zero based lines last.

Link to comment
Share on other sites

I always wondered why the smaller "warp in" bitmap had the hook at the top. Now we know...it can't be zero for centering.

 

what's your angle for investigation, I'm apparently going about this wrong.

 

Stella is invaluable here. You can point and click on any image and fill to that point. The kernel routine will show you the values it's using, so you just need to backtrack through a disassembly file to see where they were saved. Rinse and repeat for each step of the value involved. I had a hunch that the large data tables at LFB00/LFB50 were involved in some way (because many of those values matched LSB's where bitmaps and color values were located). Looking for those 2 tags led me to the routine @$F1C9. I already knew from stepping through the display kernel that the upper nybble of MSB pointers was done there, So looking for a table that only had low nybbles in the same pattern as object #'s pointed that one out at $F948. Reading though the routine solved the rest.

 

Kinda haphazard, I know. Brainiacs like Thomas or Dennis could probably do it all in their heads.

Link to comment
Share on other sites

BTW if you are moving things around, take care not to move enemy sprite data below $xx94. The program subtracts the scanline count of where they should appear onscreen from the LSB's before the kernel is executed (so instructions will run over by a cycle if that value ends up to be less than zero). The stargate does not move from it's position, so that object is allowed to be a bit lower in memory. Only color data is allowed to extend right to the end of a page.

 

The player ship and standing humanoids use their own method for display.

Edited by Nukey Shay
Link to comment
Share on other sites

Thank you sir.

 

Before I read this I found that out the hard way. But given the enemies I am changing, colors schemes, etc. I saved enough space to fit in where I can add some new code. I am trying to take a scalpel to the original code to try and maintain the code spacing and image/table areas as well, but I can shift that around if needed too.

 

I got a test cityscape in, looks like garbage but proves out it can be done. I was trying to port in the CityScape from the original defender, but it needs 12 bytes of RAM free to handle the cityscape area so they can build it and roll it. I was attempting to find enough free ram to handle it. I think i've found 8 bytes (2 4 byte contiguous area), but not 12 (at least not twelve where 4 bytes more are contiguous), which offers a new challenge in deciding what to do next.

 

It is moving along, slowly.... much slower than I was anticipating.

 

For you Stella experts. I don't see it in the doc, the trace back in history is really nice. Is there a way to set watchpoints on RAM so it breaks when a watchpoint is hit?

Link to comment
Share on other sites

I got a test cityscape in, looks like garbage but proves out it can be done. I was trying to port in the CityScape from the original defender, but it needs 12 bytes of RAM free...

 

...or 1 byte of Ram and 240 bytes of Rom:

 

Ram for the index value (value 0-19), and 3 sets of 20 bytes x 4 lines for each register. You could cut this to 160 bytes of Rom if you made the first and 4th buildings identical.

 

The main hurdle is creating enough cycle time to handle the changes...24 cycles to update PF from Rom using an index, or 20 cycles if the 1st and 4th buildings look the same.

Link to comment
Share on other sites

Not sure I can cut out that much ROM space and still retain a good amount of gameplay. Even with cutting out enemies and graphic rotation, I only saved about 100 bytes after compressing everything a bit. I am still working on more compression though. This is a lot of trial and error to move, test, move, test, etc.

 

One thing I am unclear on is:

Data FC00 to FCA0 - obviously this is loaded from some major indexing off a base address. I cannot pinpoint what this block of stuff is actually doing, it all seems to majorly affect gameplay, dimensions, etc.

Data FE22 to FEA7 - seems to be used for the starfield in the background (which I tend to like), but I am surprised at the amount of space needed.

 

Data FCFE to FD8B actually seems to be free....

Link to comment
Share on other sites

Lotta opportunities to cut program code here...I'm slowly working though that (without cutting data tables).

 

The data at $FE22 is used to display the player blip in the radar...in addition to the stars. Uses a large table to reuse the scanline counter as the index. Look above and below LF348 to see how this is used.

 

$FCFE/FF are unused...but I assumed that the lower portion of page $FD is called when your ship is carrying a humanoid? Those ship tables are so long because the blanks are used to fill in space when you are high on the screen (that way, no need to mask off or load pointers).

Edited by Nukey Shay
Link to comment
Share on other sites

I've been on this one for 2 days on and off can you tell where these are called up?

 

Person: FD8C-95

Extra Ship: FD96-9B

Ship: FF8C-FF90

Lives: F840-44

 

I am going to feel really silly if they are called up in bank 2. I've search on MSB, LSB, decrementing and incrementing address off the LSB. I've scanned through bank 0 too, but not quite as thoroughly. These are the last bits that I want to move as far as graphics but I cannot do it until I find how they are referenced.

Link to comment
Share on other sites

There is no "extra ship" (with the person). That is the sprite gfx used when catching a humanoid. Normally, ram $94/$95 (the player ship indirect-y vector) is set to page $FF...displaying a ship without a humanoid below it (that's the one at $FF8C). When you collide with any sprite, it gets recorded in an array starting at ram $B0. This is later checked outside the kernel to decide what to do...

 

       LDX    rA3                     ;3
       DEX                            ;2
LD20B:
       DEX                            ;2
       BMI    LD243                   ;2
       LDA    rB0,X                   ;4
       BPL    LD20B                   ;2 branch if no sprite collisions for this section
       LDY    read+$43,X              ;4
       LDA    r99                     ;3
       SBC    #$05                    ;2
       CMP.wy $E0,Y                   ;4
       BCS    LD243                   ;2
       LDX    read+$22,Y              ;4
       CPX    #$0D                    ;2 check humanoid tag #
  IF INVULNERABLE
       BCC    LD243                   ;2 ignore enemy collisions
  ELSE
       BCC    LD25F                   ;2 branch if any enemy (lower tag # than humanoid)
  ENDIF
       BEQ    LD246                   ;2 branch to catch humanoid
       CPX    #$10                    ;2 Hit stargate?
       BEQ    LD282                   ;2 branch if so
;       CPX    #$10                    ;2 superfluous
       BCS    LD243                   ;2 ignore warp-ins, explosion (higher tag # than stargate
       LDA    #$00                    ;2
       STA    write+$22,Y             ;5
       LDX    rAF                     ;3
       INC    rAF                     ;5
       CLC                            ;2
       LDA    LDE0D,X                 ;4
       JSR    LDC56                   ;6
       LDA    #$D2                    ;2
       STA    r91                     ;3
LD243:
       JMP    LD2F5                   ;3

 

I haven't yet worked out all of that, but the gist is that when a humanoid (tag # $0D) is touched by the ship, the MSB of the ship vector is changed to be page $FD...the ship gfx + humanoid.

 

There's a cheat up above for you :)

 

Not much you can do with those long tables for the ship...the LSB's must remain identical between them.

 

Extra Lives ($F840), Smart Bombs ($F853), and Inviso ($F8DD) are all called by the "print score" subroutine...so those images must reside on the same page as score digits - there's not enough kernel time to change the MSB's! Other text messages and the logo are displayed outside of active gameplay, so those can be on any page).

 

 

LF2D9:
       STX    NUSIZ1                  ;3
       STX    VDELP0                  ;3
       STX    VDELP1                  ;3
       LDY    #$06                    ;2 7 scanlines
       LDA    r81                     ;3 frame counter
       ASL                            ;2
       AND    #$F0                    ;2
       ORA    #$14                    ;2 merge flashing score color
       JSR    LF900                   ;6 draw score
;@01
       LDY    r82                     ;3 Ships in reserve
       BNE    LF2F2                   ;2 branch if ships remain
       JMP    LF118                   ;3
LF2F2:
       DEY                            ;2 (do not count current ship)
       LDA    #<LF840                 ;2 reserve ship gfx location
       JSR    LF66B                   ;6 set LSBs
       LDA    #$32                    ;2 reserve ship color
       LDY    #$04                    ;2 5 scanlines
       JSR    LF900                   ;6 draw ships
;@01
       LDY    r83                     ;3 # smart bombs in reserve
       LDA    #<LF853                 ;2 smart bomb gfx location
       JSR    LF66B                   ;6 set LSBs
       LDY    #$02                    ;2 3 scanlines
       LDA    #$FF                    ;2 smart bomb color
       JSR    LF900                   ;6 draw smart bombs remaining
;@01
       LDY    r84                     ;3 # inviso time in reserve
       LDA    #<LF8DD                 ;2 inviso gfx location
       JSR    LF66B                   ;6 set LSBs
       LDY    #$01                    ;2 2 scanlines
       LDA    #$32                    ;2 inviso color
       JSR    LF900                   ;6 draw inviso remaining
;@01
Link to comment
Share on other sites

More cheats to make testing easier:

 

 

 
LD1A1:
       LDA    CXM0P                   ;3
       BPL    LD1B5                   ;2 branch if not shot by enemy
  IF IMMUNE
       BMI    LD1B5                   ;2 ignore if shot
  ELSE
       LDA    rAB                     ;3
  ENDIF

 

 

  IF INFINITE_SHIPS
       DEC    $2E                     ;5
  ELSE
       DEC    r82                     ;5
  ENDIF
LD3EC:

 

 

;* = $D57D
  IF INFINITE_BOMBS
       DEC    $2E                     ;5
  ELSE
       DEC    r83                     ;5
  ENDIF

 

 

LD5B3:
  IF INFINITE_INVISO
       DEC    $2E                     ;5
  ELSE
       DEC    r84                     ;5
  ENDIF
Link to comment
Share on other sites

Its weird, I moved the graphics for the lander and mutant into FC from FF (updated all the tables). So, the lander gets glitchy occassionally when being destroyed. As soon as I move it back to FF, it starts working fine again. This makes me think that something else is up with the mapping that I am not quite figuring out just yet. So graphics compression is taking a bit more time.

 

I did actually get some code in to change the radar to look more like Defender 1 (trying to get some small wins while doing this). so I have a bar going across almost the entire top of the play area and a full box around the radar area. So, hey, that's kind of cool. I actually found a few places where I could change branching/instructions around to save some cycles and keep the address space uniform.

 

Now back to the graphics.....

Link to comment
Share on other sites

+And the color tables? Gotta be on the same page as the bitmap(s).

 

Why move stuff outta $FF? No wasted space there.

 

 

My thought was, remove enemies which is somewhat what PacManPlus did in Defender Arcade (removing unique Phred, and the guppy completely, I may have to dump the Dynamo too). At that point, consolidate everything up to create as much free space as possible. The thought there is that since there isn't enough free RAM without drastically changing the program, that I would take the "bitmap" idea for the cityscape, but I need to put that somewhere and the best idea was to do in gigantic chunk at the bottom of page 2. Like you said, I need 160 to 240 bytes free for that. On top of that, I need space for the routines to handle the cityscape too.

 

I fixed the glitch, which seemed to be a graphics bitmap spacing thing, which I am not sure I fully understand. I moved the lander FCA0 to FCA9 which gave me 2 0x00 rows at the bottom at FCA0 and FCA1. But, that was casuing a glitch that was making a random and dramatic line of graphics interpreted garbage that would show up from the top to bottom of the pay area for one cycle of the counter. So, I shifted it down to FCA3 to FCAC and let FCA0-FCA2 be 0x00 lines as well; which seemed to solve that, which I cannot explain. I can work with it.

 

I guess one of the things I am surprised as are the two ships (one ship with person). The fall at the end of large 0x00 defined graphics area used for other things. So it looks like the ship reads in a large amount of lines above the end of the ship (including the 0x00 space) to draw the ship graphic. So in reality it appears the ship is drawn across a whole column of the play area, it just happens that most of it is 0x00 so is unseen. ITs not the way I was expecting this to be either, which means I'll have trouble consolidating free space without changing the algorithms that draw the ship/ship with person too.

 

Roadblocks that I'll have to overcome. I'm just a bit surprised at how some of this works. In some cases I see coding that could majorly be consolidated, and in other places, code that is majorly compact and in other places I see places where space is just, for lack of a better term, wasted.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...