Community
AGI Programming => AGI Development Tools => Topic started by: lance.ewing on October 19, 2016, 05:49:09 PM
-
How many AGI versions are we aware of prior to the introduction of AGI 2?
Recently I've seen:
v1.10: User by the Apple II version of King's Quest 2
v1.12: Used by the original booter PC versions of Black Cauldron
v1.20: Used by the Apple II version of Black Cauldron
I'm pretty sure there must be others.
What version of AGI did the original booter PC versions of King's Quest 2 use?
-
Are these numbers even comparable? I hate to be the one to ask all these questions, but at least in SCI, each platform seems to have had its own versioning scheme. That's one reason why ScummVM dropped the idea of using version numbers directly, as we had done in FreeSCI (another reason being unmarked interpreters - x.yyy.zzz - and partially textual version numbers, such as T.A00.081; I never did find out what lay behind these).
-
The HWM list IDs 5. With the addition of Apple and Atari 9 KQ1.
http://agiwiki.sierrahelp.com/index.php?title=Sierra_AGI_Release_List#AGI1
ETA: Also of note is that he calls KQ1 "AGI0"
-
What version of AGI did the original booter PC versions of King's Quest 2 use?
Unfortunately, it does not print a version number when entering the debug mode, nor is there any version string in the data segment. Version 1.0W's executable however differs from version 1.1H's, so there must be at least two non-numbered versions.
I have managed to extract the resources from version 1.0W and recompile the VOL.X packages so that I can open it in AGI Studio. The picture and view resources open flawlessly (so you know I did not goof in compiling the VOL.X files); the sound resources are known to be in a different format --- Sierra accidently left a utility on the SQ1 1.1A disk to convert sounds to the AGI v2 format --- but the logic resources cannot be decoded at all, and obviously, the game doesn't run when fit with a v2 interpreter.
-
Are these numbers even comparable?
Looking at the link that Collector provided, then I'd say no. :(
That's unfortunate. Clearly the Atari ST version of Donald Duck's Playground can't be using version 1.00C of the Interpreter, in fact given the release date, we'd expect that to actually be AGI v2. So either that number is wrong, or the numbering restarted on the Atari ST platform.
I'm surprised that the Apple II version of KQ1 is also v1.10 of the interpreter. KQ2 on Apple II also uses v1.10. I might need to go and double check that now to make sure I was looking at the right game. Did the two games come out at roughly the same time on that platform?
I have hopes that perhaps the Apple II versioning is in alignment with the versioning used for the PC variants, but perhaps this isn't the case. We'll never know I guess.
-
I have managed to extract the resources from version 1.0W and recompile the VOL.X packages so that I can open it in AGI Studio. The picture and view resources open flawlessly (so you know I did not goof in compiling the VOL.X files); the sound resources are known to be in a different format --- Sierra accidently left a utility on the SQ1 1.1A disk to convert sounds to the AGI v2 format --- but the logic resources cannot be decoded at all, and obviously, the game doesn't run when fit with a v2 interpreter.
I've done something similar for the Apple II KQ2 game, but rather than rebuild a whole VOL, I instead extracted a couple of PICTURE and VIEW resources. These also loaded flawlessly in to AGI Studio. But the LOGIC resources I tried did not. I didn't even try a SOUND because I knew it was a different format.
So there's a mystery around the LOGIC then. It looks to be similar to the AGI v2 LOGIC format. I can see the test sections and even test command patterns that I recognise. I'll take a closer look when I get a bit more time.
-
I'm surprised that the Apple II version of KQ1 is also v1.10 of the interpreter. KQ2 on Apple II also uses v1.10. I might need to go and double check that now to make sure I was looking at the right game.
Please check again, because that seems highly unlikely, given that all text is in the clear on the KQ1 Apple disk but Avis-Durgan-encrypted on the KQ2 Apple disks. (And my KQ2 Apple disk says AGI v1.08, not 1.10.)
Of course, we also may be dealing with several versions of the same game having come out on the Apple II, just like on the PC, in case of which everyone would be correct. I would definitely insist however on not mixing version numbers --- interpreter or game --- from different platforms, otherwise we're creating a mess.
-
otherwise we're creating a mess.
Too late.
-
Please check again, because that seems highly unlikely, given that all text is in the clear on the KQ1 Apple disk but Avis-Durgan-encrypted on the KQ2 Apple disks. (And my KQ2 Apple disk says AGI v1.08, not 1.10.)
We appear to have different KQ2 Apple II disks. I've just checked it again and my one is definitely saying 1.10 for the interpreter version and 1.0H for the game version.
-
I would definitely insist however on not mixing version numbers --- interpreter or game --- from different platforms, otherwise we're creating a mess.
I think I'm starting to agree with this. I'm going to take the BC PC versions out of my original post list and stick to the Apple II versions for now.
So we have:
v1.08 Used by King's Quest 2 version 1.0G
v1.10 Used by King's Quest 2 version 1.0H and King's Quest 1 version 2.0C
v1.20 Used by Black Cauldron (not sure what version)
The main reason for laying out the above is to highlight that the shared 1.10 version between KQ1 and KQ2 seems to be due to the fact that the KQ1 is a version 2.0 of the game. The original 1.0 version of KQ would not have been on that version of the interpreter.
This is actually very interesting. The KQ2 1.0H version that I've been looking at looks very AGI like. The PICTURE format is identical. The VIEW format is identical. The LOGIC format, although not compatible with AGI Studio, still looks to be using a recognisable AGI LOGIC structure (I'm guessing that some of the action and test commands have changed in some way). Is there a version of KQ1 out there somewhere for the Apple II (i.e. KQ1 version 2.0C) where the data looks as AGI-like as this? Probably very rare these days.
-
So there's a mystery around the LOGIC then. It looks to be similar to the AGI v2 LOGIC format. I can see the test sections and even test command patterns that I recognise. I'll take a closer look when I get a bit more time.
I've found a fairly short LOGIC in the Apple II KQ2 that I'm going to try to work out by hand. AGI Studio complains that it has an unknown test command. I guess my first thought in response to that is that maybe one of the test commands has a different number of parameters in this version. Or it could be that the test commands have been reassigned numbers. I'm surprised though that it got to position 0x0086 in to the LOGIC file before it complained. Seems like there might not be too many changes then.
-
So it turns out that the LOGIC I chose is for room 1 of KQ2.
The general structure is the same, in that the FF, FE, FD, and FC codes are doing the if, else, !, || and &&. The size of the if block is handled the same as well.
Some of the test commands have the same code, e.g. 07 is still testing a flag value and 01 a variable value. But posn appears to have a different code, and that means others will as well.
The action command codes are quite a bit different. Variable assignment has the same code but new.room has a different code, as do most of the others.
Still working through it.
Edit:
The flags are in different places as well. For example, the init.log flag mentioned in the AGI.DOC. This is flag 5 in AGIv2 but is flag 13 in what I'm currently looking at. At the moment it is an assumption that flag 13 is init.log given that it is tested at the start of every room in the same way that flag 5 is in the AGIv2 games.
Edit Edit:
Some examples of commands with different codes: The new.room command is 0x12 in AGIv2 but is 0x0B in the Apple II KQ2 game. The position command is 0x25 in AGIv2 but is 0x18 in the Apple II KQ2.
-
This is my current best effort of working through LOGIC.1 in the Apple II KQ2 1.0H game:
[
[ Apple II - KQ2 1.0H - ROOM 1 (STARTING ROOM - BEACH)
[
[ v0 = (no idea at present)
[ v1 = Current room
[ v2 = Previous room
[ v3 = Edge ego hit
[
[ v20 = Used to work with ego X pos
[ v21 = Used to work with ego Y pos
[
ff 07 0d ff if (isset(init.log)) {
6d 00
58 00 00 [ Unknown. Something done to ego maybe?
38 01 load.pic(v1);
36 98 load.logics(152); [ Beach logic
36 65 load.logics(101); [ Swimming logic
09 01 load.view(1); [ Splashing wave
09 61 load.view(97); [ Ego Swimming
09 68 load.view(104); [ Ego drowning
09 41 load.view(65); [ Magic lamp
09 62 load.view(98); [ Magic carpet
0c 01 draw.pic(v1);
18 1c 00 32 position(o28, 0, 50); [ Wave
ff fc 07 0f if (isset(f15) ||
01 02 61 (previous.room == 97) ||
01 02 68 fc ff (previous.room == 104)) {
07 00
18 00 64 64 position(ego, 100, 100);
fe } else {
1a 00
ff 01 02 2b ff if (previous.room == 43) { [ From north
13 00
ff fd 01 8d 00 ff if (v141 != 0) {
07 00
18 00 0a 3c position(ego, 10, 60);
fe } else {
04 00
18 00 6e 28 position(ego, 110, 40);
}
}
}
ff 01 02 08 ff if (previous.room == 8) { [ From south
03 00
20 00 00 [ Unknown. Could be: set.view(ego, 0);
}
ff 01 02 32 ff if (previous.room == 50) { [ From ocean
12 00
1a 00 14 15 get.posn(ego, v20, v21);
ff 05 15 87 ff if (v21 > 135) {
07 00
03 15 87 v21 = 135;
19 00 14 15 position.v(ego, v20, v21);
}
}
16 00 draw(ego);
}
ff fd 07 8d 07 04 ff if (!isset(f141) && isset(f4)) {
1f 00
03 8e ff v142 = 255;
ff 0a 00 20 30 2b 35 ff if (posn(ego, 32, 48, 43, 53)) {
06 00
03 8e 0a v142 = 10;
03 8f 37 v143 = 55;
}
ff 01 8e ff ff if (v142 == 255) {
05 00
3d 8e reset(f142);
fe } else {
0c 00
1a 00 14 15 get.posn(ego, v20, v21);
08 8e 14 v142 -= v20;
08 8f 15 v143 -= v21;
3c 8c set(f140);
}
}
ff fd 01 03 00 ff if (edge.ego.hit != 0) {
02 00
3c c4 set(f196);
}
ff 0a 00 00 32 1e 35 if (posn(ego, 0, 50, 30, 53) &&
fd 01 8d 00 ff (v141 != 0)) {
02 00
0b 2b new.room(43);
}
ff 01 03 01 ff if (edge.ego.hit == 1) {
02 00
0b 2b new.room(43);
}
ff 01 03 02 ff if (edge.ego.hit == 2) {
02 00
0b 02 new.room(2);
}
ff 01 03 04 ff if (edge.ego.hit == 4) {
02 00
0b 32 new.room(50);
}
ff 01 03 03 ff if (edge.ego.hit == 3) {
02 00
0b 08 new.room(8);
}
00 return();
[ Messages (none in this example)
00
02 00
So the LOGIC format itself appears to match the AGIv2 format. This example doesn't have messages, so I didn't look at what is happening in that section yet.
The reason that AGI Studio would not like it though is because the test and action commands do not have the same assigned numbers.
I didn't look at any Interpreter code to work any of this out. It was just deducing what the actions and test commands must be, using the AGIv2 KQ1 as a guide, and working out what made sense.
So far we have these test commands:
0x01 = equaln (==)
0x05 = greatern (>)
0x07 = isset
0x0A = posn
The first three are in the right place compared to AGIv2, but posn is one lower.
For the action commands we have:
0x00 = return
0x03 = assignn (=)
0x08 = subn (-=)
0x09 = load.view
0x0B = new.room
0x0C = draw.pic
0x16 = draw
0x18 = position
0x19 = position.v
0x1A = get.posn
0x36 = load.logics
0x38 = load.pic
0x3C = set
0x3D = reset
I'm going to continue working through some more examples to try to identify the number codes for other AGI commands. With set and reset being quite low down, it does seem to support the idea that flags were not present in earlier versions.
Edit:
It is interesting to note that both the variables and flags use different numbers for a lot of the ones we're familiar with. For example, v1, v2, and v3 all have different purposes than they do in AGI v2 (where v0, v1 and v2 are used instead for those same purposes). The flag to say that the logic should initialise itself also has a different number.
All the concepts that we're familiar with are there though.
-
This one is LOGIC.2:
[
[ Apple II - KQ2 1.0H - ROOM 2
[
ff 07 0d ff if (isset(init.log)) {
15 00
58 14 08 [ Still not sure what this is.
38 01 load.pic(current.room);
36 99 load.logics(153);
36 97 load.logics(151);
09 41 load.view(65); [ Magic lamp
09 62 load.view(98); [ Magic carpet
09 03 load.view(3); [ Red riding hood
09 02 load.view(2); [ Red riding hood
0c 01 draw.pic(current.room);
16 00 draw(ego);
}
ff 09 02 00 99 00 ff if (said("look", "fence"))
02 00
0d 02 print("You see a low white fence.");
}
ff 09 01 00 99 00 if (said("anyword", "fence") &&
fd 09 04 00 99 00 !said("enter", "fence")
fd 09 02 00 99 00 ff !said("look", "fence")
02 00
0d 01 print("You should do nothing with the fence!");
}
ff 01 03 01 ff if (edge.ego.hit == 1) {
02 00
0b 2c new.room(44);
}
ff 01 03 02 ff if (edge.ego.hit == 2) {
02 00
0b 03 new.room(3);
}
ff 01 03 04 ff if (edge.ego.hit == 4) {
02 00
0b 01 new.room(1);
}
ff 01 03 03 ff if (edge.ego.hit == 3) {
02 00
0b 09 new.room(9);
}
00 return();
[ Messages
02 [ 2 messages
47 00 [ Pointer to end of messages
06 00 [ Pointer to first message
2c 00 [ Pointer to second message
18 19 1c 53 53 2c 1a 07 0b 05 4e [ "You should do nothing with the fence!"
25 19 49 1d 4f 30 1d 1b 09 06 4e
36 1f 1d 1b 00 30 1d 17 47 07 0b
2f 15 0c 52 20
1d 1a 07 47 12 0b 24 56 08 53 4c [ "You see a low white fence."
2b 02 52 10 09 07 35 13 49 15 45
2a 16 17 49 61
The message section is as expected, and as documented in the AGI specs. The message text is XORed with Avis Durgan.
One new test command discovered: 0x09 said
One new action command discovered: 0x0D print
-
LOGIC.3 had quite a few additional commands. The list of known commands and variables in the Apple II KQ2 1.0H now looks like this:
[ v1 = Current room
[ v2 = Previous room
[ v3 = Edge ego hit
[ v6 = Score
0x01 = equaln
0x05 = greatern
0x07 = isset
0x09 = said
0x0A = posn
0x00 = return
0x03 = assignn
0x05 = addn
0x08 = subn
0x09 = load.view
0x0A = animate.obj
0x0B = new.room
0x0C = draw.pic
0x0D = print
0x14 = get
0x16 = draw
0x18 = position
0x19 = position.v
0x1A = get.posn
0x1B = set.cel
0x1D = end.of.loop
0x1E = reverse.loop
0x20 = set.view
0x24 = ignore.blocks
0x25 = observe.blocks
0x2A = (???stop.cycling???)
0x2C = stop.update
0x2D = start.update
0x30 = set.priority
0x36 = load.logics
0x38 = load.pic
0x3C = set
0x3D = reset
0x49 = ignore.objs
0x4A = observe.objs
0x4B = distance
While decompiling the first three LOGICs by hand was fun, and good as a refresher, I think I'm going to switch to something a bit more automatic now.
I've identified where the four DIR "files" are on the KQ2 Apple II game, so I'll use those to extract the games resources, and then I'll feed the LOGICs through a decompiler and work out the rest of the commands as I go through each LOGIC.
FYI, the four DIRs are at these offsets on the first disk: LOGDIR (0x1000), PICDIR (0x1300), SNDDIR (0x1600), VIEWDIR (0x1900). The OBJECT data is at 0x2900, and the WORDS at 0x3000.
-
Ignoring the 5 byte header, the rest of the data in the four DIR "files" are of the same format as in AGIv2.
If a DIR entry points to VOL number 0, then that can be found on any one of the disks at offset 0x01A000. This means that every offset contained in a DIR entry that references VOL 0 needs to have 0x01A000 added to the offset before using the value to read the data from the disk image.
If a DIR entry points to VOL number 1, then that is on the first disk but at offset 0x012000. This means that every offset contained in a DIR entry that references VOL 1 needs to have 0x012000 added to the offset before using the value to read the data from the disk image.
If a DIR entry points to VOL 2, 3, 4, or 5, then those are on the disk image of the same number, and they all start at offset 0x000000. So nothing to add to the DIR entry offsets in this case.
-
I've done something similar for the Apple II KQ2 game, but rather than rebuild a whole VOL, I instead extracted a couple of PICTURE and VIEW resources. These also loaded flawlessly in to AGI Studio.
So yes, the PICTURE resources do load in to AGI Studio flawlessly, and they have the right colours. The VIEWs do also load in without error, but I failed to notice that the colours are completely wrong. The splashing wave has the water in a green and brown colour, so the animation actually looks like the ground is exploding rather than a wave splashing. It might be that when I tried loading it in to AGI Studio, I didn't realise that it was a VIEW for a splashing wave. I probably thought it was meant to be a ground exploding animation.
I guess the VIEWs on the Apple II will be using the Apple II colour palette. Not sure why this is the case for the VIEWs when the PICTUREs are clearly using the correct colours.
-
It would appear that test command 0x09 that I have identified as "said" in the Apple II KQ2 game does not have the variable number of words that the AGIv2 instruction has. It always requires two words; no more, no less. Well that's what I'm currently assuming based on the fact that the byte that specifies how many words the said has is not present in the LOGIC files.
-
Actually, what appears to be going on is that they had two test commands for said, i.e. one that takes two words, and one that takes one word. The test command 0x0F is being used in a scenario where the AGiv2 version of KQ2 is using said with one word.
So this seems like a case of evolution. They originally built "said" to have two words, then somewhere along the line they must have needed to handle a single word, so they added another test command.
Then when they moved to AGIv2, they must have tidied things up a bit and consolidated the two test commands in to a single command that supports a variable number of words.
-
Seems reasonable to me.
-
For what it's worth, GAL's said test always uses two words.
-
I guess that adds more weight to the three step evolution. GAL supported only two words, AGI v1 having two said commands, and AGI v2 having a single variable word count said command.
-
I'm beginning to doubt that AGI v1 (or at least the version used by the Apple II KQ2 game) supported the "call" command. In every example so far where I've compared a LOGIC script between the Apple II KQ2 and the PC AGI v2 KQ2, when the later has "call" commands, the former is lacking those call commands. The Apple II KQ2 does have the same load.logic calls (or at least I think that's what they are), but it is missing the calls to those logics. So there must be some sort of automatic calling of the logics taking place. Perhaps it calls the logics when they're loaded, or maybe it calls any loaded logics at the end of the current script. Don't know yet.
-
Not 100% certain about this yet, but there is a possibility that AGI v1 had a third "said" test command, that supported three words.
-
I'm also starting to realise that there is no "has" test command. Instead it appears to be using flags to keep track of whether an item is in the inventory or not.
-
Now that deserves a "wow".
Wow.
-
Sierra's original CG does not seem to have action and test commands hard-coded into the compiler. Instead, they are defined in a text file called SYSDEFS, which looks like this:
%action increment(VAR) 1
%action decrement(VAR) 2
%action assignn(VAR, NUM) 3
%action assignv(VAR, VAR) 4And how does one April 1987 time-stamped game source define "said" in that definition file??%test said(WORDLIST) 14
%define said1 said
%define said3 saidHeh.I'm also starting to realise that there is no "has" test command. Instead it appears to be using flags to keep track of whether an item is in the inventory or not.
GAL has a "get" action but apparently no "has" action either.
-
And how does one April 1987 time-stamped game source define "said" in that definition file??%test said(WORDLIST) 14
%define said1 said
%define said3 said
Well I guess that would seem to confirm it. It seems to suggest that they used three different names within their source code though (i.e. pre-AGIv2 source code). So I'd expect the original source for KQ2 to have something like:
if (said1("look")) {
}
...otherwise why would you need such a define? It suggests that at one point in time, they were compiling pre-AGIv2 scripts with an AGI v2 compiler, perhaps when converting a game released originally for AGIv1 to the AGIv2 version.
I'm also starting to realise that there is no "has" test command. Instead it appears to be using flags to keep track of whether an item is in the inventory or not.
GAL has a "get" action but apparently no "has" action either.
I'm planning to investigate this further today by finding more examples in KQ2 where "has" has not been used in places where it is used in the AGI v2 version.
-
GAL has a "get" action but apparently no "has" action either.
But "has" would be a test, not an action right?
-
It would. But the only tests that GAL knows are equal, not equal, posn, and said with two words.
-
The OBJECT data in the Apple II KQ2 is very similar to early AGI v2 games (i.e. where the item names are in plain text and not XORed with Avis Durgan), but it seems to be missing these three bytes from the start:
Byte Meaning
----- -----------------------------------------------------------
0-1 Offset of the start of inventory item names
2 Maximum number of animated objects
----- -----------------------------------------------------------
A small tweak to account for that and JAGI's Object viewer can list all the inventory items.
-
I'm also starting to realise that there is no "has" test command. Instead it appears to be using flags to keep track of whether an item is in the inventory or not.
Turns out this is wrong. I'd misidentified test command 0x08. This is issetv in AGIv2, but appears to be "has" in the Apple II KQ2. I'm certain that 0x07 is "isset", which is the same as in AGI v2, but if there is an "issetv", then it doesn't immediately follow isset.
-
The WORDS data is different from the AGI v2 version in a number of ways:
* The words appear in there entirety rather than referring to parts of the previous word.
* The text is not XORed with 0x7F but instead appears in it's plain ASCII form.
* All 2-byte offset values are stored in the normal LO-HI seen elsewhere in AGI rather than the HI-LO that the AGI v2 WORDS.TOK uses.
-
add.to.pic in the Apple II KQ2 1.0H version has only the first six parameters.
-
I have debugged the PC interpreters of both KQ2 v1.1H (no interpreter version number) and BC v1.1M (interpreter v1.12) and compared my disassembly with that of later game versions. There are a few quite unique commands such as bit test/set/clear commands and the mysterious (tentatively named) "distance.to.water", which seems to only exist in that one interpreter version.
%test equaln(VAR,NUM) 1
%test equalv(VAR,VAR) 2
%test lessn(VAR,NUM) 3
%test lessv(VAR,VAR) 4
%test greatern(VAR,NUM) 5
%test greaterv(VAR,NUM) 6
%test isset(FLAG) 7
%test has(OBJECT) 8
%test said(WORD,WORD) 9
%test posn(OBJECT,NUM,NUM,NUM,NUM) 10
%test controller(NUM) 11
%test obj.in.room(OBJECT, VAR) 12
%test said3(WORD,WORD,WORD) 13
%test have.key() 14
%test said1(WORD) 15
%test bit.set(NUM,VAR) 16
%action return() 0
%action increment(VAR) 1
%action decrement(VAR) 2
%action assignn(VAR,NUM) 3
%action assignv(VAR,VAR) 4
%action addn(VAR,NUM) 5
%action addv(VAR,VAR) 6
%action subn(VAR,NUM) 7
%action subv(VAR,VAR) 8
%action load.view(VIEW) 9
%action animate.obj(OBJECT) 10
%action new.room(NUM) 11
%action draw.pic(VAR) 12
%action print(MSGNUM) 13
%action status() 14
%action init.game() 15
%action restore.game() 16
%action init.disk() 17
%action restart.game() 18
%action random(VAR) 19
%action get(OBJECT) 20
%action drop(OBJECT) 21
%action draw(OBJECT) 22
%action erase(OBJECT) 23
%action position(OBJECT,NUM,NUM) 24
%action position.f(OBJECT,VAR,VAR) 25
%action get.posn(OBJECT,VAR,VAR) 26
%action set.cel(OBJECT,NUM) 27
%action set.loop(OBJECT,NUM) 28
%action end.of.loop(OBJECT,FLAG) 29
%action reverse.loop(OBJECT,FLAG) 30
%action move.obj(OBJECT,NUM,NUM,NUM,FLAG) 31
%action set.view(OBJECT,VIEW) 32
%action follow.ego(OBJECT,NUM,FLAG) 33
%action block(NUM,NUM,NUM,NUM) 34
%action unblock() 35
%action ignore.blocks(OBJECT) 36
%action observe.blocks(OBJECT) 37
%action wander(OBJECT) 38
%action reposition(OBJECT,VAR,VAR) 39
%action stop.motion(OBJECT) 40
%action start.motion(OBJECT) 41
%action stop.cycling(OBJECT) 42
%action start.cycling(OBJECT) 43
%action stop.update(OBJECT) 44
%action start.update(OBJECT) 45
%action program.control() 46
%action player.control() 47
%action set.priority(OBJECT,NUM) 48
%action release.priority(OBJECT) 49
%action add.to.pic(VIEW,NUM,NUM,NUM,NUM,NUM) 50
%action set.horizon(NUM) 51
%action ignore.horizon(OBJECT) 52
%action observe.horizon(OBJECT) 53
%action load.logics(NUM) 54
%action object.on.water(OBJECT) 55
%action load.pic(VAR) 56
%action load.sound(NUM) 57
%action sound(NUM,FLAG) 58
%action stop.sound() 59
%action set(FLAG) 60
%action reset(FLAG) 61
%action toggle(FLAG) 62
%action new.room.f(VAR) 63
%action call(NUM) 64
%action quit() 65
%action set.speed(VAR) 66
%action move.obj.f(OBJECT,VAR,VAR,VAR,FLAG) 67
%action get.num(MSGNUM,VAR) 68
%action get.f(VAR) 69
%action lindirectv(VAR, VAR) 70
%action print.flag.value(VAR) 71
%action get.priority(OBJECT,VAR) 72
%action ignore.objs(OBJECT) 73
%action observe.objs(OBJECT) 74
%action distance(OBJECT,OBJECT,VAR) 75
%action object.on.land(OBJECT) 76
%action set.priority.f(OBJECT,VAR) 77
%action show.obj(VIEW) 78
%action load.last.logics(NUM) 79
%action display(NUM,NUM,NUM,MSGNUM) 80
%action prevent.input() 81
%action nop1() 82
%action text.screen.attribute(NUM) 83
%action graphics() 84
%action clear.bottom.lines() 85
%action discard.view(VIEW) 86
%action discard.pic(VAR) 87 [ Last command in KQ2 v1.1H
%action set.key(NUM,FLAG) 88
%action reverse.cycle(OBJECT) 89
%action step.size(OBJECT,VAR) 90
%action last.cel(OBJECT,VAR) 91
%action normal.cycle(OBJECT) 92
%action load.view(VIEW) 93 [ Verified duplicate
%action nop2(NUM) 94
%action distance.to.water(NUM,VAR) 95 [ returns 250 if the distance is too great. Seems to take ego's direction into account as well.
%action set.bit(NUM,VAR) 96
%action clear.bit(NUM,VAR) 97 [ Last command in BC v1.1M
%var current.room 1
%var previous.room 2
%var edge.ego.hit 3
%var score 6
%flag have.input 9
%flag init.log 13
%flag restart.in.progress 15
While there is a call command, logics loaded with load.logics seem to simply get appended to an execution queue, while load.last.logics is guaranteed to be executed last.
From what I can see, Donald Duck's Playground version 1.0Q does justice to its v2.001 interpreter version and seems to decompile well with the regular AGI v2.xxx SYSDEFS.
-
I've compared those test command and action command numbers to what I've identified so far in the Apple II KQ2 game and they all appear to line up exactly. I still had quite a few unidentified commands, but what you've listed makes sense for the gaps I have.
There is one action command with number 88 in the Apple II KQ2 game that I haven't yet identified, and your list says that the PC KQ2 commands end before that. It may end up being set.key as you have for BC, but I'll need to see if the parameters in the places where it is used make sense for that. It could end up being something different. When used, it is usually one of the first commands to be called in a room.
I had some additional flag names identified. This is my current list:
f4=on.water
f5=ego.hidden
f9=have.input
f10=hit.special
f13=init.log
f15=restart.in.progress
For the vars, I currently have the same four that you have.
-
I'll post my customizable AGI decompiler later, which may be useful to you. Customizable as in allowing (and requiring) you to supply a SYSDEFS file that specifies all action and test commands with parameters. I spent the last few days finding and fixing all edge cases of resolving implicit GOTOs into ELSE block, and keeping them as GOTOs where they cannot be resolved. To do this, I studied rm14 of Donald Duck's Playground --- the dreaded payroll room --- extensively.
I would also like to support Apple II disk images, but am hesitant because it seems that the locations of the various directories are hard-coded somewhere inside the machine code. At least I could not find something similar to the INITDIR that the PC v1.x AGI games have in track 0, sector 9.
-
I haven't yet found where the offsets are stored either, although I didn't do more than try searching for the offset values across the first disk.
Regarding resolving implicit GOTOs into ELSE blocks, I guess due to the existence of the explicit goto keyword, there will be situations where we can't be certain what the original source code had in it. They may have chosen to use a goto where an else could also have been used. So the decompiler has to choose in that scenario between the two, and I guess the preference would be for the ELSE.
-
Something just dawned on me.
In AGI v1, are variables and flags essentially the same thing? Is there one 256 byte var/flag table?
I ask this for two reasons:
1. The first is due to the pattern of my currently unidentified flags and variables:
f0=
f1=
f2=
f3=
f4=on.water
f5=ego.hidden
f6=
f7=
f8=
f9=have.input
f10=hit.special
f11=have.match
f12=
f13=init.log
f14=
f15=restart.in.progress
# Variables
v0=
v1=current.room
v2=previous.room
v3=edge.ego.hit
v4=
v5=
v6=score
v7=
v8=
v9=
v10=
v11=
v12=ego.dir
i.e. the identified vars interleave in to the gaps of the unidentified flags.
2. The second reasons is due to this code from the Apple II KQ2 game:
if (said(fast))
{
reset(f203);
set.speed(v203);
}
if (said(normal))
{
v203 = 2;
set.speed(v203);
}
if (said(slow))
{
v203 = 4;
set.speed(203);
}
It seems like there was some kind of var/flag duality going on. The reset(f203) is actually setting var 203 to 0.
This might answer the mystery as to why the var commands initially had ".f" at the end of their names.
Edit:
The more I look, the more evidence I find, this time from the AGI v2 docs. The list of AGI v2 flag positions when compared with the AGI v1 positions would be the same if the variables were not interleaved between the v1 flags. This is why init.log is 0x05 in AGI v2 but 0x0D in AGI v1. I was initially thinking that they removed some flags that had become redundant, but actually they align if you account for the shared var/flag table space.
I think we can use this observation to make an educated guess as to what var 7 and var 8 are. At position 6 we have score, and position 12 we have ego.dir. According to the AGI v2 docs, there are only two vars between those two (obj.hit.edge and edge.obj.hit). The only two available slots between 6 and 12 are 7 and 8, due to the others being used by flags.
-
From PC KQ2 v1.0W's interpreter:
%action assignn(VAR,NUM) 3
CS:0269
mov bx, si
inc si
mov al, [bx]
sub ah, ah
mov [bp-2], ax
mov bx, si
inc si
mov al, [bx]
mov [bp-18], ax
mov bx, [bp-2]
mov al, [bp-18]
mov [bx+0025], al
jmp 0215
%action set(FLAG) 60
CS:0A50:
mov bx, si
inc si
mov al, [bx]
sub ah, ah
mov bx, ax
mov byte ptr [bx+0025], 1
jmp 0215The BX+0025 is the array on which both "assignn" and "set" operate. This indicates that variables and flags really are identical. Good job spotting that. I debugged that interpreter before but did not notice that the commands operated on the same array.
-
Following on with the pattern, var 14 must be max.score. It seems to fit for KQ2. I can see it being set to 185 in logic 0.
-
There is something that has been puzzling me about the Apple II KQ2 game for a while. The first named object in the OBJECT file starts at inventory item number 50. The first 50 slots prior to that have no name, and yet quite a few of them have a value for the room number, which is somewhat strange.
I checked the AGIv2 version of KQ2 and the inventory items start at number 50 in that case as well, but both AGI Studio and WinAGI are showing a value of 0 for the room numbers of all of the first 50 nameless objects. I haven't checked the raw data yet to see if those tools are correct about this, but I have to assume that they are.
So whatever those room number values were in the AGIv1 version, the data doesn't seem to have been important in the AGIv2 version.
Are there any clues from the PC version of the AGIv1 KQ2 game as to what those first 50 slots in the OBJECT file might be?
-
I emailed you Transcopy images of my KQ Tandy booter disks to explore. They will boot in a special build of DOSBox by NRS that supports Transcopy images. It is version 01.00.00. Not sure of the interpreter version.
-
%action clear.bit(NUM,VAR) 97 [ Last command in BC v1.1M
Apparently there is a 98 action command in the Apple II version of BC. It isn't just an obscure command either. It seems to appear at the top of every init.log block of almost every LOGIC. It could well be Apple II only though.
-
Further analysis and comparison with the KQ2 Apple II version suggestions that this command (i.e. 98, or 0x62) in BC might be the same as command 88 (or 0x58) in the KQ2 Apple II game. They are used in the same way and have the same number of parameters.
In the BC Apple II game, it would appear that 88 (0x58) has now become set.key, as was identified in the PC version.
This seems to be a case where an action command (possibly an Apple II specific one?) has moved location.
-
Looking back at this...
%action discard.pic(VAR) 87 [ Last command in KQ2 v1.1H
%action set.key(NUM,FLAG) 88
%action reverse.cycle(OBJECT) 89
%action step.size(OBJECT,VAR) 90
%action last.cel(OBJECT,VAR) 91
%action normal.cycle(OBJECT) 92
%action load.view(VIEW) 93 [ Verified duplicate
%action nop2(NUM) 94
%action distance.to.water(NUM,VAR) 95 [ returns 250 if the distance is too great. Seems to take ego's direction into account as well.
%action set.bit(NUM,VAR) 96
%action clear.bit(NUM,VAR) 97 [ Last command in BC v1.1M
...it seems to make sense that with 87 being the last action command in the PC KQ2, that any Apple II specific commands would appear after that. So we have 88 in the Apple II KQ2 game appearing to be an Apple II specific command of some sort.
And with 97 being the last action command in the PC Black Cauldron game, the Apple II version has matched all 97 of those and moved what was command 88 in the Apple II KQ2 game up to position 98.