It's a day later than I'd estimated, but last night, I finished the Kyra disassembler, including function detection.
For now, I'm only handling one game - Hand of Fate - but it would be pretty simple to add the other Kyra games as well, as the only things different between them are the "magic" functions, and they're all referred to by a parameter to a specific opcode. However, there's not much point in doing that right now; it won't help me to decompile the bytecode.
Here's an excerpt from the disassembly of a small script:
00000016: jumpTo 0x0 (0)
00000018: push 6 (1)
0000001a: push 3 (1)
0000001c: setCharacterPos (0)
0000001e: addSP 2 (-2)
00000020: push 6 (1)
00000022: push 2 (1)
00000024: setCharacterPos (0)
00000026: addSP 2 (-2)
The next step is to get the code flow analysis working with KYRA, and then it's on to the code generation.
After some work, I've gotten a good, automatic function detection algorithm implemented in the CFG analysis, which engines can choose to opt-in to. This is perfect for Kyra, as some of these scripts really do require you to look at the control flow to determine where they stop.
The algorithm is really pretty simple: we find any unreachable code that is not already inside a function, and follow the code flow to see where that piece of code ends - and that is then registered as a function. However, it still requierd quite a bit of rewriting to accomplish this properly, so it took a bit longer than I'd planned - but it should be worth it.
Here's a relatively small sample script from the HoF CD demo:
and just for the heck of it, here's a really big script (
Warning: full image is 19873x16660 pixels large!):
Now, it's finally time for the code generation part of Kyra. I'd originally planned to finish it Friday, but this took a day longer than planned, so I have a feeling the code generation won't be ready before Saturday - but we'll see. At the very least, I should be able to get it done during the weekend, so I have all of next week to polish the documentation, clean up some of the code, add some small features that would be nice to have - stuff like that.
Well, I did manage to get the code generation running in just one day after all! That's means I have the entire weekend to rewrite the documentation, and there's still the final week after that for polishing everything off.
Here's a function as seen in one of the scripts (INHOME.EMC):
00000F88: global_sub0xF88() {
00000F8A: if ((-1 < var4)) {
00000F94: if (!(var17)) {
00000F9C: var17 = 1;
00000FA0: retval = auto_sub0x33C(30, 0, 28);
00000FAC: retval = o1_queryGameFlag(2);
00000FB2: localvar1 = retval;
00000FB6: retval = o1_queryGameFlag(1);
00000FBC: localvar2 = retval;
00000FC0: var3 = 1;
00000FC4: if ((localvar2 && localvar1)) {
00000FCE: retval = o2_zanthiaChat("At least I found my cauldron and my spellbook.", 29);
00000FD6: return;
00000FDA: }
00000FDA: if (localvar1) {
00000FE0: retval = o2_zanthiaChat("At least I found my cauldron.", 30);
00000FE8: return;
00000FEC: }
00000FEC: if (localvar2) {
00000FF2: retval = o2_zanthiaChat("At least I found my spellbook.", 31);
00000FFA: return;
00000FFE: }
00000FFE: retval = auto_sub0x33C(34, 0, 32);
0000100A: retval = auto_sub0x33C(35, 0, 33);
00001016: return;
0000101C: } else {
0000101C: var17 = 0;
00001020: retval = o2_randomSceneChat();
00001020: }
00001022: var3 = 1;
00001026: return;
0000102A: }
0000102A: retval = o2_useItemOnMainChar();
0000102C: return;
0000102C: }
Currently, the decompiler only works with scripts from the talkie version of Kyra2, as one of the functions differ in the number of arguments - but I'll get that fixed before GSoC is over.
Right now, though, I'll focus on the documentation - there's a lot of stuff that needs to be written and rewritten with the changes I've made for Kyra.