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