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