added support for BD game engine to Makefile for Android
[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 GdObject *gd_object_new_from_string(char *str)
374 {
375   char *equalsign;
376   char *name, *param;
377   GdObject object;
378   char elem0[100], elem1[100];
379
380   equalsign = strchr(str, '=');
381   if (!equalsign)
382     return NULL;
383
384   // split string by replacing the equal sign with zero
385   *equalsign = '\0';
386   name = str;
387   param = equalsign + 1;
388
389   // INDIVIDUAL POINT CAVE OBJECT
390   if (strcasecmp(name, "Point") == 0)
391   {
392     object.type = GD_POINT;
393     if (sscanf(param, "%d %d %s", &object.x1, &object.y1, elem0) == 3)
394     {
395       object.element = gd_get_element_from_string(elem0);
396
397       return get_memcpy(&object, sizeof (GdObject));
398     }
399
400     return NULL;
401   }
402
403   // LINE OBJECT
404   if (strcasecmp(name, "Line") == 0)
405   {
406     object.type = GD_LINE;
407     if (sscanf(param, "%d %d %d %d %s", &object.x1, &object.y1, &object.x2, &object.y2, elem0) == 5)
408     {
409       object.element = gd_get_element_from_string(elem0);
410
411       return get_memcpy(&object, sizeof (GdObject));
412     }
413
414     return NULL;
415   }
416
417   // RECTANGLE OBJECT
418   if (strcasecmp(name, "Rectangle") == 0)
419   {
420     if (sscanf(param, "%d %d %d %d %s", &object.x1, &object.y1, &object.x2, &object.y2, elem0) == 5)
421     {
422       object.type = GD_RECTANGLE;
423       object.element = gd_get_element_from_string (elem0);
424
425       return get_memcpy(&object, sizeof (GdObject));
426     }
427
428     return NULL;
429   }
430
431   // FILLED RECTANGLE OBJECT
432   if (strcasecmp(name, "FillRect") == 0)
433   {
434     int paramcount;
435
436     paramcount = sscanf(param, "%d %d %d %d %s %s", &object.x1, &object.y1, &object.x2, &object.y2, elem0, elem1);
437     object.type = GD_FILLED_RECTANGLE;
438
439     if (paramcount == 6)
440     {
441       object.element = gd_get_element_from_string (elem0);
442       object.fill_element = gd_get_element_from_string (elem1);
443
444       return get_memcpy(&object, sizeof (GdObject));
445     }
446
447     if (paramcount == 5)
448     {
449       object.element = object.fill_element = gd_get_element_from_string (elem0);
450
451       return get_memcpy(&object, sizeof (GdObject));
452     }
453
454     return NULL;
455   }
456
457   // RASTER
458   if (strcasecmp(name, "Raster") == 0)
459   {
460     int nx, ny;
461
462     if (sscanf(param, "%d %d %d %d %d %d %s", &object.x1, &object.y1, &nx, &ny, &object.dx, &object.dy, elem0) == 7)
463     {
464       nx--;
465       ny--;
466       object.x2 = object.x1 + nx * object.dx;
467       object.y2 = object.y1 + ny * object.dy;
468       object.type = GD_RASTER;
469       object.element = gd_get_element_from_string (elem0);
470
471       return get_memcpy(&object, sizeof (GdObject));
472     }
473
474     return NULL;
475   }
476
477   // JOIN
478   if (strcasecmp(name, "Join") == 0 ||
479       strcasecmp(name, "Add") == 0)
480   {
481     if (sscanf(param, "%d %d %s %s", &object.dx, &object.dy, elem0, elem1) == 4)
482     {
483       object.type = GD_JOIN;
484       object.element = gd_get_element_from_string (elem0);
485       object.fill_element = gd_get_element_from_string (elem1);
486
487       return get_memcpy(&object, sizeof (GdObject));
488     }
489
490     return NULL;
491   }
492
493   // FILL TO BORDER OBJECT
494   if (strcasecmp(name, "BoundaryFill") == 0)
495   {
496     if (sscanf(param, "%d %d %s %s", &object.x1, &object.y1, elem0, elem1) == 4)
497     {
498       object.type = GD_FLOODFILL_BORDER;
499       object.fill_element = gd_get_element_from_string (elem0);
500       object.element = gd_get_element_from_string (elem1);
501
502       return get_memcpy(&object, sizeof (GdObject));
503     }
504
505     return NULL;
506   }
507
508   // REPLACE FILL OBJECT
509   if (strcasecmp(name, "FloodFill") == 0)
510   {
511     if (sscanf(param, "%d %d %s %s", &object.x1, &object.y1, elem0, elem1) == 4)
512     {
513       object.type = GD_FLOODFILL_REPLACE;
514       object.fill_element = gd_get_element_from_string (elem0);
515       object.element = gd_get_element_from_string (elem1);
516
517       return get_memcpy(&object, sizeof (GdObject));
518     }
519
520     return NULL;
521   }
522
523   // MAZE OBJECT
524   // MAZE UNICURSAL OBJECT
525   // BRAID MAZE OBJECT
526   if (strcasecmp(name, "Maze") == 0)
527   {
528     char type[100] = "perfect";
529
530     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)
531     {
532       if (strcasecmp(type, "unicursal") == 0)
533         object.type = GD_MAZE_UNICURSAL;
534       else if (strcasecmp(type, "perfect") == 0)
535         object.type = GD_MAZE;
536       else if (strcasecmp(type, "braid") == 0)
537         object.type = GD_MAZE_BRAID;
538       else
539       {
540         Warn("unknown maze type: %s, defaulting to perfect", type);
541         object.type = GD_MAZE;
542       }
543
544       object.element = gd_get_element_from_string (elem0);
545       object.fill_element = gd_get_element_from_string (elem1);
546
547       return get_memcpy(&object, sizeof (GdObject));
548     }
549
550     return NULL;
551   }
552
553   // RANDOM FILL OBJECT
554   if (strcasecmp(name, "RandomFill") == 0 ||
555       strcasecmp(name, "RandomFillC64") == 0)
556   {
557     static char **words = NULL;
558     int l, i;
559
560     object.type = GD_RANDOM_FILL;
561     if (strcasecmp(name, "RandomFillC64") == 0)
562       // totally the same, but uses c64 random generator
563       object.c64_random = TRUE;
564     else
565       object.c64_random = FALSE;
566
567     if (sscanf(param, "%d %d %d %d", &object.x1, &object.y1, &object.x2, &object.y2) != 4)
568       return NULL;
569
570     if (words)
571       freeStringArray(words);
572
573     words = getSplitStringArray(param, " ", -1);
574     l = getStringArrayLength(words);
575
576     if (l < 10 || l > 19)
577       return NULL;
578
579     for (i = 0; i < 5; i++)
580       if (sscanf(words[4 + i], "%d", &object.seed[i]) != 1)
581         return NULL;
582
583     object.fill_element = gd_get_element_from_string(words[9]);
584
585     for (i = 0; i < 4; i++)
586     {
587       object.random_fill[i] = O_DIRT;
588       object.random_fill_probability[i] = 0;
589     }
590
591     for (i = 10; i < l - 1; i += 2)
592     {
593       object.random_fill[(i - 10) / 2] = gd_get_element_from_string(words[i]);
594       if (sscanf(words[i + 1], "%d", &object.random_fill_probability[(i - 10) / 2]) == 0)
595         return NULL;
596     }
597
598     object.element = O_NONE;
599
600     if (l > 10 && l % 2 == 1)
601       object.element = gd_get_element_from_string(words[l - 1]);
602
603     return get_memcpy(&object, sizeof (GdObject));
604   }
605
606   // COPY PASTE OBJECT
607   if (strcasecmp(name, "CopyPaste") == 0)
608   {
609     char mirror[100] = "nomirror";
610     char flip[100] = "noflip";
611     object.type = GD_COPY_PASTE;
612
613     object.flip = object.mirror = FALSE;
614
615     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)
616       return NULL;
617
618     // MIRROR PROPERTY
619     if (strcasecmp(mirror, "mirror") == 0)
620       object.mirror = TRUE;
621     else if (strcasecmp(mirror, "nomirror") == 0)
622       object.mirror = FALSE;
623     else
624       Warn("invalid setting for copypaste mirror property: %s", mirror);
625
626     // FLIP PROPERTY
627     if (strcasecmp(flip, "flip") == 0)
628       object.flip = TRUE;
629     else if (strcasecmp(flip, "noflip") == 0)
630       object.flip = FALSE;
631     else
632       Warn("invalid setting for copypaste flip property: %s", flip);
633
634     return get_memcpy(&object, sizeof(GdObject));
635   }
636
637   return NULL;
638 }
639
640 // drawing a line, using bresenham's
641 static void draw_line (GdCave *cave, const GdObject *object)
642 {
643   int x, y, x1, y1, x2, y2;
644   boolean steep;
645   int error, dx, dy, ystep;
646
647   x1 = object->x1;
648   y1 = object->y1, x2 = object->x2;
649   y2 = object->y2;
650   steep = ABS (y2 - y1) > ABS (x2 - x1);
651
652   if (steep)
653   {
654     x = x1;
655     x1 = y1;
656     y1 = x;
657     x = x2;
658     x2 = y2;
659     y2 = x;
660   }
661
662   if (x1 > x2)
663   {
664     x = x1;
665     x1 = x2;
666     x2 = x;
667     x = y1;
668     y1 = y2;
669     y2 = x;
670   }
671
672   dx = x2 - x1;
673   dy = ABS (y2 - y1);
674   y = y1;
675   error = 0;
676   ystep = (y1 < y2) ? 1 : -1;
677
678   for (x = x1; x <= x2; x++)
679   {
680     if (steep)
681       gd_cave_store_rc (cave, y, x, object->element, object);
682     else
683       gd_cave_store_rc (cave, x, y, object->element, object);
684
685     error += dy;
686
687     if (error * 2 >= dx)
688     {
689       y += ystep;
690       error -= dx;
691     }
692   }
693 }
694
695
696
697 static void draw_fill_replace_proc(GdCave *cave, int x, int y, const GdObject *object)
698 {
699   // fill with border so we do not come back
700   gd_cave_store_rc(cave, x, y, object->fill_element, object);
701
702   if (x > 0 && gd_cave_get_rc(cave, x - 1, y) == object->element)
703     draw_fill_replace_proc(cave, x - 1, y, object);
704
705   if (y > 0 && gd_cave_get_rc(cave, x, y - 1) == object->element)
706     draw_fill_replace_proc(cave, x, y - 1, object);
707
708   if (x < cave->w - 1 && gd_cave_get_rc(cave, x + 1, y) == object->element)
709     draw_fill_replace_proc(cave, x + 1, y, object);
710
711   if (y < cave->h - 1 && gd_cave_get_rc(cave, x, y + 1) == object->element)
712     draw_fill_replace_proc(cave, x, y + 1, object);
713 }
714
715 static void draw_fill_replace (GdCave *cave, const GdObject *object)
716 {
717   // check bounds
718   if (object->x1 < 0 ||
719       object->y1 < 0 ||
720       object->x1 >= cave->w ||
721       object->y1 >= cave->h)
722     return;
723
724   if (object->element == object->fill_element)
725     return;
726
727   // this procedure fills the area with the object->element.
728   draw_fill_replace_proc(cave, object->x1, object->y1, object);
729 }
730
731 static void draw_fill_border_proc (GdCave *cave, int x, int y, const GdObject *object)
732 {
733   // fill with border so we do not come back
734   gd_cave_store_rc(cave, x, y, object->element, object);
735
736   if (x > 0 && gd_cave_get_rc(cave, x - 1, y) != object->element)
737     draw_fill_border_proc(cave, x - 1, y, object);
738
739   if (y > 0 && gd_cave_get_rc(cave, x, y - 1) != object->element)
740     draw_fill_border_proc(cave, x, y - 1, object);
741
742   if (x < cave->w - 1 && gd_cave_get_rc(cave, x + 1, y) != object->element)
743     draw_fill_border_proc(cave, x + 1, y, object);
744
745   if (y < cave->h-1 && gd_cave_get_rc(cave, x, y + 1) != object->element)
746     draw_fill_border_proc(cave, x, y + 1, object);
747 }
748
749 static void draw_fill_border (GdCave *cave, const GdObject *object)
750 {
751   int x, y;
752
753   // check bounds
754   if (object->x1 < 0 ||
755       object->y1 < 0 ||
756       object->x1 >= cave->w ||
757       object->y1 >= cave->h)
758     return;
759
760   // this procedure fills the area with the object->element.
761   draw_fill_border_proc(cave, object->x1, object->y1, object);
762
763   // after the fill, we change all filled cells to the fill_element.
764   // we find those by looking at the object_order[][]
765   for (y = 0; y < cave->h; y++)
766     for (x = 0; x < cave->w; x++)
767       if (cave->objects_order[y][x] == object)
768         cave->map[y][x] = object->fill_element;
769 }
770
771 // rectangle, frame only
772 static void draw_rectangle(GdCave *cave, const GdObject *object)
773 {
774   int x1, y1, x2, y2, x, y;
775
776   // reorder coordinates if not drawing from northwest to southeast
777   x1 = object->x1;
778   y1 = object->y1, x2 = object->x2;
779   y2 = object->y2;
780
781   if (y1 > y2)
782   {
783     y = y1;
784     y1 = y2;
785     y2 = y;
786   }
787
788   if (x1 > x2)
789   {
790     x = x1;
791     x1 = x2;
792     x2 = x;
793   }
794
795   for (x = x1; x <= x2; x++)
796   {
797     gd_cave_store_rc(cave, x, object->y1, object->element, object);
798     gd_cave_store_rc(cave, x, object->y2, object->element, object);
799   }
800
801   for (y = y1; y <= y2; y++)
802   {
803     gd_cave_store_rc(cave, object->x1, y, object->element, object);
804     gd_cave_store_rc(cave, object->x2, y, object->element, object);
805   }
806 }
807
808 // rectangle, filled one
809 static void draw_filled_rectangle(GdCave *cave, const GdObject *object)
810 {
811   int x1, y1, x2, y2, x, y;
812
813   // reorder coordinates if not drawing from northwest to southeast
814   x1 = object->x1;
815   y1 = object->y1, x2 = object->x2;
816   y2 = object->y2;
817
818   if (y1 > y2)
819   {
820     y = y1;
821     y1 = y2;
822     y2 = y;
823   }
824
825   if (x1 > x2)
826   {
827     x = x1;
828     x1 = x2;
829     x2 = x;
830   }
831
832   for (y = y1; y <= y2; y++)
833     for (x = x1; x <= x2; x++)
834       gd_cave_store_rc(cave, x, y, (y == object->y1 ||
835                                     y == object->y2 ||
836                                     x == object->x1 ||
837                                     x == object->x2) ? object->element : object->fill_element, object);
838 }
839
840 // something like ordered fill, increment is dx and dy.
841 static void draw_raster(GdCave *cave, const GdObject *object)
842 {
843   int x, y, x1, y1, x2, y2;
844   int dx, dy;
845
846   // reorder coordinates if not drawing from northwest to southeast
847   x1 = object->x1;
848   y1 = object->y1;
849   x2 = object->x2;
850   y2 = object->y2;
851
852   if (y1 > y2)
853   {
854     y = y1;
855     y1 = y2;
856     y2 = y;
857   }
858
859   if (x1 > x2)
860   {
861     x = x1;
862     x1 = x2;
863     x2 = x;
864   }
865
866   dx = object->dx;
867
868   if (dx < 1)
869     dx = 1;
870
871   dy = object->dy;
872
873   if (dy < 1)
874     dy = 1;
875
876   for (y = y1; y <= y2; y += dy)
877     for (x = x1; x <= x2; x += dx)
878       gd_cave_store_rc(cave, x, y, object->element, object);
879 }
880
881 // find every object, and put fill_element next to it. relative coordinates dx,dy
882 static void draw_join(GdCave *cave, const GdObject *object)
883 {
884   int x, y;
885
886   for (y = 0; y < cave->h; y++)
887   {
888     for (x = 0; x < cave->w; x++)
889     {
890       if (cave->map[y][x] == object->element)
891       {
892         int nx = x + object->dx;
893         int ny = y + object->dy;
894         // this one implements wraparound for joins.
895         // it is needed by many caves in profi boulder series
896         while (nx >= cave->w)
897           nx -= cave->w, ny++;
898
899         gd_cave_store_rc(cave, nx, ny, object->fill_element, object);
900       }
901     }
902   }
903 }
904
905 // create a maze in a boolean **maze.
906 // recursive algorithm.
907 static void mazegen(GdRand *rand, boolean **maze, int width, int height, int x, int y, int horiz)
908 {
909   int dirmask = 15;
910
911   maze[y][x] = TRUE;
912   while (dirmask != 0)
913   {
914     int dir;
915
916     // horiz or vert
917     dir = gd_rand_int_range(rand, 0, 100) < horiz ? 2 : 0;
918
919     // if no horizontal movement possible, choose vertical
920     if (dir == 2 && (dirmask & 12) == 0)
921       dir = 0;
922     else if (dir == 0 && (dirmask & 3) == 0)    // and vice versa
923       dir = 2;
924
925     dir += gd_rand_int_range(rand, 0, 2);                // dir
926     if (dirmask & (1 << dir))
927     {
928       dirmask &= ~(1 << dir);
929
930       switch (dir)
931       {
932         case 0:    // up
933           if (y >= 2 && !maze[y - 2][x])
934           {
935             maze[y - 1][x] = TRUE;
936             mazegen(rand, maze, width, height, x, y - 2, horiz);
937           }
938           break;
939
940         case 1:    // down
941           if (y < height-2 && !maze[y + 2][x]) {
942             maze[y + 1][x] = TRUE;
943             mazegen(rand, maze, width, height, x, y + 2, horiz);
944           }
945           break;
946
947         case 2:    // left
948           if (x >= 2 && !maze[y][x - 2]) {
949             maze[y][x - 1] = TRUE;
950             mazegen(rand, maze, width, height, x - 2, y, horiz);
951           }
952           break;
953
954         case 3:    // right
955           if (x < width - 2 && !maze[y][x + 2]) {
956             maze[y][x + 1] = TRUE;
957             mazegen(rand, maze, width, height, x + 2, y, horiz);
958           }
959           break;
960
961         default:
962           break;
963       }
964     }
965   }
966 }
967
968 static void braidmaze(GdRand *rand, boolean **maze, int w, int h)
969 {
970   int x, y;
971
972   for (y = 0; y < h; y += 2)
973   {
974     for (x = 0; x < w; x += 2)
975     {
976       int closed = 0, dirs = 0;
977       int closed_dirs[4];
978
979       // if it is the edge of the map, OR no path carved, then we can't go in that direction.
980       if (x < 1 || !maze[y][x - 1])
981       {
982         // closed from this side.
983         closed++;
984
985         // if not the edge, we might open this wall (carve a path) to remove a dead end
986         if (x > 0)
987           closed_dirs[dirs++] = GD_MV_LEFT;
988       }
989
990       // other 3 directions similar
991       if (y < 1 || !maze[y - 1][x])
992       {
993         closed++;
994         if (y > 0)
995           closed_dirs[dirs++] = GD_MV_UP;
996       }
997
998       if (x >= w - 1 || !maze[y][x + 1])
999       {
1000         closed++;
1001         if (x < w - 1)
1002           closed_dirs[dirs++] = GD_MV_RIGHT;
1003       }
1004
1005       if (y >= h - 1 || !maze[y + 1][x]) {
1006         closed++;
1007         if (y < h - 1)
1008           closed_dirs[dirs++] = GD_MV_DOWN;
1009       }
1010
1011       // if closed from 3 sides, then it is a dead end. also check dirs != 0,
1012       // that might fail for a 1x1 maze :)
1013       if (closed == 3 && dirs != 0)
1014       {
1015         // make up a random direction, and open in that direction, so dead end is removed
1016         int dir = closed_dirs[gd_rand_int_range(rand, 0, dirs)];
1017
1018         switch (dir)
1019         {
1020           case GD_MV_LEFT:
1021             maze[y][x - 1] = TRUE; break;
1022           case GD_MV_UP:
1023             maze[y - 1][x] = TRUE; break;
1024           case GD_MV_RIGHT:
1025             maze[y][x + 1] = TRUE; break;
1026           case GD_MV_DOWN:
1027             maze[y + 1][x] = TRUE; break;
1028         }
1029       }
1030     }
1031   }
1032 }
1033
1034 static void draw_maze(GdCave *cave, const GdObject *object, int level)
1035 {
1036   int x, y;
1037   boolean **map;
1038   int x1 = object->x1;
1039   int y1 = object->y1;
1040   int x2 = object->x2;
1041   int y2 = object->y2;
1042   int w, h, path, wall;
1043   int xk, yk;
1044   GdRand *rand;
1045   int i,j;
1046
1047   // change coordinates if not in correct order
1048   if (y1 > y2)
1049   {
1050     y = y1;
1051     y1 = y2;
1052     y2 = y;
1053   }
1054
1055   if (x1 > x2)
1056   {
1057     x = x1;
1058     x1 = x2;
1059     x2 = x;
1060   }
1061
1062   wall = object->dx;
1063   if (wall < 1)
1064     wall = 1;
1065
1066   path = object->dy;
1067   if (path < 1)
1068     path = 1;
1069
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     //
1448     // start from row 1 (0 skipped), and fill also the borders on left and right hand side,
1449     // as c64 did. this way works the original random generator the right way.
1450     // also, do not fill last row, that is needed for the random seeds to be correct
1451     // after filling! predictable slime will use it.
1452     for (y = 1; y < cave->h - 1; y++)
1453     {
1454       for (x = 0; x < cave->w; x++)
1455       {
1456         unsigned int randm;
1457
1458         if (data->level_rand[level] < 0)
1459           // use the much better glib random generator
1460           randm = gd_rand_int_range(cave->random, 0, 256);
1461         else
1462           // use c64
1463           randm = gd_cave_c64_random(cave);
1464
1465         element = data->initial_fill;
1466         if (randm < data->random_fill_probability[0])
1467           element = data->random_fill[0];
1468         if (randm < data->random_fill_probability[1])
1469           element = data->random_fill[1];
1470         if (randm < data->random_fill_probability[2])
1471           element = data->random_fill[2];
1472         if (randm < data->random_fill_probability[3])
1473           element = data->random_fill[3];
1474
1475         gd_cave_store_rc(cave, x, y, element, NULL);
1476       }
1477     }
1478
1479     // draw initial border
1480     for (y = 0; y < cave->h; y++)
1481     {
1482       gd_cave_store_rc(cave, 0,           y, cave->initial_border, NULL);
1483       gd_cave_store_rc(cave, cave->w - 1, y, cave->initial_border, NULL);
1484     }
1485
1486     for (x = 0; x < cave->w; x++)
1487     {
1488       gd_cave_store_rc(cave, x,           0, cave->initial_border, NULL);
1489       gd_cave_store_rc(cave, x, cave->h - 1, cave->initial_border, NULL);
1490     }
1491
1492     // store if random number generator needs correction for static random seed
1493     cave->slime_correct_random = (data->level_rand[level] >= 0);
1494   }
1495   else
1496   {
1497     // IF CAVE HAS A MAP, SIMPLY USE IT... no need to fill with random elements
1498
1499     // initialize c64 predictable random for slime.
1500     // the values were taken from afl bd, see docs/internals.txt
1501     gd_cave_c64_random_set_seed(cave, 0, 0x1e);
1502
1503     // correct random number generator if cave was rendered with static random seed
1504     if (cave->slime_correct_random)
1505     {
1506       int i;
1507
1508       // set static random seed used when rendering the cave
1509       gd_cave_c64_random_set_seed(cave, 0, data->level_rand[level]);
1510
1511       for (i = 0; i < cave->w * (cave->h - 2); i++)
1512         gd_cave_c64_random(cave);
1513     }
1514   }
1515
1516   if (data->level_slime_seed_c64[level] != -1)
1517   {
1518     // if a specific slime seed is requested, change it now.
1519
1520     gd_cave_c64_random_set_seed(cave,
1521                                 data->level_slime_seed_c64[level] / 256,
1522                                 data->level_slime_seed_c64[level] % 256);
1523   }
1524
1525   // render cave objects above random data or map
1526   for (iter = data->objects; iter; iter = list_next(iter))
1527   {
1528     GdObject *object = (GdObject *)iter->data;
1529
1530     if (object->levels & gd_levels_mask[level])
1531       gd_cave_draw_object(cave, iter->data, level);
1532   }
1533
1534   // check if we use c64 ckdelay or milliseconds for timing
1535   if (cave->scheduling == GD_SCHEDULING_MILLISECONDS)
1536     cave->speed = data->level_speed[level];        // exact timing
1537   else
1538   {
1539     // delay loop based timing... set something for first iteration,
1540     // then later it will be calculated
1541     cave->speed = 120;
1542
1543     // this one may be used by iterate routine to calculate actual delay
1544     // if c64scheduling is selected
1545     cave->c64_timing = data->level_ckdelay[level];
1546   }
1547
1548   gd_cave_correct_visible_size(cave);
1549
1550   return cave;
1551 }
1552
1553 /*
1554   render cave at specified level.
1555   copy result to the map; remove objects.
1556   the cave will be map-based.
1557 */
1558 void gd_flatten_cave(GdCave *cave, const int level)
1559 {
1560   GdCave *rendered;
1561
1562   if (cave == NULL)
1563     return;
1564
1565   // render cave at specified level to obtain map. seed = 0
1566   rendered = gd_cave_new_rendered(cave, level, 0);
1567
1568   // forget old map without objects
1569   gd_cave_map_free(cave->map);
1570
1571   // copy new map to cave
1572   cave->map = gd_cave_map_dup(rendered, map);
1573   gd_cave_free(rendered);
1574
1575   // forget objects
1576   list_foreach(cave->objects, (list_fn) free, NULL);
1577   cave->objects = NULL;
1578 }