forked from NagyD/SDLPoP
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathseg004.c
583 lines (548 loc) · 15.7 KB
/
seg004.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
/*
SDLPoP, a port/conversion of the DOS game Prince of Persia.
Copyright (C) 2013-2015 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 (!options.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 (!(options.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() {
short var_2;
if (
Char.action == actions_1_run_jump &&
Char.alive < 0 &&
Char.sword >= sword_2_drawn
) {
if (
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()) {
var_2 = dist_from_wall_behind(curr_tile2);
if (var_2 < 0 && var_2 > -13) {
Char.x = char_dx_forward(-var_2);
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;
}
}
}