1 /*
2 SDLPoP, a port/conversion of the DOS game Prince of Persia.
3 Copyright (C) 2013-2021 Dávid Nagy
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>.
17
18 The authors of this program may be contacted at https://forum.princed.org
19 */
20
21 #include "common.h"
22
23 #define SEQTBL_BASE 0x196E
24 #define SEQTBL_0 (seqtbl - SEQTBL_BASE)
25 extern const byte seqtbl[]; // the sequence table is defined in seqtbl.c
26
27 // seg006:0006
get_tile(int room,int col,int row)28 int __pascal far get_tile(int room,int col,int row) {
29 curr_room = room;
30 tile_col = col;
31 tile_row = row;
32 curr_room = find_room_of_tile();
33 // bugfix: check_chomped_kid may call with room = -1
34 if (curr_room > 0) {
35 get_room_address(curr_room);
36 curr_tilepos = tbl_line[tile_row] + tile_col;
37 curr_tile2 = curr_room_tiles[curr_tilepos] & 0x1F;
38 } else {
39 // wall in room 0
40 curr_tile2 = custom->level_edge_hit_tile; // tiles_20_wall
41 }
42 return curr_tile2;
43 }
44
45 // seg006:005D
find_room_of_tile()46 int __pascal far find_room_of_tile() {
47 again:
48 #ifdef FIX_CORNER_GRAB
49 // Check tile_row < 0 first, this way the prince can grab a ledge at the bottom right corner of a room with no room below.
50 // Details: https://forum.princed.org/viewtopic.php?p=30410#p30410
51 if (tile_row < 0) {
52 tile_row += 3;
53 if (curr_room) {
54 curr_room = level.roomlinks[curr_room - 1].up;
55 }
56 //find_room_of_tile();
57 goto again;
58 }
59 #endif
60 if (tile_col < 0) {
61 tile_col += 10;
62 if (curr_room) {
63 curr_room = level.roomlinks[curr_room - 1].left;
64 }
65 //find_room_of_tile();
66 goto again;
67 }
68 if (tile_col >= 10) {
69 tile_col -= 10;
70 if (curr_room) {
71 curr_room = level.roomlinks[curr_room - 1].right;
72 }
73 //find_room_of_tile();
74 goto again;
75 }
76 #ifndef FIX_CORNER_GRAB
77 // if (tile_row < 0) was here originally
78 if (tile_row < 0) {
79 tile_row += 3;
80 if (curr_room) {
81 curr_room = level.roomlinks[curr_room - 1].up;
82 }
83 //find_room_of_tile();
84 goto again;
85 }
86 #endif
87 if (tile_row >= 3) {
88 tile_row -= 3;
89 if (curr_room) {
90 curr_room = level.roomlinks[curr_room - 1].down;
91 }
92 //find_room_of_tile();
93 goto again;
94 }
95 return curr_room;
96 }
97
98 // seg006:00EC
get_tilepos(int tile_col,int tile_row)99 int __pascal far get_tilepos(int tile_col,int tile_row) {
100 if (tile_row < 0) {
101 return -(tile_col + 1);
102 } else if (tile_row >= 3 || tile_col >= 10 || tile_col < 0) {
103 return 30;
104 } else {
105 return tbl_line[tile_row] + tile_col;
106 }
107 }
108
109 // seg006:0124
get_tilepos_nominus(int tile_col,int tile_row)110 int __pascal far get_tilepos_nominus(int tile_col,int tile_row) {
111 short var_2;
112 var_2 = get_tilepos(tile_col, tile_row);
113 if (var_2 < 0) return 30; else return var_2;
114 }
115
116 // seg006:0144
load_fram_det_col()117 void __pascal far load_fram_det_col() {
118 load_frame();
119 determine_col();
120 }
121
122 // seg006:014D
determine_col()123 void __pascal far determine_col() {
124 Char.curr_col = get_tile_div_mod_m7(dx_weight());
125 }
126
127 // data:0FE0
128 const frame_type frame_table_kid[] = {
129 { 255, 0x00| 0, 0, 0, 0x00| 0},
130 { 0, 0x00| 0, 1, 0, 0xC0| 4},
131 { 1, 0x00| 0, 1, 0, 0x40| 4},
132 { 2, 0x00| 0, 3, 0, 0x40| 7},
133 { 3, 0x00| 0, 4, 0, 0x40| 8},
134 { 4, 0x00| 0, 0, 0, 0xE0| 6},
135 { 5, 0x00| 0, 0, 0, 0x40| 9},
136 { 6, 0x00| 0, 0, 0, 0x40|10},
137 { 7, 0x00| 0, 0, 0, 0xC0| 5},
138 { 8, 0x00| 0, 0, 0, 0x40| 4},
139 { 9, 0x00| 0, 0, 0, 0x40| 7},
140 { 10, 0x00| 0, 0, 0, 0x40|11},
141 { 11, 0x00| 0, 0, 0, 0x40| 3},
142 { 12, 0x00| 0, 0, 0, 0xC0| 3},
143 { 13, 0x00| 0, 0, 0, 0x40| 7},
144 { 14, 0x00| 9, 0, 0, 0x40| 3},
145 { 15, 0x00| 0, 0, 0, 0xC0| 3},
146 { 16, 0x00| 0, 0, 0, 0x40| 4},
147 { 17, 0x00| 0, 0, 0, 0x40| 6},
148 { 18, 0x00| 0, 0, 0, 0x40| 8},
149 { 19, 0x00| 0, 0, 0, 0x80| 9},
150 { 20, 0x00| 0, 0, 0, 0x00|11},
151 { 21, 0x00| 0, 0, 0, 0x80|11},
152 { 22, 0x00| 0, 0, 0, 0x00|17},
153 { 23, 0x00| 0, 0, 0, 0x00| 7},
154 { 24, 0x00| 0, 0, 0, 0x00| 5},
155 { 25, 0x00| 0, 0, 0, 0xC0| 1},
156 { 26, 0x00| 0, 0, 0, 0xC0| 6},
157 { 27, 0x00| 0, 0, 0, 0x40| 3},
158 { 28, 0x00| 0, 0, 0, 0x40| 8},
159 { 29, 0x00| 0, 0, 0, 0x40| 2},
160 { 30, 0x00| 0, 0, 0, 0x40| 2},
161 { 31, 0x00| 0, 0, 0, 0xC0| 2},
162 { 32, 0x00| 0, 0, 0, 0xC0| 2},
163 { 33, 0x00| 0, 0, 0, 0x40| 3},
164 { 34, 0x00| 0, 0, 0, 0x40| 8},
165 { 35, 0x00| 0, 0, 0, 0xC0|14},
166 { 36, 0x00| 0, 0, 0, 0xC0| 1},
167 { 37, 0x00| 0, 0, 0, 0x40| 5},
168 { 38, 0x00| 0, 0, 0, 0x80|14},
169 { 39, 0x00| 0, 0, 0, 0x00|11},
170 { 40, 0x00| 0, 0, 0, 0x80|11},
171 { 41, 0x00| 0, 0, 0, 0x80|10},
172 { 42, 0x00| 0, 0, 0, 0x00| 1},
173 { 43, 0x00| 0, 0, 0, 0xC0| 4},
174 { 44, 0x00| 0, 0, 0, 0xC0| 3},
175 { 45, 0x00| 0, 0, 0, 0xC0| 3},
176 { 46, 0x00| 0, 0, 0, 0xA0| 5},
177 { 47, 0x00| 0, 0, 0, 0xA0| 4},
178 { 48, 0x00| 0, 0, 0, 0x60| 6},
179 { 49, 0x00| 0, 4, 0, 0x60| 7},
180 { 50, 0x00| 0, 3, 0, 0x60| 6},
181 { 51, 0x00| 0, 1, 0, 0x40| 4},
182 { 64, 0x00| 0, 0, 0, 0xC0| 2},
183 { 65, 0x00| 0, 0, 0, 0x40| 1},
184 { 66, 0x00| 0, 0, 0, 0x40| 2},
185 { 67, 0x00| 0, 0, 0, 0x00| 0},
186 { 68, 0x00| 0, 0, 0, 0x00| 0},
187 { 69, 0x00| 0, 0, 0, 0x80| 0},
188 { 70, 0x00| 0, 0, 0, 0x00| 0},
189 { 71, 0x00| 0, 0, 0, 0x80| 0},
190 { 72, 0x00| 0, 0, 0, 0x00| 0},
191 { 73, 0x00| 0, 0, 0, 0x80| 0},
192 { 74, 0x00| 0, 0, 0, 0x00| 0},
193 { 75, 0x00| 0, 0, 0, 0x00| 0},
194 { 76, 0x00| 0, 0, 0, 0x80| 0},
195 { 255, 0x00| 0, 0, 0, 0x00| 0},
196 { 80, 0x00| 0, -2, 0, 0x40| 1},
197 { 81, 0x00| 0, -2, 0, 0x40| 1},
198 { 82, 0x00| 0, -1, 0, 0xC0| 2},
199 { 83, 0x00| 0, -2, 0, 0x40| 2},
200 { 84, 0x00| 0, -2, 0, 0x40| 1},
201 { 85, 0x00| 0, -2, 0, 0x40| 1},
202 { 86, 0x00| 0, -2, 0, 0x40| 1},
203 { 87, 0x00| 0, -1, 0, 0x00| 7},
204 { 88, 0x00| 0, -1, 0, 0x00| 5},
205 { 89, 0x00| 0, 2, 0, 0x00| 7},
206 { 90, 0x00| 0, 2, 0, 0x00| 7},
207 { 91, 0x00| 0, 2, -3, 0x00| 0},
208 { 92, 0x00| 0, 2, -10, 0x00| 0},
209 { 93, 0x00| 0, 2, -11, 0x80| 0},
210 { 94, 0x00| 0, 3, -2, 0x40| 3},
211 { 95, 0x00| 0, 3, 0, 0xC0| 3},
212 { 96, 0x00| 0, 3, 0, 0xC0| 3},
213 { 97, 0x00| 0, 3, 0, 0x60| 3},
214 { 98, 0x00| 0, 4, 0, 0xE0| 3},
215 { 28, 0x00| 0, 0, 0, 0x00| 0},
216 { 99, 0x00| 0, 7, -14, 0x80| 0},
217 { 100, 0x00| 0, 7, -12, 0x80| 0},
218 { 101, 0x00| 0, 4, -12, 0x00| 0},
219 { 102, 0x00| 0, 3, -10, 0x80| 0},
220 { 103, 0x00| 0, 2, -10, 0x80| 0},
221 { 104, 0x00| 0, 1, -10, 0x80| 0},
222 { 105, 0x00| 0, 0, -11, 0x00| 0},
223 { 106, 0x00| 0, -1, -12, 0x00| 0},
224 { 107, 0x00| 0, -1, -14, 0x00| 0},
225 { 108, 0x00| 0, -1, -14, 0x00| 0},
226 { 109, 0x00| 0, -1, -15, 0x80| 0},
227 { 110, 0x00| 0, -1, -15, 0x80| 0},
228 { 111, 0x00| 0, 0, -15, 0x00| 0},
229 { 255, 0x00| 0, 0, 0, 0x00| 0},
230 { 255, 0x00| 0, 0, 0, 0x00| 0},
231 { 112, 0x00| 0, 0, 0, 0xC0| 6},
232 { 113, 0x00| 0, 0, 0, 0x40| 6},
233 { 114, 0x00| 0, 0, 0, 0xC0| 5},
234 { 115, 0x00| 0, 0, 0, 0x40| 5},
235 { 116, 0x00| 0, 0, 0, 0xC0| 2},
236 { 117, 0x00| 0, 0, 0, 0xC0| 4},
237 { 118, 0x00| 0, 0, 0, 0xC0| 5},
238 { 119, 0x00| 0, 0, 0, 0x40| 6},
239 { 120, 0x00| 0, 0, 0, 0x40| 7},
240 { 121, 0x00| 0, 0, 0, 0x40| 7},
241 { 122, 0x00| 0, 0, 0, 0x40| 9},
242 { 123, 0x00| 0, 0, 0, 0xC0| 8},
243 { 124, 0x00| 0, 0, 0, 0xC0| 9},
244 { 125, 0x00| 0, 0, 0, 0x40| 9},
245 { 126, 0x00| 0, 0, 0, 0x40| 5},
246 { 127, 0x00| 0, 2, 0, 0x40| 5},
247 { 128, 0x00| 0, 2, 0, 0xC0| 5},
248 { 129, 0x00| 0, 0, 0, 0xC0| 3},
249 { 255, 0x00| 0, 0, 0, 0x00| 0},
250 { 133, 0x00| 0, 0, 0, 0x40| 3},
251 { 134, 0x00| 0, 0, 0, 0xC0| 4},
252 { 135, 0x00| 0, 0, 0, 0xC0| 5},
253 { 136, 0x00| 0, 0, 0, 0x40| 8},
254 { 137, 0x00| 0, 0, 0, 0x60|12},
255 { 138, 0x00| 0, 0, 0, 0xE0|15},
256 { 139, 0x00| 0, 0, 0, 0x60| 3},
257 { 140, 0x00| 0, 0, 0, 0xC0| 3},
258 { 141, 0x00| 0, 0, 0, 0x40| 3},
259 { 142, 0x00| 0, 0, 0, 0x40| 3},
260 { 143, 0x00| 0, 0, 0, 0x40| 4},
261 { 144, 0x00| 0, 0, 0, 0x40| 4},
262 { 172, 0x00| 0, 0, 1, 0xC0| 1},
263 { 173, 0x00| 0, 0, 1, 0xC0| 7},
264 { 145, 0x00| 0, 0, -12, 0x00| 1},
265 { 146, 0x00| 0, 0, -21, 0x00| 0},
266 { 147, 0x00| 0, 1, -26, 0x80| 0},
267 { 148, 0x00| 0, 4, -32, 0x80| 0},
268 { 149, 0x00| 0, 6, -36, 0x80| 1},
269 { 150, 0x00| 0, 7, -41, 0x80| 2},
270 { 151, 0x00| 0, 2, 17, 0x40| 2},
271 { 152, 0x00| 0, 4, 9, 0xC0| 4},
272 { 153, 0x00| 0, 4, 5, 0xC0| 9},
273 { 154, 0x00| 0, 4, 4, 0xC0| 8},
274 { 155, 0x00| 0, 5, 0, 0x60| 9},
275 { 156, 0x00| 0, 5, 0, 0xE0| 9},
276 { 157, 0x00| 0, 5, 0, 0xE0| 8},
277 { 158, 0x00| 0, 5, 0, 0x60| 9},
278 { 159, 0x00| 0, 5, 0, 0x60| 9},
279 { 184, 0x00|16, 0, 2, 0x80| 0},
280 { 174, 0x00|26, 0, 2, 0x80| 0},
281 { 175, 0x00|18, 3, 2, 0x00| 0},
282 { 176, 0x00|22, 7, 2, 0xC0| 4},
283 { 177, 0x00|21, 10, 2, 0x00| 0},
284 { 178, 0x00|23, 7, 2, 0x80| 0},
285 { 179, 0x00|25, 4, 2, 0x80| 0},
286 { 180, 0x00|24, 0, 2, 0xC0|14},
287 { 181, 0x00|15, 0, 2, 0xC0|13},
288 { 182, 0x00|20, 3, 2, 0x00| 0},
289 { 183, 0x00|31, 3, 2, 0x00| 0},
290 { 184, 0x00|16, 0, 2, 0x80| 0},
291 { 185, 0x00|17, 0, 2, 0x80| 0},
292 { 186, 0x00|32, 0, 2, 0x00| 0},
293 { 187, 0x00|33, 0, 2, 0x80| 0},
294 { 188, 0x00|34, 2, 2, 0xC0| 3},
295 { 14, 0x00| 0, 0, 0, 0x40| 3},
296 { 189, 0x00|19, 7, 2, 0x80| 0},
297 { 190, 0x00|14, 1, 2, 0x80| 0},
298 { 191, 0x00|27, 0, 2, 0x80| 0},
299 { 181, 0x00|15, 0, 2, 0xC0|13},
300 { 181, 0x00|15, 0, 2, 0xC0|13},
301 { 112, 0x00|43, 0, 0, 0xC0| 6},
302 { 113, 0x00|44, 0, 0, 0x40| 6},
303 { 114, 0x00|45, 0, 0, 0xC0| 5},
304 { 115, 0x00|46, 0, 0, 0x40| 5},
305 { 114, 0x00| 0, 0, 0, 0xC0| 5},
306 { 78, 0x00| 0, 0, 3, 0x80|10},
307 { 77, 0x00| 0, 4, 3, 0x80| 7},
308 { 211, 0x00| 0, 0, 1, 0x40| 4},
309 { 212, 0x00| 0, 0, 1, 0x40| 4},
310 { 213, 0x00| 0, 0, 1, 0x40| 4},
311 { 214, 0x00| 0, 0, 1, 0x40| 7},
312 { 215, 0x00| 0, 0, 7, 0x40|11},
313 { 255, 0x00| 0, 0, 0, 0x00| 0},
314 { 79, 0x00| 0, 4, 7, 0x40| 9},
315 { 130, 0x00| 0, 0, 0, 0x40| 4},
316 { 131, 0x00| 0, 0, 0, 0x40| 4},
317 { 132, 0x00| 0, 0, 2, 0x40| 4},
318 { 255, 0x00| 0, 0, 0, 0x00| 0},
319 { 255, 0x00| 0, 0, 0, 0x00| 0},
320 { 192, 0x00| 0, 0, 0, 0x00| 0},
321 { 193, 0x00| 0, 0, 1, 0x00| 0},
322 { 194, 0x00| 0, 0, 0, 0x80| 0},
323 { 195, 0x00| 0, 0, 0, 0x00| 0},
324 { 196, 0x00| 0, -1, 0, 0x00| 0},
325 { 197, 0x00| 0, -1, 0, 0x00| 0},
326 { 198, 0x00| 0, -1, 0, 0x00| 0},
327 { 199, 0x00| 0, -4, 0, 0x00| 0},
328 { 200, 0x00| 0, -4, 0, 0x80| 0},
329 { 201, 0x00| 0, -4, 0, 0x00| 0},
330 { 202, 0x00| 0, -4, 0, 0x00| 0},
331 { 203, 0x00| 0, -4, 0, 0x00| 0},
332 { 204, 0x00| 0, -4, 0, 0x00| 0},
333 { 205, 0x00| 0, -5, 0, 0x00| 0},
334 { 206, 0x00| 0, -5, 0, 0x00| 0},
335 { 255, 0x00| 0, 0, 0, 0x00| 0},
336 { 207, 0x00| 0, 0, 1, 0x40| 6},
337 { 208, 0x00| 0, 0, 1, 0xC0| 6},
338 { 209, 0x00| 0, 0, 1, 0xC0| 8},
339 { 210, 0x00| 0, 0, 1, 0x40|10},
340 { 255, 0x00| 0, 0, 0, 0x00| 0},
341 { 255, 0x00| 0, 0, 0, 0x00| 0},
342 { 255, 0x00| 0, 0, 0, 0x00| 0},
343 { 255, 0x00| 0, 0, 0, 0x00| 0},
344 { 255, 0x00| 0, 0, 0, 0x00| 0},
345 { 255, 0x00| 0, 0, 0, 0x00| 0},
346 { 52, 0x00| 0, 0, 0, 0x80| 0},
347 { 53, 0x00| 0, 0, 0, 0x00| 0},
348 { 54, 0x00| 0, 0, 0, 0x00| 0},
349 { 55, 0x00| 0, 0, 0, 0x00| 0},
350 { 56, 0x00| 0, 0, 0, 0x80| 0},
351 { 57, 0x00| 0, 0, 0, 0x00| 0},
352 { 58, 0x00| 0, 0, 0, 0x00| 0},
353 { 59, 0x00| 0, 0, 0, 0x00| 0},
354 { 60, 0x00| 0, 0, 0, 0x80| 0},
355 { 61, 0x00| 0, 0, 0, 0x00| 0},
356 { 62, 0x00| 0, 0, 0, 0x80| 0},
357 { 63, 0x00| 0, 0, 0, 0x00| 0},
358 { 160, 0x00|35, 1, 1, 0xC0| 3},
359 { 161, 0x00|36, 0, 1, 0x40| 9},
360 { 162, 0x00|37, 0, 1, 0xC0| 3},
361 { 163, 0x00|38, 0, 1, 0x40| 9},
362 { 164, 0x00|39, 0, 1, 0xC0| 3},
363 { 165, 0x00|40, 1, 1, 0x40| 9},
364 { 166, 0x00|41, 1, 1, 0x40| 3},
365 { 167, 0x00|42, 1, 1, 0xC0| 9},
366 { 168, 0x00| 0, 4, 1, 0xC0| 6},
367 { 169, 0x00| 0, 3, 1, 0xC0|10},
368 { 170, 0x00| 0, 1, 1, 0x40| 3},
369 { 171, 0x00| 0, 1, 1, 0xC0| 8},
370 };
371
372 // data:1496
373 const frame_type frame_tbl_guard[] = {
374 { 255, 0x00| 0, 0, 0, 0x00| 0},
375 { 12, 0xC0|13, 2, 1, 0x00| 0},
376 { 2, 0xC0| 1, 3, 1, 0x00| 0},
377 { 3, 0xC0| 2, 4, 1, 0x00| 0},
378 { 4, 0xC0| 3, 7, 1, 0x40| 4},
379 { 5, 0xC0| 4, 10, 1, 0x00| 0},
380 { 6, 0xC0| 5, 7, 1, 0x80| 0},
381 { 7, 0xC0| 6, 4, 1, 0x80| 0},
382 { 8, 0xC0| 7, 0, 1, 0x80| 0},
383 { 9, 0xC0| 8, 0, 1, 0xC0|13},
384 { 10, 0xC0|11, 7, 1, 0x80| 0},
385 { 11, 0xC0|12, 3, 1, 0x00| 0},
386 { 12, 0xC0|13, 2, 1, 0x00| 0},
387 { 13, 0xC0| 0, 2, 1, 0x00| 0},
388 { 14, 0xC0|28, 0, 1, 0x00| 0},
389 { 15, 0xC0|29, 0, 1, 0x80| 0},
390 { 16, 0xC0|30, 2, 1, 0xC0| 3},
391 { 17, 0xC0| 9, -1, 1, 0x40| 8},
392 { 18, 0xC0|10, 7, 1, 0x80| 0},
393 { 19, 0xC0|14, 3, 1, 0x80| 0},
394 { 9, 0xC0| 8, 0, 1, 0x80| 0},
395 { 20, 0xC0| 8, 0, 1, 0xC0|13},
396 { 21, 0xC0| 8, 0, 1, 0xC0|13},
397 { 22, 0xC0|47, 0, 0, 0xC0| 6},
398 { 23, 0xC0|48, 0, 0, 0x40| 6},
399 { 24, 0xC0|49, 0, 0, 0xC0| 5},
400 { 24, 0xC0|49, 0, 0, 0xC0| 5},
401 { 24, 0xC0|49, 0, 0, 0xC0| 5},
402 { 26, 0xC0| 0, 0, 3, 0x80|10},
403 { 27, 0xC0| 0, 4, 4, 0x80| 7},
404 { 28, 0xC0| 0, -2, 1, 0x40| 4},
405 { 29, 0xC0| 0, -2, 1, 0x40| 4},
406 { 30, 0xC0| 0, -2, 1, 0x40| 4},
407 { 31, 0xC0| 0, -2, 2, 0x40| 7},
408 { 32, 0xC0| 0, -2, 2, 0x40|10},
409 { 255, 0x00| 0, 0, 0, 0x00| 0},
410 { 33, 0xC0| 0, 3, 4, 0xC0| 9},
411 { 255, 0x00| 0, 0, 0, 0x00| 0},
412 { 255, 0x00| 0, 0, 0, 0x00| 0},
413 { 255, 0x00| 0, 0, 0, 0x00| 0},
414 { 255, 0x00| 0, 0, 0, 0x00| 0},
415 };
416
417 // data:1564
418 const frame_type frame_tbl_cuts[] = {
419 { 255, 0x00| 0, 0, 0, 0x00| 0},
420 { 15, 0x40| 0, 0, 0, 0x00| 0},
421 { 1, 0x40| 0, 0, 0, 0x80| 0},
422 { 2, 0x40| 0, 0, 0, 0x80| 0},
423 { 3, 0x40| 0, 0, 0, 0x80| 0},
424 { 4, 0x40| 0, -1, 0, 0x00| 0},
425 { 5, 0x40| 0, 2, 0, 0x80| 0},
426 { 6, 0x40| 0, 2, 0, 0x00| 0},
427 { 7, 0x40| 0, 0, 0, 0x80| 0},
428 { 8, 0x40| 0, 1, 0, 0x80| 0},
429 { 255, 0x00| 0, 0, 0, 0x00| 0},
430 { 0, 0x40| 0, 0, 0, 0x80| 0},
431 { 9, 0x40| 0, 0, 0, 0x80| 0},
432 { 10, 0x40| 0, 0, 0, 0x00| 0},
433 { 11, 0x40| 0, 0, 0, 0x80| 0},
434 { 12, 0x40| 0, 0, 0, 0x80| 0},
435 { 13, 0x40| 0, 0, 0, 0x80| 0},
436 { 14, 0x40| 0, 0, 0, 0x00| 0},
437 { 16, 0x40| 0, 0, 0, 0x00| 0},
438 { 0, 0x80| 0, 0, 0, 0x00| 0},
439 { 2, 0x80| 0, 0, 0, 0x00| 0},
440 { 3, 0x80| 0, 0, 0, 0x00| 0},
441 { 4, 0x80| 0, 0, 0, 0x80| 0},
442 { 5, 0x80| 0, 0, 0, 0x00| 0},
443 { 6, 0x80| 0, 0, 0, 0x80| 0},
444 { 7, 0x80| 0, 0, 0, 0x80| 0},
445 { 8, 0x80| 0, 0, 0, 0x00| 0},
446 { 9, 0x80| 0, 0, 0, 0x00| 0},
447 { 10, 0x80| 0, 0, 0, 0x00| 0},
448 { 11, 0x80| 0, 0, 0, 0x00| 0},
449 { 12, 0x80| 0, 0, 0, 0x00| 0},
450 { 13, 0x80| 0, 0, 0, 0x00| 0},
451 { 14, 0x80| 0, 0, 0, 0x00| 0},
452 { 15, 0x80| 0, 0, 0, 0x00| 0},
453 { 16, 0x80| 0, 0, 0, 0x00| 0},
454 { 17, 0x80| 0, 0, 0, 0x00| 0},
455 { 18, 0x80| 0, 0, 0, 0x00| 0},
456 { 19, 0x80| 0, 0, 0, 0x00| 0},
457 { 20, 0x80| 0, 0, 0, 0x80| 0},
458 { 21, 0x80| 0, 0, 0, 0x80| 0},
459 { 22, 0x80| 0, 1, 0, 0x00| 0},
460 { 23, 0x80| 0, -1, 0, 0x00| 0},
461 { 24, 0x80| 0, 2, 0, 0x00| 0},
462 { 25, 0x80| 0, 1, 0, 0x80| 0},
463 { 26, 0x80| 0, 0, 0, 0x80| 0},
464 { 27, 0x80| 0, 0, 0, 0x80| 0},
465 { 28, 0x80| 0, 0, 0, 0x80| 0},
466 { 29, 0x80| 0, -1, 0, 0x00| 0},
467 { 0, 0x80| 0, 0, 0, 0x80| 0},
468 { 1, 0x80| 0, 0, 0, 0x80| 0},
469 { 2, 0x80| 0, 0, 0, 0x80| 0},
470 { 3, 0x80| 0, 0, 0, 0x00| 0},
471 { 4, 0x80| 0, 0, 0, 0x00| 0},
472 { 5, 0x80| 0, 0, 0, 0x80| 0},
473 { 6, 0x80| 0, 0, 0, 0x80| 0},
474 { 7, 0x80| 0, 0, 0, 0x80| 0},
475 { 8, 0x80| 0, 0, 0, 0x80| 0},
476 { 9, 0x80| 0, 0, 0, 0x80| 0},
477 { 10, 0x80| 0, 0, 0, 0x80| 0},
478 { 11, 0x80| 0, 0, 0, 0x80| 0},
479 { 12, 0x80| 0, 0, 0, 0x80| 0},
480 { 13, 0x80| 0, 0, 0, 0x00| 0},
481 { 14, 0x80| 0, 0, 0, 0x80| 0},
482 { 15, 0x80| 0, 0, 0, 0x00| 0},
483 { 16, 0x80| 0, 0, 0, 0x00| 0},
484 { 17, 0x80| 0, 0, 0, 0x80| 0},
485 { 18, 0x80| 0, 0, 0, 0x00| 0},
486 { 19, 0x80| 0, 3, 0, 0x00| 0},
487 { 20, 0x80| 0, 3, 0, 0x00| 0},
488 { 21, 0x80| 0, 3, 0, 0x00| 0},
489 { 22, 0x80| 0, 2, 0, 0x00| 0},
490 { 23, 0x80| 0, 3, 0, 0x80| 0},
491 { 24, 0x80| 0, 5, 0, 0x00| 0},
492 { 25, 0x80| 0, 5, 0, 0x00| 0},
493 { 26, 0x80| 0, 1, 0, 0x80| 0},
494 { 27, 0x80| 0, 2, 0, 0x80| 0},
495 { 28, 0x80| 0, 2, 0, 0x80| 0},
496 { 29, 0x80| 0, 1, 0, 0x80| 0},
497 { 30, 0x80| 0, 1, 0, 0x00| 0},
498 { 31, 0x80| 0, 2, 0, 0x00| 0},
499 { 32, 0x80| 0, 3, 0, 0x00| 0},
500 { 33, 0x80| 0, 3, 0, 0x00| 0},
501 { 34, 0x80| 0, 0, 0, 0x80| 0},
502 { 35, 0x80| 0, 2, 0, 0x80| 0},
503 { 36, 0x80| 0, 2, 0, 0x80| 0},
504 { 37, 0x80| 0, 1, 0, 0x00| 0},
505 };
506
507
get_frame_internal(const frame_type frame_table[],int frame,const char * frame_table_name,int count)508 void get_frame_internal(const frame_type frame_table[], int frame, const char* frame_table_name, int count) {
509 if (frame >= 0 && frame < count) {
510 cur_frame = frame_table[frame];
511 } else {
512 printf("Tried to use %s[%d], not in 0..%d\n", frame_table_name, frame, count-1);
513 static const frame_type blank_frame = {255, 0, 0, 0, 0};
514 cur_frame = blank_frame;
515 }
516 }
517 #define get_frame(frame_table, frame) get_frame_internal(frame_table, frame, #frame_table, COUNT(frame_table))
518
519 // seg006:015A
load_frame()520 void __pascal far load_frame() {
521 short frame;
522 short add_frame;
523 frame = Char.frame;
524 add_frame = 0;
525 switch (Char.charid) {
526 case charid_0_kid:
527 case charid_24_mouse:
528 use_table_kid:
529 get_frame(frame_table_kid, frame);
530 break;
531 case charid_2_guard:
532 case charid_4_skeleton:
533 if (frame >= 102 && frame < 107) add_frame = 70;
534 goto use_table_guard;
535 case charid_1_shadow:
536 if (frame < 150 || frame >= 190) goto use_table_kid;
537 use_table_guard:
538 get_frame(frame_tbl_guard, frame + add_frame - 149);
539 break;
540 case charid_5_princess:
541 case charid_6_vizier:
542 // use_table_cutscene:
543 get_frame(frame_tbl_cuts, frame);
544 break;
545 }
546 }
547 #undef get_frame
548
549 // seg006:01F5
dx_weight()550 short __pascal far dx_weight() {
551 sbyte var_2;
552 var_2 = cur_frame.dx - (cur_frame.flags & FRAME_WEIGHT_X);
553 return char_dx_forward(var_2);
554 }
555
556 // seg006:0213
char_dx_forward(int delta_x)557 int __pascal far char_dx_forward(int delta_x) {
558 if (Char.direction < dir_0_right) {
559 delta_x = -delta_x;
560 }
561 return delta_x + Char.x;
562 }
563
564 // seg006:0234
obj_dx_forward(int delta_x)565 int __pascal far obj_dx_forward(int delta_x) {
566 if (obj_direction < dir_0_right) {
567 delta_x = -delta_x;
568 }
569 obj_x += delta_x;
570 return obj_x;
571 }
572
573 // seg006:0254
play_seq()574 void __pascal far play_seq() {
575 for (;;) {
576 byte item = *(SEQTBL_0 + Char.curr_seq++);
577 switch (item) {
578 case SEQ_DX: // dx
579 Char.x = char_dx_forward(*(SEQTBL_0 + Char.curr_seq++));
580 break;
581 case SEQ_DY: // dy
582 Char.y += *(SEQTBL_0 + Char.curr_seq++);
583 break;
584 case SEQ_FLIP: // flip
585 Char.direction = ~Char.direction;
586 break;
587 case SEQ_JMP_IF_FEATHER: // jump if feather
588 if (!is_feather_fall) {
589 ++Char.curr_seq;
590 ++Char.curr_seq;
591 break;
592 }
593 // fallthrough!
594 case SEQ_JMP: // jump
595 Char.curr_seq = *(const word*)(SEQTBL_0 + Char.curr_seq);
596 break;
597 case SEQ_UP: // up
598 --Char.curr_row;
599 start_chompers();
600 break;
601 case SEQ_DOWN: // down
602 inc_curr_row();
603 start_chompers();
604 break;
605 case SEQ_ACTION: // action
606 Char.action = *(SEQTBL_0 + Char.curr_seq++);
607 break;
608 case SEQ_SET_FALL: // set fall
609 Char.fall_x = *(SEQTBL_0 + Char.curr_seq++);
610 Char.fall_y = *(SEQTBL_0 + Char.curr_seq++);
611 break;
612 case SEQ_KNOCK_UP: // knock up
613 knock = 1;
614 break;
615 case SEQ_KNOCK_DOWN: // knock down
616 knock = -1;
617 break;
618 case SEQ_SOUND: // sound
619 switch (*(SEQTBL_0 + Char.curr_seq++)) {
620 case SND_SILENT: // no sound actually played, but guards still notice the kid
621 is_guard_notice = 1;
622 break;
623 case SND_FOOTSTEP: // feet
624 play_sound(sound_23_footstep); // footstep
625 is_guard_notice = 1;
626 break;
627 case SND_BUMP: // bump
628 play_sound(sound_8_bumped); // touching a wall
629 is_guard_notice = 1;
630 break;
631 case SND_DRINK: // drink
632 play_sound(sound_18_drink); // drink
633 break;
634 case SND_LEVEL: // level
635 #ifdef USE_REPLAY
636 if (recording || replaying) break; // don't do end level music in replays
637 #endif
638
639 if (is_sound_on) {
640 if (current_level == 4) {
641 play_sound(sound_32_shadow_music); // end level with shadow (level 4)
642 } else if (current_level != 13 && current_level != 15) {
643 play_sound(sound_41_end_level_music); // end level
644 }
645 }
646 break;
647 }
648 break;
649 case SEQ_END_LEVEL: // end level
650 ++next_level;
651 #ifdef USE_REPLAY
652 // Preserve the seed in this frame, to ensure reproducibility of the replay in the next level,
653 // regardless of how long the sound is still playing *after* this frame.
654 // Animations (e.g. torch) can change the seed!
655 keep_last_seed = 1;
656 if (replaying && skipping_replay) stop_sounds();
657 #endif
658 break;
659 case SEQ_GET_ITEM: // get item
660 if (*(SEQTBL_0 + Char.curr_seq++) == 1) {
661 proc_get_object();
662 }
663 break;
664 case SEQ_DIE: // nop
665 break;
666 default:
667 Char.frame = item;
668 //if (Char.frame == 185) Char.frame = 185;
669 return;
670 }
671 }
672 }
673
674 // seg006:03DE
get_tile_div_mod_m7(int xpos)675 int __pascal far get_tile_div_mod_m7(int xpos) {
676 return get_tile_div_mod(xpos - 7);
677 }
678
679 // data:22A6
680 const sbyte tile_div_tbl[256] = {
681 -5,-5,
682 -4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,
683 -3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,
684 -2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,
685 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
686 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
687 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
688 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
689 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
690 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
691 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
692 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
693 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
694 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
695 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
696 10,10,10,10,10,10,10,10,10,10,10,10,10,10,
697 11,11,11,11,11,11,11,11,11,11,11,11,11,11,
698 12,12,12,12,12,12,12,12,12,12,12,12,12,12,
699 13,13,13,13,13,13,13,13,13,13,13,13,13,13,
700 14,14
701 };
702
703 // data:23A6
704 const byte tile_mod_tbl[256] = {
705 12, 13,
706 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
707 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
708 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
709 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
710 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
711 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
712 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
713 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
714 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
715 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
716 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
717 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
718 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
719 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
720 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
721 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
722 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
723 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
724 0, 1
725 };
726
727 // seg006:03F0
get_tile_div_mod(int xpos)728 int __pascal far get_tile_div_mod(int xpos) {
729 // Determine tile column (xh) and the position within the tile (xl) from xpos.
730
731 // DOS PoP does this:
732 // obj_xl = tile_mod_tbl[xpos];
733 // return tile_div_tbl[xpos];
734
735 // xpos uses a coordinate system in which the left edge of the screen is 58, and each tile is 14 units wide.
736 int x = xpos - 58;
737 int xl = x % 14;
738 int xh = x / 14;
739 if (xl < 0) {
740 // Integer division rounds towards zero, but we want to round down.
741 --xh;
742 // Modulo returns a negative number if x is negative, but we want 0 <= xl < 14.
743 xl += 14;
744 }
745
746 // For compatibility with the DOS version, we allow for overflow access to these tables
747 // Considering the case of negative overflow
748 if (xpos < 0) {
749 // In this case DOS PoP reads the bytes directly before tile_div_tbl[] and tile_mod_tbl[] in the memory.
750 // Here we simulate these reads.
751 // Before tile_mod_tbl[] is tile_div_tbl[], and before tile_div_tbl[] are the following bytes:
752 static const byte bogus[] = {0x02, 0x00, 0x41, 0x00, 0x80, 0x00, 0xBF, 0x00, 0xFE, 0x00, 0xFF, 0x01, 0x01, 0xFF, 0xC4, 0xFF, 0x03, 0x00, 0x42, 0x00, 0x81, 0x00, 0xC0, 0x00, 0xF8, 0xFF, 0x37, 0x00, 0x76, 0x00, 0xB5, 0x00, 0xF4, 0x00};
753 if (COUNT(bogus) + xpos >= 0) {
754 xh = bogus[COUNT(bogus) + xpos]; // simulating tile_div_tbl[xpos]
755 xl = tile_div_tbl[COUNT(tile_div_tbl) + xpos]; // simulating tile_mod_tbl[xpos]
756 } else {
757 printf("xpos = %d (< %d) out of range for simulation of index overflow!\n", xpos, -(int)COUNT(bogus));
758 }
759 }
760
761 // Considering the case of positive overflow
762 int tblSize = 256;
763
764 if (xpos >= tblSize) {
765 // In this case DOS PoP reads the bytes directly after tile_div_tbl[], that is: and tile_mod_tbl[]
766 // Here we simulate these reads.
767 // After tile_mod_tbl[] there are the following bytes:
768 static const byte bogus[] = {0xF4, 0x02, 0x10, 0x1E, 0x2C, 0x3A, 0x48, 0x56, 0x64, 0x72, 0x80, 0x8E, 0x9C, 0xAA, 0xB8, 0xC6, 0xD4, 0xE2, 0xF0, 0xFE, 0x00, 0x0A, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0D, 0x00, 0x00, 0x00, 0x00};
769 if (xpos-tblSize < COUNT(bogus)) {
770 xh = tile_mod_tbl[xpos-tblSize]; // simulating tile_div_tbl[xpos]
771 xl = bogus[xpos-tblSize]; // simulating tile_mod_tbl[xpos]
772 } else {
773 printf("xpos = %d (> %d) out of range for simulation of index overflow!\n", xpos, (int)COUNT(bogus)+tblSize);
774 }
775 }
776
777 obj_xl = xl;
778 return xh;
779 }
780
781 // seg006:0433
y_to_row_mod4(int ypos)782 int __pascal far y_to_row_mod4(int ypos) {
783 return (ypos + 60) / 63 % 4 - 1;
784 }
785
786 // seg006:044F
loadkid()787 void __pascal far loadkid() {
788 Char = Kid;
789 }
790
791 // seg006:0464
savekid()792 void __pascal far savekid() {
793 Kid = Char;
794 }
795
796 // seg006:0479
loadshad()797 void __pascal far loadshad() {
798 Char = Guard;
799 }
800
801 // seg006:048E
saveshad()802 void __pascal far saveshad() {
803 Guard = Char;
804 }
805
806 // seg006:04A3
loadkid_and_opp()807 void __pascal far loadkid_and_opp() {
808 loadkid();
809 Opp = Guard;
810 }
811
812 // seg006:04BC
savekid_and_opp()813 void __pascal far savekid_and_opp() {
814 savekid();
815 Guard = Opp;
816 }
817
818 // seg006:04D5
loadshad_and_opp()819 void __pascal far loadshad_and_opp() {
820 loadshad();
821 Opp = Kid;
822 }
823
824 // seg006:04EE
saveshad_and_opp()825 void __pascal far saveshad_and_opp() {
826 saveshad();
827 Kid = Opp;
828 }
829
830 // seg006:0507
reset_obj_clip()831 void __pascal far reset_obj_clip() {
832 obj_clip_left = 0;
833 obj_clip_top = 0;
834 obj_clip_right = 320;
835 obj_clip_bottom = 192;
836 }
837
838 // seg006:051C
x_to_xh_and_xl(int xpos,sbyte * xh_addr,sbyte * xl_addr)839 void __pascal far x_to_xh_and_xl(int xpos, sbyte *xh_addr, sbyte *xl_addr) {
840 if (xpos < 0) {
841 *xh_addr = -((ABS(-xpos) >> 3) + 1);
842 *xl_addr = - ((-xpos - 1) % 8 - 7);
843 } else {
844 *xh_addr = ABS(xpos) >> 3;
845 *xl_addr = xpos % 8;
846 }
847 }
848
849 // seg006:057C
fall_accel()850 void __pascal far fall_accel() {
851 if (Char.action == actions_4_in_freefall) {
852 if (is_feather_fall) {
853 ++Char.fall_y;
854 if (Char.fall_y > 4) Char.fall_y = 4;
855 } else {
856 Char.fall_y += 3;
857 if (Char.fall_y > 33) Char.fall_y = 33;
858 }
859 }
860 }
861
862 // seg006:05AE
fall_speed()863 void __pascal far fall_speed() {
864 Char.y += Char.fall_y;
865 if (Char.action == actions_4_in_freefall) {
866 Char.x = char_dx_forward(Char.fall_x);
867 load_fram_det_col();
868 }
869 }
870
871 // seg006:05CD
check_action()872 void __pascal far check_action() {
873 short frame;
874 short action;
875 action = Char.action;
876 frame = Char.frame;
877 // frame 109: crouching
878 if (action == actions_6_hang_straight ||
879 action == actions_5_bumped
880 ) {
881 if (frame == frame_109_crouch
882
883 #ifdef FIX_STAND_ON_THIN_AIR
884 || (fixes->fix_stand_on_thin_air &&
885 frame >= frame_110_stand_up_from_crouch_1 && frame <= frame_119_stand_up_from_crouch_10)
886 #endif
887
888 ) {
889 check_on_floor();
890 }
891 } else if (action == actions_4_in_freefall) {
892 do_fall();
893 } else if (action == actions_3_in_midair) {
894 // frame 102..106: start fall + fall
895 if (frame >= frame_102_start_fall_1 && frame < frame_106_fall) {
896 check_grab();
897 }
898 } else if (action != actions_2_hang_climb) {
899 check_on_floor();
900 }
901 }
902
903 // seg006:0628
tile_is_floor(int tiletype)904 int __pascal far tile_is_floor(int tiletype) {
905 switch (tiletype) {
906 case tiles_0_empty:
907 case tiles_9_bigpillar_top:
908 case tiles_12_doortop:
909 case tiles_20_wall:
910 case tiles_26_lattice_down:
911 case tiles_27_lattice_small:
912 case tiles_28_lattice_left:
913 case tiles_29_lattice_right:
914 return 0;
915 default:
916 return 1;
917 }
918 }
919
920 // seg006:0658
check_spiked()921 void __pascal far check_spiked() {
922 short harmful;
923 short frame;
924 frame = Char.frame;
925 if (get_tile(Char.room, Char.curr_col, Char.curr_row) == tiles_2_spike) {
926 harmful = is_spike_harmful();
927 // frames 7..14: running
928 // frames 34..39: start run-jump
929 // frame 43: land from run-jump
930 // frame 26: lang from standing jump
931 if (
932 (harmful >= 2 && ((frame>= frame_7_run && frame<15) || (frame>=frame_34_start_run_jump_1 && frame<40))) ||
933 ((frame == frame_43_running_jump_4 || frame == frame_26_standing_jump_11) && harmful != 0)
934 ) {
935 spiked();
936 }
937 }
938 }
939
940 // seg006:06BD
take_hp(int count)941 int __pascal far take_hp(int count) {
942 word dead;
943 dead = 0;
944 if (Char.charid == charid_0_kid) {
945 if (count >= hitp_curr) {
946 hitp_delta = -hitp_curr;
947 dead = 1;
948 } else {
949 hitp_delta = -count;
950 }
951 } else {
952 if (count >= guardhp_curr) {
953 guardhp_delta = -guardhp_curr;
954 dead = 1;
955 } else {
956 guardhp_delta = -count;
957 }
958 }
959 return dead;
960 }
961
962 // seg006:070D
get_tile_at_char()963 int __pascal far get_tile_at_char() {
964 return get_tile(Char.room, Char.curr_col, Char.curr_row);
965 }
966
967 // seg006:0723
set_char_collision()968 void __pascal far set_char_collision() {
969 image_type* image = get_image(obj_chtab, obj_id);
970 if (image == NULL) {
971 char_width_half = 0;
972 char_height = 0;
973 } else {
974 char_width_half = (image->/*width*/w + 1) / 2;
975 char_height = image->/*height*/h;
976 }
977 char_x_left = obj_x / 2 + 58;
978 if (Char.direction >= dir_0_right) {
979 char_x_left -= char_width_half;
980 }
981 char_x_left_coll = char_x_left;
982 char_x_right_coll = char_x_right = char_x_left + char_width_half;
983 char_top_y = obj_y - char_height + 1;
984 if (char_top_y >= 192) {
985 char_top_y = 0;
986 }
987 char_top_row = y_to_row_mod4(char_top_y);
988 char_bottom_row = y_to_row_mod4(obj_y);
989 if (char_bottom_row == -1) {
990 char_bottom_row = 3;
991 }
992 char_col_left = MAX(get_tile_div_mod(char_x_left), 0);
993 char_col_right = MIN(get_tile_div_mod(char_x_right), 9);
994 if (cur_frame.flags & FRAME_THIN) {
995 // "thin" this frame for collision detection
996 char_x_left_coll += 4;
997 char_x_right_coll -= 4;
998 }
999 }
1000
1001 // seg006:0815
check_on_floor()1002 void __pascal far check_on_floor() {
1003 if (cur_frame.flags & FRAME_NEEDS_FLOOR) {
1004 if (get_tile_at_char() == tiles_20_wall) {
1005 in_wall();
1006 }
1007 if (! tile_is_floor(curr_tile2)) {
1008 // Special event: floors appear
1009 if (current_level == 12 &&
1010 #ifndef FIX_HIDDEN_FLOORS_DURING_FLASHING
1011 united_with_shadow < 0 &&
1012 #else
1013 (united_with_shadow < 0 || (fixes->fix_hidden_floors_during_flashing && united_with_shadow > 0)) &&
1014 #endif
1015 Char.curr_row == 0 &&
1016 (Char.room == 2 || (Char.room == 13 && tile_col >= 6))
1017 ) {
1018 curr_room_tiles[curr_tilepos] = tiles_1_floor;
1019 set_wipe(curr_tilepos, 1);
1020 set_redraw_full(curr_tilepos, 1);
1021 ++curr_tilepos;
1022 set_wipe(curr_tilepos, 1);
1023 set_redraw_full(curr_tilepos, 1);
1024 } else {
1025
1026 #ifdef FIX_STAND_ON_THIN_AIR
1027 if (fixes->fix_stand_on_thin_air &&
1028 Char.frame >= frame_110_stand_up_from_crouch_1 && Char.frame <= frame_119_stand_up_from_crouch_10)
1029 {
1030 // We need to prevent the Kid from stepping off a ledge accidentally while standing up.
1031 // (This can happen because the "standing up" frames now require a floor.)
1032 // --> Cancel the fall, if the tile at dx=2 behind the kid is a valid floor.
1033 int col = get_tile_div_mod_m7(dx_weight() + back_delta_x(2));
1034 if (tile_is_floor(get_tile(Char.room, col, Char.curr_row))) {
1035 return;
1036 }
1037 }
1038 #endif
1039
1040 start_fall();
1041 }
1042 }
1043 }
1044 }
1045
1046 // seg006:08B9
start_fall()1047 void __pascal far start_fall() {
1048 short frame;
1049 word seq_id;
1050 frame = Char.frame;
1051 Char.sword = sword_0_sheathed;
1052 inc_curr_row();
1053 start_chompers();
1054 fall_frame = frame;
1055 if (frame == frame_9_run) {
1056 // frame 9: run
1057 seq_id = seq_7_fall; // fall (when?)
1058 } else if (frame == frame_13_run) {
1059 // frame 13: run
1060 seq_id = seq_19_fall; // fall (when?)
1061 } else if (frame == frame_26_standing_jump_11) {
1062 // frame 26: land after standing jump
1063 seq_id = seq_18_fall_after_standing_jump; // fall after standing jump
1064 } else if (frame == frame_44_running_jump_5) {
1065 // frame 44: land after running jump
1066 seq_id = seq_21_fall_after_running_jump; // fall after running jump
1067 } else if (frame >= frame_81_hangdrop_1 && frame < 86) {
1068 // frame 81..85: land after jump up
1069 seq_id = seq_19_fall; // fall after jumping up
1070 Char.x = char_dx_forward(5);
1071 load_fram_det_col();
1072 } else if (frame >= 150 && frame < 180) {
1073 // frame 150..179: with sword + fall + dead
1074 if (Char.charid == charid_2_guard) {
1075 if (Char.curr_row == 3 && Char.curr_col == 10) {
1076 clear_char();
1077 return;
1078 }
1079 if (Char.fall_x < 0) {
1080 seq_id = seq_82_guard_pushed_off_ledge; // Guard is pushed off the ledge
1081 if (Char.direction < dir_0_right && distance_to_edge_weight() <= 7) {
1082 Char.x = char_dx_forward(-5);
1083 }
1084 } else {
1085 droppedout = 0;
1086 seq_id = seq_83_guard_fall; // fall after forwarding with sword
1087 }
1088 } else {
1089 droppedout = 1;
1090 if (Char.direction < dir_0_right && distance_to_edge_weight() <= 7) {
1091 Char.x = char_dx_forward(-5);
1092 }
1093 seq_id = seq_81_kid_pushed_off_ledge; // fall after backing with sword / Kid is pushed off the ledge
1094 }
1095 } else {
1096 seq_id = seq_7_fall; // fall after stand, run, step, crouch
1097 }
1098 seqtbl_offset_char(seq_id);
1099 play_seq();
1100 load_fram_det_col();
1101 if (get_tile_at_char() == tiles_20_wall) {
1102 in_wall();
1103 return;
1104 }
1105 int tile = get_tile_infrontof_char();
1106 if (tile == tiles_20_wall
1107
1108 #ifdef FIX_RUNNING_JUMP_THROUGH_TAPESTRY
1109 // Also treat tapestries (when approached to the left) like a wall here.
1110 || (fixes->fix_running_jump_through_tapestry && Char.direction == dir_FF_left &&
1111 (tile == tiles_12_doortop || tile == tiles_7_doortop_with_floor))
1112 #endif
1113
1114 ) {
1115 if (fall_frame != 44 || distance_to_edge_weight() >= 6) {
1116 Char.x = char_dx_forward(-1);
1117 } else {
1118 seqtbl_offset_char(seq_104_start_fall_in_front_of_wall); // start fall (when?)
1119 play_seq();
1120 }
1121 load_fram_det_col();
1122 }
1123 }
1124
1125 // seg006:0A19
check_grab()1126 void __pascal far check_grab() {
1127 word old_x;
1128
1129 #ifdef FIX_GRAB_FALLING_SPEED
1130 #define MAX_GRAB_FALLING_SPEED (fixes->fix_grab_falling_speed ? 30 : 32)
1131 #else
1132 #define MAX_GRAB_FALLING_SPEED 32
1133 #endif
1134
1135 if (control_shift < 0 && // press Shift to grab
1136 Char.fall_y < MAX_GRAB_FALLING_SPEED && // you can't grab if you're falling too fast ...
1137 Char.alive < 0 && // ... or dead
1138 (word)y_land[Char.curr_row + 1] <= (word)(Char.y + 25)
1139 ) {
1140 //printf("Falling speed: %d\t x: %d\n", Char.fall_y, Char.x);
1141 old_x = Char.x;
1142 Char.x = char_dx_forward(-8);
1143 load_fram_det_col();
1144 if ( ! can_grab_front_above()) {
1145 Char.x = old_x;
1146 } else {
1147 Char.x = char_dx_forward(distance_to_edge_weight());
1148 Char.y = y_land[Char.curr_row + 1];
1149 Char.fall_y = 0;
1150 seqtbl_offset_char(seq_15_grab_ledge_midair); // grab a ledge (after falling)
1151 play_seq();
1152 grab_timer = 12;
1153 play_sound(sound_9_grab); // grab
1154 is_screaming = 0;
1155 #ifdef FIX_CHOMPERS_NOT_STARTING
1156 if (fixes->fix_chompers_not_starting) start_chompers();
1157 #endif
1158 }
1159 }
1160 }
1161
1162 // seg006:0ABD
can_grab_front_above()1163 int __pascal far can_grab_front_above() {
1164 through_tile = get_tile_above_char();
1165 get_tile_front_above_char();
1166 return can_grab();
1167 }
1168
1169 // seg006:0ACD
in_wall()1170 void __pascal far in_wall() {
1171 short delta_x;
1172 delta_x = distance_to_edge_weight();
1173 if (delta_x >= 8 || get_tile_infrontof_char() == tiles_20_wall) {
1174 delta_x = 6 - delta_x;
1175 } else {
1176 delta_x += 4;
1177 }
1178 Char.x = char_dx_forward(delta_x);
1179 load_fram_det_col();
1180 get_tile_at_char();
1181 }
1182
1183 // seg006:0B0C
get_tile_infrontof_char()1184 int __pascal far get_tile_infrontof_char() {
1185 return get_tile(Char.room, infrontx = dir_front[Char.direction + 1] + Char.curr_col, Char.curr_row);
1186 }
1187
1188 // seg006:0B30
get_tile_infrontof2_char()1189 int __pascal far get_tile_infrontof2_char() {
1190 short var_2;
1191 var_2 = dir_front[Char.direction + 1];
1192 return get_tile(Char.room, infrontx = (var_2 << 1) + Char.curr_col, Char.curr_row);
1193 }
1194
1195 // seg006:0B66
get_tile_behind_char()1196 int __pascal far get_tile_behind_char() {
1197 return get_tile(Char.room, dir_behind[Char.direction + 1] + Char.curr_col, Char.curr_row);
1198 }
1199
1200 // seg006:0B8A
distance_to_edge_weight()1201 int __pascal far distance_to_edge_weight() {
1202 return distance_to_edge(dx_weight());
1203 }
1204
1205 // seg006:0B94
distance_to_edge(int xpos)1206 int __pascal far distance_to_edge(int xpos) {
1207 short distance;
1208 get_tile_div_mod_m7(xpos);
1209 distance = obj_xl;
1210 if (Char.direction == dir_0_right) {
1211 distance = 13 - distance;
1212 }
1213 return distance;
1214 }
1215
1216 // seg006:0BC4
fell_out()1217 void __pascal far fell_out() {
1218 if (Char.alive < 0 && Char.room == 0) {
1219 take_hp(100);
1220 Char.alive = 0;
1221 erase_bottom_text(1);
1222 Char.frame = frame_185_dead; // dead
1223 }
1224 }
1225
1226 // seg006:0BEE
play_kid()1227 void __pascal far play_kid() {
1228 fell_out();
1229 control_kid();
1230 if (Char.alive >= 0 && is_dead()) {
1231 if (resurrect_time) {
1232 stop_sounds();
1233 loadkid();
1234 hitp_delta = hitp_max;
1235 seqtbl_offset_char(seq_2_stand); // stand
1236 Char.x += 8;
1237 play_seq();
1238 load_fram_det_col();
1239 set_start_pos();
1240 }
1241 if (check_sound_playing() && current_sound != 5) { // gate opening
1242 return;
1243 }
1244 is_show_time = 0;
1245 if (Char.alive < 0 || Char.alive >= 6) {
1246 if (Char.alive == 6) {
1247 if (is_sound_on &&
1248 current_level != 0 && // no death music on demo level
1249 current_level != 15 // no death music on potions level
1250 ) {
1251 play_death_music();
1252 }
1253 } else {
1254 if (Char.alive != 7 || check_sound_playing()) return;
1255 if (rem_min == 0) {
1256 expired();
1257 }
1258 if (current_level != 0 && // no message if died on demo level
1259 current_level != 15 // no message if died on potions level
1260 ) {
1261 text_time_remaining = text_time_total = 288;
1262 display_text_bottom("Press Button to Continue");
1263 } else {
1264 text_time_remaining = text_time_total = 36;
1265 }
1266 }
1267 }
1268 ++Char.alive;
1269 }
1270 }
1271
1272 // seg006:0CD1
control_kid()1273 void __pascal far control_kid() {
1274 word key;
1275 if (Char.alive < 0 && hitp_curr == 0) {
1276 Char.alive = 0;
1277 // stop feather fall when kid dies
1278 if (fixes->fix_quicksave_during_feather && is_feather_fall > 0) {
1279 is_feather_fall = 0;
1280 if (check_sound_playing()) {
1281 stop_sounds();
1282 }
1283 }
1284 }
1285 if (grab_timer != 0) {
1286 --grab_timer;
1287 }
1288 #ifdef USE_REPLAY
1289 if (current_level == 0 && !play_demo_level && !replaying) {
1290 #else
1291 if (current_level == 0 && !play_demo_level) {
1292 #endif
1293 do_demo();
1294 control();
1295 // The player can start a new game or load a saved game during the demo.
1296 key = key_test_quit();
1297 if (key == (SDL_SCANCODE_L | WITH_CTRL)) { // Ctrl+L
1298 if (load_game()) {
1299 start_game();
1300 }
1301 } else {
1302 if (key) {
1303 start_level = custom->first_level; // 1
1304 start_game();
1305 }
1306 }
1307 } else {
1308 rest_ctrl_1();
1309 do_paused();
1310 #ifdef USE_REPLAY
1311 if (recording) add_replay_move();
1312 if (replaying) do_replay_move();
1313 #endif
1314 read_user_control();
1315 user_control();
1316 save_ctrl_1();
1317 }
1318 }
1319
1320 // This was moved to custom_options_type.
1321 /*
1322 const auto_move_type demo_moves[] = {
1323 {0x00, 0},
1324 {0x01, 1},
1325 {0x0D, 0},
1326 {0x1E, 1},
1327 {0x25, 5},
1328 {0x2F, 0},
1329 {0x30, 1},
1330 {0x41, 0},
1331 {0x49, 2},
1332 {0x4B, 0},
1333 {0x63, 2},
1334 {0x64, 0},
1335 {0x73, 5},
1336 {0x80, 6},
1337 {0x88, 3},
1338 {0x9D, 7},
1339 {0x9E, 0},
1340 {0x9F, 1},
1341 {0xAB, 4},
1342 {0xB1, 0},
1343 {0xB2, 1},
1344 {0xBC, 0},
1345 {0xC1, 1},
1346 {0xCD, 0},
1347 {0xE9,-1},
1348 };
1349 */
1350
1351 // seg006:0D49
1352 void __pascal far do_demo() {
1353 if (checkpoint) {
1354 control_shift2 = release_arrows();
1355 control_forward = control_x = -1;
1356 } else if (Char.sword) {
1357 guard_skill = 10;
1358 autocontrol_opponent();
1359 guard_skill = 11;
1360 } else {
1361 do_auto_moves(custom->demo_moves);
1362 }
1363 }
1364
1365 // seg006:0D85
1366 void __pascal far play_guard() {
1367 if (Char.charid == charid_24_mouse) {
1368 autocontrol_opponent();
1369 } else {
1370 if (Char.alive < 0) {
1371 if (guardhp_curr == 0) {
1372 Char.alive = 0;
1373 on_guard_killed();
1374 } else {
1375 goto loc_7A65;
1376 }
1377 }
1378 if (Char.charid == charid_1_shadow) {
1379 clear_char();
1380 }
1381 loc_7A65:
1382 autocontrol_opponent();
1383 control();
1384 }
1385 }
1386
1387 // seg006:0DC0
1388 void __pascal far user_control() {
1389 if (Char.direction >= dir_0_right) {
1390 flip_control_x();
1391 control();
1392 flip_control_x();
1393 } else {
1394 control();
1395 }
1396 }
1397
1398 // seg006:0DDC
1399 void __pascal far flip_control_x() {
1400 byte temp;
1401 control_x = -control_x;
1402 temp = control_forward;
1403 control_forward = control_backward;
1404 control_backward = temp;
1405 }
1406
1407 // seg006:0E00
1408 int __pascal far release_arrows() {
1409 control_backward = control_forward = control_up = control_down = 0;
1410 return 1;
1411 }
1412
1413 // seg006:0E12
1414 void __pascal far save_ctrl_1() {
1415 ctrl1_forward = control_forward;
1416 ctrl1_backward = control_backward;
1417 ctrl1_up = control_up;
1418 ctrl1_down = control_down;
1419 ctrl1_shift2 = control_shift2;
1420 }
1421
1422 // seg006:0E31
1423 void __pascal far rest_ctrl_1() {
1424 control_forward = ctrl1_forward;
1425 control_backward = ctrl1_backward;
1426 control_up = ctrl1_up;
1427 control_down = ctrl1_down;
1428 control_shift2 = ctrl1_shift2;
1429 }
1430
1431 // seg006:0E8E
1432 void __pascal far clear_saved_ctrl() {
1433 ctrl1_forward = ctrl1_backward = ctrl1_up = ctrl1_down = ctrl1_shift2 = 0;
1434 }
1435
1436 // seg006:0EAF
1437 void __pascal far read_user_control() {
1438 if (control_forward >= 0) {
1439 if (control_x < 0) {
1440 if (control_forward == 0) {
1441 control_forward = -1;
1442 }
1443 } else {
1444 control_forward = 0;
1445 }
1446 }
1447 if (control_backward >= 0) {
1448 if (control_x == 1) {
1449 if (control_backward == 0) {
1450 control_backward = -1;
1451 }
1452 } else {
1453 control_backward = 0;
1454 }
1455 }
1456 if (control_up >= 0) {
1457 if (control_y < 0) {
1458 if (control_up == 0) {
1459 control_up = -1;
1460 }
1461 } else {
1462 control_up = 0;
1463 }
1464 }
1465 if (control_down >= 0) {
1466 if (control_y == 1) {
1467 if (control_down == 0) {
1468 control_down = -1;
1469 }
1470 } else {
1471 control_down = 0;
1472 }
1473 }
1474 if (control_shift2 >= 0) {
1475 if (control_shift < 0) {
1476 if (control_shift2 == 0) {
1477 control_shift2 = -1;
1478 }
1479 } else {
1480 control_shift2 = 0;
1481 }
1482 }
1483 }
1484
1485 // seg006:0F55
1486 int __pascal far can_grab() {
1487 // Can char grab curr_tile2 through through_tile?
1488 byte modifier;
1489 modifier = curr_room_modif[curr_tilepos];
1490 // can't grab through wall
1491 if (through_tile == tiles_20_wall) return 0;
1492 // can't grab through a door top if looking right
1493 if (through_tile == tiles_12_doortop && Char.direction >= dir_0_right) return 0;
1494 // can't grab through floor
1495 if (tile_is_floor(through_tile)) return 0;
1496 // can't grab a shaking loose floor
1497 // Allow climbing onto a shaking loose floor if the delay is greater than the default. TODO: This should be a separate option.
1498 if (curr_tile2 == tiles_11_loose && modifier != 0 && !(custom->loose_floor_delay > 11)) return 0;
1499 // a doortop with floor can be grabbed only from the left (looking right)
1500 if (curr_tile2 == tiles_7_doortop_with_floor && Char.direction < dir_0_right) return 0;
1501 // can't grab something that has no floor
1502 if ( ! tile_is_floor(curr_tile2)) return 0;
1503 return 1;
1504 }
1505
1506 // seg006:0FC3
1507 int __pascal far wall_type(byte tiletype) {
1508 switch (tiletype) {
1509 case tiles_4_gate:
1510 case tiles_7_doortop_with_floor:
1511 case tiles_12_doortop:
1512 return 1; // wall at right
1513 case tiles_13_mirror:
1514 return 2; // wall at left
1515 case tiles_18_chomper:
1516 return 3; // chomper at left
1517 case tiles_20_wall:
1518 return 4; // wall at both sides
1519 default:
1520 return 0; // no wall
1521 }
1522 }
1523
1524 // seg006:1005
1525 int __pascal far get_tile_above_char() {
1526 return get_tile(Char.room, Char.curr_col, Char.curr_row - 1);
1527 }
1528
1529 // seg006:1020
1530 int __pascal far get_tile_behind_above_char() {
1531 return get_tile(Char.room, dir_behind[Char.direction + 1] + Char.curr_col, Char.curr_row - 1);
1532 }
1533
1534 // seg006:1049
1535 int __pascal far get_tile_front_above_char() {
1536 return get_tile(Char.room, infrontx = dir_front[Char.direction + 1] + Char.curr_col, Char.curr_row - 1);
1537 }
1538
1539 // seg006:1072
1540 int __pascal far back_delta_x(int delta_x) {
1541 if (Char.direction < dir_0_right) {
1542 // direction = left
1543 return delta_x;
1544 } else {
1545 // direction = right
1546 return -delta_x;
1547 }
1548 }
1549
1550 // seg006:108A
1551 void __pascal far do_pickup(int obj_type) {
1552 pickup_obj_type = obj_type;
1553 control_shift2 = 1;
1554 // erase picked up item
1555 curr_room_tiles[curr_tilepos] = tiles_1_floor;
1556 curr_room_modif[curr_tilepos] = 0;
1557 redraw_height = 35;
1558 set_wipe(curr_tilepos, 1);
1559 set_redraw_full(curr_tilepos, 1);
1560 }
1561
1562 // seg006:10E6
1563 void __pascal far check_press() {
1564 short frame;
1565 short action;
1566 frame = Char.frame;
1567 action = Char.action;
1568 // frames 87..99: hanging
1569 // frames 135..140: start climb up
1570 if ((frame >= frame_87_hanging_1 && frame < 100) || (frame >= frame_135_climbing_1 && frame < frame_141_climbing_7)) {
1571 // the pressed tile is the one that the char is grabbing
1572 get_tile_above_char();
1573 } else if (action == actions_7_turn || action == actions_5_bumped || action < actions_2_hang_climb) {
1574 // frame 79: jumping up
1575 if (frame == frame_79_jumphang && get_tile_above_char() == tiles_11_loose) {
1576 // break a loose floor from above
1577 make_loose_fall(1);
1578 } else {
1579 // the pressed tile is the one that the char is standing on
1580 if (! (cur_frame.flags & FRAME_NEEDS_FLOOR)) return;
1581 #ifdef FIX_PRESS_THROUGH_CLOSED_GATES
1582 if (fixes->fix_press_through_closed_gates) determine_col();
1583 #endif
1584 get_tile_at_char();
1585 }
1586 } else {
1587 return;
1588 }
1589 if (curr_tile2 == tiles_15_opener || curr_tile2 == tiles_6_closer) {
1590 if (Char.alive < 0) {
1591 trigger_button(1, 0, -1);
1592 } else {
1593 died_on_button();
1594 }
1595 } else if (curr_tile2 == tiles_11_loose) {
1596 is_guard_notice = 1;
1597 make_loose_fall(1);
1598 }
1599 }
1600
1601 // seg006:1199
1602 void __pascal far check_spike_below() {
1603 short not_finished;
1604 short room;
1605 short row;
1606 short col;
1607 short right_col;
1608 right_col = get_tile_div_mod_m7(char_x_right);
1609 if (right_col < 0) return;
1610 row = Char.curr_row;
1611 room = Char.room;
1612 for (col = get_tile_div_mod_m7(char_x_left); col <= right_col; ++col) {
1613 row = Char.curr_row;
1614 do {
1615 not_finished = 0;
1616 if (get_tile(room, col, row) == tiles_2_spike) {
1617 start_anim_spike(curr_room, curr_tilepos);
1618 } else if (
1619 ! tile_is_floor(curr_tile2) &&
1620 curr_room != 0 &&
1621 #ifdef FIX_INFINITE_DOWN_BUG
1622 (fixes->fix_infinite_down_bug ? (row <= 2) : (room == curr_room))
1623 #else
1624 room == curr_room
1625 #endif
1626 ) {
1627 ++row;
1628 not_finished = 1;
1629 }
1630 } while(not_finished);
1631 }
1632 }
1633
1634 // seg006:1231
1635 void __pascal far clip_char() {
1636 short frame;
1637 short room;
1638 short action;
1639 short col;
1640 short var_A;
1641 short row;
1642 short var_E;
1643 frame = Char.frame;
1644 action = Char.action;
1645 room = Char.room;
1646 row = Char.curr_row;
1647 reset_obj_clip();
1648 // frames 217..228: going up the level door
1649 if (frame >= frame_224_exit_stairs_8 && frame < 229) {
1650 obj_clip_top = leveldoor_ybottom + 1;
1651 obj_clip_right = leveldoor_right;
1652 } else {
1653 if (
1654 get_tile(room, char_col_left, char_top_row) == tiles_20_wall ||
1655 tile_is_floor(curr_tile2)
1656 ) {
1657 // frame 79: jump up, frame 81: grab
1658 if ((action == actions_0_stand && (frame == frame_79_jumphang || frame == frame_81_hangdrop_1)) ||
1659 get_tile(room, char_col_right, char_top_row) == tiles_20_wall ||
1660 tile_is_floor(curr_tile2)
1661 ) {
1662 var_E = row + 1;
1663 if (var_E == 1 ||
1664 ((var_A = y_clip[var_E]) < obj_y && var_A - 15 < char_top_y)
1665 ) {
1666 obj_clip_top = char_top_y = y_clip[var_E];
1667 }
1668 }
1669 }
1670 col = get_tile_div_mod(char_x_left_coll - 4);
1671 if (get_tile(room, col + 1, row) == tiles_7_doortop_with_floor ||
1672 curr_tile2 == tiles_12_doortop
1673 ) {
1674 obj_clip_right = (tile_col << 5) + 32;
1675 } else {
1676 if ((get_tile(room, col, row) != tiles_7_doortop_with_floor &&
1677 curr_tile2 != tiles_12_doortop) ||
1678 action == actions_3_in_midair ||
1679 (action == actions_4_in_freefall && frame == frame_106_fall) ||
1680 (action == actions_5_bumped && frame == frame_107_fall_land_1) ||
1681 (Char.direction < dir_0_right && (
1682 action == actions_2_hang_climb ||
1683 action == actions_6_hang_straight ||
1684 (action == actions_1_run_jump &&
1685 frame >= frame_137_climbing_3 && frame < frame_140_climbing_6)
1686 ))
1687 ) {
1688 if (
1689 (get_tile(room, col = get_tile_div_mod(char_x_right_coll), row) == tiles_20_wall ||
1690 (curr_tile2 == tiles_13_mirror && Char.direction == dir_0_right)) &&
1691 (get_tile(room, col, char_top_row) == tiles_20_wall ||
1692 curr_tile2 == tiles_13_mirror) &&
1693 room == curr_room
1694 ) {
1695 obj_clip_right = tile_col << 5;
1696 }
1697 } else {
1698 obj_clip_right = (tile_col << 5) + 32;
1699 }
1700 }
1701 }
1702 }
1703
1704 // seg006:13E6
1705 void __pascal far stuck_lower() {
1706 if (get_tile_at_char() == tiles_5_stuck) {
1707 ++Char.y;
1708 }
1709 }
1710
1711 // seg006:13F3
1712 void __pascal far set_objtile_at_char() {
1713 short char_frame;
1714 short char_action;
1715 char_frame = Char.frame;
1716 char_action = Char.action;
1717 if (char_action == actions_1_run_jump) {
1718 tile_row = char_bottom_row;
1719 tile_col = char_col_left;
1720 } else {
1721 tile_row = Char.curr_row;
1722 tile_col = Char.curr_col;
1723 }
1724 // frame 135..148: climbing
1725 if ((char_frame >= frame_135_climbing_1 && char_frame < 149) ||
1726 char_action == actions_2_hang_climb ||
1727 char_action == actions_3_in_midair ||
1728 char_action == actions_4_in_freefall ||
1729 char_action == actions_6_hang_straight
1730 ) {
1731 --tile_col;
1732 }
1733 obj_tilepos = get_tilepos_nominus(tile_col, tile_row);
1734 //printf("set_objtile_at_char: obj_tile = %d\n", obj_tile); // debug
1735 }
1736
1737 // seg006:1463
1738 void __pascal far proc_get_object() {
1739 if (Char.charid != charid_0_kid || pickup_obj_type == 0) return;
1740 if (pickup_obj_type == -1) {
1741 have_sword = -1;
1742 play_sound(sound_37_victory); // get sword
1743 flash_color = color_14_brightyellow;
1744 flash_time = 8;
1745 } else {
1746 switch (--pickup_obj_type) {
1747 case 0: // health
1748 if (hitp_curr != hitp_max) {
1749 stop_sounds();
1750 play_sound(sound_33_small_potion); // small potion
1751 hitp_delta = 1;
1752 flash_color = color_4_red;
1753 flash_time = 2;
1754 }
1755 break;
1756 case 1: // life
1757 stop_sounds();
1758 play_sound(sound_30_big_potion); // big potion
1759 flash_color = color_4_red;
1760 flash_time = 4;
1761 add_life();
1762 break;
1763 case 2: // feather
1764 feather_fall();
1765 break;
1766 case 3: // invert
1767 toggle_upside();
1768 break;
1769 case 5: // open
1770 get_tile(8, 0, 0);
1771 trigger_button(0, 0, -1);
1772 break;
1773 case 4: // hurt
1774 stop_sounds();
1775 play_sound(sound_13_kid_hurt); // Kid hurt (by potion)
1776 // Special event: blue potions on potions level take half of HP
1777 if (current_level == 15) {
1778 hitp_delta = - ((hitp_max + 1) >> 1);
1779 } else {
1780 hitp_delta = -1;
1781 }
1782 break;
1783 }
1784 }
1785 }
1786
1787 // seg006:1599
1788 int __pascal far is_dead() {
1789 // 177: spiked, 178: chomped, 185: dead
1790 // or maybe this was a switch-case?
1791 return Char.frame >= frame_177_spiked && (Char.frame <= frame_178_chomped || Char.frame == frame_185_dead);
1792 }
1793
1794 // seg006:15B5
1795 void __pascal far play_death_music() {
1796 word sound_id;
1797 if (Guard.charid == charid_1_shadow) {
1798 sound_id = sound_32_shadow_music; // killed by shadow
1799 } else if (holding_sword) {
1800 sound_id = sound_28_death_in_fight; // death in fight
1801 } else {
1802 sound_id = sound_24_death_regular; // death not in fight
1803 }
1804 play_sound(sound_id);
1805 }
1806
1807 // seg006:15E8
1808 void __pascal far on_guard_killed() {
1809 if (current_level == 0) {
1810 // demo level: after killing Guard, run out of room
1811 checkpoint = 1;
1812 demo_index = demo_time = 0;
1813 } else if (current_level == /*13*/ custom->jaffar_victory_level) {
1814 // Jaffar's level: flash
1815 flash_color = color_15_brightwhite; // white
1816 flash_time = /*18*/ custom->jaffar_victory_flash_time;
1817 is_show_time = 1;
1818 leveldoor_open = 2;
1819 play_sound(sound_43_victory_Jaffar); // Jaffar's death
1820 } else if (Char.charid != charid_1_shadow) {
1821 play_sound(sound_37_victory); // Guard's death
1822 }
1823 }
1824
1825 // seg006:1634
1826 void __pascal far clear_char() {
1827 Char.direction = dir_56_none;
1828 Char.alive = 0;
1829 Char.action = 0;
1830 draw_guard_hp(0, guardhp_curr);
1831 guardhp_curr = 0;
1832 }
1833
1834 // data:42EC
1835 byte obj2_tilepos;
1836 // data:34A6
1837 word obj2_x;
1838 // data:34A8
1839 byte obj2_y;
1840 // data:599E
1841 sbyte obj2_direction;
1842 // data:5948
1843 byte obj2_id;
1844 // data:42BE
1845 byte obj2_chtab;
1846 // data:4D90
1847 short obj2_clip_top;
1848 // data:460C
1849 short obj2_clip_bottom;
1850 // data:4C94
1851 short obj2_clip_left;
1852 // data:4CDE
1853 short obj2_clip_right;
1854
1855 // seg006:1654
1856 void __pascal far save_obj() {
1857 obj2_tilepos = obj_tilepos;
1858 obj2_x = obj_x;
1859 obj2_y = obj_y;
1860 obj2_direction = obj_direction;
1861 obj2_id = obj_id;
1862 obj2_chtab = obj_chtab;
1863 obj2_clip_top = obj_clip_top;
1864 obj2_clip_bottom = obj_clip_bottom;
1865 obj2_clip_left = obj_clip_left;
1866 obj2_clip_right = obj_clip_right;
1867 }
1868
1869 // seg006:1691
1870 void __pascal far load_obj() {
1871 obj_tilepos = obj2_tilepos;
1872 obj_x = obj2_x;
1873 obj_y = obj2_y;
1874 obj_direction = obj2_direction;
1875 obj_id = obj2_id;
1876 obj_chtab = obj2_chtab;
1877 obj_clip_top = obj2_clip_top;
1878 obj_clip_bottom = obj2_clip_bottom;
1879 obj_clip_left = obj2_clip_left;
1880 obj_clip_right = obj2_clip_right;
1881 }
1882
1883 // seg006:16CE
1884 void __pascal far draw_hurt_splash() {
1885 short frame;
1886 frame = Char.frame;
1887 if (frame != frame_178_chomped) { // chomped
1888 save_obj();
1889 obj_tilepos = -1;
1890 // frame 185: dead
1891 // frame 106..110: fall + land
1892 if (frame == frame_185_dead || (frame>= frame_106_fall && frame<111)) {
1893 obj_y += 4;
1894 obj_dx_forward(5);
1895 } else if (frame == frame_177_spiked) { // spiked
1896 obj_dx_forward(-5);
1897 } else {
1898 obj_y -= ((Char.charid == charid_0_kid) << 2) + 11;
1899 obj_dx_forward(5);
1900 }
1901 if (Char.charid == charid_0_kid) {
1902 obj_chtab = id_chtab_2_kid;
1903 obj_id = 218; // splash!
1904 } else {
1905 obj_chtab = id_chtab_5_guard;
1906 obj_id = 1; // splash!
1907 }
1908 reset_obj_clip();
1909 add_objtable(5); // hurt splash
1910 load_obj();
1911 }
1912 }
1913
1914 // seg006:175D
1915 void __pascal far check_killed_shadow() {
1916 // Special event: killed the shadow
1917 if (current_level == 12) {
1918 if ((Char.charid | Opp.charid) == charid_1_shadow &&
1919 Char.alive < 0 && Opp.alive >= 0
1920 ) {
1921 flash_color = color_15_brightwhite; // white
1922 flash_time = 5;
1923 take_hp(100);
1924 }
1925 }
1926 }
1927
1928 // data:1712
1929 const sword_table_type sword_tbl[] = {
1930 { 255, 0, 0},
1931 { 0, 0, -9},
1932 { 5, -9, -29},
1933 { 1, 7, -25},
1934 { 2, 17, -26},
1935 { 6, 7, -14},
1936 { 7, 0, -5},
1937 { 3, 17, -16},
1938 { 4, 16, -19},
1939 { 30, 12, -9},
1940 { 8, 13, -34},
1941 { 9, 7, -25},
1942 { 10, 10, -16},
1943 { 11, 10, -11},
1944 { 12, 22, -21},
1945 { 13, 28, -23},
1946 { 14, 13, -35},
1947 { 15, 0, -38},
1948 { 16, 0, -29},
1949 { 17, 21, -19},
1950 { 18, 14, -23},
1951 { 19, 21, -22},
1952 { 19, 22, -23},
1953 { 17, 7, -13},
1954 { 17, 15, -18},
1955 { 7, 0, -8},
1956 { 1, 7, -27},
1957 { 28, 14, -28},
1958 { 8, 7, -27},
1959 { 4, 6, -23},
1960 { 4, 9, -21},
1961 { 10, 11, -18},
1962 { 13, 24, -23},
1963 { 13, 19, -23},
1964 { 13, 21, -23},
1965 { 20, 7, -32},
1966 { 21, 14, -32},
1967 { 22, 14, -31},
1968 { 23, 14, -29},
1969 { 24, 28, -28},
1970 { 25, 28, -28},
1971 { 26, 21, -25},
1972 { 27, 14, -22},
1973 { 255, 14, -25},
1974 { 255, 21, -25},
1975 { 29, 0, -16},
1976 { 8, 8, -37},
1977 { 31, 14, -24},
1978 { 32, 14, -24},
1979 { 33, 7, -14},
1980 { 8, 8, -37},
1981 };
1982
1983 // seg006:1798
1984 void __pascal far add_sword_to_objtable() {
1985 short frame;
1986 short sword_frame;
1987 frame = Char.frame;
1988 if ((frame >= frame_229_found_sword && frame < 238) || // found sword + put sword away
1989 Char.sword != sword_0_sheathed ||
1990 (Char.charid == charid_2_guard && Char.alive < 0)
1991 ) {
1992 sword_frame = cur_frame.sword & 0x3F;
1993 if (sword_frame) {
1994 obj_id = sword_tbl[sword_frame].id;
1995 if (obj_id != 0xFF) {
1996 obj_x = calc_screen_x_coord(obj_x);
1997 obj_dx_forward(sword_tbl[sword_frame].x);
1998 obj_y += sword_tbl[sword_frame].y;
1999 obj_chtab = id_chtab_0_sword;
2000 add_objtable(3); // sword
2001 }
2002 }
2003 }
2004 }
2005
2006 // seg006:1827
2007 void __pascal far control_guard_inactive() {
2008 if (Char.frame == frame_166_stand_inactive && control_down < 0) {
2009 if (control_forward < 0) {
2010 draw_sword();
2011 } else {
2012 control_down = 1;
2013 seqtbl_offset_char(seq_80_stand_flipped); // stand flipped
2014 }
2015 }
2016 }
2017
2018 // seg006:1852
2019 int __pascal far char_opp_dist() {
2020 // >0 if Opp is in front of char
2021 // <0 if Opp is behind char
2022 short distance;
2023 if (Char.room != Opp.room) {
2024 return 999;
2025 }
2026 distance = Opp.x - Char.x;
2027 if (Char.direction < dir_0_right) {
2028 distance = -distance;
2029 }
2030 if (distance >= 0 && Char.direction != Opp.direction) {
2031 distance += 13;
2032 }
2033 return distance;
2034 }
2035
2036 // seg006:189B
2037 void __pascal far inc_curr_row() {
2038 ++Char.curr_row;
2039 }
2040