Subversion Repositories Games.Prince of Persia

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
/*
2
SDLPoP, a port/conversion of the DOS game Prince of Persia.
3
Copyright (C) 2013-2018  Dávid Nagy
4
 
5
This program is free software: you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation, either version 3 of the License, or
8
(at your option) any later version.
9
 
10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
GNU General Public License for more details.
14
 
15
You should have received a copy of the GNU General Public License
16
along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
 
18
The authors of this program may be contacted at http://forum.princed.org
19
*/
20
 
21
#include "common.h"
22
 
23
// seg007:0000
24
void __pascal far process_trobs() {
25
        word need_delete;
26
        word index;
27
        word new_index;
28
        need_delete = 0;
29
        if (trobs_count == 0) return;
30
        for (index = 0; index < trobs_count; ++index) {
31
                trob = trobs[index];
32
                animate_tile();
33
                trobs[index].type = trob.type;
34
                if (trob.type < 0) {
35
                        need_delete = 1;
36
                }
37
        }
38
        if (need_delete) {
39
                for (index = new_index = 0; index < trobs_count; ++index) {
40
                        if (trobs[index].type >= 0) {
41
                                trobs[new_index++] = trobs[index];
42
                        }
43
                }
44
                trobs_count = new_index;
45
        }
46
}
47
 
48
// seg007:00AF
49
void __pascal far animate_tile() {
50
        get_room_address(trob.room);
51
        switch (get_curr_tile(trob.tilepos)) {
52
                case tiles_19_torch:
53
                case tiles_30_torch_with_debris:
54
                        animate_torch();
55
                break;
56
                case tiles_6_closer:
57
                case tiles_15_opener:
58
                        animate_button();
59
                break;
60
                case tiles_2_spike:
61
                        animate_spike();
62
                break;
63
                case tiles_11_loose:
64
                        animate_loose();
65
                break;
66
                case tiles_0_empty:
67
                        animate_empty();
68
                break;
69
                case tiles_18_chomper:
70
                        animate_chomper();
71
                break;
72
                case tiles_4_gate:
73
                        animate_door();
74
                break;
75
                case tiles_16_level_door_left:
76
                        animate_leveldoor();
77
                break;
78
                case tiles_10_potion:
79
                        animate_potion();
80
                break;
81
                case tiles_22_sword:
82
                        animate_sword();
83
                break;
84
                default:
85
                        trob.type = -1;
86
                break;
87
        }
88
        curr_room_modif[trob.tilepos] = curr_modifier;
89
}
90
 
91
// seg007:0166
92
short __pascal far is_trob_in_drawn_room() {
93
        if (trob.room != drawn_room) {
94
                trob.type = -1;
95
                return 0;
96
        } else {
97
                return 1;
98
        }
99
}
100
 
101
// seg007:017E
102
void __pascal far set_redraw_anim_right() {
103
        set_redraw_anim(get_trob_right_pos_in_drawn_room(), 1);
104
}
105
 
106
// seg007:018C
107
void __pascal far set_redraw_anim_curr() {
108
        set_redraw_anim(get_trob_pos_in_drawn_room(), 1);
109
}
110
 
111
// seg007:019A
112
void __pascal far redraw_at_trob() {
113
        word tilepos;
114
        redraw_height = 63;
115
        tilepos = get_trob_pos_in_drawn_room();
116
        set_redraw_full(tilepos, 1);
117
        set_wipe(tilepos, 1);
118
}
119
 
120
// seg007:01C5
121
void __pascal far redraw_21h() {
122
        redraw_height = 0x21;
123
        redraw_tile_height();
124
}
125
 
126
// seg007:01D0
127
void __pascal far redraw_11h() {
128
        redraw_height = 0x11;
129
        redraw_tile_height();
130
}
131
 
132
// seg007:01DB
133
void __pascal far redraw_20h() {
134
        redraw_height = 0x20;
135
        redraw_tile_height();
136
}
137
 
138
// seg007:01E6
139
void __pascal far draw_trob() {
140
        word var_2;
141
        var_2 = get_trob_right_pos_in_drawn_room();
142
        set_redraw_anim(var_2, 1);
143
        set_redraw_fore(var_2, 1);
144
        set_redraw_anim(get_trob_right_above_pos_in_drawn_room(), 1);
145
}
146
 
147
// seg007:0218
148
void __pascal far redraw_tile_height() {
149
        short tilepos;
150
        tilepos = get_trob_pos_in_drawn_room();
151
        set_redraw_full(tilepos, 1);
152
        set_wipe(tilepos, 1);
153
        tilepos = get_trob_right_pos_in_drawn_room();
154
        set_redraw_full(tilepos, 1);
155
        set_wipe(tilepos, 1);
156
}
157
 
158
// seg007:0258
159
short __pascal far get_trob_pos_in_drawn_room() {
160
        short tilepos;
161
        tilepos = trob.tilepos;
162
        if (trob.room == room_A) {
163
                if (tilepos >= 20 && tilepos < 30) {
164
                        // 20..29 -> -1..-10
165
                        tilepos = 19 - tilepos;
166
                } else {
167
                        tilepos = 30;
168
                }
169
        } else {
170
                if (trob.room != drawn_room) {
171
                        tilepos = 30;
172
                }
173
        }
174
        return tilepos;
175
}
176
 
177
// seg007:029D
178
short __pascal far get_trob_right_pos_in_drawn_room() {
179
        word tilepos;
180
        tilepos = trob.tilepos;
181
        if (trob.room == drawn_room) {
182
                if (tilepos % 10 != 9) {
183
                        ++tilepos;
184
                } else {
185
                        tilepos = 30;
186
                }
187
        } else if (trob.room == room_L) {
188
                if (tilepos % 10 == 9) {
189
                        tilepos -= 9;
190
                } else {
191
                        tilepos = 30;
192
                }
193
        } else if (trob.room == room_A) {
194
                if (tilepos >= 20 && tilepos < 29) {
195
                        // 20..28 -> -2..-10
196
                        tilepos = 18 - tilepos;
197
                } else {
198
                        tilepos = 30;
199
                }
200
        } else if (trob.room == room_AL && tilepos == 29) {
201
                tilepos = -1;
202
        } else {
203
                tilepos = 30;
204
        }
205
        return tilepos;
206
}
207
 
208
// seg007:032C
209
short __pascal far get_trob_right_above_pos_in_drawn_room() {
210
        word tilepos;
211
        tilepos = trob.tilepos;
212
        if (trob.room == drawn_room) {
213
                if (tilepos % 10 != 9) {
214
                        if (tilepos < 10) {
215
                                // 0..8 -> -2..-10
216
                                tilepos = -(tilepos + 2);
217
                        } else {
218
                                tilepos -= 9;
219
                        }
220
                } else {
221
                        tilepos = 30;
222
                }
223
        } else if (trob.room == room_L) {
224
                if (tilepos == 9) {
225
                        tilepos = -1;
226
                } else {
227
                        if (tilepos % 10 == 9) {
228
                                tilepos -= 19;
229
                        } else {
230
                                tilepos = 30;
231
                        }
232
                }
233
        } else if (trob.room == room_B) {
234
                if (tilepos < 9) {
235
                        tilepos += 21;
236
                } else {
237
                        tilepos = 30;
238
                }
239
        } else if (trob.room == room_BL && tilepos == 9) {
240
                tilepos = 20;
241
        } else {
242
                tilepos = 30;
243
        }
244
        return tilepos;
245
}
246
 
247
// seg007:03CF
248
void __pascal far animate_torch() {
249
        if (is_trob_in_drawn_room()) {
250
                curr_modifier = get_torch_frame(curr_modifier);
251
                set_redraw_anim_right();
252
        }
253
}
254
 
255
// seg007:03E9
256
void __pascal far animate_potion() {
257
        word type;
258
        if (trob.type >= 0 && is_trob_in_drawn_room()) {
259
                type = curr_modifier & 0xF8;
260
                curr_modifier = bubble_next_frame(curr_modifier & 0x07) | type;
261
                set_redraw_anim_curr();
262
        }
263
}
264
 
265
// seg007:0425
266
void __pascal far animate_sword() {
267
        if (is_trob_in_drawn_room()) {
268
                --curr_modifier;
269
                if (curr_modifier == 0) {
270
                        curr_modifier = (prandom(255) & 0x3F) + 0x28;
271
                }
272
                set_redraw_anim_curr();
273
        }
274
}
275
 
276
// seg007:0448
277
void __pascal far animate_chomper() {
278
        word blood;
279
        word frame;
280
        if (trob.type >= 0) {
281
                blood = curr_modifier & 0x80;
282
                frame = (curr_modifier & 0x7F) + 1;
283
                if (frame > 15) {
284
                        frame = 1;
285
                }
286
                curr_modifier = blood | frame;
287
                if (frame == 2) {
288
                        play_sound(sound_47_chomper); // chomper
289
                }
290
                // If either:
291
                // - Kid left this room
292
                // - Kid left this row
293
                // - Kid died but not in this chomper
294
                // and chomper is past frame 6
295
                // then stop.
296
                if ((trob.room != drawn_room || trob.tilepos / 10 != Kid.curr_row ||
297
                        (Kid.alive >= 0 && blood == 0)) && (curr_modifier & 0x7F) >= 6
298
                ) {
299
                        trob.type = -1;
300
                }
301
        }
302
        if ((curr_modifier & 0x7F) < 6) {
303
                redraw_at_trob();
304
        }
305
}
306
 
307
// seg007:04D3
308
void __pascal far animate_spike() {
309
        if (trob.type >= 0) {
310
                // 0xFF means a disabled spike.
311
                if (curr_modifier == 0xFF) return;
312
                if (curr_modifier & 0x80) {
313
                        --curr_modifier;
314
                        if (curr_modifier & 0x7F) return;
315
                        curr_modifier = 6;
316
                } else {
317
                        ++curr_modifier;
318
                        if (curr_modifier == 5) {
319
                                curr_modifier = 0x8F;
320
                        } else if (curr_modifier == 9) {
321
                                curr_modifier = 0;
322
                                trob.type = -1;
323
                        }
324
                }
325
        }
326
        redraw_21h();
327
}
328
 
329
// data:27B2
330
const byte gate_close_speeds[] = {0, 0, 0, 20, 40, 60, 80, 100, 120};
331
// data:27C0
332
const byte door_delta[] = {-1, 4, 4};
333
// seg007:0522
334
void __pascal far animate_door() {
335
/*
336
Possible values of anim_type:
337
0: closing
338
1: open
339
2: permanent open
340
3,4,5,6,7,8: fast closing with speeds 20,40,60,80,100,120 /4 pixel/frame
341
*/
342
        sbyte anim_type;
343
        anim_type = trob.type;
344
        if (anim_type >= 0) {
345
                if (anim_type >= 3) {
346
                        // closing fast
347
                        if (anim_type < 8) {
348
                                ++anim_type;
349
                                trob.type = anim_type;
350
                        }
351
                        short new_mod = curr_modifier - gate_close_speeds[anim_type];
352
                        curr_modifier = new_mod;
353
                        //if ((sbyte)curr_modifier < 0) {
354
                        if (new_mod < 0) {
355
                        //if ((curr_modifier -= gate_close_speeds[anim_type]) < 0) {
356
                                curr_modifier = 0;
357
                                trob.type = -1;
358
                                play_sound(sound_6_gate_closing_fast); // gate closing fast
359
                        }
360
                } else {
361
                        if (curr_modifier != 0xFF) {
362
                                // 0xFF means permanently open.
363
                                curr_modifier += door_delta[anim_type];
364
                                if (anim_type == 0) {
365
                                        // closing
366
                                        if (curr_modifier != 0) {
367
                                                if (curr_modifier < 188) {
368
                                                        if ((curr_modifier & 3) == 3) {
369
                                                                play_door_sound_if_visible(sound_4_gate_closing); // gate closing
370
                                                        }
371
                                                }
372
                                        } else {
373
                                                gate_stop();
374
                                        }
375
                                } else {
376
                                        // opening
377
                                        if (curr_modifier < 188) {
378
                                                if ((curr_modifier & 7) == 0) {
379
                                                        play_sound(sound_5_gate_opening); // gate opening
380
                                                }
381
                                        } else {
382
                                                // stop
383
                                                if (anim_type < 2) {
384
                                                        // after regular open
385
                                                        curr_modifier = 238;
386
                                                        trob.type = 0; // closing
387
                                                        play_sound(sound_7_gate_stop); // gate stop (after opening)
388
                                                } else {
389
                                                        // after permanent open
390
                                                        curr_modifier = 0xFF; // keep open
391
                                                        gate_stop();
392
                                                }
393
                                        }
394
                                }
395
                        } else {
396
                                gate_stop();
397
                        }
398
                }
399
        }
400
        draw_trob();
401
}
402
 
403
// seg007:05E3
404
void __pascal far gate_stop() {
405
        trob.type = -1;
406
        play_door_sound_if_visible(sound_7_gate_stop); // gate stop (after closing)
407
}
408
 
409
// data:27B8
410
const byte leveldoor_close_speeds[] = {0, 5, 17, 99, 0};
411
// seg007:05F1
412
void __pascal far animate_leveldoor() {
413
/*
414
Possible values of trob_type:
415
0: open
416
1: open (with button)
417
2: open
418
3,4,5,6: fast closing with speeds 0,5,17,99 pixel/frame
419
*/
420
        word trob_type;
421
        trob_type = trob.type;
422
        if (trob.type >= 0) {
423
                if (trob_type >= 3) {
424
                        // closing
425
                        ++trob.type;
426
                        curr_modifier -= leveldoor_close_speeds[trob.type - 3];
427
                        if ((sbyte)curr_modifier < 0) {
428
                                curr_modifier = 0;
429
                                trob.type = -1;
430
                                play_sound(sound_14_leveldoor_closing); // level door closing
431
                        } else {
432
                                if (trob.type == 4 &&
433
                                        (sound_flags & sfDigi)
434
                                ) {
435
                                        sound_interruptible[sound_15_leveldoor_sliding] = 1;
436
                                        play_sound(sound_15_leveldoor_sliding); // level door sliding (closing)
437
                                }
438
                        }
439
                } else {
440
                        // opening
441
                        ++curr_modifier;
442
                        if (curr_modifier >= 43) {
443
                                trob.type = -1;
444
#ifdef FIX_FEATHER_INTERRUPTED_BY_LEVELDOOR
445
                                if (!(fix_feather_interrupted_by_leveldoor && is_feather_fall))
446
#endif
447
                                stop_sounds();
448
                                if (leveldoor_open == 0 || leveldoor_open == 2) {
449
                                        leveldoor_open = 1;
450
                                        if (current_level == 4) {
451
                                                // Special event: place mirror
452
                                                get_tile(4, 4, 0);
453
                                                curr_room_tiles[curr_tilepos] = tiles_13_mirror;
454
                                        }
455
                                }
456
                        } else {
457
                                sound_interruptible[15] = 0;
458
                                play_sound(sound_15_leveldoor_sliding); // level door sliding (opening)
459
                        }
460
                }
461
        }
462
        set_redraw_anim_right();
463
}
464
 
465
// seg007:06AD
466
short __pascal far bubble_next_frame(short curr) {
467
        short next;
468
        next = curr + 1;
469
        if (next >= 8) next = 1;
470
        return next;
471
}
472
 
473
// seg007:06CD
474
short __pascal far get_torch_frame(short curr) {
475
        short next;
476
        next = prandom(255);
477
        if (next != curr) {
478
                if (next < 9) {
479
                        return next;
480
                } else {
481
                        next = curr;
482
                }
483
        }
484
        ++next;
485
        if (next >= 9) next = 0;
486
        return next;
487
}
488
 
489
// seg007:070A
490
void __pascal far set_redraw_anim(short tilepos, byte frames) {
491
        if (tilepos < 30) {
492
                if (tilepos < 0) {
493
                        ++tilepos;
494
                        redraw_frames_above[-tilepos] = frames;
495
                        // or simply: ~tilepos
496
                } else {
497
                        redraw_frames_anim[tilepos] = frames;
498
                }
499
        }
500
}
501
 
502
// seg007:0738
503
void __pascal far set_redraw2(short tilepos, byte frames) {
504
        if (tilepos < 30) {
505
                if (tilepos < 0) {
506
                        // trying to draw a mob at a negative tilepos, in the range -1 .. -10
507
                        // used e.g. when the kid is climbing up to the room above
508
                        // however, loose tiles falling out of the room end up with a negative tilepos {-2 .. -11} !
509
                        tilepos = (-tilepos) - 1;
510
                        if (tilepos > 9) tilepos = 9; // prevent array index out of bounds!
511
                        redraw_frames_above[tilepos] = frames;
512
                } else {
513
                        redraw_frames2[tilepos] = frames;
514
                }
515
        }
516
}
517
 
518
// seg007:0766
519
void __pascal far set_redraw_floor_overlay(short tilepos, byte frames) {
520
        if (tilepos < 30) {
521
                if (tilepos < 0) {
522
                        ++tilepos;
523
                        redraw_frames_above[-tilepos] = frames;
524
                        // or simply: ~tilepos
525
                } else {
526
                        redraw_frames_floor_overlay[tilepos] = frames;
527
                }
528
        }
529
}
530
 
531
// seg007:0794
532
void __pascal far set_redraw_full(short tilepos, byte frames) {
533
        if (tilepos < 30) {
534
                if (tilepos < 0) {
535
                        ++tilepos;
536
                        redraw_frames_above[-tilepos] = frames;
537
                        // or simply: ~tilepos
538
                } else {
539
                        redraw_frames_full[tilepos] = frames;
540
                }
541
        }
542
}
543
 
544
// seg007:07C2
545
void __pascal far set_redraw_fore(short tilepos, byte frames) {
546
        if (tilepos < 30 && tilepos >= 0) {
547
                redraw_frames_fore[tilepos] = frames;
548
        }
549
}
550
 
551
// seg007:07DF
552
void __pascal far set_wipe(short tilepos, byte frames) {
553
        if (tilepos < 30 && tilepos >= 0) {
554
                if (wipe_frames[tilepos] != 0) {
555
                        redraw_height = MAX(wipe_heights[tilepos], redraw_height);
556
                }
557
                wipe_heights[tilepos] = redraw_height;
558
                wipe_frames[tilepos] = frames;
559
        }
560
}
561
 
562
// seg007:081E
563
void __pascal far start_anim_torch(short room,short tilepos) {
564
        curr_room_modif[tilepos] = prandom(8);
565
        add_trob(room, tilepos, 1);
566
}
567
 
568
// seg007:0847
569
void __pascal far start_anim_potion(short room,short tilepos) {
570
        curr_room_modif[tilepos] &= 0xF8;
571
        curr_room_modif[tilepos] |= prandom(6) + 1;
572
        add_trob(room, tilepos, 1);
573
}
574
 
575
// seg007:087C
576
void __pascal far start_anim_sword(short room,short tilepos) {
577
        curr_room_modif[tilepos] = prandom(0xFF) & 0x1F;
578
        add_trob(room, tilepos, 1);
579
}
580
 
581
// seg007:08A7
582
void __pascal far start_anim_chomper(short room,short tilepos, byte modifier) {
583
        short old_modifier;
584
        old_modifier = curr_room_modif[tilepos];
585
        if (old_modifier == 0 || old_modifier >= 6) {
586
                curr_room_modif[tilepos] = modifier;
587
                add_trob(room, tilepos, 1);
588
        }
589
}
590
 
591
// seg007:08E3
592
void __pascal far start_anim_spike(short room,short tilepos) {
593
        sbyte old_modifier;
594
        old_modifier = curr_room_modif[tilepos];
595
        if (old_modifier <= 0) {
596
                if (old_modifier == 0) {
597
                        add_trob(room, tilepos, 1);
598
                        play_sound(sound_49_spikes); // spikes
599
                } else {
600
                        // 0xFF means a disabled spike.
601
                        if (old_modifier != (sbyte)0xFF) {
602
                                curr_room_modif[tilepos] = 0x8F;
603
                        }
604
                }
605
        }
606
}
607
 
608
// seg007:092C
609
short __pascal far trigger_gate(short room,short tilepos,short button_type) {
610
        byte modifier;
611
        modifier = curr_room_modif[tilepos];
612
        if (button_type == tiles_15_opener) {
613
                // If the gate is permanently open, don't to anything.
614
                if (modifier == 0xFF) return -1;
615
                if (modifier >= 188) { // if it's already open
616
                        curr_room_modif[tilepos] = 238; // keep it open for a while
617
                        return -1;
618
                }
619
                curr_room_modif[tilepos] = (modifier + 3) & 0xFC;
620
                return 1; // regular open
621
        } else if (button_type == tiles_14_debris) {
622
                // If it's not fully open:
623
                if (modifier < 188) return 2; // permanent open
624
                curr_room_modif[tilepos] = 0xFF; // keep open
625
                return -1;
626
        } else {
627
                if (modifier != 0) {
628
                        return 3; // close fast
629
                } else {
630
                        // already closed
631
                        return -1;
632
                }
633
        }
634
}
635
 
636
// seg007:0999
637
short __pascal far trigger_1(short target_type,short room,short tilepos,short button_type) {
638
        short result;
639
        result = -1;
640
        if (target_type == tiles_4_gate) {
641
                result = trigger_gate(room, tilepos, button_type);
642
        } else if (target_type == tiles_16_level_door_left) {
643
                if (curr_room_modif[tilepos] != 0) {
644
                        result = -1;
645
                } else {
646
                        result = 1;
647
                }
648
        } else if (allow_triggering_any_tile) { //allow_triggering_any_tile hack
649
                result = 1;
650
        }
651
        return result;
652
}
653
 
654
// seg007:09E5
655
void __pascal far do_trigger_list(short index,short button_type) {
656
        word room;
657
        word tilepos;
658
        byte target_type;
659
        sbyte trigger_result;
660
//      while (doorlink1_ad[index] != -1) { // these can't be equal!
661
        while (1) {  // Same as the above but just a little faster and no compiler warning.
662
                room = get_doorlink_room(index);
663
                get_room_address(room);
664
                tilepos = get_doorlink_tile(index);
665
                target_type = curr_room_tiles[tilepos] & 0x1F;
666
                trigger_result = trigger_1(target_type, room, tilepos, button_type);
667
                if (trigger_result >= 0) {
668
                        add_trob(room, tilepos, trigger_result);
669
                }
670
                if (get_doorlink_next(index++) == 0) break;
671
        }
672
}
673
 
674
// seg007:0A5A
675
void __pascal far add_trob(byte room,byte tilepos,sbyte type) {
676
        short found;
677
        if (trobs_count >= 30) {
678
                show_dialog("Trobs Overflow");
679
                return /*0*/; // added
680
        }
681
        trob.room = room;
682
        trob.tilepos = tilepos;
683
        trob.type = type;
684
        found = find_trob();
685
        if (found == -1) {
686
                // add new
687
                if (trobs_count == 30) return;
688
                trobs[trobs_count++] = trob;
689
        } else {
690
                // change existing
691
                trobs[found].type = trob.type;
692
        }
693
}
694
 
695
// seg007:0ACA
696
short __pascal far find_trob() {
697
        short index;
698
        for (index = 0; index < trobs_count; ++index) {
699
                if (trobs[index].tilepos == trob.tilepos &&
700
                        trobs[index].room == trob.room) return index;
701
        }
702
        return -1;
703
}
704
 
705
// seg007:0B0A
706
void __pascal far clear_tile_wipes() {
707
        memset_near(redraw_frames_full, 0, sizeof(redraw_frames_full));
708
        memset_near(wipe_frames, 0, sizeof(wipe_frames));
709
        memset_near(wipe_heights, 0, sizeof(wipe_heights));
710
        memset_near(redraw_frames_anim, 0, sizeof(redraw_frames_anim));
711
        memset_near(redraw_frames_fore, 0, sizeof(redraw_frames_fore));
712
        memset_near(redraw_frames2, 0, sizeof(redraw_frames2));
713
        memset_near(redraw_frames_floor_overlay, 0, sizeof(redraw_frames_floor_overlay));
714
        memset_near(tile_object_redraw, 0, sizeof(tile_object_redraw));
715
        memset_near(redraw_frames_above, 0, sizeof(redraw_frames_above));
716
}
717
 
718
// seg007:0BB6
719
short __pascal far get_doorlink_timer(short index) {
720
        return doorlink2_ad[index] & 0x1F;
721
}
722
 
723
// seg007:0BCD
724
short __pascal far set_doorlink_timer(short index,byte value) {
725
        doorlink2_ad[index] &= 0xE0;
726
        doorlink2_ad[index] |= value & 0x1F;
727
        return doorlink2_ad[index];
728
}
729
 
730
// seg007:0BF2
731
short __pascal far get_doorlink_tile(short index) {
732
        return doorlink1_ad[index] & 0x1F;
733
}
734
 
735
// seg007:0C09
736
short __pascal far get_doorlink_next(short index) {
737
        return !(doorlink1_ad[index] & 0x80);
738
}
739
 
740
// seg007:0C26
741
short __pascal far get_doorlink_room(short index) {
742
        return
743
                ((doorlink1_ad[index] & 0x60) >> 5) +
744
                ((doorlink2_ad[index] & 0xE0) >> 3);
745
}
746
 
747
// seg007:0C53
748
void __pascal far trigger_button(int playsound,int button_type,int modifier) {
749
        sbyte link_timer;
750
        get_curr_tile(curr_tilepos);
751
        if (button_type == 0) {
752
                // 0 means currently selected
753
                button_type = curr_tile;
754
        }
755
        if (modifier == -1) {
756
                // -1 means currently selected
757
                modifier = curr_modifier;
758
        }
759
        link_timer = get_doorlink_timer(modifier);
760
        // is the event jammed?
761
        if (link_timer != 0x1F) {
762
                set_doorlink_timer(modifier, 5);
763
                if (link_timer < 2) {
764
                        add_trob(curr_room, curr_tilepos, 1);
765
                        redraw_11h();
766
                        is_guard_notice = 1;
767
                        if (playsound) {
768
                                play_sound(sound_3_button_pressed); // button pressed
769
                        }
770
                }
771
                do_trigger_list(modifier, button_type);
772
        }
773
}
774
 
775
// seg007:0CD9
776
void __pascal far died_on_button() {
777
        word button_type;
778
        word modifier;
779
        button_type = get_curr_tile(curr_tilepos);
780
        modifier = curr_modifier;
781
        if (curr_tile == tiles_15_opener) {
782
                curr_room_tiles[curr_tilepos] = tiles_1_floor;
783
                curr_room_modif[curr_tilepos] = 0;
784
                button_type = tiles_14_debris; // force permanent open
785
        } else {
786
                curr_room_tiles[curr_tilepos] = tiles_5_stuck;
787
        }
788
        trigger_button(1, button_type, modifier);
789
}
790
 
791
// seg007:0D3A
792
void __pascal far animate_button() {
793
        word var_2;
794
        if (trob.type >= 0) {
795
                set_doorlink_timer(curr_modifier, var_2 = get_doorlink_timer(curr_modifier) - 1);
796
                if (var_2 < 2) {
797
                        trob.type = -1;
798
                        redraw_11h();
799
                }
800
        }
801
}
802
 
803
// seg007:0D72
804
void __pascal far start_level_door(short room,short tilepos) {
805
        curr_room_modif[tilepos] = 43; // start fully open
806
        add_trob(room, tilepos, 3);
807
}
808
 
809
// seg007:0D93
810
void __pascal far animate_empty() {
811
        trob.type = -1;
812
        redraw_20h();
813
}
814
 
815
// data:2284
816
const word y_loose_land[] = {2, 65, 128, 191, 254};
817
// seg007:0D9D
818
void __pascal far animate_loose() {
819
        word room;
820
        word row;
821
        word tilepos;
822
        short anim_type;
823
        anim_type = trob.type;
824
        if (anim_type >= 0) {
825
                ++curr_modifier;
826
                if (curr_modifier & 0x80) {
827
                        // just shaking
828
                        // don't shake on level 13
829
                        if (current_level == 13) return;
830
                        if (curr_modifier >= 0x84) {
831
                                curr_modifier = 0;
832
                                trob.type = -1;
833
                        }
834
                        loose_shake(!curr_modifier);
835
                } else {
836
                        // something is on the floor
837
                        // should it fall already?
838
                        if (curr_modifier >= 11) {
839
                                curr_modifier = remove_loose(room = trob.room, tilepos = trob.tilepos);
840
                                trob.type = -1;
841
                                curmob.xh = (tilepos % 10) << 2;
842
                                row = tilepos / 10;
843
                                curmob.y = y_loose_land[row + 1];
844
                                curmob.room = room;
845
                                curmob.speed = 0;
846
                                curmob.type = 0;
847
                                curmob.row = row;
848
                                add_mob();
849
                        } else {
850
                                loose_shake(0);
851
                        }
852
                }
853
        }
854
        redraw_20h();
855
}
856
 
857
// data:2734
858
const byte loose_sound[] = {0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0};
859
// seg007:0E55
860
void __pascal far loose_shake(int arg_0) {
861
        word sound_id;
862
        if (arg_0 || loose_sound[curr_modifier & 0x7F]) {
863
                do {
864
                        // Sounds 20,21,22: loose floor shaking
865
                        sound_id = prandom(2) + sound_20_loose_shake_1;
866
                } while(sound_id == last_loose_sound);
867
                if (sound_flags & sfDigi) {
868
                        last_loose_sound = sound_id;
869
                        // random sample rate (10500..11500)
870
                        //sound_pointers[sound_id]->samplerate = prandom(1000) + 10500;
871
                }
872
                play_sound(sound_id);
873
        }
874
}
875
 
876
// seg007:0EB8
877
int __pascal far remove_loose(int room, int tilepos) {
878
        curr_room_tiles[tilepos] = tiles_0_empty;
879
        // note: the level type is used to determine the modifier of the empty space left behind
880
        return tbl_level_type[current_level];
881
}
882
 
883
// seg007:0ED5
884
void __pascal far make_loose_fall(byte modifier) {
885
        // is it a "solid" loose floor?
886
        if ((curr_room_tiles[curr_tilepos] & 0x20) == 0) {
887
                if ((sbyte)curr_room_modif[curr_tilepos] <= 0) {
888
                        curr_room_modif[curr_tilepos] = modifier;
889
                        add_trob(curr_room, curr_tilepos, 0);
890
                        redraw_20h();
891
                }
892
        }
893
}
894
 
895
// seg007:0F13
896
void __pascal far start_chompers() {
897
        short timing;
898
        short modifier;
899
        short tilepos;
900
        short column;
901
        timing = 15;
902
        if ((byte)Char.curr_row < 3) {
903
                get_room_address(Char.room);
904
                for (column = 0, tilepos = tbl_line[Char.curr_row];
905
                        column < 10; ++column, ++tilepos
906
                ){
907
                        if (get_curr_tile(tilepos) == tiles_18_chomper) {
908
                                modifier = curr_modifier & 0x7F;
909
                                if (modifier == 0 || modifier >= 6) {
910
                                        start_anim_chomper(Char.room, tilepos, timing | (curr_modifier & 0x80));
911
                                        timing = next_chomper_timing(timing);
912
                                }
913
                        }
914
                }
915
        }
916
}
917
 
918
// seg007:0F9A
919
int __pascal far next_chomper_timing(byte timing) {
920
        // 15,12,9,6,13,10,7,14,11,8,repeat
921
        timing -= 3;
922
        if (timing < 6) {
923
                timing += 10;
924
        }
925
        return timing;
926
}
927
 
928
// seg007:0FB4
929
void __pascal far loose_make_shake() {
930
        if (curr_room_modif[curr_tilepos] == 0 && current_level != 13) {
931
                curr_room_modif[curr_tilepos] = 0x80;
932
                add_trob(curr_room, curr_tilepos, 1);
933
        }
934
}
935
 
936
// seg007:0FE0
937
void __pascal far do_knock(int room,int tile_row) {
938
        short tile_col;
939
        for (tile_col = 0; tile_col < 10; ++tile_col) {
940
                if (get_tile(room, tile_col, tile_row) == tiles_11_loose) {
941
                        loose_make_shake();
942
                }
943
        }
944
}
945
 
946
// seg007:1010
947
void __pascal far add_mob() {
948
        if (mobs_count >= 14) {
949
                show_dialog("Mobs Overflow");
950
                return /*0*/; // added
951
        }
952
        mobs[mobs_count++] = curmob;
953
}
954
 
955
// seg007:1041
956
short __pascal far get_curr_tile(short tilepos) {
957
        curr_modifier = curr_room_modif[tilepos];
958
        return curr_tile = curr_room_tiles[tilepos] & 0x1F;
959
}
960
 
961
// data:43DC
962
word curmob_index;
963
 
964
// seg007:1063
965
void __pascal far do_mobs() {
966
        short n_mobs;
967
        short index;
968
        short new_index;
969
        n_mobs = mobs_count;
970
        for (curmob_index = 0; n_mobs > curmob_index; ++curmob_index) {
971
                curmob = mobs[curmob_index];
972
                move_mob();
973
                check_loose_fall_on_kid();
974
                mobs[curmob_index] = curmob;
975
        }
976
        new_index = 0;
977
        for (index = 0; index < mobs_count; ++index) {
978
                if (mobs[index].speed != -1) {
979
                        mobs[new_index++] = mobs[index];
980
                }
981
        }
982
        mobs_count = new_index;
983
}
984
 
985
// seg007:110F
986
void __pascal far move_mob() {
987
        if (curmob.type == 0) {
988
                move_loose();
989
        }
990
        if (curmob.speed <= 0) {
991
                ++curmob.speed;
992
        }
993
}
994
 
995
// data:227A
996
const short y_something[] = {-1, 62, 125, 188, 25};
997
// data:594A
998
word curr_tile_temp;
999
// seg007:1126
1000
void __pascal far move_loose() {
1001
        if (curmob.speed < 0) return;
1002
        if (curmob.speed < 29) curmob.speed += 3;
1003
        curmob.y += curmob.speed;
1004
        if (curmob.room == 0) {
1005
                if (curmob.y < 210) {
1006
                        return;
1007
                } else {
1008
                        curmob.speed = -2;
1009
                        return;
1010
                }
1011
        }
1012
        if (curmob.y < 226 && y_something[curmob.row + 1] <= curmob.y) {
1013
                // fell into a different row
1014
                curr_tile_temp = get_tile(curmob.room, curmob.xh >> 2, curmob.row);
1015
                if (curr_tile_temp == tiles_11_loose) {
1016
                        loose_fall();
1017
                }
1018
                if (curr_tile_temp == tiles_0_empty ||
1019
                        curr_tile_temp == tiles_11_loose
1020
                ) {
1021
                        mob_down_a_row();
1022
                        return;
1023
                }
1024
                play_sound(sound_2_tile_crashing); // tile crashing
1025
                do_knock(curmob.room, curmob.row);
1026
                curmob.y = y_something[curmob.row + 1];
1027
                curmob.speed = -2;
1028
                loose_land();
1029
        }
1030
}
1031
 
1032
// seg007:11E8
1033
void __pascal far loose_land() {
1034
        short button_type;
1035
        short tiletype;
1036
        button_type = 0;
1037
        tiletype = get_tile(curmob.room, curmob.xh >> 2, curmob.row);
1038
        switch (tiletype) {
1039
                case tiles_15_opener:
1040
                        curr_room_tiles[curr_tilepos] = tiles_14_debris;
1041
                        button_type = tiles_14_debris;
1042
                // fallthrough!
1043
                case tiles_6_closer:
1044
                        trigger_button(1, button_type, -1);
1045
                        tiletype = get_tile(curmob.room, curmob.xh >> 2, curmob.row);
1046
                // fallthrough!
1047
                case tiles_1_floor:
1048
                case tiles_2_spike:
1049
                case tiles_10_potion:
1050
                case tiles_19_torch:
1051
                case tiles_30_torch_with_debris:
1052
                        if (tiletype == tiles_19_torch ||
1053
                                tiletype == tiles_30_torch_with_debris
1054
                        ) {
1055
                                curr_room_tiles[curr_tilepos] = tiles_30_torch_with_debris;
1056
                        } else {
1057
                                curr_room_tiles[curr_tilepos] = tiles_14_debris;
1058
                        }
1059
                        redraw_at_cur_mob();
1060
                        if (tile_col != 0) {
1061
                                set_redraw_full(curr_tilepos - 1, 1);
1062
                        }
1063
        }
1064
}
1065
 
1066
// seg007:12CB
1067
void __pascal far loose_fall() {
1068
        curr_room_modif[curr_tilepos] = remove_loose(curr_room, curr_tilepos);
1069
        curmob.speed >>= 1;
1070
        mobs[curmob_index] = curmob;
1071
        curmob.y += 6;
1072
        mob_down_a_row();
1073
        add_mob();
1074
        curmob = mobs[curmob_index];
1075
        redraw_at_cur_mob();
1076
}
1077
 
1078
// seg007:132C
1079
void __pascal far redraw_at_cur_mob() {
1080
        if (curmob.room == drawn_room) {
1081
                redraw_height = 0x20;
1082
                set_redraw_full(curr_tilepos, 1);
1083
                set_wipe(curr_tilepos, 1);
1084
                // Redraw tile to the right only if it's in the same room.
1085
                if ((curr_tilepos % 10) + 1 < 10) { // changed
1086
                        set_redraw_full(curr_tilepos + 1, 1);
1087
                        set_wipe(curr_tilepos + 1, 1);
1088
                }
1089
        }
1090
}
1091
 
1092
// seg007:1387
1093
void __pascal far mob_down_a_row() {
1094
        ++curmob.row;
1095
        if (curmob.row >= 3) {
1096
                curmob.y -= 192;
1097
                curmob.row = 0;
1098
                curmob.room = level.roomlinks[curmob.room - 1].down;
1099
        }
1100
}
1101
 
1102
// seg007:13AE
1103
void __pascal far draw_mobs() {
1104
        short index;
1105
        for (index = 0; index < mobs_count; ++index) {
1106
                curmob = mobs[index];
1107
                draw_mob();
1108
        }
1109
}
1110
 
1111
// seg007:13E5
1112
void __pascal far draw_mob() {
1113
        short tile_row;
1114
        short ypos;
1115
        short top_row;
1116
        short tilepos;
1117
        short tile_col;
1118
        ypos = curmob.y;
1119
        if (curmob.room == drawn_room) {
1120
                if (curmob.y >= 210) return;
1121
        } else if (curmob.room == room_B) {
1122
                if (ABS(ypos) >= 18) return;
1123
                curmob.y += 192;
1124
                ypos = curmob.y;
1125
        } else if (curmob.room == room_A) {
1126
                if (curmob.y < 174) return;
1127
                ypos = curmob.y - 189;
1128
        } else {
1129
                return;
1130
        }
1131
        tile_col = curmob.xh >> 2;
1132
        tile_row = y_to_row_mod4(ypos);
1133
        obj_tilepos = get_tilepos_nominus(tile_col, tile_row);
1134
        ++tile_col;
1135
        tilepos = get_tilepos(tile_col, tile_row);
1136
        set_redraw2(tilepos, 1);
1137
        set_redraw_fore(tilepos, 1);
1138
        top_row = y_to_row_mod4(ypos - 18);
1139
        if (top_row != tile_row) {
1140
                tilepos = get_tilepos(tile_col, top_row);
1141
                set_redraw2(tilepos, 1);
1142
                set_redraw_fore(tilepos, 1);
1143
        }
1144
        add_mob_to_objtable(ypos);
1145
}
1146
 
1147
// seg007:14DE
1148
void __pascal far add_mob_to_objtable(int ypos) {
1149
        word index;
1150
        objtable_type* curr_obj;
1151
        index = objtable_count++;
1152
        curr_obj = &objtable[index];
1153
        curr_obj->obj_type = curmob.type | 0x80;
1154
        curr_obj->xh = curmob.xh;
1155
        curr_obj->xl = 0;
1156
        curr_obj->y = ypos;
1157
        curr_obj->chtab_id = id_chtab_6_environment;
1158
        curr_obj->id = 10;
1159
        curr_obj->clip.top = 0;
1160
        curr_obj->clip.left = 0;
1161
        curr_obj->clip.right = 40;
1162
        mark_obj_tile_redraw(index);
1163
}
1164
 
1165
// seg007:153E
1166
void __pascal far sub_9A8E() {
1167
        // This function is not used.
1168
        method_1_blit_rect(onscreen_surface_, offscreen_surface, &rect_top, &rect_top, 0);
1169
}
1170
 
1171
// seg007:1556
1172
int __pascal far is_spike_harmful() {
1173
        sbyte modifier;
1174
        modifier = curr_room_modif[curr_tilepos];
1175
        if (modifier == 0 || modifier == -1) {
1176
                return 0;
1177
        } else if (modifier < 0) {
1178
                return 1;
1179
        } else if (modifier < 5) {
1180
                return 2;
1181
        } else {
1182
                return 0;
1183
        }
1184
}
1185
 
1186
// seg007:1591
1187
void __pascal far check_loose_fall_on_kid() {
1188
        loadkid();
1189
        if (Char.room == curmob.room &&
1190
                Char.curr_col == curmob.xh >> 2 &&
1191
                curmob.y < Char.y &&
1192
                Char.y - 30 < curmob.y
1193
        ) {
1194
                fell_on_your_head();
1195
                savekid();
1196
        }
1197
}
1198
 
1199
// seg007:15D3
1200
void __pascal far fell_on_your_head() {
1201
        short frame;
1202
        short action;
1203
        frame = Char.frame;
1204
        action = Char.action;
1205
        // loose floors hurt you in frames 5..14 (running) only on level 13
1206
        if (
1207
                (current_level == 13 || (frame < frame_5_start_run || frame >= 15)) &&
1208
                (action < actions_2_hang_climb || action == actions_7_turn)
1209
        ) {
1210
                Char.y = y_land[Char.curr_row + 1];
1211
                if (take_hp(1)) {
1212
                        seqtbl_offset_char(seq_22_crushed); // dead (because of loose floor)
1213
                        if (frame == frame_177_spiked) { // spiked
1214
                                Char.x = char_dx_forward(-12);
1215
                        }
1216
                } else {
1217
                        if (frame != frame_109_crouch) { // crouching
1218
                                if (get_tile_behind_char() == 0) {
1219
                                        Char.x = char_dx_forward(-2);
1220
                                }
1221
                                seqtbl_offset_char(seq_52_loose_floor_fell_on_kid); // loose floor fell on Kid
1222
                        }
1223
                }
1224
        }
1225
}
1226
 
1227
// seg007:1669
1228
void __pascal far play_door_sound_if_visible(int sound_id) {
1229
        word has_sound;
1230
        word tilepos;
1231
        word gate_room;
1232
        tilepos = trob.tilepos;
1233
        gate_room = trob.room;
1234
        has_sound = 0;
1235
 
1236
#ifdef FIX_GATE_SOUNDS
1237
        sbyte has_sound_condition;
1238
        if (fix_gate_sounds)
1239
                has_sound_condition =   (gate_room == room_L && tilepos % 10 == 9) ||
1240
                                        (gate_room == drawn_room && tilepos % 10 != 9);
1241
        else
1242
                has_sound_condition =  gate_room == room_L ? tilepos % 10 == 9 :
1243
                                      (gate_room == drawn_room && tilepos % 10 != 9);
1244
        #define GATE_SOUND_CONDITION has_sound_condition
1245
#else
1246
        #define GATE_SOUND_CONDITION gate_room == room_L ? tilepos % 10 == 9 :          \
1247
                                    (gate_room == drawn_room && tilepos % 10 != 9)
1248
#endif
1249
        // Special event: sound of closing gates
1250
        if ((current_level == 3 && gate_room == 2) || GATE_SOUND_CONDITION) {
1251
                has_sound = 1;
1252
        }
1253
        if (has_sound) {
1254
                play_sound(sound_id);
1255
        }
1256
}