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