Annotation of talos/src/talos.c, revision 1.1.1.1
1.1 nick 1: /*
2: * Froggix
3: *
4: * Nicholas DeClario 2009
5: * <nick@declario.com>
6: *
7: * This program is distributed under the GNU Public License
8: * <Insert GNU license blurb here>
9: */
10:
11:
12: /*
13: * Our pretty standard includes
14: */
15: #include <stdio.h>
16: #include <stdlib.h>
17: #include <unistd.h>
18: #include <time.h>
19:
20: #include <SDL.h>
21: #include <SDL_mixer.h>
22: #include <SDL_image.h>
23: #include <SDL_ttf.h>
24:
25: /*
26: * Set some basic definitions
27: */
28: #define VER "$Id$";
29: #define TITLE "Talos"
30: #define SCREEN_WIDTH 640
31: #define SCREEN_HEIGHT 480
32: #define FALSE 0
33: #define TRUE 1
34: #define LIVES 3
35: #define COLORKEY 255, 0, 255
36: #define BGCOLOR 0, 0, 0
37: #define TALOS_START_X 290
38: #define TALOS_START_Y 425
39: #define UP 1
40: #define DOWN 2
41: #define LEFT 3
42: #define RIGHT 4
43: #define X 0
44: #define Y 1
45: #define FRAME 24
46: #define HFRAME 12
47:
48: /* Point table */
49: #define HIGH_SCORE 4630
50:
51: /* baddies */
52: #define VEHICLE 0
53: #define LOG 1
54: #define TURTLE 2
55: #define GATOR 3
56: #define SNAKE 4
57: #define BEAVER 5
58:
59: /* Turtles */
60: #define DIVE_START_TIME 50
61: #define DIVE_PHASE_TIME 20
62: #define MAX_TURTLES 9
63: #define TURTLE_ANIM_TIME 5
64:
65: /* Vehicles */
66: #define MAX_VEHICLES 40
67:
68:
69: /*
70: * Froggers dstruct
71: */
72: typedef struct {
73: int placement[2];
74: int oldPlacement[2];
75: int direction;
76: int location;
77: int hopCount;
78: int currentRow;
79: int alive;
80: int riding;
81: int ridingIdx;
82: int ridingType;
83: int talos; /* Are we talos or bonus talos */
84: int deathType;
85: int deathCount;
86:
87: SDL_Rect src;
88: SDL_Rect dst;
89:
90: Mix_Chunk *s_hop;
91: Mix_Chunk *s_squash;
92: Mix_Chunk *s_splash;
93: Mix_Chunk *s_extra;
94: } talosObj;
95:
96: /*
97: * Vehicles
98: */
99: typedef struct {
100: int placement[2];
101: int oldPlacement[2];
102: int direction; // LEFT or RIGHT
103: int row; // row
104: int speed; // How fast are we traveling
105: int level; // Must be >= this level to display
106:
107: SDL_Rect src;
108: } vehicleObj;
109:
110: int keyEvents( SDL_Event event );
111: int mySDLInit( void );
112: void beginGame( void );
113: int loadMedia( void );
114: int heartbeat( void );
115: int updateGameState( void );
116: void checkFly( void );
117: void checkGator( void );
118: void configGameScreen( void );
119: void drawGameScreen( void );
120: void drawBackground( void );
121: int getRowPixel ( int row );
122: int collisionRow ( void );
123: int freeFrog( int score );
124: int collideFrogger ( int x, int y, int h, int w );
125: void checkFroggerBorder( void );
126: void levelUp( void );
127: int checkGoals( void );
128: void talosReset( void );
129: void moveFrogger( void );
130: void ridingFrogger( );
131: void drawTitleScreen( void );
132: void drawPauseScreen( void );
133: void drawGameOver( void );
134: int drawDeathSequence( int deathType );
135: int checkTimer( void );
136: void drawScore( int high, int score );
137: void drawNumbers( int num, int x, int y );
138: void drawGoals( void );
139: void drawTimer( int length );
140: void drawLives( int lives );
141: void drawLevel( int level );
142: void drawWood( void );
143: void drawTurtles( void );
144: void drawVehicles( void );
145: void drawImage(SDL_Surface *srcimg, int sx, int sy, int sw, int sh, SDL_Surface *dstimg, int dx, int dy, int alpha );
146: void playSound( Mix_Chunk *sound );
147: void setFullScreenMode( void );
148:
149: int flyTimer = 0;
150: int gatorTimer = 0;
151: int level = 0;
152: int playing = 0;
153: int lives = 0;
154: int players = 0;
155: int score = 0;
156: int givenFreeFrog = 0;
157: int hScore = HIGH_SCORE;
158: int redraw_all = 0;
159: int fullscreen = 0;
160: int drawBG = 0;
161: int goDelay;
162: float timeLeft;
163: talosObj talos;
164:
165: Mix_Chunk *s_freeFrog;
166: SDL_Surface *gfx;
167: SDL_Surface *background; // This is the talos back drop
168: SDL_Rect backgroundRect;
169: SDL_Surface *titleSurface; // Title 'Froggix' image
170: SDL_Surface *screen; //This pointer will reference the backbuffer
171: SDL_Rect leftBorderRect;
172: SDL_Rect rightBorderRect;
173: TTF_Font *font;
174:
175: int debugBorder = 0;
176:
177: /*
178: * int mySDLInit(void);
179: *
180: * This starts the basic SDL initialization for everything we'll need
181: *
182: */
183: int mySDLInit( void ) {
184: int result = 1;
185:
186: if( SDL_Init( SDL_INIT_VIDEO ) != 0 ) {
187: fprintf( stderr, "Warning: Unable to initialize video: %s\n", SDL_GetError( ) );
188: result--;
189: }
190:
191: if( TTF_Init( ) == -1 ) {
192: fprintf( stderr, "Warning: Unable to initialize font engine: %s\n", TTF_GetError( ) );
193: result--;
194: }
195:
196: if( SDL_Init( SDL_INIT_AUDIO ) != 0 ) {
197: fprintf( stderr, "Warning: Unable to initialize audio: %s\n", SDL_GetError( ) );
198: result--;
199: }
200:
201: if( Mix_OpenAudio( 11025, AUDIO_S16, 2, 512 ) < 0 ) {
202: fprintf( stderr, "Warning: Audio set failed: %s\n", SDL_GetError( ) );
203: result--;
204: }
205:
206: screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, 16, SDL_HWSURFACE );
207:
208: if ( screen == NULL ) {
209: fprintf( stderr, "Error: Unable to set video mode: %s\n", SDL_GetError( ) );
210: result--;
211: }
212:
213: SDL_WM_SetCaption( TITLE, NULL );
214:
215: return result;
216: }
217:
218: /*
219: * void beginGame( void );
220: *
221: * Main game routine
222: */
223: void beginGame( void ) {
224: float next_heartbeat = 0;
225: SDL_Event event;
226: int done = 0;
227:
228: printf ( "D: Starting main game loop\n" );
229:
230: if ( loadMedia( ) <= 0 ) {
231: fprintf( stderr, "Error: Failed to load graphics and audio!\n" );
232: return;
233: }
234:
235: drawBackground( );
236:
237: while( ! done ) {
238: while( SDL_PollEvent( &event ) ) {
239: done = keyEvents( event );
240: }
241:
242: /* Check the heartbeat to see if we're ready */
243: if ( SDL_GetTicks( ) >= next_heartbeat ) {
244: next_heartbeat = SDL_GetTicks( ) + heartbeat( );
245: }
246: SDL_Delay( 30 );
247: }
248:
249: SDL_FreeSurface( gfx );
250: }
251:
252: int loadMedia( void ) {
253: int result = 1;
254:
255: /*
256: * Load talos's textures and sounds
257: */
258: gfx = IMG_Load( "images/talos.png" );
259: if ( gfx == NULL ) {
260: fprintf( stderr, "Error: 'images/talos.bmp' could not be open: %s\n", SDL_GetError( ) );
261: result--;
262: }
263:
264: if ( SDL_SetColorKey( gfx, SDL_SRCCOLORKEY | SDL_RLEACCEL, SDL_MapRGB( gfx->format, COLORKEY ) ) == -1 )
265: fprintf( stderr, "Warning: colorkey will not be used, reason: %s\n", SDL_GetError( ) );
266:
267: background = IMG_Load( "images/gameboard.png" );
268:
269: if ( gfx == NULL ) {
270: fprintf( stderr, "Error: 'images/gameboard.png' could not be open: %s\n", SDL_GetError( ) );
271: result--;
272: }
273:
274: titleSurface = IMG_Load( "images/talos-title.png" );
275: if ( titleSurface == NULL ) {
276: fprintf( stderr, "Error: 'images/talos-title.png' could not be open: %s\n", SDL_GetError( ) );
277: result--;
278: }
279:
280: font = TTF_OpenFont( "fonts/CourierNew-Bold.ttf", 22 );
281: if ( font == NULL ) {
282: printf( "TTF_OpenFont: %s\n", TTF_GetError( ) );
283: result--;
284: }
285:
286: talos.s_hop = Mix_LoadWAV( "sounds/talos-hop.wav" );
287:
288: if ( talos.s_hop == NULL )
289: fprintf( stderr, "Warning: dp_talos_hop.wav could not be opened: %s\n", SDL_GetError( ) );
290:
291: talos.s_squash = Mix_LoadWAV( "sounds/dp_talos_squash.wav" );
292: if ( talos.s_squash == NULL )
293: fprintf( stderr, "Warning: dp_talos_plunk could not be opened %s\n", SDL_GetError( ));
294:
295: talos.s_splash = Mix_LoadWAV( "sounds/dp_talos_plunk.wav" );
296: if ( talos.s_splash == NULL )
297: fprintf( stderr, "Warning: dp_talos_splash could not be opened %s\n", SDL_GetError( ));
298:
299: s_freeFrog = Mix_LoadWAV( "sounds/dp_talos_extra.wav" );
300: if ( s_freeFrog == NULL )
301: fprintf( stderr, "Warning: dp_talos_extra could not be opened %s\n", SDL_GetError( ));
302:
303: return result;
304: }
305:
306: /*
307: * void keyEvents( void );
308: *
309: * Process the incoming keyboard and mouse events
310: *
311: */
312: int keyEvents( SDL_Event event ) {
313: int done = 0;
314:
315: /* Always check for shutdown */
316: switch( event.type ) {
317: case SDL_QUIT:
318: done = 1;
319: break;
320: case SDL_KEYDOWN:
321: /* printf( "Found key: %i\n", event.key.keysym.sym );*/
322: switch( event.key.keysym.sym ) {
323: case SDLK_ESCAPE:
324: done = 1;
325: break;
326: case 102:
327: setFullScreenMode( );
328: break;
329: default:
330: break;
331: }
332: break;
333: default:
334: break;
335: }
336: /* We are playing the game */
337: if ( level ) {
338: /* Main game playing input */
339: if ( playing ) {
340: if ( event.type == SDL_KEYDOWN && talos.alive ) {
341: switch( event.key.keysym.sym ) {
342: case SDLK_UP:
343: if ( ! talos.direction ) {
344: talos.hopCount = 0;
345: talos.direction = UP;
346: talos.currentRow++;
347: playSound( talos.s_hop );
348: }
349: break;
350: case SDLK_DOWN:
351: if ( ! talos.direction ) {
352: talos.hopCount = 0;
353: talos.direction = DOWN;
354: talos.currentRow--;
355: playSound( talos.s_hop );
356: }
357: break;
358: case SDLK_LEFT:
359: if ( ! talos.direction ) {
360: talos.hopCount = 0;
361: talos.direction = LEFT;
362: playSound( talos.s_hop );
363: }
364: break;
365: case SDLK_RIGHT:
366: if ( ! talos.direction ) {
367: talos.hopCount = 0;
368: talos.direction = RIGHT;
369: playSound( talos.s_hop );
370: }
371: break;
372: case 108:
373: levelUp( );
374: fprintf( stderr, "Increase level to %i.\n", level );
375: break;
376: default:
377: break;
378: }
379: /* Uncomment for positioning debug information
380: printf( "x,y,d => %i,%i,%i,%i\n", talos.placement[X],
381: talos.placement[Y],
382: talos.direction,
383: talos.currentRow );
384: */
385: }
386: /* Game over man, game over! */
387: if ( ! lives ) {
388:
389: }
390: }
391: /* we're at the pause screen */
392: else {
393:
394: }
395: }
396: /* Main intro screen input */
397: else {
398: if ( event.type == SDL_KEYUP ) {
399: switch( event.key.keysym.sym ) {
400: case SDLK_ESCAPE:
401: done = 1;
402: break;
403: case SDLK_1:
404: printf( "D: Starting single player game\n" );
405: level = 1;
406: lives = LIVES;
407: playing = TRUE;
408: score = 0;
409: players = 1;
410: redraw_all = 1;
411: break;
412: default:
413: break;
414: }
415: }
416: }
417:
418: return done;
419: }
420:
421: int updateGameState( void ) {
422:
423: if ( ! drawBG ) configGameScreen( );
424:
425: if ( lives <= 0 ) {
426: goDelay++;
427: drawGameOver( );
428: /* Display game over screen for 50 ticks before returning
429: * to the main screen */
430: if ( goDelay > 7 ) {
431: playing = 0;
432: lives = 0;
433: level = 0;
434: score = 0;
435: givenFreeFrog = 0;
436: drawBG = 0;
437:
438: }
439: return 500;
440: }
441:
442: drawGameScreen( );
443:
444: return 50;
445: }
446:
447: void configGameScreen( void ) {
448: drawBG = 1;
449:
450: /*
451: * Draw background map
452: */
453: //drawBackground( );
454: drawImage( background, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, screen, 0, 0, 255 );
455:
456: /* Cars drive on rows 1 - 5
457: * Logs are on rows 8, 9 and 11, 8 = short, 9 long, 11 medium
458: * Turtles are on rows 7, 10
459: * Frogger starts on Row 0,
460: * Sidewalk is row 6
461: * and the goal is row 12
462: */
463:
464: /* I MUST figure out a better way to handle the logs, turtles and cars */
465:
466: /*
467: * Draw talos in starting position
468: */
469: talosReset( );
470: }
471:
472: void drawGameScreen( void ) {
473: /*
474: * Update talos
475: */
476: if ( talos.direction ) moveFrogger( );
477: if ( talos.riding ) ridingFrogger( );
478:
479: /*
480: * Update and draw everthing else
481: */
482: checkFly( );
483: checkGator( );
484: drawImage( background, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, screen, 0, 0, 255 );
485: drawScore( 0, score );
486: drawScore( 1, hScore );
487: drawGoals( );
488: drawLives( lives );
489: drawLevel( level );
490: drawWood( );
491: drawTurtles( );
492: drawVehicles( );
493:
494: if ( talos.alive == FALSE ) {
495: talos.riding = FALSE;
496: if ( ! drawDeathSequence( talos.deathType ) ) {
497: lives--;
498: if ( lives < 0 ) { drawGameOver( ); }
499: else { talosReset( ); }
500: }
501: }
502:
503: if ( talos.alive ) {
504: talos.alive = checkTimer( );
505: drawImage( gfx, talos.src.x, talos.src.y, talos.src.w,
506: talos.src.h, screen, talos.dst.x, talos.dst.y, 255 );
507: }
508: if ( ! debugBorder ) {
509: SDL_FillRect( screen, &leftBorderRect, SDL_MapRGB( screen->format, BGCOLOR ) );
510: SDL_FillRect( screen, &rightBorderRect, SDL_MapRGB( screen->format, BGCOLOR ) );
511: }
512:
513: SDL_Flip( screen );
514: }
515:
516: void drawBackground( void ) {
517: /*
518: * Draw background map
519: */
520: backgroundRect.x = 0;
521: backgroundRect.y = 0;
522: SDL_BlitSurface( background, NULL, screen, &backgroundRect );
523: SDL_UpdateRect( screen, 0, 0, 0, 0 );
524: }
525:
526: /*
527: * This calculates the pixel top of the requested row
528: */
529: int getRowPixel ( int row ) {
530: return 0;//ROW_BASE - ( row * HOP_DISTANCE );
531: }
532:
533: /*
534: * Check our fly timers to determine if we need to display or
535: * remove a fly from the goal area
536: */
537: void checkFly ( void ) {
538: }
539:
540: /*
541: * Check our gator timers. Similiar to fly timers above, however, the gator
542: * has an extra stage as it enters in to the goal area.
543: */
544: void checkGator ( void ) {
545: }
546:
547: /*
548: * This does collision detection based on the row talos
549: * is in to help reduce overhead
550: */
551: int collisionRow ( void ) {
552: return 0;
553: }
554:
555: /* If the player gets enough points, award them a free talos */
556: int freeFrog ( int score ) {
557: return 0;
558: }
559:
560: /* Check what talos is colliding with */
561: int collideFrogger ( int x, int y, int h, int w ) {
562: h++; w++;
563:
564: if ( ( talos.placement[Y] >= ( y + h ) ) ||
565: ( talos.placement[X] >= ( x + w ) ) ||
566: ( y >= ( talos.placement[Y] + FRAME ) ) ||
567: ( x >= ( talos.placement[X] + FRAME ) ) ) {
568: return( 0 );
569: }
570: return( 1 );
571: }
572:
573: /* Check left and right borders */
574: void checkFroggerBorder( void ) {
575:
576: }
577:
578: void levelUp ( void ) {
579: }
580:
581: int checkGoals ( void ) {
582: return 0;
583: }
584:
585: void talosReset ( void ) {
586: }
587:
588: /*
589: * This actually moves talos... I need to come up with a better
590: * algorithm for calculating the distance and time
591: */
592: void moveFrogger( void ) {
593: int x = 0;
594: int y = 0;
595: int h = FRAME;
596: int w = FRAME;
597:
598: talos.oldPlacement[Y] = talos.placement[Y];
599: talos.oldPlacement[X] = talos.placement[X];
600:
601: switch( talos.direction ) {
602: case UP:
603: x = FRAME;
604: // talos.placement[Y] -= ( HOP_DISTANCE / HOP_SPEED );
605: break;
606: case DOWN:
607: x = ( 5 * FRAME );
608: // talos.placement[Y] += ( HOP_DISTANCE / HOP_SPEED );
609: break;
610: case LEFT:
611: x = ( 7 * FRAME );
612: // talos.placement[X] -= ( HOP_DISTANCE / HOP_SPEED );
613: break;
614: case RIGHT:
615: x = ( 3 * FRAME );
616: //talos.placement[X] += ( HOP_DISTANCE / HOP_SPEED );
617: break;
618: }
619:
620: checkFroggerBorder( );
621:
622: /* select the frame to display */
623: talos.src.y = y;
624: talos.src.x = x;
625: talos.src.w = w;
626: talos.src.h = h;
627:
628: /* Set the old place to be erased */
629: talos.dst.y = talos.oldPlacement[Y];
630: talos.dst.x = talos.oldPlacement[X];
631:
632: SDL_FillRect( screen, NULL, SDL_MapRGB( screen->format, BGCOLOR ) );
633:
634: /* Place the new position */
635: talos.dst.y = talos.placement[Y];
636: talos.dst.x = talos.placement[X];
637:
638: talos.hopCount++;
639:
640: }
641:
642: void ridingFrogger( void ) {
643: }
644:
645: void drawTitleScreen( void ) {
646: SDL_Surface *introText;
647: SDL_Color fontColor = { 123, 158, 53, 255 };
648: int center = ( SCREEN_WIDTH / 2 ) - ( titleSurface->w / 2 );
649: int i;
650: char *txt[] = { "Press 1 for single player game",
651: "Press 2 for two player games",
652: "Press F for full screen mode",
653: "Press ESC to quit" };
654:
655: // drawBackground( );
656:
657: drawImage( titleSurface, 0, 0, titleSurface->w,
658: titleSurface->h, screen, center, 100, 255 );
659:
660: for( i = 0; i <= 3; i++ ) {
661: introText = TTF_RenderText_Solid( font, txt[i], fontColor );
662: drawImage( introText, 0, 0, introText->w, introText->h, screen,
663: 140, 300 + ( i * introText->h ), 255 );
664: }
665:
666: SDL_Flip( screen );
667: }
668:
669: void drawPauseScreen( void ) {
670: printf( "D: Draw Pause Screen\n" );
671:
672: }
673:
674: void drawGameOver( void ) {
675: printf( "D: Game Over\n" );
676: }
677:
678: void playSound( Mix_Chunk *sound ) {
679: Mix_PlayChannel( -1, sound, 0 );
680: }
681:
682: void setFullScreenMode( void ) {
683: /* Lets give fullscreen mode a try */
684: if ( ! fullscreen ) {
685: screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, 16, SDL_HWSURFACE | SDL_FULLSCREEN );
686: fullscreen = TRUE;
687: }
688: /* Switch back to window mode */
689: else {
690: screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, 16, SDL_HWSURFACE );
691: fullscreen = FALSE;
692: }
693:
694: printf( "D: Fullscreen : %i\n", fullscreen );
695: }
696:
697: int drawDeathSequence( int deathType ) {
698: return 1;
699: }
700:
701: /* draw green timer and return 0 if out of time */
702: int checkTimer( void ) {
703: return 1;
704: }
705:
706: void drawScore( int high, int score ) {
707: int x = 169;
708: int y = 14;
709:
710: if ( score > hScore ) hScore = score;
711: if ( high ) x = 260;
712:
713: drawNumbers( score, x, y );
714: }
715:
716: void drawNumbers( int num, int x, int y ) {
717: char numStr[6] = "00000";
718: int i;
719:
720: /* Assume anything less than 50 pixels location is a score and
721: * pad with '0'.
722: */
723: if ( y <= 15 ) sprintf( numStr, "%05i", num );
724: else sprintf( numStr, "%i", num );
725:
726: for ( i = 0; i <= 4; i++ ) {
727: char c = numStr[i];
728: int n = atoi( &c );
729:
730: drawImage( gfx, n * HFRAME, FRAME * 3 , HFRAME, FRAME,
731: screen, x + ( i * HFRAME ) + 2, y, 255 );
732: }
733: }
734:
735: /* Normally this functions manages and draws the flys, gators and saved taloss
736: * but if drawDebugRect below is turned on it will draw the rectangle
737: * used for collision detectiong for debuggin purposes in timer green
738: */
739: void drawGoals( void ) {
740:
741: }
742:
743: void drawTimer( int length ) {
744: }
745:
746: void drawLives( int lives ) {
747: }
748:
749: void drawLevel( int level ) {
750: }
751:
752: void drawWood ( void ) {
753: }
754:
755: void drawTurtles ( void ) {
756: }
757:
758: void drawVehicles ( void ) {
759:
760: }
761:
762: void drawImage( SDL_Surface *srcimg, int sx, int sy, int sw, int sh,
763: SDL_Surface *dstimg, int dx, int dy, int alpha ) {
764: if ((!srcimg) || (alpha == 0)) return;
765: SDL_Rect src, dst;
766:
767: src.x = sx; src.y = sy; src.w = sw; src.h = sh;
768: dst.x = dx; dst.y = dy; dst.w = src.w; dst.h = src.h;
769:
770: if (alpha != 255) SDL_SetAlpha(srcimg, SDL_SRCALPHA, alpha);
771: SDL_BlitSurface(srcimg, &src, dstimg, &dst);
772: }
773:
774: int heartbeat ( void ) {
775: int ticks;
776: if ( level ) {
777: if ( playing ) {
778: ticks = updateGameState( );
779: if ( ticks <= 0 ) ticks = 50;
780: return ticks;
781: }
782: else {
783: drawPauseScreen( );
784: return 500;
785: }
786: }
787: else {
788: drawTitleScreen( );
789: return 500;
790: }
791:
792: return 50;
793: }
794:
795: /*
796: * Main program starts here. We'll init the video and audio
797: * and then begin our main program loop here
798: *
799: */
800: int main ( int argc, char **argv ) {
801: if ( mySDLInit( ) <= 0 ) {
802: fprintf( stderr, "Failure to start %s\n", TITLE );
803: return 255;
804: }
805:
806: beginGame( );
807:
808: SDL_Quit( );
809:
810: return 0;
811: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>