While working on the content for the upcoming post about the musical resources of the LucasArts video game Indiana Jones and the Fate of Atlantis[1] (or simply FOA), I wanted to develop a small tool to extract the color palettes and background images from the game.
I thought that having the background images for each environment in the game would eventually be useful to quickly recall the events of the game at any given moment in the story.
The Python code I wrote to export these images is hosted on my GitHub page, here[2]. To make it work, you need to have the original FOA game files: the index file ATLANTIS.000
and the resource file ATLANTIS.001
.
Below a table with all the room images and palettes extracted with the tool:
Room Number | Room Name | Background Image | Color Palette |
1 | col-offic |
![]() |
![]() |
2 | col-hall_ |
![]() |
![]() |
3 | col-basem |
![]() |
![]() |
4 | col-attic |
![]() |
![]() |
5 | col-store |
![]() |
![]() |
6 | col-archi |
![]() |
![]() |
7 | col-catro |
![]() |
![]() |
8 | wallet___ |
![]() |
![]() |
9 | natl-geo_ |
![]() |
![]() |
10 | sop-theat |
![]() |
![]() |
11 | sop-stage |
![]() |
![]() |
12 | sop-sides |
![]() |
![]() |
13 | de-ice-ex |
![]() |
![]() |
14 | dig-top__ |
![]() |
![]() |
15 | sop-study |
![]() |
![]() |
16 | a2-skelet |
![]() |
![]() |
17 | a2-digger |
![]() |
![]() |
18 | a2-rube__ |
![]() |
![]() |
19 | de-azores |
![]() |
![]() |
20 | sahara___ |
![]() |
![]() |
21 | a3-pit-to |
![]() |
![]() |
22 | a3-god-ma |
![]() |
![]() |
23 | a3-center |
![]() |
![]() |
24 | deadroom_ |
![]() |
![]() |
25 | sub-volca |
![]() |
![]() |
26 | de-ice-in |
![]() |
![]() |
27 | mc-hotel_ |
![]() |
![]() |
28 | mc-seance |
![]() |
![]() |
29 | af-cas-fl |
![]() |
![]() |
30 | a3-god-hi |
![]() |
![]() |
31 | a2-cu-rob |
![]() |
![]() |
32 | bal-deser |
![]() |
![]() |
33 | lab-crete |
![]() |
![]() |
35 | a1-2-bot_ |
![]() |
![]() |
36 | a1-o-mach |
![]() |
![]() |
37 | a1-o-pool |
![]() |
![]() |
39 | sub-1-ins |
![]() |
![]() |
40 | sub-2-ins |
![]() |
![]() |
41 | sub-conn- |
![]() |
![]() |
42 | sal-surfa |
![]() |
![]() |
43 | cr-bro-ex |
![]() |
![]() |
44 | cr-bro-in |
![]() |
![]() |
45 | digger-ri |
![]() |
![]() |
46 | a1-canal_ |
![]() |
![]() |
47 | cu-uberma |
![]() |
![]() |
48 | a1-darkro |
![]() |
![]() |
49 | th-dock__ |
![]() |
![]() |
50 | labyrinth |
![]() |
![]() |
51 | catacombs |
![]() |
![]() |
52 | labwat-1_ |
![]() |
![]() |
53 | lab-subwa |
![]() |
![]() |
54 | lab-hide_ |
![]() |
![]() |
55 | a3-maze__ |
![]() |
![]() |
56 | lab-eleva |
![]() |
![]() |
57 | lab-three |
![]() |
![]() |
58 | transit__ |
![]() |
![]() |
59 | lab-mapro |
![]() |
![]() |
60 | lab-goldb |
![]() |
![]() |
61 | labwat-2_ |
![]() |
![]() |
62 | nazi-labo |
![]() |
![]() |
63 | th-landsc |
![]() |
![]() |
64 | af-cas-st |
![]() |
![]() |
65 | af-cas-ho |
![]() |
![]() |
66 | sub-under |
![]() |
![]() |
67 | af-atl-ex |
![]() |
![]() |
68 | logo_____ |
![]() |
![]() |
69 | th-dig-ex |
![]() |
![]() |
70 | mc-chase_ |
![]() |
![]() |
71 | mc-smashu |
![]() |
![]() |
72 | th-dig-in |
![]() |
![]() |
73 | af-atl-in |
![]() |
![]() |
74 | cu-microt |
![]() |
![]() |
75 | map-world |
![]() |
![]() |
76 | de-yuc-ex |
![]() |
![]() |
77 | de-yuc-in |
![]() |
![]() |
78 | af-cas-ov |
![]() |
![]() |
79 | cu-neckla |
![]() |
![]() |
80 | af-launch |
![]() |
![]() |
81 | lockrock_ |
![]() |
![]() |
82 | sal-under |
![]() |
![]() |
83 | cu-plato_ |
![]() |
![]() |
84 | cu-rube__ |
![]() |
![]() |
85 | a1-nw-top |
![]() |
![]() |
86 | a1-ne-top |
![]() |
![]() |
87 | a1-sw-top |
![]() |
![]() |
88 | a1-se-top |
![]() |
![]() |
89 | end-volca |
![]() |
![]() |
90 | end-v2___ |
![]() |
![]() |
91 | a1-2-dark |
![]() |
![]() |
92 | atlan-1__ |
![]() |
![]() |
93 | atlan-2__ |
![]() |
![]() |
94 | a2-generi |
![]() |
![]() |
95 | bal-sea__ |
![]() |
![]() |
96 | endscene_ |
![]() |
![]() |
97 | a1-cagero |
![]() |
![]() |
98 | _________ |
![]() |
![]() |
The images from LucasArts video games were stored in the resource file in a compressed format. They were "sliced" into vertical strips, each 8 pixels wide, and then the strip data was compressed using a sort of custom RLE algorithm[3], which could change depending on the graphic content of each strip.
Building the decoder wasn’t exactly straightforward because I found few references online, and in some cases, even conflicting ones. During my experiments, I encountered interesting glitch effects, such as those caused by an incorrect increment of the color pointer within the palette in the codec1
.
If the codec1 implementation is as follows
while pixel_left > 0: if bitReader.read_bit(): if not bitReader.read_bit(): color_index = bitReader.read_bits( palette_index_size ) inc = -1 else: if bitReader.read_bit(): inc = -inc color_index += inc image_writer.write_pixel( i, COLOR_LOOKUP_TABLE[ color_index ], 1, direction ) pixel_left -= 1
... everything works correctly, but if instead of inc = -1
we use inc = +1
, here's what happens:
Codec1 glitch Image |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
The tool I developed was heavily inspired by other similar tools that can be found with a simple web search.
Moreover, it wouldn't have been possible to implement it without the vast amount of resources and documentation available on the ScummVM project website and elsewhere. Below is a non-exhaustive list:
^ | [1] | Indiana Jones and the Fate of Atlantis wiki page |
^ | [2] | Custom python FOA palette and background images extraction tool |
^ | [3] | RLE algorithm wiki page |