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