1 /*
2   Head
3 */
4 
5 #include "head.h"
6 
7 #include "infocom.h"
8 #include "mem.h"
9 #include "os.h"
10 #include "page.h"
11 #include "shared.h"
12 #include "stop.h"
13 #include "support.h"
14 #include "wio.h"
15 
16 static filep game_file;
17 
18 /* Interpreter numbers */
19 
20 #define XZIP             0
21 #define DEC_20           1
22 #define APPLE_2E         2
23 #define MACINTOSH        3
24 #define AMIGA            4
25 #define ATARI_ST         5
26 #define IBM_MSDOS        6
27 #define COMMODORE_128    7
28 #define C64              8
29 #define APPLE_2C         9
30 #define APPLE_2GS       10
31 #define TANDY_COLOR     11
32 
33 #ifndef INTERPRETER
34 #define INTERPRETER     APPLE_2E
35 #endif
36 
37 /* Script flags */
38 
39 #define SCRIPT_MODE_ON      0x0001
40 #define USE_NON_PROP_FONT   0x0002
41 #define SCRIPT_ERROR        0x0400
42 
43 /* Mode flags (change with version) */
44 
45 #define mode3_status        0x02 /* What sort of status line */
46 #define mode3_tandy         0x08 /* Set for tandy interpreters */
47 #define mode3_non_status    0x10 /* Set if can't do status line */
48 #define mode3_can_split     0x20 /* Set if can split screen */
49 #define mode3_non_fixed     0x40 /* Set if using non-fixed-space fonts */
50 
51 #define set_mode3           (mode3_status | mode3_can_split | mode3_non_fixed)
52 #define clr_mode3           (mode3_non_status)
53 
54 #define mode4_can_colour    0x01 /* Colour available */
55 #define mode4_can_picture   0x02 /* Always on V4, If pictures on V6 */
56 #define mode4_can_bold      0x04 /* Bold available */
57 #define mode4_can_emph      0x08 /* Can do underline */
58 #define mode4_can_fixed     0x10 /* Can do fixed width */
59 #define mode4_can_sound     0x20 /* Sound effects */
60 #define mode4_can_timed     0x80 /* Can do timed inputs */
61 
62 #define set_mode4           (mode4_can_colour | mode4_can_bold | mode4_can_emph | mode4_can_fixed)
63 #define clr_mode4           (mode4_can_sound | mode4_can_timed)
64 
65 /* Offsets into the header, all are 1 byte in extent unless specified */
66 
67 #define z_code_version        0 /* Game's Z-CODE Version Number      */
68 #define mode_bits             1 /* Status Bar display indicator      */
69 #define release               2 /* 2 bytes for game release number   */
70 #define resident_bytes        4 /* 2 bytes giving resident bytes     */
71 #define start                 6 /* 2 bytes, offset to game start     */
72 #define vocab                 8 /* 2 bytes, offset to vocabulary     */
73 #define object_list          10 /* 2 bytes, offset to objects        */
74 #define globals              12 /* 2 bytes, offset to globals        */
75 #define save_bytes           14 /* 2 bytes, length to save to disk   */
76 #define script_status        16 /* 2 bytes, printing modes           */
77 #define serial_no            18 /* 6 bytes, serial number            */
78 #define common_word          24 /* 2 bytes, offset to common words   */
79 #define verify_length        26 /* 2 bytes, total game file size     */
80 #define verify_checksum      28 /* 2 bytes, checksum for verify      */
81 #define interpreter_number   30 /* 1 byte, set by interpreter        */
82 #define interpreter_version  31 /* 1 byte, letter set by interpreter */
83 #define screen_height        32 /* 1 byte, set by interpreter        */
84 #define screen_width         33 /* 1 byte, set by interpreter        */
85 #define left                 34 /* 1 byte, set by interpreter        */
86 #define right                35 /* 1 byte, set by interpreter        */
87 #define top                  36 /* 1 byte, set by interpreter        */
88 #define bottom               37 /* 1 byte, set by interpreter        */
89 #define unknown1             38 /* 1 unknown, set by interpreter     */
90 #define unknown2             39 /* 1 unknown, set by interpreter     */
91 #define code_offset          40 /* 1 word, code offset in longs (>V5)*/
92 #define text_offset          42 /* 1 word, code offset in longs (>V5)*/
93 #define default_back         44 /* 1 byte, default paper set by interpreter */
94 #define default_fore         45 /* 1 byte, default ink set by interpreter */
95 #define unknown5             46 /* 1 unknown, set in data file       */
96 #define padding2             48 /* 6 blanks                          */
97 #define unknown6             54 /* 2 unknowns                        */
98 #define padding3             56 /* 8 blanks                          */
99 
100 /* For a total of 64 bytes of header */
101 
hd_open(char * filename)102 int hd_open(char *filename)
103 {
104   game_file = os_wild_read(filename);
105   return game_file != 0;
106 }
107 
hd_close(void)108 void hd_close(void)
109 {
110   os_close(game_file);
111 }
112 
hd_load(word block,word num_blocks,byte * ptr)113 void hd_load(word block, word num_blocks, byte *ptr)
114 {
115   int wide    = hd_width();
116   int high    = hd_height();
117   long_word offset = ((long_word) block) << BLOCK_SHIFT;
118   if(os_seek_fore(game_file, offset) < 0)
119   {
120     display((byte *) "Failed to Seek required Blocks\n");
121     quit();
122   }
123   /* Need the -1 since we may want a final (incomplete) block */
124   else if(os_read(ptr, BLOCK_SIZE, num_blocks, game_file) < num_blocks - 1)
125   {
126     display((byte *) "Failed to Read required Blocks\n");
127     quit();
128   }
129   hd_set_size(high, wide);
130 }
131 
hd_flip(word page,byte * block)132 void hd_flip(word page, byte *block)
133 {
134 #if 0
135   int i;
136   byte b[BLOCK_SIZE];
137   hd_load(page, 1, b);
138   for(i = 0; i < BLOCK_SIZE; ++i)
139     block[i] ^= b[i];
140 #else
141   byte b[BLOCK_SIZE];
142   word *s = (void *) b;
143   word *d = (void *) block;
144   int c = BLOCK_SIZE / (2 * sizeof(*s));
145   hd_load(page, 1, b);
146   do { *d ^= *s; *++d ^= *++s; ++d; ++s; } while(--c);
147 #endif
148 }
149 
hd_no_colour(void)150 void hd_no_colour(void)
151 {
152   if(hd_plus())
153     base_ptr[mode_bits] &= ~mode4_can_sound;
154 }
155 
hd_init(void)156 void hd_init(void)
157 {
158   base_ptr[interpreter_number]  = INTERPRETER;
159   base_ptr[interpreter_version] = 'A';
160   if(hd_plus())
161     base_ptr[mode_bits] = (base_ptr[mode_bits] | set_mode4) & ~clr_mode4;
162   else
163     base_ptr[mode_bits] = (base_ptr[mode_bits] | set_mode3) & ~clr_mode3;
164   if(hd_five())
165   {
166     base_ptr[left]         = 0;
167     base_ptr[top]          = 0;
168     base_ptr[unknown1]     = 1;
169     base_ptr[unknown2]     = 1;
170     base_ptr[default_back] = 9;
171     base_ptr[default_fore] = 2;
172   }
173 }
174 
hd_set_size(int high,int wide)175 void hd_set_size(int high, int wide)
176 {
177   base_ptr[screen_width]  = wide;
178   base_ptr[screen_height] = high - 1;
179   base_ptr[right]         = wide;
180   base_ptr[bottom]        = high - 1;
181 }
182 
hd_width(void)183 int hd_width(void)
184 {
185   return base_ptr[screen_width];
186 }
187 
hd_height(void)188 int hd_height(void)
189 {
190   return (int) base_ptr[screen_height] + 1;
191 }
192 
hd_version(void)193 version hd_version(void)
194 {
195   return base_ptr[z_code_version];
196 }
197 
198 /*
199   hd_resident_blocks could actually use save_bytes rather than
200   resident_bytes -- Graham calls these
201 
202   dynamic memory                        (can be changed)
203                 <-- split defined by $0e, so save_bytes
204   static memory                         (assumed resident)
205                 <-- split defined by $04, so resident_bytes
206   high_memory                           (used for code and strings)
207 
208   Doing so would mean that pg_delta packed pages less often
209 */
210 
hd_resident_blocks(void)211 word hd_resident_blocks(void)
212 {
213 #if 0
214   return pg_blocks(rd_word_ptr(base_ptr + resident_bytes));
215 #else
216   return pg_blocks(rd_word_ptr(base_ptr + save_bytes));
217 #endif
218 }
219 
hd_verify(void)220 word hd_verify(void)
221 {
222   return rd_word_ptr(base_ptr + verify_length);
223 }
224 
hd_save_blocks(void)225 word hd_save_blocks(void)
226 {
227   return pg_blocks(rd_word_ptr(base_ptr + save_bytes));
228 }
229 
hd_start(void)230 word hd_start(void)
231 {
232   return rd_word_ptr(base_ptr + start);
233 }
234 
hd_mode(void)235 byte hd_mode(void)
236 {
237   return base_ptr[mode_bits];
238 }
239 
hd_set_screen(void)240 void hd_set_screen(void)
241 {
242   wr_word_ptr(base_ptr + mode_bits, rd_word_ptr(base_ptr + mode_bits) | SCREEN_MODES);
243 }
244 
hd_check(void)245 word hd_check(void)
246 {
247   return rd_word_ptr(base_ptr + verify_checksum);
248 }
249 
hd_script(void)250 static word hd_script(void)
251 {
252   return rd_word_ptr(base_ptr + script_status);
253 }
254 
hd_set_script(int on)255 void hd_set_script(int on)
256 {
257   if(on)
258     wr_word_ptr(base_ptr + script_status, rd_word_ptr(base_ptr + script_status) | SCRIPT_MODE_ON);
259   else
260     wr_word_ptr(base_ptr + script_status, rd_word_ptr(base_ptr + script_status) & ~ SCRIPT_MODE_ON);
261 }
262 
hd_set_fixed(int on)263 void hd_set_fixed(int on)
264 {
265   if(on)
266     wr_word_ptr(base_ptr + script_status, rd_word_ptr(base_ptr + script_status) | USE_NON_PROP_FONT);
267   else
268     wr_word_ptr(base_ptr + script_status, rd_word_ptr(base_ptr + script_status) & ~USE_NON_PROP_FONT);
269 }
270 
hd_get_script(void)271 bool hd_get_script(void)
272 {
273   return (hd_script() & SCRIPT_MODE_ON) != 0;
274 }
275 
hd_get_fixed(void)276 bool hd_get_fixed(void)
277 {
278   return (hd_script() & USE_NON_PROP_FONT) != 0;
279 }
280 
hd_err_script(void)281 void hd_err_script(void)
282 {
283   wr_word_ptr(base_ptr + script_status, SCRIPT_ERROR);
284 }
285 
hd_object(void)286 word hd_object(void)
287 {
288   return rd_word_ptr(base_ptr + object_list);
289 }
290 
hd_global(void)291 word hd_global(void)
292 {
293   return rd_word_ptr(base_ptr + globals);
294 }
295 
hd_common(void)296 word hd_common(void)
297 {
298   return rd_word_ptr(base_ptr + common_word);
299 }
300 
hd_vocab(void)301 word hd_vocab(void)
302 {
303   return rd_word_ptr(base_ptr + vocab);
304 }
305 
hd_plus(void)306 int hd_plus(void)
307 {
308   return hd_version() >= VERSION_4;
309 }
310 
hd_five(void)311 int hd_five(void)
312 {
313   return hd_version() >= VERSION_5;
314 }
315 
hd_offset(word w)316 static word hd_offset(word w)
317 {
318   switch(hd_version())
319   {
320     case VERSION_6:
321     case VERSION_7:
322       return rd_word_ptr(base_ptr + w);
323     default:
324       return 0;
325   }
326 }
327 
hd_code_offset(void)328 word hd_code_offset(void)
329 { return hd_offset(code_offset); }
330 
hd_text_offset(void)331 word hd_text_offset(void)
332 { return hd_offset(text_offset); }
333 
hd_request_status(void)334 void hd_request_status(void)
335 {
336   /* Set the header bit asking for a redraw? */
337 }
338