1 /* $Id: loop.c,v 1.146 2009/11/10 18:55:36 oohara Exp $ */
2 
3 #include <stdio.h>
4 
5 #include "tenm_object.h"
6 #include "tenm_table.h"
7 #include "player.h"
8 #include "tenm_timer.h"
9 #include "tenm_input.h"
10 #include "const.h"
11 #include "tenm_graphic.h"
12 #include "background.h"
13 #include "scheduler.h"
14 #include "score.h"
15 #include "chain.h"
16 #include "stage.h"
17 #include "ship.h"
18 #include "stage-select.h"
19 #include "pause.h"
20 #include "result.h"
21 #include "esc-ok.h"
22 #include "option.h"
23 #include "info.h"
24 #include "record_data.h"
25 #include "record_io.h"
26 #include "slow.h"
27 
28 #include "loop.h"
29 
30 static int main_loop(int tutorial);
31 static void ship_bonus(void);
32 /*
33 static int draw_all_mass(tenm_object *my, int n);
34 */
35 
36 /* returns 1 if the program should quit, 0 if not */
37 int
game_loop(int tutorial)38 game_loop(int tutorial)
39 {
40   int i;
41   int status = 0;
42   game_record *record = NULL;
43 
44   clear_chain();
45   clear_chain_scroll();
46   clear_score();
47   clear_score_scroll();
48   clear_ship();
49   clear_ship_scroll();
50   set_stage_number(1);
51   for (i = 1; i <= 6; i++)
52   {
53     set_stage_id(i, -1);
54     set_stage_name(i, NULL);
55     set_stage_difficulty(i, -1);
56   }
57 
58   record = game_record_load();
59   if (record == NULL)
60   {
61     fprintf(stderr, "game_loop: game_record_load failed\n");
62     return 1;
63   }
64   if ((!tutorial) && (!cheating()))
65     increment_play_total(record);
66 
67   while (1 == 1)
68   {
69     if (tutorial)
70     {
71       set_stage_id(get_stage_number(), -1);
72     }
73     else
74     {
75       clear_chain_scroll();
76       clear_score_scroll();
77       clear_ship_scroll();
78       status = stage_select(record);
79       if (status != 0)
80         break;
81     }
82 
83     status = main_loop(tutorial);
84 
85     if ((!cheating()) && (get_stage_id(get_stage_number()) >= 0))
86     {
87       /* the order does matter here (when you clear this plan first time) */
88       increment_play_plan(record, get_stage_id(get_stage_number()));
89       game_record_update(record);
90       if (status == 0)
91         increment_clear_plan(record, get_stage_id(get_stage_number()));
92     }
93 
94     if (tutorial)
95       break;
96     if (status != 0)
97       break;
98 
99     add_stage_number(1);
100     if (get_stage_number() >= 6)
101     {
102       ship_bonus();
103       game_record_update(record);
104       break;
105     }
106   }
107 
108   if (!cheating())
109   {
110     if (game_record_save(record) != 0)
111       fprintf(stderr, "game_loop: game_record_save failed\n");
112   }
113   if (record != NULL)
114     game_record_delete(record);
115   record = NULL;
116 
117   if ((!tutorial) && (status != 2))
118   {
119     if (show_result() != 0)
120       return 1;
121   }
122 
123   if (status == 2)
124     return 1;
125 
126   return 0;
127 }
128 
129 /* return
130  * 0 if the player cleared the stage
131  * 1 if the game or the tutorial is over
132  * 2 if the program should quit
133  * player (arg 1) is freed if and only if the return value is non-zero
134  */
135 static int
main_loop(int tutorial)136 main_loop(int tutorial)
137 {
138   int i;
139   int t = 0;
140   int frame_passed = 0;
141   int status = 0;
142   int temp;
143   tenm_object *player = NULL;
144   const option *op = NULL;
145 
146   op = get_option();
147   if (op == NULL)
148   {
149     fprintf(stderr, "game_loop: get_option failed\n");
150     return 2;
151   }
152 
153   set_background(0);
154 
155   tenm_table_clear_all();
156 
157   clear_chain();
158 
159   player = player_new(tutorial);
160   if (player == NULL)
161   {
162     fprintf(stderr, "game_loop: player_new failed\n");
163     return 2;
164   }
165 
166   tenm_set_focus_handler((void (*)(int)) pause_by_mouse);
167   clear_pause();
168   clear_slow();
169 
170   tenm_timer_reset();
171 
172   while (1 == 1)
173   {
174     /* quit the program if a SDL_QUIT event happened
175      * (for example, if a SIGINT signal (sent by Ctrl+c) is received)
176      */
177     if (tenm_event_handle() != 0)
178     {
179       status = 2;
180       break;
181     }
182 
183     /* back to the title if ESC is pressed  */
184     if (tenm_get_key_status() & 32)
185     {
186       if (get_esc_ok())
187       {
188         set_esc_ok(0);
189         status = 1;
190         break;
191       }
192     }
193     else
194     {
195       set_esc_ok(1);
196     }
197 
198     /* pause */
199     if (do_pause(tenm_get_key_status() & 64))
200     {
201       frame_passed++;
202       /* update the "paused" message */
203       tenm_redraw_window();
204       /* do_pause() needs this wait */
205       tenm_wait_next_frame();
206       continue;
207     }
208 
209     for (i = 1; i <= 30; i++)
210     {
211       if (tenm_table_detect_collision(player) != 0)
212         player = NULL;
213       if (tenm_table_move(player, 30) != 0)
214         player = NULL;
215     }
216 
217     /* scheduler() must be called before tenm_table_do_action()
218      * to clear action_needed flag correctly */
219     temp = scheduler(tutorial, t);
220 
221     if (tenm_table_do_action(player) != 0)
222       player = NULL;
223 
224     clear_window_with_background();
225 
226     tenm_table_draw(player);
227 
228     show_score(player);
229     show_ship(player);
230     show_chain(player);
231 
232     /* for those who want to see the world as it is */
233     /* note that
234      * (1) the player is not in the table
235      * (2) this is slow
236      */
237     /*
238     tenm_table_apply_all((int (*)(tenm_object *, int)) draw_all_mass, 0);
239     */
240 
241     tenm_redraw_window();
242 
243     tenm_wait_next_frame();
244     /* slow down if CAPS lock is set */
245     if ((op->slow != 0) && (do_slow(tenm_get_key_status() & 128)))
246       tenm_wait_next_frame();
247 
248     if (player == NULL)
249     {
250       /* no more life, game over */
251       status = 1;
252       break;
253     }
254 
255     t++;
256     frame_passed++;
257     if (temp == SCHEDULER_NEXT_STAGE)
258       break;
259   }
260 
261   if (frame_passed > 0)
262   {
263     printf("average fps: %f\n", tenm_calculate_fps(frame_passed));
264     fflush(stdout);
265   }
266 
267   tenm_table_clear_all();
268   if (player != NULL)
269     tenm_object_delete(player);
270 
271   return status;
272 }
273 
274 static void
ship_bonus(void)275 ship_bonus(void)
276 {
277   if (get_stage_number() != 6)
278     return;
279   if (get_stage_cleared(6) != 0)
280     return;
281 
282   set_stage_id(6, 0);
283   add_score(get_ship() * 30000);
284   set_stage_cleared(6, 1);
285 }
286 
287 #if 0
288 static int
289 draw_all_mass(tenm_object *my, int n)
290 {
291   /* sanity check */
292   if (my == NULL)
293     return 0;
294 
295   if (my->mass == NULL)
296     return 0;
297   if (my->attr == 0)
298     return 0;
299 
300   if (tenm_draw_mass(my->mass, tenm_map_color(0, 0, 0)) != 0)
301   {
302     fprintf(stderr, "draw_all_mass: tenm_draw_mass failed (%d)\n",
303             my->table_index);
304   }
305 
306   return 0;
307 }
308 #endif /* 0 */
309