Annotation of froggix/src/froggix.c, revision 1.2
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: */
1.2 ! nick 28: #define VERSION "$Id: froggix.c,v 1.1 2009-03-28 03:48:45 nick Exp $"
1.1 nick 29: #define TITLE "Froggix"
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 FROGGER_START_X 290
38: #define FROGGER_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: #define HOP_DISTANCE 30
48: #define HOP_SPEED 3
49: #define ROW_BASE 425
50: #define LEFT_SIDE 115
51: #define RIGHT_SIDE 525
52: #define SPLASH 1 /* Death types */
53: #define SPLAT 2
54:
55: /* Point table */
56: #define SCORE_HOP 10
57: #define SCORE_GOAL 50
58: #define SCORE_LEVEL 1000
59: #define SCORE_FLY 150
60: #define SCORE_PINK 200
61: #define SCORE_SECONDS 10
62: #define HIGH_SCORE 4630
63: #define SCORE_FREE_FROG 200
64:
65: /* The green game timer */
66: #define MAX_TIMER 350
67: #define TIMER_SIZE 150
68: #define TIMER_COLOR 32, 211, 0
69: #define TIMER_LOW_COLOR 255, 0, 0
70:
71: /* baddies */
72: #define VEHICLE 0
73: #define LOG 1
74: #define TURTLE 2
75: #define GATOR 3
76: #define SNAKE 4
77: #define BEAVER 5
78:
79: /* Goal areas */
80: #define MAX_GOALS 5
81:
82: /* logs */
83: #define SHORT_LOG 4
84: #define MEDIUM_LOG 6
85: #define LONG_LOG 9
86: #define MAX_WOOD 7
87:
88: /* Turtles */
89: #define DIVE_START_TIME 50
90: #define DIVE_PHASE_TIME 20
91: #define MAX_TURTLES 9
92: #define TURTLE_ANIM_TIME 5
93:
94: /* Vehicles */
95: #define MAX_VEHICLES 40
96:
97:
98: /*
99: * Froggers dstruct
100: */
101: typedef struct {
102: int placement[2];
103: int oldPlacement[2];
104: int direction;
105: int location;
106: int hopCount;
107: int currentRow;
108: int alive;
109: int riding;
110: int ridingIdx;
111: int ridingType;
112: int frogger; /* Are we frogger or bonus frog */
113: int deathType;
114: int deathCount;
115:
116: SDL_Rect src;
117: SDL_Rect dst;
118:
119: Mix_Chunk *s_hop;
120: Mix_Chunk *s_squash;
121: Mix_Chunk *s_splash;
122: Mix_Chunk *s_extra;
123: } froggerObj;
124:
125: /*
126: * Goals
127: */
128: typedef struct {
129: int x, y, w, h;
130: int occupied;
131: int fly;
132: int gator;
133: } goalObj;
134:
135: /*
136: * Vehicles
137: */
138: typedef struct {
139: int placement[2];
140: int oldPlacement[2];
141: int direction; // LEFT or RIGHT
142: int row; // row
143: int speed; // How fast are we traveling
144: int level; // Must be >= this level to display
145:
146: SDL_Rect src;
147: } vehicleObj;
148:
149: /*
150: * It's Log!
151: */
152: typedef struct {
153: int placement[2];
154: int oldPlacement[2];
155: int row; /* Current row we are in */
156: int type; /* SHORT, MEDIUM, or LONG */
157: int speed; /* What speed does the log move at */
158: int hasPink; // Is bonus frog riding
159:
160: SDL_Rect src;
161: } logObj;
162:
163: /*
164: * Turtles
165: */
166: typedef struct {
167: int placement[2];
168: int oldPlacement[2];
169: int row; /* Which row are the turtles in? */
170: int count; /* How many turtles in this group? */
171: int speed; /* How fast are they swimming */
172: int canDive; /* Can this group dive */
173: int diveStep; /* If they can dive, what diving step are then in */
174: int diveTime; /* Current dive time */
175: int animStep; /* Current animation frame */
176: int animDelay; /* The number of ticks to wait between frames */
177:
178: SDL_Rect src;
179: } turtleObj;
180:
181: int keyEvents( SDL_Event event );
182: int mySDLInit( void );
183: void beginGame( void );
184: int loadMedia( void );
185: int heartbeat( void );
186: int updateGameState( void );
187: void configGameScreen( void );
188: void drawGameScreen( void );
189: void drawBackground( void );
190: int getRowPixel ( int row );
191: int collisionRow ( void );
192: int freeFrog( int score );
193: int collideFrogger ( int x, int y, int h, int w );
194: void checkFroggerBorder( void );
195: void levelUp( void );
196: int checkGoals( void );
197: void froggerReset( void );
198: logObj setWood( int type, int speed, int row, int startX );
199: turtleObj setTurtle( int dive, int diveTimer, int speed, int row, int startX, int count );
200: vehicleObj setVehicle( int row, int startX, int speed, int level );
201: goalObj setGoal( int x, int y, int w, int h );
202: void moveFrogger( void );
203: void ridingFrogger( );
204: void drawTitleScreen( void );
205: void drawPauseScreen( void );
206: void drawGameOver( void );
207: int drawDeathSequence( int deathType );
208: int checkTimer( void );
209: void drawScore( int high, int score );
210: void drawNumbers( int num, int x, int y );
211: void drawGoals( void );
212: void drawTimer( int length );
213: void drawLives( int lives );
214: void drawLevel( int level );
215: void drawWood( void );
216: void drawTurtles( void );
217: void drawVehicles( void );
218: void drawImage(SDL_Surface *srcimg, int sx, int sy, int sw, int sh, SDL_Surface *dstimg, int dx, int dy, int alpha );
219: void playSound( Mix_Chunk *sound );
220: void setFullScreenMode( void );
221:
222: int level = 0;
223: int playing = 0;
224: int lives = 0;
225: int players = 0;
226: int score = 0;
227: int givenFreeFrog = 0;
228: int hScore = HIGH_SCORE;
229: int redraw_all = 0;
230: int fullscreen = 0;
231: int drawBG = 0;
232: int goDelay;
233: float timeLeft;
234: froggerObj frogger;
235: logObj wood[MAX_WOOD];
236: turtleObj turtle[MAX_TURTLES];
237: vehicleObj vehicle[MAX_VEHICLES];
238: goalObj goals[MAX_GOALS];
239:
240: Mix_Chunk *s_freeFrog;
241: SDL_Surface *gfx;
242: SDL_Surface *background; // This is the frogger back drop
243: SDL_Rect backgroundRect;
244: SDL_Surface *titleSurface; // Title 'Froggix' image
245: SDL_Surface *screen; //This pointer will reference the backbuffer
246: SDL_Rect leftBorderRect;
247: SDL_Rect rightBorderRect;
248: TTF_Font *font;
249:
250: int debugBorder = 0;
251:
252: /*
253: * int mySDLInit(void);
254: *
255: * This starts the basic SDL initialization for everything we'll need
256: *
257: */
258: int mySDLInit( void ) {
259: int result = 1;
260:
261: if( SDL_Init( SDL_INIT_VIDEO ) != 0 ) {
262: fprintf( stderr, "Warning: Unable to initialize video: %s\n", SDL_GetError( ) );
263: result--;
264: }
265:
266: if( TTF_Init( ) == -1 ) {
267: fprintf( stderr, "Warning: Unable to initialize font engine: %s\n", TTF_GetError( ) );
268: result--;
269: }
270:
271: if( SDL_Init( SDL_INIT_AUDIO ) != 0 ) {
272: fprintf( stderr, "Warning: Unable to initialize audio: %s\n", SDL_GetError( ) );
273: result--;
274: }
275:
276: if( Mix_OpenAudio( 11025, AUDIO_S16, 2, 512 ) < 0 ) {
277: fprintf( stderr, "Warning: Audio set failed: %s\n", SDL_GetError( ) );
278: result--;
279: }
280:
281: screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, 16, SDL_HWSURFACE );
282:
283: if ( screen == NULL ) {
284: fprintf( stderr, "Error: Unable to set video mode: %s\n", SDL_GetError( ) );
285: result--;
286: }
287:
288: SDL_WM_SetCaption( TITLE, NULL );
289:
290: return result;
291: }
292:
293: /*
294: * void beginGame( void );
295: *
296: * Main game routine
297: */
298: void beginGame( void ) {
299: float next_heartbeat = 0;
300: SDL_Event event;
301: int done = 0;
302:
303: printf ( "D: Starting main game loop\n" );
304:
305: if ( loadMedia( ) <= 0 ) {
306: fprintf( stderr, "Error: Failed to load graphics and audio!\n" );
307: return;
308: }
309:
310: drawBackground( );
311:
312: while( ! done ) {
313: while( SDL_PollEvent( &event ) ) {
314: done = keyEvents( event );
315: }
316:
317: /* Check the heartbeat to see if we're ready */
318: if ( SDL_GetTicks( ) >= next_heartbeat ) {
319: next_heartbeat = SDL_GetTicks( ) + heartbeat( );
320: }
321: SDL_Delay( 30 );
322: }
323:
324: SDL_FreeSurface( gfx );
325: }
326:
327: int loadMedia( void ) {
328: int result = 1;
329:
330: /*
331: * Load frogger's textures and sounds
332: */
333: gfx = IMG_Load( "images/frogger.png" );
1.2 ! nick 334: frogger.riding = FALSE;
1.1 nick 335:
336: if ( gfx == NULL ) {
337: fprintf( stderr, "Error: 'images/frogger.bmp' could not be open: %s\n", SDL_GetError( ) );
338: result--;
339: }
340:
341: if ( SDL_SetColorKey( gfx, SDL_SRCCOLORKEY | SDL_RLEACCEL, SDL_MapRGB( gfx->format, COLORKEY ) ) == -1 )
342: fprintf( stderr, "Warning: colorkey will not be used, reason: %s\n", SDL_GetError( ) );
343:
344: background = IMG_Load( "images/gameboard.png" );
345:
346: if ( gfx == NULL ) {
347: fprintf( stderr, "Error: 'images/gameboard.png' could not be open: %s\n", SDL_GetError( ) );
348: result--;
349: }
350:
351: titleSurface = IMG_Load( "images/froggix-title.png" );
352: if ( titleSurface == NULL ) {
353: fprintf( stderr, "Error: 'images/froggix-title.png' could not be open: %s\n", SDL_GetError( ) );
354: result--;
355: }
356:
357: font = TTF_OpenFont( "fonts/CourierNew-Bold.ttf", 22 );
358: if ( font == NULL ) {
359: printf( "TTF_OpenFont: %s\n", TTF_GetError( ) );
360: result--;
361: }
362:
363: frogger.s_hop = Mix_LoadWAV( "sounds/froggix-hop.wav" );
364:
365: if ( frogger.s_hop == NULL )
366: fprintf( stderr, "Warning: dp_frogger_hop.wav could not be opened: %s\n", SDL_GetError( ) );
367:
368: frogger.s_squash = Mix_LoadWAV( "sounds/dp_frogger_squash.wav" );
369: if ( frogger.s_squash == NULL )
370: fprintf( stderr, "Warning: dp_frogger_plunk could not be opened %s\n", SDL_GetError( ));
371:
372: frogger.s_splash = Mix_LoadWAV( "sounds/dp_frogger_plunk.wav" );
373: if ( frogger.s_splash == NULL )
374: fprintf( stderr, "Warning: dp_frogger_splash could not be opened %s\n", SDL_GetError( ));
375:
376: s_freeFrog = Mix_LoadWAV( "sounds/dp_frogger_extra.wav" );
377: if ( s_freeFrog == NULL )
378: fprintf( stderr, "Warning: dp_frogger_extra could not be opened %s\n", SDL_GetError( ));
379:
380: return result;
381: }
382:
383: /*
384: * void keyEvents( void );
385: *
386: * Process the incoming keyboard and mouse events
387: *
388: */
389: int keyEvents( SDL_Event event ) {
390: int done = 0;
391:
392: /* Always check for shutdown */
393: switch( event.type ) {
394: case SDL_QUIT:
395: done = 1;
396: break;
397: case SDL_KEYDOWN:
398: /* printf( "Found key: %i\n", event.key.keysym.sym );*/
399: switch( event.key.keysym.sym ) {
400: case SDLK_ESCAPE:
401: done = 1;
402: break;
403: case 102:
404: setFullScreenMode( );
405: break;
406: default:
407: break;
408: }
409: break;
410: default:
411: break;
412: }
413: /* We are playing the game */
414: if ( level ) {
415: /* Main game playing input */
416: if ( playing ) {
417: if ( event.type == SDL_KEYDOWN && frogger.alive ) {
418: switch( event.key.keysym.sym ) {
419: case SDLK_UP:
420: if ( ! frogger.direction ) {
421: frogger.hopCount = 0;
422: frogger.direction = UP;
423: frogger.currentRow++;
424: playSound( frogger.s_hop );
425: }
426: break;
427: case SDLK_DOWN:
428: if ( ! frogger.direction ) {
429: frogger.hopCount = 0;
430: frogger.direction = DOWN;
431: frogger.currentRow--;
432: playSound( frogger.s_hop );
433: }
434: break;
435: case SDLK_LEFT:
436: if ( ! frogger.direction ) {
437: frogger.hopCount = 0;
438: frogger.direction = LEFT;
439: playSound( frogger.s_hop );
440: }
441: break;
442: case SDLK_RIGHT:
443: if ( ! frogger.direction ) {
444: frogger.hopCount = 0;
445: frogger.direction = RIGHT;
446: playSound( frogger.s_hop );
447: }
448: break;
449: case 108:
450: levelUp( );
451: fprintf( stderr, "Increase level to %i.\n", level );
452: break;
453: default:
454: break;
455: }
456: printf( "x,y,d => %i,%i,%i,%i\n", frogger.placement[X],
457: frogger.placement[Y],
458: frogger.direction,
459: frogger.currentRow );
460: }
461: /* Game over man, game over! */
462: if ( ! lives ) {
463:
464: }
465: }
466: /* we're at the pause screen */
467: else {
468:
469: }
470: }
471: /* Main intro screen input */
472: else {
473: if ( event.type == SDL_KEYUP ) {
474: switch( event.key.keysym.sym ) {
475: case SDLK_ESCAPE:
476: done = 1;
477: break;
478: case SDLK_1:
479: printf( "D: Starting single player game\n" );
480: level = 1;
481: lives = LIVES;
482: playing = TRUE;
483: score = 0;
484: players = 1;
485: redraw_all = 1;
486: break;
487: default:
488: break;
489: }
490: }
491: }
492:
493: return done;
494: }
495:
496: int updateGameState( void ) {
1.2 ! nick 497: int i;
! 498:
1.1 nick 499: if ( ! drawBG ) configGameScreen( );
500:
501: if ( lives <= 0 ) {
502: goDelay++;
503: drawGameOver( );
504: /* Display game over screen for 50 ticks before returning
505: * to the main screen */
506: if ( goDelay > 7 ) {
507: playing = 0;
508: lives = 0;
509: level = 0;
1.2 ! nick 510: score = 0;
! 511: givenFreeFrog = 0;
! 512: drawBG = 0;
! 513: for ( i = 0; i < MAX_GOALS; i++ ) { goals[i].occupied = 0; }
! 514:
1.1 nick 515: }
516: return 500;
517: }
518:
519: drawGameScreen( );
520:
521: return 50;
522: }
523:
524: logObj setWood( int type, int speed, int row, int startX ) {
525: logObj tempWood;
526: int imgPixelSrc = 0;
527:
528: switch( type ) {
529: case LONG_LOG:
530: imgPixelSrc = 0;
531: break;
532: case MEDIUM_LOG:
533: imgPixelSrc = FRAME * LONG_LOG;
534: break;
535: case SHORT_LOG:
536: imgPixelSrc = FRAME * ( LONG_LOG + MEDIUM_LOG );
537: break;
538: }
539:
540: tempWood.row = row;
541: tempWood.type = type;
542: tempWood.speed = speed;
543: tempWood.hasPink = 0;
544: tempWood.placement[X] = LEFT_SIDE + startX;
545: tempWood.placement[Y] = getRowPixel( row );
546: tempWood.oldPlacement[X] = LEFT_SIDE + startX;
547: tempWood.oldPlacement[Y] = getRowPixel( row );
548: tempWood.src.y = FRAME;
549: tempWood.src.x = imgPixelSrc;
550: tempWood.src.w = FRAME * tempWood.type;
551: tempWood.src.h = FRAME;
552:
553: return tempWood;
554: }
555:
556: turtleObj setTurtle( int dive, int diveTimer, int speed, int row, int startX, int count ) {
557: turtleObj tt;
558:
559: tt.row = row;
560: tt.canDive = dive;
561: tt.diveStep = 0;
562: tt.diveTime = diveTimer;
563: tt.animStep = 0;
564: tt.animDelay = 0;
565: tt.speed = speed;
566: tt.count = count;
567: tt.placement[X] = LEFT_SIDE + startX;
568: tt.placement[Y] = getRowPixel( row );
569: tt.oldPlacement[X] = tt.placement[X];
570: tt.oldPlacement[Y] = tt.placement[Y];
571: tt.src.y = FRAME * 2;
572: tt.src.x = 0;
573: tt.src.w = FRAME;
574: tt.src.h = FRAME;
575:
576: return tt;
577: }
578:
579:
580: vehicleObj setVehicle( int row, int startX, int speed, int level ) {
581: vehicleObj v;
582:
583: v.direction = ( row % 2 ) ? LEFT : RIGHT; /* Odd rows travel left, evens go right */
584: v.row = row;
585: v.speed = speed;
586: v.level = level;
587: v.placement[X] = LEFT_SIDE + startX;
588: v.placement[Y] = getRowPixel( row );
589: v.oldPlacement[X] = v.placement[X];
590: v.oldPlacement[Y] = v.placement[Y];
591: v.src.y = FRAME * 2;
592: v.src.x = FRAME * ( 4 + row );
593: v.src.w = ( row == 5 ) ? FRAME * 2 : FRAME; /* Are we a truck? */
594: v.src.h = FRAME;
595:
596: return v;
597: }
598:
599: goalObj setGoals( int x, int y, int w, int h ) {
600: goalObj g;
601:
602: g.x = x;
603: g.y = y;
604: g.w = w;
605: g.h = h;
606: g.occupied = 0;
607: g.fly = 0;
608: g.gator = 0;
609:
610: return g;
611: }
612:
613: void configGameScreen( void ) {
614: drawBG = 1;
615:
616: /*
617: * Draw background map
618: */
619: //drawBackground( );
620: drawImage( background, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, screen, 0, 0, 255 );
621:
622: /* Cars drive on rows 1 - 5
623: * Logs are on rows 8, 9 and 11, 8 = short, 9 long, 11 medium
624: * Turtles are on rows 7, 10
625: * Frogger starts on Row 0,
626: * Sidewalk is row 6
627: * and the goal is row 12
628: */
629:
630: /* I MUST figure out a better way to handle the logs, turtles and cars */
631:
632: /* Set up the LONG logs on row 9 first */
633: wood[0] = setWood( LONG_LOG, 3, 9, 0 );
634: wood[1] = setWood( LONG_LOG, 3, 9, 305 );
635: wood[2] = setWood( SHORT_LOG, 2, 8, 25 );
636: wood[3] = setWood( SHORT_LOG, 2, 8, 160 );
637: wood[4] = setWood( SHORT_LOG, 2, 8, 380 );
638: wood[5] = setWood( MEDIUM_LOG, 4, 11, 140 );
639: wood[6] = setWood( MEDIUM_LOG, 4, 11, 440 );
640:
641: drawWood( );
642:
643: /* Configure our turtles */
644: turtle[0] = setTurtle( FALSE, 0, 1, 7, 0, 3 );
645: turtle[1] = setTurtle( TRUE, 0, 1, 7, 125, 3 );
646: turtle[2] = setTurtle( FALSE, 0, 1, 7, 250, 3 );
647: turtle[3] = setTurtle( TRUE, 30, 1, 7, 375, 3 );
648: turtle[4] = setTurtle( FALSE, 0, 2, 10, 100, 2 );
649: turtle[5] = setTurtle( TRUE, 50, 2, 10, 200, 2 );
650: turtle[6] = setTurtle( FALSE, 0, 2, 10, 300, 2 );
651: turtle[7] = setTurtle( TRUE, 10, 2, 10, 400, 2 );
652: turtle[8] = setTurtle( FALSE, 0, 2, 10, 500, 2 );
653:
654: drawTurtles( );
655:
656: /* Configure vehicles */
657: /* row, X, speed */
658: /* Row 1 -- yellow car */
659: vehicle[0] = setVehicle( 1, 0, 1, 1 );
660: vehicle[1] = setVehicle( 1, 100, 1, 3 );
661: vehicle[2] = setVehicle( 1, 200, 1, 1 );
662: vehicle[3] = setVehicle( 1, 300, 1, 1 );
663: // /* Row 2 -- tractor */
664: vehicle[4] = setVehicle( 2, 0, 3, 1 );
665: vehicle[5] = setVehicle( 2, 100, 3, 2 );
666: vehicle[6] = setVehicle( 2, 200, 3, 1 );
667: vehicle[7] = setVehicle( 2, 300, 3, 3 );
668: // /* Row 3 -- pink car */
669: vehicle[8] = setVehicle( 3, 75, 2,1 );
670: vehicle[9] = setVehicle( 3, 150, 2, 3 );
671: vehicle[10] = setVehicle( 3, 225, 2, 1 );
672: vehicle[11] = setVehicle( 3, 375, 2, 2 );
673: // /* Row 4 -- white car */
674: vehicle[12] = setVehicle( 4, 75, 5, 1 );
675: vehicle[13] = setVehicle( 4, 150, 5, 3 );
676: vehicle[14] = setVehicle( 4, 225, 5, 2 );
677: vehicle[15] = setVehicle( 4, 375, 5, 3 );
678: // /* Row 5 -- Trucks */
679: vehicle[16] = setVehicle( 5, 30, 3, 1 );
680: vehicle[17] = setVehicle( 5, 150, 3, 1 );
681: vehicle[18] = setVehicle( 5, 250, 3, 1 );
682: vehicle[19] = setVehicle( 5, 350, 3, 3 );
683:
684: drawVehicles( );
685:
686: /* Configure the goals for frogger */
687: goals[0] = setGoals( LEFT_SIDE + 3, 55, 43, 35 );
688: goals[1] = setGoals( LEFT_SIDE + 91, 55, 43, 35 );
689: goals[2] = setGoals( LEFT_SIDE + 179, 55, 43, 35 );
690: goals[3] = setGoals( LEFT_SIDE + 267, 55, 43, 35 );
691: goals[4] = setGoals( LEFT_SIDE + 355, 55, 43, 35 );
692:
693: /*
694: * Configure the left and right side black borders to conceal logs,
695: * turtles, cars, etc. that go past their boundries
696: */
697: leftBorderRect.x = 0;
698: leftBorderRect.y = 0;
699: leftBorderRect.w = LEFT_SIDE;
700: leftBorderRect.h = SCREEN_HEIGHT;
701:
702: rightBorderRect.x = RIGHT_SIDE;
703: rightBorderRect.y = 0;
704: rightBorderRect.w = SCREEN_WIDTH - RIGHT_SIDE;
705: rightBorderRect.h = SCREEN_HEIGHT;
706:
707:
708: /*
709: * Draw frogger in starting position
710: */
711: froggerReset( );
712: }
713:
714: void drawGameScreen( void ) {
715: /*
716: * Update frogger
717: */
718: if ( frogger.direction ) moveFrogger( );
719: if ( frogger.riding ) ridingFrogger( );
720:
721: /* Check for collisions with frogger */
722: if ( frogger.alive ) {
723: if ( frogger.currentRow > 6 && frogger.currentRow < 12 ) {
724: if ( ( ! collisionRow( ) ) || ( frogger.riding == FALSE ) ) {
725: playSound( frogger.s_splash );
726: frogger.deathType = SPLASH;
727: fprintf( stderr, "D: Frog in water!!\n" );
728: frogger.alive = FALSE;
729: }
730: }
731: else if ( frogger.currentRow == 12 ) {
732: if ( collisionRow( ) ) {
733: playSound( frogger.s_squash );
734: frogger.deathType = SPLAT;
735: fprintf( stderr, "D: Frog in thorn bushes!\n" );
736: frogger.alive = FALSE;
737: }
738: }
739: else if( collisionRow( ) ) {
740: playSound( frogger.s_squash );
741: frogger.deathType = SPLAT;
742: fprintf( stderr, "D: Frog Squashed!\n" );
743: frogger.alive = FALSE;
744: }
745: }
746:
747: /*
748: * Update and draw everthing else
749: */
750: drawImage( background, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, screen, 0, 0, 255 );
751: drawScore( 0, score );
752: drawScore( 1, hScore );
753: drawGoals( );
754: drawLives( lives );
755: drawLevel( level );
756: drawWood( );
757: drawTurtles( );
758: drawVehicles( );
759:
760: if ( frogger.alive == FALSE ) {
1.2 ! nick 761: frogger.riding = FALSE;
1.1 nick 762: if ( ! drawDeathSequence( frogger.deathType ) ) {
763: lives--;
764: if ( lives < 0 ) { drawGameOver( ); }
765: else { froggerReset( ); }
766: }
767: }
768:
769: if ( frogger.alive ) {
770: frogger.alive = checkTimer( );
771: drawImage( gfx, frogger.src.x, frogger.src.y, frogger.src.w,
772: frogger.src.h, screen, frogger.dst.x, frogger.dst.y, 255 );
773: }
774: if ( ! debugBorder ) {
775: SDL_FillRect( screen, &leftBorderRect, SDL_MapRGB( screen->format, BGCOLOR ) );
776: SDL_FillRect( screen, &rightBorderRect, SDL_MapRGB( screen->format, BGCOLOR ) );
777: }
778:
779: SDL_Flip( screen );
780: }
781:
782: void drawBackground( void ) {
783: /*
784: * Draw background map
785: */
786: backgroundRect.x = 0;
787: backgroundRect.y = 0;
788: SDL_BlitSurface( background, NULL, screen, &backgroundRect );
789: SDL_UpdateRect( screen, 0, 0, 0, 0 );
790: }
791:
792: /*
793: * This calculates the pixel top of the requested row
794: */
795: int getRowPixel ( int row ) {
796: return ROW_BASE - ( row * HOP_DISTANCE );
797: }
798:
799: /*
800: * This does collision detection based on the row frogger
801: * is in to help reduce overhead
802: */
803: int collisionRow ( void ) {
804: int i;
805:
806: if ( frogger.currentRow <= 0 ) return 0;
807:
808: /* Check collision with cars */
809: if ( frogger.currentRow < 6 ) {
810: for( i = 0; i < MAX_VEHICLES; i++ ) {
811: if ( level >= vehicle[i].level ) {
812: int length = ( vehicle[i].row == 5 ) ? FRAME * 2 : FRAME; /* Trucks */
813: if ( collideFrogger( vehicle[i].placement[X],
814: vehicle[i].placement[Y], FRAME,
815: length ) ) {
816: return 1;
817: }
818: }
819: }
820: return 0;
821: }
822: /* check for collisions with turtles, logs, etc.. */
823: else if ( frogger.currentRow > 6 && frogger.currentRow < 12 ) {
824: /* here a collision is good, else death */
825: for( i = 0; i < MAX_TURTLES; i++ ) {
826: if ( collideFrogger( turtle[i].placement[X],
827: turtle[i].placement[Y], FRAME,
828: FRAME * turtle[i].count ) ) {
829: frogger.riding = ( turtle[i].diveStep == 3 ) ? FALSE : LEFT;
830: frogger.ridingIdx = i;
831: frogger.ridingType = TURTLE;
832: return 1;
833: }
834: }
835: for( i = 0; i < MAX_WOOD; i++ ) {
836: if ( collideFrogger( wood[i].placement[X],
837: wood[i].placement[Y], FRAME,
838: FRAME * wood[i].type ) ) {
839: frogger.riding = RIGHT;
840: frogger.ridingIdx = i;
841: frogger.ridingType = LOG;
842: return 1;
843: }
844: }
845: }
846: /* We're on the path, if the snake is active, check that */
847: else if ( frogger.currentRow == 6 ) {
848: frogger.riding = FALSE; /*in case we hopped off a turtle */
849: }
850: /* This leaves the goal area only */
851: else {
852: for ( i = 0; i < MAX_GOALS; i++ ) {
853: if ( collideFrogger( goals[i].x, goals[i].y, goals[i].w, goals[i].h ) ) {
854: if ( goals[i].occupied ) return 1;
855: goals[i].occupied++;
856: /* playSound( s_goal ); */
857: score += SCORE_GOAL;
858: score += ( ( int ) ( timeLeft / 10 ) ) * 10;
859: lives += freeFrog( score );
860: froggerReset( );
861: if ( checkGoals( ) ) levelUp( );
862: return 0;
863: }
864: }
865: return 1;
866: }
867:
868: return 0;
869: }
870:
871: /* If the player gets enough points, award them a free frog */
872: int freeFrog ( int score ) {
873: if ( givenFreeFrog ) return 0;
874: if ( score >= SCORE_FREE_FROG ) {
875: givenFreeFrog++;
876: playSound( s_freeFrog );
877: return 1;
878: }
879: return 0;
880: }
881:
882: /* Check what frogger is colliding with */
883: int collideFrogger ( int x, int y, int h, int w ) {
884: h++; w++;
885:
886: if ( ( frogger.placement[Y] >= ( y + h ) ) ||
887: ( frogger.placement[X] >= ( x + w ) ) ||
888: ( y >= ( frogger.placement[Y] + FRAME ) ) ||
889: ( x >= ( frogger.placement[X] + FRAME ) ) ) {
890: return( 0 );
891: }
892: return( 1 );
893: }
894:
895: /* Check left and right borders */
896: void checkFroggerBorder( void ) {
897: if ( frogger.placement[Y] - 5 >= getRowPixel( 0 ) ) {
898: frogger.placement[Y] = frogger.oldPlacement[Y];
899: frogger.currentRow = 0;
900: }
901:
902: if ( ( frogger.placement[X] <= LEFT_SIDE ) ||
903: ( frogger.placement[X] + frogger.src.w >= RIGHT_SIDE ) ) {
904: if ( ( frogger.currentRow == 0 ) ||
905: ( frogger.currentRow == 6 ) ) {
906: frogger.placement[X] = frogger.oldPlacement[X];
907: }
908: else {
909: frogger.alive = FALSE;
910: }
911: }
912: }
913:
914: void levelUp ( void ) {
915: int i;
916:
917: fprintf ( stderr, "Level %i beat! ", level );
918:
919: level++;
920: score += SCORE_LEVEL;
921: lives += freeFrog( score );
922: froggerReset( );
923: /* Play sounds */
924:
925: /* Empty goals */
926: for ( i = 0; i < MAX_GOALS; i++ ) goals[i].occupied = 0;
927:
928: /* Speed things up */
929: vehicle[0].speed = level;
930: vehicle[1].speed = level;
931: vehicle[2].speed = level;
932: vehicle[3].speed = level;
933:
934: fprintf (stderr, "Starting level %i!\n", level );
935: }
936:
937: int checkGoals ( void ) {
938: int savedFrogs = 0;
939: int i;
940:
941: for ( i = 0; i < MAX_GOALS; i++ ) {
942: if ( goals[i].occupied ) savedFrogs++;
943: }
944:
945: drawGoals( );
946:
947: return ( savedFrogs >= 5 ) ? 1 : 0;
948: }
949:
950: void froggerReset ( void ) {
951: timeLeft = MAX_TIMER;
952:
953: frogger.placement[X] = FROGGER_START_X;
954: frogger.placement[Y] = FROGGER_START_Y;
955: frogger.oldPlacement[X] = FROGGER_START_X;
956: frogger.oldPlacement[Y] = FROGGER_START_Y;
957: frogger.hopCount = 0;
958: frogger.direction = 0;
959: frogger.currentRow = 0;
960: frogger.alive = TRUE;
961: frogger.riding = FALSE;
962: frogger.deathType = 0; /* Death type SPLAT or SPLASH */
963: frogger.deathCount = 0; /* death animation timer */
964:
965: frogger.src.y = 0;
966: frogger.src.x = 0;
967: frogger.src.w = FRAME;
968: frogger.src.h = FRAME;
969: frogger.dst.y = frogger.placement[Y];
970: frogger.dst.x = frogger.placement[X];
971:
972: drawImage( gfx, frogger.src.x, frogger.src.y, frogger.src.w,
973: frogger.src.h, screen, frogger.dst.x, frogger.dst.y, 255 );
974: }
975:
976: /*
977: * This actually moves frogger... I need to come up with a better
978: * algorithm for calculating the distance and time
979: */
980: void moveFrogger( void ) {
981: int currentFrame = 0;
982: int x = 0;
983: int y = 0;
984: int h = FRAME;
985: int w = FRAME;
986: int frameLow = HOP_SPEED / 3;
987: int frameHigh = frameLow * 2;
988:
989: /* Determine which frame of frogger to display */
990: if ( ( frogger.hopCount >= frameLow ) && ( frogger.hopCount <= frameHigh ) )
991: currentFrame = FRAME;
992:
993: frogger.oldPlacement[Y] = frogger.placement[Y];
994: frogger.oldPlacement[X] = frogger.placement[X];
995:
996: switch( frogger.direction ) {
997: case UP:
998: x = currentFrame;
999: frogger.placement[Y] -= ( HOP_DISTANCE / HOP_SPEED );
1000: break;
1001: case DOWN:
1002: x = currentFrame + ( 4 * FRAME );
1003: frogger.placement[Y] += ( HOP_DISTANCE / HOP_SPEED );
1004: break;
1005: case LEFT:
1006: x = currentFrame + ( 6 * FRAME );
1007: frogger.placement[X] -= ( HOP_DISTANCE / HOP_SPEED );
1008: break;
1009: case RIGHT:
1010: x = currentFrame + ( 2 * FRAME );
1011: frogger.placement[X] += ( HOP_DISTANCE / HOP_SPEED );
1012: break;
1013: }
1014:
1015: checkFroggerBorder( );
1016:
1017: /* select the frame to display */
1018: frogger.src.y = y;
1019: frogger.src.x = x;
1020: frogger.src.w = w;
1021: frogger.src.h = h;
1022:
1023: /* Set the old place to be erased */
1024: frogger.dst.y = frogger.oldPlacement[Y];
1025: frogger.dst.x = frogger.oldPlacement[X];
1026:
1027: SDL_FillRect( screen, NULL, SDL_MapRGB( screen->format, BGCOLOR ) );
1028:
1029: /* Place the new position */
1030: frogger.dst.y = frogger.placement[Y];
1031: frogger.dst.x = frogger.placement[X];
1032:
1033: frogger.hopCount++;
1034:
1035: if ( frogger.hopCount >= HOP_SPEED ) {
1036: frogger.hopCount = 0;
1037: frogger.direction = FALSE;
1038: score += SCORE_HOP;
1039: lives += freeFrog( score );
1040: }
1041: }
1042:
1043: void ridingFrogger( void ) {
1044: int speed = 0;
1045:
1046: if ( frogger.hopCount > 0 ) return;
1047:
1048: switch( frogger.ridingType ) {
1049: case LOG:
1050: speed = wood[frogger.ridingIdx].speed;
1051: break;
1052: case TURTLE:
1053: speed = turtle[frogger.ridingIdx].speed + 2;
1054: break;
1055: }
1056:
1057: switch( frogger.riding ) {
1058: case LEFT:
1059: frogger.oldPlacement[X] = frogger.placement[X];
1060: frogger.placement[X] -= speed;
1061: frogger.dst.x = frogger.placement[X];
1062: break;
1063: case RIGHT:
1064: frogger.oldPlacement[X] = frogger.placement[X];
1065: frogger.placement[X] += speed;
1066: frogger.dst.x = frogger.placement[X];
1067: break;
1068: }
1069:
1070: checkFroggerBorder( );
1071: }
1072:
1073: void drawTitleScreen( void ) {
1074: SDL_Surface *introText;
1075: SDL_Color fontColor = { 123, 158, 53, 255 };
1076: int center = ( SCREEN_WIDTH / 2 ) - ( titleSurface->w / 2 );
1077: int i;
1078: char *txt[] = { "Press 1 for single player game",
1079: "Press 2 for two player games",
1080: "Press F for full screen mode",
1081: "Press ESC to quit" };
1082:
1083: // drawBackground( );
1084:
1085: drawImage( titleSurface, 0, 0, titleSurface->w,
1086: titleSurface->h, screen, center, 100, 255 );
1087:
1088: for( i = 0; i <= 3; i++ ) {
1089: introText = TTF_RenderText_Solid( font, txt[i], fontColor );
1090: drawImage( introText, 0, 0, introText->w, introText->h, screen,
1091: 140, 300 + ( i * introText->h ), 255 );
1092: }
1093:
1094: SDL_Flip( screen );
1095: }
1096:
1097: void drawPauseScreen( void ) {
1098: printf( "D: Draw Pause Screen\n" );
1099:
1100: }
1101:
1102: void drawGameOver( void ) {
1103: printf( "D: Game Over\n" );
1104: }
1105:
1106: void playSound( Mix_Chunk *sound ) {
1107: Mix_PlayChannel( -1, sound, 0 );
1108: }
1109:
1110: void setFullScreenMode( void ) {
1111: /* Lets give fullscreen mode a try */
1112: if ( ! fullscreen ) {
1113: screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, 16, SDL_HWSURFACE | SDL_FULLSCREEN );
1114: fullscreen = TRUE;
1115: }
1116: /* Switch back to window mode */
1117: else {
1118: screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, 16, SDL_HWSURFACE );
1119: fullscreen = FALSE;
1120: }
1121:
1122: printf( "D: Fullscreen : %i\n", fullscreen );
1123: }
1124:
1125: int drawDeathSequence( int deathType ) {
1126: int animDelay = 55;
1127: int animOffset = ( deathType == SPLAT ) ? 8 : 11;
1128: int dFrame = 0;
1129:
1130: if ( frogger.deathCount < 7 ) dFrame = 0;
1131: if ( frogger.deathCount >= 7 ) dFrame = 1;
1132: if ( frogger.deathCount >= 14) dFrame = 2;
1133: if ( frogger.deathCount > 20 ) animOffset = 12;
1134:
1135: frogger.deathCount++;
1136: if ( frogger.deathCount >= animDelay )
1137: return 0; /* we're done with death */
1138:
1139: drawImage( gfx, FRAME * ( animOffset + dFrame ), 0, FRAME, FRAME,
1140: screen, frogger.placement[X], frogger.placement[Y], 255 );
1141:
1142: return 1;
1143: }
1144:
1145: /* draw green timer and return 0 if out of time */
1146: int checkTimer( void ) {
1147: float lvl = level;
1148: int step = ( int ) ( lvl / 2 );
1149: if ( step < 1 ) step = 1;
1150: if ( step > 3 ) step = 3;
1151: timeLeft -= step;
1152:
1153: drawTimer( (int) ( ( timeLeft / MAX_TIMER ) * TIMER_SIZE ) );
1154:
1155: if ( timeLeft <= 0 ) return 0;
1156: return 1;
1157: }
1158:
1159: void drawScore( int high, int score ) {
1160: int x = 169;
1161: int y = 14;
1162:
1163: if ( score > hScore ) hScore = score;
1164: if ( high ) x = 260;
1165:
1166: drawNumbers( score, x, y );
1167: }
1168:
1169: void drawNumbers( int num, int x, int y ) {
1170: char numStr[6] = "00000";
1171: int i;
1172:
1173: /* Assume anything less than 50 pixels location is a score and
1174: * pad with '0'.
1175: */
1176: if ( y <= 15 ) sprintf( numStr, "%05i", num );
1177: else sprintf( numStr, "%i", num );
1178:
1179: for ( i = 0; i <= 4; i++ ) {
1180: char c = numStr[i];
1181: int n = atoi( &c );
1182:
1183: drawImage( gfx, n * HFRAME, FRAME * 3 , HFRAME, FRAME,
1184: screen, x + ( i * HFRAME ) + 2, y, 255 );
1185: }
1186: }
1187:
1188: /* Normally this functions manages and draws the flys, gators and saved frogs
1189: * but if drawDebugRect below is turned on it will draw the rectangle
1190: * used for collision detectiong for debuggin purposes in timer green
1191: */
1192: void drawGoals( void ) {
1193: int drawDebugRect = 0;
1194: int i;
1195:
1196: for ( i = 0; i < MAX_GOALS; i++ ) {
1197: if ( drawDebugRect ) {
1198: SDL_Rect d;
1199: d.x = goals[i].x;
1200: d.y = goals[i].y;
1201: d.w = goals[i].w;
1202: d.h = goals[i].h;
1203:
1204: SDL_FillRect( screen, &d, SDL_MapRGB( screen->format, TIMER_COLOR ) );
1205: }
1206:
1207: if ( goals[i].occupied )
1208: drawImage( gfx, FRAME * 15, 0, FRAME, FRAME,
1209: screen, goals[i].x + 13, goals[i].y + 5, 255 );
1210: }
1211: }
1212:
1213: void drawTimer( int length ) {
1214: SDL_Rect timerRect;
1215:
1216: timerRect.x = RIGHT_SIDE - 60 - length;
1217: timerRect.y = 465;
1218: timerRect.w = length;
1219: timerRect.h = 15;
1220:
1221: SDL_FillRect( screen, &timerRect, SDL_MapRGB( screen->format, TIMER_COLOR ) );
1222: }
1223:
1224: void drawLives( int lives ) {
1225: int i;
1226: int lifeFroggerSize = 16;
1227:
1228: for( i = 0; i <= lives - 2; i++ ) {
1229: drawImage( gfx, FRAME * 11, FRAME * 2, lifeFroggerSize, FRAME,
1230: screen, LEFT_SIDE + ( lifeFroggerSize * i ), 450, 255 );
1231: }
1232: }
1233:
1234: void drawLevel( int level ) {
1235: int i;
1236: int levelImageSize = 12;
1237:
1238: for( i = 0; i <= level - 1; i++ ) {
1239: drawImage( gfx, FRAME * 12, FRAME * 2, levelImageSize, FRAME,
1240: screen, RIGHT_SIDE - levelImageSize - ( levelImageSize * i ), 450, 255 );
1241: }
1242: }
1243:
1244: void drawWood ( void ) {
1245: int i;
1246:
1247: for ( i = 0; i < MAX_WOOD; i++ ) {
1248: if ( wood[i].placement[X] > ( RIGHT_SIDE + 5 ) )
1249: wood[i].placement[X] = LEFT_SIDE - wood[i].src.w - 5;
1250: wood[i].placement[X] += wood[i].speed;
1251: drawImage( gfx, wood[i].src.x, wood[i].src.y,
1252: wood[i].src.w, wood[i].src.h,
1253: screen, wood[i].placement[X],
1254: wood[i].placement[Y], 255 );
1255: }
1256: }
1257:
1258: void drawTurtles ( void ) {
1259: int i = 0;
1260: int n = 0;
1261: int animFrame = 0;
1262:
1263: for ( i = 0; i < MAX_TURTLES; i++ ) {
1264: /* This managed the turtles basic 3 frames of animation */
1265: animFrame = turtle[i].animStep;
1266: if ( turtle[i].animDelay >= TURTLE_ANIM_TIME ) {
1267: turtle[i].animDelay = 0;
1268: turtle[i].animStep++;
1269: if ( turtle[i].animStep > 2 ) turtle[i].animStep = 0;
1270: }
1271: else {
1272: turtle[i].animDelay++;
1273: }
1274:
1275: /* If a set of turtles have dive capability, this enables that */
1276: if ( turtle[i].canDive ) {
1277: turtle[i].diveTime++;
1278: /* Check if turtle is diving */
1279: if ( turtle[i].diveStep > 0 ) {
1280: switch( turtle[i].diveStep ) {
1281: case 1:
1282: animFrame = 3;
1283: break;
1284: case 2:
1285: animFrame = 4;
1286: break;
1287: case 4:
1288: animFrame = 4;
1289: break;
1290: case 5:
1291: animFrame = 3;
1292: break;
1293: case 6:
1294: turtle[i].diveStep = 0;
1295: turtle[i].diveTime = 0;
1296: break;
1297: default:
1298: animFrame = 4;
1299: break;
1300: }
1301:
1302: if ( turtle[i].diveTime > DIVE_START_TIME + ( DIVE_PHASE_TIME * turtle[i].diveStep ) )
1303: turtle[i].diveStep++;
1304:
1305: }
1306: else {
1307: if ( turtle[i].diveTime > DIVE_START_TIME )
1308: turtle[i].diveStep++;
1309: }
1310: }
1311:
1312: /* Display out turtles */
1313: for ( n = 0; n <= ( turtle[i].count - 1 ); n++ ) {
1314: turtle[i].placement[X] -= turtle[i].speed;
1315: if ( turtle[i].placement[X] <= LEFT_SIDE - ( turtle[i].count * FRAME ) + 10 )
1316: turtle[i].placement[X] = RIGHT_SIDE + 10;
1317: if ( turtle[i].diveStep != 4 )
1318: drawImage( gfx, turtle[i].src.x + ( FRAME * animFrame ),
1319: turtle[i].src.y, turtle[i].src.w, turtle[i].src.h,
1320: screen, turtle[i].placement[X] + ( ( FRAME + 3 ) * n ),
1321: turtle[i].placement[Y], 255 );
1322: }
1323: }
1324: }
1325:
1326: void drawVehicles ( void ) {
1327: int i;
1328:
1329: for ( i = 0; i < MAX_VEHICLES; i++ ) {
1330: if ( vehicle[i].direction == RIGHT ) {
1331: if ( vehicle[i].placement[X] > ( RIGHT_SIDE + 5 ) )
1332: vehicle[i].placement[X] = LEFT_SIDE - vehicle[i].src.w - 5;
1333: vehicle[i].placement[X] += vehicle[i].speed;
1334: }
1335: else {
1336: if ( vehicle[i].placement[X] < ( LEFT_SIDE - 5 ) )
1337: vehicle[i].placement[X] = RIGHT_SIDE + vehicle[i].src.w + 5;
1338: vehicle[i].placement[X] -= vehicle[i].speed;
1339: }
1340:
1341: if ( level >= vehicle[i].level )
1342: drawImage( gfx, vehicle[i].src.x, vehicle[i].src.y,
1343: vehicle[i].src.w, vehicle[i].src.h,
1344: screen, vehicle[i].placement[X],
1345: vehicle[i].placement[Y], 255 );
1346: }
1347: }
1348:
1349: void drawImage( SDL_Surface *srcimg, int sx, int sy, int sw, int sh,
1350: SDL_Surface *dstimg, int dx, int dy, int alpha ) {
1351: if ((!srcimg) || (alpha == 0)) return;
1352: SDL_Rect src, dst;
1353:
1354: src.x = sx; src.y = sy; src.w = sw; src.h = sh;
1355: dst.x = dx; dst.y = dy; dst.w = src.w; dst.h = src.h;
1356:
1357: if (alpha != 255) SDL_SetAlpha(srcimg, SDL_SRCALPHA, alpha);
1358: SDL_BlitSurface(srcimg, &src, dstimg, &dst);
1359: }
1360:
1361: int heartbeat ( void ) {
1362: int ticks;
1363: if ( level ) {
1364: if ( playing ) {
1365: ticks = updateGameState( );
1366: if ( ticks <= 0 ) ticks = 50;
1367: return ticks;
1368: }
1369: else {
1370: drawPauseScreen( );
1371: return 500;
1372: }
1373: }
1374: else {
1375: drawTitleScreen( );
1376: return 500;
1377: }
1378:
1379: return 50;
1380: }
1381:
1382: /*
1383: * Main program starts here. We'll init the video and audio
1384: * and then begin our main program loop here
1385: *
1386: */
1387: int main ( int argc, char **argv ) {
1388: if ( mySDLInit( ) <= 0 ) {
1389: fprintf( stderr, "Failure to start froggix\n" );
1390: return 255;
1391: }
1392:
1393: beginGame( );
1394:
1395: SDL_Quit( );
1396:
1397: return 0;
1398: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>