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 | #include <setjmp.h> |
||
| 23 | #include <math.h> |
||
| 24 | |||
| 25 | // data:461E |
||
| 26 | dat_type * dathandle; |
||
| 27 | |||
| 28 | // data:4C08 |
||
| 29 | word need_redraw_because_flipped; |
||
| 30 | |||
| 31 | // seg000:0000 |
||
| 32 | void far pop_main() { |
||
| 33 | const char* temp = check_param("seed="); |
||
| 34 | if (temp != NULL) { |
||
| 35 | random_seed = atoi(temp+5); |
||
| 36 | seed_was_init = 1; |
||
| 37 | } |
||
| 38 | |||
| 39 | // debug only: check that the sequence table deobfuscation did not mess things up |
||
| 40 | #ifdef CHECK_SEQTABLE_MATCHES_ORIGINAL |
||
| 41 | check_seqtable_matches_original(); |
||
| 42 | #endif |
||
| 43 | |||
| 44 | load_global_options(); |
||
| 45 | |||
| 46 | #ifdef USE_REPLAY |
||
| 47 | if (g_argc > 1) { |
||
| 48 | char *filename = g_argv[1]; // file dragged on top of executable or double clicked |
||
| 49 | char *e = strrchr(filename, '.'); |
||
| 50 | if (e != NULL && strcasecmp(e, ".P1R") == 0) { // valid replay filename passed as first arg |
||
| 51 | start_with_replay_file(filename); |
||
| 52 | } |
||
| 53 | } |
||
| 54 | |||
| 55 | temp = check_param("validate"); |
||
| 56 | if (temp != NULL) { |
||
| 57 | is_validate_mode = 1; |
||
| 58 | start_with_replay_file(temp); |
||
| 59 | } |
||
| 60 | #endif |
||
| 61 | |||
| 62 | check_mod_param(); |
||
| 63 | load_mod_options(); |
||
| 64 | |||
| 65 | // CusPop option |
||
| 66 | is_blind_mode = start_in_blind_mode; |
||
| 67 | // Bug: with start_in_blind_mode enabled, moving objects are not displayed until blind mode is toggled off+on?? |
||
| 68 | |||
| 69 | apply_seqtbl_patches(); |
||
| 70 | |||
| 71 | char sprintf_temp[100]; |
||
| 72 | int i; |
||
| 73 | |||
| 74 | dathandle = open_dat("PRINCE.DAT", 0); |
||
| 75 | |||
| 76 | /*video_mode =*/ parse_grmode(); |
||
| 77 | |||
| 78 | init_timer(60); |
||
| 79 | parse_cmdline_sound(); |
||
| 80 | |||
| 81 | set_hc_pal(); |
||
| 82 | |||
| 83 | current_target_surface = rect_sthg(onscreen_surface_, &screen_rect); |
||
| 84 | show_loading(); |
||
| 85 | set_joy_mode(); |
||
| 86 | cheats_enabled = check_param("megahit") != NULL; |
||
| 87 | #ifdef USE_DEBUG_CHEATS |
||
| 88 | debug_cheats_enabled = check_param("debug") != NULL; |
||
| 89 | if (debug_cheats_enabled) cheats_enabled = 1; // param 'megahit' not necessary if 'debug' is used |
||
| 90 | #endif |
||
| 91 | draw_mode = check_param("draw") != NULL && cheats_enabled; |
||
| 92 | demo_mode = check_param("demo") != NULL; |
||
| 93 | |||
| 94 | init_copyprot_dialog(); |
||
| 95 | #ifdef USE_REPLAY |
||
| 96 | init_record_replay(); |
||
| 97 | #endif |
||
| 98 | |||
| 99 | if (cheats_enabled |
||
| 100 | #ifdef USE_REPLAY |
||
| 101 | || recording |
||
| 102 | #endif |
||
| 103 | ) { |
||
| 104 | for (i = 15; i >= 0; --i) { |
||
| 105 | snprintf(sprintf_temp, sizeof(sprintf_temp), "%d", i); |
||
| 106 | if (check_param(sprintf_temp)) { |
||
| 107 | start_level = i; |
||
| 108 | break; |
||
| 109 | } |
||
| 110 | } |
||
| 111 | } |
||
| 112 | #ifdef USE_SCREENSHOT |
||
| 113 | init_screenshot(); |
||
| 114 | #endif |
||
| 115 | |||
| 116 | init_game_main(); |
||
| 117 | } |
||
| 118 | |||
| 119 | byte* level_var_palettes; |
||
| 120 | |||
| 121 | // seg000:024F |
||
| 122 | void __pascal far init_game_main() { |
||
| 123 | doorlink1_ad = /*&*/level.doorlinks1; |
||
| 124 | doorlink2_ad = /*&*/level.doorlinks2; |
||
| 125 | prandom(1); |
||
| 126 | if (graphics_mode == gmMcgaVga) { |
||
| 127 | // Guard palettes |
||
| 128 | guard_palettes = (byte*) load_from_opendats_alloc(10, "bin", NULL, NULL); |
||
| 129 | // (blood, hurt flash) #E00030 = red |
||
| 130 | set_pal(12, 0x38, 0x00, 0x0C, 1); |
||
| 131 | // (palace wall pattern) #C09850 = light brown |
||
| 132 | set_pal( 6, 0x30, 0x26, 0x14, 0); |
||
| 133 | |||
| 134 | // Level color variations (1.3) |
||
| 135 | level_var_palettes = load_from_opendats_alloc(20, "bin", NULL, NULL); |
||
| 136 | } |
||
| 137 | // PRINCE.DAT: sword |
||
| 138 | chtab_addrs[id_chtab_0_sword] = load_sprites_from_file(700, 1<<2, 1); |
||
| 139 | // PRINCE.DAT: flame, sword on floor, potion |
||
| 140 | chtab_addrs[id_chtab_1_flameswordpotion] = load_sprites_from_file(150, 1<<3, 1); |
||
| 141 | close_dat(dathandle); |
||
| 142 | #ifdef USE_LIGHTING |
||
| 143 | init_lighting(); |
||
| 144 | #endif |
||
| 145 | load_sounds(0, 43); |
||
| 146 | load_opt_sounds(43, 56); //added |
||
| 147 | hof_read(); |
||
| 148 | show_splash(); // added |
||
| 149 | show_use_fixes_and_enhancements_prompt(); // added |
||
| 150 | start_game(); |
||
| 151 | } |
||
| 152 | |||
| 153 | |||
| 154 | // data:02C2 |
||
| 155 | word first_start = 1; |
||
| 156 | // data:4C38 |
||
| 157 | jmp_buf setjmp_buf; |
||
| 158 | // seg000:0358 |
||
| 159 | void __pascal far start_game() { |
||
| 160 | #ifdef USE_COPYPROT |
||
| 161 | word which_entry; |
||
| 162 | word pos; |
||
| 163 | word entry_used[40]; |
||
| 164 | byte letts_used[26]; |
||
| 165 | #endif |
||
| 166 | screen_updates_suspended = 0; |
||
| 167 | // Prevent filling of stack. |
||
| 168 | // start_game is called from many places to restart the game, for example: |
||
| 169 | // process_key, play_frame, draw_game_frame, play_level, control_kid, end_sequence, expired |
||
| 170 | if (first_start) { |
||
| 171 | first_start = 0; |
||
| 172 | setjmp(/*&*/setjmp_buf); |
||
| 173 | } else { |
||
| 174 | draw_rect(&screen_rect, 0); |
||
| 175 | show_quotes(); |
||
| 176 | clear_screen_and_sounds(); |
||
| 177 | longjmp(/*&*/setjmp_buf,-1); |
||
| 178 | } |
||
| 179 | release_title_images(); // added |
||
| 180 | free_optsnd_chtab(); // added |
||
| 181 | #ifdef USE_COPYPROT |
||
| 182 | copyprot_plac = prandom(13); |
||
| 183 | memset(&entry_used, 0, sizeof(entry_used)); |
||
| 184 | memset(&letts_used, 0, sizeof(letts_used)); |
||
| 185 | for (pos = 0; pos < 14; ++pos) { |
||
| 186 | do { |
||
| 187 | if (pos == copyprot_plac) { |
||
| 188 | which_entry = copyprot_idx = prandom(39); |
||
| 189 | } else { |
||
| 190 | which_entry = prandom(39); |
||
| 191 | } |
||
| 192 | } while (entry_used[which_entry] || letts_used[copyprot_letter[which_entry]-'A']); |
||
| 193 | cplevel_entr[pos] = which_entry; |
||
| 194 | entry_used[which_entry] = 1; |
||
| 195 | letts_used[copyprot_letter[which_entry]-'A'] = 1; |
||
| 196 | } |
||
| 197 | #endif |
||
| 198 | if (skip_title) { // CusPop option: skip the title sequence (level loads instantly) |
||
| 199 | int level_number = (start_level >= 0) ? start_level : first_level; |
||
| 200 | init_game(level_number); |
||
| 201 | return; |
||
| 202 | } |
||
| 203 | |||
| 204 | if (start_level < 0) { |
||
| 205 | show_title(); |
||
| 206 | } else { |
||
| 207 | init_game(start_level); |
||
| 208 | } |
||
| 209 | } |
||
| 210 | |||
| 211 | #ifdef USE_QUICKSAVE |
||
| 212 | // All these functions return true on success, false otherwise. |
||
| 213 | |||
| 214 | FILE* quick_fp; |
||
| 215 | |||
| 216 | int process_save(void* data, size_t data_size) { |
||
| 217 | return fwrite(data, data_size, 1, quick_fp) == 1; |
||
| 218 | } |
||
| 219 | |||
| 220 | int process_load(void* data, size_t data_size) { |
||
| 221 | return fread(data, data_size, 1, quick_fp) == 1; |
||
| 222 | } |
||
| 223 | |||
| 224 | typedef int process_func_type(void* data, size_t data_size); |
||
| 225 | |||
| 226 | int quick_process(process_func_type process_func) { |
||
| 227 | int ok = 1; |
||
| 228 | #define process(x) ok = ok && process_func(&(x), sizeof(x)) |
||
| 229 | // level |
||
| 230 | process(level); |
||
| 231 | process(checkpoint); |
||
| 232 | process(upside_down); |
||
| 233 | process(drawn_room); |
||
| 234 | process(current_level); |
||
| 235 | process(next_level); |
||
| 236 | process(mobs_count); |
||
| 237 | process(mobs); |
||
| 238 | process(trobs_count); |
||
| 239 | process(trobs); |
||
| 240 | process(leveldoor_open); |
||
| 241 | //process(exit_room_timer); |
||
| 242 | // kid |
||
| 243 | process(Kid); |
||
| 244 | process(hitp_curr); |
||
| 245 | process(hitp_max); |
||
| 246 | process(hitp_beg_lev); |
||
| 247 | process(grab_timer); |
||
| 248 | process(holding_sword); |
||
| 249 | process(united_with_shadow); |
||
| 250 | process(have_sword); |
||
| 251 | /*process(ctrl1_forward); |
||
| 252 | process(ctrl1_backward); |
||
| 253 | process(ctrl1_up); |
||
| 254 | process(ctrl1_down); |
||
| 255 | process(ctrl1_shift2);*/ |
||
| 256 | process(kid_sword_strike); |
||
| 257 | process(pickup_obj_type); |
||
| 258 | process(offguard); |
||
| 259 | // guard |
||
| 260 | process(Guard); |
||
| 261 | process(Char); |
||
| 262 | process(Opp); |
||
| 263 | process(guardhp_curr); |
||
| 264 | process(guardhp_max); |
||
| 265 | process(demo_index); |
||
| 266 | process(demo_time); |
||
| 267 | process(curr_guard_color); |
||
| 268 | process(guard_notice_timer); |
||
| 269 | process(guard_skill); |
||
| 270 | process(shadow_initialized); |
||
| 271 | process(guard_refrac); |
||
| 272 | process(justblocked); |
||
| 273 | process(droppedout); |
||
| 274 | // collision |
||
| 275 | process(curr_row_coll_room); |
||
| 276 | process(curr_row_coll_flags); |
||
| 277 | process(below_row_coll_room); |
||
| 278 | process(below_row_coll_flags); |
||
| 279 | process(above_row_coll_room); |
||
| 280 | process(above_row_coll_flags); |
||
| 281 | process(prev_collision_row); |
||
| 282 | // flash |
||
| 283 | process(flash_color); |
||
| 284 | process(flash_time); |
||
| 285 | // sounds |
||
| 286 | process(need_level1_music); |
||
| 287 | process(is_screaming); |
||
| 288 | process(is_feather_fall); |
||
| 289 | process(last_loose_sound); |
||
| 290 | //process(next_sound); |
||
| 291 | //process(current_sound); |
||
| 292 | // random |
||
| 293 | process(random_seed); |
||
| 294 | // remaining time |
||
| 295 | process(rem_min); |
||
| 296 | process(rem_tick); |
||
| 297 | // saved controls |
||
| 298 | process(control_x); |
||
| 299 | process(control_y); |
||
| 300 | process(control_shift); |
||
| 301 | process(control_forward); |
||
| 302 | process(control_backward); |
||
| 303 | process(control_up); |
||
| 304 | process(control_down); |
||
| 305 | process(control_shift2); |
||
| 306 | process(ctrl1_forward); |
||
| 307 | process(ctrl1_backward); |
||
| 308 | process(ctrl1_up); |
||
| 309 | process(ctrl1_down); |
||
| 310 | process(ctrl1_shift2); |
||
| 311 | #undef process |
||
| 312 | return ok; |
||
| 313 | } |
||
| 314 | |||
| 315 | const char* quick_file = "QUICKSAVE.SAV"; |
||
| 316 | const char quick_version[] = "V1.16b4 "; |
||
| 317 | char quick_control[] = "........"; |
||
| 318 | #ifdef OSX |
||
| 319 | #include <CoreServices/CoreServices.h> |
||
| 320 | #endif // OSX |
||
| 321 | |||
| 322 | const char* get_quick_path(char* custom_path_buffer, size_t max_len) { |
||
| 323 | if (!use_custom_levelset) { |
||
| 324 | #ifdef OSX |
||
| 325 | static char path[PATH_MAX] = ""; |
||
| 326 | if (path[0] == 0) |
||
| 327 | { |
||
| 328 | FSRef ref; |
||
| 329 | FSFindFolder (kUserDomain, kApplicationSupportFolderType, kCreateFolder, &ref); |
||
| 330 | FSRefMakePath (&ref, (UInt8 *) &path, PATH_MAX); |
||
| 331 | strcat (path, "/Prince of Persia"); |
||
| 332 | mkdir (path, 0755); |
||
| 333 | strcat (path, "/QUICKSAVE.SAV"); |
||
| 334 | } |
||
| 335 | return (path); |
||
| 336 | #else // !OSX |
||
| 337 | return quick_file; |
||
| 338 | #endif // OSX |
||
| 339 | } |
||
| 340 | // if playing a custom levelset, try to use the mod folder |
||
| 341 | snprintf(custom_path_buffer, max_len, "mods/%s/%s", levelset_name, quick_file /*QUICKSAVE.SAV*/ ); |
||
| 342 | return custom_path_buffer; |
||
| 343 | } |
||
| 344 | |||
| 345 | int quick_save() { |
||
| 346 | int ok = 0; |
||
| 347 | char custom_quick_path[POP_MAX_PATH]; |
||
| 348 | const char* path = get_quick_path(custom_quick_path, sizeof(custom_quick_path)); |
||
| 349 | quick_fp = fopen(path, "wb"); |
||
| 350 | if (quick_fp != NULL) { |
||
| 351 | process_save((void*) quick_version, COUNT(quick_version)); |
||
| 352 | ok = quick_process(process_save); |
||
| 353 | fclose(quick_fp); |
||
| 354 | quick_fp = NULL; |
||
| 355 | } |
||
| 356 | return ok; |
||
| 357 | } |
||
| 358 | |||
| 359 | void restore_room_after_quick_load() { |
||
| 360 | int temp1 = curr_guard_color; |
||
| 361 | int temp2 = next_level; |
||
| 362 | reset_level_unused_fields(false); |
||
| 363 | load_lev_spr(current_level); |
||
| 364 | curr_guard_color = temp1; |
||
| 365 | next_level = temp2; |
||
| 366 | |||
| 367 | //need_full_redraw = 1; |
||
| 368 | different_room = 1; |
||
| 369 | next_room = drawn_room; |
||
| 370 | load_room_links(); |
||
| 371 | //draw_level_first(); |
||
| 372 | //gen_palace_wall_colors(); |
||
| 373 | is_guard_notice = 0; // prevent guard turning around immediately |
||
| 374 | draw_game_frame(); // for falling |
||
| 375 | //redraw_screen(1); // for room_L |
||
| 376 | |||
| 377 | hitp_delta = guardhp_delta = 1; // force HP redraw |
||
| 378 | draw_hp(); |
||
| 379 | loadkid_and_opp(); |
||
| 380 | // Get rid of "press button" message if kid was dead before quickload. |
||
| 381 | text_time_total = text_time_remaining = 0; |
||
| 382 | //next_sound = current_sound = -1; |
||
| 383 | exit_room_timer = 0; |
||
| 384 | } |
||
| 385 | |||
| 386 | int quick_load() { |
||
| 387 | int ok = 0; |
||
| 388 | char custom_quick_path[POP_MAX_PATH]; |
||
| 389 | const char* path = get_quick_path(custom_quick_path, sizeof(custom_quick_path)); |
||
| 390 | quick_fp = fopen(path, "rb"); |
||
| 391 | if (quick_fp != NULL) { |
||
| 392 | // check quicksave version is compatible |
||
| 393 | process_load(quick_control, COUNT(quick_control)); |
||
| 394 | if (strcmp(quick_control, quick_version) != 0) { |
||
| 395 | fclose(quick_fp); |
||
| 396 | quick_fp = NULL; |
||
| 397 | return 0; |
||
| 398 | } |
||
| 399 | |||
| 400 | stop_sounds(); |
||
| 401 | start_timer(timer_0, 5); // briefly display a black screen as a visual cue |
||
| 402 | draw_rect(&screen_rect, 0); |
||
| 403 | screen_updates_suspended = 0; |
||
| 404 | request_screen_update(); |
||
| 405 | screen_updates_suspended = 1; |
||
| 406 | short old_rem_min = rem_min; |
||
| 407 | word old_rem_tick = rem_tick; |
||
| 408 | |||
| 409 | ok = quick_process(process_load); |
||
| 410 | fclose(quick_fp); |
||
| 411 | quick_fp = NULL; |
||
| 412 | |||
| 413 | restore_room_after_quick_load(); |
||
| 414 | |||
| 415 | do_wait(timer_0); |
||
| 416 | screen_updates_suspended = 0; |
||
| 417 | request_screen_update(); |
||
| 418 | |||
| 419 | #ifdef USE_QUICKLOAD_PENALTY |
||
| 420 | // Subtract one minute from the remaining time (if it is above 5 minutes) |
||
| 421 | if (enable_quicksave_penalty && |
||
| 422 | // don't apply the penalty after time has already stopped! |
||
| 423 | (current_level < 13 || (current_level == 13 && leveldoor_open < 2)) |
||
| 424 | ) { |
||
| 425 | int ticks_elapsed = 720 * (rem_min - old_rem_min) + (rem_tick - old_rem_tick); |
||
| 426 | // don't restore time at all if the elapsed time is between 0 and 1 minutes |
||
| 427 | if (ticks_elapsed > 0 && ticks_elapsed < 720) { |
||
| 428 | rem_min = old_rem_min; |
||
| 429 | rem_tick = old_rem_tick; |
||
| 430 | } |
||
| 431 | else { |
||
| 432 | if (rem_min == 6) rem_tick = 719; // crop to "5 minutes" exactly, if hitting the threshold in <1 minute |
||
| 433 | if (rem_min > 5 /*be lenient, not much time left*/ || rem_min < 0 /*time runs 'forward' if < 0*/) { |
||
| 434 | --rem_min; |
||
| 435 | } |
||
| 436 | } |
||
| 437 | |||
| 438 | } |
||
| 439 | #endif |
||
| 440 | } |
||
| 441 | return ok; |
||
| 442 | } |
||
| 443 | |||
| 444 | int need_quick_save = 0; |
||
| 445 | int need_quick_load = 0; |
||
| 446 | |||
| 447 | void check_quick_op() { |
||
| 448 | if (!enable_quicksave) return; |
||
| 449 | if (need_quick_save) { |
||
| 450 | if (!is_feather_fall && quick_save()) { |
||
| 451 | display_text_bottom("GAME SAVED"); |
||
| 452 | } else { |
||
| 453 | display_text_bottom("UNABLE TO SAVE GAME"); |
||
| 454 | } |
||
| 455 | need_quick_save = 0; |
||
| 456 | text_time_total = 24; |
||
| 457 | text_time_remaining = 24; |
||
| 458 | } |
||
| 459 | if (need_quick_load) { |
||
| 460 | #ifdef USE_REPLAY |
||
| 461 | if (recording) { |
||
| 462 | stop_recording(); // quickloading would mess up the replay! |
||
| 463 | } |
||
| 464 | #endif |
||
| 465 | if (quick_load()) { |
||
| 466 | display_text_bottom("GAME LOADED"); |
||
| 467 | } else { |
||
| 468 | display_text_bottom("NO SAVEGAME AVAILABLE"); |
||
| 469 | } |
||
| 470 | need_quick_load = 0; |
||
| 471 | text_time_total = 24; |
||
| 472 | text_time_remaining = 24; |
||
| 473 | } |
||
| 474 | } |
||
| 475 | |||
| 476 | |||
| 477 | #endif // USE_QUICKSAVE |
||
| 478 | |||
| 479 | Uint32 temp_shift_release_callback(Uint32 interval, void *param) { |
||
| 480 | const Uint8* state = SDL_GetKeyboardState(NULL); |
||
| 481 | if (state[SDL_SCANCODE_LSHIFT]) key_states[SDL_SCANCODE_LSHIFT] = 1; |
||
| 482 | if (state[SDL_SCANCODE_RSHIFT]) key_states[SDL_SCANCODE_RSHIFT] = 1; |
||
| 483 | return 0; // causes the timer to be removed |
||
| 484 | } |
||
| 485 | |||
| 486 | // seg000:04CD |
||
| 487 | int __pascal far process_key() { |
||
| 488 | char sprintf_temp[80]; |
||
| 489 | int key; |
||
| 490 | const char* answer_text = NULL; |
||
| 491 | word need_show_text; |
||
| 492 | need_show_text = 0; |
||
| 493 | key = key_test_quit(); |
||
| 494 | |||
| 495 | if (start_level < 0) { |
||
| 496 | if (key || control_shift) { |
||
| 497 | #ifdef USE_QUICKSAVE |
||
| 498 | if (key == SDL_SCANCODE_F9) need_quick_load = 1; |
||
| 499 | #endif |
||
| 500 | #ifdef USE_REPLAY |
||
| 501 | if (key == SDL_SCANCODE_TAB || need_start_replay) { |
||
| 502 | start_replay(); |
||
| 503 | } |
||
| 504 | else if (key == (SDL_SCANCODE_TAB | WITH_CTRL)) { |
||
| 505 | start_level = first_level; |
||
| 506 | start_recording(); |
||
| 507 | } else |
||
| 508 | #endif |
||
| 509 | if (key == (SDL_SCANCODE_L | WITH_CTRL)) { // ctrl-L |
||
| 510 | if (!load_game()) return 0; |
||
| 511 | } else { |
||
| 512 | start_level = first_level; // 1 |
||
| 513 | } |
||
| 514 | draw_rect(&screen_rect, 0); |
||
| 515 | #ifdef USE_FADE |
||
| 516 | if (is_global_fading) { |
||
| 517 | fade_palette_buffer->proc_restore_free(fade_palette_buffer); |
||
| 518 | is_global_fading = 0; |
||
| 519 | } |
||
| 520 | #endif |
||
| 521 | start_game(); |
||
| 522 | } |
||
| 523 | } |
||
| 524 | // If the Kid died, enter or shift will restart the level. |
||
| 525 | if (rem_min != 0 && Kid.alive > 6 && (control_shift || key == SDL_SCANCODE_RETURN)) { |
||
| 526 | key = SDL_SCANCODE_A | WITH_CTRL; // ctrl-a |
||
| 527 | } |
||
| 528 | #ifdef USE_REPLAY |
||
| 529 | if (recording) key_press_while_recording(&key); |
||
| 530 | else if (replaying) key_press_while_replaying(&key); |
||
| 531 | #endif |
||
| 532 | if (key == 0) return 0; |
||
| 533 | if (is_keyboard_mode) clear_kbd_buf(); |
||
| 534 | |||
| 535 | if (!cheats_enabled) // Pierre-Marie Baty -- allow typing 'megahit' in game to enable cheats |
||
| 536 | { |
||
| 537 | static const int megahit_chars[] = { SDL_SCANCODE_M, SDL_SCANCODE_E, SDL_SCANCODE_G, SDL_SCANCODE_A, SDL_SCANCODE_H, SDL_SCANCODE_I, SDL_SCANCODE_T }; |
||
| 538 | static int megahit_index = 0; |
||
| 539 | megahit_index = (key == megahit_chars[megahit_index] ? megahit_index + 1 : 0); |
||
| 540 | if (megahit_index == sizeof (megahit_chars) / sizeof (megahit_chars[0])) |
||
| 541 | { |
||
| 542 | answer_text = "CHEATS ENABLED"; |
||
| 543 | need_show_text = 1; |
||
| 544 | cheats_enabled = 1; |
||
| 545 | } |
||
| 546 | } |
||
| 547 | |||
| 548 | switch(key) { |
||
| 549 | case SDL_SCANCODE_ESCAPE: // esc |
||
| 550 | case SDL_SCANCODE_ESCAPE | WITH_SHIFT: // allow pause while grabbing |
||
| 551 | is_paused = 1; |
||
| 552 | break; |
||
| 553 | case SDL_SCANCODE_SPACE: // space |
||
| 554 | is_show_time = 1; |
||
| 555 | break; |
||
| 556 | case SDL_SCANCODE_A | WITH_CTRL: // ctrl-a |
||
| 557 | if (current_level != 15) { |
||
| 558 | stop_sounds(); |
||
| 559 | is_restart_level = 1; |
||
| 560 | } |
||
| 561 | break; |
||
| 562 | case SDL_SCANCODE_G | WITH_CTRL: // ctrl-g |
||
| 563 | // CusPoP: first and last level where saving is allowed |
||
| 564 | // if (current_level > 2 && current_level < 14) { // original |
||
| 565 | if (current_level >= saving_allowed_first_level && current_level <= saving_allowed_last_level) { |
||
| 566 | save_game(); |
||
| 567 | } |
||
| 568 | break; |
||
| 569 | case SDL_SCANCODE_J | WITH_CTRL: // ctrl-j |
||
| 570 | if ((sound_flags & sfDigi) && sound_mode == smTandy) { |
||
| 571 | answer_text = "JOYSTICK UNAVAILABLE"; |
||
| 572 | } else { |
||
| 573 | if (set_joy_mode()) { |
||
| 574 | answer_text = "JOYSTICK MODE"; |
||
| 575 | } else { |
||
| 576 | answer_text = "JOYSTICK NOT FOUND"; |
||
| 577 | } |
||
| 578 | } |
||
| 579 | need_show_text = 1; |
||
| 580 | break; |
||
| 581 | case SDL_SCANCODE_K | WITH_CTRL: // ctrl-k |
||
| 582 | answer_text = "KEYBOARD MODE"; |
||
| 583 | is_joyst_mode = 0; |
||
| 584 | is_keyboard_mode = 1; |
||
| 585 | need_show_text = 1; |
||
| 586 | break; |
||
| 587 | case SDL_SCANCODE_R | WITH_CTRL: // ctrl-r |
||
| 588 | start_level = -1; |
||
| 589 | start_game(); |
||
| 590 | break; |
||
| 591 | case SDL_SCANCODE_S | WITH_CTRL: // ctrl-s |
||
| 592 | turn_sound_on_off((!is_sound_on) * 15); |
||
| 593 | answer_text = "SOUND OFF"; |
||
| 594 | if (is_sound_on) { |
||
| 595 | answer_text = "SOUND ON"; |
||
| 596 | } |
||
| 597 | // |
||
| 598 | need_show_text = 1; |
||
| 599 | break; |
||
| 600 | case SDL_SCANCODE_V | WITH_CTRL: // ctrl-v |
||
| 601 | //answer_text = "PRINCE OF PERSIA V1.0"; |
||
| 602 | snprintf(sprintf_temp, sizeof(sprintf_temp), "Prince of Persia v%s-SDL\n", SDLPOP_VERSION); |
||
| 603 | answer_text = sprintf_temp; |
||
| 604 | need_show_text = 1; |
||
| 605 | break; |
||
| 606 | case SDL_SCANCODE_L | WITH_SHIFT: // shift-l |
||
| 607 | if (current_level < shift_L_allowed_until_level /* 4 */ || cheats_enabled) { |
||
| 608 | // if shift is not released within the delay, the cutscene is skipped |
||
| 609 | Uint32 delay = 250; |
||
| 610 | key_states[SDL_SCANCODE_LSHIFT] = 0; |
||
| 611 | key_states[SDL_SCANCODE_RSHIFT] = 0; |
||
| 612 | SDL_TimerID timer; |
||
| 613 | timer = SDL_AddTimer(delay, temp_shift_release_callback, NULL); |
||
| 614 | if (timer == 0) { |
||
| 615 | sdlperror("SDL_AddTimer"); |
||
| 616 | quit(1); |
||
| 617 | } |
||
| 618 | if (current_level == 14) { |
||
| 619 | next_level = 1; |
||
| 620 | } else { |
||
| 621 | if (current_level == 15 && cheats_enabled) { |
||
| 622 | #ifdef USE_COPYPROT |
||
| 623 | if (enable_copyprot) { |
||
| 624 | next_level = copyprot_level; |
||
| 625 | copyprot_level = -1; |
||
| 626 | } |
||
| 627 | #endif |
||
| 628 | } else { |
||
| 629 | next_level = current_level + 1; |
||
| 630 | if (!cheats_enabled && rem_min > shift_L_reduced_minutes /* 15 */) { |
||
| 631 | rem_min = shift_L_reduced_minutes; // 15 |
||
| 632 | rem_tick = shift_L_reduced_ticks; // 719 |
||
| 633 | } |
||
| 634 | } |
||
| 635 | } |
||
| 636 | stop_sounds(); |
||
| 637 | } |
||
| 638 | break; |
||
| 639 | #ifdef USE_QUICKSAVE |
||
| 640 | case SDL_SCANCODE_F6: |
||
| 641 | case SDL_SCANCODE_F6 | WITH_SHIFT: |
||
| 642 | if (Kid.alive < 0) need_quick_save = 1; |
||
| 643 | break; |
||
| 644 | case SDL_SCANCODE_F9: |
||
| 645 | case SDL_SCANCODE_F9 | WITH_SHIFT: |
||
| 646 | need_quick_load = 1; |
||
| 647 | break; |
||
| 648 | #ifdef USE_REPLAY |
||
| 649 | case SDL_SCANCODE_TAB | WITH_CTRL: |
||
| 650 | case SDL_SCANCODE_TAB | WITH_CTRL | WITH_SHIFT: |
||
| 651 | if (recording) { // finished recording |
||
| 652 | stop_recording(); |
||
| 653 | } |
||
| 654 | else { // should start recording |
||
| 655 | start_recording(); |
||
| 656 | } |
||
| 657 | break; |
||
| 658 | #endif // USE_REPLAY |
||
| 659 | #endif // USE_QUICKSAVE |
||
| 660 | } |
||
| 661 | if (cheats_enabled) { |
||
| 662 | switch (key) { |
||
| 663 | case SDL_SCANCODE_C: // c |
||
| 664 | snprintf(sprintf_temp, sizeof(sprintf_temp), "S%d L%d R%d A%d B%d", drawn_room, room_L, room_R, room_A, room_B); |
||
| 665 | answer_text = /*&*/sprintf_temp; |
||
| 666 | need_show_text = 1; |
||
| 667 | break; |
||
| 668 | case SDL_SCANCODE_C | WITH_SHIFT: // shift-c |
||
| 669 | snprintf(sprintf_temp, sizeof(sprintf_temp), "AL%d AR%d BL%d BR%d", room_AL, room_AR, room_BL, room_BR); |
||
| 670 | answer_text = /*&*/sprintf_temp; |
||
| 671 | need_show_text = 1; |
||
| 672 | break; |
||
| 673 | case SDL_SCANCODE_MINUS: |
||
| 674 | case SDL_SCANCODE_KP_MINUS: // '-' --> subtract time cheat |
||
| 675 | if (rem_min > 1) --rem_min; |
||
| 676 | |||
| 677 | #ifdef ALLOW_INFINITE_TIME |
||
| 678 | else if (rem_min < -1) ++rem_min; // if negative/infinite, time runs 'forward' |
||
| 679 | else if (rem_min == -1) rem_tick = 720; // resets the timer to 00:00:00 |
||
| 680 | #endif |
||
| 681 | |||
| 682 | text_time_total = 0; |
||
| 683 | text_time_remaining = 0; |
||
| 684 | is_show_time = 1; |
||
| 685 | break; |
||
| 686 | case SDL_SCANCODE_EQUALS | WITH_SHIFT: // '+' |
||
| 687 | case SDL_SCANCODE_KP_PLUS: // '+' --> add time cheat |
||
| 688 | |||
| 689 | #ifdef ALLOW_INFINITE_TIME |
||
| 690 | if (rem_min < 0) { // if negative/infinite, time runs 'forward' |
||
| 691 | if (rem_min > INT16_MIN) --rem_min; |
||
| 692 | } |
||
| 693 | else ++rem_min; |
||
| 694 | #else |
||
| 695 | ++rem_min; |
||
| 696 | #endif |
||
| 697 | |||
| 698 | text_time_total = 0; |
||
| 699 | text_time_remaining = 0; |
||
| 700 | is_show_time = 1; |
||
| 701 | break; |
||
| 702 | case SDL_SCANCODE_R: // R --> revive kid cheat |
||
| 703 | if (Kid.alive > 0) { |
||
| 704 | resurrect_time = 20; |
||
| 705 | Kid.alive = -1; |
||
| 706 | erase_bottom_text(1); |
||
| 707 | } |
||
| 708 | break; |
||
| 709 | case SDL_SCANCODE_K: // K --> kill guard cheat |
||
| 710 | guardhp_delta = -guardhp_curr; |
||
| 711 | Guard.alive = 0; |
||
| 712 | break; |
||
| 713 | case SDL_SCANCODE_I | WITH_SHIFT: // shift+I --> invert cheat |
||
| 714 | toggle_upside(); |
||
| 715 | break; |
||
| 716 | case SDL_SCANCODE_W | WITH_SHIFT: // shift+W --> feather fall cheat |
||
| 717 | feather_fall(); |
||
| 718 | break; |
||
| 719 | case SDL_SCANCODE_H: // H --> view room to the left |
||
| 720 | draw_guard_hp(0, 10); |
||
| 721 | next_room = room_L; |
||
| 722 | break; |
||
| 723 | case SDL_SCANCODE_J: // J --> view room to the right |
||
| 724 | draw_guard_hp(0, 10); |
||
| 725 | next_room = room_R; |
||
| 726 | break; |
||
| 727 | case SDL_SCANCODE_U: // U --> view room above |
||
| 728 | draw_guard_hp(0, 10); |
||
| 729 | next_room = room_A; |
||
| 730 | break; |
||
| 731 | case SDL_SCANCODE_N: // N --> view room below |
||
| 732 | draw_guard_hp(0, 10); |
||
| 733 | next_room = room_B; |
||
| 734 | break; |
||
| 735 | case SDL_SCANCODE_B | WITH_SHIFT: // shift-b |
||
| 736 | is_blind_mode = !is_blind_mode; |
||
| 737 | if (is_blind_mode) { |
||
| 738 | draw_rect(&rect_top, 0); |
||
| 739 | } else { |
||
| 740 | need_full_redraw = 1; |
||
| 741 | } |
||
| 742 | break; |
||
| 743 | case SDL_SCANCODE_S | WITH_SHIFT: // shift-s |
||
| 744 | if (hitp_curr != hitp_max) { |
||
| 745 | play_sound(sound_33_small_potion); // small potion (cheat) |
||
| 746 | hitp_delta = 1; |
||
| 747 | flash_color = 4; // red |
||
| 748 | flash_time = 2; |
||
| 749 | } |
||
| 750 | break; |
||
| 751 | case SDL_SCANCODE_T | WITH_SHIFT: // shift-t |
||
| 752 | play_sound(sound_30_big_potion); // big potion (cheat) |
||
| 753 | flash_color = 4; // red |
||
| 754 | flash_time = 4; |
||
| 755 | add_life(); |
||
| 756 | break; |
||
| 757 | #ifdef USE_DEBUG_CHEATS |
||
| 758 | case SDL_SCANCODE_T: |
||
| 759 | is_timer_displayed = 1 - is_timer_displayed; // toggle |
||
| 760 | if (!is_timer_displayed) { |
||
| 761 | need_full_redraw = 1; |
||
| 762 | } |
||
| 763 | break; |
||
| 764 | #endif |
||
| 765 | } |
||
| 766 | } |
||
| 767 | |||
| 768 | if (need_show_text) { |
||
| 769 | display_text_bottom(answer_text); |
||
| 770 | text_time_total = 24; |
||
| 771 | text_time_remaining = 24; |
||
| 772 | } |
||
| 773 | return 1; |
||
| 774 | } |
||
| 775 | |||
| 776 | // seg000:08EB |
||
| 777 | void __pascal far play_frame() { |
||
| 778 | do_mobs(); |
||
| 779 | process_trobs(); |
||
| 780 | check_skel(); |
||
| 781 | check_can_guard_see_kid(); |
||
| 782 | // if level is restarted, return immediately |
||
| 783 | if (play_kid_frame()) return; |
||
| 784 | play_guard_frame(); |
||
| 785 | if (0 == resurrect_time) { |
||
| 786 | check_sword_hurting(); |
||
| 787 | check_sword_hurt(); |
||
| 788 | } |
||
| 789 | check_sword_vs_sword(); |
||
| 790 | do_delta_hp(); |
||
| 791 | exit_room(); |
||
| 792 | check_the_end(); |
||
| 793 | check_guard_fallout(); |
||
| 794 | if (current_level == 0) { |
||
| 795 | // Special event: level 0 running exit |
||
| 796 | if (Kid.room == 24) { |
||
| 797 | draw_rect(&screen_rect, 0); |
||
| 798 | start_level = -1; |
||
| 799 | need_quotes = 1; |
||
| 800 | start_game(); |
||
| 801 | } |
||
| 802 | } else if(current_level == 6) { |
||
| 803 | // Special event: level 6 falling exit |
||
| 804 | if (roomleave_result == -2) { |
||
| 805 | Kid.y = -1; |
||
| 806 | stop_sounds(); |
||
| 807 | ++next_level; |
||
| 808 | } |
||
| 809 | } else if(current_level == 12) { |
||
| 810 | // Special event: level 12 running exit |
||
| 811 | if (Kid.room == 23) { |
||
| 812 | ++next_level; |
||
| 813 | // Sounds must be stopped, because play_level_2() checks next_level only if there are no sounds playing. |
||
| 814 | stop_sounds(); |
||
| 815 | seamless = 1; |
||
| 816 | } |
||
| 817 | } |
||
| 818 | show_time(); |
||
| 819 | // expiring doesn't count on Jaffar/princess level |
||
| 820 | if (current_level < 13 && rem_min == 0) { |
||
| 821 | expired(); |
||
| 822 | } |
||
| 823 | } |
||
| 824 | |||
| 825 | // seg000:09B6 |
||
| 826 | void __pascal far draw_game_frame() { |
||
| 827 | short var_2; |
||
| 828 | if (need_full_redraw) { |
||
| 829 | redraw_screen(0); |
||
| 830 | need_full_redraw = 0; |
||
| 831 | } else { |
||
| 832 | if (different_room) { |
||
| 833 | drawn_room = next_room; |
||
| 834 | if (tbl_level_type[current_level]) { |
||
| 835 | gen_palace_wall_colors(); |
||
| 836 | } |
||
| 837 | redraw_screen(1); |
||
| 838 | } else { |
||
| 839 | if (need_redraw_because_flipped) { |
||
| 840 | need_redraw_because_flipped = 0; |
||
| 841 | redraw_screen(0); |
||
| 842 | } else { |
||
| 843 | memset_near(&table_counts, 0, sizeof(table_counts)); |
||
| 844 | draw_moving(); |
||
| 845 | draw_tables(); |
||
| 846 | if (is_blind_mode) { |
||
| 847 | draw_rect(&rect_top, 0); |
||
| 848 | } |
||
| 849 | if (upside_down) { |
||
| 850 | flip_screen(offscreen_surface); |
||
| 851 | } |
||
| 852 | while (drects_count--) { |
||
| 853 | copy_screen_rect(&drects[drects_count]); |
||
| 854 | } |
||
| 855 | if (upside_down) { |
||
| 856 | flip_screen(offscreen_surface); |
||
| 857 | } |
||
| 858 | drects_count = 0; |
||
| 859 | } |
||
| 860 | } |
||
| 861 | } |
||
| 862 | |||
| 863 | play_next_sound(); |
||
| 864 | // Note: texts are identified by their total time! |
||
| 865 | if (text_time_remaining == 1) { |
||
| 866 | // If the text's is about to expire: |
||
| 867 | if (text_time_total == 36 || text_time_total == 288) { |
||
| 868 | // 36: died on demo/potions level |
||
| 869 | // 288: press button to continue |
||
| 870 | // In this case, restart the game. |
||
| 871 | start_level = -1; |
||
| 872 | need_quotes = 1; |
||
| 873 | |||
| 874 | #ifdef USE_REPLAY |
||
| 875 | if (recording) stop_recording(); |
||
| 876 | if (replaying) end_replay(); |
||
| 877 | #endif |
||
| 878 | |||
| 879 | start_game(); |
||
| 880 | } else { |
||
| 881 | // Otherwise, just clear it. |
||
| 882 | erase_bottom_text(1); |
||
| 883 | } |
||
| 884 | } else { |
||
| 885 | if (text_time_remaining != 0 && text_time_total != 1188) { |
||
| 886 | // 1188: potions level (page/line/word) -- this one does not disappear |
||
| 887 | --text_time_remaining; |
||
| 888 | if (text_time_total == 288 && text_time_remaining < 72) { |
||
| 889 | // 288: press button to continue |
||
| 890 | // Blink the message: |
||
| 891 | var_2 = text_time_remaining % 12; |
||
| 892 | if (var_2 > 3) { |
||
| 893 | erase_bottom_text(0); |
||
| 894 | } else { |
||
| 895 | if (var_2 == 3) { |
||
| 896 | display_text_bottom("Press Button to Continue"); |
||
| 897 | play_sound_from_buffer(sound_pointers[sound_38_blink]); // press button blink |
||
| 898 | } |
||
| 899 | } |
||
| 900 | } |
||
| 901 | } |
||
| 902 | } |
||
| 903 | } |
||
| 904 | |||
| 905 | // seg000:0B12 |
||
| 906 | void __pascal far anim_tile_modif() { |
||
| 907 | word tilepos; |
||
| 908 | for (tilepos = 0; tilepos < 30; ++tilepos) { |
||
| 909 | switch (get_curr_tile(tilepos)) { |
||
| 910 | case tiles_10_potion: |
||
| 911 | start_anim_potion(drawn_room, tilepos); |
||
| 912 | break; |
||
| 913 | case tiles_19_torch: |
||
| 914 | case tiles_30_torch_with_debris: |
||
| 915 | start_anim_torch(drawn_room, tilepos); |
||
| 916 | break; |
||
| 917 | case tiles_22_sword: |
||
| 918 | start_anim_sword(drawn_room, tilepos); |
||
| 919 | break; |
||
| 920 | } |
||
| 921 | } |
||
| 922 | } |
||
| 923 | |||
| 924 | // seg000:0B72 |
||
| 925 | void __pascal far load_sounds(int first,int last) { |
||
| 926 | dat_type* ibm_dat = NULL; |
||
| 927 | dat_type* digi1_dat = NULL; |
||
| 928 | // dat_type* digi2_dat = NULL; |
||
| 929 | dat_type* digi3_dat = NULL; |
||
| 930 | dat_type* midi_dat = NULL; |
||
| 931 | short current; |
||
| 932 | ibm_dat = open_dat("IBM_SND1.DAT", 0); |
||
| 933 | if (sound_flags & sfDigi) { |
||
| 934 | digi1_dat = open_dat("DIGISND1.DAT", 0); |
||
| 935 | // digi2_dat = open_dat("DIGISND2.DAT", 0); |
||
| 936 | digi3_dat = open_dat("DIGISND3.DAT", 0); |
||
| 937 | } |
||
| 938 | if (sound_flags & sfMidi) { |
||
| 939 | midi_dat = open_dat("MIDISND1.DAT", 0); |
||
| 940 | } |
||
| 941 | |||
| 942 | #ifdef USE_MIXER |
||
| 943 | load_sound_names(); |
||
| 944 | #endif |
||
| 945 | |||
| 946 | for (current = first; current <= last; ++current) { |
||
| 947 | if (sound_pointers[current] != NULL) continue; |
||
| 948 | /*if (demo_mode) { |
||
| 949 | sound_pointers[current] = decompress_sound((sound_buffer_type*) load_from_opendats_alloc(current + 10000)); |
||
| 950 | } else*/ { |
||
| 951 | //sound_pointers[current] = (sound_buffer_type*) load_from_opendats_alloc(current + 10000, "bin", NULL, NULL); |
||
| 952 | //printf("overwriting sound_pointers[%d] = %p\n", current, sound_pointers[current]); |
||
| 953 | |||
| 954 | |||
| 955 | sound_pointers[current] = load_sound(current); |
||
| 956 | } |
||
| 957 | } |
||
| 958 | if (midi_dat) close_dat(midi_dat); |
||
| 959 | if (digi1_dat) close_dat(digi1_dat); |
||
| 960 | // if (digi2_dat) close_dat(digi2_dat); |
||
| 961 | if (digi3_dat) close_dat(digi3_dat); |
||
| 962 | close_dat(ibm_dat); |
||
| 963 | } |
||
| 964 | |||
| 965 | // seg000:0C5E |
||
| 966 | void __pascal far load_opt_sounds(int first,int last) { |
||
| 967 | // stub |
||
| 968 | dat_type* ibm_dat = NULL; |
||
| 969 | dat_type* digi_dat = NULL; |
||
| 970 | dat_type* midi_dat = NULL; |
||
| 971 | short current; |
||
| 972 | ibm_dat = open_dat("IBM_SND2.DAT", 0); |
||
| 973 | if (sound_flags & sfDigi) { |
||
| 974 | digi_dat = open_dat("DIGISND2.DAT", 0); |
||
| 975 | } |
||
| 976 | if (sound_flags & sfMidi) { |
||
| 977 | midi_dat = open_dat("MIDISND2.DAT", 0); |
||
| 978 | } |
||
| 979 | for (current = first; current <= last; ++current) { |
||
| 980 | //We don't free sounds, so load only once. |
||
| 981 | if (sound_pointers[current] != NULL) continue; |
||
| 982 | /*if (demo_mode) { |
||
| 983 | sound_pointers[current] = decompress_sound((sound_buffer_type*) load_from_opendats_alloc(current + 10000)); |
||
| 984 | } else*/ { |
||
| 985 | //sound_pointers[current] = (sound_buffer_type*) load_from_opendats_alloc(current + 10000, "bin", NULL, NULL); |
||
| 986 | //printf("overwriting sound_pointers[%d] = %p\n", current, sound_pointers[current]); |
||
| 987 | sound_pointers[current] = load_sound(current); |
||
| 988 | } |
||
| 989 | } |
||
| 990 | if (midi_dat) close_dat(midi_dat); |
||
| 991 | if (digi_dat) close_dat(digi_dat); |
||
| 992 | close_dat(ibm_dat); |
||
| 993 | } |
||
| 994 | |||
| 995 | // data:03BA |
||
| 996 | const char*const tbl_guard_dat[] = {"GUARD.DAT", "FAT.DAT", "SKEL.DAT", "VIZIER.DAT", "SHADOW.DAT"}; |
||
| 997 | // data:03C4 |
||
| 998 | const char*const tbl_envir_gr[] = {"", "C", "C", "E", "E", "V"}; |
||
| 999 | // data:03D0 |
||
| 1000 | const char*const tbl_envir_ki[] = {"DUNGEON", "PALACE"}; |
||
| 1001 | // seg000:0D20 |
||
| 1002 | void __pascal far load_lev_spr(int level) { |
||
| 1003 | dat_type* dathandle; |
||
| 1004 | short guardtype; |
||
| 1005 | char filename[20]; |
||
| 1006 | dathandle = NULL; |
||
| 1007 | current_level = next_level = level; |
||
| 1008 | draw_rect(&screen_rect, 0); |
||
| 1009 | free_optsnd_chtab(); |
||
| 1010 | snprintf(filename, sizeof(filename), "%s%s.DAT", |
||
| 1011 | tbl_envir_gr[graphics_mode], |
||
| 1012 | tbl_envir_ki[tbl_level_type[current_level]] |
||
| 1013 | ); |
||
| 1014 | load_chtab_from_file(id_chtab_6_environment, 200, filename, 1<<5); |
||
| 1015 | load_more_opt_graf(filename); |
||
| 1016 | guardtype = tbl_guard_type[current_level]; |
||
| 1017 | if (guardtype != -1) { |
||
| 1018 | if (guardtype == 0) { |
||
| 1019 | dathandle = open_dat(tbl_level_type[current_level] ? "GUARD1.DAT" : "GUARD2.DAT", 0); |
||
| 1020 | } |
||
| 1021 | load_chtab_from_file(id_chtab_5_guard, 750, tbl_guard_dat[guardtype], 1<<8); |
||
| 1022 | if (dathandle) { |
||
| 1023 | close_dat(dathandle); |
||
| 1024 | } |
||
| 1025 | } |
||
| 1026 | curr_guard_color = 0; |
||
| 1027 | load_chtab_from_file(id_chtab_7_environmentwall, 360, filename, 1<<6); |
||
| 1028 | |||
| 1029 | // Level colors (1.3) |
||
| 1030 | if (graphics_mode == gmMcgaVga && level_var_palettes != NULL) { |
||
| 1031 | int level_color = tbl_level_color[current_level]; |
||
| 1032 | if (level_color != 0) { |
||
| 1033 | byte* env_pal = level_var_palettes + 0x30*(level_color-1); |
||
| 1034 | byte* wall_pal = env_pal + 0x30 * tbl_level_type[current_level]; |
||
| 1035 | set_pal_arr(0x50, 0x10, (rgb_type*)env_pal, 1); |
||
| 1036 | set_pal_arr(0x60, 0x10, (rgb_type*)wall_pal, 1); |
||
| 1037 | set_chtab_palette(chtab_addrs[id_chtab_6_environment], env_pal, 0x10); |
||
| 1038 | set_chtab_palette(chtab_addrs[id_chtab_7_environmentwall], wall_pal, 0x10); |
||
| 1039 | } |
||
| 1040 | } |
||
| 1041 | |||
| 1042 | /*if (comp_skeleton[current_level])*/ { |
||
| 1043 | load_opt_sounds(44, 44); // skel alive |
||
| 1044 | } |
||
| 1045 | /*if (comp_mirror[current_level])*/ { |
||
| 1046 | load_opt_sounds(45, 45); // mirror |
||
| 1047 | } |
||
| 1048 | /*if (comp_chomper[current_level])*/ { |
||
| 1049 | load_opt_sounds(46, 47); // something chopped, chomper |
||
| 1050 | } |
||
| 1051 | /*if (comp_spike[current_level])*/ { |
||
| 1052 | load_opt_sounds(48, 49); // something spiked, spikes |
||
| 1053 | } |
||
| 1054 | } |
||
| 1055 | |||
| 1056 | // seg000:0E6C |
||
| 1057 | void __pascal far load_level() { |
||
| 1058 | dat_type* dathandle; |
||
| 1059 | dathandle = open_dat("LEVELS.DAT", 0); |
||
| 1060 | load_from_opendats_to_area(current_level + 2000, &level, sizeof(level), "bin"); |
||
| 1061 | close_dat(dathandle); |
||
| 1062 | |||
| 1063 | alter_mods_allrm(); |
||
| 1064 | reset_level_unused_fields(true); // added |
||
| 1065 | } |
||
| 1066 | |||
| 1067 | void reset_level_unused_fields(bool loading_clean_level) { |
||
| 1068 | // Entirely unused fields in the level format: reset to zero for now |
||
| 1069 | // They can be repurposed to add new stuff to the level format in the future |
||
| 1070 | memset(level.roomxs, 0, sizeof(level.roomxs)); |
||
| 1071 | memset(level.roomys, 0, sizeof(level.roomys)); |
||
| 1072 | memset(level.fill_1, 0, sizeof(level.fill_1)); |
||
| 1073 | memset(level.fill_2, 0, sizeof(level.fill_2)); |
||
| 1074 | memset(level.fill_3, 0, sizeof(level.fill_3)); |
||
| 1075 | |||
| 1076 | // For these fields, only use the bits that are actually used, and set the rest to zero. |
||
| 1077 | // Good for repurposing the unused bits in the future. |
||
| 1078 | int i; |
||
| 1079 | for (i = 0; i < level.used_rooms; ++i) { |
||
| 1080 | //level.guards_dir[i] &= 0x01; // 1 bit in use |
||
| 1081 | level.guards_skill[i] &= 0x0F; // 4 bits in use |
||
| 1082 | } |
||
| 1083 | |||
| 1084 | // In savestates, additional information may be stored (e.g. remembered guard hp) - should not reset this then! |
||
| 1085 | if (loading_clean_level) { |
||
| 1086 | for (i = 0; i < level.used_rooms; ++i) { |
||
| 1087 | level.guards_color[i] &= 0x0F; // 4 bits in use (other 4 bits repurposed as remembered guard hp) |
||
| 1088 | } |
||
| 1089 | } |
||
| 1090 | |||
| 1091 | } |
||
| 1092 | |||
| 1093 | // seg000:0EA8 |
||
| 1094 | // returns 1 if level is restarted, 0 otherwise |
||
| 1095 | int __pascal far play_kid_frame() { |
||
| 1096 | loadkid_and_opp(); |
||
| 1097 | load_fram_det_col(); |
||
| 1098 | check_killed_shadow(); |
||
| 1099 | play_kid(); |
||
| 1100 | if (upside_down && Char.alive >= 0) { |
||
| 1101 | upside_down = 0; |
||
| 1102 | need_redraw_because_flipped = 1; |
||
| 1103 | } |
||
| 1104 | if (is_restart_level) { |
||
| 1105 | return 1; |
||
| 1106 | } |
||
| 1107 | if (Char.room != 0) { |
||
| 1108 | play_seq(); |
||
| 1109 | fall_accel(); |
||
| 1110 | fall_speed(); |
||
| 1111 | load_frame_to_obj(); |
||
| 1112 | load_fram_det_col(); |
||
| 1113 | set_char_collision(); |
||
| 1114 | bump_into_opponent(); |
||
| 1115 | check_collisions(); |
||
| 1116 | check_bumped(); |
||
| 1117 | check_gate_push(); |
||
| 1118 | check_action(); |
||
| 1119 | check_press(); |
||
| 1120 | check_spike_below(); |
||
| 1121 | if (resurrect_time == 0) { |
||
| 1122 | check_spiked(); |
||
| 1123 | check_chomped_kid(); |
||
| 1124 | } |
||
| 1125 | check_knock(); |
||
| 1126 | } |
||
| 1127 | savekid(); |
||
| 1128 | return 0; |
||
| 1129 | } |
||
| 1130 | |||
| 1131 | // seg000:0F48 |
||
| 1132 | void __pascal far play_guard_frame() { |
||
| 1133 | if (Guard.direction != dir_56_none) { |
||
| 1134 | loadshad_and_opp(); |
||
| 1135 | load_fram_det_col(); |
||
| 1136 | check_killed_shadow(); |
||
| 1137 | play_guard(); |
||
| 1138 | if (Char.room == drawn_room) { |
||
| 1139 | play_seq(); |
||
| 1140 | if (Char.x >= 44 && Char.x < 211) { |
||
| 1141 | fall_accel(); |
||
| 1142 | fall_speed(); |
||
| 1143 | load_frame_to_obj(); |
||
| 1144 | load_fram_det_col(); |
||
| 1145 | set_char_collision(); |
||
| 1146 | check_guard_bumped(); |
||
| 1147 | check_action(); |
||
| 1148 | check_press(); |
||
| 1149 | check_spike_below(); |
||
| 1150 | check_spiked(); |
||
| 1151 | check_chomped_guard(); |
||
| 1152 | } |
||
| 1153 | } |
||
| 1154 | saveshad(); |
||
| 1155 | } |
||
| 1156 | } |
||
| 1157 | |||
| 1158 | // seg000:0FBD |
||
| 1159 | void __pascal far check_the_end() { |
||
| 1160 | if (next_room != 0 && next_room != drawn_room) { |
||
| 1161 | drawn_room = next_room; |
||
| 1162 | load_room_links(); |
||
| 1163 | if (current_level == 14 && drawn_room == 5) { |
||
| 1164 | #ifdef USE_REPLAY |
||
| 1165 | if (recording) stop_recording(); |
||
| 1166 | if (replaying) end_replay(); |
||
| 1167 | #endif |
||
| 1168 | // Special event: end of game |
||
| 1169 | end_sequence(); |
||
| 1170 | } |
||
| 1171 | different_room = 1; |
||
| 1172 | loadkid(); |
||
| 1173 | anim_tile_modif(); |
||
| 1174 | start_chompers(); |
||
| 1175 | check_fall_flo(); |
||
| 1176 | check_shadow(); |
||
| 1177 | } |
||
| 1178 | } |
||
| 1179 | |||
| 1180 | // seg000:1009 |
||
| 1181 | void __pascal far check_fall_flo() { |
||
| 1182 | // Special event: falling floors |
||
| 1183 | if (current_level == 13 && (drawn_room == 23 || drawn_room == 16)) { |
||
| 1184 | get_room_address(curr_room = room_A); |
||
| 1185 | for (curr_tilepos = 22; curr_tilepos <= 27; ++curr_tilepos) { |
||
| 1186 | make_loose_fall(-(prandom(0xFF) & 0x0F)); |
||
| 1187 | } |
||
| 1188 | } |
||
| 1189 | } |
||
| 1190 | |||
| 1191 | void get_joystick_state(int raw_x, int raw_y, int axis_state[2]) { |
||
| 1192 | |||
| 1193 | #define DEGREES_TO_RADIANS (M_PI/180.0) |
||
| 1194 | |||
| 1195 | // check if the X/Y position is within the 'dead zone' of the joystick |
||
| 1196 | int dist_squared = raw_x*raw_x + raw_y*raw_y; |
||
| 1197 | if (dist_squared < joystick_threshold*joystick_threshold) { |
||
| 1198 | axis_state[0] = 0; |
||
| 1199 | axis_state[1] = 0; |
||
| 1200 | } else { |
||
| 1201 | double angle = atan2(raw_y, raw_x); // angle of the joystick: 0 = right, >0 = downward, <0 = upward |
||
| 1202 | //printf("Joystick angle is %f degrees\n", angle/DEGREES_TO_RADIANS); |
||
| 1203 | |||
| 1204 | if (fabs(angle) < (60*DEGREES_TO_RADIANS)) // 120 degree range facing right |
||
| 1205 | axis_state[0] = 1; |
||
| 1206 | |||
| 1207 | else if (fabs(angle) > (120*DEGREES_TO_RADIANS)) // 120 degree range facing left |
||
| 1208 | axis_state[0] = -1; |
||
| 1209 | |||
| 1210 | else { |
||
| 1211 | // joystick is neutral horizontally, so the control should be released |
||
| 1212 | // however: prevent stop running if the Kid was already running / trying to do a running-jump |
||
| 1213 | // (this tweak makes it a bit easier to do (multiple) running jumps) |
||
| 1214 | if (!(angle < 0 /*facing upward*/ && Kid.action == actions_1_run_jump)) { |
||
| 1215 | axis_state[0] = 0; |
||
| 1216 | } |
||
| 1217 | } |
||
| 1218 | |||
| 1219 | if (angle < (-30*DEGREES_TO_RADIANS) && angle > (-150*DEGREES_TO_RADIANS)) // 120 degree range facing up |
||
| 1220 | axis_state[1] = -1; |
||
| 1221 | |||
| 1222 | // down slightly less sensitive than up (prevent annoyance when your thumb slips down a bit by accident) |
||
| 1223 | // (not sure if this adjustment is really necessary) |
||
| 1224 | else if (angle > (35*DEGREES_TO_RADIANS) && angle < (145*DEGREES_TO_RADIANS)) // 110 degree range facing down |
||
| 1225 | axis_state[1] = 1; |
||
| 1226 | |||
| 1227 | else { |
||
| 1228 | // joystick is neutral vertically, so the control should be released |
||
| 1229 | // however: should prevent unintended standing up when attempting to crouch-hop |
||
| 1230 | if (!((Kid.frame >= frame_108_fall_land_2 && Kid.frame <= frame_112_stand_up_from_crouch_3) |
||
| 1231 | && angle > 0 /*facing downward*/)) |
||
| 1232 | { |
||
| 1233 | axis_state[1] = 0; |
||
| 1234 | } |
||
| 1235 | } |
||
| 1236 | } |
||
| 1237 | } |
||
| 1238 | |||
| 1239 | void get_joystick_state_hor_only(int raw_x, int axis_state[2]) { |
||
| 1240 | if (raw_x > joystick_threshold) { |
||
| 1241 | axis_state[0] = 1; |
||
| 1242 | } else if (raw_x < -joystick_threshold) { |
||
| 1243 | axis_state[0] = -1; |
||
| 1244 | } else axis_state[0] = 0; |
||
| 1245 | |||
| 1246 | // disregard all vertical input from the joystick controls (only use Y and A buttons or D-pad for up/down) |
||
| 1247 | axis_state[1] = 0; |
||
| 1248 | } |
||
| 1249 | |||
| 1250 | // seg000:1051 |
||
| 1251 | void __pascal far read_joyst_control() { |
||
| 1252 | |||
| 1253 | if (joystick_only_horizontal) { |
||
| 1254 | get_joystick_state_hor_only(joy_axis[SDL_CONTROLLER_AXIS_LEFTX], joy_left_stick_states); |
||
| 1255 | get_joystick_state_hor_only(joy_axis[SDL_CONTROLLER_AXIS_RIGHTX], joy_right_stick_states); |
||
| 1256 | } else { |
||
| 1257 | get_joystick_state(joy_axis[SDL_CONTROLLER_AXIS_LEFTX], joy_axis[SDL_CONTROLLER_AXIS_LEFTY], joy_left_stick_states); |
||
| 1258 | get_joystick_state(joy_axis[SDL_CONTROLLER_AXIS_RIGHTX], joy_axis[SDL_CONTROLLER_AXIS_RIGHTY], joy_right_stick_states); |
||
| 1259 | } |
||
| 1260 | |||
| 1261 | if (joy_left_stick_states[0] == -1 || joy_right_stick_states[0] == -1 || joy_hat_states[0] == -1) |
||
| 1262 | control_x = -1; |
||
| 1263 | |||
| 1264 | if (joy_left_stick_states[0] == 1 || joy_right_stick_states[0] == 1 || joy_hat_states[0] == 1) |
||
| 1265 | control_x = 1; |
||
| 1266 | |||
| 1267 | if (joy_left_stick_states[1] == -1 || joy_right_stick_states[1] == -1 || joy_hat_states[1] == -1 || joy_AY_buttons_state == -1) |
||
| 1268 | control_y = -1; |
||
| 1269 | |||
| 1270 | if (joy_left_stick_states[1] == 1 || joy_right_stick_states[1] == 1 || joy_hat_states[1] == 1 || joy_AY_buttons_state == 1) |
||
| 1271 | control_y = 1; |
||
| 1272 | |||
| 1273 | if (joy_X_button_state == 1 || |
||
| 1274 | joy_axis[SDL_CONTROLLER_AXIS_TRIGGERLEFT] > 8000 || |
||
| 1275 | joy_axis[SDL_CONTROLLER_AXIS_TRIGGERRIGHT] > 8000) |
||
| 1276 | { |
||
| 1277 | control_shift = -1; |
||
| 1278 | } |
||
| 1279 | |||
| 1280 | } |
||
| 1281 | |||
| 1282 | // seg000:10EA |
||
| 1283 | void __pascal far draw_kid_hp(short curr_hp,short max_hp) { |
||
| 1284 | short drawn_hp_index; |
||
| 1285 | for (drawn_hp_index = curr_hp; drawn_hp_index < max_hp; ++drawn_hp_index) { |
||
| 1286 | // empty HP |
||
| 1287 | method_6_blit_img_to_scr(get_image(id_chtab_2_kid, 217), drawn_hp_index * 7, 194, blitters_0_no_transp); |
||
| 1288 | } |
||
| 1289 | for (drawn_hp_index = 0; drawn_hp_index < curr_hp; ++drawn_hp_index) { |
||
| 1290 | // full HP |
||
| 1291 | method_6_blit_img_to_scr(get_image(id_chtab_2_kid, 216), drawn_hp_index * 7, 194, blitters_0_no_transp); |
||
| 1292 | } |
||
| 1293 | } |
||
| 1294 | |||
| 1295 | // seg000:1159 |
||
| 1296 | void __pascal far draw_guard_hp(short curr_hp,short max_hp) { |
||
| 1297 | short drawn_hp_index; |
||
| 1298 | short guard_charid; |
||
| 1299 | if (chtab_addrs[id_chtab_5_guard] == NULL) return; |
||
| 1300 | guard_charid = Guard.charid; |
||
| 1301 | if (guard_charid != charid_4_skeleton && |
||
| 1302 | guard_charid != charid_24_mouse && |
||
| 1303 | // shadow has HP only on level 12 |
||
| 1304 | (guard_charid != charid_1_shadow || current_level == 12) |
||
| 1305 | ) { |
||
| 1306 | for (drawn_hp_index = curr_hp; drawn_hp_index < max_hp; ++drawn_hp_index) { |
||
| 1307 | method_6_blit_img_to_scr(chtab_addrs[id_chtab_5_guard]->images[0], 314 - drawn_hp_index * 7, 194, blitters_9_black); |
||
| 1308 | } |
||
| 1309 | for (drawn_hp_index = 0; drawn_hp_index < curr_hp; ++drawn_hp_index) { |
||
| 1310 | method_6_blit_img_to_scr(chtab_addrs[id_chtab_5_guard]->images[0], 314 - drawn_hp_index * 7, 194, blitters_0_no_transp); |
||
| 1311 | } |
||
| 1312 | } |
||
| 1313 | } |
||
| 1314 | |||
| 1315 | // seg000:11EC |
||
| 1316 | void __pascal far add_life() { |
||
| 1317 | short hpmax = hitp_max; |
||
| 1318 | ++hpmax; |
||
| 1319 | // CusPop: set maximum number of hitpoints (max_hitp_allowed, default = 10) |
||
| 1320 | // if (hpmax > 10) hpmax = 10; // original |
||
| 1321 | if (hpmax > max_hitp_allowed) hpmax = max_hitp_allowed; |
||
| 1322 | hitp_max = hpmax; |
||
| 1323 | set_health_life(); |
||
| 1324 | } |
||
| 1325 | |||
| 1326 | // seg000:1200 |
||
| 1327 | void __pascal far set_health_life() { |
||
| 1328 | hitp_delta = hitp_max - hitp_curr; |
||
| 1329 | } |
||
| 1330 | |||
| 1331 | // seg000:120B |
||
| 1332 | void __pascal far draw_hp() { |
||
| 1333 | if (hitp_delta) { |
||
| 1334 | draw_kid_hp(hitp_curr, hitp_max); |
||
| 1335 | } |
||
| 1336 | if (hitp_curr == 1 && current_level != 15) { |
||
| 1337 | // blinking hitpoint |
||
| 1338 | if (rem_tick & 1) { |
||
| 1339 | draw_kid_hp(1, 0); |
||
| 1340 | } else { |
||
| 1341 | draw_kid_hp(0, 1); |
||
| 1342 | } |
||
| 1343 | } |
||
| 1344 | if (guardhp_delta) { |
||
| 1345 | draw_guard_hp(guardhp_curr, guardhp_max); |
||
| 1346 | } |
||
| 1347 | if (guardhp_curr == 1) { |
||
| 1348 | if (rem_tick & 1) { |
||
| 1349 | draw_guard_hp(1, 0); |
||
| 1350 | } else { |
||
| 1351 | draw_guard_hp(0, 1); |
||
| 1352 | } |
||
| 1353 | } |
||
| 1354 | } |
||
| 1355 | |||
| 1356 | // seg000:127B |
||
| 1357 | void __pascal far do_delta_hp() { |
||
| 1358 | // level 12: if the shadow is hurt, Kid is also hurt |
||
| 1359 | if (Opp.charid == charid_1_shadow && |
||
| 1360 | current_level == 12 && |
||
| 1361 | guardhp_delta != 0 |
||
| 1362 | ) { |
||
| 1363 | hitp_delta = guardhp_delta; |
||
| 1364 | } |
||
| 1365 | hitp_curr = MIN(MAX(hitp_curr + hitp_delta, 0), hitp_max); |
||
| 1366 | guardhp_curr = MIN(MAX(guardhp_curr + guardhp_delta, 0), guardhp_max); |
||
| 1367 | } |
||
| 1368 | |||
| 1369 | byte sound_prio_table[] = { |
||
| 1370 | 0x14, 0x1E, 0x23, 0x66, 0x32, 0x37, 0x30, 0x30, 0x4B, 0x50, 0x0A, |
||
| 1371 | 0x12, 0x0C, 0x0B, 0x69, 0x6E, 0x73, 0x78, 0x7D, 0x82, 0x91, 0x96, |
||
| 1372 | 0x9B, 0xA0, 1, 1, 1, 1, 1, 0x13, 1, 1, 1, 1, 1, 1, 1, |
||
| 1373 | 1, 1, 0, 1, 1, 1, 1, 0x87, 0x8C, 0x0F, 0x10, 0x19, 0x16, 1, |
||
| 1374 | 0, 1, 1, 1, 1, 1, 0 |
||
| 1375 | }; |
||
| 1376 | byte sound_pcspeaker_exists[] = { |
||
| 1377 | 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, |
||
| 1378 | 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
||
| 1379 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
||
| 1380 | 1, 1, 1, 0 |
||
| 1381 | }; |
||
| 1382 | |||
| 1383 | // seg000:12C5 |
||
| 1384 | void __pascal far play_sound(int sound_id) { |
||
| 1385 | //printf("Would play sound %d\n", sound_id); |
||
| 1386 | if (next_sound < 0 || sound_prio_table[sound_id] <= sound_prio_table[next_sound]) { |
||
| 1387 | if (NULL == sound_pointers[sound_id]) return; |
||
| 1388 | if (sound_pcspeaker_exists[sound_id] != 0 || sound_pointers[sound_id]->type != sound_speaker) { |
||
| 1389 | next_sound = sound_id; |
||
| 1390 | } |
||
| 1391 | } |
||
| 1392 | } |
||
| 1393 | |||
| 1394 | // seg000:1304 |
||
| 1395 | void __pascal far play_next_sound() { |
||
| 1396 | if (next_sound >= 0) { |
||
| 1397 | if (!check_sound_playing() || |
||
| 1398 | (sound_interruptible[current_sound] != 0 && sound_prio_table[next_sound] <= sound_prio_table[current_sound]) |
||
| 1399 | ) { |
||
| 1400 | current_sound = next_sound; |
||
| 1401 | play_sound_from_buffer(sound_pointers[current_sound]); |
||
| 1402 | } |
||
| 1403 | } |
||
| 1404 | next_sound = -1; |
||
| 1405 | } |
||
| 1406 | |||
| 1407 | // seg000:1353 |
||
| 1408 | void __pascal far check_sword_vs_sword() { |
||
| 1409 | if (Kid.frame == 167 || Guard.frame == 167) { |
||
| 1410 | play_sound(sound_10_sword_vs_sword); // sword vs. sword |
||
| 1411 | } |
||
| 1412 | } |
||
| 1413 | |||
| 1414 | // seg000:136A |
||
| 1415 | void __pascal far load_chtab_from_file(int chtab_id,int resource,const char near *filename,int palette_bits) { |
||
| 1416 | //printf("Loading chtab %d, id %d from %s\n",chtab_id,resource,filename); |
||
| 1417 | dat_type* dathandle; |
||
| 1418 | if (chtab_addrs[chtab_id] != NULL) return; |
||
| 1419 | dathandle = open_dat(filename, 0); |
||
| 1420 | chtab_addrs[chtab_id] = load_sprites_from_file(resource, palette_bits, 1); |
||
| 1421 | close_dat(dathandle); |
||
| 1422 | } |
||
| 1423 | |||
| 1424 | // seg000:13BA |
||
| 1425 | void __pascal far free_all_chtabs_from(int first) { |
||
| 1426 | word chtab_id; |
||
| 1427 | free_peels(); |
||
| 1428 | for (chtab_id = first; chtab_id < 10; ++chtab_id) { |
||
| 1429 | if (chtab_addrs[chtab_id]) { |
||
| 1430 | free_chtab(chtab_addrs[chtab_id]); |
||
| 1431 | chtab_addrs[chtab_id] = NULL; |
||
| 1432 | } |
||
| 1433 | } |
||
| 1434 | } |
||
| 1435 | |||
| 1436 | // seg009:12EF |
||
| 1437 | void __pascal far load_one_optgraf(chtab_type* chtab_ptr,dat_pal_type far *pal_ptr,int base_id,int min_index,int max_index) { |
||
| 1438 | short index; |
||
| 1439 | for (index = min_index; index <= max_index; ++index) { |
||
| 1440 | image_type* image = load_image(base_id + index + 1, pal_ptr); |
||
| 1441 | if (image != NULL) chtab_ptr->images[index] = image; |
||
| 1442 | } |
||
| 1443 | } |
||
| 1444 | |||
| 1445 | byte optgraf_min[] = {0x01, 0x1E, 0x4B, 0x4E, 0x56, 0x65, 0x7F, 0x0A}; |
||
| 1446 | byte optgraf_max[] = {0x09, 0x1F, 0x4D, 0x53, 0x5B, 0x7B, 0x8F, 0x0D}; |
||
| 1447 | // seg000:13FC |
||
| 1448 | void __pascal far load_more_opt_graf(const char *filename) { |
||
| 1449 | // stub |
||
| 1450 | dat_type* dathandle; |
||
| 1451 | dat_shpl_type area; |
||
| 1452 | short graf_index; |
||
| 1453 | dathandle = NULL; |
||
| 1454 | for (graf_index = 0; graf_index < 8; ++graf_index) { |
||
| 1455 | /*if (...) */ { |
||
| 1456 | if (dathandle == NULL) { |
||
| 1457 | dathandle = open_dat(filename, 0); |
||
| 1458 | load_from_opendats_to_area(200, &area, sizeof(area), "pal"); |
||
| 1459 | area.palette.row_bits = 0x20; |
||
| 1460 | } |
||
| 1461 | load_one_optgraf(chtab_addrs[id_chtab_6_environment], &area.palette, 1200, optgraf_min[graf_index] - 1, optgraf_max[graf_index] - 1); |
||
| 1462 | } |
||
| 1463 | } |
||
| 1464 | if (dathandle != NULL) { |
||
| 1465 | close_dat(dathandle); |
||
| 1466 | } |
||
| 1467 | } |
||
| 1468 | |||
| 1469 | // seg000:148D |
||
| 1470 | int __pascal far do_paused() { |
||
| 1471 | #ifdef USE_REPLAY |
||
| 1472 | if (replaying && skipping_replay) return 0; |
||
| 1473 | #endif |
||
| 1474 | |||
| 1475 | word key; |
||
| 1476 | key = 0; |
||
| 1477 | next_room = 0; |
||
| 1478 | control_shift = 0; |
||
| 1479 | control_y = 0; |
||
| 1480 | control_x = 0; |
||
| 1481 | if (is_joyst_mode) { |
||
| 1482 | read_joyst_control(); |
||
| 1483 | } else { |
||
| 1484 | read_keyb_control(); |
||
| 1485 | } |
||
| 1486 | key = process_key(); |
||
| 1487 | if (is_paused) { |
||
| 1488 | is_paused = 0; |
||
| 1489 | display_text_bottom("GAME PAUSED"); |
||
| 1490 | // busy waiting? |
||
| 1491 | do { |
||
| 1492 | idle(); |
||
| 1493 | //request_screen_update(); |
||
| 1494 | } while (! process_key()); |
||
| 1495 | erase_bottom_text(1); |
||
| 1496 | } |
||
| 1497 | return key || control_shift; |
||
| 1498 | } |
||
| 1499 | |||
| 1500 | // seg000:1500 |
||
| 1501 | void __pascal far read_keyb_control() { |
||
| 1502 | |||
| 1503 | if (key_states[SDL_SCANCODE_UP] || key_states[SDL_SCANCODE_HOME] || key_states[SDL_SCANCODE_PAGEUP] |
||
| 1504 | || key_states[SDL_SCANCODE_KP_8] || key_states[SDL_SCANCODE_KP_7] || key_states[SDL_SCANCODE_KP_9] |
||
| 1505 | ) { |
||
| 1506 | control_y = -1; |
||
| 1507 | } else if (key_states[SDL_SCANCODE_CLEAR] || key_states[SDL_SCANCODE_DOWN] |
||
| 1508 | || key_states[SDL_SCANCODE_KP_5] || key_states[SDL_SCANCODE_KP_2] |
||
| 1509 | ) { |
||
| 1510 | control_y = 1; |
||
| 1511 | } |
||
| 1512 | if (key_states[SDL_SCANCODE_LEFT] || key_states[SDL_SCANCODE_HOME] |
||
| 1513 | || key_states[SDL_SCANCODE_KP_4] || key_states[SDL_SCANCODE_KP_7] |
||
| 1514 | ) { |
||
| 1515 | control_x = -1; |
||
| 1516 | } else if (key_states[SDL_SCANCODE_RIGHT] || key_states[SDL_SCANCODE_PAGEUP] |
||
| 1517 | || key_states[SDL_SCANCODE_KP_6] || key_states[SDL_SCANCODE_KP_9] |
||
| 1518 | ) { |
||
| 1519 | control_x = 1; |
||
| 1520 | } |
||
| 1521 | control_shift = -(key_states[SDL_SCANCODE_LSHIFT] || key_states[SDL_SCANCODE_RSHIFT]); |
||
| 1522 | |||
| 1523 | #ifdef USE_DEBUG_CHEATS |
||
| 1524 | if (cheats_enabled && debug_cheats_enabled) { |
||
| 1525 | if (key_states[SDL_SCANCODE_RIGHTBRACKET]) ++Char.x; |
||
| 1526 | else if (key_states[SDL_SCANCODE_LEFTBRACKET]) --Char.x; |
||
| 1527 | } |
||
| 1528 | #endif |
||
| 1529 | } |
||
| 1530 | |||
| 1531 | // seg000:156D |
||
| 1532 | void __pascal far copy_screen_rect(const rect_type far *source_rect_ptr) { |
||
| 1533 | const rect_type* far target_rect_ptr; |
||
| 1534 | rect_type target_rect; |
||
| 1535 | if (upside_down) { |
||
| 1536 | target_rect_ptr = &target_rect; |
||
| 1537 | /**target_rect_ptr*/target_rect = *source_rect_ptr; |
||
| 1538 | /*target_rect_ptr->*/target_rect.top = 192 - source_rect_ptr->bottom; |
||
| 1539 | /*target_rect_ptr->*/target_rect.bottom = 192 - source_rect_ptr->top; |
||
| 1540 | } else { |
||
| 1541 | target_rect_ptr = source_rect_ptr; |
||
| 1542 | } |
||
| 1543 | method_1_blit_rect(onscreen_surface_, offscreen_surface, target_rect_ptr, target_rect_ptr, 0); |
||
| 1544 | #ifdef USE_LIGHTING |
||
| 1545 | update_lighting(target_rect_ptr); |
||
| 1546 | #endif |
||
| 1547 | } |
||
| 1548 | |||
| 1549 | // seg000:15E9 |
||
| 1550 | void __pascal far toggle_upside() { |
||
| 1551 | upside_down = ~ upside_down; |
||
| 1552 | need_redraw_because_flipped = 1; |
||
| 1553 | } |
||
| 1554 | |||
| 1555 | // seg000:15F8 |
||
| 1556 | void __pascal far feather_fall() { |
||
| 1557 | is_feather_fall = 1; |
||
| 1558 | flash_color = 2; // green |
||
| 1559 | flash_time = 3; |
||
| 1560 | stop_sounds(); |
||
| 1561 | play_sound(sound_39_low_weight); // low weight |
||
| 1562 | } |
||
| 1563 | |||
| 1564 | // seg000:1618 |
||
| 1565 | int __pascal far parse_grmode() { |
||
| 1566 | // stub |
||
| 1567 | set_gr_mode(gmMcgaVga); |
||
| 1568 | return gmMcgaVga; |
||
| 1569 | } |
||
| 1570 | |||
| 1571 | // seg000:172C |
||
| 1572 | void __pascal far gen_palace_wall_colors() { |
||
| 1573 | dword old_randseed; |
||
| 1574 | word prev_color; |
||
| 1575 | short row; |
||
| 1576 | short subrow; |
||
| 1577 | word color_base; |
||
| 1578 | short column; |
||
| 1579 | word color; |
||
| 1580 | |||
| 1581 | old_randseed = random_seed; |
||
| 1582 | random_seed = drawn_room; |
||
| 1583 | prandom(1); // discard |
||
| 1584 | for (row = 0; row < 3; row++) { |
||
| 1585 | for (subrow = 0; subrow < 4; subrow++) { |
||
| 1586 | if (subrow % 2) { |
||
| 1587 | color_base = 0x61; // 0x61..0x64 in subrow 1 and 3 |
||
| 1588 | } else { |
||
| 1589 | color_base = 0x66; // 0x66..0x69 in subrow 0 and 2 |
||
| 1590 | } |
||
| 1591 | prev_color = -1; |
||
| 1592 | for (column = 0; column <= 10; ++column) { |
||
| 1593 | do { |
||
| 1594 | color = color_base + prandom(3); |
||
| 1595 | } while (color == prev_color); |
||
| 1596 | palace_wall_colors[44 * row + 11 * subrow + column] = color; |
||
| 1597 | //palace_wall_colors[row][subrow][column] = color; |
||
| 1598 | prev_color = color; |
||
| 1599 | } |
||
| 1600 | } |
||
| 1601 | } |
||
| 1602 | random_seed = old_randseed; |
||
| 1603 | } |
||
| 1604 | |||
| 1605 | // data:042E |
||
| 1606 | const rect_type rect_titles = {106,24,195,296}; |
||
| 1607 | |||
| 1608 | // seg000:17E6 |
||
| 1609 | void __pascal far show_title() { |
||
| 1610 | word textcolor; |
||
| 1611 | load_opt_sounds(sound_50_story_2_princess, sound_55_story_1_absence); // main theme, story, princess door |
||
| 1612 | textcolor = get_text_color(15, color_15_brightwhite, 0x800); |
||
| 1613 | dont_reset_time = 0; |
||
| 1614 | if(offscreen_surface) free_surface(offscreen_surface); // missing in original |
||
| 1615 | offscreen_surface = make_offscreen_buffer(&screen_rect); |
||
| 1616 | load_title_images(1); |
||
| 1617 | current_target_surface = offscreen_surface; |
||
| 1618 | do_wait(timer_0); |
||
| 1619 | |||
| 1620 | draw_image_2(0 /*main title image*/, chtab_title50, 0, 0, blitters_0_no_transp); |
||
| 1621 | fade_in_2(offscreen_surface, 0x1000); //STUB |
||
| 1622 | method_1_blit_rect(onscreen_surface_, offscreen_surface, &screen_rect, &screen_rect, blitters_0_no_transp); |
||
| 1623 | play_sound_from_buffer(sound_pointers[54]); // main theme |
||
| 1624 | start_timer(timer_0, 0x82); |
||
| 1625 | draw_image_2(1 /*Broderbund Software presents*/, chtab_title50, 96, 106, blitters_0_no_transp); |
||
| 1626 | do_wait(timer_0); |
||
| 1627 | |||
| 1628 | start_timer(timer_0,0xCD); |
||
| 1629 | method_1_blit_rect(onscreen_surface_, offscreen_surface, &rect_titles, &rect_titles, blitters_0_no_transp); |
||
| 1630 | draw_image_2(0 /*main title image*/, chtab_title50, 0, 0, blitters_0_no_transp); |
||
| 1631 | do_wait(timer_0); |
||
| 1632 | |||
| 1633 | start_timer(timer_0,0x41); |
||
| 1634 | method_1_blit_rect(onscreen_surface_, offscreen_surface, &rect_titles, &rect_titles, blitters_0_no_transp); |
||
| 1635 | draw_image_2(0 /*main title image*/, chtab_title50, 0, 0, blitters_0_no_transp); |
||
| 1636 | draw_image_2(2 /*a game by Jordan Mechner*/, chtab_title50, 96, 122, blitters_0_no_transp); |
||
| 1637 | do_wait(timer_0); |
||
| 1638 | |||
| 1639 | start_timer(timer_0,0x10E); |
||
| 1640 | method_1_blit_rect(onscreen_surface_, offscreen_surface, &rect_titles, &rect_titles, blitters_0_no_transp); |
||
| 1641 | draw_image_2(0 /*main title image*/, chtab_title50, 0, 0, blitters_0_no_transp); |
||
| 1642 | do_wait(timer_0); |
||
| 1643 | |||
| 1644 | start_timer(timer_0,0xEB); |
||
| 1645 | method_1_blit_rect(onscreen_surface_, offscreen_surface, &rect_titles, &rect_titles, blitters_0_no_transp); |
||
| 1646 | draw_image_2(0 /*main title image*/, chtab_title50, 0, 0, blitters_0_no_transp); |
||
| 1647 | draw_image_2(3 /*Prince Of Persia*/, chtab_title50, 24, 107, blitters_10h_transp); |
||
| 1648 | draw_image_2(4 /*Copyright 1990 Jordan Mechner*/, chtab_title50, 48, 184, blitters_0_no_transp); |
||
| 1649 | do_wait(timer_0); |
||
| 1650 | |||
| 1651 | method_1_blit_rect(onscreen_surface_, offscreen_surface, &rect_titles, &rect_titles, blitters_0_no_transp); |
||
| 1652 | draw_image_2(0 /*story frame*/, chtab_title40, 0, 0, blitters_0_no_transp); |
||
| 1653 | draw_image_2(1 /*In the Sultan's absence*/, chtab_title40, 24, 25, textcolor); |
||
| 1654 | current_target_surface = onscreen_surface_; |
||
| 1655 | while (check_sound_playing()) { |
||
| 1656 | idle(); |
||
| 1657 | do_paused(); |
||
| 1658 | } |
||
| 1659 | // method_1_blit_rect(onscreen_surface_, offscreen_surface, &screen_rect, &screen_rect, blitters_0_no_transp); |
||
| 1660 | play_sound_from_buffer(sound_pointers[sound_55_story_1_absence]); // story 1: In the absence |
||
| 1661 | transition_ltr(); |
||
| 1662 | pop_wait(timer_0, 0x258); |
||
| 1663 | fade_out_2(0x800); |
||
| 1664 | release_title_images(); |
||
| 1665 | |||
| 1666 | load_intro(0, &pv_scene, 0); |
||
| 1667 | |||
| 1668 | load_title_images(1); |
||
| 1669 | current_target_surface = offscreen_surface; |
||
| 1670 | draw_image_2(0 /*story frame*/, chtab_title40, 0, 0, blitters_0_no_transp); |
||
| 1671 | draw_image_2(2 /*Marry Jaffar*/, chtab_title40, 24, 25, textcolor); |
||
| 1672 | fade_in_2(offscreen_surface, 0x800); |
||
| 1673 | draw_image_2(0 /*main title image*/, chtab_title50, 0, 0, blitters_0_no_transp); |
||
| 1674 | draw_image_2(3 /*Prince Of Persia*/, chtab_title50, 24, 107, blitters_10h_transp); |
||
| 1675 | draw_image_2(4 /*Copyright 1990 Jordan Mechner*/, chtab_title50, 48, 184, blitters_0_no_transp); |
||
| 1676 | while (check_sound_playing()) { |
||
| 1677 | idle(); |
||
| 1678 | do_paused(); |
||
| 1679 | } |
||
| 1680 | transition_ltr(); |
||
| 1681 | pop_wait(timer_0, 0x78); |
||
| 1682 | draw_image_2(0 /*story frame*/, chtab_title40, 0, 0, blitters_0_no_transp); |
||
| 1683 | draw_image_2(4 /*credits*/, chtab_title40, 24, 26, textcolor); |
||
| 1684 | transition_ltr(); |
||
| 1685 | pop_wait(timer_0, 0x168); |
||
| 1686 | if (hof_count) { |
||
| 1687 | draw_image_2(0 /*story frame*/, chtab_title40, 0, 0, blitters_0_no_transp); |
||
| 1688 | draw_image_2(3 /*Prince Of Persia*/, chtab_title50, 24, 24, blitters_10h_transp); |
||
| 1689 | show_hof(); |
||
| 1690 | transition_ltr(); |
||
| 1691 | pop_wait(timer_0, 0xF0); |
||
| 1692 | } |
||
| 1693 | current_target_surface = onscreen_surface_; |
||
| 1694 | while (check_sound_playing()) { |
||
| 1695 | idle(); |
||
| 1696 | do_paused(); |
||
| 1697 | } |
||
| 1698 | fade_out_2(0x1800); |
||
| 1699 | free_surface(offscreen_surface); |
||
| 1700 | offscreen_surface = NULL; // added |
||
| 1701 | release_title_images(); |
||
| 1702 | init_game(0); |
||
| 1703 | } |
||
| 1704 | |||
| 1705 | // seg000:1BB3 |
||
| 1706 | void __pascal far transition_ltr() { |
||
| 1707 | short position; |
||
| 1708 | rect_type rect; |
||
| 1709 | rect.top = 0; |
||
| 1710 | rect.bottom = 200; |
||
| 1711 | rect.left = 0; |
||
| 1712 | rect.right = 2; |
||
| 1713 | for (position = 0; position < 320; position += 2) { |
||
| 1714 | method_1_blit_rect(onscreen_surface_, offscreen_surface, &rect, &rect, 0); |
||
| 1715 | rect.left += 2; |
||
| 1716 | rect.right += 2; |
||
| 1717 | pop_wait(timer_1, 0); |
||
| 1718 | } |
||
| 1719 | } |
||
| 1720 | |||
| 1721 | // seg000:1C0F |
||
| 1722 | void __pascal far release_title_images() { |
||
| 1723 | if (chtab_title50) { |
||
| 1724 | free_chtab(chtab_title50); |
||
| 1725 | chtab_title50 = NULL; |
||
| 1726 | } |
||
| 1727 | if (chtab_title40) { |
||
| 1728 | free_chtab(chtab_title40); |
||
| 1729 | chtab_title40 = NULL; |
||
| 1730 | } |
||
| 1731 | } |
||
| 1732 | |||
| 1733 | // seg000:1C3A |
||
| 1734 | void __pascal far draw_image_2(int id, chtab_type* chtab_ptr, int xpos, int ypos, int blit) { |
||
| 1735 | image_type* source; |
||
| 1736 | image_type* decoded_image; |
||
| 1737 | image_type* mask; |
||
| 1738 | mask = NULL; |
||
| 1739 | if (NULL == chtab_ptr) return; |
||
| 1740 | source = chtab_ptr->images[id]; |
||
| 1741 | decoded_image = source; |
||
| 1742 | if (blit != blitters_0_no_transp && blit != blitters_10h_transp) { |
||
| 1743 | method_3_blit_mono(decoded_image, xpos, ypos, blitters_0_no_transp, blit); |
||
| 1744 | } else if (blit == blitters_10h_transp) { |
||
| 1745 | if (graphics_mode == gmCga || graphics_mode == gmHgaHerc) { |
||
| 1746 | //... |
||
| 1747 | } else { |
||
| 1748 | mask = decoded_image; |
||
| 1749 | } |
||
| 1750 | draw_image_transp(decoded_image, mask, xpos, ypos); |
||
| 1751 | if (graphics_mode == gmCga || graphics_mode == gmHgaHerc) { |
||
| 1752 | free_far(mask); |
||
| 1753 | } |
||
| 1754 | } else { |
||
| 1755 | method_6_blit_img_to_scr(decoded_image, xpos, ypos, blit); |
||
| 1756 | } |
||
| 1757 | } |
||
| 1758 | |||
| 1759 | // seg000:1D2C |
||
| 1760 | void __pascal far load_kid_sprite() { |
||
| 1761 | load_chtab_from_file(id_chtab_2_kid, 400, "KID.DAT", 1<<7); |
||
| 1762 | } |
||
| 1763 | |||
| 1764 | const char* save_file = "PRINCE.SAV"; |
||
| 1765 | |||
| 1766 | const char* get_save_path(char* custom_path_buffer, size_t max_len) { |
||
| 1767 | if (!use_custom_levelset) { |
||
| 1768 | return save_file; |
||
| 1769 | } |
||
| 1770 | // if playing a custom levelset, try to use the mod folder |
||
| 1771 | snprintf(custom_path_buffer, max_len, "mods/%s/%s", levelset_name, save_file /*PRINCE.SAV*/ ); |
||
| 1772 | return custom_path_buffer; |
||
| 1773 | } |
||
| 1774 | |||
| 1775 | // seg000:1D45 |
||
| 1776 | void __pascal far save_game() { |
||
| 1777 | word success; |
||
| 1778 | int handle; |
||
| 1779 | success = 0; |
||
| 1780 | char custom_save_path[POP_MAX_PATH]; |
||
| 1781 | const char* save_path = get_save_path(custom_save_path, sizeof(custom_save_path)); |
||
| 1782 | // no O_TRUNC |
||
| 1783 | handle = open(save_path, O_WRONLY | O_CREAT | O_BINARY, 0600); |
||
| 1784 | if (handle == -1) goto loc_1DB8; |
||
| 1785 | if (write(handle, &rem_min, 2) == 2) goto loc_1DC9; |
||
| 1786 | loc_1D9B: |
||
| 1787 | close(handle); |
||
| 1788 | if (!success) { |
||
| 1789 | unlink(save_path); |
||
| 1790 | } |
||
| 1791 | loc_1DB8: |
||
| 1792 | if (!success) goto loc_1E18; |
||
| 1793 | display_text_bottom("GAME SAVED"); |
||
| 1794 | goto loc_1E2E; |
||
| 1795 | loc_1DC9: |
||
| 1796 | if (write(handle, &rem_tick, 2) != 2) goto loc_1D9B; |
||
| 1797 | if (write(handle, ¤t_level, 2) != 2) goto loc_1D9B; |
||
| 1798 | if (write(handle, &hitp_beg_lev, 2) != 2) goto loc_1D9B; |
||
| 1799 | success = 1; |
||
| 1800 | goto loc_1D9B; |
||
| 1801 | loc_1E18: |
||
| 1802 | display_text_bottom("UNABLE TO SAVE GAME"); |
||
| 1803 | //play_sound_from_buffer(&sound_cant_save); |
||
| 1804 | loc_1E2E: |
||
| 1805 | text_time_remaining = 24; |
||
| 1806 | } |
||
| 1807 | |||
| 1808 | // seg000:1E38 |
||
| 1809 | short __pascal far load_game() { |
||
| 1810 | int handle; |
||
| 1811 | word success; |
||
| 1812 | success = 0; |
||
| 1813 | char custom_save_path[POP_MAX_PATH]; |
||
| 1814 | const char* save_path = get_save_path(custom_save_path, sizeof(custom_save_path)); |
||
| 1815 | handle = open(save_path, O_RDONLY | O_BINARY); |
||
| 1816 | if (handle == -1) goto loc_1E99; |
||
| 1817 | if (read(handle, &rem_min, 2) == 2) goto loc_1E9E; |
||
| 1818 | loc_1E8E: |
||
| 1819 | close(handle); |
||
| 1820 | loc_1E99: |
||
| 1821 | return success; |
||
| 1822 | loc_1E9E: |
||
| 1823 | if (read(handle, &rem_tick, 2) != 2) goto loc_1E8E; |
||
| 1824 | if (read(handle, &start_level, 2) != 2) goto loc_1E8E; |
||
| 1825 | if (read(handle, &hitp_beg_lev, 2) != 2) goto loc_1E8E; |
||
| 1826 | #ifdef USE_COPYPROT |
||
| 1827 | if (enable_copyprot && copyprot_level > 0) { |
||
| 1828 | copyprot_level = start_level; |
||
| 1829 | } |
||
| 1830 | #endif |
||
| 1831 | success = 1; |
||
| 1832 | dont_reset_time = 1; |
||
| 1833 | goto loc_1E8E; |
||
| 1834 | } |
||
| 1835 | |||
| 1836 | // seg000:1F02 |
||
| 1837 | void __pascal far clear_screen_and_sounds() { |
||
| 1838 | short index; |
||
| 1839 | stop_sounds(); |
||
| 1840 | current_target_surface = rect_sthg(onscreen_surface_, &screen_rect); |
||
| 1841 | |||
| 1842 | is_cutscene = 0; |
||
| 1843 | peels_count = 0; |
||
| 1844 | // should these be freed? |
||
| 1845 | for (index = 2; index < 10; ++index) { |
||
| 1846 | if (chtab_addrs[index]) { |
||
| 1847 | // Original code does not free these? |
||
| 1848 | free_chtab(chtab_addrs[index]); |
||
| 1849 | chtab_addrs[index] = NULL; |
||
| 1850 | } |
||
| 1851 | } |
||
| 1852 | /* //Don't free sounds. |
||
| 1853 | for (index = 44; index < 57; ++index) { |
||
| 1854 | //continue; // don't release sounds? modern machines have enough memory |
||
| 1855 | free_sound(sound_pointers[index]); // added |
||
| 1856 | sound_pointers[index] = NULL; |
||
| 1857 | } |
||
| 1858 | */ |
||
| 1859 | current_level = -1; |
||
| 1860 | } |
||
| 1861 | |||
| 1862 | // seg000:1F7B |
||
| 1863 | void __pascal far parse_cmdline_sound() { |
||
| 1864 | // stub |
||
| 1865 | sound_flags |= sfDigi; |
||
| 1866 | } |
||
| 1867 | |||
| 1868 | // seg000:226D |
||
| 1869 | void __pascal far free_optional_sounds() { |
||
| 1870 | /* //Don't free sounds. |
||
| 1871 | int sound_id; |
||
| 1872 | for (sound_id = 44; sound_id < 57; ++sound_id) { |
||
| 1873 | free_sound(sound_pointers[sound_id]); |
||
| 1874 | sound_pointers[sound_id] = NULL; |
||
| 1875 | } |
||
| 1876 | */ |
||
| 1877 | // stub |
||
| 1878 | } |
||
| 1879 | |||
| 1880 | const byte tbl_snd_is_music[] = { |
||
| 1881 | 0,0,0,0,0,0,0,0,0,0, //9 |
||
| 1882 | 0,0,0,0,0,0,0,0,0,0, //19 |
||
| 1883 | 0,0,0,0,1,1,1,1,1,1, //29 |
||
| 1884 | 1,0,1,1,1,1,1,1,0,1, //39 |
||
| 1885 | 1,1,0,1,0,0,0,0,0,0, //49 |
||
| 1886 | 1,0,1,1,1,1,1 |
||
| 1887 | }; |
||
| 1888 | |||
| 1889 | void reload_non_music_sounds() { |
||
| 1890 | int i; |
||
| 1891 | for (i = 0; i < COUNT(tbl_snd_is_music); ++i) { |
||
| 1892 | if (!tbl_snd_is_music[i]) { |
||
| 1893 | free_sound(sound_pointers[i]); |
||
| 1894 | sound_pointers[i] = NULL; |
||
| 1895 | } |
||
| 1896 | } |
||
| 1897 | load_sounds(0, 43); |
||
| 1898 | load_opt_sounds(44, 56); |
||
| 1899 | } |
||
| 1900 | |||
| 1901 | // seg000:22BB |
||
| 1902 | void __pascal far free_optsnd_chtab() { |
||
| 1903 | free_optional_sounds(); |
||
| 1904 | free_all_chtabs_from(id_chtab_3_princessinstory); |
||
| 1905 | } |
||
| 1906 | |||
| 1907 | // seg000:22C8 |
||
| 1908 | void __pascal far load_title_images(int bgcolor) { |
||
| 1909 | dat_type* dathandle; |
||
| 1910 | dathandle = open_dat("TITLE.DAT", 0); |
||
| 1911 | chtab_title40 = load_sprites_from_file(40, 1<<11, 1); |
||
| 1912 | chtab_title50 = load_sprites_from_file(50, 1<<12, 1); |
||
| 1913 | close_dat(dathandle); |
||
| 1914 | if (graphics_mode == gmMcgaVga) { |
||
| 1915 | // background of text frame |
||
| 1916 | SDL_Color color; |
||
| 1917 | if (bgcolor) { |
||
| 1918 | // RGB(4,0,18h) = #100060 = dark blue |
||
| 1919 | set_pal((find_first_pal_row(1<<11) << 4) + 14, 0x04, 0x00, 0x18, 1); |
||
| 1920 | color.r = 0x10; |
||
| 1921 | color.g = 0x00; |
||
| 1922 | color.b = 0x60; |
||
| 1923 | color.a = 0xFF; |
||
| 1924 | } else { |
||
| 1925 | // RGB(20h,0,0) = #800000 = dark red |
||
| 1926 | set_pal((find_first_pal_row(1<<11) << 4) + 14, 0x20, 0x00, 0x00, 1); |
||
| 1927 | color.r = 0x80; |
||
| 1928 | color.g = 0x00; |
||
| 1929 | color.b = 0x00; |
||
| 1930 | color.a = 0xFF; |
||
| 1931 | } |
||
| 1932 | if (NULL != chtab_title40) { |
||
| 1933 | SDL_SetPaletteColors(chtab_title40->images[0]->format->palette, &color, 14, 1); |
||
| 1934 | } |
||
| 1935 | } else if (graphics_mode == gmEga || graphics_mode == gmTga) { |
||
| 1936 | // ... |
||
| 1937 | } |
||
| 1938 | } |
||
| 1939 | |||
| 1940 | #ifdef USE_COPYPROT |
||
| 1941 | // data:017A |
||
| 1942 | const word copyprot_word[] = {9, 1, 6, 4, 5, 3, 6, 3, 4, 4, 3, 2,12, 5,13, 1, 9, 2, 2, 4, 9, 4,11, 8, 5, 4, 1, 6, 2, 4, 6, 8, 4, 2, 7,11, 5, 4, 1, 2}; |
||
| 1943 | // data:012A |
||
| 1944 | const word copyprot_line[] = {2, 1, 5, 4, 3, 5, 1, 3, 7, 2, 2, 4, 6, 6, 2, 6, 3, 1, 2, 3, 2, 2, 3,10, 5, 6, 5, 6, 3, 5, 7, 2, 2, 4, 5, 7, 2, 6, 5, 5}; |
||
| 1945 | // data:00DA |
||
| 1946 | const word copyprot_page[] = {5, 3, 7, 3, 3, 4, 1, 5,12, 5,11,10, 1, 2, 8, 8, 2, 4, 6, 1, 4, 7, 3, 2, 1, 7,10, 1, 4, 3, 4, 1, 4, 1, 8, 1, 1,10, 3, 3}; |
||
| 1947 | #endif |
||
| 1948 | |||
| 1949 | // seg000:23F4 |
||
| 1950 | void __pascal far show_copyprot(int where) { |
||
| 1951 | #ifdef USE_COPYPROT |
||
| 1952 | char sprintf_temp[140]; |
||
| 1953 | if (current_level != 15) return; |
||
| 1954 | if (where) { |
||
| 1955 | if (text_time_remaining || is_cutscene) return; |
||
| 1956 | text_time_total = 1188; |
||
| 1957 | text_time_remaining = 1188; |
||
| 1958 | is_show_time = 0; |
||
| 1959 | snprintf(sprintf_temp, sizeof(sprintf_temp), |
||
| 1960 | "WORD %d LINE %d PAGE %d", |
||
| 1961 | copyprot_word[copyprot_idx], copyprot_line[copyprot_idx], copyprot_page[copyprot_idx]); |
||
| 1962 | display_text_bottom(sprintf_temp); |
||
| 1963 | } else { |
||
| 1964 | snprintf(sprintf_temp, sizeof(sprintf_temp), |
||
| 1965 | "Drink potion matching the first letter of Word %d on Line %d\n" |
||
| 1966 | "of Page %d of the manual.", |
||
| 1967 | copyprot_word[copyprot_idx], copyprot_line[copyprot_idx], copyprot_page[copyprot_idx]); |
||
| 1968 | show_dialog(sprintf_temp); |
||
| 1969 | } |
||
| 1970 | #endif |
||
| 1971 | } |
||
| 1972 | |||
| 1973 | // seg000:2489 |
||
| 1974 | void __pascal far show_loading() { |
||
| 1975 | show_text(&screen_rect, 0, 0, "Loading. . . ."); |
||
| 1976 | } |
||
| 1977 | |||
| 1978 | // data:42C4 |
||
| 1979 | word which_quote; |
||
| 1980 | |||
| 1981 | char const * const tbl_quotes[2] = { |
||
| 1982 | "\"(****/****) Incredibly realistic. . . The " |
||
| 1983 | "adventurer character actually looks human as he " |
||
| 1984 | "runs, jumps, climbs, and hangs from ledges.\"\n" |
||
| 1985 | "\n" |
||
| 1986 | " Computer Entertainer\n" |
||
| 1987 | "\n" |
||
| 1988 | "\n" |
||
| 1989 | "\n" |
||
| 1990 | "\n" |
||
| 1991 | "\"A tremendous achievement. . . Mechner has crafted " |
||
| 1992 | "the smoothest animation ever seen in a game of this " |
||
| 1993 | "type.\n" |
||
| 1994 | "\n" |
||
| 1995 | "\"PRINCE OF PERSIA is the STAR WARS of its field.\"\n" |
||
| 1996 | "\n" |
||
| 1997 | " Computer Gaming World", |
||
| 1998 | "\"An unmitigated delight. . . comes as close to " |
||
| 1999 | "(perfection) as any arcade game has come in a long, " |
||
| 2000 | "long time. . . what makes this game so wonderful (am " |
||
| 2001 | "I gushing?) is that the little onscreen character " |
||
| 2002 | "does not move like a little onscreen character -- he " |
||
| 2003 | "moves like a person.\"\n" |
||
| 2004 | "\n" |
||
| 2005 | " Nibble" |
||
| 2006 | }; |
||
| 2007 | |||
| 2008 | // seg000:249D |
||
| 2009 | void __pascal far show_quotes() { |
||
| 2010 | //start_timer(timer_0,0); |
||
| 2011 | //remove_timer(timer_0); |
||
| 2012 | if (demo_mode && need_quotes) { |
||
| 2013 | draw_rect(&screen_rect, 0); |
||
| 2014 | show_text(&screen_rect, -1, 0, tbl_quotes[which_quote]); |
||
| 2015 | which_quote = !which_quote; |
||
| 2016 | start_timer(timer_0,0x384); |
||
| 2017 | } |
||
| 2018 | need_quotes = 0; |
||
| 2019 | } |
||
| 2020 | |||
| 2021 | const rect_type splash_text_1_rect = {0, 0, 50, 320}; |
||
| 2022 | const rect_type splash_text_2_rect = {50, 0, 200, 320}; |
||
| 2023 | |||
| 2024 | const char* splash_text_1 = "SDLPoP " SDLPOP_VERSION; |
||
| 2025 | const char* splash_text_2 = |
||
| 2026 | "To quick save/load, press F6/F9 in-game.\n" |
||
| 2027 | "\n" |
||
| 2028 | #ifdef USE_REPLAY |
||
| 2029 | "To record replays, press Ctrl+Tab in-game.\n" |
||
| 2030 | "To view replays, press Tab on the title screen.\n" |
||
| 2031 | "\n" |
||
| 2032 | #endif |
||
| 2033 | "Edit game.ini to customize SDLPoP.\n" |
||
| 2034 | "Mods also work with SDLPoP.\n" |
||
| 2035 | "\n" |
||
| 2036 | "For more information, read doc/Readme.txt.\n" |
||
| 2037 | "Questions? Visit http://forum.princed.org\n" |
||
| 2038 | "\n" |
||
| 2039 | "Press any key to continue..."; |
||
| 2040 | |||
| 2041 | void show_splash() { |
||
| 2042 | if (!enable_info_screen || start_level >= 0) return; |
||
| 2043 | screen_updates_suspended = 0; |
||
| 2044 | current_target_surface = onscreen_surface_; |
||
| 2045 | draw_rect(&screen_rect, 0); |
||
| 2046 | show_text_with_color(&splash_text_1_rect, 0, 0, splash_text_1, color_15_brightwhite); |
||
| 2047 | show_text_with_color(&splash_text_2_rect, 0, -1, splash_text_2, color_7_lightgray); |
||
| 2048 | |||
| 2049 | int key = 0; |
||
| 2050 | do { |
||
| 2051 | idle(); |
||
| 2052 | key = key_test_quit(); |
||
| 2053 | |||
| 2054 | if (joy_hat_states[0] != 0 || joy_X_button_state != 0 || joy_AY_buttons_state != 0 || joy_B_button_state != 0) { |
||
| 2055 | joy_hat_states[0] = 0; |
||
| 2056 | joy_AY_buttons_state = 0; |
||
| 2057 | joy_X_button_state = 0; |
||
| 2058 | joy_B_button_state = 0; |
||
| 2059 | key_states[SDL_SCANCODE_LSHIFT] = 1; // close the splash screen using the gamepad |
||
| 2060 | } |
||
| 2061 | |||
| 2062 | } while(key == 0 && !(key_states[SDL_SCANCODE_LSHIFT] || key_states[SDL_SCANCODE_RSHIFT])); |
||
| 2063 | |||
| 2064 | if ((key & WITH_CTRL) || (enable_quicksave && key == SDL_SCANCODE_F9) || (enable_replay && key == SDL_SCANCODE_TAB)) { |
||
| 2065 | extern int last_key_scancode; // defined in seg009.c |
||
| 2066 | last_key_scancode = key; // can immediately do Ctrl+L, etc from the splash screen |
||
| 2067 | } |
||
| 2068 | key_states[SDL_SCANCODE_LSHIFT] = 0; // don't immediately start the game if shift was pressed! |
||
| 2069 | key_states[SDL_SCANCODE_RSHIFT] = 0; |
||
| 2070 | } |