@13:46 Yes, it was just an error! I disassembled the earliest version of code I have (this is actually Crazy Otto). It shows the correct patch for all four monsters: 2745: 2A 0A 4D ld hl,($4D0A) 2748: 3A 2C 4D ld a,($4D2C) 274B: CD 2F 3F call $3F2F 274E: CD 66 29 call $2966 277B: 2A 0C 4D ld hl,($4D0C) 277E: 3A 2D 4D ld a,($4D2D) 2781: CD 2F 3F call $3F2F 2784: CD 66 29 call $2966 27B8: 2A 0E 4D ld hl,($4D0E) 27BB: 3A 2E 4D ld a,($4D2E) 27BE: CD 2F 3F call $3F2F 27C1: CD 66 29 call $2966 2800: 2A 10 4D ld hl,($4D10) 2803: 3A 2F 4D ld a,($4D2F) 2806: CD 2F 3F call $3F2F 2809: CD 66 29 call $2966 Note they all have the same CALL $3F2F. So originally we had it working, all four monsters random, and then we screwed up INKY and SUE when we adjusted the patch code to align with 8-byte boundaries. Ok that is seriously depressing. A bug report for work we did in November 1981, 43 years ago.
Wow, I'm actually flattered that you would take the time to look at the old code! I know the saying goes "better late than never" but maybe 43 years is a bit too late! Thank you!
Didn’t expect one of the Ms. Pac-Man devs to come across this vid and answer this question, awesome! Just curious, when Ms. Pac-Man was still Crazy Otto, did the four monsters have their own names before they were mostly changed back when turning it into Ms. Pac-Man?
The real question is then, why bother lining up patch code with the 8 bit boundaries when it seems you had plenty of room left? I suppose making room for future changes or just trying to be efficient.
@@colinwood9717 In another reply, they explain that the video was wrong to say that that they had plenty of extra space. The PAL chips only offered 42 patches and they used all but two (paraphrasing from their comment; go find the original for details in case I got something wrong).
@@Eventlesstew in the first prototype we showed to Midway, we didn't have time to create a new attract mode. So we used the existing Pac-Man attract mode. Phil Kaaret (I think? might have been Chris Rode) changed the monster names and nicknames as follows: MAD DOG "PLATO" KILLER "DARWIN" BRUTE "FREUD" SAM "NEWTON" Once we signed the deal with Midway, they changed back to their original names. Then, once the hero character changed to female, we switched CLYDE's name. First it changed to BONNIE (get it? Bonnie & Clyde?) and finally to SUE, named after Doug Macrae's sister.
@13:00 Actually the PAL hardware only allowed 42 eight-byte patches. This is because each PAL output is driven by a 7-input OR gate. Each input decodes a single patch address. Six of the PAL outputs are then OR-ed together, making a giant 42-input OR function to detect if this is a patch address. So we ended up with only two spare patches.
@10:07 Yes, your speculation is exactly right. We wanted the patches to align with 8-byte boundaries. So that's why the INKY and SUE patches are different. The reason for the 8-byte boundaries, was a limitation of the PAL chips. The PALs had a limited number of input pins. Eight bytes seemed to be a good compromise. That required decoding eleven Z80 address signals A3-A13.
Oh that's awesome! Thank you for making such a wonderful iteration of Pac-Man, it's a hugely important part of video games history, and I always love hearing the perspective of developers who made these games. I have one simple question: What did working on these arcade hacks look like? Which is to say, what tools and hardware did you use to dump the ROM and modify it?
@@Dutchsnake5 you are most welcome! If you want to know more gory details about our game development, watch my Ms. Pac-Man Postmortem from GDC 2016. It's here on UA-cam.
@14:00 I think your speculation here is correct: we patched INKY and SUE properly at first, and then changed our code! I suspect the fix was originally the same for all the monsters. Once I started designing the patch hardware, we went back and rewrote some of the code such that the patches were on 8-byte boundaries. And it looks like we messed up these two. I have earlier versions of the code, and I may be able to see how these patches were implemented initially. Maybe…
I cannot imagine the feeling of watching a detailed, high-production-value analysis of someone (likely) correctly identifying the reasons behind quirks in your own code.
For all of you wondering why he sounds tired/depressed, he put out a post addressing it on his Bluesky: > For all of my "followup" videos (the ones I put the quicker intro in), I tend to use my footnote voice, which is just my normal speaking voice instead of super enthusiastic voice I use for the main videos. > > Of course that means I get a lot of comments asking if I'm depressed, ha and in another post: > Which I mean... yeah.. but it's not that bad! In fact things have been pretty good lately
Oh! Thank you so much for posting this comment, I was genuinely wondering if he was okay, and wrestling with whether I should ask or not, and trying to figure out a way to ask that wouldn't just come across as annoying or nosy! Very glad to know that he's doing fine and it's just his "footnote voice" 😅
You know you're a hardcore IT guy when the people who wrote the program you're talking about find you and add extra information you missed. Fantastic work as always!
It could be that when they were writing the patches they didn’t know how many they will end up with so they wanted to be efficient with them. At the end it turned out they had plenty to spare but at that point no one went back to look at those two.
this immediately comes to mind. They had to lay all this out manually. Today we could easily write code that could calculate the best way to get the most out of the patch space available that could run even on the hardware of the time but they didn't have software development techniques like this back then. The hardware has advanced a lot but the way we think about and program for any given hardware had advanced a lot as well.
I could understand that would be the case if they didn’t patch the two last ghosts at all, but why patch and waste two of those precious patch blocks on useless code the result of which gets overwritten in the next line? In my opinion it’s far more likely they calculated the position of the second patch relative to the first and used the same offset for the third and fourth patch, without even checking if it landed in the correct place
Same thing I thought. If you went through and knew there was a limit on the amount of patches you could do, you'd try to use as few as possible, and once they got to the end, they probably just saw that the game ran fine and didn't think about going back and changing those to use more patches. In a kind of "If it ain't broke, don't fix it" kind of way...
@@Astervista This is the most likely case. Anything else presumes that the authors decided to purposefully write a patch that was knowingly ineffective and less efficient than not patching anything at all. It would also require them to go out of their way to needlessly complicate their own patch code with the additional ld, jr, ld instructions.
that hijacking thing describes exactly how i've done any romhack requiring custom code. find some empty space, write the code i need, overwrite the bytes where it needs to go with a JMP to the new code and plug the overwritten code into it along with an instruction to JMP back. it always feels so gross to do lol. but it also makes me, a not particularly good programmer, feel incredibly powerful
The Insert ASM codetype for Gecko Codes (GCN and Wii cheat codes) do exactly this as well with unused memory in the reserved space for exception handlers. I've always heard the technique be referred to as a code trampoline.
This is how most nontrivial code changes in ROM hacks work. Since we don't have access to the original ASM code, it's not possible to reassemble the whole ROM, so it's much easier to just patch in a jump to a handler routine that can be written in empty space somewhere.
@@michaelcalvin42 yeah idk how else you'd add to already assembled code, it's just cool to be watching a video and all of a sudden they're describing a process that i spent a bunch of time independently figuring out how to do with basically no asm knowledge. my eyes lit up like "ooh yeah ive done that a few times! 😎" lol
@@ZaurthurNice joke, but going from 0 to 255, or -128 to 127, is still considered a case of integer overflow. “Underflow” is a term only correctly used to refer to a different kind of error with floating point numbers.
@@photonicpizza1466 looking up the term "integer underflow", there are many articles that use the term and describe it to mean exactly what they intended it to mean. it seems that this is a term that is used and has that meaning.
Reminds me of my early days of modding Minecraft. All the “little” runtime patches it took to get the features you wanted. Tiptoeing around the IL byte code to avoid writing in landmines. Good old days. Never would I have imagined something like it purposely existing in a production system. Neat. Thanks for posting!
@@animowany111 .NET's bytecode is called CIL, not just IL. JVM bytecode is indeed an intermediate language. Saying "IL bytecode" is definitely redundant, though.
@@Purely_Andy The difference is that the CIL is often just called IL, especially in .NET-based game modding. Not helped by the fact the main disassembly tool used to be called ILSpy. I've never seen anyone refer to JVM bytecode as "IL" in practice, though. It is technically an intermediate language, but when someone says IL they usually either mean the intermediate language inside compilers like LLVM and GCC - in which case they usually specify further - or they are referring to the CIL, in which case "IL (byte)code" is in fact the common term.
Well, the JVM would at least fail in a much more useful way if you got something wrong. But I don't envy the task of *any* Java reverse engineering before the proliferation of Fernflower, and for Minecraft before Mojang/Microsoft started publishing mappings for their intentionally obfuscated code.
You know what i think would be a great topic for this channel? The instant replay feature in Food Fight. Nobody is quite sure how it works and what triggers it, so it would be nice for someone to explain how it functions.
We would have to ask Jonathan Hurd (the developer/programmer) who could tell you for sure. But as I recall, the collision detection code watches to see how close Chuck came to dying, that is, how many pixels away from a collision (with food, manhole, anything that can kill you). And if you got "this close" without dying, that triggers instant replay. There was a bug during development, where sometimes Chuck would die during the instant replay! It was not being played back exactly the same as the real game. So, what's going on here? What is different with instant replay, vs actual game play? Well, during instant replay, there is music playing! (Thanks to amazing musician/composer Patty Goodson.) And the music playing was enough to tweak the timings of the game play. The fix IIRC was to ALWAYS play the music, but during normal game play the music volume is zero. I think. Maybe. It might be this was a bug in 7800 version of Food Fight, not the arcade. Wow so long ago…
@ Wow! Thank you so much for responding! I didn’t expect one of the original developers from GCE to show up, and yet, here we are. I would still like to know about it in more detail though, like how the game records the inputs and how it plays it back, e.t.c. Still though, thank you for answering.
@@sgolson I always thought the replay just happened every fifth level regardless of how you played it - so long as you completed the level, it would just play it back.
This feels like them writing the patch, thinking for the first two "oh great, this instruction needs to go anyway, let's just override it", and then for the other two "Mmh, can't do that here with one patch. Meh, dunno how many patches we need, and it might be nice to have some spare for potential future spinoffs. I guess it's easier to just copy the ld dir instruction to the startvand fall through. Can't really do it with the instruction after". And simply forgetting that they needed to remove that instruction.
1:47 I appreciate that, where many other channels would break with an apology that Things Are About To Get Even More Complicated, But Just Stick With Me For A Second, instead you just moved on to the topic. You know why we're all here
3:18 HEY!! You're finally showing something in my wheelhouse. ARCADE SCHEMATICS!! 30 Year arcade tech and I collect and restore arcade machines. I own a Ms Pacman myself as well. Mostly CLASSICS, but a few modern as well. Just brought them back from an ANIME CONVENTION a couple of a days ago 😀
What also seems weird is that even if they wanted to only use one patch and replace the previous instruction, they could have still had a change in behavior: Just adjust the return address on the stack to jump over the next load, then the result works correctly. This only requires a few more bytes in the new code, so it should be trivial to add.
This would require the return address to conditionally be modified depending on whether the code was being executed for the first 2 ghosts or last 2 ghosts. In terms of the simplest z80 instructions needed for the operations, if you assume no overflow, it looks like you could do `POP HL; INC; INC; INC; PUSH HL`. That's 1+1+1+1+1 = 5 additional bytes. There's no direct way to add 3 as an immediate in z80. If you assume overflow is possible, you'd need to do `POP HL; LD DE, 3; ADD HL, DE; PUSH HL; which is 1+3+1+1 = 6 additional bytes. There is a 2 byte increment for 16-bit operations that would account for overflow, but that increment (INC ss) is 2 bytes long which would give you 'POP HL; INC HL; INC HL; INC HL; PUSH HL', which is 1+2+2+2+1 = 8 additional bytes. TLDR; looks like the cheapest is 5 or 6 additional bytes depending on whether the return address is at 16-bit boundary.
@@snaphat Instead of using a CALL instruction to reach the GET_RAND_QUADRANT_INKY/SUE subroutines which ultimately fallthrough to GET_RAND_QUADRANT in order to return to the patch's insertion point, the subroutines for Inky and Sue could be written another way. Assuming Inky and Sue's random quadrant subroutine is only used in this place, a fixed jump instruction into a sequence of new instructions containing the hijacked instruction at the insertion point, a CALL instruction to the GET_RAND_QUADRANT subroutine, and another fixed jump back out to the desired location (skipping the unwanted instruction in the original code) would allow for the GET_RAND_QUADRANT subroutine to be reused correctly in a case where using two patches is not wanted.
@@Starwort Oops, apologizes, I wrote that very poorly. I didn't mean to imply it requires extra branch instructions. You get the 5 or 6 extra bytes depending on whether you need to handle overflow or not WITHOUT any additional branch instructions. In terms of where you'd place the instruction sequences, the proper place is directly above the GET_RAND_QUADRANT label
As someone who has been hacking Super Mario World for years, finding out that code hijacks actually have their origin much earlier and used to be done on a hardware level blows my mind! It's also just cool to see just how far technology has come. Back in the days, these super complicated hardware patching mechanisms were needed to save money. Nowadays, when you want to release a patch for a game, you just replace the entire executable and it doesn't even matter, because who cares about these few megabytes of space wasted.
I have no interest in being a computer programmer, even though I was decently competent in class. But if I was building these games in their day, I think I'd really enjoy playing around with the assembly like this.
Very funny. Seems like the developer felt it was unclean to "waste" two patch slots on a single patch, especially since they wouldn't have known upfront how many they were going to use in total. But then they didn't notice that this made their patch functionally useless for two of the ghosts.
Noticed a caption glitch in this video that I think is also present in other Ms. Pac-Man videos. Looks like the software that creates captions based on video script recognises the period in Ms. Pac-Man as the end of a sentence, thus most of the time Ms. ends up being at the end of a subtitle, and Pac-Man at the beginning of the next one. What I think should solve the problem is putting a non-breaking space between Ms. Pac-Man instead of a regular space.
i am always excited for your videos since they are some of the greatest on the platform and have been eager since your community post!! keep up the good work!!!!
I'm guessing that they wrote the patch in a lazy fashion and decided it wasn't worth the effort (or they didn't have time) to fix it. It doesn't seem that if they knew the 8-byte boundaries and the exact code they were patching, it would have been difficult for them to do the patch the "right" way, so it feels like an error or an oversight.
Given the official replies to this video, it seems I was sort of in the right general area, but pretty far off the mark. Thanks for the more specific info straight from the dev!
Ngl the entire concept is really funny You plug in a whole board of extra data chips to patch the game without messing everything up, carefully directing execution through tons of chips in order to move to a bonus function to generate a random number for these ghosts to use… and then immediately after you tell the ghosts to use a preset value anyways
Maybe they intended to use a JMP to jump back to right after the LD instruction, but they forgot to do it? That would allow using just one patch instead of two.
The way they could implement that is to replace the RET at the end of the hijack payload with POP HL, add 3 to it, check if HL points to Inky or Sue (and if so add another 3 to it), then JMP HL.
@@diskpoppyYou'd need to increment it for those two because you're not just skipping the CALL instruction, but also the subsequent LD instruction. But yeah, you're right, you'd need to increment it three times, then an additional three times for those two ghosts.
@@ENCHANTMEN_ oh right, forgot that they also share the code with Blinky and Pinky. that could also be remedied by Inky and Sue's hijack entry points CALLing the common code instead
It's worth noting that the Red and Pink ghosts are the most immediate in their pursuit of Ms. Pac-Man, and since, when the Blue ghost begins to chase, it relies on Red's position, it will already have some chaos injected into its pursuit routine. Since the purpose of the randomness in Ms. Pac-Man was to break Pac-Man's susceptibility to patterns, there just wasn't any need to further randomize Blue's movement. And Orange's function is largely as a spoiler, the other ghosts are plenty efficient in their pursuit of the player themselves, it's mainly around to get in the way and provide a fourth target to chase while Energizers are active.
Sounds like hacking patches into old ROM chips in the early arcade era was at the software level just like rewiring any electrical device in hardware with jumper wires. Not a lot of space on storage chip, very primitive coding languages without automated resorting and renumbering algorithms to help quickly recompile a program to incorporate even minor changes, and hard coding limits mean hijacking electrical signals and bank switching very rapidly becomes a necessary but tangled web to make changes to a piece of software on non-volatile hardware.
I think it's pretty obvious that they tried to be conservative just in case they ended up tight in patch blocks, and also forgetting to disable the old op code.
I wonder if it is because an instruction can't straddle two patches? That might be something that _should_ work but the pal or something causes a timing glitch if you try to grab an instruction from two adjacent patches.
maybe the hardware could not handle two patch blocks in a row without unpatched code between them? there could be some kind of hardware thingus, such as a a latch that saves the patch number when the patch block is entered, and then gets reset when it jumps to an address at 8000-ffff (where the patches live). this would mean the same patch would've gotten executed over and over again. the two separate patches with adjacent blocks wouldn't trigger this kind of event since it is called from different places and not run contiguously.
13:00 Using a single block is also quite possible, eg: replace 11 40 with 37 30 this decodes as scf; jr nc, xx: set carry then jump +xx if carry not set, effectively skipping the extra byte after the patch
There's seems very little chance this was intentional. If they had intended to put the patch for inky and sue where it is located in the final hijack, then there wouldn't be a purpose in performing the hijack at all. 1) If they had decided to make it ineffective at a later point, it would have required them to change both the call site patch location and the injected patch code itself. i.e. from some other set of instructions to the 'LD JR LD' combo at the beginning of the patch code. 2) If for some reason, late in the development, they couldn't *not* perform a patch and had to keep *some* patch in place. They could have just patched the code to be the same code that got replaced instead of the CALL instruction. For example, patch 'LD, A, ' over 'LD, A, '. Of course, there is the possibility that it was a late-stage change, and that whoever was doing the changes didn't realize they could just do something simpler than this by either removing the patch altogether or patching the instructions to the same instructions.
It was enough randomness to get the job done of making it so players just can’t memorize the play patterns. And yeah if Bandai-Namco had just added that feature to Pac-Man, players woulda been mad
I have to wonder if the last 2 bytes of the patches could have been set to something that changes the LD de instructions into something that is effectively a noop, z80 surely has some candidate 3 byte instructions where the last byte wont matter in this situation. Perhaps a load into a different register could have been done perhaps LD bc instead as b and c don't seem to be used here but they might need to be preserved so maybe not. Could also just alter the hijacks to mess with the return address to move it past the ld de instructions. There were solutions to this so they must not have cared or known that it was bugged. I wouldn't expect that Ms Pac-Man went through thorough QA so I'm willing to believe they just didn't know about this problem.
Yep, your idea makes sense. If we had realized this bug, I bet that's how we would have fixed it. Now you've got me wondering what instructions we could have used!
Hm... $40 decodes to "LD B, B", which would be a NOP. Is that actually valid or illegal somehow? From what I see that is a valid NOP on both gameboy CPU and original Z80 - and probably would have been ideal filler here. Unless this CPU was special - such instructions are a typical place to insert vendor specific stuff, as $00 is already the "official" NOP.
@@divVerent No that wont work. Single byte nops wont fix the problem of the 3rd byte of the LD de instruction that can't be changed. If you nop out the first 2 bytes, the third byte will still do something
sheesh, they could even have finished their patches with 18 01 to skip the last byte of the LD DE,target instructions. And if the alignment had been worse (only the opcode byte available to overwrite), they could have written: GET_RAND_QUAD_INKY: LD A, JR GET_RAND_QUAD_FIXUP GET_RAND_QUAD_SUE: LD A, GET_RAND_QUAD_FIXUP: POP DE -- increment return address by 3. INC DE INC DE INC DE PUSH DE GET_RAND_QUADRANT: ....
"assembly code that's already been assembled" is "machine code". would be no different if it were c, c++, rust, etc that's already been compiled. i've never come across machine code being called byte code before. byte code is usually higher level and interpreted at runtime. really interesting video though!
The amount of abstract thinking needed to design a chip that overrides specific code with a new one makes me think it's be easier to just copy the code and update relative addresses after all.
Is it possible it’s a timing issue? You mentioned the only consecutive patches replace two different functions, so presumably there’s a fair amount of time between them being executed. The PAL must introduce some level of delay to address reads, and maybe crossing an 8-byte boundary causes enough delay that the CPU timing contract is violated?
i am guessing its more likely to be eather the first or 3rd reason with a diffrent reason for the first. maby they at the time didnt know you could patch between 2 patch blocks or maby it wasnt in best pratice at the time. i dont think its a second one because they made an effort to prevent a likely diffrent bug.
There is a romset out there called "mspacmab" (Ms. Pac-Man bootleg I suppose) that is essentially this but I'm unsure if it was ever implemented in hardware anywhere.
Maybe they tried playing it, and it was just too easy or too hard the new way. I'm speculating, but there's no real reason someone couldn't make the changes and see how it plays.
How do you see what each bit of code says? Like how to you know if something is a jump function or a call function? If you use a program, tell me what it is because I want to play around with that a bit!
The process is called "disassembly". You can do it by hand using reference tables if you really want to, although this is only really practical for small pieces of code. The process can be automated to some extent using a program called a "disassembler", that supports the particular processor architecture the code was written for (in this case the Zilog Z80). They aren't fool proof, and will usually need some manual intervention in order to produce readable code eg. giving meaningful names to labels, identifying what is code and what is data. The more sophisticated disassemblers actually execute the code on an emulation of the target machine in order to determine whether particular sections of memory are code, data (or even both); they can even identify specific memory areas and give hints as to what the actual function of a routine is. eg. if it's writing to video RAM, reading input ports, writing to sound registers etc. Personally, I use SkoolKit for Z80 disassembly. It's primarily designed around disassembling ZX Spectrum programs, but it's open-source and can be adapted to most Z80 based platforms with a bit of work. However, for a first attempt at disassembling the Pac-Man arcade boards, you may want to start with a more generic Z80 disassembler.
Looked like a mistake to me on first video, or a revert because it made the game too difficult (too unpredictable, too unfair). A good video game AI is a fun one, not a smart one that annihilates the player...
They didn't have the source code. Ms pacman was developed by GCC for a game called crazy otto and licensed to midway, as they were keen on an upgraded game but namco had not developed one (midway were just the US distributor). Originally GCC wanted to make sure they could sell their game without violating namcos copyright. If they had just shipped a patched ROM then they would have violated copyright law. It also had the added benefit of making it slightly harder for people to copy their upgrade. In the end I don't think it was sold as an upgrade and they maybe could have gotten a license, but the work was already done by that point. Ms pacman copyright has been a problem for namco ever since.
Nice video. I like the creativity they had in the early days. Saving lots of resources with a little bit of engineering effort. Most people these days don't do this anymore, be it software or hardware. Example.. Need some boolean status flags? Majority of people: Make an array of N and wonder why memory gets low. People who think about it: Use bit maps and store 32 bool states in 4 Bytes instead. There is a little bit code overhead involved, but thanks to shift operations and logical operations that is quickly optimized on many architectures by default.
I recently got A/B testing on the channel, so the thumbnail isn't set in stone until about a day after the upload goes live. You must have been shown the losing option first!
@13:46 Yes, it was just an error!
I disassembled the earliest version of code I have (this is actually Crazy Otto). It shows the correct patch for all four monsters:
2745: 2A 0A 4D ld hl,($4D0A)
2748: 3A 2C 4D ld a,($4D2C)
274B: CD 2F 3F call $3F2F
274E: CD 66 29 call $2966
277B: 2A 0C 4D ld hl,($4D0C)
277E: 3A 2D 4D ld a,($4D2D)
2781: CD 2F 3F call $3F2F
2784: CD 66 29 call $2966
27B8: 2A 0E 4D ld hl,($4D0E)
27BB: 3A 2E 4D ld a,($4D2E)
27BE: CD 2F 3F call $3F2F
27C1: CD 66 29 call $2966
2800: 2A 10 4D ld hl,($4D10)
2803: 3A 2F 4D ld a,($4D2F)
2806: CD 2F 3F call $3F2F
2809: CD 66 29 call $2966
Note they all have the same CALL $3F2F. So originally we had it working, all four monsters random, and then we screwed up INKY and SUE when we adjusted the patch code to align with 8-byte boundaries.
Ok that is seriously depressing. A bug report for work we did in November 1981, 43 years ago.
Wow, I'm actually flattered that you would take the time to look at the old code! I know the saying goes "better late than never" but maybe 43 years is a bit too late! Thank you!
Didn’t expect one of the Ms. Pac-Man devs to come across this vid and answer this question, awesome!
Just curious, when Ms. Pac-Man was still Crazy Otto, did the four monsters have their own names before they were mostly changed back when turning it into Ms. Pac-Man?
The real question is then, why bother lining up patch code with the 8 bit boundaries when it seems you had plenty of room left? I suppose making room for future changes or just trying to be efficient.
@@colinwood9717 In another reply, they explain that the video was wrong to say that that they had plenty of extra space. The PAL chips only offered 42 patches and they used all but two (paraphrasing from their comment; go find the original for details in case I got something wrong).
@@Eventlesstew in the first prototype we showed to Midway, we didn't have time to create a new attract mode. So we used the existing Pac-Man attract mode. Phil Kaaret (I think? might have been Chris Rode) changed the monster names and nicknames as follows:
MAD DOG "PLATO"
KILLER "DARWIN"
BRUTE "FREUD"
SAM "NEWTON"
Once we signed the deal with Midway, they changed back to their original names. Then, once the hero character changed to female, we switched CLYDE's name. First it changed to BONNIE (get it? Bonnie & Clyde?) and finally to SUE, named after Doug Macrae's sister.
@13:00 Actually the PAL hardware only allowed 42 eight-byte patches. This is because each PAL output is driven by a 7-input OR gate. Each input decodes a single patch address. Six of the PAL outputs are then OR-ed together, making a giant 42-input OR function to detect if this is a patch address.
So we ended up with only two spare patches.
I'm sorry are you one of the actual devs??? Waow
@10:07 Yes, your speculation is exactly right. We wanted the patches to align with 8-byte boundaries. So that's why the INKY and SUE patches are different.
The reason for the 8-byte boundaries, was a limitation of the PAL chips. The PALs had a limited number of input pins. Eight bytes seemed to be a good compromise. That required decoding eleven Z80 address signals A3-A13.
Oh that's awesome! Thank you for making such a wonderful iteration of Pac-Man, it's a hugely important part of video games history, and I always love hearing the perspective of developers who made these games.
I have one simple question: What did working on these arcade hacks look like? Which is to say, what tools and hardware did you use to dump the ROM and modify it?
@@Dutchsnake5 you are most welcome! If you want to know more gory details about our game development, watch my Ms. Pac-Man Postmortem from GDC 2016. It's here on UA-cam.
That sounds very interesting. I love Ms. Pac-Man!
Wait, I watched that analog shutdown video when I was a kid! That was you??
@@PhirePhlame yep that was me! Although there were several other NTSC shutdown videos. Wow long ago…
@12:50 Yes, your good guess is exactly right. Patches were aligned on eight byte boundaries.
@14:00 I think your speculation here is correct: we patched INKY and SUE properly at first, and then changed our code! I suspect the fix was originally the same for all the monsters. Once I started designing the patch hardware, we went back and rewrote some of the code such that the patches were on 8-byte boundaries. And it looks like we messed up these two.
I have earlier versions of the code, and I may be able to see how these patches were implemented initially. Maybe…
having a look at the initial versions of the patches would be so cool!
I cannot imagine the feeling of watching a detailed, high-production-value analysis of someone (likely) correctly identifying the reasons behind quirks in your own code.
@@hanthonyc yes, well, I'm just sitting here thinking "We did what? Really? Ouch…"
@@kalamaike see my comment showing original code, confirming that we had it correct, and then messed it up…
Guy, don't blame yourself, it never mind is a big part of computer history - YOU are part of, grats and thanks for your work!!!
For all of you wondering why he sounds tired/depressed, he put out a post addressing it on his Bluesky:
> For all of my "followup" videos (the ones I put the quicker intro in), I tend to use my footnote voice, which is just my normal speaking voice instead of super enthusiastic voice I use for the main videos.
>
> Of course that means I get a lot of comments asking if I'm depressed, ha
and in another post:
> Which I mean... yeah.. but it's not that bad! In fact things have been pretty good lately
Oh! Thank you so much for posting this comment, I was genuinely wondering if he was okay, and wrestling with whether I should ask or not, and trying to figure out a way to ask that wouldn't just come across as annoying or nosy! Very glad to know that he's doing fine and it's just his "footnote voice" 😅
When you have "resting bitch face", but its your voice and not your face
You know you're a hardcore IT guy when the people who wrote the program you're talking about find you and add extra information you missed. Fantastic work as always!
It could be that when they were writing the patches they didn’t know how many they will end up with so they wanted to be efficient with them. At the end it turned out they had plenty to spare but at that point no one went back to look at those two.
This is my suspicion as well
this immediately comes to mind. They had to lay all this out manually. Today we could easily write code that could calculate the best way to get the most out of the patch space available that could run even on the hardware of the time but they didn't have software development techniques like this back then. The hardware has advanced a lot but the way we think about and program for any given hardware had advanced a lot as well.
I could understand that would be the case if they didn’t patch the two last ghosts at all, but why patch and waste two of those precious patch blocks on useless code the result of which gets overwritten in the next line? In my opinion it’s far more likely they calculated the position of the second patch relative to the first and used the same offset for the third and fourth patch, without even checking if it landed in the correct place
Same thing I thought. If you went through and knew there was a limit on the amount of patches you could do, you'd try to use as few as possible, and once they got to the end, they probably just saw that the game ran fine and didn't think about going back and changing those to use more patches. In a kind of "If it ain't broke, don't fix it" kind of way...
@@Astervista This is the most likely case. Anything else presumes that the authors decided to purposefully write a patch that was knowingly ineffective and less efficient than not patching anything at all. It would also require them to go out of their way to needlessly complicate their own patch code with the additional ld, jr, ld instructions.
that hijacking thing describes exactly how i've done any romhack requiring custom code. find some empty space, write the code i need, overwrite the bytes where it needs to go with a JMP to the new code and plug the overwritten code into it along with an instruction to JMP back. it always feels so gross to do lol. but it also makes me, a not particularly good programmer, feel incredibly powerful
Same!
Interestingly this is also how more advanced cheat engine cheats work.
The Insert ASM codetype for Gecko Codes (GCN and Wii cheat codes) do exactly this as well with unused memory in the reserved space for exception handlers. I've always heard the technique be referred to as a code trampoline.
This is how most nontrivial code changes in ROM hacks work. Since we don't have access to the original ASM code, it's not possible to reassemble the whole ROM, so it's much easier to just patch in a jump to a handler routine that can be written in empty space somewhere.
@@michaelcalvin42 yeah idk how else you'd add to already assembled code, it's just cool to be watching a video and all of a sudden they're describing a process that i spent a bunch of time independently figuring out how to do with basically no asm knowledge. my eyes lit up like "ooh yeah ive done that a few times! 😎" lol
The real reason: Inky and Sue are stubborn. They refuse to change their routine.
A joke so bad it integer underflowed.
I could definitely believe this about Sue or Clyde, but Inky, Blinky, and Pinky always seemed so easygoing.
@@ZaurthurNice joke, but going from 0 to 255, or -128 to 127, is still considered a case of integer overflow. “Underflow” is a term only correctly used to refer to a different kind of error with floating point numbers.
@@photonicpizza1466 the amount I care about this distinction caused an arithmetic underflow.
@@photonicpizza1466 looking up the term "integer underflow", there are many articles that use the term and describe it to mean exactly what they intended it to mean. it seems that this is a term that is used and has that meaning.
Reminds me of my early days of modding Minecraft. All the “little” runtime patches it took to get the features you wanted. Tiptoeing around the IL byte code to avoid writing in landmines. Good old days.
Never would I have imagined something like it purposely existing in a production system. Neat.
Thanks for posting!
IL Byte code? Are you talking about a different game? Minecraft is Java, not .NET.
@@animowany111 I suspect they meant JVM bytecode?
@@animowany111 .NET's bytecode is called CIL, not just IL. JVM bytecode is indeed an intermediate language. Saying "IL bytecode" is definitely redundant, though.
@@Purely_Andy The difference is that the CIL is often just called IL, especially in .NET-based game modding. Not helped by the fact the main disassembly tool used to be called ILSpy.
I've never seen anyone refer to JVM bytecode as "IL" in practice, though. It is technically an intermediate language, but when someone says IL they usually either mean the intermediate language inside compilers like LLVM and GCC - in which case they usually specify further - or they are referring to the CIL, in which case "IL (byte)code" is in fact the common term.
Well, the JVM would at least fail in a much more useful way if you got something wrong. But I don't envy the task of *any* Java reverse engineering before the proliferation of Fernflower, and for Minecraft before Mojang/Microsoft started publishing mappings for their intentionally obfuscated code.
You know what i think would be a great topic for this channel? The instant replay feature in Food Fight. Nobody is quite sure how it works and what triggers it, so it would be nice for someone to explain how it functions.
That’s a great idea!
I don't even know what Food Fight is, but I am now desperate to know how its instant replay feature works. RGME, please make it happen!
We would have to ask Jonathan Hurd (the developer/programmer) who could tell you for sure. But as I recall, the collision detection code watches to see how close Chuck came to dying, that is, how many pixels away from a collision (with food, manhole, anything that can kill you). And if you got "this close" without dying, that triggers instant replay.
There was a bug during development, where sometimes Chuck would die during the instant replay! It was not being played back exactly the same as the real game. So, what's going on here? What is different with instant replay, vs actual game play? Well, during instant replay, there is music playing! (Thanks to amazing musician/composer Patty Goodson.) And the music playing was enough to tweak the timings of the game play. The fix IIRC was to ALWAYS play the music, but during normal game play the music volume is zero.
I think. Maybe. It might be this was a bug in 7800 version of Food Fight, not the arcade. Wow so long ago…
@ Wow! Thank you so much for responding! I didn’t expect one of the original developers from GCE to show up, and yet, here we are. I would still like to know about it in more detail though, like how the game records the inputs and how it plays it back, e.t.c.
Still though, thank you for answering.
@@sgolson I always thought the replay just happened every fifth level regardless of how you played it - so long as you completed the level, it would just play it back.
Interesting bit of trivia: "Zilog announced the discontinuation of the Z80 in April 2024 after nearly five decades of production."
This feels like them writing the patch, thinking for the first two "oh great, this instruction needs to go anyway, let's just override it", and then for the other two "Mmh, can't do that here with one patch. Meh, dunno how many patches we need, and it might be nice to have some spare for potential future spinoffs. I guess it's easier to just copy the ld dir instruction to the startvand fall through. Can't really do it with the instruction after". And simply forgetting that they needed to remove that instruction.
having the actual Dev reply on this video is absolutely fantastic, this is one of the best video series yet!
1:47 I appreciate that, where many other channels would break with an apology that Things Are About To Get Even More Complicated, But Just Stick With Me For A Second, instead you just moved on to the topic. You know why we're all here
3:18 HEY!! You're finally showing something in my wheelhouse. ARCADE SCHEMATICS!! 30 Year arcade tech and I collect and restore arcade machines. I own a Ms Pacman myself as well. Mostly CLASSICS, but a few modern as well. Just brought them back from an ANIME CONVENTION a couple of a days ago 😀
What also seems weird is that even if they wanted to only use one patch and replace the previous instruction, they could have still had a change in behavior: Just adjust the return address on the stack to jump over the next load, then the result works correctly. This only requires a few more bytes in the new code, so it should be trivial to add.
This would require the return address to conditionally be modified depending on whether the code was being executed for the first 2 ghosts or last 2 ghosts. In terms of the simplest z80 instructions needed for the operations, if you assume no overflow, it looks like you could do `POP HL; INC; INC; INC; PUSH HL`. That's 1+1+1+1+1 = 5 additional bytes. There's no direct way to add 3 as an immediate in z80.
If you assume overflow is possible, you'd need to do `POP HL; LD DE, 3; ADD HL, DE; PUSH HL; which is 1+3+1+1 = 6 additional bytes.
There is a 2 byte increment for 16-bit operations that would account for overflow, but that increment (INC ss) is 2 bytes long which would give you 'POP HL; INC HL; INC HL; INC HL; PUSH HL', which is 1+2+2+2+1 = 8 additional bytes.
TLDR; looks like the cheapest is 5 or 6 additional bytes depending on whether the return address is at 16-bit boundary.
Adjusting the return address is slower and takes more effort to get right. They had enough rom space
@@snaphat Instead of using a CALL instruction to reach the GET_RAND_QUADRANT_INKY/SUE subroutines which ultimately fallthrough to GET_RAND_QUADRANT in order to return to the patch's insertion point, the subroutines for Inky and Sue could be written another way. Assuming Inky and Sue's random quadrant subroutine is only used in this place, a fixed jump instruction into a sequence of new instructions containing the hijacked instruction at the insertion point, a CALL instruction to the GET_RAND_QUADRANT subroutine, and another fixed jump back out to the desired location (skipping the unwanted instruction in the original code) would allow for the GET_RAND_QUADRANT subroutine to be reused correctly in a case where using two patches is not wanted.
@@snaphatjust modify the return address immediately before the main routine, the same way the patches already worked
@@Starwort Oops, apologizes, I wrote that very poorly. I didn't mean to imply it requires extra branch instructions. You get the 5 or 6 extra bytes depending on whether you need to handle overflow or not WITHOUT any additional branch instructions. In terms of where you'd place the instruction sequences, the proper place is directly above the GET_RAND_QUADRANT label
Yay, more Pac Man videos!
Hijacks are basically how I added some custom assembly to a romhack I worked on. It is indeed NOT pretty!
The CPU doesn't care and I have a framework I built to make it easy for my projects. Pretty enough. I'm more interested in clock cycles
As someone who has been hacking Super Mario World for years, finding out that code hijacks actually have their origin much earlier and used to be done on a hardware level blows my mind!
It's also just cool to see just how far technology has come. Back in the days, these super complicated hardware patching mechanisms were needed to save money. Nowadays, when you want to release a patch for a game, you just replace the entire executable and it doesn't even matter, because who cares about these few megabytes of space wasted.
Cohost shut down?
Damnit, here goes my monthly reading about game internals :(
I have no interest in being a computer programmer, even though I was decently competent in class. But if I was building these games in their day, I think I'd really enjoy playing around with the assembly like this.
That drive me off the window *the renaming of Clyde to Sue* I eventually learn but what's the question that stuck to me for a very long time
This sentence makes no sense. What are you trying to communicate?
Very funny. Seems like the developer felt it was unclean to "waste" two patch slots on a single patch, especially since they wouldn't have known upfront how many they were going to use in total. But then they didn't notice that this made their patch functionally useless for two of the ghosts.
Before I saw the title saying Mrs Pac-Man, I was confused when I saw the name Sue.
Always a good day when there's a new RGME video 🔥🔥🔥🔥🔥
I always thought Ms. Pac-Man was its own code. I had no idea it was this convoluted.
Noticed a caption glitch in this video that I think is also present in other Ms. Pac-Man videos.
Looks like the software that creates captions based on video script recognises the period in Ms. Pac-Man as the end of a sentence, thus most of the time Ms. ends up being at the end of a subtitle, and Pac-Man at the beginning of the next one. What I think should solve the problem is putting a non-breaking space between Ms. Pac-Man instead of a regular space.
It's amazing how much all of those old bits of code will be dissected while newer games are lucky if anyone takes a second look at them.
Love your fantastic deep dives! Thanks so much for all the effort you put into crafting them. They are a treat for my brain.
“Yeah this code isn’t pretty” it’s some of the coolest and cleverest shit my pea brain has ever seen
i am always excited for your videos since they are some of the greatest on the platform and have been eager since your community post!! keep up the good work!!!!
I'm guessing that they wrote the patch in a lazy fashion and decided it wasn't worth the effort (or they didn't have time) to fix it. It doesn't seem that if they knew the 8-byte boundaries and the exact code they were patching, it would have been difficult for them to do the patch the "right" way, so it feels like an error or an oversight.
Given the official replies to this video, it seems I was sort of in the right general area, but pretty far off the mark. Thanks for the more specific info straight from the dev!
these videos are so interesting thanks for the new upload!!
that "hijack" is exactly what you do for API hooking, Microsoft even begins api with dummy instructions to avoid moving away the overwritten code
Ngl the entire concept is really funny
You plug in a whole board of extra data chips to patch the game without messing everything up, carefully directing execution through tons of chips in order to move to a bonus function to generate a random number for these ghosts to use… and then immediately after you tell the ghosts to use a preset value anyways
yay more pac-man vids
Maybe they intended to use a JMP to jump back to right after the LD instruction, but they forgot to do it? That would allow using just one patch instead of two.
The way they could implement that is to replace the RET at the end of the hijack payload with POP HL, add 3 to it, check if HL points to Inky or Sue (and if so add another 3 to it), then JMP HL.
checking if HL points to Inky or Sue is not needed at all
(and small correction - the return address needs to be incremented thrice, not twice)
@@diskpoppyYou'd need to increment it for those two because you're not just skipping the CALL instruction, but also the subsequent LD instruction.
But yeah, you're right, you'd need to increment it three times, then an additional three times for those two ghosts.
@@ENCHANTMEN_ oh right, forgot that they also share the code with Blinky and Pinky. that could also be remedied by Inky and Sue's hijack entry points CALLing the common code instead
omg a new rgme video ?! on my birthday ?! yippee!!
Happy birthday!
Happy birthday!
Happy birthday!
It's worth noting that the Red and Pink ghosts are the most immediate in their pursuit of Ms. Pac-Man, and since, when the Blue ghost begins to chase, it relies on Red's position, it will already have some chaos injected into its pursuit routine. Since the purpose of the randomness in Ms. Pac-Man was to break Pac-Man's susceptibility to patterns, there just wasn't any need to further randomize Blue's movement. And Orange's function is largely as a spoiler, the other ghosts are plenty efficient in their pursuit of the player themselves, it's mainly around to get in the way and provide a fourth target to chase while Energizers are active.
Thank you for the assembly breakdown
Sounds like hacking patches into old ROM chips in the early arcade era was at the software level just like rewiring any electrical device in hardware with jumper wires.
Not a lot of space on storage chip, very primitive coding languages without automated resorting and renumbering algorithms to help quickly recompile a program to incorporate even minor changes, and hard coding limits mean hijacking electrical signals and bank switching very rapidly becomes a necessary but tangled web to make changes to a piece of software on non-volatile hardware.
Great video as always. Maybe I missed something, but why is it that patches were needed in the first place rather than just swapping the ROM chips?
I think it's pretty obvious that they tried to be conservative just in case they ended up tight in patch blocks, and also forgetting to disable the old op code.
It’s funny that they changed the name Clyde to Sue but kept the same behavior
Woo! New upload ❤
I wonder if it is because an instruction can't straddle two patches? That might be something that _should_ work but the pal or something causes a timing glitch if you try to grab an instruction from two adjacent patches.
The little ghosties are so cute though... ❤️🧡💙💜
👀 emoji: them looking left
I've been a software developer for 2 years and I didn't understant shit, but it is so cool to watch
they could also hijack the LDA line as usual and change the LDDE instruction to something ineffective to use only one patch.
maybe the hardware could not handle two patch blocks in a row without unpatched code between them? there could be some kind of hardware thingus, such as a a latch that saves the patch number when the patch block is entered, and then gets reset when it jumps to an address at 8000-ffff (where the patches live). this would mean the same patch would've gotten executed over and over again. the two separate patches with adjacent blocks wouldn't trigger this kind of event since it is called from different places and not run contiguously.
Do a video on the donkey kong barrels next!
“Now let’s talk about arcade cabinet hardware”
Me, who barely understands how electricity works in the first place: oh fuck yes
love your work please do this forever
Yay new video!
It looks a lot like an oversight and not on purpose at all.
13:00 Using a single block is also quite possible, eg: replace 11 40 with 37 30
this decodes as scf; jr nc, xx: set carry then jump +xx if carry not set, effectively skipping the extra byte after the patch
There's seems very little chance this was intentional.
If they had intended to put the patch for inky and sue where it is located in the final hijack, then there wouldn't be a purpose in performing the hijack at all.
1) If they had decided to make it ineffective at a later point, it would have required them to change both the call site patch location and the injected patch code itself. i.e. from some other set of instructions to the 'LD JR LD' combo at the beginning of the patch code.
2) If for some reason, late in the development, they couldn't *not* perform a patch and had to keep *some* patch in place. They could have just patched the code to be the same code that got replaced instead of the CALL instruction. For example, patch 'LD, A, ' over 'LD, A, '.
Of course, there is the possibility that it was a late-stage change, and that whoever was doing the changes didn't realize they could just do something simpler than this by either removing the patch altogether or patching the instructions to the same instructions.
I can eat food later, rgmechex uploaded
It was enough randomness to get the job done of making it so players just can’t memorize the play patterns. And yeah if Bandai-Namco had just added that feature to Pac-Man, players woulda been mad
I have to wonder if the last 2 bytes of the patches could have been set to something that changes the LD de instructions into something that is effectively a noop, z80 surely has some candidate 3 byte instructions where the last byte wont matter in this situation. Perhaps a load into a different register could have been done perhaps LD bc instead as b and c don't seem to be used here but they might need to be preserved so maybe not. Could also just alter the hijacks to mess with the return address to move it past the ld de instructions. There were solutions to this so they must not have cared or known that it was bugged. I wouldn't expect that Ms Pac-Man went through thorough QA so I'm willing to believe they just didn't know about this problem.
Yep, your idea makes sense. If we had realized this bug, I bet that's how we would have fixed it. Now you've got me wondering what instructions we could have used!
Hm... $40 decodes to "LD B, B", which would be a NOP. Is that actually valid or illegal somehow? From what I see that is a valid NOP on both gameboy CPU and original Z80 - and probably would have been ideal filler here.
Unless this CPU was special - such instructions are a typical place to insert vendor specific stuff, as $00 is already the "official" NOP.
@@divVerent No that wont work. Single byte nops wont fix the problem of the 3rd byte of the LD de instruction that can't be changed. If you nop out the first 2 bytes, the third byte will still do something
@@sgolson Probably the 2-byte long relative jump? Just make it jump over the stray byte to the instruction that's following it...
My mistake, I misread. The 3rd byte of these instructions was not $40. But indeed, JR would work.
sheesh, they could even have finished their patches with 18 01 to skip the last byte of the LD DE,target instructions. And if the alignment had been worse (only the opcode byte available to overwrite), they could have written:
GET_RAND_QUAD_INKY:
LD A,
JR GET_RAND_QUAD_FIXUP
GET_RAND_QUAD_SUE:
LD A,
GET_RAND_QUAD_FIXUP:
POP DE -- increment return address by 3.
INC DE
INC DE
INC DE
PUSH DE
GET_RAND_QUADRANT:
....
Last time I was this early,
I was never this early because this is the first video he's uploaded since I subscribed.
The idea of needing twice as much ROM to hold a game's code as you need to hold it's graphics ....
"assembly code that's already been assembled" is "machine code". would be no different if it were c, c++, rust, etc that's already been compiled. i've never come across machine code being called byte code before. byte code is usually higher level and interpreted at runtime.
really interesting video though!
WOOOOOOOO NEW VIDEO
The amount of abstract thinking needed to design a chip that overrides specific code with a new one makes me think it's be easier to just copy the code and update relative addresses after all.
"But first we have to talk about-"
Parallel Universes???
"...no"
A bus of framerules?
@@KernelLeak the bus _is_ the framerule i thought
Have you tried to contact the guys who founded GCC? They still do talks at retro conference, who knows, maybe they'll remember why.
Thanks for asking; I'll try and answer what I can. Wow, hard to believe this was over FORTY years ago…
I wish you had a fediverse account to follow you on...
Babe wake up, new RGME video just droped
Unexpected but interesting topic
Is it possible it’s a timing issue? You mentioned the only consecutive patches replace two different functions, so presumably there’s a fair amount of time between them being executed. The PAL must introduce some level of delay to address reads, and maybe crossing an 8-byte boundary causes enough delay that the CPU timing contract is violated?
i am guessing its more likely to be eather the first or 3rd reason with a diffrent reason for the first. maby they at the time didnt know you could patch between 2 patch blocks or maby it wasnt in best pratice at the time. i dont think its a second one because they made an effort to prevent a likely diffrent bug.
Player starts at the bottom of the screen and they probably ran into issues with getting killed to early so they reversed it
You just gotta love modders.
I can't seem to find your account on the Fediverse instance I use, weird.
It would be cool to have a modified rom of ms. pacman that has this code patched so inky and sue are also random
What would happen if you tried making a convert Ms.Pac Man arcade without using the daughter board?
There is a romset out there called "mspacmab" (Ms. Pac-Man bootleg I suppose) that is essentially this but I'm unsure if it was ever implemented in hardware anywhere.
I like your funny words magic man
I would have though that a rom chip is cheaper then the pal chips. Do you have an idea why they didn't go that way instead?
Sue, the original gaming trans icon apparently
Good for her
Maybe they tried playing it, and it was just too easy or too hard the new way. I'm speculating, but there's no real reason someone couldn't make the changes and see how it plays.
How do you see what each bit of code says? Like how to you know if something is a jump function or a call function? If you use a program, tell me what it is because I want to play around with that a bit!
The process is called "disassembly". You can do it by hand using reference tables if you really want to, although this is only really practical for small pieces of code.
The process can be automated to some extent using a program called a "disassembler", that supports the particular processor architecture the code was written for (in this case the Zilog Z80). They aren't fool proof, and will usually need some manual intervention in order to produce readable code eg. giving meaningful names to labels, identifying what is code and what is data. The more sophisticated disassemblers actually execute the code on an emulation of the target machine in order to determine whether particular sections of memory are code, data (or even both); they can even identify specific memory areas and give hints as to what the actual function of a routine is. eg. if it's writing to video RAM, reading input ports, writing to sound registers etc.
Personally, I use SkoolKit for Z80 disassembly. It's primarily designed around disassembling ZX Spectrum programs, but it's open-source and can be adapted to most Z80 based platforms with a bit of work. However, for a first attempt at disassembling the Pac-Man arcade boards, you may want to start with a more generic Z80 disassembler.
@@gwishart Wow, thanks so much!
Looked like a mistake to me on first video, or a revert because it made the game too difficult (too unpredictable, too unfair).
A good video game AI is a fun one, not a smart one that annihilates the player...
What about Jr pac man tell me about that one to
Maybe make s video on How NES Pacman Works
cool!
In my headcanon, Sue is called Stinky.
I mean... duh?!
LOL
Oh, hi jack
did sue transition between games
No. Clyde and Sue are different ghosts.
@@sa3270thank goodness
Take a slug of vodka every time he says FFF
I'm surprised they didn't just reassemble the source code.
They didn't have the source code. Ms pacman was developed by GCC for a game called crazy otto and licensed to midway, as they were keen on an upgraded game but namco had not developed one (midway were just the US distributor).
Originally GCC wanted to make sure they could sell their game without violating namcos copyright. If they had just shipped a patched ROM then they would have violated copyright law. It also had the added benefit of making it slightly harder for people to copy their upgrade.
In the end I don't think it was sold as an upgrade and they maybe could have gotten a license, but the work was already done by that point.
Ms pacman copyright has been a problem for namco ever since.
🎉
OK ok ok, but I really need to know why there's no chip co-ordinates for 6G and 6I.
Probably just to prevent any accidental ambiguity, same reason there is no O or Q row.
@RGMechEx Aah, OK, now I can enjoy the rest of my life. Thanks muchly 👍🏽
Nice video. I like the creativity they had in the early days. Saving lots of resources with a little bit of engineering effort.
Most people these days don't do this anymore, be it software or hardware.
Example..
Need some boolean status flags?
Majority of people: Make an array of N and wonder why memory gets low.
People who think about it: Use bit maps and store 32 bool states in 4 Bytes instead. There is a little bit code overhead involved, but thanks to shift operations and logical operations that is quickly optimized on many architectures by default.
I thought they can't change course mid-corridor, only at intersections? So why call their AI every frame?
Is there a reason the thumbnail was changed?
I recently got A/B testing on the channel, so the thumbnail isn't set in stone until about a day after the upload goes live. You must have been shown the losing option first!
@@RGMechEx Fair enough! Thanks!
lfg new rgme time