/* SDLPoP, a port/conversion of the DOS game Prince of Persia. Copyright (C) 2013-2021 Dávid Nagy This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . The authors of this program may be contacted at https://forum.princed.org */ #include "common.h" // seg007:0000 void __pascal far process_trobs() { word need_delete; word index; word new_index; need_delete = 0; if (trobs_count == 0) return; for (index = 0; index < trobs_count; ++index) { trob = trobs[index]; animate_tile(); trobs[index].type = trob.type; if (trob.type < 0) { need_delete = 1; } } if (need_delete) { for (index = new_index = 0; index < trobs_count; ++index) { if (trobs[index].type >= 0) { trobs[new_index++] = trobs[index]; } } trobs_count = new_index; } } // seg007:00AF void __pascal far animate_tile() { get_room_address(trob.room); switch (get_curr_tile(trob.tilepos)) { case tiles_19_torch: case tiles_30_torch_with_debris: animate_torch(); break; case tiles_6_closer: case tiles_15_opener: animate_button(); break; case tiles_2_spike: animate_spike(); break; case tiles_11_loose: animate_loose(); break; case tiles_0_empty: animate_empty(); break; case tiles_18_chomper: animate_chomper(); break; case tiles_4_gate: animate_door(); break; case tiles_16_level_door_left: animate_leveldoor(); break; case tiles_10_potion: animate_potion(); break; case tiles_22_sword: animate_sword(); break; default: trob.type = -1; break; } curr_room_modif[trob.tilepos] = curr_modifier; } // seg007:0166 short __pascal far is_trob_in_drawn_room() { if (trob.room != drawn_room) { trob.type = -1; return 0; } else { return 1; } } // seg007:017E void __pascal far set_redraw_anim_right() { set_redraw_anim(get_trob_right_pos_in_drawn_room(), 1); } // seg007:018C void __pascal far set_redraw_anim_curr() { set_redraw_anim(get_trob_pos_in_drawn_room(), 1); } // seg007:019A void __pascal far redraw_at_trob() { word tilepos; redraw_height = 63; tilepos = get_trob_pos_in_drawn_room(); set_redraw_full(tilepos, 1); set_wipe(tilepos, 1); } // seg007:01C5 void __pascal far redraw_21h() { redraw_height = 0x21; redraw_tile_height(); } // seg007:01D0 void __pascal far redraw_11h() { redraw_height = 0x11; redraw_tile_height(); } // seg007:01DB void __pascal far redraw_20h() { redraw_height = 0x20; redraw_tile_height(); } // seg007:01E6 void __pascal far draw_trob() { word var_2; var_2 = get_trob_right_pos_in_drawn_room(); set_redraw_anim(var_2, 1); set_redraw_fore(var_2, 1); set_redraw_anim(get_trob_right_above_pos_in_drawn_room(), 1); } // seg007:0218 void __pascal far redraw_tile_height() { short tilepos; tilepos = get_trob_pos_in_drawn_room(); set_redraw_full(tilepos, 1); set_wipe(tilepos, 1); tilepos = get_trob_right_pos_in_drawn_room(); set_redraw_full(tilepos, 1); set_wipe(tilepos, 1); } // seg007:0258 short __pascal far get_trob_pos_in_drawn_room() { short tilepos; tilepos = trob.tilepos; if (trob.room == room_A) { if (tilepos >= 20 && tilepos < 30) { // 20..29 -> -1..-10 tilepos = 19 - tilepos; } else { tilepos = 30; } } else { if (trob.room != drawn_room) { tilepos = 30; } } return tilepos; } // seg007:029D short __pascal far get_trob_right_pos_in_drawn_room() { word tilepos; tilepos = trob.tilepos; if (trob.room == drawn_room) { if (tilepos % 10 != 9) { ++tilepos; } else { tilepos = 30; } } else if (trob.room == room_L) { if (tilepos % 10 == 9) { tilepos -= 9; } else { tilepos = 30; } } else if (trob.room == room_A) { if (tilepos >= 20 && tilepos < 29) { // 20..28 -> -2..-10 tilepos = 18 - tilepos; } else { tilepos = 30; } } else if (trob.room == room_AL && tilepos == 29) { tilepos = -1; } else { tilepos = 30; } return tilepos; } // seg007:032C short __pascal far get_trob_right_above_pos_in_drawn_room() { word tilepos; tilepos = trob.tilepos; if (trob.room == drawn_room) { if (tilepos % 10 != 9) { if (tilepos < 10) { // 0..8 -> -2..-10 tilepos = -(tilepos + 2); } else { tilepos -= 9; } } else { tilepos = 30; } } else if (trob.room == room_L) { if (tilepos == 9) { tilepos = -1; } else { if (tilepos % 10 == 9) { tilepos -= 19; } else { tilepos = 30; } } } else if (trob.room == room_B) { if (tilepos < 9) { tilepos += 21; } else { tilepos = 30; } } else if (trob.room == room_BL && tilepos == 9) { tilepos = 20; } else { tilepos = 30; } return tilepos; } // seg007:03CF void __pascal far animate_torch() { //if (is_trob_in_drawn_room()) { // Keep animating torches in the rightmost column of the left-side room as well, because they are visible in the current room. if (trob.room == drawn_room || (trob.room == room_L && (trob.tilepos % 10) == 9) ) { curr_modifier = get_torch_frame(curr_modifier); set_redraw_anim_right(); } else { trob.type = -1; } } // seg007:03E9 void __pascal far animate_potion() { word type; if (trob.type >= 0 && is_trob_in_drawn_room()) { type = curr_modifier & 0xF8; curr_modifier = bubble_next_frame(curr_modifier & 0x07) | type; #ifdef FIX_LOOSE_NEXT_TO_POTION redraw_at_trob(); #else set_redraw_anim_curr(); #endif } } // seg007:0425 void __pascal far animate_sword() { if (is_trob_in_drawn_room()) { --curr_modifier; if (curr_modifier == 0) { curr_modifier = (prandom(255) & 0x3F) + 0x28; } #ifdef FIX_LOOSE_NEXT_TO_POTION redraw_at_trob(); #else set_redraw_anim_curr(); #endif } } // seg007:0448 void __pascal far animate_chomper() { word blood; word frame; if (trob.type >= 0) { blood = curr_modifier & 0x80; frame = (curr_modifier & 0x7F) + 1; if (frame > /*15*/ custom->chomper_speed) { frame = 1; } curr_modifier = blood | frame; if (frame == 2) { play_sound(sound_47_chomper); // chomper } // If either: // - Kid left this room // - Kid left this row // - Kid died but not in this chomper // and chomper is past frame 6 // then stop. if ((trob.room != drawn_room || trob.tilepos / 10 != Kid.curr_row || (Kid.alive >= 0 && blood == 0)) && (curr_modifier & 0x7F) >= 6 ) { trob.type = -1; } } if ((curr_modifier & 0x7F) < 6) { redraw_at_trob(); } } // seg007:04D3 void __pascal far animate_spike() { if (trob.type >= 0) { // 0xFF means a disabled spike. if (curr_modifier == 0xFF) return; if (curr_modifier & 0x80) { --curr_modifier; if (curr_modifier & 0x7F) return; curr_modifier = 6; } else { ++curr_modifier; if (curr_modifier == 5) { curr_modifier = 0x8F; } else if (curr_modifier == 9) { curr_modifier = 0; trob.type = -1; } } } redraw_21h(); } // data:27B2 const byte gate_close_speeds[] = {0, 0, 0, 20, 40, 60, 80, 100, 120}; // data:27C0 const byte door_delta[] = {-1, 4, 4}; // seg007:0522 void __pascal far animate_door() { /* Possible values of anim_type: 0: closing 1: open 2: permanent open 3,4,5,6,7,8: fast closing with speeds 20,40,60,80,100,120 /4 pixel/frame */ sbyte anim_type; anim_type = trob.type; if (anim_type >= 0) { if (anim_type >= 3) { // closing fast if (anim_type < 8) { ++anim_type; trob.type = anim_type; } short new_mod = curr_modifier - gate_close_speeds[anim_type]; curr_modifier = new_mod; //if ((sbyte)curr_modifier < 0) { if (new_mod < 0) { //if ((curr_modifier -= gate_close_speeds[anim_type]) < 0) { curr_modifier = 0; trob.type = -1; play_sound(sound_6_gate_closing_fast); // gate closing fast } } else { if (curr_modifier != 0xFF) { // 0xFF means permanently open. curr_modifier += door_delta[anim_type]; if (anim_type == 0) { // closing if (curr_modifier != 0) { if (curr_modifier < 188) { if ((curr_modifier & 3) == 3) { play_door_sound_if_visible(sound_4_gate_closing); // gate closing } } } else { gate_stop(); } } else { // opening if (curr_modifier < 188) { if ((curr_modifier & 7) == 0) { play_sound(sound_5_gate_opening); // gate opening } } else { // stop if (anim_type < 2) { // after regular open curr_modifier = 238; trob.type = 0; // closing play_sound(sound_7_gate_stop); // gate stop (after opening) } else { // after permanent open curr_modifier = 0xFF; // keep open gate_stop(); } } } } else { gate_stop(); } } } draw_trob(); } // seg007:05E3 void __pascal far gate_stop() { trob.type = -1; play_door_sound_if_visible(sound_7_gate_stop); // gate stop (after closing) } // data:27B8 const byte leveldoor_close_speeds[] = {0, 5, 17, 99, 0}; // seg007:05F1 void __pascal far animate_leveldoor() { /* Possible values of trob_type: 0: open 1: open (with button) 2: open 3,4,5,6: fast closing with speeds 0,5,17,99 pixel/frame */ word trob_type; trob_type = trob.type; if (trob.type >= 0) { if (trob_type >= 3) { // closing ++trob.type; curr_modifier -= leveldoor_close_speeds[trob.type - 3]; if ((sbyte)curr_modifier < 0) { curr_modifier = 0; trob.type = -1; play_sound(sound_14_leveldoor_closing); // level door closing } else { if (trob.type == 4 && (sound_flags & sfDigi) ) { sound_interruptible[sound_15_leveldoor_sliding] = 1; play_sound(sound_15_leveldoor_sliding); // level door sliding (closing) } } } else { // opening ++curr_modifier; if (curr_modifier >= 43) { trob.type = -1; #ifdef FIX_FEATHER_INTERRUPTED_BY_LEVELDOOR if (!(fixes->fix_feather_interrupted_by_leveldoor && is_feather_fall)) #endif stop_sounds(); if (leveldoor_open == 0 || leveldoor_open == 2) { leveldoor_open = 1; if (current_level == /*4*/ custom->mirror_level) { // Special event: place mirror get_tile(/*4*/ custom->mirror_room, /*4*/ custom->mirror_column, /*0*/ custom->mirror_row); curr_room_tiles[curr_tilepos] = /*tiles_13_mirror*/ custom->mirror_tile; } } } else { sound_interruptible[sound_15_leveldoor_sliding] = 0; play_sound(sound_15_leveldoor_sliding); // level door sliding (opening) } } } set_redraw_anim_right(); } // seg007:06AD short __pascal far bubble_next_frame(short curr) { short next; next = curr + 1; if (next >= 8) next = 1; return next; } // seg007:06CD short __pascal far get_torch_frame(short curr) { short next; next = prandom(255); if (next != curr) { if (next < 9) { return next; } else { next = curr; } } ++next; if (next >= 9) next = 0; return next; } // seg007:070A void __pascal far set_redraw_anim(short tilepos, byte frames) { if (tilepos < 30) { if (tilepos < 0) { ++tilepos; redraw_frames_above[-tilepos] = frames; // or simply: ~tilepos } else { redraw_frames_anim[tilepos] = frames; } } } // seg007:0738 void __pascal far set_redraw2(short tilepos, byte frames) { if (tilepos < 30) { if (tilepos < 0) { // trying to draw a mob at a negative tilepos, in the range -1 .. -10 // used e.g. when the kid is climbing up to the room above // however, loose tiles falling out of the room end up with a negative tilepos {-2 .. -11} ! tilepos = (-tilepos) - 1; if (tilepos > 9) tilepos = 9; // prevent array index out of bounds! redraw_frames_above[tilepos] = frames; } else { redraw_frames2[tilepos] = frames; } } } // seg007:0766 void __pascal far set_redraw_floor_overlay(short tilepos, byte frames) { if (tilepos < 30) { if (tilepos < 0) { ++tilepos; redraw_frames_above[-tilepos] = frames; // or simply: ~tilepos } else { redraw_frames_floor_overlay[tilepos] = frames; } } } // seg007:0794 void __pascal far set_redraw_full(short tilepos, byte frames) { if (tilepos < 30) { if (tilepos < 0) { ++tilepos; redraw_frames_above[-tilepos] = frames; // or simply: ~tilepos } else { redraw_frames_full[tilepos] = frames; } } } // seg007:07C2 void __pascal far set_redraw_fore(short tilepos, byte frames) { if (tilepos < 30 && tilepos >= 0) { redraw_frames_fore[tilepos] = frames; } } // seg007:07DF void __pascal far set_wipe(short tilepos, byte frames) { if (tilepos < 30 && tilepos >= 0) { if (wipe_frames[tilepos] != 0) { redraw_height = MAX(wipe_heights[tilepos], redraw_height); } wipe_heights[tilepos] = redraw_height; wipe_frames[tilepos] = frames; } } // seg007:081E void __pascal far start_anim_torch(short room,short tilepos) { curr_room_modif[tilepos] = prandom(8); add_trob(room, tilepos, 1); } // seg007:0847 void __pascal far start_anim_potion(short room,short tilepos) { curr_room_modif[tilepos] &= 0xF8; curr_room_modif[tilepos] |= prandom(6) + 1; add_trob(room, tilepos, 1); } // seg007:087C void __pascal far start_anim_sword(short room,short tilepos) { curr_room_modif[tilepos] = prandom(0xFF) & 0x1F; add_trob(room, tilepos, 1); } // seg007:08A7 void __pascal far start_anim_chomper(short room,short tilepos, byte modifier) { short old_modifier; old_modifier = curr_room_modif[tilepos]; if (old_modifier == 0 || old_modifier >= 6) { curr_room_modif[tilepos] = modifier; add_trob(room, tilepos, 1); } } // seg007:08E3 void __pascal far start_anim_spike(short room,short tilepos) { sbyte old_modifier; old_modifier = curr_room_modif[tilepos]; if (old_modifier <= 0) { if (old_modifier == 0) { add_trob(room, tilepos, 1); play_sound(sound_49_spikes); // spikes } else { // 0xFF means a disabled spike. if (old_modifier != (sbyte)0xFF) { curr_room_modif[tilepos] = 0x8F; } } } } // seg007:092C short __pascal far trigger_gate(short room,short tilepos,short button_type) { byte modifier; modifier = curr_room_modif[tilepos]; if (button_type == tiles_15_opener) { // If the gate is permanently open, don't to anything. if (modifier == 0xFF) return -1; if (modifier >= 188) { // if it's already open curr_room_modif[tilepos] = 238; // keep it open for a while return -1; } curr_room_modif[tilepos] = (modifier + 3) & 0xFC; return 1; // regular open } else if (button_type == tiles_14_debris) { // If it's not fully open: if (modifier < 188) return 2; // permanent open curr_room_modif[tilepos] = 0xFF; // keep open return -1; } else { if (modifier != 0) { return 3; // close fast } else { // already closed return -1; } } } // seg007:0999 short __pascal far trigger_1(short target_type,short room,short tilepos,short button_type) { short result; result = -1; if (target_type == tiles_4_gate) { result = trigger_gate(room, tilepos, button_type); } else if (target_type == tiles_16_level_door_left) { if (curr_room_modif[tilepos] != 0) { result = -1; } else { result = 1; } } else if (custom->allow_triggering_any_tile) { //allow_triggering_any_tile hack result = 1; } return result; } // seg007:09E5 void __pascal far do_trigger_list(short index,short button_type) { word room; word tilepos; byte target_type; sbyte trigger_result; // while (doorlink1_ad[index] != -1) { // these can't be equal! while (1) { // Same as the above but just a little faster and no compiler warning. room = get_doorlink_room(index); get_room_address(room); tilepos = get_doorlink_tile(index); target_type = curr_room_tiles[tilepos] & 0x1F; trigger_result = trigger_1(target_type, room, tilepos, button_type); if (trigger_result >= 0) { add_trob(room, tilepos, trigger_result); } if (get_doorlink_next(index++) == 0) break; } } // seg007:0A5A void __pascal far add_trob(byte room,byte tilepos,sbyte type) { short found; if (trobs_count >= 30) { show_dialog("Trobs Overflow"); return /*0*/; // added } trob.room = room; trob.tilepos = tilepos; trob.type = type; found = find_trob(); if (found == -1) { // add new if (trobs_count == 30) return; trobs[trobs_count++] = trob; } else { // change existing trobs[found].type = trob.type; } } // seg007:0ACA short __pascal far find_trob() { short index; for (index = 0; index < trobs_count; ++index) { if (trobs[index].tilepos == trob.tilepos && trobs[index].room == trob.room) return index; } return -1; } // seg007:0B0A void __pascal far clear_tile_wipes() { memset_near(redraw_frames_full, 0, sizeof(redraw_frames_full)); memset_near(wipe_frames, 0, sizeof(wipe_frames)); memset_near(wipe_heights, 0, sizeof(wipe_heights)); memset_near(redraw_frames_anim, 0, sizeof(redraw_frames_anim)); memset_near(redraw_frames_fore, 0, sizeof(redraw_frames_fore)); memset_near(redraw_frames2, 0, sizeof(redraw_frames2)); memset_near(redraw_frames_floor_overlay, 0, sizeof(redraw_frames_floor_overlay)); memset_near(tile_object_redraw, 0, sizeof(tile_object_redraw)); memset_near(redraw_frames_above, 0, sizeof(redraw_frames_above)); } // seg007:0BB6 short __pascal far get_doorlink_timer(short index) { return doorlink2_ad[index] & 0x1F; } // seg007:0BCD short __pascal far set_doorlink_timer(short index,byte value) { doorlink2_ad[index] &= 0xE0; doorlink2_ad[index] |= value & 0x1F; return doorlink2_ad[index]; } // seg007:0BF2 short __pascal far get_doorlink_tile(short index) { return doorlink1_ad[index] & 0x1F; } // seg007:0C09 short __pascal far get_doorlink_next(short index) { return !(doorlink1_ad[index] & 0x80); } // seg007:0C26 short __pascal far get_doorlink_room(short index) { return ((doorlink1_ad[index] & 0x60) >> 5) + ((doorlink2_ad[index] & 0xE0) >> 3); } // seg007:0C53 void __pascal far trigger_button(int playsound,int button_type,int modifier) { sbyte link_timer; get_curr_tile(curr_tilepos); if (button_type == 0) { // 0 means currently selected button_type = curr_tile; } if (modifier == -1) { // -1 means currently selected modifier = curr_modifier; } link_timer = get_doorlink_timer(modifier); // is the event jammed? if (link_timer != 0x1F) { set_doorlink_timer(modifier, 5); if (link_timer < 2) { add_trob(curr_room, curr_tilepos, 1); redraw_11h(); is_guard_notice = 1; if (playsound) { play_sound(sound_3_button_pressed); // button pressed } } do_trigger_list(modifier, button_type); } } // seg007:0CD9 void __pascal far died_on_button() { word button_type; word modifier; button_type = get_curr_tile(curr_tilepos); modifier = curr_modifier; if (curr_tile == tiles_15_opener) { curr_room_tiles[curr_tilepos] = tiles_1_floor; curr_room_modif[curr_tilepos] = 0; button_type = tiles_14_debris; // force permanent open } else { curr_room_tiles[curr_tilepos] = tiles_5_stuck; } trigger_button(1, button_type, modifier); } // seg007:0D3A void __pascal far animate_button() { word var_2; if (trob.type >= 0) { set_doorlink_timer(curr_modifier, var_2 = get_doorlink_timer(curr_modifier) - 1); if (var_2 < 2) { trob.type = -1; redraw_11h(); } } } // seg007:0D72 void __pascal far start_level_door(short room,short tilepos) { curr_room_modif[tilepos] = 43; // start fully open add_trob(room, tilepos, 3); } // seg007:0D93 void __pascal far animate_empty() { trob.type = -1; redraw_20h(); } // data:2284 const word y_loose_land[] = {2, 65, 128, 191, 254}; // seg007:0D9D void __pascal far animate_loose() { word room; word row; word tilepos; short anim_type; anim_type = trob.type; if (anim_type >= 0) { ++curr_modifier; if (curr_modifier & 0x80) { // just shaking // don't stop on level 13, needed for the auto-falling floors if (current_level == 13) return; if (curr_modifier >= 0x84) { curr_modifier = 0; trob.type = -1; } loose_shake(!curr_modifier); } else { // something is on the floor // should it fall already? if (curr_modifier >= /*11*/ custom->loose_floor_delay) { curr_modifier = remove_loose(room = trob.room, tilepos = trob.tilepos); trob.type = -1; curmob.xh = (tilepos % 10) << 2; row = tilepos / 10; curmob.y = y_loose_land[row + 1]; curmob.room = room; curmob.speed = 0; curmob.type = 0; curmob.row = row; add_mob(); } else { loose_shake(0); } } } redraw_20h(); } // data:2734 const byte loose_sound[] = {0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0}; // seg007:0E55 void __pascal far loose_shake(int arg_0) { word sound_id; if (arg_0 || loose_sound[curr_modifier & 0x7F]) { do { // Sounds 20,21,22: loose floor shaking sound_id = prandom(2) + sound_20_loose_shake_1; } while(sound_id == last_loose_sound); #ifdef USE_REPLAY // Skip this prandom call if we are replaying, and the replay file was made with an old version of SDLPoP (which didn't have this call). if (!(replaying && g_deprecation_number < 2)) #endif { prandom(2); // For vanilla pop compatibility, an RNG cycle is wasted here // Note: In DOS PoP, it's wasted a few lines below. } if (sound_flags & sfDigi) { last_loose_sound = sound_id; // random sample rate (10500..11500) //sound_pointers[sound_id]->samplerate = prandom(1000) + 10500; } play_sound(sound_id); } } // seg007:0EB8 int __pascal far remove_loose(int room, int tilepos) { curr_room_tiles[tilepos] = tiles_0_empty; // note: the level type is used to determine the modifier of the empty space left behind return custom->tbl_level_type[current_level]; } // seg007:0ED5 void __pascal far make_loose_fall(byte modifier) { // is it a "solid" loose floor? if ((curr_room_tiles[curr_tilepos] & 0x20) == 0) { if ((sbyte)curr_room_modif[curr_tilepos] <= 0) { curr_room_modif[curr_tilepos] = modifier; add_trob(curr_room, curr_tilepos, 0); redraw_20h(); } } } // seg007:0F13 void __pascal far start_chompers() { short timing; short modifier; short tilepos; short column; timing = 15; if ((byte)Char.curr_row < 3) { get_room_address(Char.room); for (column = 0, tilepos = tbl_line[Char.curr_row]; column < 10; ++column, ++tilepos ){ if (get_curr_tile(tilepos) == tiles_18_chomper) { modifier = curr_modifier & 0x7F; if (modifier == 0 || modifier >= 6) { start_anim_chomper(Char.room, tilepos, timing | (curr_modifier & 0x80)); timing = next_chomper_timing(timing); } } } } } // seg007:0F9A int __pascal far next_chomper_timing(byte timing) { // 15,12,9,6,13,10,7,14,11,8,repeat timing -= 3; if (timing < 6) { timing += 10; } return timing; } // seg007:0FB4 void __pascal far loose_make_shake() { // don't shake on level 13 if (curr_room_modif[curr_tilepos] == 0 && current_level != 13) { curr_room_modif[curr_tilepos] = 0x80; add_trob(curr_room, curr_tilepos, 1); } } // seg007:0FE0 void __pascal far do_knock(int room,int tile_row) { short tile_col; for (tile_col = 0; tile_col < 10; ++tile_col) { if (get_tile(room, tile_col, tile_row) == tiles_11_loose) { loose_make_shake(); } } } // seg007:1010 void __pascal far add_mob() { if (mobs_count >= 14) { show_dialog("Mobs Overflow"); return /*0*/; // added } mobs[mobs_count++] = curmob; } // seg007:1041 short __pascal far get_curr_tile(short tilepos) { curr_modifier = curr_room_modif[tilepos]; return curr_tile = curr_room_tiles[tilepos] & 0x1F; } // data:43DC word curmob_index; // seg007:1063 void __pascal far do_mobs() { short n_mobs; short index; short new_index; n_mobs = mobs_count; for (curmob_index = 0; n_mobs > curmob_index; ++curmob_index) { curmob = mobs[curmob_index]; move_mob(); check_loose_fall_on_kid(); mobs[curmob_index] = curmob; } new_index = 0; for (index = 0; index < mobs_count; ++index) { if (mobs[index].speed != -1) { mobs[new_index++] = mobs[index]; } } mobs_count = new_index; } // seg007:110F void __pascal far move_mob() { if (curmob.type == 0) { move_loose(); } if (curmob.speed <= 0) { ++curmob.speed; } } // data:227A const short y_something[] = {-1, 62, 125, 188, 25}; // data:594A word curr_tile_temp; // seg007:1126 void __pascal far move_loose() { if (curmob.speed < 0) return; if (curmob.speed < 29) curmob.speed += 3; curmob.y += curmob.speed; if (curmob.room == 0) { if (curmob.y < 210) { return; } else { curmob.speed = -2; return; } } if (curmob.y < 226 && y_something[curmob.row + 1] <= curmob.y) { // fell into a different row curr_tile_temp = get_tile(curmob.room, curmob.xh >> 2, curmob.row); if (curr_tile_temp == tiles_11_loose) { loose_fall(); } if (curr_tile_temp == tiles_0_empty || curr_tile_temp == tiles_11_loose ) { mob_down_a_row(); return; } play_sound(sound_2_tile_crashing); // tile crashing do_knock(curmob.room, curmob.row); curmob.y = y_something[curmob.row + 1]; curmob.speed = -2; loose_land(); } } // seg007:11E8 void __pascal far loose_land() { short button_type; short tiletype; button_type = 0; tiletype = get_tile(curmob.room, curmob.xh >> 2, curmob.row); switch (tiletype) { case tiles_15_opener: curr_room_tiles[curr_tilepos] = tiles_14_debris; button_type = tiles_14_debris; // fallthrough! case tiles_6_closer: trigger_button(1, button_type, -1); tiletype = get_tile(curmob.room, curmob.xh >> 2, curmob.row); // fallthrough! case tiles_1_floor: case tiles_2_spike: case tiles_10_potion: case tiles_19_torch: case tiles_30_torch_with_debris: if (tiletype == tiles_19_torch || tiletype == tiles_30_torch_with_debris ) { curr_room_tiles[curr_tilepos] = tiles_30_torch_with_debris; } else { curr_room_tiles[curr_tilepos] = tiles_14_debris; } redraw_at_cur_mob(); if (tile_col != 0) { set_redraw_full(curr_tilepos - 1, 1); } } } // seg007:12CB void __pascal far loose_fall() { curr_room_modif[curr_tilepos] = remove_loose(curr_room, curr_tilepos); curmob.speed >>= 1; mobs[curmob_index] = curmob; curmob.y += 6; mob_down_a_row(); add_mob(); curmob = mobs[curmob_index]; redraw_at_cur_mob(); } // seg007:132C void __pascal far redraw_at_cur_mob() { if (curmob.room == drawn_room) { redraw_height = 0x20; set_redraw_full(curr_tilepos, 1); set_wipe(curr_tilepos, 1); // Redraw tile to the right only if it's in the same room. if ((curr_tilepos % 10) + 1 < 10) { // changed set_redraw_full(curr_tilepos + 1, 1); set_wipe(curr_tilepos + 1, 1); } } } // seg007:1387 void __pascal far mob_down_a_row() { ++curmob.row; if (curmob.row >= 3) { curmob.y -= 192; curmob.row = 0; curmob.room = level.roomlinks[curmob.room - 1].down; } } // seg007:13AE void __pascal far draw_mobs() { short index; for (index = 0; index < mobs_count; ++index) { curmob = mobs[index]; draw_mob(); } } // seg007:13E5 void __pascal far draw_mob() { short tile_row; short ypos; short top_row; short tilepos; short tile_col; ypos = curmob.y; if (curmob.room == drawn_room) { if (curmob.y >= 210) return; } else if (curmob.room == room_B) { if (ABS((sbyte)ypos) >= 18) return; curmob.y += 192; ypos = curmob.y; } else if (curmob.room == room_A) { if (curmob.y < 174) return; ypos = curmob.y - 189; } else { return; } tile_col = curmob.xh >> 2; tile_row = y_to_row_mod4(ypos); obj_tilepos = get_tilepos_nominus(tile_col, tile_row); ++tile_col; tilepos = get_tilepos(tile_col, tile_row); set_redraw2(tilepos, 1); set_redraw_fore(tilepos, 1); top_row = y_to_row_mod4(ypos - 18); if (top_row != tile_row) { tilepos = get_tilepos(tile_col, top_row); set_redraw2(tilepos, 1); set_redraw_fore(tilepos, 1); } add_mob_to_objtable(ypos); } // seg007:14DE void __pascal far add_mob_to_objtable(int ypos) { word index; objtable_type* curr_obj; index = objtable_count++; curr_obj = &objtable[index]; curr_obj->obj_type = curmob.type | 0x80; curr_obj->xh = curmob.xh; curr_obj->xl = 0; curr_obj->y = ypos; curr_obj->chtab_id = id_chtab_6_environment; curr_obj->id = 10; curr_obj->clip.top = 0; curr_obj->clip.left = 0; curr_obj->clip.right = 40; mark_obj_tile_redraw(index); } // seg007:153E void __pascal far sub_9A8E() { // This function is not used. method_1_blit_rect(onscreen_surface_, offscreen_surface, &rect_top, &rect_top, 0); } // seg007:1556 int __pascal far is_spike_harmful() { sbyte modifier; modifier = curr_room_modif[curr_tilepos]; if (modifier == 0 || modifier == -1) { return 0; } else if (modifier < 0) { return 1; } else if (modifier < 5) { return 2; } else { return 0; } } // seg007:1591 void __pascal far check_loose_fall_on_kid() { loadkid(); if (Char.room == curmob.room && Char.curr_col == curmob.xh >> 2 && curmob.y < Char.y && Char.y - 30 < curmob.y ) { fell_on_your_head(); savekid(); } } // seg007:15D3 void __pascal far fell_on_your_head() { short frame; short action; frame = Char.frame; action = Char.action; // loose floors hurt you in frames 5..14 (running) only on level 13 if ( (current_level == 13 || (frame < frame_5_start_run || frame >= 15)) && (action < actions_2_hang_climb || action == actions_7_turn) ) { Char.y = y_land[Char.curr_row + 1]; if (take_hp(1)) { seqtbl_offset_char(seq_22_crushed); // dead (because of loose floor) if (frame == frame_177_spiked) { // spiked Char.x = char_dx_forward(-12); } } else { if (frame != frame_109_crouch) { // crouching if (get_tile_behind_char() == 0) { Char.x = char_dx_forward(-2); } seqtbl_offset_char(seq_52_loose_floor_fell_on_kid); // loose floor fell on Kid } } } } // seg007:1669 void __pascal far play_door_sound_if_visible(int sound_id) { word has_sound; word tilepos; word gate_room; tilepos = trob.tilepos; gate_room = trob.room; has_sound = 0; #ifdef FIX_GATE_SOUNDS sbyte has_sound_condition; if (fixes->fix_gate_sounds) has_sound_condition = (gate_room == room_L && tilepos % 10 == 9) || (gate_room == drawn_room && tilepos % 10 != 9); else has_sound_condition = gate_room == room_L ? tilepos % 10 == 9 : (gate_room == drawn_room && tilepos % 10 != 9); #define GATE_SOUND_CONDITION has_sound_condition #else #define GATE_SOUND_CONDITION gate_room == room_L ? tilepos % 10 == 9 : \ (gate_room == drawn_room && tilepos % 10 != 9) #endif // Special event: sound of closing gates if ((current_level == 3 && gate_room == 2) || GATE_SOUND_CONDITION) { has_sound = 1; } if (has_sound) { play_sound(sound_id); } }