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:3D1A |
||
| 24 | sbyte distance_mirror; |
||
| 25 | |||
| 26 | // seg003:0000 |
||
| 27 | void __pascal far init_game(int level) { |
||
| 28 | if(offscreen_surface) { |
||
| 29 | free_surface(offscreen_surface); // missing in original |
||
| 30 | offscreen_surface = NULL; |
||
| 31 | } |
||
| 32 | offscreen_surface = make_offscreen_buffer(&rect_top); |
||
| 33 | load_kid_sprite(); |
||
| 34 | text_time_remaining = 0; |
||
| 35 | text_time_total = 0; |
||
| 36 | is_show_time = 0; |
||
| 37 | checkpoint = 0; |
||
| 38 | upside_down = 0; // N.B. upside_down is also reset in set_start_pos() |
||
| 39 | resurrect_time = 0; |
||
| 40 | if (!dont_reset_time) { |
||
| 41 | rem_min = start_minutes_left; // 60 |
||
| 42 | rem_tick = start_ticks_left; // 719 |
||
| 43 | hitp_beg_lev = start_hitp; // 3 |
||
| 44 | } |
||
| 45 | need_level1_music = (level == 1); |
||
| 46 | play_level(level); |
||
| 47 | } |
||
| 48 | |||
| 49 | // seg003:005C |
||
| 50 | void __pascal far play_level(int level_number) { |
||
| 51 | cutscene_ptr_type cutscene_func; |
||
| 52 | #ifdef USE_COPYPROT |
||
| 53 | if (enable_copyprot && level_number == copyprot_level) { |
||
| 54 | level_number = 15; |
||
| 55 | } |
||
| 56 | #endif |
||
| 57 | for (;;) { |
||
| 58 | if (demo_mode && level_number > 2) { |
||
| 59 | start_level = -1; |
||
| 60 | need_quotes = 1; |
||
| 61 | start_game(); |
||
| 62 | } |
||
| 63 | if (level_number != current_level) { |
||
| 64 | if (level_number <0 || level_number >15) { |
||
| 65 | printf("Tried to load cutscene for level %d, not in 0..15\n", level_number); |
||
| 66 | quit(1); |
||
| 67 | } |
||
| 68 | cutscene_func = tbl_cutscenes[level_number]; |
||
| 69 | if (cutscene_func != NULL |
||
| 70 | |||
| 71 | #ifdef USE_REPLAY |
||
| 72 | && !(recording || replaying) |
||
| 73 | #endif |
||
| 74 | #ifdef USE_SCREENSHOT |
||
| 75 | && !want_auto_screenshot() |
||
| 76 | #endif |
||
| 77 | ) { |
||
| 78 | load_intro(level_number > 2, cutscene_func, 1); |
||
| 79 | } |
||
| 80 | } |
||
| 81 | if (level_number != current_level) { |
||
| 82 | load_lev_spr(level_number); |
||
| 83 | } |
||
| 84 | load_level(); |
||
| 85 | pos_guards(); |
||
| 86 | clear_coll_rooms(); |
||
| 87 | clear_saved_ctrl(); |
||
| 88 | drawn_room = 0; |
||
| 89 | mobs_count = 0; |
||
| 90 | trobs_count = 0; |
||
| 91 | next_sound = -1; |
||
| 92 | holding_sword = 0; |
||
| 93 | grab_timer = 0; |
||
| 94 | can_guard_see_kid = 0; |
||
| 95 | united_with_shadow = 0; |
||
| 96 | flash_time = 0; |
||
| 97 | leveldoor_open = 0; |
||
| 98 | demo_index = 0; |
||
| 99 | demo_time = 0; |
||
| 100 | guardhp_curr = 0; |
||
| 101 | hitp_delta = 0; |
||
| 102 | Guard.charid = charid_2_guard; |
||
| 103 | Guard.direction = dir_56_none; |
||
| 104 | do_startpos(); |
||
| 105 | have_sword = (level_number != 1); |
||
| 106 | find_start_level_door(); |
||
| 107 | // busy waiting? |
||
| 108 | while (check_sound_playing() && !do_paused()) idle(); |
||
| 109 | stop_sounds(); |
||
| 110 | #ifdef USE_REPLAY |
||
| 111 | if (replaying) replay_restore_level(); |
||
| 112 | if (skipping_replay) { |
||
| 113 | if (replay_seek_target == replay_seek_0_next_room || |
||
| 114 | replay_seek_target == replay_seek_1_next_level |
||
| 115 | ) |
||
| 116 | skipping_replay = 0; // resume replay from here |
||
| 117 | } |
||
| 118 | #endif |
||
| 119 | draw_level_first(); |
||
| 120 | show_copyprot(0); |
||
| 121 | level_number = play_level_2(); |
||
| 122 | // hacked... |
||
| 123 | #ifdef USE_COPYPROT |
||
| 124 | if (enable_copyprot && level_number == copyprot_level && !demo_mode) { |
||
| 125 | level_number = 15; |
||
| 126 | } else { |
||
| 127 | if (level_number == 16) { |
||
| 128 | level_number = copyprot_level; |
||
| 129 | copyprot_level = -1; |
||
| 130 | } |
||
| 131 | } |
||
| 132 | #endif |
||
| 133 | free_peels(); |
||
| 134 | } |
||
| 135 | } |
||
| 136 | |||
| 137 | // seg003:01A3 |
||
| 138 | void __pascal far do_startpos() { |
||
| 139 | word x; |
||
| 140 | // Special event: start at checkpoint |
||
| 141 | if (current_level == 3 && checkpoint) { |
||
| 142 | level.start_dir = dir_FF_left; |
||
| 143 | level.start_room = 2; |
||
| 144 | level.start_pos = 6; |
||
| 145 | // Special event: remove loose floor |
||
| 146 | get_tile(7, 4, 0); |
||
| 147 | curr_room_tiles[curr_tilepos] = tiles_0_empty; |
||
| 148 | } |
||
| 149 | next_room = Char.room = level.start_room; |
||
| 150 | x = level.start_pos; |
||
| 151 | Char.curr_col = x % 10; |
||
| 152 | Char.curr_row = x / 10; |
||
| 153 | Char.x = x_bump[Char.curr_col + 5] + 14; |
||
| 154 | // Start in the opposite direction (and turn into the correct one). |
||
| 155 | Char.direction = ~ level.start_dir; |
||
| 156 | if (seamless == 0) { |
||
| 157 | if (current_level != 0) { |
||
| 158 | x = hitp_beg_lev; |
||
| 159 | } else { |
||
| 160 | // HP on demo level |
||
| 161 | x = 4; |
||
| 162 | } |
||
| 163 | hitp_max = hitp_curr = x; |
||
| 164 | } |
||
| 165 | if (current_level == 1) { |
||
| 166 | // Special event: press button + falling entry |
||
| 167 | get_tile(5, 2, 0); |
||
| 168 | trigger_button(0, 0, -1); |
||
| 169 | seqtbl_offset_char(seq_7_fall); // fall |
||
| 170 | } else if (current_level == 13) { |
||
| 171 | // Special event: running entry |
||
| 172 | seqtbl_offset_char(seq_84_run); // run |
||
| 173 | } else { |
||
| 174 | seqtbl_offset_char(seq_5_turn); // turn |
||
| 175 | } |
||
| 176 | set_start_pos(); |
||
| 177 | } |
||
| 178 | |||
| 179 | // seg003:028A |
||
| 180 | void __pascal far set_start_pos() { |
||
| 181 | Char.y = y_land[Char.curr_row + 1]; |
||
| 182 | Char.alive = -1; |
||
| 183 | Char.charid = charid_0_kid; |
||
| 184 | is_screaming = 0; |
||
| 185 | knock = 0; |
||
| 186 | upside_down = start_upside_down; // 0 |
||
| 187 | is_feather_fall = 0; |
||
| 188 | Char.fall_y = 0; |
||
| 189 | Char.fall_x = 0; |
||
| 190 | offguard = 0; |
||
| 191 | Char.sword = sword_0_sheathed; |
||
| 192 | droppedout = 0; |
||
| 193 | play_seq(); |
||
| 194 | if (current_level == 7 && Char.room == 17) { |
||
| 195 | // Special event: level 7 falling entry |
||
| 196 | // level 7, room 17: show room below |
||
| 197 | goto_other_room(3); |
||
| 198 | } |
||
| 199 | savekid(); |
||
| 200 | } |
||
| 201 | |||
| 202 | // seg003:02E6 |
||
| 203 | void __pascal far find_start_level_door() { |
||
| 204 | short tilepos; |
||
| 205 | get_room_address(Kid.room); |
||
| 206 | for (tilepos = 0; tilepos < 30; ++tilepos) { |
||
| 207 | if ((curr_room_tiles[tilepos] & 0x1F) == tiles_16_level_door_left) { |
||
| 208 | start_level_door(Kid.room, tilepos); |
||
| 209 | } |
||
| 210 | } |
||
| 211 | } |
||
| 212 | |||
| 213 | // seg003:0326 |
||
| 214 | void __pascal far draw_level_first() { |
||
| 215 | screen_updates_suspended = 1; |
||
| 216 | |||
| 217 | next_room = Kid.room; |
||
| 218 | check_the_end(); |
||
| 219 | if (tbl_level_type[current_level]) { |
||
| 220 | gen_palace_wall_colors(); |
||
| 221 | } |
||
| 222 | draw_rect(&screen_rect, 0); |
||
| 223 | show_level(); |
||
| 224 | redraw_screen(0); |
||
| 225 | draw_kid_hp(hitp_curr, hitp_max); |
||
| 226 | |||
| 227 | screen_updates_suspended = 0; |
||
| 228 | request_screen_update(); |
||
| 229 | |||
| 230 | #ifdef USE_SCREENSHOT |
||
| 231 | auto_screenshot(); |
||
| 232 | #endif |
||
| 233 | |||
| 234 | // Busy waiting! |
||
| 235 | start_timer(timer_1, 5); |
||
| 236 | do_simple_wait(1); |
||
| 237 | } |
||
| 238 | |||
| 239 | // seg003:037B |
||
| 240 | void __pascal far redraw_screen(int drawing_different_room) { |
||
| 241 | //remove_flash(); |
||
| 242 | if (drawing_different_room) { |
||
| 243 | draw_rect(&rect_top, 0); |
||
| 244 | } |
||
| 245 | |||
| 246 | different_room = 0; |
||
| 247 | if (is_blind_mode) { |
||
| 248 | draw_rect(&rect_top, 0); |
||
| 249 | } else { |
||
| 250 | if (curr_guard_color) { |
||
| 251 | // Moved *before* drawings. |
||
| 252 | set_chtab_palette(chtab_addrs[id_chtab_5_guard], &guard_palettes[0x30 * curr_guard_color - 0x30], 0x10); |
||
| 253 | } |
||
| 254 | need_drects = 0; |
||
| 255 | redraw_room(); |
||
| 256 | #ifdef USE_LIGHTING |
||
| 257 | redraw_lighting(); |
||
| 258 | #endif |
||
| 259 | if (is_keyboard_mode) { |
||
| 260 | clear_kbd_buf(); |
||
| 261 | } |
||
| 262 | is_blind_mode = 1; |
||
| 263 | draw_tables(); |
||
| 264 | if (is_keyboard_mode) { |
||
| 265 | clear_kbd_buf(); |
||
| 266 | } |
||
| 267 | #ifdef USE_COPYPROT |
||
| 268 | if (current_level == 15) { |
||
| 269 | // letters on potions level |
||
| 270 | current_target_surface = offscreen_surface; |
||
| 271 | short var_2; |
||
| 272 | for (var_2 = 0; var_2 < 14; ++var_2) { |
||
| 273 | if (copyprot_room[var_2] == drawn_room) { |
||
| 274 | set_curr_pos((copyprot_tile[var_2] % 10 << 5) + 24, copyprot_tile[var_2] / 10 * 63 + 38); |
||
| 275 | draw_text_character(copyprot_letter[cplevel_entr[var_2]]); |
||
| 276 | } |
||
| 277 | } |
||
| 278 | current_target_surface = onscreen_surface_; |
||
| 279 | } |
||
| 280 | #endif |
||
| 281 | is_blind_mode = 0; |
||
| 282 | memset_near(table_counts, 0, sizeof(table_counts)); |
||
| 283 | draw_moving(); |
||
| 284 | draw_tables(); |
||
| 285 | if (is_keyboard_mode) { |
||
| 286 | clear_kbd_buf(); |
||
| 287 | } |
||
| 288 | need_drects = 1; |
||
| 289 | if (curr_guard_color) { |
||
| 290 | //set_pal_arr(0x80, 0x10, &guard_palettes[0x30 * curr_guard_color - 0x30], 1); |
||
| 291 | } |
||
| 292 | if (upside_down) { |
||
| 293 | flip_screen(offscreen_surface); |
||
| 294 | } |
||
| 295 | copy_screen_rect(&rect_top); |
||
| 296 | if (upside_down) { |
||
| 297 | flip_screen(offscreen_surface); |
||
| 298 | } |
||
| 299 | if (is_keyboard_mode) { |
||
| 300 | clear_kbd_buf(); |
||
| 301 | } |
||
| 302 | } |
||
| 303 | exit_room_timer = 2; |
||
| 304 | |||
| 305 | } |
||
| 306 | |||
| 307 | // seg003:04F8 |
||
| 308 | // Returns a level number: |
||
| 309 | // - The current level if it was restarted. |
||
| 310 | // - The next level if the level was completed. |
||
| 311 | int __pascal far play_level_2() { |
||
| 312 | while (1) { // main loop |
||
| 313 | #ifdef USE_QUICKSAVE |
||
| 314 | check_quick_op(); |
||
| 315 | #endif |
||
| 316 | |||
| 317 | #ifdef USE_REPLAY |
||
| 318 | if (need_replay_cycle) replay_cycle(); |
||
| 319 | #endif |
||
| 320 | |||
| 321 | if (Kid.sword == sword_2_drawn) { |
||
| 322 | // speed when fighting (smaller is faster) |
||
| 323 | start_timer(timer_1, 6); |
||
| 324 | } else { |
||
| 325 | // speed when not fighting (smaller is faster) |
||
| 326 | start_timer(timer_1, 5); |
||
| 327 | } |
||
| 328 | guardhp_delta = 0; |
||
| 329 | hitp_delta = 0; |
||
| 330 | timers(); |
||
| 331 | play_frame(); |
||
| 332 | |||
| 333 | #ifdef USE_REPLAY |
||
| 334 | // At the exact "end of level" frame, preserve the seed to ensure reproducibility, |
||
| 335 | // regardless of how long the sound is still playing *after* this frame (torch animation modifies the seed!) |
||
| 336 | if (keep_last_seed == 1) { |
||
| 337 | preserved_seed = random_seed; |
||
| 338 | keep_last_seed = -1; // disable repeat |
||
| 339 | } |
||
| 340 | #endif |
||
| 341 | |||
| 342 | if (is_restart_level) { |
||
| 343 | is_restart_level = 0; |
||
| 344 | return current_level; |
||
| 345 | } else { |
||
| 346 | if (next_level == current_level || check_sound_playing()) { |
||
| 347 | screen_updates_suspended = 1; |
||
| 348 | draw_game_frame(); |
||
| 349 | if (flash_if_hurt()) { |
||
| 350 | screen_updates_suspended = 0; |
||
| 351 | request_screen_update(); // display the flash |
||
| 352 | delay_ticks(2); // and add a short delay |
||
| 353 | } |
||
| 354 | screen_updates_suspended = 0; |
||
| 355 | remove_flash_if_hurt(); |
||
| 356 | |||
| 357 | #ifdef USE_DEBUG_CHEATS |
||
| 358 | if (debug_cheats_enabled && is_timer_displayed) { |
||
| 359 | char timer_text[16]; |
||
| 360 | if (rem_min < 0) { |
||
| 361 | snprintf(timer_text, 16, "%02d:%02d:%02d", -(rem_min + 1), (719 - rem_tick) / 12, (719 - rem_tick) % 12); |
||
| 362 | } else { |
||
| 363 | snprintf(timer_text, 16, "%02d:%02d:%02d", rem_min - 1, rem_tick / 12, rem_tick % 12); |
||
| 364 | } |
||
| 365 | screen_updates_suspended = 1; |
||
| 366 | draw_rect(&timer_rect, color_0_black); |
||
| 367 | show_text(&timer_rect, -1, -1, timer_text); |
||
| 368 | screen_updates_suspended = 0; |
||
| 369 | } |
||
| 370 | #endif |
||
| 371 | |||
| 372 | request_screen_update(); // request screen update manually |
||
| 373 | do_simple_wait(1); |
||
| 374 | } else { |
||
| 375 | stop_sounds(); |
||
| 376 | hitp_beg_lev = hitp_max; |
||
| 377 | checkpoint = 0; |
||
| 378 | |||
| 379 | #ifdef USE_REPLAY |
||
| 380 | if (keep_last_seed == -1) { |
||
| 381 | random_seed = preserved_seed; // Ensure reproducibility in the next level. |
||
| 382 | keep_last_seed = 0; |
||
| 383 | } |
||
| 384 | #endif |
||
| 385 | |||
| 386 | return next_level; |
||
| 387 | } |
||
| 388 | } |
||
| 389 | } |
||
| 390 | } |
||
| 391 | |||
| 392 | // seg003:0576 |
||
| 393 | void __pascal far redraw_at_char() { |
||
| 394 | short x_top_row; |
||
| 395 | short tile_col; |
||
| 396 | short tile_row; |
||
| 397 | short x_col_left; |
||
| 398 | short x_col_right; |
||
| 399 | if (Char.sword >= sword_2_drawn) { |
||
| 400 | // If char is holding sword, it makes redraw-area bigger. |
||
| 401 | if (Char.direction >= dir_0_right) { |
||
| 402 | if (++char_col_right > 9) char_col_right = 9; |
||
| 403 | // char_col_right = MIN(char_col_right + 1, 9); |
||
| 404 | } else { |
||
| 405 | if (--char_col_left < 0) char_col_left = 0; |
||
| 406 | // char_col_left = MAX(char_col_left - 1, 0); |
||
| 407 | } |
||
| 408 | } |
||
| 409 | if (Char.charid == charid_0_kid) { |
||
| 410 | x_top_row = MIN(char_top_row, prev_char_top_row); |
||
| 411 | x_col_right = MAX(char_col_right, prev_char_col_right); |
||
| 412 | x_col_left = MIN(char_col_left, prev_char_col_left); |
||
| 413 | } else { |
||
| 414 | x_top_row = char_top_row; |
||
| 415 | x_col_right = char_col_right; |
||
| 416 | x_col_left = char_col_left; |
||
| 417 | } |
||
| 418 | for (tile_row = x_top_row; tile_row <= char_bottom_row; ++tile_row) { |
||
| 419 | for (tile_col = x_col_left; tile_col <= x_col_right; ++tile_col) { |
||
| 420 | set_redraw_fore(get_tilepos(tile_col, tile_row), 1); |
||
| 421 | } |
||
| 422 | } |
||
| 423 | if (Char.charid == charid_0_kid) { |
||
| 424 | prev_char_top_row = char_top_row; |
||
| 425 | prev_char_col_right = char_col_right; |
||
| 426 | prev_char_col_left = char_col_left; |
||
| 427 | } |
||
| 428 | } |
||
| 429 | |||
| 430 | // seg003:0645 |
||
| 431 | void __pascal far redraw_at_char2() { |
||
| 432 | short char_action; |
||
| 433 | short char_frame; |
||
| 434 | void __pascal (* redraw_func)(short, byte); |
||
| 435 | char_action = Char.action; |
||
| 436 | char_frame = Char.frame; |
||
| 437 | redraw_func = &set_redraw2; |
||
| 438 | // frames 78..80: grab |
||
| 439 | if (char_frame < frame_78_jumphang || char_frame >= frame_80_jumphang) { |
||
| 440 | // frames 135..149: climb up |
||
| 441 | if (char_frame >= frame_137_climbing_3 && char_frame < frame_145_climbing_11) { |
||
| 442 | redraw_func = &set_redraw_floor_overlay; |
||
| 443 | } else { |
||
| 444 | // frames 102..106: fall |
||
| 445 | if (char_action != actions_2_hang_climb && char_action != actions_3_in_midair && |
||
| 446 | char_action != actions_4_in_freefall && char_action != actions_6_hang_straight && |
||
| 447 | (char_action != actions_5_bumped || char_frame < frame_102_start_fall_1 || char_frame > frame_106_fall)) { |
||
| 448 | return; |
||
| 449 | } |
||
| 450 | } |
||
| 451 | } |
||
| 452 | for (tile_col = char_col_right; tile_col >= char_col_left; --tile_col) { |
||
| 453 | if (char_action != 2) { |
||
| 454 | redraw_func(get_tilepos(tile_col, char_bottom_row), 1); |
||
| 455 | } |
||
| 456 | if (char_top_row != char_bottom_row) { |
||
| 457 | redraw_func(get_tilepos(tile_col, char_top_row), 1); |
||
| 458 | } |
||
| 459 | } |
||
| 460 | } |
||
| 461 | |||
| 462 | // seg003:0706 |
||
| 463 | void __pascal far check_knock() { |
||
| 464 | if (knock) { |
||
| 465 | do_knock(Char.room, Char.curr_row - (knock>0)); |
||
| 466 | knock = 0; |
||
| 467 | } |
||
| 468 | } |
||
| 469 | |||
| 470 | // seg003:0735 |
||
| 471 | void __pascal far timers() { |
||
| 472 | if (united_with_shadow > 0) { |
||
| 473 | --united_with_shadow; |
||
| 474 | if (united_with_shadow == 0) { |
||
| 475 | --united_with_shadow; |
||
| 476 | } |
||
| 477 | } |
||
| 478 | if (guard_notice_timer > 0) { |
||
| 479 | --guard_notice_timer; |
||
| 480 | } |
||
| 481 | if (resurrect_time > 0) { |
||
| 482 | --resurrect_time; |
||
| 483 | } |
||
| 484 | if (is_feather_fall && !check_sound_playing()) { |
||
| 485 | #ifdef USE_REPLAY |
||
| 486 | if (recording) special_move = MOVE_EFFECT_END; |
||
| 487 | if (!replaying) // during replays, feather effect gets cancelled in do_replay_move() |
||
| 488 | #endif |
||
| 489 | is_feather_fall = 0; |
||
| 490 | } |
||
| 491 | // Special event: mouse |
||
| 492 | if (current_level == 8 && Char.room == 16 && leveldoor_open) { |
||
| 493 | ++leveldoor_open; |
||
| 494 | // time before mouse comes: 150/12=12.5 seconds |
||
| 495 | if (leveldoor_open == 150) { |
||
| 496 | do_mouse(); |
||
| 497 | } |
||
| 498 | } |
||
| 499 | } |
||
| 500 | |||
| 501 | // seg003:0798 |
||
| 502 | void __pascal far check_mirror() { |
||
| 503 | word clip_top; |
||
| 504 | if (jumped_through_mirror == -1) { |
||
| 505 | jump_through_mirror(); |
||
| 506 | } else { |
||
| 507 | if (get_tile_at_char() == tiles_13_mirror) { |
||
| 508 | loadkid(); |
||
| 509 | load_frame(); |
||
| 510 | check_mirror_image(); |
||
| 511 | if (distance_mirror >= 0) { |
||
| 512 | load_frame_to_obj(); |
||
| 513 | reset_obj_clip(); |
||
| 514 | clip_top = y_clip[Char.curr_row + 1]; |
||
| 515 | if (clip_top < obj_y) { |
||
| 516 | obj_clip_top = clip_top; |
||
| 517 | obj_clip_left = (Char.curr_col << 5) + 9; |
||
| 518 | add_objtable(4); // mirror image |
||
| 519 | } |
||
| 520 | } |
||
| 521 | } |
||
| 522 | } |
||
| 523 | } |
||
| 524 | |||
| 525 | // seg003:080A |
||
| 526 | void __pascal far jump_through_mirror() { |
||
| 527 | loadkid(); |
||
| 528 | load_frame(); |
||
| 529 | check_mirror_image(); |
||
| 530 | jumped_through_mirror = 0; |
||
| 531 | Char.charid = charid_1_shadow; |
||
| 532 | play_sound(sound_45_jump_through_mirror); // jump through mirror |
||
| 533 | saveshad(); |
||
| 534 | guardhp_max = guardhp_curr = hitp_max; |
||
| 535 | hitp_curr = 1; |
||
| 536 | draw_kid_hp(1, hitp_max); |
||
| 537 | draw_guard_hp(guardhp_curr, guardhp_max); |
||
| 538 | } |
||
| 539 | |||
| 540 | // seg003:085B |
||
| 541 | void __pascal far check_mirror_image() { |
||
| 542 | short distance; |
||
| 543 | short xpos; |
||
| 544 | xpos = x_bump[Char.curr_col + 5] + 10; |
||
| 545 | distance = distance_to_edge_weight(); |
||
| 546 | if (Char.direction >= dir_0_right) { |
||
| 547 | distance = (~distance) + 14; |
||
| 548 | } |
||
| 549 | distance_mirror = distance - 2; |
||
| 550 | Char.x = (xpos << 1) - Char.x; |
||
| 551 | Char.direction = ~Char.direction; |
||
| 552 | } |
||
| 553 | |||
| 554 | // seg003:08AA |
||
| 555 | void __pascal far bump_into_opponent() { |
||
| 556 | // This is called from play_kid_frame, so char=Kid, Opp=Guard |
||
| 557 | short distance; |
||
| 558 | if (can_guard_see_kid >= 2 && |
||
| 559 | Char.sword == sword_0_sheathed && // Kid must not be in fighting pose |
||
| 560 | Opp.sword != sword_0_sheathed && // but Guard must |
||
| 561 | Opp.action < 2 && |
||
| 562 | Char.direction != Opp.direction // must be facing toward each other |
||
| 563 | ) { |
||
| 564 | distance = char_opp_dist(); |
||
| 565 | if (ABS(distance) <= 15) { |
||
| 566 | |||
| 567 | #ifdef FIX_PAINLESS_FALL_ON_GUARD |
||
| 568 | if (fix_painless_fall_on_guard) { |
||
| 569 | if (Char.fall_y >= 33) return; // don't bump; dead |
||
| 570 | else if (Char.fall_y >= 22) { // medium land |
||
| 571 | take_hp(1); |
||
| 572 | play_sound(sound_16_medium_land); |
||
| 573 | } |
||
| 574 | } |
||
| 575 | #endif |
||
| 576 | |||
| 577 | Char.y = y_land[Char.curr_row + 1]; |
||
| 578 | Char.fall_y = 0; |
||
| 579 | seqtbl_offset_char(seq_47_bump); // bump into opponent |
||
| 580 | play_seq(); |
||
| 581 | } |
||
| 582 | } |
||
| 583 | } |
||
| 584 | |||
| 585 | // seg003:0913 |
||
| 586 | void __pascal far pos_guards() { |
||
| 587 | short guard_tile; |
||
| 588 | short room1; |
||
| 589 | for (room1 = 0; room1 < 24; ++room1) { |
||
| 590 | guard_tile = level.guards_tile[room1]; |
||
| 591 | if (guard_tile < 30) { |
||
| 592 | level.guards_x[room1] = x_bump[guard_tile % 10 + 5] + 14; |
||
| 593 | level.guards_seq_hi[room1] = 0; |
||
| 594 | } |
||
| 595 | } |
||
| 596 | } |
||
| 597 | |||
| 598 | // seg003:0959 |
||
| 599 | void __pascal far check_can_guard_see_kid() { |
||
| 600 | /* |
||
| 601 | Possible results in can_guard_see_kid: |
||
| 602 | 0: Guard can't see Kid |
||
| 603 | 1: Guard can see Kid, but won't come |
||
| 604 | 2: Guard can see Kid, and will come |
||
| 605 | */ |
||
| 606 | short kid_frame; |
||
| 607 | short left_pos; |
||
| 608 | short temp; |
||
| 609 | short right_pos; |
||
| 610 | kid_frame = Kid.frame; |
||
| 611 | if (Guard.charid == charid_24_mouse) { |
||
| 612 | return; |
||
| 613 | } |
||
| 614 | if ((Guard.charid != charid_1_shadow || current_level == 12) && |
||
| 615 | // frames 217..228: going up on stairs |
||
| 616 | kid_frame != 0 && (kid_frame < frame_219_exit_stairs_3 || kid_frame >= 229) && |
||
| 617 | Guard.direction != dir_56_none && Kid.alive < 0 && Guard.alive < 0 && Kid.room == Guard.room && Kid.curr_row == Guard.curr_row |
||
| 618 | ) { |
||
| 619 | can_guard_see_kid = 2; |
||
| 620 | left_pos = x_bump[Kid.curr_col + 5] + 7; |
||
| 621 | right_pos = x_bump[Guard.curr_col + 5] + 7; |
||
| 622 | if (left_pos > right_pos) { |
||
| 623 | temp = left_pos; |
||
| 624 | left_pos = right_pos; |
||
| 625 | right_pos = temp; |
||
| 626 | } |
||
| 627 | // A chomper is on the left side of a tile, so it doesn't count. |
||
| 628 | if (get_tile_at_kid(left_pos) == tiles_18_chomper) { |
||
| 629 | left_pos += 14; |
||
| 630 | } |
||
| 631 | // A gate is on the right side of a tile, so it doesn't count. |
||
| 632 | if (get_tile_at_kid(right_pos) == tiles_4_gate) { |
||
| 633 | right_pos -= 14; |
||
| 634 | } |
||
| 635 | if (right_pos >= left_pos) { |
||
| 636 | while (left_pos <= right_pos) { |
||
| 637 | // Can't see through these tiles. |
||
| 638 | if (get_tile_at_kid(left_pos) == tiles_20_wall || |
||
| 639 | curr_tile2 == tiles_7_doortop_with_floor || |
||
| 640 | curr_tile2 == tiles_12_doortop |
||
| 641 | ) { |
||
| 642 | can_guard_see_kid = 0; return; |
||
| 643 | } |
||
| 644 | // Can see through these, but won't go through them. |
||
| 645 | if (curr_tile2 == tiles_11_loose || |
||
| 646 | curr_tile2 == tiles_18_chomper || |
||
| 647 | (curr_tile2 == tiles_4_gate && curr_room_modif[curr_tilepos] < 112) || |
||
| 648 | !tile_is_floor(curr_tile2) |
||
| 649 | ) { |
||
| 650 | can_guard_see_kid = 1; |
||
| 651 | } |
||
| 652 | left_pos += 14; |
||
| 653 | } |
||
| 654 | } |
||
| 655 | } else { |
||
| 656 | can_guard_see_kid = 0; |
||
| 657 | } |
||
| 658 | } |
||
| 659 | |||
| 660 | // seg003:0A99 |
||
| 661 | byte __pascal far get_tile_at_kid(int xpos) { |
||
| 662 | return get_tile(Kid.room, get_tile_div_mod_m7(xpos), Kid.curr_row); |
||
| 663 | } |
||
| 664 | |||
| 665 | // seg003:0ABA |
||
| 666 | void __pascal far do_mouse() { |
||
| 667 | loadkid(); |
||
| 668 | Char.charid = charid_24_mouse; |
||
| 669 | Char.x = 200; |
||
| 670 | Char.curr_row = 0; |
||
| 671 | Char.y = y_land[Char.curr_row + 1]; |
||
| 672 | Char.alive = -1; |
||
| 673 | Char.direction = dir_FF_left; |
||
| 674 | guardhp_curr = 1; |
||
| 675 | seqtbl_offset_char(seq_105_mouse_forward); // mouse forward |
||
| 676 | play_seq(); |
||
| 677 | saveshad(); |
||
| 678 | } |
||
| 679 | |||
| 680 | // seg003:0AFC |
||
| 681 | int __pascal far flash_if_hurt() { |
||
| 682 | if (flash_time != 0) { |
||
| 683 | do_flash_no_delay(flash_color); // don't add delay to the flash |
||
| 684 | return 1; |
||
| 685 | } else if (hitp_delta < 0) { |
||
| 686 | if (is_joyst_mode && enable_controller_rumble && sdl_haptic != NULL) { |
||
| 687 | SDL_HapticRumblePlay(sdl_haptic, 1.0, 100); // rumble at full strength for 100 milliseconds |
||
| 688 | } |
||
| 689 | do_flash_no_delay(color_12_brightred); // red |
||
| 690 | return 1; |
||
| 691 | } |
||
| 692 | return 0; // not flashed |
||
| 693 | } |
||
| 694 | |||
| 695 | // seg003:0B1A |
||
| 696 | void __pascal far remove_flash_if_hurt() { |
||
| 697 | if (flash_time != 0) { |
||
| 698 | --flash_time; |
||
| 699 | } else { |
||
| 700 | if (hitp_delta >= 0) return; |
||
| 701 | } |
||
| 702 | remove_flash(); |
||
| 703 | } |