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