1 /***************************************************************************
2                           game.cpp  -  description
3                              -------------------
4     begin                : Tue Feb 29 2000
5     copyright            : (C) 2000 by Michael Speck
6     email                :
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 
18 #include <sys/types.h>
19 #include <sys/timeb.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include "game.h"
23 #include "breakout.h"
24 #include "menumanager.h"
25 #include "level.h"
26 
27 extern "C" {
28 	int ftime(struct timeb *tp);
29 };
30 
31 #ifdef SOUND
32 extern SndSrv sndsrv;
33 #endif
34 extern Sdl sdl;
35 extern int fast_quit;
36 extern DrawRgn dr_src, dr_dst;
37 
Game()38 Game::Game()
39 {
40 	//video mode
41 #ifdef SOUND
42 	Sdl_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER);
43 #else
44 	Sdl_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
45 #endif
46 	if (Sdl_SetVideoMode(450, 325, 16, SDL_HWSURFACE))
47 		exit(1);
48 	SDL_WM_SetCaption("LBreakout", 0);
49 
50 	//load title
51 	title = SSur_Load("title.bmp", SDL_HWSURFACE);
52 	SDL_SetColorKey(title, 0, 0);
53 	if (title == 0) {
54 		title = SSur_Create(sdl.scr->w, sdl.scr->h, SDL_HWSURFACE);
55 		DR_SETFULLDST(title);
56 		SSur_Fill(0x0);
57 	}
58 	f_copy = SFnt_Load("font_s.sdlfnt");
59 	f_copy->algn = TA_X_RIGHT | TA_Y_BOTTOM;
60 	SFnt_Write(f_copy, title, title->w-3, title->h-1, "(C) 2000 Michael Speck", 0);
61 	f_copy->algn = TA_X_LEFT | TA_Y_BOTTOM;
62 	SFnt_Write(f_copy, title, 0, title->h-1, "http://lgames.sourceforge.net", 0);
63     SFnt_Free(f_copy);
64 
65     //load logo
66     logo = SSur_Load("logo.bmp", SDL_HWSURFACE);
67 //  SDL_SetAlpha(logo, SDL_SRCALPHA, 16);
68     if (logo == 0)
69     	exit(1);
70     logo_x = (sdl.scr->w - logo->w) / 2;
71     logo_y = 40;
72 
73 	//load fonts
74 	f_menu_w = SFnt_LoadFixed("f_yellow.bmp", 32, 96, 10);
75 	f_menu_w->algn = TA_X_CENTER | TA_Y_CENTER;
76 	f_menu_b = SFnt_LoadFixed("f_white.bmp", 32, 96, 10);
77 	f_menu_b->algn = TA_X_CENTER | TA_Y_CENTER;
78 	f_hiscore = SFnt_LoadFixed("f_yellow.bmp", 32, 96, 10);
79 	f_hiscore->algn = TA_X_LEFT | TA_Y_TOP;
80 	f_enlgt_hiscore = SFnt_LoadFixed("f_white.bmp", 32, 96, 10);
81 	f_enlgt_hiscore->algn = TA_X_LEFT | TA_Y_TOP;
82 
83 	//restricted keys
84 	memset(val_ctrl_keys, 0, sizeof(val_ctrl_keys));
85 	for (int i = 32; i < 128; i++)
86 		val_ctrl_keys[i] = 1;
87 	val_ctrl_keys[SDLK_RETURN] = 0;
88 	val_ctrl_keys[SDLK_ESCAPE] = 0;
89 	val_ctrl_keys[SDLK_q] = 0;
90 	val_ctrl_keys[SDLK_r] = 0;
91 	val_ctrl_keys[SDLK_f] = 0;
92 	val_ctrl_keys[SDLK_p] = 0;
93 	val_ctrl_keys[SDLK_UP] = 1;
94 	val_ctrl_keys[SDLK_DOWN] = 1;
95 	val_ctrl_keys[SDLK_RIGHT] = 1;
96 	val_ctrl_keys[SDLK_LEFT] = 1;
97 
98 	//breakout
99 	breakout = new BreakOut();
100 
101 	//create menumanager
102 	char    *str_gfx[] = {
103 	    "Off",
104 	    "Low",
105 	    "High"
106 	};
107 	char    *str_ctrls[] = {
108 	    "Only Keyboard",
109 	    "Only Mouse",
110 	    "Keyboard&Mouse"
111 	};
112 	char    *str_diff[] = {
113 	    "Easy",
114 	    "Medium",
115 	    "Hard"
116 	};
117 	mm = new MenuManager(title, sdl.scr->w / 2, 240, f_menu_w, f_menu_b, 9, val_ctrl_keys);
118 	//create menus
119 	Menu *menu[9];
120 	menu[0] = new Menu("main", 4);
121 	menu[1] = new Menu("newgame", 4);
122 	menu[2] = new Menu("options", 6);
123 	menu[3] = new Menu("graphics", 8);
124 	menu[4] = new Menu("audio", 4);
125 	menu[5] = new Menu("controls", 8);
126 	menu[6] = new Menu("game", 10);
127 	menu[7] = new Menu("level", 4);
128 	menu[8] = new Menu("mouse", 5);
129     menu[0]->InsertItem(0, new MenuItem("New Game", menu[1]));
130     menu[0]->InsertItem(1, new MenuItem("HiScores", AT_HISCORE));
131     menu[0]->InsertItem(2, new MenuItem("Options", menu[2]));
132     menu[0]->InsertItem(3, new MenuItem("Quit", AT_QUIT));
133     menu[1]->InsertItem(0, new MenuItem("New Game", AT_NEWGAME));
134     menu[1]->InsertItem(1, new MenuItem("Name", breakout->Setup()->name, 10));
135     menu[1]->InsertItem(2, new MenuItem());
136     menu[1]->InsertItem(3, new MenuItem("Back", menu[0]));
137     menu[2]->InsertItem(0, new MenuItem("Game", menu[6]));
138     menu[2]->InsertItem(1, new MenuItem("Controls", menu[5]));
139     menu[2]->InsertItem(2, new MenuItem("Graphics", menu[3]));
140 #ifdef SOUND
141     menu[2]->InsertItem(3, new MenuItem("Audio", menu[4]));
142 #else
143     menu[2]->InsertItem(3, new MenuItem("Audio"));
144 #endif
145     menu[2]->InsertItem(4, new MenuItem());
146     menu[2]->InsertItem(5, new MenuItem("Back", menu[0]));
147     menu[3]->InsertItem(0, new MenuItem("Transparency:", &breakout->Setup()->trp, "Off", "On"));
148     menu[3]->InsertItem(1, new MenuItem("Animations:", &breakout->Setup()->anim, str_gfx, 3));
149     menu[3]->InsertItem(2, new MenuItem("Bonus Information:", &breakout->Setup()->no_exdisp, "On", "Off"));
150 	menu[3]->InsertItem(3, new MenuItem());
151     menu[3]->InsertItem(4, new MenuItem("Background:", &breakout->Setup()->bkgnd, "Off", "On"));
152     menu[3]->InsertItem(5, new MenuItem("Display:", &breakout->Setup()->fullscreen, "Window", "Fullscreen"));
153 	menu[3]->InsertItem(6, new MenuItem());
154     menu[3]->InsertItem(7, new MenuItem("Back", menu[2]));
155     menu[4]->InsertItem(0, new MenuItem("Sound:", &breakout->Setup()->snd_on, "Off", "On"));
156     menu[4]->InsertItem(1, new MenuItem("Volume:", &breakout->Setup()->snd_vol, 1, 8));
157     menu[4]->InsertItem(2, new MenuItem());
158     menu[4]->InsertItem(3, new MenuItem("Back", menu[2]));
159 	menu[5]->InsertItem(0, new MenuItem("Left", &breakout->Setup()->k_left, 0));
160 	menu[5]->InsertItem(1, new MenuItem("Right", &breakout->Setup()->k_right, 0));
161 	menu[5]->InsertItem(2, new MenuItem("Fire", &breakout->Setup()->k_fire, 0));
162 	menu[5]->InsertItem(3, new MenuItem());
163     menu[5]->InsertItem(4, new MenuItem("Mouse", menu[8]));
164 	menu[5]->InsertItem(5, new MenuItem("Use:", &breakout->Setup()->control, str_ctrls, 3));
165 	menu[5]->InsertItem(6, new MenuItem());
166 	menu[5]->InsertItem(7, new MenuItem("Back", menu[2]));
167     menu[6]->InsertItem(0, new MenuItem("Difficulty:", &breakout->Setup()->diff, str_diff, 3));
168     menu[6]->InsertItem(1, new MenuItem("Starting Level:", &breakout->Setup()->startlevel, 0, LEVEL_NUM-1, 5));
169     menu[6]->InsertItem(2, new MenuItem("Paddle:", &breakout->Setup()->convex, "Flat Surface", "Convex Surface"));
170     menu[6]->InsertItem(3, new MenuItem("Ball's Starting Angle:", &breakout->Setup()->rnd_start, "50 Degree", "Random"));
171 	menu[6]->InsertItem(4, new MenuItem());
172     menu[6]->InsertItem(5, new MenuItem("", &breakout->Setup()->lvls_frm_file, "Play Original Levels", "Play Own Levels"));
173 	menu[6]->InsertItem(6, new MenuItem("Level File", menu[7]));
174 	menu[6]->InsertItem(7, new MenuItem("(not selected)"));
175 	menu[6]->InsertItem(8, new MenuItem());
176 	menu[6]->InsertItem(9, new MenuItem("Back", menu[2]));
177     menu[7]->InsertItem(0, new MenuItem("Path", breakout->Setup()->lvl_path, 31));
178     menu[7]->InsertItem(1, new MenuItem("File", breakout->Setup()->lvl_file, 19));
179 	menu[7]->InsertItem(2, new MenuItem());
180 	menu[7]->InsertItem(3, new MenuItem("Back", menu[6]));
181     menu[8]->InsertItem(0, new MenuItem("Warp Mouse:", &breakout->Setup()->warp, "Off", "On"));
182     menu[8]->InsertItem(1, new MenuItem("Invert Mouse:", &breakout->Setup()->invert, "Off", "On"));
183     menu[8]->InsertItem(2, new MenuItem("Motion Modifier:", &breakout->Setup()->motion_mod, 40, 100, 10));
184 	menu[8]->InsertItem(3, new MenuItem());
185 	menu[8]->InsertItem(4, new MenuItem("Back", menu[5]));
186     //add to manager
187     mm->InsertMenu(0, menu[0]);
188     mm->InsertMenu(1, menu[1]);
189     mm->InsertMenu(2, menu[2]);
190     mm->InsertMenu(3, menu[3]);
191     mm->InsertMenu(4, menu[4]);
192     mm->InsertMenu(5, menu[5]);
193     mm->InsertMenu(6, menu[6]);
194     mm->InsertMenu(7, menu[7]);
195     mm->InsertMenu(8, menu[8]);
196     mm->Activate();
197 
198     level_sw = menu[6]->Item(5);
199     level_menu = menu[7]->Item(3);
200     level_menu->SetUsed(1); level_sw->SetUsed(1);
201     CheckLevelFile();
202 
203     //randomize
204     timeb t;
205     ftime(&t);
206     srand((unsigned int)t.time);
207 
208 #ifdef SOUND
209 	//load waves
210     snd_menu = Wave_Load("click.wav");
211 #endif
212 }
213 
~Game()214 Game::~Game()
215 {
216 	if (breakout) delete breakout;
217 	if (title) SDL_FreeSurface(title);
218 	if (logo) SDL_FreeSurface(logo);
219 	if (mm) delete mm;
220 	if (f_menu_w) SFnt_Free(f_menu_w);
221 	if (f_menu_b) SFnt_Free(f_menu_b);
222 	if (f_hiscore) SFnt_Free(f_hiscore);
223 	if (f_enlgt_hiscore) SFnt_Free(f_enlgt_hiscore);
224 #ifdef SOUND
225 	if (snd_menu) Wave_Free(snd_menu);
226 #endif
227     Sdl_Quit();
228 }
229 
Run()230 void Game::Run()
231 {
232 #ifdef SOUND
233     sndsrv.spec.freq = 22050;
234     sndsrv.spec.format = AUDIO_U8;
235     sndsrv.spec.samples = 128;
236     sndsrv.spec.channels = 1;
237 	SndSrv_Open(snd_menu->spec);
238 #endif
239 
240 	mm->Prepare();
241 
242 	DR_SETFULLDST(sdl.scr);
243 	DR_SETFULLSRC(title);
244 	SSur_Blit();
245 	DR_SETDST(sdl.scr, logo_x, logo_y, logo->w, logo->h);
246 	DR_SETSRC(logo, 0, 0);
247 	SSur_Blit();
248 
249 	SDL_UNDIM();
250 
251 	mm->CurMenu()->Show(1);
252 	//loop
253 	SDL_Event	event;
254 	int			go_on = 1;
255 	int         rank;
256 	int         ret;
257 	while (go_on && !fast_quit) {
258 	    ret = MR_CONTINUE;
259 		if (SDL_PollEvent(&event)) {
260 		    switch (event.type) {
261 				case SDL_MOUSEMOTION:
262 				    mm->CurMenu()->MouseMotion(event.motion.x, event.motion.y);
263 				    break;
264 				case SDL_MOUSEBUTTONUP:
265 #ifdef SOUND
266     				SndSrv_Play(snd_menu, 0);
267 #endif
268 				    ret = mm->ButtonEvent(event.button);
269 				    break;
270 		        case SDL_KEYUP:
271 #ifdef SOUND
272     				SndSrv_Play(snd_menu, 0);
273 #endif
274     				if (event.key.keysym.sym == SDLK_ESCAPE) {
275     				    go_on = 0;
276     				    break;
277     				}
278     				ret = mm->KeyEvent(&event.key);
279                 break;
280 				case SDL_QUIT:
281 				    fast_quit = 1;
282 				    break;
283 				default:
284 				    break;
285 			}
286    			switch (ret) {
287 				case MR_CONTINUE:
288    					break;
289 				case AT_HISCORE:
290    					SDL_DIM();
291     				ShowHiScore(0);
292                   	DR_SETFULLDST(sdl.scr);
293                   	DR_SETFULLSRC(title);
294                   	SSur_Blit();
295                     DR_SETDST(sdl.scr, logo_x, logo_y, logo->w, logo->h);
296                     DR_SETSRC(logo, 0, 0);
297                     SSur_Blit();
298    					SDL_UNDIM();
299     				mm->CurMenu()->Show(1);
300 	    			break;
301 		    	case AT_QUIT:
302 					go_on = 0;
303     				break;
304     			case AT_NEWGAME:
305 	    			SDL_DIM();
306 		    		rank = breakout->Run(); //game
307 					if (!fast_quit) {
308   					    if (rank != 0)
309     					    ShowHiScore(rank);
310                        	DR_SETFULLDST(sdl.scr);
311                        	DR_SETFULLSRC(title);
312                        	SSur_Blit();
313                         DR_SETDST(sdl.scr, logo_x, logo_y, logo->w, logo->h);
314                         DR_SETSRC(logo, 0, 0);
315                         SSur_Blit();
316          			    SDL_UNDIM();
317 					    mm->CurMenu()->ClearState();
318   					    mm->SetCurMenu(0);
319     				    mm->CurMenu()->Prepare(0);
320 					    mm->CurMenu()->Show(1);
321    					}
322     		        break;
323    			}
324 		}
325 
326 		if (fast_quit) break;
327 
328 		CheckLevelFile();
329 
330 	 	//compute
331  	    mm->CurMenu()->Compute();
332  	    mm->CurMenu()->Update(1);
333 
334 	 	SDL_Delay(8);
335 
336 #ifdef SOUND
337 		SndSrv_SetActive(breakout->Setup()->snd_on);
338  		SndSrv_SetVolume(breakout->Setup()->snd_vol);
339 #endif
340 	}
341 
342     SDL_DIM();
343 
344 #ifdef SOUND
345 	SndSrv_Close();
346 #endif
347 }
348 
ShowHiScore(int r)349 void Game::ShowHiScore(int r)
350 {
351 	int i;
352 	int a_y = 100;
353 	int off = 50;
354 	int entry_h = f_hiscore->lh + 2;
355 	char buffer[12];
356 	HiScoreEntry	entry;
357 	SFnt			*font;
358 
359 	for (int page = 0; page<2; page++) {
360     DR_SETFULLDST(sdl.scr);
361     DR_SETFULLSRC(title);
362     SSur_Blit();
363 	SDL_UNDIM();
364 
365     f_hiscore->algn = TA_X_CENTER | TA_Y_CENTER;
366     const char* txt;
367     if (0==page) txt="Highest Scores";
368     else txt="Highest Levels";
369     SFnt_Write(f_hiscore, sdl.scr, sdl.scr->w / 2, 50, const_cast<char*>(txt), 0);
370     f_hiscore->algn = 0;
371     for (i = 0; i < 10; i++) {
372         if ((0==page && r%10 == i+1)
373             || (1==page && r/10 == i+1))
374             font = f_enlgt_hiscore;
375         else
376             font = f_hiscore;
377         entry = breakout->GetHiScore()->Entry(i,page);
378         font->algn = TA_X_LEFT | TA_Y_TOP;
379         SFnt_Write(font, sdl.scr, off, a_y + i * entry_h, entry.name, 0);
380         font->algn = TA_X_CENTER | TA_Y_TOP;
381         sprintf(buffer, "%i", entry.level);
382         SFnt_Write(font, sdl.scr, sdl.scr->w / 2, a_y + i * entry_h, buffer, 0);
383         font->algn = TA_X_RIGHT | TA_Y_TOP;
384         sprintf(buffer, "%i", entry.score);
385         SFnt_Write(font, sdl.scr, sdl.scr->w - off, a_y + i * entry_h, buffer, 0);
386     }
387     Sdl_FullUpdate();
388     Sdl_WaitForClick();
389 
390 	SDL_DIM();
391 	}
392 }
393 
CheckLevelFile()394 void Game::CheckLevelFile()
395 {
396      // strange and bad code, I know... //
397     if (!level_sw->Used() && !level_menu->Used()) return;
398     level_menu->Used();
399 
400     int rep = mm->GetMenu(6) == mm->CurMenu() ? 1 : 0;
401     if (!breakout->Setup()->lvls_frm_file) {
402         mm->GetMenu(6)->Item(7)->SetString("(not selected)", rep);
403         mm->GetMenu(6)->Item(1)->SetRange(0, LEVEL_NUM - 1, 5, rep);
404         return;
405     }
406     char str[256];
407     FILE *f;
408     if ((f = breakout->Levels_OpenFile(str)) == 0) {
409         mm->GetMenu(6)->Item(7)->SetString("(not found)", rep);
410         mm->GetMenu(6)->Item(1)->SetRange(0, LEVEL_NUM - 1, 5, rep);
411         return;
412     }
413     else
414         mm->GetMenu(6)->Item(7)->SetString("(found)", rep);
415 
416 
417     int lev_num = 0;
418     char *cur_pos;
419 
420     // load file into mem //
421     fseek(f, 0, SEEK_END);
422     int fsize = ftell(f);
423     char *fbuf = new char[fsize];
424     fseek(f, 0, SEEK_SET);
425     fread(fbuf, fsize, 1, f);
426     cur_pos = fbuf;
427     fclose(f);
428 
429     // count
430     while (cur_pos < fbuf + fsize) {
431         if (!strncmp(cur_pos, "[LEV", 4))
432             lev_num++;
433         cur_pos = breakout->NextLine(0, cur_pos, fbuf + fsize);
434     }
435 
436     if (lev_num > 0)
437         mm->GetMenu(6)->Item(1)->SetRange(0, lev_num - 1, 5, rep);
438 
439     delete fbuf;
440 }
441