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