Jump to content

Photo

(Apple ][) It's on like Donkey Kong...


99 replies to this topic

#1 The Usotsuki OFFLINE  

The Usotsuki

    River Patroller

  • 2,000 posts
  • Also called "Licca"

Posted Mon Nov 19, 2012 8:35 AM

So after mulling it over all year (literally - my original expression of interest was dated January 2, 2012), I finally had the eureka moment and file-cracked the Apple ][ version of Donkey Kong.

On November 6, I isolated everything that was loaded from the disk to their own files, except for the boot splash. Periodically I made notes about things I figured out from looking at the code in AppleWin's debugger. But something just wasn't sinking in...until very early this morning when I got brainstruck. In a few minutes I banged out some code and got Donkey Kong almost running from ProDOS. (There isn't the memory to use DOS 3.3, which eats almost 10K of conventional RAM. ProDOS uses memory that DOS 3.3 doesn't know about, underneath the ROM, and thus only requires a very small amount of the original 48K for itself, although now it needs 64K instead of 48K.)

I tweaked the code a little bit more...then it struck me again. I had a tool for compressing and decompressing graphics, and it was very small. Could I appropriate it for use in Donkey Kong, as I had in Rocky's Boots a couple days ago? In a word, YES... the way I had designed my own hacks, coupled with the way the original code was written, made it possible to use the same memory space for decompression that was already used to hold the levels, with no harm done because I loaded the graphics before the other data.

So I went from a full disk game (that didn't use the whole disk), to a disk using an early version of ProDOS and having 20K free, to a disk using a late version of ProDOS and having 46.5K free.

I also added the ability to exit the game somewhat cleanly by pressing Ctrl-Reset (it will perform a proper ProDOS exit). That makes it potentially suited for a hard drive install.

http://1.buric.co/dkong8p.dsk.gz

Some further thoughts...
  • Might it be possible to add, using a similar mechanism to the existing levels, the opening cutscene? Everything else is there - Kong climbing the ladder with Pauline under his arm, the elevator level, even the damn PIE LEVEL, and "How High Can You Get?" - it's actually one of the more complete ports of the game.
  • I wonder if it might be possible to hack in support for the Mockingboard, to replace the original Apple sound (if the card is detected) with sound more like the arcade game.
  • Perhaps it might be possible to make it run through all stages on levels 1 and 2 also (the Japanese arrangement) instead of just having Barrels-Rivets on level 1 and Barrels-Elevator-Rivets on level 2.
  • If some POKEs will add features like infinite lives, similar to C64 trainers, I'm willing to add a tool to apply them.
xD?

#2 JamesD OFFLINE  

JamesD

    Quadrunner

  • 8,241 posts
  • Location:Flyover State

Posted Mon Nov 19, 2012 3:04 PM

Mockingboard support would probably be the biggest improvement short of porting it to the IIgs graphics.
However, the Apple II sound is through reads or writes to an address and it's probably hard coded inline in more places than driving a sound chip.
Just placing NOP instructions in place of reads or writes would certainly get rid of the existing sound but playing sounds would require a lot more work.

I have some code I wrote that with minor modification could play the Donkey Kong background music on a Mockingboard using interrupts.
The player code was written for the Oric but the soundchip interface is pretty similar and porting should be easy. I already looked at porting it myself but I don't have a Mockingboard to test on and I don't know what tools are available to get a program running from a disk image on an Apple emulator.

Adding music would involve adding the player code, tying into the existing interrupt handler, adding the Donkey Kong music data, and adding a small amount of code to init/start/stop each tune. Music data is just a list of timing and register info for the sound chip. Data can be pretty large for a complex tune that modifies registers a lot but the code could be a starting point.

Changing the screen order should be just a matter of finding the code responsible for the screen order and patching it.

There may already be info out there on how to add infinite lives to the Apple II version of Donkey Kong.

#3 The Usotsuki OFFLINE  

The Usotsuki

    River Patroller

  • Topic Starter
  • 2,000 posts
  • Also called "Licca"

Posted Mon Nov 19, 2012 9:22 PM

There's a little room in my patch area, though it's only about 117 bytes. (If I move the code patching into the first stage, and remove all writes to the B712-B7FF area, I could gain a bit more.) The first stage (DK.SYSTEM) also has free space from 2071-23FF, and I could push that up to 24FF if I needed so long as I didn't use B700-B7FF. (B700-B711 is used for spill when decompressing the menu, and there are some writes in the RWTS area - I believe, B7E0-B7F1? - which aren't disabled but which are no longer needed.)

DK.SYSTEM loads at 2000, like all SYS files. It's lightly packed - 2400-27FF is moved up to B700 and contains my new file handling code, 2800-3FFF is moved down to 0800-1FFF, and 4000-9FFF stays put.

I don't think A000-A6FF is actually used. It may be possible to slap some patches there too.

#4 JamesD OFFLINE  

JamesD

    Quadrunner

  • 8,241 posts
  • Location:Flyover State

Posted Tue Nov 20, 2012 1:03 PM

Ok, I grabbed the player off my old laptop and took a quick look at the code.

The player needs 6 unused bytes on page 0. That is not an option. If Donkey Kong+DOS uses it all we are done right there.

The current setup routine takes around 71 bytes but much of it is Oric specific setting up a VIA timer and inserting the interrupt handler so BASIC keeps running while the demo played. The stop/cleanup routine is around 20 bytes and it's also Oric specific. These two routines would need to be changed for the Apple/Mockingboard and for use in Donkey Kong.
I like to play nice and save previous settings and restore them when I'm done. Those storage Bytes could probably be eliminated along with the setup/cleanup code that saves/restores them.

The interrupt handler that does the playing is 63 Bytes plus any specific hardware control required on the Apple. VIA control requires something around 10 bytes in the loop on the Oric where a memory mapped AY chip would require 2. I believe the Mockingboard interfaces the AY chips using VIA chips so that probably means 10 more bytes. Another 18+ Bytes would be used to process special commands in the song that aren't present in the demo... plus the actual command code itself which does not exist at present because it wasn't required for a one shot player or the demo data I had.

There is also some start/stop related bytes in addition to that. If you add commands to the song data, there is a table of pointers to the command handlers but an endless repeat would only require one table entry so that's nothing. The command table doesn't have to be at the end of the player section of the code.

If needed, a few bytes/cycles could be saved by assembling it for the 65C02. I'm guessing it would save 15 or so bytes overall, maybe more. The improved stack handling alone would probable do that. I'd leave that as a last resort, however, the code is already there if we choose to enable it.

Each level would require the appropriate song data. I can't remember if songs can safely cross a 256 byte page boundary but I'm guessing not. If it does allow crossing page boundaries, the player might be shrunk a few bytes more if songs don't cross boundaries. I really can't remember, this was written in 2009 with minor changes in 2010.

The code is well documented and it's designed to be located pretty much anywhere you want to put it.

The song data will probably be the worst part. Someone has to write it, and then output the proper format.
The current format is as follows (from the code):
; rem song
; rem wait, number of registers to change,
; register number, new value
; register number, new value
; etc.
; ends when number of registers to change is 0.

There is a wait period.
When the player's timer finishes that it reads the number of registers to change.
If zero, it exits.
If negative, we are executing a command. (optional)
Otherwise it reads register number/setting info and dumps it to the AY chip the appropriate number of times.
And it goes to the next wait.

Since the Mockingboard has two sound chips, this code could be a starting point to play one shot sound effects on the other AY sound chip.
I could add support for 6 channel music as well but sound effects + 6 channel music might be awkward. The player won't care but the music and sound effects must not conflict as far as chip settings go or things won't sound right. 6 channel music would probably require at least 20 more bytes since 10 are required for VIA control alone and the 2nd AY chip is on the other VIA(?).

Edited by JamesD, Tue Nov 20, 2012 1:05 PM.


#5 JamesD OFFLINE  

JamesD

    Quadrunner

  • 8,241 posts
  • Location:Flyover State

Posted Tue Nov 20, 2012 1:12 PM

BTW, the player could be easily adapted to about any sound chip. The music data is chip specific though.

#6 The Usotsuki OFFLINE  

The Usotsuki

    River Patroller

  • Topic Starter
  • 2,000 posts
  • Also called "Licca"

Posted Wed Nov 21, 2012 11:17 AM

Ok, I grabbed the player off my old laptop and took a quick look at the code.

The player needs 6 unused bytes on page 0. That is not an option. If Donkey Kong+DOS uses it all we are done right there.

I'm not sure ProDOS uses much of ZP. I use $06-$09 while loading levels; it might be possible to use a few more bytes in that general area.

The interrupt handler that does the playing is 63 Bytes plus any specific hardware control required on the Apple. VIA control requires something around 10 bytes in the loop on the Oric where a memory mapped AY chip would require 2. I believe the Mockingboard interfaces the AY chips using VIA chips so that probably means 10 more bytes. Another 18+ Bytes would be used to process special commands in the song that aren't present in the demo... plus the actual command code itself which does not exist at present because it wasn't required for a one shot player or the demo data I had.

By "VIA" do you mean the 6522? Since I know the Mockingboard runs the AYs through 6522s.

If needed, a few bytes/cycles could be saved by assembling it for the 65C02. I'm guessing it would save 15 or so bytes overall, maybe more. The improved stack handling alone would probable do that. I'd leave that as a last resort, however, the code is already there if we choose to enable it.


I don't think memory is going to be that big a deal. Even my own code has extra space left because I don't need all the room for RWTS. (ProDOS mostly sits up in the Language Card; I usually treat the system under ProDOS as being fair game apart from the 1K buffer I need for file loading and the 256-byte $BF page.)

#7 JamesD OFFLINE  

JamesD

    Quadrunner

  • 8,241 posts
  • Location:Flyover State

Posted Wed Nov 21, 2012 1:17 PM

VIA is just another name for the 6522.

The 6522 Versatile Interface Adapter (VIA) was an integrated circuit made by MOS Technology, as well as second sources including Rockwell and Synertek. It served as a I/O port controller for the 6502 family of microprocessors, providing the parallel I/O capabilities of the PIA as well as timers and a shift register for serial communications. The 6522 was very popular in computers of the 1980s, particularly Commodore's machines,[1] and was also a central part of the designs of the Apple III, BBC Microcomputer and Apple Macintosh. A high speed, CMOS version, the W65C22S[1], is produced by the Western Design Center (WDC).

http://en.wikipedia.org/wiki/MOS_Technology_6522

I'll see about making the changes to the code for the Mockingboard and a simple demo for the Apple using the existing song data I have.
I can add an endless repeat, 6 channel support, and I'll look at adding code to support one shot sounds.

Just let me know what addresses you want me to use and I'll see if I can make it fit. I don't think memory will really be a problem.
The biggest issue will probably be coming up with the music since I have no idea how the original song was created.

#8 The Usotsuki OFFLINE  

The Usotsuki

    River Patroller

  • Topic Starter
  • 2,000 posts
  • Also called "Licca"

Posted Wed Nov 21, 2012 1:32 PM

What works works, really. I'm not picky. I'll just have to adjust DK.SYSTEM to handle it.

In the current code, most of the B7 page is untouched; with some patching, the whole page can probably be freed, apart from the first 18 bytes, which are used for spill when decompressing the menu graphic. Also, BA79-BAFF is free; by moving some of the code into the first stage load at $2000, of which 2071-23FF is free, I could perhaps squeeze a bit more out of that space. (BB00-BEFF is used for a buffer by ProDOS while loading files, and BF00-BFFF is the only part of ProDOS that exists in the contiguous 48K.) As far as I can tell (I could only check during level 1-1 because of an AppleWin limitation) the A000-A6FF area is also unused, and based on a RAM dump I'd be liable to say 9AA8-9B88 may be fair game as well.

ETA:

I've moved some code so that the BA page is now free from BA40-BAFF. It still works.

If I really need to I can probably kill off all writes to the B7 page and then push a few things down there to get an extra paragraph or two.

ETA2:

B712-B7E7 is apparently safe too.

Edited by The Usotsuki, Wed Nov 21, 2012 2:09 PM.


#9 The Usotsuki OFFLINE  

The Usotsuki

    River Patroller

  • Topic Starter
  • 2,000 posts
  • Also called "Licca"

Posted Wed Nov 21, 2012 2:42 PM

OK, I did some moving around, now that I know what parts of the B7 page are safe (I don't really want to kill off all the writes there, so I'm leaving a landmine at the end).

Currently, in the first stage (which gets overwritten by the title graphic as soon as the second stage begins), $20AB-23EF is free. This is only useful for adding runtime patches or initial file loads before the game starts.

In the second stage, $B923-BAFF is free.

I believe $A000-A6FF is free, although that may be best handled with an overlay.

These should be the safe spots to use for additional coding.

#10 JamesD OFFLINE  

JamesD

    Quadrunner

  • 8,241 posts
  • Location:Flyover State

Posted Wed Nov 21, 2012 3:43 PM

OK, I did some moving around, now that I know what parts of the B7 page are safe (I don't really want to kill off all the writes there, so I'm leaving a landmine at the end).

Currently, in the first stage (which gets overwritten by the title graphic as soon as the second stage begins), $20AB-23EF is free. This is only useful for adding runtime patches or initial file loads before the game starts.

In the second stage, $B923-BAFF is free.

I believe $A000-A6FF is free, although that may be best handled with an overlay.

These should be the safe spots to use for additional coding.

It's probably best to stick it in the $A000-$A6FF area if it's not modified from one level to the next.

#11 The Usotsuki OFFLINE  

The Usotsuki

    River Patroller

  • Topic Starter
  • 2,000 posts
  • Also called "Licca"

Posted Wed Nov 21, 2012 4:03 PM

Haven't tried with the "pies" or "springs", but the other two levels definitely do not touch that memory.

A lot of the code is hitting a "play note" function at 7DC4.7DDD.

Another function, at 7E3D, seems to be playing half of Kong's growl.

#12 The Usotsuki OFFLINE  

The Usotsuki

    River Patroller

  • Topic Starter
  • 2,000 posts
  • Also called "Licca"

Posted Wed Nov 21, 2012 6:41 PM

I started to work on this, but don't think I'd be able to code the whole cutscene.

Posted Image
Well, I do have this as an Apple memory dump, from which this PNG is generated. If I could somehow figure out how to get the Kong-climbing-ladder sprite, then make Kong jump left, right, right, right, left (setting Pauline on the platform in the process) and growl, and then make the engine run that code when you first start a game... (The sound and sprites are already present in the code.)

#13 JamesD OFFLINE  

JamesD

    Quadrunner

  • 8,241 posts
  • Location:Flyover State

Posted Wed Nov 21, 2012 10:29 PM

I watched a video of the arcade machine and the music is pretty simple.

Intro screen music.
How high can you get.
The same tune is always played whenever Mario gets to the top and Kong carries away the girl.
The rivets screen plays it's own tune when you finish it.
There is a tune for whenever you grab a hammer that is played on any screen with a hammer.
The girder screen has a simple repeating 5 note tune.
The conveyer screen has a simple 3 note tune.
The elevator screen doesn't have a tune.
The rivets screen has another very simple 3 note tune.
It would probably take more bytes of code to set up the player to play the short tunes than actual music data.

Given how simple the music is, it probably won't be that difficult. I think the hammer, rivets tune at the top, intro tune, and how high can you get are the most complex and they are probably 20 notes or less. Trying to duplicate the arcade sound more closely would be a lot more work.

<edit>
I forgot the death tune which is also very short.

Edited by JamesD, Wed Nov 21, 2012 10:29 PM.


#14 JamesD OFFLINE  

JamesD

    Quadrunner

  • 8,241 posts
  • Location:Flyover State

Posted Thu Nov 22, 2012 12:55 AM

After some thought, the bouncing spring sound might be a tune or would be more efficient as one than separate single shot sounds.
If the tune is played each time a new spring starts without repeating it *should* stay synced with the video.
It would take careful timing and messing with the sound to get it right though.

#15 JamesD OFFLINE  

JamesD

    Quadrunner

  • 8,241 posts
  • Location:Flyover State

Posted Thu Nov 22, 2012 11:07 PM

Instead of adding the long command handling code just to do an endless repeat, I included a few bytes of code inline that reset the song pointer to the beginning if the # of registers value is negative. It's simple but should work just fine.
I still have a couple changes to make but can't do that until I rework the code that starts a tune.
I also dumped some legacy code that was part of the player before it was interrupt driven so I don't think it got any bigger.
I'll fix that and the Mockingboard stuff tomorrow if I have time.
If I can get the cross development tools to work I might get the player demo done in a few days.

#16 The Usotsuki OFFLINE  

The Usotsuki

    River Patroller

  • Topic Starter
  • 2,000 posts
  • Also called "Licca"

Posted Fri Nov 23, 2012 1:19 AM

:)

I don't have much of a build environment, but it does what I need... xD

(Then again, I'm the fool who used Roland Gustafsson's RDOS instead of DOS 3.3 or ProDOS on some of my disks)

#17 The Usotsuki OFFLINE  

The Usotsuki

    River Patroller

  • Topic Starter
  • 2,000 posts
  • Also called "Licca"

Posted Fri Nov 23, 2012 3:28 AM

Well, I found the "How High Can You Try" routine - it's at 7B92 (7B92-7BFE), which appears to only be called from 41F4.

I'm looking for other possible patches to make which I am noting.

4113- 8D F2 03 STA $03F2
4116- A9 C6	 LDA #$C6
4118- 8D F3 03 STA $03F3
411B- 49 A5	 EOR #$A5
411D- 8D F4 03 STA $03F4

This code tampers with the reset vector - big Do not want! I set it in the first stage to B91D, my "exit" function, so that a reset does a clean exit to ProDOS - I'll have to edit that out. (ETA: This code is indeed skipped by my loader!)

It looks like the "enter game" code starts at 413C. Before jumping to it, the menu loop sets a ZP address (I forgot which) to 0 or 1, i.e., the number of players minus 1.

Several addresses are zeroed in ZP and the 40xx page.

There's some sort of memory manipulation going on, then a whole bunch of ZP is erased, some more diddling, 41E5 stores the stage number (5C - my loader picks up on this) then puts a $FF in $BE. Finally, it turns on full-screen (C052) hi-res (C057) graphics (C050) and calls 7B92.

After the "How High Can You Try" routine, it turns the graphics (C051) off, calls the level loader (6BDB; I replace this function with one of my own, called "ldlvl" in the source), turns the graphics back on, puts a $40 in B2, zeroes A and X, and...then I'm lost.

Edited by The Usotsuki, Fri Nov 23, 2012 3:30 AM.


#18 The Usotsuki OFFLINE  

The Usotsuki

    River Patroller

  • Topic Starter
  • 2,000 posts
  • Also called "Licca"

Posted Fri Nov 23, 2012 7:28 AM

Just checked. 4103-413B is free. (4100-4102 might be free, haven't checked.) I could prolly expand "game start" code down to 4103 if I had to.

I guess the original loader started the game at 4000, 4000 jumped to 4103, and the 40xx page was generally used for additional state.

#19 The Usotsuki OFFLINE  

The Usotsuki

    River Patroller

  • Topic Starter
  • 2,000 posts
  • Also called "Licca"

Posted Fri Nov 23, 2012 7:52 AM

Well, the "standard level victory" code is at 697A. This shows the heart, a little Pauline animation, then Kong climbing, then advances the level.

But I can't exactly understand it to hack it. :<

#20 JamesD OFFLINE  

JamesD

    Quadrunner

  • 8,241 posts
  • Location:Flyover State

Posted Fri Nov 23, 2012 9:43 AM

Well, the "standard level victory" code is at 697A. This shows the heart, a little Pauline animation, then Kong climbing, then advances the level.

But I can't exactly understand it to hack it. :<

Apple II graphics are an interleaved nightmare that isn't very straightforward. I wrote a graphics screen text printing routine for an assembly language class when I was it college. The code was actually quite clever... and if I were to disassemble it, it would be total gibberish! Seems to me I used a lot of offsets in the Y register and a few page zero pointers. I'm guessing that's what you have run into.

I suggest you take the divide and conquer approach. Find where each separate step of the sequence takes place, then try to figure on what a section of code you want to hack does.
When Mario gets to the top of the girder screen, the game takes the following steps:
It draws the heart.
Delays
Erases Kong from where he was standing.
It draws the sprite of Kong with his back turned in the ladder area with one leg up and the other down.
Legs my be one sprite and the body another.
Drawing and erasing Kong seems to just be EORing the Kong sprite with the background.
This eliminates the need for saving and restoring the background.
Draw Kong at new location with XOR, wait, draw Kong again with XOR this erases him, update location for next Kong and start the loop over.
After a couple steps, it erases Pauline and draws the broken heart over the top of the normal one
Then it plays a tune and the Kong sound.
Then Kong continues to move up the ladders drawing only the visible portion of the sprite as it goes.

If you can identify the sound part, the music patch should be simple.
It shouldn't be too difficult to code an intro screen if you can isolate the Kong sprite drawing code.
It's going to need changes to work across a much larger screen area (not just cut and past I'm assuming) but you should be able to reuse much of the code.
Kong Bouncing around and the girders bending will require a lot of new code I'm afraid.

I can try to help you figure out the code if you want... at least once I have the music player ready.

Edited by JamesD, Fri Nov 23, 2012 9:49 AM.


#21 The Usotsuki OFFLINE  

The Usotsuki

    River Patroller

  • Topic Starter
  • 2,000 posts
  • Also called "Licca"

Posted Fri Nov 23, 2012 10:22 AM

xD

Well, I'll see what I can figure out. I'm a horrible coder, honestly.

But knowing the start point is certainly a help XD.

Also - just found where the call is to do the "How High Can You Try" music:
6D9F- 20 C4 7D JSR $7DC4

6A1D is the middle of the "win a level" code, and there's a call to 6C64, that erases Kong.

6b1d calls 6961, this seems to be a delay in Kong's climbing. This might be in the middle of the function that pushes him up the ladder :)?

#22 The Usotsuki OFFLINE  

The Usotsuki

    River Patroller

  • Topic Starter
  • 2,000 posts
  • Also called "Licca"

Posted Fri Nov 23, 2012 10:50 AM

By manipulating the "LDA $80E1, X" at 41E2, you can control what order levels are...

I'm still trying to figure out how to get Japanese order out of that but it shouldn't be too hard.

#23 JamesD OFFLINE  

JamesD

    Quadrunner

  • 8,241 posts
  • Location:Flyover State

Posted Fri Nov 23, 2012 11:10 AM

By manipulating the "LDA $80E1, X" at 41E2, you can control what order levels are...

I'm still trying to figure out how to get Japanese order out of that but it shouldn't be too hard.

This is a total guess, but $80E1 probably contains a table with the level order and the value in A after that point is what level is loaded.
If you alter the data at $80E1, change "LDA $80E1,X" to point to your own table, or use self modifying code to change that address in the instruction under program control that should do the trick.

<edit>
That would make X the counter for which screen you are on. By screen I mean number (1st, 2nd, 3rd, 4rth, 5th...) not girder, conveyer, rivets, elevators.

Edited by JamesD, Fri Nov 23, 2012 11:13 AM.


#24 JamesD OFFLINE  

JamesD

    Quadrunner

  • 8,241 posts
  • Location:Flyover State

Posted Fri Nov 23, 2012 11:25 AM

The self modifying code would look something like this:
 LDA LSB_JAPAN_TABLE
 STA  $41E2+1
 LDA MSB_JAPAN_TABLE
 STA $41E2+2

 LDA LSB_US_TABLE  ;$E1
 STA  $41E2+1
 LDA MSB_US_TABLE ;$80
 STA $41E2+2

As part of the start screen you could ask which screen order to use and just patch the code from there.

#25 The Usotsuki OFFLINE  

The Usotsuki

    River Patroller

  • Topic Starter
  • 2,000 posts
  • Also called "Licca"

Posted Fri Nov 23, 2012 11:33 AM

Yeah. My first attempt at a patch, though, backfired and gave me Barrels all the way.



Reply to this topic



  


0 user(s) are browsing this forum

0 members, 0 guests, 0 anonymous users