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