MOTIVATION
While working on my "Sprite Thief" program, I found "DROL" in the higher levels to be too difficult for my reflexes.
Just if you are not familiar with the game, it's a platform game in which a small blue robot controlled by the player needs to catch a girl running after a balloon, a boy running after a toy helicopter, and finally, their mom, which is bound on the lowest level of the dungeon. There also is a jet pack lizard and a jet pack crocodile to catch to finish the first and second stages. Various enemies, most are jumping, need to be dodged or shot down. Some enemies are indestructible and must be avoided. In higher levels the enemies start to spit or shoot at the robot.
The game has four stages per level which are freshly reloaded from the floppy disk each time. This is a complication for a hacker who seeks to give invulnerability to the robot. Still, it is possible by invoking the debugger present in AppleWin using the F7 key (alas, the version of LinApple I have has no debugger).
To get invulnerability, wait after a new stage is loaded and wait after the robot appears the first time. Do not apply the patch (see below) before the robot appears, because the same subroutine which is disabled by the patch both spawns the robot and later checks if it got hit. This information is conveyed by zero page location $1E. But we don't manipulate that. Too tedious.
Instead, we take out the hit detection subroutine by replacing the opcode for JSR ($20) with the opcode for BIT abs ($2C). This is a very economical patch. The game uses the same technique to enable and disable subroutines in its main loop ($67CB). Self-modifying code depending on the game state. Aaarg ! Did not see this foul trick in any other piece of 6502 software in all the 40 years.
THE INVULNERABILITY PATCH
After a new stage has been loaded and the robot has appeared, press F7 to invoke the debugger. Not needed for stage #4 with the movie where mom and kids are reunited and the player is praised for his/her skills - no robot there.
Enter the command:
67cb:2c <return>
then press F7 again to continue the game. Rinse and repeat this procedure after a new stage has been loaded.
EFFECT OF THE PATCH
The robot becomes invulnerable. No enemy can harm it. Instead, all the enemies which normally can be destroyed by shooting them get destroyed when they touch the robot. You still can shoot them. In both cases, you get points.
WHY IS THIS PATCH SO SIMPLE ?
I can only make a conjecture here: this behaviour was intentionally programmed into the game, to give the developer a sort of "God" mode, which is a common method to test a game in development. In some games (like Quake) this mode is still present in the release version. But so far I did not find some trigger / secret key combination in DROL to invoke the "God" mode - which would just need to replace that single byte. I did not search too intensively, though. Maybe there is no such combination. I don't have time to look any further.
YET ANOTHER HACK
You can also use the debugger to change zero page location $5E which is the number of lives in BCD. This is how I started hacking the game. Until I had developed the invulnerability patch this was the only way for me to get to level 3 with - almost - honest game play. Except for the 30+ lives my "robot" needed to get there.
CRITICISM
While DROL is one of my favourite Apple II games, full of funny, well animated cartoon like characters, only level 1 is playable for me. Without any hacks / foul tricks I could never complete level 2. I think the jump in difficulty from level 1 to level 2 is far too wild. This may have frustrated many players since the game was released in 1983.
Comments invited !
(Footnote: the DROL.DSK file you can find on the web is a cracked version of the game where the copy protection has been removed back in the early 1983s. Like all too many cracked games, it does not work properly and hangs, at least on LinApple - the "reunion" level 4 never happens. The DROL.WOZ file found on the web works, as it faithfully reproduces the original code, but the version of LinApple I have running under Linux does not support WOZ files. And AppleWin does not have my screentrace patch. Ouch ! This is how a harmless looking "little" projects turns into a man-month sucking coding endavour. But at least I have all the means now to study the mechanics of the game. And to "steal" its funny sprites ;-)
Very interesting! Coincidentally, I just fixed a SC-3000H which runs SC-1000 games, and DROL is one of the games I burned to EPROM to play (It works...).
Maybe I will try this on the Apple II. It would also be very interesting to see if the Sega SC cartridge has this same "feature" in there somewhere.
I wonder if 4am has a clean crack of Drol? His stuff usually works properly.
In post #3, softwarejanitor wrote:
"I wonder if 4am has a clean crack of Drol? His stuff usually works properly."
Uncle Bernie answers:
never mind. This afternoon I have tried the DROL.DSK disk image on AppleWin 1.30.12.0 and it works with it. It did not work with LinApple (hanging in the "reunion screen". The "invulnerability" hack works for both the DSK and WOZ files.
I'm still a bit stuck here as I can't compile AppleWin from the sources, which I did with LinApple to put in my "screen trace" feature which is needed for the "Sprite Thief". It's not a lot of code, 16 lines added or so.
If there is anyone reading this who could compile AppleWin with my "screen trace" add-on, please send me a PM. I will give away the source code (~16 lines !) for free if I can get the resulting AppleWin with the "screen trace" feature. I think AppleWin should have that feature (on-demand streaming hires pages into a file while a game is played) but I could not find it despite there seem to be multiple ways of screen capture implemented in it. But I need 8k Byte raw screen buffer "video" and nothing more sophisticated for my "Sprite Thief" utility.
- Uncle Bernie
I think I have found the reason why the DROL.DSK game hangs in the "reunion screen" when running in LinApple.
There is some code on $68E0 which reads 'bit vapor' (AD 50 C0) and compares it to a constant $80. When I replace the LDA $C050 with LDA #0 NOP (A9 00 EA) then the "reunion screen" hangs on AppleWin in the same way as on LinApple: the mom is there but the kids never appear. So poor mom waits forever and the game won't continue.
I think that LinApple does not properly reproduce the 'bit vapors' left over by the video address generation and so that 'vapor lock' technique to synchronize the game to the video frames fails.
Too late for today to further pursue this. I will look at the difference between the MemReadFloatingBus() routines in both AppleWin and LinApple tomorrow. Maybe I can find the culprit and make the game work on LinApple.
- Uncle Bernie
In post #5, Uncle Bernie wrote:
"I will look at the difference between the MemReadFloatingBus() routines in both AppleWin and LinApple tomorrow. Maybe I can find the culprit and make the game work on LinApple."
Now here is what I found today:
The MemReadFloatingBus() functions of AppleWin and LinApple differ, calling different functions to get the video scanner address. It looks to me as if LinApple was forked from AppleWin too soon, at a stage where there still were problems with the cycle-for-cycle accuracy of the 'bit vapors' needed to make the Vaporlock technique work for all (?) games.
Moving all these improvements from the later AppleWin versions (which I can't compile from the sources, lacking the required Microsoft SDK) to LinApple (which I can compile fine under Linux Mint) looks like a major project I don't have any time for.
So I settled for a crude patch in LinApple to prevent "DROL" from hanging in the "reunion" screen. In the Memory.cpp source file I added the following line of code to the MemReadFloatingBus() function, just before the old return ... line:
if(mem[0x68DE] == 0xA2) return 0x80;
This crude patch of course only works for running DROL on LinApple. Any other game may break if it has a LDX # at address 0x68DE. Oh, and the effect on DROL is that now the kids do appear in the "reunion" screen, and the whole game can now be played through all its levels, but the kids flicker and have poor animation, as the "Vaporlock" loop for moving them at the right time is fooled into thinking it's the right time, always. The high quality of animation in all the other stages other than the "reunion" screen is not affected, however. Only in the "reunion" screen the above if() gets TRUE and this impairs the quality of the animation there.
But for my mission ("stealing" the sprites from DROL and developing the tools for that), it's good enough.
I still hope that some LinApple developer will continue to maintain it and add all the improvements AppleWin got over the last decade into it. But it seems LinApple has no friends to maintain it anymore, so it is stuck in its imperfect state. Which is a pity. Because the "bones" of it are good. But this type of neglect is typical for open source software - most developers / maintainers are students and when they move on to a paying job, then the software they wrote / maintained is abandoned and makes no progress anymore.
The "Apple Avenue" is littered with such emulator wrecks to the left and to the right. Before I got the tip with LinApple, I tried maybe half a dozen Apple II emulators from various decades - some dating back to the 1980s - but none of them would compile under Y2022 Linux Mint anymore. Same is true with some X11 based tools I wrote back in the 1980s. They once worked fine but now are broken. It seems X11 is not maintained anymore for Linux Mint. So I had to start with OpenGL / GLUT to write the "Sprite Thief". Which makes coding mouse based graphics stuff amazingly easy but as I haven't figured out some fine points yet, the rendering of the graphics "stolen" from the game still leaves much to be desired, especially when the window is resized by the user. But I'm getting there.
Comments invited !
- Uncle Bernie
LinApple was indeed forked quite a long time ago. It would probably be good if some of the newer code was backported. I don't have time for that either. For me as it is LinApple is good enough for what I need it for. I mostly prefer to run Apple II software on the real hardware, since that's part of the whole experience. But I understand your project. One of my favorite emulators from the 1990s is one of the ones that no longer works because of changes to the way that color mapping works in modern X11 code. I thought about doing the work to fix it back in the mid 2000s when it broke, but it was easier at that time just to switch to a different emulator.
Here is another Linux port of AppleWin: https://github.com/audetto/AppleWin
This one seems to be under active development right now. I see lots of recent updates from the main AppleWin project. Most importantly Memory.cpp where MemReadFloatingBus() resides is identical to the one in AppleWin for Windows.
This is very valuable information. It may be just what Uncle Bernie is looking for... I'm going to clone the git repository and build it to see how it works.
I had to install a few libraries to get it all to build. It's all there in the docs, but to save other people time, this script should handle everything... If nor there may be a few other libraries needed that I already had installed...
#!/bin/sh
sudo apt install -y build-essential
sudo apt install -y cmake
sudo apt install -y libyaml-dev
sudo apt install -y minizip
sudo apt install -y libminizip-dev
sudo apt install -y qtcreator
sudo apt install -y qtbase5-dev
sudo apt install -y qtbase5-examples
sudo apt install -y qtdeclarative5-dev
sudo apt install -y qtmultimedia5-dev
sudo apt install -y libqt5gamepad5-dev
sudo apt install -y libqt5multimedia5-plugins
sudo apt install -y libboost-program-options-dev
sudo apt install -y libncurses-dev
sudo apt install -y libevdev-dev
sudo apt install -y libsdl2-dev
sudo apt install -y libsdl2-image-dev
sudo apt install -y libgles-dev
sudo apt install -y libpcap-dev
sudo apt install -y libslirp-dev
sudo apt install -y libqhexview-dev
git clone https://github.com/audetto/AppleWin --recursive
cd AppleWin/
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=RELEASE ..
cmake -DBUILD_SA2=ON -DBUILD_LIBRETRO=ON ..
make
sudo make install
OK so I built it... and it seems to run... but am I totally missing something? LinApple I press F3 or F4 and I can pick the disk image I want... What F'ing key is it for this thing? I've tried everything and no bueno.
Are you using SA2? Looks like they deliberately left out some of the hotkeys of the AppleWin UI, but at least they did drag-and-drop for floppies:
Hotkeys
F2
,F5
,F6
,F9
,F11
,F12
andPause
have the same meaning as in AppleWin.Left Alt
andRight Alt
emulate the Open and Solid Apple key.Shift-Insert
pastes the clipboard to the input key buffer.Ctrl-Insert
copies the text screen (in AppleWin this isCtrl-PrintScreen
).More here: https://github.com/audetto/AppleWin/blob/master/source/frontends/sdl/README.md
So how do you select a floppy? Whoever did this seems to have made it completely useless. It needs the F3 and F4 to select floppies. Without that it's pointless. What they talk about for drag and drop of floppies makes no sense at all? I see no place to drop things and where do I drag from? Stupid UI. I don't get it. F3 pop me up a dialog to let me pick a disk image file. How could that be any easier?
OK so you can drag from Files onto the sa2 window... that puts the disk on s6d1... so it at least proves that the emulator works. The UI is worse than what LinApple provides in my opinion... But it may be enough for Uncle Bernie to do what he needs to do.
Based on what I read, they added a setting in System->Settings->Disks->D&D to specify which floppy a drop action would land in. Not sure why they went out of their way to do this, when simply alternating the floppy drive for consecutive drop events would have been much better and easier to implement.