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