removed unused functions and definitions
[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   int i;
447   GdCave *cave;
448
449   cave = checked_calloc(sizeof(GdCave));
450
451   /* hash table which stores unknown tags as strings. */
452   cave->tags = g_hash_table_new_full(gd_str_case_hash, gd_str_case_equal, free, free);
453
454   /* for strings */
455   for (i = 0; gd_cave_properties[i].identifier != NULL; i++)
456     if (gd_cave_properties[i].type == GD_TYPE_LONGSTRING)
457       G_STRUCT_MEMBER(GString *, cave, gd_cave_properties[i].offset) = g_string_new(NULL);
458
459   gd_cave_set_gdash_defaults(cave);
460
461   return cave;
462 }
463
464 /* cave maps.
465    cave maps are continuous areas in memory. the allocated memory
466    is width * height * bytes_per_cell long.
467    the cave map[0] stores the pointer given by g_malloc().
468    the map itself is also an allocated array of pointers to the
469    beginning of rows.
470    therefore:
471    rows = new (pointers to rows);
472    rows[0] = new map
473    rows[1..h-1] = rows[0] + width * bytes
474
475    freeing this:
476    free(rows[0])
477    free(rows)
478 */
479
480 /*
481   allocate a cave map-like array, and initialize to zero.
482   one cell is cell_size bytes long.
483 */
484 gpointer gd_cave_map_new_for_cave(const GdCave *cave, const int cell_size)
485 {
486   gpointer *rows;                /* this is void**, pointer to array of ... */
487   int y;
488
489   rows = checked_malloc((cave->h) * sizeof(gpointer));
490   rows[0] = checked_calloc(cell_size * cave->w * cave->h);
491
492   for (y = 1; y < cave->h; y++)
493     /* base pointer + num_of_bytes_per_element * width * number_of_row; as sizeof(char) = 1 */
494     rows[y] = (char *)rows[0] + cell_size * cave->w * y;
495
496   return rows;
497 }
498
499 /*
500   duplicate map
501
502   if map is null, this also returns null.
503 */
504 gpointer gd_cave_map_dup_size(const GdCave *cave, const gpointer map, const int cell_size)
505 {
506   gpointer *rows;
507   gpointer *maplines = (gpointer *)map;
508   int y;
509
510   if (!map)
511     return NULL;
512
513   rows = checked_malloc((cave->h) * sizeof(gpointer));
514   rows[0] = g_memdup (maplines[0], cell_size * cave->w * cave->h);
515
516   for (y = 1; y < cave->h; y++)
517     rows[y] = (char *)rows[0] + cell_size * cave->w * y;
518
519   return rows;
520 }
521
522 void gd_cave_map_free(gpointer map)
523 {
524   gpointer *maplines = (gpointer *) map;
525
526   if (!map)
527     return;
528
529   free(maplines[0]);
530   free(map);
531 }
532
533 /*
534   frees memory associated to cave
535 */
536 void gd_cave_free(GdCave *cave)
537 {
538   int i;
539
540   if (!cave)
541     return;
542
543   if (cave->tags)
544     g_hash_table_destroy(cave->tags);
545
546   if (cave->random)    /* random generator is a GRand * */
547     g_rand_free(cave->random);
548
549   /* free GStrings */
550   for (i = 0; gd_cave_properties[i].identifier != NULL; i++)
551     if (gd_cave_properties[i].type == GD_TYPE_LONGSTRING)
552       g_string_free(G_STRUCT_MEMBER(GString *, cave, gd_cave_properties[i].offset), TRUE);
553
554   /* map */
555   gd_cave_map_free(cave->map);
556
557   /* rendered data */
558   gd_cave_map_free(cave->objects_order);
559
560   /* hammered walls to reappear data */
561   gd_cave_map_free(cave->hammered_reappear);
562
563   /* free objects */
564   g_list_foreach(cave->objects, (GFunc) free, NULL);
565   g_list_free (cave->objects);
566
567   /* free replays */
568   g_list_foreach(cave->replays, (GFunc) gd_replay_free, NULL);
569   g_list_free(cave->replays);
570
571   /* freeing main pointer */
572   free (cave);
573 }
574
575 static void hash_copy_foreach(const char *key, const char *value, GHashTable *dest)
576 {
577   g_hash_table_insert(dest, g_strdup(key), g_strdup(value));
578 }
579
580 /* copy cave from src to destination, with duplicating dynamically allocated data */
581 void gd_cave_copy(GdCave *dest, const GdCave *src)
582 {
583   int i;
584
585   /* copy entire data */
586   g_memmove(dest, src, sizeof(GdCave));
587
588   /* but duplicate dynamic data */
589   dest->tags = g_hash_table_new_full(gd_str_case_hash, gd_str_case_equal,
590                                      free, free);
591   if (src->tags)
592     g_hash_table_foreach(src->tags, (GHFunc) hash_copy_foreach, dest->tags);
593
594   dest->map = gd_cave_map_dup(src, map);
595   dest->hammered_reappear = gd_cave_map_dup(src, hammered_reappear);
596
597   /* for longstrings */
598   for (i = 0; gd_cave_properties[i].identifier != NULL; i++)
599     if (gd_cave_properties[i].type == GD_TYPE_LONGSTRING)
600       G_STRUCT_MEMBER(GString *, dest, gd_cave_properties[i].offset) =
601         g_string_new(G_STRUCT_MEMBER(GString *, src, gd_cave_properties[i].offset)->str);
602
603   /* no reason to copy this */
604   dest->objects_order = NULL;
605
606   /* copy objects list */
607   if (src->objects)
608   {
609     GList *iter;
610
611     dest->objects = NULL;    /* new empty list */
612     for (iter = src->objects; iter != NULL; iter = iter->next) /* do a deep copy */
613       dest->objects = g_list_append(dest->objects, g_memdup (iter->data, sizeof (GdObject)));
614   }
615
616   /* copy replays */
617   if (src->replays)
618   {
619     GList *iter;
620
621     dest->replays = NULL;
622     for (iter = src->replays; iter != NULL; iter = iter->next) /* do a deep copy */
623       dest->replays = g_list_append(dest->replays, gd_replay_new_from_replay(iter->data));
624   }
625
626   /* copy random number generator */
627   if (src->random)
628     dest->random = g_rand_copy(src->random);
629 }
630
631 /* create new cave, which is a copy of the cave given. */
632 GdCave *gd_cave_new_from_cave(const GdCave *orig)
633 {
634   GdCave *cave;
635
636   cave = gd_cave_new();
637   gd_cave_copy(cave, orig);
638
639   return cave;
640 }
641
642 /*
643   Put an object to the specified position.
644   Performs range checking.
645   If wraparound objects are selected, wraps around x coordinates, with or without lineshift.
646   (The y coordinate is not wrapped, as it did not work like that on the c64)
647   order is a pointer to the GdObject describing this object. Thus the editor can identify which cell was created by which object.
648 */
649 void gd_cave_store_rc(GdCave *cave, int x, int y, const GdElement element, const void *order)
650 {
651   /* if we do not need to draw, exit now */
652   if (element == O_NONE)
653     return;
654
655   /* check bounds */
656   if (cave->wraparound_objects)
657   {
658     if (cave->lineshift)
659     {
660       /* fit x coordinate within range, with correcting y at the same time */
661       while (x < 0)
662       {
663         x += cave->w;    /* out of bounds on the left... */
664         y--;             /* previous row */
665       }
666
667       while (x >= cave->w)
668       {
669         x -= cave->w;
670         y++;
671       }
672
673       /* lineshifting does not fix the y coordinates.
674          if out of bounds, element will not be displayed. */
675       /* if such an object appeared in the c64 game, well, it was a buffer overrun. */
676     }
677     else
678     {
679       /* non lineshifting: changing x does not change y coordinate. */
680       while (x < 0)
681         x += cave->w;
682
683       while (x >= cave->w)
684         x -= cave->w;
685
686       /* after that, fix y coordinate */
687       while (y < 0)
688         y += cave->h;
689
690       while (y >= cave->h)
691         y -= cave->h;
692     }
693   }
694
695   /* if the above wraparound code fixed the coordinates, this will always be true. */
696   /* but see the above comment for lineshifting y coordinate */
697   if (x >= 0 && x < cave->w && y >= 0 && y < cave->h)
698   {
699     cave->map[y][x] = element;
700     cave->objects_order[y][x] = (void *)order;
701   }
702 }
703
704 GdElement gd_cave_get_rc(const GdCave *cave, int x, int y)
705 {
706   /* always fix coordinates as if cave was wraparound. */
707
708   /* fix x coordinate */
709   if (cave->lineshift)
710   {
711     /* fit x coordinate within range, with correcting y at the same time */
712     while (x < 0)
713     {
714       x += cave->w;    /* out of bounds on the left... */
715       y--;             /* previous row */
716     }
717     while (x >= cave->w)
718     {
719       x -= cave->w;
720       y++;
721     }
722   }
723   else
724   {
725     /* non lineshifting: changing x does not change y coordinate. */
726     while (x < 0)
727       x += cave->w;
728
729     while (x >= cave->w)
730       x -= cave->w;
731   }
732
733   /* after that, fix y coordinate */
734   while (y < 0)
735     y += cave->h;
736
737   while (y >= cave->h)
738     y -= cave->h;
739
740   return cave->map[y][x];
741 }
742
743 unsigned int gd_c64_random(GdC64RandomGenerator *rand)
744 {
745   unsigned int temp_rand_1, temp_rand_2, carry, result;
746
747   temp_rand_1 = (rand->rand_seed_1 & 0x0001) << 7;
748   temp_rand_2 = (rand->rand_seed_2 >> 1) & 0x007F;
749   result = (rand->rand_seed_2) + ((rand->rand_seed_2 & 0x0001) << 7);
750   carry = (result >> 8);
751   result = result & 0x00FF;
752   result = result + carry + 0x13;
753   carry = (result >> 8);
754   rand->rand_seed_2 = result & 0x00FF;
755   result = rand->rand_seed_1 + carry + temp_rand_1;
756   carry = (result >> 8);
757   result = result & 0x00FF;
758   result = result + carry + temp_rand_2;
759   rand->rand_seed_1 = result & 0x00FF;
760
761   return rand->rand_seed_1;
762 }
763
764 /*
765   C64 BD predictable random number generator.
766   Used to load the original caves imported from c64 files.
767   Also by the predictable slime.
768 */
769 unsigned int gd_cave_c64_random(GdCave *cave)
770 {
771   return gd_c64_random(&cave->c64_rand);
772 }
773
774 void gd_c64_random_set_seed(GdC64RandomGenerator *rand, int seed1, int seed2)
775 {
776   rand->rand_seed_1 = seed1;
777   rand->rand_seed_2 = seed2;
778 }
779
780 void gd_cave_c64_random_set_seed(GdCave *cave, int seed1, int seed2)
781 {
782   gd_c64_random_set_seed(&cave->c64_rand, seed1, seed2);
783 }
784
785 /*
786   select random colors for a given cave.
787   this function will select colors so that they should look somewhat nice; for example
788   brick walls won't be the darkest color, for example.
789 */
790 static inline void swap(int *i1, int *i2)
791 {
792   int t = *i1;
793   *i1 = *i2;
794   *i2 = t;
795 }
796
797 /*
798   shrink cave
799   if last line or last row is just steel wall (or (invisible) outbox).
800   used after loading a game for playing.
801   after this, ew and eh will contain the effective width and height.
802 */
803 void gd_cave_auto_shrink(GdCave *cave)
804 {
805
806   int x, y;
807   enum
808   {
809     STEEL_ONLY,
810     STEEL_OR_OTHER,
811     NO_SHRINK
812   }
813   empty;
814
815   /* set to maximum size, then try to shrink */
816   cave->x1 = 0;
817   cave->y1 = 0;
818   cave->x2 = cave->w - 1;
819   cave->y2 = cave->h - 1;
820
821   /* search for empty, steel-wall-only last rows. */
822   /* clear all lines, which are only steel wall.
823    * and clear only one line, which is steel wall, but also has a player or an outbox. */
824   empty = STEEL_ONLY;
825
826   do
827   {
828     for (y = cave->y2 - 1; y <= cave->y2; y++)
829     {
830       for (x = cave->x1; x <= cave->x2; x++)
831       {
832         switch (gd_cave_get_rc (cave, x, y))
833         {
834           /* if steels only, this is to be deleted. */
835           case O_STEEL:
836             break;
837
838           case O_PRE_OUTBOX:
839           case O_PRE_INVIS_OUTBOX:
840           case O_INBOX:
841             if (empty == STEEL_OR_OTHER)
842               empty = NO_SHRINK;
843
844             /* if this, delete only this one, and exit. */
845             if (empty == STEEL_ONLY)
846               empty = STEEL_OR_OTHER;
847             break;
848
849           default:
850             /* anything else, that should be left in the cave. */
851             empty = NO_SHRINK;
852             break;
853         }
854       }
855     }
856
857     /* shrink if full steel or steel and player/outbox. */
858     if (empty != NO_SHRINK)
859       cave->y2--;            /* one row shorter */
860   }
861   while (empty == STEEL_ONLY);    /* if found just steels, repeat. */
862
863   /* search for empty, steel-wall-only first rows. */
864   empty = STEEL_ONLY;
865
866   do
867   {
868     for (y = cave->y1; y <= cave->y1 + 1; y++)
869     {
870       for (x = cave->x1; x <= cave->x2; x++)
871       {
872         switch (gd_cave_get_rc (cave, x, y))
873         {
874           case O_STEEL:
875             break;
876
877           case O_PRE_OUTBOX:
878           case O_PRE_INVIS_OUTBOX:
879           case O_INBOX:
880             /* shrink only lines, which have only ONE player or outbox.
881                this is for bd4 intermission 2, for example. */
882             if (empty == STEEL_OR_OTHER)
883               empty = NO_SHRINK;
884             if (empty == STEEL_ONLY)
885               empty = STEEL_OR_OTHER;
886             break;
887
888           default:
889             empty = NO_SHRINK;
890             break;
891         }
892       }
893     }
894
895     if (empty != NO_SHRINK)
896       cave->y1++;
897   }
898   while (empty == STEEL_ONLY);    /* if found one, repeat. */
899
900   /* empty last columns. */
901   empty = STEEL_ONLY;
902
903   do
904   {
905     for (y = cave->y1; y <= cave->y2; y++)
906     {
907       for (x = cave->x2 - 1; x <= cave->x2; x++)
908       {
909         switch (gd_cave_get_rc (cave, x, y))
910         {
911           case O_STEEL:
912             break;
913
914           case O_PRE_OUTBOX:
915           case O_PRE_INVIS_OUTBOX:
916           case O_INBOX:
917             if (empty == STEEL_OR_OTHER)
918               empty = NO_SHRINK;
919             if (empty == STEEL_ONLY)
920               empty = STEEL_OR_OTHER;
921             break;
922
923           default:
924             empty = NO_SHRINK;
925             break;
926         }
927       }
928     }
929
930     /* just remember that one column shorter.
931        free will know the size of memchunk, no need to realloc! */
932     if (empty != NO_SHRINK)
933       cave->x2--;
934   }
935   while (empty == STEEL_ONLY);    /* if found one, repeat. */
936
937   /* empty first columns. */
938   empty = STEEL_ONLY;
939
940   do
941   {
942     for (y = cave->y1; y <= cave->y2; y++)
943     {
944       for (x = cave->x1; x <= cave->x1 + 1; x++)
945       {
946         switch (gd_cave_get_rc (cave, x, y))
947         {
948           case O_STEEL:
949             break;
950
951           case O_PRE_OUTBOX:
952           case O_PRE_INVIS_OUTBOX:
953           case O_INBOX:
954             if (empty == STEEL_OR_OTHER)
955               empty = NO_SHRINK;
956             if (empty == STEEL_ONLY)
957               empty = STEEL_OR_OTHER;
958             break;
959
960           default:
961             empty = NO_SHRINK;
962             break;
963         }
964       }
965     }
966
967     if (empty != NO_SHRINK)
968       cave->x1++;
969   }
970   while (empty == STEEL_ONLY);    /* if found one, repeat. */
971 }
972
973 /* check if cave visible part coordinates
974    are outside cave sizes, or not in the right order.
975    correct them if needed.
976 */
977 void gd_cave_correct_visible_size(GdCave *cave)
978 {
979   /* change visible coordinates if they do not point to upperleft and lowerright */
980   if (cave->x2 < cave->x1)
981   {
982     int t = cave->x2;
983     cave->x2 = cave->x1;
984     cave->x1 = t;
985   }
986
987   if (cave->y2 < cave->y1)
988   {
989     int t = cave->y2;
990     cave->y2 = cave->y1;
991     cave->y1 = t;
992   }
993
994   if (cave->x1 < 0)
995     cave->x1 = 0;
996
997   if (cave->y1 < 0)
998     cave->y1 = 0;
999
1000   if (cave->x2 > cave->w - 1)
1001     cave->x2 = cave->w - 1;
1002
1003   if (cave->y2 > cave->h - 1)
1004     cave->y2 = cave->h - 1;
1005 }
1006
1007 /*
1008   bd1 and similar engines had animation bits in cave data, to set which elements to animate
1009   (firefly, butterfly, amoeba).
1010   animating an element also caused some delay each frame; according to my measurements,
1011   around 2.6 ms/element.
1012 */
1013 static void cave_set_ckdelay_extra_for_animation(GdCave *cave)
1014 {
1015   int x, y;
1016   boolean has_amoeba = FALSE, has_firefly = FALSE, has_butterfly = FALSE;
1017
1018   for (y = 0; y < cave->h; y++)
1019   {
1020     for (x = 0; x < cave->w; x++)
1021     {
1022       switch (cave->map[y][x] & ~SCANNED)
1023       {
1024         case O_FIREFLY_1:
1025         case O_FIREFLY_2:
1026         case O_FIREFLY_3:
1027         case O_FIREFLY_4:
1028           has_firefly = TRUE;
1029           break;
1030
1031         case O_BUTTER_1:
1032         case O_BUTTER_2:
1033         case O_BUTTER_3:
1034         case O_BUTTER_4:
1035           has_butterfly = TRUE;
1036           break;
1037
1038         case O_AMOEBA:
1039           has_amoeba = TRUE;
1040           break;
1041       }
1042     }
1043   }
1044
1045   cave->ckdelay_extra_for_animation = 0;
1046   if (has_amoeba)
1047     cave->ckdelay_extra_for_animation += 2600;
1048   if (has_firefly)
1049     cave->ckdelay_extra_for_animation += 2600;
1050   if (has_butterfly)
1051     cave->ckdelay_extra_for_animation += 2600;
1052   if (has_amoeba)
1053     cave->ckdelay_extra_for_animation += 2600;
1054 }
1055
1056 /* do some init - setup some cave variables before the game. */
1057 void gd_cave_setup_for_game(GdCave *cave)
1058 {
1059   int x, y;
1060
1061   cave_set_ckdelay_extra_for_animation(cave);
1062
1063   /* find the player which will be the one to scroll to at the beginning of the game
1064      (before the player's birth) */
1065   if (cave->active_is_first_found)
1066   {
1067     /* uppermost player is active */
1068     for (y = cave->h - 1; y >= 0; y--)
1069     { 
1070      for (x = cave->w - 1; x >= 0; x--)
1071      {
1072         if (cave->map[y][x] == O_INBOX)
1073         {
1074           cave->player_x = x;
1075           cave->player_y = y;
1076         }
1077      }
1078     }
1079   }
1080   else
1081   {
1082     /* lowermost player is active */
1083     for (y = 0; y < cave->h; y++)
1084     {
1085       for (x = 0; x < cave->w; x++)
1086       {
1087         if (cave->map[y][x] == O_INBOX)
1088         {
1089           cave->player_x = x;
1090           cave->player_y = y;
1091         }
1092       }
1093     }
1094   }
1095
1096   /* select number of milliseconds (for pal and ntsc) */
1097   cave->timing_factor = cave->pal_timing ? 1200 : 1000;
1098
1099   cave->time                    *= cave->timing_factor;
1100   cave->magic_wall_time         *= cave->timing_factor;
1101   cave->amoeba_time             *= cave->timing_factor;
1102   cave->amoeba_2_time           *= cave->timing_factor;
1103   cave->hatching_delay_time     *= cave->timing_factor;
1104
1105   if (cave->hammered_walls_reappear)
1106     cave->hammered_reappear = gd_cave_map_new(cave, int);
1107 }
1108
1109 /* cave diamonds needed can be set to n<=0. */
1110 /* if so, count the diamonds at the time of the hatching, and decrement that value from */
1111 /* the number of diamonds found. */
1112 /* of course, this function is to be called from the cave engine, at the exact time of hatching. */
1113 void gd_cave_count_diamonds(GdCave *cave)
1114 {
1115   int x, y;
1116
1117   /* if automatically counting diamonds. if this was negative,
1118    * the sum will be this less than the number of all the diamonds in the cave */
1119   if (cave->diamonds_needed <= 0)
1120   {
1121     for (y = 0; y < cave->h; y++)
1122       for (x = 0; x < cave->w; x++)
1123         if (cave->map[y][x] == O_DIAMOND)
1124           cave->diamonds_needed++;
1125
1126     /* if still below zero, let this be 0, so gate will be open immediately */
1127     if (cave->diamonds_needed < 0)
1128       cave->diamonds_needed = 0;
1129   }
1130 }
1131
1132 /* takes a cave and a gfx buffer, and fills the buffer with cell indexes.
1133    the indexes might change if bonus life flash is active (small lines in
1134    "SPACE" cells),
1135    for the paused state (which is used in gdash but not in sdash) - yellowish
1136    color.
1137    also one can select the animation frame (0..7) to draw the cave on. so the
1138    caller manages
1139    increasing that.
1140
1141    if a cell is changed, it is flagged with GD_REDRAW; the flag can be cleared
1142    by the caller.
1143 */
1144 void gd_drawcave_game(const GdCave *cave, int **element_buffer, int **gfx_buffer,
1145                       boolean bonus_life_flash, int animcycle, boolean hate_invisible_outbox)
1146 {
1147   static int player_blinking = 0;
1148   static int player_tapping = 0;
1149   int elemmapping[O_MAX];
1150   int elemdrawing[O_MAX];
1151   int x, y, map, draw;
1152
1153   if (cave->last_direction)
1154   {
1155     /* he is moving, so stop blinking and tapping. */
1156     player_blinking = 0;
1157     player_tapping = 0;
1158   }
1159   else
1160   {
1161     /* he is idle, so animations can be done. */
1162     if (animcycle == 0)
1163     {
1164       /* blinking and tapping is started at the beginning of animation sequences. */
1165       /* 1/4 chance of blinking, every sequence. */
1166       player_blinking = g_random_int_range(0, 4) == 0;
1167
1168       /* 1/16 chance of starting or stopping tapping. */
1169       if (g_random_int_range(0, 16) == 0)
1170         player_tapping = !player_tapping;
1171     }
1172   }
1173
1174   for (x = 0; x < O_MAX; x++)
1175   {
1176     elemmapping[x] = x;
1177     elemdrawing[x] = gd_elements[x].image_game;
1178   }
1179
1180   if (bonus_life_flash)
1181   {
1182     elemmapping[O_SPACE] = O_FAKE_BONUS;
1183     elemdrawing[O_SPACE] = gd_elements[O_FAKE_BONUS].image_game;
1184   }
1185
1186   elemmapping[O_MAGIC_WALL] = (cave->magic_wall_state == GD_MW_ACTIVE ? O_MAGIC_WALL : O_BRICK);
1187   elemdrawing[O_MAGIC_WALL] = gd_elements[cave->magic_wall_state == GD_MW_ACTIVE ? O_MAGIC_WALL : O_BRICK].image_game;
1188
1189   elemmapping[O_CREATURE_SWITCH] = (cave->creatures_backwards ? O_CREATURE_SWITCH_ON : O_CREATURE_SWITCH);
1190   elemdrawing[O_CREATURE_SWITCH] = gd_elements[cave->creatures_backwards ? O_CREATURE_SWITCH_ON : O_CREATURE_SWITCH].image_game;
1191
1192   elemmapping[O_EXPANDING_WALL_SWITCH] = (cave->expanding_wall_changed ? O_EXPANDING_WALL_SWITCH_VERT : O_EXPANDING_WALL_SWITCH_HORIZ);
1193   elemdrawing[O_EXPANDING_WALL_SWITCH] = gd_elements[cave->expanding_wall_changed ? O_EXPANDING_WALL_SWITCH_VERT : O_EXPANDING_WALL_SWITCH_HORIZ].image_game;
1194
1195   elemmapping[O_GRAVITY_SWITCH] = (cave->gravity_switch_active ? O_GRAVITY_SWITCH_ACTIVE : O_GRAVITY_SWITCH);
1196   elemdrawing[O_GRAVITY_SWITCH] = gd_elements[cave->gravity_switch_active ? O_GRAVITY_SWITCH_ACTIVE : O_GRAVITY_SWITCH].image_game;
1197
1198   elemmapping[O_REPLICATOR_SWITCH] = (cave->replicators_active ? O_REPLICATOR_SWITCH_ON : O_REPLICATOR_SWITCH_OFF);
1199   elemdrawing[O_REPLICATOR_SWITCH] = gd_elements[cave->replicators_active ? O_REPLICATOR_SWITCH_ON : O_REPLICATOR_SWITCH_OFF].image_game;
1200
1201   if (cave->replicators_active)
1202     /* if the replicators are active, animate them. */
1203     elemmapping[O_REPLICATOR] = O_REPLICATOR_ACTIVE;
1204
1205   if (!cave->replicators_active)
1206     /* if the replicators are inactive, do not animate them. */
1207     elemdrawing[O_REPLICATOR] = ABS(elemdrawing[O_REPLICATOR]);
1208
1209   elemmapping[O_CONVEYOR_SWITCH] = (cave->conveyor_belts_active ? O_CONVEYOR_SWITCH_ON : O_CONVEYOR_SWITCH_OFF);
1210   elemdrawing[O_CONVEYOR_SWITCH] = gd_elements[cave->conveyor_belts_active ? O_CONVEYOR_SWITCH_ON : O_CONVEYOR_SWITCH_OFF].image_game;
1211
1212   if (cave->conveyor_belts_direction_changed)
1213   {
1214     /* if direction is changed, animation is changed. */
1215     int temp;
1216
1217     elemmapping[O_CONVEYOR_LEFT] = O_CONVEYOR_RIGHT;
1218     elemmapping[O_CONVEYOR_RIGHT] = O_CONVEYOR_LEFT;
1219
1220     temp = elemdrawing[O_CONVEYOR_LEFT];
1221     elemdrawing[O_CONVEYOR_LEFT] = elemdrawing[O_CONVEYOR_RIGHT];
1222     elemdrawing[O_CONVEYOR_RIGHT] = temp;
1223
1224     elemmapping[O_CONVEYOR_DIR_SWITCH] = O_CONVEYOR_DIR_CHANGED;
1225     elemdrawing[O_CONVEYOR_DIR_SWITCH] = gd_elements[O_CONVEYOR_DIR_CHANGED].image_game;
1226   }
1227   else
1228   {
1229     elemmapping[O_CONVEYOR_DIR_SWITCH] = O_CONVEYOR_DIR_NORMAL;
1230     elemdrawing[O_CONVEYOR_DIR_SWITCH] = gd_elements[O_CONVEYOR_DIR_NORMAL].image_game;
1231   }
1232
1233   if (cave->conveyor_belts_active)
1234   {
1235     /* keep potentially changed direction */
1236     int offset = (O_CONVEYOR_LEFT_ACTIVE - O_CONVEYOR_LEFT);
1237
1238     /* if they are running, animate them. */
1239     elemmapping[O_CONVEYOR_LEFT]  += offset;
1240     elemmapping[O_CONVEYOR_RIGHT] += offset;
1241   }
1242   if (!cave->conveyor_belts_active)
1243   {
1244     /* if they are not running, do not animate them. */
1245     elemdrawing[O_CONVEYOR_LEFT] = ABS(elemdrawing[O_CONVEYOR_LEFT]);
1246     elemdrawing[O_CONVEYOR_RIGHT] = ABS(elemdrawing[O_CONVEYOR_RIGHT]);
1247   }
1248
1249   if (animcycle & 2)
1250   {
1251     /* also a hack, like biter_switch */
1252     elemdrawing[O_PNEUMATIC_ACTIVE_LEFT]  += 2;
1253     elemdrawing[O_PNEUMATIC_ACTIVE_RIGHT] += 2;
1254     elemdrawing[O_PLAYER_PNEUMATIC_LEFT]  += 2;
1255     elemdrawing[O_PLAYER_PNEUMATIC_RIGHT] += 2;
1256   }
1257
1258   if ((cave->last_direction) == GD_MV_STILL)
1259   {
1260     /* player is idle. */
1261     if (player_blinking && player_tapping)
1262     {
1263       map = O_PLAYER_TAP_BLINK;
1264       draw = gd_elements[O_PLAYER_TAP_BLINK].image_game;
1265     }
1266     else if (player_blinking)
1267     {
1268       map = O_PLAYER_BLINK;
1269       draw = gd_elements[O_PLAYER_BLINK].image_game;
1270     }
1271     else if (player_tapping)
1272     {
1273       map = O_PLAYER_TAP;
1274       draw = gd_elements[O_PLAYER_TAP].image_game;
1275     }
1276     else
1277     {
1278       map = O_PLAYER;
1279       draw = gd_elements[O_PLAYER].image_game;
1280     }
1281   }
1282   else if (cave->last_horizontal_direction == GD_MV_LEFT)
1283   {
1284     map = O_PLAYER_LEFT;
1285     draw = gd_elements[O_PLAYER_LEFT].image_game;
1286   }
1287   else
1288   {
1289     /* of course this is GD_MV_RIGHT. */
1290     map = O_PLAYER_RIGHT;
1291     draw = gd_elements[O_PLAYER_RIGHT].image_game;
1292   }
1293
1294   elemmapping[O_PLAYER] = map;
1295   elemmapping[O_PLAYER_GLUED] = map;
1296
1297   elemdrawing[O_PLAYER] = draw;
1298   elemdrawing[O_PLAYER_GLUED] = draw;
1299
1300   /* player with bomb does not blink or tap - no graphics drawn for that.
1301      running is drawn using w/o bomb cells */
1302   if (cave->last_direction!=GD_MV_STILL)
1303   {
1304     elemmapping[O_PLAYER_BOMB] = map;
1305     elemdrawing[O_PLAYER_BOMB] = draw;
1306   }
1307
1308   elemmapping[O_INBOX] = (cave->inbox_flash_toggle ? O_INBOX_OPEN : O_INBOX_CLOSED);
1309   elemdrawing[O_INBOX] = gd_elements[cave->inbox_flash_toggle ? O_OUTBOX_OPEN : O_OUTBOX_CLOSED].image_game;
1310
1311   elemmapping[O_OUTBOX] = (cave->inbox_flash_toggle ? O_OUTBOX_OPEN : O_OUTBOX_CLOSED);
1312   elemdrawing[O_OUTBOX] = gd_elements[cave->inbox_flash_toggle ? O_OUTBOX_OPEN : O_OUTBOX_CLOSED].image_game;
1313
1314   /* hack, not fit into gd_elements */
1315   elemmapping[O_BITER_SWITCH] = O_BITER_SWITCH_1 + cave->biter_delay_frame;
1316   /* hack, not fit into gd_elements */
1317   elemdrawing[O_BITER_SWITCH] = gd_elements[O_BITER_SWITCH].image_game + cave->biter_delay_frame;
1318
1319   /* visual effects */
1320   elemmapping[O_DIRT] = cave->dirt_looks_like;
1321   elemmapping[O_EXPANDING_WALL] = cave->expanding_wall_looks_like;
1322   elemmapping[O_V_EXPANDING_WALL] = cave->expanding_wall_looks_like;
1323   elemmapping[O_H_EXPANDING_WALL] = cave->expanding_wall_looks_like;
1324   elemmapping[O_AMOEBA_2] = cave->amoeba_2_looks_like;
1325
1326   /* visual effects */
1327   elemdrawing[O_DIRT] = elemdrawing[cave->dirt_looks_like];
1328   elemdrawing[O_EXPANDING_WALL] = elemdrawing[cave->expanding_wall_looks_like];
1329   elemdrawing[O_V_EXPANDING_WALL] = elemdrawing[cave->expanding_wall_looks_like];
1330   elemdrawing[O_H_EXPANDING_WALL] = elemdrawing[cave->expanding_wall_looks_like];
1331   elemdrawing[O_AMOEBA_2] = elemdrawing[cave->amoeba_2_looks_like];
1332
1333   /* change only graphically */
1334   if (hate_invisible_outbox)
1335   {
1336     elemmapping[O_PRE_INVIS_OUTBOX] = O_PRE_OUTBOX;
1337     elemmapping[O_INVIS_OUTBOX] = O_OUTBOX;
1338   }
1339
1340   if (hate_invisible_outbox)
1341   {
1342     elemdrawing[O_PRE_INVIS_OUTBOX] = elemdrawing[O_PRE_OUTBOX];
1343     elemdrawing[O_INVIS_OUTBOX] = elemdrawing[O_OUTBOX];
1344   }
1345
1346   for (y = cave->y1; y <= cave->y2; y++)
1347   {
1348     for (x = cave->x1; x <= cave->x2; x++)
1349     {
1350       GdElement actual = cave->map[y][x];
1351
1352       /* if covered, real element is not important */
1353       if (actual & COVERED)
1354         map = O_COVERED;
1355       else
1356         map = elemmapping[actual];
1357
1358       /* if covered, real element is not important */
1359       if (actual & COVERED)
1360         draw = gd_elements[O_COVERED].image_game;
1361       else
1362         draw = elemdrawing[actual];
1363
1364       /* if negative, animated. */
1365       if (draw < 0)
1366         draw = -draw + animcycle;
1367
1368       /* flash */
1369       if (cave->gate_open_flash)
1370         draw += GD_NUM_OF_CELLS;
1371
1372       /* set to buffer, with caching */
1373       if (element_buffer[y][x] != map)
1374         element_buffer[y][x] = map;
1375
1376       if (gfx_buffer[y][x] != draw)
1377         gfx_buffer[y][x] = draw | GD_REDRAW;
1378     }
1379   }
1380 }
1381
1382 /* cave time is rounded _UP_ to seconds. so at the exact moment when it
1383    changes from
1384    2sec remaining to 1sec remaining, the player has exactly one second.
1385    when it changes
1386    to zero, it is the exact moment of timeout. */
1387 /* internal time is milliseconds (or 1200 milliseconds for pal timing). */
1388 int gd_cave_time_show(const GdCave *cave, int internal_time)
1389 {
1390   return (internal_time + cave->timing_factor - 1) / cave->timing_factor;
1391 }
1392
1393 GdReplay *gd_replay_new(void)
1394 {
1395   GdReplay *rep;
1396
1397   rep = checked_calloc(sizeof(GdReplay));
1398
1399   /* create dynamic objects */
1400   rep->comment = g_string_new(NULL);
1401   rep->movements = g_byte_array_new();
1402
1403   return rep;
1404 }
1405
1406 GdReplay *gd_replay_new_from_replay(GdReplay *orig)
1407 {
1408   GdReplay *rep;
1409
1410   rep = g_memdup(orig, sizeof(GdReplay));
1411
1412   /* replicate dynamic data */
1413   rep->comment = g_string_new(orig->comment->str);
1414   rep->movements = g_byte_array_new();
1415   g_byte_array_append(rep->movements, orig->movements->data, orig->movements->len);
1416
1417   return rep;
1418 }
1419
1420 void gd_replay_free(GdReplay *replay)
1421 {
1422   g_byte_array_free(replay->movements, TRUE);
1423   g_string_free(replay->comment, TRUE);
1424   free(replay);
1425 }
1426
1427 /* store movement in a replay */
1428 void gd_replay_store_movement(GdReplay *replay, GdDirection player_move,
1429                               boolean player_fire, boolean suicide)
1430 {
1431   guint8 data[1];
1432
1433   data[0] = ((player_move) |
1434              (player_fire ? GD_REPLAY_FIRE_MASK : 0) |
1435              (suicide ? GD_REPLAY_SUICIDE_MASK : 0));
1436
1437   g_byte_array_append(replay->movements, data, 1);
1438 }
1439
1440 /* get next available movement from a replay; store variables to player_move,
1441    player_fire, suicide */
1442 /* return true if successful */
1443 boolean gd_replay_get_next_movement(GdReplay *replay, GdDirection *player_move,
1444                                     boolean *player_fire, boolean *suicide)
1445 {
1446   guint8 data;
1447
1448   /* if no more available movements */
1449   if (replay->current_playing_pos >= replay->movements->len)
1450     return FALSE;
1451
1452   data = replay->movements->data[replay->current_playing_pos++];
1453   *suicide = (data & GD_REPLAY_SUICIDE_MASK) != 0;
1454   *player_fire = (data & GD_REPLAY_FIRE_MASK) != 0;
1455   *player_move = (data & GD_REPLAY_MOVE_MASK);
1456
1457   return TRUE;
1458 }
1459
1460 /* calculate adler checksum for a rendered cave; this can be used for more caves. */
1461 void gd_cave_adler_checksum_more(GdCave *cave, guint32 *a, guint32 *b)
1462 {
1463   int x, y;
1464
1465   for (y = 0; y < cave->h; y++)
1466     for (x = 0; x < cave->w; x++)
1467     {
1468       *a += gd_elements[cave->map[y][x]].character;
1469       *b += *a;
1470
1471       *a %= 65521;
1472       *b %= 65521;
1473     }
1474 }
1475
1476 /* calculate adler checksum for a single rendered cave. */
1477 guint32
1478 gd_cave_adler_checksum(GdCave *cave)
1479 {
1480   guint32 a = 1;
1481   guint32 b = 0;
1482
1483   gd_cave_adler_checksum_more(cave, &a, &b);
1484   return (b << 16) + a;
1485 }
1486
1487 /* return c64 color with index. */
1488 GdColor gd_c64_color(int index)
1489 {
1490   return (GD_COLOR_TYPE_C64 << 24) + index;
1491 }