/*
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:1888
extern const word seqtbl_offsets[];
// seg005:000A
void __pascal far seqtbl_offset_char(short seq_index) {
Char.curr_seq = seqtbl_offsets[seq_index];
}
// seg005:001D
void __pascal far seqtbl_offset_opp(int seq_index) {
Opp.curr_seq = seqtbl_offsets[seq_index];
}
// seg005:0030
void __pascal far do_fall() {
if (is_screaming == 0 && Char.fall_y >= 31) {
play_sound(sound_1_falling); // falling
is_screaming = 1;
}
if ((word)y_land[Char.curr_row + 1] > (word)Char.y) {
check_grab();
#ifdef FIX_GLIDE_THROUGH_WALL
if (fix_glide_through_wall) {
// Fix for the kid falling through walls after turning around while running (especially when weightless)
determine_col();
get_tile_at_char();
if (curr_tile2 == tiles_20_wall ||
((curr_tile2 == tiles_12_doortop || curr_tile2 == tiles_7_doortop_with_floor) &&
Char.direction == dir_FF_left)
) {
int delta_x = distance_to_edge_weight();
//printf("delta_x = %d\n", delta_x);
// When falling into a wall or doortop after turning or running, delta_x is likely to be either 8, 11 or 12
// Calling in_wall() here produces the desired fix (no glitching through wall), but only when delta_x >= 10
// The code below "emulates" in_wall() to always get the same effect as if delta_x == 10
// (which distance actually looks/behaves best is a matter of preference)
#define delta_x_reference 10
if (delta_x >= 8) {
delta_x = -5 + delta_x - delta_x_reference;
Char.x = (byte) char_dx_forward(delta_x);
Char.fall_x = 0; // not in in_wall(), but we do need to cancel horizontal movement
}
}
}
#endif
} else {
#ifdef FIX_JUMP_THROUGH_WALL_ABOVE_GATE
if (fix_jump_through_wall_above_gate) {
// At this point, Char.curr_col has not yet been updated since check_bumped()
// Basically, Char.curr_col is still set to the column of the wall itself (even though the kid
// may have 'bumped' against the wall, with Char.x being offset)
// To prevent in_wall() from being called we need to update Char.curr_col here.
// (in_wall() only makes things worse, because it tries to 'eject' the kid from the wall the wrong way.
// For this reason, the kid can end up behind a closed gate below, like is possible in Level 7)
// The fix is calling determine_col() here.
// One caveat: the kid can also land on the rightmost edge of a closed gate tile, when doing a running jump
// to the left from two floors up. This 'trick' can be used in original PoP, but is 'fixed' by this change.
// To still allow this trick to be possible, we can check that we not jumping into a gate tile.
// (By the way, strangely enough, in unmodified PoP the trick even works with a tapestry + floor tile...)
if (get_tile_at_char() != tiles_4_gate)
determine_col();
}
#endif
if (get_tile_at_char() == tiles_20_wall) {
in_wall();
}
#ifdef FIX_DROP_THROUGH_TAPESTRY
else if (fix_drop_through_tapestry && get_tile_at_char() == tiles_12_doortop && Char.direction == dir_FF_left) {
if (distance_to_edge_weight() >= 8) // only intervene if the kid is actually IN FRONT of the tapestry
in_wall();
}
#endif
if (tile_is_floor(curr_tile2)) {
land();
} else {
inc_curr_row();
}
}
}
// seg005:0090
void __pascal far land() {
word seq_id;
is_screaming = 0;
Char.y = y_land[Char.curr_row + 1];
if (get_tile_at_char() != tiles_2_spike) {
if (! tile_is_floor(get_tile_infrontof_char()) &&
distance_to_edge_weight() < 3
) {
Char.x = char_dx_forward(-3);
}
#ifdef FIX_LAND_AGAINST_GATE_OR_TAPESTRY
else if (fix_land_against_gate_or_tapestry) {
// A closed gate right in front of the landing spot should not behave like an open floor tile, but like a wall
// Similar for a tapestry tile (with floor)
get_tile_infrontof_char();
if (Char.direction == dir_FF_left && (
(curr_tile2 == tiles_4_gate && can_bump_into_gate()) ||
(curr_tile2 == tiles_7_doortop_with_floor))
&& distance_to_edge_weight() < 3
) {
Char.x = char_dx_forward(-3);
}
}
#endif
start_chompers();
} else {
// fell on spikes
goto loc_5EE6;
}
if (Char.alive < 0) {
// alive
if ((distance_to_edge_weight() >= 12 &&
get_tile_behind_char() == tiles_2_spike) ||
get_tile_at_char() == tiles_2_spike
) {
// fell on spikes
loc_5EE6:
if (is_spike_harmful()) {
spiked();
return;
}
#ifdef FIX_SAFE_LANDING_ON_SPIKES
else if (fix_safe_landing_on_spikes && curr_room_modif[curr_tilepos] == 0) {
// spikes ARE dangerous, just not out yet.
spiked();
return;
}
#endif // FIX_SAFE_LANDING_ON_SPIKES
}
{
if (Char.fall_y < 22) {
// fell 1 row
loc_5EFD:
if (Char.charid >= charid_2_guard || Char.sword == sword_2_drawn) {
Char.sword = sword_2_drawn;
seq_id = seq_63_guard_stand_active; // stand active after landing
} else {
seq_id = seq_17_soft_land; // crouch (soft land)
}
if (Char.charid == charid_0_kid) {
play_sound(sound_17_soft_land); // soft land (crouch)
is_guard_notice = 1;
}
} else if (Char.fall_y < 33) {
// fell 2 rows
if (Char.charid == charid_1_shadow) goto loc_5EFD;
if (Char.charid == charid_2_guard) goto loc_5F6C;
// kid (or skeleton (bug!))
if (! take_hp(1)) {
// still alive
play_sound(sound_16_medium_land); // medium land
is_guard_notice = 1;
seq_id = seq_20_medium_land; // medium land (lose 1 HP, crouch)
} else {
// dead (this was the last HP)
goto loc_5F75;
}
} else {
// fell 3 or more rows
goto loc_5F6C;
}
}
} else {
// dead
loc_5F6C:
take_hp(100);
loc_5F75:
play_sound(sound_0_fell_to_death); // prince crashing into the floor
seq_id = seq_22_crushed; // dead (after falling)
}
seqtbl_offset_char(seq_id);
play_seq();
Char.fall_y = 0;
}
// seg005:01B7
void __pascal far spiked() {
// If someone falls into spikes, those spikes become harmless (to others).
curr_room_modif[curr_tilepos] = 0xFF;
Char.y = y_land[Char.curr_row + 1];
Char.x = x_bump[tile_col + 5] + 10;
Char.x = char_dx_forward(8);
Char.fall_y = 0;
play_sound(sound_48_spiked); // something spiked
take_hp(100);
seqtbl_offset_char(seq_51_spiked); // spiked
play_seq();
}
// seg005:0213
void __pascal far control() {
short char_frame;
short char_action;
char_frame = Char.frame;
if (Char.alive >= 0) {
if (char_frame == frame_15_stand || // stand
char_frame == frame_166_stand_inactive || // stand
char_frame == frame_158_stand_with_sword || // stand with sword
char_frame == frame_171_stand_with_sword // stand with sword
) {
seqtbl_offset_char(seq_71_dying); // dying (not stabbed)
}
} else {
char_action = Char.action;
if (char_action == actions_5_bumped ||
char_action == actions_4_in_freefall
) {
release_arrows();
} else if (Char.sword == sword_2_drawn) {
control_with_sword();
} else if (Char.charid >= charid_2_guard) {
control_guard_inactive();
} else if (char_frame == frame_15_stand || // standing
(char_frame>= frame_50_turn && char_frame<53) // end of turning
) {
control_standing();
} else if (char_frame == frame_48_turn) { // a frame in turning
control_turning();
} else if (char_frame < 4) { // start run
control_startrun();
} else if (char_frame >= frame_67_start_jump_up_1 && char_frame < frame_70_jumphang) { // start jump up
control_jumpup();
} else if (char_frame < 15) { // running
control_running();
} else if (char_frame >= frame_87_hanging_1 && char_frame < 100) { // hanging
control_hanging();
} else if (char_frame == frame_109_crouch) { // crouching
control_crouched();
}
#ifdef ALLOW_CROUCH_AFTER_CLIMBING
// When ducking with down+forward, give time to release the forward control (prevents unintended crouch-hops)
else if (enable_crouch_after_climbing && Char.curr_seq >= seqtbl_offsets[seq_50_crouch] &&
Char.curr_seq < seqtbl_offsets[seq_49_stand_up_from_crouch]) // while stooping
if (control_forward < 1) control_forward = 0;
#endif
#ifdef FIX_MOVE_AFTER_DRINK
if (fix_move_after_drink && char_frame >= frame_191_drink && char_frame <= frame_205_drink)
release_arrows();
#endif
#ifdef FIX_MOVE_AFTER_SHEATHE
if (fix_move_after_sheathe &&
Char.curr_seq >= seqtbl_offsets[seq_92_put_sword_away] &&
Char.curr_seq < seqtbl_offsets[seq_93_put_sword_away_fast]
)
release_arrows();
#endif
}
}
// seg005:02EB
void __pascal far control_crouched() {
if (need_level1_music != 0 && current_level == 1) {
// Special event: music when crouching
if (! check_sound_playing()) {
if (need_level1_music == 1) {
play_sound(sound_25_presentation); // presentation (level 1 start)
need_level1_music = 2;
} else {
#ifdef USE_REPLAY
if (recording) special_move = MOVE_EFFECT_END;
if (!replaying) // during replays, crouch immobilization gets cancelled in do_replay_move()
#endif
need_level1_music = 0;
}
}
} else {
need_level1_music = 0;
if (control_shift2 < 0 && check_get_item()) return;
if (control_y != 1) {
seqtbl_offset_char(seq_49_stand_up_from_crouch); // stand up from crouch
} else {
if (control_forward < 0) {
control_forward = 1; // disable automatic repeat
seqtbl_offset_char(seq_79_crouch_hop); // crouch-hop
}
}
}
}
// seg005:0358
void __pascal far control_standing() {
short var_2;
if (control_shift2 < 0 && control_shift < 0 && check_get_item()) {
return;
}
if (Char.charid != charid_0_kid && control_down < 0 && control_forward < 0) {
draw_sword();
return;
} //else
if (have_sword) {
if (offguard != 0 && control_shift >= 0) goto loc_6213;
if (can_guard_see_kid >= 2) {
var_2 = char_opp_dist();
if (var_2 >= -10 && var_2 < 90) {
holding_sword = 1;
if ((word)var_2 < (word)-6) {
if (Opp.charid == charid_1_shadow &&
(Opp.action == actions_3_in_midair || (Opp.frame >= frame_107_fall_land_1 && Opp.frame < 118))
) {
offguard = 0;
} else {
draw_sword();
return;
}
} else {
back_pressed();
return;
}
}
} else {
offguard = 0;
}
}
if (control_shift < 0) {
if (control_backward < 0) {
back_pressed();
} else if (control_up < 0) {
up_pressed();
} else if (control_down < 0) {
down_pressed();
} else if (control_x < 0 && control_forward < 0) {
safe_step();
}
} else loc_6213: if (control_forward < 0) {
if (is_keyboard_mode && control_up < 0) {
standing_jump();
} else {
forward_pressed();
}
} else if (control_backward < 0) {
back_pressed();
} else if (control_up < 0) {
if (is_keyboard_mode && control_forward < 0) {
standing_jump();
} else {
up_pressed();
}
} else if (control_down < 0) {
down_pressed();
} else if (control_x < 0) {
forward_pressed();
}
}
// seg005:0482
void __pascal far up_pressed() {
int leveldoor_tilepos = -1;
if (get_tile_at_char() == tiles_16_level_door_left) leveldoor_tilepos = curr_tilepos;
else if (get_tile_behind_char() == tiles_16_level_door_left) leveldoor_tilepos = curr_tilepos;
else if (get_tile_infrontof_char() == tiles_16_level_door_left) leveldoor_tilepos = curr_tilepos;
if ((leveldoor_tilepos != -1) &&
level.start_room != drawn_room &&
curr_room_modif[leveldoor_tilepos] >= 42 // this door must be fully open
){
go_up_leveldoor();
} else {
if (control_x < 0) {
standing_jump();
} else {
check_jump_up();
}
}
}
// seg005:04C7
void __pascal far down_pressed() {
control_down = 1; // disable automatic repeat
if (! tile_is_floor(get_tile_infrontof_char()) &&
distance_to_edge_weight() < 3
) {
Char.x = char_dx_forward(5);
load_fram_det_col();
} else {
if (! tile_is_floor(get_tile_behind_char()) &&
distance_to_edge_weight() >= 8
) {
through_tile = get_tile_behind_char();
get_tile_at_char();
if (can_grab() &&
#ifdef ALLOW_CROUCH_AFTER_CLIMBING
(!(enable_crouch_after_climbing && control_forward == -1)) &&
#endif
(Char.direction >= dir_0_right ||
get_tile_at_char() != tiles_4_gate ||
curr_room_modif[curr_tilepos] >> 2 >= 6)
) {
Char.x = char_dx_forward(distance_to_edge_weight() - 9);
seqtbl_offset_char(seq_68_climb_down); // climb down
} else {
crouch();
}
} else {
crouch();
}
}
}
// seg005:0574
void __pascal far go_up_leveldoor() {
Char.x = x_bump[tile_col + 5] + 10;
Char.direction = dir_FF_left; // right
seqtbl_offset_char(seq_70_go_up_on_level_door); // go up on level door
}
// seg005:058F
void __pascal far control_turning() {
if (control_shift >= 0 && control_x < 0 && control_y >= 0) {
seqtbl_offset_char(seq_43_start_run_after_turn); // start run and run (after turning)
}
// Added:
// When using a joystick, the kid may sometimes jump/duck/turn unintendedly after turning around.
// To prevent this: clear the remembered controls, so that if the stick has already moved to another/neutral position,
// the kid will not jump, duck, or turn again.
if (is_joyst_mode) {
if (control_up < 0 && control_y >= 0) {
control_up = 0;
}
if (control_down < 0 && control_y <= 0) {
control_down = 0;
}
if (control_backward < 0 && control_x == 0) {
control_backward = 0;
}
}
}
// seg005:05AD
void __pascal far crouch() {
seqtbl_offset_char(seq_50_crouch); // crouch
control_down = release_arrows();
}
// seg005:05BE
void __pascal far back_pressed() {
word seq_id;
control_backward = release_arrows();
// After turn, Kid will draw sword if ...
if (have_sword == 0 || // if Kid has sword
can_guard_see_kid < 2 || // and can see Guard
char_opp_dist() > 0 || // and Guard was behind him
distance_to_edge_weight() < 2
) {
seq_id = seq_5_turn; // turn
} else {
Char.sword = sword_2_drawn;
offguard = 0;
seq_id = seq_89_turn_draw_sword; // turn and draw sword
}
seqtbl_offset_char(seq_id);
}
// seg005:060F
void __pascal far forward_pressed() {
short distance;
distance = get_edge_distance();
#ifdef ALLOW_CROUCH_AFTER_CLIMBING
if (enable_crouch_after_climbing && control_down < 0) {
down_pressed();
control_forward = 0;
return;
}
#endif
if (edge_type == 1 && curr_tile2 != tiles_18_chomper && distance < 8) {
// If char is near a wall, step instead of run.
if (control_forward < 0) {
safe_step();
}
} else {
seqtbl_offset_char(seq_1_start_run); // start run and run
}
}
// seg005:0649
void __pascal far control_running() {
if (control_x == 0 && (Char.frame == frame_7_run || Char.frame == frame_11_run)) {
control_forward = release_arrows();
seqtbl_offset_char(seq_13_stop_run); // stop run
} else if (control_x > 0) {
control_backward = release_arrows();
seqtbl_offset_char(seq_6_run_turn); // run-turn
} else if (control_y < 0 && control_up < 0) {
run_jump();
} else if (control_down < 0) {
control_down = 1; // disable automatic repeat
seqtbl_offset_char(seq_26_crouch_while_running); // crouch while running
}
}
// seg005:06A8
void __pascal far safe_step() {
short distance;
control_shift2 = 1; // disable automatic repeat
control_forward = 1; // disable automatic repeat
distance = get_edge_distance();
if (distance) {
Char.repeat = 1;
seqtbl_offset_char(distance + 28); // 29..42: safe step to edge
} else if (edge_type != 1 && Char.repeat != 0) {
Char.repeat = 0;
seqtbl_offset_char(seq_44_step_on_edge); // step on edge
} else {
seqtbl_offset_char(seq_39_safe_step_11); // unsafe step (off ledge)
}
}
// seg005:06F0
int __pascal far check_get_item() {
if (get_tile_at_char() == tiles_10_potion ||
curr_tile2 == tiles_22_sword
) {
if (! tile_is_floor(get_tile_behind_char())) {
return 0;
}
Char.x = char_dx_forward(-14);
load_fram_det_col();
}
if (get_tile_infrontof_char() == tiles_10_potion ||
curr_tile2 == tiles_22_sword
) {
get_item();
return 1;
}
return 0;
}
// seg005:073E
void __pascal far get_item() {
short distance;
if (Char.frame != frame_109_crouch) { // crouching
distance = get_edge_distance();
if (edge_type != 2) {
Char.x = char_dx_forward(distance);
}
if (Char.direction >= dir_0_right) {
Char.x = char_dx_forward((curr_tile2 == tiles_10_potion) - 2);
}
crouch();
} else if (curr_tile2 == tiles_22_sword) {
do_pickup(-1);
seqtbl_offset_char(seq_91_get_sword); // get sword
} else { // potion
do_pickup(curr_room_modif[curr_tilepos] >> 3);
seqtbl_offset_char(seq_78_drink); // drink
#ifdef USE_COPYPROT
if (current_level == 15) {
short index;
for (index = 0; index < 14; ++index) {
// remove letter on potions level
if (copyprot_room[index] == curr_room &&
copyprot_tile[index] == curr_tilepos
) {
copyprot_room[index] = 0;
break;
}
}
}
#endif
}
}
// seg005:07FF
void __pascal far control_startrun() {
if (control_y < 0 && control_x < 0) {
standing_jump();
}
}
// seg005:0812
void __pascal far control_jumpup() {
if (control_x < 0 || control_forward < 0) {
standing_jump();
}
}
// seg005:0825
void __pascal far standing_jump() {
control_up = control_forward = 1; // disable automatic repeat
seqtbl_offset_char(seq_3_standing_jump); // standing jump
}
// seg005:0836
void __pascal far check_jump_up() {
control_up = release_arrows();
through_tile = get_tile_above_char();
get_tile_front_above_char();
if (can_grab()) {
grab_up_with_floor_behind();
} else {
through_tile = get_tile_behind_above_char();
get_tile_above_char();
if (can_grab()) {
jump_up_or_grab();
} else {
jump_up();
}
}
}
// seg005:087B
void __pascal far jump_up_or_grab() {
short distance;
distance = distance_to_edge_weight();
if (distance < 6) {
jump_up();
} else if (! tile_is_floor(get_tile_behind_char())) {
// There is not floor behind char.
grab_up_no_floor_behind();
} else {
// There is floor behind char, go back a bit.
Char.x = char_dx_forward(distance - 14);
load_fram_det_col();
grab_up_with_floor_behind();
}
}
// seg005:08C7
void __pascal far grab_up_no_floor_behind() {
get_tile_above_char();
Char.x = char_dx_forward(distance_to_edge_weight() - 10);
seqtbl_offset_char(seq_16_jump_up_and_grab); // jump up and grab (no floor behind)
}
// seg005:08E6
void __pascal far jump_up() {
short distance;
control_up = release_arrows();
distance = get_edge_distance();
if (distance < 4 && edge_type == 1) {
Char.x = char_dx_forward(distance - 3);
}
#ifdef FIX_JUMP_DISTANCE_AT_EDGE
// When climbing up two floors, turning around and jumping upward, the kid falls down.
// This fix makes the workaround of Trick 25 unnecessary.
if (fix_jump_distance_at_edge && distance == 3 && edge_type == 0) {
Char.x = char_dx_forward(-1);
}
#endif
get_tile(Char.room, get_tile_div_mod(back_delta_x(0) + dx_weight() - 6), Char.curr_row - 1);
if (curr_tile2 != tiles_20_wall && ! tile_is_floor(curr_tile2)) {
seqtbl_offset_char(seq_28_jump_up_with_nothing_above); // jump up with nothing above
} else {
seqtbl_offset_char(seq_14_jump_up_into_ceiling); // jump up with wall or floor above
}
}
// seg005:0968
void __pascal far control_hanging() {
if (Char.alive < 0) {
if (grab_timer == 0 && control_y < 0) {
can_climb_up();
} else if (control_shift < 0) {
// hanging against a wall or a doortop
if (Char.action != actions_6_hang_straight &&
(get_tile_at_char() == tiles_20_wall ||
(Char.direction == dir_FF_left && ( // facing left
curr_tile2 == tiles_7_doortop_with_floor ||
curr_tile2 == tiles_12_doortop
)))
) {
if (grab_timer == 0) {
play_sound(sound_8_bumped); // touching a wall (hang against wall)
}
seqtbl_offset_char(seq_25_hang_against_wall); // hang against wall (straight)
} else {
if (! tile_is_floor(get_tile_above_char())) {
hang_fall();
}
}
} else {
hang_fall();
}
} else {
hang_fall();
}
}
// seg005:09DF
void __pascal far can_climb_up() {
short seq_id;
seq_id = seq_10_climb_up; // climb up
control_up = control_shift2 = release_arrows();
get_tile_above_char();
if (((curr_tile2 == tiles_13_mirror || curr_tile2 == tiles_18_chomper) &&
Char.direction == dir_0_right) ||
(curr_tile2 == tiles_4_gate && Char.direction != dir_0_right &&
curr_room_modif[curr_tilepos] >> 2 < 6)
) {
seq_id = seq_73_climb_up_to_closed_gate; // climb up to closed gate and down
}
seqtbl_offset_char(seq_id);
}
// seg005:0A46
void __pascal far hang_fall() {
control_down = release_arrows();
if (! tile_is_floor(get_tile_behind_char()) &&
! tile_is_floor(get_tile_at_char())
) {
seqtbl_offset_char(seq_23_release_ledge_and_fall); // release ledge and fall
} else {
if (get_tile_at_char() == tiles_20_wall ||
(Char.direction < dir_0_right && ( // looking left
curr_tile2 == tiles_7_doortop_with_floor ||
curr_tile2 == tiles_12_doortop
))
) {
Char.x = char_dx_forward(-7);
}
seqtbl_offset_char(seq_11_release_ledge_and_land); // end of climb down
}
}
// seg005:0AA8
void __pascal far grab_up_with_floor_behind() {
short distance;
distance = distance_to_edge_weight();
// The global variable edge_type (which we need!) gets set as a side effect of get_edge_distance()
short edge_distance = get_edge_distance();
//printf("Distance to edge weight: %d\tedge type: %d\tedge distance: %d\n", distance, edge_type, edge_distance);
#ifdef FIX_EDGE_DISTANCE_CHECK_WHEN_CLIMBING
// When climbing to a higher floor, the game unnecessarily checks how far away the edge below is;
// This contributes to sometimes "teleporting" considerable distances when climbing from firm ground
#define JUMP_STRAIGHT_CONDITION (fix_edge_distance_check_when_climbing) \
? (distance < 4 && edge_type != 1) \
: (distance < 4 && edge_distance < 4 && edge_type != 1)
#else
#define JUMP_STRAIGHT_CONDITION distance < 4 && edge_distance < 4 && edge_type != 1
#endif
if (JUMP_STRAIGHT_CONDITION) {
Char.x = char_dx_forward(distance);
seqtbl_offset_char(seq_8_jump_up_and_grab_straight); // jump up and grab (when?)
} else {
Char.x = char_dx_forward(distance - 4);
seqtbl_offset_char(seq_24_jump_up_and_grab_forward); // jump up and grab (with floor behind)
}
}
// seg005:0AF7
void __pascal far run_jump() {
short var_2;
short xpos;
short col;
short var_8;
if (Char.frame >= frame_7_run) {
// Align Kid to edge of floor.
xpos = char_dx_forward(4);
col = get_tile_div_mod_m7(xpos);
for (var_2 = 0; var_2 < 2; ++var_2) {
col += dir_front[Char.direction + 1];
get_tile(Char.room, col, Char.curr_row);
if (curr_tile2 == tiles_2_spike || ! tile_is_floor(curr_tile2)) {
var_8 = distance_to_edge(xpos) + 14 * var_2 - 14;
if ((word)var_8 < (word)-8 || var_8 >= 2) {
if (var_8 < 128) return;
var_8 = -3;
}
Char.x = char_dx_forward(var_8 + 4);
break;
}
}
control_up = release_arrows(); // disable automatic repeat
seqtbl_offset_char(seq_4_run_jump); // run-jump
}
}
// sseg005:0BB5
void __pascal far back_with_sword() {
short frame;
frame = Char.frame;
if (frame == frame_158_stand_with_sword || frame == frame_170_stand_with_sword || frame == frame_171_stand_with_sword) {
control_backward = 1; // disable automatic repeat
seqtbl_offset_char(seq_57_back_with_sword); // back with sword
}
}
// seg005:0BE3
void __pascal far forward_with_sword() {
short frame;
frame = Char.frame;
if (frame == frame_158_stand_with_sword || frame == frame_170_stand_with_sword || frame == frame_171_stand_with_sword) {
control_forward = 1; // disable automatic repeat
if (Char.charid != charid_0_kid) {
seqtbl_offset_char(seq_56_guard_forward_with_sword); // forward with sword (Guard)
} else {
seqtbl_offset_char(seq_86_forward_with_sword); // forward with sword (Kid)
}
}
}
// seg005:0C1D
void __pascal far draw_sword() {
word seq_id;
seq_id = seq_55_draw_sword; // draw sword
control_forward = control_shift2 = release_arrows();
#ifdef FIX_UNINTENDED_SWORD_STRIKE
if (fix_unintended_sword_strike) {
ctrl1_shift2 = 1; // prevent restoring control_shift2 to -1 in rest_ctrl_1()
}
#endif
if (Char.charid == charid_0_kid) {
play_sound(sound_19_draw_sword); // taking out the sword
offguard = 0;
} else if (Char.charid != charid_1_shadow) {
seq_id = seq_90_en_garde; // stand active
}
Char.sword = sword_2_drawn;
seqtbl_offset_char(seq_id);
}
// seg005:0C67
void __pascal far control_with_sword() {
short distance;
if (Char.action < actions_2_hang_climb) {
if (get_tile_at_char() == tiles_11_loose || can_guard_see_kid >= 2) {
distance = char_opp_dist();
if ((word)distance < (word)90) {
swordfight();
return;
} else if (distance < 0) {
if ((word)distance < (word)-4) {
seqtbl_offset_char(seq_60_turn_with_sword); // turn with sword (after switching places)
return;
} else {
swordfight();
return;
}
}
} /*else*/ {
if (Char.charid == charid_0_kid && Char.alive < 0) {
holding_sword = 0;
}
if (Char.charid < charid_2_guard) {
// frame 171: stand with sword
if (Char.frame == frame_171_stand_with_sword) {
Char.sword = sword_0_sheathed;
seqtbl_offset_char(seq_92_put_sword_away); // put sword away (Guard died)
}
} else {
swordfight();
}
}
}
}
// seg005:0CDB
void __pascal far swordfight() {
short frame;
short seq_id;
short charid;
frame = Char.frame;
charid = Char.charid;
// frame 161: parry
if (frame == frame_161_parry && control_shift2 >= 0) {
seqtbl_offset_char(seq_57_back_with_sword); // back with sword (when parrying)
return;
} else if (control_shift2 < 0) {
if (charid == charid_0_kid) {
kid_sword_strike = 15;
}
sword_strike();
if (control_shift2 == 1) return;
}
if (control_down < 0) {
if (frame == frame_158_stand_with_sword || frame == frame_170_stand_with_sword || frame == frame_171_stand_with_sword) {
control_down = 1; // disable automatic repeat
Char.sword = sword_0_sheathed;
if (charid == charid_0_kid) {
offguard = 1;
guard_refrac = 9;
holding_sword = 0;
seq_id = seq_93_put_sword_away_fast; // put sword away fast (down pressed)
} else if (charid == charid_1_shadow) {
seq_id = seq_92_put_sword_away; // put sword away
} else {
seq_id = seq_87_guard_become_inactive; // stand inactive (when Kid leaves sight)
}
seqtbl_offset_char(seq_id);
}
} else if (control_up < 0) {
parry();
} else if (control_forward < 0) {
forward_with_sword();
} else if (control_backward < 0) {
back_with_sword();
}
}
// seg005:0DB0
void __pascal far sword_strike() {
short frame;
short seq_id;
frame = Char.frame;
if (frame == frame_157_walk_with_sword || // walk with sword
frame == frame_158_stand_with_sword || // stand with sword
frame == frame_170_stand_with_sword || // stand with sword
frame == frame_171_stand_with_sword || // stand with sword
frame == frame_165_walk_with_sword // walk with sword
) {
if (Char.charid == charid_0_kid) {
seq_id = seq_75_strike; // strike with sword (Kid)
} else {
seq_id = seq_58_guard_strike; // strike with sword (Guard)
}
} else if (frame == frame_150_parry || frame == frame_161_parry) { // parry
seq_id = seq_66_strike_after_parry; // strike with sword after parrying
} else {
return;
}
control_shift2 = 1; // disable automatic repeat
seqtbl_offset_char(seq_id);
}
// seg005:0E0F
void __pascal far parry() {
short opp_frame;
short char_frame;
short var_6;
short seq_id;
short char_charid;
char_frame = Char.frame;
opp_frame = Opp.frame;
char_charid = Char.charid;
seq_id = seq_62_parry; // defend (parry) with sword
var_6 = 0;
if (
char_frame == frame_158_stand_with_sword || // stand with sword
char_frame == frame_170_stand_with_sword || // stand with sword
char_frame == frame_171_stand_with_sword || // stand with sword
char_frame == frame_168_back || // back?
char_frame == frame_165_walk_with_sword // walk with sword
) {
if (char_opp_dist() >= 32 && char_charid != charid_0_kid) {
back_with_sword();
return;
} else if (char_charid == charid_0_kid) {
if (opp_frame == frame_168_back) return;
if (opp_frame != frame_151_strike_1 &&
opp_frame != frame_152_strike_2 &&
opp_frame != frame_162_block_to_strike
) {
if (opp_frame == frame_153_strike_3) { // strike
var_6 = 1;
} else
if (char_charid != charid_0_kid) {
back_with_sword();
return;
}
}
} else {
if (opp_frame != frame_152_strike_2) return;
}
} else {
if (char_frame != frame_167_blocked) return;
seq_id = seq_61_parry_after_strike; // parry after striking with sword
}
control_up = 1; // disable automatic repeat
seqtbl_offset_char(seq_id);
if (var_6) {
play_seq();
}
}