1 /* $Id: map.c,v 1.28 2009-05-11 20:51:25 stpohle Exp $ */
2 /* map handling, like generate and load maps. */
3 
4 #include "bomberclone.h"
5 #include "player.h"
6 
7 _map map;
8 
9 // put the special items into the field
10 void
map_fillitems(int fieldtype,int num)11 map_fillitems (int fieldtype, int num)
12 {
13     int nb_try = 100,
14         d,
15         x,
16         y;
17     /* this is the item factor we multiply it with this so we know
18        how much items we want in the game */
19     float fkt = ((float) (map.size.x * map.size.y)) / (25.0 * 17.0);
20 
21     for (d = 0; d < num * fkt; d++) {
22         x = y = 0;
23         while (map.field[x][y].type != FT_stone && map.field[x][y].special != FT_nothing) {
24             x = ((float) rand () / (float) RAND_MAX) * (map.size.x - 1);
25             y = ((float) rand () / (float) RAND_MAX) * (map.size.y - 1);
26             nb_try--;
27             if (nb_try < 0)
28                 break;
29         }
30         if (map.field[x][y].type != FT_tunnel)
31             map.field[x][y].special = fieldtype;
32     }
33 }
34 
35 
36 // loads or generate an map
37 void
map_new(char * filename)38 map_new (char *filename)
39 {
40     int x,
41       y;
42     FILE *fmap;
43     signed char old_maptype = map.type;
44     int pl_cnt, pl;
45 
46     /* initialize the start_point array in the _map struct */
47 
48     map_init_start_points();
49 
50     if (filename) {
51         fmap = fopen (filename, "r");
52 
53         /* if we can't open the given filename for any reason, reverting
54            to default value else, load the file map */
55         if (fmap)
56             map_load (fmap);
57     }
58     else
59         fmap = NULL;
60 
61     // Clean and create the field //
62     if (fmap == NULL)
63 		map_genrandom ();
64 
65 	/* Generate a More random map if requested */
66     if (map.map_selection == MAPS_morerand)
67         map_genmorerandom();
68 
69     if (map.type == -1)
70         map.type = s_random (MAPT_max);
71 
72     if (map.type == MAPT_tunnel) {
73         /* insert tunnels */
74         for (x = 0; x < GAME_MAX_TUNNELS; x++)
75             map.tunnel[x].x = map.tunnel[x].y = -1;
76         map.field[3][3].type = FT_tunnel;
77         map.field[3][3].special = 0;
78         map.field[map.size.x - 4][map.size.y - 4].type = FT_tunnel;
79         map.field[map.size.x - 4][map.size.y - 4].special = 1;
80 
81         if (map.size.y > 12) {
82             map.field[map.size.x - 4][3].type = FT_tunnel;
83             map.field[map.size.x - 4][3].special = 2;
84             map.field[3][map.size.y - 4].type = FT_tunnel;
85             map.field[3][map.size.y - 4].special = 3;
86 
87             map.tunnel[0].x = map.size.x - 4;
88             map.tunnel[0].y = 3;
89             map.tunnel[1].x = 3;
90             map.tunnel[1].y = map.size.y - 4;
91             map.tunnel[2].x = map.size.x - 4;
92             map.tunnel[2].y = map.size.y - 4;
93             map.tunnel[3].x = 3;
94             map.tunnel[3].y = 3;
95         }
96         else {
97             map.tunnel[0].x = map.size.x - 4;
98             map.tunnel[0].y = map.size.y - 4;
99             map.tunnel[1].x = 3;
100             map.tunnel[1].y = 3;
101         }
102     }
103 
104 
105     /* delete the bfield data */
106     for (x = 0; x < MAX_FIELDSIZE_X; x++)
107         for (y = 0; y < MAX_FIELDSIZE_Y; y++)
108             map.bfield[x][y] = 0;
109 
110     /* count the number of players on this map so we know how many starting points
111      * to find
112      */
113 
114     pl_cnt = 0;
115     for (pl = 0; pl < MAX_PLAYERS; pl++) {
116         if (PS_IS_used (players[pl].state)) {
117             pl_cnt++;
118         }
119     }
120 
121 
122     /* identify possible starting positions for players and store them in the
123      * start_point array in the _map struct.  This will always succeed.  If
124      * it cannot find starting points within the tolerance, it first attempts
125      * to create start points within the tolerence and otherwise lowers the
126      * tolerence until it can satisfy the proper number of start points.
127      * eventually the tolerence reaches 0, so it can, in the worst case, start
128      * all players at the same start point.
129      */
130 
131     map_find_and_add_start_points(pl_cnt - map_num_defined_start_points(), MAP_POSITION_TOLERENCE);
132 
133     /* Set the Playerinformation */
134     map_set_playerposition (fmap != NULL);
135 
136     /* put the fire powerups in the field */
137     map_fillitems (FT_fire, map.fire);
138     /* put the bomb powerups in the field */
139     map_fillitems (FT_bomb, map.bombs);
140     /* put the shoe powerup in the field */
141     map_fillitems (FT_shoe, map.shoes);
142     /* put the death ?powerups? in the field */
143     map_fillitems (FT_death, map.death);
144     /* put the mixed powerrup in the field */
145     map_fillitems (FT_mixed, map.mixed);
146     /* put the trigger special in the field */
147     map_fillitems (FT_sp_trigger, map.sp_trigger);
148     /* put the row special in the field */
149     map_fillitems (FT_sp_row, map.sp_row);
150     /* put the push special in the field */
151     map_fillitems (FT_sp_push, map.sp_push);
152     map_fillitems (FT_sp_liquid, map.sp_push);
153     map_fillitems (FT_sp_moved, map.sp_push);
154     /* put the push special in the field */
155 	map_fillitems(FT_sp_kick,map.sp_kick);
156 
157     map.type = old_maptype;
158 }
159 
160 void
map_genrandom()161 map_genrandom ()
162 {
163     int x,
164       y,
165       d;
166 
167     /* if we can't load the map check first the fieldsize settings */
168     if (map.size.x < MIN_FIELDSIZE_X)
169         map.size.x = MIN_FIELDSIZE_X;
170     if (map.size.x > MAX_FIELDSIZE_X)
171         map.size.x = MAX_FIELDSIZE_X;
172 
173     for (x = 0; x < map.size.x; x++)
174         for (y = 0; y < map.size.y; y++) {
175             if ((y == 0) || (y == map.size.y - 1))
176                 map.field[x][y].type = FT_block;
177             else if ((x == 0) || (x == map.size.x - 1))
178                 map.field[x][y].type = FT_block;
179             else if (((x & 1) == 0) && ((y & 1) == 0))
180                 map.field[x][y].type = FT_block;
181             else {
182                 // create random field
183                 if ((s_random (256) & 3) == 0)
184                     map.field[x][y].type = FT_nothing;
185                 else
186                     map.field[x][y].type = FT_stone;
187             }
188 
189             for (d = 0; d < 4; d++)
190                 map.field[x][y].ex[d].frame = map.field[x][y].ex[d].count = 0;
191             map.field[x][y].ex_nr = -1;
192             map.field[x][y].frame = 0.0f;
193             map.field[x][y].special = FT_nothing;
194         }
195 
196 	/* set the corners of the map to be valid start points */
197 
198 	// map_ensure_corner_start_points();
199 }
200 
201 void
map_genmorerandom()202 map_genmorerandom ()
203 {
204     int x,
205       y,
206       d,
207       ra;
208 
209     /* This is an enhanced version of genrandom() used by "more random" */
210     d_printf("genmorerandom: *** init ***\n");
211     /* if we can't load the map check first the fieldsize settings */
212     if (map.size.x < MIN_FIELDSIZE_X)
213         map.size.x = MIN_FIELDSIZE_X;
214     if (map.size.x > MAX_FIELDSIZE_X)
215         map.size.x = MAX_FIELDSIZE_X;
216 
217     for (x = 0; x < map.size.x; x++)
218         for (y = 0; y < map.size.y; y++) {
219             if ((y == 0) || (y == map.size.y - 1))
220                 map.field[x][y].type = FT_block;
221             else if ((x == 0) || (x == map.size.x - 1))
222                 map.field[x][y].type = FT_block;
223             else {
224                 // create random field
225                 ra = s_random (256) & 3;
226                 d_printf("genmorerandom: ra = %i\n", ra);
227 
228                 if (ra == 0)
229                     map.field[x][y].type = FT_nothing;
230                 else if (ra == 1)
231                     map.field[x][y].type = FT_block;
232                 else
233                     map.field[x][y].type = FT_stone;
234             }
235 
236             for (d = 0; d < 4; d++)
237                 map.field[x][y].ex[d].frame = map.field[x][y].ex[d].count = 0;
238             map.field[x][y].ex_nr = -1;
239             map.field[x][y].frame = 0.0f;
240             map.field[x][y].special = FT_nothing;
241         }
242 
243 	d_printf("genmorerandom: *** exit ***\n");
244 	/* set the corners of the map to be valid start points */
245 
246 	// map_ensure_corner_start_points();
247 }
248 
249 
250 /* will set the playerposition but in a way that we won't start on a block */
251 /* i am just too lazy to write this all again and again */
252 void
map_set_playerposition(int usermap)253 map_set_playerposition (int usermap)
254 {
255     int pl;
256 
257 	d_printf ("map_set_playerposition\n");
258 
259     /* This is the new code that will set every player in a starting point
260      * It should never fail, but if it does, it will fall through to the old method
261      */
262 
263     for (pl = 0; pl < MAX_PLAYERS; pl++) {
264         if (PS_IS_used(players[pl].state)) {
265             map_place_player(pl);
266         }
267     }
268 }
269 
270 /* load a random map */
271 void
map_random()272 map_random ()
273 {
274     _direntry *destart,
275      *de,
276      *desel;
277     char path[LEN_PATHFILENAME];
278     int max,
279       sel;
280 
281     sprintf (path, "%s/maps", bman.datapath);
282     desel = destart = s_getdir (path);
283 
284     for (max = 0, de = destart; de != NULL; de = de->next)
285         if ((de->flags & DF_file) == DF_file)
286             max++;
287 
288     sel = s_random (max);
289     for (max = 0, de = destart; max <= sel && de != NULL; de = de->next)
290         if ((de->flags & DF_file) == DF_file) {
291             desel = de;
292             max++;
293         }
294 
295     d_printf ("Random Map %s (%d on %d)\n", desel->name, sel, max);
296 
297     if (desel != NULL)
298         sprintf (map.map, "%s/maps/%s", bman.datapath, desel->name);
299 }
300 
301 
302 // Init the game according to options
303 void
init_map_tileset()304 init_map_tileset ()
305 {
306 	if (GT_MP_PTPM || GT_SP) {
307 		switch (map.map_selection) {
308     		case (0):
309         		map_new (map.map);
310         		break;
311     		case (1):
312         		map_random ();
313         		map_new (map.map);
314         		break;
315     		case (2):
316         		map_new (NULL);
317             case (3):
318 				map_new (NULL); /* for more random */
319         	break;
320 		}
321 		if (map.random_tileset)
322     	   	tileset_random ();
323 	}
324 }
325 
326 
327 /* read from an open file map, determine field.x and field.y
328    and fill the field.
329    (# correspond to a bloc and @ correspond to a stone,
330     an espace is nothing ' '
331     % are commentary at the beginning of the map */
332 void
map_load(FILE * fmap)333 map_load (FILE * fmap)
334 {
335     size_t length;
336     char *currentline;
337     char tmp[MAX_FIELDSIZE_X];
338     int sizex = 0;
339     int sizey = 0;
340     int i;
341     int d;
342 
343     while ((currentline = fgets (tmp, MAX_FIELDSIZE_X, fmap))) {
344         length = strlen (currentline);
345         if (currentline[0] == '%')
346             continue;
347         /* now each line correspond to the field */
348         else if (strstr (currentline, "bombs") == currentline) // bombs
349             map.bombs = atoi (strchr (currentline, '=') + 1);
350         else if (strstr (currentline, "fire") == currentline) // fire
351             map.fire = atoi (strchr (currentline, '=') + 1);
352         else if (strstr (currentline, "shoes") == currentline) // shoes
353             map.shoes = atoi (strchr (currentline, '=') + 1);
354         else if (strstr (currentline, "mixed") == currentline) // mixed
355             map.mixed = atoi (strchr (currentline, '=') + 1);
356         else if (strstr (currentline, "death") == currentline) // death
357             map.death = atoi (strchr (currentline, '=') + 1);
358         else if (strstr (currentline, "sp_trigger") == currentline) // trigger special
359             map.sp_trigger = atoi (strchr (currentline, '=') + 1);
360         else if (strstr (currentline, "sp_push") == currentline) // push special
361             map.sp_push = atoi (strchr (currentline, '=') + 1);
362         else if (strstr (currentline, "sp_row") == currentline) // row special
363             map.sp_row = atoi (strchr (currentline, '=') + 1);
364         else if (currentline[0] == '#') { /* the map itself */
365             for (i = 0; i < length; i++) {
366                 switch (currentline[i]) {
367                 case '#':
368                     map.field[i][sizey].type = FT_block;
369                     break;
370                 case '@':
371                     map.field[i][sizey].type = FT_stone;
372                     break;
373                 case ' ':
374                     map.field[i][sizey].type = FT_nothing;
375                 default:
376                     break;
377                 }
378                 for (d = 0; d < 4; d++)
379                     map.field[i][sizey].ex[d].frame = map.field[i][sizey].ex[d].count = 0;
380                 map.field[i][sizey].ex_nr = -1;
381                 map.field[i][sizey].frame = 0.0f;
382                 map.field[i][sizey].special = FT_nothing;
383             }
384             sizey++;
385             if (sizex < length)
386                 sizex = length;
387         }
388     }
389 
390     map.size.x = sizex - 1;
391     map.size.y = sizey;
392 
393     /* darw the border so we know everything is right */
394     for (i = 0; i < map.size.x; i++)
395         map.field[i][0].type = map.field[i][map.size.y - 1].type = FT_block;
396     for (i = 0; i < map.size.y; i++)
397         map.field[0][i].type = map.field[map.size.x - 1][i].type = FT_block;
398 
399     fclose (fmap);
400 };
401 
402 
403 /* This is called for randomly generated maps.  It clears out each corner of the map
404  * to make sure that the 4 corners are legal start points.
405  */
406 
407 int
map_ensure_corner_start_points()408 map_ensure_corner_start_points ()
409 {
410 
411     /* make sure all the corners are empty as well as the 1 field in the Y direction
412      * and one in the X direction
413      */
414 
415     /* top left corner is safe start point */
416     map.field[1][1].type = FT_nothing;
417     map.field[1][2].type = FT_nothing;
418     map.field[2][1].type = FT_nothing;
419 
420     map_add_start_point(1, 1);
421 
422     /* bottom left corner is safe start point */
423     map.field[1][map.size.y - 2].type = FT_nothing;
424     map.field[1][map.size.y - 3].type = FT_nothing;
425     map.field[2][map.size.y - 2].type = FT_nothing;
426 
427     map_add_start_point(1, map.size.y - 2);
428 
429     /* top right corner is safe start point */
430     map.field[map.size.x - 2][1].type = FT_nothing;
431     map.field[map.size.x - 3][1].type = FT_nothing;
432     map.field[map.size.x - 2][2].type = FT_nothing;
433 
434     map_add_start_point(map.size.x - 2, 1);
435 
436     /* bottom right corner is safe start point */
437     map.field[map.size.x - 2][map.size.y - 2].type = FT_nothing;
438     map.field[map.size.x - 2][map.size.y - 3].type = FT_nothing;
439     map.field[map.size.x - 3][map.size.y - 2].type = FT_nothing;
440 
441     map_add_start_point(map.size.x - 2, map.size.y - 2);
442 
443     return 1;
444 }
445 
446 
447 /* initializes all the start points for the map to (-1,-1) and their used flag to 0 */
448 
449 int
map_init_start_points()450 map_init_start_points()
451 {
452     int i;
453 
454     for (i = 0; i < MAX_PLAYERS; i++) {
455         map.start_point[i].pos.x = -1;
456         map.start_point[i].pos.y = -1;
457         map.start_point[i].used = 0;
458     }
459 
460     return 0;
461 }
462 
463 /* blindly sets (x,y) as the idx'th start point in the map */
464 
465 int
map_set_start_point(int idx,int x,int y)466 map_set_start_point(int idx, int x, int y)
467 {
468     map.start_point[idx].pos.x = x;
469     map.start_point[idx].pos.y = y;
470     return idx;
471 }
472 
473 /* checks to see if all start points have been set, if not, sets (x,y) as a possible start point
474  * returns 0 on successful set, -1 on failure
475  */
476 
477 int
map_add_start_point(int x,int y)478 map_add_start_point(int x, int y)
479 {
480     int i;
481 
482     /* find the first unset start point */
483     for (i = 0; i < MAX_PLAYERS; i++) {
484 
485         if ((map.start_point[i].pos.x == -1) && (map.start_point[i].pos.y == -1)) {
486             map_set_start_point(i, x, y);
487             return 0;
488         }
489     }
490 
491     /* if all start points are already set, do nothing and return -1 */
492 
493     return -1;
494 }
495 
496 
497 /* returns 0 if (x,y) is not already set as a start point in the current map, nonzero otherwise */
498 
499 int
map_is_start_point(int x,int y)500 map_is_start_point(int x, int y)
501 {
502     int i;
503 
504     for (i = 0; i < MAX_PLAYERS; i++) {
505 
506         if ((map.start_point[i].pos.x == x) && (map.start_point[i].pos.y == y))
507             return 1;
508     }
509 
510     return 0;
511 }
512 
513 /* returns the number of start points set in the current map */
514 
515 int
map_num_defined_start_points()516 map_num_defined_start_points()
517 {
518     int pts = 0;
519     int i;
520 
521     for (i = 0; i < MAX_PLAYERS; i++) {
522 
523         if ((map.start_point[i].pos.x != -1) && (map.start_point[i].pos.y != -1))
524             pts++;
525     }
526 
527     return pts;
528 }
529 
530 
531 /* checks if the start point (x, y) is far enough away from all the other start points
532  * returns 1 if it is far enough, 0 otherwise
533  */
534 
535 int
map_check_start_point(int x,int y,int tol)536 map_check_start_point(int x, int y, int tol)
537 {
538     int i;
539     int dx, dy;
540     float dist;
541 
542     for (i = 0; i < MAX_PLAYERS; i++) {
543 
544         if ((map.start_point[i].pos.x != -1) && (map.start_point[i].pos.y != -1)) {
545 
546             dx = map.start_point[i].pos.x - x;
547             dy = map.start_point[i].pos.y - y;
548 
549             dist = sqrt(dx * dx + dy * dy);
550 
551             if (dist < tol)
552                 return 0;
553         }
554     }
555 
556     return 1;
557 }
558 
559 
560 /* checks to see if there is an available start point and if (x, y) is sufficiently far from all
561  * defined start points and adds (x, y) as a start point if the conditions are met.
562  * returns 1 on success, 0 on failure
563  */
564 
565 int
map_check_and_add_start_point(int x,int y,int tol)566 map_check_and_add_start_point(int x, int y, int tol)
567 {
568     if ((map_num_defined_start_points() < MAX_PLAYERS) && (map_check_start_point(x, y, tol))) {
569 
570         map_add_start_point(x, y);
571         return 1;
572     }
573 
574     return 0;
575 }
576 
577 
578 /* locates and adds num start points to the current map.  returns the number of start points added. */
579 
580 int
map_find_and_add_start_points(int num,int tol)581 map_find_and_add_start_points(int num, int tol)
582 {
583     int x;
584     int y;
585     int i;
586     int added = 0;
587 
588     while ((added < num) && (tol >= 0)) {
589         for (x = 0; x < map.size.x; x++) {
590 
591             for (y = 0; y < map.size.y; y++) {
592 
593                 if (map_is_possible_start_point(x, y)) {
594 
595                     added += map_check_and_add_start_point(x, y, tol);
596                 }
597             }
598         }
599 
600         for (i = 0; i < num - added; i++) {
601 
602             added += map_create_and_add_start_point(tol);
603         }
604 
605         tol--;
606     }
607 
608     /* printf("Minimum Tolerance: %d\n", tol + 1); */
609 
610     return added;
611 }
612 
613 /* returns 1 if (x,y) is a feasible start point such that the player can safely lay a bomb and not die
614  * otherwise returns 0.  Note: this is a quick check only checking immediately adjacent fields.  It will not
615  * check secondary adjacencies, however, the idea is that when looking for possible start poitns, it will be run
616  * on every FT_nothing field so it will catch the secondary adjacencies when they become primary adjacencies
617  */
618 
619 int
map_is_possible_start_point(int x,int y)620 map_is_possible_start_point(int x, int y)
621 {
622 
623     int x_ok_pos;
624     int x_ok_neg;
625     int y_ok_pos;
626     int y_ok_neg;
627 
628     int x_adj = 0;
629     int y_adj = 0;
630     int i;
631 
632     /* if (x, y) is not FT_nothing, this is not a valid start point */
633 
634     if (map.field[x][y].type != FT_nothing) {
635 
636         return 0;
637     }
638 
639     x_ok_pos = (x < map.size.x - 2) ? 1:0;
640     x_ok_neg = (x > 1) ? 1:0;
641 
642     y_ok_pos = (y < map.size.y - 2) ? 1:0;
643     y_ok_neg = (y > 1) ? 1:0;
644 
645     /* calculate the number of adjacent FT_nothing fields in the X and Y directions */
646 
647     for (i = 1; i < bman.start_range + 2; i++) {
648 
649         if (x_ok_pos) {
650 
651             if (map.field[x+i][y].type == FT_nothing) {
652 
653                 x_adj++;
654             } else {
655 
656                 x_ok_pos = 0;
657             }
658         }
659 
660         if (x_ok_neg) {
661 
662             if (map.field[x-i][y].type == FT_nothing) {
663 
664                 x_adj++;
665             } else {
666 
667                 x_ok_neg = 0;
668             }
669         }
670 
671         if (y_ok_pos) {
672 
673             if (map.field[x][y+i].type == FT_nothing) {
674 
675                 y_adj++;
676             } else {
677 
678                 y_ok_pos = 0;
679             }
680         }
681 
682         if (y_ok_neg) {
683 
684             if (map.field[x][y-i].type == FT_nothing) {
685 
686                 y_adj++;
687             } else {
688                 y_ok_neg = 0;
689             }
690         }
691     }
692 
693     if ((x_adj >= bman.start_range + 1) || (y_adj >= bman.start_range + 1)) {
694 
695         return 1;
696     }
697 
698     if ((x_adj >= 1) && (y_adj >= 1)) {
699 
700         return 1;
701     }
702 
703     return 0;
704 }
705 
706 
707 /* alters the map to create another start point at least tol units from any other
708  * start point.  returns 1 on success, 0 on failure
709  */
710 
711 int
map_create_and_add_start_point(int tol)712 map_create_and_add_start_point(int tol)
713 {
714     int x;
715     int y;
716     int dx;
717     int dy;
718 
719     int init_x;
720     int init_y;
721     int end_x;
722     int end_y;
723     int step_x;
724     int step_y;
725 
726     /* this changes how we traverse the map when looking for a place to put
727      * a start point.  this is so all the start points don't get stuck in one
728      * part of the map if the map is large enough
729      */
730 
731     if (s_random(100) % 2) {
732 
733         init_x = 0;
734         end_x = map.size.x;
735         step_x = 1;
736     } else {
737 
738         init_x = map.size.x - 1;
739         end_x = -1;
740         step_x = -1;
741     }
742 
743     if (s_random(100) % 2) {
744 
745         init_y = 0;
746         end_y = map.size.y;
747         step_y = 1;
748     } else {
749 
750         init_y = map.size.y - 1;
751         end_y = -1;
752         step_y = -1;
753     }
754 
755 
756     /* first try only FT_nothing fields as start points */
757 
758     for (x = init_x; x != end_x; x += step_x) {
759 
760         for (y = init_y; y != end_y; y+= step_y) {
761 
762             if ((map.field[x][y].type == FT_nothing) && (map_check_start_point(x, y, tol))) {
763 
764                 dx = (x >= map.size.x - 2) ? -1:1;
765                 dy = (y >= map.size.y - 2) ? -1:1;
766 
767                 if ((map_is_removable_field(x+dx, y)) && (map_is_removable_field(x, y+dy))) {
768 
769                     /* printf("Creating Start Point (%d, %d).\n", x, y); */
770 
771                     map.field[x][y].type = FT_nothing;
772 
773                     map.field[x+dx][y].type = FT_nothing;
774                     map.field[x][y+dy].type = FT_nothing;
775 
776                     map_add_start_point(x, y);
777 
778                     return 1;
779                 }
780             }
781         }
782     }
783 
784     /* if we get here we didn't find a useful FT_nothing field, so check the FT_stone
785      * fields
786      */
787 
788     for (x = init_x; x != end_x; x += step_x) {
789 
790         for (y = init_y; y != end_y; y+= step_y) {
791 
792             if ((map.field[x][y].type == FT_stone) && (map_check_start_point(x, y, tol))) {
793 
794                 dx = (x >= map.size.x - 2) ? -1:1;
795                 dy = (y >= map.size.y - 2) ? -1:1;
796 
797                 if ((map_is_removable_field(x+dx, y)) && (map_is_removable_field(x, y+dy))) {
798 
799                     /* printf("Creating Start Point (%d, %d).\n", x, y); */
800 
801                     map.field[x][y].type = FT_nothing;
802 
803                     map.field[x+dx][y].type = FT_nothing;
804                     map.field[x][y+dy].type = FT_nothing;
805 
806                     map_add_start_point(x, y);
807 
808                     return 1;
809                 }
810             }
811         }
812     }
813 
814     /* if we get to this point, we tried every field that we want to turn into a
815      * start point, so we return 0 indicating failure
816      */
817 
818     return 0;
819 }
820 
821 
822 /* checks the type of the field at (x, y).  if it is something we can remove without
823  * drastically altering the map (that is to say, not a FT_tunnel or FT_block) returns
824  * 1, returns 0 if this is not a field that we want to alter
825  */
826 
827 int
map_is_removable_field(int x,int y)828 map_is_removable_field(int x, int y)
829 {
830     if ((map.field[x][y].type == FT_nothing) || (map.field[x][y].type == FT_stone)) {
831 
832         return 1;
833     } else {
834 
835         return 0;
836     }
837 }
838 
839 
840 /* sets the players[pl] initial position to one of the start_points found in the map
841  * randomly selects the start point so the same players don't always start near each
842  * other
843  */
844 
845 int
map_place_player(int pl)846 map_place_player(int pl)
847 {
848     int index;
849     int start_points;
850     int idx;
851     int i;
852 
853     start_points = map_num_defined_start_points();
854     index = (s_random(MAX_PLAYERS) + 1) % start_points;
855 
856     for (i = 0; i < start_points; i++) {
857 
858         idx = (index + i) % start_points;
859 
860         if ((!map.start_point[idx].used) && (map.start_point[idx].pos.x != -1)
861             && (map.start_point[idx].pos.y != -1)) {
862 
863             players[pl].pos.x = map.start_point[idx].pos.x;
864             players[pl].pos.y = map.start_point[idx].pos.y;
865             map.start_point[idx].used = 1;
866 
867             return 1;
868         }
869     }
870 
871     return 0;
872 }
873 
874 
875 /* this will randomly select a start point, check to see if it is a safe place to
876  * respawn the player, and then set their position.  It cannot fail unless there is
877  * no start point possible on the map (which would prevent the game from ever starting)
878  */
879 
880 /* note: this is not used yet, but could be used to respawn players instead of the old
881  * method
882  */
883 
884 int
map_respawn_player(int pl)885 map_respawn_player(int pl)
886 {
887     int x;
888     int y;
889 
890     do {
891 
892         x = s_random (map.size.x - 2) + 1;
893         y = s_random (map.size.y - 2) + 1;
894     } while (!map_is_possible_start_point(x, y));
895 
896     players[pl].pos.x = x;
897     players[pl].pos.y = y;
898 
899     return 1;
900 }
901