added option for BD1 magic wall / amoeba bug for native 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     if (cave->magic_wall_breakscan && cave->amoeba_state == GD_AM_AWAKE)
1375       cave->convert_amoeba_this_frame = TRUE;
1376
1377     return TRUE;
1378   }
1379   else
1380     return FALSE;
1381 }
1382
1383 static boolean do_fall_try_crush(GdCave *cave, int x, int y, GdDirection fall_dir)
1384 {
1385   if (explodes_by_hit_dir(cave, x, y, fall_dir))
1386   {
1387     explode_dir(cave, x, y, fall_dir);
1388     return TRUE;
1389   }
1390   else
1391     return FALSE;
1392 }
1393
1394 static boolean do_fall_roll_or_stop(GdCave *cave, int x, int y,
1395                                     GdDirection fall_dir, GdElement bouncing)
1396 {
1397   if (is_space_dir(cave, x, y, fall_dir))
1398   {
1399     // falling further
1400     move(cave, x, y, fall_dir, get(cave, x, y));
1401
1402     return TRUE;
1403   }
1404
1405   // check if it is on a sloped element, and it can roll.
1406   // for example, sloped wall looks like:
1407   //  /|
1408   // /_|
1409   // this is tagged as sloped up&left.
1410   // first check if the stone or diamond is coming from "up" (ie. opposite of gravity)
1411   // then check the direction to roll (left or right)
1412   // this way, gravity can also be pointing right, and the above slope will work as one would expect
1413
1414   if (sloped_dir(cave, x, y, fall_dir, opposite[fall_dir]))
1415   {
1416     // sloped element, falling to left or right
1417     if (sloped_dir(cave, x, y, fall_dir, cw_fourth[fall_dir]) &&
1418         is_space_dir(cave, x, y, cw_eighth[fall_dir]) &&
1419         is_space_dir(cave, x, y, cw_fourth[fall_dir]))
1420     {
1421       play_sound_of_element(cave, get(cave, x, y), x, y);
1422
1423       // try to roll left first - see O_STONE to understand why cw_fourth
1424       move(cave, x, y, cw_fourth[fall_dir], get(cave, x, y));
1425     }
1426     else if (sloped_dir(cave, x, y, fall_dir, ccw_fourth[fall_dir]) &&
1427              is_space_dir(cave, x, y, ccw_eighth[fall_dir]) &&
1428              is_space_dir(cave, x, y, ccw_fourth[fall_dir]))
1429     {
1430       play_sound_of_element(cave, get(cave, x, y), x, y);
1431
1432       // if not, try to roll right
1433       move(cave, x, y, ccw_fourth[fall_dir], get(cave, x, y));
1434     }
1435     else
1436     {
1437       // cannot roll in any direction, so it stops
1438       play_sound_of_element(cave, get(cave, x, y), x, y);
1439       store(cave, x, y, bouncing);
1440     }
1441
1442     return TRUE;
1443   }
1444
1445   // any other element, stops
1446   play_sound_of_element(cave, get(cave, x, y), x, y);
1447   store(cave, x, y, bouncing);
1448   return TRUE;
1449 }
1450
1451 static void update_cave_speed(GdCave *cave)
1452 {
1453   // update timing calculated by iterating and counting elements which were slow to process on c64
1454   switch (cave->scheduling)
1455   {
1456     case GD_SCHEDULING_MILLISECONDS:
1457       // cave->speed already contains the milliseconds value, do not touch it
1458       break;
1459
1460     case GD_SCHEDULING_BD1:
1461       if (!cave->intermission)
1462         // non-intermissions
1463         cave->speed = (88 + 3.66 * cave->c64_timing + (cave->ckdelay + cave->ckdelay_extra_for_animation) / 1000);
1464       else
1465         // intermissions were quicker, as only lines 1-12 were processed by the engine.
1466         cave->speed = (60 + 3.66 * cave->c64_timing + (cave->ckdelay + cave->ckdelay_extra_for_animation) / 1000);
1467       break;
1468
1469     case GD_SCHEDULING_BD1_ATARI:
1470       // about 20ms/frame faster than c64 version
1471       if (!cave->intermission)
1472         cave->speed = (74 + 3.2 * cave->c64_timing + (cave->ckdelay) / 1000);            // non-intermissions
1473       else
1474         cave->speed = (65 + 2.88 * cave->c64_timing + (cave->ckdelay) / 1000);        // for intermissions
1475       break;
1476
1477     case GD_SCHEDULING_BD2:
1478       // 60 is a guess.
1479       cave->speed = MAX(60 + (cave->ckdelay + cave->ckdelay_extra_for_animation)/1000, cave->c64_timing * 20);
1480       break;
1481
1482     case GD_SCHEDULING_PLCK:
1483       // 65 is totally empty cave in construction kit, with delay = 0)
1484       cave->speed = MAX(65 + cave->ckdelay / 1000, cave->c64_timing * 20);
1485       break;
1486
1487     case GD_SCHEDULING_BD2_PLCK_ATARI:
1488       // a really fast engine; timing works like c64 plck.
1489       // 40 ms was measured in the construction kit, with delay = 0
1490       cave->speed = MAX(40 + cave->ckdelay / 1000, cave->c64_timing * 20);
1491       break;
1492
1493     case GD_SCHEDULING_CRDR:
1494       if (cave->hammered_walls_reappear) // this made the engine very slow.
1495         cave->ckdelay += 60000;
1496       cave->speed = MAX(130 + cave->ckdelay / 1000, cave->c64_timing * 20);
1497       break;
1498
1499     case GD_SCHEDULING_MAX:
1500       break;
1501   }
1502 }
1503
1504 // process a cave.
1505 void gd_cave_iterate(GdCave *cave, GdDirection player_move, boolean player_fire, boolean suicide)
1506 {
1507   int x, y, i;
1508
1509   // for border scan
1510   int ymin, ymax;
1511
1512   // amoeba found to be enclosed. if not, this is cleared
1513   boolean amoeba_found_enclosed, amoeba_2_found_enclosed;
1514
1515   // counting the number of amoebas. after scan, check if too much
1516   int amoeba_count, amoeba_2_count;
1517
1518   // cave scan found water - for sound
1519   boolean found_water;
1520
1521   boolean inbox_toggle;
1522   boolean start_signal;
1523
1524   // gravity for falling wall, bladder, ...
1525   GdDirection grav_compat = cave->gravity_affects_all ? cave->gravity : GD_MV_DOWN;
1526
1527   // directions for o_something_1, 2, 3 and 4 (creatures)
1528   static const GdDirection creature_dir[] =
1529   {
1530     GD_MV_LEFT,
1531     GD_MV_UP,
1532     GD_MV_RIGHT,
1533     GD_MV_DOWN
1534   };
1535   static const GdDirection creature_chdir[] =
1536   {
1537     GD_MV_RIGHT,
1538     GD_MV_DOWN,
1539     GD_MV_LEFT,
1540     GD_MV_UP
1541   };
1542   int time_decrement_sec;
1543
1544   // biters eating elements preference, they try to go in this order
1545   GdElement biter_try[] =
1546   {
1547     O_DIRT,
1548     cave->biter_eat,
1549     O_SPACE, O_STONE
1550   };
1551
1552   boolean amoeba_sound, magic_sound;
1553
1554   gd_cave_clear_sounds(cave);
1555
1556   // if diagonal movements not allowed,
1557   // horizontal movements have precedence. [BROADRIBB]
1558   if (!cave->diagonal_movements)
1559   {
1560     switch (player_move)
1561     {
1562       case GD_MV_UP_RIGHT:
1563       case GD_MV_DOWN_RIGHT:
1564         player_move = GD_MV_RIGHT;
1565         break;
1566
1567       case GD_MV_UP_LEFT:
1568       case GD_MV_DOWN_LEFT:
1569         player_move = GD_MV_LEFT;
1570         break;
1571
1572       default:
1573         // no correction needed
1574         break;
1575     }
1576   }
1577
1578   // set cave get function; to implement perfect or lineshifting borders
1579   if (cave->lineshift)
1580   {
1581     cave->getp = getp_shift;
1582     cave->getx = getx_shift;
1583     cave->gety = gety_shift;
1584   }
1585   else
1586   {
1587     cave->getp = getp_perfect;
1588     cave->getx = getx_perfect;
1589     cave->gety = gety_perfect;
1590   }
1591
1592   // increment this. if the scan routine comes across player, clears it (sets to zero).
1593   if (cave->player_seen_ago < 100)
1594     cave->player_seen_ago++;
1595
1596   if (cave->pneumatic_hammer_active_delay > 0)
1597     cave->pneumatic_hammer_active_delay--;
1598
1599   // inboxes and outboxes flash with the rhythm of the game, not the display.
1600   // also, a player can be born only from an open, not from a steel-wall-like inbox.
1601   cave->inbox_flash_toggle = !cave->inbox_flash_toggle;
1602   inbox_toggle = cave->inbox_flash_toggle;
1603
1604   if (cave->gate_open_flash > 0)
1605     cave->gate_open_flash--;
1606
1607   // score collected this frame
1608   cave->score = 0;
1609
1610   // to implement buggy bd1 amoeba+magic wall behaviour
1611   cave->convert_amoeba_this_frame = FALSE;
1612
1613   // suicide only kills the active player
1614   // player_x, player_y was set by the previous iterate routine, or the cave setup.
1615   // we must check if there is a player or not - he may have exploded or something like that
1616   if (suicide && cave->player_state == GD_PL_LIVING &&
1617       is_player(cave, cave->player_x, cave->player_y))
1618     store(cave, cave->player_x, cave->player_y, O_EXPLODE_1);
1619
1620   // check for walls reappearing
1621   if (cave->hammered_reappear)
1622   {
1623     for (y = 0; y < cave->h; y++)
1624     {
1625       for (x = 0; x < cave->w; x++)
1626       {
1627         // timer for the cell > 0?
1628         if (cave->hammered_reappear[y][x] > 0)
1629         {
1630           // decrease timer
1631           cave->hammered_reappear[y][x]--;
1632
1633           // check if it became zero
1634           if (cave->hammered_reappear[y][x] == 0)
1635           {
1636             store(cave, x, y, O_BRICK);
1637             gd_sound_play(cave, GD_S_WALL_REAPPEARING, O_BRICK, x, y);
1638           }
1639         }
1640       }
1641     }
1642   }
1643
1644   // variables to check during the scan
1645
1646   // will be set to false if any of the amoeba is found free.
1647   amoeba_found_enclosed = TRUE;
1648   amoeba_2_found_enclosed = TRUE;
1649   amoeba_count = 0;
1650   amoeba_2_count = 0;
1651   found_water = FALSE;
1652   cave->ckdelay = 0;
1653   time_decrement_sec = 0;
1654
1655   // check whether to scan the first and last line
1656   if (cave->border_scan_first_and_last)
1657   {
1658     ymin = 0;
1659     ymax = cave->h - 1;
1660   }
1661   else
1662   {
1663     ymin = 1;
1664     ymax = cave->h - 2;
1665   }
1666
1667   // the cave scan routine
1668   for (y = ymin; y <= ymax; y++)
1669   {
1670     for (x = 0; x < cave->w; x++)
1671     {
1672       // if we find a scanned element, change it to the normal one, and that's all.
1673       // this is required, for example for chasing stones, which have moved, always passing slime!
1674       if (get(cave, x, y) & SCANNED)
1675       {
1676         store(cave, x, y, get(cave, x, y) & ~SCANNED);
1677
1678         continue;
1679       }
1680
1681       // add the ckdelay correction value for every element seen.
1682       cave->ckdelay += gd_elements[get(cave, x, y)].ckdelay;
1683
1684       switch (get(cave, x, y))
1685       {
1686         // ============================================================================
1687         //    P L A Y E R S
1688         // ============================================================================
1689
1690         case O_PLAYER:
1691           if (cave->kill_player)
1692           {
1693             explode (cave, x, y);
1694             break;
1695           }
1696
1697           cave->player_seen_ago = 0;
1698           // bd4 intermission caves have many players. so if one of them has exited,
1699           // do not change the flag anymore. so this if () is needed
1700           if (cave->player_state != GD_PL_EXITED)
1701             cave->player_state = GD_PL_LIVING;
1702
1703           // check for pneumatic hammer things
1704           // 1) press fire, 2) have pneumatic hammer 4) space on left or right
1705           // for hammer 5) stand on something
1706           if (player_fire && cave->got_pneumatic_hammer &&
1707               is_space_dir(cave, x, y, player_move) &&
1708               !is_space_dir(cave, x, y, GD_MV_DOWN))
1709           {
1710             if (player_move == GD_MV_LEFT &&
1711                 can_be_hammered_dir(cave, x, y, GD_MV_DOWN_LEFT))
1712             {
1713               cave->pneumatic_hammer_active_delay = cave->pneumatic_hammer_frame;
1714               store_dir(cave, x, y, GD_MV_LEFT, O_PNEUMATIC_ACTIVE_LEFT);
1715               store(cave, x, y, O_PLAYER_PNEUMATIC_LEFT);
1716               break;    // finished.
1717             }
1718
1719             if (player_move == GD_MV_RIGHT &&
1720                 can_be_hammered_dir(cave, x, y, GD_MV_DOWN_RIGHT))
1721             {
1722               cave->pneumatic_hammer_active_delay = cave->pneumatic_hammer_frame;
1723               store_dir(cave, x, y, GD_MV_RIGHT, O_PNEUMATIC_ACTIVE_RIGHT);
1724               store(cave, x, y, O_PLAYER_PNEUMATIC_RIGHT);
1725               break;    // finished.
1726             }
1727           }
1728
1729           if (player_move != GD_MV_STILL)
1730           {
1731             // only do every check if he is not moving
1732             GdElement what = get_dir(cave, x, y, player_move);
1733             GdElement remains = what;
1734             boolean push;
1735
1736             // if we are 'eating' a teleporter, and the function returns true
1737             // (teleporting worked), break here
1738             if (what == O_TELEPORTER && do_teleporter(cave, x, y, player_move))
1739               break;
1740
1741             // try to push element; if successful, break
1742             push = do_push(cave, x, y, player_move, player_fire);
1743             if (push)
1744             {
1745               remains = O_SPACE;
1746             }
1747             else
1748             {
1749               switch (what)
1750               {
1751                 case O_BOMB:
1752                   // if its a bomb, remember he now has one.
1753                   // we do not change the "remains" and "what" variables,
1754                   // so that part of the code will be ineffective
1755                   gd_sound_play(cave, GD_S_BOMB_COLLECTING, what, x, y);
1756                   store_dir(cave, x, y, player_move, O_SPACE);
1757
1758                   if (player_fire)
1759                     store(cave, x, y, O_PLAYER_BOMB);
1760                   else
1761                     move(cave, x, y, player_move, O_PLAYER_BOMB);
1762                   break;
1763
1764                 case O_ROCKET_LAUNCHER:
1765                   // if its a rocket launcher, remember he now has one.
1766                   // we do not change the "remains" and "what" variables,
1767                   // so that part of the code will be ineffective
1768                   gd_sound_play(cave, GD_S_BOMB_COLLECTING, what, x, y);
1769                   store_dir(cave, x, y, player_move, O_SPACE);
1770
1771                   if (player_fire)
1772                     store(cave, x, y, O_PLAYER_ROCKET_LAUNCHER);
1773                   else
1774                     move(cave, x, y, player_move, O_PLAYER_ROCKET_LAUNCHER);
1775                   break;
1776
1777                 case O_POT:
1778                   // we do not change the "remains" and "what" variables,
1779                   // so that part of the code will be ineffective
1780                   if (!player_fire && !cave->gravity_switch_active &&
1781                       cave->skeletons_collected >= cave->skeletons_needed_for_pot)
1782                   {
1783                     cave->skeletons_collected -= cave->skeletons_needed_for_pot;
1784                     move(cave, x, y, player_move, O_PLAYER_STIRRING);
1785                     cave->gravity_disabled = TRUE;
1786                   }
1787                   break;
1788
1789                 case O_GRAVITY_SWITCH:
1790                   // (we cannot use player_get for this as it does not have player_move parameter)
1791                   // only allow changing direction if the new dir is not diagonal
1792                   if (cave->gravity_switch_active &&
1793                       (player_move == GD_MV_LEFT ||
1794                        player_move == GD_MV_RIGHT ||
1795                        player_move == GD_MV_UP ||
1796                        player_move == GD_MV_DOWN))
1797                   {
1798                     gd_sound_play(cave, GD_S_SWITCH_GRAVITY, what, x, y);
1799                     cave->gravity_will_change =
1800                       cave->gravity_change_time * cave->timing_factor;
1801                     cave->gravity_next_direction = player_move;
1802                     cave->gravity_switch_active = FALSE;
1803                   }
1804                   break;
1805
1806                 default:
1807                   // get element - process others.
1808                   // if cannot get, player_get_element will return the same
1809                   remains = player_get_element(cave, what, x, y);
1810                   break;
1811               }
1812             }
1813
1814             if (remains != what || remains == O_SPACE)
1815             {
1816               // if anything changed, apply the change.
1817
1818               // if snapping anything and we have snapping explosions set.
1819               // but these is not true for pushing.
1820               if (remains == O_SPACE && player_fire && !push)
1821                 remains = cave->snap_element;
1822
1823               if (remains != O_SPACE || player_fire)
1824                 // if any other element than space, player cannot move.
1825                 // also if pressing fire, will not move.
1826                 store_dir(cave, x, y, player_move, remains);
1827               else
1828                 // if space remains there, the player moves.
1829                 move(cave, x, y, player_move, O_PLAYER);
1830             }
1831           }
1832           break;
1833
1834         case O_PLAYER_BOMB:
1835           // much simpler; cannot steal stones
1836           if (cave->kill_player)
1837           {
1838             explode(cave, x, y);
1839             break;
1840           }
1841
1842           cave->player_seen_ago = 0;
1843           // bd4 intermission caves have many players. so if one of them has exited,
1844           // do not change the flag anymore. so this if () is needed
1845           if (cave->player_state != GD_PL_EXITED)
1846             cave->player_state = GD_PL_LIVING;
1847
1848           if (player_move != GD_MV_STILL)
1849           {
1850             // if the player does not move, nothing to do
1851             GdElement what = get_dir(cave, x, y, player_move);
1852             GdElement remains = what;
1853
1854             if (player_fire)
1855             {
1856               // placing a bomb into empty space or dirt
1857               if (is_space_dir(cave, x, y, player_move) ||
1858                   is_element_dir(cave, x, y, player_move, O_DIRT))
1859               {
1860                 store_dir(cave, x, y, player_move, O_BOMB_TICK_1);
1861
1862                 // placed bomb, he is normal player again
1863                 store(cave, x, y, O_PLAYER);
1864                 gd_sound_play(cave, GD_S_BOMB_PLACING, O_BOMB, x, y);
1865               }
1866               break;
1867             }
1868
1869             // pushing and collecting
1870             // if we are 'eating' a teleporter, and the function returns true
1871             // (teleporting worked), break here
1872             if (what == O_TELEPORTER && do_teleporter(cave, x, y, player_move))
1873               break;
1874
1875             // player fire is false...
1876             if (do_push(cave, x, y, player_move, FALSE))
1877             {
1878               remains = O_SPACE;
1879             }
1880             else
1881             {
1882               switch (what)
1883               {
1884                 case O_GRAVITY_SWITCH:
1885                   // (we cannot use player_get for this as it does not have
1886                   // player_move parameter)
1887                   // only allow changing direction if the new dir is not diagonal
1888                   if (cave->gravity_switch_active &&
1889                       (player_move == GD_MV_LEFT ||
1890                        player_move == GD_MV_RIGHT ||
1891                        player_move == GD_MV_UP ||
1892                        player_move == GD_MV_DOWN))
1893                   {
1894                     gd_sound_play(cave, GD_S_SWITCH_GRAVITY, what, x, y);
1895                     cave->gravity_will_change =
1896                       cave->gravity_change_time * cave->timing_factor;
1897                     cave->gravity_next_direction = player_move;
1898                     cave->gravity_switch_active = FALSE;
1899                   }
1900                   break;
1901
1902                 default:
1903                   // get element. if cannot get, player_get_element will return the same
1904                   remains = player_get_element (cave, what, x, y);
1905                   break;
1906               }
1907             }
1908
1909             // if element changed, OR there is space, move.
1910             if (remains != what || remains == O_SPACE)
1911             {
1912               // if anything changed, apply the change.
1913               move(cave, x, y, player_move, O_PLAYER_BOMB);
1914             }
1915           }
1916           break;
1917
1918         case O_PLAYER_ROCKET_LAUNCHER:
1919           // much simpler; cannot snap-push stones
1920           if (cave->kill_player)
1921           {
1922             explode(cave, x, y);
1923             break;
1924           }
1925
1926           cave->player_seen_ago = 0;
1927           // bd4 intermission caves have many players. so if one of them has exited,
1928           // do not change the flag anymore. so this if () is needed
1929           if (cave->player_state != GD_PL_EXITED)
1930             cave->player_state = GD_PL_LIVING;
1931
1932           // firing a rocket?
1933           if (player_move != GD_MV_STILL)
1934           {
1935             // if the player does not move, nothing to do
1936             GdElement what = get_dir(cave, x, y, player_move);
1937             GdElement remains = what;
1938
1939             // to fire a rocket, diagonal movement should not be allowed.
1940             // so either x or y must be zero
1941             if (player_fire)
1942             {
1943               // placing a rocket into empty space
1944               if (is_space_dir(cave, x, y, player_move))
1945               {
1946                 switch (player_move)
1947                 {
1948                   case GD_MV_RIGHT:
1949                     store_dir(cave, x, y, player_move, O_ROCKET_1);
1950                     if (!cave->infinite_rockets)
1951                       store(cave, x, y, O_PLAYER);
1952                     break;
1953
1954                   case GD_MV_UP:
1955                     store_dir(cave, x, y, player_move, O_ROCKET_2);
1956                     if (!cave->infinite_rockets)
1957                       store(cave, x, y, O_PLAYER);
1958                     break;
1959
1960                   case GD_MV_LEFT:
1961                     store_dir(cave, x, y, player_move, O_ROCKET_3);
1962                     if (!cave->infinite_rockets)
1963                       store(cave, x, y, O_PLAYER);
1964                     break;
1965
1966                   case GD_MV_DOWN:
1967                     store_dir(cave, x, y, player_move, O_ROCKET_4);
1968                     if (!cave->infinite_rockets)
1969                       store(cave, x, y, O_PLAYER);
1970                     break;
1971
1972                   default:
1973                     // cannot fire in other directions
1974                     break;
1975                 }
1976
1977                 gd_sound_play(cave, GD_S_BOMB_PLACING, O_BOMB, x, y);
1978               }
1979
1980               // a player with rocket launcher cannot snap elements, so stop here
1981               break;
1982             }
1983
1984             // pushing and collecting
1985             // if we are 'eating' a teleporter, and the function returns true
1986             // (teleporting worked), break here
1987             if (what == O_TELEPORTER && do_teleporter(cave, x, y, player_move))
1988               break;
1989
1990             // player fire is false...
1991             if (do_push(cave, x, y, player_move, FALSE))
1992             {
1993               remains = O_SPACE;
1994             }
1995             else
1996             {
1997               // get element. if cannot get, player_get_element will return the same
1998               remains = player_get_element(cave, what, x, y);
1999             }
2000
2001             // if something changed, OR there is space, move.
2002             if (remains != what || remains == O_SPACE)
2003             {
2004               // if anything changed, apply the change.
2005               move(cave, x, y, player_move, O_PLAYER_ROCKET_LAUNCHER);
2006             }
2007           }
2008           break;
2009
2010         case O_PLAYER_STIRRING:
2011           if (cave->kill_player)
2012           {
2013             explode(cave, x, y);
2014             break;
2015           }
2016
2017           // stirring sound, if no other walking sound or explosion
2018           gd_sound_play(cave, GD_S_STIRRING, O_PLAYER_STIRRING, x, y);
2019
2020           cave->player_seen_ago = 0;
2021           // bd4 intermission caves have many players. so if one of them has exited,
2022           // do not change the flag anymore. so this if () is needed
2023           if (cave->player_state != GD_PL_EXITED)
2024             cave->player_state = GD_PL_LIVING;
2025
2026           if (player_fire)
2027           {
2028             // player "exits" stirring the pot by pressing fire
2029             cave->gravity_disabled = FALSE;
2030             store(cave, x, y, O_PLAYER);
2031             cave->gravity_switch_active = TRUE;
2032           }
2033           break;
2034
2035           // player holding pneumatic hammer
2036         case O_PLAYER_PNEUMATIC_LEFT:
2037         case O_PLAYER_PNEUMATIC_RIGHT:
2038           // usual player stuff
2039           if (cave->kill_player)
2040           {
2041             explode(cave, x, y);
2042             break;
2043           }
2044
2045           cave->player_seen_ago = 0;
2046           if (cave->player_state != GD_PL_EXITED)
2047             cave->player_state = GD_PL_LIVING;
2048
2049           // if hammering time is up, becomes a normal player again.
2050           if (cave->pneumatic_hammer_active_delay == 0)
2051             store(cave, x, y, O_PLAYER);
2052           break;
2053
2054           // the active pneumatic hammer itself
2055         case O_PNEUMATIC_ACTIVE_RIGHT:
2056         case O_PNEUMATIC_ACTIVE_LEFT:
2057           if (cave->pneumatic_hammer_active_delay == 0)
2058           {
2059             GdElement new_elem;
2060
2061             // pneumatic hammer element disappears
2062             store(cave, x, y, O_SPACE);
2063
2064             // which is the new element which appears after that one is hammered?
2065             new_elem = gd_element_get_hammered(get_dir(cave, x, y, GD_MV_DOWN));
2066
2067             // if there is a new element, display it
2068             // O_NONE might be returned, for example if the element being
2069             // hammered explodes during hammering (by a nearby explosion)
2070             if (new_elem != O_NONE)
2071             {
2072               store_dir(cave, x, y, GD_MV_DOWN, new_elem);
2073
2074               // and if walls reappear, remember it in array
2075               if (cave->hammered_walls_reappear)
2076               {
2077                 int wall_y;
2078
2079                 wall_y = (y + 1) % cave->h;
2080                 cave->hammered_reappear[wall_y][x] = cave->hammered_wall_reappear_frame;
2081               }
2082             }
2083           }
2084           break;
2085
2086           // ============================================================================
2087           //    S T O N E S,   D I A M O N D S
2088           // ============================================================================
2089
2090         case O_STONE:           // standing stone
2091           do_start_fall(cave, x, y, cave->gravity, cave->stone_falling_effect);
2092           break;
2093
2094         case O_MEGA_STONE:      // standing mega_stone
2095           do_start_fall(cave, x, y, cave->gravity, O_MEGA_STONE_F);
2096           break;
2097
2098         case O_DIAMOND:         // standing diamond
2099           do_start_fall(cave, x, y, cave->gravity, cave->diamond_falling_effect);
2100           break;
2101
2102         case O_NUT:             // standing nut
2103           do_start_fall(cave, x, y, cave->gravity, O_NUT_F);
2104           break;
2105
2106         case O_DIRT_BALL:       // standing dirt ball
2107           do_start_fall(cave, x, y, cave->gravity, O_DIRT_BALL_F);
2108           break;
2109
2110         case O_DIRT_LOOSE:      // standing loose dirt
2111           do_start_fall(cave, x, y, cave->gravity, O_DIRT_LOOSE_F);
2112           break;
2113
2114         case O_FLYING_STONE:    // standing stone
2115           do_start_fall(cave, x, y, opposite[cave->gravity], O_FLYING_STONE_F);
2116           break;
2117
2118         case O_FLYING_DIAMOND:  // standing diamond
2119           do_start_fall(cave, x, y, opposite[cave->gravity], O_FLYING_DIAMOND_F);
2120           break;
2121
2122           // ============================================================================
2123           //    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
2124           // ============================================================================
2125
2126         case O_DIRT_BALL_F:     // falling dirt ball
2127           if (!cave->gravity_disabled)
2128             do_fall_roll_or_stop(cave, x, y, cave->gravity, O_DIRT_BALL);
2129           break;
2130
2131         case O_DIRT_LOOSE_F:    // falling loose dirt
2132           if (!cave->gravity_disabled)
2133             do_fall_roll_or_stop(cave, x, y, cave->gravity, O_DIRT_LOOSE);
2134           break;
2135
2136         case O_STONE_F:         // falling stone
2137           if (!cave->gravity_disabled)
2138           {
2139             if (do_fall_try_crush_voodoo(cave, x, y, cave->gravity))
2140               break;
2141
2142             if (do_fall_try_crack_nut(cave, x, y, cave->gravity, cave->stone_bouncing_effect))
2143               break;
2144
2145             if (do_fall_try_magic(cave, x, y, cave->gravity, cave->magic_stone_to))
2146               break;
2147
2148             if (do_fall_try_crush(cave, x, y, cave->gravity))
2149               break;
2150
2151             do_fall_roll_or_stop(cave, x, y, cave->gravity, cave->stone_bouncing_effect);
2152           }
2153           break;
2154
2155         case O_MEGA_STONE_F:    // falling mega
2156           if (!cave->gravity_disabled)
2157           {
2158             if (do_fall_try_crush_voodoo(cave, x, y, cave->gravity))
2159               break;
2160
2161             if (do_fall_try_crack_nut(cave, x, y, cave->gravity, O_MEGA_STONE))
2162               break;
2163
2164             if (do_fall_try_magic(cave, x, y, cave->gravity, cave->magic_mega_stone_to))
2165               break;
2166
2167             if (do_fall_try_crush(cave, x, y, cave->gravity))
2168               break;
2169
2170             do_fall_roll_or_stop(cave, x, y, cave->gravity, O_MEGA_STONE);
2171           }
2172           break;
2173
2174         case O_DIAMOND_F:       // falling diamond
2175           if (!cave->gravity_disabled)
2176           {
2177             if (do_fall_try_eat_voodoo(cave, x, y, cave->gravity))
2178               break;
2179
2180             if (do_fall_try_magic(cave, x, y, cave->gravity, cave->magic_diamond_to))
2181               break;
2182
2183             if (do_fall_try_crush(cave, x, y, cave->gravity))
2184               break;
2185
2186             do_fall_roll_or_stop(cave, x, y, cave->gravity, cave->diamond_bouncing_effect);
2187           }
2188           break;
2189
2190         case O_NUT_F:           // falling nut
2191           if (!cave->gravity_disabled)
2192           {
2193             if (do_fall_try_magic(cave, x, y, cave->gravity, cave->magic_nut_to))
2194               break;
2195
2196             if (do_fall_try_crush(cave, x, y, cave->gravity))
2197               break;
2198
2199             do_fall_roll_or_stop(cave, x, y, cave->gravity, O_NUT);
2200           }
2201           break;
2202
2203         case O_FLYING_STONE_F:  // falling stone
2204           if (!cave->gravity_disabled)
2205           {
2206             GdDirection fall_dir = opposite[cave->gravity];
2207
2208             if (do_fall_try_crush_voodoo(cave, x, y, fall_dir))
2209               break;
2210
2211             if (do_fall_try_crack_nut(cave, x, y, fall_dir, O_FLYING_STONE))
2212               break;
2213
2214             if (do_fall_try_magic(cave, x, y, fall_dir, cave->magic_flying_stone_to))
2215               break;
2216
2217             if (do_fall_try_crush(cave, x, y, fall_dir))
2218               break;
2219
2220             do_fall_roll_or_stop(cave, x, y, fall_dir, O_FLYING_STONE);
2221           }
2222           break;
2223
2224         case O_FLYING_DIAMOND_F:    // falling diamond
2225           if (!cave->gravity_disabled)
2226           {
2227             GdDirection fall_dir = opposite[cave->gravity];
2228
2229             if (do_fall_try_eat_voodoo(cave, x, y, fall_dir))
2230               break;
2231
2232             if (do_fall_try_magic(cave, x, y, fall_dir, cave->magic_flying_diamond_to))
2233               break;
2234
2235             if (do_fall_try_crush(cave, x, y, fall_dir))
2236               break;
2237
2238             do_fall_roll_or_stop(cave, x, y, fall_dir, O_FLYING_DIAMOND);
2239           }
2240           break;
2241
2242           // ============================================================================
2243           //    N I T R O    P A C K
2244           // ============================================================================
2245
2246         case O_NITRO_PACK:      // standing nitro pack
2247           do_start_fall(cave, x, y, cave->gravity, O_NITRO_PACK_F);
2248           break;
2249
2250         case O_NITRO_PACK_F:    // falling nitro pack
2251           if (!cave->gravity_disabled)
2252           {
2253             if (is_space_dir(cave, x, y, cave->gravity))    // if space, falling further
2254               move(cave, x, y, cave->gravity, get(cave, x, y));
2255             else if (do_fall_try_magic(cave, x, y, cave->gravity, cave->magic_nitro_pack_to))
2256             {
2257               // try magic wall; if true, function did the work
2258             }
2259             else if (is_element_dir(cave, x, y, cave->gravity, O_DIRT))
2260             {
2261               // falling on a dirt, it does NOT explode - just stops at its place.
2262               play_sound_of_element(cave, O_NITRO_PACK, x, y);
2263               store(cave, x, y, O_NITRO_PACK);
2264             }
2265             else
2266               // falling on any other element it explodes
2267               explode(cave, x, y);
2268           }
2269           break;
2270
2271         case O_NITRO_PACK_EXPLODE:    // a triggered nitro pack
2272           explode(cave, x, y);
2273           break;
2274
2275           // ============================================================================
2276           //    C R E A T U R E S
2277           // ============================================================================
2278
2279         case O_COW_1:
2280         case O_COW_2:
2281         case O_COW_3:
2282         case O_COW_4:
2283           // if cannot move in any direction, becomes an enclosed cow
2284           if (!is_space_dir(cave, x, y, GD_MV_UP) && !is_space_dir(cave, x, y, GD_MV_DOWN) &&
2285               !is_space_dir(cave, x, y, GD_MV_LEFT) && !is_space_dir(cave, x, y, GD_MV_RIGHT))
2286             store(cave, x, y, O_COW_ENCLOSED_1);
2287           else
2288           {
2289             // THIS IS THE CREATURE MOVE thing copied.
2290             const GdDirection *creature_move;
2291             boolean ccw = rotates_ccw(cave, x, y);    // check if default is counterclockwise
2292             GdElement base;    // base element number (which is like O_***_1)
2293             int dir, dirn, dirp;    // direction
2294
2295             base = O_COW_1;
2296
2297             dir = get(cave, x, y)-base;    // facing where
2298             creature_move = cave->creatures_backwards ? creature_chdir : creature_dir;
2299
2300             // now change direction if backwards
2301             if (cave->creatures_backwards)
2302               ccw = !ccw;
2303
2304             if (ccw)
2305             {
2306               dirn = (dir + 3) & 3;    // fast turn
2307               dirp = (dir + 1) & 3;    // slow turn
2308             }
2309             else
2310             {
2311               dirn = (dir + 1) & 3;    // fast turn
2312               dirp = (dir + 3) & 3;    // slow turn
2313             }
2314
2315             if (is_space_dir(cave, x, y, creature_move[dirn]))
2316               move(cave, x, y, creature_move[dirn], base + dirn);    // turn and move to preferred dir
2317             else if (is_space_dir(cave, x, y, creature_move[dir]))
2318               move(cave, x, y, creature_move[dir], base + dir);    // go on
2319             else
2320               store(cave, x, y, base + dirp);    // turn in place if nothing else possible
2321           }
2322           break;
2323
2324           // enclosed cows wait some time before turning to a skeleton
2325         case O_COW_ENCLOSED_1:
2326         case O_COW_ENCLOSED_2:
2327         case O_COW_ENCLOSED_3:
2328         case O_COW_ENCLOSED_4:
2329         case O_COW_ENCLOSED_5:
2330         case O_COW_ENCLOSED_6:
2331           if (is_space_dir(cave, x, y, GD_MV_UP) ||
2332               is_space_dir(cave, x, y, GD_MV_LEFT) ||
2333               is_space_dir(cave, x, y, GD_MV_RIGHT) ||
2334               is_space_dir(cave, x, y, GD_MV_DOWN))
2335             store(cave, x, y, O_COW_1);
2336           else
2337             next(cave, x, y);
2338           break;
2339
2340         case O_COW_ENCLOSED_7:
2341           if (is_space_dir(cave, x, y, GD_MV_UP) ||
2342               is_space_dir(cave, x, y, GD_MV_LEFT) ||
2343               is_space_dir(cave, x, y, GD_MV_RIGHT) ||
2344               is_space_dir(cave, x, y, GD_MV_DOWN))
2345             store(cave, x, y, O_COW_1);
2346           else
2347             store(cave, x, y, O_SKELETON);
2348           break;
2349
2350         case O_FIREFLY_1:
2351         case O_FIREFLY_2:
2352         case O_FIREFLY_3:
2353         case O_FIREFLY_4:
2354         case O_ALT_FIREFLY_1:
2355         case O_ALT_FIREFLY_2:
2356         case O_ALT_FIREFLY_3:
2357         case O_ALT_FIREFLY_4:
2358         case O_BUTTER_1:
2359         case O_BUTTER_2:
2360         case O_BUTTER_3:
2361         case O_BUTTER_4:
2362         case O_ALT_BUTTER_1:
2363         case O_ALT_BUTTER_2:
2364         case O_ALT_BUTTER_3:
2365         case O_ALT_BUTTER_4:
2366         case O_STONEFLY_1:
2367         case O_STONEFLY_2:
2368         case O_STONEFLY_3:
2369         case O_STONEFLY_4:
2370           // check if touches a voodoo
2371           if (get_dir(cave, x, y, GD_MV_LEFT)  == O_VOODOO ||
2372               get_dir(cave, x, y, GD_MV_RIGHT) == O_VOODOO ||
2373               get_dir(cave, x, y, GD_MV_UP)    == O_VOODOO ||
2374               get_dir(cave, x, y, GD_MV_DOWN)  == O_VOODOO)
2375             cave->voodoo_touched = TRUE;
2376
2377           // check if touches something bad and should explode (includes voodoo by the flags)
2378           if (blows_up_flies_dir(cave, x, y, GD_MV_DOWN) ||
2379               blows_up_flies_dir(cave, x, y, GD_MV_UP) ||
2380               blows_up_flies_dir(cave, x, y, GD_MV_LEFT) ||
2381               blows_up_flies_dir(cave, x, y, GD_MV_RIGHT))
2382             explode (cave, x, y);
2383           // otherwise move
2384           else
2385           {
2386             const GdDirection *creature_move;
2387             boolean ccw = rotates_ccw(cave, x, y);    // check if default is counterclockwise
2388             GdElement base = -1;    // base element number (which is like O_***_1)
2389             int dir, dirn, dirp;    // direction
2390
2391             if (get(cave, x, y) >= O_FIREFLY_1 &&
2392                 get(cave, x, y) <= O_FIREFLY_4)
2393               base = O_FIREFLY_1;
2394             else if (get(cave, x, y) >= O_BUTTER_1 &&
2395                      get(cave, x, y) <= O_BUTTER_4)
2396               base = O_BUTTER_1;
2397             else if (get(cave, x, y) >= O_STONEFLY_1 &&
2398                      get(cave, x, y) <= O_STONEFLY_4)
2399               base = O_STONEFLY_1;
2400             else if (get(cave, x, y) >= O_ALT_FIREFLY_1 &&
2401                      get(cave, x, y) <= O_ALT_FIREFLY_4)
2402               base = O_ALT_FIREFLY_1;
2403             else if (get(cave, x, y) >= O_ALT_BUTTER_1 &&
2404                      get(cave, x, y) <= O_ALT_BUTTER_4)
2405               base = O_ALT_BUTTER_1;
2406
2407             dir = get(cave, x, y) - base;    // facing where
2408             creature_move = cave->creatures_backwards ? creature_chdir : creature_dir;
2409
2410             // now change direction if backwards
2411             if (cave->creatures_backwards)
2412               ccw = !ccw;
2413
2414             if (ccw)
2415             {
2416               dirn = (dir + 3) & 3;    // fast turn
2417               dirp = (dir + 1) & 3;    // slow turn
2418             }
2419             else
2420             {
2421               dirn = (dir + 1) & 3;    // fast turn
2422               dirp = (dir + 3) & 3;    // slow turn
2423             }
2424
2425             if (is_space_dir(cave, x, y, creature_move[dirn]))
2426               move(cave, x, y, creature_move[dirn], base + dirn);    // turn and move to preferred dir
2427             else if (is_space_dir(cave, x, y, creature_move[dir]))
2428               move(cave, x, y, creature_move[dir], base + dir);    // go on
2429             else
2430               store(cave, x, y, base + dirp);    // turn in place if nothing else possible
2431           }
2432           break;
2433
2434         case O_WAITING_STONE:
2435           if (is_space_dir(cave, x, y, grav_compat))
2436           {
2437             // beginning to fall
2438             // it wakes up.
2439             move(cave, x, y, grav_compat, O_CHASING_STONE);
2440           }
2441           else if (sloped_dir(cave, x, y, grav_compat, opposite[grav_compat]))
2442           {
2443             // rolling down a brick wall or a stone
2444             if (sloped_dir(cave, x, y, grav_compat, cw_fourth[grav_compat]) &&
2445                 is_space_dir(cave, x, y, cw_fourth[grav_compat]) &&
2446                 is_space_dir(cave, x, y, cw_eighth[grav_compat]))
2447             {
2448               // maybe rolling left - see case O_STONE to understand why we use cw_fourth here
2449               move(cave, x, y, cw_fourth[grav_compat], O_WAITING_STONE);
2450             }
2451             else if (sloped_dir(cave, x, y, grav_compat, ccw_fourth[grav_compat]) &&
2452                      is_space_dir(cave, x, y, ccw_fourth[grav_compat]) &&
2453                      is_space_dir(cave, x, y, ccw_eighth[grav_compat]))
2454             {
2455               // or maybe right
2456               move(cave, x, y, ccw_fourth[grav_compat], O_WAITING_STONE);
2457             }
2458           }
2459           break;
2460
2461         case O_CHASING_STONE:
2462           {
2463             int px = cave->px[0];
2464             int py = cave->py[0];
2465             boolean horizontal = gd_rand_boolean(cave->random);
2466             boolean dont_move = FALSE;
2467             int i = 3;
2468
2469             // try to move...
2470             while (1)
2471             {
2472               if (horizontal)
2473               {
2474                 // ------------------------------------------------------------
2475                 // check for a horizontal movement
2476                 // ------------------------------------------------------------
2477                 if (px == x)
2478                 {
2479                   // if coordinates are the same
2480                   i -= 1;
2481                   horizontal = !horizontal;
2482
2483                   if (i == 2)
2484                     continue;
2485                 }
2486                 else
2487                 {
2488                   if (px > x && is_space_dir(cave, x, y, GD_MV_RIGHT))
2489                   {
2490                     move(cave, x, y, GD_MV_RIGHT, O_CHASING_STONE);
2491                     dont_move = TRUE;
2492                     break;
2493                   }
2494                   else if (px < x && is_space_dir(cave, x, y, GD_MV_LEFT))
2495                   {
2496                     move(cave, x, y, GD_MV_LEFT, O_CHASING_STONE);
2497                     dont_move = TRUE;
2498                     break;
2499                   }
2500                   else
2501                   {
2502                     i -= 2;
2503                     if (i == 1)
2504                     {
2505                       horizontal = !horizontal;
2506                       continue;
2507                     }
2508                   }
2509                 }
2510               }
2511               else
2512               {
2513                 // ------------------------------------------------------------
2514                 // check for a vertical movement
2515                 // ------------------------------------------------------------
2516                 if (py == y)
2517                 {
2518                   // if coordinates are the same
2519                   i -= 1;
2520                   horizontal = !horizontal;
2521                   if (i == 2)
2522                     continue;
2523                 }
2524                 else
2525                 {
2526                   if (py > y && is_space_dir(cave, x, y, GD_MV_DOWN))
2527                   {
2528                     move(cave, x, y, GD_MV_DOWN, O_CHASING_STONE);
2529                     dont_move = TRUE;
2530                     break;
2531                   }
2532                   else if (py < y && is_space_dir(cave, x, y, GD_MV_UP))
2533                   {
2534                     move(cave, x, y, GD_MV_UP, O_CHASING_STONE);
2535                     dont_move = TRUE;
2536                     break;
2537                   }
2538                   else
2539                   {
2540                     i -= 2;
2541                     if (i == 1)
2542                     {
2543                       horizontal = !horizontal;
2544                       continue;
2545                     }
2546                   }
2547                 }
2548               }
2549
2550               if (i != 0)
2551                 dont_move = TRUE;
2552
2553               break;
2554             }
2555
2556             // if we should move in both directions, but can not move in any, stop.
2557             if (!dont_move)
2558             {
2559               if (horizontal)
2560               {
2561                 // check for horizontal
2562                 if (x >= px)
2563                 {
2564                   if (is_space_dir(cave, x, y, GD_MV_UP) &&
2565                       is_space_dir(cave, x, y, GD_MV_UP_LEFT))
2566                     move(cave, x, y, GD_MV_UP, O_CHASING_STONE);
2567                   else if (is_space_dir(cave, x, y, GD_MV_DOWN) &&
2568                            is_space_dir(cave, x, y, GD_MV_DOWN_LEFT))
2569                     move(cave, x, y, GD_MV_DOWN, O_CHASING_STONE);
2570                 }
2571                 else
2572                 {
2573                   if (is_space_dir(cave, x, y, GD_MV_UP) &&
2574                       is_space_dir(cave, x, y, GD_MV_UP_RIGHT))
2575                     move(cave, x, y, GD_MV_UP, O_CHASING_STONE);
2576                   else if (is_space_dir(cave, x, y, GD_MV_DOWN) &&
2577                            is_space_dir(cave, x, y, GD_MV_DOWN_RIGHT))
2578                     move(cave, x, y, GD_MV_DOWN, O_CHASING_STONE);
2579                 }
2580               }
2581               else
2582               {
2583                 // check for vertical
2584                 if (y >= py)
2585                 {
2586                   if (is_space_dir(cave, x, y, GD_MV_LEFT) &&
2587                       is_space_dir(cave, x, y, GD_MV_UP_LEFT))
2588                     move(cave, x, y, GD_MV_LEFT, O_CHASING_STONE);
2589                   else if (is_space_dir(cave, x, y, GD_MV_RIGHT) &&
2590                            is_space_dir(cave, x, y, GD_MV_UP_RIGHT))
2591                     move(cave, x, y, GD_MV_RIGHT, O_CHASING_STONE);
2592                 }
2593                 else
2594                 {
2595                   if (is_space_dir(cave, x, y, GD_MV_LEFT) &&
2596                       is_space_dir(cave, x, y, GD_MV_DOWN_LEFT))
2597                     move(cave, x, y, GD_MV_LEFT, O_CHASING_STONE);
2598                   else if (is_space_dir(cave, x, y, GD_MV_RIGHT) &&
2599                            is_space_dir(cave, x, y, GD_MV_DOWN_RIGHT))
2600                     move(cave, x, y, GD_MV_RIGHT, O_CHASING_STONE);
2601                 }
2602               }
2603             }
2604           }
2605           break;
2606
2607         case O_REPLICATOR:
2608           if (cave->replicators_wait_frame == 0 &&
2609               cave->replicators_active &&
2610               !cave->gravity_disabled)
2611           {
2612             // only replicate, if space is under it.
2613             // do not replicate players!
2614             // also obeys gravity settings.
2615             // only replicate element if it is not a scanned one
2616             // do not replicate space... that condition looks like it
2617             // makes no sense, but otherwise it generates SCANNED spaces,
2618             // which cannot be "collected" by the player, so he cannot run
2619             // under a replicator
2620             if (is_space_dir(cave, x, y, cave->gravity) &&
2621                 !is_player_dir(cave, x, y, opposite[cave->gravity]) &&
2622                 !is_space_dir(cave, x, y, opposite[cave->gravity]))
2623             {
2624               store_dir(cave, x, y, cave->gravity, get_dir(cave, x, y, opposite[cave->gravity]));
2625               gd_sound_play(cave, GD_S_REPLICATOR, O_REPLICATOR, x, y);
2626             }
2627           }
2628           break;
2629
2630         case O_BITER_1:
2631         case O_BITER_2:
2632         case O_BITER_3:
2633         case O_BITER_4:
2634           if (cave->biters_wait_frame == 0)
2635           {
2636             static GdDirection biter_move[] =
2637             {
2638               GD_MV_UP,
2639               GD_MV_RIGHT,
2640               GD_MV_DOWN,
2641               GD_MV_LEFT
2642             };
2643
2644             // direction, last two bits 0..3
2645             int dir = get(cave, x, y) - O_BITER_1;
2646             int dirn = (dir + 3) & 3;
2647             int dirp = (dir + 1) & 3;
2648             int i;
2649             GdElement made_sound_of = O_NONE;
2650
2651             for (i = 0; i < ARRAY_SIZE (biter_try); i++)
2652             {
2653               if (is_element_dir(cave, x, y, biter_move[dir], biter_try[i]))
2654               {
2655                 move(cave, x, y, biter_move[dir], O_BITER_1 + dir);
2656                 if (biter_try[i] != O_SPACE)
2657                   made_sound_of = O_BITER_1;    // sound of a biter eating
2658                 break;
2659               }
2660               else if (is_element_dir(cave, x, y, biter_move[dirn], biter_try[i]))
2661               {
2662                 move(cave, x, y, biter_move[dirn], O_BITER_1 + dirn);
2663                 if (biter_try[i] != O_SPACE)
2664                   made_sound_of = O_BITER_1;    // sound of a biter eating
2665                 break;
2666               }
2667               else if (is_element_dir(cave, x, y, biter_move[dirp], biter_try[i]))
2668               {
2669                 move(cave, x, y, biter_move[dirp], O_BITER_1 + dirp);
2670                 if (biter_try[i] != O_SPACE)
2671                   made_sound_of = O_BITER_1;    // sound of a biter eating
2672                 break;
2673               }
2674             }
2675
2676             if (i == ARRAY_SIZE(biter_try))
2677               // i = number of elements in array: could not move, so just turn
2678               store(cave, x, y, O_BITER_1 + dirp);
2679             else if (biter_try[i] == O_STONE)
2680             {
2681               // if there was a stone there, where we moved...
2682               // do not eat stones, just throw them back
2683               store(cave, x, y, O_STONE);
2684               made_sound_of = O_STONE;
2685             }
2686
2687             // if biter did move, we had sound. play it.
2688             if (made_sound_of != O_NONE)
2689               play_sound_of_element(cave, made_sound_of, x, y);
2690           }
2691           break;
2692
2693         case O_DRAGONFLY_1:
2694         case O_DRAGONFLY_2:
2695         case O_DRAGONFLY_3:
2696         case O_DRAGONFLY_4:
2697           // check if touches a voodoo
2698           if (get_dir(cave, x, y, GD_MV_LEFT)  == O_VOODOO ||
2699               get_dir(cave, x, y, GD_MV_RIGHT) == O_VOODOO ||
2700               get_dir(cave, x, y, GD_MV_UP)    == O_VOODOO ||
2701               get_dir(cave, x, y, GD_MV_DOWN)  == O_VOODOO)
2702             cave->voodoo_touched = TRUE;
2703
2704           // check if touches something bad and should explode (includes voodoo by the flags)
2705           if (blows_up_flies_dir(cave, x, y, GD_MV_DOWN) ||
2706               blows_up_flies_dir(cave, x, y, GD_MV_UP) ||
2707               blows_up_flies_dir(cave, x, y, GD_MV_LEFT) ||
2708               blows_up_flies_dir(cave, x, y, GD_MV_RIGHT))
2709             explode (cave, x, y);
2710           // otherwise move
2711           else
2712           {
2713             const GdDirection *creature_move;
2714             boolean ccw = rotates_ccw(cave, x, y);    // check if default is counterclockwise
2715             GdElement base = O_DRAGONFLY_1;    // base element number (which is like O_***_1)
2716             int dir, dirn;    // direction
2717
2718             dir = get(cave, x, y)-base;    // facing where
2719             creature_move = cave->creatures_backwards ? creature_chdir : creature_dir;
2720
2721             // now change direction if backwards
2722             if (cave->creatures_backwards)
2723               ccw = !ccw;
2724
2725             if (ccw)
2726               dirn = (dir + 3) & 3;    // fast turn
2727             else
2728               dirn = (dir + 1) & 3;    // fast turn
2729
2730             // if can move forward, does so.
2731             if (is_space_dir(cave, x, y, creature_move[dir]))
2732               move(cave, x, y, creature_move[dir], base + dir);
2733             else
2734               // otherwise turns 90 degrees in place.
2735               store(cave, x, y, base + dirn);
2736           }
2737           break;
2738
2739         case O_BLADDER:
2740           store(cave, x, y, O_BLADDER_1);
2741           break;
2742
2743         case O_BLADDER_1:
2744         case O_BLADDER_2:
2745         case O_BLADDER_3:
2746         case O_BLADDER_4:
2747         case O_BLADDER_5:
2748         case O_BLADDER_6:
2749         case O_BLADDER_7:
2750         case O_BLADDER_8:
2751           // bladder with any delay state: try to convert to clock.
2752           if (is_element_dir(cave, x, y, opposite[grav_compat], cave->bladder_converts_by) ||
2753               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))
2754           {
2755             // if touches the specified element, let it be a clock
2756             store(cave, x, y, O_PRE_CLOCK_1);
2757
2758             // plays the bladder convert sound
2759             play_sound_of_element(cave, O_PRE_CLOCK_1, x, y);
2760           }
2761           else
2762           {
2763             // is space over the bladder?
2764             if (is_space_dir(cave, x, y, opposite[grav_compat]))
2765             {
2766               if (get(cave, x, y) == O_BLADDER_8)
2767               {
2768                 // if it is a bladder 8, really move up
2769                 move(cave, x, y, opposite[grav_compat], O_BLADDER_1);
2770                 play_sound_of_element(cave, O_BLADDER, x, y);
2771               }
2772               else
2773                 // if smaller delay, just increase delay.
2774                 next(cave, x, y);
2775             }
2776             else
2777               // if not space, is something sloped over the bladder?
2778               if (sloped_for_bladder_dir(cave, x, y, opposite[grav_compat]) &&
2779                   sloped_dir(cave, x, y, opposite[grav_compat], opposite[grav_compat]))
2780               {
2781                 if (sloped_dir(cave, x, y, opposite[grav_compat], ccw_fourth[opposite[grav_compat]]) &&
2782                     is_space_dir(cave, x, y, ccw_fourth[opposite[grav_compat]]) &&
2783                     is_space_dir(cave, x, y, ccw_eighth[opposite[grav_compat]]))
2784                 {
2785                   // rolling up, to left
2786                   if (get(cave, x, y) == O_BLADDER_8)
2787                   {
2788                     // if it is a bladder 8, really roll
2789                     move(cave, x, y, ccw_fourth[opposite[grav_compat]], O_BLADDER_8);
2790                     play_sound_of_element(cave, O_BLADDER, x, y);
2791                   }
2792                   else
2793                     // if smaller delay, just increase delay.
2794                     next(cave, x, y);
2795                 }
2796                 else if (sloped_dir(cave, x, y, opposite[grav_compat], cw_fourth[opposite[grav_compat]]) &&
2797                          is_space_dir(cave, x, y, cw_fourth[opposite[grav_compat]]) &&
2798                          is_space_dir(cave, x, y, cw_eighth[opposite[grav_compat]]))
2799                 {
2800                   // rolling up, to left
2801                   if (get(cave, x, y) == O_BLADDER_8)
2802                   {
2803                     // if it is a bladder 8, really roll
2804                     move(cave, x, y, cw_fourth[opposite[grav_compat]], O_BLADDER_8);
2805                     play_sound_of_element(cave, O_BLADDER, x, y);
2806                   }
2807                   else
2808                     // if smaller delay, just increase delay.
2809                     next(cave, x, y);
2810                 }
2811               }
2812
2813             // no space, no sloped thing over it - store bladder 1 and that is for now.
2814               else
2815                 store(cave, x, y, O_BLADDER_1);
2816           }
2817           break;
2818
2819         case O_GHOST:
2820           if (blows_up_flies_dir(cave, x, y, GD_MV_DOWN) ||
2821               blows_up_flies_dir(cave, x, y, GD_MV_UP) ||
2822               blows_up_flies_dir(cave, x, y, GD_MV_LEFT) ||
2823               blows_up_flies_dir(cave, x, y, GD_MV_RIGHT))
2824             explode (cave, x, y);
2825           else
2826           {
2827             int i;
2828
2829             // the ghost is given four possibilities to move.
2830             for (i = 0; i < 4; i++)
2831             {
2832               static GdDirection dirs[] =
2833               {
2834                 GD_MV_UP,
2835                 GD_MV_DOWN,
2836                 GD_MV_LEFT,
2837                 GD_MV_RIGHT
2838               };
2839               GdDirection random_dir;
2840
2841               random_dir = dirs[gd_rand_int_range(cave->random, 0, ARRAY_SIZE(dirs))];
2842               if (is_space_dir(cave, x, y, random_dir))
2843               {
2844                 move(cave, x, y, random_dir, O_GHOST);
2845                 break;    // ghost did move -> exit loop
2846               }
2847             }
2848           }
2849           break;
2850
2851           // ============================================================================
2852           //    A C T I V E    E L E M E N T S
2853           // ============================================================================
2854
2855         case O_AMOEBA:
2856           // emulating BD1 amoeba+magic wall bug
2857           if (cave->convert_amoeba_this_frame && amoeba_found_enclosed)
2858           {
2859             store(cave, x, y, cave->amoeba_enclosed_effect);
2860             break;
2861           }
2862
2863           amoeba_count++;
2864           switch (cave->amoeba_state)
2865           {
2866             case GD_AM_TOO_BIG:
2867               store(cave, x, y, cave->amoeba_too_big_effect);
2868               break;
2869
2870             case GD_AM_ENCLOSED:
2871               store(cave, x, y, cave->amoeba_enclosed_effect);
2872               break;
2873
2874             case GD_AM_SLEEPING:
2875             case GD_AM_AWAKE:
2876               // if no amoeba found during THIS SCAN yet, which was able to grow, check this one.
2877               if (amoeba_found_enclosed)
2878                 // if still found enclosed, check all four directions, if this one is able to grow.
2879                 if (amoeba_eats_dir(cave, x, y, GD_MV_UP) ||
2880                     amoeba_eats_dir(cave, x, y, GD_MV_DOWN) ||
2881                     amoeba_eats_dir(cave, x, y, GD_MV_LEFT) ||
2882                     amoeba_eats_dir(cave, x, y, GD_MV_RIGHT))
2883                 {
2884                   // not enclosed. this is a local (per scan) flag!
2885                   amoeba_found_enclosed = FALSE;
2886                   cave->amoeba_state = GD_AM_AWAKE;
2887                 }
2888
2889               // if alive, check in which dir to grow (or not)
2890               if (cave->amoeba_state == GD_AM_AWAKE)
2891               {
2892                 if (gd_rand_int_range(cave->random, 0, 1000000) < cave->amoeba_growth_prob)
2893                 {
2894                   switch (gd_rand_int_range(cave->random, 0, 4))
2895                   {
2896                     // decided to grow, choose a random direction.
2897                     case 0:    // let this be up. numbers indifferent.
2898                       if (amoeba_eats_dir(cave, x, y, GD_MV_UP))
2899                         store_dir(cave, x, y, GD_MV_UP, O_AMOEBA);
2900                       break;
2901
2902                     case 1:    // down
2903                       if (amoeba_eats_dir(cave, x, y, GD_MV_DOWN))
2904                         store_dir(cave, x, y, GD_MV_DOWN, O_AMOEBA);
2905                       break;
2906
2907                     case 2:    // left
2908                       if (amoeba_eats_dir(cave, x, y, GD_MV_LEFT))
2909                         store_dir(cave, x, y, GD_MV_LEFT, O_AMOEBA);
2910                       break;
2911
2912                     case 3:    // right
2913                       if (amoeba_eats_dir(cave, x, y, GD_MV_RIGHT))
2914                         store_dir(cave, x, y, GD_MV_RIGHT, O_AMOEBA);
2915                       break;
2916                   }
2917                 }
2918               }
2919               break;
2920
2921           }
2922           break;
2923
2924         case O_AMOEBA_2:
2925           amoeba_2_count++;
2926           // check if it is touching an amoeba, and explosion is enabled
2927           if (cave->amoeba_2_explodes_by_amoeba &&
2928               (is_element_dir(cave, x, y, GD_MV_DOWN, O_AMOEBA) ||
2929                is_element_dir(cave, x, y, GD_MV_UP, O_AMOEBA) ||
2930                is_element_dir(cave, x, y, GD_MV_LEFT, O_AMOEBA) ||
2931                is_element_dir(cave, x, y, GD_MV_RIGHT, O_AMOEBA)))
2932             explode (cave, x, y);
2933           else
2934             switch (cave->amoeba_2_state)
2935             {
2936               case GD_AM_TOO_BIG:
2937                 store(cave, x, y, cave->amoeba_2_too_big_effect);
2938                 break;
2939
2940               case GD_AM_ENCLOSED:
2941                 store(cave, x, y, cave->amoeba_2_enclosed_effect);
2942                 break;
2943
2944               case GD_AM_SLEEPING:
2945               case GD_AM_AWAKE:
2946                 // if no amoeba found during THIS SCAN yet, which was able to grow, check this one.
2947                 if (amoeba_2_found_enclosed)
2948                   if (amoeba_eats_dir(cave, x, y, GD_MV_UP) ||
2949                       amoeba_eats_dir(cave, x, y, GD_MV_DOWN) ||
2950                       amoeba_eats_dir(cave, x, y, GD_MV_LEFT) ||
2951                       amoeba_eats_dir(cave, x, y, GD_MV_RIGHT))
2952                   {
2953                     // not enclosed. this is a local (per scan) flag!
2954                     amoeba_2_found_enclosed = FALSE;
2955                     cave->amoeba_2_state = GD_AM_AWAKE;
2956                   }
2957
2958                 // if it is alive, decide if it attempts to grow
2959                 if (cave->amoeba_2_state == GD_AM_AWAKE)
2960                   if (gd_rand_int_range(cave->random, 0, 1000000) < cave->amoeba_2_growth_prob)
2961                   {
2962                     switch (gd_rand_int_range(cave->random, 0, 4))
2963                     {
2964                       // decided to grow, choose a random direction.
2965                       case 0:    // let this be up. numbers indifferent.
2966                         if (amoeba_eats_dir(cave, x, y, GD_MV_UP))
2967                           store_dir(cave, x, y, GD_MV_UP, O_AMOEBA_2);
2968                         break;
2969
2970                       case 1:    // down
2971                         if (amoeba_eats_dir(cave, x, y, GD_MV_DOWN))
2972                           store_dir(cave, x, y, GD_MV_DOWN, O_AMOEBA_2);
2973                         break;
2974
2975                       case 2:    // left
2976                         if (amoeba_eats_dir(cave, x, y, GD_MV_LEFT))
2977                           store_dir(cave, x, y, GD_MV_LEFT, O_AMOEBA_2);
2978                         break;
2979
2980                       case 3:    // right
2981                         if (amoeba_eats_dir(cave, x, y, GD_MV_RIGHT))
2982                           store_dir(cave, x, y, GD_MV_RIGHT, O_AMOEBA_2);
2983                         break;
2984                     }
2985                   }
2986                 break;
2987
2988             }
2989           break;
2990
2991         case O_ACID:
2992           // choose randomly, if it spreads
2993           if (gd_rand_int_range(cave->random, 0, 1000000) <= cave->acid_spread_ratio)
2994           {
2995             // the current one explodes
2996             store(cave, x, y, cave->acid_turns_to);
2997
2998             // and if neighbours are eaten, put acid there.
2999             if (is_element_dir(cave, x, y, GD_MV_UP, cave->acid_eats_this))
3000             {
3001               play_sound_of_element(cave, O_ACID, x, y);
3002               store_dir(cave, x, y, GD_MV_UP, O_ACID);
3003             }
3004
3005             if (is_element_dir(cave, x, y, GD_MV_DOWN, cave->acid_eats_this))
3006             {
3007               play_sound_of_element(cave, O_ACID, x, y);
3008               store_dir(cave, x, y, GD_MV_DOWN, O_ACID);
3009             }
3010
3011             if (is_element_dir(cave, x, y, GD_MV_LEFT, cave->acid_eats_this))
3012             {
3013               play_sound_of_element(cave, O_ACID, x, y);
3014               store_dir(cave, x, y, GD_MV_LEFT, O_ACID);
3015             }
3016
3017             if (is_element_dir(cave, x, y, GD_MV_RIGHT, cave->acid_eats_this))
3018             {
3019               play_sound_of_element(cave, O_ACID, x, y);
3020               store_dir(cave, x, y, GD_MV_RIGHT, O_ACID);
3021             }
3022           }
3023           break;
3024
3025         case O_WATER:
3026           found_water = TRUE;
3027           if (!cave->water_does_not_flow_down &&
3028               is_space_dir(cave, x, y, GD_MV_DOWN))
3029             // emulating the odd behaviour in crdr
3030             store_dir(cave, x, y, GD_MV_DOWN, O_WATER_1);
3031
3032           if (is_space_dir(cave, x, y, GD_MV_UP))
3033             store_dir(cave, x, y, GD_MV_UP, O_WATER_1);
3034
3035           if (is_space_dir(cave, x, y, GD_MV_LEFT))
3036             store_dir(cave, x, y, GD_MV_LEFT, O_WATER_1);
3037
3038           if (is_space_dir(cave, x, y, GD_MV_RIGHT))
3039             store_dir(cave, x, y, GD_MV_RIGHT, O_WATER_1);
3040           break;
3041
3042         case O_WATER_16:
3043           store(cave, x, y, O_WATER);
3044           break;
3045
3046         case O_H_EXPANDING_WALL:
3047         case O_V_EXPANDING_WALL:
3048         case O_H_EXPANDING_STEEL_WALL:
3049         case O_V_EXPANDING_STEEL_WALL:
3050           // checks first if direction is changed.
3051           if (((get(cave, x, y) == O_H_EXPANDING_WALL ||
3052                 get(cave, x, y) == O_H_EXPANDING_STEEL_WALL) &&
3053                !cave->expanding_wall_changed) ||
3054               ((get(cave, x, y) == O_V_EXPANDING_WALL ||
3055                 get(cave, x, y) == O_V_EXPANDING_STEEL_WALL) &&
3056                cave->expanding_wall_changed))
3057           {
3058             if (is_space_dir(cave, x, y, GD_MV_LEFT))
3059             {
3060               store_dir(cave, x, y, GD_MV_LEFT, get(cave, x, y));
3061               play_sound_of_element(cave, get(cave, x, y), x, y);
3062             }
3063
3064             if (is_space_dir(cave, x, y, GD_MV_RIGHT)) {
3065               store_dir(cave, x, y, GD_MV_RIGHT, get(cave, x, y));
3066               play_sound_of_element(cave, get(cave, x, y), x, y);
3067             }
3068           }
3069           else
3070           {
3071             if (is_space_dir(cave, x, y, GD_MV_UP)) {
3072               store_dir(cave, x, y, GD_MV_UP, get(cave, x, y));
3073               play_sound_of_element(cave, get(cave, x, y), x, y);
3074             }
3075
3076             if (is_space_dir(cave, x, y, GD_MV_DOWN)) {
3077               store_dir(cave, x, y, GD_MV_DOWN, get(cave, x, y));
3078               play_sound_of_element(cave, get(cave, x, y), x, y);
3079             }
3080           }
3081           break;
3082
3083         case O_EXPANDING_WALL:
3084         case O_EXPANDING_STEEL_WALL:
3085           // the wall which grows in all four directions.
3086           if (is_space_dir(cave, x, y, GD_MV_LEFT))
3087           {
3088             store_dir(cave, x, y, GD_MV_LEFT, get(cave, x, y));
3089             play_sound_of_element(cave, get(cave, x, y), x, y);
3090           }
3091
3092           if (is_space_dir(cave, x, y, GD_MV_RIGHT)) {
3093             store_dir(cave, x, y, GD_MV_RIGHT, get(cave, x, y));
3094             play_sound_of_element(cave, get(cave, x, y), x, y);
3095           }
3096
3097           if (is_space_dir(cave, x, y, GD_MV_UP)) {
3098             store_dir(cave, x, y, GD_MV_UP, get(cave, x, y));
3099             play_sound_of_element(cave, get(cave, x, y), x, y);
3100           }
3101
3102           if (is_space_dir(cave, x, y, GD_MV_DOWN)) {
3103             store_dir(cave, x, y, GD_MV_DOWN, get(cave, x, y));
3104             play_sound_of_element(cave, get(cave, x, y), x, y);
3105           }
3106           break;
3107
3108         case O_SLIME:
3109 #if 1
3110           ; // to make compilers happy ...
3111 #else
3112           Info("Step[%03d]", cave->frame); // XXX
3113 #endif
3114           int rrr = gd_cave_c64_random(cave);
3115 #if 1
3116 #else
3117           Info(".Rand[%03d].Perm[%03d].Result[%d]\n", rrr, cave->slime_permeability_c64,
3118                (rrr & cave->slime_permeability_c64) == 0);
3119 #endif
3120           /*
3121            * unpredictable: gd_rand_int
3122            * predictable: c64 predictable random generator.
3123            *    for predictable, a random number is generated,
3124            *    whether or not it is even possible that the stone will be able to pass.
3125            */
3126           if (cave->slime_predictable ? ((rrr /* XXX */ & cave->slime_permeability_c64) == 0) : gd_rand_int_range(cave->random, 0, 1000000) < cave->slime_permeability)
3127           {
3128             GdDirection grav = cave->gravity;
3129             GdDirection oppos = opposite[cave->gravity];
3130
3131             // space under the slime? elements may pass from top to bottom then.
3132             if (is_space_dir(cave, x, y, grav))
3133             {
3134               if (get_dir(cave, x, y, oppos) == cave->slime_eats_1)
3135               {
3136                 // output a falling xy under
3137                 store_dir(cave, x, y, grav, cave->slime_converts_1);
3138
3139                 store_dir(cave, x, y, oppos, O_SPACE);
3140                 play_sound_of_element(cave, O_SLIME, x, y);
3141               }
3142               else if (get_dir(cave, x, y, oppos) == cave->slime_eats_2)
3143               {
3144                 store_dir(cave, x, y, grav, cave->slime_converts_2);
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) == cave->slime_eats_3)
3149               {
3150                 store_dir(cave, x, y, grav, cave->slime_converts_3);
3151                 store_dir(cave, x, y, oppos, O_SPACE);
3152                 play_sound_of_element(cave, O_SLIME, x, y);
3153               }
3154               else if (get_dir(cave, x, y, oppos) == O_WAITING_STONE)
3155               {
3156                 // waiting stones pass without awakening
3157                 store_dir(cave, x, y, grav, O_WAITING_STONE);
3158                 store_dir(cave, x, y, oppos, O_SPACE);
3159                 play_sound_of_element(cave, O_SLIME, x, y);
3160               }
3161               else if (get_dir(cave, x, y, oppos) == O_CHASING_STONE)
3162               {
3163                 // chasing stones pass
3164                 store_dir(cave, x, y, grav, O_CHASING_STONE);
3165                 store_dir(cave, x, y, oppos, O_SPACE);
3166                 play_sound_of_element(cave, O_SLIME, x, y);
3167               }
3168             }
3169             else
3170             {
3171               // or space over the slime? elements may pass from bottom to up then.
3172               if (is_space_dir(cave, x, y, oppos))
3173               {
3174                 if (get_dir(cave, x, y, grav) == O_BLADDER)
3175                 {
3176                   // bladders move UP the slime
3177                   store_dir(cave, x, y, grav, O_SPACE);
3178                   store_dir(cave, x, y, oppos, O_BLADDER_1);
3179                   play_sound_of_element(cave, O_SLIME, x, y);
3180                 }
3181                 else if (get_dir(cave, x, y, grav) == O_FLYING_STONE)
3182                 {
3183                   store_dir(cave, x, y, grav, O_SPACE);
3184                   store_dir(cave, x, y, oppos, O_FLYING_STONE_F);
3185                   play_sound_of_element(cave, O_SLIME, x, y);
3186                 }
3187                 else if (get_dir(cave, x, y, grav) == O_FLYING_DIAMOND)
3188                 {
3189                   store_dir(cave, x, y, grav, O_SPACE);
3190                   store_dir(cave, x, y, oppos, O_FLYING_DIAMOND_F);
3191                   play_sound_of_element(cave, O_SLIME, x, y);
3192                 }
3193               }
3194             }
3195           }
3196           break;
3197
3198         case O_FALLING_WALL:
3199           if (is_space_dir(cave, x, y, grav_compat))
3200           {
3201             // try falling if space under.
3202             int yy;
3203
3204             for (yy = y + 1; yy < y + cave->h; yy++)
3205               // yy < y + cave->h is to check everything OVER the wall - since caves wrap around !!
3206               if (get(cave, x, yy) != O_SPACE)
3207                 // stop cycle when other than space
3208                 break;
3209
3210             // if scanning stopped by a player... start falling!
3211             if (get(cave, x, yy) == O_PLAYER ||
3212                 get(cave, x, yy) == O_PLAYER_GLUED ||
3213                 get(cave, x, yy) == O_PLAYER_BOMB)
3214             {
3215               move(cave, x, y, grav_compat, O_FALLING_WALL_F);
3216               // no sound when the falling wall starts falling!
3217             }
3218           }
3219           break;
3220
3221         case O_FALLING_WALL_F:
3222           switch (get_dir(cave, x, y, grav_compat))
3223           {
3224             case O_PLAYER:
3225             case O_PLAYER_GLUED:
3226             case O_PLAYER_BOMB:
3227               // if player under, it explodes - the falling wall, not the player!
3228               explode(cave, x, y);
3229               break;
3230
3231             case O_SPACE:
3232               // continue falling
3233               move(cave, x, y, grav_compat, O_FALLING_WALL_F);
3234               break;
3235
3236             default:
3237               // stop
3238               play_sound_of_element(cave, get(cave, x, y), x, y);
3239               store(cave, x, y, O_FALLING_WALL);
3240               break;
3241           }
3242           break;
3243
3244           // ============================================================================
3245           //    C O N V E Y O R    B E L T S
3246           // ============================================================================
3247
3248         case O_CONVEYOR_RIGHT:
3249         case O_CONVEYOR_LEFT:
3250           // only works if gravity is up or down!!!
3251           // first, check for gravity and running belts.
3252           if (!cave->gravity_disabled && cave->conveyor_belts_active)
3253           {
3254             const GdDirection *dir;
3255             boolean left;
3256
3257             // decide direction
3258             left = get(cave, x, y) != O_CONVEYOR_RIGHT;
3259             if (cave->conveyor_belts_direction_changed)
3260               left = !left;
3261             dir = left ? ccw_eighth : cw_eighth;
3262
3263             // CHECK IF IT CONVEYS THE ELEMENT ABOVE IT
3264             // if gravity is normal, and the conveyor belt has something
3265             // ABOVE which can be moved
3266             // OR
3267             // the gravity is up, so anything that should float now goes
3268             // DOWN and touches the conveyor
3269             if ((cave->gravity == GD_MV_DOWN &&
3270                  moved_by_conveyor_top_dir(cave, x, y, GD_MV_UP)) ||
3271                 (cave->gravity == GD_MV_UP &&
3272                  moved_by_conveyor_bottom_dir(cave, x, y, GD_MV_UP)))
3273             {
3274               if (!is_scanned_dir(cave, x, y, GD_MV_UP) &&
3275                   is_space_dir(cave, x, y, dir[GD_MV_UP]))
3276               {
3277                 store_dir(cave, x, y, dir[GD_MV_UP], get_dir(cave, x, y, GD_MV_UP));    // move
3278                 store_dir(cave, x, y, GD_MV_UP, O_SPACE);    // and place a space.
3279               }
3280             }
3281
3282             // CHECK IF IT CONVEYS THE ELEMENT BELOW IT
3283             if ((cave->gravity == GD_MV_UP &&
3284                  moved_by_conveyor_top_dir(cave, x, y, GD_MV_DOWN)) ||
3285                 (cave->gravity == GD_MV_DOWN &&
3286                  moved_by_conveyor_bottom_dir(cave, x, y, GD_MV_DOWN)))
3287             {
3288               if (!is_scanned_dir(cave, x, y, GD_MV_DOWN) &&
3289                   is_space_dir(cave, x, y, dir[GD_MV_DOWN]))
3290               {
3291                 store_dir(cave, x, y, dir[GD_MV_DOWN], get_dir(cave, x, y, GD_MV_DOWN));    // move
3292                 store_dir(cave, x, y, GD_MV_DOWN, O_SPACE);    // and clear.
3293               }
3294             }
3295           }
3296           break;
3297
3298           // ============================================================================
3299           //    R O C K E T S
3300           // ============================================================================
3301
3302         case O_ROCKET_1:
3303           if (is_space_dir(cave, x, y, GD_MV_RIGHT))
3304             move(cave, x, y, GD_MV_RIGHT, O_ROCKET_1);
3305           else
3306             explode(cave, x, y);
3307           break;
3308
3309         case O_ROCKET_2:
3310           if (is_space_dir(cave, x, y, GD_MV_UP))
3311             move(cave, x, y, GD_MV_UP, O_ROCKET_2);
3312           else
3313             explode(cave, x, y);
3314           break;
3315
3316         case O_ROCKET_3:
3317           if (is_space_dir(cave, x, y, GD_MV_LEFT))
3318             move(cave, x, y, GD_MV_LEFT, O_ROCKET_3);
3319           else
3320             explode(cave, x, y);
3321           break;
3322
3323         case O_ROCKET_4:
3324           if (is_space_dir(cave, x, y, GD_MV_DOWN))
3325             move(cave, x, y, GD_MV_DOWN, O_ROCKET_4);
3326           else
3327             explode(cave, x, y);
3328           break;
3329
3330           // ============================================================================
3331           //    S I M P L E   C H A N G I N G;   E X P L O S I O N S
3332           // ============================================================================
3333
3334         case O_EXPLODE_5:
3335           store(cave, x, y, cave->explosion_effect);
3336           break;
3337
3338         case O_NUT_EXPL_4:
3339           store(cave, x, y, O_DIAMOND);
3340           break;
3341
3342         case O_PRE_DIA_5:
3343           store(cave, x, y, cave->diamond_birth_effect);
3344           break;
3345
3346         case O_PRE_STONE_4:
3347           store(cave, x, y, O_STONE);
3348           break;
3349
3350         case O_NITRO_EXPL_4:
3351           store(cave, x, y, cave->nitro_explosion_effect);
3352           break;
3353
3354         case O_BOMB_EXPL_4:
3355           store(cave, x, y, cave->bomb_explosion_effect);
3356           break;
3357
3358         case O_AMOEBA_2_EXPL_4:
3359           store(cave, x, y, cave->amoeba_2_explosion_effect);
3360           break;
3361
3362         case O_GHOST_EXPL_4:
3363           {
3364             static GdElement ghost_explode[] =
3365             {
3366               O_SPACE, O_SPACE, O_DIRT, O_DIRT, O_CLOCK, O_CLOCK, O_PRE_OUTBOX,
3367               O_BOMB, O_BOMB, O_PLAYER, O_GHOST, O_BLADDER, O_DIAMOND, O_SWEET,
3368               O_WAITING_STONE, O_BITER_1
3369             };
3370
3371             store(cave, x, y, ghost_explode[gd_rand_int_range(cave->random, 0, ARRAY_SIZE(ghost_explode))]);
3372           }
3373           break;
3374
3375         case O_PRE_STEEL_4:
3376           store(cave, x, y, O_STEEL);
3377           break;
3378
3379         case O_PRE_CLOCK_4:
3380           store(cave, x, y, O_CLOCK);
3381           break;
3382
3383         case O_BOMB_TICK_7:
3384           explode(cave, x, y);
3385           break;
3386
3387         case O_TRAPPED_DIAMOND:
3388           if (cave->diamond_key_collected)
3389             store(cave, x, y, O_DIAMOND);
3390           break;
3391
3392         case O_PRE_OUTBOX:
3393           if (cave->gate_open) // if no more diamonds needed
3394             store(cave, x, y, O_OUTBOX);    // open outbox
3395           break;
3396
3397         case O_PRE_INVIS_OUTBOX:
3398           if (cave->gate_open)    // if no more diamonds needed
3399             store(cave, x, y, O_INVIS_OUTBOX);    // open outbox. invisible one :P
3400           break;
3401
3402         case O_INBOX:
3403           if (cave->hatched && !inbox_toggle)    // if it is time of birth
3404             store(cave, x, y, O_PRE_PL_1);
3405           inbox_toggle = !inbox_toggle;
3406           break;
3407
3408         case O_PRE_PL_3:
3409           store(cave, x, y, O_PLAYER);
3410           break;
3411
3412         case O_PRE_DIA_1:
3413         case O_PRE_DIA_2:
3414         case O_PRE_DIA_3:
3415         case O_PRE_DIA_4:
3416         case O_PRE_STONE_1:
3417         case O_PRE_STONE_2:
3418         case O_PRE_STONE_3:
3419         case O_BOMB_TICK_1:
3420         case O_BOMB_TICK_2:
3421         case O_BOMB_TICK_3:
3422         case O_BOMB_TICK_4:
3423         case O_BOMB_TICK_5:
3424         case O_BOMB_TICK_6:
3425         case O_PRE_STEEL_1:
3426         case O_PRE_STEEL_2:
3427         case O_PRE_STEEL_3:
3428         case O_BOMB_EXPL_1:
3429         case O_BOMB_EXPL_2:
3430         case O_BOMB_EXPL_3:
3431         case O_NUT_EXPL_1:
3432         case O_NUT_EXPL_2:
3433         case O_NUT_EXPL_3:
3434         case O_GHOST_EXPL_1:
3435         case O_GHOST_EXPL_2:
3436         case O_GHOST_EXPL_3:
3437         case O_EXPLODE_1:
3438         case O_EXPLODE_2:
3439         case O_EXPLODE_3:
3440         case O_EXPLODE_4:
3441         case O_PRE_PL_1:
3442         case O_PRE_PL_2:
3443         case O_PRE_CLOCK_1:
3444         case O_PRE_CLOCK_2:
3445         case O_PRE_CLOCK_3:
3446         case O_NITRO_EXPL_1:
3447         case O_NITRO_EXPL_2:
3448         case O_NITRO_EXPL_3:
3449         case O_AMOEBA_2_EXPL_1:
3450         case O_AMOEBA_2_EXPL_2:
3451         case O_AMOEBA_2_EXPL_3:
3452           // simply the next identifier
3453           next(cave, x, y);
3454           break;
3455
3456         case O_WATER_1:
3457         case O_WATER_2:
3458         case O_WATER_3:
3459         case O_WATER_4:
3460         case O_WATER_5:
3461         case O_WATER_6:
3462         case O_WATER_7:
3463         case O_WATER_8:
3464         case O_WATER_9:
3465         case O_WATER_10:
3466         case O_WATER_11:
3467         case O_WATER_12:
3468         case O_WATER_13:
3469         case O_WATER_14:
3470         case O_WATER_15:
3471           found_water = TRUE;    // for sound
3472           // simply the next identifier
3473           next(cave, x, y);
3474           break;
3475
3476         case O_BLADDER_SPENDER:
3477           if (is_space_dir(cave, x, y, opposite[grav_compat]))
3478           {
3479             store_dir(cave, x, y, opposite[grav_compat], O_BLADDER);
3480             store(cave, x, y, O_PRE_STEEL_1);
3481             play_sound_of_element(cave, O_BLADDER_SPENDER, x, y);
3482           }
3483           break;
3484
3485         default:
3486           // other inanimate elements that do nothing
3487           break;
3488       }
3489     }
3490   }
3491
3492
3493   // ============================================================================
3494   // POSTPROCESSING
3495   // ============================================================================
3496
3497   // another scan-like routine:
3498   // short explosions (for example, in bd1) started with explode_2.
3499   // internally we use explode_1; and change it to explode_2 if needed.
3500   if (cave->short_explosions)
3501   {
3502     for (y = 0; y < cave->h; y++)
3503     {
3504       for (x = 0; x < cave->w; x++)
3505       {
3506         if (is_first_stage_of_explosion(cave, x, y))
3507         {
3508           next(cave, x, y);    // select next frame of explosion
3509
3510           // forget scanned flag immediately
3511           store(cave, x, y, get(cave, x, y) & ~SCANNED);
3512         }
3513       }
3514     }
3515   }
3516
3517   // finally: forget "scanned" flags for objects.
3518   // also, check for time penalties.
3519   // these is something like an effect table, but we do not really use one.
3520   for (y = 0; y < cave->h; y++)
3521   {
3522     for (x = 0; x < cave->w; x++)
3523     {
3524       if (get(cave, x, y) & SCANNED)
3525         store(cave, x, y, get(cave, x, y) & ~SCANNED);
3526
3527       if (get(cave, x, y) == O_TIME_PENALTY)
3528       {
3529         store(cave, x, y, O_GRAVESTONE);
3530
3531         // there is time penalty for destroying the voodoo
3532         time_decrement_sec += cave->time_penalty;
3533       }
3534     }
3535   }
3536
3537   // this loop finds the coordinates of the player. needed for scrolling and chasing stone.
3538   // but we only do this, if a living player was found. if not yet, the setup
3539   // routine coordinates are used
3540   if (cave->player_state == GD_PL_LIVING)
3541   {
3542     if (cave->active_is_first_found)
3543     {
3544       // to be 1stb compatible, we do everything backwards.
3545       for (y = cave->h - 1; y >= 0; y--)
3546       {
3547         for (x = cave->w - 1; x >= 0; x--)
3548         {
3549           if (is_player(cave, x, y))
3550           {
3551             // here we remember the coordinates.
3552             cave->player_x = x;
3553             cave->player_y = y;
3554           }
3555         }
3556       }
3557     }
3558     else
3559     {
3560       // as in the original: look for the last one
3561       for (y = 0; y < cave->h; y++)
3562       {
3563         for (x = 0; x < cave->w; x++)
3564         {
3565           if (is_player(cave, x, y))
3566           {
3567             // here we remember the coordinates.
3568             cave->player_x = x;
3569             cave->player_y = y;
3570           }
3571         }
3572       }
3573     }
3574   }
3575
3576   // record coordinates of player for chasing stone
3577   for (i = 0; i < ARRAY_SIZE(cave->px) - 1; i++)
3578   {
3579     cave->px[i] = cave->px[i + 1];
3580     cave->py[i] = cave->py[i + 1];
3581   }
3582
3583   cave->px[ARRAY_SIZE(cave->px) - 1] = cave->player_x;
3584   cave->py[ARRAY_SIZE(cave->py) - 1] = cave->player_y;
3585
3586   // SCHEDULING
3587
3588   // update timing calculated by iterating and counting elements
3589   update_cave_speed(cave);
3590
3591   // cave 3 sounds. precedence is controlled by the sound_play function.
3592   // but we have to check amoeba&magic together as they had a different gritty sound when mixed
3593   if (found_water)
3594     gd_sound_play(cave, GD_S_WATER, O_WATER, -1, -1);
3595
3596   magic_sound = (cave->magic_wall_state == GD_MW_ACTIVE &&
3597                  cave->magic_wall_sound);
3598
3599   amoeba_sound = (cave->hatched && cave->amoeba_sound &&
3600                   ((amoeba_count > 0 && cave->amoeba_state == GD_AM_AWAKE) ||
3601                    (amoeba_2_count > 0 && cave->amoeba_2_state == GD_AM_AWAKE)));
3602
3603   if (amoeba_sound && magic_sound)
3604   {
3605     gd_sound_play(cave, GD_S_AMOEBA_MAGIC, O_AMOEBA, -1, -1);
3606   }
3607   else
3608   {
3609     if (amoeba_sound)
3610       gd_sound_play(cave, GD_S_AMOEBA, O_AMOEBA, -1, -1);
3611     else if (magic_sound)
3612       gd_sound_play(cave, GD_S_MAGIC_WALL, O_MAGIC_WALL, -1, -1);
3613   }
3614
3615   if (cave->hatched)
3616   {
3617     if ((amoeba_count   > 0 && cave->amoeba_state   == GD_AM_AWAKE) ||
3618         (amoeba_2_count > 0 && cave->amoeba_2_state == GD_AM_AWAKE))
3619       play_sound_of_element(cave, O_AMOEBA, x, y);
3620   }
3621
3622   // pneumatic hammer sound - overrides everything.
3623   if (cave->pneumatic_hammer_active_delay > 0)
3624     gd_sound_play(cave, GD_S_PNEUMATIC_HAMMER, O_PNEUMATIC_HAMMER, -1, -1);
3625
3626
3627   // ============================================================================
3628   // CAVE VARIABLES
3629   // ============================================================================
3630
3631   // PLAYER
3632
3633   // check if player is alive.
3634   if ((cave->player_state == GD_PL_LIVING && cave->player_seen_ago > 1) || cave->kill_player)
3635     cave->player_state = GD_PL_DIED;
3636
3637   // check if any voodoo exploded, and kill players the next scan if that happended.
3638   if (cave->voodoo_touched)
3639     cave->kill_player = TRUE;
3640
3641   // AMOEBA
3642
3643   // check flags after evaluating.
3644   if (cave->amoeba_state == GD_AM_AWAKE)
3645   {
3646     if (amoeba_count >= cave->amoeba_max_count)
3647       cave->amoeba_state = GD_AM_TOO_BIG;
3648     if (amoeba_found_enclosed)
3649       cave->amoeba_state = GD_AM_ENCLOSED;
3650     }
3651
3652   // amoeba can also be turned into diamond by magic wall
3653   if (cave->magic_wall_stops_amoeba && cave->magic_wall_state == GD_MW_ACTIVE)
3654     cave->amoeba_state = GD_AM_ENCLOSED;
3655
3656   // AMOEBA 2
3657   if (cave->amoeba_2_state == GD_AM_AWAKE)
3658   {
3659     // check flags after evaluating.
3660     if (amoeba_2_count >= cave->amoeba_2_max_count)
3661       cave->amoeba_2_state = GD_AM_TOO_BIG;
3662
3663     if (amoeba_2_found_enclosed)
3664       cave->amoeba_2_state = GD_AM_ENCLOSED;
3665   }
3666
3667   // amoeba 2 can also be turned into diamond by magic wall
3668   if (cave->magic_wall_stops_amoeba && cave->magic_wall_state == GD_MW_ACTIVE)
3669     cave->amoeba_2_state = GD_AM_ENCLOSED;
3670
3671   // now check times. ---------------------------
3672   // decrement time if a voodoo was killed.
3673   cave->time -= time_decrement_sec * cave->timing_factor;
3674   if (cave->time < 0)
3675     cave->time = 0;
3676
3677   // only decrement time when player is already born.
3678   if (cave->hatched)
3679   {
3680     int secondsbefore, secondsafter;
3681
3682     secondsbefore = cave->time / cave->timing_factor;
3683     cave->time -= cave->speed;
3684     if (cave->time <= 0)
3685       cave->time = 0;
3686
3687     secondsafter = cave->time / cave->timing_factor;
3688     if (cave->time / cave->timing_factor < 10)
3689       // if less than 10 seconds, no walking sound, but play explosion sound
3690       gd_sound_play(cave, GD_S_NONE, O_NONE, -1, -1);
3691
3692     if (secondsbefore != secondsafter)
3693       gd_cave_set_seconds_sound(cave);
3694   }
3695
3696   // a gravity switch was activated; seconds counting down
3697   if (cave->gravity_will_change > 0)
3698   {
3699     cave->gravity_will_change -= cave->speed;
3700     if (cave->gravity_will_change < 0)
3701       cave->gravity_will_change = 0;
3702
3703     if (cave->gravity_will_change == 0)
3704     {
3705       cave->gravity = cave->gravity_next_direction;
3706       gd_sound_play(cave, GD_S_GRAVITY_CHANGING, O_GRAVITY_SWITCH, -1, -1);    // takes precedence over amoeba and magic wall sound
3707     }
3708   }
3709
3710   // creatures direction automatically change
3711   if (cave->creatures_direction_will_change > 0)
3712   {
3713     cave->creatures_direction_will_change -= cave->speed;
3714     if (cave->creatures_direction_will_change < 0)
3715       cave->creatures_direction_will_change = 0;
3716
3717     if (cave->creatures_direction_will_change == 0)
3718     {
3719       gd_sound_play(cave, GD_S_SWITCH_CREATURES, O_CREATURE_SWITCH, -1, -1);
3720
3721       cave->creatures_backwards = !cave->creatures_backwards;
3722       cave->creatures_direction_will_change =
3723         cave->creatures_direction_auto_change_time * cave->timing_factor;
3724     }
3725   }
3726
3727   // magic wall; if active&wait or not wait for hatching
3728   if (cave->magic_wall_state == GD_MW_ACTIVE &&
3729       (cave->hatched || !cave->magic_timer_wait_for_hatching) &&
3730       !(cave->magic_wall_time == 0 && cave->magic_timer_zero_is_infinite))
3731   {
3732     cave->magic_wall_time -= cave->speed;
3733     if (cave->magic_wall_time < 0)
3734       cave->magic_wall_time = 0;
3735     if (cave->magic_wall_time == 0)
3736       cave->magic_wall_state = GD_MW_EXPIRED;
3737   }
3738
3739   // we may wait for hatching, when starting amoeba
3740   if (cave->amoeba_timer_started_immediately ||
3741       (cave->amoeba_state == GD_AM_AWAKE &&
3742        (cave->hatched || !cave->amoeba_timer_wait_for_hatching)))
3743   {
3744     cave->amoeba_time -= cave->speed;
3745     if (cave->amoeba_time < 0)
3746       cave->amoeba_time = 0;
3747     if (cave->amoeba_time == 0)
3748       cave->amoeba_growth_prob = cave->amoeba_fast_growth_prob;
3749   }
3750
3751   // we may wait for hatching, when starting amoeba
3752   if (cave->amoeba_timer_started_immediately ||
3753       (cave->amoeba_2_state == GD_AM_AWAKE &&
3754        (cave->hatched || !cave->amoeba_timer_wait_for_hatching)))
3755   {
3756     cave->amoeba_2_time -= cave->speed;
3757     if (cave->amoeba_2_time < 0)
3758       cave->amoeba_2_time = 0;
3759     if (cave->amoeba_2_time == 0)
3760       cave->amoeba_2_growth_prob = cave->amoeba_2_fast_growth_prob;
3761   }
3762
3763   // check for player hatching.
3764   start_signal = FALSE;
3765
3766   // if not the c64 scheduling, but the correct frametime is used,
3767   // hatching delay should always be decremented.
3768   // otherwise, the if (millisecs...) condition below will set this.
3769   if (cave->scheduling == GD_SCHEDULING_MILLISECONDS)
3770   {
3771     // NON-C64 scheduling
3772     if (cave->hatching_delay_frame > 0)
3773     {
3774       // for milliseconds-based, non-c64 schedulings, hatching delay means frames.
3775       cave->hatching_delay_frame--;
3776       if (cave->hatching_delay_frame == 0)
3777         start_signal = TRUE;
3778     }
3779   }
3780   else
3781   {
3782     // C64 scheduling
3783     if (cave->hatching_delay_time > 0)
3784     {
3785       // for c64 schedulings, hatching delay means milliseconds.
3786       cave->hatching_delay_time -= cave->speed;
3787       if (cave->hatching_delay_time <= 0)
3788       {
3789         cave->hatching_delay_time = 0;
3790         start_signal = TRUE;
3791       }
3792     }
3793   }
3794
3795   // if decremented hatching, and it became zero:
3796   if (start_signal)
3797   {
3798     // THIS IS THE CAVE START SIGNAL
3799
3800     // record that now the cave is in its normal state
3801     cave->hatched = TRUE;
3802
3803     // if diamonds needed is below zero, we count the available diamonds now.
3804     gd_cave_count_diamonds(cave);
3805
3806     // setup direction auto change
3807     if (cave->creatures_direction_auto_change_time)
3808     {
3809       cave->creatures_direction_will_change =
3810         cave->creatures_direction_auto_change_time * cave->timing_factor;
3811
3812       if (cave->creatures_direction_auto_change_on_start)
3813         cave->creatures_backwards = !cave->creatures_backwards;
3814     }
3815
3816     gd_sound_play(cave, GD_S_CRACKING, O_INBOX, -1, -1);
3817   }
3818
3819   // for biters
3820   if (cave->biters_wait_frame == 0)
3821     cave->biters_wait_frame = cave->biter_delay_frame;
3822   else
3823     cave->biters_wait_frame--;
3824
3825   // replicators delay
3826   if (cave->replicators_wait_frame == 0)
3827     cave->replicators_wait_frame = cave->replicator_delay_frame;
3828   else
3829     cave->replicators_wait_frame--;
3830
3831
3832   // ============================================================================
3833   // LAST THOUGTS
3834   // ============================================================================
3835
3836 #if 1
3837   // check if cave failed by timeout is done in main game engine
3838 #else
3839   // check if cave failed by timeout
3840   if (cave->player_state == GD_PL_LIVING && cave->time == 0)
3841   {
3842     gd_cave_clear_sounds(cave);
3843     cave->player_state = GD_PL_TIMEOUT;
3844     gd_sound_play(cave, GD_S_TIMEOUT_0, O_NONE, -1, -1);
3845   }
3846 #endif
3847
3848   // set these for drawing.
3849   cave->last_direction = player_move;
3850
3851   // here we remember last movements for animation. this is needed here,
3852   // as animation is in sync with the game, not the keyboard directly.
3853   // (for example, after exiting the cave, the player was "running" in the
3854   // original, till bonus points were counted for remaining time and so on.
3855   if (player_move == GD_MV_LEFT ||
3856       player_move == GD_MV_UP_LEFT ||
3857       player_move == GD_MV_DOWN_LEFT)
3858     cave->last_horizontal_direction = GD_MV_LEFT;
3859
3860   if (player_move == GD_MV_RIGHT ||
3861       player_move == GD_MV_UP_RIGHT ||
3862       player_move == GD_MV_DOWN_RIGHT)
3863     cave->last_horizontal_direction = GD_MV_RIGHT;
3864
3865   cave->frame++;  // XXX
3866 }
3867
3868 void set_initial_cave_speed(GdCave *cave)
3869 {
3870   int ymin, ymax;
3871   int x, y;
3872
3873   // set cave get function; to implement perfect or lineshifting borders
3874   if (cave->lineshift)
3875     cave->getp = getp_shift;
3876   else
3877     cave->getp = getp_perfect;
3878
3879   // check whether to scan the first and last line
3880   if (cave->border_scan_first_and_last)
3881   {
3882     ymin = 0;
3883     ymax = cave->h - 1;
3884   }
3885   else
3886   {
3887     ymin = 1;
3888     ymax = cave->h - 2;
3889   }
3890
3891   for (y = ymin; y <= ymax; y++)
3892   {
3893     for (x = 0; x < cave->w; x++)
3894     {
3895       // add the ckdelay correction value for every element seen.
3896       cave->ckdelay += gd_elements[get(cave, x, y)].ckdelay;
3897     }
3898   }
3899
3900   // update timing calculated by iterating and counting elements
3901   update_cave_speed(cave);
3902 }