News:

Herr Otto Partz says you're all nothing but pipsqueaks!

Main Menu
Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Messages - dstien

#1
Quote from: llm on October 10, 2025, 02:00:01 PMax seems to be undefined if x and y = 0 in the asm routine

so the question is: does Stunts rely on this "random" behavior? and if - how to fake it in C?

clvn implemented this by just doing return result; before assigning any value to result. Since this type of randomness isn't portable, I did some (probably too brief) testing and determined that AX is always 0 in the game in these situations. But now that you brought it up I started wondering whether the case could be otherwise in certain circumstances. If I recall correctly, Stunts have a type of bug where a replay can't be fast-forwarded, because the simulation outcome is different than when it's played through, indicating that there's undefined behaviour that changes when the graphics code is involved. I did a repldump batch run on 100s of replays from the Zak Stunts archive, and it turns out that atan(0/0) happens frequently. But every occurrence that I tested in-game has AX=0, for example for @Duplode on ZCT289:

(The replay controls aren't redrawn on every frame, so printf debugging kinda works.)

Does anyone remember some particular replays that has the "can't fast-forward" bug? If not, I guess we should be able to find them automatically. All competition replays are supposed to finish successfully, while a bugged run would either crash or never cross the finish line in repldump.

Edit: Found a bunch of files don't register as finished in the last frame, but the only one I have confirmed with this behaviour so far is zct244/02-ROT.RPL. Haven't found any connection to atan(0/0) though. Looks like hitting water ends the joyride in the pure analysis, while the playback let the car continue straight over the surface.
#2
Quote from: Cas on October 06, 2025, 11:33:59 PMIs it possible to isolate the physical engine for analysis?

Yes, this was the motivation for the repldump utility. We took the code path that Stunts uses when loading a replay from the options menu and processes it to the end, then ripped away as much as we could without breaking it. Simulation still requires a fair bit of loading and initialisation. The old repldump was a bit hairy since we hadn't analysed enough to properly separate the graphics, audio and input initialisation. That's why it changes video mode on startup and throws a fatal error after processing in order to stop all the interrupts. clvn did a lot of analysis and porting since, so with the current knowledge I have streamlined repldump further.

The essential part is:
// ...initialisations...

while (gameconfig.game_recordedframes > state.game_frame) {
    input = td16_rpl_buffer[state.game_frame];
    state.game_frame++;
    player_op(input);
}
repldump is slightly more complicated because we want it to create the exact same game state as the original code, so it also handles the movement of an opponent, the cameras, explosions and FPS smoothing.

player_op() (debug symbol moveplayer) is translated to C in state.c in the original restunts repo. The inner function call to update_car_speed (doengine) is in statecar.c, and update_player_state (movecar) is in stateply.c. These are mostly 1:1 unanalysed ASM to C translations. I can't remember whether they are 100% complete. The other inner function calls upd_statef20_from_steer_input (dosteering) and update_grip (dohandling) are not ported, but these are fairly simple functions. My current focus in restunts2 is to start with the basic leaf functions of the simulation and work my way down the call stack so that all ported code is tested for correctness when it is included.

Quote from: llm on October 07, 2025, 10:08:55 AM
QuoteParticularly the database from the program whose vendor has a history of refusing to sell to people outside the infosec clique.

isn't that like the myth that IDA dropped DOS support (which is only true for IDA freeware versions)

i know serveral private people that bought an IDA license - like me - without any infosec background

Hehe, true. I got a bit carried away with my bombastic parroting of blog hearsay from 18 years ago. At least now I know that 50% of my IDA licence holding friends don't work in the sec biz.

Quote from: llm on October 08, 2025, 11:04:26 AMwill you also try to compare to the original implementation - something like int_atan2 disassembly + C port over the complete integer range or is something like that too much?

That's a good idea to catch corner cases. I added an "-x" option to the DOS build of the unit tests. The full range should be INT16_MIN + 1 .. INT16_MAX - 1 (peak values crashes both implementations), but it takes an eternity to run, so I just used -0x400 .. 0x400

Quote from: llm on October 08, 2025, 11:04:26 AMcompile with current Watcom V2 on Windows for DOS 16bit Model small exe using wcl+wasm
the test run was done on a real DOS 6.22 on VMWare Player (because dosbox failed to run the complete test without hanging)

Does this include the fix I pushed the other day? Strangely I can't reproduce it on my end with dosemu2 or DOSBox. Could you attach the exe file? I'm keen to have a look.
#3
Quote from: Daniel3D on October 27, 2021, 12:37:40 AMASMORIG_OBJFILES = $(ASM_OBJDIR)\segments.obj $(ASMORIG_OBJDIR)\seg000.obj
should be ASMORIG of course.
Not that it matters, but this was intentional. segments.asm was handwritten and there was only supposed to be one copy shared by asm and asmorig.

Quote from: Daniel3D on November 07, 2023, 06:59:33 AM
Quote from: llm on November 07, 2023, 06:38:29 AMdstien isn't the initial creator/svn maintainer of restunts - clvn is - so he never controlled the source
Yeah, I know. But dstien is traceable to an extent outside this community. I know nothing about clvn. So impossible to tell for me if he maintains a copy..
Sadly his batman.no domain has lapsed, but since anders-e.com is still up I'm assuming he's well, just busy with middle-aged life. clvn was a bit of a celebrity in the Norwegian demo scene in the mid-90's. I was surprised to hear him namedropped in a Norwegian podcast about Amiga music a few years back.

Quote from: llm on October 31, 2021, 06:13:42 PMSo dereadnaut, just replace

QuoteA clone of dstien's restunts SVN repository.

with

QuoteA clone of clvn's restunts SVN repository.

dstien got no public SVN repo
Indeed, clvn started and ran this project. He figured out all the bit-trickery that allowed us to rebuild working executables injected with our own code. He did the majority of the analysis and porting to C. I mostly ported low-hanging fruit and cheered on the sideline.

I appreciate the efforts to make the code public, and I have thought about doing it myself from time to time. But I also wanted to do things a bit different, modernise the toolchain, cleaning up cruft, ensuring ported code is both portable and correct, and getting rid of the blobs. Particularly the database from the program whose vendor has a history of refusing to sell to people outside the infosec clique. Seeing the spectacular work of @HerrNove on SuperSight inspired me to have another crack at it. I decided to start with a clean slate to avoid said blobs and avoid offending anyone when deleting their code. Whether the new repo should be placed under the 4d-stunts org or be merged with the mainline repo is not for me to decide, it's still an experiment.

The first order of business was to convert the ID* Pr* database to Ghidra. After discovering that Ghidra provide an XML exporter script for ID*, I got my hopes up. Checking the output of the script confirmed that everything we needed were included, we could just use Ghidra's XML import and this project would be done in an evening or two.

Turned out it would take over a month before I had a working restunts.exe built from Ghidra. First the export script ignored symbols it deemed automatically generated based on their prefix. When we used names like "arg_cheeseburger" it would be dropped. It's just a Python script, so it was a quick fix. Next it turned out that our "arg_cheeseburger" wouldn't be imported at all anyway, as Ghidra's importer ignores function stack frames entirely. I think the reasoning is that Ghidra prefers to trust its own analysis to build the stack frame layout, which it does with its powerful decompiler that can infer arguments and their sizes. Our problem with that, besides losing argument and local variable names, is that Ghidra's support for working with segmented memory appears to be an afterthought. While ID* was first released in 1991 when 16-bit was still dominant, and its segmented memory handling remains a first-class citizen. There are many related issues filed for Ghidra about this, and many remains unactioned for years. There seem to be a, quite natural, distance between the NSA's and the retro community's priorities. I found quite a few pull requests for issues I was having that had been rejected. The maintainers seem understanding, but they don't accept duct tape patches, instead wanting to redesign their cores to properly support the features they initially hadn't accounted for. And it appears there's just never time granted for the NSA to accommodate to nostalgic gamers.

At this point I had long since given up on documenting all the Ghidra issues I found, and just did a LOT of manual fixups. The upside to this was that I got a solid refresher on Stunt's code. The next step was to port the IDC script to Ghidra. I chose the Jython approach to interface with Ghidra's Java API. It's archaic Python 2.7 and very, very slow, but it works right out of the box, no compilation needed, and it's thus very hackable. Initially I thought reproducing TASM output like the original script would be the easiest solution. But nothing is easy. While ID*'s native disassembly syntax is more or less MASM/TASM compatible, Ghidra goes its own way. Things that are implicit in Ghidra may have to be explicit in TASM, and vice versa. When I found myself writing my own x86 disassembler in Ghidra Script in order to format memory operands with proper TASM syntax I realised we might just target a contemporary assembler. I first pivoted towards NASM, it's widely (pun intended) available and has the best documentation of any assembler by far. But its syntax is even further out there. I eventually settled on the Watcom Assembler, whose name unfortunately now means something very different. There are several modern WASM forks, but I wanted to use the whole Watcom toolchain anyway, so I settled on the original to avoid further dependency complexity.

I wanted to make patching of the generated assembly code dynamic. This is done by using the tags <REPLACE>, <INSERT>, <NOP> and <DELETE> in comments. See the README for more details. This also proved to be a convenient crutch when my Ghidra knowledge fell short:


Another change is that only one set of asm files is created, instead using a build-time toggle to determine whether to wire up ported or keep original functions.

Something we wasted a lot of time on back in the day was trying to use unofficial ID* database synchronisation tools so that we could work on it simultaneously. Ghidra comes with its own server which I have set up on re.stunts.no. Anonymous readonly-connections are accepted. For those who want to contribute, send me a PM with a username and I'll add you.

I've gone back to the trusted old wlink. This sacrifices support for Turbo Debugger, but Watcom Debugger also seem very capable:

wlink can also produce DWARF and CodeView debug data, so it may open up for even more debuggers?

For the C code I wanted to carefully pull in one function at a time from the original restunts code. Making sure everything is portable and correct. So far I've only added the good old sin_fast() and cos_fast(), and made unit tests for these. The GitHub repo has a CI-task for building and testing, and test output can be inspected there. I haven't yet made up my mind how we'd go about testing functions with side effects. I don't know how realistic it is, but I want to see how far we can take it by only using Stunts' clib in seg010 and not link in any Watcom libraries as long as we rely on linking with the original code.

I've only tested building on Linux. Adding Windows support again will probably take some work, and I don't know if it's worth it as it probably works out of the box in WSL. There's also no proper dependency tracking for incremental building yet. Compilation is so fast that I've just been doing rm -drf build && make so far. Which I hear is in vogue with the handmade crowd these days anyway.

Quote from: llm on October 28, 2021, 09:25:30 AMit would have been very easy if it was originaly developed for 32bit systems - like many other DOS games - then we could only replace the hardware access stuff and it would then run on windows/linux and we could have used todays development tools - but its just way too old :(
There are two 32-bit builds of Stunts; FM Towns and FM Towns Marty are built for i386, using the Phar Lap 386|DOS-Extender. While FM Towns isn't DOS compatible, and these versions aren't entirely bug-compatible with the DOS versions, there's a lot of shared code that is far more pleasant to explore without segmented memory. This is where the 32-bit anecdote was supposed to end, but I wanted to add these executables to the Ghidra server repo, and since Ghidra don't have a loader for Phar Lap payloads, I had a look at the files to see how much effort it would take:

That's some peculiar structured information after the DATA section... I can't believe it took 32 years for us to find out that WE HAD DEBUG SYMBOLS FOR STUNTS ALL ALONG! It's only public symbols, no types or stack variables, but still. It's over 2000 symbols. Since the porters appears to have kept many of the original DOS funtions as stubs, we even have these names.

Here's a function in the FM Towns Marty port and DOS side-by-side:

This is a striking example showing how spot-on some of the original analysis is, how unknown data now has clear names, and how the FM Towns code deviates from the DOS code when dealing with IO. When the FM Towns code has generated labels (_DAT_addr) it's usually because it is a struct member offset, but we only know the name of the root value.

I added both FM Towns executables in the Ghidra repo with all debug symbols loaded, no further analysis. I discovered this just now, so I haven't explored the symbols in depth yet. I'm not sure if we should adopt all the original names, as some are quitehardtoread compared to our snake_case_notation.

More details on how to connect to the Ghidra server, use the Ghidra script and build is in the repo readme: https://github.com/dstien/restunts2
The problems I encountered myself already are covered in the troubleshooting section.
#4
Quote from: HerrNove on August 13, 2025, 02:45:33 PMLuckily I had enough writing momentum to complete the saga in a matter of days :) Here the grand finale:

https://marnetto.net/2025/08/13/broderbund-stunts-3

Wow! I did not expect to hear about new Stunts discoveries on the orange site. Incredible work, and I can't overstate how delightful I found your in-depth and well-illustrated writeup. Very encouraging to see the restunts project resurrected, I'll have to relearn how to rebuild that relic.
#5
After a long journey around multiple code hosting services, version control systems and repositories, stunpack now has its own GitHub repo with releases and CI pipeline for cross compilation. Have some more features planned before giving stressed and restunts the same treatment.

Latest release
stunpack-0.2.0 (2023-07-12)
  • Brøderbund Stunts 1.0 support
  • MS DOS build (@alex-286)

Past releases
stunpack-0.1.0 (2008-04-12)
  • Extract packed code and resource files from Brøderbund Stunts 1.1 and Mindscape 4D Sports Driving 1.1 for MS DOS.
#6
That's spectacular, Overdrijf! Love this wholesome project. Seeing the Home Computer Museum's related Instagram post a while ago, combining Stunts with that alluring Compaq Presario, prompted me to dive back into Stunts again.

#7
Stunts Chat / Re: Stunts WIKI
June 22, 2023, 10:20:09 AM
Quote from: Duplode on February 04, 2012, 02:35:04 AMA rather less elegant trick, which I just activated for testing, is to disable edit rights for registered users and create a 'trusted' group with edit rights for the above-mentioned accounts(*).

Could we also set the autopatrol permission to the trusted group? If I understand the MediaWiki documentation correctly this is done by adding the line $wgGroupPermissions['trusted']['autopatrol'] = true; to the file LocalSettings.php. Not a big deal, but the patrol flag clutters the changes list for admins. Actually, it is a pretty small deal, but it caused me to check what the patrolling deal was all about.
#8
Team Zone / Re: Slowdrive
January 18, 2016, 02:49:04 PM
Quote from: Shoegazing Leo on January 16, 2016, 12:24:41 AM
Continue with the same formation?

Don't change a winning team. ;D
#11
Thanks for the reminder. Here's my last-minute panic-submission.
#13
dstien // FastSlowdrive // Norway
#14
Stunts Reverse Engineering / Re: bypassing load.exe
March 17, 2015, 11:58:52 PM
Quote from: divip on March 16, 2015, 10:45:10 PM
Hi, I'm divip, a Hungarian coder living in Budapest.

Welcome, divip! Nice to finally hear from the mythical Haskell Stunts project. :)

Quote from: divip on March 16, 2015, 10:45:10 PM
We decided that besides developing the modern Bullet physics, the authentic original physics should also be kept. This is what I am working on now.

Good choice. I too tried to combine Stunts' assets with a modern rendering engine and Bullet once. It turned out to be remarkably boring after just a few minutes. The dirty physics engine is definitely needed. ;D

Quote from: divip on March 16, 2015, 10:45:10 PM
We chose a different path to revive the original physics.
First, we use the uncompressed game.exe as a starting point.

Then we emulate every single 8086 instructions and the needed DOS functions with a Haskell program.
The Haskell emulator is at the moment 3338 LOC, located in 8 files in this directory:
https://github.com/csabahruska/stunts/tree/master/emulate8086
Currently it is a bit slow (takes 26 seconds to reach the main menu), but it seems to do the right job.

Next, we are going automatically transform the machine code into a program library.
This is not trivial at all, but we have some initial results already.

llm was working on a similar approach with Fake86 in C, but time is unfortunately not a renewable resource. Really looking forward to hear more about your progress on this project. In addition to being awesome, the outcome will be useful for restunts as well.
#15
Chat - Misc / Re: Avatar Fight
March 10, 2015, 03:09:27 PM
Quote from: BonzaiJoe on March 10, 2015, 11:11:47 AM
CTG is an internet troll and the psychology of internet trolls is reasonably well established. Happy people don't troll. Trolls use people's reactions to build up a false identity to cover for their real issues with themselves. If you starve them of reactions, they will need to look elsewhere for a magic identity mirror (or actually deal with their issues).

What separates CTG from your run-of-the-mill troll that feasts on hate is that he appears to genuinely love Stunts. He spends a significant portion of his spare time managing competitions, racing at a high level and creating original content. Why he constantly tries to manipulate the only community in the world that shares this passion with him is a mystery to me.