fixed default graphics for growing or exploding BD engine elements
[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) && skip_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   // if diagonal movements not allowed,
1574   // horizontal movements have precedence. [BROADRIBB]
1575   if (!cave->diagonal_movements)
1576   {
1577     switch (player_move)
1578     {
1579       case GD_MV_UP_RIGHT:
1580       case GD_MV_DOWN_RIGHT:
1581         player_move = GD_MV_RIGHT;
1582         break;
1583
1584       case GD_MV_UP_LEFT:
1585       case GD_MV_DOWN_LEFT:
1586         player_move = GD_MV_LEFT;
1587         break;
1588
1589       default:
1590         // no correction needed
1591         break;
1592     }
1593   }
1594
1595   // set cave get function; to implement perfect or lineshifting borders
1596   if (cave->lineshift)
1597   {
1598     cave->getp = getp_shift;
1599     cave->getx = getx_shift;
1600     cave->gety = gety_shift;
1601   }
1602   else
1603   {
1604     cave->getp = getp_perfect;
1605     cave->getx = getx_perfect;
1606     cave->gety = gety_perfect;
1607   }
1608
1609   // increment this. if the scan routine comes across player, clears it (sets to zero).
1610   if (cave->player_seen_ago < 100)
1611     cave->player_seen_ago++;
1612
1613   if (cave->pneumatic_hammer_active_delay > 0)
1614     cave->pneumatic_hammer_active_delay--;
1615
1616   // inboxes and outboxes flash with the rhythm of the game, not the display.
1617   // also, a player can be born only from an open, not from a steel-wall-like inbox.
1618   cave->inbox_flash_toggle = !cave->inbox_flash_toggle;
1619   inbox_toggle = cave->inbox_flash_toggle;
1620
1621   if (cave->gate_open_flash > 0)
1622     cave->gate_open_flash--;
1623
1624   // score collected this frame
1625   cave->score = 0;
1626
1627   // to implement buggy bd1 amoeba+magic wall behaviour
1628   cave->convert_amoeba_this_frame = FALSE;
1629
1630   // suicide only kills the active player
1631   // player_x, player_y was set by the previous iterate routine, or the cave setup.
1632   // we must check if there is a player or not - he may have exploded or something like that
1633   if (suicide && cave->player_state == GD_PL_LIVING &&
1634       is_player(cave, cave->player_x, cave->player_y))
1635     store(cave, cave->player_x, cave->player_y, O_EXPLODE_1);
1636
1637   // check for walls reappearing
1638   if (cave->hammered_reappear)
1639   {
1640     for (y = 0; y < cave->h; y++)
1641     {
1642       for (x = 0; x < cave->w; x++)
1643       {
1644         // timer for the cell > 0?
1645         if (cave->hammered_reappear[y][x] > 0)
1646         {
1647           // decrease timer
1648           cave->hammered_reappear[y][x]--;
1649
1650           // check if it became zero
1651           if (cave->hammered_reappear[y][x] == 0)
1652           {
1653             store(cave, x, y, O_BRICK);
1654             gd_sound_play(cave, GD_S_WALL_REAPPEARING, O_BRICK, x, y);
1655           }
1656         }
1657       }
1658     }
1659   }
1660
1661   // variables to check during the scan
1662
1663   // will be set to false if any of the amoeba is found free.
1664   amoeba_found_enclosed = TRUE;
1665   amoeba_2_found_enclosed = TRUE;
1666   amoeba_count = 0;
1667   amoeba_2_count = 0;
1668   found_water = FALSE;
1669   cave->ckdelay = 0;
1670   time_decrement_sec = 0;
1671
1672   // check whether to scan the first and last line
1673   if (cave->border_scan_first_and_last)
1674   {
1675     ymin = 0;
1676     ymax = cave->h - 1;
1677   }
1678   else
1679   {
1680     ymin = 1;
1681     ymax = cave->h - 2;
1682   }
1683
1684   // the cave scan routine
1685   for (y = ymin; y <= ymax; y++)
1686   {
1687     for (x = 0; x < cave->w; x++)
1688     {
1689       // if we find a scanned element, change it to the normal one, and that's all.
1690       // this is required, for example for chasing stones, which have moved, always passing slime!
1691       if (get(cave, x, y) & SCANNED)
1692       {
1693         store(cave, x, y, get(cave, x, y) & ~SCANNED);
1694
1695         continue;
1696       }
1697
1698       // add the ckdelay correction value for every element seen.
1699       cave->ckdelay += gd_elements[get(cave, x, y)].ckdelay;
1700
1701       switch (get(cave, x, y))
1702       {
1703         // ============================================================================
1704         //    P L A Y E R S
1705         // ============================================================================
1706
1707         case O_PLAYER:
1708           if (cave->kill_player)
1709           {
1710             explode (cave, x, y);
1711             break;
1712           }
1713
1714           cave->player_seen_ago = 0;
1715           // bd4 intermission caves have many players. so if one of them has exited,
1716           // do not change the flag anymore. so this if () is needed
1717           if (cave->player_state != GD_PL_EXITED)
1718             cave->player_state = GD_PL_LIVING;
1719
1720           // check for pneumatic hammer things
1721           // 1) press fire, 2) have pneumatic hammer 4) space on left or right
1722           // for hammer 5) stand on something
1723           if (player_fire && cave->got_pneumatic_hammer &&
1724               is_space_dir(cave, x, y, player_move) &&
1725               !is_space_dir(cave, x, y, GD_MV_DOWN))
1726           {
1727             if (player_move == GD_MV_LEFT &&
1728                 can_be_hammered_dir(cave, x, y, GD_MV_DOWN_LEFT))
1729             {
1730               cave->pneumatic_hammer_active_delay = cave->pneumatic_hammer_frame;
1731               store_dir(cave, x, y, GD_MV_LEFT, O_PNEUMATIC_ACTIVE_LEFT);
1732               store(cave, x, y, O_PLAYER_PNEUMATIC_LEFT);
1733               break;    // finished.
1734             }
1735
1736             if (player_move == GD_MV_RIGHT &&
1737                 can_be_hammered_dir(cave, x, y, GD_MV_DOWN_RIGHT))
1738             {
1739               cave->pneumatic_hammer_active_delay = cave->pneumatic_hammer_frame;
1740               store_dir(cave, x, y, GD_MV_RIGHT, O_PNEUMATIC_ACTIVE_RIGHT);
1741               store(cave, x, y, O_PLAYER_PNEUMATIC_RIGHT);
1742               break;    // finished.
1743             }
1744           }
1745
1746           if (player_move != GD_MV_STILL)
1747           {
1748             // only do every check if he is not moving
1749             GdElement what = get_dir(cave, x, y, player_move);
1750             GdElement remains = what;
1751             boolean push;
1752
1753             // if we are 'eating' a teleporter, and the function returns true
1754             // (teleporting worked), break here
1755             if (what == O_TELEPORTER && do_teleporter(cave, x, y, player_move))
1756               break;
1757
1758             // try to push element; if successful, break
1759             push = do_push(cave, x, y, player_move, player_fire);
1760             if (push)
1761             {
1762               remains = O_SPACE;
1763             }
1764             else
1765             {
1766               switch (what)
1767               {
1768                 case O_BOMB:
1769                   // if its a bomb, remember he now has one.
1770                   // we do not change the "remains" and "what" variables,
1771                   // so that part of the code will be ineffective
1772                   gd_sound_play(cave, GD_S_BOMB_COLLECTING, what, x, y);
1773                   store_dir(cave, x, y, player_move, O_SPACE);
1774
1775                   if (player_fire)
1776                     store(cave, x, y, O_PLAYER_BOMB);
1777                   else
1778                     move(cave, x, y, player_move, O_PLAYER_BOMB);
1779                   break;
1780
1781                 case O_ROCKET_LAUNCHER:
1782                   // if its a rocket launcher, remember he now has one.
1783                   // we do not change the "remains" and "what" variables,
1784                   // so that part of the code will be ineffective
1785                   gd_sound_play(cave, GD_S_BOMB_COLLECTING, what, x, y);
1786                   store_dir(cave, x, y, player_move, O_SPACE);
1787
1788                   if (player_fire)
1789                     store(cave, x, y, O_PLAYER_ROCKET_LAUNCHER);
1790                   else
1791                     move(cave, x, y, player_move, O_PLAYER_ROCKET_LAUNCHER);
1792                   break;
1793
1794                 case O_POT:
1795                   // we do not change the "remains" and "what" variables,
1796                   // so that part of the code will be ineffective
1797                   if (!player_fire && !cave->gravity_switch_active &&
1798                       cave->skeletons_collected >= cave->skeletons_needed_for_pot)
1799                   {
1800                     cave->skeletons_collected -= cave->skeletons_needed_for_pot;
1801                     move(cave, x, y, player_move, O_PLAYER_STIRRING);
1802                     cave->gravity_disabled = TRUE;
1803                   }
1804                   break;
1805
1806                 case O_GRAVITY_SWITCH:
1807                   // (we cannot use player_get for this as it does not have player_move parameter)
1808                   // only allow changing direction if the new dir is not diagonal
1809                   if (cave->gravity_switch_active &&
1810                       (player_move == GD_MV_LEFT ||
1811                        player_move == GD_MV_RIGHT ||
1812                        player_move == GD_MV_UP ||
1813                        player_move == GD_MV_DOWN))
1814                   {
1815                     gd_sound_play(cave, GD_S_SWITCH_GRAVITY, what, x, y);
1816                     cave->gravity_will_change =
1817                       cave->gravity_change_time * cave->timing_factor;
1818                     cave->gravity_next_direction = player_move;
1819                     cave->gravity_switch_active = FALSE;
1820                   }
1821                   break;
1822
1823                 default:
1824                   // get element - process others.
1825                   // if cannot get, player_get_element will return the same
1826                   remains = player_get_element(cave, what, x, y);
1827                   break;
1828               }
1829             }
1830
1831             if (remains != what || remains == O_SPACE)
1832             {
1833               // if anything changed, apply the change.
1834
1835               // if snapping anything and we have snapping explosions set.
1836               // but these is not true for pushing.
1837               if (remains == O_SPACE && player_fire && !push)
1838                 remains = cave->snap_element;
1839
1840               if (remains != O_SPACE || player_fire)
1841                 // if any other element than space, player cannot move.
1842                 // also if pressing fire, will not move.
1843                 store_dir(cave, x, y, player_move, remains);
1844               else
1845                 // if space remains there, the player moves.
1846                 move(cave, x, y, player_move, O_PLAYER);
1847             }
1848           }
1849           break;
1850
1851         case O_PLAYER_BOMB:
1852           // much simpler; cannot steal stones
1853           if (cave->kill_player)
1854           {
1855             explode(cave, x, y);
1856             break;
1857           }
1858
1859           cave->player_seen_ago = 0;
1860           // bd4 intermission caves have many players. so if one of them has exited,
1861           // do not change the flag anymore. so this if () is needed
1862           if (cave->player_state != GD_PL_EXITED)
1863             cave->player_state = GD_PL_LIVING;
1864
1865           if (player_move != GD_MV_STILL)
1866           {
1867             // if the player does not move, nothing to do
1868             GdElement what = get_dir(cave, x, y, player_move);
1869             GdElement remains = what;
1870
1871             if (player_fire)
1872             {
1873               // placing a bomb into empty space or dirt
1874               if (is_space_dir(cave, x, y, player_move) ||
1875                   is_element_dir(cave, x, y, player_move, O_DIRT))
1876               {
1877                 store_dir(cave, x, y, player_move, O_BOMB_TICK_1);
1878
1879                 // placed bomb, he is normal player again
1880                 store(cave, x, y, O_PLAYER);
1881                 gd_sound_play(cave, GD_S_BOMB_PLACING, O_BOMB, x, y);
1882               }
1883               break;
1884             }
1885
1886             // pushing and collecting
1887             // if we are 'eating' a teleporter, and the function returns true
1888             // (teleporting worked), break here
1889             if (what == O_TELEPORTER && do_teleporter(cave, x, y, player_move))
1890               break;
1891
1892             // player fire is false...
1893             if (do_push(cave, x, y, player_move, FALSE))
1894             {
1895               remains = O_SPACE;
1896             }
1897             else
1898             {
1899               switch (what)
1900               {
1901                 case O_GRAVITY_SWITCH:
1902                   // (we cannot use player_get for this as it does not have
1903                   // player_move parameter)
1904                   // only allow changing direction if the new dir is not diagonal
1905                   if (cave->gravity_switch_active &&
1906                       (player_move == GD_MV_LEFT ||
1907                        player_move == GD_MV_RIGHT ||
1908                        player_move == GD_MV_UP ||
1909                        player_move == GD_MV_DOWN))
1910                   {
1911                     gd_sound_play(cave, GD_S_SWITCH_GRAVITY, what, x, y);
1912                     cave->gravity_will_change =
1913                       cave->gravity_change_time * cave->timing_factor;
1914                     cave->gravity_next_direction = player_move;
1915                     cave->gravity_switch_active = FALSE;
1916                   }
1917                   break;
1918
1919                 default:
1920                   // get element. if cannot get, player_get_element will return the same
1921                   remains = player_get_element (cave, what, x, y);
1922                   break;
1923               }
1924             }
1925
1926             // if element changed, OR there is space, move.
1927             if (remains != what || remains == O_SPACE)
1928             {
1929               // if anything changed, apply the change.
1930               move(cave, x, y, player_move, O_PLAYER_BOMB);
1931             }
1932           }
1933           break;
1934
1935         case O_PLAYER_ROCKET_LAUNCHER:
1936           // much simpler; cannot snap-push stones
1937           if (cave->kill_player)
1938           {
1939             explode(cave, x, y);
1940             break;
1941           }
1942
1943           cave->player_seen_ago = 0;
1944           // bd4 intermission caves have many players. so if one of them has exited,
1945           // do not change the flag anymore. so this if () is needed
1946           if (cave->player_state != GD_PL_EXITED)
1947             cave->player_state = GD_PL_LIVING;
1948
1949           // firing a rocket?
1950           if (player_move != GD_MV_STILL)
1951           {
1952             // if the player does not move, nothing to do
1953             GdElement what = get_dir(cave, x, y, player_move);
1954             GdElement remains = what;
1955
1956             // to fire a rocket, diagonal movement should not be allowed.
1957             // so either x or y must be zero
1958             if (player_fire)
1959             {
1960               // placing a rocket into empty space
1961               if (is_space_dir(cave, x, y, player_move))
1962               {
1963                 switch (player_move)
1964                 {
1965                   case GD_MV_RIGHT:
1966                     store_dir(cave, x, y, player_move, O_ROCKET_1);
1967                     if (!cave->infinite_rockets)
1968                       store(cave, x, y, O_PLAYER);
1969                     break;
1970
1971                   case GD_MV_UP:
1972                     store_dir(cave, x, y, player_move, O_ROCKET_2);
1973                     if (!cave->infinite_rockets)
1974                       store(cave, x, y, O_PLAYER);
1975                     break;
1976
1977                   case GD_MV_LEFT:
1978                     store_dir(cave, x, y, player_move, O_ROCKET_3);
1979                     if (!cave->infinite_rockets)
1980                       store(cave, x, y, O_PLAYER);
1981                     break;
1982
1983                   case GD_MV_DOWN:
1984                     store_dir(cave, x, y, player_move, O_ROCKET_4);
1985                     if (!cave->infinite_rockets)
1986                       store(cave, x, y, O_PLAYER);
1987                     break;
1988
1989                   default:
1990                     // cannot fire in other directions
1991                     break;
1992                 }
1993
1994                 gd_sound_play(cave, GD_S_BOMB_PLACING, O_BOMB, x, y);
1995               }
1996
1997               // a player with rocket launcher cannot snap elements, so stop here
1998               break;
1999             }
2000
2001             // pushing and collecting
2002             // if we are 'eating' a teleporter, and the function returns true
2003             // (teleporting worked), break here
2004             if (what == O_TELEPORTER && do_teleporter(cave, x, y, player_move))
2005               break;
2006
2007             // player fire is false...
2008             if (do_push(cave, x, y, player_move, FALSE))
2009             {
2010               remains = O_SPACE;
2011             }
2012             else
2013             {
2014               // get element. if cannot get, player_get_element will return the same
2015               remains = player_get_element(cave, what, x, y);
2016             }
2017
2018             // if something changed, OR there is space, move.
2019             if (remains != what || remains == O_SPACE)
2020             {
2021               // if anything changed, apply the change.
2022               move(cave, x, y, player_move, O_PLAYER_ROCKET_LAUNCHER);
2023             }
2024           }
2025           break;
2026
2027         case O_PLAYER_STIRRING:
2028           if (cave->kill_player)
2029           {
2030             explode(cave, x, y);
2031             break;
2032           }
2033
2034           // stirring sound, if no other walking sound or explosion
2035           gd_sound_play(cave, GD_S_STIRRING, O_PLAYER_STIRRING, x, y);
2036
2037           cave->player_seen_ago = 0;
2038           // bd4 intermission caves have many players. so if one of them has exited,
2039           // do not change the flag anymore. so this if () is needed
2040           if (cave->player_state != GD_PL_EXITED)
2041             cave->player_state = GD_PL_LIVING;
2042
2043           if (player_fire)
2044           {
2045             // player "exits" stirring the pot by pressing fire
2046             cave->gravity_disabled = FALSE;
2047             store(cave, x, y, O_PLAYER);
2048             cave->gravity_switch_active = TRUE;
2049           }
2050           break;
2051
2052           // player holding pneumatic hammer
2053         case O_PLAYER_PNEUMATIC_LEFT:
2054         case O_PLAYER_PNEUMATIC_RIGHT:
2055           // usual player stuff
2056           if (cave->kill_player)
2057           {
2058             explode(cave, x, y);
2059             break;
2060           }
2061
2062           cave->player_seen_ago = 0;
2063           if (cave->player_state != GD_PL_EXITED)
2064             cave->player_state = GD_PL_LIVING;
2065
2066           // if hammering time is up, becomes a normal player again.
2067           if (cave->pneumatic_hammer_active_delay == 0)
2068             store(cave, x, y, O_PLAYER);
2069           break;
2070
2071           // the active pneumatic hammer itself
2072         case O_PNEUMATIC_ACTIVE_RIGHT:
2073         case O_PNEUMATIC_ACTIVE_LEFT:
2074           if (cave->pneumatic_hammer_active_delay == 0)
2075           {
2076             GdElement new_elem;
2077
2078             // pneumatic hammer element disappears
2079             store(cave, x, y, O_SPACE);
2080
2081             // which is the new element which appears after that one is hammered?
2082             new_elem = gd_element_get_hammered(get_dir(cave, x, y, GD_MV_DOWN));
2083
2084             // if there is a new element, display it
2085             // O_NONE might be returned, for example if the element being
2086             // hammered explodes during hammering (by a nearby explosion)
2087             if (new_elem != O_NONE)
2088             {
2089               store_dir(cave, x, y, GD_MV_DOWN, new_elem);
2090
2091               // and if walls reappear, remember it in array
2092               if (cave->hammered_walls_reappear)
2093               {
2094                 int wall_y;
2095
2096                 wall_y = (y + 1) % cave->h;
2097                 cave->hammered_reappear[wall_y][x] = cave->hammered_wall_reappear_frame;
2098               }
2099             }
2100           }
2101           break;
2102
2103           // ============================================================================
2104           //    S T O N E S,   D I A M O N D S
2105           // ============================================================================
2106
2107         case O_STONE:           // standing stone
2108           do_start_fall(cave, x, y, cave->gravity, cave->stone_falling_effect);
2109           break;
2110
2111         case O_MEGA_STONE:      // standing mega_stone
2112           do_start_fall(cave, x, y, cave->gravity, O_MEGA_STONE_F);
2113           break;
2114
2115         case O_DIAMOND:         // standing diamond
2116           do_start_fall(cave, x, y, cave->gravity, cave->diamond_falling_effect);
2117           break;
2118
2119         case O_NUT:             // standing nut
2120           do_start_fall(cave, x, y, cave->gravity, O_NUT_F);
2121           break;
2122
2123         case O_DIRT_BALL:       // standing dirt ball
2124           do_start_fall(cave, x, y, cave->gravity, O_DIRT_BALL_F);
2125           break;
2126
2127         case O_DIRT_LOOSE:      // standing loose dirt
2128           do_start_fall(cave, x, y, cave->gravity, O_DIRT_LOOSE_F);
2129           break;
2130
2131         case O_FLYING_STONE:    // standing stone
2132           do_start_fall(cave, x, y, opposite[cave->gravity], O_FLYING_STONE_F);
2133           break;
2134
2135         case O_FLYING_DIAMOND:  // standing diamond
2136           do_start_fall(cave, x, y, opposite[cave->gravity], O_FLYING_DIAMOND_F);
2137           break;
2138
2139           // ============================================================================
2140           //    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
2141           // ============================================================================
2142
2143         case O_DIRT_BALL_F:     // falling dirt ball
2144           if (!cave->gravity_disabled)
2145             do_fall_roll_or_stop(cave, x, y, cave->gravity, O_DIRT_BALL);
2146           break;
2147
2148         case O_DIRT_LOOSE_F:    // falling loose dirt
2149           if (!cave->gravity_disabled)
2150             do_fall_roll_or_stop(cave, x, y, cave->gravity, O_DIRT_LOOSE);
2151           break;
2152
2153         case O_STONE_F:         // falling stone
2154           if (!cave->gravity_disabled)
2155           {
2156             if (do_fall_try_crush_voodoo(cave, x, y, cave->gravity))
2157               break;
2158
2159             if (do_fall_try_crack_nut(cave, x, y, cave->gravity, cave->stone_bouncing_effect))
2160               break;
2161
2162             if (do_fall_try_magic(cave, x, y, cave->gravity, cave->magic_stone_to))
2163               break;
2164
2165             if (do_fall_try_crush(cave, x, y, cave->gravity))
2166               break;
2167
2168             do_fall_roll_or_stop(cave, x, y, cave->gravity, cave->stone_bouncing_effect);
2169           }
2170           break;
2171
2172         case O_MEGA_STONE_F:    // falling mega
2173           if (!cave->gravity_disabled)
2174           {
2175             if (do_fall_try_crush_voodoo(cave, x, y, cave->gravity))
2176               break;
2177
2178             if (do_fall_try_crack_nut(cave, x, y, cave->gravity, O_MEGA_STONE))
2179               break;
2180
2181             if (do_fall_try_magic(cave, x, y, cave->gravity, cave->magic_mega_stone_to))
2182               break;
2183
2184             if (do_fall_try_crush(cave, x, y, cave->gravity))
2185               break;
2186
2187             do_fall_roll_or_stop(cave, x, y, cave->gravity, O_MEGA_STONE);
2188           }
2189           break;
2190
2191         case O_DIAMOND_F:       // falling diamond
2192           if (!cave->gravity_disabled)
2193           {
2194             if (do_fall_try_eat_voodoo(cave, x, y, cave->gravity))
2195               break;
2196
2197             if (do_fall_try_magic(cave, x, y, cave->gravity, cave->magic_diamond_to))
2198               break;
2199
2200             if (do_fall_try_crush(cave, x, y, cave->gravity))
2201               break;
2202
2203             do_fall_roll_or_stop(cave, x, y, cave->gravity, cave->diamond_bouncing_effect);
2204           }
2205           break;
2206
2207         case O_NUT_F:           // falling nut
2208           if (!cave->gravity_disabled)
2209           {
2210             if (do_fall_try_magic(cave, x, y, cave->gravity, cave->magic_nut_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, O_NUT);
2217           }
2218           break;
2219
2220         case O_FLYING_STONE_F:  // falling stone
2221           if (!cave->gravity_disabled)
2222           {
2223             GdDirection fall_dir = opposite[cave->gravity];
2224
2225             if (do_fall_try_crush_voodoo(cave, x, y, fall_dir))
2226               break;
2227
2228             if (do_fall_try_crack_nut(cave, x, y, fall_dir, O_FLYING_STONE))
2229               break;
2230
2231             if (do_fall_try_magic(cave, x, y, fall_dir, cave->magic_flying_stone_to))
2232               break;
2233
2234             if (do_fall_try_crush(cave, x, y, fall_dir))
2235               break;
2236
2237             do_fall_roll_or_stop(cave, x, y, fall_dir, O_FLYING_STONE);
2238           }
2239           break;
2240
2241         case O_FLYING_DIAMOND_F:    // falling diamond
2242           if (!cave->gravity_disabled)
2243           {
2244             GdDirection fall_dir = opposite[cave->gravity];
2245
2246             if (do_fall_try_eat_voodoo(cave, x, y, fall_dir))
2247               break;
2248
2249             if (do_fall_try_magic(cave, x, y, fall_dir, cave->magic_flying_diamond_to))
2250               break;
2251
2252             if (do_fall_try_crush(cave, x, y, fall_dir))
2253               break;
2254
2255             do_fall_roll_or_stop(cave, x, y, fall_dir, O_FLYING_DIAMOND);
2256           }
2257           break;
2258
2259           // ============================================================================
2260           //    N I T R O    P A C K
2261           // ============================================================================
2262
2263         case O_NITRO_PACK:      // standing nitro pack
2264           do_start_fall(cave, x, y, cave->gravity, O_NITRO_PACK_F);
2265           break;
2266
2267         case O_NITRO_PACK_F:    // falling nitro pack
2268           if (!cave->gravity_disabled)
2269           {
2270             if (is_space_dir(cave, x, y, cave->gravity))    // if space, falling further
2271               move(cave, x, y, cave->gravity, get(cave, x, y));
2272             else if (do_fall_try_magic(cave, x, y, cave->gravity, cave->magic_nitro_pack_to))
2273             {
2274               // try magic wall; if true, function did the work
2275             }
2276             else if (is_element_dir(cave, x, y, cave->gravity, O_DIRT))
2277             {
2278               // falling on a dirt, it does NOT explode - just stops at its place.
2279               play_sound_of_element(cave, O_NITRO_PACK, x, y);
2280               store(cave, x, y, O_NITRO_PACK);
2281             }
2282             else
2283               // falling on any other element it explodes
2284               explode(cave, x, y);
2285           }
2286           break;
2287
2288         case O_NITRO_PACK_EXPLODE:    // a triggered nitro pack
2289           explode(cave, x, y);
2290           break;
2291
2292           // ============================================================================
2293           //    C R E A T U R E S
2294           // ============================================================================
2295
2296         case O_COW_1:
2297         case O_COW_2:
2298         case O_COW_3:
2299         case O_COW_4:
2300           // if cannot move in any direction, becomes an enclosed cow
2301           if (!is_space_dir(cave, x, y, GD_MV_UP) && !is_space_dir(cave, x, y, GD_MV_DOWN) &&
2302               !is_space_dir(cave, x, y, GD_MV_LEFT) && !is_space_dir(cave, x, y, GD_MV_RIGHT))
2303             store(cave, x, y, O_COW_ENCLOSED_1);
2304           else
2305           {
2306             // THIS IS THE CREATURE MOVE thing copied.
2307             const GdDirection *creature_move;
2308             boolean ccw = rotates_ccw(cave, x, y);    // check if default is counterclockwise
2309             GdElement base;    // base element number (which is like O_***_1)
2310             int dir, dirn, dirp;    // direction
2311
2312             base = O_COW_1;
2313
2314             dir = get(cave, x, y)-base;    // facing where
2315             creature_move = cave->creatures_backwards ? creature_chdir : creature_dir;
2316
2317             // now change direction if backwards
2318             if (cave->creatures_backwards)
2319               ccw = !ccw;
2320
2321             if (ccw)
2322             {
2323               dirn = (dir + 3) & 3;    // fast turn
2324               dirp = (dir + 1) & 3;    // slow turn
2325             }
2326             else
2327             {
2328               dirn = (dir + 1) & 3;    // fast turn
2329               dirp = (dir + 3) & 3;    // slow turn
2330             }
2331
2332             if (is_space_dir(cave, x, y, creature_move[dirn]))
2333               move(cave, x, y, creature_move[dirn], base + dirn);    // turn and move to preferred dir
2334             else if (is_space_dir(cave, x, y, creature_move[dir]))
2335               move(cave, x, y, creature_move[dir], base + dir);    // go on
2336             else
2337               store(cave, x, y, base + dirp);    // turn in place if nothing else possible
2338           }
2339           break;
2340
2341           // enclosed cows wait some time before turning to a skeleton
2342         case O_COW_ENCLOSED_1:
2343         case O_COW_ENCLOSED_2:
2344         case O_COW_ENCLOSED_3:
2345         case O_COW_ENCLOSED_4:
2346         case O_COW_ENCLOSED_5:
2347         case O_COW_ENCLOSED_6:
2348           if (is_space_dir(cave, x, y, GD_MV_UP) ||
2349               is_space_dir(cave, x, y, GD_MV_LEFT) ||
2350               is_space_dir(cave, x, y, GD_MV_RIGHT) ||
2351               is_space_dir(cave, x, y, GD_MV_DOWN))
2352             store(cave, x, y, O_COW_1);
2353           else
2354             next(cave, x, y);
2355           break;
2356
2357         case O_COW_ENCLOSED_7:
2358           if (is_space_dir(cave, x, y, GD_MV_UP) ||
2359               is_space_dir(cave, x, y, GD_MV_LEFT) ||
2360               is_space_dir(cave, x, y, GD_MV_RIGHT) ||
2361               is_space_dir(cave, x, y, GD_MV_DOWN))
2362             store(cave, x, y, O_COW_1);
2363           else
2364             store(cave, x, y, O_SKELETON);
2365           break;
2366
2367         case O_FIREFLY_1:
2368         case O_FIREFLY_2:
2369         case O_FIREFLY_3:
2370         case O_FIREFLY_4:
2371         case O_ALT_FIREFLY_1:
2372         case O_ALT_FIREFLY_2:
2373         case O_ALT_FIREFLY_3:
2374         case O_ALT_FIREFLY_4:
2375         case O_BUTTER_1:
2376         case O_BUTTER_2:
2377         case O_BUTTER_3:
2378         case O_BUTTER_4:
2379         case O_ALT_BUTTER_1:
2380         case O_ALT_BUTTER_2:
2381         case O_ALT_BUTTER_3:
2382         case O_ALT_BUTTER_4:
2383         case O_STONEFLY_1:
2384         case O_STONEFLY_2:
2385         case O_STONEFLY_3:
2386         case O_STONEFLY_4:
2387           // check if touches a voodoo
2388           if (get_dir(cave, x, y, GD_MV_LEFT)  == O_VOODOO ||
2389               get_dir(cave, x, y, GD_MV_RIGHT) == O_VOODOO ||
2390               get_dir(cave, x, y, GD_MV_UP)    == O_VOODOO ||
2391               get_dir(cave, x, y, GD_MV_DOWN)  == O_VOODOO)
2392             cave->voodoo_touched = TRUE;
2393
2394           // check if touches something bad and should explode (includes voodoo by the flags)
2395           if (blows_up_flies_dir(cave, x, y, GD_MV_DOWN) ||
2396               blows_up_flies_dir(cave, x, y, GD_MV_UP) ||
2397               blows_up_flies_dir(cave, x, y, GD_MV_LEFT) ||
2398               blows_up_flies_dir(cave, x, y, GD_MV_RIGHT))
2399             explode (cave, x, y);
2400           // otherwise move
2401           else
2402           {
2403             const GdDirection *creature_move;
2404             boolean ccw = rotates_ccw(cave, x, y);    // check if default is counterclockwise
2405             GdElement base = -1;    // base element number (which is like O_***_1)
2406             int dir, dirn, dirp;    // direction
2407
2408             if (get(cave, x, y) >= O_FIREFLY_1 &&
2409                 get(cave, x, y) <= O_FIREFLY_4)
2410               base = O_FIREFLY_1;
2411             else if (get(cave, x, y) >= O_BUTTER_1 &&
2412                      get(cave, x, y) <= O_BUTTER_4)
2413               base = O_BUTTER_1;
2414             else if (get(cave, x, y) >= O_STONEFLY_1 &&
2415                      get(cave, x, y) <= O_STONEFLY_4)
2416               base = O_STONEFLY_1;
2417             else if (get(cave, x, y) >= O_ALT_FIREFLY_1 &&
2418                      get(cave, x, y) <= O_ALT_FIREFLY_4)
2419               base = O_ALT_FIREFLY_1;
2420             else if (get(cave, x, y) >= O_ALT_BUTTER_1 &&
2421                      get(cave, x, y) <= O_ALT_BUTTER_4)
2422               base = O_ALT_BUTTER_1;
2423
2424             dir = get(cave, x, y) - base;    // facing where
2425             creature_move = cave->creatures_backwards ? creature_chdir : creature_dir;
2426
2427             // now change direction if backwards
2428             if (cave->creatures_backwards)
2429               ccw = !ccw;
2430
2431             if (ccw)
2432             {
2433               dirn = (dir + 3) & 3;    // fast turn
2434               dirp = (dir + 1) & 3;    // slow turn
2435             }
2436             else
2437             {
2438               dirn = (dir + 1) & 3;    // fast turn
2439               dirp = (dir + 3) & 3;    // slow turn
2440             }
2441
2442             if (is_space_dir(cave, x, y, creature_move[dirn]))
2443               move(cave, x, y, creature_move[dirn], base + dirn);    // turn and move to preferred dir
2444             else if (is_space_dir(cave, x, y, creature_move[dir]))
2445               move(cave, x, y, creature_move[dir], base + dir);    // go on
2446             else
2447               store(cave, x, y, base + dirp);    // turn in place if nothing else possible
2448           }
2449           break;
2450
2451         case O_WAITING_STONE:
2452           if (is_space_dir(cave, x, y, grav_compat))
2453           {
2454             // beginning to fall
2455             // it wakes up.
2456             move(cave, x, y, grav_compat, O_CHASING_STONE);
2457           }
2458           else if (sloped_dir(cave, x, y, grav_compat, opposite[grav_compat]))
2459           {
2460             // rolling down a brick wall or a stone
2461             if (sloped_dir(cave, x, y, grav_compat, cw_fourth[grav_compat]) &&
2462                 is_space_dir(cave, x, y, cw_fourth[grav_compat]) &&
2463                 is_space_dir(cave, x, y, cw_eighth[grav_compat]))
2464             {
2465               // maybe rolling left - see case O_STONE to understand why we use cw_fourth here
2466               move(cave, x, y, cw_fourth[grav_compat], O_WAITING_STONE);
2467             }
2468             else if (sloped_dir(cave, x, y, grav_compat, ccw_fourth[grav_compat]) &&
2469                      is_space_dir(cave, x, y, ccw_fourth[grav_compat]) &&
2470                      is_space_dir(cave, x, y, ccw_eighth[grav_compat]))
2471             {
2472               // or maybe right
2473               move(cave, x, y, ccw_fourth[grav_compat], O_WAITING_STONE);
2474             }
2475           }
2476           break;
2477
2478         case O_CHASING_STONE:
2479           {
2480             int px = cave->px[0];
2481             int py = cave->py[0];
2482             boolean horizontal = gd_rand_boolean(cave->random);
2483             boolean dont_move = FALSE;
2484             int i = 3;
2485
2486             // try to move...
2487             while (1)
2488             {
2489               if (horizontal)
2490               {
2491                 // ------------------------------------------------------------
2492                 // check for a horizontal movement
2493                 // ------------------------------------------------------------
2494                 if (px == x)
2495                 {
2496                   // if coordinates are the same
2497                   i -= 1;
2498                   horizontal = !horizontal;
2499
2500                   if (i == 2)
2501                     continue;
2502                 }
2503                 else
2504                 {
2505                   if (px > x && is_space_dir(cave, x, y, GD_MV_RIGHT))
2506                   {
2507                     move(cave, x, y, GD_MV_RIGHT, O_CHASING_STONE);
2508                     dont_move = TRUE;
2509                     break;
2510                   }
2511                   else if (px < x && is_space_dir(cave, x, y, GD_MV_LEFT))
2512                   {
2513                     move(cave, x, y, GD_MV_LEFT, O_CHASING_STONE);
2514                     dont_move = TRUE;
2515                     break;
2516                   }
2517                   else
2518                   {
2519                     i -= 2;
2520                     if (i == 1)
2521                     {
2522                       horizontal = !horizontal;
2523                       continue;
2524                     }
2525                   }
2526                 }
2527               }
2528               else
2529               {
2530                 // ------------------------------------------------------------
2531                 // check for a vertical movement
2532                 // ------------------------------------------------------------
2533                 if (py == y)
2534                 {
2535                   // if coordinates are the same
2536                   i -= 1;
2537                   horizontal = !horizontal;
2538                   if (i == 2)
2539                     continue;
2540                 }
2541                 else
2542                 {
2543                   if (py > y && is_space_dir(cave, x, y, GD_MV_DOWN))
2544                   {
2545                     move(cave, x, y, GD_MV_DOWN, O_CHASING_STONE);
2546                     dont_move = TRUE;
2547                     break;
2548                   }
2549                   else if (py < y && is_space_dir(cave, x, y, GD_MV_UP))
2550                   {
2551                     move(cave, x, y, GD_MV_UP, O_CHASING_STONE);
2552                     dont_move = TRUE;
2553                     break;
2554                   }
2555                   else
2556                   {
2557                     i -= 2;
2558                     if (i == 1)
2559                     {
2560                       horizontal = !horizontal;
2561                       continue;
2562                     }
2563                   }
2564                 }
2565               }
2566
2567               if (i != 0)
2568                 dont_move = TRUE;
2569
2570               break;
2571             }
2572
2573             // if we should move in both directions, but can not move in any, stop.
2574             if (!dont_move)
2575             {
2576               if (horizontal)
2577               {
2578                 // check for horizontal
2579                 if (x >= px)
2580                 {
2581                   if (is_space_dir(cave, x, y, GD_MV_UP) &&
2582                       is_space_dir(cave, x, y, GD_MV_UP_LEFT))
2583                     move(cave, x, y, GD_MV_UP, O_CHASING_STONE);
2584                   else if (is_space_dir(cave, x, y, GD_MV_DOWN) &&
2585                            is_space_dir(cave, x, y, GD_MV_DOWN_LEFT))
2586                     move(cave, x, y, GD_MV_DOWN, O_CHASING_STONE);
2587                 }
2588                 else
2589                 {
2590                   if (is_space_dir(cave, x, y, GD_MV_UP) &&
2591                       is_space_dir(cave, x, y, GD_MV_UP_RIGHT))
2592                     move(cave, x, y, GD_MV_UP, O_CHASING_STONE);
2593                   else if (is_space_dir(cave, x, y, GD_MV_DOWN) &&
2594                            is_space_dir(cave, x, y, GD_MV_DOWN_RIGHT))
2595                     move(cave, x, y, GD_MV_DOWN, O_CHASING_STONE);
2596                 }
2597               }
2598               else
2599               {
2600                 // check for vertical
2601                 if (y >= py)
2602                 {
2603                   if (is_space_dir(cave, x, y, GD_MV_LEFT) &&
2604                       is_space_dir(cave, x, y, GD_MV_UP_LEFT))
2605                     move(cave, x, y, GD_MV_LEFT, O_CHASING_STONE);
2606                   else if (is_space_dir(cave, x, y, GD_MV_RIGHT) &&
2607                            is_space_dir(cave, x, y, GD_MV_UP_RIGHT))
2608                     move(cave, x, y, GD_MV_RIGHT, O_CHASING_STONE);
2609                 }
2610                 else
2611                 {
2612                   if (is_space_dir(cave, x, y, GD_MV_LEFT) &&
2613                       is_space_dir(cave, x, y, GD_MV_DOWN_LEFT))
2614                     move(cave, x, y, GD_MV_LEFT, O_CHASING_STONE);
2615                   else if (is_space_dir(cave, x, y, GD_MV_RIGHT) &&
2616                            is_space_dir(cave, x, y, GD_MV_DOWN_RIGHT))
2617                     move(cave, x, y, GD_MV_RIGHT, O_CHASING_STONE);
2618                 }
2619               }
2620             }
2621           }
2622           break;
2623
2624         case O_REPLICATOR:
2625           if (cave->replicators_wait_frame == 0 &&
2626               cave->replicators_active &&
2627               !cave->gravity_disabled)
2628           {
2629             // only replicate, if space is under it.
2630             // do not replicate players!
2631             // also obeys gravity settings.
2632             // only replicate element if it is not a scanned one
2633             // do not replicate space... that condition looks like it
2634             // makes no sense, but otherwise it generates SCANNED spaces,
2635             // which cannot be "collected" by the player, so he cannot run
2636             // under a replicator
2637             if (is_space_dir(cave, x, y, cave->gravity) &&
2638                 !is_player_dir(cave, x, y, opposite[cave->gravity]) &&
2639                 !is_space_dir(cave, x, y, opposite[cave->gravity]))
2640             {
2641               store_dir(cave, x, y, cave->gravity, get_dir(cave, x, y, opposite[cave->gravity]));
2642               gd_sound_play(cave, GD_S_REPLICATOR, O_REPLICATOR, x, y);
2643             }
2644           }
2645           break;
2646
2647         case O_BITER_1:
2648         case O_BITER_2:
2649         case O_BITER_3:
2650         case O_BITER_4:
2651           if (cave->biters_wait_frame == 0)
2652           {
2653             static GdDirection biter_move[] =
2654             {
2655               GD_MV_UP,
2656               GD_MV_RIGHT,
2657               GD_MV_DOWN,
2658               GD_MV_LEFT
2659             };
2660
2661             // direction, last two bits 0..3
2662             int dir = get(cave, x, y) - O_BITER_1;
2663             int dirn = (dir + 3) & 3;
2664             int dirp = (dir + 1) & 3;
2665             int i;
2666             GdElement made_sound_of = O_NONE;
2667
2668             for (i = 0; i < ARRAY_SIZE (biter_try); i++)
2669             {
2670               if (is_element_dir(cave, x, y, biter_move[dir], biter_try[i]))
2671               {
2672                 move(cave, x, y, biter_move[dir], O_BITER_1 + dir);
2673                 if (biter_try[i] != O_SPACE)
2674                   made_sound_of = O_BITER_1;    // sound of a biter eating
2675                 break;
2676               }
2677               else if (is_element_dir(cave, x, y, biter_move[dirn], biter_try[i]))
2678               {
2679                 move(cave, x, y, biter_move[dirn], O_BITER_1 + dirn);
2680                 if (biter_try[i] != O_SPACE)
2681                   made_sound_of = O_BITER_1;    // sound of a biter eating
2682                 break;
2683               }
2684               else if (is_element_dir(cave, x, y, biter_move[dirp], biter_try[i]))
2685               {
2686                 move(cave, x, y, biter_move[dirp], O_BITER_1 + dirp);
2687                 if (biter_try[i] != O_SPACE)
2688                   made_sound_of = O_BITER_1;    // sound of a biter eating
2689                 break;
2690               }
2691             }
2692
2693             if (i == ARRAY_SIZE(biter_try))
2694               // i = number of elements in array: could not move, so just turn
2695               store(cave, x, y, O_BITER_1 + dirp);
2696             else if (biter_try[i] == O_STONE)
2697             {
2698               // if there was a stone there, where we moved...
2699               // do not eat stones, just throw them back
2700               store(cave, x, y, O_STONE);
2701               made_sound_of = O_STONE;
2702             }
2703
2704             // if biter did move, we had sound. play it.
2705             if (made_sound_of != O_NONE)
2706               play_sound_of_element(cave, made_sound_of, x, y);
2707           }
2708           break;
2709
2710         case O_DRAGONFLY_1:
2711         case O_DRAGONFLY_2:
2712         case O_DRAGONFLY_3:
2713         case O_DRAGONFLY_4:
2714           // check if touches a voodoo
2715           if (get_dir(cave, x, y, GD_MV_LEFT)  == O_VOODOO ||
2716               get_dir(cave, x, y, GD_MV_RIGHT) == O_VOODOO ||
2717               get_dir(cave, x, y, GD_MV_UP)    == O_VOODOO ||
2718               get_dir(cave, x, y, GD_MV_DOWN)  == O_VOODOO)
2719             cave->voodoo_touched = TRUE;
2720
2721           // check if touches something bad and should explode (includes voodoo by the flags)
2722           if (blows_up_flies_dir(cave, x, y, GD_MV_DOWN) ||
2723               blows_up_flies_dir(cave, x, y, GD_MV_UP) ||
2724               blows_up_flies_dir(cave, x, y, GD_MV_LEFT) ||
2725               blows_up_flies_dir(cave, x, y, GD_MV_RIGHT))
2726             explode (cave, x, y);
2727           // otherwise move
2728           else
2729           {
2730             const GdDirection *creature_move;
2731             boolean ccw = rotates_ccw(cave, x, y);    // check if default is counterclockwise
2732             GdElement base = O_DRAGONFLY_1;    // base element number (which is like O_***_1)
2733             int dir, dirn;    // direction
2734
2735             dir = get(cave, x, y)-base;    // facing where
2736             creature_move = cave->creatures_backwards ? creature_chdir : creature_dir;
2737
2738             // now change direction if backwards
2739             if (cave->creatures_backwards)
2740               ccw = !ccw;
2741
2742             if (ccw)
2743               dirn = (dir + 3) & 3;    // fast turn
2744             else
2745               dirn = (dir + 1) & 3;    // fast turn
2746
2747             // if can move forward, does so.
2748             if (is_space_dir(cave, x, y, creature_move[dir]))
2749               move(cave, x, y, creature_move[dir], base + dir);
2750             else
2751               // otherwise turns 90 degrees in place.
2752               store(cave, x, y, base + dirn);
2753           }
2754           break;
2755
2756         case O_BLADDER:
2757           store(cave, x, y, O_BLADDER_1);
2758           break;
2759
2760         case O_BLADDER_1:
2761         case O_BLADDER_2:
2762         case O_BLADDER_3:
2763         case O_BLADDER_4:
2764         case O_BLADDER_5:
2765         case O_BLADDER_6:
2766         case O_BLADDER_7:
2767         case O_BLADDER_8:
2768           // bladder with any delay state: try to convert to clock.
2769           if (is_element_dir(cave, x, y, opposite[grav_compat], cave->bladder_converts_by) ||
2770               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))
2771           {
2772             // if touches the specified element, let it be a clock
2773             store(cave, x, y, O_PRE_CLOCK_1);
2774
2775             // plays the bladder convert sound
2776             play_sound_of_element(cave, O_PRE_CLOCK_1, x, y);
2777           }
2778           else
2779           {
2780             // is space over the bladder?
2781             if (is_space_dir(cave, x, y, opposite[grav_compat]))
2782             {
2783               if (get(cave, x, y) == O_BLADDER_8)
2784               {
2785                 // if it is a bladder 8, really move up
2786                 move(cave, x, y, opposite[grav_compat], O_BLADDER_1);
2787                 play_sound_of_element(cave, O_BLADDER, x, y);
2788               }
2789               else
2790                 // if smaller delay, just increase delay.
2791                 next(cave, x, y);
2792             }
2793             else
2794               // if not space, is something sloped over the bladder?
2795               if (sloped_for_bladder_dir(cave, x, y, opposite[grav_compat]) &&
2796                   sloped_dir(cave, x, y, opposite[grav_compat], opposite[grav_compat]))
2797               {
2798                 if (sloped_dir(cave, x, y, opposite[grav_compat], ccw_fourth[opposite[grav_compat]]) &&
2799                     is_space_dir(cave, x, y, ccw_fourth[opposite[grav_compat]]) &&
2800                     is_space_dir(cave, x, y, ccw_eighth[opposite[grav_compat]]))
2801                 {
2802                   // rolling up, to left
2803                   if (get(cave, x, y) == O_BLADDER_8)
2804                   {
2805                     // if it is a bladder 8, really roll
2806                     move(cave, x, y, ccw_fourth[opposite[grav_compat]], O_BLADDER_8);
2807                     play_sound_of_element(cave, O_BLADDER, x, y);
2808                   }
2809                   else
2810                     // if smaller delay, just increase delay.
2811                     next(cave, x, y);
2812                 }
2813                 else if (sloped_dir(cave, x, y, opposite[grav_compat], cw_fourth[opposite[grav_compat]]) &&
2814                          is_space_dir(cave, x, y, cw_fourth[opposite[grav_compat]]) &&
2815                          is_space_dir(cave, x, y, cw_eighth[opposite[grav_compat]]))
2816                 {
2817                   // rolling up, to left
2818                   if (get(cave, x, y) == O_BLADDER_8)
2819                   {
2820                     // if it is a bladder 8, really roll
2821                     move(cave, x, y, cw_fourth[opposite[grav_compat]], O_BLADDER_8);
2822                     play_sound_of_element(cave, O_BLADDER, x, y);
2823                   }
2824                   else
2825                     // if smaller delay, just increase delay.
2826                     next(cave, x, y);
2827                 }
2828               }
2829
2830             // no space, no sloped thing over it - store bladder 1 and that is for now.
2831               else
2832                 store(cave, x, y, O_BLADDER_1);
2833           }
2834           break;
2835
2836         case O_GHOST:
2837           if (blows_up_flies_dir(cave, x, y, GD_MV_DOWN) ||
2838               blows_up_flies_dir(cave, x, y, GD_MV_UP) ||
2839               blows_up_flies_dir(cave, x, y, GD_MV_LEFT) ||
2840               blows_up_flies_dir(cave, x, y, GD_MV_RIGHT))
2841             explode (cave, x, y);
2842           else
2843           {
2844             int i;
2845
2846             // the ghost is given four possibilities to move.
2847             for (i = 0; i < 4; i++)
2848             {
2849               static GdDirection dirs[] =
2850               {
2851                 GD_MV_UP,
2852                 GD_MV_DOWN,
2853                 GD_MV_LEFT,
2854                 GD_MV_RIGHT
2855               };
2856               GdDirection random_dir;
2857
2858               random_dir = dirs[gd_rand_int_range(cave->random, 0, ARRAY_SIZE(dirs))];
2859               if (is_space_dir(cave, x, y, random_dir))
2860               {
2861                 move(cave, x, y, random_dir, O_GHOST);
2862                 break;    // ghost did move -> exit loop
2863               }
2864             }
2865           }
2866           break;
2867
2868           // ============================================================================
2869           //    A C T I V E    E L E M E N T S
2870           // ============================================================================
2871
2872         case O_AMOEBA:
2873           // emulating BD1 amoeba+magic wall bug
2874           if (cave->convert_amoeba_this_frame && amoeba_found_enclosed)
2875           {
2876             store(cave, x, y, cave->amoeba_enclosed_effect);
2877             break;
2878           }
2879
2880           amoeba_count++;
2881           switch (cave->amoeba_state)
2882           {
2883             case GD_AM_TOO_BIG:
2884               store(cave, x, y, cave->amoeba_too_big_effect);
2885               break;
2886
2887             case GD_AM_ENCLOSED:
2888               store(cave, x, y, cave->amoeba_enclosed_effect);
2889               break;
2890
2891             case GD_AM_SLEEPING:
2892             case GD_AM_AWAKE:
2893               // if no amoeba found during THIS SCAN yet, which was able to grow, check this one.
2894               if (amoeba_found_enclosed)
2895                 // if still found enclosed, check all four directions, if this one is able to grow.
2896                 if (amoeba_eats_dir(cave, x, y, GD_MV_UP) ||
2897                     amoeba_eats_dir(cave, x, y, GD_MV_DOWN) ||
2898                     amoeba_eats_dir(cave, x, y, GD_MV_LEFT) ||
2899                     amoeba_eats_dir(cave, x, y, GD_MV_RIGHT))
2900                 {
2901                   // not enclosed. this is a local (per scan) flag!
2902                   amoeba_found_enclosed = FALSE;
2903                   cave->amoeba_state = GD_AM_AWAKE;
2904                 }
2905
2906               // if alive, check in which dir to grow (or not)
2907               if (cave->amoeba_state == GD_AM_AWAKE)
2908               {
2909                 if (gd_rand_int_range(cave->random, 0, 1000000) < cave->amoeba_growth_prob)
2910                 {
2911                   switch (gd_rand_int_range(cave->random, 0, 4))
2912                   {
2913                     // decided to grow, choose a random direction.
2914                     case 0:    // let this be up. numbers indifferent.
2915                       if (amoeba_eats_dir(cave, x, y, GD_MV_UP))
2916                         store_dir(cave, x, y, GD_MV_UP, O_AMOEBA);
2917                       break;
2918
2919                     case 1:    // down
2920                       if (amoeba_eats_dir(cave, x, y, GD_MV_DOWN))
2921                         store_dir(cave, x, y, GD_MV_DOWN, O_AMOEBA);
2922                       break;
2923
2924                     case 2:    // left
2925                       if (amoeba_eats_dir(cave, x, y, GD_MV_LEFT))
2926                         store_dir(cave, x, y, GD_MV_LEFT, O_AMOEBA);
2927                       break;
2928
2929                     case 3:    // right
2930                       if (amoeba_eats_dir(cave, x, y, GD_MV_RIGHT))
2931                         store_dir(cave, x, y, GD_MV_RIGHT, O_AMOEBA);
2932                       break;
2933                   }
2934                 }
2935               }
2936               break;
2937
2938           }
2939           break;
2940
2941         case O_AMOEBA_2:
2942           amoeba_2_count++;
2943           // check if it is touching an amoeba, and explosion is enabled
2944           if (cave->amoeba_2_explodes_by_amoeba &&
2945               (is_element_dir(cave, x, y, GD_MV_DOWN, O_AMOEBA) ||
2946                is_element_dir(cave, x, y, GD_MV_UP, O_AMOEBA) ||
2947                is_element_dir(cave, x, y, GD_MV_LEFT, O_AMOEBA) ||
2948                is_element_dir(cave, x, y, GD_MV_RIGHT, O_AMOEBA)))
2949             explode (cave, x, y);
2950           else
2951             switch (cave->amoeba_2_state)
2952             {
2953               case GD_AM_TOO_BIG:
2954                 store(cave, x, y, cave->amoeba_2_too_big_effect);
2955                 break;
2956
2957               case GD_AM_ENCLOSED:
2958                 store(cave, x, y, cave->amoeba_2_enclosed_effect);
2959                 break;
2960
2961               case GD_AM_SLEEPING:
2962               case GD_AM_AWAKE:
2963                 // if no amoeba found during THIS SCAN yet, which was able to grow, check this one.
2964                 if (amoeba_2_found_enclosed)
2965                   if (amoeba_eats_dir(cave, x, y, GD_MV_UP) ||
2966                       amoeba_eats_dir(cave, x, y, GD_MV_DOWN) ||
2967                       amoeba_eats_dir(cave, x, y, GD_MV_LEFT) ||
2968                       amoeba_eats_dir(cave, x, y, GD_MV_RIGHT))
2969                   {
2970                     // not enclosed. this is a local (per scan) flag!
2971                     amoeba_2_found_enclosed = FALSE;
2972                     cave->amoeba_2_state = GD_AM_AWAKE;
2973                   }
2974
2975                 // if it is alive, decide if it attempts to grow
2976                 if (cave->amoeba_2_state == GD_AM_AWAKE)
2977                   if (gd_rand_int_range(cave->random, 0, 1000000) < cave->amoeba_2_growth_prob)
2978                   {
2979                     switch (gd_rand_int_range(cave->random, 0, 4))
2980                     {
2981                       // decided to grow, choose a random direction.
2982                       case 0:    // let this be up. numbers indifferent.
2983                         if (amoeba_eats_dir(cave, x, y, GD_MV_UP))
2984                           store_dir(cave, x, y, GD_MV_UP, O_AMOEBA_2);
2985                         break;
2986
2987                       case 1:    // down
2988                         if (amoeba_eats_dir(cave, x, y, GD_MV_DOWN))
2989                           store_dir(cave, x, y, GD_MV_DOWN, O_AMOEBA_2);
2990                         break;
2991
2992                       case 2:    // left
2993                         if (amoeba_eats_dir(cave, x, y, GD_MV_LEFT))
2994                           store_dir(cave, x, y, GD_MV_LEFT, O_AMOEBA_2);
2995                         break;
2996
2997                       case 3:    // right
2998                         if (amoeba_eats_dir(cave, x, y, GD_MV_RIGHT))
2999                           store_dir(cave, x, y, GD_MV_RIGHT, O_AMOEBA_2);
3000                         break;
3001                     }
3002                   }
3003                 break;
3004
3005             }
3006           break;
3007
3008         case O_ACID:
3009           // choose randomly, if it spreads
3010           if (gd_rand_int_range(cave->random, 0, 1000000) <= cave->acid_spread_ratio)
3011           {
3012             // the current one explodes
3013             store(cave, x, y, cave->acid_turns_to);
3014
3015             // and if neighbours are eaten, put acid there.
3016             if (is_element_dir(cave, x, y, GD_MV_UP, cave->acid_eats_this))
3017             {
3018               play_sound_of_element(cave, O_ACID, x, y);
3019               store_dir(cave, x, y, GD_MV_UP, O_ACID);
3020             }
3021
3022             if (is_element_dir(cave, x, y, GD_MV_DOWN, cave->acid_eats_this))
3023             {
3024               play_sound_of_element(cave, O_ACID, x, y);
3025               store_dir(cave, x, y, GD_MV_DOWN, O_ACID);
3026             }
3027
3028             if (is_element_dir(cave, x, y, GD_MV_LEFT, cave->acid_eats_this))
3029             {
3030               play_sound_of_element(cave, O_ACID, x, y);
3031               store_dir(cave, x, y, GD_MV_LEFT, O_ACID);
3032             }
3033
3034             if (is_element_dir(cave, x, y, GD_MV_RIGHT, cave->acid_eats_this))
3035             {
3036               play_sound_of_element(cave, O_ACID, x, y);
3037               store_dir(cave, x, y, GD_MV_RIGHT, O_ACID);
3038             }
3039           }
3040           break;
3041
3042         case O_WATER:
3043           found_water = TRUE;
3044           if (!cave->water_does_not_flow_down &&
3045               is_space_dir(cave, x, y, GD_MV_DOWN))
3046             // emulating the odd behaviour in crdr
3047             store_dir(cave, x, y, GD_MV_DOWN, O_WATER_1);
3048
3049           if (is_space_dir(cave, x, y, GD_MV_UP))
3050             store_dir(cave, x, y, GD_MV_UP, O_WATER_1);
3051
3052           if (is_space_dir(cave, x, y, GD_MV_LEFT))
3053             store_dir(cave, x, y, GD_MV_LEFT, O_WATER_1);
3054
3055           if (is_space_dir(cave, x, y, GD_MV_RIGHT))
3056             store_dir(cave, x, y, GD_MV_RIGHT, O_WATER_1);
3057           break;
3058
3059         case O_WATER_16:
3060           store(cave, x, y, O_WATER);
3061           break;
3062
3063         case O_H_EXPANDING_WALL:
3064         case O_V_EXPANDING_WALL:
3065         case O_H_EXPANDING_STEEL_WALL:
3066         case O_V_EXPANDING_STEEL_WALL:
3067           // checks first if direction is changed.
3068           if (((get(cave, x, y) == O_H_EXPANDING_WALL ||
3069                 get(cave, x, y) == O_H_EXPANDING_STEEL_WALL) &&
3070                !cave->expanding_wall_changed) ||
3071               ((get(cave, x, y) == O_V_EXPANDING_WALL ||
3072                 get(cave, x, y) == O_V_EXPANDING_STEEL_WALL) &&
3073                cave->expanding_wall_changed))
3074           {
3075             if (is_space_dir(cave, x, y, GD_MV_LEFT))
3076             {
3077               store_dir(cave, x, y, GD_MV_LEFT, get(cave, x, y));
3078               play_sound_of_element(cave, get(cave, x, y), x, y);
3079             }
3080
3081             if (is_space_dir(cave, x, y, GD_MV_RIGHT)) {
3082               store_dir(cave, x, y, GD_MV_RIGHT, get(cave, x, y));
3083               play_sound_of_element(cave, get(cave, x, y), x, y);
3084             }
3085           }
3086           else
3087           {
3088             if (is_space_dir(cave, x, y, GD_MV_UP)) {
3089               store_dir(cave, x, y, GD_MV_UP, get(cave, x, y));
3090               play_sound_of_element(cave, get(cave, x, y), x, y);
3091             }
3092
3093             if (is_space_dir(cave, x, y, GD_MV_DOWN)) {
3094               store_dir(cave, x, y, GD_MV_DOWN, get(cave, x, y));
3095               play_sound_of_element(cave, get(cave, x, y), x, y);
3096             }
3097           }
3098           break;
3099
3100         case O_EXPANDING_WALL:
3101         case O_EXPANDING_STEEL_WALL:
3102           // the wall which grows in all four directions.
3103           if (is_space_dir(cave, x, y, GD_MV_LEFT))
3104           {
3105             store_dir(cave, x, y, GD_MV_LEFT, get(cave, x, y));
3106             play_sound_of_element(cave, get(cave, x, y), x, y);
3107           }
3108
3109           if (is_space_dir(cave, x, y, GD_MV_RIGHT)) {
3110             store_dir(cave, x, y, GD_MV_RIGHT, get(cave, x, y));
3111             play_sound_of_element(cave, get(cave, x, y), x, y);
3112           }
3113
3114           if (is_space_dir(cave, x, y, GD_MV_UP)) {
3115             store_dir(cave, x, y, GD_MV_UP, get(cave, x, y));
3116             play_sound_of_element(cave, get(cave, x, y), x, y);
3117           }
3118
3119           if (is_space_dir(cave, x, y, GD_MV_DOWN)) {
3120             store_dir(cave, x, y, GD_MV_DOWN, get(cave, x, y));
3121             play_sound_of_element(cave, get(cave, x, y), x, y);
3122           }
3123           break;
3124
3125         case O_SLIME:
3126 #if 1
3127           ; // to make compilers happy ...
3128 #else
3129           Info("Step[%03d]", cave->frame); // XXX
3130 #endif
3131           int rrr = gd_cave_c64_random(cave);
3132 #if 1
3133 #else
3134           Info(".Rand[%03d].Perm[%03d].Result[%d]\n", rrr, cave->slime_permeability_c64,
3135                (rrr & cave->slime_permeability_c64) == 0);
3136 #endif
3137           /*
3138            * unpredictable: gd_rand_int
3139            * predictable: c64 predictable random generator.
3140            *    for predictable, a random number is generated,
3141            *    whether or not it is even possible that the stone will be able to pass.
3142            */
3143           if (cave->slime_predictable ? ((rrr /* XXX */ & cave->slime_permeability_c64) == 0) : gd_rand_int_range(cave->random, 0, 1000000) < cave->slime_permeability)
3144           {
3145             GdDirection grav = cave->gravity;
3146             GdDirection oppos = opposite[cave->gravity];
3147
3148             // space under the slime? elements may pass from top to bottom then.
3149             if (is_space_dir(cave, x, y, grav))
3150             {
3151               if (get_dir(cave, x, y, oppos) == cave->slime_eats_1)
3152               {
3153                 // output a falling xy under
3154                 store_dir(cave, x, y, grav, cave->slime_converts_1);
3155
3156                 store_dir(cave, x, y, oppos, O_SPACE);
3157                 play_sound_of_element(cave, O_SLIME, x, y);
3158               }
3159               else if (get_dir(cave, x, y, oppos) == cave->slime_eats_2)
3160               {
3161                 store_dir(cave, x, y, grav, cave->slime_converts_2);
3162                 store_dir(cave, x, y, oppos, O_SPACE);
3163                 play_sound_of_element(cave, O_SLIME, x, y);
3164               }
3165               else if (get_dir(cave, x, y, oppos) == cave->slime_eats_3)
3166               {
3167                 store_dir(cave, x, y, grav, cave->slime_converts_3);
3168                 store_dir(cave, x, y, oppos, O_SPACE);
3169                 play_sound_of_element(cave, O_SLIME, x, y);
3170               }
3171               else if (get_dir(cave, x, y, oppos) == O_WAITING_STONE)
3172               {
3173                 // waiting stones pass without awakening
3174                 store_dir(cave, x, y, grav, O_WAITING_STONE);
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) == O_CHASING_STONE)
3179               {
3180                 // chasing stones pass
3181                 store_dir(cave, x, y, grav, O_CHASING_STONE);
3182                 store_dir(cave, x, y, oppos, O_SPACE);
3183                 play_sound_of_element(cave, O_SLIME, x, y);
3184               }
3185             }
3186             else
3187             {
3188               // or space over the slime? elements may pass from bottom to up then.
3189               if (is_space_dir(cave, x, y, oppos))
3190               {
3191                 if (get_dir(cave, x, y, grav) == O_BLADDER)
3192                 {
3193                   // bladders move UP the slime
3194                   store_dir(cave, x, y, grav, O_SPACE);
3195                   store_dir(cave, x, y, oppos, O_BLADDER_1);
3196                   play_sound_of_element(cave, O_SLIME, x, y);
3197                 }
3198                 else if (get_dir(cave, x, y, grav) == O_FLYING_STONE)
3199                 {
3200                   store_dir(cave, x, y, grav, O_SPACE);
3201                   store_dir(cave, x, y, oppos, O_FLYING_STONE_F);
3202                   play_sound_of_element(cave, O_SLIME, x, y);
3203                 }
3204                 else if (get_dir(cave, x, y, grav) == O_FLYING_DIAMOND)
3205                 {
3206                   store_dir(cave, x, y, grav, O_SPACE);
3207                   store_dir(cave, x, y, oppos, O_FLYING_DIAMOND_F);
3208                   play_sound_of_element(cave, O_SLIME, x, y);
3209                 }
3210               }
3211             }
3212           }
3213           break;
3214
3215         case O_FALLING_WALL:
3216           if (is_space_dir(cave, x, y, grav_compat))
3217           {
3218             // try falling if space under.
3219             int yy;
3220
3221             for (yy = y + 1; yy < y + cave->h; yy++)
3222               // yy < y + cave->h is to check everything OVER the wall - since caves wrap around !!
3223               if (get(cave, x, yy) != O_SPACE)
3224                 // stop cycle when other than space
3225                 break;
3226
3227             // if scanning stopped by a player... start falling!
3228             if (get(cave, x, yy) == O_PLAYER ||
3229                 get(cave, x, yy) == O_PLAYER_GLUED ||
3230                 get(cave, x, yy) == O_PLAYER_BOMB)
3231             {
3232               move(cave, x, y, grav_compat, O_FALLING_WALL_F);
3233               // no sound when the falling wall starts falling!
3234             }
3235           }
3236           break;
3237
3238         case O_FALLING_WALL_F:
3239           switch (get_dir(cave, x, y, grav_compat))
3240           {
3241             case O_PLAYER:
3242             case O_PLAYER_GLUED:
3243             case O_PLAYER_BOMB:
3244               // if player under, it explodes - the falling wall, not the player!
3245               explode(cave, x, y);
3246               break;
3247
3248             case O_SPACE:
3249               // continue falling
3250               move(cave, x, y, grav_compat, O_FALLING_WALL_F);
3251               break;
3252
3253             default:
3254               // stop
3255               play_sound_of_element(cave, get(cave, x, y), x, y);
3256               store(cave, x, y, O_FALLING_WALL);
3257               break;
3258           }
3259           break;
3260
3261           // ============================================================================
3262           //    C O N V E Y O R    B E L T S
3263           // ============================================================================
3264
3265         case O_CONVEYOR_RIGHT:
3266         case O_CONVEYOR_LEFT:
3267           // only works if gravity is up or down!!!
3268           // first, check for gravity and running belts.
3269           if (!cave->gravity_disabled && cave->conveyor_belts_active)
3270           {
3271             const GdDirection *dir;
3272             boolean left;
3273
3274             // decide direction
3275             left = get(cave, x, y) != O_CONVEYOR_RIGHT;
3276             if (cave->conveyor_belts_direction_changed)
3277               left = !left;
3278             dir = left ? ccw_eighth : cw_eighth;
3279
3280             // CHECK IF IT CONVEYS THE ELEMENT ABOVE IT
3281             // if gravity is normal, and the conveyor belt has something
3282             // ABOVE which can be moved
3283             // OR
3284             // the gravity is up, so anything that should float now goes
3285             // DOWN and touches the conveyor
3286             if ((cave->gravity == GD_MV_DOWN &&
3287                  moved_by_conveyor_top_dir(cave, x, y, GD_MV_UP)) ||
3288                 (cave->gravity == GD_MV_UP &&
3289                  moved_by_conveyor_bottom_dir(cave, x, y, GD_MV_UP)))
3290             {
3291               if (!is_scanned_dir(cave, x, y, GD_MV_UP) &&
3292                   is_space_dir(cave, x, y, dir[GD_MV_UP]))
3293               {
3294                 store_dir(cave, x, y, dir[GD_MV_UP], get_dir(cave, x, y, GD_MV_UP));    // move
3295                 store_dir(cave, x, y, GD_MV_UP, O_SPACE);    // and place a space.
3296               }
3297             }
3298
3299             // CHECK IF IT CONVEYS THE ELEMENT BELOW IT
3300             if ((cave->gravity == GD_MV_UP &&
3301                  moved_by_conveyor_top_dir(cave, x, y, GD_MV_DOWN)) ||
3302                 (cave->gravity == GD_MV_DOWN &&
3303                  moved_by_conveyor_bottom_dir(cave, x, y, GD_MV_DOWN)))
3304             {
3305               if (!is_scanned_dir(cave, x, y, GD_MV_DOWN) &&
3306                   is_space_dir(cave, x, y, dir[GD_MV_DOWN]))
3307               {
3308                 store_dir(cave, x, y, dir[GD_MV_DOWN], get_dir(cave, x, y, GD_MV_DOWN));    // move
3309                 store_dir(cave, x, y, GD_MV_DOWN, O_SPACE);    // and clear.
3310               }
3311             }
3312           }
3313           break;
3314
3315           // ============================================================================
3316           //    R O C K E T S
3317           // ============================================================================
3318
3319         case O_ROCKET_1:
3320           if (is_space_dir(cave, x, y, GD_MV_RIGHT))
3321             move(cave, x, y, GD_MV_RIGHT, O_ROCKET_1);
3322           else
3323             explode(cave, x, y);
3324           break;
3325
3326         case O_ROCKET_2:
3327           if (is_space_dir(cave, x, y, GD_MV_UP))
3328             move(cave, x, y, GD_MV_UP, O_ROCKET_2);
3329           else
3330             explode(cave, x, y);
3331           break;
3332
3333         case O_ROCKET_3:
3334           if (is_space_dir(cave, x, y, GD_MV_LEFT))
3335             move(cave, x, y, GD_MV_LEFT, O_ROCKET_3);
3336           else
3337             explode(cave, x, y);
3338           break;
3339
3340         case O_ROCKET_4:
3341           if (is_space_dir(cave, x, y, GD_MV_DOWN))
3342             move(cave, x, y, GD_MV_DOWN, O_ROCKET_4);
3343           else
3344             explode(cave, x, y);
3345           break;
3346
3347           // ============================================================================
3348           //    S I M P L E   C H A N G I N G;   E X P L O S I O N S
3349           // ============================================================================
3350
3351         case O_EXPLODE_5:
3352           store(cave, x, y, cave->explosion_effect);
3353           break;
3354
3355         case O_NUT_EXPL_4:
3356           store(cave, x, y, O_DIAMOND);
3357           break;
3358
3359         case O_PRE_DIA_5:
3360           store(cave, x, y, cave->diamond_birth_effect);
3361           break;
3362
3363         case O_PRE_STONE_4:
3364           store(cave, x, y, O_STONE);
3365           break;
3366
3367         case O_NITRO_EXPL_4:
3368           store(cave, x, y, cave->nitro_explosion_effect);
3369           break;
3370
3371         case O_BOMB_EXPL_4:
3372           store(cave, x, y, cave->bomb_explosion_effect);
3373           break;
3374
3375         case O_AMOEBA_2_EXPL_4:
3376           store(cave, x, y, cave->amoeba_2_explosion_effect);
3377           break;
3378
3379         case O_GHOST_EXPL_4:
3380           {
3381             static GdElement ghost_explode[] =
3382             {
3383               O_SPACE, O_SPACE, O_DIRT, O_DIRT, O_CLOCK, O_CLOCK, O_PRE_OUTBOX,
3384               O_BOMB, O_BOMB, O_PLAYER, O_GHOST, O_BLADDER, O_DIAMOND, O_SWEET,
3385               O_WAITING_STONE, O_BITER_1
3386             };
3387
3388             store(cave, x, y, ghost_explode[gd_rand_int_range(cave->random, 0, ARRAY_SIZE(ghost_explode))]);
3389           }
3390           break;
3391
3392         case O_PRE_STEEL_4:
3393           store(cave, x, y, O_STEEL);
3394           break;
3395
3396         case O_PRE_CLOCK_4:
3397           store(cave, x, y, O_CLOCK);
3398           break;
3399
3400         case O_BOMB_TICK_7:
3401           explode(cave, x, y);
3402           break;
3403
3404         case O_TRAPPED_DIAMOND:
3405           if (cave->diamond_key_collected)
3406             store(cave, x, y, O_DIAMOND);
3407           break;
3408
3409         case O_PRE_OUTBOX:
3410           if (cave->gate_open) // if no more diamonds needed
3411             store(cave, x, y, O_OUTBOX);    // open outbox
3412           break;
3413
3414         case O_PRE_INVIS_OUTBOX:
3415           if (cave->gate_open)    // if no more diamonds needed
3416             store(cave, x, y, O_INVIS_OUTBOX);    // open outbox. invisible one :P
3417           break;
3418
3419         case O_INBOX:
3420           if (cave->hatched && !inbox_toggle)    // if it is time of birth
3421             store(cave, x, y, O_PRE_PL_1);
3422           inbox_toggle = !inbox_toggle;
3423           break;
3424
3425         case O_PRE_PL_3:
3426           store(cave, x, y, O_PLAYER);
3427           break;
3428
3429         case O_PRE_DIA_1:
3430         case O_PRE_DIA_2:
3431         case O_PRE_DIA_3:
3432         case O_PRE_DIA_4:
3433         case O_PRE_STONE_1:
3434         case O_PRE_STONE_2:
3435         case O_PRE_STONE_3:
3436         case O_BOMB_TICK_1:
3437         case O_BOMB_TICK_2:
3438         case O_BOMB_TICK_3:
3439         case O_BOMB_TICK_4:
3440         case O_BOMB_TICK_5:
3441         case O_BOMB_TICK_6:
3442         case O_PRE_STEEL_1:
3443         case O_PRE_STEEL_2:
3444         case O_PRE_STEEL_3:
3445         case O_BOMB_EXPL_1:
3446         case O_BOMB_EXPL_2:
3447         case O_BOMB_EXPL_3:
3448         case O_NUT_EXPL_1:
3449         case O_NUT_EXPL_2:
3450         case O_NUT_EXPL_3:
3451         case O_GHOST_EXPL_1:
3452         case O_GHOST_EXPL_2:
3453         case O_GHOST_EXPL_3:
3454         case O_EXPLODE_1:
3455         case O_EXPLODE_2:
3456         case O_EXPLODE_3:
3457         case O_EXPLODE_4:
3458         case O_PRE_PL_1:
3459         case O_PRE_PL_2:
3460         case O_PRE_CLOCK_1:
3461         case O_PRE_CLOCK_2:
3462         case O_PRE_CLOCK_3:
3463         case O_NITRO_EXPL_1:
3464         case O_NITRO_EXPL_2:
3465         case O_NITRO_EXPL_3:
3466         case O_AMOEBA_2_EXPL_1:
3467         case O_AMOEBA_2_EXPL_2:
3468         case O_AMOEBA_2_EXPL_3:
3469           // simply the next identifier
3470           next(cave, x, y);
3471           break;
3472
3473         case O_WATER_1:
3474         case O_WATER_2:
3475         case O_WATER_3:
3476         case O_WATER_4:
3477         case O_WATER_5:
3478         case O_WATER_6:
3479         case O_WATER_7:
3480         case O_WATER_8:
3481         case O_WATER_9:
3482         case O_WATER_10:
3483         case O_WATER_11:
3484         case O_WATER_12:
3485         case O_WATER_13:
3486         case O_WATER_14:
3487         case O_WATER_15:
3488           found_water = TRUE;    // for sound
3489           // simply the next identifier
3490           next(cave, x, y);
3491           break;
3492
3493         case O_BLADDER_SPENDER:
3494           if (is_space_dir(cave, x, y, opposite[grav_compat]))
3495           {
3496             store_dir(cave, x, y, opposite[grav_compat], O_BLADDER);
3497             store(cave, x, y, O_PRE_STEEL_1);
3498             play_sound_of_element(cave, O_BLADDER_SPENDER, x, y);
3499           }
3500           break;
3501
3502         default:
3503           // other inanimate elements that do nothing
3504           break;
3505       }
3506     }
3507   }
3508
3509
3510   // ============================================================================
3511   // POSTPROCESSING
3512   // ============================================================================
3513
3514   // another scan-like routine:
3515   // short explosions (for example, in bd1) started with explode_2.
3516   // internally we use explode_1; and change it to explode_2 if needed.
3517   if (cave->short_explosions)
3518   {
3519     for (y = 0; y < cave->h; y++)
3520     {
3521       for (x = 0; x < cave->w; x++)
3522       {
3523         if (is_first_stage_of_explosion(cave, x, y))
3524         {
3525           next(cave, x, y);    // select next frame of explosion
3526
3527           // forget scanned flag immediately
3528           store(cave, x, y, get(cave, x, y) & ~SCANNED);
3529         }
3530       }
3531     }
3532   }
3533
3534   // finally: forget "scanned" flags for objects.
3535   // also, check for time penalties.
3536   // these is something like an effect table, but we do not really use one.
3537   for (y = 0; y < cave->h; y++)
3538   {
3539     for (x = 0; x < cave->w; x++)
3540     {
3541       if (get(cave, x, y) & SCANNED)
3542         store(cave, x, y, get(cave, x, y) & ~SCANNED);
3543
3544       if (get(cave, x, y) == O_TIME_PENALTY)
3545       {
3546         store(cave, x, y, O_GRAVESTONE);
3547
3548         // there is time penalty for destroying the voodoo
3549         time_decrement_sec += cave->time_penalty;
3550       }
3551     }
3552   }
3553
3554   // this loop finds the coordinates of the player. needed for scrolling and chasing stone.
3555   // but we only do this, if a living player was found. if not yet, the setup
3556   // routine coordinates are used
3557   if (cave->player_state == GD_PL_LIVING)
3558   {
3559     if (cave->active_is_first_found)
3560     {
3561       // to be 1stb compatible, we do everything backwards.
3562       for (y = cave->h - 1; y >= 0; y--)
3563       {
3564         for (x = cave->w - 1; x >= 0; x--)
3565         {
3566           if (is_player(cave, x, y))
3567           {
3568             // here we remember the coordinates.
3569             cave->player_x = x;
3570             cave->player_y = y;
3571           }
3572         }
3573       }
3574     }
3575     else
3576     {
3577       // as in the original: look for the last one
3578       for (y = 0; y < cave->h; y++)
3579       {
3580         for (x = 0; x < cave->w; x++)
3581         {
3582           if (is_player(cave, x, y))
3583           {
3584             // here we remember the coordinates.
3585             cave->player_x = x;
3586             cave->player_y = y;
3587           }
3588         }
3589       }
3590     }
3591   }
3592
3593   // record coordinates of player for chasing stone
3594   for (i = 0; i < ARRAY_SIZE(cave->px) - 1; i++)
3595   {
3596     cave->px[i] = cave->px[i + 1];
3597     cave->py[i] = cave->py[i + 1];
3598   }
3599
3600   cave->px[ARRAY_SIZE(cave->px) - 1] = cave->player_x;
3601   cave->py[ARRAY_SIZE(cave->py) - 1] = cave->player_y;
3602
3603   // SCHEDULING
3604
3605   // update timing calculated by iterating and counting elements
3606   update_cave_speed(cave);
3607
3608   // cave 3 sounds. precedence is controlled by the sound_play function.
3609   // but we have to check amoeba&magic together as they had a different gritty sound when mixed
3610   if (found_water)
3611     gd_sound_play(cave, GD_S_WATER, O_WATER, -1, -1);
3612
3613   magic_sound = (cave->magic_wall_state == GD_MW_ACTIVE &&
3614                  cave->magic_wall_sound);
3615
3616   amoeba_sound = (cave->hatched && cave->amoeba_sound &&
3617                   ((amoeba_count > 0 && cave->amoeba_state == GD_AM_AWAKE) ||
3618                    (amoeba_2_count > 0 && cave->amoeba_2_state == GD_AM_AWAKE)));
3619
3620   if (amoeba_sound && magic_sound)
3621   {
3622     gd_sound_play(cave, GD_S_AMOEBA_MAGIC, O_AMOEBA, -1, -1);
3623   }
3624   else
3625   {
3626     if (amoeba_sound)
3627       gd_sound_play(cave, GD_S_AMOEBA, O_AMOEBA, -1, -1);
3628     else if (magic_sound)
3629       gd_sound_play(cave, GD_S_MAGIC_WALL, O_MAGIC_WALL, -1, -1);
3630   }
3631
3632   if (cave->hatched)
3633   {
3634     if ((amoeba_count   > 0 && cave->amoeba_state   == GD_AM_AWAKE) ||
3635         (amoeba_2_count > 0 && cave->amoeba_2_state == GD_AM_AWAKE))
3636       play_sound_of_element(cave, O_AMOEBA, x, y);
3637   }
3638
3639   // pneumatic hammer sound - overrides everything.
3640   if (cave->pneumatic_hammer_active_delay > 0)
3641     gd_sound_play(cave, GD_S_PNEUMATIC_HAMMER, O_PNEUMATIC_HAMMER, -1, -1);
3642
3643
3644   // ============================================================================
3645   // CAVE VARIABLES
3646   // ============================================================================
3647
3648   // PLAYER
3649
3650   // check if player is alive.
3651   if ((cave->player_state == GD_PL_LIVING && cave->player_seen_ago > 1) || cave->kill_player)
3652     cave->player_state = GD_PL_DIED;
3653
3654   // check if any voodoo exploded, and kill players the next scan if that happended.
3655   if (cave->voodoo_touched)
3656     cave->kill_player = TRUE;
3657
3658   // AMOEBA
3659
3660   // check flags after evaluating.
3661   if (cave->amoeba_state == GD_AM_AWAKE)
3662   {
3663     if (amoeba_count >= cave->amoeba_max_count)
3664       cave->amoeba_state = GD_AM_TOO_BIG;
3665     if (amoeba_found_enclosed)
3666       cave->amoeba_state = GD_AM_ENCLOSED;
3667     }
3668
3669   // amoeba can also be turned into diamond by magic wall
3670   if (cave->magic_wall_stops_amoeba && cave->magic_wall_state == GD_MW_ACTIVE)
3671     cave->amoeba_state = GD_AM_ENCLOSED;
3672
3673   // AMOEBA 2
3674   if (cave->amoeba_2_state == GD_AM_AWAKE)
3675   {
3676     // check flags after evaluating.
3677     if (amoeba_2_count >= cave->amoeba_2_max_count)
3678       cave->amoeba_2_state = GD_AM_TOO_BIG;
3679
3680     if (amoeba_2_found_enclosed)
3681       cave->amoeba_2_state = GD_AM_ENCLOSED;
3682   }
3683
3684   // amoeba 2 can also be turned into diamond by magic wall
3685   if (cave->magic_wall_stops_amoeba && cave->magic_wall_state == GD_MW_ACTIVE)
3686     cave->amoeba_2_state = GD_AM_ENCLOSED;
3687
3688   // now check times. ---------------------------
3689   // decrement time if a voodoo was killed.
3690   cave->time -= time_decrement_sec * cave->timing_factor;
3691   if (cave->time < 0)
3692     cave->time = 0;
3693
3694   // only decrement time when player is already born.
3695   if (cave->hatched)
3696   {
3697     int secondsbefore, secondsafter;
3698
3699     secondsbefore = cave->time / cave->timing_factor;
3700     cave->time -= cave->speed;
3701     if (cave->time <= 0)
3702       cave->time = 0;
3703
3704     secondsafter = cave->time / cave->timing_factor;
3705     if (cave->time / cave->timing_factor < 10)
3706       // if less than 10 seconds, no walking sound, but play explosion sound
3707       gd_sound_play(cave, GD_S_NONE, O_NONE, -1, -1);
3708
3709     if (secondsbefore != secondsafter)
3710       gd_cave_set_seconds_sound(cave);
3711   }
3712
3713   // a gravity switch was activated; seconds counting down
3714   if (cave->gravity_will_change > 0)
3715   {
3716     cave->gravity_will_change -= cave->speed;
3717     if (cave->gravity_will_change < 0)
3718       cave->gravity_will_change = 0;
3719
3720     if (cave->gravity_will_change == 0)
3721     {
3722       cave->gravity = cave->gravity_next_direction;
3723       gd_sound_play(cave, GD_S_GRAVITY_CHANGING, O_GRAVITY_SWITCH, -1, -1);    // takes precedence over amoeba and magic wall sound
3724     }
3725   }
3726
3727   // creatures direction automatically change
3728   if (cave->creatures_direction_will_change > 0)
3729   {
3730     cave->creatures_direction_will_change -= cave->speed;
3731     if (cave->creatures_direction_will_change < 0)
3732       cave->creatures_direction_will_change = 0;
3733
3734     if (cave->creatures_direction_will_change == 0)
3735     {
3736       gd_sound_play(cave, GD_S_SWITCH_CREATURES, O_CREATURE_SWITCH, -1, -1);
3737
3738       cave->creatures_backwards = !cave->creatures_backwards;
3739       cave->creatures_direction_will_change =
3740         cave->creatures_direction_auto_change_time * cave->timing_factor;
3741     }
3742   }
3743
3744   // magic wall; if active&wait or not wait for hatching
3745   if (cave->magic_wall_state == GD_MW_ACTIVE &&
3746       (cave->hatched || !cave->magic_timer_wait_for_hatching) &&
3747       !(cave->magic_wall_time == 0 && cave->magic_timer_zero_is_infinite))
3748   {
3749     cave->magic_wall_time -= cave->speed;
3750     if (cave->magic_wall_time < 0)
3751       cave->magic_wall_time = 0;
3752     if (cave->magic_wall_time == 0)
3753       cave->magic_wall_state = GD_MW_EXPIRED;
3754   }
3755
3756   // we may wait for hatching, when starting amoeba
3757   if (cave->amoeba_timer_started_immediately ||
3758       (cave->amoeba_state == GD_AM_AWAKE &&
3759        (cave->hatched || !cave->amoeba_timer_wait_for_hatching)))
3760   {
3761     cave->amoeba_time -= cave->speed;
3762     if (cave->amoeba_time < 0)
3763       cave->amoeba_time = 0;
3764     if (cave->amoeba_time == 0)
3765       cave->amoeba_growth_prob = cave->amoeba_fast_growth_prob;
3766   }
3767
3768   // we may wait for hatching, when starting amoeba
3769   if (cave->amoeba_timer_started_immediately ||
3770       (cave->amoeba_2_state == GD_AM_AWAKE &&
3771        (cave->hatched || !cave->amoeba_timer_wait_for_hatching)))
3772   {
3773     cave->amoeba_2_time -= cave->speed;
3774     if (cave->amoeba_2_time < 0)
3775       cave->amoeba_2_time = 0;
3776     if (cave->amoeba_2_time == 0)
3777       cave->amoeba_2_growth_prob = cave->amoeba_2_fast_growth_prob;
3778   }
3779
3780   // check for player hatching.
3781   start_signal = FALSE;
3782
3783   // if not the c64 scheduling, but the correct frametime is used,
3784   // hatching delay should always be decremented.
3785   // otherwise, the if (millisecs...) condition below will set this.
3786   if (cave->scheduling == GD_SCHEDULING_MILLISECONDS)
3787   {
3788     // NON-C64 scheduling
3789     if (cave->hatching_delay_frame > 0)
3790     {
3791       // for milliseconds-based, non-c64 schedulings, hatching delay means frames.
3792       cave->hatching_delay_frame--;
3793       if (cave->hatching_delay_frame == 0)
3794         start_signal = TRUE;
3795     }
3796   }
3797   else
3798   {
3799     // C64 scheduling
3800     if (cave->hatching_delay_time > 0)
3801     {
3802       // for c64 schedulings, hatching delay means milliseconds.
3803       cave->hatching_delay_time -= cave->speed;
3804       if (cave->hatching_delay_time <= 0)
3805       {
3806         cave->hatching_delay_time = 0;
3807         start_signal = TRUE;
3808       }
3809     }
3810   }
3811
3812   // if decremented hatching, and it became zero:
3813   if (start_signal)
3814   {
3815     // THIS IS THE CAVE START SIGNAL
3816
3817     // record that now the cave is in its normal state
3818     cave->hatched = TRUE;
3819
3820     // if diamonds needed is below zero, we count the available diamonds now.
3821     gd_cave_count_diamonds(cave);
3822
3823     // setup direction auto change
3824     if (cave->creatures_direction_auto_change_time)
3825     {
3826       cave->creatures_direction_will_change =
3827         cave->creatures_direction_auto_change_time * cave->timing_factor;
3828
3829       if (cave->creatures_direction_auto_change_on_start)
3830         cave->creatures_backwards = !cave->creatures_backwards;
3831     }
3832
3833     gd_sound_play(cave, GD_S_CRACKING, O_INBOX, -1, -1);
3834   }
3835
3836   // for biters
3837   if (cave->biters_wait_frame == 0)
3838     cave->biters_wait_frame = cave->biter_delay_frame;
3839   else
3840     cave->biters_wait_frame--;
3841
3842   // replicators delay
3843   if (cave->replicators_wait_frame == 0)
3844     cave->replicators_wait_frame = cave->replicator_delay_frame;
3845   else
3846     cave->replicators_wait_frame--;
3847
3848
3849   // ============================================================================
3850   // LAST THOUGTS
3851   // ============================================================================
3852
3853 #if 1
3854   // check if cave failed by timeout is done in main game engine
3855 #else
3856   // check if cave failed by timeout
3857   if (cave->player_state == GD_PL_LIVING && cave->time == 0)
3858   {
3859     gd_cave_clear_sounds(cave);
3860     cave->player_state = GD_PL_TIMEOUT;
3861     gd_sound_play(cave, GD_S_TIMEOUT_0, O_NONE, -1, -1);
3862   }
3863 #endif
3864
3865   // set these for drawing.
3866   cave->last_direction = player_move;
3867
3868   // here we remember last movements for animation. this is needed here,
3869   // as animation is in sync with the game, not the keyboard directly.
3870   // (for example, after exiting the cave, the player was "running" in the
3871   // original, till bonus points were counted for remaining time and so on.
3872   if (player_move == GD_MV_LEFT ||
3873       player_move == GD_MV_UP_LEFT ||
3874       player_move == GD_MV_DOWN_LEFT)
3875     cave->last_horizontal_direction = GD_MV_LEFT;
3876
3877   if (player_move == GD_MV_RIGHT ||
3878       player_move == GD_MV_UP_RIGHT ||
3879       player_move == GD_MV_DOWN_RIGHT)
3880     cave->last_horizontal_direction = GD_MV_RIGHT;
3881
3882   cave->frame++;  // XXX
3883 }
3884
3885 void set_initial_cave_speed(GdCave *cave)
3886 {
3887   int ymin, ymax;
3888   int x, y;
3889
3890   // set cave get function; to implement perfect or lineshifting borders
3891   if (cave->lineshift)
3892     cave->getp = getp_shift;
3893   else
3894     cave->getp = getp_perfect;
3895
3896   // check whether to scan the first and last line
3897   if (cave->border_scan_first_and_last)
3898   {
3899     ymin = 0;
3900     ymax = cave->h - 1;
3901   }
3902   else
3903   {
3904     ymin = 1;
3905     ymax = cave->h - 2;
3906   }
3907
3908   for (y = ymin; y <= ymax; y++)
3909   {
3910     for (x = 0; x < cave->w; x++)
3911     {
3912       // add the ckdelay correction value for every element seen.
3913       cave->ckdelay += gd_elements[get(cave, x, y)].ckdelay;
3914     }
3915   }
3916
3917   // update timing calculated by iterating and counting elements
3918   update_cave_speed(cave);
3919 }