replaced glib function calls to g_strfreev()
[rocksndiamonds.git] / src / game_bd / bd_caveobject.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 GdObjectLevels gd_levels_mask[] =
24 {
25   GD_OBJECT_LEVEL1,
26   GD_OBJECT_LEVEL2,
27   GD_OBJECT_LEVEL3,
28   GD_OBJECT_LEVEL4,
29   GD_OBJECT_LEVEL5
30 };
31
32 /* bdcff text description of object. caller should free string. */
33 char *gd_object_get_bdcff(const GdObject *object)
34 {
35   GString *str;
36   int j;
37   const char *type;
38
39   switch (object->type)
40   {
41     case GD_POINT:
42       return g_strdup_printf("Point=%d %d %s",
43                              object->x1, object->y1,
44                              gd_elements[object->element].filename);
45
46     case GD_LINE:
47       return g_strdup_printf("Line=%d %d %d %d %s",
48                              object->x1, object->y1, object->x2, object->y2,
49                              gd_elements[object->element].filename);
50
51     case GD_RECTANGLE:
52       return g_strdup_printf("Rectangle=%d %d %d %d %s",
53                              object->x1, object->y1, object->x2, object->y2,
54                              gd_elements[object->element].filename);
55
56     case GD_FILLED_RECTANGLE:
57       /* if elements are not the same */
58       if (object->fill_element != object->element)
59         return g_strdup_printf("FillRect=%d %d %d %d %s %s",
60                                object->x1, object->y1, object->x2, object->y2,
61                                gd_elements[object->element].filename,
62                                gd_elements[object->fill_element].filename);
63
64       /* they are the same */
65       return g_strdup_printf("FillRect=%d %d %d %d %s",
66                              object->x1, object->y1, object->x2, object->y2,
67                              gd_elements[object->element].filename);
68
69     case GD_RASTER:
70       return g_strdup_printf("Raster=%d %d %d %d %d %d %s",
71                              object->x1, object->y1,
72                              (object->x2 - object->x1) / object->dx + 1,
73                              (object->y2 - object->y1) / object->dy + 1,
74                              object->dx, object->dy,
75                              gd_elements[object->element].filename);
76
77     case GD_JOIN:
78       return g_strdup_printf("Add=%d %d %s %s",
79                              object->dx, object->dy,
80                              gd_elements[object->element].filename,
81                              gd_elements[object->fill_element].filename);
82
83     case GD_FLOODFILL_BORDER:
84       return g_strdup_printf("BoundaryFill=%d %d %s %s",
85                              object->x1, object->y1,
86                              gd_elements[object->fill_element].filename,
87                              gd_elements[object->element].filename);
88
89     case GD_FLOODFILL_REPLACE:
90       return g_strdup_printf("FloodFill=%d %d %s %s",
91                              object->x1, object->y1,
92                              gd_elements[object->fill_element].filename,
93                              gd_elements[object->element].filename);
94
95     case GD_MAZE:
96     case GD_MAZE_UNICURSAL:
97     case GD_MAZE_BRAID:
98       switch (object->type)
99       {
100         case GD_MAZE: type = "perfect"; break;
101         case GD_MAZE_UNICURSAL: type = "unicursal"; break;
102         case GD_MAZE_BRAID: type = "braid"; break;
103         default: break;
104       }
105
106       return g_strdup_printf("Maze=%d %d %d %d %d %d %d %d %d %d %d %d %s %s %s",
107                              object->x1, object->y1, object->x2, object->y2,
108                              object->dx, object->dy,
109                              object->horiz,
110                              object->seed[0],
111                              object->seed[1],
112                              object->seed[2],
113                              object->seed[3],
114                              object->seed[4],
115                              gd_elements[object->element].filename,
116                              gd_elements[object->fill_element].filename, type);
117
118     case GD_RANDOM_FILL:
119       str = g_string_new(NULL);
120       /* seed and initial fill */
121       g_string_append_printf(str, "%s=%d %d %d %d %d %d %d %d %d %s",
122                              object->c64_random ? "RandomFillC64" : "RandomFill",
123                              object->x1, object->y1, object->x2, object->y2,
124                              object->seed[0],
125                              object->seed[1],
126                              object->seed[2],
127                              object->seed[3],
128                              object->seed[4],
129                              gd_elements[object->fill_element].filename);
130
131       for (j = 0; j < 4; j++)
132       {
133         if (object->random_fill_probability[j] != 0)
134           g_string_append_printf(str, " %s %d",
135                                  gd_elements[object->random_fill[j]].filename,
136                                  object->random_fill_probability[j]);
137       }
138
139       if (object->element!=O_NONE)
140         g_string_append_printf(str, " %s",
141                                gd_elements[object->element].filename);
142
143       /* free string but do not free char *; return char *. */
144       return g_string_free(str, FALSE);
145
146     case GD_COPY_PASTE:
147       return g_strdup_printf("CopyPaste=%d %d %d %d %d %d %s %s",
148                              object->x1, object->y1, object->x2, object->y2,
149                              object->dx, object->dy,
150                              object->mirror ? "mirror" : "nomirror",
151                              object->flip?"flip":"noflip");
152
153     case NONE:
154       break;
155   }
156
157   return NULL;
158 }
159
160 /* create an INDIVIDUAL POINT CAVE OBJECT */
161 GdObject *gd_object_new_point(GdObjectLevels levels, int x, int y, GdElement elem)
162 {
163   GdObject *newobj = checked_calloc(sizeof(GdObject));
164
165   newobj->levels = levels;
166   newobj->type = GD_POINT;
167   newobj->x1 = x;
168   newobj->y1 = y;
169   newobj->element = elem;
170
171   return newobj;
172 }
173
174 /* create a LINE OBJECT */
175 GdObject *gd_object_new_line(GdObjectLevels levels, int x1, int y1, int x2, int y2,
176                              GdElement elem)
177 {
178   GdObject *newobj = checked_calloc(sizeof(GdObject));
179
180   newobj->levels = levels;
181   newobj->type = GD_LINE;
182   newobj->x1 = x1;
183   newobj->y1 = y1;
184   newobj->x2 = x2;
185   newobj->y2 = y2;
186   newobj->element = elem;
187
188   return newobj;
189 }
190
191 /* create a RECTANGLE OBJECT */
192 GdObject *gd_object_new_rectangle(GdObjectLevels levels, int x1, int y1, int x2, int y2,
193                                   GdElement elem)
194 {
195   GdObject *newobj = checked_calloc(sizeof(GdObject));
196
197   newobj->levels = levels;
198   newobj->type = GD_RECTANGLE;
199   newobj->x1 = x1;
200   newobj->y1 = y1;
201   newobj->x2 = x2;
202   newobj->y2 = y2;
203   newobj->element = elem;
204
205   return newobj;
206 }
207
208 /* create a RECTANGLE OBJECT */
209 GdObject *gd_object_new_filled_rectangle(GdObjectLevels levels, int x1, int y1, int x2, int y2,
210                                          GdElement elem, GdElement fill_elem)
211 {
212   GdObject *newobj = checked_calloc(sizeof(GdObject));
213
214   newobj->levels = levels;
215   newobj->type = GD_FILLED_RECTANGLE;
216   newobj->x1 = x1;
217   newobj->y1 = y1;
218   newobj->x2 = x2;
219   newobj->y2 = y2;
220   newobj->element = elem;
221   newobj->fill_element = fill_elem;
222
223   return newobj;
224 }
225
226 /* create a raster object */
227 GdObject *gd_object_new_raster(GdObjectLevels levels, int x1, int y1, int x2, int y2,
228                                int dx, int dy, GdElement elem)
229 {
230   GdObject *newobj = checked_calloc(sizeof(GdObject));
231
232   newobj->levels = levels;
233   newobj->type = GD_RASTER;
234   newobj->x1 = x1;
235   newobj->y1 = y1;
236   newobj->x2 = x2;
237   newobj->y2 = y2;
238   newobj->dx = dx;
239   newobj->dy = dy;
240   newobj->element = elem;
241
242   return newobj;
243 }
244
245 /* create a raster object */
246 GdObject *gd_object_new_join(GdObjectLevels levels, int dx, int dy,
247                              GdElement search, GdElement replace)
248 {
249   GdObject *newobj = checked_calloc(sizeof(GdObject));
250
251   newobj->levels = levels;
252   newobj->type = GD_JOIN;
253   newobj->dx = dx;
254   newobj->dy = dy;
255   newobj->element = search;
256   newobj->fill_element = replace;
257
258   return newobj;
259 }
260
261 /* create a new boundary fill object */
262 GdObject *gd_object_new_floodfill_border(GdObjectLevels levels, int x1, int y1,
263                                          GdElement fill, GdElement border)
264 {
265   GdObject *newobj = checked_calloc(sizeof(GdObject));
266
267   newobj->levels = levels;
268   newobj->type = GD_FLOODFILL_BORDER;
269   newobj->x1 = x1;
270   newobj->y1 = y1;
271   newobj->element = border;
272   newobj->fill_element = fill;
273
274   return newobj;
275 }
276
277 GdObject *gd_object_new_floodfill_replace(GdObjectLevels levels, int x1, int y1,
278                                           GdElement fill, GdElement to_replace)
279 {
280   GdObject *newobj = checked_calloc(sizeof(GdObject));
281
282   newobj->levels = levels;
283   newobj->type = GD_FLOODFILL_REPLACE;
284   newobj->x1 = x1;
285   newobj->y1 = y1;
286   newobj->element = to_replace;
287   newobj->fill_element = fill;
288
289   return newobj;
290 }
291
292 GdObject *gd_object_new_maze(GdObjectLevels levels, int x1, int y1, int x2, int y2,
293                              int wall_w, int path_w, GdElement wall_e, GdElement path_e,
294                              int horiz_percent, const gint32 seed[5])
295 {
296   int i;
297   GdObject *newobj = checked_calloc(sizeof(GdObject));
298
299   newobj->levels = levels;
300   newobj->type = GD_MAZE;
301   newobj->x1 = x1;
302   newobj->y1 = y1;
303   newobj->x2 = x2;
304   newobj->y2 = y2;
305   newobj->dx = wall_w;
306   newobj->dy = path_w;
307   newobj->element = wall_e;
308   newobj->fill_element = path_e;
309   newobj->horiz = horiz_percent;
310
311   for (i = 0; i < 5; ++i)
312     newobj->seed[i] = seed[i];
313
314   return newobj;
315 }
316
317 GdObject *gd_object_new_maze_unicursal(GdObjectLevels levels, int x1, int y1, int x2, int y2,
318                                        int wall_w, int path_w, GdElement wall_e, GdElement path_e,
319                                        int horiz_percent, const gint32 seed[5])
320 {
321   int i;
322   GdObject *newobj = checked_calloc(sizeof(GdObject));
323
324   newobj->levels = levels;
325   newobj->type = GD_MAZE_UNICURSAL;
326   newobj->x1 = x1;
327   newobj->y1 = y1;
328   newobj->x2 = x2;
329   newobj->y2 = y2;
330   newobj->dx = wall_w;
331   newobj->dy = path_w;
332   newobj->element = wall_e;
333   newobj->fill_element = path_e;
334   newobj->horiz = horiz_percent;
335
336   for (i = 0; i < 5; ++i)
337     newobj->seed[i] = seed[i];
338
339   return newobj;
340 }
341
342 GdObject *gd_object_new_maze_braid(GdObjectLevels levels, int x1, int y1, int x2, int y2,
343                                    int wall_w, int path_w, GdElement wall_e, GdElement path_e,
344                                    int horiz_percent, const gint32 seed[5])
345 {
346   int i;
347   GdObject *newobj = checked_calloc(sizeof(GdObject));
348
349   newobj->levels = levels;
350   newobj->type = GD_MAZE_BRAID;
351   newobj->x1 = x1;
352   newobj->y1 = y1;
353   newobj->x2 = x2;
354   newobj->y2 = y2;
355   newobj->dx = wall_w;
356   newobj->dy = path_w;
357   newobj->element = wall_e;
358   newobj->fill_element = path_e;
359   newobj->horiz = horiz_percent;
360
361   for (i = 0; i < 5; ++i)
362     newobj->seed[i] = seed[i];
363
364   return newobj;
365 }
366
367 GdObject *gd_object_new_random_fill(GdObjectLevels levels, int x1, int y1, int x2, int y2,
368                                     const gint32 seed[5], GdElement initial,
369                                     const GdElement random[4], const gint32 prob[4],
370                                     GdElement replace_only, boolean c64)
371 {
372   int i;
373   GdObject *newobj = checked_calloc(sizeof(GdObject));
374
375   newobj->levels = levels;
376   newobj->type = GD_RANDOM_FILL;
377   newobj->x1 = x1;
378   newobj->y1 = y1;
379   newobj->x2 = x2;
380   newobj->y2 = y2;
381   newobj->fill_element = initial;
382
383   for (i = 0; i < 5; ++i)
384     newobj->seed[i] = seed[i];
385
386   for (i = 0; i < 4; ++i)
387   {
388     newobj->random_fill[i] = random[i];
389     newobj->random_fill_probability[i] = prob[i];
390   }
391
392   newobj->element = replace_only;
393   newobj->c64_random = c64;
394
395   return newobj;
396 }
397
398 GdObject *gd_object_new_copy_paste(GdObjectLevels levels, int x1, int y1, int x2, int y2,
399                                    int dx, int dy, boolean mirror, boolean flip)
400 {
401   GdObject *newobj = checked_calloc(sizeof(GdObject));
402
403   newobj->levels = levels;
404   newobj->type = GD_COPY_PASTE;
405   newobj->x1 = x1;
406   newobj->y1 = y1;
407   newobj->x2 = x2;
408   newobj->y2 = y2;
409   newobj->dx = dx;
410   newobj->dy = dy;
411   newobj->mirror = mirror;
412   newobj->flip = flip;
413
414   return newobj;
415 }
416
417 /* create new object from bdcff description.
418    return new object if ok; return null if failed.
419  */
420 GdObject *gd_object_new_from_string(char *str)
421 {
422   char *equalsign;
423   char *name, *param;
424   GdObject object;
425   char elem0[100], elem1[100];
426
427   equalsign = strchr(str, '=');
428   if (!equalsign)
429     return NULL;
430
431   /* split string by replacing the equal sign with zero */
432   *equalsign = '\0';
433   name = str;
434   param = equalsign + 1;
435
436   /* INDIVIDUAL POINT CAVE OBJECT */
437   if (strcasecmp(name, "Point") == 0)
438   {
439     object.type = GD_POINT;
440     if (sscanf(param, "%d %d %s", &object.x1, &object.y1, elem0) == 3)
441     {
442       object.element = gd_get_element_from_string(elem0);
443
444       return g_memdup(&object, sizeof (GdObject));
445     }
446
447     return NULL;
448   }
449
450   /* LINE OBJECT */
451   if (strcasecmp(name, "Line") == 0)
452   {
453     object.type = GD_LINE;
454     if (sscanf(param, "%d %d %d %d %s", &object.x1, &object.y1, &object.x2, &object.y2, elem0) == 5)
455     {
456       object.element = gd_get_element_from_string(elem0);
457
458       return g_memdup(&object, sizeof (GdObject));
459     }
460
461     return NULL;
462   }
463
464   /* RECTANGLE OBJECT */
465   if (strcasecmp(name, "Rectangle") == 0)
466   {
467     if (sscanf(param, "%d %d %d %d %s", &object.x1, &object.y1, &object.x2, &object.y2, elem0) == 5)
468     {
469       object.type = GD_RECTANGLE;
470       object.element = gd_get_element_from_string (elem0);
471
472       return g_memdup(&object, sizeof (GdObject));
473     }
474
475     return NULL;
476   }
477
478   /* FILLED RECTANGLE OBJECT */
479   if (strcasecmp(name, "FillRect") == 0)
480   {
481     int paramcount;
482
483     paramcount = sscanf(param, "%d %d %d %d %s %s", &object.x1, &object.y1, &object.x2, &object.y2, elem0, elem1);
484     object.type = GD_FILLED_RECTANGLE;
485
486     if (paramcount == 6)
487     {
488       object.element = gd_get_element_from_string (elem0);
489       object.fill_element = gd_get_element_from_string (elem1);
490
491       return g_memdup(&object, sizeof (GdObject));
492     }
493
494     if (paramcount == 5)
495     {
496       object.element = object.fill_element = gd_get_element_from_string (elem0);
497
498       return g_memdup(&object, sizeof (GdObject));
499     }
500
501     return NULL;
502   }
503
504   /* RASTER */
505   if (strcasecmp(name, "Raster") == 0)
506   {
507     int nx, ny;
508
509     if (sscanf(param, "%d %d %d %d %d %d %s", &object.x1, &object.y1, &nx, &ny, &object.dx, &object.dy, elem0) == 7)
510     {
511       nx--;
512       ny--;
513       object.x2 = object.x1 + nx * object.dx;
514       object.y2 = object.y1 + ny * object.dy;
515       object.type = GD_RASTER;
516       object.element = gd_get_element_from_string (elem0);
517
518       return g_memdup(&object, sizeof (GdObject));
519     }
520
521     return NULL;
522   }
523
524   /* JOIN */
525   if (strcasecmp(name, "Join") == 0 ||
526       strcasecmp(name, "Add") == 0)
527   {
528     if (sscanf(param, "%d %d %s %s", &object.dx, &object.dy, elem0, elem1) == 4)
529     {
530       object.type = GD_JOIN;
531       object.element = gd_get_element_from_string (elem0);
532       object.fill_element = gd_get_element_from_string (elem1);
533
534       return g_memdup(&object, sizeof (GdObject));
535     }
536
537     return NULL;
538   }
539
540   /* FILL TO BORDER OBJECT */
541   if (strcasecmp(name, "BoundaryFill") == 0)
542   {
543     if (sscanf(param, "%d %d %s %s", &object.x1, &object.y1, elem0, elem1) == 4)
544     {
545       object.type = GD_FLOODFILL_BORDER;
546       object.fill_element = gd_get_element_from_string (elem0);
547       object.element = gd_get_element_from_string (elem1);
548
549       return g_memdup(&object, sizeof (GdObject));
550     }
551
552     return NULL;
553   }
554
555   /* REPLACE FILL OBJECT */
556   if (strcasecmp(name, "FloodFill") == 0)
557   {
558     if (sscanf(param, "%d %d %s %s", &object.x1, &object.y1, elem0, elem1) == 4)
559     {
560       object.type = GD_FLOODFILL_REPLACE;
561       object.fill_element = gd_get_element_from_string (elem0);
562       object.element = gd_get_element_from_string (elem1);
563
564       return g_memdup(&object, sizeof (GdObject));
565     }
566
567     return NULL;
568   }
569
570   /* MAZE OBJECT */
571   /* MAZE UNICURSAL OBJECT */
572   /* BRAID MAZE OBJECT */
573   if (strcasecmp(name, "Maze") == 0)
574   {
575     char type[100] = "perfect";
576
577     if (sscanf(param, "%d %d %d %d %d %d %d %d %d %d %d %d %s %s %s", &object.x1, &object.y1, &object.x2, &object.y2, &object.dx, &object.dy, &object.horiz, &object.seed[0], &object.seed[1], &object.seed[2], &object.seed[3], &object.seed[4], elem0, elem1, type) >= 14)
578     {
579       if (strcasecmp(type, "unicursal") == 0)
580         object.type = GD_MAZE_UNICURSAL;
581       else if (strcasecmp(type, "perfect") == 0)
582         object.type = GD_MAZE;
583       else if (strcasecmp(type, "braid") == 0)
584         object.type = GD_MAZE_BRAID;
585       else
586       {
587         Warn("unknown maze type: %s, defaulting to perfect", type);
588         object.type = GD_MAZE;
589       }
590
591       object.element = gd_get_element_from_string (elem0);
592       object.fill_element = gd_get_element_from_string (elem1);
593
594       return g_memdup(&object, sizeof (GdObject));
595     }
596
597     return NULL;
598   }
599
600   /* RANDOM FILL OBJECT */
601   if (strcasecmp(name, "RandomFill") == 0 ||
602       strcasecmp(name, "RandomFillC64") == 0)
603   {
604     static char **words = NULL;
605     int l, i;
606
607     object.type = GD_RANDOM_FILL;
608     if (strcasecmp(name, "RandomFillC64") == 0)
609       /* totally the same, but uses c64 random generator */
610       object.c64_random = TRUE;
611     else
612       object.c64_random = FALSE;
613
614     if (sscanf(param, "%d %d %d %d", &object.x1, &object.y1, &object.x2, &object.y2) != 4)
615       return NULL;
616
617     if (words)
618       freeStringArray(words);
619
620     words = getSplitStringArray(param, " ", -1);
621     l = g_strv_length(words);
622
623     if (l < 10 || l > 19)
624       return NULL;
625
626     for (i = 0; i < 5; i++)
627       if (sscanf(words[4 + i], "%d", &object.seed[i]) != 1)
628         return NULL;
629
630     object.fill_element = gd_get_element_from_string(words[9]);
631
632     for (i = 0; i < 4; i++)
633     {
634       object.random_fill[i] = O_DIRT;
635       object.random_fill_probability[i] = 0;
636     }
637
638     for (i = 10; i < l - 1; i += 2)
639     {
640       object.random_fill[(i - 10) / 2] = gd_get_element_from_string(words[i]);
641       if (sscanf(words[i + 1], "%d", &object.random_fill_probability[(i - 10) / 2]) == 0)
642         return NULL;
643     }
644
645     object.element = O_NONE;
646
647     if (l > 10 && l % 2 == 1)
648       object.element = gd_get_element_from_string(words[l - 1]);
649
650     return g_memdup(&object, sizeof (GdObject));
651   }
652
653   /* COPY PASTE OBJECT */
654   if (strcasecmp(name, "CopyPaste") == 0)
655   {
656     char mirror[100] = "nomirror";
657     char flip[100] = "noflip";
658     object.type = GD_COPY_PASTE;
659
660     object.flip = object.mirror = FALSE;
661
662     if (sscanf(param, "%d %d %d %d %d %d %s %s", &object.x1, &object.y1, &object.x2, &object.y2, &object.dx, &object.dy, mirror, flip) < 6)
663       return NULL;
664
665     /* MIRROR PROPERTY */
666     if (strcasecmp(mirror, "mirror") == 0)
667       object.mirror = TRUE;
668     else if (strcasecmp(mirror, "nomirror") == 0)
669       object.mirror = FALSE;
670     else
671       Warn("invalid setting for copypaste mirror property: %s", mirror);
672
673     /* FLIP PROPERTY */
674     if (strcasecmp(flip, "flip") == 0)
675       object.flip = TRUE;
676     else if (strcasecmp(flip, "noflip") == 0)
677       object.flip = FALSE;
678     else
679       Warn("invalid setting for copypaste flip property: %s", flip);
680
681     return g_memdup(&object, sizeof(GdObject));
682   }
683
684   return NULL;
685 }
686
687 /** drawing a line, using bresenham's */
688 static void draw_line (GdCave *cave, const GdObject *object)
689 {
690   int x, y, x1, y1, x2, y2;
691   boolean steep;
692   int error, dx, dy, ystep;
693
694   x1 = object->x1;
695   y1 = object->y1, x2 = object->x2;
696   y2 = object->y2;
697   steep = ABS (y2 - y1) > ABS (x2 - x1);
698
699   if (steep)
700   {
701     x = x1;
702     x1 = y1;
703     y1 = x;
704     x = x2;
705     x2 = y2;
706     y2 = x;
707   }
708
709   if (x1 > x2)
710   {
711     x = x1;
712     x1 = x2;
713     x2 = x;
714     x = y1;
715     y1 = y2;
716     y2 = x;
717   }
718
719   dx = x2 - x1;
720   dy = ABS (y2 - y1);
721   y = y1;
722   error = 0;
723   ystep = (y1 < y2) ? 1 : -1;
724
725   for (x = x1; x <= x2; x++)
726   {
727     if (steep)
728       gd_cave_store_rc (cave, y, x, object->element, object);
729     else
730       gd_cave_store_rc (cave, x, y, object->element, object);
731
732     error += dy;
733
734     if (error * 2 >= dx)
735     {
736       y += ystep;
737       error -= dx;
738     }
739   }
740 }
741
742
743
744 static void draw_fill_replace_proc(GdCave *cave, int x, int y, const GdObject *object)
745 {
746   /* fill with border so we do not come back */
747   gd_cave_store_rc(cave, x, y, object->fill_element, object);
748
749   if (x > 0 && gd_cave_get_rc(cave, x - 1, y) == object->element)
750     draw_fill_replace_proc(cave, x - 1, y, object);
751
752   if (y > 0 && gd_cave_get_rc(cave, x, y - 1) == object->element)
753     draw_fill_replace_proc(cave, x, y - 1, object);
754
755   if (x < cave->w - 1 && gd_cave_get_rc(cave, x + 1, y) == object->element)
756     draw_fill_replace_proc(cave, x + 1, y, object);
757
758   if (y < cave->h - 1 && gd_cave_get_rc(cave, x, y + 1) == object->element)
759     draw_fill_replace_proc(cave, x, y + 1, object);
760 }
761
762 static void draw_fill_replace (GdCave *cave, const GdObject *object)
763 {
764   /* check bounds */
765   if (object->x1 < 0 ||
766       object->y1 < 0 ||
767       object->x1 >= cave->w ||
768       object->y1 >= cave->h)
769     return;
770
771   if (object->element == object->fill_element)
772     return;
773
774   /* this procedure fills the area with the object->element. */
775   draw_fill_replace_proc(cave, object->x1, object->y1, object);
776 }
777
778 static void draw_fill_border_proc (GdCave *cave, int x, int y, const GdObject *object)
779 {
780   /* fill with border so we do not come back */
781   gd_cave_store_rc(cave, x, y, object->element, object);
782
783   if (x > 0 && gd_cave_get_rc(cave, x - 1, y) != object->element)
784     draw_fill_border_proc(cave, x - 1, y, object);
785
786   if (y > 0 && gd_cave_get_rc(cave, x, y - 1) != object->element)
787     draw_fill_border_proc(cave, x, y - 1, object);
788
789   if (x < cave->w - 1 && gd_cave_get_rc(cave, x + 1, y) != object->element)
790     draw_fill_border_proc(cave, x + 1, y, object);
791
792   if (y < cave->h-1 && gd_cave_get_rc(cave, x, y + 1) != object->element)
793     draw_fill_border_proc(cave, x, y + 1, object);
794 }
795
796 static void draw_fill_border (GdCave *cave, const GdObject *object)
797 {
798   int x, y;
799
800   /* check bounds */
801   if (object->x1 < 0 ||
802       object->y1 < 0 ||
803       object->x1 >= cave->w ||
804       object->y1 >= cave->h)
805     return;
806
807   /* this procedure fills the area with the object->element. */
808   draw_fill_border_proc(cave, object->x1, object->y1, object);
809
810   /* after the fill, we change all filled cells to the fill_element. */
811   /* we find those by looking at the object_order[][] */
812   for (y = 0; y < cave->h; y++)
813     for (x = 0; x < cave->w; x++)
814       if (cave->objects_order[y][x] == object)
815         cave->map[y][x] = object->fill_element;
816 }
817
818 /* rectangle, frame only */
819 static void draw_rectangle(GdCave *cave, const GdObject *object)
820 {
821   int x1, y1, x2, y2, x, y;
822
823   /* reorder coordinates if not drawing from northwest to southeast */
824   x1 = object->x1;
825   y1 = object->y1, x2 = object->x2;
826   y2 = object->y2;
827
828   if (y1 > y2)
829   {
830     y = y1;
831     y1 = y2;
832     y2 = y;
833   }
834
835   if (x1 > x2)
836   {
837     x = x1;
838     x1 = x2;
839     x2 = x;
840   }
841
842   for (x = x1; x <= x2; x++)
843   {
844     gd_cave_store_rc(cave, x, object->y1, object->element, object);
845     gd_cave_store_rc(cave, x, object->y2, object->element, object);
846   }
847
848   for (y = y1; y <= y2; y++)
849   {
850     gd_cave_store_rc(cave, object->x1, y, object->element, object);
851     gd_cave_store_rc(cave, object->x2, y, object->element, object);
852   }
853 }
854
855 /* rectangle, filled one */
856 static void draw_filled_rectangle(GdCave *cave, const GdObject *object)
857 {
858   int x1, y1, x2, y2, x, y;
859
860   /* reorder coordinates if not drawing from northwest to southeast */
861   x1 = object->x1;
862   y1 = object->y1, x2 = object->x2;
863   y2 = object->y2;
864
865   if (y1 > y2)
866   {
867     y = y1;
868     y1 = y2;
869     y2 = y;
870   }
871
872   if (x1 > x2)
873   {
874     x = x1;
875     x1 = x2;
876     x2 = x;
877   }
878
879   for (y = y1; y <= y2; y++)
880     for (x = x1; x <= x2; x++)
881       gd_cave_store_rc(cave, x, y, (y == object->y1 ||
882                                     y == object->y2 ||
883                                     x == object->x1 ||
884                                     x == object->x2) ? object->element : object->fill_element, object);
885 }
886
887 /* something like ordered fill, increment is dx and dy. */
888 static void draw_raster(GdCave *cave, const GdObject *object)
889 {
890   int x, y, x1, y1, x2, y2;
891   int dx, dy;
892
893   /* reorder coordinates if not drawing from northwest to southeast */
894   x1 = object->x1;
895   y1 = object->y1;
896   x2 = object->x2;
897   y2 = object->y2;
898
899   if (y1 > y2)
900   {
901     y = y1;
902     y1 = y2;
903     y2 = y;
904   }
905
906   if (x1 > x2)
907   {
908     x = x1;
909     x1 = x2;
910     x2 = x;
911   }
912
913   dx = object->dx;
914
915   if (dx < 1)
916     dx = 1;
917
918   dy = object->dy;
919
920   if (dy < 1)
921     dy = 1;
922
923   for (y = y1; y <= y2; y += dy)
924     for (x = x1; x <= x2; x += dx)
925       gd_cave_store_rc(cave, x, y, object->element, object);
926 }
927
928 /* find every object, and put fill_element next to it. relative coordinates dx,dy */
929 static void draw_join(GdCave *cave, const GdObject *object)
930 {
931   int x, y;
932
933   for (y = 0; y < cave->h; y++)
934   {
935     for (x = 0; x < cave->w; x++)
936     {
937       if (cave->map[y][x] == object->element)
938       {
939         int nx = x + object->dx;
940         int ny = y + object->dy;
941         /* this one implements wraparound for joins.
942            it is needed by many caves in profi boulder series */
943         while (nx >= cave->w)
944           nx -= cave->w, ny++;
945
946         gd_cave_store_rc(cave, nx, ny, object->fill_element, object);
947       }
948     }
949   }
950 }
951
952 /* create a maze in a boolean **maze. */
953 /* recursive algorithm. */
954 static void mazegen(GRand *rand, boolean **maze, int width, int height, int x, int y, int horiz)
955 {
956   int dirmask = 15;
957
958   maze[y][x] = TRUE;
959   while (dirmask != 0)
960   {
961     int dir;
962
963     /* horiz or vert */
964     dir = g_rand_int_range(rand, 0, 100) <horiz ? 2 : 0;
965
966     /* if no horizontal movement possible, choose vertical */
967     if (dir == 2 && (dirmask & 12) == 0)
968       dir = 0;
969     else if (dir == 0 && (dirmask&3) == 0)    /* and vice versa */
970       dir = 2;
971
972     dir += g_rand_int_range(rand, 0, 2);                /* dir */
973     if (dirmask & (1 << dir))
974     {
975       dirmask &= ~(1 << dir);
976
977       switch (dir)
978       {
979         case 0:    /* up */
980           if (y >= 2 && !maze[y - 2][x])
981           {
982             maze[y - 1][x] = TRUE;
983             mazegen(rand, maze, width, height, x, y - 2, horiz);
984           }
985           break;
986
987         case 1:    /* down */
988           if (y < height-2 && !maze[y + 2][x]) {
989             maze[y + 1][x] = TRUE;
990             mazegen(rand, maze, width, height, x, y + 2, horiz);
991           }
992           break;
993
994         case 2:    /* left */
995           if (x >= 2 && !maze[y][x - 2]) {
996             maze[y][x - 1] = TRUE;
997             mazegen(rand, maze, width, height, x - 2, y, horiz);
998           }
999           break;
1000
1001         case 3:    /* right */
1002           if (x < width - 2 && !maze[y][x + 2]) {
1003             maze[y][x + 1] = TRUE;
1004             mazegen(rand, maze, width, height, x + 2, y, horiz);
1005           }
1006           break;
1007
1008         default:
1009           break;
1010       }
1011     }
1012   }
1013 }
1014
1015 static void braidmaze(GRand *rand, boolean **maze, int w, int h)
1016 {
1017   int x, y;
1018
1019   for (y = 0; y < h; y += 2)
1020   {
1021     for (x = 0; x < w; x += 2)
1022     {
1023       int closed = 0, dirs = 0;
1024       int closed_dirs[4];
1025
1026       /* if it is the edge of the map, OR no path carved, then we can't go in that direction. */
1027       if (x < 1 || !maze[y][x - 1])
1028       {
1029         /* closed from this side. */
1030         closed++;
1031
1032         /* if not the edge, we might open this wall (carve a path) to remove a dead end */
1033         if (x > 0)
1034           closed_dirs[dirs++] = GD_MV_LEFT;
1035       }
1036
1037       /* other 3 directions similar */
1038       if (y < 1 || !maze[y - 1][x])
1039       {
1040         closed++;
1041         if (y > 0)
1042           closed_dirs[dirs++] = GD_MV_UP;
1043       }
1044
1045       if (x >= w - 1 || !maze[y][x + 1])
1046       {
1047         closed++;
1048         if (x < w - 1)
1049           closed_dirs[dirs++] = GD_MV_RIGHT;
1050       }
1051
1052       if (y >= h - 1 || !maze[y + 1][x]) {
1053         closed++;
1054         if (y < h - 1)
1055           closed_dirs[dirs++] = GD_MV_DOWN;
1056       }
1057
1058       /* if closed from 3 sides, then it is a dead end. also check dirs != 0,
1059          that might fail for a 1x1 maze :) */
1060       if (closed == 3 && dirs != 0)
1061       {
1062         /* make up a random direction, and open in that direction, so dead end is removed */
1063         int dir = closed_dirs[g_rand_int_range(rand, 0, dirs)];
1064
1065         switch (dir)
1066         {
1067           case GD_MV_LEFT:
1068             maze[y][x - 1] = TRUE; break;
1069           case GD_MV_UP:
1070             maze[y - 1][x] = TRUE; break;
1071           case GD_MV_RIGHT:
1072             maze[y][x + 1] = TRUE; break;
1073           case GD_MV_DOWN:
1074             maze[y + 1][x] = TRUE; break;
1075         }
1076       }
1077     }
1078   }
1079 }
1080
1081 static void draw_maze(GdCave *cave, const GdObject *object, int level)
1082 {
1083   int x, y;
1084   boolean **map;
1085   int x1 = object->x1;
1086   int y1 = object->y1;
1087   int x2 = object->x2;
1088   int y2 = object->y2;
1089   int w, h, path, wall;
1090   int xk, yk;
1091   GRand *rand;
1092   int i,j;
1093
1094   /* change coordinates if not in correct order */
1095   if (y1 > y2)
1096   {
1097     y = y1;
1098     y1 = y2;
1099     y2 = y;
1100   }
1101
1102   if (x1 > x2)
1103   {
1104     x = x1;
1105     x1 = x2;
1106     x2 = x;
1107   }
1108
1109   wall = object->dx;
1110   if (wall < 1)
1111     wall = 1;
1112
1113   path = object->dy;
1114   if (path < 1)
1115     path = 1;
1116
1117   /* calculate the width and height of the maze.
1118      n = number of passages, path = path width, wall = wall width, maze = maze width.
1119      if given the number of passages, the width of the maze is:
1120
1121      n * path + (n - 1) * wall = maze
1122      n * path + n * wall - wall = maze
1123      n * (path + wall) = maze + wall
1124      n = (maze + wall) / (path + wall)
1125   */
1126
1127   /* number of passages for each side */
1128   w = (x2 - x1 + 1 + wall) / (path + wall);
1129   h = (y2 - y1 + 1 + wall) / (path + wall);
1130
1131   /* and we calculate the size of the internal map */
1132   if (object->type == GD_MAZE_UNICURSAL)
1133   {
1134     /* for unicursal maze, width and height must be mod2 = 0,
1135        and we will convert to paths & walls later */
1136     w = w / 2 * 2;
1137     h = h / 2 * 2;
1138   }
1139   else
1140   {
1141     /* for normal maze */
1142     w = 2 * (w - 1) + 1;
1143     h = 2 * (h - 1) + 1;
1144   }
1145
1146   /* twodimensional boolean array to generate map in */
1147   map = checked_malloc((h) * sizeof(boolean *));
1148   for (y = 0; y < h; y++)
1149     map[y] = checked_calloc(w * sizeof(boolean));
1150
1151   /* start generation, if map is big enough.
1152      otherwise the application would crash, as the editor places maze objects
1153      during mouse click & drag that have no sense */
1154   rand = g_rand_new_with_seed(object->seed[level] == -1 ?
1155                               g_rand_int(cave->random) : object->seed[level]);
1156
1157   if (w >= 1 && h >= 1)
1158     mazegen(rand, map, w, h, 0, 0, object->horiz);
1159
1160   if (object->type == GD_MAZE_BRAID)
1161     braidmaze(rand, map, w, h);
1162
1163   g_rand_free(rand);
1164
1165   if (w >= 1 && h >= 1 && object->type == GD_MAZE_UNICURSAL)
1166   {
1167     boolean **unicursal;
1168
1169     /* convert to unicursal maze */
1170     /* original:
1171         xxx x
1172           x x
1173         xxxxx
1174
1175         unicursal:
1176         xxxxxxx xxx
1177         x     x x x
1178         xxxxx x x x
1179             x x x x
1180         xxxxx xxx x
1181         x         x
1182         xxxxxxxxxxx
1183     */
1184
1185     unicursal = checked_malloc((h * 2 - 1) * sizeof(boolean *));
1186
1187     for (y = 0; y < h * 2 - 1; y++)
1188       unicursal[y] = checked_calloc((w * 2 - 1) * sizeof(boolean));
1189
1190     for (y = 0; y < h; y++)
1191     {
1192       for(x = 0; x < w; x++)
1193       {
1194         if (map[y][x]) {
1195           unicursal[y * 2][x * 2] = TRUE;
1196           unicursal[y * 2][x * 2 + 2] = TRUE;
1197           unicursal[y * 2 + 2][x * 2] = TRUE;
1198           unicursal[y * 2 + 2][x * 2 + 2] = TRUE;
1199
1200           if (x < 1      || !map[y][x - 1]) unicursal[y * 2 + 1][x * 2] = TRUE;
1201           if (y < 1      || !map[y - 1][x]) unicursal[y * 2][x * 2 + 1] = TRUE;
1202           if (x >= w - 1 || !map[y][x + 1]) unicursal[y * 2 + 1][x * 2 + 2] = TRUE;
1203           if (y >= h - 1 || !map[y + 1][x]) unicursal[y * 2 + 2][x * 2 + 1] = TRUE;
1204         }
1205       }
1206     }
1207
1208     /* free original map */
1209     for (y = 0; y < h; y++)
1210       free(map[y]);
1211     free(map);
1212
1213     /* change to new map - the unicursal maze */
1214     map = unicursal;
1215     h = h * 2 - 1;
1216     w = w * 2 - 1;
1217   }
1218
1219   /* copy map to cave with correct elements and size */
1220   /* now copy the map into the cave. the copying works like this...
1221      pwpwp
1222      xxxxx p
1223      x x   w
1224      x xxx p
1225      x     w
1226      xxxxx p
1227      columns and rows denoted with "p" are to be drawn with path width,
1228      the others with wall width. */
1229
1230   yk = y1;
1231
1232   for (y = 0; y < h; y++)
1233   {
1234     for (i = 0; i < (y % 2 == 0 ? path : wall); i++)
1235     {
1236       xk = x1;
1237
1238       for (x = 0; x < w; x++)
1239         for (j = 0; j < (x % 2 == 0 ? path : wall); j++)
1240           gd_cave_store_rc(cave, xk++, yk, map[y][x] ? object->fill_element : object->element, object);
1241
1242       /* if width is smaller than requested, fill with wall */
1243       for(x = xk; x <= x2; x++)
1244         gd_cave_store_rc(cave, x, yk, object->element, object);
1245
1246       yk++;
1247     }
1248   }
1249
1250   /* if height is smaller than requested, fill with wall */
1251   for (y = yk; y <= y2; y++)
1252     for (x = x1; x <= x2; x++)
1253       gd_cave_store_rc(cave, x, y, object->element, object);
1254
1255   /* free map */
1256   for (y = 0; y < h; y++)
1257     free(map[y]);
1258   free(map);
1259 }
1260
1261 static void draw_random_fill(GdCave *cave, const GdObject *object, int level)
1262 {
1263   int x, y;
1264   int x1 = object->x1;
1265   int y1 = object->y1;
1266   int x2 = object->x2;
1267   int y2 = object->y2;
1268   GRand *rand;
1269   GdC64RandomGenerator c64_rand;
1270   guint32 seed;
1271
1272   /* -1 means that it should be different every time played. */
1273   if (object->seed[level] == -1)
1274     seed = g_rand_int(cave->random);
1275   else
1276     seed = object->seed[level];
1277
1278   rand = g_rand_new_with_seed(seed);
1279   /* for c64 random, use the 2*8 lsb. */
1280   gd_c64_random_set_seed(&c64_rand, seed / 256 % 256, seed % 256);
1281
1282   /* change coordinates if not in correct order */
1283   if (y1 > y2)
1284   {
1285     y = y1;
1286     y1 = y2;
1287     y2 = y;
1288   }
1289
1290   if (x1 > x2)
1291   {
1292     x = x1;
1293     x1 = x2;
1294     x2 = x;
1295   }
1296
1297   for (y = y1; y <= y2; y++)
1298   {
1299     for (x = x1; x <= x2; x++)
1300     {
1301       unsigned int randm;
1302       GdElement element;
1303
1304       if (object->c64_random)
1305         /* use c64 random generator */
1306         randm = gd_c64_random(&c64_rand);
1307       else
1308         /* use the much better glib random generator */
1309         randm = g_rand_int_range(rand, 0, 256);
1310
1311       element = object->fill_element;
1312       if (randm < object->random_fill_probability[0])
1313         element = object->random_fill[0];
1314       if (randm < object->random_fill_probability[1])
1315         element = object->random_fill[1];
1316       if (randm < object->random_fill_probability[2])
1317         element = object->random_fill[2];
1318       if (randm < object->random_fill_probability[3])
1319         element = object->random_fill[3];
1320
1321       if (object->element==O_NONE ||
1322           gd_cave_get_rc(cave, x, y) == object->element)
1323         gd_cave_store_rc(cave, x, y, element, object);
1324     }
1325   }
1326
1327   g_rand_free(rand);
1328 }
1329
1330
1331 static void draw_copy_paste(GdCave *cave, const GdObject *object)
1332 {
1333   int x1 = object->x1, y1 = object->y1, x2 = object->x2, y2 = object->y2;
1334   int x, y;    /* iterators */
1335   int w, h;
1336   GdElement *clipboard;
1337
1338   /* reorder coordinates if not drawing from northwest to southeast */
1339   if (x2 < x1)
1340   {
1341     x = x2;
1342     x2 = x1;
1343     x1 = x;
1344   }
1345
1346   if (y2 < y1)
1347   {
1348     y = y2;
1349     y2 = y1;
1350     y1 = y;
1351   }
1352
1353   w = x2 - x1 + 1;
1354   h = y2 - y1 + 1;
1355
1356   clipboard = checked_malloc((w * h) * sizeof(GdElement));
1357
1358   /* copy to "clipboard" */
1359   for (y = 0; y < h; y++)
1360     for (x = 0; x < w; x++)
1361       clipboard[y * w + x] = gd_cave_get_rc(cave, x + x1, y + y1);
1362
1363   for (y = 0; y < h; y++)
1364   {
1365     int ydest;
1366
1367     ydest = object->flip ? h - 1 - y : y;
1368
1369     for (x = 0; x < w; x++)
1370     {
1371       int xdest;
1372
1373       xdest = object->mirror ? w - 1 - x : x;
1374
1375       /* dx and dy are used here are "paste to" coordinates */
1376       gd_cave_store_rc(cave, object->dx + xdest, object->dy + ydest,
1377                        clipboard[y * w + x], object);
1378     }
1379   }
1380
1381   free(clipboard);
1382 }
1383
1384 /* draw the specified game object into cave's data.
1385    also remember, which cell was set by which cave object. */
1386 void gd_cave_draw_object(GdCave *cave, const GdObject *object, int level)
1387 {
1388   switch (object->type)
1389   {
1390     case GD_POINT:
1391       /* single point */
1392       gd_cave_store_rc(cave, object->x1, object->y1, object->element, object);
1393       break;
1394
1395     case GD_LINE:
1396       draw_line(cave, object);
1397       break;
1398
1399     case GD_RECTANGLE:
1400       draw_rectangle(cave, object);
1401       break;
1402
1403     case GD_FILLED_RECTANGLE:
1404       draw_filled_rectangle(cave, object);
1405       break;
1406
1407     case GD_RASTER:
1408       draw_raster(cave, object);
1409       break;
1410
1411     case GD_JOIN:
1412       draw_join(cave, object);
1413       break;
1414
1415     case GD_FLOODFILL_BORDER:
1416       draw_fill_border(cave, object);
1417       break;
1418
1419     case GD_FLOODFILL_REPLACE:
1420       draw_fill_replace(cave, object);
1421       break;
1422
1423     case GD_MAZE:
1424     case GD_MAZE_UNICURSAL:
1425     case GD_MAZE_BRAID:
1426       draw_maze(cave, object, level);
1427       break;
1428
1429     case GD_RANDOM_FILL:
1430       draw_random_fill(cave, object, level);
1431       break;
1432
1433     case GD_COPY_PASTE:
1434       draw_copy_paste(cave, object);
1435       break;
1436
1437     case NONE:
1438       break;
1439
1440     default:
1441       Error("Unknown object %d", object->type);
1442       break;
1443   }
1444 }
1445
1446 /* load cave to play... also can be called rendering the cave elements */
1447 GdCave *gd_cave_new_rendered(const GdCave *data, const int level, const guint32 seed)
1448 {
1449   GdCave *cave;
1450   GdElement element;
1451   int x, y;
1452   GList *iter;
1453
1454   /* make a copy */
1455   cave = gd_cave_new_from_cave(data);
1456   cave->rendered = level + 1;
1457
1458   cave->render_seed = seed;
1459   cave->random = g_rand_new_with_seed(cave->render_seed);
1460
1461   /* maps needed during drawing and gameplay */
1462   cave->objects_order = gd_cave_map_new(cave, gpointer);
1463
1464   cave->time                   = data->level_time[level];
1465   cave->timevalue              = data->level_timevalue[level];
1466   cave->diamonds_needed        = data->level_diamonds[level];
1467   cave->magic_wall_time        = data->level_magic_wall_time[level];
1468   cave->slime_permeability     = data->level_slime_permeability[level];
1469   cave->slime_permeability_c64 = data->level_slime_permeability_c64[level];
1470   cave->time_bonus             = data->level_bonus_time[level];
1471   cave->time_penalty           = data->level_penalty_time[level];
1472   cave->amoeba_time            = data->level_amoeba_time[level];
1473   cave->amoeba_max_count       = data->level_amoeba_threshold[level];
1474   cave->amoeba_2_time          = data->level_amoeba_2_time[level];
1475   cave->amoeba_2_max_count     = data->level_amoeba_2_threshold[level];
1476   cave->hatching_delay_time    = data->level_hatching_delay_time[level];
1477   cave->hatching_delay_frame   = data->level_hatching_delay_frame[level];
1478
1479   if (!cave->map)
1480   {
1481     /* if we have no map, fill with predictable random generator. */
1482     cave->map = gd_cave_map_new(cave, GdElement);
1483
1484     /* IF CAVE HAS NO MAP, USE THE RANDOM NUMBER GENERATOR */
1485     /* init c64 randomgenerator */
1486     if (data->level_rand[level] < 0)
1487       gd_cave_c64_random_set_seed(cave, g_rand_int_range(cave->random, 0, 256),
1488                                   g_rand_int_range(cave->random, 0, 256));
1489     else
1490       gd_cave_c64_random_set_seed(cave, 0, data->level_rand[level]);
1491
1492     /* generate random fill
1493      * start from row 1 (0 skipped), and fill also the borders on left and right hand side,
1494      * as c64 did. this way works the original random generator the right way.
1495      * also, do not fill last row, that is needed for the random seeds to be correct
1496      * after filling! predictable slime will use it. */
1497     for (y = 1; y < cave->h - 1; y++)
1498     {
1499       for (x = 0; x < cave->w; x++)
1500       {
1501         unsigned int randm;
1502
1503         if (data->level_rand[level] < 0)
1504           /* use the much better glib random generator */
1505           randm = g_rand_int_range(cave->random, 0, 256);
1506         else
1507           /* use c64 */
1508           randm = gd_cave_c64_random(cave);
1509
1510         element = data->initial_fill;
1511         if (randm < data->random_fill_probability[0])
1512           element = data->random_fill[0];
1513         if (randm < data->random_fill_probability[1])
1514           element = data->random_fill[1];
1515         if (randm < data->random_fill_probability[2])
1516           element = data->random_fill[2];
1517         if (randm < data->random_fill_probability[3])
1518           element = data->random_fill[3];
1519
1520         gd_cave_store_rc(cave, x, y, element, NULL);
1521       }
1522     }
1523
1524     /* draw initial border */
1525     for (y = 0; y < cave->h; y++)
1526     {
1527       gd_cave_store_rc(cave, 0,           y, cave->initial_border, NULL);
1528       gd_cave_store_rc(cave, cave->w - 1, y, cave->initial_border, NULL);
1529     }
1530
1531     for (x = 0; x < cave->w; x++)
1532     {
1533       gd_cave_store_rc(cave, x,           0, cave->initial_border, NULL);
1534       gd_cave_store_rc(cave, x, cave->h - 1, cave->initial_border, NULL);
1535     }
1536   }
1537   else
1538   {
1539     /* IF CAVE HAS A MAP, SIMPLY USE IT... no need to fill with random elements */
1540
1541     /* initialize c64 predictable random for slime.
1542        the values were taken from afl bd, see docs/internals.txt */
1543     gd_cave_c64_random_set_seed(cave, 0, 0x1e);
1544   }
1545
1546   if (data->level_slime_seed_c64[level] != -1)
1547   {
1548     /* if a specific slime seed is requested, change it now. */
1549
1550     gd_cave_c64_random_set_seed(cave,
1551                                 data->level_slime_seed_c64[level] / 256,
1552                                 data->level_slime_seed_c64[level] % 256);
1553   }
1554
1555   /* render cave objects above random data or map */
1556   for (iter = data->objects; iter; iter = g_list_next(iter))
1557   {
1558     GdObject *object = (GdObject *)iter->data;
1559
1560     if (object->levels & gd_levels_mask[level])
1561       gd_cave_draw_object(cave, iter->data, level);
1562   }
1563
1564   /* check if we use c64 ckdelay or milliseconds for timing */
1565   if (cave->scheduling == GD_SCHEDULING_MILLISECONDS)
1566     cave->speed = data->level_speed[level];        /* exact timing */
1567   else
1568   {
1569     /* delay loop based timing... set something for first iteration,
1570        then later it will be calculated */
1571     cave->speed = 120;
1572
1573     /* this one may be used by iterate routine to calculate actual delay
1574        if c64scheduling is selected */
1575     cave->c64_timing = data->level_ckdelay[level];
1576   }
1577
1578   gd_cave_correct_visible_size(cave);
1579
1580   return cave;
1581 }
1582
1583 /*
1584    render cave at specified level.
1585    copy result to the map; remove objects.
1586    the cave will be map-based.
1587  */
1588 void gd_flatten_cave(GdCave *cave, const int level)
1589 {
1590   GdCave *rendered;
1591
1592   if (cave == NULL)
1593     return;
1594
1595   /* render cave at specified level to obtain map. seed = 0 */
1596   rendered = gd_cave_new_rendered(cave, level, 0);
1597
1598   /* forget old map without objects */
1599   gd_cave_map_free(cave->map);
1600
1601   /* copy new map to cave */
1602   cave->map = gd_cave_map_dup(rendered, map);
1603   gd_cave_free(rendered);
1604
1605   /* forget objects */
1606   g_list_foreach(cave->objects, (GFunc) free, NULL);
1607   cave->objects = NULL;
1608 }