🎄 Merry Christmas, TCRF! 🎄
Talk:King's Quest: Quest for the Crown
|
|
IBM PCJr.
The IBM PCJr. version is rather odd compared to later releases, such as a different opening jingle and some odd changes here and there. It's not all that well-documented here, but I'm curious if anyone else can knows of something about this first version. --From: divingkataetheweirdo (talk) 16:15, 25 November 2015 (EST)
- I took notes on the PCJr. version about three years ago. I didn't add them to the page because I was either told not to since it's basically a port comparison, or decided not to on my own, I can't remember. Here are the notes.
- About the formatting: The control codes for the PCJr. version and the AGI engine are different, which is why the PCJr. version is properly formatted in the document and the AGI text isn't.--GoldS (talk) 00:21, 28 November 2015 (EST)
Version differences
One example of several text revisions here: https://twitter.com/dosnostalgic/status/1260013345794486272 Not sure if anyone knows a good way to do a full text dump and diff for changes, but could be interesting to add. --RavenWorks (talk) 20:44, 5 February 2022 (UTC)
Unused duplicate resources in VOL files
The VOL.0, VOL.1, and VOL.2 files contain most of the game data in the form of "resources". The directory files LOGDIR, PICDIR, VIEWDIR, and SNDDIR contain indexes into the VOL files. This Python program searches for unused bytes between resources:
#!/usr/bin/env python3 # Looks for unused bytes in AGIv2 VOL files -- bytes that are not referred to by # any of the directory files. # # Usage: python3 volunused /path/to/kq1 # where /path/to/kq1 is a directory containing the game files # LOGDIR, PICDIR, VIEWDIR, SNDDIR, and VOL.*. import collections import getopt import hashlib import os import struct import sys _, (game_path,) = getopt.gnu_getopt(sys.argv[1:], "") INTERVALS = {} Interval = collections.namedtuple("Interval", ("label", "begin", "end")) # Truncated hash, intended to make it easy to see when two resources are # identical in the output. def digest(data): return hashlib.sha256(data).digest()[:16].hex() for dirname in ("LOGDIR", "PICDIR", "VIEWDIR", "SNDDIR"): with open(os.path.join(game_path, dirname), "rb") as dir: i = 0 while True: label = f"{dirname}.{i}" # http://agiwiki.sierrahelp.com/index.php?title=AGI_Specifications:_Chapter_5_-_Resource_Formats#Version_2_directories entry = dir.read(3) if not entry: break elif entry == b"\xff\xff\xff": pass else: assert len(entry) == 3, entry vol_no = (entry[0] & 0xf0) >> 4 pos = ((entry[0] & 0x0f) << 16) | (entry[1] << 8) | (entry[2] << 0) vol_filename = f"VOL.{vol_no}" with open(os.path.join(game_path, vol_filename), "rb") as vol: vol.seek(pos) # http://agiwiki.sierrahelp.com/index.php?title=AGI_Specifications:_Chapter_5_-_Resource_Formats#5.2_Format_of_Vol_files_.28version_2.29 header = vol.read(5) if header: assert len(header) == 5, header sig, header_vol_no, size = struct.unpack("<HBH", header) assert sig == 0x3412, sig assert header_vol_no == vol_no, header_vol_no int = Interval(label, pos, pos + len(header) + size) INTERVALS.setdefault(vol_filename, []) INTERVALS[vol_filename].append(int) data = vol.read(size) assert len(data) == size, (len(data), size) print(f"{vol_filename} used {label:11} {pos:6}--{int.end:<6} {int.end - pos:4} {digest(data)}") else: print(f"{vol_filename} out-of-bounds {label:11} {pos:6}") i += 1 for intervals in INTERVALS.values(): intervals.sort(key = lambda int: int.begin) for vol_filename in sorted(INTERVALS.keys()): intervals = INTERVALS[vol_filename] vol_size = os.stat(vol_filename).st_size with open(os.path.join(game_path, vol_filename), "rb") as vol: def unused(begin, end): vol.seek(begin) data = vol.read(end - begin) # If the beginning of the unused data looks like a resource header, # show the digest of what follows the header. Otherwise show "-". dig = "-" if len(data) >= 5: sig, header_vol_no, size = struct.unpack("<HBH", data[:5]) if sig == 0x3412 and 5 + size <= len(data): dig = digest(data[5:5 + size]) print(f"{vol_filename} unused {begin:6}--{end:<6} {end - begin:4} {dig} {data}") prev = None for int in intervals: if prev is None and int.begin != 0: # Unused bytes at the beginning. unused(0, int.begin) elif prev is not None and prev.end < int.begin: # Unused bytes between two intervals. unused(prev.end, int.begin) elif prev is not None and prev.end > int.begin: print(f"{vol_filename} overlap {prev} {int}") if int.end > vol_size: print(f"{vol_filename} overrun {int} {vol_size}") if prev is None or int.end > prev.end: prev = int if prev is not None and prev.end < vol_size: # Unused bytes at the end. unused(prev.end, vol_size)
Running the program on the game files of https://archive.org/details/msdos_Kings_Quest_I_-_Quest_for_the_Crown_1987 finds 6216 bytes that are never referred to, but they are all either duplicates of other resources that are used, or truncated resource headers.
VOL.2 out-of-bounds SNDDIR.34 134703 VOL.2 out-of-bounds SNDDIR.35 134799 VOL.2 out-of-bounds SNDDIR.36 134893 VOL.2 out-of-bounds SNDDIR.37 135787 VOL.0 unused 24488--26319 1831 665eec864221d42b018a050e44a8365d b'\x124\x00"\x07\x01\x01...' VOL.0 unused 42422--43628 1206 43f1789de4e413024199c323b59ffb6f b'\x124\x00\xb1\x04\x08\x00\x9f...' VOL.0 unused 44797--44800 3 - b'\x124\x00' VOL.1 unused 23296--24086 790 5e53845a0eb120cb2a578f77165a2c02 b'\x124\x01\x11\x03\xf0\x00\xf2...' VOL.1 unused 90010--90800 790 5e53845a0eb120cb2a578f77165a2c02 b'\x124\x01\x11\x03\xf0\x00\xf2...' VOL.1 unused 105213--105216 3 - b'\x124\x01' VOL.1 unused 120233--121023 790 5e53845a0eb120cb2a578f77165a2c02 b'\x124\x01\x11\x03\xf0\x00\xf2...' VOL.1 unused 131717--132507 790 5e53845a0eb120cb2a578f77165a2c02 b'\x124\x01\x11\x03\xf0\x00\xf2...' VOL.1 unused 145406--145408 2 - b'\x124' VOL.1 unused 162301--162304 3 - b'\x124\x01' VOL.1 unused 199421--199424 3 - b'\x124\x01' VOL.2 unused 34559--34560 1 - b'\x12' VOL.2 unused 90108--90112 4 - b'\x124\x02\xb7'
665eec864221d42b018a050e44a8365d
is a copy of VIEWDIR.14 in VOL.1.43f1789de4e413024199c323b59ffb6f
is a copy of SNDDIR.0 in VOL.1.5e53845a0eb120cb2a578f77165a2c02
are copies of PICDIR.84 (the picture overlay for the base of the beanstalk) in VOL.1.