Fix error message when SDL_ttf is not present.
[attac-man.git] / shot.c
bloba22e67d6227156bb00caede58d933edfe444a7df
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: shot.c,v 1.15 2003/11/22 17:32:10 nsubtil Exp $";
23 #ifdef _WIN32
24 #include <windows.h>
25 #endif
27 #include <GL/gl.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
32 #include "game.h"
33 #include "player.h"
34 #include "ghost.h"
35 #include "map.h"
36 #include "render.h"
37 #include "m_math.h"
38 #include "object.h"
39 #include "particle.h"
40 #include "audio.h"
42 #include "shot.h"
44 void shot_new(struct game *game, int owner, int shot_type, float speed)
46 float p_direction[3], p_speed[3], p_color[3] = {1.0, 1.0, 1.0};
47 struct shot *new;
49 game->shots = realloc(game->shots, sizeof(struct shot) * (game->n_shots + 1));
50 new = &game->shots[game->n_shots];
51 game->n_shots++;
53 new->owner = owner;
54 new->type = shot_type;
55 new->time = 0.0;
56 new->speed = speed;
57 new->position[X] = game->players[owner].position[X];
58 new->position[Y] = game->players[owner].position[Y];
59 new->position[Z] = game->players[owner].position[Z];
60 new->position[W] = 1.0;
61 new->direction = game->players[owner].direction;
62 new->state = SHOT_STATE_ACTIVE;
64 switch(shot_type)
66 case SHOT_TYPE_ROCKET:
67 new->model = object_read_file("gfx/rocket.3d", &new->frames);
68 switch(new->direction)
70 case DIRECTION_UP:
71 p_speed[X] = 0.0;
72 p_speed[Y] = 0.0;
73 p_speed[Z] = 1.0;
75 p_direction[X] = 0.0;
76 p_direction[Y] = 0.0;
77 p_direction[Z] = -1.0;
78 break;
80 case DIRECTION_DOWN:
81 p_speed[X] = 0.0;
82 p_speed[Y] = 0.0;
83 p_speed[Z] = -1.0;
85 p_direction[X] = 0.0;
86 p_direction[Y] = 0.0;
87 p_direction[Z] = 1.0;
88 break;
90 case DIRECTION_LEFT:
91 p_speed[X] = -1.0;
92 p_speed[Y] = 0.0;
93 p_speed[Z] = 0.0;
95 p_direction[X] = 1.0;
96 p_direction[Y] = 0.0;
97 p_direction[Z] = 0.0;
98 break;
100 case DIRECTION_RIGHT:
101 p_speed[X] = 1.0;
102 p_speed[Y] = 0.0;
103 p_speed[Z] = 0.0;
105 p_direction[X] = -1.0;
106 p_direction[Y] = 0.0;
107 p_direction[Z] = 0.0;
108 break;
111 math_len_vec3(p_speed, p_speed, new->speed);
113 new->particle_trail = particle_new_src(0.5, /* particle life time */
114 1.2, /* particle fade time */
115 200.0, /* particle gen. rate */
116 1.0, /* particle size */
117 new->position, /* fountain position */
118 p_direction, /* emission direction */
119 p_speed, /* fountain speed */
120 0.2, /* radial spread */
121 1.0, /* particle speed */
122 0.005, /* particle speed spread */
123 -2.0, /* particle gravity */
124 p_color); /* particle color */
126 audio_play_sample("sfx/rocket-launch.wav");
129 new->light_src = light_new();
130 light_defaults(new->light_src);
131 new->light_src->linked_position = new->position;
133 MATH_SET_VEC4(new->light_src->ambient, 0.0, 0.0, 0.0, 1.0);
134 MATH_SET_VEC4(new->light_src->diffuse, 1.0, 1.0, 1.0, 1.0);
135 MATH_SET_VEC4(new->light_src->specular, 1.0, 1.0, 1.0, 1.0);
136 MATH_SET_VEC3(new->light_src->attn, 15.0, 15.0, 15.0);
137 new->light_src->spot_exponent = 64.0;
139 break;
140 default:
141 new->particle_trail = NULL;
145 void shot_kill(struct game *game, int shot_no, float delta)
147 struct shot *shot;
149 shot = &game->shots[shot_no];
151 if(shot->particle_trail)
153 shot->state = SHOT_STATE_DEAD;
154 MATH_COPY_VEC3(shot->particle_trail->position, shot->position);
155 shot->particle_trail->particle_rate = 0.0;
156 particle_src_explode(shot->particle_trail, 150 + (int)(shot->speed * shot->speed),
157 1.0 + shot->speed / 2.0);
160 shot->light_src = light_new();
161 light_defaults(shot->light_src);
163 MATH_COPY_VEC4(shot->light_src->position, shot->position);
164 MATH_SET_VEC4(shot->light_src->ambient, 0.0, 0.0, 0.0, 1.0);
165 MATH_SET_VEC4(shot->light_src->diffuse, 1.0, 0.1, 0.1, 1.0);
166 MATH_SET_VEC4(shot->light_src->specular, 1.0, 0.1, 0.1, 1.0);
167 shot->light_src->spot_exponent = 64.0;
168 MATH_SET_VEC3(shot->light_src->attn, 0.0, 0.0, 10.0);
170 audio_play_sample("sfx/explosion.wav");
171 } else
172 shot_remove(game, shot_no);
175 void shot_remove(struct game *game, int shot_no)
177 particle_free_src(game->shots[shot_no].particle_trail);
178 /* light_release(game->shots[shot_no].light_src);*/
179 memmove(&game->shots[shot_no], &game->shots[shot_no + 1], (game->n_shots - shot_no) * sizeof(struct shot));
180 game->n_shots--;
181 game->shots = realloc(game->shots, game->n_shots * sizeof(struct shot));
184 void shot_update(struct game *game, int shot_no, float delta)
186 struct shot *shot;
187 float new_position[3];
188 int old_tile[2], new_tile[2];
189 int c;
192 shot = &game->shots[shot_no];
194 if(shot->state == SHOT_STATE_DEAD)
196 if(shot->particle_trail)
198 particle_src_update(game, shot->particle_trail, delta);
200 if(shot->light_src)
202 math_scale_vec3(shot->light_src->diffuse, 0.95, shot->light_src->diffuse);
203 math_scale_vec3(shot->light_src->specular, 0.95, shot->light_src->specular);
206 if(particle_src_all_dead(shot->particle_trail))
207 shot_remove(game, shot_no);
208 } else
209 shot_remove(game, shot_no);
211 return;
214 shot->time += delta;
216 old_tile[X] = (int)shot->position[X];
217 old_tile[Y] = (int)shot->position[Z];
219 new_position[Y] = shot->position[Y];
221 switch(shot->direction)
223 case DIRECTION_UP:
224 new_position[X] = shot->position[X];
225 new_position[Z] = shot->position[Z] + delta * shot->speed;
226 break;
228 case DIRECTION_DOWN:
229 new_position[X] = shot->position[X];
230 new_position[Z] = shot->position[Z] - delta * shot->speed;
231 break;
233 case DIRECTION_LEFT:
234 new_position[Z] = shot->position[Z];
235 new_position[X] = shot->position[X] - delta * shot->speed;
236 break;
238 case DIRECTION_RIGHT:
239 new_position[Z] = shot->position[Z];
240 new_position[X] = shot->position[X] + delta * shot->speed;
241 break;
243 default:
244 printf("invalid shot direction %d\n", shot->direction);
245 exit(1);
248 new_tile[X] = (int)new_position[X];
249 new_tile[Y] = (int)new_position[Z];
251 if(new_tile[X] < 0 || new_tile[X] >= game->map->width ||
252 new_tile[Y] < 0 || new_tile[Y] >= game->map->height)
254 /* shot went out of map */
255 MATH_COPY_VEC3(shot->position, new_position);
256 shot_kill(game, shot_no, delta);
257 return;
260 /* check for collisions with walls along the way from old_tile to new_tile */
261 switch(shot->direction)
263 case DIRECTION_UP:
264 for(c = old_tile[Y]; c <= new_tile[Y]; c++)
265 if(MAP(game->map, old_tile[X], c).wall != MAP_WALL_NONE)
267 /* boom! (old_tile[X], c) */
268 MATH_SET_VEC3(shot->position,
269 (float)old_tile[X] + 0.5,
270 shot->position[Y],
271 (float)c + 0.5 - 0.5);
272 shot_kill(game, shot_no, delta);
273 return;
275 break;
277 case DIRECTION_DOWN:
278 for(c = old_tile[Y]; c >= new_tile[Y]; c--)
279 if(MAP(game->map, old_tile[X], c).wall != MAP_WALL_NONE)
281 /* boom! (old_tile[X], c) */
282 MATH_SET_VEC3(shot->position,
283 (float)old_tile[X] + 0.5,
284 shot->position[Y],
285 (float)c + 0.5 + 0.5);
286 shot_kill(game, shot_no, delta);
287 return;
289 break;
291 case DIRECTION_LEFT:
292 for(c = old_tile[X]; c >= new_tile[X]; c--)
293 if(MAP(game->map, c, old_tile[Y]).wall != MAP_WALL_NONE)
295 /* boom! (c, old_tile[Y]) */
296 MATH_SET_VEC3(shot->position,
297 (float)c + 0.5 + 0.5,
298 shot->position[Y],
299 (float)old_tile[Y] + 0.5);
300 shot_kill(game, shot_no, delta);
301 return;
303 break;
305 case DIRECTION_RIGHT:
306 for(c = old_tile[X]; c <= new_tile[X]; c++)
307 if(MAP(game->map, c, old_tile[Y]).wall != MAP_WALL_NONE)
309 /* boom! (c, old_tile[Y]) */
310 MATH_SET_VEC3(shot->position,
311 (float)c + 0.5 - 0.5,
312 shot->position[Y],
313 (float)old_tile[Y] + 0.5);
314 shot_kill(game, shot_no, delta);
315 return;
317 break;
320 /* no collisions with walls, check collisions with ghosts */
321 for(c = 0; c < game->n_ghosts; c++)
323 float vec[3];
325 math_sub_vec3(vec, game->ghosts[c].position, new_position);
326 if(math_norm_vec3(vec) < 0.7)
328 /* boom! hit ghost c */
329 if(game->ghosts[c].state == GHOST_STATE_ACTIVE)
331 ghost_kill(game, &game->ghosts[c]);
332 MATH_COPY_VEC3(shot->position, game->ghosts[c].position);
333 shot_kill(game, shot_no, delta);
334 return;
339 /* collisions with players */
340 for(c = 0; c < game->n_players; c++)
342 float vec[3];
344 if(c == shot->owner)
345 /* do not damage self */
346 continue;
348 math_sub_vec3(vec, game->players[c].position, new_position);
349 if(math_norm_vec3(vec) < 0.7)
351 /* hit player c */
352 player_kill(game, c);
353 MATH_COPY_VEC3(shot->position, game->players[c].position);
354 shot_kill(game, shot_no, delta);
355 return;
359 MATH_COPY_VEC3(shot->position, new_position);
360 particle_src_update(game, shot->particle_trail, delta);
362 if(shot->type == SHOT_TYPE_ROCKET)
364 float tmp[3];
366 math_len_vec3(tmp, shot->particle_trail->src_speed, 1.0);
367 math_scale_vec3(tmp, 10.0 * delta, tmp);
368 math_add_vec3(shot->particle_trail->src_speed, shot->particle_trail->src_speed, tmp);
370 shot->speed += 10.0 * delta;
371 shot->particle_trail->particle_rate += 20.0 * delta;