예제 #1
0
    def _read(self):
        f = File(self.file_path)

        n_entries = f.readUInt16()
        for i in range(n_entries):
            self.offsets.append(f.readUInt32())

        unknown1 = f.readUInt8()
        unknown2 = f.readUInt8()
        unknown3 = f.readUInt8()
        unknown4 = f.readUInt8()

        for i in range(n_entries):
            print(f.pos(), self.offsets[i])
            assert f.pos() == self.offsets[i]

            width = f.readUInt16()
            height = f.readUInt16()
            image = Image(width, height)

            for y in range(height):
                for x in range(width):
                    colour = self.palette[f.readUInt8()]
                    image.set(colour, x, y)

            self.images.append(image)
예제 #2
0
def savegame(input_path):
    f = File(input_path)
    data = {}

    # Header
    assert (f.readString() == "STTNG_GAME")

    blocks = readBlockHeaders(f)
    assert (len(blocks) == 9)

    print(blocks[0])
    data |= readBlockCompstat(f, blocks[0])
    print(blocks[1])
    data |= readBlockAststat(f, blocks[1])
    print(blocks[2])
    print(blocks[3])
    print(blocks[4])
    print(blocks[5])
    data |= readBlockTravelHistory(f, blocks[5])
    print(blocks[6])
    try:
        data |= readBlockObjects(f, blocks[6])
    except:
        print(
            "AN ERROR OCURRED FETCHING OBJECTS - SAVEGAME SUPPORT IS A WORK IN PROGRESS"
        )
    print(blocks[7])
    print(blocks[8])

    return data
예제 #3
0
def lst(file_path):
    f = File(file_path)
    n = f.readUInt32()
    entries = []
    while not f.eof():
        entries.append(f.readString())
    assert (n == len(entries))
    return entries
예제 #4
0
def adviceDat(file_path):
	# Reads w{world}a000.dat files. The contain information about characters giving the player advie.
	# I'm pretty sure this file is not for the game to read.
	# There're so many typos and variations, I'm pretty sure they're developer notes.
	f = File(file_path)
	entries = []
	while not f.eof():
		level = _adviceEntry(f)
		if level is None:
			break
		entries.append(level)
	return entries
예제 #5
0
def astromapDb(file_path):
    f = File(file_path)

    eof = len(f)
    offsets = []
    while True:
        offset = f.readUInt32()
        if offset == eof:
            break
        offsets.append(offset)

    sectors = []
    for offset in offsets:
        assert (f.pos() == offset)

        sector = readSector(f)

        for j in range(sector["n_systems"]):
            system = readSystem(f)
            system.pop("name_offset")
            system.pop("alias_offset")
            system.pop("notable_offset")
            assert (system.pop("description_offset") == 0)
            system.pop("station_offset")
            sector["systems"].append(system)

        for j in range(sector["n_bodies"]):
            body = readBody(f)
            body.pop("name_offset")
            sector["bodies"].append(body)

        for j in range(sector["n_stations"]):
            station = readStation(f)
            station.pop("name_offset")
            sector["stations"].append(station)

        sectors.append(sector)

    _addSectorNames(sectors, file_path)

    return sectors
예제 #6
0
def worldList(file_path):
	f = File(file_path)
	data = {}
	while not f.eof():
		scene_id = f.readUInt16()
		assert(f.readUInt16() == scene_id)
		assert(f.readUInt16() == 0)
		comment = f.readStringBuffer(21)
		data[scene_id] = comment
	return data
예제 #7
0
def worldObj(file_path):
	f = File(file_path)
	screen = []
	while not f.eof():
		counter = f.readUInt16()
		object_id = _readObjectId(f)
		assert(object_id["id"] == counter)
		name = f.readStringBuffer(30).strip()
		description = f.readStringBuffer(260).strip()
		screen.append({
			"id": object_id,
			"name": name,
			"description": description,
		})
	return screen
예제 #8
0
def singlePalette(palette_path):
    """Read a single (128 colour) palette from a file"""
    return readSinglePalette(File(palette_path))
예제 #9
0
def sprite(sprite_path, background_path, palette_path=None):

    palette_path = Palette.getGlobalPalettePath(sprite_path, palette_path)
    global_palette = Palette.singlePalette(palette_path)
    local_palette = Palette.singlePalette(background_path)
    palette = Palette.combinePalettes(local_palette, global_palette)

    f = File(sprite_path)

    spr = {
        "name": sprite_path.name,
        "blocks": [],
        "images": {},
    }

    block = _readBlockHeader(f)
    assert (block["name"] == "SPRT")
    assert (f.readUInt32() == 0x100)
    eof = block["offset"] + block["length"]

    block_offsets = []

    while f.pos() < eof:
        block = _readBlockHeader(f)

        if block["name"] == "LIST":
            block["entries"] = []
            length = f.readUInt32()
            for i in range(length):
                offset = f.readUInt32()
                block["entries"].append({"offset": block["offset"] + offset})

        elif block["name"] == "SETF":
            block["flag"] = f.readUInt32()  # 0, 1, 2, 3 or 4

        elif block["name"] == "POSN":
            block["x"] = f.readUInt32()
            block["y"] = f.readUInt32()

        elif block["name"] == "COMP":
            image = _readImage(f, block, palette)
            offset = image.pop("offset")
            block["image_offset"] = offset
            if image["image"] is not None:
                image["image"].name = _imageName(sprite_path, offset)
                spr["images"][offset] = image

        elif block["name"] == "TIME":
            block["time"] = f.readUInt32()

        elif block["name"] == "MARK":
            pass

        elif block["name"] == "MASK":
            pass

        elif block["name"] == "SCOM":
            image = _readImage(f, block, palette)
            offset = image.pop("offset")
            block["image_offset"] = offset
            if image["image"] is not None:
                image["image"].name = _imageName(sprite_path, offset)
                spr["images"][offset] = image

        elif block["name"] == "RAND":
            rand_extra = f.readUInt32()
            block["min"] = f.readUInt32()
            block["max"] = block["min"] + rand_extra

        elif block["name"] == "JUMP":
            block["index"] = f.readUInt32()

        elif block["name"] == "RPOS":
            block["dx"] = f.readSInt32()
            block["dy"] = f.readSInt32()

        elif block["name"] == "SNDF":
            sound_volume = f.readUInt32()  # 75, 95 or 100. volume?
            assert (f.readUInt32() == 0)
            sound_file = str(f.read(16))
            block["volume"] = sound_volume
            block["file"] = sound_file

        elif block["name"] == "MPOS":
            block["x"] = f.readUInt32()
            block["y"] = f.readUInt32()

        elif block["name"] == "PAUS":
            pass

        elif block["name"] == "EXIT":
            pass

        elif block["name"] == "STAT":
            pass

        elif block["name"] == "RGBP":
            palette = Palette.readFullPalette(f)

        else:
            raise ValueError("Unknown block {} at {:#x}".format(
                block["name"], block["start"]))

        block_offsets.append(block["offset"])
        block.pop("length")  # we don't need this any more
        spr["blocks"].append(block)

    for block in spr["blocks"]:
        if block["name"] == "LIST":
            for entry in block["entries"]:
                entry["index"] = block_offsets.index(entry["offset"])

    return spr
예제 #10
0
def triggers(file_path):
    f = File(file_path)
    data = []
    while not f.eof():
        trigger = {"id": f.readUInt32()}

        assert (f.readUInt16() == 0xffff)
        trigger["unknown_a"] = f.readUInt8()
        assert (f.readUInt8() == 0xff)
        trigger["type"] = TriggerType(f.readUInt32())
        trigger["target"] = _readObjectId(f)
        trigger["enabled"] = bool(f.readUInt8())
        trigger["unknown_b"] = f.readUInt8()
        assert (f.readUInt16() == 0xffff)
        trigger["timer_start"] = f.readUInt32()

        if trigger["type"] == TriggerType.TIMER:
            assert (f.readUInt32() == 0)
            assert (f.readUInt32() == 0)
        elif trigger["type"] == TriggerType.PROXIMITY:
            trigger["distance"] = f.readUInt16()
            assert (f.readUInt16() == 0xffff)
            trigger["from"] = _readObjectId(f)
            trigger["to"] = _readObjectId(f)
            trigger["reversed"] = bool(f.readUInt8())
            trigger["instant"] = bool(f.readUInt8())
            assert (f.readUInt16() == 0xffff)
        elif trigger["type"] == TriggerType.UNUSED:
            assert (f.readUInt32() == 0)

        data.append(trigger)
    return data
예제 #11
0
def compstat(file_path):
	f = File(file_path)
	return readCompstat(f)
예제 #12
0
def worldStrt(file_path):
	f = File(file_path)
	data = []
	while not f.eof():
		screen = {}
		screen["advice_id"] = f.readUInt16()
		screen["advice_timer"] = f.readUInt16()
		screen["unknown1"] = f.readUInt8()
		screen["unknown2"] = f.readUInt8()
		screen["id"] = f.readUInt16()
		assert (screen["id"] == len(data))
		screen["target"] = _readObjectId(f)
		screen["action_type"] = f.readUInt8()
		screen["who"] = _readObjectId(f)
		screen["other"] = _readObjectId(f)
		assert(f.readUInt32() == 0xffffffff) # unknown3
		screen["unknown4"] = f.readUInt16()
		assert(screen["unknown4"] in (0xff, 0x1, 0x0))
		assert(f.readUInt16() == 0x0) # unknown5
		assert(f.readUInt8() == 0x0) # unknown6
		for i in range(15):
			assert (f.readUInt8() == 0)
		data.append(screen)
	return data
예제 #13
0
def astStatDat(file_path):
    f = File(file_path)
    state = readAstroState(f)
    assert (f.eof())
    return state
예제 #14
0
def sectorAst(file_path):
    f = File(file_path)
    return {i: f.readLine() for i in range(N_SECTORS)}
예제 #15
0
def worldSlScr(file_path):
	f = File(file_path)

	n_screens = f.readUInt16()
	screens = []
	for i in range(n_screens):
		screen_id = f.readUInt32()
		screen_offset = f.readUInt32()
		screens.append( (screen_id,screen_offset) )

	assert( f.readUInt32() == 0xFF )
	eof = f.readUInt32()

	world_screens = []
	for screen_id,screen_offset in screens:
		assert( f.pos() == screen_offset )

		screen = {
			"id": screen_id,
			"entrances": [],
		}

		background_file_length = f.readUInt8()
		background_file = f.readString()
		assert(len(background_file) + 1 == background_file_length)
		screen["background"] = background_file

		polygons_file_length = f.readUInt8()
		polygons_file = f.readString()
		assert(len(polygons_file) + 1 == polygons_file_length)
		screen["polygons"] = polygons_file

		n_entrances = f.readUInt8()
		for i in range(n_entrances):
			entrance_id = f.readUInt8()

			# unknown is 0x1 for every single screen in every world except
			# screen 11 in world 2, where it's 0x8d.
			# If you don't unwind by one byte then, you end up overrunning
			# the block, and the entrance positions are nonsense.
			entrance_unknown = f.readUInt8()
			if( entrance_unknown != 0x1 ):
				f.setPosition(f.pos() - 1)

			entrance_vertices = []
			for j in range(4):
				entrance_vertices.append({"x": f.readUInt16(), "y": f.readUInt16()})
			entrance = {
				"entrance_id": entrance_id,
				"unknown": entrance_unknown,
				"vertices": entrance_vertices,
			}
			screen["entrances"].append(entrance)
		world_screens.append(screen)

	assert(f.pos() == eof)

	return { "screens": world_screens }
예제 #16
0
def worldStScr(file_path):
	f = File(file_path)

	n_entries = f.readUInt16()
	entries = []
	for i in range(n_entries):
		id = f.readUInt32()
		offset = f.readUInt32()
		entries.append( (id,offset) )

	assert(f.readUInt32() == 0xFF)
	eof = f.readUInt32()

	n_screen_unknown = f.readUInt8()
	screen_unknown = [f.readUInt16() for x in range(n_screen_unknown)]

	screen_polygons = []
	for id,offset in entries:
		assert(f.pos() == offset)

		poly_type = f.readUInt8()
		assert(poly_type in [0,1,3,4])

		assert(f.readUInt16() == 0)

		n_vertices = f.readUInt8()
		poly_vertices = []
		for i in range(n_vertices):
			x = f.readUInt16()
			y = f.readUInt16()
			distance = f.readUInt16()
			poly_vertices.append({
				"x": x,
				"y": y,
				"distance": distance,
				})

		n_poly_unknown = f.readUInt8()
		poly_unknown = []
		for i in range(n_poly_unknown):
			poly_unknown.append((f.readUInt8(), f.readUInt8()))

		assert(f.readUInt16() == 0)

		screen_polygons.append({
			"type": poly_type,
			"vertices": poly_vertices,
			"unknown": poly_unknown,
		})

	assert(f.pos() == eof)

	screen = {
		"unknown": screen_unknown,
		"polgons": screen_polygons,
	}

	return screen
예제 #17
0
def fullPalette(local_path, global_path):
    """Read a full (256 colour) palette, getting the local and global parts from two separate files"""
    local_palette = readSinglePalette(File(local_path))
    global_palette = readSinglePalette(File(global_path))
    return local_palette + global_palette