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