added single step support for BD engine
[rocksndiamonds.git] / src / game_bd / bd_caveengine.c
1 /*
2  * Copyright (c) 2007, 2008, 2009, Czirkos Zoltan <cirix@fw.hu>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 // IMPORTANT NOTES
18
19 /*
20  * LAVA.
21  *
22  * Lava absorbs everything going into it. Everything.
23  * But it does not "pull" elements; only the things disappear which
24  * _do_ go directly into it. So if the player steps into the lava,
25  * he will die. If a dragonfly flies over it, it will not.
26  *
27  * This behavior is implemented in the is_space_dir and the store
28  * functions. is_space_dir returns true for the lava, too. The store
29  * function ignores any store requests into the lava.
30  * The player_get function will also behave for lava as it does for space.
31  */
32
33 #include "main_bd.h"
34
35
36 // for gravity
37 static const GdDirection ccw_eighth[] =
38 {
39   GD_MV_STILL,
40   GD_MV_UP_LEFT,
41   GD_MV_UP,
42   GD_MV_UP_RIGHT,
43   GD_MV_RIGHT,
44   GD_MV_DOWN_RIGHT,
45   GD_MV_DOWN,
46   GD_MV_DOWN_LEFT
47 };
48
49 static const GdDirection ccw_fourth[] =
50 {
51   GD_MV_STILL,
52   GD_MV_LEFT,
53   GD_MV_UP_LEFT,
54   GD_MV_UP,
55   GD_MV_UP_RIGHT,
56   GD_MV_RIGHT,
57   GD_MV_DOWN_RIGHT,
58   GD_MV_DOWN,
59   GD_MV_DOWN_LEFT,
60   GD_MV_LEFT
61 };
62
63 static const GdDirection cw_eighth[] =
64 {
65   GD_MV_STILL,
66   GD_MV_UP_RIGHT,
67   GD_MV_RIGHT,
68   GD_MV_DOWN_RIGHT,
69   GD_MV_DOWN,
70   GD_MV_DOWN_LEFT,
71   GD_MV_LEFT,
72   GD_MV_UP_LEFT,
73   GD_MV_UP
74 };
75
76 static const GdDirection cw_fourth[] =
77 {
78   GD_MV_STILL,
79   GD_MV_RIGHT,
80   GD_MV_DOWN_RIGHT,
81   GD_MV_DOWN,
82   GD_MV_DOWN_LEFT,
83   GD_MV_LEFT,
84   GD_MV_UP_LEFT,
85   GD_MV_UP,
86   GD_MV_UP_RIGHT
87 };
88
89 static const GdDirection opposite[] =
90 {
91   GD_MV_STILL,
92   GD_MV_DOWN,
93   GD_MV_DOWN_LEFT,
94   GD_MV_LEFT,
95   GD_MV_UP_LEFT,
96   GD_MV_UP,
97   GD_MV_UP_RIGHT,
98   GD_MV_RIGHT,
99   GD_MV_DOWN_RIGHT
100 };
101
102 // sets timeout sound.
103 void gd_cave_set_seconds_sound(GdCave *cave)
104 {
105   // when not counting bonus time, timeout sounds will be played by main game engine;
106   // also skip timeout sounds when not using native sound engine
107   if (game_bd.game == NULL || game_bd.game->state_counter != GAME_INT_CHECK_BONUS_TIME ||
108       !game.use_native_bd_sound_engine)
109     return;
110
111   // this is an integer division, so 0 seconds can be 0.5 seconds...
112   // also, when this reaches 8, the player still has 8.9999 seconds.
113   // so the sound is played at almost t = 9s.
114   switch (cave->time / cave->timing_factor)
115   {
116     case 9: gd_sound_play(cave, GD_S_TIMEOUT_10, O_NONE, -1, -1); break;
117     case 8: gd_sound_play(cave, GD_S_TIMEOUT_9,  O_NONE, -1, -1); break;
118     case 7: gd_sound_play(cave, GD_S_TIMEOUT_8,  O_NONE, -1, -1); break;
119     case 6: gd_sound_play(cave, GD_S_TIMEOUT_7,  O_NONE, -1, -1); break;
120     case 5: gd_sound_play(cave, GD_S_TIMEOUT_6,  O_NONE, -1, -1); break;
121     case 4: gd_sound_play(cave, GD_S_TIMEOUT_5,  O_NONE, -1, -1); break;
122     case 3: gd_sound_play(cave, GD_S_TIMEOUT_4,  O_NONE, -1, -1); break;
123     case 2: gd_sound_play(cave, GD_S_TIMEOUT_3,  O_NONE, -1, -1); break;
124     case 1: gd_sound_play(cave, GD_S_TIMEOUT_2,  O_NONE, -1, -1); break;
125     case 0: gd_sound_play(cave, GD_S_TIMEOUT_1,  O_NONE, -1, -1); break;
126   }
127 }
128
129 // returns true if the element can fall
130 static inline boolean el_can_fall(const int element)
131 {
132   return (gd_elements[element & O_MASK].properties & P_CAN_FALL) != 0;
133 }
134
135 // play diamond or stone sound of given element.
136 static void play_sound_of_element(GdCave *cave, GdElement element, int x, int y)
137 {
138   // check if sound should be skipped for falling elements (and only be played on impact)
139   if (el_can_fall(element) && !use_bd_falling_sounds())
140     return;
141
142   // stone and diamond fall sounds.
143   switch (element)
144   {
145     case O_NUT:
146       gd_sound_play(cave, GD_S_NUT_FALLING, element, x, y);
147       break;
148
149     case O_NUT_F:
150       gd_sound_play(cave, GD_S_NUT_IMPACT, element, x, y);
151       break;
152
153     case O_STONE:
154       gd_sound_play(cave, GD_S_STONE_FALLING, element, x, y);
155       break;
156
157     case O_STONE_F:
158       gd_sound_play(cave, GD_S_STONE_IMPACT, element, x, y);
159       break;
160
161     case O_FLYING_STONE:
162       gd_sound_play(cave, GD_S_FLYING_STONE_FALLING, element, x, y);
163       break;
164
165     case O_FLYING_STONE_F:
166       gd_sound_play(cave, GD_S_FLYING_STONE_IMPACT, element, x, y);
167       break;
168
169     case O_MEGA_STONE:
170       gd_sound_play(cave, GD_S_MEGA_STONE_FALLING, element, x, y);
171       break;
172
173     case O_MEGA_STONE_F:
174       gd_sound_play(cave, GD_S_MEGA_STONE_IMPACT, element, x, y);
175       break;
176
177     case O_NITRO_PACK:
178       gd_sound_play(cave, GD_S_NITRO_PACK_FALLING, element, x, y);
179       break;
180
181     case O_NITRO_PACK_F:
182       gd_sound_play(cave, GD_S_NITRO_PACK_IMPACT, element, x, y);
183       break;
184
185     case O_FALLING_WALL:
186       gd_sound_play(cave, GD_S_FALLING_WALL_FALLING, element, x, y);
187       break;
188
189     case O_FALLING_WALL_F:
190       gd_sound_play(cave, GD_S_FALLING_WALL_IMPACT, element, x, y);
191       break;
192
193     case O_H_EXPANDING_WALL:
194     case O_V_EXPANDING_WALL:
195     case O_EXPANDING_WALL:
196     case O_H_EXPANDING_STEEL_WALL:
197     case O_V_EXPANDING_STEEL_WALL:
198     case O_EXPANDING_STEEL_WALL:
199       gd_sound_play(cave, GD_S_EXPANDING_WALL, element, x, y);
200       break;
201
202     case O_DIAMOND:
203       gd_sound_play(cave, GD_S_DIAMOND_FALLING_RANDOM, element, x, y);
204       break;
205
206     case O_DIAMOND_F:
207       gd_sound_play(cave, GD_S_DIAMOND_IMPACT_RANDOM, element, x, y);
208       break;
209
210     case O_FLYING_DIAMOND:
211       gd_sound_play(cave, GD_S_FLYING_DIAMOND_FALLING_RANDOM, element, x, y);
212       break;
213
214     case O_FLYING_DIAMOND_F:
215       gd_sound_play(cave, GD_S_FLYING_DIAMOND_IMPACT_RANDOM, element, x, y);
216       break;
217
218     case O_BLADDER_SPENDER:
219       gd_sound_play(cave, GD_S_BLADDER_SPENDER, element, x, y);
220       break;
221
222     case O_PRE_CLOCK_1:
223       gd_sound_play(cave, GD_S_BLADDER_CONVERTING, element, x, y);
224       break;
225
226     case O_SLIME:
227       gd_sound_play(cave, GD_S_SLIME, element, x, y);
228       break;
229
230     case O_LAVA:
231       gd_sound_play(cave, GD_S_LAVA, element, x, y);
232       break;
233
234     case O_ACID:
235       gd_sound_play(cave, GD_S_ACID_SPREADING, element, x, y);
236       break;
237
238     case O_BLADDER:
239       gd_sound_play(cave, GD_S_BLADDER_MOVING, element, x, y);
240       break;
241
242     case O_BITER_1:
243     case O_BITER_2:
244     case O_BITER_3:
245     case O_BITER_4:
246       gd_sound_play(cave, GD_S_BITER_EATING, element, x, y);
247       break;
248
249     case O_DIRT_BALL:
250       gd_sound_play(cave, GD_S_DIRT_BALL_FALLING, element, x, y);
251       break;
252
253     case O_DIRT_BALL_F:
254       gd_sound_play(cave, GD_S_DIRT_BALL_IMPACT, element, x, y);
255       break;
256
257     case O_DIRT_LOOSE:
258       gd_sound_play(cave, GD_S_DIRT_LOOSE_FALLING, element, x, y);
259       break;
260
261     case O_DIRT_LOOSE_F:
262       gd_sound_play(cave, GD_S_DIRT_LOOSE_IMPACT, element, x, y);
263       break;
264
265     default:
266       // do nothing.
267       break;
268   }
269 }
270
271 // play sound of given element being pushed.
272 static void play_sound_of_element_pushing(GdCave *cave, GdElement element, int x, int y)
273 {
274   switch (element)
275   {
276     case O_NUT:
277       gd_sound_play(cave, GD_S_NUT_PUSHING, element, x, y);
278       break;
279
280     case O_STONE:
281       gd_sound_play(cave, GD_S_STONE_PUSHING, element, x, y);
282       break;
283
284     case O_FLYING_STONE:
285       gd_sound_play(cave, GD_S_FLYING_STONE_PUSHING, element, x, y);
286       break;
287
288     case O_MEGA_STONE:
289       gd_sound_play(cave, GD_S_MEGA_STONE_PUSHING, element, x, y);
290       break;
291
292     case O_WAITING_STONE:
293       gd_sound_play(cave, GD_S_WAITING_STONE_PUSHING, element, x, y);
294       break;
295
296     case O_CHASING_STONE:
297       gd_sound_play(cave, GD_S_CHASING_STONE_PUSHING, element, x, y);
298       break;
299
300     case O_NITRO_PACK:
301       gd_sound_play(cave, GD_S_NITRO_PACK_PUSHING, element, x, y);
302       break;
303
304     case O_BLADDER:
305       gd_sound_play(cave, GD_S_BLADDER_PUSHING, element, x, y);
306       break;
307
308     default:
309       // do nothing.
310       break;
311   }
312 }
313
314 static inline int getx(const GdCave *cave, const int x, const int y)
315 {
316   return cave->getx(cave, x, y);
317 }
318
319 static inline int gety(const GdCave *cave, const int x, const int y)
320 {
321   return cave->gety(cave, x, y);
322 }
323
324 // perfect (non-lineshifting) GET x/y functions; returns range corrected x/y position
325 static inline int getx_perfect(const GdCave *cave, const int x, const int y)
326 {
327   return (x + cave->w) % cave->w;
328 }
329
330 static inline int gety_perfect(const GdCave *cave, const int x, const int y)
331 {
332   return (y + cave->h) % cave->h;
333 }
334
335 // line shifting GET x/y function; returns range corrected x/y position
336 static inline int getx_shift(const GdCave *cave, int x, int y)
337 {
338   return (x + cave->w) % cave->w;
339 }
340
341 static inline int gety_shift(const GdCave *cave, int x, int y)
342 {
343   return ((x < 0 ? y - 1 : x >= cave->w ? y + 1 : y) + cave->h) % cave->h;
344 }
345
346 static inline GdElement *getp(const GdCave *cave, const int x, const int y)
347 {
348   return cave->getp(cave, x, y);
349 }
350
351 /*
352   perfect (non-lineshifting) GET function.
353   returns a pointer to a selected cave element by its coordinates.
354 */
355 static inline GdElement *getp_perfect(const GdCave *cave, const int x, const int y)
356 {
357   // (x + n) mod n: this works also for x >= n and -n + 1 < x < 0
358   return &(cave->map[(y + cave->h) % cave->h][(x + cave->w) % cave->w]);
359 }
360
361 /*
362   line shifting GET function; returns a pointer to the selected cave element.
363   this is used to emulate the line-shifting behaviour of original games, so that
364   the player entering one side will appear one row above or below on the other.
365 */
366 static inline GdElement *getp_shift(const GdCave *cave, int x, int y)
367 {
368   if (x >= cave->w)
369   {
370     y++;
371     x -= cave->w;
372   }
373   else if (x < 0)
374   {
375     y--;
376     x += cave->w;
377   }
378
379   y = (y + cave->h) % cave->h;
380
381   return &(cave->map[y][x]);
382 }
383
384 static inline GdElement get(const GdCave *cave, const int x, const int y)
385 {
386   return *getp(cave, x, y);
387 }
388
389 // returns an element which is somewhere near x,y
390 static inline GdElement get_dir(const GdCave *cave, const int x, const int y,
391                                 const GdDirection dir)
392 {
393   return get(cave, x + gd_dx[dir], y + gd_dy[dir]);
394 }
395
396 static inline boolean explodes_by_hit_dir(const GdCave *cave, const int x,
397                                           const int y, GdDirection dir)
398 {
399   return (gd_elements[get_dir(cave, x, y, dir) & O_MASK].properties & P_EXPLODES_BY_HIT) != 0;
400 }
401
402 // returns true if the element is not explodable, for example the steel wall
403 static inline boolean non_explodable(const GdCave *cave, const int x, const int y)
404 {
405   return (gd_elements[get(cave, x,y) & O_MASK].properties & P_NON_EXPLODABLE) != 0;
406 }
407
408 // returns true if the element can be eaten by the amoeba, eg. space and dirt.
409 static inline boolean amoeba_eats_dir(const GdCave *cave, const int x, const int y,
410                                       const GdDirection dir)
411 {
412   return (gd_elements[get_dir(cave, x, y, dir) & O_MASK].properties & P_AMOEBA_CONSUMES) != 0;
413 }
414
415 // returns true if the element is sloped, so stones and diamonds roll down on it.
416 // for example a stone or brick wall
417 static inline boolean sloped_dir(const GdCave *cave, const int x, const int y,
418                                  const GdDirection dir, const GdDirection slop)
419 {
420   switch (slop)
421   {
422     case GD_MV_LEFT:
423       return (gd_elements[get_dir(cave, x, y, dir) & O_MASK].properties & P_SLOPED_LEFT) != 0;
424
425     case GD_MV_RIGHT:
426       return (gd_elements[get_dir(cave, x, y, dir) & O_MASK].properties & P_SLOPED_RIGHT) != 0;
427
428     case GD_MV_UP:
429       return (gd_elements[get_dir(cave, x, y, dir) & O_MASK].properties & P_SLOPED_UP) != 0;
430
431     case GD_MV_DOWN:
432       return (gd_elements[get_dir(cave, x, y, dir) & O_MASK].properties & P_SLOPED_DOWN) != 0;
433
434     default:
435       break;
436   }
437
438   return FALSE;
439 }
440
441 // returns true if the element is sloped for bladder movement
442 // (brick = yes, diamond = no, for example)
443 static inline boolean sloped_for_bladder_dir (const GdCave *cave, const int x, const int y,
444                                               const GdDirection dir)
445 {
446   return (gd_elements[get_dir(cave, x, y, dir) & O_MASK].properties & P_BLADDER_SLOPED) != 0;
447 }
448
449 static inline boolean blows_up_flies_dir(const GdCave *cave, const int x, const int y,
450                                          const GdDirection dir)
451 {
452     return (gd_elements[get_dir(cave, x, y, dir) & O_MASK].properties & P_BLOWS_UP_FLIES) != 0;
453 }
454
455 // returns true if the element is a counter-clockwise creature
456 static inline boolean rotates_ccw (const GdCave *cave, const int x, const int y)
457 {
458   return (gd_elements[get(cave, x, y) & O_MASK].properties & P_CCW) != 0;
459 }
460
461 // returns true if the element is a player
462 boolean is_player(const GdCave *cave, const int x, const int y)
463 {
464   return (gd_elements[get(cave, x, y) & O_MASK].properties & P_PLAYER) != 0;
465 }
466
467 // returns true if the element is a player
468 static inline boolean is_player_dir(const GdCave *cave, const int x, const int y,
469                                     const GdDirection dir)
470 {
471   return (gd_elements[get_dir(cave, x, y, dir) & O_MASK].properties & P_PLAYER) != 0;
472 }
473
474 static inline boolean can_be_hammered_dir(const GdCave *cave, const int x, const int y,
475                                           const GdDirection dir)
476 {
477   return (gd_elements[get_dir(cave, x, y, dir) & O_MASK].properties & P_CAN_BE_HAMMERED) != 0;
478 }
479
480 // returns true if the element can be pushed
481 boolean can_be_pushed_dir(const GdCave *cave, const int x, const int y,
482                           const GdDirection dir)
483 {
484   return (gd_elements[get_dir(cave, x, y, dir) & O_MASK].properties & P_PUSHABLE) != 0;
485 }
486
487 // returns true if the element is explodable and explodes to space, for example the player
488 static inline boolean is_first_stage_of_explosion(const GdCave *cave, const int x, const int y)
489 {
490   return (gd_elements[get(cave, x, y) & O_MASK].properties & P_EXPLOSION_FIRST_STAGE) != 0;
491 }
492
493 // returns true if the element is moved by the conveyor belt
494 static inline boolean moved_by_conveyor_top_dir(const GdCave *cave, const int x, const int y,
495                                                 const GdDirection dir)
496 {
497   return (gd_elements[get_dir(cave, x, y, dir) & O_MASK].properties & P_MOVED_BY_CONVEYOR_TOP) != 0;
498 }
499
500 // returns true if the element is moved by the conveyor belt
501 static inline boolean moved_by_conveyor_bottom_dir(const GdCave *cave, const int x, const int y,
502                                                    const GdDirection dir)
503 {
504   return (gd_elements[get_dir(cave, x, y, dir) & O_MASK].properties & P_MOVED_BY_CONVEYOR_BOTTOM) != 0;
505 }
506
507 static inline boolean is_scanned_dir(const GdCave *cave, const int x, const int y,
508                                      const GdDirection dir)
509 {
510   return (get_dir(cave, x, y, dir) & SCANNED) != 0;
511 }
512
513 // returns true if neighbouring element is "e"
514 // treats dirt specially
515 // treats lava specially
516 static inline boolean is_element_dir(const GdCave *cave, const int x, const int y,
517                                      const GdDirection dir, GdElement e)
518 {
519   GdElement examined = get_dir(cave, x, y, dir);
520
521   // if it is a dirt-like, change to dirt, so equality will evaluate to true
522   if (gd_elements[examined & O_MASK].properties & P_DIRT)
523     examined = O_DIRT;
524
525   if (gd_elements[e & O_MASK].properties & P_DIRT)
526     e = O_DIRT;
527
528   // if the element on the map is a lava, it should be like space
529   if (examined == O_LAVA)
530     examined = O_SPACE;
531
532   return (e == examined);
533 }
534
535 // returns true if neighbouring element is space
536 static inline boolean is_space_dir(const GdCave *cave, const int x, const int y,
537                                    const GdDirection dir)
538 {
539   GdElement e = get_dir(cave, x, y, dir) & O_MASK;
540
541   return (e == O_SPACE || e == O_LAVA);
542 }
543
544 static inline void store_dir_buffer(GdCave *cave, const int x, const int y, const GdDirection dir)
545 {
546   // raw values without range correction
547   int raw_x = x + gd_dx[dir];
548   int raw_y = y + gd_dy[dir];
549
550   // final values with range correction
551   int new_x = getx(cave, raw_x, raw_y);
552   int new_y = gety(cave, raw_x, raw_y);
553   int new_dir = (dir > GD_MV_TWICE ? dir - GD_MV_TWICE : dir);
554
555   game_bd.game->dir_buffer[new_y][new_x] = new_dir;
556 }
557
558 // store an element at the given position
559 static inline void store(GdCave *cave, const int x, const int y, const GdElement element)
560 {
561   GdElement *e = getp(cave, x, y);
562
563   if (*e == O_LAVA)
564   {
565     play_sound_of_element(cave, O_LAVA, x, y);
566
567     return;
568   }
569
570   *e = element;
571 }
572
573 // store an element with SCANNED flag turned on
574 static inline void store_sc(GdCave *cave, const int x, const int y, const GdElement element)
575 {
576   store(cave, x, y, element | SCANNED);
577 }
578
579 // store an element to a neighbouring cell
580 static inline void store_dir(GdCave *cave, const int x, const int y,
581                              const GdDirection dir, const GdElement element)
582 {
583   store_dir_buffer(cave, x, y, dir);
584   store(cave, x + gd_dx[dir], y + gd_dy[dir], element | SCANNED);
585 }
586
587 // store an element to a neighbouring cell
588 static inline void store_dir_no_scanned(GdCave *cave, const int x, const int y,
589                                         const GdDirection dir, const GdElement element)
590 {
591   store_dir_buffer(cave, x, y, dir);
592   store(cave, x + gd_dx[dir], y + gd_dy[dir], element);
593 }
594
595 // move element to direction; then place space at x, y
596 static inline void move(GdCave *cave, const int x, const int y,
597                         const GdDirection dir, const GdElement e)
598 {
599   store_dir(cave, x, y, dir, e);
600   store(cave, x, y, O_SPACE);
601 }
602
603 // increment a cave element; can be used for elements which are one after
604 // the other, for example bladder1, bladder2, bladder3...
605 static inline void next(GdCave *cave, const int x, const int y)
606 {
607   (*getp(cave, x, y))++;
608 }
609
610 static void cell_explode(GdCave *cave, int x, int y, GdElement explode_to)
611 {
612   if (non_explodable (cave, x, y))
613     return;
614
615   if (cave->voodoo_any_hurt_kills_player && get(cave, x, y) == O_VOODOO)
616     cave->voodoo_touched = TRUE;
617
618   if (get(cave, x, y) == O_VOODOO && !cave->voodoo_disappear_in_explosion)
619     // voodoo turns into a time penalty
620     store_sc(cave, x, y, O_TIME_PENALTY);
621   else if (get(cave, x, y) == O_NITRO_PACK ||
622            get(cave, x, y) == O_NITRO_PACK_F)
623     // nitro pack inside an explosion - it is now triggered
624     store_sc(cave, x, y, O_NITRO_PACK_EXPLODE);
625   else
626     // for everything else
627     store_sc(cave, x, y, explode_to);
628 }
629
630 // a creature explodes to a 3x3 something.
631 static void creature_explode(GdCave *cave, int x, int y, GdElement explode_to)
632 {
633   int xx, yy;
634
635   // the processing of an explosion took pretty much time: processing 3x3 = 9 elements
636   cave->ckdelay += 1200;
637   gd_sound_play(cave, GD_S_EXPLODING, get(cave, x, y), x, y);
638
639   for (yy = y - 1; yy <= y + 1; yy++)
640     for (xx = x - 1; xx <= x + 1; xx++)
641       cell_explode(cave, xx, yy, explode_to);
642 }
643
644 static void nitro_explode(GdCave *cave, int x, int y)
645 {
646   int xx, yy;
647
648   // the processing of an explosion took pretty much time: processing 3x3 = 9 elements
649   cave->ckdelay += 1200;
650   gd_sound_play(cave, GD_S_NITRO_PACK_EXPLODING, get(cave, x, y), x, y);
651
652   for (yy = y - 1; yy <= y + 1; yy++)
653     for (xx = x - 1; xx <= x + 1; xx++)
654       cell_explode(cave, xx, yy, O_NITRO_EXPL_1);
655
656   // the current cell is explicitly changed into a nitro expl,
657   // as cell_explode changes it to a triggered nitro pack
658   store_sc(cave, x, y, O_NITRO_EXPL_1);
659 }
660
661 // a voodoo explodes, leaving a 3x3 steel and a time penalty behind.
662 static void voodoo_explode(GdCave *cave, int x, int y)
663 {
664   int xx, yy;
665
666   // the processing of an explosion took pretty much time: processing 3x3 = 9 elements
667   cave->ckdelay += 1000;
668
669   gd_sound_play(cave, GD_S_VOODOO_EXPLODING, get(cave, x, y), x, y);
670   if (cave->voodoo_any_hurt_kills_player)
671     cave->voodoo_touched = TRUE;
672
673   // voodoo explodes to 3x3 steel
674   for (yy = y - 1; yy <= y + 1; yy++)
675     for (xx = x - 1; xx <= x + 1; xx++)
676       store_sc(cave, xx, yy, O_PRE_STEEL_1);
677
678   // middle is a time penalty (which will be turned into a gravestone)
679   store_sc(cave, x, y, O_TIME_PENALTY);
680 }
681
682 /*
683   a bomb does not explode the voodoo, neither does the ghost.
684   this function check this, and stores the new element or not.
685   destroying the voodoo is also controlled by the
686   voodoo_disappear_in_explosion flag.
687 */
688 static void explode_try_skip_voodoo(GdCave *cave, const int x, const int y, const GdElement expl)
689 {
690   if (non_explodable (cave, x, y))
691     return;
692
693   // bomb does not explode voodoo
694   if (!cave->voodoo_disappear_in_explosion && get(cave, x, y) == O_VOODOO)
695     return;
696
697   if (cave->voodoo_any_hurt_kills_player && get(cave, x, y) == O_VOODOO)
698     cave->voodoo_touched = TRUE;
699
700   store_sc (cave, x, y, expl);
701 }
702
703 // X shaped ghost explosion; does not touch voodoo!
704 static void ghost_explode(GdCave *cave, const int x, const int y)
705 {
706   gd_sound_play(cave, GD_S_GHOST_EXPLODING, get(cave, x, y), x, y);
707
708   // the processing of an explosion took pretty much time: processing 5 elements
709   cave->ckdelay += 650;
710
711   explode_try_skip_voodoo(cave, x,     y,     O_GHOST_EXPL_1);
712   explode_try_skip_voodoo(cave, x - 1, y - 1, O_GHOST_EXPL_1);
713   explode_try_skip_voodoo(cave, x + 1, y + 1, O_GHOST_EXPL_1);
714   explode_try_skip_voodoo(cave, x - 1, y + 1, O_GHOST_EXPL_1);
715   explode_try_skip_voodoo(cave, x + 1, y - 1, O_GHOST_EXPL_1);
716 }
717
718 // +shaped bomb explosion; does not touch voodoo!
719 static void bomb_explode(GdCave *cave, const int x, const int y)
720 {
721   gd_sound_play(cave, GD_S_BOMB_EXPLODING, get(cave, x, y), x, y);
722
723   // the processing of an explosion took pretty much time: processing 5 elements
724   cave->ckdelay += 650;
725
726   explode_try_skip_voodoo(cave, x,     y,     O_BOMB_EXPL_1);
727   explode_try_skip_voodoo(cave, x - 1, y,     O_BOMB_EXPL_1);
728   explode_try_skip_voodoo(cave, x + 1, y,     O_BOMB_EXPL_1);
729   explode_try_skip_voodoo(cave, x,     y + 1, O_BOMB_EXPL_1);
730   explode_try_skip_voodoo(cave, x,     y - 1, O_BOMB_EXPL_1);
731 }
732
733 /*
734   explode an element with the appropriate type of exlposion.
735  */
736 static void explode(GdCave *cave, int x, int y)
737 {
738   GdElement e = get(cave, x, y) & O_MASK;
739
740   switch (e)
741   {
742     case O_GHOST:
743       ghost_explode(cave, x, y);
744       break;
745
746     case O_BOMB_TICK_7:
747       bomb_explode(cave, x, y);
748       break;
749
750     case O_VOODOO:
751       voodoo_explode(cave, x, y);
752       break;
753
754     case O_NITRO_PACK:
755     case O_NITRO_PACK_F:
756     case O_NITRO_PACK_EXPLODE:
757       nitro_explode(cave, x, y);
758       break;
759
760     case O_AMOEBA_2:
761       creature_explode(cave, x, y, O_AMOEBA_2_EXPL_1);
762       break;
763
764     case O_FALLING_WALL_F:
765       creature_explode(cave, x, y, O_EXPLODE_1);
766       break;
767
768     case O_ROCKET_1:
769     case O_ROCKET_2:
770     case O_ROCKET_3:
771     case O_ROCKET_4:
772       creature_explode(cave, x, y, O_EXPLODE_1);
773       break;
774
775     case O_BUTTER_1:
776     case O_BUTTER_2:
777     case O_BUTTER_3:
778     case O_BUTTER_4:
779       creature_explode(cave, x, y, cave->butterfly_explode_to);
780       break;
781
782     case O_ALT_BUTTER_1:
783     case O_ALT_BUTTER_2:
784     case O_ALT_BUTTER_3:
785     case O_ALT_BUTTER_4:
786       creature_explode(cave, x, y, cave->alt_butterfly_explode_to);
787       break;
788
789     case O_FIREFLY_1:
790     case O_FIREFLY_2:
791     case O_FIREFLY_3:
792     case O_FIREFLY_4:
793       creature_explode(cave, x, y, cave->firefly_explode_to);
794       break;
795
796     case O_ALT_FIREFLY_1:
797     case O_ALT_FIREFLY_2:
798     case O_ALT_FIREFLY_3:
799     case O_ALT_FIREFLY_4:
800       creature_explode(cave, x, y, cave->alt_firefly_explode_to);
801       break;
802
803     case O_PLAYER:
804     case O_PLAYER_BOMB:
805     case O_PLAYER_GLUED:
806     case O_PLAYER_STIRRING:
807     case O_PLAYER_ROCKET_LAUNCHER:
808     case O_PLAYER_PNEUMATIC_LEFT:
809     case O_PLAYER_PNEUMATIC_RIGHT:
810       creature_explode(cave, x, y, O_EXPLODE_1);
811       break;
812
813     case O_STONEFLY_1:
814     case O_STONEFLY_2:
815     case O_STONEFLY_3:
816     case O_STONEFLY_4:
817       creature_explode(cave, x, y, cave->stonefly_explode_to);
818       break;
819
820     case O_DRAGONFLY_1:
821     case O_DRAGONFLY_2:
822     case O_DRAGONFLY_3:
823     case O_DRAGONFLY_4:
824       creature_explode(cave, x, y, cave->dragonfly_explode_to);
825       break;
826
827     default:
828       break;
829   }
830 }
831
832 static void inline explode_dir(GdCave *cave, const int x, const int y, GdDirection dir)
833 {
834   explode(cave, x + gd_dx[dir], y + gd_dy[dir]);
835 }
836
837 /*
838   player eats specified object.
839   returns O_SPACE if he eats it (diamond, dirt, space, outbox)
840   returns other element if something other appears there and he can't move.
841   cave pointer is needed to know the diamond values.
842 */
843 static GdElement player_get_element(GdCave* cave, const GdElement object, int x, int y)
844 {
845   int i;
846
847   switch (object)
848   {
849     case O_DIAMOND_KEY:
850       cave->diamond_key_collected = TRUE;
851       gd_sound_play(cave, GD_S_DIAMOND_KEY_COLLECTING, object, x, y);
852       return O_SPACE;
853
854     // KEYS AND DOORS
855     case O_KEY_1:
856       gd_sound_play(cave, GD_S_KEY_COLLECTING, object, x, y);
857       cave->key1++;
858       return O_SPACE;
859
860     case O_KEY_2:
861       gd_sound_play(cave, GD_S_KEY_COLLECTING, object, x, y);
862       cave->key2++;
863       return O_SPACE;
864
865     case O_KEY_3:
866       gd_sound_play(cave, GD_S_KEY_COLLECTING, object, x, y);
867       cave->key3++;
868       return O_SPACE;
869
870     case O_DOOR_1:
871       if (cave->key1 == 0)
872         return object;
873       gd_sound_play(cave, GD_S_DOOR_OPENING, object, x, y);
874       cave->key1--;
875       return O_SPACE;
876
877     case O_DOOR_2:
878       if (cave->key2 == 0)
879         return object;
880       gd_sound_play(cave, GD_S_DOOR_OPENING, object, x, y);
881       cave->key2--;
882       return O_SPACE;
883
884     case O_DOOR_3:
885       if (cave->key3 == 0)
886         return object;
887       gd_sound_play(cave, GD_S_DOOR_OPENING, object, x, y);
888       cave->key3--;
889       return O_SPACE;
890
891     // SWITCHES
892     case O_CREATURE_SWITCH:        // creatures change direction.
893       gd_sound_play(cave, GD_S_SWITCH_CREATURES, object, x, y);
894       cave->creatures_backwards = !cave->creatures_backwards;
895       return object;
896
897     case O_EXPANDING_WALL_SWITCH:        // expanding wall change direction.
898       gd_sound_play(cave, GD_S_SWITCH_EXPANDING, object, x, y);
899       cave->expanding_wall_changed = !cave->expanding_wall_changed;
900       return object;
901
902     case O_BITER_SWITCH:        // biter change delay
903       gd_sound_play(cave, GD_S_SWITCH_BITER, object, x, y);
904       cave->biter_delay_frame++;
905       if (cave->biter_delay_frame == 4)
906         cave->biter_delay_frame = 0;
907       return object;
908
909     case O_REPLICATOR_SWITCH:    // replicator on/off switch
910       gd_sound_play(cave, GD_S_SWITCH_REPLICATOR, object, x, y);
911       cave->replicators_active = !cave->replicators_active;
912       return object;
913
914     case O_CONVEYOR_SWITCH:    // conveyor belts on/off
915       gd_sound_play(cave, GD_S_SWITCH_CONVEYOR, object, x, y);
916       cave->conveyor_belts_active = !cave->conveyor_belts_active;
917       return object;
918
919     case O_CONVEYOR_DIR_SWITCH: // conveyor belts switch direction
920       gd_sound_play(cave, GD_S_SWITCH_CONVEYOR, object, x, y);
921       cave->conveyor_belts_direction_changed = !cave->conveyor_belts_direction_changed;
922       return object;
923
924     // USUAL STUFF
925     case O_DIRT:
926     case O_DIRT2:
927     case O_STEEL_EATABLE:
928     case O_BRICK_EATABLE:
929     case O_DIRT_SLOPED_UP_RIGHT:
930     case O_DIRT_SLOPED_UP_LEFT:
931     case O_DIRT_SLOPED_DOWN_LEFT:
932     case O_DIRT_SLOPED_DOWN_RIGHT:
933     case O_DIRT_BALL:
934     case O_DIRT_LOOSE:
935       gd_sound_play(cave, GD_S_DIRT_WALKING, object, x, y);
936       return O_SPACE;
937
938     case O_SWEET:
939       gd_sound_play(cave, GD_S_SWEET_COLLECTING, object, x, y);
940       cave->sweet_eaten = TRUE;
941       return O_SPACE;
942
943     case O_PNEUMATIC_HAMMER:
944       gd_sound_play(cave, GD_S_PNEUMATIC_COLLECTING, object, x, y);
945       cave->got_pneumatic_hammer = TRUE;
946       return O_SPACE;
947
948     case O_CLOCK:
949       // bonus time
950       gd_sound_play(cave, GD_S_CLOCK_COLLECTING, object, x, y);
951       cave->time += cave->time_bonus * cave->timing_factor;
952       if (cave->time > cave->max_time * cave->timing_factor)
953         cave->time -= cave->max_time * cave->timing_factor;
954       // no space, rather a dirt remains there...
955       return O_DIRT;
956
957     case O_DIAMOND:
958     case O_FLYING_DIAMOND:
959       // prevent diamond sounds for O_SKELETON (see below)
960       if (x != -1 && y != -1)
961         gd_sound_play(cave, (object == O_DIAMOND ? GD_S_DIAMOND_COLLECTING :
962                              GD_S_FLYING_DIAMOND_COLLECTING), object, x, y);
963
964       cave->score += cave->diamond_value;
965       cave->diamonds_collected++;
966
967       if (cave->diamonds_needed == cave->diamonds_collected)
968       {
969         cave->gate_open = TRUE;
970
971         // extra is worth more points.
972         cave->diamond_value = cave->extra_diamond_value;
973
974         cave->gate_open_flash = 1;
975         cave->sound3 = GD_S_CRACKING;
976         gd_sound_play(cave, GD_S_CRACKING, O_OUTBOX, x, y);
977       }
978       return O_SPACE;
979
980     case O_SKELETON:
981       cave->skeletons_collected++;
982
983       // as if player got a diamond
984       for (i = 0; i < cave->skeletons_worth_diamonds; i++)
985         player_get_element(cave, O_DIAMOND, -1, -1);
986
987       // _after_ calling get_element for the fake diamonds, so we overwrite its sounds
988       gd_sound_play(cave, GD_S_SKELETON_COLLECTING, object, x, y);
989       return O_SPACE;
990
991     case O_OUTBOX:
992     case O_INVIS_OUTBOX:
993       cave->player_state = GD_PL_EXITED;    // player now exits the cave!
994       return O_SPACE;
995
996     case O_SPACE:
997     case O_LAVA:    // player goes into lava, as if it was space
998       gd_sound_play(cave, GD_S_EMPTY_WALKING, object, x, y);
999       return O_SPACE;
1000
1001     default:
1002       // the object will remain there.
1003       return object;
1004   }
1005 }
1006
1007 /*
1008   process a crazy dream-style teleporter.
1009   called from gd_cave_iterate, for a player or a player_bomb.
1010   player is standing at px, py, and trying to move in the direction player_move,
1011   where there is a teleporter at (tx_start, ty_start). we check the whole cave,
1012   from (tx_start + 1, ty_start), till we get back to (tx_start, ty_start) (by wrapping
1013   around). the first teleporter we find, and which is suitable, will be the destination.
1014   return TRUE if teleporter worked, FALSE if cound not find any suitable teleporter.
1015 */
1016 static boolean do_teleporter(GdCave *cave, int px, int py, GdDirection player_move)
1017 {
1018   // start at teleporter position (not at player position!)
1019   int tx_start = px + gd_dx[player_move];
1020   int ty_start = py + gd_dy[player_move];
1021   int tx = tx_start;
1022   int ty = ty_start;
1023
1024   do
1025   {
1026     // jump to next element; wrap around columns and rows.
1027     tx++;
1028
1029     if (tx >= cave->w)
1030     {
1031       tx = 0;
1032       ty++;
1033
1034       if (ty >= cave->h)
1035         ty = 0;
1036     }
1037
1038     // if we found a teleporter...
1039     if (get(cave, tx, ty) == O_TELEPORTER &&
1040         is_space_dir(cave, tx, ty, player_move))
1041     {
1042       // new player appears near teleporter found
1043       store_dir(cave, tx, ty, player_move, get(cave, px, py));
1044
1045       // current player disappears
1046       store(cave, px, py, O_SPACE);
1047
1048       gd_sound_play(cave, GD_S_TELEPORTER, O_TELEPORTER, tx, ty);
1049
1050       return TRUE;    // return true as teleporter worked
1051     }
1052   }
1053   // loop until we get back to original coordinates
1054   while (tx != tx_start || ty != ty_start);
1055
1056   // return false as we did not find any usable teleporter
1057   return FALSE;
1058 }
1059
1060 /*
1061   try to push an element.
1062   returns true if the push is possible; also does move the specified _element_.
1063   up to the caller to move the _player_itself_.
1064 */
1065 static boolean do_push(GdCave *cave, int x, int y, GdDirection player_move, boolean player_fire)
1066 {
1067   boolean result;
1068   GdElement what = get_dir(cave, x, y, player_move);
1069
1070   // gravity for falling wall, bladder, ...
1071   GdDirection grav_compat = cave->gravity_affects_all ? cave->gravity : GD_MV_DOWN;
1072
1073   result = FALSE;
1074
1075   switch (what)
1076   {
1077     case O_WAITING_STONE:
1078     case O_STONE:
1079     case O_NITRO_PACK:
1080     case O_CHASING_STONE:
1081     case O_MEGA_STONE:
1082     case O_FLYING_STONE:
1083     case O_NUT:
1084       // pushing some kind of stone or nut
1085       // directions possible: 90degrees cw or ccw to current gravity.
1086       // only push if player dir is orthogonal to gravity,
1087       // ie. gravity down, pushing left & right possible
1088       if (player_move == ccw_fourth[cave->gravity] ||
1089           player_move == cw_fourth[cave->gravity])
1090       {
1091         int prob;
1092
1093         prob = 0;
1094
1095         // different probabilities for different elements.
1096         switch (what)
1097         {
1098           case O_WAITING_STONE:
1099             // waiting stones are light, can always push
1100             prob = 1000000;
1101             break;
1102
1103           case O_CHASING_STONE:
1104             // chasing can be pushed if player is turbo
1105             if (cave->sweet_eaten)
1106               prob = 1000000;
1107             break;
1108
1109           case O_MEGA_STONE:
1110             // mega may(!) be pushed if player is turbo
1111             if (cave->mega_stones_pushable_with_sweet && cave->sweet_eaten)
1112               prob = 1000000;
1113             break;
1114
1115           case O_STONE:
1116           case O_NUT:
1117           case O_FLYING_STONE:
1118           case O_NITRO_PACK:
1119             if (cave->sweet_eaten)
1120               prob = cave->pushing_stone_prob_sweet; // probability with sweet
1121             else
1122               prob = cave->pushing_stone_prob; // probability without sweet.
1123             break;
1124
1125           default:
1126             break;
1127         }
1128
1129         if (is_space_dir(cave, x, y, GD_MV_TWICE + player_move) &&
1130             gd_rand_int_range(cave->random, 0, 1000000) < prob)
1131         {
1132           // if decided that he will be able to push,
1133           store_dir(cave, x, y, GD_MV_TWICE + player_move, what);
1134           play_sound_of_element_pushing(cave, what, x, y);
1135           result = TRUE;
1136         }
1137       }
1138       break;
1139
1140     case O_BLADDER:
1141     case O_BLADDER_1:
1142     case O_BLADDER_2:
1143     case O_BLADDER_3:
1144     case O_BLADDER_4:
1145     case O_BLADDER_5:
1146     case O_BLADDER_6:
1147     case O_BLADDER_7:
1148     case O_BLADDER_8:
1149       // pushing a bladder. keep in mind that after pushing, we always get an O_BLADDER,
1150       // not an O_BLADDER_x.
1151       // there is no "delayed" state of a bladder, so we use store_dir_no_scanned!
1152
1153       // first check: we cannot push a bladder "up"
1154       if (player_move != opposite[grav_compat])
1155       {
1156         // pushing a bladder "down". p = player, o = bladder, 1, 2, 3 = directions to check.
1157         // player moving in the direction of gravity.
1158         //  p   p  g
1159         // 2o3  |  |
1160         //  1   v  v
1161         if (player_move == grav_compat)
1162         {
1163           // pushing bladder down
1164           if (is_space_dir(cave, x, y, GD_MV_TWICE + player_move))
1165             store_dir_no_scanned(cave, x, y, GD_MV_TWICE + player_move, O_BLADDER), result = TRUE;
1166           // if no space to push down, maybe left (down-left to player)
1167           else if (is_space_dir(cave, x, y, cw_eighth[grav_compat]))
1168
1169             // left is "down, turned right (cw)"
1170             store_dir_no_scanned(cave, x, y, cw_eighth[grav_compat], O_BLADDER), result = TRUE;
1171           // if not, maybe right (down-right to player)
1172           else if (is_space_dir(cave, x, y, ccw_eighth[grav_compat]))
1173             store_dir_no_scanned(cave, x, y, ccw_eighth[grav_compat], O_BLADDER), result = TRUE;
1174         }
1175
1176         // pushing a bladder "left". p = player, o = bladder, 1, 2, 3 = directions to check.
1177         //  3        g
1178         // 1op  <-p  |
1179         //  2        v
1180         else if (player_move == cw_fourth[grav_compat])
1181         {
1182           if (is_space_dir(cave, x, y, GD_MV_TWICE + cw_fourth[grav_compat]))    // pushing it left
1183             store_dir_no_scanned(cave, x, y, GD_MV_TWICE + cw_fourth[grav_compat], O_BLADDER), result = TRUE;
1184           else if (is_space_dir(cave, x, y, cw_eighth[grav_compat]))    // maybe down, and player will move left
1185             store_dir_no_scanned(cave, x, y, cw_eighth[grav_compat], O_BLADDER), result = TRUE;
1186           else if (is_space_dir(cave, x, y, cw_eighth[player_move]))    // maybe up, and player will move left
1187             store_dir_no_scanned(cave, x, y, cw_eighth[player_move], O_BLADDER), result = TRUE;
1188         }
1189
1190         // pushing a bladder "right". p = player, o = bladder, 1, 2, 3 = directions to check.
1191         //  3        g
1192         // po1  p-<  |
1193         //  2        v
1194         else if (player_move == ccw_fourth[grav_compat])
1195         {
1196           if (is_space_dir(cave, x, y, GD_MV_TWICE + player_move))    // pushing it right
1197             store_dir_no_scanned(cave, x, y, GD_MV_TWICE + player_move, O_BLADDER), result = TRUE;
1198           else if (is_space_dir(cave, x, y, ccw_eighth[grav_compat]))    // maybe down, and player will move right
1199             store_dir_no_scanned(cave, x, y, ccw_eighth[grav_compat], O_BLADDER), result = TRUE;
1200           else if (is_space_dir(cave, x, y, ccw_eighth[player_move]))    // maybe up, and player will move right
1201             store_dir_no_scanned(cave, x, y, ccw_eighth[player_move], O_BLADDER), result = TRUE;
1202         }
1203
1204         if (result)
1205           play_sound_of_element_pushing(cave, O_BLADDER, x, y);
1206       }
1207       break;
1208
1209     case O_BOX:
1210       // a box is only pushed with the fire pressed
1211       if (player_fire)
1212       {
1213         // but always with 100% probability
1214         switch (player_move)
1215         {
1216           case GD_MV_LEFT:
1217           case GD_MV_RIGHT:
1218           case GD_MV_UP:
1219           case GD_MV_DOWN:
1220             // pushing in some dir, two steps in that dir - is there space?
1221             if (is_space_dir(cave, x, y, player_move + GD_MV_TWICE))
1222             {
1223               // yes, so push.
1224               store_dir(cave, x, y, player_move + GD_MV_TWICE, O_BOX);
1225               result = TRUE;
1226               gd_sound_play(cave, GD_S_BOX_PUSHING, what, x, y);
1227             }
1228             break;
1229
1230           default:
1231             // push in no other directions possible
1232             break;
1233         }
1234       }
1235       break;
1236
1237       // pushing of other elements not possible
1238     default:
1239       break;
1240   }
1241
1242   return result;
1243 }
1244
1245 // from the key press booleans, create a direction
1246 GdDirection gd_direction_from_keypress(boolean up, boolean down, boolean left, boolean right)
1247 {
1248   GdDirection player_move;
1249
1250   // from the key press booleans, create a direction
1251   if (up && right)
1252     player_move = GD_MV_UP_RIGHT;
1253   else if (down && right)
1254     player_move = GD_MV_DOWN_RIGHT;
1255   else if (down && left)
1256     player_move = GD_MV_DOWN_LEFT;
1257   else if (up && left)
1258     player_move = GD_MV_UP_LEFT;
1259   else if (up)
1260     player_move = GD_MV_UP;
1261   else if (down)
1262     player_move = GD_MV_DOWN;
1263   else if (left)
1264     player_move = GD_MV_LEFT;
1265   else if (right)
1266     player_move = GD_MV_RIGHT;
1267   else
1268     player_move = GD_MV_STILL;
1269
1270   return player_move;
1271 }
1272
1273 // clear these to no sound; and they will be set during iteration.
1274 void gd_cave_clear_sounds(GdCave *cave)
1275 {
1276   cave->sound1 = GD_S_NONE;
1277   cave->sound2 = GD_S_NONE;
1278   cave->sound3 = GD_S_NONE;
1279 }
1280
1281 static void do_start_fall(GdCave *cave, int x, int y, GdDirection falling_direction,
1282                           GdElement falling_element)
1283 {
1284   if (cave->gravity_disabled)
1285     return;
1286
1287   if (is_space_dir(cave, x, y, falling_direction))
1288   {
1289     // beginning to fall
1290     play_sound_of_element(cave, get(cave, x, y), x, y);
1291     move(cave, x, y, falling_direction, falling_element);
1292   }
1293
1294   // check if it is on a sloped element, and it can roll.
1295   // for example, sloped wall looks like:
1296   //  /|
1297   // /_|
1298   // this is tagged as sloped up&left.
1299   // first check if the stone or diamond is coming from "up" (ie. opposite of gravity)
1300   // then check the direction to roll (left or right)
1301   // this way, gravity can also be pointing right, and the above slope will work as one would expect
1302   else if (sloped_dir(cave, x, y, falling_direction, opposite[falling_direction]))
1303   {
1304     // rolling down, if sitting on a sloped object
1305     if (sloped_dir(cave, x, y, falling_direction, cw_fourth[falling_direction]) &&
1306         is_space_dir(cave, x, y, cw_fourth[falling_direction]) &&
1307         is_space_dir(cave, x, y, cw_eighth[falling_direction]))
1308     {
1309       // rolling left? - keep in mind that ccw_fourth rotates gravity ccw,
1310       // so here we use cw_fourth
1311       play_sound_of_element(cave, get(cave, x, y), x, y);
1312       move(cave, x, y, cw_fourth[falling_direction], falling_element);
1313     }
1314     else if (sloped_dir(cave, x, y, falling_direction, ccw_fourth[falling_direction]) &&
1315              is_space_dir(cave, x, y, ccw_fourth[falling_direction]) &&
1316              is_space_dir(cave, x, y, ccw_eighth[falling_direction]))
1317     {
1318       // rolling right?
1319       play_sound_of_element(cave, get(cave, x, y), x, y);
1320       move(cave, x, y, ccw_fourth[falling_direction], falling_element);
1321     }
1322   }
1323 }
1324
1325 static boolean do_fall_try_crush_voodoo(GdCave *cave, int x, int y, GdDirection fall_dir)
1326 {
1327   if (get_dir(cave, x, y, fall_dir) == O_VOODOO &&
1328       cave->voodoo_dies_by_stone)
1329   {
1330     // this is a 1stB-style vodo. explodes by stone, collects diamonds
1331     explode_dir(cave, x, y, fall_dir);
1332     return TRUE;
1333   }
1334   else
1335     return FALSE;
1336 }
1337
1338 static boolean do_fall_try_eat_voodoo(GdCave *cave, int x, int y, GdDirection fall_dir)
1339 {
1340   if (get_dir(cave, x, y, fall_dir) == O_VOODOO &&
1341       cave->voodoo_collects_diamonds)
1342   {
1343     // this is a 1stB-style voodoo. explodes by stone, collects diamonds
1344     player_get_element(cave, O_DIAMOND, x, y);   // as if player got diamond
1345     store(cave, x, y, O_SPACE);    // diamond disappears
1346     return TRUE;
1347   }
1348   else
1349     return FALSE;
1350 }
1351
1352 static boolean do_fall_try_crack_nut(GdCave *cave, int x, int y,
1353                                      GdDirection fall_dir, GdElement bouncing)
1354 {
1355   if (get_dir(cave, x, y, fall_dir) == O_NUT ||
1356       get_dir(cave, x, y, fall_dir) == O_NUT_F)
1357   {
1358     // stones
1359     store(cave, x, y, bouncing);
1360     store_dir(cave, x, y, fall_dir, cave->nut_turns_to_when_crushed);
1361
1362     gd_sound_play(cave, GD_S_NUT_CRACKING, O_NUT, x, y);
1363
1364     return TRUE;
1365   }
1366   else
1367     return FALSE;
1368 }
1369
1370 static boolean do_fall_try_magic(GdCave *cave, int x, int y,
1371                                  GdDirection fall_dir, GdElement magic)
1372 {
1373   if (get_dir(cave, x, y, fall_dir) == O_MAGIC_WALL)
1374   {
1375     play_sound_of_element(cave, O_DIAMOND, x, y);    // always play diamond sound
1376
1377     if (cave->magic_wall_state == GD_MW_DORMANT)
1378       cave->magic_wall_state = GD_MW_ACTIVE;
1379
1380     if (cave->magic_wall_state == GD_MW_ACTIVE &&
1381         is_space_dir(cave, x, y, GD_MV_TWICE+fall_dir))
1382     {
1383       // if magic wall active and place underneath, it turns element
1384       // into anything the effect says to do.
1385       store_dir(cave, x, y, GD_MV_TWICE+fall_dir, magic);
1386     }
1387
1388     // active or non-active or anything, element falling in will always disappear
1389     store(cave, x, y, O_SPACE);
1390
1391     if (cave->magic_wall_breakscan && cave->amoeba_state == GD_AM_AWAKE)
1392       cave->convert_amoeba_this_frame = TRUE;
1393
1394     return TRUE;
1395   }
1396   else
1397     return FALSE;
1398 }
1399
1400 static boolean do_fall_try_crush(GdCave *cave, int x, int y, GdDirection fall_dir)
1401 {
1402   if (explodes_by_hit_dir(cave, x, y, fall_dir))
1403   {
1404     explode_dir(cave, x, y, fall_dir);
1405     return TRUE;
1406   }
1407   else
1408     return FALSE;
1409 }
1410
1411 static boolean do_fall_roll_or_stop(GdCave *cave, int x, int y,
1412                                     GdDirection fall_dir, GdElement bouncing)
1413 {
1414   if (is_space_dir(cave, x, y, fall_dir))
1415   {
1416     // falling further
1417     move(cave, x, y, fall_dir, get(cave, x, y));
1418
1419     return TRUE;
1420   }
1421
1422   // check if it is on a sloped element, and it can roll.
1423   // for example, sloped wall looks like:
1424   //  /|
1425   // /_|
1426   // this is tagged as sloped up&left.
1427   // first check if the stone or diamond is coming from "up" (ie. opposite of gravity)
1428   // then check the direction to roll (left or right)
1429   // this way, gravity can also be pointing right, and the above slope will work as one would expect
1430
1431   if (sloped_dir(cave, x, y, fall_dir, opposite[fall_dir]))
1432   {
1433     // sloped element, falling to left or right
1434     if (sloped_dir(cave, x, y, fall_dir, cw_fourth[fall_dir]) &&
1435         is_space_dir(cave, x, y, cw_eighth[fall_dir]) &&
1436         is_space_dir(cave, x, y, cw_fourth[fall_dir]))
1437     {
1438       play_sound_of_element(cave, get(cave, x, y), x, y);
1439
1440       // try to roll left first - see O_STONE to understand why cw_fourth
1441       move(cave, x, y, cw_fourth[fall_dir], get(cave, x, y));
1442     }
1443     else if (sloped_dir(cave, x, y, fall_dir, ccw_fourth[fall_dir]) &&
1444              is_space_dir(cave, x, y, ccw_eighth[fall_dir]) &&
1445              is_space_dir(cave, x, y, ccw_fourth[fall_dir]))
1446     {
1447       play_sound_of_element(cave, get(cave, x, y), x, y);
1448
1449       // if not, try to roll right
1450       move(cave, x, y, ccw_fourth[fall_dir], get(cave, x, y));
1451     }
1452     else
1453     {
1454       // cannot roll in any direction, so it stops
1455       play_sound_of_element(cave, get(cave, x, y), x, y);
1456       store(cave, x, y, bouncing);
1457     }
1458
1459     return TRUE;
1460   }
1461
1462   // any other element, stops
1463   play_sound_of_element(cave, get(cave, x, y), x, y);
1464   store(cave, x, y, bouncing);
1465   return TRUE;
1466 }
1467
1468 static void update_cave_speed(GdCave *cave)
1469 {
1470   // update timing calculated by iterating and counting elements which were slow to process on c64
1471   switch (cave->scheduling)
1472   {
1473     case GD_SCHEDULING_MILLISECONDS:
1474       // cave->speed already contains the milliseconds value, do not touch it
1475       break;
1476
1477     case GD_SCHEDULING_BD1:
1478       if (!cave->intermission)
1479         // non-intermissions
1480         cave->speed = (88 + 3.66 * cave->c64_timing + (cave->ckdelay + cave->ckdelay_extra_for_animation) / 1000);
1481       else
1482         // intermissions were quicker, as only lines 1-12 were processed by the engine.
1483         cave->speed = (60 + 3.66 * cave->c64_timing + (cave->ckdelay + cave->ckdelay_extra_for_animation) / 1000);
1484       break;
1485
1486     case GD_SCHEDULING_BD1_ATARI:
1487       // about 20ms/frame faster than c64 version
1488       if (!cave->intermission)
1489         cave->speed = (74 + 3.2 * cave->c64_timing + (cave->ckdelay) / 1000);            // non-intermissions
1490       else
1491         cave->speed = (65 + 2.88 * cave->c64_timing + (cave->ckdelay) / 1000);        // for intermissions
1492       break;
1493
1494     case GD_SCHEDULING_BD2:
1495       // 60 is a guess.
1496       cave->speed = MAX(60 + (cave->ckdelay + cave->ckdelay_extra_for_animation)/1000, cave->c64_timing * 20);
1497       break;
1498
1499     case GD_SCHEDULING_PLCK:
1500       // 65 is totally empty cave in construction kit, with delay = 0)
1501       cave->speed = MAX(65 + cave->ckdelay / 1000, cave->c64_timing * 20);
1502       break;
1503
1504     case GD_SCHEDULING_BD2_PLCK_ATARI:
1505       // a really fast engine; timing works like c64 plck.
1506       // 40 ms was measured in the construction kit, with delay = 0
1507       cave->speed = MAX(40 + cave->ckdelay / 1000, cave->c64_timing * 20);
1508       break;
1509
1510     case GD_SCHEDULING_CRDR:
1511       if (cave->hammered_walls_reappear) // this made the engine very slow.
1512         cave->ckdelay += 60000;
1513       cave->speed = MAX(130 + cave->ckdelay / 1000, cave->c64_timing * 20);
1514       break;
1515
1516     case GD_SCHEDULING_MAX:
1517       break;
1518   }
1519 }
1520
1521 // process a cave.
1522 void gd_cave_iterate(GdCave *cave, GdDirection player_move, boolean player_fire, boolean suicide)
1523 {
1524   int x, y, i;
1525
1526   // for border scan
1527   int ymin, ymax;
1528
1529   // amoeba found to be enclosed. if not, this is cleared
1530   boolean amoeba_found_enclosed, amoeba_2_found_enclosed;
1531
1532   // counting the number of amoebas. after scan, check if too much
1533   int amoeba_count, amoeba_2_count;
1534
1535   // cave scan found water - for sound
1536   boolean found_water;
1537
1538   boolean inbox_toggle;
1539   boolean start_signal;
1540
1541   // gravity for falling wall, bladder, ...
1542   GdDirection grav_compat = cave->gravity_affects_all ? cave->gravity : GD_MV_DOWN;
1543
1544   // directions for o_something_1, 2, 3 and 4 (creatures)
1545   static const GdDirection creature_dir[] =
1546   {
1547     GD_MV_LEFT,
1548     GD_MV_UP,
1549     GD_MV_RIGHT,
1550     GD_MV_DOWN
1551   };
1552   static const GdDirection creature_chdir[] =
1553   {
1554     GD_MV_RIGHT,
1555     GD_MV_DOWN,
1556     GD_MV_LEFT,
1557     GD_MV_UP
1558   };
1559   int time_decrement_sec;
1560
1561   // biters eating elements preference, they try to go in this order
1562   GdElement biter_try[] =
1563   {
1564     O_DIRT,
1565     cave->biter_eat,
1566     O_SPACE, O_STONE
1567   };
1568
1569   boolean amoeba_sound, magic_sound;
1570
1571   gd_cave_clear_sounds(cave);
1572
1573   game_bd.player_moving = FALSE;
1574   game_bd.player_snapping = FALSE;
1575
1576   // if diagonal movements not allowed,
1577   // horizontal movements have precedence. [BROADRIBB]
1578   if (!cave->diagonal_movements)
1579   {
1580     switch (player_move)
1581     {
1582       case GD_MV_UP_RIGHT:
1583       case GD_MV_DOWN_RIGHT:
1584         player_move = GD_MV_RIGHT;
1585         break;
1586
1587       case GD_MV_UP_LEFT:
1588       case GD_MV_DOWN_LEFT:
1589         player_move = GD_MV_LEFT;
1590         break;
1591
1592       default:
1593         // no correction needed
1594         break;
1595     }
1596   }
1597
1598   // set cave get function; to implement perfect or lineshifting borders
1599   if (cave->lineshift)
1600   {
1601     cave->getp = getp_shift;
1602     cave->getx = getx_shift;
1603     cave->gety = gety_shift;
1604   }
1605   else
1606   {
1607     cave->getp = getp_perfect;
1608     cave->getx = getx_perfect;
1609     cave->gety = gety_perfect;
1610   }
1611
1612   // increment this. if the scan routine comes across player, clears it (sets to zero).
1613   if (cave->player_seen_ago < 100)
1614     cave->player_seen_ago++;
1615
1616   if (cave->pneumatic_hammer_active_delay > 0)
1617     cave->pneumatic_hammer_active_delay--;
1618
1619   // inboxes and outboxes flash with the rhythm of the game, not the display.
1620   // also, a player can be born only from an open, not from a steel-wall-like inbox.
1621   cave->inbox_flash_toggle = !cave->inbox_flash_toggle;
1622   inbox_toggle = cave->inbox_flash_toggle;
1623
1624   if (cave->gate_open_flash > 0)
1625     cave->gate_open_flash--;
1626
1627   // score collected this frame
1628   cave->score = 0;
1629
1630   // to implement buggy bd1 amoeba+magic wall behaviour
1631   cave->convert_amoeba_this_frame = FALSE;
1632
1633   // suicide only kills the active player
1634   // player_x, player_y was set by the previous iterate routine, or the cave setup.
1635   // we must check if there is a player or not - he may have exploded or something like that
1636   if (suicide && cave->player_state == GD_PL_LIVING &&
1637       is_player(cave, cave->player_x, cave->player_y))
1638     store(cave, cave->player_x, cave->player_y, O_EXPLODE_1);
1639
1640   // check for walls reappearing
1641   if (cave->hammered_reappear)
1642   {
1643     for (y = 0; y < cave->h; y++)
1644     {
1645       for (x = 0; x < cave->w; x++)
1646       {
1647         // timer for the cell > 0?
1648         if (cave->hammered_reappear[y][x] > 0)
1649         {
1650           // decrease timer
1651           cave->hammered_reappear[y][x]--;
1652
1653           // check if it became zero
1654           if (cave->hammered_reappear[y][x] == 0)
1655           {
1656             store(cave, x, y, O_BRICK);
1657             gd_sound_play(cave, GD_S_WALL_REAPPEARING, O_BRICK, x, y);
1658           }
1659         }
1660       }
1661     }
1662   }
1663
1664   // variables to check during the scan
1665
1666   // will be set to false if any of the amoeba is found free.
1667   amoeba_found_enclosed = TRUE;
1668   amoeba_2_found_enclosed = TRUE;
1669   amoeba_count = 0;
1670   amoeba_2_count = 0;
1671   found_water = FALSE;
1672   cave->ckdelay = 0;
1673   time_decrement_sec = 0;
1674
1675   // check whether to scan the first and last line
1676   if (cave->border_scan_first_and_last)
1677   {
1678     ymin = 0;
1679     ymax = cave->h - 1;
1680   }
1681   else
1682   {
1683     ymin = 1;
1684     ymax = cave->h - 2;
1685   }
1686
1687   // the cave scan routine
1688   for (y = ymin; y <= ymax; y++)
1689   {
1690     for (x = 0; x < cave->w; x++)
1691     {
1692       // if we find a scanned element, change it to the normal one, and that's all.
1693       // this is required, for example for chasing stones, which have moved, always passing slime!
1694       if (get(cave, x, y) & SCANNED)
1695       {
1696         store(cave, x, y, get(cave, x, y) & ~SCANNED);
1697
1698         continue;
1699       }
1700
1701       // add the ckdelay correction value for every element seen.
1702       cave->ckdelay += gd_elements[get(cave, x, y)].ckdelay;
1703
1704       switch (get(cave, x, y))
1705       {
1706         // ============================================================================
1707         //    P L A Y E R S
1708         // ============================================================================
1709
1710         case O_PLAYER:
1711           if (cave->kill_player)
1712           {
1713             explode (cave, x, y);
1714             break;
1715           }
1716
1717           cave->player_seen_ago = 0;
1718           // bd4 intermission caves have many players. so if one of them has exited,
1719           // do not change the flag anymore. so this if () is needed
1720           if (cave->player_state != GD_PL_EXITED)
1721             cave->player_state = GD_PL_LIVING;
1722
1723           // check for pneumatic hammer things
1724           // 1) press fire, 2) have pneumatic hammer 4) space on left or right
1725           // for hammer 5) stand on something
1726           if (player_fire && cave->got_pneumatic_hammer &&
1727               is_space_dir(cave, x, y, player_move) &&
1728               !is_space_dir(cave, x, y, GD_MV_DOWN))
1729           {
1730             if (player_move == GD_MV_LEFT &&
1731                 can_be_hammered_dir(cave, x, y, GD_MV_DOWN_LEFT))
1732             {
1733               cave->pneumatic_hammer_active_delay = cave->pneumatic_hammer_frame;
1734               store_dir(cave, x, y, GD_MV_LEFT, O_PNEUMATIC_ACTIVE_LEFT);
1735               store(cave, x, y, O_PLAYER_PNEUMATIC_LEFT);
1736               break;    // finished.
1737             }
1738
1739             if (player_move == GD_MV_RIGHT &&
1740                 can_be_hammered_dir(cave, x, y, GD_MV_DOWN_RIGHT))
1741             {
1742               cave->pneumatic_hammer_active_delay = cave->pneumatic_hammer_frame;
1743               store_dir(cave, x, y, GD_MV_RIGHT, O_PNEUMATIC_ACTIVE_RIGHT);
1744               store(cave, x, y, O_PLAYER_PNEUMATIC_RIGHT);
1745               break;    // finished.
1746             }
1747           }
1748
1749           if (player_move != GD_MV_STILL)
1750           {
1751             // only do every check if he is not moving
1752             GdElement what = get_dir(cave, x, y, player_move);
1753             GdElement remains = what;
1754             boolean push;
1755
1756             // if we are 'eating' a teleporter, and the function returns true
1757             // (teleporting worked), break here
1758             if (what == O_TELEPORTER && do_teleporter(cave, x, y, player_move))
1759               break;
1760
1761             // try to push element; if successful, break
1762             push = do_push(cave, x, y, player_move, player_fire);
1763             if (push)
1764             {
1765               remains = O_SPACE;
1766             }
1767             else
1768             {
1769               switch (what)
1770               {
1771                 case O_BOMB:
1772                   // if its a bomb, remember he now has one.
1773                   // we do not change the "remains" and "what" variables,
1774                   // so that part of the code will be ineffective
1775                   gd_sound_play(cave, GD_S_BOMB_COLLECTING, what, x, y);
1776                   store_dir(cave, x, y, player_move, O_SPACE);
1777
1778                   if (player_fire)
1779                     store(cave, x, y, O_PLAYER_BOMB);
1780                   else
1781                     move(cave, x, y, player_move, O_PLAYER_BOMB);
1782                   break;
1783
1784                 case O_ROCKET_LAUNCHER:
1785                   // if its a rocket launcher, remember he now has one.
1786                   // we do not change the "remains" and "what" variables,
1787                   // so that part of the code will be ineffective
1788                   gd_sound_play(cave, GD_S_BOMB_COLLECTING, what, x, y);
1789                   store_dir(cave, x, y, player_move, O_SPACE);
1790
1791                   if (player_fire)
1792                     store(cave, x, y, O_PLAYER_ROCKET_LAUNCHER);
1793                   else
1794                     move(cave, x, y, player_move, O_PLAYER_ROCKET_LAUNCHER);
1795                   break;
1796
1797                 case O_POT:
1798                   // we do not change the "remains" and "what" variables,
1799                   // so that part of the code will be ineffective
1800                   if (!player_fire && !cave->gravity_switch_active &&
1801                       cave->skeletons_collected >= cave->skeletons_needed_for_pot)
1802                   {
1803                     cave->skeletons_collected -= cave->skeletons_needed_for_pot;
1804                     move(cave, x, y, player_move, O_PLAYER_STIRRING);
1805                     cave->gravity_disabled = TRUE;
1806                   }
1807                   break;
1808
1809                 case O_GRAVITY_SWITCH:
1810                   // (we cannot use player_get for this as it does not have player_move parameter)
1811                   // only allow changing direction if the new dir is not diagonal
1812                   if (cave->gravity_switch_active &&
1813                       (player_move == GD_MV_LEFT ||
1814                        player_move == GD_MV_RIGHT ||
1815                        player_move == GD_MV_UP ||
1816                        player_move == GD_MV_DOWN))
1817                   {
1818                     gd_sound_play(cave, GD_S_SWITCH_GRAVITY, what, x, y);
1819                     cave->gravity_will_change =
1820                       cave->gravity_change_time * cave->timing_factor;
1821                     cave->gravity_next_direction = player_move;
1822                     cave->gravity_switch_active = FALSE;
1823                   }
1824                   break;
1825
1826                 default:
1827                   // get element - process others.
1828                   // if cannot get, player_get_element will return the same
1829                   remains = player_get_element(cave, what, x, y);
1830                   break;
1831               }
1832             }
1833
1834             if (remains != what || remains == O_SPACE)
1835             {
1836               // if anything changed, apply the change.
1837
1838               // if snapping anything and we have snapping explosions set.
1839               // but these is not true for pushing.
1840               if (remains == O_SPACE && player_fire && !push)
1841               {
1842                 remains = cave->snap_element;
1843
1844                 game_bd.player_snapping = TRUE;
1845               }
1846
1847               if (remains != O_SPACE || player_fire)
1848               {
1849                 // if any other element than space, player cannot move.
1850                 // also if pressing fire, will not move.
1851                 store_dir(cave, x, y, player_move, remains);
1852               }
1853               else
1854               {
1855                 // if space remains there, the player moves.
1856                 move(cave, x, y, player_move, O_PLAYER);
1857
1858                 game_bd.player_moving = TRUE;
1859               }
1860             }
1861           }
1862           break;
1863
1864         case O_PLAYER_BOMB:
1865           // much simpler; cannot steal stones
1866           if (cave->kill_player)
1867           {
1868             explode(cave, x, y);
1869             break;
1870           }
1871
1872           cave->player_seen_ago = 0;
1873           // bd4 intermission caves have many players. so if one of them has exited,
1874           // do not change the flag anymore. so this if () is needed
1875           if (cave->player_state != GD_PL_EXITED)
1876             cave->player_state = GD_PL_LIVING;
1877
1878           if (player_move != GD_MV_STILL)
1879           {
1880             // if the player does not move, nothing to do
1881             GdElement what = get_dir(cave, x, y, player_move);
1882             GdElement remains = what;
1883
1884             if (player_fire)
1885             {
1886               // placing a bomb into empty space or dirt
1887               if (is_space_dir(cave, x, y, player_move) ||
1888                   is_element_dir(cave, x, y, player_move, O_DIRT))
1889               {
1890                 store_dir(cave, x, y, player_move, O_BOMB_TICK_1);
1891
1892                 // placed bomb, he is normal player again
1893                 store(cave, x, y, O_PLAYER);
1894                 gd_sound_play(cave, GD_S_BOMB_PLACING, O_BOMB, x, y);
1895               }
1896               break;
1897             }
1898
1899             // pushing and collecting
1900             // if we are 'eating' a teleporter, and the function returns true
1901             // (teleporting worked), break here
1902             if (what == O_TELEPORTER && do_teleporter(cave, x, y, player_move))
1903               break;
1904
1905             // player fire is false...
1906             if (do_push(cave, x, y, player_move, FALSE))
1907             {
1908               remains = O_SPACE;
1909             }
1910             else
1911             {
1912               switch (what)
1913               {
1914                 case O_GRAVITY_SWITCH:
1915                   // (we cannot use player_get for this as it does not have
1916                   // player_move parameter)
1917                   // only allow changing direction if the new dir is not diagonal
1918                   if (cave->gravity_switch_active &&
1919                       (player_move == GD_MV_LEFT ||
1920                        player_move == GD_MV_RIGHT ||
1921                        player_move == GD_MV_UP ||
1922                        player_move == GD_MV_DOWN))
1923                   {
1924                     gd_sound_play(cave, GD_S_SWITCH_GRAVITY, what, x, y);
1925                     cave->gravity_will_change =
1926                       cave->gravity_change_time * cave->timing_factor;
1927                     cave->gravity_next_direction = player_move;
1928                     cave->gravity_switch_active = FALSE;
1929                   }
1930                   break;
1931
1932                 default:
1933                   // get element. if cannot get, player_get_element will return the same
1934                   remains = player_get_element (cave, what, x, y);
1935                   break;
1936               }
1937             }
1938
1939             // if element changed, OR there is space, move.
1940             if (remains != what || remains == O_SPACE)
1941             {
1942               // if anything changed, apply the change.
1943               move(cave, x, y, player_move, O_PLAYER_BOMB);
1944             }
1945           }
1946           break;
1947
1948         case O_PLAYER_ROCKET_LAUNCHER:
1949           // much simpler; cannot snap-push stones
1950           if (cave->kill_player)
1951           {
1952             explode(cave, x, y);
1953             break;
1954           }
1955
1956           cave->player_seen_ago = 0;
1957           // bd4 intermission caves have many players. so if one of them has exited,
1958           // do not change the flag anymore. so this if () is needed
1959           if (cave->player_state != GD_PL_EXITED)
1960             cave->player_state = GD_PL_LIVING;
1961
1962           // firing a rocket?
1963           if (player_move != GD_MV_STILL)
1964           {
1965             // if the player does not move, nothing to do
1966             GdElement what = get_dir(cave, x, y, player_move);
1967             GdElement remains = what;
1968
1969             // to fire a rocket, diagonal movement should not be allowed.
1970             // so either x or y must be zero
1971             if (player_fire)
1972             {
1973               // placing a rocket into empty space
1974               if (is_space_dir(cave, x, y, player_move))
1975               {
1976                 switch (player_move)
1977                 {
1978                   case GD_MV_RIGHT:
1979                     store_dir(cave, x, y, player_move, O_ROCKET_1);
1980                     if (!cave->infinite_rockets)
1981                       store(cave, x, y, O_PLAYER);
1982                     break;
1983
1984                   case GD_MV_UP:
1985                     store_dir(cave, x, y, player_move, O_ROCKET_2);
1986                     if (!cave->infinite_rockets)
1987                       store(cave, x, y, O_PLAYER);
1988                     break;
1989
1990                   case GD_MV_LEFT:
1991                     store_dir(cave, x, y, player_move, O_ROCKET_3);
1992                     if (!cave->infinite_rockets)
1993                       store(cave, x, y, O_PLAYER);
1994                     break;
1995
1996                   case GD_MV_DOWN:
1997                     store_dir(cave, x, y, player_move, O_ROCKET_4);
1998                     if (!cave->infinite_rockets)
1999                       store(cave, x, y, O_PLAYER);
2000                     break;
2001
2002                   default:
2003                     // cannot fire in other directions
2004                     break;
2005                 }
2006
2007                 gd_sound_play(cave, GD_S_BOMB_PLACING, O_BOMB, x, y);
2008               }
2009
2010               // a player with rocket launcher cannot snap elements, so stop here
2011               break;
2012             }
2013
2014             // pushing and collecting
2015             // if we are 'eating' a teleporter, and the function returns true
2016             // (teleporting worked), break here
2017             if (what == O_TELEPORTER && do_teleporter(cave, x, y, player_move))
2018               break;
2019
2020             // player fire is false...
2021             if (do_push(cave, x, y, player_move, FALSE))
2022             {
2023               remains = O_SPACE;
2024             }
2025             else
2026             {
2027               // get element. if cannot get, player_get_element will return the same
2028               remains = player_get_element(cave, what, x, y);
2029             }
2030
2031             // if something changed, OR there is space, move.
2032             if (remains != what || remains == O_SPACE)
2033             {
2034               // if anything changed, apply the change.
2035               move(cave, x, y, player_move, O_PLAYER_ROCKET_LAUNCHER);
2036             }
2037           }
2038           break;
2039
2040         case O_PLAYER_STIRRING:
2041           if (cave->kill_player)
2042           {
2043             explode(cave, x, y);
2044             break;
2045           }
2046
2047           // stirring sound, if no other walking sound or explosion
2048           gd_sound_play(cave, GD_S_STIRRING, O_PLAYER_STIRRING, x, y);
2049
2050           cave->player_seen_ago = 0;
2051           // bd4 intermission caves have many players. so if one of them has exited,
2052           // do not change the flag anymore. so this if () is needed
2053           if (cave->player_state != GD_PL_EXITED)
2054             cave->player_state = GD_PL_LIVING;
2055
2056           if (player_fire)
2057           {
2058             // player "exits" stirring the pot by pressing fire
2059             cave->gravity_disabled = FALSE;
2060             store(cave, x, y, O_PLAYER);
2061             cave->gravity_switch_active = TRUE;
2062           }
2063           break;
2064
2065           // player holding pneumatic hammer
2066         case O_PLAYER_PNEUMATIC_LEFT:
2067         case O_PLAYER_PNEUMATIC_RIGHT:
2068           // usual player stuff
2069           if (cave->kill_player)
2070           {
2071             explode(cave, x, y);
2072             break;
2073           }
2074
2075           cave->player_seen_ago = 0;
2076           if (cave->player_state != GD_PL_EXITED)
2077             cave->player_state = GD_PL_LIVING;
2078
2079           // if hammering time is up, becomes a normal player again.
2080           if (cave->pneumatic_hammer_active_delay == 0)
2081             store(cave, x, y, O_PLAYER);
2082           break;
2083
2084           // the active pneumatic hammer itself
2085         case O_PNEUMATIC_ACTIVE_RIGHT:
2086         case O_PNEUMATIC_ACTIVE_LEFT:
2087           if (cave->pneumatic_hammer_active_delay == 0)
2088           {
2089             GdElement new_elem;
2090
2091             // pneumatic hammer element disappears
2092             store(cave, x, y, O_SPACE);
2093
2094             // which is the new element which appears after that one is hammered?
2095             new_elem = gd_element_get_hammered(get_dir(cave, x, y, GD_MV_DOWN));
2096
2097             // if there is a new element, display it
2098             // O_NONE might be returned, for example if the element being
2099             // hammered explodes during hammering (by a nearby explosion)
2100             if (new_elem != O_NONE)
2101             {
2102               store_dir(cave, x, y, GD_MV_DOWN, new_elem);
2103
2104               // and if walls reappear, remember it in array
2105               if (cave->hammered_walls_reappear)
2106               {
2107                 int wall_y;
2108
2109                 wall_y = (y + 1) % cave->h;
2110                 cave->hammered_reappear[wall_y][x] = cave->hammered_wall_reappear_frame;
2111               }
2112             }
2113           }
2114           break;
2115
2116           // ============================================================================
2117           //    S T O N E S,   D I A M O N D S
2118           // ============================================================================
2119
2120         case O_STONE:           // standing stone
2121           do_start_fall(cave, x, y, cave->gravity, cave->stone_falling_effect);
2122           break;
2123
2124         case O_MEGA_STONE:      // standing mega_stone
2125           do_start_fall(cave, x, y, cave->gravity, O_MEGA_STONE_F);
2126           break;
2127
2128         case O_DIAMOND:         // standing diamond
2129           do_start_fall(cave, x, y, cave->gravity, cave->diamond_falling_effect);
2130           break;
2131
2132         case O_NUT:             // standing nut
2133           do_start_fall(cave, x, y, cave->gravity, O_NUT_F);
2134           break;
2135
2136         case O_DIRT_BALL:       // standing dirt ball
2137           do_start_fall(cave, x, y, cave->gravity, O_DIRT_BALL_F);
2138           break;
2139
2140         case O_DIRT_LOOSE:      // standing loose dirt
2141           do_start_fall(cave, x, y, cave->gravity, O_DIRT_LOOSE_F);
2142           break;
2143
2144         case O_FLYING_STONE:    // standing stone
2145           do_start_fall(cave, x, y, opposite[cave->gravity], O_FLYING_STONE_F);
2146           break;
2147
2148         case O_FLYING_DIAMOND:  // standing diamond
2149           do_start_fall(cave, x, y, opposite[cave->gravity], O_FLYING_DIAMOND_F);
2150           break;
2151
2152           // ============================================================================
2153           //    F A L L I N G    E L E M E N T S,    F L Y I N G   S T O N E S,   D I A M O N D S
2154           // ============================================================================
2155
2156         case O_DIRT_BALL_F:     // falling dirt ball
2157           if (!cave->gravity_disabled)
2158             do_fall_roll_or_stop(cave, x, y, cave->gravity, O_DIRT_BALL);
2159           break;
2160
2161         case O_DIRT_LOOSE_F:    // falling loose dirt
2162           if (!cave->gravity_disabled)
2163             do_fall_roll_or_stop(cave, x, y, cave->gravity, O_DIRT_LOOSE);
2164           break;
2165
2166         case O_STONE_F:         // falling stone
2167           if (!cave->gravity_disabled)
2168           {
2169             if (do_fall_try_crush_voodoo(cave, x, y, cave->gravity))
2170               break;
2171
2172             if (do_fall_try_crack_nut(cave, x, y, cave->gravity, cave->stone_bouncing_effect))
2173               break;
2174
2175             if (do_fall_try_magic(cave, x, y, cave->gravity, cave->magic_stone_to))
2176               break;
2177
2178             if (do_fall_try_crush(cave, x, y, cave->gravity))
2179               break;
2180
2181             do_fall_roll_or_stop(cave, x, y, cave->gravity, cave->stone_bouncing_effect);
2182           }
2183           break;
2184
2185         case O_MEGA_STONE_F:    // falling mega
2186           if (!cave->gravity_disabled)
2187           {
2188             if (do_fall_try_crush_voodoo(cave, x, y, cave->gravity))
2189               break;
2190
2191             if (do_fall_try_crack_nut(cave, x, y, cave->gravity, O_MEGA_STONE))
2192               break;
2193
2194             if (do_fall_try_magic(cave, x, y, cave->gravity, cave->magic_mega_stone_to))
2195               break;
2196
2197             if (do_fall_try_crush(cave, x, y, cave->gravity))
2198               break;
2199
2200             do_fall_roll_or_stop(cave, x, y, cave->gravity, O_MEGA_STONE);
2201           }
2202           break;
2203
2204         case O_DIAMOND_F:       // falling diamond
2205           if (!cave->gravity_disabled)
2206           {
2207             if (do_fall_try_eat_voodoo(cave, x, y, cave->gravity))
2208               break;
2209
2210             if (do_fall_try_magic(cave, x, y, cave->gravity, cave->magic_diamond_to))
2211               break;
2212
2213             if (do_fall_try_crush(cave, x, y, cave->gravity))
2214               break;
2215
2216             do_fall_roll_or_stop(cave, x, y, cave->gravity, cave->diamond_bouncing_effect);
2217           }
2218           break;
2219
2220         case O_NUT_F:           // falling nut
2221           if (!cave->gravity_disabled)
2222           {
2223             if (do_fall_try_magic(cave, x, y, cave->gravity, cave->magic_nut_to))
2224               break;
2225
2226             if (do_fall_try_crush(cave, x, y, cave->gravity))
2227               break;
2228
2229             do_fall_roll_or_stop(cave, x, y, cave->gravity, O_NUT);
2230           }
2231           break;
2232
2233         case O_FLYING_STONE_F:  // falling stone
2234           if (!cave->gravity_disabled)
2235           {
2236             GdDirection fall_dir = opposite[cave->gravity];
2237
2238             if (do_fall_try_crush_voodoo(cave, x, y, fall_dir))
2239               break;
2240
2241             if (do_fall_try_crack_nut(cave, x, y, fall_dir, O_FLYING_STONE))
2242               break;
2243
2244             if (do_fall_try_magic(cave, x, y, fall_dir, cave->magic_flying_stone_to))
2245               break;
2246
2247             if (do_fall_try_crush(cave, x, y, fall_dir))
2248               break;
2249
2250             do_fall_roll_or_stop(cave, x, y, fall_dir, O_FLYING_STONE);
2251           }
2252           break;
2253
2254         case O_FLYING_DIAMOND_F:    // falling diamond
2255           if (!cave->gravity_disabled)
2256           {
2257             GdDirection fall_dir = opposite[cave->gravity];
2258
2259             if (do_fall_try_eat_voodoo(cave, x, y, fall_dir))
2260               break;
2261
2262             if (do_fall_try_magic(cave, x, y, fall_dir, cave->magic_flying_diamond_to))
2263               break;
2264
2265             if (do_fall_try_crush(cave, x, y, fall_dir))
2266               break;
2267
2268             do_fall_roll_or_stop(cave, x, y, fall_dir, O_FLYING_DIAMOND);
2269           }
2270           break;
2271
2272           // ============================================================================
2273           //    N I T R O    P A C K
2274           // ============================================================================
2275
2276         case O_NITRO_PACK:      // standing nitro pack
2277           do_start_fall(cave, x, y, cave->gravity, O_NITRO_PACK_F);
2278           break;
2279
2280         case O_NITRO_PACK_F:    // falling nitro pack
2281           if (!cave->gravity_disabled)
2282           {
2283             if (is_space_dir(cave, x, y, cave->gravity))    // if space, falling further
2284               move(cave, x, y, cave->gravity, get(cave, x, y));
2285             else if (do_fall_try_magic(cave, x, y, cave->gravity, cave->magic_nitro_pack_to))
2286             {
2287               // try magic wall; if true, function did the work
2288             }
2289             else if (is_element_dir(cave, x, y, cave->gravity, O_DIRT))
2290             {
2291               // falling on a dirt, it does NOT explode - just stops at its place.
2292               play_sound_of_element(cave, O_NITRO_PACK, x, y);
2293               store(cave, x, y, O_NITRO_PACK);
2294             }
2295             else
2296               // falling on any other element it explodes
2297               explode(cave, x, y);
2298           }
2299           break;
2300
2301         case O_NITRO_PACK_EXPLODE:    // a triggered nitro pack
2302           explode(cave, x, y);
2303           break;
2304
2305           // ============================================================================
2306           //    C R E A T U R E S
2307           // ============================================================================
2308
2309         case O_COW_1:
2310         case O_COW_2:
2311         case O_COW_3:
2312         case O_COW_4:
2313           // if cannot move in any direction, becomes an enclosed cow
2314           if (!is_space_dir(cave, x, y, GD_MV_UP) && !is_space_dir(cave, x, y, GD_MV_DOWN) &&
2315               !is_space_dir(cave, x, y, GD_MV_LEFT) && !is_space_dir(cave, x, y, GD_MV_RIGHT))
2316             store(cave, x, y, O_COW_ENCLOSED_1);
2317           else
2318           {
2319             // THIS IS THE CREATURE MOVE thing copied.
2320             const GdDirection *creature_move;
2321             boolean ccw = rotates_ccw(cave, x, y);    // check if default is counterclockwise
2322             GdElement base;    // base element number (which is like O_***_1)
2323             int dir, dirn, dirp;    // direction
2324
2325             base = O_COW_1;
2326
2327             dir = get(cave, x, y)-base;    // facing where
2328             creature_move = cave->creatures_backwards ? creature_chdir : creature_dir;
2329
2330             // now change direction if backwards
2331             if (cave->creatures_backwards)
2332               ccw = !ccw;
2333
2334             if (ccw)
2335             {
2336               dirn = (dir + 3) & 3;    // fast turn
2337               dirp = (dir + 1) & 3;    // slow turn
2338             }
2339             else
2340             {
2341               dirn = (dir + 1) & 3;    // fast turn
2342               dirp = (dir + 3) & 3;    // slow turn
2343             }
2344
2345             if (is_space_dir(cave, x, y, creature_move[dirn]))
2346               move(cave, x, y, creature_move[dirn], base + dirn);    // turn and move to preferred dir
2347             else if (is_space_dir(cave, x, y, creature_move[dir]))
2348               move(cave, x, y, creature_move[dir], base + dir);    // go on
2349             else
2350               store(cave, x, y, base + dirp);    // turn in place if nothing else possible
2351           }
2352           break;
2353
2354           // enclosed cows wait some time before turning to a skeleton
2355         case O_COW_ENCLOSED_1:
2356         case O_COW_ENCLOSED_2:
2357         case O_COW_ENCLOSED_3:
2358         case O_COW_ENCLOSED_4:
2359         case O_COW_ENCLOSED_5:
2360         case O_COW_ENCLOSED_6:
2361           if (is_space_dir(cave, x, y, GD_MV_UP) ||
2362               is_space_dir(cave, x, y, GD_MV_LEFT) ||
2363               is_space_dir(cave, x, y, GD_MV_RIGHT) ||
2364               is_space_dir(cave, x, y, GD_MV_DOWN))
2365             store(cave, x, y, O_COW_1);
2366           else
2367             next(cave, x, y);
2368           break;
2369
2370         case O_COW_ENCLOSED_7:
2371           if (is_space_dir(cave, x, y, GD_MV_UP) ||
2372               is_space_dir(cave, x, y, GD_MV_LEFT) ||
2373               is_space_dir(cave, x, y, GD_MV_RIGHT) ||
2374               is_space_dir(cave, x, y, GD_MV_DOWN))
2375             store(cave, x, y, O_COW_1);
2376           else
2377             store(cave, x, y, O_SKELETON);
2378           break;
2379
2380         case O_FIREFLY_1:
2381         case O_FIREFLY_2:
2382         case O_FIREFLY_3:
2383         case O_FIREFLY_4:
2384         case O_ALT_FIREFLY_1:
2385         case O_ALT_FIREFLY_2:
2386         case O_ALT_FIREFLY_3:
2387         case O_ALT_FIREFLY_4:
2388         case O_BUTTER_1:
2389         case O_BUTTER_2:
2390         case O_BUTTER_3:
2391         case O_BUTTER_4:
2392         case O_ALT_BUTTER_1:
2393         case O_ALT_BUTTER_2:
2394         case O_ALT_BUTTER_3:
2395         case O_ALT_BUTTER_4:
2396         case O_STONEFLY_1:
2397         case O_STONEFLY_2:
2398         case O_STONEFLY_3:
2399         case O_STONEFLY_4:
2400           // check if touches a voodoo
2401           if (get_dir(cave, x, y, GD_MV_LEFT)  == O_VOODOO ||
2402               get_dir(cave, x, y, GD_MV_RIGHT) == O_VOODOO ||
2403               get_dir(cave, x, y, GD_MV_UP)    == O_VOODOO ||
2404               get_dir(cave, x, y, GD_MV_DOWN)  == O_VOODOO)
2405             cave->voodoo_touched = TRUE;
2406
2407           // check if touches something bad and should explode (includes voodoo by the flags)
2408           if (blows_up_flies_dir(cave, x, y, GD_MV_DOWN) ||
2409               blows_up_flies_dir(cave, x, y, GD_MV_UP) ||
2410               blows_up_flies_dir(cave, x, y, GD_MV_LEFT) ||
2411               blows_up_flies_dir(cave, x, y, GD_MV_RIGHT))
2412             explode (cave, x, y);
2413           // otherwise move
2414           else
2415           {
2416             const GdDirection *creature_move;
2417             boolean ccw = rotates_ccw(cave, x, y);    // check if default is counterclockwise
2418             GdElement base = -1;    // base element number (which is like O_***_1)
2419             int dir, dirn, dirp;    // direction
2420
2421             if (get(cave, x, y) >= O_FIREFLY_1 &&
2422                 get(cave, x, y) <= O_FIREFLY_4)
2423               base = O_FIREFLY_1;
2424             else if (get(cave, x, y) >= O_BUTTER_1 &&
2425                      get(cave, x, y) <= O_BUTTER_4)
2426               base = O_BUTTER_1;
2427             else if (get(cave, x, y) >= O_STONEFLY_1 &&
2428                      get(cave, x, y) <= O_STONEFLY_4)
2429               base = O_STONEFLY_1;
2430             else if (get(cave, x, y) >= O_ALT_FIREFLY_1 &&
2431                      get(cave, x, y) <= O_ALT_FIREFLY_4)
2432               base = O_ALT_FIREFLY_1;
2433             else if (get(cave, x, y) >= O_ALT_BUTTER_1 &&
2434                      get(cave, x, y) <= O_ALT_BUTTER_4)
2435               base = O_ALT_BUTTER_1;
2436
2437             dir = get(cave, x, y) - base;    // facing where
2438             creature_move = cave->creatures_backwards ? creature_chdir : creature_dir;
2439
2440             // now change direction if backwards
2441             if (cave->creatures_backwards)
2442               ccw = !ccw;
2443
2444             if (ccw)
2445             {
2446               dirn = (dir + 3) & 3;    // fast turn
2447               dirp = (dir + 1) & 3;    // slow turn
2448             }
2449             else
2450             {
2451               dirn = (dir + 1) & 3;    // fast turn
2452               dirp = (dir + 3) & 3;    // slow turn
2453             }
2454
2455             if (is_space_dir(cave, x, y, creature_move[dirn]))
2456               move(cave, x, y, creature_move[dirn], base + dirn);    // turn and move to preferred dir
2457             else if (is_space_dir(cave, x, y, creature_move[dir]))
2458               move(cave, x, y, creature_move[dir], base + dir);    // go on
2459             else
2460               store(cave, x, y, base + dirp);    // turn in place if nothing else possible
2461           }
2462           break;
2463
2464         case O_WAITING_STONE:
2465           if (is_space_dir(cave, x, y, grav_compat))
2466           {
2467             // beginning to fall
2468             // it wakes up.
2469             move(cave, x, y, grav_compat, O_CHASING_STONE);
2470           }
2471           else if (sloped_dir(cave, x, y, grav_compat, opposite[grav_compat]))
2472           {
2473             // rolling down a brick wall or a stone
2474             if (sloped_dir(cave, x, y, grav_compat, cw_fourth[grav_compat]) &&
2475                 is_space_dir(cave, x, y, cw_fourth[grav_compat]) &&
2476                 is_space_dir(cave, x, y, cw_eighth[grav_compat]))
2477             {
2478               // maybe rolling left - see case O_STONE to understand why we use cw_fourth here
2479               move(cave, x, y, cw_fourth[grav_compat], O_WAITING_STONE);
2480             }
2481             else if (sloped_dir(cave, x, y, grav_compat, ccw_fourth[grav_compat]) &&
2482                      is_space_dir(cave, x, y, ccw_fourth[grav_compat]) &&
2483                      is_space_dir(cave, x, y, ccw_eighth[grav_compat]))
2484             {
2485               // or maybe right
2486               move(cave, x, y, ccw_fourth[grav_compat], O_WAITING_STONE);
2487             }
2488           }
2489           break;
2490
2491         case O_CHASING_STONE:
2492           {
2493             int px = cave->px[0];
2494             int py = cave->py[0];
2495             boolean horizontal = gd_rand_boolean(cave->random);
2496             boolean dont_move = FALSE;
2497             int i = 3;
2498
2499             // try to move...
2500             while (1)
2501             {
2502               if (horizontal)
2503               {
2504                 // ------------------------------------------------------------
2505                 // check for a horizontal movement
2506                 // ------------------------------------------------------------
2507                 if (px == x)
2508                 {
2509                   // if coordinates are the same
2510                   i -= 1;
2511                   horizontal = !horizontal;
2512
2513                   if (i == 2)
2514                     continue;
2515                 }
2516                 else
2517                 {
2518                   if (px > x && is_space_dir(cave, x, y, GD_MV_RIGHT))
2519                   {
2520                     move(cave, x, y, GD_MV_RIGHT, O_CHASING_STONE);
2521                     dont_move = TRUE;
2522                     break;
2523                   }
2524                   else if (px < x && is_space_dir(cave, x, y, GD_MV_LEFT))
2525                   {
2526                     move(cave, x, y, GD_MV_LEFT, O_CHASING_STONE);
2527                     dont_move = TRUE;
2528                     break;
2529                   }
2530                   else
2531                   {
2532                     i -= 2;
2533                     if (i == 1)
2534                     {
2535                       horizontal = !horizontal;
2536                       continue;
2537                     }
2538                   }
2539                 }
2540               }
2541               else
2542               {
2543                 // ------------------------------------------------------------
2544                 // check for a vertical movement
2545                 // ------------------------------------------------------------
2546                 if (py == y)
2547                 {
2548                   // if coordinates are the same
2549                   i -= 1;
2550                   horizontal = !horizontal;
2551                   if (i == 2)
2552                     continue;
2553                 }
2554                 else
2555                 {
2556                   if (py > y && is_space_dir(cave, x, y, GD_MV_DOWN))
2557                   {
2558                     move(cave, x, y, GD_MV_DOWN, O_CHASING_STONE);
2559                     dont_move = TRUE;
2560                     break;
2561                   }
2562                   else if (py < y && is_space_dir(cave, x, y, GD_MV_UP))
2563                   {
2564                     move(cave, x, y, GD_MV_UP, O_CHASING_STONE);
2565                     dont_move = TRUE;
2566                     break;
2567                   }
2568                   else
2569                   {
2570                     i -= 2;
2571                     if (i == 1)
2572                     {
2573                       horizontal = !horizontal;
2574                       continue;
2575                     }
2576                   }
2577                 }
2578               }
2579
2580               if (i != 0)
2581                 dont_move = TRUE;
2582
2583               break;
2584             }
2585
2586             // if we should move in both directions, but can not move in any, stop.
2587             if (!dont_move)
2588             {
2589               if (horizontal)
2590               {
2591                 // check for horizontal
2592                 if (x >= px)
2593                 {
2594                   if (is_space_dir(cave, x, y, GD_MV_UP) &&
2595                       is_space_dir(cave, x, y, GD_MV_UP_LEFT))
2596                     move(cave, x, y, GD_MV_UP, O_CHASING_STONE);
2597                   else if (is_space_dir(cave, x, y, GD_MV_DOWN) &&
2598                            is_space_dir(cave, x, y, GD_MV_DOWN_LEFT))
2599                     move(cave, x, y, GD_MV_DOWN, O_CHASING_STONE);
2600                 }
2601                 else
2602                 {
2603                   if (is_space_dir(cave, x, y, GD_MV_UP) &&
2604                       is_space_dir(cave, x, y, GD_MV_UP_RIGHT))
2605                     move(cave, x, y, GD_MV_UP, O_CHASING_STONE);
2606                   else if (is_space_dir(cave, x, y, GD_MV_DOWN) &&
2607                            is_space_dir(cave, x, y, GD_MV_DOWN_RIGHT))
2608                     move(cave, x, y, GD_MV_DOWN, O_CHASING_STONE);
2609                 }
2610               }
2611               else
2612               {
2613                 // check for vertical
2614                 if (y >= py)
2615                 {
2616                   if (is_space_dir(cave, x, y, GD_MV_LEFT) &&
2617                       is_space_dir(cave, x, y, GD_MV_UP_LEFT))
2618                     move(cave, x, y, GD_MV_LEFT, O_CHASING_STONE);
2619                   else if (is_space_dir(cave, x, y, GD_MV_RIGHT) &&
2620                            is_space_dir(cave, x, y, GD_MV_UP_RIGHT))
2621                     move(cave, x, y, GD_MV_RIGHT, O_CHASING_STONE);
2622                 }
2623                 else
2624                 {
2625                   if (is_space_dir(cave, x, y, GD_MV_LEFT) &&
2626                       is_space_dir(cave, x, y, GD_MV_DOWN_LEFT))
2627                     move(cave, x, y, GD_MV_LEFT, O_CHASING_STONE);
2628                   else if (is_space_dir(cave, x, y, GD_MV_RIGHT) &&
2629                            is_space_dir(cave, x, y, GD_MV_DOWN_RIGHT))
2630                     move(cave, x, y, GD_MV_RIGHT, O_CHASING_STONE);
2631                 }
2632               }
2633             }
2634           }
2635           break;
2636
2637         case O_REPLICATOR:
2638           if (cave->replicators_wait_frame == 0 &&
2639               cave->replicators_active &&
2640               !cave->gravity_disabled)
2641           {
2642             // only replicate, if space is under it.
2643             // do not replicate players!
2644             // also obeys gravity settings.
2645             // only replicate element if it is not a scanned one
2646             // do not replicate space... that condition looks like it
2647             // makes no sense, but otherwise it generates SCANNED spaces,
2648             // which cannot be "collected" by the player, so he cannot run
2649             // under a replicator
2650             if (is_space_dir(cave, x, y, cave->gravity) &&
2651                 !is_player_dir(cave, x, y, opposite[cave->gravity]) &&
2652                 !is_space_dir(cave, x, y, opposite[cave->gravity]))
2653             {
2654               store_dir(cave, x, y, cave->gravity, get_dir(cave, x, y, opposite[cave->gravity]));
2655               gd_sound_play(cave, GD_S_REPLICATOR, O_REPLICATOR, x, y);
2656             }
2657           }
2658           break;
2659
2660         case O_BITER_1:
2661         case O_BITER_2:
2662         case O_BITER_3:
2663         case O_BITER_4:
2664           if (cave->biters_wait_frame == 0)
2665           {
2666             static GdDirection biter_move[] =
2667             {
2668               GD_MV_UP,
2669               GD_MV_RIGHT,
2670               GD_MV_DOWN,
2671               GD_MV_LEFT
2672             };
2673
2674             // direction, last two bits 0..3
2675             int dir = get(cave, x, y) - O_BITER_1;
2676             int dirn = (dir + 3) & 3;
2677             int dirp = (dir + 1) & 3;
2678             int i;
2679             GdElement made_sound_of = O_NONE;
2680
2681             for (i = 0; i < ARRAY_SIZE (biter_try); i++)
2682             {
2683               if (is_element_dir(cave, x, y, biter_move[dir], biter_try[i]))
2684               {
2685                 move(cave, x, y, biter_move[dir], O_BITER_1 + dir);
2686                 if (biter_try[i] != O_SPACE)
2687                   made_sound_of = O_BITER_1;    // sound of a biter eating
2688                 break;
2689               }
2690               else if (is_element_dir(cave, x, y, biter_move[dirn], biter_try[i]))
2691               {
2692                 move(cave, x, y, biter_move[dirn], O_BITER_1 + dirn);
2693                 if (biter_try[i] != O_SPACE)
2694                   made_sound_of = O_BITER_1;    // sound of a biter eating
2695                 break;
2696               }
2697               else if (is_element_dir(cave, x, y, biter_move[dirp], biter_try[i]))
2698               {
2699                 move(cave, x, y, biter_move[dirp], O_BITER_1 + dirp);
2700                 if (biter_try[i] != O_SPACE)
2701                   made_sound_of = O_BITER_1;    // sound of a biter eating
2702                 break;
2703               }
2704             }
2705
2706             if (i == ARRAY_SIZE(biter_try))
2707               // i = number of elements in array: could not move, so just turn
2708               store(cave, x, y, O_BITER_1 + dirp);
2709             else if (biter_try[i] == O_STONE)
2710             {
2711               // if there was a stone there, where we moved...
2712               // do not eat stones, just throw them back
2713               store(cave, x, y, O_STONE);
2714               made_sound_of = O_STONE;
2715             }
2716
2717             // if biter did move, we had sound. play it.
2718             if (made_sound_of != O_NONE)
2719               play_sound_of_element(cave, made_sound_of, x, y);
2720           }
2721           break;
2722
2723         case O_DRAGONFLY_1:
2724         case O_DRAGONFLY_2:
2725         case O_DRAGONFLY_3:
2726         case O_DRAGONFLY_4:
2727           // check if touches a voodoo
2728           if (get_dir(cave, x, y, GD_MV_LEFT)  == O_VOODOO ||
2729               get_dir(cave, x, y, GD_MV_RIGHT) == O_VOODOO ||
2730               get_dir(cave, x, y, GD_MV_UP)    == O_VOODOO ||
2731               get_dir(cave, x, y, GD_MV_DOWN)  == O_VOODOO)
2732             cave->voodoo_touched = TRUE;
2733
2734           // check if touches something bad and should explode (includes voodoo by the flags)
2735           if (blows_up_flies_dir(cave, x, y, GD_MV_DOWN) ||
2736               blows_up_flies_dir(cave, x, y, GD_MV_UP) ||
2737               blows_up_flies_dir(cave, x, y, GD_MV_LEFT) ||
2738               blows_up_flies_dir(cave, x, y, GD_MV_RIGHT))
2739             explode (cave, x, y);
2740           // otherwise move
2741           else
2742           {
2743             const GdDirection *creature_move;
2744             boolean ccw = rotates_ccw(cave, x, y);    // check if default is counterclockwise
2745             GdElement base = O_DRAGONFLY_1;    // base element number (which is like O_***_1)
2746             int dir, dirn;    // direction
2747
2748             dir = get(cave, x, y)-base;    // facing where
2749             creature_move = cave->creatures_backwards ? creature_chdir : creature_dir;
2750
2751             // now change direction if backwards
2752             if (cave->creatures_backwards)
2753               ccw = !ccw;
2754
2755             if (ccw)
2756               dirn = (dir + 3) & 3;    // fast turn
2757             else
2758               dirn = (dir + 1) & 3;    // fast turn
2759
2760             // if can move forward, does so.
2761             if (is_space_dir(cave, x, y, creature_move[dir]))
2762               move(cave, x, y, creature_move[dir], base + dir);
2763             else
2764               // otherwise turns 90 degrees in place.
2765               store(cave, x, y, base + dirn);
2766           }
2767           break;
2768
2769         case O_BLADDER:
2770           store(cave, x, y, O_BLADDER_1);
2771           break;
2772
2773         case O_BLADDER_1:
2774         case O_BLADDER_2:
2775         case O_BLADDER_3:
2776         case O_BLADDER_4:
2777         case O_BLADDER_5:
2778         case O_BLADDER_6:
2779         case O_BLADDER_7:
2780         case O_BLADDER_8:
2781           // bladder with any delay state: try to convert to clock.
2782           if (is_element_dir(cave, x, y, opposite[grav_compat], cave->bladder_converts_by) ||
2783               is_element_dir(cave, x, y, cw_fourth[grav_compat], cave->bladder_converts_by) || is_element_dir(cave, x, y, ccw_fourth[grav_compat], cave->bladder_converts_by))
2784           {
2785             // if touches the specified element, let it be a clock
2786             store(cave, x, y, O_PRE_CLOCK_1);
2787
2788             // plays the bladder convert sound
2789             play_sound_of_element(cave, O_PRE_CLOCK_1, x, y);
2790           }
2791           else
2792           {
2793             // is space over the bladder?
2794             if (is_space_dir(cave, x, y, opposite[grav_compat]))
2795             {
2796               if (get(cave, x, y) == O_BLADDER_8)
2797               {
2798                 // if it is a bladder 8, really move up
2799                 move(cave, x, y, opposite[grav_compat], O_BLADDER_1);
2800                 play_sound_of_element(cave, O_BLADDER, x, y);
2801               }
2802               else
2803                 // if smaller delay, just increase delay.
2804                 next(cave, x, y);
2805             }
2806             else
2807               // if not space, is something sloped over the bladder?
2808               if (sloped_for_bladder_dir(cave, x, y, opposite[grav_compat]) &&
2809                   sloped_dir(cave, x, y, opposite[grav_compat], opposite[grav_compat]))
2810               {
2811                 if (sloped_dir(cave, x, y, opposite[grav_compat], ccw_fourth[opposite[grav_compat]]) &&
2812                     is_space_dir(cave, x, y, ccw_fourth[opposite[grav_compat]]) &&
2813                     is_space_dir(cave, x, y, ccw_eighth[opposite[grav_compat]]))
2814                 {
2815                   // rolling up, to left
2816                   if (get(cave, x, y) == O_BLADDER_8)
2817                   {
2818                     // if it is a bladder 8, really roll
2819                     move(cave, x, y, ccw_fourth[opposite[grav_compat]], O_BLADDER_8);
2820                     play_sound_of_element(cave, O_BLADDER, x, y);
2821                   }
2822                   else
2823                     // if smaller delay, just increase delay.
2824                     next(cave, x, y);
2825                 }
2826                 else if (sloped_dir(cave, x, y, opposite[grav_compat], cw_fourth[opposite[grav_compat]]) &&
2827                          is_space_dir(cave, x, y, cw_fourth[opposite[grav_compat]]) &&
2828                          is_space_dir(cave, x, y, cw_eighth[opposite[grav_compat]]))
2829                 {
2830                   // rolling up, to left
2831                   if (get(cave, x, y) == O_BLADDER_8)
2832                   {
2833                     // if it is a bladder 8, really roll
2834                     move(cave, x, y, cw_fourth[opposite[grav_compat]], O_BLADDER_8);
2835                     play_sound_of_element(cave, O_BLADDER, x, y);
2836                   }
2837                   else
2838                     // if smaller delay, just increase delay.
2839                     next(cave, x, y);
2840                 }
2841               }
2842
2843             // no space, no sloped thing over it - store bladder 1 and that is for now.
2844               else
2845                 store(cave, x, y, O_BLADDER_1);
2846           }
2847           break;
2848
2849         case O_GHOST:
2850           if (blows_up_flies_dir(cave, x, y, GD_MV_DOWN) ||
2851               blows_up_flies_dir(cave, x, y, GD_MV_UP) ||
2852               blows_up_flies_dir(cave, x, y, GD_MV_LEFT) ||
2853               blows_up_flies_dir(cave, x, y, GD_MV_RIGHT))
2854             explode (cave, x, y);
2855           else
2856           {
2857             int i;
2858
2859             // the ghost is given four possibilities to move.
2860             for (i = 0; i < 4; i++)
2861             {
2862               static GdDirection dirs[] =
2863               {
2864                 GD_MV_UP,
2865                 GD_MV_DOWN,
2866                 GD_MV_LEFT,
2867                 GD_MV_RIGHT
2868               };
2869               GdDirection random_dir;
2870
2871               random_dir = dirs[gd_rand_int_range(cave->random, 0, ARRAY_SIZE(dirs))];
2872               if (is_space_dir(cave, x, y, random_dir))
2873               {
2874                 move(cave, x, y, random_dir, O_GHOST);
2875                 break;    // ghost did move -> exit loop
2876               }
2877             }
2878           }
2879           break;
2880
2881           // ============================================================================
2882           //    A C T I V E    E L E M E N T S
2883           // ============================================================================
2884
2885         case O_AMOEBA:
2886           // emulating BD1 amoeba+magic wall bug
2887           if (cave->convert_amoeba_this_frame && amoeba_found_enclosed)
2888           {
2889             store(cave, x, y, cave->amoeba_enclosed_effect);
2890             break;
2891           }
2892
2893           amoeba_count++;
2894           switch (cave->amoeba_state)
2895           {
2896             case GD_AM_TOO_BIG:
2897               store(cave, x, y, cave->amoeba_too_big_effect);
2898               break;
2899
2900             case GD_AM_ENCLOSED:
2901               store(cave, x, y, cave->amoeba_enclosed_effect);
2902               break;
2903
2904             case GD_AM_SLEEPING:
2905             case GD_AM_AWAKE:
2906               // if no amoeba found during THIS SCAN yet, which was able to grow, check this one.
2907               if (amoeba_found_enclosed)
2908                 // if still found enclosed, check all four directions, if this one is able to grow.
2909                 if (amoeba_eats_dir(cave, x, y, GD_MV_UP) ||
2910                     amoeba_eats_dir(cave, x, y, GD_MV_DOWN) ||
2911                     amoeba_eats_dir(cave, x, y, GD_MV_LEFT) ||
2912                     amoeba_eats_dir(cave, x, y, GD_MV_RIGHT))
2913                 {
2914                   // not enclosed. this is a local (per scan) flag!
2915                   amoeba_found_enclosed = FALSE;
2916                   cave->amoeba_state = GD_AM_AWAKE;
2917                 }
2918
2919               // if alive, check in which dir to grow (or not)
2920               if (cave->amoeba_state == GD_AM_AWAKE)
2921               {
2922                 if (gd_rand_int_range(cave->random, 0, 1000000) < cave->amoeba_growth_prob)
2923                 {
2924                   switch (gd_rand_int_range(cave->random, 0, 4))
2925                   {
2926                     // decided to grow, choose a random direction.
2927                     case 0:    // let this be up. numbers indifferent.
2928                       if (amoeba_eats_dir(cave, x, y, GD_MV_UP))
2929                         store_dir(cave, x, y, GD_MV_UP, O_AMOEBA);
2930                       break;
2931
2932                     case 1:    // down
2933                       if (amoeba_eats_dir(cave, x, y, GD_MV_DOWN))
2934                         store_dir(cave, x, y, GD_MV_DOWN, O_AMOEBA);
2935                       break;
2936
2937                     case 2:    // left
2938                       if (amoeba_eats_dir(cave, x, y, GD_MV_LEFT))
2939                         store_dir(cave, x, y, GD_MV_LEFT, O_AMOEBA);
2940                       break;
2941
2942                     case 3:    // right
2943                       if (amoeba_eats_dir(cave, x, y, GD_MV_RIGHT))
2944                         store_dir(cave, x, y, GD_MV_RIGHT, O_AMOEBA);
2945                       break;
2946                   }
2947                 }
2948               }
2949               break;
2950
2951           }
2952           break;
2953
2954         case O_AMOEBA_2:
2955           amoeba_2_count++;
2956           // check if it is touching an amoeba, and explosion is enabled
2957           if (cave->amoeba_2_explodes_by_amoeba &&
2958               (is_element_dir(cave, x, y, GD_MV_DOWN, O_AMOEBA) ||
2959                is_element_dir(cave, x, y, GD_MV_UP, O_AMOEBA) ||
2960                is_element_dir(cave, x, y, GD_MV_LEFT, O_AMOEBA) ||
2961                is_element_dir(cave, x, y, GD_MV_RIGHT, O_AMOEBA)))
2962             explode (cave, x, y);
2963           else
2964             switch (cave->amoeba_2_state)
2965             {
2966               case GD_AM_TOO_BIG:
2967                 store(cave, x, y, cave->amoeba_2_too_big_effect);
2968                 break;
2969
2970               case GD_AM_ENCLOSED:
2971                 store(cave, x, y, cave->amoeba_2_enclosed_effect);
2972                 break;
2973
2974               case GD_AM_SLEEPING:
2975               case GD_AM_AWAKE:
2976                 // if no amoeba found during THIS SCAN yet, which was able to grow, check this one.
2977                 if (amoeba_2_found_enclosed)
2978                   if (amoeba_eats_dir(cave, x, y, GD_MV_UP) ||
2979                       amoeba_eats_dir(cave, x, y, GD_MV_DOWN) ||
2980                       amoeba_eats_dir(cave, x, y, GD_MV_LEFT) ||
2981                       amoeba_eats_dir(cave, x, y, GD_MV_RIGHT))
2982                   {
2983                     // not enclosed. this is a local (per scan) flag!
2984                     amoeba_2_found_enclosed = FALSE;
2985                     cave->amoeba_2_state = GD_AM_AWAKE;
2986                   }
2987
2988                 // if it is alive, decide if it attempts to grow
2989                 if (cave->amoeba_2_state == GD_AM_AWAKE)
2990                   if (gd_rand_int_range(cave->random, 0, 1000000) < cave->amoeba_2_growth_prob)
2991                   {
2992                     switch (gd_rand_int_range(cave->random, 0, 4))
2993                     {
2994                       // decided to grow, choose a random direction.
2995                       case 0:    // let this be up. numbers indifferent.
2996                         if (amoeba_eats_dir(cave, x, y, GD_MV_UP))
2997                           store_dir(cave, x, y, GD_MV_UP, O_AMOEBA_2);
2998                         break;
2999
3000                       case 1:    // down
3001                         if (amoeba_eats_dir(cave, x, y, GD_MV_DOWN))
3002                           store_dir(cave, x, y, GD_MV_DOWN, O_AMOEBA_2);
3003                         break;
3004
3005                       case 2:    // left
3006                         if (amoeba_eats_dir(cave, x, y, GD_MV_LEFT))
3007                           store_dir(cave, x, y, GD_MV_LEFT, O_AMOEBA_2);
3008                         break;
3009
3010                       case 3:    // right
3011                         if (amoeba_eats_dir(cave, x, y, GD_MV_RIGHT))
3012                           store_dir(cave, x, y, GD_MV_RIGHT, O_AMOEBA_2);
3013                         break;
3014                     }
3015                   }
3016                 break;
3017
3018             }
3019           break;
3020
3021         case O_ACID:
3022           // choose randomly, if it spreads
3023           if (gd_rand_int_range(cave->random, 0, 1000000) <= cave->acid_spread_ratio)
3024           {
3025             // the current one explodes
3026             store(cave, x, y, cave->acid_turns_to);
3027
3028             // and if neighbours are eaten, put acid there.
3029             if (is_element_dir(cave, x, y, GD_MV_UP, cave->acid_eats_this))
3030             {
3031               play_sound_of_element(cave, O_ACID, x, y);
3032               store_dir(cave, x, y, GD_MV_UP, O_ACID);
3033             }
3034
3035             if (is_element_dir(cave, x, y, GD_MV_DOWN, cave->acid_eats_this))
3036             {
3037               play_sound_of_element(cave, O_ACID, x, y);
3038               store_dir(cave, x, y, GD_MV_DOWN, O_ACID);
3039             }
3040
3041             if (is_element_dir(cave, x, y, GD_MV_LEFT, cave->acid_eats_this))
3042             {
3043               play_sound_of_element(cave, O_ACID, x, y);
3044               store_dir(cave, x, y, GD_MV_LEFT, O_ACID);
3045             }
3046
3047             if (is_element_dir(cave, x, y, GD_MV_RIGHT, cave->acid_eats_this))
3048             {
3049               play_sound_of_element(cave, O_ACID, x, y);
3050               store_dir(cave, x, y, GD_MV_RIGHT, O_ACID);
3051             }
3052           }
3053           break;
3054
3055         case O_WATER:
3056           found_water = TRUE;
3057           if (!cave->water_does_not_flow_down &&
3058               is_space_dir(cave, x, y, GD_MV_DOWN))
3059             // emulating the odd behaviour in crdr
3060             store_dir(cave, x, y, GD_MV_DOWN, O_WATER_1);
3061
3062           if (is_space_dir(cave, x, y, GD_MV_UP))
3063             store_dir(cave, x, y, GD_MV_UP, O_WATER_1);
3064
3065           if (is_space_dir(cave, x, y, GD_MV_LEFT))
3066             store_dir(cave, x, y, GD_MV_LEFT, O_WATER_1);
3067
3068           if (is_space_dir(cave, x, y, GD_MV_RIGHT))
3069             store_dir(cave, x, y, GD_MV_RIGHT, O_WATER_1);
3070           break;
3071
3072         case O_WATER_16:
3073           store(cave, x, y, O_WATER);
3074           break;
3075
3076         case O_H_EXPANDING_WALL:
3077         case O_V_EXPANDING_WALL:
3078         case O_H_EXPANDING_STEEL_WALL:
3079         case O_V_EXPANDING_STEEL_WALL:
3080           // checks first if direction is changed.
3081           if (((get(cave, x, y) == O_H_EXPANDING_WALL ||
3082                 get(cave, x, y) == O_H_EXPANDING_STEEL_WALL) &&
3083                !cave->expanding_wall_changed) ||
3084               ((get(cave, x, y) == O_V_EXPANDING_WALL ||
3085                 get(cave, x, y) == O_V_EXPANDING_STEEL_WALL) &&
3086                cave->expanding_wall_changed))
3087           {
3088             if (is_space_dir(cave, x, y, GD_MV_LEFT))
3089             {
3090               store_dir(cave, x, y, GD_MV_LEFT, get(cave, x, y));
3091               play_sound_of_element(cave, get(cave, x, y), x, y);
3092             }
3093
3094             if (is_space_dir(cave, x, y, GD_MV_RIGHT)) {
3095               store_dir(cave, x, y, GD_MV_RIGHT, get(cave, x, y));
3096               play_sound_of_element(cave, get(cave, x, y), x, y);
3097             }
3098           }
3099           else
3100           {
3101             if (is_space_dir(cave, x, y, GD_MV_UP)) {
3102               store_dir(cave, x, y, GD_MV_UP, get(cave, x, y));
3103               play_sound_of_element(cave, get(cave, x, y), x, y);
3104             }
3105
3106             if (is_space_dir(cave, x, y, GD_MV_DOWN)) {
3107               store_dir(cave, x, y, GD_MV_DOWN, get(cave, x, y));
3108               play_sound_of_element(cave, get(cave, x, y), x, y);
3109             }
3110           }
3111           break;
3112
3113         case O_EXPANDING_WALL:
3114         case O_EXPANDING_STEEL_WALL:
3115           // the wall which grows in all four directions.
3116           if (is_space_dir(cave, x, y, GD_MV_LEFT))
3117           {
3118             store_dir(cave, x, y, GD_MV_LEFT, get(cave, x, y));
3119             play_sound_of_element(cave, get(cave, x, y), x, y);
3120           }
3121
3122           if (is_space_dir(cave, x, y, GD_MV_RIGHT)) {
3123             store_dir(cave, x, y, GD_MV_RIGHT, get(cave, x, y));
3124             play_sound_of_element(cave, get(cave, x, y), x, y);
3125           }
3126
3127           if (is_space_dir(cave, x, y, GD_MV_UP)) {
3128             store_dir(cave, x, y, GD_MV_UP, get(cave, x, y));
3129             play_sound_of_element(cave, get(cave, x, y), x, y);
3130           }
3131
3132           if (is_space_dir(cave, x, y, GD_MV_DOWN)) {
3133             store_dir(cave, x, y, GD_MV_DOWN, get(cave, x, y));
3134             play_sound_of_element(cave, get(cave, x, y), x, y);
3135           }
3136           break;
3137
3138         case O_SLIME:
3139 #if 1
3140           ; // to make compilers happy ...
3141 #else
3142           Info("Step[%03d]", cave->frame); // XXX
3143 #endif
3144           int rrr = gd_cave_c64_random(cave);
3145 #if 1
3146 #else
3147           Info(".Rand[%03d].Perm[%03d].Result[%d]\n", rrr, cave->slime_permeability_c64,
3148                (rrr & cave->slime_permeability_c64) == 0);
3149 #endif
3150           /*
3151            * unpredictable: gd_rand_int
3152            * predictable: c64 predictable random generator.
3153            *    for predictable, a random number is generated,
3154            *    whether or not it is even possible that the stone will be able to pass.
3155            */
3156           if (cave->slime_predictable ? ((rrr /* XXX */ & cave->slime_permeability_c64) == 0) : gd_rand_int_range(cave->random, 0, 1000000) < cave->slime_permeability)
3157           {
3158             GdDirection grav = cave->gravity;
3159             GdDirection oppos = opposite[cave->gravity];
3160
3161             // space under the slime? elements may pass from top to bottom then.
3162             if (is_space_dir(cave, x, y, grav))
3163             {
3164               if (get_dir(cave, x, y, oppos) == cave->slime_eats_1)
3165               {
3166                 // output a falling xy under
3167                 store_dir(cave, x, y, grav, cave->slime_converts_1);
3168
3169                 store_dir(cave, x, y, oppos, O_SPACE);
3170                 play_sound_of_element(cave, O_SLIME, x, y);
3171               }
3172               else if (get_dir(cave, x, y, oppos) == cave->slime_eats_2)
3173               {
3174                 store_dir(cave, x, y, grav, cave->slime_converts_2);
3175                 store_dir(cave, x, y, oppos, O_SPACE);
3176                 play_sound_of_element(cave, O_SLIME, x, y);
3177               }
3178               else if (get_dir(cave, x, y, oppos) == cave->slime_eats_3)
3179               {
3180                 store_dir(cave, x, y, grav, cave->slime_converts_3);
3181                 store_dir(cave, x, y, oppos, O_SPACE);
3182                 play_sound_of_element(cave, O_SLIME, x, y);
3183               }
3184               else if (get_dir(cave, x, y, oppos) == O_WAITING_STONE)
3185               {
3186                 // waiting stones pass without awakening
3187                 store_dir(cave, x, y, grav, O_WAITING_STONE);
3188                 store_dir(cave, x, y, oppos, O_SPACE);
3189                 play_sound_of_element(cave, O_SLIME, x, y);
3190               }
3191               else if (get_dir(cave, x, y, oppos) == O_CHASING_STONE)
3192               {
3193                 // chasing stones pass
3194                 store_dir(cave, x, y, grav, O_CHASING_STONE);
3195                 store_dir(cave, x, y, oppos, O_SPACE);
3196                 play_sound_of_element(cave, O_SLIME, x, y);
3197               }
3198             }
3199             else
3200             {
3201               // or space over the slime? elements may pass from bottom to up then.
3202               if (is_space_dir(cave, x, y, oppos))
3203               {
3204                 if (get_dir(cave, x, y, grav) == O_BLADDER)
3205                 {
3206                   // bladders move UP the slime
3207                   store_dir(cave, x, y, grav, O_SPACE);
3208                   store_dir(cave, x, y, oppos, O_BLADDER_1);
3209                   play_sound_of_element(cave, O_SLIME, x, y);
3210                 }
3211                 else if (get_dir(cave, x, y, grav) == O_FLYING_STONE)
3212                 {
3213                   store_dir(cave, x, y, grav, O_SPACE);
3214                   store_dir(cave, x, y, oppos, O_FLYING_STONE_F);
3215                   play_sound_of_element(cave, O_SLIME, x, y);
3216                 }
3217                 else if (get_dir(cave, x, y, grav) == O_FLYING_DIAMOND)
3218                 {
3219                   store_dir(cave, x, y, grav, O_SPACE);
3220                   store_dir(cave, x, y, oppos, O_FLYING_DIAMOND_F);
3221                   play_sound_of_element(cave, O_SLIME, x, y);
3222                 }
3223               }
3224             }
3225           }
3226           break;
3227
3228         case O_FALLING_WALL:
3229           if (is_space_dir(cave, x, y, grav_compat))
3230           {
3231             // try falling if space under.
3232             int yy;
3233
3234             for (yy = y + 1; yy < y + cave->h; yy++)
3235               // yy < y + cave->h is to check everything OVER the wall - since caves wrap around !!
3236               if (get(cave, x, yy) != O_SPACE)
3237                 // stop cycle when other than space
3238                 break;
3239
3240             // if scanning stopped by a player... start falling!
3241             if (get(cave, x, yy) == O_PLAYER ||
3242                 get(cave, x, yy) == O_PLAYER_GLUED ||
3243                 get(cave, x, yy) == O_PLAYER_BOMB)
3244             {
3245               move(cave, x, y, grav_compat, O_FALLING_WALL_F);
3246               // no sound when the falling wall starts falling!
3247             }
3248           }
3249           break;
3250
3251         case O_FALLING_WALL_F:
3252           switch (get_dir(cave, x, y, grav_compat))
3253           {
3254             case O_PLAYER:
3255             case O_PLAYER_GLUED:
3256             case O_PLAYER_BOMB:
3257               // if player under, it explodes - the falling wall, not the player!
3258               explode(cave, x, y);
3259               break;
3260
3261             case O_SPACE:
3262               // continue falling
3263               move(cave, x, y, grav_compat, O_FALLING_WALL_F);
3264               break;
3265
3266             default:
3267               // stop
3268               play_sound_of_element(cave, get(cave, x, y), x, y);
3269               store(cave, x, y, O_FALLING_WALL);
3270               break;
3271           }
3272           break;
3273
3274           // ============================================================================
3275           //    C O N V E Y O R    B E L T S
3276           // ============================================================================
3277
3278         case O_CONVEYOR_RIGHT:
3279         case O_CONVEYOR_LEFT:
3280           // only works if gravity is up or down!!!
3281           // first, check for gravity and running belts.
3282           if (!cave->gravity_disabled && cave->conveyor_belts_active)
3283           {
3284             const GdDirection *dir;
3285             boolean left;
3286
3287             // decide direction
3288             left = get(cave, x, y) != O_CONVEYOR_RIGHT;
3289             if (cave->conveyor_belts_direction_changed)
3290               left = !left;
3291             dir = left ? ccw_eighth : cw_eighth;
3292
3293             // CHECK IF IT CONVEYS THE ELEMENT ABOVE IT
3294             // if gravity is normal, and the conveyor belt has something
3295             // ABOVE which can be moved
3296             // OR
3297             // the gravity is up, so anything that should float now goes
3298             // DOWN and touches the conveyor
3299             if ((cave->gravity == GD_MV_DOWN &&
3300                  moved_by_conveyor_top_dir(cave, x, y, GD_MV_UP)) ||
3301                 (cave->gravity == GD_MV_UP &&
3302                  moved_by_conveyor_bottom_dir(cave, x, y, GD_MV_UP)))
3303             {
3304               if (!is_scanned_dir(cave, x, y, GD_MV_UP) &&
3305                   is_space_dir(cave, x, y, dir[GD_MV_UP]))
3306               {
3307                 store_dir(cave, x, y, dir[GD_MV_UP], get_dir(cave, x, y, GD_MV_UP));    // move
3308                 store_dir(cave, x, y, GD_MV_UP, O_SPACE);    // and place a space.
3309               }
3310             }
3311
3312             // CHECK IF IT CONVEYS THE ELEMENT BELOW IT
3313             if ((cave->gravity == GD_MV_UP &&
3314                  moved_by_conveyor_top_dir(cave, x, y, GD_MV_DOWN)) ||
3315                 (cave->gravity == GD_MV_DOWN &&
3316                  moved_by_conveyor_bottom_dir(cave, x, y, GD_MV_DOWN)))
3317             {
3318               if (!is_scanned_dir(cave, x, y, GD_MV_DOWN) &&
3319                   is_space_dir(cave, x, y, dir[GD_MV_DOWN]))
3320               {
3321                 store_dir(cave, x, y, dir[GD_MV_DOWN], get_dir(cave, x, y, GD_MV_DOWN));    // move
3322                 store_dir(cave, x, y, GD_MV_DOWN, O_SPACE);    // and clear.
3323               }
3324             }
3325           }
3326           break;
3327
3328           // ============================================================================
3329           //    R O C K E T S
3330           // ============================================================================
3331
3332         case O_ROCKET_1:
3333           if (is_space_dir(cave, x, y, GD_MV_RIGHT))
3334             move(cave, x, y, GD_MV_RIGHT, O_ROCKET_1);
3335           else
3336             explode(cave, x, y);
3337           break;
3338
3339         case O_ROCKET_2:
3340           if (is_space_dir(cave, x, y, GD_MV_UP))
3341             move(cave, x, y, GD_MV_UP, O_ROCKET_2);
3342           else
3343             explode(cave, x, y);
3344           break;
3345
3346         case O_ROCKET_3:
3347           if (is_space_dir(cave, x, y, GD_MV_LEFT))
3348             move(cave, x, y, GD_MV_LEFT, O_ROCKET_3);
3349           else
3350             explode(cave, x, y);
3351           break;
3352
3353         case O_ROCKET_4:
3354           if (is_space_dir(cave, x, y, GD_MV_DOWN))
3355             move(cave, x, y, GD_MV_DOWN, O_ROCKET_4);
3356           else
3357             explode(cave, x, y);
3358           break;
3359
3360           // ============================================================================
3361           //    S I M P L E   C H A N G I N G;   E X P L O S I O N S
3362           // ============================================================================
3363
3364         case O_EXPLODE_5:
3365           store(cave, x, y, cave->explosion_effect);
3366           break;
3367
3368         case O_NUT_EXPL_4:
3369           store(cave, x, y, O_DIAMOND);
3370           break;
3371
3372         case O_PRE_DIA_5:
3373           store(cave, x, y, cave->diamond_birth_effect);
3374           break;
3375
3376         case O_PRE_STONE_4:
3377           store(cave, x, y, O_STONE);
3378           break;
3379
3380         case O_NITRO_EXPL_4:
3381           store(cave, x, y, cave->nitro_explosion_effect);
3382           break;
3383
3384         case O_BOMB_EXPL_4:
3385           store(cave, x, y, cave->bomb_explosion_effect);
3386           break;
3387
3388         case O_AMOEBA_2_EXPL_4:
3389           store(cave, x, y, cave->amoeba_2_explosion_effect);
3390           break;
3391
3392         case O_GHOST_EXPL_4:
3393           {
3394             static GdElement ghost_explode[] =
3395             {
3396               O_SPACE, O_SPACE, O_DIRT, O_DIRT, O_CLOCK, O_CLOCK, O_PRE_OUTBOX,
3397               O_BOMB, O_BOMB, O_PLAYER, O_GHOST, O_BLADDER, O_DIAMOND, O_SWEET,
3398               O_WAITING_STONE, O_BITER_1
3399             };
3400
3401             store(cave, x, y, ghost_explode[gd_rand_int_range(cave->random, 0, ARRAY_SIZE(ghost_explode))]);
3402           }
3403           break;
3404
3405         case O_PRE_STEEL_4:
3406           store(cave, x, y, O_STEEL);
3407           break;
3408
3409         case O_PRE_CLOCK_4:
3410           store(cave, x, y, O_CLOCK);
3411           break;
3412
3413         case O_BOMB_TICK_7:
3414           explode(cave, x, y);
3415           break;
3416
3417         case O_TRAPPED_DIAMOND:
3418           if (cave->diamond_key_collected)
3419             store(cave, x, y, O_DIAMOND);
3420           break;
3421
3422         case O_PRE_OUTBOX:
3423           if (cave->gate_open) // if no more diamonds needed
3424             store(cave, x, y, O_OUTBOX);    // open outbox
3425           break;
3426
3427         case O_PRE_INVIS_OUTBOX:
3428           if (cave->gate_open)    // if no more diamonds needed
3429             store(cave, x, y, O_INVIS_OUTBOX);    // open outbox. invisible one :P
3430           break;
3431
3432         case O_INBOX:
3433           if (cave->hatched && !inbox_toggle)    // if it is time of birth
3434             store(cave, x, y, O_PRE_PL_1);
3435           inbox_toggle = !inbox_toggle;
3436           break;
3437
3438         case O_PRE_PL_3:
3439           store(cave, x, y, O_PLAYER);
3440           break;
3441
3442         case O_PRE_DIA_1:
3443         case O_PRE_DIA_2:
3444         case O_PRE_DIA_3:
3445         case O_PRE_DIA_4:
3446         case O_PRE_STONE_1:
3447         case O_PRE_STONE_2:
3448         case O_PRE_STONE_3:
3449         case O_BOMB_TICK_1:
3450         case O_BOMB_TICK_2:
3451         case O_BOMB_TICK_3:
3452         case O_BOMB_TICK_4:
3453         case O_BOMB_TICK_5:
3454         case O_BOMB_TICK_6:
3455         case O_PRE_STEEL_1:
3456         case O_PRE_STEEL_2:
3457         case O_PRE_STEEL_3:
3458         case O_BOMB_EXPL_1:
3459         case O_BOMB_EXPL_2:
3460         case O_BOMB_EXPL_3:
3461         case O_NUT_EXPL_1:
3462         case O_NUT_EXPL_2:
3463         case O_NUT_EXPL_3:
3464         case O_GHOST_EXPL_1:
3465         case O_GHOST_EXPL_2:
3466         case O_GHOST_EXPL_3:
3467         case O_EXPLODE_1:
3468         case O_EXPLODE_2:
3469         case O_EXPLODE_3:
3470         case O_EXPLODE_4:
3471         case O_PRE_PL_1:
3472         case O_PRE_PL_2:
3473         case O_PRE_CLOCK_1:
3474         case O_PRE_CLOCK_2:
3475         case O_PRE_CLOCK_3:
3476         case O_NITRO_EXPL_1:
3477         case O_NITRO_EXPL_2:
3478         case O_NITRO_EXPL_3:
3479         case O_AMOEBA_2_EXPL_1:
3480         case O_AMOEBA_2_EXPL_2:
3481         case O_AMOEBA_2_EXPL_3:
3482           // simply the next identifier
3483           next(cave, x, y);
3484           break;
3485
3486         case O_WATER_1:
3487         case O_WATER_2:
3488         case O_WATER_3:
3489         case O_WATER_4:
3490         case O_WATER_5:
3491         case O_WATER_6:
3492         case O_WATER_7:
3493         case O_WATER_8:
3494         case O_WATER_9:
3495         case O_WATER_10:
3496         case O_WATER_11:
3497         case O_WATER_12:
3498         case O_WATER_13:
3499         case O_WATER_14:
3500         case O_WATER_15:
3501           found_water = TRUE;    // for sound
3502           // simply the next identifier
3503           next(cave, x, y);
3504           break;
3505
3506         case O_BLADDER_SPENDER:
3507           if (is_space_dir(cave, x, y, opposite[grav_compat]))
3508           {
3509             store_dir(cave, x, y, opposite[grav_compat], O_BLADDER);
3510             store(cave, x, y, O_PRE_STEEL_1);
3511             play_sound_of_element(cave, O_BLADDER_SPENDER, x, y);
3512           }
3513           break;
3514
3515         default:
3516           // other inanimate elements that do nothing
3517           break;
3518       }
3519     }
3520   }
3521
3522
3523   // ============================================================================
3524   // POSTPROCESSING
3525   // ============================================================================
3526
3527   // another scan-like routine:
3528   // short explosions (for example, in bd1) started with explode_2.
3529   // internally we use explode_1; and change it to explode_2 if needed.
3530   if (cave->short_explosions)
3531   {
3532     for (y = 0; y < cave->h; y++)
3533     {
3534       for (x = 0; x < cave->w; x++)
3535       {
3536         if (is_first_stage_of_explosion(cave, x, y))
3537         {
3538           next(cave, x, y);    // select next frame of explosion
3539
3540           // forget scanned flag immediately
3541           store(cave, x, y, get(cave, x, y) & ~SCANNED);
3542         }
3543       }
3544     }
3545   }
3546
3547   // finally: forget "scanned" flags for objects.
3548   // also, check for time penalties.
3549   // these is something like an effect table, but we do not really use one.
3550   for (y = 0; y < cave->h; y++)
3551   {
3552     for (x = 0; x < cave->w; x++)
3553     {
3554       if (get(cave, x, y) & SCANNED)
3555         store(cave, x, y, get(cave, x, y) & ~SCANNED);
3556
3557       if (get(cave, x, y) == O_TIME_PENALTY)
3558       {
3559         store(cave, x, y, O_GRAVESTONE);
3560
3561         // there is time penalty for destroying the voodoo
3562         time_decrement_sec += cave->time_penalty;
3563       }
3564     }
3565   }
3566
3567   // this loop finds the coordinates of the player. needed for scrolling and chasing stone.
3568   // but we only do this, if a living player was found. if not yet, the setup
3569   // routine coordinates are used
3570   if (cave->player_state == GD_PL_LIVING)
3571   {
3572     if (cave->active_is_first_found)
3573     {
3574       // to be 1stb compatible, we do everything backwards.
3575       for (y = cave->h - 1; y >= 0; y--)
3576       {
3577         for (x = cave->w - 1; x >= 0; x--)
3578         {
3579           if (is_player(cave, x, y))
3580           {
3581             // here we remember the coordinates.
3582             cave->player_x = x;
3583             cave->player_y = y;
3584           }
3585         }
3586       }
3587     }
3588     else
3589     {
3590       // as in the original: look for the last one
3591       for (y = 0; y < cave->h; y++)
3592       {
3593         for (x = 0; x < cave->w; x++)
3594         {
3595           if (is_player(cave, x, y))
3596           {
3597             // here we remember the coordinates.
3598             cave->player_x = x;
3599             cave->player_y = y;
3600           }
3601         }
3602       }
3603     }
3604   }
3605
3606   // record coordinates of player for chasing stone
3607   for (i = 0; i < ARRAY_SIZE(cave->px) - 1; i++)
3608   {
3609     cave->px[i] = cave->px[i + 1];
3610     cave->py[i] = cave->py[i + 1];
3611   }
3612
3613   cave->px[ARRAY_SIZE(cave->px) - 1] = cave->player_x;
3614   cave->py[ARRAY_SIZE(cave->py) - 1] = cave->player_y;
3615
3616   // SCHEDULING
3617
3618   // update timing calculated by iterating and counting elements
3619   update_cave_speed(cave);
3620
3621   // cave 3 sounds. precedence is controlled by the sound_play function.
3622   // but we have to check amoeba&magic together as they had a different gritty sound when mixed
3623   if (found_water)
3624     gd_sound_play(cave, GD_S_WATER, O_WATER, -1, -1);
3625
3626   magic_sound = (cave->magic_wall_state == GD_MW_ACTIVE &&
3627                  cave->magic_wall_sound);
3628
3629   amoeba_sound = (cave->hatched && cave->amoeba_sound &&
3630                   ((amoeba_count > 0 && cave->amoeba_state == GD_AM_AWAKE) ||
3631                    (amoeba_2_count > 0 && cave->amoeba_2_state == GD_AM_AWAKE)));
3632
3633   if (amoeba_sound && magic_sound)
3634   {
3635     gd_sound_play(cave, GD_S_AMOEBA_MAGIC, O_AMOEBA, -1, -1);
3636   }
3637   else
3638   {
3639     if (amoeba_sound)
3640       gd_sound_play(cave, GD_S_AMOEBA, O_AMOEBA, -1, -1);
3641     else if (magic_sound)
3642       gd_sound_play(cave, GD_S_MAGIC_WALL, O_MAGIC_WALL, -1, -1);
3643   }
3644
3645   if (cave->hatched)
3646   {
3647     if ((amoeba_count   > 0 && cave->amoeba_state   == GD_AM_AWAKE) ||
3648         (amoeba_2_count > 0 && cave->amoeba_2_state == GD_AM_AWAKE))
3649       play_sound_of_element(cave, O_AMOEBA, -1, -1);
3650   }
3651
3652   // pneumatic hammer sound - overrides everything.
3653   if (cave->pneumatic_hammer_active_delay > 0)
3654     gd_sound_play(cave, GD_S_PNEUMATIC_HAMMER, O_PNEUMATIC_HAMMER, -1, -1);
3655
3656
3657   // ============================================================================
3658   // CAVE VARIABLES
3659   // ============================================================================
3660
3661   // PLAYER
3662
3663   // check if player is alive.
3664   if ((cave->player_state == GD_PL_LIVING && cave->player_seen_ago > 1) || cave->kill_player)
3665     cave->player_state = GD_PL_DIED;
3666
3667   // check if any voodoo exploded, and kill players the next scan if that happended.
3668   if (cave->voodoo_touched)
3669     cave->kill_player = TRUE;
3670
3671   // AMOEBA
3672
3673   // check flags after evaluating.
3674   if (cave->amoeba_state == GD_AM_AWAKE)
3675   {
3676     if (amoeba_count >= cave->amoeba_max_count)
3677       cave->amoeba_state = GD_AM_TOO_BIG;
3678     if (amoeba_found_enclosed)
3679       cave->amoeba_state = GD_AM_ENCLOSED;
3680     }
3681
3682   // amoeba can also be turned into diamond by magic wall
3683   if (cave->magic_wall_stops_amoeba && cave->magic_wall_state == GD_MW_ACTIVE)
3684     cave->amoeba_state = GD_AM_ENCLOSED;
3685
3686   // AMOEBA 2
3687   if (cave->amoeba_2_state == GD_AM_AWAKE)
3688   {
3689     // check flags after evaluating.
3690     if (amoeba_2_count >= cave->amoeba_2_max_count)
3691       cave->amoeba_2_state = GD_AM_TOO_BIG;
3692
3693     if (amoeba_2_found_enclosed)
3694       cave->amoeba_2_state = GD_AM_ENCLOSED;
3695   }
3696
3697   // amoeba 2 can also be turned into diamond by magic wall
3698   if (cave->magic_wall_stops_amoeba && cave->magic_wall_state == GD_MW_ACTIVE)
3699     cave->amoeba_2_state = GD_AM_ENCLOSED;
3700
3701   // now check times. ---------------------------
3702   // decrement time if a voodoo was killed.
3703   cave->time -= time_decrement_sec * cave->timing_factor;
3704   if (cave->time < 0)
3705     cave->time = 0;
3706
3707   // only decrement time when player is already born.
3708   if (cave->hatched)
3709   {
3710     int secondsbefore, secondsafter;
3711
3712     secondsbefore = cave->time / cave->timing_factor;
3713     cave->time -= cave->speed;
3714     if (cave->time <= 0)
3715       cave->time = 0;
3716
3717     secondsafter = cave->time / cave->timing_factor;
3718     if (cave->time / cave->timing_factor < 10)
3719       // if less than 10 seconds, no walking sound, but play explosion sound
3720       gd_sound_play(cave, GD_S_NONE, O_NONE, -1, -1);
3721
3722     if (secondsbefore != secondsafter)
3723       gd_cave_set_seconds_sound(cave);
3724   }
3725
3726   // a gravity switch was activated; seconds counting down
3727   if (cave->gravity_will_change > 0)
3728   {
3729     cave->gravity_will_change -= cave->speed;
3730     if (cave->gravity_will_change < 0)
3731       cave->gravity_will_change = 0;
3732
3733     if (cave->gravity_will_change == 0)
3734     {
3735       cave->gravity = cave->gravity_next_direction;
3736       gd_sound_play(cave, GD_S_GRAVITY_CHANGING, O_GRAVITY_SWITCH, -1, -1);    // takes precedence over amoeba and magic wall sound
3737     }
3738   }
3739
3740   // creatures direction automatically change
3741   if (cave->creatures_direction_will_change > 0)
3742   {
3743     cave->creatures_direction_will_change -= cave->speed;
3744     if (cave->creatures_direction_will_change < 0)
3745       cave->creatures_direction_will_change = 0;
3746
3747     if (cave->creatures_direction_will_change == 0)
3748     {
3749       gd_sound_play(cave, GD_S_SWITCH_CREATURES, O_CREATURE_SWITCH, -1, -1);
3750
3751       cave->creatures_backwards = !cave->creatures_backwards;
3752       cave->creatures_direction_will_change =
3753         cave->creatures_direction_auto_change_time * cave->timing_factor;
3754     }
3755   }
3756
3757   // magic wall; if active&wait or not wait for hatching
3758   if (cave->magic_wall_state == GD_MW_ACTIVE &&
3759       (cave->hatched || !cave->magic_timer_wait_for_hatching) &&
3760       !(cave->magic_wall_time == 0 && cave->magic_timer_zero_is_infinite))
3761   {
3762     cave->magic_wall_time -= cave->speed;
3763     if (cave->magic_wall_time < 0)
3764       cave->magic_wall_time = 0;
3765     if (cave->magic_wall_time == 0)
3766       cave->magic_wall_state = GD_MW_EXPIRED;
3767   }
3768
3769   // we may wait for hatching, when starting amoeba
3770   if (cave->amoeba_timer_started_immediately ||
3771       (cave->amoeba_state == GD_AM_AWAKE &&
3772        (cave->hatched || !cave->amoeba_timer_wait_for_hatching)))
3773   {
3774     cave->amoeba_time -= cave->speed;
3775     if (cave->amoeba_time < 0)
3776       cave->amoeba_time = 0;
3777     if (cave->amoeba_time == 0)
3778       cave->amoeba_growth_prob = cave->amoeba_fast_growth_prob;
3779   }
3780
3781   // we may wait for hatching, when starting amoeba
3782   if (cave->amoeba_timer_started_immediately ||
3783       (cave->amoeba_2_state == GD_AM_AWAKE &&
3784        (cave->hatched || !cave->amoeba_timer_wait_for_hatching)))
3785   {
3786     cave->amoeba_2_time -= cave->speed;
3787     if (cave->amoeba_2_time < 0)
3788       cave->amoeba_2_time = 0;
3789     if (cave->amoeba_2_time == 0)
3790       cave->amoeba_2_growth_prob = cave->amoeba_2_fast_growth_prob;
3791   }
3792
3793   // check for player hatching.
3794   start_signal = FALSE;
3795
3796   // if not the c64 scheduling, but the correct frametime is used,
3797   // hatching delay should always be decremented.
3798   // otherwise, the if (millisecs...) condition below will set this.
3799   if (cave->scheduling == GD_SCHEDULING_MILLISECONDS)
3800   {
3801     // NON-C64 scheduling
3802     if (cave->hatching_delay_frame > 0)
3803     {
3804       // for milliseconds-based, non-c64 schedulings, hatching delay means frames.
3805       cave->hatching_delay_frame--;
3806       if (cave->hatching_delay_frame == 0)
3807         start_signal = TRUE;
3808     }
3809   }
3810   else
3811   {
3812     // C64 scheduling
3813     if (cave->hatching_delay_time > 0)
3814     {
3815       // for c64 schedulings, hatching delay means milliseconds.
3816       cave->hatching_delay_time -= cave->speed;
3817       if (cave->hatching_delay_time <= 0)
3818       {
3819         cave->hatching_delay_time = 0;
3820         start_signal = TRUE;
3821       }
3822     }
3823   }
3824
3825   // if decremented hatching, and it became zero:
3826   if (start_signal)
3827   {
3828     // THIS IS THE CAVE START SIGNAL
3829
3830     // record that now the cave is in its normal state
3831     cave->hatched = TRUE;
3832
3833     // if diamonds needed is below zero, we count the available diamonds now.
3834     gd_cave_count_diamonds(cave);
3835
3836     // setup direction auto change
3837     if (cave->creatures_direction_auto_change_time)
3838     {
3839       cave->creatures_direction_will_change =
3840         cave->creatures_direction_auto_change_time * cave->timing_factor;
3841
3842       if (cave->creatures_direction_auto_change_on_start)
3843         cave->creatures_backwards = !cave->creatures_backwards;
3844     }
3845
3846     gd_sound_play(cave, GD_S_CRACKING, O_INBOX, -1, -1);
3847   }
3848
3849   // for biters
3850   if (cave->biters_wait_frame == 0)
3851     cave->biters_wait_frame = cave->biter_delay_frame;
3852   else
3853     cave->biters_wait_frame--;
3854
3855   // replicators delay
3856   if (cave->replicators_wait_frame == 0)
3857     cave->replicators_wait_frame = cave->replicator_delay_frame;
3858   else
3859     cave->replicators_wait_frame--;
3860
3861
3862   // ============================================================================
3863   // LAST THOUGTS
3864   // ============================================================================
3865
3866 #if 1
3867   // check if cave failed by timeout is done in main game engine
3868 #else
3869   // check if cave failed by timeout
3870   if (cave->player_state == GD_PL_LIVING && cave->time == 0)
3871   {
3872     gd_cave_clear_sounds(cave);
3873     cave->player_state = GD_PL_TIMEOUT;
3874     gd_sound_play(cave, GD_S_TIMEOUT_0, O_NONE, -1, -1);
3875   }
3876 #endif
3877
3878   // set these for drawing.
3879   cave->last_direction = player_move;
3880
3881   // here we remember last movements for animation. this is needed here,
3882   // as animation is in sync with the game, not the keyboard directly.
3883   // (for example, after exiting the cave, the player was "running" in the
3884   // original, till bonus points were counted for remaining time and so on.
3885   if (player_move == GD_MV_LEFT ||
3886       player_move == GD_MV_UP_LEFT ||
3887       player_move == GD_MV_DOWN_LEFT)
3888     cave->last_horizontal_direction = GD_MV_LEFT;
3889
3890   if (player_move == GD_MV_RIGHT ||
3891       player_move == GD_MV_UP_RIGHT ||
3892       player_move == GD_MV_DOWN_RIGHT)
3893     cave->last_horizontal_direction = GD_MV_RIGHT;
3894
3895   cave->frame++;  // XXX
3896 }
3897
3898 void set_initial_cave_speed(GdCave *cave)
3899 {
3900   int ymin, ymax;
3901   int x, y;
3902
3903   // set cave get function; to implement perfect or lineshifting borders
3904   if (cave->lineshift)
3905     cave->getp = getp_shift;
3906   else
3907     cave->getp = getp_perfect;
3908
3909   // check whether to scan the first and last line
3910   if (cave->border_scan_first_and_last)
3911   {
3912     ymin = 0;
3913     ymax = cave->h - 1;
3914   }
3915   else
3916   {
3917     ymin = 1;
3918     ymax = cave->h - 2;
3919   }
3920
3921   for (y = ymin; y <= ymax; y++)
3922   {
3923     for (x = 0; x < cave->w; x++)
3924     {
3925       // add the ckdelay correction value for every element seen.
3926       cave->ckdelay += gd_elements[get(cave, x, y)].ckdelay;
3927     }
3928   }
3929
3930   // update timing calculated by iterating and counting elements
3931   update_cave_speed(cave);
3932 }