1 /* $Id: tenm_table.c,v 1.56 2003/08/31 12:34:01 oohara Exp $ */
2
3 #include <stdio.h>
4 /* malloc, atexit */
5 #include <stdlib.h>
6 /* errno */
7 #include <errno.h>
8 /* strerror */
9 #include <string.h>
10
11 #include "tenm_object.h"
12
13 #include "tenm_table.h"
14
15 static int table_size = 0;
16 static int table_draw_min_priority = 0;
17 static int table_draw_max_priority = -1;
18 static tenm_object **object_table = NULL;
19 static int *action_needed = NULL;
20
21 static void tenm_table_quit(void);
22
23 /* return 0 on success, 1 on error */
24 int
tenm_table_init(int size,int draw_min_priority,int draw_max_priority)25 tenm_table_init(int size, int draw_min_priority, int draw_max_priority)
26 {
27 int i;
28
29 /* sanity check */
30 if (draw_min_priority > draw_max_priority)
31 {
32 fprintf(stderr, "tenm_table_init: draw_min_priority > "
33 "draw_max_priority\n");
34 /* this is a fatal error */
35 return 1;
36 }
37
38 if (object_table != NULL)
39 {
40 fprintf(stderr, "tenm_table_init: warning: object_table is not NULL,"
41 "freeing\n");
42 tenm_table_clear_all();
43 free(object_table);
44 object_table = NULL;
45 }
46 object_table = (tenm_object **) malloc(sizeof(tenm_object *) * size);
47 if (object_table == NULL)
48 {
49 fprintf(stderr, "tenm_table_init: malloc(object_table) failed\n");
50 tenm_table_quit();
51 return 1;
52 }
53
54 if (action_needed != NULL)
55 {
56 fprintf(stderr, "tenm_table_init: warning: action_needed is not NULL,"
57 "freeing\n");
58 free(action_needed);
59 action_needed = NULL;
60 }
61 action_needed = (int *) malloc(sizeof(int) * size);
62 if (action_needed == NULL)
63 {
64 fprintf(stderr, "tenm_table_init: malloc(action_needed) failed\n");
65 tenm_table_quit();
66 return 1;
67 }
68
69 errno = 0;
70 if (atexit(tenm_table_quit) != 0)
71 {
72 fprintf(stderr, "tenm_table_init: cannot register tenm_table_quit "
73 "to exit");
74 if (errno != 0)
75 fprintf(stderr, " (%s)", strerror(errno));
76 fprintf(stderr, "\n");
77 tenm_table_quit();
78 return 1;
79 }
80
81 table_size = size;
82 for (i = 0; i < size; i++)
83 {
84 object_table[i] = NULL;
85 action_needed[i] = 1;
86 }
87
88 table_draw_min_priority = draw_min_priority;
89 table_draw_max_priority = draw_max_priority;
90 return 0;
91 }
92
93 /* return the index of the table on success, -1 on error
94 */
95 int
tenm_table_add(tenm_object * object)96 tenm_table_add(tenm_object *object)
97 {
98 int i;
99 /* sanity check */
100 if (object == NULL)
101 {
102 fprintf(stderr, "tenm_table_add: object is NULL\n");
103 return -1;
104 }
105 if ((object_table == NULL) || (action_needed == NULL))
106 {
107 fprintf(stderr, "tenm_table_add: table is not initialized\n");
108 return -1;
109 }
110
111 for (i = 0; i < table_size; i++)
112 if (object_table[i] == NULL)
113 {
114 object->table_index = i;
115 object_table[i] = object;
116 action_needed[i] = 0;
117 return i;
118 }
119 fprintf(stderr, "tenm_table_add: no more space\n");
120 return -1;
121 }
122
123 void
tenm_table_delete(int i)124 tenm_table_delete(int i)
125 {
126 if (object_table == NULL)
127 return;
128 if (object_table[i] == NULL)
129 return;
130 if (action_needed == NULL)
131 return;
132
133 tenm_object_delete(object_table[i]);
134 object_table[i] = NULL;
135 action_needed[i] = 1;
136 }
137
138 void
tenm_table_clear_all(void)139 tenm_table_clear_all(void)
140 {
141 int i;
142
143 if (object_table == NULL)
144 return;
145
146 for (i = 0; i < table_size; i++)
147 if (object_table[i] != NULL)
148 tenm_table_delete(i);
149 }
150
151 /* return 1 if player is deleted, 0 if not */
152 int
tenm_table_move(tenm_object * player,int turn_per_frame)153 tenm_table_move(tenm_object *player, int turn_per_frame)
154 {
155 int i;
156 double tpf = (double) turn_per_frame;
157
158 /* sanity check */
159 if ((object_table == NULL) || (action_needed == NULL))
160 {
161 fprintf(stderr, "tenm_table_move: table is not initialized\n");
162 return 0;
163 }
164 if (turn_per_frame < 1)
165 {
166 fprintf(stderr, "tenm_table_move: strange turn_per_frame (%d)\n",
167 turn_per_frame);
168 return 0;
169 }
170
171 for (i = 0; i < table_size; i++)
172 {
173 if (object_table[i] == NULL)
174 continue;
175 if (object_table[i]->move == NULL)
176 continue;
177 if ((*(object_table[i]->move))(object_table[i], tpf))
178 tenm_table_delete(i);
179 }
180 if (player == NULL)
181 return 0;
182 if (player->move == NULL)
183 return 0;
184 if ((*(player->move))(player, tpf))
185 {
186 tenm_object_delete(player);
187 /* note that this "player" is a local variable */
188 player = NULL;
189 return 1;
190 }
191 return 0;
192 }
193
194
195 /* return 1 if player is deleted, 0 if not */
196 int
tenm_table_detect_collision(tenm_object * player)197 tenm_table_detect_collision(tenm_object *player)
198 {
199 int i;
200 int j;
201 int i_need_delete = 0;
202 int j_need_delete = 0;
203 int status = 0;
204
205 /* sanity check */
206 if ((object_table == NULL) || (action_needed == NULL))
207 {
208 fprintf(stderr, "tenm_table_detect_collision: table is not initialized\n");
209 return 0;
210 }
211
212 /* collision between objects */
213 for (i = 0; i < table_size; i++)
214 for (j = i + 1; j < table_size; j++)
215 {
216 if (object_table[i] == NULL)
217 continue;
218 if (object_table[j] == NULL)
219 continue;
220 /* no need to detect collision if there is nothing to do when
221 * they collide
222 */
223 if ((!(object_table[i]->hit_mask & object_table[j]->attr))
224 && (!(object_table[j]->hit_mask & object_table[i]->attr)))
225 continue;
226 if ((object_table[i]->hit == NULL) && (object_table[j]->hit == NULL))
227 continue;
228 if (object_table[i]->mass == NULL)
229 continue;
230 if (object_table[j]->mass == NULL)
231 continue;
232
233 if (! tenm_collided_mass(object_table[i]->mass, object_table[j]->mass))
234 continue;
235
236 i_need_delete = 0;
237 j_need_delete = 0;
238 if ((object_table[i] != NULL) && (object_table[j] != NULL)
239 && (object_table[i]->hit_mask & object_table[j]->attr))
240 if ((object_table[i]->hit != NULL)
241 && ((*(object_table[i]->hit))(object_table[i],
242 object_table[j]) != 0))
243 i_need_delete = 1;
244 /* we have to check if the objects are not NULL because
245 * hit() of object_table[i] may delete object_table[j]
246 * via tenm_table_apply()
247 */
248 if ((object_table[i] != NULL) && (object_table[j] != NULL)
249 && (object_table[j]->hit_mask & object_table[i]->attr))
250 if ((object_table[j]->hit != NULL)
251 && ((*(object_table[j]->hit))(object_table[j],
252 object_table[i]) != 0))
253 j_need_delete = 1;
254
255 if (i_need_delete)
256 tenm_table_delete(i);
257 if (j_need_delete)
258 tenm_table_delete(j);
259 }
260
261 /* collison between player and object */
262 for (i = 0; i < table_size; i++)
263 {
264 if (object_table[i] == NULL)
265 continue;
266 if (player == NULL)
267 continue;
268 /* no need to detect collision if there is nothing to do when
269 * they collide
270 */
271 if ((!(object_table[i]->hit_mask & player->attr))
272 && (!(player->hit_mask & object_table[i]->attr)))
273 continue;
274 if ((object_table[i]->hit == NULL) && (player->hit == NULL))
275 continue;
276 if (object_table[i]->mass == NULL)
277 continue;
278 if (player->mass == NULL)
279 continue;
280
281 if (! tenm_collided_mass(object_table[i]->mass, player->mass))
282 continue;
283
284 i_need_delete = 0;
285 j_need_delete = 0;
286 if ((object_table[i] != NULL) && (player != NULL)
287 && (object_table[i]->hit_mask & player->attr))
288 if ((object_table[i]->hit != NULL)
289 && ((*(object_table[i]->hit))(object_table[i], player) != 0))
290 i_need_delete = 1;
291 if ((object_table[i] != NULL) && (player != NULL)
292 && (player->hit_mask & object_table[i]->attr))
293 if ((player->hit != NULL)
294 && ((*(player->hit))(player, object_table[i]) != 0))
295 j_need_delete = 1;
296
297 if (i_need_delete)
298 tenm_table_delete(i);
299 if (j_need_delete)
300 {
301 tenm_object_delete(player);
302 /* note that this "player" is a local variable */
303 player = NULL;
304 status = 1;
305 }
306 }
307
308 return status;
309 }
310
311 /* return 1 if player is deleted, 0 if not */
312 int
tenm_table_do_action(tenm_object * player)313 tenm_table_do_action(tenm_object *player)
314 {
315 int i;
316
317 /* sanity check */
318 if ((object_table == NULL) || (action_needed == NULL))
319 {
320 fprintf(stderr, "tenm_table_do_action: table is not initialized\n");
321 return 0;
322 }
323
324 for (i = 0; i < table_size; i++)
325 {
326 if (object_table[i] == NULL)
327 continue;
328 if (object_table[i]->act == NULL)
329 continue;
330 if (action_needed[i] == 0)
331 continue;
332 if ((*(object_table[i]->act))(object_table[i], player) != 0)
333 tenm_table_delete(i);
334 }
335 if (player == NULL)
336 return 0;
337 if (player->act == NULL)
338 return 0;
339 if ((*(player->act))(player, NULL) != 0)
340 {
341 tenm_object_delete(player);
342 /* note that this "player" is a local variable */
343 player = NULL;
344 return 1;
345 }
346
347 for (i = 0; i < table_size; i++)
348 action_needed[i] = 1;
349
350 return 0;
351 }
352
353 /* return 0 on success, 1 on error */
354 int
tenm_table_draw(tenm_object * player)355 tenm_table_draw(tenm_object *player)
356 {
357 int i;
358 int j;
359 int status = 0;
360
361 /* sanity check */
362 if ((object_table == NULL) || (action_needed == NULL))
363 {
364 fprintf(stderr, "tenm_table_draw: table is not initialized\n");
365 return 0;
366 }
367
368 for (i = table_draw_min_priority; i <= table_draw_max_priority; i++)
369 {
370 if ((player != NULL) && (player->draw != NULL))
371 {
372 if ((*(player->draw))(player, i) != 0)
373 status = 1;
374 }
375
376 for (j = 0; j < table_size; j++)
377 {
378 if (object_table[j] == NULL)
379 continue;
380 if (object_table[j]->draw == NULL)
381 continue;
382 if ((*(object_table[j]->draw))(object_table[j], i) != 0)
383 status = 1;
384 }
385 }
386
387 return status;
388 }
389
390 void
tenm_table_apply(int i,int (* func)(tenm_object *,int),int n)391 tenm_table_apply(int i, int (*func)(tenm_object *, int), int n)
392 {
393 /* sanity check */
394 if ((object_table == NULL) || (action_needed == NULL))
395 {
396 fprintf(stderr, "tenm_table_apply: table is not initialized\n");
397 return;
398 }
399 if (func == NULL)
400 {
401 fprintf(stderr, "tenm_table_apply: func is NULL\n");
402 return;
403 }
404 if ((i < 0) || (i >= table_size))
405 {
406 fprintf(stderr, "tenm_table_apply: i (%d) is out of range (0 -- %d)\n",
407 i, table_size - 1);
408 return;
409 }
410
411 if (object_table[i] == NULL)
412 return;
413 if ((*func)(object_table[i], n) != 0)
414 tenm_table_delete(i);
415 }
416
417 void
tenm_table_apply_all(int (* func)(tenm_object *,int),int n)418 tenm_table_apply_all(int (*func)(tenm_object *, int), int n)
419 {
420 int i;
421
422 /* sanity check */
423 if ((object_table == NULL) || (action_needed == NULL))
424 {
425 fprintf(stderr, "tenm_table_apply_all: table is not initialized\n");
426 return;
427 }
428 if (func == NULL)
429 {
430 fprintf(stderr, "tenm_table_apply_all: func is NULL\n");
431 return;
432 }
433
434 for (i = 0; i < table_size; i++)
435 tenm_table_apply(i, (int (*)(tenm_object *, int)) func, n);
436 }
437
438 static void
tenm_table_quit(void)439 tenm_table_quit(void)
440 {
441 table_size = 0;
442 table_draw_min_priority = 0;
443 table_draw_max_priority = -1;
444
445 if (object_table != NULL)
446 {
447 tenm_table_clear_all();
448 free(object_table);
449 object_table = NULL;
450 }
451 if (action_needed != NULL)
452 {
453 free(action_needed);
454 action_needed = NULL;
455 }
456 }
457