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