- /* 
- SDLPoP, a port/conversion of the DOS game Prince of Persia. 
- Copyright (C) 2013-2018  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 <http://www.gnu.org/licenses/>. 
-   
- The authors of this program may be contacted at http://forum.princed.org 
- */ 
-   
- #include "common.h" 
-   
- // data:432F 
- sbyte bump_col_left_of_wall; 
- // data:436E 
- sbyte bump_col_right_of_wall; 
- // data:4C0A 
- sbyte right_checked_col; 
- // data:408A 
- sbyte left_checked_col; 
-   
-   
- // data:4C0C 
- short coll_tile_left_xpos; 
- // These two arrays are indexed with the return value of wall_type. 
- // data:24BA 
- const sbyte wall_dist_from_left[] = {0, 10, 0, -1, 0, 0}; 
- // data:24C0 
- const sbyte wall_dist_from_right[] = {0, 0, 10, 13, 0, 0}; 
-   
- // seg004:0004 
- void __pascal far check_collisions() { 
-         short column; 
-         bump_col_left_of_wall = bump_col_right_of_wall = -1; 
-         if (Char.action == actions_7_turn) return; 
-         collision_row = Char.curr_row; 
-         move_coll_to_prev(); 
-         prev_collision_row = collision_row; 
-         right_checked_col = MIN(get_tile_div_mod_m7(char_x_right_coll) + 2, 11); 
-         left_checked_col = get_tile_div_mod_m7(char_x_left_coll) - 1; 
-         get_row_collision_data(collision_row    , curr_row_coll_room, curr_row_coll_flags); 
-         get_row_collision_data(collision_row + 1, below_row_coll_room, below_row_coll_flags); 
-         get_row_collision_data(collision_row - 1, above_row_coll_room, above_row_coll_flags); 
-         for (column = 9; column >= 0; --column) { 
-                 if (curr_row_coll_room[column] >= 0 && 
-                         prev_coll_room[column] == curr_row_coll_room[column] 
-                 ) { 
-                         // char bumps into left of wall 
-                         if ( 
-                                 (prev_coll_flags[column] & 0x0F) == 0 && 
-                                 (curr_row_coll_flags[column] & 0x0F) != 0 
-                         ) { 
-                                 bump_col_left_of_wall = column; 
-                         } 
-                         // char bumps into right of wall 
-                         if ( 
-                                 (prev_coll_flags[column] & 0xF0) == 0 && 
-                                 (curr_row_coll_flags[column] & 0xF0) != 0 
-                         ) { 
-                                 bump_col_right_of_wall = column; 
-                         } 
-                 } 
-         } 
- } 
-   
- // seg004:00DF 
- void __pascal far move_coll_to_prev() { 
-         sbyte* row_coll_room_ptr; 
-         byte* row_coll_flags_ptr; 
-         short column; 
-         if (collision_row     == prev_collision_row || 
-                 collision_row + 3 == prev_collision_row || 
-                 collision_row - 3 == prev_collision_row 
-         ) { 
-                 row_coll_room_ptr = curr_row_coll_room; 
-                 row_coll_flags_ptr = curr_row_coll_flags; 
-         } else if ( 
-                 collision_row + 1 == prev_collision_row || 
-                 collision_row - 2 == prev_collision_row 
-         ) { 
-                 row_coll_room_ptr = above_row_coll_room; 
-                 row_coll_flags_ptr = above_row_coll_flags; 
-         } else { 
-                 row_coll_room_ptr = below_row_coll_room; 
-                 row_coll_flags_ptr = below_row_coll_flags; 
-         } 
-         for (column = 0; column < 10; ++column) { 
-                 prev_coll_room[column] = row_coll_room_ptr[column]; 
-                 prev_coll_flags[column] = row_coll_flags_ptr[column]; 
-                 below_row_coll_room[column] = -1; 
-                 above_row_coll_room[column] = -1; 
-                 curr_row_coll_room[column] = -1; 
-                 // bugfix: 
-                 curr_row_coll_flags[column] = 0; 
-                 below_row_coll_flags[column] = 0; 
-                 above_row_coll_flags[column] = 0; 
-         } 
- } 
-   
- // seg004:0185 
- void __pascal far get_row_collision_data(short row, sbyte *row_coll_room_ptr, byte *row_coll_flags_ptr) { 
-         short right_wall_xpos; 
-         byte curr_flags; 
-         short room; 
-         short column; 
-         short left_wall_xpos; 
-         room = Char.room; 
-         coll_tile_left_xpos = x_bump[left_checked_col + 5] + 7; 
-         for (column = left_checked_col; column <= right_checked_col; ++column) { 
-                 left_wall_xpos = get_left_wall_xpos(room, column, row); 
-                 right_wall_xpos = get_right_wall_xpos(room, column, row); 
-                 // char bumps into left of wall 
-                 curr_flags = (left_wall_xpos < char_x_right_coll) * 0x0F; 
-                 // char bumps into right of wall 
-                 curr_flags |= (right_wall_xpos > char_x_left_coll) * 0xF0; 
-                 row_coll_flags_ptr[tile_col] = curr_flags; 
-                 row_coll_room_ptr[tile_col] = curr_room; 
-                 coll_tile_left_xpos += 14; 
-         } 
- } 
-   
- // seg004:0226 
- int __pascal far get_left_wall_xpos(int room,int column,int row) { 
-         short type; 
-         type = wall_type(get_tile(room, column, row)); 
-         if (type) { 
-                 return wall_dist_from_left[type] + coll_tile_left_xpos; 
-         } else { 
-                 return 0xFF; 
-         } 
- } 
-   
- // seg004:025F 
- int __pascal far get_right_wall_xpos(int room,int column,int row) { 
-         short type; 
-         type = wall_type(get_tile(room, column, row)); 
-         if (type) { 
-                 return coll_tile_left_xpos - wall_dist_from_right[type] + 13; 
-         } else { 
-                 return 0; 
-         } 
- } 
-   
- // seg004:029D 
- void __pascal far check_bumped() { 
-         if ( 
-                 Char.action != actions_2_hang_climb && 
-                 Char.action != actions_6_hang_straight && 
-                 // frames 135..149: climb up 
-                 (Char.frame < frame_135_climbing_1 || Char.frame >= 149) 
-         ) { 
- #ifdef FIX_TWO_COLL_BUG 
-                 if (bump_col_left_of_wall >= 0) { 
-                         check_bumped_look_right(); 
-                         if (!fix_two_coll_bug) return; // check for the left-oriented collision only with the fix enabled 
-                 } 
-                 if (bump_col_right_of_wall >= 0) { 
-                         check_bumped_look_left(); 
-                 } 
- #else 
-                 if (bump_col_left_of_wall >= 0) { 
-                         check_bumped_look_right(); 
-                 } 
-                 else 
-                 if (bump_col_right_of_wall >= 0) { 
-                         check_bumped_look_left(); 
-                 } 
- #endif // FIX_TWO_COLL_BUG 
-   
-         } 
- } 
-   
- // seg004:02D2 
- void __pascal far check_bumped_look_left() { 
-         if ((Char.sword == sword_2_drawn || Char.direction < dir_0_right) && // looking left 
-                 is_obstacle_at_col(bump_col_right_of_wall) 
-         ) { 
-                 bumped(get_right_wall_xpos(curr_room, tile_col, tile_row) - char_x_left_coll, dir_0_right); 
-         } 
- } 
-   
- // seg004:030A 
- void __pascal far check_bumped_look_right() { 
-         if ((Char.sword == sword_2_drawn || Char.direction == dir_0_right) && // looking right 
-                 is_obstacle_at_col(bump_col_left_of_wall) 
-         ) { 
-                 bumped(get_left_wall_xpos(curr_room, tile_col, tile_row) - char_x_right_coll, dir_FF_left); 
-         } 
- } 
-   
- // seg004:0343 
- int __pascal far is_obstacle_at_col(int tile_col) { 
-         short tile_row; 
-         tile_row = Char.curr_row; 
-         if (tile_row < 0) { 
-                 tile_row += 3; 
-         } 
-         if (tile_row >= 3) { 
-                 tile_row -= 3; 
-         } 
-         get_tile(curr_row_coll_room[tile_col], tile_col, tile_row); 
-         return is_obstacle(); 
- } 
-   
- // seg004:037E 
- int __pascal far is_obstacle() { 
-         if (curr_tile2 == tiles_10_potion) { 
-                 return 0; 
-         } else if (curr_tile2 == tiles_4_gate) { 
-                 if (! can_bump_into_gate()) return 0; 
-         } else if (curr_tile2 == tiles_18_chomper) { 
-                 // is the chomper closed? 
-                 if (curr_room_modif[curr_tilepos] != 2) return 0; 
-         } else if ( 
-                 curr_tile2 == tiles_13_mirror && 
-                 Char.charid == charid_0_kid && 
-                 Char.frame >= frame_39_start_run_jump_6 && Char.frame < frame_44_running_jump_5 && // run-jump 
-                 Char.direction < dir_0_right // right-to-left only 
-         ) { 
-                 curr_room_modif[curr_tilepos] = 0x56; // broken mirror or what? 
-                 jumped_through_mirror = -1; 
-                 return 0; 
-         } 
-         coll_tile_left_xpos = xpos_in_drawn_room(x_bump[tile_col + 5]) + 7; 
-         return 1; 
- } 
-   
- // seg004:0405 
- int __pascal far xpos_in_drawn_room(int xpos) { 
-         if (curr_room != drawn_room) { 
-                 if (curr_room == room_L || curr_room == room_BL) { 
-                         xpos -= 140; 
-                 } else if (curr_room == room_R || curr_room == room_BR) { 
-                         xpos += 140; 
-                 } 
-         } 
-         return xpos; 
- } 
-   
- // seg004:0448 
- void __pascal far bumped(sbyte delta_x,sbyte push_direction) { 
-         // frame 177: spiked 
-         if (Char.alive < 0 && Char.frame != frame_177_spiked) { 
-                 Char.x += delta_x; 
-                 if (push_direction < dir_0_right) { 
-                         // pushing left 
-                         if (curr_tile2 == tiles_20_wall) { 
-                                 get_tile(curr_room, --tile_col, tile_row); 
-                         } 
-                 } else { 
-                         // pushing right 
-                         if (curr_tile2 == tiles_12_doortop || 
-                                 curr_tile2 == tiles_7_doortop_with_floor || 
-                                 curr_tile2 == tiles_20_wall 
-                         ) { 
-                                 ++tile_col; 
-                                 if (curr_room == 0 && tile_col == 10) { 
-                                         curr_room = Char.room; 
-                                         tile_col = 0; 
-                                 } 
-                                 get_tile(curr_room, tile_col, tile_row); 
-                         } 
-                 } 
-                 if (tile_is_floor(curr_tile2)) { 
-                         bumped_floor(push_direction); 
-                 } else { 
-                         bumped_fall(); 
-                 } 
-         } 
- } 
-   
- // seg004:04E4 
- void __pascal far bumped_fall() { 
-         short action; 
-         action = Char.action; 
-         Char.x = char_dx_forward(-4); 
-         if (action == actions_4_in_freefall) { 
-                 Char.fall_x = 0; 
-         } else { 
-                 seqtbl_offset_char(seq_45_bumpfall); // fall after bumped 
-                 play_seq(); 
-         } 
-         bumped_sound(); 
- } 
-   
- // seg004:0520 
- void __pascal far bumped_floor(sbyte push_direction) { 
-         short frame; 
-         short seq_index; 
-         if (Char.sword != sword_2_drawn && (word)(y_land[Char.curr_row + 1] - Char.y) >= (word)15) { 
-                 bumped_fall(); 
-         } else { 
-                 Char.y = y_land[Char.curr_row + 1]; 
-                 if (Char.fall_y >= 22) { 
-                         Char.x = char_dx_forward(-5); 
-                 } else { 
-                         Char.fall_y = 0; 
-                         if (Char.alive) { 
-                                 if (Char.sword == sword_2_drawn) { 
-                                         if (push_direction == Char.direction) { 
-                                                 seqtbl_offset_char(seq_65_bump_forward_with_sword); // pushed forward with sword (Kid) 
-                                                 play_seq(); 
-                                                 Char.x = char_dx_forward(1); 
-                                                 return; 
-                                         } else { 
-                                                 seq_index = seq_64_pushed_back_with_sword; // pushed back with sword 
-                                         } 
-                                 } else { 
-                                         frame = Char.frame; 
-                                         if (frame == 24 || frame == 25 || 
-                                                 (frame >= 40 && frame < 43) || 
-                                                 (frame >= frame_102_start_fall_1 && frame < 107) 
-                                         ) { 
-                                                 seq_index = seq_46_hardbump; // bump into wall after run-jump (crouch) 
-                                         } else { 
-                                                 seq_index = seq_47_bump; // bump into wall 
-                                         } 
-                                 } 
-                                 seqtbl_offset_char(seq_index); 
-                                 play_seq(); 
-                                 bumped_sound(); 
-                         } 
-                 } 
-         } 
- } 
-   
- // seg004:05F1 
- void __pascal far bumped_sound() { 
-         is_guard_notice = 1; 
-         play_sound(sound_8_bumped); // touching a wall 
- } 
-   
- // seg004:0601 
- void __pascal far clear_coll_rooms() { 
-         memset_near(prev_coll_room, -1, sizeof(prev_coll_room)); 
-         memset_near(curr_row_coll_room, -1, sizeof(curr_row_coll_room)); 
-         memset_near(below_row_coll_room, -1, sizeof(below_row_coll_room)); 
-         memset_near(above_row_coll_room, -1, sizeof(above_row_coll_room)); 
-         // workaround 
-         memset_near(prev_coll_flags, 0, sizeof(prev_coll_flags)); 
-         memset_near(curr_row_coll_flags, 0, sizeof(curr_row_coll_flags)); 
-         memset_near(below_row_coll_flags, 0, sizeof(below_row_coll_flags)); 
-         memset_near(above_row_coll_flags, 0, sizeof(above_row_coll_flags)); 
-         prev_collision_row = -1; 
- } 
-   
- // seg004:0657 
- int __pascal far can_bump_into_gate() { 
-         return (curr_room_modif[curr_tilepos] >> 2) + 6 < char_height; 
- } 
-   
- // seg004:067C 
- int __pascal far get_edge_distance() { 
- /* 
- Possible results in edge_type: 
- 0: closer/sword/potion 
- 1: edge 
- 2: floor (nothing near char) 
- */ 
-         short distance; 
-         byte tiletype; 
-         determine_col(); 
-         load_frame_to_obj(); 
-         set_char_collision(); 
-         tiletype = get_tile_at_char(); 
-         if (wall_type(tiletype) != 0) { 
-                 tile_col = Char.curr_col; 
-                 distance = dist_from_wall_forward(tiletype); 
-                 if (distance >= 0) { 
-                         loc_59DD: 
-                         if (distance < 14) { 
-                                 edge_type = 1; 
-                         } else { 
-                                 edge_type = 2; 
-                                 distance = 11; 
-                         } 
-                 } else { 
-                         goto loc_59E8; 
-                 } 
-         } else { 
-                 loc_59E8: 
-                 tiletype = get_tile_infrontof_char(); 
-                 if (tiletype == tiles_12_doortop && Char.direction >= dir_0_right) { 
-                         loc_59FB: 
-                         edge_type = 0; 
-                         distance = distance_to_edge_weight(); 
-                 } else { 
-                         if (wall_type(tiletype) != 0) { 
-                                 tile_col = infrontx; 
-                                 distance = dist_from_wall_forward(tiletype); 
-                                 if (distance >= 0) goto loc_59DD; 
-                         } 
-                         if (tiletype == tiles_11_loose) goto loc_59FB; 
-                         if ( 
-                                 tiletype == tiles_6_closer || 
-                                 tiletype == tiles_22_sword || 
-                                 tiletype == tiles_10_potion 
-                         ) { 
-                                 distance = distance_to_edge_weight(); 
-                                 if (distance != 0) { 
-                                         edge_type = 0; 
-                                 } else { 
-                                         edge_type = 2; 
-                                         distance = 11; 
-                                 } 
-                         } else { 
-                                 if (tile_is_floor(tiletype)) { 
-                                         edge_type = 2; 
-                                         distance = 11; 
-                                 } else { 
-                                         goto loc_59FB; 
-                                 } 
-                         } 
-                 } 
-         } 
-         curr_tile2 = tiletype; 
-         return distance; 
- } 
-   
- // seg004:076B 
- void __pascal far check_chomped_kid() { 
-         short tile_col; 
-         short tile_row; 
-         tile_row = Char.curr_row; 
-         for (tile_col = 0; tile_col < 10; ++tile_col) { 
-                 if (curr_row_coll_flags[tile_col] == 0xFF && 
-                         get_tile(curr_row_coll_room[tile_col], tile_col, tile_row) == tiles_18_chomper && 
-                         (curr_room_modif[curr_tilepos] & 0x7F) == 2 // closed chomper 
-                 ) { 
-                         chomped(); 
-                 } 
-         } 
- } 
-   
- // seg004:07BF 
- void __pascal far chomped() { 
-         #ifdef FIX_SKELETON_CHOMPER_BLOOD 
-         if (!(fix_skeleton_chomper_blood && Char.charid == charid_4_skeleton)) 
-         #endif 
-                 curr_room_modif[curr_tilepos] |= 0x80; // put blood 
-         if (Char.frame != frame_178_chomped && Char.room == curr_room) { 
-                 Char.x = x_bump[tile_col + 5] + 7; 
-                 Char.x = char_dx_forward(7 - !Char.direction); 
-                 Char.y = y_land[Char.curr_row + 1]; 
-                 take_hp(100); 
-                 play_sound(sound_46_chomped); // something chomped 
-                 seqtbl_offset_char(seq_54_chomped); // chomped 
-                 play_seq(); 
-         } 
- } 
-   
- // seg004:0833 
- void __pascal far check_gate_push() { 
-         // Closing gate pushes Kid 
-         short frame; 
-         short var_4; 
-         frame = Char.frame; 
-         if (Char.action == actions_7_turn || 
-                 frame == frame_15_stand || // stand 
-                 (frame >= frame_108_fall_land_2 && frame < 111) // crouch 
-         ) { 
-                 get_tile_at_char(); 
-                 var_4 = tile_col; 
-                 if ((curr_tile2 == tiles_4_gate || 
-                         get_tile(curr_room, --tile_col, tile_row) == tiles_4_gate) && 
-                         (curr_row_coll_flags[tile_col] & prev_coll_flags[tile_col]) == 0xFF && 
-                         can_bump_into_gate() 
-                 ) { 
-                         bumped_sound(); 
-                         // push Kid left if var_4 <= tile_col, gate at char's tile 
-                         // push Kid right if var_4 > tile_col, gate is left from char's tile 
-                         Char.x += 5 - (var_4 <= tile_col) * 10; 
-                 } 
-         } 
- } 
-   
- // seg004:08C3 
- void __pascal far check_guard_bumped() { 
-         if ( 
-                 Char.action == actions_1_run_jump && 
-                 Char.alive < 0 && 
-                 Char.sword >= sword_2_drawn 
-         ) { 
-                 if ( 
-   
-                         #ifdef FIX_PUSH_GUARD_INTO_WALL 
-                         // Should also check for a wall BEHIND the guard, instead of only the current tile 
-                         (fix_push_guard_into_wall && get_tile_behind_char() == tiles_20_wall) || 
-                         #endif 
-   
-                         get_tile_at_char() == tiles_20_wall || 
-                         curr_tile2 == tiles_7_doortop_with_floor || 
-                         (curr_tile2 == tiles_4_gate && can_bump_into_gate()) || 
-                         (Char.direction >= dir_0_right && ( 
-                                 get_tile(curr_room, --tile_col, tile_row) == tiles_7_doortop_with_floor || 
-                                 (curr_tile2 == tiles_4_gate && can_bump_into_gate()) 
-                         )) 
-                 ) { 
-                         load_frame_to_obj(); 
-                         set_char_collision(); 
-                         if (is_obstacle()) { 
-                                 short delta_x; 
-                                 delta_x = dist_from_wall_behind(curr_tile2); 
-                                 if (delta_x < 0 && delta_x > -13) { 
-                                         Char.x = char_dx_forward(-delta_x); 
-                                         seqtbl_offset_char(seq_65_bump_forward_with_sword); // pushed to wall with sword (Guard) 
-                                         play_seq(); 
-                                         load_fram_det_col(); 
-                                 } 
-                         } 
-                 } 
-         } 
- } 
-   
- // seg004:0989 
- void __pascal far check_chomped_guard() { 
-         get_tile_at_char(); 
-         if ( ! check_chomped_here()) { 
-                 get_tile(curr_room, ++tile_col, tile_row); 
-                 check_chomped_here(); 
-         } 
- } 
-   
- // seg004:09B0 
- int __pascal far check_chomped_here() { 
-         if (curr_tile2 == tiles_18_chomper && 
-                 (curr_room_modif[curr_tilepos] & 0x7F) == 2 
-         ) { 
-                 coll_tile_left_xpos = x_bump[tile_col + 5] + 7; 
-                 if (get_left_wall_xpos(curr_room, tile_col, tile_row) < char_x_right_coll && 
-                         get_right_wall_xpos(curr_room, tile_col, tile_row) > char_x_left_coll 
-                 ) { 
-                         chomped(); 
-                         return 1; 
-                 } else { 
-                         return 0; 
-                 } 
-         } else { 
-                 return 0; 
-         } 
- } 
-   
- // seg004:0A10 
- int __pascal far dist_from_wall_forward(byte tiletype) { 
-         short type; 
-         if (tiletype == tiles_4_gate && ! can_bump_into_gate()) { 
-                 return -1; 
-         } else { 
-                 coll_tile_left_xpos = x_bump[tile_col + 5] + 7; 
-                 type = wall_type(tiletype); 
-                 if (type == 0) return -1; 
-                 if (Char.direction < dir_0_right) { 
-                         // looking left 
-                         //return wall_dist_from_right[type] + char_x_left_coll - coll_tile_left_xpos - 13; 
-                         return char_x_left_coll - (coll_tile_left_xpos + 13 - wall_dist_from_right[type]); 
-                 } else { 
-                         // looking right 
-                         return wall_dist_from_left[type] + coll_tile_left_xpos - char_x_right_coll; 
-                 } 
-         } 
- } 
-   
- // seg004:0A7B 
- int __pascal far dist_from_wall_behind(byte tiletype) { 
-         short type; 
-         type = wall_type(tiletype); 
-         if (type == 0) { 
-                 return 99; 
-         } else { 
-                 if (Char.direction >= dir_0_right) { 
-                         // looking right 
-                         //return wall_dist_from_right[type] + char_x_left_coll - coll_tile_left_xpos - 13; 
-                         return char_x_left_coll - (coll_tile_left_xpos + 13 - wall_dist_from_right[type]); 
-                 } else { 
-                         // looking left 
-                         return wall_dist_from_left[type] + coll_tile_left_xpos - char_x_right_coll; 
-                 } 
-         } 
- } 
-