Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1 | pmbaty | 1 | /* |
2 | SDLPoP, a port/conversion of the DOS game Prince of Persia. |
||
3 | Copyright (C) 2013-2018 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 <http://www.gnu.org/licenses/>. |
||
17 | |||
18 | The authors of this program may be contacted at http://forum.princed.org |
||
19 | */ |
||
20 | |||
21 | #include "common.h" |
||
22 | |||
23 | // data:1888 |
||
24 | extern const word seqtbl_offsets[]; |
||
25 | |||
26 | // seg005:000A |
||
27 | void __pascal far seqtbl_offset_char(short seq_index) { |
||
28 | Char.curr_seq = seqtbl_offsets[seq_index]; |
||
29 | } |
||
30 | |||
31 | // seg005:001D |
||
32 | void __pascal far seqtbl_offset_opp(int seq_index) { |
||
33 | Opp.curr_seq = seqtbl_offsets[seq_index]; |
||
34 | } |
||
35 | |||
36 | // seg005:0030 |
||
37 | void __pascal far do_fall() { |
||
38 | if (is_screaming == 0 && Char.fall_y >= 31) { |
||
39 | play_sound(sound_1_falling); // falling |
||
40 | is_screaming = 1; |
||
41 | } |
||
42 | if ((word)y_land[Char.curr_row + 1] > (word)Char.y) { |
||
43 | check_grab(); |
||
44 | |||
45 | #ifdef FIX_GLIDE_THROUGH_WALL |
||
46 | if (fix_glide_through_wall) { |
||
47 | // Fix for the kid falling through walls after turning around while running (especially when weightless) |
||
48 | determine_col(); |
||
49 | get_tile_at_char(); |
||
50 | if (curr_tile2 == tiles_20_wall || |
||
51 | ((curr_tile2 == tiles_12_doortop || curr_tile2 == tiles_7_doortop_with_floor) && |
||
52 | Char.direction == dir_FF_left) |
||
53 | ) { |
||
54 | int delta_x = distance_to_edge_weight(); |
||
55 | //printf("delta_x = %d\n", delta_x); |
||
56 | // When falling into a wall or doortop after turning or running, delta_x is likely to be either 8, 11 or 12 |
||
57 | // Calling in_wall() here produces the desired fix (no glitching through wall), but only when delta_x >= 10 |
||
58 | // The code below "emulates" in_wall() to always get the same effect as if delta_x == 10 |
||
59 | // (which distance actually looks/behaves best is a matter of preference) |
||
60 | #define delta_x_reference 10 |
||
61 | if (delta_x >= 8) { |
||
62 | delta_x = -5 + delta_x - delta_x_reference; |
||
63 | Char.x = (byte) char_dx_forward(delta_x); |
||
64 | |||
65 | Char.fall_x = 0; // not in in_wall(), but we do need to cancel horizontal movement |
||
66 | } |
||
67 | } |
||
68 | } |
||
69 | #endif |
||
70 | |||
71 | } else { |
||
72 | |||
73 | #ifdef FIX_JUMP_THROUGH_WALL_ABOVE_GATE |
||
74 | if (fix_jump_through_wall_above_gate) { |
||
75 | // At this point, Char.curr_col has not yet been updated since check_bumped() |
||
76 | // Basically, Char.curr_col is still set to the column of the wall itself (even though the kid |
||
77 | // may have 'bumped' against the wall, with Char.x being offset) |
||
78 | |||
79 | // To prevent in_wall() from being called we need to update Char.curr_col here. |
||
80 | // (in_wall() only makes things worse, because it tries to 'eject' the kid from the wall the wrong way. |
||
81 | // For this reason, the kid can end up behind a closed gate below, like is possible in Level 7) |
||
82 | |||
83 | // The fix is calling determine_col() here. |
||
84 | |||
85 | // One caveat: the kid can also land on the rightmost edge of a closed gate tile, when doing a running jump |
||
86 | // to the left from two floors up. This 'trick' can be used in original PoP, but is 'fixed' by this change. |
||
87 | // To still allow this trick to be possible, we can check that we not jumping into a gate tile. |
||
88 | // (By the way, strangely enough, in unmodified PoP the trick even works with a tapestry + floor tile...) |
||
89 | |||
90 | if (get_tile_at_char() != tiles_4_gate) |
||
91 | determine_col(); |
||
92 | } |
||
93 | #endif |
||
94 | |||
95 | if (get_tile_at_char() == tiles_20_wall) { |
||
96 | in_wall(); |
||
97 | } |
||
98 | #ifdef FIX_DROP_THROUGH_TAPESTRY |
||
99 | else if (fix_drop_through_tapestry && get_tile_at_char() == tiles_12_doortop && Char.direction == dir_FF_left) { |
||
100 | if (distance_to_edge_weight() >= 8) // only intervene if the kid is actually IN FRONT of the tapestry |
||
101 | in_wall(); |
||
102 | } |
||
103 | #endif |
||
104 | |||
105 | if (tile_is_floor(curr_tile2)) { |
||
106 | land(); |
||
107 | } else { |
||
108 | inc_curr_row(); |
||
109 | } |
||
110 | } |
||
111 | } |
||
112 | |||
113 | // seg005:0090 |
||
114 | void __pascal far land() { |
||
115 | word seq_id; |
||
116 | is_screaming = 0; |
||
117 | Char.y = y_land[Char.curr_row + 1]; |
||
118 | if (get_tile_at_char() != tiles_2_spike) { |
||
119 | |||
120 | |||
121 | if (! tile_is_floor(get_tile_infrontof_char()) && |
||
122 | distance_to_edge_weight() < 3 |
||
123 | ) { |
||
124 | Char.x = char_dx_forward(-3); |
||
125 | } |
||
126 | |||
127 | #ifdef FIX_LAND_AGAINST_GATE_OR_TAPESTRY |
||
128 | else if (fix_land_against_gate_or_tapestry) { |
||
129 | // A closed gate right in front of the landing spot should not behave like an open floor tile, but like a wall |
||
130 | // Similar for a tapestry tile (with floor) |
||
131 | get_tile_infrontof_char(); |
||
132 | if (Char.direction == dir_FF_left && ( |
||
133 | (curr_tile2 == tiles_4_gate && can_bump_into_gate()) || |
||
134 | (curr_tile2 == tiles_7_doortop_with_floor)) |
||
135 | && distance_to_edge_weight() < 3 |
||
136 | ) { |
||
137 | Char.x = char_dx_forward(-3); |
||
138 | } |
||
139 | } |
||
140 | #endif |
||
141 | start_chompers(); |
||
142 | } else { |
||
143 | // fell on spikes |
||
144 | goto loc_5EE6; |
||
145 | } |
||
146 | if (Char.alive < 0) { |
||
147 | // alive |
||
148 | if ((distance_to_edge_weight() >= 12 && |
||
149 | get_tile_behind_char() == tiles_2_spike) || |
||
150 | get_tile_at_char() == tiles_2_spike |
||
151 | ) { |
||
152 | // fell on spikes |
||
153 | loc_5EE6: |
||
154 | if (is_spike_harmful()) { |
||
155 | spiked(); |
||
156 | return; |
||
157 | } |
||
158 | #ifdef FIX_SAFE_LANDING_ON_SPIKES |
||
159 | else if (fix_safe_landing_on_spikes && curr_room_modif[curr_tilepos] == 0) { |
||
160 | // spikes ARE dangerous, just not out yet. |
||
161 | spiked(); |
||
162 | return; |
||
163 | } |
||
164 | #endif // FIX_SAFE_LANDING_ON_SPIKES |
||
165 | } |
||
166 | { |
||
167 | if (Char.fall_y < 22) { |
||
168 | // fell 1 row |
||
169 | loc_5EFD: |
||
170 | if (Char.charid >= charid_2_guard || Char.sword == sword_2_drawn) { |
||
171 | Char.sword = sword_2_drawn; |
||
172 | seq_id = seq_63_guard_stand_active; // stand active after landing |
||
173 | } else { |
||
174 | seq_id = seq_17_soft_land; // crouch (soft land) |
||
175 | } |
||
176 | if (Char.charid == charid_0_kid) { |
||
177 | play_sound(sound_17_soft_land); // soft land (crouch) |
||
178 | is_guard_notice = 1; |
||
179 | } |
||
180 | } else if (Char.fall_y < 33) { |
||
181 | // fell 2 rows |
||
182 | if (Char.charid == charid_1_shadow) goto loc_5EFD; |
||
183 | if (Char.charid == charid_2_guard) goto loc_5F6C; |
||
184 | // kid (or skeleton (bug!)) |
||
185 | if (! take_hp(1)) { |
||
186 | // still alive |
||
187 | play_sound(sound_16_medium_land); // medium land |
||
188 | is_guard_notice = 1; |
||
189 | seq_id = seq_20_medium_land; // medium land (lose 1 HP, crouch) |
||
190 | } else { |
||
191 | // dead (this was the last HP) |
||
192 | goto loc_5F75; |
||
193 | } |
||
194 | } else { |
||
195 | // fell 3 or more rows |
||
196 | goto loc_5F6C; |
||
197 | } |
||
198 | } |
||
199 | } else { |
||
200 | // dead |
||
201 | loc_5F6C: |
||
202 | take_hp(100); |
||
203 | loc_5F75: |
||
204 | play_sound(sound_0_fell_to_death); // prince crashing into the floor |
||
205 | seq_id = seq_22_crushed; // dead (after falling) |
||
206 | } |
||
207 | seqtbl_offset_char(seq_id); |
||
208 | play_seq(); |
||
209 | Char.fall_y = 0; |
||
210 | } |
||
211 | |||
212 | // seg005:01B7 |
||
213 | void __pascal far spiked() { |
||
214 | // If someone falls into spikes, those spikes become harmless (to others). |
||
215 | curr_room_modif[curr_tilepos] = 0xFF; |
||
216 | Char.y = y_land[Char.curr_row + 1]; |
||
217 | Char.x = x_bump[tile_col + 5] + 10; |
||
218 | Char.x = char_dx_forward(8); |
||
219 | Char.fall_y = 0; |
||
220 | play_sound(sound_48_spiked); // something spiked |
||
221 | take_hp(100); |
||
222 | seqtbl_offset_char(seq_51_spiked); // spiked |
||
223 | play_seq(); |
||
224 | } |
||
225 | |||
226 | // seg005:0213 |
||
227 | void __pascal far control() { |
||
228 | short char_frame; |
||
229 | short char_action; |
||
230 | char_frame = Char.frame; |
||
231 | if (Char.alive >= 0) { |
||
232 | if (char_frame == frame_15_stand || // stand |
||
233 | char_frame == frame_166_stand_inactive || // stand |
||
234 | char_frame == frame_158_stand_with_sword || // stand with sword |
||
235 | char_frame == frame_171_stand_with_sword // stand with sword |
||
236 | ) { |
||
237 | seqtbl_offset_char(seq_71_dying); // dying (not stabbed) |
||
238 | } |
||
239 | } else { |
||
240 | char_action = Char.action; |
||
241 | if (char_action == actions_5_bumped || |
||
242 | char_action == actions_4_in_freefall |
||
243 | ) { |
||
244 | release_arrows(); |
||
245 | } else if (Char.sword == sword_2_drawn) { |
||
246 | control_with_sword(); |
||
247 | } else if (Char.charid >= charid_2_guard) { |
||
248 | control_guard_inactive(); |
||
249 | } else if (char_frame == frame_15_stand || // standing |
||
250 | (char_frame>= frame_50_turn && char_frame<53) // end of turning |
||
251 | ) { |
||
252 | control_standing(); |
||
253 | } else if (char_frame == frame_48_turn) { // a frame in turning |
||
254 | control_turning(); |
||
255 | } else if (char_frame < 4) { // start run |
||
256 | control_startrun(); |
||
257 | } else if (char_frame >= frame_67_start_jump_up_1 && char_frame < frame_70_jumphang) { // start jump up |
||
258 | control_jumpup(); |
||
259 | } else if (char_frame < 15) { // running |
||
260 | control_running(); |
||
261 | } else if (char_frame >= frame_87_hanging_1 && char_frame < 100) { // hanging |
||
262 | control_hanging(); |
||
263 | } else if (char_frame == frame_109_crouch) { // crouching |
||
264 | control_crouched(); |
||
265 | } |
||
266 | |||
267 | #ifdef ALLOW_CROUCH_AFTER_CLIMBING |
||
268 | // When ducking with down+forward, give time to release the forward control (prevents unintended crouch-hops) |
||
269 | else if (enable_crouch_after_climbing && Char.curr_seq >= seqtbl_offsets[seq_50_crouch] && |
||
270 | Char.curr_seq < seqtbl_offsets[seq_49_stand_up_from_crouch]) // while stooping |
||
271 | if (control_forward < 1) control_forward = 0; |
||
272 | #endif |
||
273 | |||
274 | #ifdef FIX_MOVE_AFTER_DRINK |
||
275 | if (fix_move_after_drink && char_frame >= frame_191_drink && char_frame <= frame_205_drink) |
||
276 | release_arrows(); |
||
277 | #endif |
||
278 | |||
279 | #ifdef FIX_MOVE_AFTER_SHEATHE |
||
280 | if (fix_move_after_sheathe && |
||
281 | Char.curr_seq >= seqtbl_offsets[seq_92_put_sword_away] && |
||
282 | Char.curr_seq < seqtbl_offsets[seq_93_put_sword_away_fast] |
||
283 | ) |
||
284 | release_arrows(); |
||
285 | #endif |
||
286 | } |
||
287 | } |
||
288 | |||
289 | // seg005:02EB |
||
290 | void __pascal far control_crouched() { |
||
291 | if (need_level1_music != 0 && current_level == 1) { |
||
292 | // Special event: music when crouching |
||
293 | if (! check_sound_playing()) { |
||
294 | if (need_level1_music == 1) { |
||
295 | play_sound(sound_25_presentation); // presentation (level 1 start) |
||
296 | need_level1_music = 2; |
||
297 | } else { |
||
298 | #ifdef USE_REPLAY |
||
299 | if (recording) special_move = MOVE_EFFECT_END; |
||
300 | if (!replaying) // during replays, crouch immobilization gets cancelled in do_replay_move() |
||
301 | #endif |
||
302 | need_level1_music = 0; |
||
303 | } |
||
304 | } |
||
305 | } else { |
||
306 | need_level1_music = 0; |
||
307 | if (control_shift2 < 0 && check_get_item()) return; |
||
308 | if (control_y != 1) { |
||
309 | seqtbl_offset_char(seq_49_stand_up_from_crouch); // stand up from crouch |
||
310 | } else { |
||
311 | if (control_forward < 0) { |
||
312 | control_forward = 1; // disable automatic repeat |
||
313 | seqtbl_offset_char(seq_79_crouch_hop); // crouch-hop |
||
314 | } |
||
315 | } |
||
316 | } |
||
317 | } |
||
318 | |||
319 | // seg005:0358 |
||
320 | void __pascal far control_standing() { |
||
321 | short var_2; |
||
322 | if (control_shift2 < 0 && control_shift < 0 && check_get_item()) { |
||
323 | return; |
||
324 | } |
||
325 | if (Char.charid != charid_0_kid && control_down < 0 && control_forward < 0) { |
||
326 | draw_sword(); |
||
327 | return; |
||
328 | } //else |
||
329 | if (have_sword) { |
||
330 | if (offguard != 0 && control_shift >= 0) goto loc_6213; |
||
331 | if (can_guard_see_kid >= 2) { |
||
332 | var_2 = char_opp_dist(); |
||
333 | if (var_2 >= -10 && var_2 < 90) { |
||
334 | holding_sword = 1; |
||
335 | if ((word)var_2 < (word)-6) { |
||
336 | if (Opp.charid == charid_1_shadow && |
||
337 | (Opp.action == actions_3_in_midair || (Opp.frame >= frame_107_fall_land_1 && Opp.frame < 118)) |
||
338 | ) { |
||
339 | offguard = 0; |
||
340 | } else { |
||
341 | draw_sword(); |
||
342 | return; |
||
343 | } |
||
344 | } else { |
||
345 | back_pressed(); |
||
346 | return; |
||
347 | } |
||
348 | } |
||
349 | } else { |
||
350 | offguard = 0; |
||
351 | } |
||
352 | } |
||
353 | if (control_shift < 0) { |
||
354 | if (control_backward < 0) { |
||
355 | back_pressed(); |
||
356 | } else if (control_up < 0) { |
||
357 | up_pressed(); |
||
358 | } else if (control_down < 0) { |
||
359 | down_pressed(); |
||
360 | } else if (control_x < 0 && control_forward < 0) { |
||
361 | safe_step(); |
||
362 | } |
||
363 | } else loc_6213: if (control_forward < 0) { |
||
364 | if (is_keyboard_mode && control_up < 0) { |
||
365 | standing_jump(); |
||
366 | } else { |
||
367 | forward_pressed(); |
||
368 | } |
||
369 | } else if (control_backward < 0) { |
||
370 | back_pressed(); |
||
371 | } else if (control_up < 0) { |
||
372 | if (is_keyboard_mode && control_forward < 0) { |
||
373 | standing_jump(); |
||
374 | } else { |
||
375 | up_pressed(); |
||
376 | } |
||
377 | } else if (control_down < 0) { |
||
378 | down_pressed(); |
||
379 | } else if (control_x < 0) { |
||
380 | forward_pressed(); |
||
381 | } |
||
382 | } |
||
383 | |||
384 | // seg005:0482 |
||
385 | void __pascal far up_pressed() { |
||
386 | int leveldoor_tilepos = -1; |
||
387 | if (get_tile_at_char() == tiles_16_level_door_left) leveldoor_tilepos = curr_tilepos; |
||
388 | else if (get_tile_behind_char() == tiles_16_level_door_left) leveldoor_tilepos = curr_tilepos; |
||
389 | else if (get_tile_infrontof_char() == tiles_16_level_door_left) leveldoor_tilepos = curr_tilepos; |
||
390 | if ((leveldoor_tilepos != -1) && |
||
391 | level.start_room != drawn_room && |
||
392 | curr_room_modif[leveldoor_tilepos] >= 42 // this door must be fully open |
||
393 | ){ |
||
394 | go_up_leveldoor(); |
||
395 | } else { |
||
396 | if (control_x < 0) { |
||
397 | standing_jump(); |
||
398 | } else { |
||
399 | check_jump_up(); |
||
400 | } |
||
401 | } |
||
402 | } |
||
403 | |||
404 | // seg005:04C7 |
||
405 | void __pascal far down_pressed() { |
||
406 | control_down = 1; // disable automatic repeat |
||
407 | if (! tile_is_floor(get_tile_infrontof_char()) && |
||
408 | distance_to_edge_weight() < 3 |
||
409 | ) { |
||
410 | Char.x = char_dx_forward(5); |
||
411 | load_fram_det_col(); |
||
412 | } else { |
||
413 | if (! tile_is_floor(get_tile_behind_char()) && |
||
414 | distance_to_edge_weight() >= 8 |
||
415 | ) { |
||
416 | through_tile = get_tile_behind_char(); |
||
417 | get_tile_at_char(); |
||
418 | if (can_grab() && |
||
419 | #ifdef ALLOW_CROUCH_AFTER_CLIMBING |
||
420 | (!(enable_crouch_after_climbing && control_forward == -1)) && |
||
421 | #endif |
||
422 | (Char.direction >= dir_0_right || |
||
423 | get_tile_at_char() != tiles_4_gate || |
||
424 | curr_room_modif[curr_tilepos] >> 2 >= 6) |
||
425 | ) { |
||
426 | Char.x = char_dx_forward(distance_to_edge_weight() - 9); |
||
427 | seqtbl_offset_char(seq_68_climb_down); // climb down |
||
428 | } else { |
||
429 | crouch(); |
||
430 | } |
||
431 | } else { |
||
432 | crouch(); |
||
433 | } |
||
434 | } |
||
435 | } |
||
436 | |||
437 | // seg005:0574 |
||
438 | void __pascal far go_up_leveldoor() { |
||
439 | Char.x = x_bump[tile_col + 5] + 10; |
||
440 | Char.direction = dir_FF_left; // right |
||
441 | seqtbl_offset_char(seq_70_go_up_on_level_door); // go up on level door |
||
442 | } |
||
443 | |||
444 | // seg005:058F |
||
445 | void __pascal far control_turning() { |
||
446 | if (control_shift >= 0 && control_x < 0 && control_y >= 0) { |
||
447 | seqtbl_offset_char(seq_43_start_run_after_turn); // start run and run (after turning) |
||
448 | } |
||
449 | |||
450 | // Added: |
||
451 | // When using a joystick, the kid may sometimes jump/duck/turn unintendedly after turning around. |
||
452 | // To prevent this: clear the remembered controls, so that if the stick has already moved to another/neutral position, |
||
453 | // the kid will not jump, duck, or turn again. |
||
454 | if (is_joyst_mode) { |
||
455 | if (control_up < 0 && control_y >= 0) { |
||
456 | control_up = 0; |
||
457 | } |
||
458 | if (control_down < 0 && control_y <= 0) { |
||
459 | control_down = 0; |
||
460 | } |
||
461 | if (control_backward < 0 && control_x == 0) { |
||
462 | control_backward = 0; |
||
463 | } |
||
464 | } |
||
465 | } |
||
466 | |||
467 | // seg005:05AD |
||
468 | void __pascal far crouch() { |
||
469 | seqtbl_offset_char(seq_50_crouch); // crouch |
||
470 | control_down = release_arrows(); |
||
471 | } |
||
472 | |||
473 | // seg005:05BE |
||
474 | void __pascal far back_pressed() { |
||
475 | word seq_id; |
||
476 | control_backward = release_arrows(); |
||
477 | // After turn, Kid will draw sword if ... |
||
478 | if (have_sword == 0 || // if Kid has sword |
||
479 | can_guard_see_kid < 2 || // and can see Guard |
||
480 | char_opp_dist() > 0 || // and Guard was behind him |
||
481 | distance_to_edge_weight() < 2 |
||
482 | ) { |
||
483 | seq_id = seq_5_turn; // turn |
||
484 | } else { |
||
485 | Char.sword = sword_2_drawn; |
||
486 | offguard = 0; |
||
487 | seq_id = seq_89_turn_draw_sword; // turn and draw sword |
||
488 | } |
||
489 | seqtbl_offset_char(seq_id); |
||
490 | } |
||
491 | |||
492 | // seg005:060F |
||
493 | void __pascal far forward_pressed() { |
||
494 | short distance; |
||
495 | distance = get_edge_distance(); |
||
496 | #ifdef ALLOW_CROUCH_AFTER_CLIMBING |
||
497 | if (enable_crouch_after_climbing && control_down < 0) { |
||
498 | down_pressed(); |
||
499 | control_forward = 0; |
||
500 | return; |
||
501 | } |
||
502 | #endif |
||
503 | |||
504 | if (edge_type == 1 && curr_tile2 != tiles_18_chomper && distance < 8) { |
||
505 | // If char is near a wall, step instead of run. |
||
506 | if (control_forward < 0) { |
||
507 | safe_step(); |
||
508 | } |
||
509 | } else { |
||
510 | seqtbl_offset_char(seq_1_start_run); // start run and run |
||
511 | } |
||
512 | } |
||
513 | |||
514 | // seg005:0649 |
||
515 | void __pascal far control_running() { |
||
516 | if (control_x == 0 && (Char.frame == frame_7_run || Char.frame == frame_11_run)) { |
||
517 | control_forward = release_arrows(); |
||
518 | seqtbl_offset_char(seq_13_stop_run); // stop run |
||
519 | } else if (control_x > 0) { |
||
520 | control_backward = release_arrows(); |
||
521 | seqtbl_offset_char(seq_6_run_turn); // run-turn |
||
522 | } else if (control_y < 0 && control_up < 0) { |
||
523 | run_jump(); |
||
524 | } else if (control_down < 0) { |
||
525 | control_down = 1; // disable automatic repeat |
||
526 | seqtbl_offset_char(seq_26_crouch_while_running); // crouch while running |
||
527 | } |
||
528 | } |
||
529 | |||
530 | // seg005:06A8 |
||
531 | void __pascal far safe_step() { |
||
532 | short distance; |
||
533 | control_shift2 = 1; // disable automatic repeat |
||
534 | control_forward = 1; // disable automatic repeat |
||
535 | distance = get_edge_distance(); |
||
536 | if (distance) { |
||
537 | Char.repeat = 1; |
||
538 | seqtbl_offset_char(distance + 28); // 29..42: safe step to edge |
||
539 | } else if (edge_type != 1 && Char.repeat != 0) { |
||
540 | Char.repeat = 0; |
||
541 | seqtbl_offset_char(seq_44_step_on_edge); // step on edge |
||
542 | } else { |
||
543 | seqtbl_offset_char(seq_39_safe_step_11); // unsafe step (off ledge) |
||
544 | } |
||
545 | } |
||
546 | |||
547 | // seg005:06F0 |
||
548 | int __pascal far check_get_item() { |
||
549 | if (get_tile_at_char() == tiles_10_potion || |
||
550 | curr_tile2 == tiles_22_sword |
||
551 | ) { |
||
552 | if (! tile_is_floor(get_tile_behind_char())) { |
||
553 | return 0; |
||
554 | } |
||
555 | Char.x = char_dx_forward(-14); |
||
556 | load_fram_det_col(); |
||
557 | } |
||
558 | if (get_tile_infrontof_char() == tiles_10_potion || |
||
559 | curr_tile2 == tiles_22_sword |
||
560 | ) { |
||
561 | get_item(); |
||
562 | return 1; |
||
563 | } |
||
564 | return 0; |
||
565 | } |
||
566 | |||
567 | // seg005:073E |
||
568 | void __pascal far get_item() { |
||
569 | short distance; |
||
570 | if (Char.frame != frame_109_crouch) { // crouching |
||
571 | distance = get_edge_distance(); |
||
572 | if (edge_type != 2) { |
||
573 | Char.x = char_dx_forward(distance); |
||
574 | } |
||
575 | if (Char.direction >= dir_0_right) { |
||
576 | Char.x = char_dx_forward((curr_tile2 == tiles_10_potion) - 2); |
||
577 | } |
||
578 | crouch(); |
||
579 | } else if (curr_tile2 == tiles_22_sword) { |
||
580 | do_pickup(-1); |
||
581 | seqtbl_offset_char(seq_91_get_sword); // get sword |
||
582 | } else { // potion |
||
583 | do_pickup(curr_room_modif[curr_tilepos] >> 3); |
||
584 | seqtbl_offset_char(seq_78_drink); // drink |
||
585 | #ifdef USE_COPYPROT |
||
586 | if (current_level == 15) { |
||
587 | short index; |
||
588 | for (index = 0; index < 14; ++index) { |
||
589 | // remove letter on potions level |
||
590 | if (copyprot_room[index] == curr_room && |
||
591 | copyprot_tile[index] == curr_tilepos |
||
592 | ) { |
||
593 | copyprot_room[index] = 0; |
||
594 | break; |
||
595 | } |
||
596 | } |
||
597 | } |
||
598 | #endif |
||
599 | } |
||
600 | } |
||
601 | |||
602 | // seg005:07FF |
||
603 | void __pascal far control_startrun() { |
||
604 | if (control_y < 0 && control_x < 0) { |
||
605 | standing_jump(); |
||
606 | } |
||
607 | } |
||
608 | |||
609 | // seg005:0812 |
||
610 | void __pascal far control_jumpup() { |
||
611 | if (control_x < 0 || control_forward < 0) { |
||
612 | standing_jump(); |
||
613 | } |
||
614 | } |
||
615 | |||
616 | // seg005:0825 |
||
617 | void __pascal far standing_jump() { |
||
618 | control_up = control_forward = 1; // disable automatic repeat |
||
619 | seqtbl_offset_char(seq_3_standing_jump); // standing jump |
||
620 | } |
||
621 | |||
622 | // seg005:0836 |
||
623 | void __pascal far check_jump_up() { |
||
624 | control_up = release_arrows(); |
||
625 | through_tile = get_tile_above_char(); |
||
626 | get_tile_front_above_char(); |
||
627 | if (can_grab()) { |
||
628 | grab_up_with_floor_behind(); |
||
629 | } else { |
||
630 | through_tile = get_tile_behind_above_char(); |
||
631 | get_tile_above_char(); |
||
632 | if (can_grab()) { |
||
633 | jump_up_or_grab(); |
||
634 | } else { |
||
635 | jump_up(); |
||
636 | } |
||
637 | } |
||
638 | } |
||
639 | |||
640 | // seg005:087B |
||
641 | void __pascal far jump_up_or_grab() { |
||
642 | short distance; |
||
643 | distance = distance_to_edge_weight(); |
||
644 | if (distance < 6) { |
||
645 | jump_up(); |
||
646 | } else if (! tile_is_floor(get_tile_behind_char())) { |
||
647 | // There is not floor behind char. |
||
648 | grab_up_no_floor_behind(); |
||
649 | } else { |
||
650 | // There is floor behind char, go back a bit. |
||
651 | Char.x = char_dx_forward(distance - 14); |
||
652 | load_fram_det_col(); |
||
653 | grab_up_with_floor_behind(); |
||
654 | } |
||
655 | } |
||
656 | |||
657 | // seg005:08C7 |
||
658 | void __pascal far grab_up_no_floor_behind() { |
||
659 | get_tile_above_char(); |
||
660 | Char.x = char_dx_forward(distance_to_edge_weight() - 10); |
||
661 | seqtbl_offset_char(seq_16_jump_up_and_grab); // jump up and grab (no floor behind) |
||
662 | } |
||
663 | |||
664 | // seg005:08E6 |
||
665 | void __pascal far jump_up() { |
||
666 | short distance; |
||
667 | control_up = release_arrows(); |
||
668 | distance = get_edge_distance(); |
||
669 | if (distance < 4 && edge_type == 1) { |
||
670 | Char.x = char_dx_forward(distance - 3); |
||
671 | } |
||
672 | #ifdef FIX_JUMP_DISTANCE_AT_EDGE |
||
673 | // When climbing up two floors, turning around and jumping upward, the kid falls down. |
||
674 | // This fix makes the workaround of Trick 25 unnecessary. |
||
675 | if (fix_jump_distance_at_edge && distance == 3 && edge_type == 0) { |
||
676 | Char.x = char_dx_forward(-1); |
||
677 | } |
||
678 | #endif |
||
679 | get_tile(Char.room, get_tile_div_mod(back_delta_x(0) + dx_weight() - 6), Char.curr_row - 1); |
||
680 | if (curr_tile2 != tiles_20_wall && ! tile_is_floor(curr_tile2)) { |
||
681 | seqtbl_offset_char(seq_28_jump_up_with_nothing_above); // jump up with nothing above |
||
682 | } else { |
||
683 | seqtbl_offset_char(seq_14_jump_up_into_ceiling); // jump up with wall or floor above |
||
684 | } |
||
685 | } |
||
686 | |||
687 | // seg005:0968 |
||
688 | void __pascal far control_hanging() { |
||
689 | if (Char.alive < 0) { |
||
690 | if (grab_timer == 0 && control_y < 0) { |
||
691 | can_climb_up(); |
||
692 | } else if (control_shift < 0) { |
||
693 | // hanging against a wall or a doortop |
||
694 | if (Char.action != actions_6_hang_straight && |
||
695 | (get_tile_at_char() == tiles_20_wall || |
||
696 | (Char.direction == dir_FF_left && ( // facing left |
||
697 | curr_tile2 == tiles_7_doortop_with_floor || |
||
698 | curr_tile2 == tiles_12_doortop |
||
699 | ))) |
||
700 | ) { |
||
701 | if (grab_timer == 0) { |
||
702 | play_sound(sound_8_bumped); // touching a wall (hang against wall) |
||
703 | } |
||
704 | seqtbl_offset_char(seq_25_hang_against_wall); // hang against wall (straight) |
||
705 | } else { |
||
706 | if (! tile_is_floor(get_tile_above_char())) { |
||
707 | hang_fall(); |
||
708 | } |
||
709 | } |
||
710 | } else { |
||
711 | hang_fall(); |
||
712 | } |
||
713 | } else { |
||
714 | hang_fall(); |
||
715 | } |
||
716 | } |
||
717 | |||
718 | // seg005:09DF |
||
719 | void __pascal far can_climb_up() { |
||
720 | short seq_id; |
||
721 | seq_id = seq_10_climb_up; // climb up |
||
722 | control_up = control_shift2 = release_arrows(); |
||
723 | get_tile_above_char(); |
||
724 | if (((curr_tile2 == tiles_13_mirror || curr_tile2 == tiles_18_chomper) && |
||
725 | Char.direction == dir_0_right) || |
||
726 | (curr_tile2 == tiles_4_gate && Char.direction != dir_0_right && |
||
727 | curr_room_modif[curr_tilepos] >> 2 < 6) |
||
728 | ) { |
||
729 | seq_id = seq_73_climb_up_to_closed_gate; // climb up to closed gate and down |
||
730 | } |
||
731 | seqtbl_offset_char(seq_id); |
||
732 | } |
||
733 | |||
734 | // seg005:0A46 |
||
735 | void __pascal far hang_fall() { |
||
736 | control_down = release_arrows(); |
||
737 | if (! tile_is_floor(get_tile_behind_char()) && |
||
738 | ! tile_is_floor(get_tile_at_char()) |
||
739 | ) { |
||
740 | seqtbl_offset_char(seq_23_release_ledge_and_fall); // release ledge and fall |
||
741 | } else { |
||
742 | if (get_tile_at_char() == tiles_20_wall || |
||
743 | (Char.direction < dir_0_right && ( // looking left |
||
744 | curr_tile2 == tiles_7_doortop_with_floor || |
||
745 | curr_tile2 == tiles_12_doortop |
||
746 | )) |
||
747 | ) { |
||
748 | Char.x = char_dx_forward(-7); |
||
749 | } |
||
750 | seqtbl_offset_char(seq_11_release_ledge_and_land); // end of climb down |
||
751 | } |
||
752 | } |
||
753 | |||
754 | // seg005:0AA8 |
||
755 | void __pascal far grab_up_with_floor_behind() { |
||
756 | short distance; |
||
757 | distance = distance_to_edge_weight(); |
||
758 | |||
759 | // The global variable edge_type (which we need!) gets set as a side effect of get_edge_distance() |
||
760 | short edge_distance = get_edge_distance(); |
||
761 | //printf("Distance to edge weight: %d\tedge type: %d\tedge distance: %d\n", distance, edge_type, edge_distance); |
||
762 | |||
763 | #ifdef FIX_EDGE_DISTANCE_CHECK_WHEN_CLIMBING |
||
764 | // When climbing to a higher floor, the game unnecessarily checks how far away the edge below is; |
||
765 | // This contributes to sometimes "teleporting" considerable distances when climbing from firm ground |
||
766 | #define JUMP_STRAIGHT_CONDITION (fix_edge_distance_check_when_climbing) \ |
||
767 | ? (distance < 4 && edge_type != 1) \ |
||
768 | : (distance < 4 && edge_distance < 4 && edge_type != 1) |
||
769 | #else |
||
770 | #define JUMP_STRAIGHT_CONDITION distance < 4 && edge_distance < 4 && edge_type != 1 |
||
771 | #endif |
||
772 | |||
773 | if (JUMP_STRAIGHT_CONDITION) { |
||
774 | Char.x = char_dx_forward(distance); |
||
775 | seqtbl_offset_char(seq_8_jump_up_and_grab_straight); // jump up and grab (when?) |
||
776 | } else { |
||
777 | Char.x = char_dx_forward(distance - 4); |
||
778 | seqtbl_offset_char(seq_24_jump_up_and_grab_forward); // jump up and grab (with floor behind) |
||
779 | } |
||
780 | } |
||
781 | |||
782 | // seg005:0AF7 |
||
783 | void __pascal far run_jump() { |
||
784 | short var_2; |
||
785 | short xpos; |
||
786 | short col; |
||
787 | short var_8; |
||
788 | if (Char.frame >= frame_7_run) { |
||
789 | // Align Kid to edge of floor. |
||
790 | xpos = char_dx_forward(4); |
||
791 | col = get_tile_div_mod_m7(xpos); |
||
792 | for (var_2 = 0; var_2 < 2; ++var_2) { |
||
793 | col += dir_front[Char.direction + 1]; |
||
794 | get_tile(Char.room, col, Char.curr_row); |
||
795 | if (curr_tile2 == tiles_2_spike || ! tile_is_floor(curr_tile2)) { |
||
796 | var_8 = distance_to_edge(xpos) + 14 * var_2 - 14; |
||
797 | if ((word)var_8 < (word)-8 || var_8 >= 2) { |
||
798 | if (var_8 < 128) return; |
||
799 | var_8 = -3; |
||
800 | } |
||
801 | Char.x = char_dx_forward(var_8 + 4); |
||
802 | break; |
||
803 | } |
||
804 | } |
||
805 | control_up = release_arrows(); // disable automatic repeat |
||
806 | seqtbl_offset_char(seq_4_run_jump); // run-jump |
||
807 | } |
||
808 | } |
||
809 | |||
810 | // sseg005:0BB5 |
||
811 | void __pascal far back_with_sword() { |
||
812 | short frame; |
||
813 | frame = Char.frame; |
||
814 | if (frame == frame_158_stand_with_sword || frame == frame_170_stand_with_sword || frame == frame_171_stand_with_sword) { |
||
815 | control_backward = 1; // disable automatic repeat |
||
816 | seqtbl_offset_char(seq_57_back_with_sword); // back with sword |
||
817 | } |
||
818 | } |
||
819 | |||
820 | // seg005:0BE3 |
||
821 | void __pascal far forward_with_sword() { |
||
822 | short frame; |
||
823 | frame = Char.frame; |
||
824 | if (frame == frame_158_stand_with_sword || frame == frame_170_stand_with_sword || frame == frame_171_stand_with_sword) { |
||
825 | control_forward = 1; // disable automatic repeat |
||
826 | if (Char.charid != charid_0_kid) { |
||
827 | seqtbl_offset_char(seq_56_guard_forward_with_sword); // forward with sword (Guard) |
||
828 | } else { |
||
829 | seqtbl_offset_char(seq_86_forward_with_sword); // forward with sword (Kid) |
||
830 | } |
||
831 | } |
||
832 | } |
||
833 | |||
834 | // seg005:0C1D |
||
835 | void __pascal far draw_sword() { |
||
836 | word seq_id; |
||
837 | seq_id = seq_55_draw_sword; // draw sword |
||
838 | control_forward = control_shift2 = release_arrows(); |
||
839 | #ifdef FIX_UNINTENDED_SWORD_STRIKE |
||
840 | if (fix_unintended_sword_strike) { |
||
841 | ctrl1_shift2 = 1; // prevent restoring control_shift2 to -1 in rest_ctrl_1() |
||
842 | } |
||
843 | #endif |
||
844 | if (Char.charid == charid_0_kid) { |
||
845 | play_sound(sound_19_draw_sword); // taking out the sword |
||
846 | offguard = 0; |
||
847 | } else if (Char.charid != charid_1_shadow) { |
||
848 | seq_id = seq_90_en_garde; // stand active |
||
849 | } |
||
850 | Char.sword = sword_2_drawn; |
||
851 | seqtbl_offset_char(seq_id); |
||
852 | } |
||
853 | |||
854 | // seg005:0C67 |
||
855 | void __pascal far control_with_sword() { |
||
856 | short distance; |
||
857 | if (Char.action < actions_2_hang_climb) { |
||
858 | if (get_tile_at_char() == tiles_11_loose || can_guard_see_kid >= 2) { |
||
859 | distance = char_opp_dist(); |
||
860 | if ((word)distance < (word)90) { |
||
861 | swordfight(); |
||
862 | return; |
||
863 | } else if (distance < 0) { |
||
864 | if ((word)distance < (word)-4) { |
||
865 | seqtbl_offset_char(seq_60_turn_with_sword); // turn with sword (after switching places) |
||
866 | return; |
||
867 | } else { |
||
868 | swordfight(); |
||
869 | return; |
||
870 | } |
||
871 | } |
||
872 | } /*else*/ { |
||
873 | if (Char.charid == charid_0_kid && Char.alive < 0) { |
||
874 | holding_sword = 0; |
||
875 | } |
||
876 | if (Char.charid < charid_2_guard) { |
||
877 | // frame 171: stand with sword |
||
878 | if (Char.frame == frame_171_stand_with_sword) { |
||
879 | Char.sword = sword_0_sheathed; |
||
880 | seqtbl_offset_char(seq_92_put_sword_away); // put sword away (Guard died) |
||
881 | } |
||
882 | } else { |
||
883 | swordfight(); |
||
884 | } |
||
885 | } |
||
886 | } |
||
887 | } |
||
888 | |||
889 | // seg005:0CDB |
||
890 | void __pascal far swordfight() { |
||
891 | short frame; |
||
892 | short seq_id; |
||
893 | short charid; |
||
894 | frame = Char.frame; |
||
895 | charid = Char.charid; |
||
896 | // frame 161: parry |
||
897 | if (frame == frame_161_parry && control_shift2 >= 0) { |
||
898 | seqtbl_offset_char(seq_57_back_with_sword); // back with sword (when parrying) |
||
899 | return; |
||
900 | } else if (control_shift2 < 0) { |
||
901 | if (charid == charid_0_kid) { |
||
902 | kid_sword_strike = 15; |
||
903 | } |
||
904 | sword_strike(); |
||
905 | if (control_shift2 == 1) return; |
||
906 | } |
||
907 | if (control_down < 0) { |
||
908 | if (frame == frame_158_stand_with_sword || frame == frame_170_stand_with_sword || frame == frame_171_stand_with_sword) { |
||
909 | control_down = 1; // disable automatic repeat |
||
910 | Char.sword = sword_0_sheathed; |
||
911 | if (charid == charid_0_kid) { |
||
912 | offguard = 1; |
||
913 | guard_refrac = 9; |
||
914 | holding_sword = 0; |
||
915 | seq_id = seq_93_put_sword_away_fast; // put sword away fast (down pressed) |
||
916 | } else if (charid == charid_1_shadow) { |
||
917 | seq_id = seq_92_put_sword_away; // put sword away |
||
918 | } else { |
||
919 | seq_id = seq_87_guard_become_inactive; // stand inactive (when Kid leaves sight) |
||
920 | } |
||
921 | seqtbl_offset_char(seq_id); |
||
922 | } |
||
923 | } else if (control_up < 0) { |
||
924 | parry(); |
||
925 | } else if (control_forward < 0) { |
||
926 | forward_with_sword(); |
||
927 | } else if (control_backward < 0) { |
||
928 | back_with_sword(); |
||
929 | } |
||
930 | } |
||
931 | |||
932 | // seg005:0DB0 |
||
933 | void __pascal far sword_strike() { |
||
934 | short frame; |
||
935 | short seq_id; |
||
936 | frame = Char.frame; |
||
937 | if (frame == frame_157_walk_with_sword || // walk with sword |
||
938 | frame == frame_158_stand_with_sword || // stand with sword |
||
939 | frame == frame_170_stand_with_sword || // stand with sword |
||
940 | frame == frame_171_stand_with_sword || // stand with sword |
||
941 | frame == frame_165_walk_with_sword // walk with sword |
||
942 | ) { |
||
943 | if (Char.charid == charid_0_kid) { |
||
944 | seq_id = seq_75_strike; // strike with sword (Kid) |
||
945 | } else { |
||
946 | seq_id = seq_58_guard_strike; // strike with sword (Guard) |
||
947 | } |
||
948 | } else if (frame == frame_150_parry || frame == frame_161_parry) { // parry |
||
949 | seq_id = seq_66_strike_after_parry; // strike with sword after parrying |
||
950 | } else { |
||
951 | return; |
||
952 | } |
||
953 | control_shift2 = 1; // disable automatic repeat |
||
954 | seqtbl_offset_char(seq_id); |
||
955 | } |
||
956 | |||
957 | // seg005:0E0F |
||
958 | void __pascal far parry() { |
||
959 | short opp_frame; |
||
960 | short char_frame; |
||
961 | short var_6; |
||
962 | short seq_id; |
||
963 | short char_charid; |
||
964 | char_frame = Char.frame; |
||
965 | opp_frame = Opp.frame; |
||
966 | char_charid = Char.charid; |
||
967 | seq_id = seq_62_parry; // defend (parry) with sword |
||
968 | var_6 = 0; |
||
969 | if ( |
||
970 | char_frame == frame_158_stand_with_sword || // stand with sword |
||
971 | char_frame == frame_170_stand_with_sword || // stand with sword |
||
972 | char_frame == frame_171_stand_with_sword || // stand with sword |
||
973 | char_frame == frame_168_back || // back? |
||
974 | char_frame == frame_165_walk_with_sword // walk with sword |
||
975 | ) { |
||
976 | if (char_opp_dist() >= 32 && char_charid != charid_0_kid) { |
||
977 | back_with_sword(); |
||
978 | return; |
||
979 | } else if (char_charid == charid_0_kid) { |
||
980 | if (opp_frame == frame_168_back) return; |
||
981 | if (opp_frame != frame_151_strike_1 && |
||
982 | opp_frame != frame_152_strike_2 && |
||
983 | opp_frame != frame_162_block_to_strike |
||
984 | ) { |
||
985 | if (opp_frame == frame_153_strike_3) { // strike |
||
986 | var_6 = 1; |
||
987 | } else |
||
988 | if (char_charid != charid_0_kid) { |
||
989 | back_with_sword(); |
||
990 | return; |
||
991 | } |
||
992 | } |
||
993 | } else { |
||
994 | if (opp_frame != frame_152_strike_2) return; |
||
995 | } |
||
996 | } else { |
||
997 | if (char_frame != frame_167_blocked) return; |
||
998 | seq_id = seq_61_parry_after_strike; // parry after striking with sword |
||
999 | } |
||
1000 | control_up = 1; // disable automatic repeat |
||
1001 | seqtbl_offset_char(seq_id); |
||
1002 | if (var_6) { |
||
1003 | play_seq(); |
||
1004 | } |
||
1005 | } |