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