I was gonna say that it would make sense if they originally had a save system that let you save anywhere, but not exactly: some stuff is missing that'd let you have a real mid-level save.
it doesn't save your keys or if you have the access card, which means you could be trapped after reloading a mid-level save
but yeah: despite it technically being visible for 32 years, I never noticed that the game doesn't just save which hallway you're in.
It saves where the duke is relative to the hallway, even if not his actual position.
I just loaded two different saves of Duke in the first hallway. Didn't press any other buttons... but he appears in different places!
guess I'll have to find out where it shows the "you can only save in hallways, dummkopf!" dialog and see if there's an if(!in_hallway && !debug_mode)" before it
I found the part where it shows that dialogbox, it was tricky because it was in Dark Code, but I can't find what calls it for presumably exactly the same reason
it also means there's yet another dialog_box function that's identical to all the others except for a couple things that could be easily parameterized
segmented real mode DOS is so silly.
I know this function is a far call (not a "fall car", as my fingers somehow typed it) so I just need to look for JMP 208e:1bb0, right?
what if instead they JMP to 208F:1BA0? that's the same linear address!
or any of the 256 other possible addresses for the same fucking function?

> Exception while decompiling 208e:4094: Decompiler process died

this would be easier if Ghidra would STOP FUCKING CRASHING

oh god this code better not be jumping into the middle of an instruction
it's always fun to find things like that while looking at disassembly. it's a telltale sign that the compiled code ends here. a human wrote this
here there be dragons
NOPE! it just checks if you're on an even level, and then tells you to fuck off if so.
idea: what happen if I sabotage this check and make it always let you save?
it's time... for hax
75 09 ; JNZ +9
turns into
EB 09 ; JMP +9
There we go! I'm saving mid-level.
and it loads properly. Nothing about the level state is saved (other than your player position relative to the default camera position), mind you, so there's not really any reason to do this.
Although it does... okay I think I may have figured out why they did this. One moment while I test.
okay I think I know why they disabled mid-level saving:
so, they don't save your position or level state when saving a game, but there IS an exploit: the gun powerup
the gun powerup is unique in that it can be collected multiple times. The game is smart enough to not let you collect permanent powerups again: if you enter the level where you get the jump boots already wearing them, they simply won't spawn
but that's not the case with the gun powerup because you collect up to three of them over the course of the game. The game doesn't know if it should make them appear or not, since you may have gotten a previous one
and if you can save mid-level, your gun powerup state is saved.
So you enter level 4, collect the gun powerup, and save. quit and restore your game. You now have the gun powerup, and you can collect it again, getting you to gun level 3. Save and restore again, and now you're max gun level (4).
and making you save only in hallways avoids this. And the game stores the state of duke in the last hallway: so when you use f10 to restart, it takes you back to the last hallway, but you lose all your upgrades

so you can't use this trick.

now I think they could have solved this in another way: make the save function save the state of duke as he entered the level. They already save that for restoring the player when you die

but maybe they didn't figure out this exploit into late in development and just sticking a "you can only save in hallways" patch on it was easier
you can also use this trick to get infinite health, but that's a much less impactful exploit than maxing out your gun much earlier

oh interesting.
the game does reuse a dialog box!

just one of them: The main-hallway hints and Dr. Proton's security-camera taunts? They're literally the same system, with the two sets of text intertwined.

the game selects what message to play based on your current level. on odd-numbered levels, it ends up being a hint message (because those are the hallway levels), and on even-numbered levels, it's dr. proton taunting you
my ghidra is full of a lot of comments like "this actually points to keyboard_interrupt_handler" because ghidra is mis-compiling this so badly
ghidra really doesn't do a great job of handling 32bit pointers in a 16bit real mode program.
The problem is that they're handled as two 16bit integers, not a single 32bit integer.

So sometimes a function fill be like void foobar(int a, int b, char far * string)

and ghidra will be like "oh it takes 4 parameters!"

nope! far pointers are passed as two 16-bit integers but actually represent one 20/24-bit pointer.

honestly real mode x86 is such an abomination of nonsense that we should pretend it doesn't exist.

if only for the minor problem that nearly all PC software and games were written in it for like 12 years

ugh. I don't know what this function even does but I can already tell that the only difference between two adjacent functions is which pointers they use.

TODD, PARAMETERS. PARAMETERS TODD

I'm really doubting the function duplications has anything to do with aggressive compiler optimizations because there's one very small function to determine if something is onscreen or not. It's a couple additions and 4 compares. prime inlining material!

it's not inlined. it's far-called from 148 locations

optimization level: this is a consumer-grade compiler for DOS from 1988, you're lucky we even know what optimization is
I hope this is just me misunderstanding the purpose of this function and this game doesn't just have a function named process_sodas
oh fuck me I think it does
instead of having a big array called like GameObjects and a big update function that loops through them all, I think there's separate arrays for sodas and turkeys and atomic molecules and flags and footballs and floppy disks and and and
and a separate copy-pasted function to update each one
I'm going to set this game on fire

oh god it even does it for static things like doors

apparently every frame it loops through the doors array and checks if the player is standing in front of them and then checks if the player is pushing the up key

instead of, you know, waiting until the user pushes the up key, then figuring out what they're in front of, and triggering the appropriate action
also apparently beating the game gives you 34,464 points.
random-ass number.
at least it doesn't loop over a shoes array, since there can only be one per level
I'm now doing some hybrid static/dynamic debugging. I set a breakpoint on the add_score function, then I'm doing stuff to get points, and seeing what function called add_score
there's a separate function and array that's looped over for EVERY SINGLE ENEMY TYPE
my current theory:
todd replogle didn't really understand C programming but unfortunately did a lot of it when he made duke nukem 1
I think that instead of iterating over all the destructable blocks, it instead calls handle_block_hit from every update function when a bullet doesn't hit an enemy, and that function checks if it was a destructable block and gives you points if it was
but I could be wrong
I hope I'm wrong
for some reason, unlike every other enemy, the rabbitoids are handled in the "main loop" function that also handles the menus
okay so beating the game doesn't give you 34464, it gives you 100,000 points. It's just not clear because WHOOPS a 32bit integer in a 16bit mode?
does add_score take two 16bit integers or one 32bit integer? who can say?

anyway I think I've found them all and there's 29 mostly-copy-pasted functions for updating all the various objects in the game.
29 arrays.
29 number-of-items-in-array variables

WHY TODD

okay I'm too fried to keep working on this anymore today.

but at least I found out the function 1097:7b68: process_floppies

@foone Now I have read all of your comments on this, and I'm glad I couldn't see the mess behind this game while playing it back then. As a programmer, I could only guess that he was inexperienced, and this was his first project.
@foone having recently reverse engineered the entire game logic of Duke 1 myself, this thread was an absolute treat to follow along. Happy to see you're just as baffled by Todd's strange decisions & coding style. 😄
@lethal_guitar oh neat! Is that info online anywhere?
@foone unfortunately not at the moment, as I did this in the context of an upcoming commercial remaster project. But I hope I'll be able to share some things publicly at some point in the future 🙂
@lethal_guitar ahh, cool! Carry on, then, and good luck!
@foone nah this is misleading, the rabbitoids are handled like other enemies. But there's code in the main loop to count how many there are, for the end of level bonus.
@lethal_guitar ahh, good to know. I was following the addscore calls, so I must have missed the bunny update function
@foone I can't help but wonder if any of this helps explain Duke Nukem Forever. Or maybe the entire series is just cursed with bad programming.
@BluJBird nah, he only got "special thanks" credit on that one

@foone

I get the sense that late-80s-era gamedevs tended toward high INT, low WIS.

@foone he made quite a leap with Cosmo and Duke 2. But still often preferred global variables over function parameters, for some reason.
@foone As someone who is normally trying to dissect genius-level code where it's like, "oh yes, we developed this unique system to cram 32KB of data into just 1.9KB and by the way we put it in the display memory using this palette trick" I am living vicariously through this documentary of the same kind of stupid shit I used to do when I'd only been programming a few years.
@foone
Game developers today: "oh no I need to use fancy algorithms to make sure I only check the door the player is in front of"
Game developers then: "I will literally check every possible door each time."