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