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