replaced glib function calls to g_string_*()
[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 GHashTable *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 g_strdupped strings to elemenets (integers) */
279   name_to_element = g_hash_table_new_full(gd_str_case_hash, gd_str_case_equal,
280                                           free, NULL);
281
282   for (i = 0; i < O_MAX; i++)
283   {
284     char *key;
285
286     key = g_ascii_strup(gd_elements[i].filename, -1);
287
288     if (g_hash_table_lookup_extended(name_to_element, key, NULL, NULL))
289       Warn("Name %s already used for element %x", key, i);
290
291     g_hash_table_insert(name_to_element, key, GINT_TO_POINTER(i));
292     /* ^^^ do not free "key", as hash table needs it during the whole time! */
293
294     key = g_strdup_printf("SCANNED_%s", key);        /* new string */
295
296     g_hash_table_insert(name_to_element, key, GINT_TO_POINTER(i));
297     /* once again, do not free "key" ^^^ */
298   }
299
300   /* for compatibility with tim stridmann's memorydump->bdcff converter... .... ... */
301   g_hash_table_insert(name_to_element, "HEXPANDING_WALL", GINT_TO_POINTER(O_H_EXPANDING_WALL));
302   g_hash_table_insert(name_to_element, "FALLING_DIAMOND", GINT_TO_POINTER(O_DIAMOND_F));
303   g_hash_table_insert(name_to_element, "FALLING_BOULDER", GINT_TO_POINTER(O_STONE_F));
304   g_hash_table_insert(name_to_element, "EXPLOSION1S", GINT_TO_POINTER(O_EXPLODE_1));
305   g_hash_table_insert(name_to_element, "EXPLOSION2S", GINT_TO_POINTER(O_EXPLODE_2));
306   g_hash_table_insert(name_to_element, "EXPLOSION3S", GINT_TO_POINTER(O_EXPLODE_3));
307   g_hash_table_insert(name_to_element, "EXPLOSION4S", GINT_TO_POINTER(O_EXPLODE_4));
308   g_hash_table_insert(name_to_element, "EXPLOSION5S", GINT_TO_POINTER(O_EXPLODE_5));
309   g_hash_table_insert(name_to_element, "EXPLOSION1D", GINT_TO_POINTER(O_PRE_DIA_1));
310   g_hash_table_insert(name_to_element, "EXPLOSION2D", GINT_TO_POINTER(O_PRE_DIA_2));
311   g_hash_table_insert(name_to_element, "EXPLOSION3D", GINT_TO_POINTER(O_PRE_DIA_3));
312   g_hash_table_insert(name_to_element, "EXPLOSION4D", GINT_TO_POINTER(O_PRE_DIA_4));
313   g_hash_table_insert(name_to_element, "EXPLOSION5D", GINT_TO_POINTER(O_PRE_DIA_5));
314   g_hash_table_insert(name_to_element, "WALL2", GINT_TO_POINTER(O_STEEL_EXPLODABLE));
315
316   /* compatibility with old bd-faq (pre disassembly of bladder) */
317   g_hash_table_insert(name_to_element, "BLADDERd9", GINT_TO_POINTER(O_BLADDER_8));
318
319   /* create table to show errors at the start of the application */
320   gd_create_char_to_element_table();
321 }
322
323 /* search the element database for the specified name, and return the element */
324 GdElement gd_get_element_from_string (const char *string)
325 {
326   char *upper = g_ascii_strup(string, -1);
327   gpointer value;
328   boolean found;
329
330   if (!string)
331   {
332     Warn("Invalid string representing element: (null)");
333     return O_UNKNOWN;
334   }
335
336   found = g_hash_table_lookup_extended(name_to_element, upper, NULL, &value);
337   free(upper);
338   if (found)
339     return (GdElement) (GPOINTER_TO_INT(value));
340
341   Warn("Invalid string representing element: %s", string);
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(gconstpointer a, gconstpointer 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 (g_str_equal(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 boolean gd_str_case_equal(gconstpointer s1, gconstpointer s2)
425 {
426   return strcasecmp(s1, s2) == 0;
427 }
428
429 guint gd_str_case_hash(gconstpointer v)
430 {
431   char *upper;
432   guint hash;
433
434   upper = g_ascii_strup(v, -1);
435   hash = g_str_hash(v);
436   free(upper);
437   return hash;
438 }
439
440 /*
441   create new cave with default values.
442   sets every value, also default size, diamond value etc.
443 */
444 GdCave *gd_cave_new(void)
445 {
446   GdCave *cave;
447
448   cave = checked_calloc(sizeof(GdCave));
449
450   /* hash table which stores unknown tags as strings. */
451   cave->tags = g_hash_table_new_full(gd_str_case_hash, gd_str_case_equal, free, free);
452
453   gd_cave_set_gdash_defaults(cave);
454
455   return cave;
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 gpointer gd_cave_map_new_for_cave(const GdCave *cave, const int cell_size)
479 {
480   gpointer *rows;                /* this is void**, pointer to array of ... */
481   int y;
482
483   rows = checked_malloc((cave->h) * sizeof(gpointer));
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 gpointer gd_cave_map_dup_size(const GdCave *cave, const gpointer map, const int cell_size)
499 {
500   gpointer *rows;
501   gpointer *maplines = (gpointer *)map;
502   int y;
503
504   if (!map)
505     return NULL;
506
507   rows = checked_malloc((cave->h) * sizeof(gpointer));
508   rows[0] = g_memdup (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(gpointer map)
517 {
518   gpointer *maplines = (gpointer *) 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     g_hash_table_destroy(cave->tags);
539
540   if (cave->random)    /* random generator is a GRand * */
541     g_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(G_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   g_list_foreach(cave->objects, (GFunc) free, NULL);
559   g_list_free (cave->objects);
560
561   /* free replays */
562   g_list_foreach(cave->replays, (GFunc) gd_replay_free, NULL);
563   g_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, GHashTable *dest)
570 {
571   g_hash_table_insert(dest, g_strdup(key), g_strdup(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   g_memmove(dest, src, sizeof(GdCave));
581
582   /* but duplicate dynamic data */
583   dest->tags = g_hash_table_new_full(gd_str_case_hash, gd_str_case_equal,
584                                      free, free);
585   if (src->tags)
586     g_hash_table_foreach(src->tags, (GHFunc) 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       G_STRUCT_MEMBER(char *, dest, gd_cave_properties[i].offset) =
595         getStringCopy(G_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     GList *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 = g_list_append(dest->objects, g_memdup (iter->data, sizeof (GdObject)));
608   }
609
610   /* copy replays */
611   if (src->replays)
612   {
613     GList *iter;
614
615     dest->replays = NULL;
616     for (iter = src->replays; iter != NULL; iter = iter->next) /* do a deep copy */
617       dest->replays = g_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 = g_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 which cell was created by which object.
642 */
643 void gd_cave_store_rc(GdCave *cave, int x, int y, const GdElement element, const void *order)
644 {
645   /* if we do not need to draw, exit now */
646   if (element == O_NONE)
647     return;
648
649   /* check bounds */
650   if (cave->wraparound_objects)
651   {
652     if (cave->lineshift)
653     {
654       /* fit x coordinate within range, with correcting y at the same time */
655       while (x < 0)
656       {
657         x += cave->w;    /* out of bounds on the left... */
658         y--;             /* previous row */
659       }
660
661       while (x >= cave->w)
662       {
663         x -= cave->w;
664         y++;
665       }
666
667       /* lineshifting does not fix the y coordinates.
668          if out of bounds, element will not be displayed. */
669       /* if such an object appeared in the c64 game, well, it was a buffer overrun. */
670     }
671     else
672     {
673       /* non lineshifting: changing x does not change y coordinate. */
674       while (x < 0)
675         x += cave->w;
676
677       while (x >= cave->w)
678         x -= cave->w;
679
680       /* after that, fix y coordinate */
681       while (y < 0)
682         y += cave->h;
683
684       while (y >= cave->h)
685         y -= cave->h;
686     }
687   }
688
689   /* if the above wraparound code fixed the coordinates, this will always be true. */
690   /* but see the above comment for lineshifting y coordinate */
691   if (x >= 0 && x < cave->w && y >= 0 && y < cave->h)
692   {
693     cave->map[y][x] = element;
694     cave->objects_order[y][x] = (void *)order;
695   }
696 }
697
698 GdElement gd_cave_get_rc(const GdCave *cave, int x, int y)
699 {
700   /* always fix coordinates as if cave was wraparound. */
701
702   /* fix x coordinate */
703   if (cave->lineshift)
704   {
705     /* fit x coordinate within range, with correcting y at the same time */
706     while (x < 0)
707     {
708       x += cave->w;    /* out of bounds on the left... */
709       y--;             /* previous row */
710     }
711     while (x >= cave->w)
712     {
713       x -= cave->w;
714       y++;
715     }
716   }
717   else
718   {
719     /* non lineshifting: changing x does not change y coordinate. */
720     while (x < 0)
721       x += cave->w;
722
723     while (x >= cave->w)
724       x -= cave->w;
725   }
726
727   /* after that, fix y coordinate */
728   while (y < 0)
729     y += cave->h;
730
731   while (y >= cave->h)
732     y -= cave->h;
733
734   return cave->map[y][x];
735 }
736
737 unsigned int gd_c64_random(GdC64RandomGenerator *rand)
738 {
739   unsigned int temp_rand_1, temp_rand_2, carry, result;
740
741   temp_rand_1 = (rand->rand_seed_1 & 0x0001) << 7;
742   temp_rand_2 = (rand->rand_seed_2 >> 1) & 0x007F;
743   result = (rand->rand_seed_2) + ((rand->rand_seed_2 & 0x0001) << 7);
744   carry = (result >> 8);
745   result = result & 0x00FF;
746   result = result + carry + 0x13;
747   carry = (result >> 8);
748   rand->rand_seed_2 = result & 0x00FF;
749   result = rand->rand_seed_1 + carry + temp_rand_1;
750   carry = (result >> 8);
751   result = result & 0x00FF;
752   result = result + carry + temp_rand_2;
753   rand->rand_seed_1 = result & 0x00FF;
754
755   return rand->rand_seed_1;
756 }
757
758 /*
759   C64 BD predictable random number generator.
760   Used to load the original caves imported from c64 files.
761   Also by the predictable slime.
762 */
763 unsigned int gd_cave_c64_random(GdCave *cave)
764 {
765   return gd_c64_random(&cave->c64_rand);
766 }
767
768 void gd_c64_random_set_seed(GdC64RandomGenerator *rand, int seed1, int seed2)
769 {
770   rand->rand_seed_1 = seed1;
771   rand->rand_seed_2 = seed2;
772 }
773
774 void gd_cave_c64_random_set_seed(GdCave *cave, int seed1, int seed2)
775 {
776   gd_c64_random_set_seed(&cave->c64_rand, seed1, seed2);
777 }
778
779 /*
780   select random colors for a given cave.
781   this function will select colors so that they should look somewhat nice; for example
782   brick walls won't be the darkest color, for example.
783 */
784 static inline void swap(int *i1, int *i2)
785 {
786   int t = *i1;
787   *i1 = *i2;
788   *i2 = t;
789 }
790
791 /*
792   shrink cave
793   if last line or last row is just steel wall (or (invisible) outbox).
794   used after loading a game for playing.
795   after this, ew and eh will contain the effective width and height.
796 */
797 void gd_cave_auto_shrink(GdCave *cave)
798 {
799
800   int x, y;
801   enum
802   {
803     STEEL_ONLY,
804     STEEL_OR_OTHER,
805     NO_SHRINK
806   }
807   empty;
808
809   /* set to maximum size, then try to shrink */
810   cave->x1 = 0;
811   cave->y1 = 0;
812   cave->x2 = cave->w - 1;
813   cave->y2 = cave->h - 1;
814
815   /* search for empty, steel-wall-only last rows. */
816   /* clear all lines, which are only steel wall.
817    * and clear only one line, which is steel wall, but also has a player or an outbox. */
818   empty = STEEL_ONLY;
819
820   do
821   {
822     for (y = cave->y2 - 1; y <= cave->y2; y++)
823     {
824       for (x = cave->x1; x <= cave->x2; x++)
825       {
826         switch (gd_cave_get_rc (cave, x, y))
827         {
828           /* if steels only, this is to be deleted. */
829           case O_STEEL:
830             break;
831
832           case O_PRE_OUTBOX:
833           case O_PRE_INVIS_OUTBOX:
834           case O_INBOX:
835             if (empty == STEEL_OR_OTHER)
836               empty = NO_SHRINK;
837
838             /* if this, delete only this one, and exit. */
839             if (empty == STEEL_ONLY)
840               empty = STEEL_OR_OTHER;
841             break;
842
843           default:
844             /* anything else, that should be left in the cave. */
845             empty = NO_SHRINK;
846             break;
847         }
848       }
849     }
850
851     /* shrink if full steel or steel and player/outbox. */
852     if (empty != NO_SHRINK)
853       cave->y2--;            /* one row shorter */
854   }
855   while (empty == STEEL_ONLY);    /* if found just steels, repeat. */
856
857   /* search for empty, steel-wall-only first rows. */
858   empty = STEEL_ONLY;
859
860   do
861   {
862     for (y = cave->y1; y <= cave->y1 + 1; y++)
863     {
864       for (x = cave->x1; x <= cave->x2; x++)
865       {
866         switch (gd_cave_get_rc (cave, x, y))
867         {
868           case O_STEEL:
869             break;
870
871           case O_PRE_OUTBOX:
872           case O_PRE_INVIS_OUTBOX:
873           case O_INBOX:
874             /* shrink only lines, which have only ONE player or outbox.
875                this is for bd4 intermission 2, for example. */
876             if (empty == STEEL_OR_OTHER)
877               empty = NO_SHRINK;
878             if (empty == STEEL_ONLY)
879               empty = STEEL_OR_OTHER;
880             break;
881
882           default:
883             empty = NO_SHRINK;
884             break;
885         }
886       }
887     }
888
889     if (empty != NO_SHRINK)
890       cave->y1++;
891   }
892   while (empty == STEEL_ONLY);    /* if found one, repeat. */
893
894   /* empty last columns. */
895   empty = STEEL_ONLY;
896
897   do
898   {
899     for (y = cave->y1; y <= cave->y2; y++)
900     {
901       for (x = cave->x2 - 1; x <= cave->x2; x++)
902       {
903         switch (gd_cave_get_rc (cave, x, y))
904         {
905           case O_STEEL:
906             break;
907
908           case O_PRE_OUTBOX:
909           case O_PRE_INVIS_OUTBOX:
910           case O_INBOX:
911             if (empty == STEEL_OR_OTHER)
912               empty = NO_SHRINK;
913             if (empty == STEEL_ONLY)
914               empty = STEEL_OR_OTHER;
915             break;
916
917           default:
918             empty = NO_SHRINK;
919             break;
920         }
921       }
922     }
923
924     /* just remember that one column shorter.
925        free will know the size of memchunk, no need to realloc! */
926     if (empty != NO_SHRINK)
927       cave->x2--;
928   }
929   while (empty == STEEL_ONLY);    /* if found one, repeat. */
930
931   /* empty first columns. */
932   empty = STEEL_ONLY;
933
934   do
935   {
936     for (y = cave->y1; y <= cave->y2; y++)
937     {
938       for (x = cave->x1; x <= cave->x1 + 1; x++)
939       {
940         switch (gd_cave_get_rc (cave, x, y))
941         {
942           case O_STEEL:
943             break;
944
945           case O_PRE_OUTBOX:
946           case O_PRE_INVIS_OUTBOX:
947           case O_INBOX:
948             if (empty == STEEL_OR_OTHER)
949               empty = NO_SHRINK;
950             if (empty == STEEL_ONLY)
951               empty = STEEL_OR_OTHER;
952             break;
953
954           default:
955             empty = NO_SHRINK;
956             break;
957         }
958       }
959     }
960
961     if (empty != NO_SHRINK)
962       cave->x1++;
963   }
964   while (empty == STEEL_ONLY);    /* if found one, repeat. */
965 }
966
967 /* check if cave visible part coordinates
968    are outside cave sizes, or not in the right order.
969    correct them if needed.
970 */
971 void gd_cave_correct_visible_size(GdCave *cave)
972 {
973   /* change visible coordinates if they do not point to upperleft and lowerright */
974   if (cave->x2 < cave->x1)
975   {
976     int t = cave->x2;
977     cave->x2 = cave->x1;
978     cave->x1 = t;
979   }
980
981   if (cave->y2 < cave->y1)
982   {
983     int t = cave->y2;
984     cave->y2 = cave->y1;
985     cave->y1 = t;
986   }
987
988   if (cave->x1 < 0)
989     cave->x1 = 0;
990
991   if (cave->y1 < 0)
992     cave->y1 = 0;
993
994   if (cave->x2 > cave->w - 1)
995     cave->x2 = cave->w - 1;
996
997   if (cave->y2 > cave->h - 1)
998     cave->y2 = cave->h - 1;
999 }
1000
1001 /*
1002   bd1 and similar engines had animation bits in cave data, to set which elements to animate
1003   (firefly, butterfly, amoeba).
1004   animating an element also caused some delay each frame; according to my measurements,
1005   around 2.6 ms/element.
1006 */
1007 static void cave_set_ckdelay_extra_for_animation(GdCave *cave)
1008 {
1009   int x, y;
1010   boolean has_amoeba = FALSE, has_firefly = FALSE, has_butterfly = FALSE;
1011
1012   for (y = 0; y < cave->h; y++)
1013   {
1014     for (x = 0; x < cave->w; x++)
1015     {
1016       switch (cave->map[y][x] & ~SCANNED)
1017       {
1018         case O_FIREFLY_1:
1019         case O_FIREFLY_2:
1020         case O_FIREFLY_3:
1021         case O_FIREFLY_4:
1022           has_firefly = TRUE;
1023           break;
1024
1025         case O_BUTTER_1:
1026         case O_BUTTER_2:
1027         case O_BUTTER_3:
1028         case O_BUTTER_4:
1029           has_butterfly = TRUE;
1030           break;
1031
1032         case O_AMOEBA:
1033           has_amoeba = TRUE;
1034           break;
1035       }
1036     }
1037   }
1038
1039   cave->ckdelay_extra_for_animation = 0;
1040   if (has_amoeba)
1041     cave->ckdelay_extra_for_animation += 2600;
1042   if (has_firefly)
1043     cave->ckdelay_extra_for_animation += 2600;
1044   if (has_butterfly)
1045     cave->ckdelay_extra_for_animation += 2600;
1046   if (has_amoeba)
1047     cave->ckdelay_extra_for_animation += 2600;
1048 }
1049
1050 /* do some init - setup some cave variables before the game. */
1051 void gd_cave_setup_for_game(GdCave *cave)
1052 {
1053   int x, y;
1054
1055   cave_set_ckdelay_extra_for_animation(cave);
1056
1057   /* find the player which will be the one to scroll to at the beginning of the game
1058      (before the player's birth) */
1059   if (cave->active_is_first_found)
1060   {
1061     /* uppermost player is active */
1062     for (y = cave->h - 1; y >= 0; y--)
1063     { 
1064      for (x = cave->w - 1; x >= 0; x--)
1065      {
1066         if (cave->map[y][x] == O_INBOX)
1067         {
1068           cave->player_x = x;
1069           cave->player_y = y;
1070         }
1071      }
1072     }
1073   }
1074   else
1075   {
1076     /* lowermost player is active */
1077     for (y = 0; y < cave->h; y++)
1078     {
1079       for (x = 0; x < cave->w; x++)
1080       {
1081         if (cave->map[y][x] == O_INBOX)
1082         {
1083           cave->player_x = x;
1084           cave->player_y = y;
1085         }
1086       }
1087     }
1088   }
1089
1090   /* select number of milliseconds (for pal and ntsc) */
1091   cave->timing_factor = cave->pal_timing ? 1200 : 1000;
1092
1093   cave->time                    *= cave->timing_factor;
1094   cave->magic_wall_time         *= cave->timing_factor;
1095   cave->amoeba_time             *= cave->timing_factor;
1096   cave->amoeba_2_time           *= cave->timing_factor;
1097   cave->hatching_delay_time     *= cave->timing_factor;
1098
1099   if (cave->hammered_walls_reappear)
1100     cave->hammered_reappear = gd_cave_map_new(cave, int);
1101 }
1102
1103 /* cave diamonds needed can be set to n<=0. */
1104 /* if so, count the diamonds at the time of the hatching, and decrement that value from */
1105 /* the number of diamonds found. */
1106 /* of course, this function is to be called from the cave engine, at the exact time of hatching. */
1107 void gd_cave_count_diamonds(GdCave *cave)
1108 {
1109   int x, y;
1110
1111   /* if automatically counting diamonds. if this was negative,
1112    * the sum will be this less than the number of all the diamonds in the cave */
1113   if (cave->diamonds_needed <= 0)
1114   {
1115     for (y = 0; y < cave->h; y++)
1116       for (x = 0; x < cave->w; x++)
1117         if (cave->map[y][x] == O_DIAMOND)
1118           cave->diamonds_needed++;
1119
1120     /* if still below zero, let this be 0, so gate will be open immediately */
1121     if (cave->diamonds_needed < 0)
1122       cave->diamonds_needed = 0;
1123   }
1124 }
1125
1126 /* takes a cave and a gfx buffer, and fills the buffer with cell indexes.
1127    the indexes might change if bonus life flash is active (small lines in
1128    "SPACE" cells),
1129    for the paused state (which is used in gdash but not in sdash) - yellowish
1130    color.
1131    also one can select the animation frame (0..7) to draw the cave on. so the
1132    caller manages
1133    increasing that.
1134
1135    if a cell is changed, it is flagged with GD_REDRAW; the flag can be cleared
1136    by the caller.
1137 */
1138 void gd_drawcave_game(const GdCave *cave, int **element_buffer, int **gfx_buffer,
1139                       boolean bonus_life_flash, int animcycle, boolean hate_invisible_outbox)
1140 {
1141   static int player_blinking = 0;
1142   static int player_tapping = 0;
1143   int elemmapping[O_MAX];
1144   int elemdrawing[O_MAX];
1145   int x, y, map, draw;
1146
1147   if (cave->last_direction)
1148   {
1149     /* he is moving, so stop blinking and tapping. */
1150     player_blinking = 0;
1151     player_tapping = 0;
1152   }
1153   else
1154   {
1155     /* he is idle, so animations can be done. */
1156     if (animcycle == 0)
1157     {
1158       /* blinking and tapping is started at the beginning of animation sequences. */
1159       /* 1/4 chance of blinking, every sequence. */
1160       player_blinking = g_random_int_range(0, 4) == 0;
1161
1162       /* 1/16 chance of starting or stopping tapping. */
1163       if (g_random_int_range(0, 16) == 0)
1164         player_tapping = !player_tapping;
1165     }
1166   }
1167
1168   for (x = 0; x < O_MAX; x++)
1169   {
1170     elemmapping[x] = x;
1171     elemdrawing[x] = gd_elements[x].image_game;
1172   }
1173
1174   if (bonus_life_flash)
1175   {
1176     elemmapping[O_SPACE] = O_FAKE_BONUS;
1177     elemdrawing[O_SPACE] = gd_elements[O_FAKE_BONUS].image_game;
1178   }
1179
1180   elemmapping[O_MAGIC_WALL] = (cave->magic_wall_state == GD_MW_ACTIVE ? O_MAGIC_WALL : O_BRICK);
1181   elemdrawing[O_MAGIC_WALL] = gd_elements[cave->magic_wall_state == GD_MW_ACTIVE ? O_MAGIC_WALL : O_BRICK].image_game;
1182
1183   elemmapping[O_CREATURE_SWITCH] = (cave->creatures_backwards ? O_CREATURE_SWITCH_ON : O_CREATURE_SWITCH);
1184   elemdrawing[O_CREATURE_SWITCH] = gd_elements[cave->creatures_backwards ? O_CREATURE_SWITCH_ON : O_CREATURE_SWITCH].image_game;
1185
1186   elemmapping[O_EXPANDING_WALL_SWITCH] = (cave->expanding_wall_changed ? O_EXPANDING_WALL_SWITCH_VERT : O_EXPANDING_WALL_SWITCH_HORIZ);
1187   elemdrawing[O_EXPANDING_WALL_SWITCH] = gd_elements[cave->expanding_wall_changed ? O_EXPANDING_WALL_SWITCH_VERT : O_EXPANDING_WALL_SWITCH_HORIZ].image_game;
1188
1189   elemmapping[O_GRAVITY_SWITCH] = (cave->gravity_switch_active ? O_GRAVITY_SWITCH_ACTIVE : O_GRAVITY_SWITCH);
1190   elemdrawing[O_GRAVITY_SWITCH] = gd_elements[cave->gravity_switch_active ? O_GRAVITY_SWITCH_ACTIVE : O_GRAVITY_SWITCH].image_game;
1191
1192   elemmapping[O_REPLICATOR_SWITCH] = (cave->replicators_active ? O_REPLICATOR_SWITCH_ON : O_REPLICATOR_SWITCH_OFF);
1193   elemdrawing[O_REPLICATOR_SWITCH] = gd_elements[cave->replicators_active ? O_REPLICATOR_SWITCH_ON : O_REPLICATOR_SWITCH_OFF].image_game;
1194
1195   if (cave->replicators_active)
1196     /* if the replicators are active, animate them. */
1197     elemmapping[O_REPLICATOR] = O_REPLICATOR_ACTIVE;
1198
1199   if (!cave->replicators_active)
1200     /* if the replicators are inactive, do not animate them. */
1201     elemdrawing[O_REPLICATOR] = ABS(elemdrawing[O_REPLICATOR]);
1202
1203   elemmapping[O_CONVEYOR_SWITCH] = (cave->conveyor_belts_active ? O_CONVEYOR_SWITCH_ON : O_CONVEYOR_SWITCH_OFF);
1204   elemdrawing[O_CONVEYOR_SWITCH] = gd_elements[cave->conveyor_belts_active ? O_CONVEYOR_SWITCH_ON : O_CONVEYOR_SWITCH_OFF].image_game;
1205
1206   if (cave->conveyor_belts_direction_changed)
1207   {
1208     /* if direction is changed, animation is changed. */
1209     int temp;
1210
1211     elemmapping[O_CONVEYOR_LEFT] = O_CONVEYOR_RIGHT;
1212     elemmapping[O_CONVEYOR_RIGHT] = O_CONVEYOR_LEFT;
1213
1214     temp = elemdrawing[O_CONVEYOR_LEFT];
1215     elemdrawing[O_CONVEYOR_LEFT] = elemdrawing[O_CONVEYOR_RIGHT];
1216     elemdrawing[O_CONVEYOR_RIGHT] = temp;
1217
1218     elemmapping[O_CONVEYOR_DIR_SWITCH] = O_CONVEYOR_DIR_CHANGED;
1219     elemdrawing[O_CONVEYOR_DIR_SWITCH] = gd_elements[O_CONVEYOR_DIR_CHANGED].image_game;
1220   }
1221   else
1222   {
1223     elemmapping[O_CONVEYOR_DIR_SWITCH] = O_CONVEYOR_DIR_NORMAL;
1224     elemdrawing[O_CONVEYOR_DIR_SWITCH] = gd_elements[O_CONVEYOR_DIR_NORMAL].image_game;
1225   }
1226
1227   if (cave->conveyor_belts_active)
1228   {
1229     /* keep potentially changed direction */
1230     int offset = (O_CONVEYOR_LEFT_ACTIVE - O_CONVEYOR_LEFT);
1231
1232     /* if they are running, animate them. */
1233     elemmapping[O_CONVEYOR_LEFT]  += offset;
1234     elemmapping[O_CONVEYOR_RIGHT] += offset;
1235   }
1236   if (!cave->conveyor_belts_active)
1237   {
1238     /* if they are not running, do not animate them. */
1239     elemdrawing[O_CONVEYOR_LEFT] = ABS(elemdrawing[O_CONVEYOR_LEFT]);
1240     elemdrawing[O_CONVEYOR_RIGHT] = ABS(elemdrawing[O_CONVEYOR_RIGHT]);
1241   }
1242
1243   if (animcycle & 2)
1244   {
1245     /* also a hack, like biter_switch */
1246     elemdrawing[O_PNEUMATIC_ACTIVE_LEFT]  += 2;
1247     elemdrawing[O_PNEUMATIC_ACTIVE_RIGHT] += 2;
1248     elemdrawing[O_PLAYER_PNEUMATIC_LEFT]  += 2;
1249     elemdrawing[O_PLAYER_PNEUMATIC_RIGHT] += 2;
1250   }
1251
1252   if ((cave->last_direction) == GD_MV_STILL)
1253   {
1254     /* player is idle. */
1255     if (player_blinking && player_tapping)
1256     {
1257       map = O_PLAYER_TAP_BLINK;
1258       draw = gd_elements[O_PLAYER_TAP_BLINK].image_game;
1259     }
1260     else if (player_blinking)
1261     {
1262       map = O_PLAYER_BLINK;
1263       draw = gd_elements[O_PLAYER_BLINK].image_game;
1264     }
1265     else if (player_tapping)
1266     {
1267       map = O_PLAYER_TAP;
1268       draw = gd_elements[O_PLAYER_TAP].image_game;
1269     }
1270     else
1271     {
1272       map = O_PLAYER;
1273       draw = gd_elements[O_PLAYER].image_game;
1274     }
1275   }
1276   else if (cave->last_horizontal_direction == GD_MV_LEFT)
1277   {
1278     map = O_PLAYER_LEFT;
1279     draw = gd_elements[O_PLAYER_LEFT].image_game;
1280   }
1281   else
1282   {
1283     /* of course this is GD_MV_RIGHT. */
1284     map = O_PLAYER_RIGHT;
1285     draw = gd_elements[O_PLAYER_RIGHT].image_game;
1286   }
1287
1288   elemmapping[O_PLAYER] = map;
1289   elemmapping[O_PLAYER_GLUED] = map;
1290
1291   elemdrawing[O_PLAYER] = draw;
1292   elemdrawing[O_PLAYER_GLUED] = draw;
1293
1294   /* player with bomb does not blink or tap - no graphics drawn for that.
1295      running is drawn using w/o bomb cells */
1296   if (cave->last_direction!=GD_MV_STILL)
1297   {
1298     elemmapping[O_PLAYER_BOMB] = map;
1299     elemdrawing[O_PLAYER_BOMB] = draw;
1300   }
1301
1302   elemmapping[O_INBOX] = (cave->inbox_flash_toggle ? O_INBOX_OPEN : O_INBOX_CLOSED);
1303   elemdrawing[O_INBOX] = gd_elements[cave->inbox_flash_toggle ? O_OUTBOX_OPEN : O_OUTBOX_CLOSED].image_game;
1304
1305   elemmapping[O_OUTBOX] = (cave->inbox_flash_toggle ? O_OUTBOX_OPEN : O_OUTBOX_CLOSED);
1306   elemdrawing[O_OUTBOX] = gd_elements[cave->inbox_flash_toggle ? O_OUTBOX_OPEN : O_OUTBOX_CLOSED].image_game;
1307
1308   /* hack, not fit into gd_elements */
1309   elemmapping[O_BITER_SWITCH] = O_BITER_SWITCH_1 + cave->biter_delay_frame;
1310   /* hack, not fit into gd_elements */
1311   elemdrawing[O_BITER_SWITCH] = gd_elements[O_BITER_SWITCH].image_game + cave->biter_delay_frame;
1312
1313   /* visual effects */
1314   elemmapping[O_DIRT] = cave->dirt_looks_like;
1315   elemmapping[O_EXPANDING_WALL] = cave->expanding_wall_looks_like;
1316   elemmapping[O_V_EXPANDING_WALL] = cave->expanding_wall_looks_like;
1317   elemmapping[O_H_EXPANDING_WALL] = cave->expanding_wall_looks_like;
1318   elemmapping[O_AMOEBA_2] = cave->amoeba_2_looks_like;
1319
1320   /* visual effects */
1321   elemdrawing[O_DIRT] = elemdrawing[cave->dirt_looks_like];
1322   elemdrawing[O_EXPANDING_WALL] = elemdrawing[cave->expanding_wall_looks_like];
1323   elemdrawing[O_V_EXPANDING_WALL] = elemdrawing[cave->expanding_wall_looks_like];
1324   elemdrawing[O_H_EXPANDING_WALL] = elemdrawing[cave->expanding_wall_looks_like];
1325   elemdrawing[O_AMOEBA_2] = elemdrawing[cave->amoeba_2_looks_like];
1326
1327   /* change only graphically */
1328   if (hate_invisible_outbox)
1329   {
1330     elemmapping[O_PRE_INVIS_OUTBOX] = O_PRE_OUTBOX;
1331     elemmapping[O_INVIS_OUTBOX] = O_OUTBOX;
1332   }
1333
1334   if (hate_invisible_outbox)
1335   {
1336     elemdrawing[O_PRE_INVIS_OUTBOX] = elemdrawing[O_PRE_OUTBOX];
1337     elemdrawing[O_INVIS_OUTBOX] = elemdrawing[O_OUTBOX];
1338   }
1339
1340   for (y = cave->y1; y <= cave->y2; y++)
1341   {
1342     for (x = cave->x1; x <= cave->x2; x++)
1343     {
1344       GdElement actual = cave->map[y][x];
1345
1346       /* if covered, real element is not important */
1347       if (actual & COVERED)
1348         map = O_COVERED;
1349       else
1350         map = elemmapping[actual];
1351
1352       /* if covered, real element is not important */
1353       if (actual & COVERED)
1354         draw = gd_elements[O_COVERED].image_game;
1355       else
1356         draw = elemdrawing[actual];
1357
1358       /* if negative, animated. */
1359       if (draw < 0)
1360         draw = -draw + animcycle;
1361
1362       /* flash */
1363       if (cave->gate_open_flash)
1364         draw += GD_NUM_OF_CELLS;
1365
1366       /* set to buffer, with caching */
1367       if (element_buffer[y][x] != map)
1368         element_buffer[y][x] = map;
1369
1370       if (gfx_buffer[y][x] != draw)
1371         gfx_buffer[y][x] = draw | GD_REDRAW;
1372     }
1373   }
1374 }
1375
1376 /* cave time is rounded _UP_ to seconds. so at the exact moment when it
1377    changes from
1378    2sec remaining to 1sec remaining, the player has exactly one second.
1379    when it changes
1380    to zero, it is the exact moment of timeout. */
1381 /* internal time is milliseconds (or 1200 milliseconds for pal timing). */
1382 int gd_cave_time_show(const GdCave *cave, int internal_time)
1383 {
1384   return (internal_time + cave->timing_factor - 1) / cave->timing_factor;
1385 }
1386
1387 GdReplay *gd_replay_new(void)
1388 {
1389   GdReplay *rep;
1390
1391   rep = checked_calloc(sizeof(GdReplay));
1392
1393   rep->movements = g_byte_array_new();
1394
1395   return rep;
1396 }
1397
1398 GdReplay *gd_replay_new_from_replay(GdReplay *orig)
1399 {
1400   GdReplay *rep;
1401
1402   rep = g_memdup(orig, sizeof(GdReplay));
1403
1404   /* replicate dynamic data */
1405   rep->comment = getStringCopy(orig->comment);
1406   rep->movements = g_byte_array_new();
1407   g_byte_array_append(rep->movements, orig->movements->data, orig->movements->len);
1408
1409   return rep;
1410 }
1411
1412 void gd_replay_free(GdReplay *replay)
1413 {
1414   g_byte_array_free(replay->movements, TRUE);
1415   checked_free(replay->comment);
1416   free(replay);
1417 }
1418
1419 /* store movement in a replay */
1420 void gd_replay_store_movement(GdReplay *replay, GdDirection player_move,
1421                               boolean player_fire, boolean suicide)
1422 {
1423   guint8 data[1];
1424
1425   data[0] = ((player_move) |
1426              (player_fire ? GD_REPLAY_FIRE_MASK : 0) |
1427              (suicide ? GD_REPLAY_SUICIDE_MASK : 0));
1428
1429   g_byte_array_append(replay->movements, data, 1);
1430 }
1431
1432 /* get next available movement from a replay; store variables to player_move,
1433    player_fire, suicide */
1434 /* return true if successful */
1435 boolean gd_replay_get_next_movement(GdReplay *replay, GdDirection *player_move,
1436                                     boolean *player_fire, boolean *suicide)
1437 {
1438   guint8 data;
1439
1440   /* if no more available movements */
1441   if (replay->current_playing_pos >= replay->movements->len)
1442     return FALSE;
1443
1444   data = replay->movements->data[replay->current_playing_pos++];
1445   *suicide = (data & GD_REPLAY_SUICIDE_MASK) != 0;
1446   *player_fire = (data & GD_REPLAY_FIRE_MASK) != 0;
1447   *player_move = (data & GD_REPLAY_MOVE_MASK);
1448
1449   return TRUE;
1450 }
1451
1452 /* calculate adler checksum for a rendered cave; this can be used for more caves. */
1453 void gd_cave_adler_checksum_more(GdCave *cave, guint32 *a, guint32 *b)
1454 {
1455   int x, y;
1456
1457   for (y = 0; y < cave->h; y++)
1458     for (x = 0; x < cave->w; x++)
1459     {
1460       *a += gd_elements[cave->map[y][x]].character;
1461       *b += *a;
1462
1463       *a %= 65521;
1464       *b %= 65521;
1465     }
1466 }
1467
1468 /* calculate adler checksum for a single rendered cave. */
1469 guint32
1470 gd_cave_adler_checksum(GdCave *cave)
1471 {
1472   guint32 a = 1;
1473   guint32 b = 0;
1474
1475   gd_cave_adler_checksum_more(cave, &a, &b);
1476   return (b << 16) + a;
1477 }
1478
1479 /* return c64 color with index. */
1480 GdColor gd_c64_color(int index)
1481 {
1482   return (GD_COLOR_TYPE_C64 << 24) + index;
1483 }