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