Fix error message when SDL_ttf is not present.
[attac-man.git] / map.c
blobe1451d5ca174cc77943047cdd326fc1c2b2af7a1
1 /*
2 Pacman Arena
3 Copyright (C) 2003 Nuno Subtil
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 static const char cvsid[] =
21 "$Id: map.c,v 1.47 2003/11/22 17:32:09 nsubtil Exp $";
23 #ifdef _WIN32
24 #include <windows.h>
25 #endif
27 #include <SDL.h>
28 #include <GL/gl.h>
29 #include <GL/glu.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <stdio.h>
33 #include <math.h>
35 #include "object.h"
36 #include "game.h"
37 #include "player.h"
38 #include "render.h"
39 #include "gfx.h"
40 #include "m_math.h"
41 #include "shot.h"
43 #include "map.h"
45 struct map *map_load_from_ascii(char **game_map, char **ghost_map, int width, int height)
47 struct map *ret;
48 int x, y;
50 ret = (struct map *)malloc(sizeof(struct map));
51 ret->width = width;
52 ret->height = height;
54 ret->tiles = (struct map_tile **)malloc(sizeof(struct map_tile *) * height);
55 for(y = 0; y < height; y++)
57 ret->tiles[y] = malloc(strlen(game_map[y]) * sizeof(struct map_tile));
59 for(x = 0; x < width ; x++)
61 switch(game_map[height - 1 - y][x])
63 case 'L':
64 MAP(ret, x, y).wall = MAP_WALL_UL;
65 MAP(ret, x, y).content = MAP_CONTENT_NONE;
66 MAP(ret, x, y).flags = MAP_FLAGS_NONE;
67 MAP(ret, x, y).ghost_dir_alive = DIRECTION_NONE;
68 break;
70 case 'l':
71 MAP(ret, x, y).wall = MAP_WALL_LL;
72 MAP(ret, x, y).content = MAP_CONTENT_NONE;
73 MAP(ret, x, y).flags = MAP_FLAGS_NONE;
74 MAP(ret, x, y).ghost_dir_alive = DIRECTION_NONE;
75 break;
77 case 'R':
78 MAP(ret, x, y).wall = MAP_WALL_UR;
79 MAP(ret, x, y).content = MAP_CONTENT_NONE;
80 MAP(ret, x, y).flags = MAP_FLAGS_NONE;
81 MAP(ret, x, y).ghost_dir_alive = DIRECTION_NONE;
82 break;
84 case 'r':
85 MAP(ret, x, y).wall = MAP_WALL_LR;
86 MAP(ret, x, y).content = MAP_CONTENT_NONE;
87 MAP(ret, x, y).flags = MAP_FLAGS_NONE;
88 MAP(ret, x, y).ghost_dir_alive = DIRECTION_NONE;
89 break;
91 case '-':
92 MAP(ret, x, y).wall = MAP_WALL_HORIZONTAL;
93 MAP(ret, x, y).content = MAP_CONTENT_NONE;
94 MAP(ret, x, y).flags = MAP_FLAGS_NONE;
95 MAP(ret, x, y).ghost_dir_alive = DIRECTION_NONE;
96 break;
98 case '|':
99 MAP(ret, x, y).wall = MAP_WALL_VERTICAL;
100 MAP(ret, x, y).content = MAP_CONTENT_NONE;
101 MAP(ret, x, y).flags = MAP_FLAGS_NONE;
102 MAP(ret, x, y).ghost_dir_alive = DIRECTION_NONE;
103 break;
105 case ' ':
106 MAP(ret, x, y).wall = MAP_WALL_GHOST_ONLY;
107 MAP(ret, x, y).content = MAP_CONTENT_NONE;
108 MAP(ret, x, y).flags = MAP_FLAGS_NONE;
109 MAP(ret, x, y).ghost_dir_alive = DIRECTION_NONE;
110 break;
112 case 'U':
113 MAP(ret, x, y).wall = MAP_WALL_GHOST_ONLY;
114 MAP(ret, x, y).content = MAP_CONTENT_NONE;
115 MAP(ret, x, y).flags = MAP_FLAGS_NONE;
116 MAP(ret, x, y).ghost_dir_alive = DIRECTION_UP;
117 break;
119 case '1':
120 MAP(ret, x, y).wall = MAP_WALL_NONE;
121 MAP(ret, x, y).content = MAP_CONTENT_TELEPORT;
122 /* XXX - ugly, terrible hack, don't look! */
123 MAP(ret, x, y).c_data.teleport.dest_x = 0;
124 MAP(ret, x, y).c_data.teleport.dest_y = y;
125 MAP_TELEPORT(ret, x, y).direction = DIRECTION_RIGHT;
126 /* it is safe to look again now */
127 MAP(ret, x, y).flags = MAP_FLAGS_NONE;
128 MAP(ret, x, y).ghost_dir_alive = DIRECTION_LEFT;
129 break;
131 case '0':
132 MAP(ret, x, y).wall = MAP_WALL_NONE;
133 MAP(ret, x, y).content = MAP_CONTENT_TELEPORT;
134 /* XXX - close your eyes... */
135 MAP(ret, x, y).c_data.teleport.dest_x = ret->width - 1;
136 MAP(ret, x, y).c_data.teleport.dest_y = y;
137 MAP_TELEPORT(ret, x, y).direction = DIRECTION_LEFT;
139 MAP(ret, x, y).flags = MAP_FLAGS_NONE;
140 MAP(ret, x, y).ghost_dir_alive = DIRECTION_RIGHT;
141 break;
143 case '.':
144 MAP(ret, x, y).wall = MAP_WALL_NONE;
145 MAP(ret, x, y).content = MAP_CONTENT_FOOD;
146 MAP(ret, x, y).c_data.food.type = FOOD_TYPE_NORMAL;
147 MAP(ret, x, y).c_data.food.status = FOOD_STATUS_ACTIVE;
148 MAP(ret, x, y).flags = MAP_FLAGS_NONE;
149 MAP(ret, x, y).ghost_dir_alive = DIRECTION_NONE;
150 break;
152 case '*':
153 MAP(ret, x, y).wall = MAP_WALL_NONE;
154 MAP(ret, x, y).content = MAP_CONTENT_PILL;
155 MAP(ret, x, y).c_data.pill.status = PILL_STATUS_ACTIVE;
156 MAP(ret, x, y).c_data.pill.phase =
157 2.0 * M_PI * (float)((rand() % 10) / 9.0);
158 MAP(ret, x, y).flags = MAP_FLAGS_NONE;
159 MAP(ret, x, y).ghost_dir_alive = DIRECTION_NONE;
160 break;
162 case 'G':
163 MAP(ret, x, y).wall = MAP_WALL_GHOST_ONLY;
164 MAP(ret, x, y).content = MAP_CONTENT_NONE;
165 MAP(ret, x, y).flags = MAP_FLAG_GHOST_START_POSITION;
166 MAP(ret, x, y).ghost_dir_alive = DIRECTION_NONE;
167 break;
169 case 'S':
170 MAP(ret, x, y).wall = MAP_WALL_NONE;
171 MAP(ret, x, y).content = MAP_CONTENT_NONE;
172 MAP(ret, x, y).flags = MAP_FLAG_PACMAN_START_POSITION;
173 MAP(ret, x, y).ghost_dir_alive = DIRECTION_NONE;
174 break;
176 default:
177 printf("map_load_from_ascii: ora portantos temos aqui um %d... (y %d, x %d, w %d, h %d)\n", game_map[height - 1 - y][x], y, x, width, height);
178 exit(1);
179 break;
182 if(ghost_map == NULL)
183 MAP(ret, x, y).ghost_dir = DIRECTION_NONE;
184 else
185 switch(ghost_map[height - 1 - y][x])
187 case 'U':
188 MAP(ret, x, y).ghost_dir = DIRECTION_UP;
189 break;
191 case 'D':
192 MAP(ret, x, y).ghost_dir = DIRECTION_DOWN;
193 break;
195 case 'L':
196 MAP(ret, x, y).ghost_dir = DIRECTION_LEFT;
197 break;
199 case 'R':
200 MAP(ret, x, y).ghost_dir = DIRECTION_RIGHT;
201 break;
203 default:
204 MAP(ret, x, y).ghost_dir = DIRECTION_NONE;
205 break;
210 return ret;
213 void map_free(struct map *map)
215 int c;
217 for(c = 0; c < map->height; c++)
218 free(map->tiles[c]);
220 free(map->tiles);
221 free(map);
224 void map_update(struct map *map, float delta)
226 int x, y;
228 for(x = 0; x < map->width; x++)
229 for(y = 0; y < map->height; y++)
231 switch(MAP(map, x, y).content)
233 case MAP_CONTENT_FOOD:
234 /* update food */
235 switch(MAP_FOOD(map, x, y).type)
237 case FOOD_TYPE_RESPAWN:
238 if(MAP_FOOD(map, x, y).status == FOOD_STATUS_EATEN)
240 MAP_FOOD(map, x, y).time -= delta;
241 if(MAP_FOOD(map, x, y).time <= 0.0)
242 MAP_FOOD(map, x, y).status =
243 FOOD_STATUS_ACTIVE;
246 break;
248 case FOOD_TYPE_INTERMITTENT:
249 MAP_FOOD(map, x, y).time -= delta;
250 if(MAP_FOOD(map, x, y).time <= 0.0)
252 switch(MAP_FOOD(map, x, y).status)
254 case FOOD_STATUS_ACTIVE:
255 MAP_FOOD(map, x, y).status =
256 FOOD_STATUS_EATEN;
257 MAP_FOOD(map, x, y).time =
258 MAP_FOOD(map, x, y).inactive_time;
259 break;
261 case FOOD_STATUS_EATEN:
262 MAP_FOOD(map, x, y).status =
263 FOOD_STATUS_ACTIVE;
264 MAP_FOOD(map, x, y).time =
265 MAP_FOOD(map, x, y).active_time;
266 break;
274 int map_collision_square(struct game *game, int x, int y)
276 struct map *map;
278 map = game->map;
280 if(MAP(map, x, y).wall == MAP_WALL_NONE ||
281 MAP(map, x, y).wall == MAP_WALL_GHOST_ONLY)
282 return 0;
284 return 1;
288 detects collisions on the map along a line between two points
289 returns 0 if no collision is detected or 1 with the tile where collision occurs in ret
291 int map_detect_collision(struct game *game, float start_pos[3], float end_pos[3], int ret[2])
293 /* bresenham line algorithm with extended coverage */
294 /* http://www.ese-metz.fr/~dedu/projects/bresenham/ */
295 /* XXX - is this even correct ? the original doesn't look very good */
296 int c, step_x, step_y, error;//, last_error;
297 int end[2];
298 int x, y, dx, dy, ddx, ddy;
300 /* for 3d collisions */
301 float h, step_h, dist, tmp[3];
303 end[X] = (int)end_pos[X];
304 end[Y] = (int)end_pos[Z];
306 x = (int)start_pos[X];
307 y = (int)start_pos[Z];
309 math_sub_vec3(tmp, end_pos, start_pos);
310 dist = math_norm_vec3(tmp);
311 h = start_pos[Y];
312 step_h = tmp[Y] / dist;
314 dx = end[X] - x;
315 dy = end[Y] - y;
317 /* check first point */
318 if(x < 0 || x >= game->map->width ||
319 y < 0 || y >= game->map->height)
320 return 0;
322 if(h > -1.0 && map_collision_square(game, x, y))
324 /* collision at x, y */
325 ret[X] = x;
326 ret[Y] = y;
327 return 1;
330 if(dy < 0)
332 step_y = -1;
333 dy = -dy;
334 } else
335 step_y = 1;
337 if(dx < 0)
339 step_x = -1;
340 dx = -dx;
341 } else
342 step_x = 1;
344 ddx = 2 * dx;
345 ddy = 2 * dy;
347 if(ddx >= ddy)
349 // last_error = dx;
350 error = dx;
352 for(c = 0; c < dx; c++)
354 x += step_x;
355 error += ddy;
357 h += step_h;
358 if(h < -1.0 && step_h < 0.0)
359 /* gone over the map, no collision possible */
360 return 0;
362 if(error > ddx)
364 y += step_y;
365 error -= ddx;
366 #if 0
367 if(error + last_error < ddx)
369 if(h > -1.0 &&
370 map_collision_square(game, x, y - step_y))
372 /* collision at x, y - step_y */
373 ret[X] = x;
374 ret[Y] = y - step_y;
375 return 1;
377 } else {
378 if(error + last_error > ddx)
380 if(h > -1.0 &&
381 map_collision_square(game, x - step_x, y))
383 /* collision at x - step_x, y */
384 ret[X] = x - step_x;
385 ret[Y] = y;
386 return 1;
388 } else {
389 if(h > -1.0 &&
390 map_collision_square(game, x, y - step_y))
392 ret[X] = x;
393 ret[Y] = y - step_y;
394 return 1;
397 if(h > -1.0 &&
398 map_collision_square(game, x - step_x, y))
400 ret[X] = x - step_x;
401 ret[Y] = y;
402 return 1;
406 #endif
409 if(x < 0 || x >= game->map->width ||
410 y < 0 || y >= game->map->height)
411 return 0;
413 if(h > -1.0 && map_collision_square(game, x, y))
415 ret[X] = x;
416 ret[Y] = y;
417 return 1;
420 } else {
421 // last_error = dy;
422 error = dy;
424 for(c = 0; c < dy; c++)
426 y += step_y;
427 error += ddx;
429 h += step_h;
430 if(h < -1.0 && step_h < 0.0)
431 /* gone over the map, no collision possible */
432 return 0;
434 if(error > ddy)
436 x += step_x;
437 error = -ddy;
438 #if 0
439 if(error + last_error < ddy)
441 if(h > -1.0 &&
442 map_collision_square(game, x - step_x, y))
444 ret[X] = x - step_x;
445 ret[Y] = y;
446 return 1;
448 } else {
449 if(error + last_error > ddy)
451 if(h > -1.0 &&
452 map_collision_square(game, x, y - step_y))
454 ret[X] = x;
455 ret[Y] = y - step_y;
456 return 1;
458 } else {
459 if(h > -1.0 &&
460 map_collision_square(game, x - step_x, y))
462 ret[X] = x - step_x;
463 ret[Y] = y;
464 return 1;
467 if(h > -1.0 &&
468 map_collision_square(game, x, y - step_y))
470 ret[X] = x;
471 ret[Y] = y - step_y;
472 return 1;
476 #endif
479 if(x < 0 || x >= game->map->width ||
480 y < 0 || y >= game->map->height)
481 return 0;
483 if(h > -1.0 &&
484 map_collision_square(game, x, y))
486 ret[X] = x;
487 ret[Y] = y;
488 return 1;
493 return 0;
496 int map_inside(struct game *game, int x, int y)
498 if(x < 0 || x > game->map->width ||
499 y < 0 || y > game->map->height)
500 return 0;
502 return 1;