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