added support for BD game engine to Makefile for Android
[rocksndiamonds.git] / src / game_bd / bd_cave.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 #include "main_bd.h"
18
19
20 // arrays for movements
21 // also no1 and bd2 cave data import helpers; line direction coordinates
22 const int gd_dx[] =
23 {
24   0, 0, 1, 1, 1, 0, -1, -1, -1, 0, 2, 2, 2, 0, -2, -2, -2
25 };
26 const int gd_dy[] =
27 {
28   0, -1, -1, 0, 1, 1, 1, 0, -1, -2, -2, 0, 2, 2, 2, 0, -2
29 };
30
31 // TRANSLATORS:
32 // None here means "no direction to move"; when there is no gravity while stirring the pot.
33 static const char* direction_name[] =
34 {
35   N_("None"),
36   N_("Up"),
37   N_("Up+right"),
38   N_("Right"),
39   N_("Down+right"),
40   N_("Down"),
41   N_("Down+left"),
42   N_("Left"),
43   N_("Up+left")
44 };
45
46 static const char* direction_filename[] =
47 {
48   "none",
49   "up",
50   "upright",
51   "right",
52   "downright",
53   "down",
54   "downleft",
55   "left",
56   "upleft"
57 };
58
59 static const char* scheduling_name[] =
60 {
61   N_("Milliseconds"),
62   "BD1",
63   "BD2",
64   "Construction Kit",
65   "Crazy Dream 7",
66   "Atari BD1",
67   "Atari BD2/Construction Kit"
68 };
69
70 static const char* scheduling_filename[] =
71 {
72   "ms",
73   "bd1",
74   "bd2",
75   "plck",
76   "crdr7",
77   "bd1atari",
78   "bd2ckatari"
79 };
80
81 static HashTable *name_to_element;
82 GdElement gd_char_to_element[256];
83
84 // color of flashing the screen, gate opening to exit
85 const GdColor gd_flash_color = 0xFFFFC0;
86
87 // selected object in editor
88 const GdColor gd_select_color = 0x8080FF;
89
90 // direction to string and vice versa
91 const char *gd_direction_get_visible_name(GdDirection dir)
92 {
93   return direction_name[dir];
94 }
95
96 const char *gd_direction_get_filename(GdDirection dir)
97 {
98   return direction_filename[dir];
99 }
100
101 GdDirection gd_direction_from_string(const char *str)
102 {
103   int i;
104
105   for (i = 1; i < ARRAY_SIZE(direction_filename); i++)
106     if (strcasecmp(str, direction_filename[i]) == 0)
107       return (GdDirection) i;
108
109   Warn("invalid direction name '%s', defaulting to down", str);
110   return GD_MV_DOWN;
111 }
112
113 // scheduling name to string and vice versa
114 const char *gd_scheduling_get_filename(GdScheduling sched)
115 {
116   return scheduling_filename[sched];
117 }
118
119 const char *gd_scheduling_get_visible_name(GdScheduling sched)
120 {
121   return scheduling_name[sched];
122 }
123
124 GdScheduling gd_scheduling_from_string(const char *str)
125 {
126   int i;
127
128   for (i = 0; i < ARRAY_SIZE(scheduling_filename); i++)
129     if (strcasecmp(str, scheduling_filename[i]) == 0)
130       return (GdScheduling) i;
131
132   Warn("invalid scheduling name '%s', defaulting to plck", str);
133
134   return GD_SCHEDULING_PLCK;
135 }
136
137 /*
138   fill a given struct with default properties.
139   "str" is the struct (data),
140   "properties" describes the structure and its pointers,
141   "defaults" are the pieces of data which will be copied to str.
142 */
143 void gd_struct_set_defaults_from_array(void *str,
144                                        const GdStructDescriptor *properties,
145                                        GdPropertyDefault *defaults)
146 {
147   int i;
148
149   for (i = 0; defaults[i].offset != -1; i++)
150   {
151     void *pvalue = STRUCT_MEMBER_P(str, defaults[i].offset);
152     // these point to the same, but to avoid the awkward cast syntax
153     int *ivalue = pvalue;
154     GdElement *evalue = pvalue;
155     GdDirection *dvalue = pvalue;
156     GdScheduling *svalue = pvalue;
157     boolean *bvalue = pvalue;
158     GdColor *cvalue = pvalue;
159     int j, n;
160
161     // check which property we are talking about: find it in gd_cave_properties.
162     n = defaults[i].property_index;
163     if (n == 0)
164     {
165       while (properties[n].identifier != NULL &&
166              properties[n].offset != defaults[i].offset)
167         n++;
168
169       // remember so we will be fast later
170       defaults[i].property_index = n;
171     }
172
173     // some properties are arrays. this loop fills all with the same values
174     for (j = 0; j < properties[n].count; j++)
175     {
176       switch (properties[n].type)
177       {
178         // these are for the gui; do nothing
179         case GD_TAB:
180         case GD_LABEL:
181           // no default value for strings
182         case GD_TYPE_STRING:
183         case GD_TYPE_LONGSTRING:
184           break;
185
186         case GD_TYPE_RATIO:
187           // this is also an integer, difference is only when saving to bdcff
188         case GD_TYPE_INT:
189           if (defaults[i].defval < properties[n].min ||
190               defaults[i].defval > properties[n].max)
191             Warn("integer property %s out of range", properties[n].identifier);
192           ivalue[j] = defaults[i].defval;
193           break;
194
195         case GD_TYPE_PROBABILITY:
196           // floats are stored as integer, /million; but are integers
197           if (defaults[i].defval < 0 ||
198               defaults[i].defval > 1000000)
199             Warn("integer property %s out of range", properties[n].identifier);
200           ivalue[j] = defaults[i].defval;
201           break;
202
203         case GD_TYPE_BOOLEAN:
204           bvalue[j] = defaults[i].defval != 0;
205           break;
206
207         case GD_TYPE_ELEMENT:
208         case GD_TYPE_EFFECT:
209           evalue[j] = (GdElement) defaults[i].defval;
210           break;
211
212         case GD_TYPE_COLOR:
213           cvalue[j] = gd_c64_color(defaults[i].defval);
214           break;
215
216         case GD_TYPE_DIRECTION:
217           dvalue[j] = (GdDirection) defaults[i].defval;
218           break;
219
220         case GD_TYPE_SCHEDULING:
221           svalue[j] = (GdScheduling) defaults[i].defval;
222           break;
223       }
224     }
225   }
226 }
227
228 /*
229   creates the character->element conversion table; using
230   the fixed-in-the-bdcff characters. later, this table
231   may be filled with more elements.
232 */
233 void gd_create_char_to_element_table(void)
234 {
235   int i;
236
237   // fill all with unknown
238   for (i = 0; i < ARRAY_SIZE(gd_char_to_element); i++)
239     gd_char_to_element[i] = O_UNKNOWN;
240
241   // then set fixed characters
242   for (i = 0; i < O_MAX; i++)
243   {
244     int c = gd_elements[i].character;
245
246     if (c)
247     {
248       if (gd_char_to_element[c] != O_UNKNOWN)
249         Warn("Character %c already used for element %x", c, gd_char_to_element[c]);
250
251       gd_char_to_element[c] = i;
252     }
253   }
254 }
255
256 // search the element database for the specified character, and return the element.
257 GdElement gd_get_element_from_character (byte character)
258 {
259   if (gd_char_to_element[character] != O_UNKNOWN)
260     return gd_char_to_element[character];
261
262   Warn ("Invalid character representing element: %c", character);
263
264   return O_UNKNOWN;
265 }
266
267 /*
268   do some init; this function is to be called at the start of the application
269 */
270 void gd_cave_init(void)
271 {
272   int i;
273
274   // put names to a hash table
275   // this is a helper for file read operations
276   // maps copied strings to elements (integers)
277   name_to_element = create_hashtable(gd_str_case_hash, gd_str_case_equal, NULL, NULL);
278
279   for (i = 0; i < O_MAX; i++)
280   {
281     char *key;
282
283     key = getStringToUpper(gd_elements[i].filename);
284
285     if (hashtable_exists(name_to_element, key))         // hash value may be 0
286       Warn("Name %s already used for element %x", key, i);
287
288     hashtable_insert(name_to_element, key, INT_TO_PTR(i));
289     // ^^^ do not free "key", as hash table needs it during the whole time!
290
291     key = getStringCat2("SCANNED_", key);               // new string
292
293     hashtable_insert(name_to_element, key, INT_TO_PTR(i));
294     // once again, do not free "key" ^^^
295   }
296
297   // for compatibility with tim stridmann's memorydump->bdcff converter... .... ...
298   hashtable_insert(name_to_element, "HEXPANDING_WALL", INT_TO_PTR(O_H_EXPANDING_WALL));
299   hashtable_insert(name_to_element, "FALLING_DIAMOND", INT_TO_PTR(O_DIAMOND_F));
300   hashtable_insert(name_to_element, "FALLING_BOULDER", INT_TO_PTR(O_STONE_F));
301   hashtable_insert(name_to_element, "EXPLOSION1S", INT_TO_PTR(O_EXPLODE_1));
302   hashtable_insert(name_to_element, "EXPLOSION2S", INT_TO_PTR(O_EXPLODE_2));
303   hashtable_insert(name_to_element, "EXPLOSION3S", INT_TO_PTR(O_EXPLODE_3));
304   hashtable_insert(name_to_element, "EXPLOSION4S", INT_TO_PTR(O_EXPLODE_4));
305   hashtable_insert(name_to_element, "EXPLOSION5S", INT_TO_PTR(O_EXPLODE_5));
306   hashtable_insert(name_to_element, "EXPLOSION1D", INT_TO_PTR(O_PRE_DIA_1));
307   hashtable_insert(name_to_element, "EXPLOSION2D", INT_TO_PTR(O_PRE_DIA_2));
308   hashtable_insert(name_to_element, "EXPLOSION3D", INT_TO_PTR(O_PRE_DIA_3));
309   hashtable_insert(name_to_element, "EXPLOSION4D", INT_TO_PTR(O_PRE_DIA_4));
310   hashtable_insert(name_to_element, "EXPLOSION5D", INT_TO_PTR(O_PRE_DIA_5));
311   hashtable_insert(name_to_element, "WALL2", INT_TO_PTR(O_STEEL_EXPLODABLE));
312
313   // compatibility with old bd-faq (pre disassembly of bladder)
314   hashtable_insert(name_to_element, "BLADDERd9", INT_TO_PTR(O_BLADDER_8));
315
316   // create table to show errors at the start of the application
317   gd_create_char_to_element_table();
318 }
319
320 // search the element database for the specified name, and return the element
321 GdElement gd_get_element_from_string (const char *string)
322 {
323   char *upper = getStringToUpper(string);
324   void *value;
325   boolean found;
326
327   if (!string)
328   {
329     Warn("Invalid string representing element: (null)");
330     return O_UNKNOWN;
331   }
332
333   found = hashtable_exists(name_to_element, upper);     // hash value may be 0
334   if (found)
335     value = hashtable_search(name_to_element, upper);
336   free(upper);
337   if (found)
338     return (GdElement) (PTR_TO_INT(value));
339
340   Warn("Invalid string representing element: '%s'", string);
341
342   return O_UNKNOWN;
343 }
344
345 void gd_cave_set_defaults_from_array(GdCave* cave, GdPropertyDefault *defaults)
346 {
347   gd_struct_set_defaults_from_array(cave, gd_cave_properties, defaults);
348 }
349
350 /*
351   load default values from description array
352   these are default for gdash and bdcff.
353 */
354 void gd_cave_set_gdash_defaults(GdCave* cave)
355 {
356   int i;
357
358   gd_cave_set_defaults_from_array(cave, gd_cave_defaults_gdash);
359
360   // these did not fit into the descriptor array
361   for (i = 0; i < 5; i++)
362   {
363     cave->level_rand[i] = i;
364     cave->level_timevalue[i] = i + 1;
365   }
366 }
367
368 // for quicksort. compares two highscores.
369 int gd_highscore_compare(const void *a, const void *b)
370 {
371   const GdHighScore *ha = a;
372   const GdHighScore *hb = b;
373   return hb->score - ha->score;
374 }
375
376 void gd_clear_highscore(GdHighScore *hs)
377 {
378   int i;
379
380   for (i = 0; i < GD_HIGHSCORE_NUM; i++)
381   {
382     strcpy(hs[i].name, "");
383     hs[i].score = 0;
384   }
385 }
386
387 boolean gd_has_highscore(GdHighScore *hs)
388 {
389   return hs[0].score > 0;
390 }
391
392 // return true if score achieved is a highscore
393 boolean gd_is_highscore(GdHighScore *scores, int score)
394 {
395   // if score is above zero AND bigger than the last one
396   if (score > 0 && score > scores[GD_HIGHSCORE_NUM-1].score)
397     return TRUE;
398
399   return FALSE;
400 }
401
402 int gd_add_highscore(GdHighScore *highscores, const char *name, int score)
403 {
404   int i;
405
406   if (!gd_is_highscore(highscores, score))
407     return -1;
408
409   // overwrite the last one
410   gd_strcpy(highscores[GD_HIGHSCORE_NUM-1].name, name);
411   highscores[GD_HIGHSCORE_NUM-1].score = score;
412
413   // and sort
414   qsort(highscores, GD_HIGHSCORE_NUM, sizeof(GdHighScore), gd_highscore_compare);
415
416   for (i = 0; i < GD_HIGHSCORE_NUM; i++)
417     if (strEqual(highscores[i].name, name) && highscores[i].score == score)
418       return i;
419
420   return -1;
421 }
422
423 // for the case-insensitive hash keys
424 int gd_str_case_equal(void *s1, void *s2)
425 {
426   return strcasecmp(s1, s2) == 0;
427 }
428
429 unsigned int gd_str_case_hash(void *v)
430 {
431   char *upper = getStringToUpper(v);
432   unsigned int hash = get_hash_from_string(upper);
433
434   free(upper);
435
436   return hash;
437 }
438
439 /*
440   create new cave with default values.
441   sets every value, also default size, diamond value etc.
442 */
443 GdCave *gd_cave_new(void)
444 {
445   GdCave *cave;
446
447   cave = checked_calloc(sizeof(GdCave));
448
449   // hash table which stores unknown tags as strings.
450   cave->tags = create_hashtable(gd_str_case_hash, gd_str_case_equal, free, free);
451
452   gd_cave_set_gdash_defaults(cave);
453
454   return cave;
455 }
456
457 /*
458   cave maps.
459   cave maps are continuous areas in memory. the allocated memory
460   is width * height * bytes_per_cell long.
461   the cave map[0] stores the pointer given by g_malloc().
462   the map itself is also an allocated array of pointers to the
463   beginning of rows.
464   therefore:
465   rows = new (pointers to rows);
466   rows[0] = new map
467   rows[1..h-1] = rows[0] + width * bytes
468
469   freeing this:
470   free(rows[0])
471   free(rows)
472 */
473
474 /*
475   allocate a cave map-like array, and initialize to zero.
476   one cell is cell_size bytes long.
477 */
478 void *gd_cave_map_new_for_cave(const GdCave *cave, const int cell_size)
479 {
480   void **rows;                // this is void**, pointer to array of ...
481   int y;
482
483   rows = checked_malloc((cave->h) * sizeof(void *));
484   rows[0] = checked_calloc(cell_size * cave->w * cave->h);
485
486   for (y = 1; y < cave->h; y++)
487     // base pointer + num_of_bytes_per_element * width * number_of_row; as sizeof(char) = 1
488     rows[y] = (char *)rows[0] + cell_size * cave->w * y;
489
490   return rows;
491 }
492
493 /*
494   duplicate map
495
496   if map is null, this also returns null.
497 */
498 void *gd_cave_map_dup_size(const GdCave *cave, const void *map, const int cell_size)
499 {
500   void **rows;
501   void **maplines = (void **)map;
502   int y;
503
504   if (!map)
505     return NULL;
506
507   rows = checked_malloc((cave->h) * sizeof(void *));
508   rows[0] = get_memcpy (maplines[0], cell_size * cave->w * cave->h);
509
510   for (y = 1; y < cave->h; y++)
511     rows[y] = (char *)rows[0] + cell_size * cave->w * y;
512
513   return rows;
514 }
515
516 void gd_cave_map_free(void *map)
517 {
518   void **maplines = (void **) map;
519
520   if (!map)
521     return;
522
523   free(maplines[0]);
524   free(map);
525 }
526
527 /*
528   frees memory associated to cave
529 */
530 void gd_cave_free(GdCave *cave)
531 {
532   int i;
533
534   if (!cave)
535     return;
536
537   if (cave->tags)
538     hashtable_destroy(cave->tags);
539
540   if (cave->random)    // random generator is a GdRand *
541     gd_rand_free(cave->random);
542
543   // free strings
544   for (i = 0; gd_cave_properties[i].identifier != NULL; i++)
545     if (gd_cave_properties[i].type == GD_TYPE_LONGSTRING)
546       checked_free(STRUCT_MEMBER(char *, cave, gd_cave_properties[i].offset));
547
548   // map
549   gd_cave_map_free(cave->map);
550
551   // rendered data
552   gd_cave_map_free(cave->objects_order);
553
554   // hammered walls to reappear data
555   gd_cave_map_free(cave->hammered_reappear);
556
557   // free objects
558   list_foreach(cave->objects, (list_fn) free, NULL);
559   list_free(cave->objects);
560
561   // free replays
562   list_foreach(cave->replays, (list_fn) gd_replay_free, NULL);
563   list_free(cave->replays);
564
565   // freeing main pointer
566   free (cave);
567 }
568
569 static void hash_copy_foreach(const char *key, const char *value, HashTable *dest)
570 {
571   hashtable_insert(dest, getStringCopy(key), getStringCopy(value));
572 }
573
574 // copy cave from src to destination, with duplicating dynamically allocated data
575 void gd_cave_copy(GdCave *dest, const GdCave *src)
576 {
577   int i;
578
579   // copy entire data
580   memmove(dest, src, sizeof(GdCave));
581
582   // but duplicate dynamic data
583   dest->tags = create_hashtable(gd_str_case_hash, gd_str_case_equal, free, free);
584
585   if (src->tags)
586     hashtable_foreach(src->tags, (hashtable_fn)hash_copy_foreach, dest->tags);
587
588   dest->map = gd_cave_map_dup(src, map);
589   dest->hammered_reappear = gd_cave_map_dup(src, hammered_reappear);
590
591   // for longstrings
592   for (i = 0; gd_cave_properties[i].identifier != NULL; i++)
593     if (gd_cave_properties[i].type == GD_TYPE_LONGSTRING)
594       STRUCT_MEMBER(char *, dest, gd_cave_properties[i].offset) =
595         getStringCopy(STRUCT_MEMBER(char *, src, gd_cave_properties[i].offset));
596
597   // no reason to copy this
598   dest->objects_order = NULL;
599
600   // copy objects list
601   if (src->objects)
602   {
603     List *iter;
604
605     dest->objects = NULL;    // new empty list
606     for (iter = src->objects; iter != NULL; iter = iter->next) // do a deep copy
607       dest->objects = list_append(dest->objects, get_memcpy (iter->data, sizeof (GdObject)));
608   }
609
610   // copy replays
611   if (src->replays)
612   {
613     List *iter;
614
615     dest->replays = NULL;
616     for (iter = src->replays; iter != NULL; iter = iter->next) // do a deep copy
617       dest->replays = list_append(dest->replays, gd_replay_new_from_replay(iter->data));
618   }
619
620   // copy random number generator
621   if (src->random)
622     dest->random = gd_rand_copy(src->random);
623 }
624
625 // create new cave, which is a copy of the cave given.
626 GdCave *gd_cave_new_from_cave(const GdCave *orig)
627 {
628   GdCave *cave;
629
630   cave = gd_cave_new();
631   gd_cave_copy(cave, orig);
632
633   return cave;
634 }
635
636 /*
637   Put an object to the specified position.
638   Performs range checking.
639   If wraparound objects are selected, wraps around x coordinates, with or without lineshift.
640   (The y coordinate is not wrapped, as it did not work like that on the c64)
641   order is a pointer to the GdObject describing this object. Thus the editor can identify
642   which cell was created by which object.
643 */
644 void gd_cave_store_rc(GdCave *cave, int x, int y, const GdElement element, const void *order)
645 {
646   // if we do not need to draw, exit now
647   if (element == O_NONE)
648     return;
649
650   // check bounds
651   if (cave->wraparound_objects)
652   {
653     if (cave->lineshift)
654     {
655       // fit x coordinate within range, with correcting y at the same time
656       while (x < 0)
657       {
658         x += cave->w;    // out of bounds on the left...
659         y--;             // previous row
660       }
661
662       while (x >= cave->w)
663       {
664         x -= cave->w;
665         y++;
666       }
667
668       // lineshifting does not fix the y coordinates.
669       // if out of bounds, element will not be displayed.
670       // if such an object appeared in the c64 game, well, it was a buffer overrun.
671     }
672     else
673     {
674       // non lineshifting: changing x does not change y coordinate.
675       while (x < 0)
676         x += cave->w;
677
678       while (x >= cave->w)
679         x -= cave->w;
680
681       // after that, fix y coordinate
682       while (y < 0)
683         y += cave->h;
684
685       while (y >= cave->h)
686         y -= cave->h;
687     }
688   }
689
690   // if the above wraparound code fixed the coordinates, this will always be true.
691   // but see the above comment for lineshifting y coordinate
692   if (x >= 0 && x < cave->w && y >= 0 && y < cave->h)
693   {
694     cave->map[y][x] = element;
695     cave->objects_order[y][x] = (void *)order;
696   }
697 }
698
699 GdElement gd_cave_get_rc(const GdCave *cave, int x, int y)
700 {
701   // always fix coordinates as if cave was wraparound.
702
703   // fix x coordinate
704   if (cave->lineshift)
705   {
706     // fit x coordinate within range, with correcting y at the same time
707     while (x < 0)
708     {
709       x += cave->w;    // out of bounds on the left...
710       y--;             // previous row
711     }
712     while (x >= cave->w)
713     {
714       x -= cave->w;
715       y++;
716     }
717   }
718   else
719   {
720     // non lineshifting: changing x does not change y coordinate.
721     while (x < 0)
722       x += cave->w;
723
724     while (x >= cave->w)
725       x -= cave->w;
726   }
727
728   // after that, fix y coordinate
729   while (y < 0)
730     y += cave->h;
731
732   while (y >= cave->h)
733     y -= cave->h;
734
735   return cave->map[y][x];
736 }
737
738 unsigned int gd_c64_random(GdC64RandomGenerator *rand)
739 {
740   unsigned int temp_rand_1, temp_rand_2, carry, result;
741
742   temp_rand_1 = (rand->rand_seed_1 & 0x0001) << 7;
743   temp_rand_2 = (rand->rand_seed_2 >> 1) & 0x007F;
744   result = (rand->rand_seed_2) + ((rand->rand_seed_2 & 0x0001) << 7);
745   carry = (result >> 8);
746   result = result & 0x00FF;
747   result = result + carry + 0x13;
748   carry = (result >> 8);
749   rand->rand_seed_2 = result & 0x00FF;
750   result = rand->rand_seed_1 + carry + temp_rand_1;
751   carry = (result >> 8);
752   result = result & 0x00FF;
753   result = result + carry + temp_rand_2;
754   rand->rand_seed_1 = result & 0x00FF;
755
756   return rand->rand_seed_1;
757 }
758
759 /*
760   C64 BD predictable random number generator.
761   Used to load the original caves imported from c64 files.
762   Also by the predictable slime.
763 */
764 unsigned int gd_cave_c64_random(GdCave *cave)
765 {
766   return gd_c64_random(&cave->c64_rand);
767 }
768
769 void gd_c64_random_set_seed(GdC64RandomGenerator *rand, int seed1, int seed2)
770 {
771   rand->rand_seed_1 = seed1;
772   rand->rand_seed_2 = seed2;
773 }
774
775 void gd_cave_c64_random_set_seed(GdCave *cave, int seed1, int seed2)
776 {
777   gd_c64_random_set_seed(&cave->c64_rand, seed1, seed2);
778 }
779
780 /*
781   select random colors for a given cave.
782   this function will select colors so that they should look somewhat nice; for example
783   brick walls won't be the darkest color, for example.
784 */
785 static inline void swap(int *i1, int *i2)
786 {
787   int t = *i1;
788
789   *i1 = *i2;
790   *i2 = t;
791 }
792
793 void gd_cave_set_random_c64_colors(GdCave *cave)
794 {
795   const int bright_colors[] = { 1, 3, 7 };
796   const int dark_colors[] = { 2, 6, 8, 9, 11 };
797
798   // always black
799   cave->colorb = gd_c64_color(0);
800   cave->color0 = gd_c64_color(0);
801
802   // choose some bright color for brick
803   cave->color3 = gd_c64_color(bright_colors[gd_random_int_range(0, ARRAY_SIZE(bright_colors))]);
804
805   // choose a dark color for dirt, but should not be == color of brick
806   do
807   {
808     cave->color1 = gd_c64_color(dark_colors[gd_random_int_range(0, ARRAY_SIZE(dark_colors))]);
809   }
810   while (cave->color1 == cave->color3);    // so it is not the same as color 1
811
812   // choose any but black for steel wall, but should not be == brick or dirt
813   do
814   {
815     // between 1 and 15 - do not use black for this.
816     cave->color2 = gd_c64_color(gd_random_int_range(1, 16));
817   }
818   while (cave->color1 == cave->color2 || cave->color2 == cave->color3);    // so colors are not the same
819
820   // copy amoeba and slime color
821   cave->color4 = cave->color3;
822   cave->color5 = cave->color1;
823 }
824
825 static void cave_set_random_indexed_colors(GdCave *cave, GdColor (*color_indexer_func) (int, int))
826 {
827   int hue = gd_random_int_range(0, 15);
828   int hue_spread = gd_random_int_range(1, 6);    // 1..5
829
830   // we only use 0..6, as saturation 15 is too bright (almost always white)
831   // also, saturation 0..1..2 is too dark. the color0=black is there for dark.
832   // so this is also 1..5. when hue spread is low, brightness spread is high
833   int bri_spread = 6 - hue_spread;
834   int bri1 = 8, bri2 = 8 - bri_spread, bri3 = 8 + bri_spread;
835
836   // there are 15 valid choices for hue, so we do a %15
837   int col1 = hue, col2 = (hue + hue_spread + 15) % 15, col3 = (hue - hue_spread + 15) % 15;
838
839   // this makes up a random color, and selects a color triad by hue+5 and hue+10.
840   // also creates a random saturation.
841   // color of brick is 8+sat, so it is always a bright color.
842   // another two are 8-sat and 8.
843   // order of colors is also changed randomly.
844   if (gd_random_boolean())    swap(&bri1, &bri2);
845
846   // we do not touch bri3 (8+sat), as it should be a bright color
847   if (gd_random_boolean())    swap(&col1, &col2);
848   if (gd_random_boolean())    swap(&col2, &col3);
849   if (gd_random_boolean())    swap(&col1, &col3);
850
851   cave->colorb = color_indexer_func(0, 0);
852   cave->color0 = color_indexer_func(0, 0);
853   cave->color1 = color_indexer_func(col1 + 1, bri1);
854   cave->color2 = color_indexer_func(col2 + 1, bri2);
855   cave->color3 = color_indexer_func(col3 + 1, bri3);
856   // amoeba and slime are different
857   // some green thing
858   cave->color4 = color_indexer_func(gd_random_int_range(11, 13), gd_random_int_range(6, 12));
859   // some blueish thing
860   cave->color5 = color_indexer_func(gd_random_int_range(7, 10),  gd_random_int_range(0, 6));
861 }
862
863 static void gd_cave_set_random_atari_colors(GdCave *cave)
864 {
865   cave_set_random_indexed_colors(cave, gd_atari_color_huesat);
866 }
867
868 static void gd_cave_set_random_c64dtv_colors(GdCave *cave)
869 {
870   cave_set_random_indexed_colors(cave, gd_c64dtv_color_huesat);
871 }
872
873 static inline void swapd(double *i1, double *i2)
874 {
875   double t = *i1;
876
877   *i1 = *i2;
878   *i2 = t;
879 }
880
881 static void gd_cave_set_random_rgb_colors(GdCave *cave)
882 {
883   const double hue_max = 10.0 / 30.0;
884   // any hue allowed
885   double hue = gd_random_double();
886   // hue 360 degress=1.  hue spread is min. 24 degrees, max 120 degrees (1/3)
887   double hue_spread = gd_random_double_range(2.0 / 30.0, hue_max);
888   double h1 = hue, h2 = hue + hue_spread, h3 = hue + 2 * hue_spread;
889   double v1, v2, v3;
890   double s1, s2, s3;
891
892   if (gd_random_boolean())
893   {
894     // when hue spread is low, brightness(saturation) spread is high
895     // this formula gives a number (x) between 0.1 and 0.4,
896     // which will be 0.5-x and 0.5+x, so the range is 0.1->0.9
897     double spread = 0.1 + 0.3 * (1 - hue_spread / hue_max);
898     v1 = 0.6;                // brightness variation, too
899     v2 = 0.7;
900     v3 = 0.8;
901     s1 = 0.5;                // saturation is different
902     s2 = 0.5 - spread;
903     s3 = 0.5 + spread;
904   }
905   else
906   {
907     // when hue spread is low, brightness(saturation) spread is high
908     // this formula gives a number (x) between 0.1 and 0.25,
909     // which will be 0.5+x and 0.5+2x, so the range is 0.5->0.9
910     double spread = 0.1 + 0.15 * (1 - hue_spread / hue_max);
911     v1 = 0.5;                // brightness is different
912     v2 = 0.5 + spread;
913     v3 = 0.5 + 2 * spread;
914     s1 = 0.7;                // saturation is same - a not fully saturated one
915     s2 = 0.8;
916     s3 = 0.9;
917   }
918
919   // randomly change values, but do not touch v3, as cave->color3 should be a bright color
920   if (gd_random_boolean())    swapd(&v1, &v2);
921
922   // randomly change hues and saturations
923   if (gd_random_boolean())    swapd(&h1, &h2);
924   if (gd_random_boolean())    swapd(&h2, &h3);
925   if (gd_random_boolean())    swapd(&h1, &h3);
926   if (gd_random_boolean())    swapd(&s1, &s2);
927   if (gd_random_boolean())    swapd(&s2, &s3);
928   if (gd_random_boolean())    swapd(&s1, &s3);
929
930   h1 = h1 * 360.0;
931   h2 = h2 * 360.0;
932   h3 = h3 * 360.0;
933
934   cave->colorb = gd_color_get_from_hsv(0, 0, 0);
935   cave->color0 = gd_color_get_from_hsv(0, 0, 0);       // black for background
936   cave->color1 = gd_color_get_from_hsv(h1, s1, v1);    // dirt
937   cave->color2 = gd_color_get_from_hsv(h2, s2, v2);    // steel
938   cave->color3 = gd_color_get_from_hsv(h3, s3, v3);    // brick
939   // green(120+-20) with the saturation and brightness of brick
940   cave->color4 = gd_color_get_from_hsv(gd_random_int_range(100, 140), s2, v2);
941   // blue(240+-20) with saturation and brightness of dirt
942   cave->color5 = gd_color_get_from_hsv(gd_random_int_range(220, 260), s1, v1);
943 }
944
945 void gd_cave_set_random_colors(GdCave *cave, GdColorType type)
946 {
947   switch (type)
948   {
949     case GD_COLOR_TYPE_RGB:
950       gd_cave_set_random_rgb_colors(cave);
951       break;
952
953     case GD_COLOR_TYPE_C64:
954       gd_cave_set_random_c64_colors(cave);
955       break;
956
957     case GD_COLOR_TYPE_C64DTV:
958       gd_cave_set_random_c64dtv_colors(cave);
959       break;
960
961     case GD_COLOR_TYPE_ATARI:
962       gd_cave_set_random_atari_colors(cave);
963       break;
964
965     default:
966       break;
967   }
968 }
969
970 /*
971   shrink cave
972   if last line or last row is just steel wall (or (invisible) outbox).
973   used after loading a game for playing.
974   after this, ew and eh will contain the effective width and height.
975 */
976 void gd_cave_auto_shrink(GdCave *cave)
977 {
978
979   int x, y;
980   enum
981   {
982     STEEL_ONLY,
983     STEEL_OR_OTHER,
984     NO_SHRINK
985   }
986   empty;
987
988   // set to maximum size, then try to shrink
989   cave->x1 = 0;
990   cave->y1 = 0;
991   cave->x2 = cave->w - 1;
992   cave->y2 = cave->h - 1;
993
994   // search for empty, steel-wall-only last rows.
995   // clear all lines, which are only steel wall.
996   // and clear only one line, which is steel wall, but also has a player or an outbox.
997   empty = STEEL_ONLY;
998
999   do
1000   {
1001     for (y = cave->y2 - 1; y <= cave->y2; y++)
1002     {
1003       for (x = cave->x1; x <= cave->x2; x++)
1004       {
1005         switch (gd_cave_get_rc (cave, x, y))
1006         {
1007           // if steels only, this is to be deleted.
1008           case O_STEEL:
1009             break;
1010
1011           case O_PRE_OUTBOX:
1012           case O_PRE_INVIS_OUTBOX:
1013           case O_INBOX:
1014             if (empty == STEEL_OR_OTHER)
1015               empty = NO_SHRINK;
1016
1017             // if this, delete only this one, and exit.
1018             if (empty == STEEL_ONLY)
1019               empty = STEEL_OR_OTHER;
1020             break;
1021
1022           default:
1023             // anything else, that should be left in the cave.
1024             empty = NO_SHRINK;
1025             break;
1026         }
1027       }
1028     }
1029
1030     // shrink if full steel or steel and player/outbox.
1031     if (empty != NO_SHRINK)
1032       cave->y2--;            // one row shorter
1033   }
1034   while (empty == STEEL_ONLY);    // if found just steels, repeat.
1035
1036   // search for empty, steel-wall-only first rows.
1037   empty = STEEL_ONLY;
1038
1039   do
1040   {
1041     for (y = cave->y1; y <= cave->y1 + 1; y++)
1042     {
1043       for (x = cave->x1; x <= cave->x2; x++)
1044       {
1045         switch (gd_cave_get_rc (cave, x, y))
1046         {
1047           case O_STEEL:
1048             break;
1049
1050           case O_PRE_OUTBOX:
1051           case O_PRE_INVIS_OUTBOX:
1052           case O_INBOX:
1053             // shrink only lines, which have only ONE player or outbox.
1054             // this is for bd4 intermission 2, for example.
1055             if (empty == STEEL_OR_OTHER)
1056               empty = NO_SHRINK;
1057             if (empty == STEEL_ONLY)
1058               empty = STEEL_OR_OTHER;
1059             break;
1060
1061           default:
1062             empty = NO_SHRINK;
1063             break;
1064         }
1065       }
1066     }
1067
1068     if (empty != NO_SHRINK)
1069       cave->y1++;
1070   }
1071   while (empty == STEEL_ONLY);    // if found one, repeat.
1072
1073   // empty last columns.
1074   empty = STEEL_ONLY;
1075
1076   do
1077   {
1078     for (y = cave->y1; y <= cave->y2; y++)
1079     {
1080       for (x = cave->x2 - 1; x <= cave->x2; x++)
1081       {
1082         switch (gd_cave_get_rc (cave, x, y))
1083         {
1084           case O_STEEL:
1085             break;
1086
1087           case O_PRE_OUTBOX:
1088           case O_PRE_INVIS_OUTBOX:
1089           case O_INBOX:
1090             if (empty == STEEL_OR_OTHER)
1091               empty = NO_SHRINK;
1092             if (empty == STEEL_ONLY)
1093               empty = STEEL_OR_OTHER;
1094             break;
1095
1096           default:
1097             empty = NO_SHRINK;
1098             break;
1099         }
1100       }
1101     }
1102
1103     // just remember that one column shorter.
1104     // free will know the size of memchunk, no need to realloc!
1105     if (empty != NO_SHRINK)
1106       cave->x2--;
1107   }
1108   while (empty == STEEL_ONLY);    // if found one, repeat.
1109
1110   // empty first columns.
1111   empty = STEEL_ONLY;
1112
1113   do
1114   {
1115     for (y = cave->y1; y <= cave->y2; y++)
1116     {
1117       for (x = cave->x1; x <= cave->x1 + 1; x++)
1118       {
1119         switch (gd_cave_get_rc (cave, x, y))
1120         {
1121           case O_STEEL:
1122             break;
1123
1124           case O_PRE_OUTBOX:
1125           case O_PRE_INVIS_OUTBOX:
1126           case O_INBOX:
1127             if (empty == STEEL_OR_OTHER)
1128               empty = NO_SHRINK;
1129             if (empty == STEEL_ONLY)
1130               empty = STEEL_OR_OTHER;
1131             break;
1132
1133           default:
1134             empty = NO_SHRINK;
1135             break;
1136         }
1137       }
1138     }
1139
1140     if (empty != NO_SHRINK)
1141       cave->x1++;
1142   }
1143   while (empty == STEEL_ONLY);    // if found one, repeat.
1144 }
1145
1146 /*
1147   check if cave visible part coordinates
1148   are outside cave sizes, or not in the right order.
1149   correct them if needed.
1150 */
1151 void gd_cave_correct_visible_size(GdCave *cave)
1152 {
1153   // change visible coordinates if they do not point to upperleft and lowerright
1154   if (cave->x2 < cave->x1)
1155   {
1156     int t = cave->x2;
1157     cave->x2 = cave->x1;
1158     cave->x1 = t;
1159   }
1160
1161   if (cave->y2 < cave->y1)
1162   {
1163     int t = cave->y2;
1164     cave->y2 = cave->y1;
1165     cave->y1 = t;
1166   }
1167
1168   if (cave->x1 < 0)
1169     cave->x1 = 0;
1170
1171   if (cave->y1 < 0)
1172     cave->y1 = 0;
1173
1174   if (cave->x2 > cave->w - 1)
1175     cave->x2 = cave->w - 1;
1176
1177   if (cave->y2 > cave->h - 1)
1178     cave->y2 = cave->h - 1;
1179 }
1180
1181 /*
1182   bd1 and similar engines had animation bits in cave data, to set which elements to animate
1183   (firefly, butterfly, amoeba).
1184   animating an element also caused some delay each frame; according to my measurements,
1185   around 2.6 ms/element.
1186 */
1187 static void cave_set_ckdelay_extra_for_animation(GdCave *cave)
1188 {
1189   int x, y;
1190   boolean has_amoeba = FALSE, has_firefly = FALSE, has_butterfly = FALSE;
1191
1192   for (y = 0; y < cave->h; y++)
1193   {
1194     for (x = 0; x < cave->w; x++)
1195     {
1196       switch (cave->map[y][x] & ~SCANNED)
1197       {
1198         case O_FIREFLY_1:
1199         case O_FIREFLY_2:
1200         case O_FIREFLY_3:
1201         case O_FIREFLY_4:
1202           has_firefly = TRUE;
1203           break;
1204
1205         case O_BUTTER_1:
1206         case O_BUTTER_2:
1207         case O_BUTTER_3:
1208         case O_BUTTER_4:
1209           has_butterfly = TRUE;
1210           break;
1211
1212         case O_AMOEBA:
1213           has_amoeba = TRUE;
1214           break;
1215       }
1216     }
1217   }
1218
1219   cave->ckdelay_extra_for_animation = 0;
1220   if (has_amoeba)
1221     cave->ckdelay_extra_for_animation += 2600;
1222   if (has_firefly)
1223     cave->ckdelay_extra_for_animation += 2600;
1224   if (has_butterfly)
1225     cave->ckdelay_extra_for_animation += 2600;
1226   if (has_amoeba)
1227     cave->ckdelay_extra_for_animation += 2600;
1228 }
1229
1230 // do some init - setup some cave variables before the game.
1231 void gd_cave_setup_for_game(GdCave *cave)
1232 {
1233   int x, y;
1234
1235   cave_set_ckdelay_extra_for_animation(cave);
1236
1237   // find the player which will be the one to scroll to at the beginning of the game
1238   // (before the player's birth)
1239   if (cave->active_is_first_found)
1240   {
1241     // uppermost player is active
1242     for (y = cave->h - 1; y >= 0; y--)
1243     { 
1244      for (x = cave->w - 1; x >= 0; x--)
1245      {
1246         if (cave->map[y][x] == O_INBOX)
1247         {
1248           cave->player_x = x;
1249           cave->player_y = y;
1250         }
1251      }
1252     }
1253   }
1254   else
1255   {
1256     // lowermost player is active
1257     for (y = 0; y < cave->h; y++)
1258     {
1259       for (x = 0; x < cave->w; x++)
1260       {
1261         if (cave->map[y][x] == O_INBOX)
1262         {
1263           cave->player_x = x;
1264           cave->player_y = y;
1265         }
1266       }
1267     }
1268   }
1269
1270   // select number of milliseconds (for pal and ntsc)
1271   cave->timing_factor = cave->pal_timing ? 1200 : 1000;
1272
1273   cave->time                    *= cave->timing_factor;
1274   cave->magic_wall_time         *= cave->timing_factor;
1275   cave->amoeba_time             *= cave->timing_factor;
1276   cave->amoeba_2_time           *= cave->timing_factor;
1277   cave->hatching_delay_time     *= cave->timing_factor;
1278
1279   if (cave->hammered_walls_reappear)
1280     cave->hammered_reappear = gd_cave_map_new(cave, int);
1281 }
1282
1283 // cave diamonds needed can be set to n<=0.
1284 // if so, count the diamonds at the time of the hatching, and decrement that value from
1285 // the number of diamonds found.
1286 // of course, this function is to be called from the cave engine, at the exact time of hatching.
1287 void gd_cave_count_diamonds(GdCave *cave)
1288 {
1289   int x, y;
1290
1291   // if automatically counting diamonds. if this was negative,
1292   // the sum will be this less than the number of all the diamonds in the cave
1293   if (cave->diamonds_needed <= 0)
1294   {
1295     for (y = 0; y < cave->h; y++)
1296       for (x = 0; x < cave->w; x++)
1297         if (cave->map[y][x] == O_DIAMOND)
1298           cave->diamonds_needed++;
1299
1300     // if still below zero, let this be 0, so gate will be open immediately
1301     if (cave->diamonds_needed < 0)
1302       cave->diamonds_needed = 0;
1303   }
1304 }
1305
1306 /*
1307   takes a cave and a gfx buffer, and fills the buffer with cell indexes.
1308   the indexes might change if bonus life flash is active (small lines in
1309   "SPACE" cells),
1310   for the paused state (which is used in gdash but not in sdash) - yellowish
1311   color.
1312   also one can select the animation frame (0..7) to draw the cave on. so the
1313   caller manages
1314   increasing that.
1315
1316   if a cell is changed, it is flagged with GD_REDRAW; the flag can be cleared
1317   by the caller.
1318 */
1319 void gd_drawcave_game(const GdCave *cave,
1320                       int **element_buffer, int **last_element_buffer, int **gfx_buffer,
1321                       boolean bonus_life_flash, int animcycle, boolean hate_invisible_outbox)
1322 {
1323   static int player_blinking = 0;
1324   static int player_tapping = 0;
1325   int elemmapping[O_MAX_ALL];
1326   int elemdrawing[O_MAX_ALL];
1327   int x, y, map, draw;
1328
1329   if (cave->last_direction)
1330   {
1331     // he is moving, so stop blinking and tapping.
1332     player_blinking = 0;
1333     player_tapping = 0;
1334   }
1335   else
1336   {
1337     // he is idle, so animations can be done.
1338     if (animcycle == 0)
1339     {
1340       // blinking and tapping is started at the beginning of animation sequences.
1341       // 1/4 chance of blinking, every sequence.
1342       player_blinking = gd_random_int_range(0, 4) == 0;
1343
1344       // 1/16 chance of starting or stopping tapping.
1345       if (gd_random_int_range(0, 16) == 0)
1346         player_tapping = !player_tapping;
1347     }
1348   }
1349
1350   for (x = 0; x < O_MAX_ALL; x++)
1351   {
1352     elemmapping[x] = x;
1353     elemdrawing[x] = gd_elements[x].image_game;
1354   }
1355
1356   if (bonus_life_flash)
1357   {
1358     elemmapping[O_SPACE] = O_FAKE_BONUS;
1359     elemdrawing[O_SPACE] = gd_elements[O_FAKE_BONUS].image_game;
1360   }
1361
1362   elemmapping[O_MAGIC_WALL] = (cave->magic_wall_state == GD_MW_ACTIVE ? O_MAGIC_WALL : O_BRICK);
1363   elemdrawing[O_MAGIC_WALL] = gd_elements[cave->magic_wall_state == GD_MW_ACTIVE ? O_MAGIC_WALL : O_BRICK].image_game;
1364
1365   elemmapping[O_CREATURE_SWITCH] = (cave->creatures_backwards ? O_CREATURE_SWITCH_ON : O_CREATURE_SWITCH);
1366   elemdrawing[O_CREATURE_SWITCH] = gd_elements[cave->creatures_backwards ? O_CREATURE_SWITCH_ON : O_CREATURE_SWITCH].image_game;
1367
1368   elemmapping[O_EXPANDING_WALL_SWITCH] = (cave->expanding_wall_changed ? O_EXPANDING_WALL_SWITCH_VERT : O_EXPANDING_WALL_SWITCH_HORIZ);
1369   elemdrawing[O_EXPANDING_WALL_SWITCH] = gd_elements[cave->expanding_wall_changed ? O_EXPANDING_WALL_SWITCH_VERT : O_EXPANDING_WALL_SWITCH_HORIZ].image_game;
1370
1371   elemmapping[O_GRAVITY_SWITCH] = (cave->gravity_switch_active ? O_GRAVITY_SWITCH_ACTIVE : O_GRAVITY_SWITCH);
1372   elemdrawing[O_GRAVITY_SWITCH] = gd_elements[cave->gravity_switch_active ? O_GRAVITY_SWITCH_ACTIVE : O_GRAVITY_SWITCH].image_game;
1373
1374   elemmapping[O_REPLICATOR_SWITCH] = (cave->replicators_active ? O_REPLICATOR_SWITCH_ON : O_REPLICATOR_SWITCH_OFF);
1375   elemdrawing[O_REPLICATOR_SWITCH] = gd_elements[cave->replicators_active ? O_REPLICATOR_SWITCH_ON : O_REPLICATOR_SWITCH_OFF].image_game;
1376
1377   if (cave->replicators_active)
1378     // if the replicators are active, animate them.
1379     elemmapping[O_REPLICATOR] = O_REPLICATOR_ACTIVE;
1380
1381   if (!cave->replicators_active)
1382     // if the replicators are inactive, do not animate them.
1383     elemdrawing[O_REPLICATOR] = ABS(elemdrawing[O_REPLICATOR]);
1384
1385   elemmapping[O_CONVEYOR_SWITCH] = (cave->conveyor_belts_active ? O_CONVEYOR_SWITCH_ON : O_CONVEYOR_SWITCH_OFF);
1386   elemdrawing[O_CONVEYOR_SWITCH] = gd_elements[cave->conveyor_belts_active ? O_CONVEYOR_SWITCH_ON : O_CONVEYOR_SWITCH_OFF].image_game;
1387
1388   if (cave->conveyor_belts_direction_changed)
1389   {
1390     // if direction is changed, animation is changed.
1391     int temp;
1392
1393     elemmapping[O_CONVEYOR_LEFT] = O_CONVEYOR_RIGHT;
1394     elemmapping[O_CONVEYOR_RIGHT] = O_CONVEYOR_LEFT;
1395
1396     temp = elemdrawing[O_CONVEYOR_LEFT];
1397     elemdrawing[O_CONVEYOR_LEFT] = elemdrawing[O_CONVEYOR_RIGHT];
1398     elemdrawing[O_CONVEYOR_RIGHT] = temp;
1399
1400     elemmapping[O_CONVEYOR_DIR_SWITCH] = O_CONVEYOR_DIR_CHANGED;
1401     elemdrawing[O_CONVEYOR_DIR_SWITCH] = gd_elements[O_CONVEYOR_DIR_CHANGED].image_game;
1402   }
1403   else
1404   {
1405     elemmapping[O_CONVEYOR_DIR_SWITCH] = O_CONVEYOR_DIR_NORMAL;
1406     elemdrawing[O_CONVEYOR_DIR_SWITCH] = gd_elements[O_CONVEYOR_DIR_NORMAL].image_game;
1407   }
1408
1409   if (cave->conveyor_belts_active)
1410   {
1411     // keep potentially changed direction
1412     int offset = (O_CONVEYOR_LEFT_ACTIVE - O_CONVEYOR_LEFT);
1413
1414     // if they are running, animate them.
1415     elemmapping[O_CONVEYOR_LEFT]  += offset;
1416     elemmapping[O_CONVEYOR_RIGHT] += offset;
1417   }
1418   if (!cave->conveyor_belts_active)
1419   {
1420     // if they are not running, do not animate them.
1421     elemdrawing[O_CONVEYOR_LEFT] = ABS(elemdrawing[O_CONVEYOR_LEFT]);
1422     elemdrawing[O_CONVEYOR_RIGHT] = ABS(elemdrawing[O_CONVEYOR_RIGHT]);
1423   }
1424
1425   if (animcycle & 2)
1426   {
1427     // also a hack, like biter_switch
1428     elemdrawing[O_PNEUMATIC_ACTIVE_LEFT]  += 2;
1429     elemdrawing[O_PNEUMATIC_ACTIVE_RIGHT] += 2;
1430     elemdrawing[O_PLAYER_PNEUMATIC_LEFT]  += 2;
1431     elemdrawing[O_PLAYER_PNEUMATIC_RIGHT] += 2;
1432   }
1433
1434   if ((cave->last_direction) == GD_MV_STILL)
1435   {
1436     // player is idle.
1437     if (player_blinking && player_tapping)
1438     {
1439       map = O_PLAYER_TAP_BLINK;
1440       draw = gd_elements[O_PLAYER_TAP_BLINK].image_game;
1441     }
1442     else if (player_blinking)
1443     {
1444       map = O_PLAYER_BLINK;
1445       draw = gd_elements[O_PLAYER_BLINK].image_game;
1446     }
1447     else if (player_tapping)
1448     {
1449       map = O_PLAYER_TAP;
1450       draw = gd_elements[O_PLAYER_TAP].image_game;
1451     }
1452     else
1453     {
1454       map = O_PLAYER;
1455       draw = gd_elements[O_PLAYER].image_game;
1456     }
1457   }
1458   else if (cave->last_direction == GD_MV_UP && use_bd_up_down_graphics())
1459   {
1460     map = O_PLAYER_UP;
1461     draw = gd_elements[O_PLAYER_UP].image_game;
1462   }
1463   else if (cave->last_direction == GD_MV_DOWN && use_bd_up_down_graphics())
1464   {
1465     map = O_PLAYER_DOWN;
1466     draw = gd_elements[O_PLAYER_DOWN].image_game;
1467   }
1468   else if (cave->last_horizontal_direction == GD_MV_LEFT)
1469   {
1470     map = O_PLAYER_LEFT;
1471     draw = gd_elements[O_PLAYER_LEFT].image_game;
1472   }
1473   else
1474   {
1475     // of course this is GD_MV_RIGHT.
1476     map = O_PLAYER_RIGHT;
1477     draw = gd_elements[O_PLAYER_RIGHT].image_game;
1478   }
1479
1480   elemmapping[O_PLAYER] = map;
1481   elemmapping[O_PLAYER_GLUED] = map;
1482
1483   elemdrawing[O_PLAYER] = draw;
1484   elemdrawing[O_PLAYER_GLUED] = draw;
1485
1486   // player with bomb/rocketlauncher does not blink or tap - no graphics drawn for that.
1487   // running is drawn using w/o bomb/rocketlauncher cells */
1488   if (cave->last_direction != GD_MV_STILL)
1489   {
1490     elemmapping[O_PLAYER_BOMB] = map;
1491     elemdrawing[O_PLAYER_BOMB] = draw;
1492
1493     elemmapping[O_PLAYER_ROCKET_LAUNCHER] = map;
1494     elemdrawing[O_PLAYER_ROCKET_LAUNCHER] = draw;
1495   }
1496
1497   elemmapping[O_INBOX] = (cave->inbox_flash_toggle ? O_INBOX_OPEN : O_INBOX_CLOSED);
1498   elemdrawing[O_INBOX] = gd_elements[cave->inbox_flash_toggle ? O_OUTBOX_OPEN : O_OUTBOX_CLOSED].image_game;
1499
1500   elemmapping[O_OUTBOX] = (cave->inbox_flash_toggle ? O_OUTBOX_OPEN : O_OUTBOX_CLOSED);
1501   elemdrawing[O_OUTBOX] = gd_elements[cave->inbox_flash_toggle ? O_OUTBOX_OPEN : O_OUTBOX_CLOSED].image_game;
1502
1503   // hack, not fit into gd_elements
1504   elemmapping[O_BITER_SWITCH] = O_BITER_SWITCH_1 + cave->biter_delay_frame;
1505   // hack, not fit into gd_elements
1506   elemdrawing[O_BITER_SWITCH] = gd_elements[O_BITER_SWITCH].image_game + cave->biter_delay_frame;
1507
1508   // visual effects
1509   elemmapping[O_DIRT] = cave->dirt_looks_like;
1510   elemmapping[O_EXPANDING_WALL] = cave->expanding_wall_looks_like;
1511   elemmapping[O_V_EXPANDING_WALL] = cave->expanding_wall_looks_like;
1512   elemmapping[O_H_EXPANDING_WALL] = cave->expanding_wall_looks_like;
1513   elemmapping[O_AMOEBA_2] = cave->amoeba_2_looks_like;
1514
1515   // visual effects
1516   elemdrawing[O_DIRT] = elemdrawing[cave->dirt_looks_like];
1517   elemdrawing[O_EXPANDING_WALL] = elemdrawing[cave->expanding_wall_looks_like];
1518   elemdrawing[O_V_EXPANDING_WALL] = elemdrawing[cave->expanding_wall_looks_like];
1519   elemdrawing[O_H_EXPANDING_WALL] = elemdrawing[cave->expanding_wall_looks_like];
1520   elemdrawing[O_AMOEBA_2] = elemdrawing[cave->amoeba_2_looks_like];
1521
1522   // change only graphically
1523   if (hate_invisible_outbox)
1524   {
1525     elemmapping[O_PRE_INVIS_OUTBOX] = elemmapping[O_PRE_OUTBOX];
1526     elemmapping[O_INVIS_OUTBOX] = elemmapping[O_OUTBOX];
1527   }
1528
1529   if (hate_invisible_outbox)
1530   {
1531     elemdrawing[O_PRE_INVIS_OUTBOX] = elemdrawing[O_PRE_OUTBOX];
1532     elemdrawing[O_INVIS_OUTBOX] = elemdrawing[O_OUTBOX];
1533   }
1534
1535   for (y = cave->y1; y <= cave->y2; y++)
1536   {
1537     for (x = cave->x1; x <= cave->x2; x++)
1538     {
1539       GdElement actual = cave->map[y][x];
1540
1541       // if covered, real element is not important
1542       if (actual & COVERED)
1543         map = O_COVERED;
1544       else
1545         map = elemmapping[actual];
1546
1547       // if covered, real element is not important
1548       if (actual & COVERED)
1549         draw = gd_elements[O_COVERED].image_game;
1550       else
1551         draw = elemdrawing[actual];
1552
1553       // draw special graphics if player is pushing something
1554       if (use_bd_pushing_graphics() &&
1555           (cave->last_direction == GD_MV_LEFT || cave->last_direction == GD_MV_RIGHT) &&
1556           is_player(cave, x, y) && can_be_pushed_dir(cave, x, y, cave->last_direction))
1557       {
1558         // special check needed when smooth game element movements selected in setup menu:
1559         // last element must either be player (before pushing) or pushable element (while pushing)
1560         // (extra check needed to prevent pushing animation when moving towards pushable element)
1561         if (!use_bd_smooth_movements() || last_element_buffer[y][x] != O_SPACE)
1562         {
1563           if (cave->last_direction == GD_MV_LEFT)
1564             map = O_PLAYER_PUSH_LEFT;
1565           else
1566             map = O_PLAYER_PUSH_RIGHT;
1567
1568           if (cave->last_direction == GD_MV_LEFT)
1569             draw = elemdrawing[O_PLAYER_PUSH_LEFT];
1570           else
1571             draw = elemdrawing[O_PLAYER_PUSH_RIGHT];
1572         }
1573       }
1574
1575       // if negative, animated.
1576       if (draw < 0)
1577         draw = -draw + animcycle;
1578
1579       // flash
1580       if (cave->gate_open_flash)
1581         draw += GD_NUM_OF_CELLS;
1582
1583       // set to buffer, with caching
1584       if (element_buffer[y][x] != map)
1585         element_buffer[y][x] = map;
1586
1587       if (gfx_buffer[y][x] != draw)
1588         gfx_buffer[y][x] = draw | GD_REDRAW;
1589     }
1590   }
1591 }
1592
1593 /*
1594   cave time is rounded _UP_ to seconds. so at the exact moment when it
1595   changes from
1596   2sec remaining to 1sec remaining, the player has exactly one second.
1597   when it changes
1598   to zero, it is the exact moment of timeout.
1599
1600   internal time is milliseconds (or 1200 milliseconds for pal timing).
1601 */
1602 int gd_cave_time_show(const GdCave *cave, int internal_time)
1603 {
1604   return (internal_time + cave->timing_factor - 1) / cave->timing_factor;
1605 }
1606
1607 GdReplay *gd_replay_new(void)
1608 {
1609   GdReplay *rep;
1610
1611   rep = checked_calloc(sizeof(GdReplay));
1612   rep->movements = checked_calloc(sizeof(GdReplayMovements));
1613
1614   return rep;
1615 }
1616
1617 GdReplay *gd_replay_new_from_replay(GdReplay *orig)
1618 {
1619   GdReplay *rep;
1620
1621   rep = get_memcpy(orig, sizeof(GdReplay));
1622
1623   // replicate dynamic data
1624   rep->comment = getStringCopy(orig->comment);
1625   rep->movements = get_memcpy(orig->movements, sizeof(GdReplayMovements));
1626
1627   return rep;
1628 }
1629
1630 void gd_replay_free(GdReplay *replay)
1631 {
1632   checked_free(replay->movements);
1633   checked_free(replay->comment);
1634   free(replay);
1635 }
1636
1637 // store movement in a replay
1638 void gd_replay_store_movement(GdReplay *replay, GdDirection player_move,
1639                               boolean player_fire, boolean suicide)
1640 {
1641   byte data[1];
1642
1643   data[0] = ((player_move) |
1644              (player_fire ? GD_REPLAY_FIRE_MASK : 0) |
1645              (suicide ? GD_REPLAY_SUICIDE_MASK : 0));
1646
1647   if (replay->movements->len < MAX_REPLAY_LEN)
1648   {
1649     replay->movements->data[replay->movements->len++] = data[0];
1650
1651     if (replay->movements->len == MAX_REPLAY_LEN)
1652       Warn("BD replay truncated: size exceeds maximum replay size %d", MAX_REPLAY_LEN);
1653   }
1654 }
1655
1656 // calculate adler checksum for a rendered cave; this can be used for more caves.
1657 void gd_cave_adler_checksum_more(GdCave *cave, unsigned int *a, unsigned int *b)
1658 {
1659   int x, y;
1660
1661   for (y = 0; y < cave->h; y++)
1662     for (x = 0; x < cave->w; x++)
1663     {
1664       *a += gd_elements[cave->map[y][x]].character;
1665       *b += *a;
1666
1667       *a %= 65521;
1668       *b %= 65521;
1669     }
1670 }
1671
1672 // calculate adler checksum for a single rendered cave.
1673 unsigned int gd_cave_adler_checksum(GdCave *cave)
1674 {
1675   unsigned int a = 1;
1676   unsigned int b = 0;
1677
1678   gd_cave_adler_checksum_more(cave, &a, &b);
1679   return (b << 16) + a;
1680 }
1681
1682 boolean gd_cave_has_levels(GdCave *cave)
1683 {
1684   GdCave c = *cave;
1685   int *cave_level_value[] =
1686   {
1687     c.level_diamonds,
1688     c.level_speed,
1689     c.level_ckdelay,
1690     c.level_time,
1691     c.level_magic_wall_time,
1692     c.level_amoeba_time,
1693     c.level_amoeba_threshold,
1694     c.level_amoeba_2_time,
1695     c.level_amoeba_2_threshold,
1696     c.level_slime_permeability,
1697     c.level_slime_permeability_c64,
1698     c.level_slime_seed_c64,
1699     c.level_hatching_delay_frame,
1700     c.level_hatching_delay_time,
1701     c.level_bonus_time,
1702     c.level_penalty_time,
1703
1704     NULL
1705   };
1706   int i, j;
1707
1708   for (i = 0; cave_level_value[i] != NULL; i++)
1709     for (j = 1; j < 5; j++)
1710       if (cave_level_value[i][j] != cave_level_value[i][0])
1711         return TRUE;
1712
1713   for (j = 1; j < 5; j++)
1714     if (cave->level_rand[j] != j &&
1715         cave->level_rand[j - 1] != j - 1 &&
1716         cave->level_rand[j] != cave->level_rand[0])
1717       return TRUE;
1718
1719   for (j = 1; j < 5; j++)
1720     if (cave->level_timevalue[j] != j + 1 &&
1721         cave->level_timevalue[j - 1] != j &&
1722         cave->level_timevalue[j] != cave->level_timevalue[0])
1723       return TRUE;
1724
1725   return FALSE;
1726 }
1727
1728 boolean gd_caveset_has_levels(void)
1729 {
1730   List *iter;
1731
1732   for (iter = gd_caveset; iter != NULL; iter = iter->next)
1733     if (gd_cave_has_levels((GdCave *)iter->data))
1734       return TRUE;
1735
1736   return FALSE;
1737 }