Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1806 | yogev_ezra | 1 | /* |
2 | ------------------------------------------------------------ |
||
3 | Fixed Rate Pig - a fixed logic frame rate demo |
||
4 | ------------------------------------------------------------ |
||
5 | * Copyright (C) 2004 David Olofson |
||
6 | * |
||
7 | * This software is released under the terms of the GPL. |
||
8 | * |
||
9 | * Contact author for permission if you want to use this |
||
10 | * software, or work derived from it, under other terms. |
||
11 | */ |
||
12 | |||
13 | #include |
||
14 | #include |
||
15 | #include |
||
16 | #include |
||
17 | #include |
||
18 | #include |
||
19 | #include "engine.h" |
||
20 | |||
21 | |||
22 | /* Graphics defines */ |
||
23 | #define SCREEN_W 800 |
||
24 | #define SCREEN_H 600 |
||
25 | #define TILE_W 32 |
||
26 | #define TILE_H 32 |
||
27 | #define MAP_W 25 |
||
28 | #define MAP_H 17 |
||
29 | #define FONT_SPACING 45 |
||
30 | #define PIG_FRAMES 12 |
||
31 | |||
32 | /* World/physics constants */ |
||
33 | #define GRAV_ACC 4 |
||
34 | #define JUMP_SPEED 28 |
||
35 | |||
36 | /* Sprite collision groups */ |
||
37 | #define GROUP_ENEMY 0x0001 |
||
38 | #define GROUP_POWERUP 0x0002 |
||
39 | |||
40 | typedef enum |
||
41 | { |
||
42 | POWER_LIFE, |
||
43 | POWER_BONUS1, |
||
44 | POWER_BONUS2 |
||
45 | } POWERUPS; |
||
46 | |||
47 | |||
48 | typedef struct GAMESTATE |
||
49 | { |
||
50 | /* I/O */ |
||
51 | PIG_engine *pe; |
||
52 | Uint8 *keys; |
||
53 | int nice; |
||
54 | int refresh_screen; |
||
55 | int jump; |
||
56 | |||
57 | /* Sprites */ |
||
58 | int lifepig; |
||
59 | int scorefont; |
||
60 | int glassfont; |
||
61 | int icons; |
||
62 | int stars; |
||
63 | int pigframes; |
||
64 | int evil; |
||
65 | int slime; |
||
66 | |||
67 | /* Global game state */ |
||
68 | int running; |
||
69 | int level; |
||
70 | int lives; |
||
71 | float lives_wobble; |
||
72 | float lives_wobble_time; |
||
73 | int score; |
||
74 | float score_wobble; |
||
75 | float score_wobble_time; |
||
76 | float dashboard_time; |
||
77 | int fun_count; |
||
78 | int enemycount; |
||
79 | int messages; |
||
80 | |||
81 | /* Objects */ |
||
82 | PIG_object *player; |
||
83 | |||
84 | /* Statistics */ |
||
85 | int logic_frames; |
||
86 | int rendered_frames; |
||
87 | } GAMESTATE; |
||
88 | |||
89 | |||
90 | static void add_life(GAMESTATE *gs); |
||
91 | static void remove_life(GAMESTATE *gs); |
||
92 | static void inc_score(GAMESTATE *gs, int v); |
||
93 | static void inc_score_nobonus(GAMESTATE *gs, int v); |
||
94 | static PIG_object *new_player(GAMESTATE *gs); |
||
95 | static void message(GAMESTATE *gs, const char *s); |
||
96 | static PIG_object *new_powerup(GAMESTATE *gs, |
||
97 | int x, int y, int speed, POWERUPS type); |
||
98 | static PIG_object *new_star(GAMESTATE *gs, int x, int y, int vx, int vy); |
||
99 | static PIG_object *new_evil(GAMESTATE *gs, |
||
100 | int x, int y, int speed); |
||
101 | static PIG_object *new_slime(GAMESTATE *gs, |
||
102 | int x, int y, int speed); |
||
103 | |||
104 | |||
105 | /*---------------------------------------------------------- |
||
106 | Init, load stuff etc |
||
107 | ----------------------------------------------------------*/ |
||
108 | |||
109 | static int load_level(GAMESTATE *gs, int map) |
||
110 | { |
||
111 | const char *m; |
||
112 | const char *k; |
||
113 | if(map > 4) |
||
114 | map = 1; |
||
115 | gs->level = map; |
||
116 | pig_object_close_all(gs->pe); |
||
117 | gs->enemycount = 0; |
||
118 | gs->messages = 0; |
||
119 | switch(map) |
||
120 | { |
||
121 | case 1: |
||
122 | case 2: |
||
123 | case 4: |
||
124 | k = "abcd" "efgh" "ijkl" /* Red, green, yellov */ |
||
125 | "0123456789ABCDEFG" /* Sky */ |
||
126 | "xyz"; /* Single R, G, Y */ |
||
127 | break; |
||
128 | case 0: |
||
129 | case 3: |
||
130 | k = "abcd" "efgh" "ijkl" /* Red, green, yellov */ |
||
131 | "................." |
||
132 | "xyz" /* Single R, G, Y */ |
||
133 | "-+012345..ABCDEF"; /* Night sky */ |
||
134 | break; |
||
135 | } |
||
136 | switch(map) |
||
137 | { |
||
138 | case 0: m = "-------------ad----------" |
||
139 | "-abcd-x-ad--ad-abcd-acd--" |
||
140 | "-x----x--abcd--x----x--x-" |
||
141 | "-abd--x---ad---abd--x--x-" |
||
142 | "-x----x--abcd--x----x--x-" |
||
143 | "-x----x-ad--ad-abcd-abd--" |
||
144 | "----efhad-eh--egh-efh----" |
||
145 | "----y--y-y--y--y--y------" |
||
146 | "++++efh++efgh++y++eh+++++" |
||
147 | "0123y50y2y45y12y45y123450" |
||
148 | "ABCDyFAyCyEFyBCyEFeghDEFA" |
||
149 | "----ijkjl-ijkl--ijkjl----" |
||
150 | "----il--il-il--il--------" |
||
151 | "----ijkjl--il--il-ikl----" |
||
152 | "----il-----il--il--il----" |
||
153 | "----il----ijkl--ijkjl----" |
||
154 | "-------------------------"; |
||
155 | break; |
||
156 | case 1: m = "0000000000000000000000000" |
||
157 | "1111111111111111111111111" |
||
158 | "2222222222222222222222222" |
||
159 | "3333333333333333333333333" |
||
160 | "4444444444444444444444444" |
||
161 | "5555555555555555555555555" |
||
162 | "6666666666666666666666666" |
||
163 | "7777777ijkjkjjkjkl7777777" |
||
164 | "8888888888888888888888888" |
||
165 | "9999999999999999999999999" |
||
166 | "abcdAAAAAAAAAAAAAAAAAabcd" |
||
167 | "BBBBBBBBBBBBBBBBBBBBBBBBB" |
||
168 | "CCCCCCCCCCCCCCCCCCCCCCCCC" |
||
169 | "efgfgffgfgfgfgfggffgfgfgh" |
||
170 | "EEEEEEEEEEEEEEEEEEEEEEEEE" |
||
171 | "FFFFFFFFFFFFFFFFFFFFFFFFF" |
||
172 | "GGGGGGGGGGGGGGGGGGGGGGGGG"; |
||
173 | new_evil(gs, 2, 0, 5); |
||
174 | new_evil(gs, 22, 0, 5); |
||
175 | new_evil(gs, 5, 0, 7); |
||
176 | new_evil(gs, 19, 0, 7); |
||
177 | break; |
||
178 | case 2: m = "0000000000000000000000000" |
||
179 | "1111111111111111111111111" |
||
180 | "2222222222222222222222222" |
||
181 | "3333333333333333333333333" |
||
182 | "4444444444xxxxx4444444444" |
||
183 | "5555555555x555x5555555555" |
||
184 | "6666666666x666x6666666666" |
||
185 | "7777777xxxx777xxxx7777777" |
||
186 | "8888888x888888888x8888888" |
||
187 | "9999999x999999999x9999999" |
||
188 | "AAAAAAAxxxxAAAxxxxAAAAAAA" |
||
189 | "BBBBBBBBBBxBBBxBBBBBBBBBB" |
||
190 | "CCCCCCCCCCxCCCxCCCCCCCCCC" |
||
191 | "DDDDDDDDDDxxxxxDDDDDDDDDD" |
||
192 | "EEEEEEEEEEEEEEEEEEEEEEEEE" |
||
193 | "ijklFFFFFFFFFFFFFFFFFijkl" |
||
194 | "GGGijlGilGilGilGilGiklGGG"; |
||
195 | new_slime(gs, 2, 0, -5); |
||
196 | new_slime(gs, 22, 0, 5); |
||
197 | new_evil(gs, 8, 0, 7); |
||
198 | new_evil(gs, 16, 0, -7); |
||
199 | break; |
||
200 | case 3: m = "-------------------------" |
||
201 | "-------------------------" |
||
202 | "-------------------------" |
||
203 | "-------------------------" |
||
204 | "ijkl----------efgh-------" |
||
205 | "-------------------------" |
||
206 | "-------------------------" |
||
207 | "z----------------abcbcbbd" |
||
208 | "+++++++++++++++++++++++++" |
||
209 | "01z3450123450123450123450" |
||
210 | "ABCDEFABCefgfgfghFABCDEFA" |
||
211 | "----z--------------------" |
||
212 | "-------------------------" |
||
213 | "------z--------------ijkl" |
||
214 | "-------------------------" |
||
215 | "-------------------------" |
||
216 | "abdefghijkl---efghijklabd"; |
||
217 | new_slime(gs, 5, 0, -5); |
||
218 | new_slime(gs, 20, 15, -5); |
||
219 | new_evil(gs, 1, 0, 7); |
||
220 | new_evil(gs, 20, 0, 10); |
||
221 | new_evil(gs, 15, 0, 7); |
||
222 | break; |
||
223 | case 4: m = "0000000000000000000000000" |
||
224 | "1111111111111111111111111" |
||
225 | "2222222222222222222222222" |
||
226 | "3333333333333333333333333" |
||
227 | "4444444444444444444444444" |
||
228 | "555555555555z555555555555" |
||
229 | "66666666666ijl66666666666" |
||
230 | "7777777777ijlil7777777777" |
||
231 | "888888888ijlikkl888888888" |
||
232 | "99999999ijkjklikl99999999" |
||
233 | "AAAAAAAikjlijkjkjlAAAAAAA" |
||
234 | "BBBBBBiklijkjlijkjlBBBBBB" |
||
235 | "CCCCCijkjlikkjklikklCCCCC" |
||
236 | "DDDDijklijjklikjkjkklDDDD" |
||
237 | "EEEijkkjkjlikjkjlijjklEEE" |
||
238 | "FFijkjlilijkjklikjlikklFF" |
||
239 | "efggfggfgfgfggfgfgfgfgfgh"; |
||
240 | new_evil(gs, 11, 0, 5); |
||
241 | new_evil(gs, 10, 0, 6); |
||
242 | new_evil(gs, 9, 0, 7); |
||
243 | new_evil(gs, 8, 0, 8); |
||
244 | new_evil(gs, 7, 0, 9); |
||
245 | new_evil(gs, 6, 0, 10); |
||
246 | new_evil(gs, 5, 0, 11); |
||
247 | new_evil(gs, 4, 0, 12); |
||
248 | new_evil(gs, 3, 0, 13); |
||
249 | new_slime(gs, 1, 0, 16); |
||
250 | new_slime(gs, 24, 0, -14); |
||
251 | break; |
||
252 | default: |
||
253 | return -1; |
||
254 | } |
||
255 | pig_map_from_string(gs->pe->map, k, m); |
||
256 | gs->refresh_screen = gs->pe->pages; |
||
257 | return 0; |
||
258 | } |
||
259 | |||
260 | |||
261 | static GAMESTATE *init_all(SDL_Surface *screen) |
||
262 | { |
||
263 | int i; |
||
264 | PIG_map *pm; |
||
265 | GAMESTATE *gs = (GAMESTATE *)calloc(1, sizeof(GAMESTATE)); |
||
266 | if(!gs) |
||
267 | return NULL; |
||
268 | |||
269 | gs->running = 1; |
||
270 | |||
271 | gs->pe = pig_open(screen); |
||
272 | if(!gs->pe) |
||
273 | { |
||
274 | fprintf(stderr, "Could not open the Pig Engine!\n"); |
||
275 | free(gs); |
||
276 | return NULL; |
||
277 | } |
||
278 | gs->pe->userdata = gs; |
||
279 | |||
280 | pig_viewport(gs->pe, 0, 0, SCREEN_W, MAP_H * TILE_H); |
||
281 | |||
282 | i = gs->lifepig = pig_sprites(gs->pe, "lifepig.png", 0, 0); |
||
283 | i |= gs->scorefont = pig_sprites(gs->pe, "font.png", 44, 56); |
||
284 | i |= gs->glassfont = pig_sprites(gs->pe, "glassfont.png", 60, 60); |
||
285 | i |= gs->icons = pig_sprites(gs->pe, "icons.png", 48, 48); |
||
286 | i |= gs->stars = pig_sprites(gs->pe, "stars.png", 32, 32); |
||
287 | i |= gs->pigframes = pig_sprites(gs->pe, "pigframes.png", 64, 48); |
||
288 | i |= gs->evil = pig_sprites(gs->pe, "evil.png", 48, 48); |
||
289 | i |= gs->slime = pig_sprites(gs->pe, "slime.png", 48, 48); |
||
290 | if(i < 0) |
||
291 | { |
||
292 | fprintf(stderr, "Could not load graphics!\n"); |
||
293 | pig_close(gs->pe); |
||
294 | free(gs); |
||
295 | return NULL; |
||
296 | } |
||
297 | for(i = gs->icons; i < gs->icons + 3*8; ++i) |
||
298 | pig_hotspot(gs->pe, i, PIG_CENTER, 45); |
||
299 | for(i = gs->pigframes; i < gs->pigframes + 12; ++i) |
||
300 | pig_hotspot(gs->pe, i, PIG_CENTER, 43); |
||
301 | for(i = gs->evil; i < gs->evil + 16; ++i) |
||
302 | pig_hotspot(gs->pe, i, PIG_CENTER, 46); |
||
303 | for(i = gs->slime; i < gs->slime + 16; ++i) |
||
304 | pig_hotspot(gs->pe, i, PIG_CENTER, 46); |
||
305 | |||
306 | pm = pig_map_open(gs->pe, MAP_W, MAP_H); |
||
307 | if(!pm) |
||
308 | { |
||
309 | fprintf(stderr, "Could not create map!\n"); |
||
310 | pig_close(gs->pe); |
||
311 | free(gs); |
||
312 | return NULL; |
||
313 | } |
||
314 | if(pig_map_tiles(pm, "tiles.png", TILE_W, TILE_H) < 0) |
||
315 | { |
||
316 | fprintf(stderr, "Could not load background graphics!\n"); |
||
317 | pig_close(gs->pe); |
||
318 | free(gs); |
||
319 | return NULL; |
||
320 | } |
||
321 | |||
322 | /* Mark tiles for collision detection */ |
||
323 | pig_map_collisions(pm, 0, 12, PIG_ALL); /* Red, green, yellov */ |
||
324 | pig_map_collisions(pm, 12, 17, PIG_NONE);/* Sky */ |
||
325 | pig_map_collisions(pm, 29, 3, PIG_ALL); /* Single R, G, Y */ |
||
326 | |||
327 | load_level(gs, 0); |
||
328 | return gs; |
||
329 | } |
||
330 | |||
331 | |||
332 | /*---------------------------------------------------------- |
||
333 | Render the dashboard |
||
334 | ----------------------------------------------------------*/ |
||
335 | static void dashboard(GAMESTATE *gs) |
||
336 | { |
||
337 | SDL_Rect r; |
||
338 | int i, v; |
||
339 | float x; |
||
340 | float t = SDL_GetTicks() * 0.001; |
||
341 | r.x = 0; |
||
342 | r.y = SCREEN_H - 56; |
||
343 | r.w = SCREEN_W; |
||
344 | r.h = 56; |
||
345 | SDL_SetClipRect(gs->pe->surface, &r); |
||
346 | |||
347 | /* Render "plasma bar" */ |
||
348 | for(i = 0; i < 56; ++i) |
||
349 | { |
||
350 | float f1, f2, m; |
||
351 | SDL_Rect cr; |
||
352 | cr.x = 0; |
||
353 | cr.w = SCREEN_W; |
||
354 | cr.y = SCREEN_H - 56 + i; |
||
355 | cr.h = 1; |
||
356 | f1 = .25 + .25 * sin(t * 1.7 + (float)i / SCREEN_H * 42); |
||
357 | f1 += .25 + .25 * sin(-t * 2.1 + (float)i / SCREEN_H * 66); |
||
358 | f2 = .25 + .25 * sin(t * 3.31 + (float)i / SCREEN_H * 90); |
||
359 | f2 += .25 + .25 * sin(-t * 1.1 + (float)i / SCREEN_H * 154); |
||
360 | m = sin((float)i * M_PI / 56.0); |
||
361 | m = sin(m * M_PI * 0.5); |
||
362 | m = sin(m * M_PI * 0.5); |
||
363 | SDL_FillRect(gs->pe->surface, |
||
364 | &cr, SDL_MapRGB(gs->pe->surface->format, |
||
365 | ((int)128.0 * f1 + 64) * m, |
||
366 | ((int)64.0 * f1 * f2 + 64) * m, |
||
367 | ((int)128.0 * f2 + 32) * m |
||
368 | )); |
||
369 | } |
||
370 | |||
371 | /* Draw pigs... uh, lives! */ |
||
372 | x = -10; |
||
373 | for(i = 0; i < gs->lives; ++i) |
||
374 | { |
||
375 | x += 48 + gs->lives_wobble * |
||
376 | sin(gs->lives_wobble_time * 12) * .2; |
||
377 | pig_draw_sprite(gs->pe, gs->lifepig, |
||
378 | (int)x + gs->lives_wobble * |
||
379 | sin(gs->lives_wobble_time * 20 + i * 1.7), |
||
380 | SCREEN_H - 56/2); |
||
381 | } |
||
382 | |||
383 | /* Print score */ |
||
384 | x = SCREEN_W + 5; |
||
385 | v = gs->score; |
||
386 | for(i = 9; i >= 0; --i) |
||
387 | { |
||
388 | int n = v % 10; |
||
389 | x -= 39 - gs->score_wobble * |
||
390 | sin(gs->score_wobble_time * 15 + i * .5); |
||
391 | pig_draw_sprite(gs->pe, gs->scorefont + n, (int)x, |
||
392 | SCREEN_H - 56/2); |
||
393 | v /= 10; |
||
394 | if(!v) |
||
395 | break; |
||
396 | } |
||
397 | |||
398 | pig_dirty(gs->pe, &r); |
||
399 | } |
||
400 | |||
401 | |||
402 | /*---------------------------------------------------------- |
||
403 | Game logic event handlers |
||
404 | ----------------------------------------------------------*/ |
||
405 | static void before_objects(PIG_engine *pe) |
||
406 | { |
||
407 | GAMESTATE *gs = (GAMESTATE *)pe->userdata; |
||
408 | if(gs->lives_wobble > 0) |
||
409 | { |
||
410 | gs->lives_wobble *= 0.95; |
||
411 | gs->lives_wobble -= 0.3; |
||
412 | if(gs->lives_wobble < 0) |
||
413 | gs->lives_wobble = 0; |
||
414 | } |
||
415 | if(gs->score_wobble > 0) |
||
416 | { |
||
417 | gs->score_wobble *= 0.95; |
||
418 | gs->score_wobble -= 0.3; |
||
419 | if(gs->score_wobble < 0) |
||
420 | gs->score_wobble = 0; |
||
421 | } |
||
422 | ++gs->logic_frames; |
||
423 | |||
424 | if(0 == gs->level) |
||
425 | { |
||
426 | switch(gs->fun_count % 60) |
||
427 | { |
||
428 | case 17: |
||
429 | new_powerup(gs, 250, -20, -10, POWER_LIFE); |
||
430 | break; |
||
431 | case 29: |
||
432 | new_powerup(gs, 550, -20, 10, POWER_LIFE); |
||
433 | break; |
||
434 | case 37: |
||
435 | new_powerup(gs, 250, -20, 10, POWER_BONUS2); |
||
436 | break; |
||
437 | case 51: |
||
438 | new_powerup(gs, 550, -20, -10, POWER_BONUS1); |
||
439 | break; |
||
440 | } |
||
441 | if(150 == gs->fun_count % 300) |
||
442 | message(gs, "Press Space!"); |
||
443 | ++gs->fun_count; |
||
444 | } |
||
445 | } |
||
446 | |||
447 | |||
448 | typedef enum |
||
449 | { |
||
450 | WAITING, |
||
451 | WALKING, |
||
452 | FALLING, |
||
453 | KNOCKED, |
||
454 | NEXT_LEVEL, |
||
455 | DEAD |
||
456 | } OBJECT_states; |
||
457 | |||
458 | |||
459 | static void player_handler(PIG_object *po, const PIG_event *ev) |
||
460 | { |
||
461 | GAMESTATE *gs = (GAMESTATE *)po->owner->userdata; |
||
462 | switch(ev->type) |
||
463 | { |
||
464 | case PIG_PREFRAME: |
||
465 | switch(po->state) |
||
466 | { |
||
467 | case WAITING: |
||
468 | if(1 == po->age) |
||
469 | message(gs, "Get ready!"); |
||
470 | else if(po->age > 50) |
||
471 | po->state = FALLING; |
||
472 | break; |
||
473 | case WALKING: |
||
474 | if(gs->keys[SDLK_LEFT]) |
||
475 | { |
||
476 | po->ax = -(20 + po->vx) * .4; |
||
477 | po->target = 3 + po->age % 4 - 1; |
||
478 | if(5 == po->target) |
||
479 | po->target = 3; |
||
480 | } |
||
481 | else if(gs->keys[SDLK_RIGHT]) |
||
482 | { |
||
483 | po->ax = (20 - po->vx) * .4; |
||
484 | po->target = 9 + po->age % 4 - 1; |
||
485 | if(11 == po->target) |
||
486 | po->target = 9; |
||
487 | } |
||
488 | else |
||
489 | { |
||
490 | po->ax = -po->vx * .8; |
||
491 | if(po->target >= 6) |
||
492 | po->target = (po->target + 1) % |
||
493 | PIG_FRAMES; |
||
494 | else if(po->target) |
||
495 | --po->target; |
||
496 | } |
||
497 | break; |
||
498 | case FALLING: |
||
499 | if(gs->keys[SDLK_LEFT]) |
||
500 | po->ax = -(20 + po->vx) * .2; |
||
501 | else if(gs->keys[SDLK_RIGHT]) |
||
502 | po->ax = (20 - po->vx) * .2; |
||
503 | else |
||
504 | po->ax = -po->vx * .2; |
||
505 | po->target = (po->target + 1) % PIG_FRAMES; |
||
506 | break; |
||
507 | } |
||
508 | po->timer[0] = 1; |
||
509 | break; |
||
510 | case PIG_TIMER0: |
||
511 | if(po->x < 0) |
||
512 | po->x = 0; |
||
513 | else if(po->x > po->owner->view.w - 1) |
||
514 | po->x = po->owner->view.w - 1; |
||
515 | switch(po->state) |
||
516 | { |
||
517 | case WALKING: |
||
518 | if(po->power) |
||
519 | --po->power; |
||
520 | po->image = po->target % PIG_FRAMES; |
||
521 | if(!pig_test_map(gs->pe, po->x, po->y + 1)) |
||
522 | { |
||
523 | po->state = FALLING; |
||
524 | po->ay = GRAV_ACC; |
||
525 | } |
||
526 | if(gs->jump || gs->keys[SDLK_UP]) |
||
527 | { |
||
528 | po->ay = 0; |
||
529 | po->vy = -JUMP_SPEED; |
||
530 | po->state = FALLING; |
||
531 | gs->jump = 0; |
||
532 | } |
||
533 | break; |
||
534 | case FALLING: |
||
535 | if(po->vy > 2) |
||
536 | po->power = 3; |
||
537 | po->ay = GRAV_ACC; |
||
538 | po->image = po->target; |
||
539 | break; |
||
540 | case KNOCKED: |
||
541 | po->power = 0; |
||
542 | po->ay = GRAV_ACC; |
||
543 | po->target = (po->target + 2) % PIG_FRAMES; |
||
544 | po->image = po->target; |
||
545 | po->ax = -po->vx * .2; |
||
546 | break; |
||
547 | case NEXT_LEVEL: |
||
548 | po->vx = (SCREEN_W / 2 - po->x) * .1; |
||
549 | po->target = (po->target + 1) % PIG_FRAMES; |
||
550 | po->image = po->target; |
||
551 | break; |
||
552 | case DEAD: |
||
553 | po->ax = po->ay = 0; |
||
554 | po->vx = po->vy = 0; |
||
555 | break; |
||
556 | } |
||
557 | if(gs->jump) |
||
558 | --gs->jump; |
||
559 | if(NEXT_LEVEL != po->state) |
||
560 | { |
||
561 | if(gs->enemycount <= 0) |
||
562 | { |
||
563 | message(gs, "Well Done!"); |
||
564 | po->state = NEXT_LEVEL; |
||
565 | po->vy = 0; |
||
566 | po->ay = -1; |
||
567 | po->tilemask = 0; |
||
568 | po->hitgroup = 0; |
||
569 | po->timer[2] = 50; |
||
570 | } |
||
571 | } |
||
572 | break; |
||
573 | |||
574 | case PIG_TIMER1: |
||
575 | /* Snap out of KNOCKED mode */ |
||
576 | po->state = FALLING; |
||
577 | break; |
||
578 | |||
579 | case PIG_TIMER2: |
||
580 | switch(po->state) |
||
581 | { |
||
582 | case NEXT_LEVEL: |
||
583 | add_life(gs); |
||
584 | pig_object_close(po); |
||
585 | load_level(gs, gs->level + 1); |
||
586 | new_player(gs); |
||
587 | break; |
||
588 | default: |
||
589 | pig_object_close(po); |
||
590 | if(!new_player(gs)) |
||
591 | load_level(gs, 0); |
||
592 | break; |
||
593 | } |
||
594 | break; |
||
595 | |||
596 | case PIG_HIT_TILE: |
||
597 | if(KNOCKED == po->state) |
||
598 | break; |
||
599 | |||
600 | if(ev->cinfo.sides & PIG_TOP) |
||
601 | { |
||
602 | po->y = ev->cinfo.y; |
||
603 | po->vy = 0; |
||
604 | po->ay = 0; |
||
605 | } |
||
606 | po->state = WALKING; |
||
607 | break; |
||
608 | |||
609 | case PIG_HIT_OBJECT: |
||
610 | if(KNOCKED == po->state) |
||
611 | break; |
||
612 | |||
613 | switch(ev->obj->hitgroup) |
||
614 | { |
||
615 | case GROUP_ENEMY: |
||
616 | if((po->power && ev->cinfo.sides & PIG_TOP) || |
||
617 | (po->vy - ev->obj->vy) >= 15) |
||
618 | { |
||
619 | /* Win: Stomp! */ |
||
620 | inc_score(gs, ev->obj->score); |
||
621 | ev->obj->y = ev->cinfo.y + 10; |
||
622 | if(po->vy > 0) |
||
623 | ev->obj->vy = po->vy; |
||
624 | else |
||
625 | ev->obj->vy = 10; |
||
626 | ev->obj->ay = GRAV_ACC; |
||
627 | ev->obj->tilemask = 0; |
||
628 | ev->obj->hitgroup = 0; |
||
629 | if(gs->jump || gs->keys[SDLK_UP]) |
||
630 | { |
||
631 | /* Mega jump! */ |
||
632 | po->vy = -(JUMP_SPEED + 7); |
||
633 | gs->jump = 0; |
||
634 | } |
||
635 | else |
||
636 | { |
||
637 | /* Bounce a little */ |
||
638 | po->vy = -15; |
||
639 | } |
||
640 | po->y = ev->cinfo.y; |
||
641 | po->ay = 0; |
||
642 | po->state = FALLING; |
||
643 | } |
||
644 | else |
||
645 | { |
||
646 | /* Lose: Knocked! */ |
||
647 | po->vy = -15; |
||
648 | po->ay = GRAV_ACC; |
||
649 | po->state = KNOCKED; |
||
650 | po->timer[1] = 11; |
||
651 | new_star(gs, po->x, po->y - 20, -5, 3); |
||
652 | new_star(gs, po->x, po->y - 20, 2, -6); |
||
653 | new_star(gs, po->x, po->y - 20, 4, 4); |
||
654 | } |
||
655 | break; |
||
656 | case GROUP_POWERUP: |
||
657 | switch(ev->obj->score) |
||
658 | { |
||
659 | case POWER_LIFE: |
||
660 | add_life(gs); |
||
661 | message(gs, "Extra Life!"); |
||
662 | break; |
||
663 | case POWER_BONUS1: |
||
664 | /* Double or 100k bonus! */ |
||
665 | if(gs->score < 100000) |
||
666 | { |
||
667 | inc_score_nobonus(gs, gs->score); |
||
668 | message(gs, "Double Score!"); |
||
669 | } |
||
670 | else |
||
671 | { |
||
672 | inc_score_nobonus(gs, 100000); |
||
673 | message(gs, "100 000!"); |
||
674 | } |
||
675 | break; |
||
676 | case POWER_BONUS2: |
||
677 | inc_score_nobonus(gs, 1000); |
||
678 | message(gs, "1000!"); |
||
679 | break; |
||
680 | } |
||
681 | ev->obj->state = DEAD; |
||
682 | ev->obj->tilemask = 0; |
||
683 | ev->obj->hitgroup = 0; |
||
684 | ev->obj->vy = -20; |
||
685 | ev->obj->ay = -2; |
||
686 | break; |
||
687 | } |
||
688 | break; |
||
689 | case PIG_OFFSCREEN: |
||
690 | /* |
||
691 | * Dead pigs don't care about being off-screen. |
||
692 | * A timer is used to remove them, and to continue |
||
693 | * the game with a new life. |
||
694 | */ |
||
695 | if(DEAD == po->state) |
||
696 | break; |
||
697 | if(po->y < 0) /* Above the playfield is ok. */ |
||
698 | break; |
||
699 | if(gs->lives) |
||
700 | message(gs, "Oiiiiiiink!!!"); |
||
701 | else |
||
702 | message(gs, "Game Over!"); |
||
703 | po->state = DEAD; |
||
704 | po->timer[2] = 50; |
||
705 | default: |
||
706 | break; |
||
707 | } |
||
708 | } |
||
709 | |||
710 | |||
711 | static void powerup_handler(PIG_object *po, const PIG_event *ev) |
||
712 | { |
||
713 | GAMESTATE *gs = (GAMESTATE *)po->owner->userdata; |
||
714 | switch(ev->type) |
||
715 | { |
||
716 | case PIG_PREFRAME: |
||
717 | if(DEAD == po->state) |
||
718 | break; |
||
719 | po->ax = (po->target - po->vx) * .3; |
||
720 | po->ay = GRAV_ACC; |
||
721 | po->image = po->age % 8; |
||
722 | ++po->power; |
||
723 | break; |
||
724 | case PIG_HIT_TILE: |
||
725 | if(DEAD == po->state) |
||
726 | break; |
||
727 | if(po->power > 2) |
||
728 | po->target = -po->target; |
||
729 | po->power = 0; |
||
730 | po->vy = 0; |
||
731 | po->ay = 0; |
||
732 | po->x = ev->cinfo.x + po->vx; |
||
733 | po->y = ev->cinfo.y; |
||
734 | break; |
||
735 | case PIG_OFFSCREEN: |
||
736 | if(po->y > SCREEN_H || (po->y < -100)) |
||
737 | { |
||
738 | pig_object_close(po); |
||
739 | --gs->enemycount; |
||
740 | } |
||
741 | default: |
||
742 | break; |
||
743 | } |
||
744 | } |
||
745 | |||
746 | |||
747 | static void star_handler(PIG_object *po, const PIG_event *ev) |
||
748 | { |
||
749 | switch(ev->type) |
||
750 | { |
||
751 | case PIG_PREFRAME: |
||
752 | if(po->age >= 8) |
||
753 | pig_object_close(po); |
||
754 | else |
||
755 | po->image = po->age; |
||
756 | default: |
||
757 | break; |
||
758 | } |
||
759 | } |
||
760 | |||
761 | |||
762 | static void evil_handler(PIG_object *po, const PIG_event *ev) |
||
763 | { |
||
764 | GAMESTATE *gs = (GAMESTATE *)po->owner->userdata; |
||
765 | int look_x; |
||
766 | switch(ev->type) |
||
767 | { |
||
768 | case PIG_PREFRAME: |
||
769 | if(DEAD == po->state) |
||
770 | break; |
||
771 | po->ax = (po->target - po->vx) * .5; |
||
772 | po->ay = GRAV_ACC; |
||
773 | po->image = po->age % 16; |
||
774 | break; |
||
775 | case PIG_HIT_TILE: |
||
776 | if(DEAD == po->state) |
||
777 | break; |
||
778 | po->vy = 0; |
||
779 | po->ay = 0; |
||
780 | po->x = ev->cinfo.x + po->vx; |
||
781 | po->y = ev->cinfo.y; |
||
782 | break; |
||
783 | case PIG_OFFSCREEN: |
||
784 | if(po->y > SCREEN_H) |
||
785 | { |
||
786 | pig_object_close(po); |
||
787 | --gs->enemycount; |
||
788 | } |
||
789 | break; |
||
790 | case PIG_POSTFRAME: |
||
791 | if(DEAD == po->state) |
||
792 | break; |
||
793 | look_x = 10 + fabs(po->vx * 2); |
||
794 | if(po->target < 0) |
||
795 | look_x = -look_x; |
||
796 | if(!pig_test_map(po->owner, po->x + look_x, po->y + 1)) |
||
797 | po->target = -po->target; |
||
798 | default: |
||
799 | break; |
||
800 | } |
||
801 | } |
||
802 | |||
803 | |||
804 | static void slime_handler(PIG_object *po, const PIG_event *ev) |
||
805 | { |
||
806 | GAMESTATE *gs = (GAMESTATE *)po->owner->userdata; |
||
807 | int look_x; |
||
808 | switch(ev->type) |
||
809 | { |
||
810 | case PIG_PREFRAME: |
||
811 | if(DEAD == po->state) |
||
812 | break; |
||
813 | po->ax = (po->target - po->vx) * .2; |
||
814 | po->ay = GRAV_ACC; |
||
815 | po->image = po->age % 16; |
||
816 | break; |
||
817 | case PIG_HIT_TILE: |
||
818 | po->vy = -(JUMP_SPEED + GRAV_ACC); |
||
819 | po->ay = 0; |
||
820 | po->y = ev->cinfo.y; |
||
821 | break; |
||
822 | case PIG_OFFSCREEN: |
||
823 | if(po->y > SCREEN_H) |
||
824 | { |
||
825 | pig_object_close(po); |
||
826 | --gs->enemycount; |
||
827 | } |
||
828 | break; |
||
829 | case PIG_POSTFRAME: |
||
830 | if(DEAD == po->state) |
||
831 | break; |
||
832 | /* Don't bother looking if we're close to a floor. */ |
||
833 | if(pig_test_map_vector(po->owner, |
||
834 | po->x, po->y, |
||
835 | po->x, po->y + 48, |
||
836 | PIG_TOP, NULL)) |
||
837 | break; |
||
838 | /* Turn around if there's no floor! */ |
||
839 | look_x = 10 + fabs(po->vx * 4); |
||
840 | if(po->target < 0) |
||
841 | look_x = -look_x; |
||
842 | if(!pig_test_map_vector(po->owner, |
||
843 | po->x + look_x, po->y, |
||
844 | po->x + look_x, SCREEN_H, |
||
845 | PIG_TOP, NULL)) |
||
846 | po->target = -po->target; |
||
847 | default: |
||
848 | break; |
||
849 | } |
||
850 | } |
||
851 | |||
852 | |||
853 | static void chain_head_handler(PIG_object *po, const PIG_event *ev) |
||
854 | { |
||
855 | GAMESTATE *gs = (GAMESTATE *)po->owner->userdata; |
||
856 | switch(ev->type) |
||
857 | { |
||
858 | case PIG_PREFRAME: |
||
859 | po->vx = (po->target - po->x) * .3; |
||
860 | po->vy = 15 * cos(po->age * .3) - 9; |
||
861 | if((gs->messages > 1) && (1 == po->state)) |
||
862 | po->timer[1] = 0; |
||
863 | if(po->timer[1]) |
||
864 | break; |
||
865 | case PIG_TIMER1: |
||
866 | switch(po->state) |
||
867 | { |
||
868 | case 0: |
||
869 | po->timer[1] = 35; |
||
870 | ++po->state; |
||
871 | break; |
||
872 | case 1: |
||
873 | po->target = -SCREEN_W; |
||
874 | po->timer[1] = 50; |
||
875 | ++po->state; |
||
876 | if(gs->messages > 0) |
||
877 | --gs->messages; |
||
878 | break; |
||
879 | case 2: |
||
880 | pig_object_close(po); |
||
881 | break; |
||
882 | } |
||
883 | default: |
||
884 | break; |
||
885 | } |
||
886 | } |
||
887 | |||
888 | static void chain_link_handler(PIG_object *po, const PIG_event *ev) |
||
889 | { |
||
890 | PIG_object *target = pig_object_find(po, po->target); |
||
891 | switch(ev->type) |
||
892 | { |
||
893 | case PIG_PREFRAME: |
||
894 | if(target) |
||
895 | { |
||
896 | po->vx = ((target->x + FONT_SPACING) - po->x) * .6; |
||
897 | po->vy = (target->y - po->y) * .6 - 9; |
||
898 | } |
||
899 | else |
||
900 | pig_object_close(po); |
||
901 | default: |
||
902 | break; |
||
903 | } |
||
904 | } |
||
905 | |||
906 | |||
907 | /*---------------------------------------------------------- |
||
908 | Accounting (score, lives etc) |
||
909 | ----------------------------------------------------------*/ |
||
910 | |||
911 | static void add_life(GAMESTATE *gs) |
||
912 | { |
||
913 | ++gs->lives; |
||
914 | gs->lives_wobble += 10; |
||
915 | if(gs->lives_wobble > 15) |
||
916 | gs->lives_wobble = 15; |
||
917 | gs->lives_wobble_time = 0; |
||
918 | } |
||
919 | |||
920 | |||
921 | static void remove_life(GAMESTATE *gs) |
||
922 | { |
||
923 | --gs->lives; |
||
924 | gs->lives_wobble += 10; |
||
925 | if(gs->lives_wobble > 15) |
||
926 | gs->lives_wobble = 15; |
||
927 | gs->lives_wobble_time = 0; |
||
928 | } |
||
929 | |||
930 | |||
931 | static void inc_score_nobonus(GAMESTATE *gs, int v) |
||
932 | { |
||
933 | int os = gs->score; |
||
934 | gs->score += v; |
||
935 | while(v) |
||
936 | { |
||
937 | gs->score_wobble += 1; |
||
938 | v /= 10; |
||
939 | } |
||
940 | if(gs->score_wobble > 15) |
||
941 | gs->score_wobble = 15; |
||
942 | gs->score_wobble_time = 0; |
||
943 | if(os / 10000 != gs->score / 10000) |
||
944 | new_powerup(gs, SCREEN_W / 2, -20, -4, POWER_LIFE); |
||
945 | } |
||
946 | |||
947 | static void inc_score(GAMESTATE *gs, int v) |
||
948 | { |
||
949 | int os = gs->score; |
||
950 | inc_score_nobonus(gs, v); |
||
951 | if(os / 5000 != gs->score / 5000) |
||
952 | new_powerup(gs, SCREEN_W / 2, -20, 8, POWER_BONUS1); |
||
953 | else if(os / 1000 != gs->score / 1000) |
||
954 | new_powerup(gs, SCREEN_W / 2, -20, -6, POWER_BONUS2); |
||
955 | } |
||
956 | |||
957 | |||
958 | static PIG_object *new_player(GAMESTATE *gs) |
||
959 | { |
||
960 | PIG_object *po; |
||
961 | if(!gs->lives) |
||
962 | return NULL; |
||
963 | |||
964 | po = pig_object_open(gs->pe, SCREEN_W / 2, -50, 1); |
||
965 | if(!po) |
||
966 | return NULL; |
||
967 | |||
968 | remove_life(gs); |
||
969 | po->ibase = gs->pigframes; |
||
970 | po->handler = player_handler; |
||
971 | po->hitmask = GROUP_POWERUP | GROUP_ENEMY; |
||
972 | return po; |
||
973 | } |
||
974 | |||
975 | |||
976 | static PIG_object *new_powerup(GAMESTATE *gs, |
||
977 | int x, int y, int speed, POWERUPS type) |
||
978 | { |
||
979 | PIG_object *po = pig_object_open(gs->pe, x, y, 1); |
||
980 | if(!po) |
||
981 | return NULL; |
||
982 | |||
983 | ++gs->enemycount; |
||
984 | po->score = type; |
||
985 | po->ibase = gs->icons + 8 * po->score; |
||
986 | po->target = speed; |
||
987 | po->handler = powerup_handler; |
||
988 | po->tilemask = PIG_TOP; |
||
989 | po->hitgroup = GROUP_POWERUP; |
||
990 | return po; |
||
991 | } |
||
992 | |||
993 | |||
994 | static PIG_object *new_star(GAMESTATE *gs, int x, int y, int vx, int vy) |
||
995 | { |
||
996 | PIG_object *po = pig_object_open(gs->pe, x + vx, y + vy, 1); |
||
997 | if(!po) |
||
998 | return NULL; |
||
999 | |||
1000 | po->ibase = gs->stars; |
||
1001 | po->ax = -vx * 0.3; |
||
1002 | po->vx = vx * 3; |
||
1003 | po->ay = -vy * 0.3; |
||
1004 | po->vy = vy * 3; |
||
1005 | po->handler = star_handler; |
||
1006 | return po; |
||
1007 | } |
||
1008 | |||
1009 | |||
1010 | static PIG_object *new_evil(GAMESTATE *gs, |
||
1011 | int x, int y, int speed) |
||
1012 | { |
||
1013 | PIG_object *po = pig_object_open(gs->pe, |
||
1014 | x * TILE_W, y * TILE_H, 1); |
||
1015 | if(!po) |
||
1016 | return NULL; |
||
1017 | |||
1018 | ++gs->enemycount; |
||
1019 | po->ibase = gs->evil; |
||
1020 | po->target = speed; |
||
1021 | po->handler = evil_handler; |
||
1022 | po->score = 200; |
||
1023 | po->tilemask = PIG_TOP; |
||
1024 | po->hitgroup = GROUP_ENEMY; |
||
1025 | return po; |
||
1026 | } |
||
1027 | |||
1028 | |||
1029 | static PIG_object *new_slime(GAMESTATE *gs, |
||
1030 | int x, int y, int speed) |
||
1031 | { |
||
1032 | PIG_object *po = pig_object_open(gs->pe, |
||
1033 | x * TILE_W, y * TILE_H, 1); |
||
1034 | if(!po) |
||
1035 | return NULL; |
||
1036 | |||
1037 | ++gs->enemycount; |
||
1038 | po->ibase = gs->slime; |
||
1039 | po->target = speed; |
||
1040 | po->handler = slime_handler; |
||
1041 | po->score = 300; |
||
1042 | po->tilemask = PIG_TOP; |
||
1043 | po->hitgroup = GROUP_ENEMY; |
||
1044 | return po; |
||
1045 | } |
||
1046 | |||
1047 | |||
1048 | static PIG_object *new_chain_head(GAMESTATE *gs, |
||
1049 | int x, int y, int image, int target_x) |
||
1050 | { |
||
1051 | PIG_object *po = pig_object_open(gs->pe, x, y, 1); |
||
1052 | if(!po) |
||
1053 | return NULL; |
||
1054 | |||
1055 | po->ibase = image; |
||
1056 | po->handler = chain_head_handler; |
||
1057 | po->target = target_x; |
||
1058 | return po; |
||
1059 | } |
||
1060 | |||
1061 | |||
1062 | static PIG_object *new_chain_link(GAMESTATE *gs, |
||
1063 | int x, int y, int image, int target) |
||
1064 | { |
||
1065 | PIG_object *po = pig_object_open(gs->pe, x, y, 1); |
||
1066 | if(!po) |
||
1067 | return NULL; |
||
1068 | |||
1069 | po->ibase = image; |
||
1070 | po->handler = chain_link_handler; |
||
1071 | po->target = target; |
||
1072 | return po; |
||
1073 | } |
||
1074 | |||
1075 | |||
1076 | static void message(GAMESTATE *gs, const char *s) |
||
1077 | { |
||
1078 | int i = 0; |
||
1079 | const int x = SCREEN_W + FONT_SPACING; |
||
1080 | const int y = MAP_H * TILE_H - 30; |
||
1081 | int tx = (SCREEN_W - ((signed)strlen(s) - 1) * FONT_SPACING) / 2; |
||
1082 | PIG_object *po = NULL; |
||
1083 | while(s[i]) |
||
1084 | { |
||
1085 | int c = toupper(s[i]) - 32 + gs->glassfont; |
||
1086 | if(0 == i) |
||
1087 | po = new_chain_head(gs, x, y, c, tx); |
||
1088 | else |
||
1089 | po = new_chain_link(gs, x, y, c, po->id); |
||
1090 | if(!po) |
||
1091 | return; |
||
1092 | ++i; |
||
1093 | } |
||
1094 | ++gs->messages; |
||
1095 | } |
||
1096 | |||
1097 | |||
1098 | static int start_game(GAMESTATE *gs) |
||
1099 | { |
||
1100 | if(0 != gs->level) |
||
1101 | return 0; /* Already playing! --> */ |
||
1102 | |||
1103 | gs->score = 0; |
||
1104 | gs->lives = 5; |
||
1105 | |||
1106 | if(load_level(gs, 1) < 0) |
||
1107 | return -1; |
||
1108 | |||
1109 | gs->player = new_player(gs); |
||
1110 | if(!gs->player) |
||
1111 | return -1; |
||
1112 | |||
1113 | return 0; |
||
1114 | } |
||
1115 | |||
1116 | |||
1117 | /*---------------------------------------------------------- |
||
1118 | Input; events and game control keys |
||
1119 | ----------------------------------------------------------*/ |
||
1120 | static void handle_input(GAMESTATE *gs, SDL_Event *ev) |
||
1121 | { |
||
1122 | switch(ev->type) |
||
1123 | { |
||
1124 | case SDL_MOUSEBUTTONUP: |
||
1125 | break; |
||
1126 | case SDL_KEYDOWN: |
||
1127 | switch(ev->key.keysym.sym) |
||
1128 | { |
||
1129 | case SDLK_UP: |
||
1130 | gs->jump = 3; |
||
1131 | break; |
||
1132 | case SDLK_F1: |
||
1133 | gs->pe->interpolation = !gs->pe->interpolation; |
||
1134 | if(gs->pe->interpolation) |
||
1135 | message(gs, "Interpolation: ON"); |
||
1136 | else |
||
1137 | message(gs, "Interpolation: OFF"); |
||
1138 | break; |
||
1139 | case SDLK_F2: |
||
1140 | gs->pe->direct = !gs->pe->direct; |
||
1141 | if(gs->pe->direct) |
||
1142 | message(gs, "Rendering: Direct"); |
||
1143 | else |
||
1144 | message(gs, "Rendering: Buffered"); |
||
1145 | break; |
||
1146 | case SDLK_F3: |
||
1147 | gs->pe->show_dirtyrects = !gs->pe->show_dirtyrects; |
||
1148 | if(gs->pe->show_dirtyrects) |
||
1149 | message(gs, "Dirtyrects: ON"); |
||
1150 | else |
||
1151 | message(gs, "Dirtyrects: OFF"); |
||
1152 | break; |
||
1153 | case SDLK_F4: |
||
1154 | gs->nice = !gs->nice; |
||
1155 | if(gs->nice) |
||
1156 | message(gs, "Be Nice: ON"); |
||
1157 | else |
||
1158 | message(gs, "Be Nice: OFF"); |
||
1159 | break; |
||
1160 | case SDLK_SPACE: |
||
1161 | start_game(gs); |
||
1162 | default: |
||
1163 | break; |
||
1164 | } |
||
1165 | break; |
||
1166 | case SDL_KEYUP: |
||
1167 | switch(ev->key.keysym.sym) |
||
1168 | { |
||
1169 | case SDLK_ESCAPE: |
||
1170 | gs->running = 0; |
||
1171 | default: |
||
1172 | break; |
||
1173 | } |
||
1174 | break; |
||
1175 | case SDL_QUIT: |
||
1176 | gs->running = 0; |
||
1177 | break; |
||
1178 | } |
||
1179 | } |
||
1180 | |||
1181 | |||
1182 | static void handle_keys(GAMESTATE *gs) |
||
1183 | { |
||
1184 | } |
||
1185 | |||
1186 | |||
1187 | static int break_received = 0; |
||
1188 | |||
1189 | #ifndef RETSIGTYPE |
||
1190 | #define RETSIGTYPE void |
||
1191 | #endif |
||
1192 | static RETSIGTYPE breakhandler(int sig) |
||
1193 | { |
||
1194 | /* For platforms that drop the handlers on the first signal... */ |
||
1195 | signal(SIGTERM, breakhandler); |
||
1196 | signal(SIGINT, breakhandler); |
||
1197 | break_received = 1; |
||
1198 | #if (RETSIGTYPE != void) |
||
1199 | return 0; |
||
1200 | #endif |
||
1201 | } |
||
1202 | |||
1203 | |||
1204 | /*---------------------------------------------------------- |
||
1205 | main() |
||
1206 | ----------------------------------------------------------*/ |
||
1207 | int main(int argc, char* argv[]) |
||
1208 | { |
||
1209 | SDL_Surface *screen; |
||
1210 | GAMESTATE *gs; |
||
1211 | int i; |
||
1212 | int bpp = 0; |
||
1213 | int last_tick, start_time, end_time; |
||
1214 | int dashframe; |
||
1215 | float logic_fps = 20.0; |
||
1216 | int flags = SDL_DOUBLEBUF | SDL_HWSURFACE; |
||
1217 | |||
1218 | SDL_Init(SDL_INIT_VIDEO); |
||
1219 | atexit(SDL_Quit); |
||
1220 | signal(SIGTERM, breakhandler); |
||
1221 | signal(SIGINT, breakhandler); |
||
1222 | |||
1223 | for(i = 1; i < argc; ++i) |
||
1224 | { |
||
1225 | if(strncmp(argv[i], "-s", 2) == 0) |
||
1226 | flags &= ~SDL_DOUBLEBUF; |
||
1227 | else if(strncmp(argv[i], "-f", 2) == 0) |
||
1228 | flags |= SDL_FULLSCREEN; |
||
1229 | else |
||
1230 | bpp = atoi(&argv[i][1]); |
||
1231 | } |
||
1232 | |||
1233 | screen = SDL_SetVideoMode(SCREEN_W, SCREEN_H, bpp, flags); |
||
1234 | if(!screen) |
||
1235 | { |
||
1236 | fprintf(stderr, "Failed to open screen!\n"); |
||
1237 | return 1; |
||
1238 | } |
||
1239 | |||
1240 | SDL_WM_SetCaption("Fixed Rate Pig", "Pig"); |
||
1241 | SDL_ShowCursor(0); |
||
1242 | |||
1243 | gs = init_all(screen); |
||
1244 | if(!gs) |
||
1245 | return 1; |
||
1246 | |||
1247 | gs->keys = SDL_GetKeyState(&i); |
||
1248 | |||
1249 | gs->logic_frames = 0; |
||
1250 | gs->rendered_frames = 0; |
||
1251 | gs->pe->before_objects = before_objects; |
||
1252 | |||
1253 | pig_start(gs->pe, 0); |
||
1254 | gs->refresh_screen = gs->pe->pages; |
||
1255 | start_time = last_tick = SDL_GetTicks(); |
||
1256 | while(gs->running) |
||
1257 | { |
||
1258 | int tick; |
||
1259 | float frames, dt; |
||
1260 | SDL_Event ev; |
||
1261 | |||
1262 | /* Handle input */ |
||
1263 | while(SDL_PollEvent(&ev) > 0) |
||
1264 | handle_input(gs, &ev); |
||
1265 | handle_keys(gs); |
||
1266 | if(break_received) |
||
1267 | gs->running = 0; |
||
1268 | |||
1269 | /* Calculate time since last update */ |
||
1270 | tick = SDL_GetTicks(); |
||
1271 | dt = (tick - last_tick) * 0.001; |
||
1272 | frames = dt * logic_fps; |
||
1273 | |||
1274 | /* Run the game logic */ |
||
1275 | pig_animate(gs->pe, frames); |
||
1276 | |||
1277 | /* |
||
1278 | * Limit the dashboard frame rate to 15 fps |
||
1279 | * when there's no wobbling going on. |
||
1280 | * |
||
1281 | * The 'dashframe' deal is about keeping the |
||
1282 | * pages in sync on a double buffered display. |
||
1283 | */ |
||
1284 | if(gs->lives_wobble || gs->score_wobble || |
||
1285 | (gs->dashboard_time > 1.0/15.0)) |
||
1286 | { |
||
1287 | dashframe = gs->pe->pages; |
||
1288 | gs->dashboard_time = 0; |
||
1289 | } |
||
1290 | if(dashframe) |
||
1291 | { |
||
1292 | --dashframe; |
||
1293 | dashboard(gs); |
||
1294 | } |
||
1295 | |||
1296 | /* Update sprites */ |
||
1297 | if(gs->refresh_screen) |
||
1298 | { |
||
1299 | --gs->refresh_screen; |
||
1300 | pig_refresh_all(gs->pe); |
||
1301 | } |
||
1302 | else |
||
1303 | pig_refresh(gs->pe); |
||
1304 | |||
1305 | /* Make the new frame visible */ |
||
1306 | pig_flip(gs->pe); |
||
1307 | |||
1308 | /* Update statistics, timers and stuff */ |
||
1309 | ++gs->rendered_frames; |
||
1310 | gs->lives_wobble_time += dt; |
||
1311 | gs->score_wobble_time += dt; |
||
1312 | gs->dashboard_time += dt; |
||
1313 | |||
1314 | last_tick = tick; |
||
1315 | if(gs->nice) |
||
1316 | SDL_Delay(10); |
||
1317 | } |
||
1318 | |||
1319 | /* Print some statistics */ |
||
1320 | end_time = SDL_GetTicks(); |
||
1321 | i = end_time - start_time; |
||
1322 | printf(" Total time running: %d ms\n", i); |
||
1323 | if(!i) |
||
1324 | i = 1; |
||
1325 | printf("Average rendering frame rate: %.2f fps\n", |
||
1326 | gs->rendered_frames * 1000.0 / i); |
||
1327 | printf(" Average logic frame rate: %.2f fps\n", |
||
1328 | gs->logic_frames * 1000.0 / i); |
||
1329 | |||
1330 | pig_close(gs->pe); |
||
1331 | return 0; |
||
1332 | }>>>>>>>=>>>>>>>>>>>> |