why? because they have strings like:
char* HE="He\0\0She\0"
char* HIS="His\0Hers\0";
char* HIM="Him\0Her\0";
so they can do like:
printf("Follow %s to %s lair, and capture %s alive!", badguy->name, HIS+badguy->gender, HIM+badguy->gender);
=> More informations about this toot | More toots from foone@digipres.club
I like how the game only asks your name, not your gender.
Player's don't have genders. Only thieves have genders.
=> More informations about this toot | More toots from foone@digipres.club
It's a prequel to Disco Elysium, and your gender is set to COP
=> More informations about this toot | More toots from foone@digipres.club
why does ghidra's "search by instruction pattern" default to BINARY?
what kind of a freak remembers the machine code for INT 21 on x86 in BINARY?
it's CD21h, not 1100110100100001!
what are you, some kind of nerd?
=> More informations about this toot | More toots from foone@digipres.club
I love reversing a string and it's:
void printString(char* str, int length);
and I go look what calls it, reverse that function, and it's:
void printStringSimple(char *str){
printString(str, strlen(str));
}
=> More informations about this toot | More toots from foone@digipres.club
it's like "aww, did someone have second thoughts about making PRINT always take a length, and got tired of having to manually calculate lengths so you just wrapped it?
and your compiler didn't inline SHIT?
=> More informations about this toot | More toots from foone@digipres.club
oh those poor people of Bamako! Someone stole their.
=> More informations about this toot | More toots from foone@digipres.club
okay so when you start a game (well, technically when you restart), the game rolls 3 dice:
0-31: where the shit was stolen from
0-2: which item it is from that location
0-8: whodunnit
=> More informations about this toot | More toots from foone@digipres.club
like if you roll 0 on the first, you get Athens.
For the second one, it's:
0: mask of Priam
1: Achilles's heel
2: sibyl's secret.
=> More informations about this toot | More toots from foone@digipres.club
The last die is used as a lookup table into the dossier's list.
It's got 1 added to it so you won't get Carmen Sandiego, as a rookie at least.
=> More informations about this toot | More toots from foone@digipres.club
so the game uses a pattern like this:
char * RANKS="Rookie\0Sleuth\0Private Eye\0Investigator\0Ace Detective\0"
and then latter they do:
char* your_rank = select_string(RANKS, player->rank);
and select_string is a confusing function to reverse engineer, but knowing the name I gave it gives it away: it advances through the list until it's on the nth string and returns it
=> More informations about this toot | More toots from foone@digipres.club
there is no check for going past the end.
=> More informations about this toot | More toots from foone@digipres.club
so probably it uses the same trick for pronouns. The string I'm seeing is probably like: "He\0Him\0She\0Her\0"
=> More informations about this toot | More toots from foone@digipres.club
Ghidra is officially sexist. It'll automatically detect the word "Female" and mark it as a string, but not the word "Male"!
Why? SEXISM!
or the fact the default minimum length for strings is 5 characters, so "female" is long enough but "male" isn't.
=> More informations about this toot | More toots from foone@digipres.club
correction: there IS a check for going over the end, it's just not used in every place select_string is called. so it's sometimes-safe
=> More informations about this toot | More toots from foone@digipres.club
they have invented a Pronoun Markup Language.
It's \x80 for He/She
It's \x81 for he/she
It's \x82 for his/her
so a string will be "\x80 mentioned \x81 liked seafood and offered me a ride in \x82 motorcycle"
and it'll fill it out based on the pronouns of the suspect
=> More informations about this toot | More toots from foone@digipres.club
BOOOOOOOOOOOOO
=> More informations about this toot | More toots from foone@digipres.club
in trying to hack myself into the game, it glitched and said I had "Hobby: Male"
no... I haven't done that in ages!
=> More informations about this toot | More toots from foone@digipres.club
I'm in the game now
=> More informations about this toot | More toots from foone@digipres.club
I modified the game's NUM_GENDERS and found where it stores the database of criminals, so now you can find me if you search SEX=NB.
=> More informations about this toot | More toots from foone@digipres.club
so in addition to the 5 listed attributes (and their name), the game tracks one hidden attribute:
food preference.
There are only two options:
00=Mexican
01=Seafood
what an odd binary
=> More informations about this toot | More toots from foone@digipres.club
I'm thinking I might do a "full"(ish) disassembly of this game. I've thought for a long while (basically ever since I knew Where In North Dakota is Carmen Sandiego? existed) that there should be an SDK for making your own version of this game, for whatever arbitrary geographical area you want.
=> More informations about this toot | More toots from foone@digipres.club
and of course there's no reason you would have to limit yourself to reality.
You could always do, like, "Where in Middle Earth is Carmen Sandiego?"
=> More informations about this toot | More toots from foone@digipres.club
you go to Rivendell and talk to an Elf who says the perp was talking about how he wanted to collect "his precious"
=> More informations about this toot | More toots from foone@digipres.club
I say "full" in quotes because I don't think I need to reverse the whole game to make it customizable, just enough to let you customize the locations, bad guys, hints, search types, etc.
=> More informations about this toot | More toots from foone@digipres.club
sadly they didn't design the game as a completely empty husk that just loads datafiles. That would have been the smart thing to do, since they could then trivially make new versions.
=> More informations about this toot | More toots from foone@digipres.club
maybe instead of fully decompiling it, I just hack it to grab data from external files, then make a tool for making those files
=> More informations about this toot | More toots from foone@digipres.club
ahh, the PC. No one else ever thought XORing your VRAM was a good idea
=> More informations about this toot | More toots from foone@digipres.club
turns out this version of the game has impressive support for older video cards. Here's Hercules support, which looks horrible without aspect ratio correction!
=> More informations about this toot | More toots from foone@digipres.club
wow, this is actually the first game I've seen actually use the VGA bios call to set the VGA palette. (int 10h, AX=1012h)
=> More informations about this toot | More toots from foone@digipres.club
everyone else just programs the VGA card directly.
=> More informations about this toot | More toots from foone@digipres.club
so when the game starts, it loads:
ACME.DAT
CARMEN.DAT
MIDISND.DAT
DIGISND.DAT
CITIES.DAT
Interestingly, it uses the same code to load the last three, suggesting they're some kind of basic container format
=> More informations about this toot | More toots from foone@digipres.club
starting writing code to generate a JSON file of all the various switchable info in the EXE. Things like hobbies, hair colors, locations, etc.
=> More informations about this toot | More toots from foone@digipres.club
this blit function seems to take a useless first argument, a second argument that's the height, a third argument that's the width, and a fourth argument that doesn't seem to do anything.
notice anything missing? like... a lot of things?
=> More informations about this toot | More toots from foone@digipres.club
I think this game might be doing something weird where blit-source positions and destination positions are all globals, for some fucking reason
=> More informations about this toot | More toots from foone@digipres.club
I think it stores them inside the VGA driver? huh
=> More informations about this toot | More toots from foone@digipres.club
the game internally has 5 drivers (as of 2.2, I have other versions here and they're different): CGA, Hercules, EGA, Tandy, VGA.
=> More informations about this toot | More toots from foone@digipres.club
WHY ARE THERE TWO STRCATS
=> More informations about this toot | More toots from foone@digipres.club
I've been working on cities.dat. I can now confirm that this game (Where in the World is Carmen Sandiego Enhanced (DOS, 1990)) has 30 cities, and they're the same 30 cities as the 1985 original.
=> More informations about this toot | More toots from foone@digipres.club
hmm. I could reuse my readString code between these two formats, but it would technically enable world cities to have pronouns.
=> More informations about this toot | More toots from foone@digipres.club
this game uses a fun text encoding method: both-ended null terminated!
It stores city names with a nul at the beginning because it reads them backwards. For some fucking reason.
=> More informations about this toot | More toots from foone@digipres.club
why in the fuck is loading the data for Paris suddenly grabbing some random data out of Kigali? this implies some weird things about the compression, or the data normalization
=> More informations about this toot | More toots from foone@digipres.club
going to moscow loads the same byte. strange.
=> More informations about this toot | More toots from foone@digipres.club
they seek to position X
read 1 byte
read 99 more bytes
then seek to position X+100
now if you know how both math and random access files work, you'll realize something the programmers of Where in the World is Carmen Sandiego? Enhanced (1990, DOS) did not:
THEY'RE SEEKING TO THE POSITION THEY'RE ALREADY AT
=> More informations about this toot | More toots from foone@digipres.club
I tried to corrupt the image to see if that'd tell me anything about how it was encoded, and it told me to put my hard drive back in.
=> More informations about this toot | More toots from foone@digipres.club
the way this game does the investigations is interesting.
so the basic gameplay is that you're in location X, you get 3 hints, which lead you to location Y, where the whole process repeats.
But if you savescum to experience the same pursuit again, they'll always go through the same places... but if you don't get the hints, they won't be there.
=> More informations about this toot | More toots from foone@digipres.club
like the hints will always tell you to go to sri lanka, but if you go there without first having heard those hints, then he won't be in sri lanka
=> More informations about this toot | More toots from foone@digipres.club
Hah! the game apparently calculates some info ahead of time, but only a few steps. I changed who the suspect was by memory editing, and it didn't take effect... until I got to the third location.
Since I went from a robbery by Fast Eddie B to one by Merey LaRoc, it means the pronouns changed when I got to London.
Congrats on coming out as a trans woman, Merey.
=> More informations about this toot | More toots from foone@digipres.club
ok I ran my dosspin tool to gibberish every byte of the save game file (it's only 102 bytes, so this is easy!) and none of them change where you start. very interesting... I'm guessing either the values are spread out too much for my gibberishing to reach, or you need to modify multiple bytes at once
=> More informations about this toot | More toots from foone@digipres.club
huh, I found a hidden(?) key: if you hold down either shift, it skips all the pauses in the printing. so it goes at MAX CPU SPEED
=> More informations about this toot | More toots from foone@digipres.club
ahh good. it's always fun to find code that looks like:
do{
while(variable!=0);
some one has a custom tick handler that's permutating a global!
=> More informations about this toot | More toots from foone@digipres.club
can't be threading, this is 16-bit DOS. There is no threading.
=> More informations about this toot | More toots from foone@digipres.club
looking at interrupts, and I think I found a bug.
they set handlers for various CPU errors, but they accidentally set 10 (COPROCESSOR ERROR) twice, instead of the 05 (BOUND check)/10 (COPRPOCESSOR) interrupts they save
someone copy-pasted and missed a bit
=> More informations about this toot | More toots from foone@digipres.club
I finally found the two helper functions they use to get and set vectors!
all the 30 other places I've seen them set/get vectors, they do it manually, but hey, maybe they use the helpers too
=> More informations about this toot | More toots from foone@digipres.club
could also be that this is a compiler-provided bit of code, which is left in because the runtime needs it, or they just didn't eliminate dead code
=> More informations about this toot | More toots from foone@digipres.club
okay I've figured out there's a shared format they're using here. it chunks the file into chunks, which have a 16-bit ID (unique per file, but not globally), an offset, and 16-bit length
=> More informations about this toot | More toots from foone@digipres.club
so like, midisnd.dat will have 12 entries, and the first 11 are 200-500 bytes each, and then the last is 3k.
presumably it's each song and then some config info?
=> More informations about this toot | More toots from foone@digipres.club
cities.dat is very interesting. There's 30 cities in total, but 491 entries in it!
So they must be doing something odd there, that doesn't divide equally. Maybe one city-chunk gives IDs of the others?
=> More informations about this toot | More toots from foone@digipres.club
idea for a test: it's easy to spot which chunk in a city is the image, because it's the biggest. Here's a way to determine if it's looking up by IDs or offsets/indices: swap the IDs of two images
=> More informations about this toot | More toots from foone@digipres.club
darn. turns out you can't just renumber the chunks, because they have to be in increasing order.
so maybe I just need to leave the chunk indexes as is, and instead of moving the entries around, I move where they're pointing?
=> More informations about this toot | More toots from foone@digipres.club
Bingo! I'm in Athens, but I'm seeing the image for Baghdad, and apparently with the Baghdad palette?
So one of these other chunks must be the palette for a city. Or it selects from a selection of palettes? Maybe they've just got a couple defined.
=> More informations about this toot | More toots from foone@digipres.club
@foone Carmen Sandiego is INSIDE THE HOUSE!
=> More informations about this toot | More toots from Norgg@mastodon.social
@foone this smells like a bit of code that originally did something else and was then changed to do this redundant thing but nobody noticed
=> More informations about this toot | More toots from vurpo@mastodon.coffee
@foone
Where
In the world
Is
The end of my last read operation?
=> More informations about this toot | More toots from wcbdata@vis.social
@foone To be fair you are at the top of my list of "people who can and will eject hard disks".
=> More informations about this toot | More toots from abstractcode@eigenmagic.net
@abstractcode @foone following foone really brings one to think about the world we're living in, right 🤣
=> More informations about this toot | More toots from ppxl@social.tchncs.de
@foone I distinctly remember an error message from well over 30 years ago saying "drive A: is missing". No, it clearly wasn't... I could see it right there in its drive bay just where it always had been.
=> More informations about this toot | More toots from shdon@mastodon.gamedev.place
@foone
How many of the hints do you need to trigger before they're actually there? This might explain some behavior I remember from long ago...
=> More informations about this toot | More toots from lumecolca@kolektiva.social
@lumecolca just one will do.
=> More informations about this toot | More toots from foone@digipres.club
@foone So, it doesn't populate at all until you see at least one hint, or are they spawned somewhere else and jump to the correct location as soon as you get a hint?
=> More informations about this toot | More toots from jeawallace@topspicy.social
@foone but there are interrupts
=> More informations about this toot | More toots from nil@furry.engineer
@nil exactly!
=> More informations about this toot | More toots from foone@digipres.club
@foone
....yeah but what if you wrote your own TSR swap engine :3
=> More informations about this toot | More toots from munin@infosec.exchange
@munin THEN I DESERVE WHAT I GET
=> More informations about this toot | More toots from foone@digipres.club
@foone Not with that attitude. If a GBA can do threading and DOS can run JavaScript, surely you can do threading in DOS.
=> More informations about this toot | More toots from kawa@mas.to
@kawa YEAH BUT YOU SHOULDN'T
=> More informations about this toot | More toots from foone@digipres.club
@foone SEE? ATTITUDE PROBLEM!
=> More informations about this toot | More toots from kawa@mas.to
@kawa I'LL PROBLEM YOUR ATTITUDE
=> More informations about this toot | More toots from foone@digipres.club
@foone words cannot express how much I'm glad I don't have to deal with interrupt handlers anymore
=> More informations about this toot | More toots from JoshJers@peoplemaking.games
@foone
Quantum???
=> More informations about this toot | More toots from MegaMichelle@a2mi.social
@foone where in the world is c:armen sandiego?
=> More informations about this toot | More toots from Craigp@mastodon.social
@foone they call me the seeker 🎶
=> More informations about this toot | More toots from nobletrout@infosec.exchange
@foone could you explain? Apparently, I know less about RAM than I thought I did (and that I should).
=> More informations about this toot | More toots from PierreM@piaille.fr
@foone I'm hearing the pseudocode in my head to the tune of the Carmen Sandiego theme song
Not sure if that was intended
=> More informations about this toot | More toots from WizardOfDocs@wandering.shop
@foone is it intended that I read the first 5 words as the carmen sandiego theme? It just happened.
=> More informations about this toot | More toots from signaleleven@fosstodon.org
@foone
It feels like a three step process
I've seen more stupid chains of fixes than this in live code, I would love to be right
=> More informations about this toot | More toots from bloognoo@retro.pizza
@foone, one use case immediately comes to mind – are these names displayed right-aligned and in a proportional-print font?
=> More informations about this toot | More toots from lp0_on_fire@social.linux.pizza
@foone now i kind of want a malloc that accepts negative sizes to mean "allocate backwards" (return pointer to the end)
=> More informations about this toot | More toots from jn@boopsnoot.de
@jn nah nah, you just use malloc backwards so you don't need a free!
p=malloc(1234);
// do something with p
malloc(-p); // free p
=> More informations about this toot | More toots from foone@digipres.club
@jn@boopsnoot.de @foone@digipres.club
it would be something like this, wouldn't it?
if (size < 0) {
return sys_malloc(abs(size)) + size;
} else {
return sys_malloc(size);
}
}
=> More informations about this toot | More toots from tauon@possum.city This content has been proxied by September (3851b).Proxy Information
text/gemini