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