Author Topic: C# AGI Interpreter  (Read 55786 times)

0 Members and 1 Guest are viewing this topic.

Offline lance.ewing

Re: C# AGI Interpreter
« Reply #270 on: December 29, 2022, 09:49:19 AM »
No, it seems like the double "return" in LOGIC.13 is decoded fine.

It looks to me like it might be LOGIC.99 that is the problem. The 274 key value is actually in relation to LOGIC 99. Viewing that LOGIC in WinAGI shows that the "if" at the end of the script is missing an ending } which makes me wonder if maybe the LOGIC is missing something for it to jump to, i.e. the location the conditional jump is jumping to doesn't exist. I guess I could either add some code to always ensure that the decoded LOGIC has a "return" at the end, so that in cases like this there is always something to jump to, or I instead make the conditional branch more robust, so that it assumes that a missing jump location means to the end.

That second option doesn't feel clean to mean though. I think I prefer the decoding adding a "return" at the end if there isn't one.

Offline lance.ewing

Re: C# AGI Interpreter
« Reply #271 on: December 29, 2022, 10:19:42 AM »
I think I prefer the decoding adding a "return" at the end if there isn't one.

I've made this change locally on my machine and it seems to fix the issue. Unfortunately there is another issue lurking behind that one, something to do with AGI String 0, being that that String is null. I added a quick hack for that to interpret that as an empty string and that has allowed it to continue and now it appears to be showing the Christmas card without any further issues, looping back to the beginning once it has been through all the screens.

I'll make these changes permanently at some point over the next day or so. I just want to think more about why the AGI String was null and why it is only this XMAS card that it is happening on. I assume something to do with the older interpreter version.

Offline AGKorson

Re: C# AGI Interpreter
« Reply #272 on: December 29, 2022, 03:25:45 PM »
The other thing I noticed in WinAGI is that this LOGIC has two return statements at the end of it.

The extra return command is because Sierra's compiler (cg.exe) automatically adds a return statement at the end of every logic. If the programmer included a return in their source code, the compiled logic would then end with two return statements. (Goldrush also has a few examples of this phenomenon.)

It does not have any effect on gameplay; the extra return statement is never used.
« Last Edit: January 16, 2023, 04:20:24 PM by AGKorson »

Offline AGKorson

Re: C# AGI Interpreter
« Reply #273 on: December 29, 2022, 03:51:07 PM »
No, it seems like the double "return" in LOGIC.13 is decoded fine.

It looks to me like it might be LOGIC.99 that is the problem. The 274 key value is actually in relation to LOGIC 99. Viewing that LOGIC in WinAGI shows that the "if" at the end of the script is missing an ending } which makes me wonder if maybe the LOGIC is missing something for it to jump to, i.e. the location the conditional jump is jumping to doesn't exist. I guess I could either add some code to always ensure that the decoded LOGIC has a "return" at the end, so that in cases like this there is always something to jump to, or I instead make the conditional branch more robust, so that it assumes that a missing jump location means to the end.

That second option doesn't feel clean to mean though. I think I prefer the decoding adding a "return" at the end if there isn't one.
The reason for this odd situation is because this logic (it's a debug logic, probably borrowed from some other game) ends with a quit command, but was originally compiled in version 2.089 (or earlier) when the quit command didn't take an argument. So the last byte of the logic, before the message section, is in fact a return (byte code 00). But since the interpreter packaged with the game is 2.272, WinAGI thinks the quit command needs an argument, so it uses the 00 byte code. (If you change the target interpreter version to 2.089, the logic decompiles correctly.)

I know it was compiled in a version that uses no arguments for quit because of the size of the 'if' block that the quit command is inside of. It correctly points to the byte code 00 when the 'if' block returns false.

Even though the logic is being run in version 2.272 interpreter, it works fine in MSDOS because the 'if' block has the correct offset value. And if the 'said' command evaluates to TRUE, you also don't see any effect of this when run in MSDOS because the quit command terminates the game immediately, and never tries to read past the end of the logic.

You did help me find an obscure bug in WinAGI's decompiler. Since the decompiler thinks the last byte is part of the quit command, it hiccups when it then tries to add the ending bracket because the decompiler's index is one past the expected value. That's why the bracket is missing. I've added a check for this in case it comes up in any other games.

Offline AGKorson

Re: C# AGI Interpreter
« Reply #274 on: December 29, 2022, 03:59:59 PM »
Unfortunately there is another issue lurking behind that one, something to do with AGI String 0, being that that String is null. I added a quick hack for that to interpret that as an empty string and that has allowed it to continue and now it appears to be showing the Christmas card without any further issues, looping back to the beginning once it has been through all the screens.

I'll make these changes permanently at some point over the next day or so. I just want to think more about why the AGI String was null and why it is only this XMAS card that it is happening on. I assume something to do with the older interpreter version.
The concept of a null string has no meaning in the MSDOS interpreter. When a game starts, the string table starts as all zeros. So any functions that read the string values will return a valid string of zero length. My guess is that your interpreter is not setting all 24 (or 12, depending on version) strings to valid zero length strings on start up. If you do that, you shouldn't have any problems with 'uninitialized' strings.

Offline lance.ewing

Re: C# AGI Interpreter
« Reply #275 on: December 30, 2022, 06:04:18 AM »
The reason for this odd situation is because this logic (it's a debug logic, probably borrowed from some other game) ends with a quit command, but was originally compiled in version 2.089 (or earlier) when the quit command didn't take an argument. So the last byte of the logic, before the message section, is in fact a return (byte code 00). But since the interpreter packaged with the game is 2.272, WinAGI thinks the quit command needs an argument, so it uses the 00 byte code. (If you change the target interpreter version to 2.089, the logic decompiles correctly.)

I know it was compiled in a version that uses no arguments for quit because of the size of the 'if' block that the quit command is inside of. It correctly points to the byte code 00 when the 'if' block returns false.

I'm trying to think through if that is the cause of the original issue that Collector reported and I think it is. AGILE will also be seeing that it is interpreter version 2.272 and will therefore decode the "quit" command with the parameter, which explains why the decoded LOGIC doesn't have a "return" at the end. AGILE does support the "quit" command without the parameter, but only if it thinks it is 2.089.

My workaround fixes the issue, and I guess it isn't going to harm anything, i.e. having an additional "return" statement at the end. It can't really determine that the LOGIC was compiled for 2.089, not when the XMAS card "game" was presumably compiled with a mixture of different CG compiler versions. I could add an interpreter version to the game detection data, but that would assume it applies to all LOGICs in the game, so it wouldn't work for this XMAS card game, unless we assume all LOGICs were compiled under 2.089.

Offline lance.ewing

Re: C# AGI Interpreter
« Reply #276 on: December 30, 2022, 06:08:27 AM »
The concept of a null string has no meaning in the MSDOS interpreter. When a game starts, the string table starts as all zeros. So any functions that read the string values will return a valid string of zero length. My guess is that your interpreter is not setting all 24 (or 12, depending on version) strings to valid zero length strings on start up. If you do that, you shouldn't have any problems with 'uninitialized' strings.

I suspected that this was the case, i.e. that AGI doesn't have this distinction. Thanks for confirming this. Yeah, your suspicion is correct, that AGILE doesn't initialise the AGI strings to be empty. I'll fix this now.

Edit: This is now fixed and pushed to my github repo.
« Last Edit: December 30, 2022, 06:29:16 AM by lance.ewing »


SMF 2.0.19 | SMF © 2021, Simple Machines
Simple Audio Video Embedder

Page created in 0.03 seconds with 22 queries.