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