1 /*
2   XBubble - xbubble.c
3 
4   Copyright (C) 2002  Ivan Djelic <ivan@savannah.gnu.org>
5 
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2 of the License, or
9   (at your option) any later version.
10 
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15 
16   You should have received a copy of the GNU General Public License
17   along with this program; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <math.h>
24 #include <unistd.h>
25 #include <sys/time.h>
26 #include <X11/Xlib.h>
27 #include <X11/Xutil.h>
28 
29 #include "setting.h"
30 #include "gettext.h"
31 
32 /*
33 #include <mcheck.h>
34 */
35 #include "cell.h"
36 #include "game.h"
37 #include "timer.h"
38 #include "screens.h"
39 #include "init.h"
40 
41 Display *display;
42 Visual *visual;
43 Window root;
44 Window win;
45 int screen;
46 int depth;
47 Colormap colormap;
48 
49 int scale;
50 int win_width;
51 int win_height;
52 int fps;
53 unsigned long frame_duration;
54 char *data_dir;
55 char *theme;
56 int colors[NB_CELLS];
57 int nb_levels;
58 int level[MAX_NB_LEVELS][NB_CELLS];
59 
60 #define level_handicap(X) ( DEFAULT_HANDICAP + 3000*( NORMAL - (X)))
61 
usage()62 void usage() {
63   printf(_("Usage: xbubble [-d display] [-s scale] [-f framerate] [-r resourcepath] [-t theme]\n\n"));
64   exit(1);
65 }
66 
create_randome_level(int nb_rows)67 static void create_randome_level( int nb_rows ) {
68   int i;
69   /* preload bubbles */
70   for ( i = 0; i < nb_rows*COLS; i++ )
71     colors[i] = rnd( NB_COLORS ) + 1;
72   for ( i = nb_rows*COLS; i < NB_CELLS; i++ )
73     colors[i] = 0;
74 }
75 
play_single_player_game(int * handicap)76 void play_single_player_game( int *handicap ) {
77   int i;
78   int won = 1;
79   int again = 1;
80   int score[2]  = { 0, 0 };
81   RuleSet_t ruleset=DEFAULT_RULE_SET;
82   enum GameResult result;
83   Game game;
84 
85   ruleset.max_fire_delay = handicap[0];
86   for ( i = 0; again && i < nb_levels; won && i++ ) {
87     game = new_game( SINGLE_PLAYER, &ruleset, level[i], i+1,
88 		     score, NORMAL );
89 
90     result = play_game(game);
91     won = ( result == PLAYER1_WON );
92     again = ( result != ABORTED );
93     delete_game( game, again && ( !won || ( i+1 < nb_levels )));
94   }
95   if ( won )
96     printf(_("CONGRATULATIONS !!!\n"));
97 }
98 
play_challenge_game(int * handicap)99 void play_challenge_game( int *handicap ) {
100   enum GameResult result;
101   int level=1;
102   int score[2] = { 0, 0 };
103   RuleSet_t ruleset=DEFAULT_RULE_SET;
104   Game game;
105 
106   ruleset.max_fire_delay = handicap[0];
107   /* preload bubbles */
108   do {
109      create_randome_level(5);
110      game = new_game( SINGLE_PLAYER, &ruleset, colors, level, score,
111 		      NORMAL );
112      result=play_game(game);
113      if (result == PLAYER1_WON)
114        level++;
115      delete_game( game, False );
116   } while (result != ABORTED);
117 }
118 
play_match(enum GameMode mode,int * handicap,enum Level level)119 void play_match( enum GameMode mode, int *handicap, enum Level level ) {
120   int round;
121   int done;
122   int score[2];
123   int games[2]  = { 0, 0 };
124   int rounds[2] = { 0, 0 };
125   RuleSet_t ruleset[2]={ DEFAULT_RULE_SET, DEFAULT_RULE_SET };
126   enum GameResult result;
127   Game game;
128 
129   ruleset[0].max_fire_delay = handicap[0];
130   ruleset[1].max_fire_delay = handicap[1];
131 
132   do {
133     score[0] = 0;
134     score[1] = 0;
135     done = 0;
136     for ( round = 1; !done; round++ ) {
137       /* preload bubbles */
138       create_randome_level(5);
139       game = new_game( mode, ruleset, colors, round, score, level);
140       result = play_game(game);
141       done = score[1]==2 || score[0]==2 || result == ABORTED;
142        //not_done= (!(((score[1]>=5)&&(score[1]-score[0]>1)) ||
143        // ((score[0]>=5)&&(score[0]-score[1]>1))) &&
144        // ( result != ABORTED ));
145       delete_game( game, !done );
146     }
147     /* update stats */
148     rounds[0] += score[0];
149     rounds[1] += score[1];
150     if ( result != ABORTED ) {
151       games[0] += ( score[0] > score[1] )? 1 : 0 ;
152       games[1] += ( score[1] > score[0] )? 1 : 0 ;
153     }
154   }
155   while ( screen_2p( mode, rounds, games ) == S3_CONTINUE );
156 }
157 
play_demo(enum Level level)158 void play_demo( enum Level level ) {
159   int not_done;
160   RuleSet_t ruleset[2]={ DEFAULT_RULE_SET, DEFAULT_RULE_SET };
161   int score[2] = { 0, 0 };
162   Game game;
163 
164   ruleset[0].max_fire_delay = level_handicap(NORMAL);
165   ruleset[1].max_fire_delay = level_handicap(NORMAL);
166 
167   do {
168     create_randome_level(5);
169     game = new_game( DEMO, ruleset,  colors, 1, score, level );
170     not_done = ( play_game(game) != ABORTED );
171     delete_game( game, not_done );
172   }
173   while ( not_done );
174 }
175 
play_xbubble()176 void play_xbubble() {
177   int quit, level;
178   int choice[2];
179   int handicap[2];
180   quit = 0;
181 
182   while ( ! quit ) {
183     handicap[0] = level_handicap(NORMAL);
184     handicap[1] = level_handicap(NORMAL);
185 
186     switch ( screen_main() ) {
187 
188     case S1_SINGLE_PLAYER:
189       /* select handicap */
190       choice[0] = screen_1p_handicap();
191       if ( choice[0] != S5_ESCAPE ) {
192 	handicap[0] = level_handicap( choice[0] );
193 	play_single_player_game( handicap );
194       }
195       break;
196 
197     case S1_TWO_PLAYERS:
198       /* select players handicaps */
199       if ( screen_2p_handicap(choice) == S4_OK ) {
200 	/* player 1 is on the left */
201 	handicap[0] = level_handicap( choice[1] );
202 	handicap[1] = level_handicap( choice[0] );
203 	play_match( TWO_PLAYERS, handicap, NORMAL );
204       }
205       break;
206 
207     case S1_PLAYER_VS_COMPUTER:
208       /* select computer skill */
209       level = screen_computer_skill();
210       if ( level != S2_ESCAPE ) {
211 	level += VERY_EASY - S2_VERY_EASY;
212 	play_match( PLAYER_VS_COMPUTER, handicap, level );
213       }
214       break;
215 
216     case S1_CHALLENGE:
217       /* select handicap */
218       choice[0] = screen_1p_handicap();
219       if ( choice[0] != S5_ESCAPE ) {
220 	handicap[0] = level_handicap( choice[0] );
221 	play_challenge_game( handicap );
222       }
223       break;
224 
225     case S1_DEMO:
226       play_demo( VERY_HARD );
227       break;
228 
229     case S1_ESCAPE:
230     case S1_QUIT:
231       quit = 1;
232       break;
233     default:
234       break;
235     }
236   }
237 }
238 
main(int argc,char ** argv)239 int main( int argc, char ** argv ) {
240   int c;
241   double zoom;
242   char *display_name;
243   char app_name[256];
244   int max_win_width;
245   int pscale;
246   struct timeval tv;
247   XSizeHints xsh;
248   XWMHints wm_hint;
249   XClassHint class_hint;
250 
251   /* NLS nuisances */
252 #if ENABLE_NLS
253   setlocale(LC_ALL, "");
254   bindtextdomain(PACKAGE, LOCALEDIR);
255   textdomain(PACKAGE);
256 #endif
257 
258   /* default values */
259   fps = DEFAULT_FPS;
260   data_dir = DATADIR;
261   theme = "fancy";
262   pscale = 0;
263   display_name = NULL;
264   /* mtrace(); */
265 
266   /* parse options */
267   while (( c = getopt( argc, argv, "s:f:r:t:d:" )) != -1 ) {
268     switch (c) {
269     case 's': /* scale */
270       if ( sscanf( optarg, "%d", &pscale ) != 1 )  {
271 	fprintf( stderr, _("Invalid scale: %s.\n"), optarg);
272 	usage();
273       }
274       break;
275     case 'f': /* frame rate */
276       if ( sscanf( optarg, "%d", &fps ) != 1 )  {
277 	fprintf( stderr, _("Invalid frame rate: %s.\n"), optarg);
278 	usage();
279       }
280       break;
281     case 'r': /* resources */
282       data_dir = optarg;
283       break;
284     case 't': /* themes */
285       theme = optarg;
286       break;
287     case 'd': /* display */
288       display_name = optarg;
289       break;
290     default:
291       usage();
292     }
293   }
294   init_display( display_name );
295 
296   /* adjust frame rate */
297   fps = clip( fps, 10, 100 );
298   frame_duration = get_closest_itimer_interval(1000000/fps);
299   fps = 1000000 / frame_duration;
300 
301   /* adjust scale */
302   max_win_width = game_win_width(MAX_SCALE);
303   if ( ! pscale ) /* automagically adjust window size to 100% of screen width */
304     pscale = DEFAULT_SCALE*WidthOfScreen(DefaultScreenOfDisplay(display))/max_win_width;
305   pscale = clip( pscale, 5, 100 );
306   scale = pscale*MAX_SCALE/100;
307   zoom = 1.0*scale/MAX_SCALE;
308 
309   win_width = game_win_width(scale);
310   win_height = game_win_height(scale);
311 
312   /* create main window */
313   win = XCreateSimpleWindow( display, root, 0, 0, win_width, win_height,0,0,0);
314   XSelectInput( display,
315 		win,
316 		ExposureMask |
317 		StructureNotifyMask |
318 		KeyPressMask |
319 		KeyReleaseMask );
320 
321   if ( depth == 8 )
322     XSetWindowColormap( display, win, colormap );
323   /* we don't want window resizing */
324   xsh.flags = PBaseSize | PMinSize | PMaxSize;
325   xsh.min_width = xsh.max_width = xsh.base_width = win_width;
326   xsh.min_height = xsh.max_height = xsh.base_height = win_height;
327   XSetWMNormalHints( display, win, &xsh );
328 
329   /* set window title name, name, class, etc. */
330   sprintf( app_name, _("XBubble @ %d fps  v%s"), fps, VERSION );
331   XStoreName( display, win, app_name );
332   class_hint.res_name = "xbubble";
333   class_hint.res_class = "XBubble";
334   wm_hint.flags = InputHint | StateHint;
335   wm_hint.input = True;
336   wm_hint.initial_state = NormalState;
337   XSetClassHint( display, win, &class_hint );
338   XSetWMHints( display, win, &wm_hint );
339 
340   /* new randomize seed */
341   gettimeofday( &tv, NULL );
342   srand( tv.tv_usec );
343 
344   splash_screen(zoom);
345   play_xbubble();
346 
347   cleanup_graphics();
348   XDestroyWindow( display, win );
349   if ( depth == 8 )
350     XFreeColormap( display, colormap );
351   XCloseDisplay( display );
352   return 0;
353 }
354