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