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