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