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