1 /* ************************************************************************* *
2 SDL-Ball - DX-Ball/Breakout remake with openGL and SDL for Linux
3 Copyright (C) 2008-2014 Jimmy Christensen ( dusted at dusted dot dk )
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 * ************************************************************************* */
18
19 #include <iostream>
20 #include <fstream>
21 #include <cstdio>
22 #include <cstdlib>
23 #include <ctime>
24 #include <unistd.h>
25 #include <GL/gl.h>
26 #include <GL/glu.h>
27 #include <SDL/SDL.h>
28 #include <SDL/SDL_ttf.h>
29 #include <SDL/SDL_image.h>
30 #include <cmath>
31 #include <cstring>
32 #include <list>
33 #include <vector>
34 #include <sys/stat.h>
35
36 #include <dirent.h>
37
38 #ifdef WIN32
39 #define _OBJC_NO_COM
40 #include <windows.h>
41 #include <GL/glext.h>
42 #endif
43
44 /* ******************************************** *
45 Here are the compile-time options !! ;)
46 * ******************************************** */
47
48 //WIN32
49 #ifndef DATADIR
50 #define DATADIR "themes/"
51 #endif
52
53 //To disable sound support:
54 //#define NOSOUND
55
56 #ifdef WITH_WIIUSE
57 #include <wiiuse.h>
58 #define MAX_WIIMOTES 1
59 #endif
60 #ifndef NOSOUND
61 #define MIX_CHANNELS 16
62 #include <SDL/SDL_mixer.h>
63 #endif
64
65 #define VERSION "1.03"
66 #define SAVEGAMEVERSION 2
67
68
69 #include "declerations.h"
70
71 #define PI 3.14159265
72 #define RAD 6.28318531
73 #define BALL_MAX_DEGREE 2.61799388 //150+15 = 165 degrees
74 #define BALL_MIN_DEGREE 0.261799388 //15 degrees
75
76 #define FALSE 0
77 #define TRUE 1
78
79 //#define debugBall 1
80 // #define DEBUG_DRAW_BALL_QUAD
81
82 #define PO_COIN 0
83 #define PO_BIGBALL 1
84 #define PO_NORMALBALL 2
85 #define PO_SMALLBALL 3
86 #define PO_EXPLOSIVE 4
87 #define PO_GLUE 5
88 #define PO_MULTIBALL 6
89 #define PO_GROWPADDLE 7
90 #define PO_SHRINKPADDLE 8
91 #define PO_AIM 9
92 #define PO_GUN 10
93 #define PO_THRU 11
94 #define PO_LASER 12
95 #define PO_LIFE 13
96 #define PO_DIE 14
97 #define PO_DROP 15
98 #define PO_DETONATE 16
99 #define PO_EXPLOSIVE_GROW 17
100 #define PO_EASYBRICK 18
101 #define PO_NEXTLEVEL 19
102 #define PO_AIMHELP 20
103
104 //"Max powerups"
105 #define MAXPOTEXTURES 21
106
107 #define EASY 0
108 #define NORMAL 1
109 #define HARD 2
110
111 //Sound effects
112 #define SND_START 0
113 #define SND_BALL_HIT_BORDER 1
114 #define SND_BALL_HIT_PADDLE 2
115 #define SND_NORM_BRICK_BREAK 3
116 #define SND_EXPL_BRICK_BREAK 4
117 #define SND_GLASS_BRICK_HIT 5
118 #define SND_GLASS_BRICK_BREAK 6
119 #define SND_CEMENT_BRICK_HIT 7
120 #define SND_PO_HIT_BORDER 8
121 #define SND_GOOD_PO_HIT_PADDLE 9
122 #define SND_EVIL_PO_HIT_PADDLE 10
123 #define SND_SHOT 11
124 #define SND_DIE 12
125 #define SND_NEXTLEVEL 13
126 #define SND_GAMEOVER 14
127 #define SND_MENUCLICK 15
128 #define SND_DOOM_BRICK_BREAK 16
129 #define SND_GLUE_BALL_HIT_PADDLE 17
130 #define SND_INVISIBLE_BRICK_APPEAR 18
131 #define SND_HIGHSCORE 19
132 #define SND_BUY_POWERUP 20
133 #define SND_NORM_BRICK_BREAKB 21
134 #define SND_NORM_BRICK_BREAKC 22
135 #define SND_NORM_BRICK_BREAKD 23
136 #define SND_NORM_BRICK_BREAKE 24
137
138 #define SNDSAMPLES 25
139
140
141 using namespace std;
142
143 void writeSettings();
144 bool initScreen();
145 void initNewGame();
146 void pauseGame();
147 void resumeGame();
148 float rndflt(float total, float negative);
149 class ball;
150 class paddle_class;
151 float bounceOffAngle(GLfloat width, GLfloat posx, GLfloat hitx);
152
153 int globalTicks;
154 float globalMilliTicks;
155 int nonpausingGlobalTicks;
156 float nonpausingGlobalMilliTicks;
157 int globalTicksSinceLastDraw;
158 float globalMilliTicksSinceLastDraw;
159
160 struct pos {
161 GLfloat x;
162 GLfloat y;
163 };
164
165
166 struct difficultyStruct {
167 GLfloat ballspeed[3];
168 GLfloat maxballspeed[3];
169 GLfloat hitbrickinc[3];
170 GLfloat hitpaddleinc[3];
171 GLfloat slowdown[3];
172 GLfloat speedup[3];
173 };
174
175 struct difficultyStruct static_difficulty, difficulty;
176
177
178 struct settings {
179 string sndTheme,gfxTheme,lvlTheme;
180 bool cfgRes[2];
181 int resx;
182 int resy;
183 int fps;
184 bool showClock;
185 bool fullscreen;
186 bool showBg;
187 bool sound;
188 bool stereo;
189 bool eyeCandy;
190 bool particleCollide;
191 //Add to menu:
192 SDLKey keyLeft, keyRight, keyShoot, keyNextPo, keyPrevPo, keyBuyPo;
193 float controlAccel;
194 float controlStartSpeed;
195 float controlMaxSpeed;
196 bool joyEnabled, joyIsDigital;
197 int JoyCalMin, JoyCalMax, JoyCalHighJitter, JoyCalLowJitter;
198 };
199
200 struct scrollInfoScruct {
201 bool drop; //0 right, 1 left, 2 up, 3 down
202 unsigned int dropspeed;
203 unsigned int lastTick; // what was the time last they moved
204 };
205
206 struct privFileStruct {
207 string programRoot;
208 string settingsFile;
209 string saveGameFile;
210 string highScoreFile;
211 string screenshotDir;
212 };
213 struct privFileStruct privFile;
214
215 struct vars {
216 bool titleScreenShow;
217 int frame;
218 int halfresx;
219 int halfresy;
220 GLfloat glunits_per_xpixel, glunits_per_ypixel;
221 bool paused;
222 int menu;
223 int menuItem;
224 bool menuPressed;
225 int menuNumItems;
226 int menuJoyCalStage;
227 bool quit;
228 bool wiiConnect;
229
230 int numlevels;
231 bool transition_half_done;
232 bool clearScreen;
233 bool idiotlock; //transition
234 bool bricksHit; //tells the mainloop if it should copy the updated array of brick status.
235
236 GLfloat averageBallSpeed;
237 int showHighScores;
238 bool enterSaveGameName;
239 bool startedPlaying;
240
241 int effectnum;
242
243 struct scrollInfoScruct scrollInfo;
244 };
245
246 //Ting der har med spillogik at gøre
247 struct gameVars {
248 bool shopNextItem, shopPrevItem, shopBuyItem; //When set to 1 shop goes next or prev
249 int deadTime; //I hvor mange millisekunder har bolden intet rørt
250 bool nextlevel;
251 bool gameOver;
252 bool newLife;
253 bool newLevel; //Start en ny level
254 int bricksleft; //hvor mange brikker er der tilbage
255 };
256 struct gameVars gVar;
257
258 struct player_struct {
259 int coins;
260 int multiply;
261 bool powerup[MAXPOTEXTURES];
262 bool explodePaddle; //This lock makes the paddle explode and it won't come back until newlife.
263 int level;
264 int lives;
265 int difficulty;
266 int score;
267 };
268
269 int listSaveGames(string slotName[]);
270 void loadGame(int slot);
271 void saveGame(int slot, string name);
272
273 struct settings setting;
274 struct player_struct player;
275 struct player_struct SOLPlayer;
276 struct vars var;
277
278 typedef GLfloat texPos[8];
279 #ifndef uint // WIN32
280 typedef unsigned int uint;
281 #endif
282
283 struct texProp {
284 GLuint texture; //Den GLtexture der er loaded
285 GLfloat xoffset;// Hvor stort er springet mellem hver subframe
286 GLfloat yoffset; //
287 int cols,rows; //hvor mange rækker og kolonner er der i denne textur
288 int ticks;
289 uint frames; //This many frames in each se
290 bool bidir; //Går Looper den fra 0 -> X - 0 eller fra 0 -> X -> 0
291 bool playing;
292
293 bool padding; //Bit of a nasty hack, but if a texture is padded with 1 pixel around each frame, this have to be set to 1
294 float pxw, pxh; //pixels width, and height
295
296 GLfloat glTexColorInfo[4];
297 GLfloat glParColorInfo[3]; //This and above replaced object::color and particle colors
298
299 string fileName; //Quite the fugly.. This will be set by readTexProps();
300 };
301
302 /* This function attempts to open path
303 It will first look for the file in ~/.config/sdl-ball/themes/theme/path
304 Then in DATADIR/themes/setting.theme/path
305 This way, each user can even override a part of a theme that exist both
306 in their own homedir and in the global themes dir.
307 If still no luck it will use the file from DATADIR/path
308 It will return the full qualified filename */
useTheme(string path,string theme)309 string useTheme(string path, string theme)
310 {
311 struct stat st;
312 string name;
313
314 if(theme.compare("default") != 0)
315 {
316 //Try in ~/.config/sdl-ball/themes/themename
317 name = privFile.programRoot+"/themes/"+ theme+"/"+path;
318 if( stat(name.data(), &st) == 0)
319 {
320 return(name);
321 }
322 //Try in DATADIR/themename/
323 name = DATADIR + theme+"/"+path;
324 if( stat(name.data(), &st) == 0)
325 {
326 return(name);
327 }
328
329 }
330 //Fall back on default file.
331 name = DATADIR"default/" + path;
332 if( stat(name.data(), &st) == 0)
333 {
334 return(name);
335 } else {
336 cout << "File Error: Could not find '" << path << "'" << endl;
337 return(name);
338 }
339 }
340
341
342 struct themeInfo {
343 string name;
344 bool snd,gfx,lvl,valid; //Valid means that there seems to be data of some kind (ie. not just an empty folder)
345 };
346 /* This function looks in ~/.config/sdl-ball/themes/
347 and in DATADIR/themes
348 for directories, it looks inside the dir
349 to decide if a theme contains:
350 gfx folder - this theme contains graphics
351 snd folder - this theme contains sound
352 level.txt - this theme contains levels.
353 It will return info even if the theme is not valid
354 It returns a vector of structs with info */
getThemes()355 vector<struct themeInfo> getThemes() {
356 DIR *pdir;
357 struct dirent *pent;
358 struct stat st;
359 struct themeInfo ti;
360 string themeDir;
361 string temp;
362 vector<struct themeInfo> v;
363
364 for(int i=0; i < 2; i++)
365 {
366 if(i==0)
367 {
368 themeDir = privFile.programRoot + "/themes";
369 } else if(i==1)
370 {
371 themeDir = DATADIR;
372 }
373 pdir = opendir(themeDir.data());
374 if (pdir)
375 {
376 themeDir.append("/");
377 while ((pent=readdir(pdir))){
378 temp=pent->d_name;
379 //We're not going to read hidden files
380 if(temp[0] != '.')
381 {
382 temp= themeDir + pent->d_name;
383 //Check if file is a dir.
384 if(stat(temp.data(), &st) == 0)
385 {
386 ti.name = pent->d_name;
387 ti.valid = 0;
388 //Check if theme have graphics
389 temp=themeDir + pent->d_name +"/gfx";
390 if(stat(temp.data(), &st) == 0)
391 {
392 ti.gfx=1;
393 ti.valid=1;
394 } else {
395 ti.gfx=0;
396 }
397
398 //Check if theme have sound
399 temp=themeDir + pent->d_name +"/snd";
400 if(stat(temp.data(), &st) == 0)
401 {
402 ti.snd=1;
403 ti.valid=1;
404 } else {
405 ti.snd=0;
406 }
407
408 //Check if theme have levels
409 temp=themeDir + pent->d_name +"/levels.txt";
410 if(stat(temp.data(), &st) == 0)
411 {
412 ti.lvl=1;
413 ti.valid=1;
414 } else {
415 ti.lvl=0;
416 }
417
418 v.push_back(ti);
419 }
420 }
421 }
422 }
423 }
424
425 return(v);
426 }
427
428 #include "text.cpp"
429 glTextClass *glText; //Pointer to the object, since we can't init (load fonts) because the settings have not been read yet.
430
431 class textureClass {
432 private:
433 float age; //Hvor gammel er den frame vi er ved?
434 bool dir; //hvis dette er en animation der går frem og tilbage hvilken retning
435
436 uint lastframe; //check om det er den samme frame som sidst, så vi kan vide om vis skal opdatere cords
437
438 public:
439 uint frame; //hvilken frame er vi nået til i texturen (den er public så vi kan lave offset)
440 bool playing; //spiller vi?
441 bool firstFrame; //If this is the first frame
442 texPos pos; //Kordinater for den frame på texturen der er nu
443 texProp prop; //Properties for den textur som dette objekt har
444
textureClass()445 textureClass() {
446 age=10000;
447 firstFrame=1;
448 lastframe=1000;
449 frame=1;
450 dir=0;
451 }
452
play()453 void play()
454 {
455 int col=0,row=0;
456 if(prop.playing)
457 {
458 //Skal vi skifte frame?
459 age += globalTicksSinceLastDraw;
460 if(age >= prop.ticks) //Denne frame har været vist længe nok
461 {
462 age=0.0;
463 if(!dir)
464 {
465 if(frame == prop.frames)
466 {
467 if(prop.bidir)
468 {
469 dir=1;
470 } else {
471 frame=1;
472 }
473 } else {
474 frame++;
475 }
476 }
477
478 if(dir) {
479 if(frame == 1)
480 {
481 dir=0;
482 frame=2;
483 } else {
484 frame--;
485 }
486 }
487 }
488 }
489
490 uint f=0;
491 if(frame != lastframe || firstFrame)
492 {
493 lastframe=frame;
494 firstFrame=0;
495
496
497 //hvor mange kolonner er der på en række
498
499 for(row=0; row < prop.rows; row++)
500 {
501 for(col=0; col < prop.cols; col ++)
502 {
503 f++;
504 if(f == frame)
505 {
506 //Øverst Venstre
507 pos[0] = (prop.xoffset*(float)col); //0.0;
508 pos[1] = (prop.yoffset*(float)row);//0.0;
509
510 //Øverst højre
511 pos[2] = (prop.xoffset*(float)col) + prop.xoffset;
512 pos[3] = (prop.yoffset*(float)row);//0.0;
513
514 //Nederst højre
515 pos[4] = (prop.xoffset*(float)col) + prop.xoffset; // 1
516 pos[5] = (prop.yoffset*(float)row) + prop.yoffset; // 1
517
518 //Nederst venstre
519 pos[6] = (prop.xoffset*(float)col);//0.0;
520 pos[7] = (prop.yoffset*(float)row) + prop.yoffset; //1
521
522 if(prop.padding)
523 {
524 pos[0] += 1.0 / prop.pxw;
525 pos[1] += 1.0 / prop.pxh;
526
527 pos[2] -= 1.0 / prop.pxw;
528 pos[3] += 1.0 / prop.pxh;
529
530 pos[4] -= 1.0 / prop.pxw;
531 pos[5] -= 1.0 / prop.pxh;
532
533 pos[6] += 1.0 / prop.pxw;
534 pos[7] -= 1.0 / prop.pxh;
535 }
536 }
537 }
538 }
539
540 }
541 }
542
543 };
544
545 /* This function reads textureProperties from fileName
546 and applies them to *tex */
547 class textureManager {
548
549 public:
550
load(string file,textureClass & tex)551 bool load(string file, textureClass & tex)
552 {
553 SDL_Surface *temp = NULL;
554 GLint maxTexSize;
555 GLuint glFormat = GL_RGBA;
556
557 if(file.substr(file.length()-3,3).compare("jpg") == 0)
558 {
559 glFormat = GL_RGB;
560 }
561
562 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize);
563
564 temp = IMG_Load(file.data());
565
566 if(temp == NULL)
567 {
568 cout << "Texture manager: " << file << " : "<< SDL_GetError() << endl;
569 SDL_FreeSurface( temp );
570 return(FALSE);
571 }
572
573
574
575 //Hvis større end tilladt:
576 if(temp->w > maxTexSize)
577 {
578 cout << "Texture manager: '" << file << "' texturesize too large." << endl;
579 SDL_FreeSurface( temp );
580 return(FALSE);
581 }
582
583
584 glGenTextures(1, &tex.prop.texture);
585 glBindTexture(GL_TEXTURE_2D, tex.prop.texture);
586
587 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
588 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
589
590 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
591 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
592
593 glTexImage2D(GL_TEXTURE_2D, 0, glFormat, temp->w, temp->h, 0, glFormat, GL_UNSIGNED_BYTE, temp->pixels);
594
595 tex.prop.pxw = temp->w;
596 tex.prop.pxh = temp->h;
597 SDL_FreeSurface( temp );
598
599 return(TRUE);
600 }
601
readTexProps(string fileName,textureClass & tex)602 void readTexProps(string fileName, textureClass & tex)
603 {
604 char rgba[4][5];
605 ifstream f;
606 string line,set,val;
607 f.open( fileName.data() );
608
609 if(f.is_open())
610 {
611 while(!f.eof())
612 {
613 getline(f, line);
614 if(line.find('=') != string::npos)
615 {
616 set=line.substr(0,line.find('='));
617 val=line.substr(line.find('=')+1);
618 if(set=="xoffset")
619 {
620 tex.prop.xoffset=atof(val.data());
621 } else if(set=="yoffset")
622 {
623 tex.prop.yoffset=atof(val.data());
624 } else if(set=="cols")
625 {
626 tex.prop.cols=atoi(val.data());
627 } else if(set=="rows")
628 {
629 tex.prop.rows=atoi(val.data());
630 } else if(set=="ticks")
631 {
632 tex.prop.ticks=atoi(val.data());
633 } else if(set=="frames")
634 {
635 tex.prop.frames=atoi(val.data());
636 } else if(set=="bidir")
637 {
638 tex.prop.bidir=atoi(val.data());
639 } else if(set=="playing")
640 {
641 tex.prop.playing=atoi(val.data());
642 } else if(set=="padding")
643 {
644 tex.prop.padding=atoi(val.data());
645 } else if(set=="texcolor")
646 {
647 //Color in hex RGBA
648 //Example:color=FFFFFFFF
649 sprintf(rgba[0], "0x%c%c", val[0], val[1]);
650 sprintf(rgba[1], "0x%c%c", val[2], val[3]);
651 sprintf(rgba[2], "0x%c%c", val[4], val[5]);
652 sprintf(rgba[3], "0x%c%c", val[6], val[7]);
653 tex.prop.glTexColorInfo[0] = 0.003921569 * strtol(rgba[0], NULL,16);
654 tex.prop.glTexColorInfo[1] = 0.003921569 * strtol(rgba[1], NULL,16);
655 tex.prop.glTexColorInfo[2] = 0.003921569 * strtol(rgba[2], NULL,16);
656 tex.prop.glTexColorInfo[3] = 0.003921569 * strtol(rgba[3], NULL,16);
657 } else if(set=="parcolor")
658 {
659 //Color in hex RGBA
660 //Example:color=FFFFFFFF
661 sprintf(rgba[0], "0x%c%c", val[0], val[1]);
662 sprintf(rgba[1], "0x%c%c", val[2], val[3]);
663 sprintf(rgba[2], "0x%c%c", val[4], val[5]);
664 tex.prop.glParColorInfo[0] = 0.003921569 * strtol(rgba[0], NULL,16);
665 tex.prop.glParColorInfo[1] = 0.003921569 * strtol(rgba[1], NULL,16);
666 tex.prop.glParColorInfo[2] = 0.003921569 * strtol(rgba[2], NULL,16);
667 } else if(set=="file")
668 {
669 tex.prop.fileName = val;
670 } else {
671 cout << "Error: '"<<fileName<<"'invalid setting '"<< set <<"' with value '" << val <<"'"<<endl;
672 }
673
674 }
675 }
676
677 //Load the texture if we have a filename.
678 if(tex.prop.fileName.length() > 1)
679 {
680 string name = "gfx/"+tex.prop.fileName;
681 load(useTheme(name,setting.gfxTheme), tex);
682 }
683
684 } else {
685 cout << "readTexProps: Cannot open '" << fileName << "'"<<endl;
686 }
687 }
688 };
689
690
691
692 #include "sound.cpp"
693 soundClass soundMan; //Public object so all objects can use it
694
695 #include "menu.cpp"
696
697 #include "scoreboard.cpp"
698
699
700 class object {
701 public:
702 // GLfloat color[3];
703 GLfloat opacity; //This is still used, because it can then be reset, and it's used for fading out bricks (i think)
704 GLfloat posx, posy;
705 GLfloat width,height;
706 GLuint dl; //opengl display list
707 bool active;
708 bool collide;
709 bool reflect; //NOTE: use this for bricks that are not going to reflect the ball? (trap brick? :D)
710
711 textureClass tex;
712
713 };
714
715 class paddle_class : public object {
716 private:
717 GLfloat growspeed;
718 GLfloat destwidth;
719 GLfloat aspect; //så meget stiger højden i forhold til bredden
720 bool growing;
721
722
723 public:
724 bool dead;
725 textureClass *layerTex;
paddle_class()726 paddle_class ()
727 {
728 init();
729 growing=0;
730 growspeed=0.05f;
731 aspect = 0.2f;
732 }
733
init()734 void init()
735 {
736 posy = -1.15;
737 width=0.1;
738 height=0.02;
739 dead=0;
740 }
741
grow(GLfloat width)742 void grow(GLfloat width)
743 {
744 destwidth = width;
745 growing = 1;
746 }
747
draw()748 void draw()
749 {
750
751 if(!dead)
752 {
753 if(player.powerup[PO_DIE])
754 {
755 player.powerup[PO_DIE]=0;
756 dead=1;
757 width=0.0;
758 height=0.0;
759 }
760
761 if(growing)
762 {
763 GLfloat ix = growspeed * globalTicksSinceLastDraw;
764
765 width += ix;
766
767 if(width >= destwidth)
768 {
769 width = destwidth;
770 height = aspect*destwidth;
771 growing=0;
772 }
773 }
774
775 glLoadIdentity();
776 glTranslatef( posx, posy, -3.0 );
777
778 tex.play();
779 glBindTexture(GL_TEXTURE_2D, tex.prop.texture);
780 glColor4f( tex.prop.glTexColorInfo[0], tex.prop.glTexColorInfo[1], tex.prop.glTexColorInfo[2], tex.prop.glTexColorInfo[3] );
781 glBegin( GL_QUADS );
782 glTexCoord2f(tex.pos[0], tex.pos[1]); glVertex3f(-width,height, 0.0f );
783 glTexCoord2f(tex.pos[2], tex.pos[3]); glVertex3f( width,height, 0.0f );
784 glTexCoord2f(tex.pos[4], tex.pos[5]); glVertex3f( width,-height, 0.0f );
785 glTexCoord2f(tex.pos[6], tex.pos[7]); glVertex3f(-width,-height, 0.0f );
786 glEnd( );
787
788 //Hvis glue?
789 if(player.powerup[PO_GLUE])
790 {
791 glBindTexture(GL_TEXTURE_2D, layerTex[0].prop.texture);
792 glColor4f( layerTex[0].prop.glTexColorInfo[0], layerTex[0].prop.glTexColorInfo[1], layerTex[0].prop.glTexColorInfo[2], layerTex[0].prop.glTexColorInfo[3] );
793 glBegin( GL_QUADS );
794 glTexCoord2f(0.0f, 0.0f); glVertex3f(-width, height, 0.0f );
795 glTexCoord2f(1.0f, 0.0f); glVertex3f( width, height, 0.0f );
796 glTexCoord2f(1.0f, 0.99f); glVertex3f( width,-height, 0.0f );
797 glTexCoord2f(0.0f, 0.99f); glVertex3f(-width,-height, 0.0f );
798 glEnd( );
799 }
800
801 //Hvis gun
802 if(player.powerup[PO_GUN])
803 {
804 layerTex[1].play();
805 glBindTexture(GL_TEXTURE_2D, layerTex[1].prop.texture);
806 glColor4f( layerTex[1].prop.glTexColorInfo[0], layerTex[1].prop.glTexColorInfo[1], layerTex[1].prop.glTexColorInfo[2], layerTex[1].prop.glTexColorInfo[3] );
807 glBegin( GL_QUADS );
808 glTexCoord2f(layerTex[1].pos[0], layerTex[1].pos[1]); glVertex3f(-width, height*4, 0.0f );
809 glTexCoord2f(layerTex[1].pos[2], layerTex[1].pos[3]); glVertex3f( width, height*4, 0.0f );
810 glTexCoord2f(layerTex[1].pos[4], layerTex[1].pos[5]-0.01); glVertex3f( width,height, 0.0f );
811 glTexCoord2f(layerTex[1].pos[6], layerTex[1].pos[7]-0.01); glVertex3f(-width,height, 0.0f );
812 glEnd( );
813 }
814 }
815 }
816 };
817
818 //nasty fix to a problem
819 int nbrick[23][26];
820 int updated_nbrick[23][26];
821
822 class brick;
823 void makeExplosive(brick & b);
824
825 textureClass * texExplosiveBrick; //NOTE:Ugly
826 class brick : public object {
827
828 public:
829 int score; //Hvor meget gir den
830 bool destroytowin; // Skal den smadres for at man kan vinde?
831 char powerup;
832 char type;
833 GLfloat fade; //hvor meget brik
834 GLfloat fadespeed;
835 GLfloat zoomspeed;
836 GLfloat zoom;
837 bool isdyingnormally;
838 bool isexploding; //springer den i luften
839 int row; //what row is this brick in
840 int bricknum; //brick in this row
841 int hitsLeft; //Hvor mange gange skal denne brik rammes før den dør?
842 bool justBecomeExplosive; //If this brick just become a explosive one.
843
844
n(int dir)845 bool n(int dir)
846 {
847 switch(dir)
848 {
849 case 0: //Er der en brik til venstre for dig?
850 if(bricknum > 0)
851 {
852 if(nbrick[row][bricknum-1] != -1)
853 return(1);
854 }
855 break;
856 case 1: //Er der en brik til højre for dig?
857 if(bricknum < 25) //26
858 {
859 if(nbrick[row][bricknum+1] != -1)
860 return(1);
861 }
862 break;
863 case 2: //Er der en brik Ovenpå dig
864 if(row > 0)
865 {
866 if(nbrick[row-1][bricknum] != -1)
867 return(1);
868 }
869 break;
870 case 3: //Er der en brik nedenunder dig
871 if(row < 22) //23
872 {
873 if(nbrick[row+1][bricknum] != -1)
874 return(1);
875 }
876 break;
877 }
878
879 return(0);
880 }
881
882
883 void hit(effectManager & fxMan, pos poSpawnPos, pos poSpawnVel, bool ballHitMe);
884
draw(brick bricks[],effectManager & fxMan)885 void draw(brick bricks[], effectManager & fxMan)
886 {
887
888 if(isdyingnormally)
889 {
890 fade -= fadespeed * globalMilliTicksSinceLastDraw;
891 opacity = fade;
892 zoom -= zoomspeed * globalMilliTicksSinceLastDraw;
893
894 if(fade < 0.0)
895 active=0;
896 }
897
898 if(isexploding && !var.paused)
899 {
900 fade -= 7.0 * globalMilliTicksSinceLastDraw;
901 opacity = fade;
902 if(fade<0.0)
903 {
904 active=0;
905
906 pos spos,svel;
907 spos.x=posx;
908 spos.y=posy;
909
910
911 if(bricknum > 0)
912 {
913 if(nbrick[row][bricknum-1] != -1)
914 {
915 svel.x=rndflt(2,0)/3.0;
916 svel.y=rndflt(2,0)/3.0;
917 bricks[nbrick[row][bricknum-1]].hit(fxMan,spos,svel,0);
918 }
919 }
920
921
922 if(bricknum < 25)
923 {
924 if(nbrick[row][bricknum+1] != -1)
925 {
926 svel.x=rndflt(2,0)/3.0;
927 svel.y=rndflt(2,0)/3.0;
928 bricks[nbrick[row][bricknum+1]].hit(fxMan,spos,svel,0);
929 }
930 }
931
932 if(row > 0)
933 {
934 if(nbrick[row-1][bricknum] != -1)
935 {
936 svel.x=rndflt(2,0)/3.0;
937 svel.y=rndflt(2,0)/3.0;
938 bricks[nbrick[row-1][bricknum]].hit(fxMan,spos,svel,0);
939 }
940 }
941
942 if(row < 22)
943 {
944 if(nbrick[row+1][bricknum] != -1)
945 {
946 svel.x=rndflt(2,0)/3.0;
947 svel.y=rndflt(2,0)/3.0;
948 bricks[nbrick[row+1][bricknum]].hit(fxMan,spos,svel,0);
949 }
950 }
951
952 if(row > 0 && bricknum > 0)
953 {
954 if(nbrick[row-1][bricknum-1] != -1)
955 {
956 svel.x=rndflt(2,0)/3.0;
957 svel.y=rndflt(2,0)/3.0;
958 bricks[nbrick[row-1][bricknum-1]].hit(fxMan,spos,svel,0);
959 }
960 }
961 if(row > 0 && bricknum < 25)
962 {
963 if(nbrick[row-1][bricknum+1] != -1)
964 {
965 svel.x=rndflt(2,0)/3.0;
966 svel.y=rndflt(2,0)/3.0;
967 bricks[nbrick[row-1][bricknum+1]].hit(fxMan,spos,svel,0);
968 }
969 }
970
971 if(row < 22 && bricknum > 0)
972 {
973 if(nbrick[row+1][bricknum-1] != -1)
974 {
975 svel.x=rndflt(2,0)/3.0;
976 svel.y=rndflt(2,0)/3.0;
977 bricks[nbrick[row+1][bricknum-1]].hit(fxMan,spos,svel,0);
978 }
979 }
980
981 if(row < 22 && bricknum < 25)
982 {
983 if(nbrick[row+1][bricknum+1] != -1)
984 {
985 svel.x=rndflt(2,0)/3.0;
986 svel.y=rndflt(2,0)/3.0;
987 bricks[nbrick[row+1][bricknum+1]].hit(fxMan,spos,svel,0);
988 }
989 }
990
991
992 }
993
994 }
995
996 tex.play();
997
998 glColor4f( tex.prop.glTexColorInfo[0], tex.prop.glTexColorInfo[1], tex.prop.glTexColorInfo[2], opacity );
999
1000 glBindTexture(GL_TEXTURE_2D, tex.prop.texture);
1001 glBegin( GL_QUADS );
1002 glTexCoord2f(tex.pos[0],tex.pos[1]);glVertex3f( posx + (-0.0616*zoom), posy + (0.035*zoom), 0.00 ); // øverst venst
1003 glTexCoord2f(tex.pos[2],tex.pos[3]);glVertex3f( posx + ( 0.0616*zoom), posy + (0.035*zoom), 0.00 ); // øverst højre
1004 glTexCoord2f(tex.pos[4],tex.pos[5]);glVertex3f( posx + ( 0.0616*zoom), posy + (-0.035*zoom), 0.00 ); // nederst højre
1005 glTexCoord2f(tex.pos[6],tex.pos[7]);glVertex3f( posx + (-0.0616*zoom), posy + (-0.035*zoom), 0.00 ); // nederst venstre
1006 glEnd( );
1007 }
1008
growExplosive(brick bricks[])1009 void growExplosive(brick bricks[])
1010 {
1011 if(type!='B' || justBecomeExplosive)
1012 {
1013 return;
1014 }
1015
1016 if(bricknum > 0)
1017 {
1018 if(nbrick[row][bricknum-1] != -1)
1019 {
1020 makeExplosive(bricks[nbrick[row][bricknum-1]]);
1021 }
1022 }
1023
1024 if(bricknum < 25)
1025 {
1026 if(nbrick[row][bricknum+1] != -1)
1027 {
1028 makeExplosive(bricks[nbrick[row][bricknum+1]]);
1029 }
1030 }
1031
1032 if(row > 0)
1033 {
1034 if(nbrick[row-1][bricknum] != -1)
1035 {
1036 makeExplosive(bricks[nbrick[row-1][bricknum]]);
1037 }
1038 }
1039
1040 if(row < 22)
1041 {
1042 if(nbrick[row+1][bricknum] != -1)
1043 {
1044 makeExplosive(bricks[nbrick[row+1][bricknum]]);
1045 }
1046 }
1047
1048 if(row > 0 && bricknum > 0)
1049 {
1050 if(nbrick[row-1][bricknum-1] != -1)
1051 {
1052 makeExplosive(bricks[nbrick[row-1][bricknum-1]]);
1053 }
1054 }
1055 if(row > 0 && bricknum < 25)
1056 {
1057 if(nbrick[row-1][bricknum+1] != -1)
1058 {
1059 makeExplosive(bricks[nbrick[row-1][bricknum+1]]);
1060 }
1061 }
1062
1063 if(row < 22 && bricknum > 0)
1064 {
1065 if(nbrick[row+1][bricknum-1] != -1)
1066 {
1067 makeExplosive(bricks[nbrick[row+1][bricknum-1]]);
1068 }
1069 }
1070
1071 if(row < 22 && bricknum < 25)
1072 {
1073 if(nbrick[row+1][bricknum+1] != -1)
1074 {
1075 makeExplosive(bricks[nbrick[row+1][bricknum+1]]);
1076 }
1077 }
1078 }
1079
breakable()1080 void breakable()
1081 {
1082 if(type == '3')
1083 {
1084 score=300;
1085 hitsLeft=1;
1086 type='1'; //hehe..
1087 tex.frame=2;
1088 tex.play();
1089 } else if(type=='4')
1090 {
1091 hitsLeft=1;
1092 tex.frame=2;
1093 tex.play();
1094 } else if(type=='9')
1095 {
1096 hitsLeft=1;
1097 tex.frame=3;
1098 tex.play();
1099 }
1100 }
1101 };
1102
makeExplosive(brick & b)1103 void makeExplosive(brick & b)
1104 {
1105 if(b.type != 'B')
1106 {
1107 b.type='B';
1108 b.tex=*texExplosiveBrick;
1109 //NOTE: for some reason, the color of the object was changed, why??
1110 b.justBecomeExplosive=1;
1111 }
1112 }
1113
1114 #include "loadlevel.cpp"
1115
1116 class moving_object : public object {
1117 public:
1118 GLfloat xvel,yvel,velocity;
1119
moving_object()1120 moving_object () {
1121 xvel=0.0;
1122 yvel=0.0;
1123
1124 }
1125
1126 };
1127
1128 #include "effects.cpp"
1129 #include "background.cpp"
1130 void spawnpowerup(char powerup, pos a, pos b);
1131
1132 class bulletsClass {
1133 private:
1134 moving_object bullets[16];
1135 public:
1136 int active;
1137
bulletsClass(textureClass & texBullet)1138 bulletsClass(textureClass & texBullet)
1139 {
1140 int i;
1141 for(i=0; i < 16; i++)
1142 {
1143 bullets[i].active=0;
1144 bullets[i].tex = texBullet;
1145 bullets[i].width = 0.02;
1146 bullets[i].height = 0.02;
1147 }
1148 }
1149
shoot(pos p)1150 void shoot(pos p)
1151 {
1152 int i;
1153 //Find ledig bullet
1154 for(i=0; i < 16; i++)
1155 {
1156 if(!bullets[i].active)
1157 {
1158 soundMan.add(SND_SHOT, p.x);
1159 bullets[i].active=1;
1160 bullets[i].posx = p.x;
1161 bullets[i].posy = p.y;
1162 bullets[i].xvel =0;
1163 bullets[i].yvel =1.0;
1164 break;
1165 }
1166 }
1167 }
1168
move()1169 void move()
1170 {
1171 int i;
1172 for(i=0; i < 16; i++)
1173 {
1174 if(bullets[i].active)
1175 {
1176 //Flyt
1177 bullets[i].posy += bullets[i].yvel * globalMilliTicks;
1178 }
1179 }
1180 }
1181
draw()1182 void draw()
1183 {
1184 int i;
1185 glColor4f(1,1,1,1);
1186 for(i=0; i < 16; i++)
1187 {
1188 if(bullets[i].active)
1189 {
1190 //draw
1191
1192 bullets[i].tex.play();
1193
1194 glLoadIdentity();
1195 glTranslatef( bullets[i].posx, bullets[i].posy, -3.0 );
1196
1197 glBindTexture(GL_TEXTURE_2D, bullets[i].tex.prop.texture);
1198 glBegin( GL_QUADS );
1199 glTexCoord2f(bullets[i].tex.pos[0],bullets[i].tex.pos[1]); glVertex3f( -bullets[i].width, bullets[i].height, 0.0 );
1200 glTexCoord2f(bullets[i].tex.pos[2],bullets[i].tex.pos[3]); glVertex3f( bullets[i].width, bullets[i].height, 0.0 );
1201 glTexCoord2f(bullets[i].tex.pos[4],bullets[i].tex.pos[5]); glVertex3f( bullets[i].width,-bullets[i].height, 0.0 );
1202 glTexCoord2f(bullets[i].tex.pos[6],bullets[i].tex.pos[7]); glVertex3f( -bullets[i].width,-bullets[i].height, 0.0 );
1203 glEnd( );
1204 }
1205 }
1206 }
1207
clear()1208 void clear()
1209 {
1210 int i;
1211 for(i=0; i < 16; i++)
1212 {
1213 bullets[i].active=0;
1214 }
1215 }
1216
coldet(brick & b,effectManager & fxMan)1217 void coldet(brick & b, effectManager & fxMan)
1218 {
1219 int i;
1220 bool hit;
1221 pos v,p;
1222 v.x=0;
1223 v.y=bullets[0].xvel;
1224
1225 for(i=0; i < 16; i++)
1226 {
1227 if(bullets[i].active)
1228 {
1229 hit=0;
1230
1231 //y
1232 if(bullets[i].posy+bullets[i].height/10.0 > b.posy-b.height && bullets[i].posy+bullets[i].height/10.0 < b.posy+b.height)
1233 {
1234 p.x = b.posx;
1235 p.y = b.posy;
1236 //Venstre side:
1237 if(bullets[i].posx > b.posx-b.width && bullets[i].posx < b.posx+b.width)
1238 {
1239 hit=1;
1240 }
1241
1242 if(hit)
1243 {
1244 b.hit(fxMan, p, v,1);
1245
1246 bullets[i].active=0;
1247
1248 p.x = bullets[i].posx;
1249 p.y = bullets[i].posy;
1250
1251 if(setting.eyeCandy)
1252 {
1253 fxMan.set(FX_VAR_TYPE, FX_SPARKS);
1254 fxMan.set(FX_VAR_COLDET,1);
1255 fxMan.set(FX_VAR_LIFE, 1300);
1256 fxMan.set(FX_VAR_NUM, 16);
1257 fxMan.set(FX_VAR_SIZE, 0.015f);
1258 fxMan.set(FX_VAR_SPEED, 0.4f);
1259 fxMan.set(FX_VAR_GRAVITY, 1.0f);
1260
1261 fxMan.set(FX_VAR_COLOR, 1.0f, 0.7f, 0.0f);
1262 fxMan.spawn(p);
1263 fxMan.set(FX_VAR_COLOR, 1.0f, 0.8f, 0.0f);
1264 fxMan.spawn(p);
1265 fxMan.set(FX_VAR_COLOR, 1.0f, 0.9f, 0.0f);
1266 fxMan.spawn(p);
1267 fxMan.set(FX_VAR_COLOR, 1.0f, 1.0f, 0.0f);
1268 fxMan.spawn(p);
1269 }
1270 }
1271 } else if(bullets[i].posy > 1.6) {
1272 bullets[i].active=0;
1273 }
1274 }
1275 }
1276 }
1277 };
1278
hit(effectManager & fxMan,pos poSpawnPos,pos poSpawnVel,bool ballHitMe)1279 void brick::hit(effectManager & fxMan, pos poSpawnPos, pos poSpawnVel, bool ballHitMe)
1280 {
1281 pos p,s;
1282
1283 if(type!='3' || player.powerup[PO_THRU])
1284 hitsLeft--;
1285
1286 //We don't want to play a sound if this brick is not an explosive, and was hit by an explosion
1287 if(ballHitMe || type=='B')
1288 {
1289 if(type=='3') //cement
1290 {
1291 soundMan.add(SND_CEMENT_BRICK_HIT, posx);
1292 } else if(type=='4' || type=='9') //glass or invisible
1293 {
1294
1295 if(hitsLeft == 2)
1296 {
1297 soundMan.add(SND_INVISIBLE_BRICK_APPEAR, posx);
1298 } else if(hitsLeft == 1)
1299 {
1300 soundMan.add(SND_GLASS_BRICK_HIT, posx);
1301 } else {
1302 soundMan.add(SND_GLASS_BRICK_BREAK, posx);
1303 }
1304 } else if(type=='B') //explosive
1305 {
1306 soundMan.add(SND_EXPL_BRICK_BREAK, posx);
1307 } else if(type=='C') //Doom brick
1308 {
1309 soundMan.add(SND_DOOM_BRICK_BREAK, posx);
1310 } else { //All the other bricks
1311 soundMan.add(SND_NORM_BRICK_BREAK, posx);
1312 }
1313 }
1314
1315
1316 if(type != '3' || player.powerup[PO_THRU])
1317 {
1318 //Brick was hit, dont do anything
1319 if(isdyingnormally || isexploding)
1320 {
1321 return;
1322 }
1323 player.score += (brick::score*player.multiply)* var.averageBallSpeed; //Speed bonus
1324
1325 if(hitsLeft < 1 || type == 'B') //Hvis brikken er explosiv kan den ikke have nogle hits tilbage
1326 {
1327 collide=0;
1328
1329 updated_nbrick[row][bricknum]=-1;
1330 var.bricksHit = 1;
1331
1332 gVar.deadTime=0;
1333
1334 spawnpowerup(powerup, poSpawnPos, poSpawnVel);
1335 powerup='0';
1336
1337 if(setting.eyeCandy)
1338 {
1339 p.x=posx;
1340 p.y=posy;
1341 s.x=width*2;
1342 s.y=height*2;
1343
1344 fxMan.set(FX_VAR_TYPE, FX_PARTICLEFIELD);
1345 fxMan.set(FX_VAR_COLDET, 1);
1346 fxMan.set(FX_VAR_LIFE, 1300);
1347 fxMan.set(FX_VAR_NUM, 20);
1348 fxMan.set(FX_VAR_SIZE, 0.03f);
1349 fxMan.set(FX_VAR_SPEED, 0.6f);
1350 fxMan.set(FX_VAR_GRAVITY, 0.7f);
1351
1352 fxMan.set(FX_VAR_RECTANGLE, s);
1353
1354 fxMan.set(FX_VAR_COLOR, tex.prop.glParColorInfo[0],tex.prop.glParColorInfo[1],tex.prop.glParColorInfo[2]);
1355 fxMan.spawn(p);
1356 }
1357
1358 if(type=='B')
1359 {
1360 isexploding=1;
1361
1362 if(setting.eyeCandy)
1363 {
1364 p.x = posx;
1365 p.y = posy;
1366 fxMan.set(FX_VAR_TYPE, FX_PARTICLEFIELD);
1367 fxMan.set(FX_VAR_COLDET,1);
1368 fxMan.set(FX_VAR_LIFE, 1200);
1369 fxMan.set(FX_VAR_NUM, 10);
1370 fxMan.set(FX_VAR_SIZE, 0.08f);
1371 fxMan.set(FX_VAR_SPEED, 0.4f);
1372 fxMan.set(FX_VAR_GRAVITY, -1.3f);
1373
1374 fxMan.set(FX_VAR_COLOR, 1.0f, 0.7f, 0.0f);
1375 fxMan.spawn(p);
1376 fxMan.set(FX_VAR_COLOR, 1.0f, 0.8f, 0.0f);
1377 fxMan.spawn(p);
1378 fxMan.set(FX_VAR_COLOR, 1.0f, 0.9f, 0.0f);
1379 fxMan.spawn(p);
1380 fxMan.set(FX_VAR_COLOR, 1.0f, 1.0f, 0.0f);
1381 fxMan.spawn(p);
1382 }
1383 } else {
1384 isdyingnormally=1;
1385 }
1386 } else { //No hits left
1387 tex.frame++;
1388 tex.play();
1389 } //Hits left
1390 }
1391 }
1392
1393 glAnnounceTextClass announce;
1394 //Slet mig måske
abs2(float x)1395 float abs2(float x)
1396 {
1397 if (x<0) {return -x;}
1398 return x;
1399 }
LinesCross(float x0,float y0,float x1,float y1,float x2,float y2,float x3,float y3,GLfloat * linx,GLfloat * liny)1400 int LinesCross(float x0,float y0,float x1,float y1,float x2,float y2,float x3,float y3, GLfloat *linx, GLfloat *liny)
1401 {
1402 float d=(x1-x0)*(y3-y2)-(y1-y0)*(x3-x2);
1403 if (abs2(d)<0.001f) {return -1;}
1404 float AB=((y0-y2)*(x3-x2)-(x0-x2)*(y3-y2))/d;
1405 if (AB>0.0 && AB<1.0)
1406 {
1407 float CD=((y0-y2)*(x1-x0)-(x0-x2)*(y1-y0))/d;
1408 if (CD>0.0 && CD<1.0)
1409 {
1410 *linx=x0+AB*(x1-x0);
1411 *liny=y0+AB*(y1-y0);
1412 return 1;
1413 }
1414 }
1415 return 0;
1416 }
1417
1418 //Leaves an trail of the ball
1419 class tracer {
1420 private:
1421 GLfloat x[100], y[100], r[100], g[100], b[100], a[100],s[100], cr,cg,cb;
1422 bool active[100];
1423 int color;
1424 GLfloat lastX, lastY; //Last position where we spawned one
1425
1426 public:
1427 GLfloat height, width;
1428 // GLuint texture;
1429 textureClass *tex;
1430 int len;
draw()1431 void draw()
1432 {
1433 int i;
1434 for(i=0; i < len; i++)
1435 {
1436
1437 if(active[i])
1438 {
1439 a[i] -= 4.0*globalMilliTicksSinceLastDraw;
1440 s[i] += 4.0*globalMilliTicksSinceLastDraw;
1441 if(a[i] < 0.0)
1442 active[i]=0;
1443
1444 tex->play();
1445 glBindTexture(GL_TEXTURE_2D, tex->prop.texture);
1446 glLoadIdentity();
1447 glTranslatef(x[i],y[i],-3.0);
1448 glColor4f(r[i], g[i], b[i], a[i]);
1449 glBegin( GL_QUADS );
1450 glTexCoord2f(tex->pos[0],tex->pos[1]);glVertex3f( -width*s[i], height*s[i], 0.00 ); // øverst venst
1451 glTexCoord2f(tex->pos[2],tex->pos[3]);glVertex3f( width*s[i], height*s[i], 0.00 ); // øverst højre
1452 glTexCoord2f(tex->pos[4],tex->pos[5]);glVertex3f( width*s[i],-height*s[i], 0.00 ); // nederst højre
1453 glTexCoord2f(tex->pos[6],tex->pos[7]);glVertex3f( -width*s[i],-height*s[i], 0.00 ); // nederst venstre
1454 glEnd( );
1455 }
1456 }
1457 }
1458
colorRotate(bool explosive,GLfloat c[])1459 void colorRotate(bool explosive, GLfloat c[])
1460 {
1461 color++;
1462 if(color > 5)
1463 color=0;
1464
1465 if(!explosive)
1466 {
1467 cr=c[0];
1468 cg=c[1];
1469 cb=c[2];
1470 } else {
1471 cr=1.0;
1472 cg=0.6;
1473 cb=0.0;
1474 }
1475 }
1476
tracer()1477 tracer()
1478 {
1479 len=100;
1480 lastX=0;
1481 lastY=0;
1482 cr=1;
1483 cg=0;
1484 cb=0;
1485 height = 0.01;
1486 width = 0.01;
1487 int i;
1488 for(i=0; i < 100; i++)
1489 {
1490 active[i]=0;
1491 }
1492 }
1493
update(GLfloat nx,GLfloat ny)1494 void update(GLfloat nx, GLfloat ny)
1495 {
1496 //If long enough away
1497 GLfloat dist = sqrt( pow(nx-lastX, 2) + pow(ny-lastY, 2) );
1498 if(dist > 0.01)
1499 {
1500 lastX = nx;
1501 lastY = ny;
1502 //find a non-active trail-part
1503 int i;
1504 for(i=0; i < len; i++)
1505 {
1506 if(!active[i])
1507 {
1508 active[i]=1;
1509 a[i]=1.0; //tweak me
1510 x[i]=nx;
1511 y[i]=ny;
1512 s[i]=1.0;
1513 r[i]=cr;
1514 g[i]=cg;
1515 b[i]=cb;
1516 break;
1517 }
1518 }
1519 }
1520 }
1521
1522
1523 };
1524
1525 class ball : public moving_object {
1526 private:
1527 GLfloat rad;
1528 bool growing,shrinking;
1529 GLfloat destwidth, growspeed;
1530
1531 public:
1532 tracer tail;
1533 bool explosive; //Makes brick explosive (to get a explosion effect) and explode it
1534
1535 bool glued; //Sidder vi fast på padden for øjeblikket?
1536 GLfloat gluedX;
1537 //Variabler med forududregnede værdier
1538 GLfloat bsin[32], bcos[32];
1539
1540 bool aimdir;
1541 textureClass fireTex;
1542
1543 GLfloat lastX,lastY;
ball()1544 ball() {
1545 growing=0;
1546 growspeed=0.1;
1547 width=0.0;
1548 height=0.0;
1549 glued=0;
1550 posx=0.0f;
1551 posy=0.0f;
1552 aimdir=0;
1553 }
1554
hit(GLfloat c[])1555 void hit(GLfloat c[])
1556 {
1557 if(setting.eyeCandy)
1558 tail.colorRotate(explosive, c);
1559 }
1560
move()1561 void move()
1562 {
1563
1564 //vi laver lige den her coldet her...
1565 if(posx+width > 1.6 && xvel > 0.0)
1566 {
1567 soundMan.add(SND_BALL_HIT_BORDER, posx);
1568 xvel *= -1;
1569 } else if(posx-width < -1.6 && xvel < 0.0)
1570 {
1571 soundMan.add(SND_BALL_HIT_BORDER, posx);
1572 xvel *= -1;
1573 } else if(posy+width > 1.25 && yvel > 0.0)
1574 {
1575 soundMan.add(SND_BALL_HIT_BORDER, posx);
1576 yvel *= -1;
1577 } else if(posy-width < -1.24)
1578 {
1579 active=0;
1580 }
1581
1582 posx +=xvel*globalMilliTicks;
1583
1584 if(!glued)
1585 {
1586 posy +=yvel*globalMilliTicks;
1587 } else {
1588 gVar.deadTime = 0;
1589 }
1590
1591 if(setting.eyeCandy)
1592 tail.update(posx,posy);
1593
1594 }
1595
draw(paddle_class & paddle)1596 void draw(paddle_class &paddle)
1597 {
1598
1599 GLfloat newsize;
1600
1601 if(setting.eyeCandy)
1602 tail.draw();
1603
1604 if(growing)
1605 {
1606 newsize = growspeed * globalMilliTicksSinceLastDraw;
1607 width += newsize;
1608 height += newsize;
1609
1610 if(width >= destwidth)
1611 {
1612 width=destwidth;
1613 height=destwidth;
1614
1615 growing=0;
1616 }
1617
1618 tail.width = width;
1619 tail.height = height;
1620
1621 } else if(shrinking)
1622 {
1623
1624 newsize = growspeed * globalMilliTicksSinceLastDraw;
1625 width -= newsize;
1626 height -= newsize;
1627 if(width <= destwidth)
1628 {
1629 width=destwidth;
1630 height=destwidth;
1631
1632 shrinking=0;
1633 }
1634
1635 tail.width = width;
1636 tail.height = height;
1637
1638 }
1639
1640 if(glued && player.powerup[PO_LASER])
1641 {
1642 if(player.powerup[PO_AIM])
1643 {
1644 if(aimdir==0)
1645 {
1646 rad -= 1.2*globalMilliTicksSinceLastDraw;
1647
1648 if(rad < BALL_MIN_DEGREE)
1649 aimdir=1;
1650 } else {
1651 rad += 1.2*globalMilliTicksSinceLastDraw;
1652 if(rad > BALL_MAX_DEGREE+BALL_MIN_DEGREE)
1653 aimdir=0;
1654 }
1655 setangle(rad);
1656 } else {
1657 getRad();
1658 }
1659
1660 GLfloat bxb = cos(rad)*0.5, byb = sin(rad)*0.5;
1661
1662 glLoadIdentity();
1663 glTranslatef( posx, posy, -3.0);
1664 glDisable(GL_TEXTURE_2D);
1665 glLineWidth ( 1.0 );
1666 glEnable( GL_LINE_SMOOTH );
1667 glBegin( GL_LINES );
1668 glColor4f(rndflt(2,0), rndflt(1,0), 0.0, 0.0);
1669 glVertex3f( 0.0, 0.0, 0.0 );
1670 glColor4f(rndflt(2,0), 0.0, 0.0, 1.0);
1671 glVertex3f( bxb, byb, 0.0 );
1672 glEnd();
1673
1674 glPointSize( 5.0f );
1675 glColor4f(1.0, 0.0, 0.0, 1.0);
1676 glEnable(GL_POINT_SMOOTH);
1677 glBegin( GL_POINTS );
1678 glVertex3f(bxb, byb, 0.0);
1679 glEnd( );
1680
1681
1682 }
1683
1684 if(!glued && player.powerup[PO_AIMHELP])
1685 {
1686 //Use line intersect to determine if this ball will collide with the paddle
1687
1688 getRad();
1689 GLfloat p[4], b[4], o[2]; //Paddle line, ball line, bounceoff endpoint
1690 p[0] = paddle.posx - paddle.width;
1691 p[1] = paddle.posx + paddle.width;
1692
1693 p[2] = paddle.posy + paddle.height + height;
1694 p[3] = paddle.posy + paddle.height + height;
1695
1696 b[0] = posx;
1697 b[1] = posx + (cos(rad) * 3.0);
1698 b[2] = posy;
1699 b[3] = posy + (sin(rad) * 3.0);
1700
1701 GLfloat cx,cy, R;
1702 if(LinesCross(p[0], p[2], p[1],p[3], b[0], b[2], b[1], b[3], &cx, &cy))
1703 {
1704 R = bounceOffAngle(paddle.width, paddle.posx, cx);
1705 o[0] = cx+(cos(R)*2.0);
1706 o[1] = cy+(sin(R)*2.0);
1707 glLoadIdentity();
1708 glTranslatef( 0.0, 0.0, -3.0);
1709 glDisable(GL_TEXTURE_2D);
1710 glLineWidth ( 2.0 );
1711 glEnable( GL_LINE_SMOOTH );
1712 glBegin( GL_LINE_STRIP );
1713 //Line from ball to paddle
1714 glColor4f(1.0, 0.0, 0.0, 0.0);
1715 glVertex3f( b[0], b[2], 0.0 );
1716 glColor4f(1.0, 1.0, 0.0, 1.0);
1717 glVertex3f( cx, cy, 0.0 );
1718 //Bounce off line.
1719 glColor4f(1.0, 0.0, 0.0, 0.0);
1720 glVertex3f( o[0], o[1], 0.0 );
1721 glEnd( );
1722
1723 }
1724
1725 }
1726
1727 glLoadIdentity();
1728 glTranslatef( posx, posy, -3.0);
1729 glEnable(GL_TEXTURE_2D);
1730
1731 glColor4f(1.0, 1.0, 1.0, 1.0);
1732
1733 if(explosive)
1734 {
1735 fireTex.play();
1736 glBindTexture(GL_TEXTURE_2D, fireTex.prop.texture);
1737 glColor4f( fireTex.prop.glTexColorInfo[0], fireTex.prop.glTexColorInfo[1], fireTex.prop.glTexColorInfo[2], fireTex.prop.glTexColorInfo[3] );
1738 glEnable(GL_BLEND);
1739 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1740 glBegin( GL_QUADS );
1741 glTexCoord2f(fireTex.pos[0],fireTex.pos[1]); glVertex3f( -width, height, 0.0 );
1742 glTexCoord2f(fireTex.pos[2],fireTex.pos[3]); glVertex3f( width, height, 0.0 );
1743 glTexCoord2f(fireTex.pos[4],fireTex.pos[5]); glVertex3f( width,-height, 0.0 );
1744 glTexCoord2f(fireTex.pos[6],fireTex.pos[7]); glVertex3f( -width,-height, 0.0 );
1745 glEnd( );
1746 } else {
1747 tex.play();
1748 glBindTexture(GL_TEXTURE_2D, tex.prop.texture);
1749 glColor4f( tex.prop.glTexColorInfo[0], tex.prop.glTexColorInfo[1], tex.prop.glTexColorInfo[2], tex.prop.glTexColorInfo[3] );
1750 glEnable(GL_BLEND);
1751 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1752 glBegin( GL_QUADS );
1753 glTexCoord2f(tex.pos[0],tex.pos[1]); glVertex3f( -width, height, 0.0 );
1754 glTexCoord2f(tex.pos[2],tex.pos[3]); glVertex3f( width, height, 0.0 );
1755 glTexCoord2f(tex.pos[4],tex.pos[5]); glVertex3f( width,-height, 0.0 );
1756 glTexCoord2f(tex.pos[6],tex.pos[7]); glVertex3f( -width,-height, 0.0 );
1757 glEnd( );
1758 }
1759
1760 #ifdef DEBUG_DRAW_BALL_QUAD
1761 glLoadIdentity();
1762 glTranslatef(posx, posy, -3.0);
1763 glDisable( GL_TEXTURE_2D );
1764 glColor4f(1.0,1.0,1.0,1.0);
1765 glBegin( GL_LINES );
1766 glVertex3f( -width, height, 0);
1767 glVertex3f( width, height, 0);
1768
1769 glVertex3f( -width, -height, 0);
1770 glVertex3f( width, -height,0);
1771
1772 glVertex3f( -width, height, 0);
1773 glVertex3f( -width, -height, 0);
1774
1775 glVertex3f( width, height, 0);
1776 glVertex3f( width, -height, 0 );
1777
1778 glEnd();
1779 glEnable(GL_TEXTURE_2D);
1780 #endif
1781
1782 }
1783
getRad()1784 GLfloat getRad()
1785 {
1786 rad = atan2(yvel,xvel);
1787 return(rad);
1788 }
1789
setangle(GLfloat o)1790 void setangle(GLfloat o)
1791 {
1792 if(o < BALL_MIN_DEGREE)
1793 {
1794 o=BALL_MIN_DEGREE;
1795 }
1796
1797 if( o > BALL_MAX_DEGREE + BALL_MIN_DEGREE)
1798 {
1799 o=BALL_MAX_DEGREE + BALL_MIN_DEGREE;
1800 }
1801
1802 rad=o;
1803 xvel = velocity * cos(rad);
1804 yvel = velocity * sin(rad);
1805 }
1806
setspeed(GLfloat v)1807 void setspeed(GLfloat v)
1808 {
1809 if(v > difficulty.maxballspeed[player.difficulty])
1810 {
1811 velocity = difficulty.maxballspeed[player.difficulty];
1812 } else {
1813 velocity = v;
1814 }
1815
1816 getRad();
1817 xvel = velocity * cos(rad);
1818 yvel = velocity * sin(rad);
1819 }
1820
setSize(GLfloat s)1821 void setSize(GLfloat s)
1822 {
1823 float rad;
1824
1825 if(s > width)
1826 growing=1;
1827 else if(s < width)
1828 shrinking=1;
1829
1830 destwidth=s;
1831
1832 int i=0;
1833
1834 //opdater points
1835 for(rad=0.0; rad < 6.3; rad +=0.2)
1836 {
1837 if(i < 32)
1838 {
1839 bsin[i] = sin(rad)*s;
1840 bcos[i] = cos(rad)*s;
1841 }
1842 i++;
1843 }
1844 }
1845
1846 };
1847
1848 void coldet(brick & br, ball & ba, pos & p, effectManager & fxMan);
1849 void padcoldet(ball & b, paddle_class & p, pos & po);
1850
1851 #define MAXBALLS 16
1852 class ballManager {
1853
1854 public:
1855 int activeBalls;
1856 ball b[MAXBALLS];
1857 textureClass tex[3];
1858
initBalls()1859 void initBalls()
1860 {
1861 activeBalls=0;
1862 clear();
1863 }
1864
ballManager(textureClass btex[])1865 ballManager(textureClass btex[])
1866 {
1867 int i;
1868 tex[0] = btex[0];
1869 tex[1] = btex[1];
1870 tex[2] = btex[2];
1871
1872
1873 for(i=0; i < MAXBALLS; i++)
1874 {
1875 b[i].tex=tex[0];
1876 b[i].fireTex=tex[1];
1877 b[i].tail.tex = &tex[2];
1878 }
1879
1880 initBalls();
1881 }
1882
getSpeed()1883 void getSpeed()
1884 {
1885 int i;
1886 var.averageBallSpeed = 0.0;
1887 for(i=0; i < MAXBALLS; i++)
1888 {
1889 if(b[i].active)
1890 {
1891 var.averageBallSpeed += b[i].velocity;
1892 }
1893 }
1894 var.averageBallSpeed /= activeBalls;
1895 }
1896
1897 //klon alle aktive bolde
multiply()1898 void multiply()
1899 {
1900 pos op;
1901 int a=0,c=0;
1902 int i;
1903 //How many balls are active?
1904 for(i=0; i < MAXBALLS; i++)
1905 {
1906 if(b[i].active)
1907 {
1908 a++;
1909 }
1910 }
1911
1912 for(i=0; i < MAXBALLS; i++)
1913 {
1914 if(b[i].active && c != a)
1915 {
1916 c++;
1917 op.y = b[i].posy;
1918 op.x = b[i].posx;
1919 spawn(op,0,0.0f,b[i].velocity, rndflt( BALL_MAX_DEGREE+BALL_MIN_DEGREE,0));
1920 }
1921 }
1922
1923 }
1924
unglue()1925 void unglue()
1926 {
1927 int i;
1928 for(i=0; i < MAXBALLS; i++)
1929 {
1930 b[i].glued=0;
1931 }
1932 }
1933
spawn(pos p,bool glued,GLfloat gx,GLfloat speed,GLfloat angle)1934 void spawn(pos p, bool glued, GLfloat gx ,GLfloat speed, GLfloat angle)
1935 {
1936 int i;
1937 for(i=0; i < MAXBALLS; i++)
1938 {
1939 if(!b[i].active)
1940 {
1941 activeBalls++;
1942 b[i].tex = tex[0];
1943 b[i].fireTex = tex[1];
1944 b[i].glued=glued;
1945
1946 b[i].width=0.0;
1947 b[i].height=0.0;
1948 b[i].gluedX=gx;
1949 b[i].active=1;
1950 b[i].collide=1;
1951 b[i].reflect=1;
1952 b[i].lastX = p.x;
1953 b[i].lastY = p.y;
1954 b[i].posx = p.x;
1955 b[i].posy = p.y;
1956 b[i].explosive=0;
1957 b[i].setspeed(speed);
1958 b[i].setangle(angle);
1959 b[i].setSize(0.025);
1960
1961 //New balls get already applied powerups if not hard
1962 if(player.difficulty < HARD)
1963 {
1964 b[i].explosive = player.powerup[PO_EXPLOSIVE];
1965
1966 if(player.powerup[PO_SMALLBALL])
1967 {
1968 powerup(PO_SMALLBALL);
1969 }
1970
1971 if(player.powerup[PO_BIGBALL])
1972 {
1973 powerup(PO_BIGBALL);
1974 }
1975 }
1976 getSpeed();
1977 break;
1978 }
1979 }
1980 }
1981
clear()1982 void clear()
1983 {
1984 int i;
1985 activeBalls=0;
1986 for(i=0; i < MAXBALLS; i++)
1987 {
1988 b[i].active=0;
1989 }
1990 getSpeed();
1991 }
1992
move()1993 void move()
1994 {
1995 int a=0;
1996 int i;
1997
1998 for(i=0; i < MAXBALLS; i++)
1999 {
2000 if(b[i].active)
2001 {
2002 b[i].move();
2003 a++;
2004 }
2005
2006 }
2007 activeBalls=a;
2008 }
2009
draw(paddle_class & paddle)2010 void draw(paddle_class &paddle)
2011 {
2012 int i;
2013
2014 for(i=0; i < MAXBALLS; i++)
2015 {
2016 if(b[i].active)
2017 {
2018 b[i].draw(paddle);
2019 }
2020 }
2021
2022 }
2023
bcoldet(brick & bri,effectManager & fxMan)2024 void bcoldet(brick & bri,effectManager & fxMan)
2025 {
2026 int i;
2027 pos p;
2028 for(i=0; i < MAXBALLS; i++)
2029 {
2030 if(b[i].active)
2031 {
2032 p.x=100;
2033 coldet(bri, b[i], p, fxMan);
2034 if(p.x < 50) //we totally hit?? :P
2035 {
2036 getSpeed();
2037
2038 if(setting.eyeCandy)
2039 {
2040 //spawn partikler
2041 fxMan.set(FX_VAR_TYPE, FX_SPARKS);
2042 fxMan.set(FX_VAR_COLDET,1);
2043
2044 fxMan.set(FX_VAR_SPEED, 1.0f);
2045
2046 fxMan.set(FX_VAR_LIFE, 1500);
2047 fxMan.set(FX_VAR_NUM, 16);
2048 fxMan.set(FX_VAR_SIZE, 0.015f);
2049
2050 fxMan.set(FX_VAR_COLOR, 1.0,1.0,0.8);
2051
2052 fxMan.spawn(p);
2053 }
2054 }
2055 }
2056 }
2057 }
2058
pcoldet(paddle_class & paddle,effectManager & fxMan)2059 int pcoldet(paddle_class & paddle,effectManager & fxMan)
2060 {
2061 int i, hits=0;
2062 pos p;
2063 for(i=0; i < MAXBALLS; i++)
2064 {
2065 if(b[i].active)
2066 {
2067 if(b[i].glued)
2068 b[i].posx=paddle.posx+paddle.width-b[i].gluedX;
2069
2070 p.x=100;
2071 padcoldet(b[i], paddle, p);
2072 if(p.x < 50)
2073 {
2074 hits++;
2075 getSpeed();
2076
2077 if(player.powerup[PO_GLUE])
2078 {
2079 soundMan.add(SND_GLUE_BALL_HIT_PADDLE, p.x);
2080 } else {
2081 soundMan.add(SND_BALL_HIT_PADDLE, p.x);
2082 }
2083
2084
2085 if(setting.eyeCandy)
2086 {
2087 //spawn partikler
2088 fxMan.set(FX_VAR_TYPE, FX_SPARKS);
2089 fxMan.set(FX_VAR_LIFE, 2000);
2090 fxMan.set(FX_VAR_GRAVITY, 0.6f);
2091 fxMan.set(FX_VAR_NUM, 16);
2092 fxMan.set(FX_VAR_COLDET,1);
2093 fxMan.set(FX_VAR_SIZE, 0.01f);
2094 fxMan.set(FX_VAR_COLOR, 1.0,1.0,0.8);
2095 p.y = paddle.posy+paddle.height;
2096 fxMan.set(FX_VAR_SPEED, 0.5f);
2097 fxMan.spawn(p);
2098
2099 } //eyecandy
2100 } // if col
2101 } //if active
2102 } //for loop
2103 return(hits);
2104 } //pcoldet
2105
updatelast()2106 void updatelast()
2107 {
2108 int i;
2109 for(i=0; i < MAXBALLS; i++)
2110 {
2111 if(b[i].active)
2112 {
2113 b[i].lastX=b[i].posx;
2114 b[i].lastY=b[i].posy;
2115 }
2116 }
2117 }
2118
powerup(int powerup)2119 void powerup(int powerup)
2120 {
2121 int i;
2122 for(i=0; i < MAXBALLS; i++)
2123 {
2124 if(b[i].active)
2125 {
2126 switch(powerup)
2127 {
2128 case PO_BIGBALL: //big balls
2129 b[i].setSize(0.04);
2130 b[i].setspeed(difficulty.ballspeed[player.difficulty]);
2131 break;
2132 case PO_SMALLBALL: //small balls
2133 b[i].setSize(0.015);
2134 //speed bolden op
2135 b[i].setspeed( b[i].velocity + ((b[i].velocity/100.f)*difficulty.speedup[player.difficulty]) );
2136 break;
2137 case PO_NORMALBALL: // normal balls
2138 b[i].setSize(0.025);
2139 b[i].setspeed(difficulty.ballspeed[player.difficulty]);
2140 break;
2141 case PO_EXPLOSIVE: //exploderer brikker
2142 b[i].explosive=1;
2143 b[i].tail.colorRotate(TRUE, 0 );
2144 break;
2145 }
2146 }
2147 }
2148 }
2149 };
2150
bounceOffAngle(GLfloat width,GLfloat posx,GLfloat hitx)2151 float bounceOffAngle(GLfloat width, GLfloat posx, GLfloat hitx)
2152 {
2153 return ( (BALL_MAX_DEGREE/(width*2.0))*(posx+width-hitx) + BALL_MIN_DEGREE );
2154 }
2155
2156
2157 class powerupClass : public moving_object {
2158 public:
2159 int score;
2160 int type;
2161 int level, maxlevel;
2162 GLfloat gravity;
2163
powerupClass()2164 powerupClass()
2165 {
2166 posx=0.0;
2167 posy=0.0;
2168 xvel=0.0;
2169 yvel=0.0;
2170 width=0.055;
2171 height=0.055;
2172 }
2173
move()2174 void move()
2175 {
2176
2177 //grav
2178 yvel -= gravity*globalMilliTicks;
2179 //cout << yvel << endl;
2180 posx +=xvel*globalMilliTicks;
2181 posy +=yvel*globalMilliTicks;
2182 }
2183
2184
coldet(paddle_class & p,effectManager & fxMan,ballManager & bMan)2185 bool coldet(paddle_class & p, effectManager & fxMan, ballManager & bMan)
2186 {
2187 bool col=0;
2188 if(posx+width > 1.6 && xvel > 0.0)
2189 {
2190 col=1;
2191 xvel *= -1;
2192 } else if(posx-width < -1.6 && xvel < 0.0)
2193 {
2194 col=1;
2195 xvel *= -1;
2196 } else if(posy+width > 1.25 && yvel > 0.0)
2197 {
2198 col=1;
2199 yvel *= -1;
2200 } else if(posy-width < -1.24)
2201 {
2202 active=0;
2203 }
2204
2205 if(col)
2206 {
2207 soundMan.add(SND_PO_HIT_BORDER, posx);
2208 }
2209
2210 //idiotisk lavet...
2211
2212 bool ycol=0;
2213 bool xcol=0;
2214 pos fxpos, fxSize;
2215
2216 //En side
2217 if(posx+width > p.posx-p.width && posx+width < p.posx+p.width)
2218 {
2219 xcol=1;
2220 }
2221
2222 if(posx-width > p.posx-p.width && posx-width < p.posx+p.width)
2223 {
2224 xcol=1;
2225 }
2226
2227 if(posy-height < p.posy+p.height && posy-height > p.posy-p.height)
2228 {
2229 ycol=1;
2230 }
2231
2232 if(posy+height < p.posy+p.height && posy+height > p.posy-p.height)
2233 {
2234 ycol=1;
2235 }
2236
2237 if(xcol && ycol)
2238 {
2239 if(setting.eyeCandy)
2240 {
2241 fxpos.x = posx;
2242 fxpos.y = posy;
2243 fxSize.x=width;
2244 fxSize.y=height;
2245
2246 fxMan.set(FX_VAR_TYPE, FX_PARTICLEFIELD);
2247 fxMan.set(FX_VAR_COLDET,1);
2248 fxMan.set(FX_VAR_SPEED, yvel/1.5f);
2249 fxMan.set(FX_VAR_LIFE, 1500);
2250 fxMan.set(FX_VAR_GRAVITY, 0.7f);
2251 fxMan.set(FX_VAR_NUM, 20);
2252 fxMan.set(FX_VAR_SIZE, 0.03f);
2253
2254 fxMan.set(FX_VAR_RECTANGLE, fxSize);
2255
2256 fxMan.set(FX_VAR_COLOR, tex.prop.glParColorInfo[0],tex.prop.glParColorInfo[1],tex.prop.glParColorInfo[2]);
2257 fxMan.spawn(fxpos);
2258 }
2259 active=0;
2260
2261 //Score
2262 player.score += score*player.multiply;
2263 //Apply powerup:
2264 switch(type)
2265 {
2266 case PO_COIN:
2267 player.coins += 1000;
2268 soundMan.add(SND_GOOD_PO_HIT_PADDLE, posx);
2269 break;
2270 case PO_GLUE:
2271 player.coins += 150;
2272 player.powerup[PO_GLUE] = 1;
2273 soundMan.add(SND_GOOD_PO_HIT_PADDLE, posx);
2274 break;
2275 case PO_BIGBALL:
2276 player.coins += 30;
2277 bMan.powerup(PO_BIGBALL);
2278 player.powerup[PO_BIGBALL]=1;
2279 player.powerup[PO_NORMALBALL]=0;
2280 player.powerup[PO_SMALLBALL]=0;
2281 soundMan.add(SND_GOOD_PO_HIT_PADDLE, posx);
2282 break;
2283 case PO_NORMALBALL:
2284 player.coins += 50;
2285 bMan.powerup(PO_NORMALBALL);
2286 player.powerup[PO_NORMALBALL]=1;
2287 player.powerup[PO_BIGBALL]=0;
2288 player.powerup[PO_SMALLBALL]=0;
2289 soundMan.add(SND_GOOD_PO_HIT_PADDLE, posx);
2290 break;
2291 case PO_SMALLBALL:
2292 player.coins += 10;
2293 bMan.powerup(PO_SMALLBALL);
2294 player.powerup[PO_SMALLBALL]=1;
2295 player.powerup[PO_BIGBALL]=0;
2296 player.powerup[PO_NORMALBALL]=0;
2297 soundMan.add(SND_EVIL_PO_HIT_PADDLE, posx);
2298 break;
2299 case PO_MULTIBALL:
2300 player.coins += 100;
2301 bMan.multiply();
2302 soundMan.add(SND_GOOD_PO_HIT_PADDLE, posx);
2303 break;
2304 case PO_AIM:
2305 player.coins += 50;
2306 if(player.difficulty==0)
2307 {
2308 player.powerup[PO_GLUE]=1;
2309 }
2310 if(!player.powerup[PO_AIM])
2311 {
2312 player.powerup[PO_AIM]=1;
2313 player.powerup[PO_LASER]=1;
2314 } else {
2315 player.powerup[PO_GLUE]=1;
2316 }
2317 soundMan.add(SND_GOOD_PO_HIT_PADDLE, posx);
2318 break;
2319 case PO_GROWPADDLE:
2320 player.coins += 100;
2321 if(p.width < 0.4) p.grow(p.width+0.03);
2322 player.powerup[PO_GUN] = 0;
2323 soundMan.add(SND_GOOD_PO_HIT_PADDLE, posx);
2324 break;
2325 case PO_SHRINKPADDLE:
2326 player.coins += 10;
2327 if(p.width > 0.02) p.grow(p.width-0.02);
2328 player.powerup[PO_GUN]=0;
2329 soundMan.add(SND_EVIL_PO_HIT_PADDLE, posx);
2330 break;
2331 case PO_EXPLOSIVE:
2332 player.coins += 150;
2333 bMan.powerup(PO_EXPLOSIVE);
2334 player.powerup[PO_EXPLOSIVE]=1;
2335 soundMan.add(SND_GOOD_PO_HIT_PADDLE, posx);
2336 break;
2337 case PO_GUN:
2338 player.coins += 200;
2339 player.powerup[PO_GUN]=1;
2340 soundMan.add(SND_GOOD_PO_HIT_PADDLE, posx);
2341 break;
2342 case PO_THRU:
2343 player.coins += 300;
2344 player.powerup[PO_THRU]=1;
2345 soundMan.add(SND_GOOD_PO_HIT_PADDLE, posx);
2346 break;
2347 case PO_LASER:
2348 player.coins += 40;
2349 player.powerup[PO_LASER]=1;
2350 soundMan.add(SND_GOOD_PO_HIT_PADDLE, posx);
2351 break;
2352 case PO_LIFE:
2353 player.coins += 400;
2354 player.lives++;
2355 soundMan.add(SND_GOOD_PO_HIT_PADDLE, posx);
2356 break;
2357 case PO_DIE:
2358 player.coins += 1;
2359 player.explodePaddle=1;
2360 player.powerup[PO_DIE]=1;
2361 //NOTE: no sound here, SND_DIE is played when paddle dissapers
2362 break;
2363 case PO_DROP:
2364 player.coins += 1;
2365 player.powerup[PO_DROP]=1;
2366 soundMan.add(SND_EVIL_PO_HIT_PADDLE, posx);
2367 break;
2368 case PO_DETONATE:
2369 player.coins += 200;
2370 player.powerup[PO_DETONATE]=1;
2371 soundMan.add(SND_GOOD_PO_HIT_PADDLE, posx);
2372 break;
2373 case PO_EXPLOSIVE_GROW:
2374 player.coins += 100;
2375 player.powerup[PO_EXPLOSIVE_GROW]=1;
2376 soundMan.add(SND_GOOD_PO_HIT_PADDLE, posx);
2377 break;
2378 case PO_EASYBRICK:
2379 player.coins += 90;
2380 player.powerup[PO_EASYBRICK]=1;
2381 soundMan.add(SND_GOOD_PO_HIT_PADDLE, posx);
2382 break;
2383 case PO_NEXTLEVEL:
2384 player.coins += 100;
2385 player.powerup[PO_NEXTLEVEL]=1;
2386 //NOTE: no sound here, SND_NEXTLEVEL is played when changing level
2387 break;
2388 case PO_AIMHELP:
2389 player.coins += 50;
2390 player.powerup[PO_AIMHELP]=1;
2391 soundMan.add(SND_GOOD_PO_HIT_PADDLE, posx);
2392 break;
2393 }
2394 return(1);
2395 }
2396
2397 return(0);
2398 }
2399
die(effectManager & fxMan)2400 void die(effectManager & fxMan)
2401 {
2402 active=0;
2403 if(setting.eyeCandy)
2404 {
2405 struct pos p;
2406 p.x = posx;
2407 p.y = posy;
2408 fxMan.set(FX_VAR_TYPE, FX_SPARKS);
2409 fxMan.set(FX_VAR_COLDET,1);
2410 fxMan.set(FX_VAR_LIFE, 1250);
2411 fxMan.set(FX_VAR_NUM, 16);
2412
2413 fxMan.set(FX_VAR_SPEED, 0.8f);
2414 fxMan.set(FX_VAR_GRAVITY, 0.6f);
2415 fxMan.set(FX_VAR_SIZE, 0.025f);
2416 fxMan.set(FX_VAR_COLOR, tex.prop.glParColorInfo[0],tex.prop.glParColorInfo[1],tex.prop.glParColorInfo[2]);
2417 fxMan.spawn(p);
2418
2419 fxMan.set(FX_VAR_SPEED, 0.4f);
2420 fxMan.set(FX_VAR_SIZE, 0.05f);
2421 fxMan.set(FX_VAR_GRAVITY, -1.0f);
2422 fxMan.set(FX_VAR_COLOR, 1.0f, 0.7f, 0.0f);
2423 fxMan.spawn(p);
2424 fxMan.set(FX_VAR_COLOR, 1.0f, 0.8f, 0.0f);
2425 fxMan.spawn(p);
2426 fxMan.set(FX_VAR_COLOR, 1.0f, 0.9f, 0.0f);
2427 fxMan.spawn(p);
2428 fxMan.set(FX_VAR_COLOR, 1.0f, 1.0f, 0.0f);
2429 fxMan.spawn(p);
2430
2431 }
2432 }
2433
draw()2434 void draw()
2435 {
2436 tex.play();
2437
2438 glBindTexture( GL_TEXTURE_2D, tex.prop.texture);
2439 glColor4f(tex.prop.glTexColorInfo[0],tex.prop.glTexColorInfo[1],tex.prop.glTexColorInfo[2],tex.prop.glTexColorInfo[3]);
2440 glLoadIdentity();
2441 glTranslatef( posx, posy, -3.0f);
2442 glBegin( GL_QUADS );
2443 glTexCoord2f(tex.pos[0],tex.pos[1]);glVertex3f( -width, height, 0.00 ); // øverst venst
2444 glTexCoord2f(tex.pos[2],tex.pos[3]);glVertex3f( width, height, 0.00 ); // øverst højre
2445 glTexCoord2f(tex.pos[4],tex.pos[5]);glVertex3f( width,-height, 0.00 ); // nederst højre
2446 glTexCoord2f(tex.pos[6],tex.pos[7]);glVertex3f( -width,-height, 0.00 ); // nederst venstre
2447 glEnd( );
2448 }
2449 };
2450
2451 #define MAXPOWERUPS 64
2452 class powerupManager {
2453 private:
2454 int i;
2455 powerupClass p[MAXPOWERUPS];
2456 textureClass* tex;
2457 public:
2458
init(textureClass texPowerup[])2459 void init(textureClass texPowerup[])
2460 {
2461
2462
2463
2464
2465 tex = new textureClass[40];
2466 tex = texPowerup;
2467 }
powerupManager()2468 powerupManager()
2469 {
2470 clear();
2471 }
2472
clear()2473 void clear()
2474 {
2475 for(i=0; i < MAXPOWERUPS; i++)
2476 {
2477 p[i].active=0;
2478 }
2479 }
2480
die(effectManager & fxMan)2481 void die(effectManager & fxMan)
2482 {
2483 for(i=0; i < MAXPOWERUPS; i++)
2484 {
2485 if(p[i].active)
2486 {
2487 p[i].die(fxMan);
2488 }
2489 }
2490 }
2491
spawn(pos spawnpos,pos velocity,int type)2492 void spawn(pos spawnpos, pos velocity, int type)
2493 {
2494 for(i=0; i < MAXPOWERUPS; i++)
2495 {
2496 if(!p[i].active)
2497 {
2498 p[i].gravity = 0.7;
2499 p[i].type = type;
2500 p[i].posx = spawnpos.x;
2501 p[i].posy = spawnpos.y;
2502 p[i].xvel = velocity.x*-1;
2503 p[i].yvel = velocity.y*-1;
2504 p[i].active=1;
2505
2506 //Give texture that this type has.
2507 p[i].tex = tex[type];
2508
2509 //FIXME: rewrite as a switch
2510 //Set colors and score
2511 if(type==PO_GLUE)
2512 {
2513 p[i].score = 500;
2514 }
2515
2516
2517 if(type==PO_MULTIBALL)
2518 {
2519 p[i].score = 500;
2520 }
2521
2522 if(type==PO_BIGBALL)
2523 {
2524 p[i].score = 300;
2525 }
2526
2527 if(type==PO_NORMALBALL)
2528 {
2529 p[i].score = 400;
2530 }
2531
2532 if(type==PO_SMALLBALL)
2533 {
2534 p[i].score = 100;
2535 }
2536
2537 if(type==PO_AIM)
2538 {
2539 p[i].score = 1600;
2540 }
2541
2542 if(type==PO_GROWPADDLE)
2543 {
2544 p[i].score = 500;
2545 }
2546
2547 if(type==PO_SHRINKPADDLE)
2548 {
2549 p[i].score = -1000;
2550 }
2551
2552 if(type==PO_EXPLOSIVE)
2553 {
2554 p[i].score = 1400;
2555 }
2556
2557 if(type==PO_GUN)
2558 {
2559 p[i].score = 1800;
2560 }
2561
2562 if(type==PO_THRU)
2563 {
2564
2565 p[i].score = 1000;
2566 }
2567
2568 if(type==PO_LASER)
2569 {
2570 p[i].score = 500;
2571 }
2572
2573 if(type==PO_LIFE)
2574 {
2575 p[i].score = 1000;
2576 }
2577
2578 if(type==PO_DIE)
2579 {
2580 p[i].score = -1000;
2581 }
2582
2583 if(type==PO_DROP)
2584 {
2585 p[i].score = -1000;
2586 }
2587
2588 if(type==PO_DETONATE)
2589 {
2590 p[i].score = 1000;
2591 }
2592
2593 if(type==PO_EXPLOSIVE_GROW)
2594 {
2595 p[i].score = 1000;
2596 }
2597
2598 if(type==PO_EASYBRICK)
2599 {
2600 p[i].score = 1000;
2601 }
2602
2603 if(type==PO_NEXTLEVEL)
2604 {
2605 p[i].score = 1000;
2606 }
2607
2608 if(type==PO_AIMHELP)
2609 {
2610 p[i].score = 1000;
2611 }
2612
2613 break; //Whats this doing?
2614 }
2615 }
2616 }
2617
coldet(paddle_class & paddle,effectManager & fxMan,ballManager & bMan)2618 int coldet(paddle_class & paddle, effectManager & fxMan, ballManager & bMan)
2619 {
2620 int hits=0;
2621 for(i=0; i < MAXPOWERUPS; i++)
2622 {
2623 if(p[i].active)
2624 {
2625 if(p[i].coldet(paddle, fxMan, bMan))
2626 {
2627 hits++;
2628 }
2629 }
2630 }
2631 return(hits);
2632 }
2633
move()2634 void move()
2635 {
2636 for(i=0; i < MAXPOWERUPS; i++)
2637 {
2638 if(p[i].active)
2639 {
2640 p[i].move();
2641 }
2642 }
2643 }
2644
draw()2645 void draw()
2646 {
2647 for(i=0; i < MAXPOWERUPS; i++)
2648 {
2649 if(p[i].active)
2650 {
2651 p[i].draw();
2652 }
2653 }
2654 }
2655 };
2656
2657 powerupManager pMan;
2658
spawnpowerup(char powerup,pos a,pos b)2659 void spawnpowerup(char powerup, pos a, pos b)
2660 {
2661
2662 if(powerup == '1')
2663 {
2664 pMan.spawn(a,b,PO_GROWPADDLE);
2665 }
2666
2667 if(powerup == '2')
2668 {
2669 pMan.spawn(a,b,PO_SHRINKPADDLE);
2670 }
2671
2672 if(powerup == '3')
2673 {
2674 pMan.spawn(a,b,PO_DIE);
2675 }
2676
2677 if(powerup == '4')
2678 {
2679 pMan.spawn(a,b,PO_GLUE);
2680 }
2681
2682 if(powerup == 'A')
2683 {
2684 pMan.spawn(a,b,PO_EASYBRICK);
2685 }
2686
2687 if(powerup == 'B')
2688 {
2689 pMan.spawn(a,b,PO_EXPLOSIVE);
2690 }
2691
2692 if(powerup == 'C')
2693 {
2694 pMan.spawn(a,b,PO_NEXTLEVEL);
2695 }
2696
2697 if(powerup == 'D')
2698 {
2699 pMan.spawn(a,b,PO_AIMHELP);
2700 }
2701
2702 if(powerup == 'E')
2703 {
2704 pMan.spawn(a,b,PO_COIN);
2705 }
2706
2707 if(powerup == '5')
2708 {
2709 pMan.spawn(a,b,PO_MULTIBALL);
2710 }
2711
2712 if(powerup == '6')
2713 {
2714 pMan.spawn(a,b,PO_THRU);
2715 }
2716
2717 if(powerup == '7')
2718 {
2719 pMan.spawn(a,b,PO_DROP);
2720 }
2721
2722 if(powerup == '8')
2723 {
2724 pMan.spawn(a,b,PO_DETONATE);
2725 }
2726
2727 if(powerup == '9')
2728 {
2729 pMan.spawn(a,b,PO_EXPLOSIVE_GROW);
2730 }
2731
2732 if(powerup == 'F')
2733 {
2734 pMan.spawn(a,b,PO_BIGBALL);
2735 }
2736
2737 if(powerup == 'G')
2738 {
2739 pMan.spawn(a,b,PO_NORMALBALL);
2740 }
2741
2742 if(powerup == 'H')
2743 {
2744 pMan.spawn(a,b,PO_SMALLBALL);
2745 }
2746
2747 if(powerup == 'I')
2748 {
2749 pMan.spawn(a,b,PO_AIM);
2750 }
2751
2752 if(powerup == 'P')
2753 {
2754 pMan.spawn(a,b,PO_GUN);
2755 }
2756
2757 if(powerup == 'R')
2758 {
2759 pMan.spawn(a,b,PO_LASER);
2760 }
2761
2762 if(powerup == 'O')
2763 {
2764 pMan.spawn(a,b,PO_LIFE);
2765 }
2766 }
2767
2768 SDL_Surface *screen = NULL;
2769
2770 /* function to reset our viewport after a window resize */
resizeWindow(int width,int height)2771 void resizeWindow( int width, int height )
2772 {
2773 /* Height / width ration */
2774 GLfloat ratio;
2775
2776 /* Protect against a divide by zero */
2777 if ( height == 0 )
2778 height = 1;
2779
2780 ratio = ( GLfloat )width / ( GLfloat )height;
2781 var.glunits_per_xpixel = (2.485281374*ratio) / setting.resx;
2782 var.glunits_per_ypixel = 2.485281374 / setting.resy;
2783
2784
2785 /* Setup our viewport. */
2786 glViewport( 0, 0, ( GLsizei )width, ( GLsizei )height );
2787
2788 /* change to the projection matrix and set our viewing volume. */
2789 glMatrixMode( GL_PROJECTION );
2790 glLoadIdentity( );
2791
2792 /* Set our perspective */
2793 gluPerspective( 45.0f, ratio, 0.1f, 10.0f );
2794
2795 /* Make sure we're chaning the model view and not the projection */
2796 glMatrixMode( GL_MODELVIEW );
2797
2798 /* Reset The View */
2799 glLoadIdentity();
2800 }
2801
initGL()2802 void initGL() {
2803
2804 // printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
2805 // printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
2806 // printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
2807 //printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
2808
2809 /* Enable smooth shading */
2810 glShadeModel( GL_SMOOTH );
2811
2812 /* Set the background black */
2813 glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
2814
2815 /* Depth buffer setup */
2816 glClearDepth( 1.0f );
2817
2818 /* Enables Depth Testing */
2819 // glEnable( GL_DEPTH_TEST );
2820
2821 /* The Type Of Depth Test To Do */
2822 glDepthFunc( GL_LEQUAL );
2823
2824 glEnable(GL_TEXTURE_2D);
2825 glEnable(GL_BLEND);
2826 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2827
2828 }
2829
rndflt(float total,float negative)2830 float rndflt(float total, float negative)
2831 {
2832
2833 return (rand()/(float(RAND_MAX)+1)*total)-negative;
2834 }
2835
initScreen()2836 bool initScreen()
2837 {
2838 bool success=1;
2839 int SDL_videomodeSettings = SDL_OPENGL|SDL_RESIZABLE;
2840
2841 if(setting.fullscreen)
2842 SDL_videomodeSettings |= SDL_FULLSCREEN;
2843
2844 /* Free the previously allocated surface */
2845 if(screen != NULL)
2846 {
2847 SDL_FreeSurface( screen );
2848 }
2849
2850 screen = SDL_SetVideoMode(setting.resx,setting.resy,32, SDL_videomodeSettings);
2851 resizeWindow(setting.resx,setting.resy);
2852
2853 if( screen == NULL )
2854 {
2855 cout << "Error:" << SDL_GetError() << endl;
2856 success=0;
2857 var.quit=1;
2858 }
2859 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
2860
2861 var.halfresx = setting.resx /2;
2862 var.halfresy = setting.resy / 2;
2863 return(success);
2864 }
2865
resetPlayerPowerups()2866 void resetPlayerPowerups()
2867 {
2868 for(int i=0; i < MAXPOTEXTURES; i++)
2869 {
2870 player.powerup[i] = 0;
2871 }
2872 }
2873
initNewGame()2874 void initNewGame()
2875 {
2876 player.level=0;
2877 player.score=0;
2878 gVar.deadTime=0;
2879
2880 gVar.newLevel=1;
2881 gVar.newLife=1;
2882
2883 player.multiply = 1;
2884
2885 switch(player.difficulty)
2886 {
2887 case EASY:
2888 player.coins = 600;
2889 player.lives = 5;
2890 break;
2891 case NORMAL:
2892 player.coins = 0;
2893 player.lives = 3;
2894 break;
2895 case HARD:
2896 player.coins = 0;
2897 player.lives = 3;
2898 break;
2899 }
2900
2901 resetPlayerPowerups();
2902 }
2903
pauseGame()2904 void pauseGame()
2905 {
2906 var.paused=1;
2907 SDL_WM_GrabInput(SDL_GRAB_OFF);
2908 SDL_ShowCursor(SDL_ENABLE);
2909 }
2910
resumeGame()2911 void resumeGame()
2912 {
2913 SDL_WM_GrabInput(SDL_GRAB_ON);
2914 SDL_ShowCursor(SDL_DISABLE);
2915 var.paused=0;
2916 var.menu=0;
2917 }
2918
mkDLscene(GLuint * dl,textureClass tex)2919 void mkDLscene(GLuint *dl,textureClass tex)
2920 {
2921 //Scenen
2922 *dl = glGenLists(1);
2923 glNewList(*dl,GL_COMPILE);
2924 glLoadIdentity();
2925 glTranslatef( 0.0f, 0.0f, -3.0 );
2926 glColor4f(1.0, 1.0, 1.0, 1.0);
2927 glEnable(GL_TEXTURE_2D);
2928 glBindTexture(GL_TEXTURE_2D, tex.prop.texture);
2929 glBegin( GL_POINTS );
2930 glVertex3f( -1.60, 1.25, 0.0 );
2931 glEnd( );
2932 glBegin( GL_QUADS );
2933 //venstre kant
2934 glTexCoord2f(0.0f,0.0f);glVertex3f( -1.66, 1.25, 0.0 );
2935 glTexCoord2f(1.0f,0.0f);glVertex3f( -1.60, 1.25, 0.0 );
2936 glTexCoord2f(1.0f,-1.0f);glVertex3f( -1.60,-1.25, 0.0 );
2937 glTexCoord2f(0.0f,-1.0f);glVertex3f( -1.66,-1.25, 0.0 );
2938 //højre kant
2939 glTexCoord2f(0.0f,0.0f);glVertex3f( 1.66, 1.25, 0.0 );
2940 glTexCoord2f(1.0f,0.0f);glVertex3f( 1.60, 1.25, 0.0 );
2941 glTexCoord2f(1.0f,-1.0f);glVertex3f( 1.60,-1.25, 0.0 );
2942 glTexCoord2f(0.0f,-1.0f);glVertex3f( 1.66,-1.25, 0.0 );
2943 glEnd( );
2944 glEndList();
2945 }
2946
coldet(brick & br,ball & ba,pos & p,effectManager & fxMan)2947 void coldet(brick & br, ball &ba, pos & p, effectManager & fxMan)
2948 {
2949
2950 GLfloat x,y;
2951 int i=0;
2952
2953 int points=0;
2954 GLfloat px=0,py=0;
2955 bool col=0;
2956 bool dirfound=0;
2957 GLfloat dist[4] = { 4.0, 4.0, 4.0, 4.0 }; //measure the distance from last pos to each possible impact, the shortest should be the right one
2958
2959 //vi tager y først da der er mindst brikker
2960 if(ba.posy < br.posy+br.height+ba.height && ba.posy > br.posy-br.height-ba.height)
2961 {
2962 //cout << " y " << endl;
2963 if(ba.posx > br.posx-br.width-ba.width && ba.posx < br.posx+br.width+ba.width)
2964 {
2965 //cout << " x " << endl;
2966 for(i=0; i < 32; i++) // 32 punkter præcis
2967 {
2968
2969 x = ba.bsin[i];
2970 y = ba.bcos[i];
2971
2972 if(ba.posx+x >= br.posx-br.width && ba.posx+x <= br.posx+br.width)
2973 {
2974 if(ba.posy+y <= br.posy+br.height && ba.posy+y >= br.posy-br.height)
2975 {
2976 //Vi har helt sikkert ramt
2977 points++;
2978 px += x;
2979 py += y;
2980 col=1;
2981 } //y
2982 } //x
2983 } //32 punkters for loop
2984
2985 if(col)
2986 {
2987
2988 px /= points;
2989 py /= points;
2990
2991 if(ba.lastX-px <= br.posx-br.width && !br.n(0)) //
2992 {
2993 dirfound=1;
2994 // cout << "På venstre"<<endl;
2995 dist[0] = sqrt( pow( br.posx-br.width - (ba.lastX+px), 2) + pow( (ba.posy+py) - (ba.lastY+py), 2) );
2996 }
2997
2998 if(ba.lastX-px >= br.posx+br.width && !br.n(1))
2999 {
3000 dirfound=1;
3001 // cout << "På højre"<<endl;
3002 dist[1] = sqrt( pow( br.posx+br.width - (ba.lastX+px), 2) + pow( (ba.posy+py) - (ba.lastY+py), 2) );
3003 }
3004
3005 if(ba.lastY-py <= br.posy-br.height && !br.n(3))
3006 {
3007 dirfound=1;
3008 // cout << "På bunden" << endl;
3009 dist[2] = sqrt( pow( (ba.posx+px) - (ba.lastX+px), 2) + pow( br.posy-br.height - (ba.lastY+py), 2) );
3010
3011 }
3012
3013 if(ba.lastY-py >= br.posy+br.height && !br.n(2)) // &&
3014 {
3015 dirfound=1;
3016 // cout << "På toppen"<< endl;
3017 dist[3] = sqrt( pow( (ba.posx+px) - (ba.lastX+px), 2) + pow( br.posy+br.height - (ba.lastY+py), 2) );
3018 }
3019
3020
3021 //Was hit on left
3022 if(dist[0] < dist[1] && dist[0] < dist[2] && dist[0] < dist[3])
3023 {
3024 ba.posx = br.posx - br.width - ba.width;
3025 if(ba.xvel > 0.0 && !player.powerup[PO_THRU])
3026 ba.xvel *=-1;
3027 }
3028
3029 //Was hit on right
3030 if(dist[1] < dist[0] && dist[1] < dist[2] && dist[1] < dist[3])
3031 {
3032 ba.posx = br.posx + br.width + ba.width;
3033 if(ba.xvel < 0 && !player.powerup[PO_THRU])
3034 ba.xvel *=-1;
3035 }
3036
3037 //Was hit on bottom
3038 if(dist[2] < dist[0] && dist[2] < dist[1] && dist[2] < dist[3])
3039 {
3040 ba.posy = br.posy - br.height - ba.height;
3041 if(ba.yvel > 0 && !player.powerup[PO_THRU])
3042 ba.yvel *=-1;
3043 }
3044
3045 //Was hit on top
3046 if(dist[3] < dist[0] && dist[3] < dist[1] && dist[3] < dist[2])
3047 {
3048 ba.posy = br.posy + br.height + ba.height;
3049 if(ba.yvel < 0 && !player.powerup[PO_THRU])
3050 ba.yvel *=-1;
3051 }
3052
3053 //Setup vars for spawning powerups
3054 pos a,b;
3055 a.x = br.posx;
3056 a.y = br.posy;
3057
3058 //Hastigheden en powerup blier sendt afsted med
3059
3060 if(player.difficulty == EASY)
3061 {
3062 b.x = ba.xvel/2.0;
3063 b.y = ba.yvel/2.0;
3064 } else if(player.difficulty == NORMAL) {
3065 b.x = ba.xvel/1.5;
3066 b.y = ba.yvel/1.5;
3067 } else //if(player.difficulty == HARD)
3068 {
3069 b.x = ba.xvel/1.25;
3070 b.y = ba.yvel/1.25;
3071 }
3072
3073 if(dirfound)
3074 {
3075 if(ba.explosive)
3076 {
3077 br.type='B';
3078 }
3079
3080 //Update p, used by caller to find out if we hit anything..
3081 p.x = ba.posx+px;
3082 p.y = ba.posy+py;
3083
3084
3085 ba.hit(br.tex.prop.glParColorInfo);
3086
3087 if(!player.powerup[PO_THRU] || player.difficulty == HARD)
3088 {
3089 ba.setspeed(ba.velocity + difficulty.hitbrickinc[player.difficulty]);
3090 }
3091 } else {
3092 cout << "Collision detection error: Don't know where the ball hit." << endl;
3093 }
3094 br.hit(fxMan, a,b,1);
3095 } //collision
3096 } //x boxcol
3097 } //y boxcol
3098
3099 }
3100
3101
padcoldet(ball & b,paddle_class & p,pos & po)3102 void padcoldet(ball & b, paddle_class & p, pos & po)
3103 {
3104 int i,points=0;
3105 GLfloat x,y,px=0,py=0;
3106 bool col=0;
3107 //Er bolden tæt nok på?
3108
3109 if(b.posy < (p.posy+p.height)+b.height && b.posy > p.posy-p.height)
3110 {
3111
3112 if(b.posx > p.posx-(p.width*2.0)-b.width && b.posx < p.posx+(p.width*2.0)+b.width)
3113 {
3114 for(i=0; i < 32; i++)
3115 {
3116 x = b.bsin[i];
3117 y = b.bcos[i];
3118
3119 //Find de punkter der er inden i padden
3120 if(b.posx+x > p.posx-p.width && b.posx+x < p.posx+p.width)
3121 {
3122 if(b.posy+y < p.posy+p.height && b.posy+y > p.posy-p.height)
3123 {
3124 col=1;
3125
3126 px +=x;
3127 py +=y;
3128 points++;
3129 }
3130 }
3131 } //For loop
3132
3133 if(col)
3134 {
3135 col=0;
3136 gVar.deadTime=0;
3137 px /= (float)points;
3138 py /= (float)points;
3139
3140 px = b.posx+px;
3141
3142 //Ved at reagere herinde fungerer yvel som en switch, så det kun sker een gang ;)
3143 if(b.yvel < 0)
3144 {
3145 b.posy=p.posy+p.height+b.height; //løft op over pad
3146
3147 //Only decrease speed if the player does not have the go-thru powerup
3148 if(!player.powerup[PO_THRU])
3149 {
3150 b.setspeed(b.velocity + difficulty.hitpaddleinc[player.difficulty]);
3151 }
3152
3153 b.setangle(bounceOffAngle(p.width, p.posx, b.posx));
3154 if(player.powerup[PO_GLUE])
3155 {
3156 b.gluedX = p.posx+p.width - px;
3157 b.glued=1;
3158 }
3159
3160 po.x = px;
3161 po.y = py;
3162 }
3163
3164 }
3165
3166 }
3167 }
3168 }
3169
3170 #include "highscores.cpp"
3171
3172 struct shopItemStruct {
3173 int price;
3174 int type;
3175 };
3176
3177 class hudClass {
3178 private:
3179 textureClass texBall;
3180
3181 //For the hud text
3182 int ticksSinceLastClockCheck;
3183 time_t nixTime; //Seconds since epoch
3184 tm timeStruct; //Time struct
3185 char clockString[13]; //Clock: 00:00\0
3186
3187
3188 //For the powerup "shop"
3189 textureClass *texPowerup; //Pointer to array of powerup textures
3190 int shopItemSelected;
3191 #define NUMITEMSFORSALE 13
3192 struct shopItemStruct item[NUMITEMSFORSALE];
3193 bool shopItemBlocked[NUMITEMSFORSALE]; //One can only buy each powerup one time each life/level
3194
3195 public:
hudClass(textureClass texB,textureClass texPo[])3196 hudClass(textureClass texB, textureClass texPo[])
3197 {
3198 texPowerup = texPo;
3199 texBall=texB;
3200 ticksSinceLastClockCheck=1001;
3201
3202 item[0].type = PO_LASER;
3203 item[0].price = 600;
3204 item[1].type = PO_NORMALBALL;
3205 item[1].price = 750;
3206 item[2].type = PO_BIGBALL;
3207 item[2].price = 800;
3208 item[3].type = PO_AIMHELP;
3209 item[3].price = 900;
3210 item[4].type = PO_GROWPADDLE;
3211 item[4].price = 960;
3212 item[5].type = PO_MULTIBALL;
3213 item[5].price = 980;
3214 item[6].type = PO_EXPLOSIVE_GROW;
3215 item[6].price = 990;
3216 item[7].type = PO_EXPLOSIVE;
3217 item[7].price = 1000;
3218 item[8].type = PO_GLUE;
3219 item[8].price = 1000;
3220 item[9].type = PO_EASYBRICK;
3221 item[9].price = 2000;
3222 item[10].type = PO_GUN;
3223 item[10].price = 3000;
3224 item[11].type = PO_THRU;
3225 item[11].price = 4000;
3226 item[12].type = PO_LIFE;
3227 item[12].price = 6000;
3228
3229 shopItemSelected=0;
3230 }
3231
draw()3232 void draw()
3233 {
3234 int i;
3235 //Draw lives left.
3236 glLoadIdentity();
3237 glTranslatef(0,0,-3.0);
3238 glColor4f( texBall.prop.glTexColorInfo[0],texBall.prop.glTexColorInfo[1],texBall.prop.glTexColorInfo[2],texBall.prop.glTexColorInfo[3]);
3239
3240 glBindTexture(GL_TEXTURE_2D, texBall.prop.texture);
3241 texBall.play();
3242 glBegin( GL_QUADS );
3243 for(i=0; i < player.lives-1; i++)
3244 {
3245 glTexCoord2f(texBall.pos[0],texBall.pos[1]); glVertex3f(1.55-(0.05*i), 1.2, 0.0);
3246 glTexCoord2f(texBall.pos[2],texBall.pos[3]); glVertex3f(1.5 -(0.05*i), 1.2, 0.0);
3247 glTexCoord2f(texBall.pos[4],texBall.pos[5]); glVertex3f(1.5 -(0.05*i),1.15, 0.0);
3248 glTexCoord2f(texBall.pos[6],texBall.pos[7]); glVertex3f(1.55 -(0.05*i), 1.15, 0.0);
3249 }
3250 glEnd( );
3251
3252 if(setting.showClock)
3253 {
3254 ticksSinceLastClockCheck += globalTicksSinceLastDraw;
3255 if(ticksSinceLastClockCheck > 1000)
3256 {
3257 ticksSinceLastClockCheck=0;
3258 time(&nixTime);
3259 timeStruct = *(localtime(&nixTime));
3260 sprintf(clockString, "Clock: %02i:%02i", timeStruct.tm_hour, timeStruct.tm_min); //Array is exactly 13 chars wide
3261 }
3262 glColor4f(1.0,1.0,1.0,1.0);
3263 glText->write(clockString, FONT_INTRODESCRIPTION, 0, 1.0, -1.58, -1.25 + glText->getHeight(FONT_INTRODESCRIPTION));
3264
3265 }
3266
3267 //Draw the "shop"
3268 //First, find out how many items the player can afford, so we can center them
3269 int canAfford=0;
3270 for(i=0; i < NUMITEMSFORSALE; i++)
3271 {
3272 if(item[i].price <= player.coins)
3273 {
3274 canAfford++;
3275 }
3276 }
3277
3278 if(shopItemSelected > canAfford || shopItemSelected < 0)
3279 {
3280 shopItemSelected=canAfford-1;
3281 }
3282
3283 GLfloat shopListStartX = -((0.11*canAfford)/2.0);
3284 if(gVar.shopNextItem)
3285 {
3286 gVar.shopNextItem=0;
3287 shopItemSelected++;
3288
3289 if(shopItemSelected > canAfford-1)
3290 {
3291 shopItemSelected=0;
3292 }
3293 } else if(gVar.shopPrevItem)
3294 {
3295 gVar.shopPrevItem=0;
3296 shopItemSelected--;
3297
3298 if(shopItemSelected < 0)
3299 {
3300 shopItemSelected=canAfford-1;
3301 if(shopItemSelected < 0)
3302 {
3303 shopItemSelected=0;
3304 }
3305 }
3306 } else if(gVar.shopBuyItem)
3307 {
3308 gVar.shopBuyItem=0;
3309 if(item[shopItemSelected].price <= player.coins && !shopItemBlocked[shopItemSelected])
3310 {
3311 struct pos a,b;
3312 a.x = shopListStartX + (0.11*shopItemSelected);
3313 a.y = 1.15;
3314 b.x = 0.0;
3315 b.y = 0.0;
3316 pMan.spawn(a,b,item[shopItemSelected].type);
3317 player.coins -= item[shopItemSelected].price;
3318 shopItemBlocked[shopItemSelected]=1;
3319 gVar.shopNextItem=1;
3320 soundMan.add(SND_BUY_POWERUP, 0.0);
3321 }
3322 }
3323
3324 glTranslatef( shopListStartX, 1.15, 0.0f);
3325 for(i=0; i < canAfford; i++)
3326 {
3327 if(i==shopItemSelected)
3328 {
3329 if(shopItemBlocked[i])
3330 {
3331 glColor4f(1.0, 0.0, 0.0, 1.0);
3332 } else {
3333 glColor4f(1.0, 1.0, 1.0, 1.0);
3334 }
3335 } else {
3336 if(shopItemBlocked[i])
3337 {
3338 glColor4f(1.0, 0.0, 0.0, 0.4);
3339 } else {
3340 glColor4f(1.0, 1.0, 1.0, 0.4);
3341 }
3342 }
3343 texPowerup[item[i].type].play();
3344 glBindTexture( GL_TEXTURE_2D, texPowerup[item[i].type].prop.texture);
3345 glBegin( GL_QUADS );
3346 glTexCoord2f(texPowerup[item[i].type].pos[0],texPowerup[item[i].type].pos[1]);glVertex3f( -0.055, 0.055, 0.00 );
3347 glTexCoord2f(texPowerup[item[i].type].pos[2],texPowerup[item[i].type].pos[3]);glVertex3f( 0.055, 0.055, 0.00 );
3348 glTexCoord2f(texPowerup[item[i].type].pos[4],texPowerup[item[i].type].pos[5]);glVertex3f( 0.055,-0.055, 0.00 );
3349 glTexCoord2f(texPowerup[item[i].type].pos[6],texPowerup[item[i].type].pos[7]);glVertex3f( -0.055,-0.055, 0.00 );
3350 glEnd( );
3351 glTranslatef( 0.11, 0.0, 0.0f);
3352 }
3353
3354 }
3355
clearShop()3356 void clearShop()
3357 {
3358 for(int i=0; i < NUMITEMSFORSALE; i++)
3359 {
3360 shopItemBlocked[i]=0;
3361 }
3362 }
3363 };
3364
writeSettings()3365 void writeSettings()
3366 {
3367 ofstream conf;
3368 conf.open(privFile.settingsFile.data(),ios::out | ios::trunc); //homeDirFiles.settingsFile.data()
3369
3370 if(conf.is_open())
3371 {
3372 conf << "eyecandy="<<setting.eyeCandy<<endl;
3373 conf << "resx="<<setting.resx<<endl;
3374 conf << "resy="<<setting.resy<<endl;
3375 conf << "showbg="<<setting.showBg<<endl;
3376 conf << "fullscreen="<<setting.fullscreen<<endl;
3377 conf << "particlecollide="<<setting.particleCollide<<endl;
3378 conf << "sound="<<setting.sound<<endl;
3379 conf << "stereo="<<setting.stereo<<endl;
3380 conf << "controlmaxspeed="<<setting.controlMaxSpeed<<endl;
3381 conf << "controlaccel="<<setting.controlAccel<<endl;
3382 conf << "controlstartspeed="<<setting.controlStartSpeed<<endl;
3383 conf << "rightkey="<<setting.keyRight<<endl;
3384 conf << "leftkey="<<setting.keyLeft<<endl;
3385 conf << "nextkey="<<setting.keyNextPo<<endl;
3386 conf << "buykey="<<setting.keyBuyPo<<endl;
3387 conf << "prevkey="<<setting.keyPrevPo<<endl;
3388 conf << "shootkey="<<setting.keyShoot<<endl;
3389 conf << "joyenabled="<<setting.joyEnabled<<endl;
3390 conf << "joyisdigital="<<setting.joyIsDigital<<endl;
3391 conf << "joycalhighjitter="<<setting.JoyCalHighJitter<<endl;
3392 conf << "joycallowjitter="<<setting.JoyCalLowJitter<<endl;
3393 conf << "joycalmax="<<setting.JoyCalMax<<endl;
3394 conf << "joycalmin="<<setting.JoyCalMin<<endl;
3395 conf << "sndtheme="<<setting.sndTheme<<endl;
3396 conf << "gfxtheme="<<setting.gfxTheme<<endl;
3397 conf << "lvltheme="<<setting.lvlTheme<<endl;
3398 conf << "startingdifficulty="<<player.difficulty<<endl;
3399 conf << "showclock="<<setting.showClock<<endl;
3400 conf << "fps="<<setting.fps<<endl;
3401 conf.close();
3402 } else {
3403 cout << "Could not open ' ' for writing." << endl;
3404 }
3405 }
3406
3407 class speedometerClass {
3408 public:
3409
draw()3410 void draw()
3411 {
3412 //GLfloat y = -1.24 + difficulty.maxballspeed[player.difficulty]/2.44*var.averageBallSpeed;
3413
3414 GLfloat y = 2.48/ (difficulty.maxballspeed[player.difficulty] - difficulty.ballspeed[player.difficulty]) * (var.averageBallSpeed - difficulty.ballspeed[player.difficulty] );
3415
3416
3417 glDisable(GL_TEXTURE_2D);
3418
3419 glLoadIdentity();
3420 glTranslatef(1.61, -1.24,-3.0);
3421 glBegin( GL_QUADS );
3422 glColor4f(0,1,0,1);
3423 glVertex3f( 0, y, 0);
3424 glVertex3f( 0.03, y, 0);
3425 glColor4f(1,1,1,1);
3426 glVertex3f( 0.03,0,0 );
3427 glVertex3f( 0, 0 ,0);
3428 glEnd( );
3429 glEnable(GL_TEXTURE_2D);
3430 }
3431 };
3432
3433 struct savedGame {
3434 char name[32];
3435 struct player_struct player;
3436 };
3437
3438 //Savegame files now consist of a int long header with a version number.
saveGame(int slot,string name)3439 void saveGame(int slot, string name) {
3440 fstream file;
3441 struct savedGame game;
3442 strcpy(game.name, name.data() );
3443 game.player = SOLPlayer; //StartOfLevelPlayer, player as it was in the start of the level
3444 file.open(privFile.saveGameFile.data(), ios::out | ios::in | ios::binary);
3445 if(!file.is_open())
3446 {
3447 cout << "Could not open '"<<privFile.saveGameFile<<"' for Read+Write." << endl;
3448 }
3449
3450 //move to the slot, mind the header
3451 file.seekp( (sizeof(int))+((sizeof(savedGame)*slot)) );
3452
3453 file.write((char *)(&game), sizeof(savedGame));
3454 file.close();
3455 }
3456
clearSaveGames()3457 void clearSaveGames()
3458 {
3459 fstream file;
3460 file.open(privFile.saveGameFile.data(), ios::out | ios::in | ios::binary);
3461 if(!file.is_open())
3462 {
3463 cout << "Could not open '"<<privFile.saveGameFile<<"' for Read+Write." << endl;
3464 }
3465 //Write the header
3466 const int sgHead = SAVEGAMEVERSION; //Savegame file version
3467 file.write( (char *)(&sgHead), sizeof(int));
3468 file.close();
3469
3470
3471 saveGame(0, "Empty Slot");
3472 saveGame(1, "Empty Slot");
3473 saveGame(2, "Empty Slot");
3474 saveGame(3, "Empty Slot");
3475 saveGame(4, "Empty Slot");
3476 saveGame(5, "Empty Slot");
3477 }
3478
loadGame(int slot)3479 void loadGame(int slot)
3480 {
3481 fstream file;
3482 struct savedGame game;
3483 file.open(privFile.saveGameFile.data(), ios::in | ios::binary);
3484 if(!file.is_open())
3485 cout << "Could not open '" << privFile.saveGameFile << "' for Reading." << endl;
3486
3487 //first, move to the slot
3488 file.seekg( sizeof(int)+(sizeof(savedGame)*slot) );
3489 file.read((char *)(&game), sizeof(savedGame));
3490 file.close();
3491
3492 if(game.player.level != 0) //Only change level if level is not 0 (level one cannot be saved, and is used for the empty slots)
3493 {
3494 game.player.level--; //subtract one, because when the savegame is loaded, nextlevel is used to apply changes. nextlevel will add one to the level.
3495 player = game.player;
3496 gVar.nextlevel=1;
3497 var.paused=1;
3498 }
3499 }
3500
listSaveGames(string slotName[])3501 int listSaveGames(string slotName[])
3502 {
3503 fstream file;
3504 struct savedGame slot[6];
3505 int i=0;
3506
3507 file.open(privFile.saveGameFile.data() , ios::in | ios::binary);
3508 if(!file.is_open())
3509 {
3510 cout << "Creating savegame slots in '"<<privFile.saveGameFile<<"'."<<endl;
3511 file.open(privFile.saveGameFile.data(), ios::out | ios::binary);
3512 if(!file.is_open())
3513 {
3514 cout << "Do not have permissions to write '" << privFile.saveGameFile << "'" <<endl;
3515 return(0);
3516 }
3517 file.close();
3518
3519 clearSaveGames();
3520 file.open(privFile.saveGameFile.data() , ios::in | ios::binary);
3521 if(!file.is_open())
3522 {
3523 cout << "Could not write template."<<endl;
3524 return(0);
3525 }
3526 }
3527
3528 //First we check if this is the right version
3529 int sgHead=0x00; //Invalid version
3530
3531 file.read((char *)(&sgHead), sizeof(int));
3532 if(sgHead!=SAVEGAMEVERSION)
3533 {
3534 cout << "Savegame format error, is v" << sgHead << " should be v'" << SAVEGAMEVERSION << "'." << endl;
3535 cout << "Overwriting old savegames..." << endl;
3536 file.close();
3537 clearSaveGames();
3538
3539 file.open(privFile.saveGameFile.data() , ios::in | ios::binary);
3540 file.seekp(sizeof(int));
3541 }
3542
3543 while(1)
3544 {
3545 if(i == 6)
3546 {
3547 break;
3548 }
3549
3550 file.read((char *)(&slot[i]), sizeof(savedGame));
3551 if( file.eof())
3552 {
3553 break;
3554 }
3555
3556 slotName[i] = slot[i].name;
3557 i++;
3558 }
3559 file.close();
3560
3561
3562 return(i);
3563 }
3564
detonateExplosives(brick bricks[],effectManager & fxMan)3565 void detonateExplosives(brick bricks[], effectManager & fxMan)
3566 {
3567 struct pos p,v;
3568 for(int i=0; i < 598; i++)
3569 {
3570 if(bricks[i].active && bricks[i].type=='B')
3571 {
3572 p.x = bricks[i].posx;
3573 p.y = bricks[i].posy;
3574 v.x = 0.0;
3575 v.y = 0.0;
3576 bricks[i].hit(fxMan, p, v,0);
3577 }
3578 }
3579 }
3580
dropBoard(brick bricks[])3581 void dropBoard(brick bricks[])
3582 {
3583 for(int i=0; i < 598; i++)
3584 {
3585 if(bricks[i].active)
3586 {
3587 bricks[i].posy -= bricks[i].height*2;
3588 if(bricks[i].posy < -1.00-bricks[i].height)
3589 {
3590 //Destroy brick, and subtract score
3591 bricks[i].active=0;
3592 updated_nbrick[bricks[i].row][bricks[i].bricknum]=-1;
3593 var.bricksHit=1;
3594 player.score -= bricks[i].score;
3595 gVar.deadTime=0;
3596 }
3597 }
3598 }
3599 }
3600
explosiveGrow(brick bricks[])3601 void explosiveGrow(brick bricks[])
3602 {
3603 for(int i=0; i < 598; i++)
3604 {
3605 if(bricks[i].active)
3606 {
3607 bricks[i].growExplosive(bricks);
3608 }
3609 }
3610
3611 for(int i=0; i < 598; i++)
3612 {
3613 bricks[i].justBecomeExplosive=0;
3614 }
3615 }
3616
easyBrick(brick bricks[])3617 void easyBrick(brick bricks[])
3618 {
3619 for(int i=0; i < 598; i++)
3620 {
3621 if(bricks[i].active)
3622 {
3623 bricks[i].breakable();
3624 }
3625 }
3626 }
3627
checkDir(string & dir)3628 bool checkDir(string & dir)
3629 {
3630 struct stat st;
3631
3632 if( stat(dir.data(), &st) != 0)
3633 {
3634 cout << "Directory '" << dir << "' does not exist, ";
3635 #ifdef WIN32
3636 if(CreateDirectory(dir.data(), NULL) != 0)
3637 #else
3638 if(mkdir(dir.data(), S_IRWXU | S_IRWXG) !=0)
3639 #endif
3640 {
3641 cout << "could not create it." << endl;
3642 return(0);
3643 }
3644 cout << "created it." << endl;
3645 }
3646 return(1);
3647 }
3648
3649 #include "input.cpp"
3650 #include "title.cpp"
screenShot()3651 bool screenShot()
3652 {
3653 FILE *fscreen;
3654
3655 char cName[256];
3656 int i = 0;
3657 bool found=0;
3658 while(!found)
3659 {
3660 sprintf(cName, "%s/sdl-ball_%i.tga",privFile.screenshotDir.data(),i);
3661 fscreen = fopen(cName,"rb");
3662 if(fscreen==NULL)
3663 {
3664 found=1;
3665 }
3666 else
3667 {
3668 fclose(fscreen);
3669 }
3670 i++;
3671 }
3672 int nS = setting.resx * setting.resy * 3;
3673 GLubyte *px = new GLubyte[nS];
3674 if(px == NULL)
3675 {
3676 cout << "Alloc err, screenshot failed." <<endl;
3677 return 0;
3678 }
3679 fscreen = fopen(cName,"wb");
3680
3681 glPixelStorei(GL_PACK_ALIGNMENT,1);
3682 glReadPixels(0, 0, setting.resx, setting.resy, GL_BGR, GL_UNSIGNED_BYTE, px);
3683
3684 unsigned char TGAheader[12]={0,0,2,0,0,0,0,0,0,0,0,0};
3685 unsigned char header[6] = { (unsigned char)(setting.resx%256), (unsigned char)(setting.resx/256),(unsigned char)(setting.resy%256),(unsigned char)(setting.resy/256),24,0};
3686 fwrite(TGAheader, sizeof(unsigned char), 12, fscreen);
3687 fwrite(header, sizeof(unsigned char), 6, fscreen);
3688
3689 fwrite(px, sizeof(GLubyte), nS, fscreen);
3690 fclose(fscreen);
3691 delete [] px;
3692 cout << "Wrote screenshot to '" << cName << "'" <<endl;
3693 return 1;
3694
3695
3696 }
3697
main(int argc,char * argv[])3698 int main (int argc, char *argv[]) {
3699
3700 var.quit=0;
3701 var.clearScreen=1;
3702 var.titleScreenShow=1;
3703 setting.gfxTheme="default";
3704 setting.sndTheme="default";
3705 setting.lvlTheme="default";
3706 setting.eyeCandy = 1;
3707 setting.showBg = 1;
3708 setting.particleCollide=1;
3709 setting.fullscreen = 1;
3710 setting.sound = 1;
3711 setting.stereo=1;
3712 //Defaults for keyboard/joystick control
3713 setting.keyLeft = (SDLKey)276;
3714 setting.keyRight= (SDLKey)275;
3715 setting.keyShoot= (SDLKey)273;
3716 setting.keyNextPo=(SDLKey)SDLK_v;
3717 setting.keyBuyPo =(SDLKey)SDLK_b;
3718 setting.keyPrevPo=(SDLKey)SDLK_n;
3719 setting.controlAccel = 7;
3720 setting.controlStartSpeed = 1.0;
3721 setting.controlMaxSpeed = 5;
3722 setting.joyEnabled = 1;
3723 setting.joyIsDigital = 1;
3724 setting.showClock = 0;
3725 //Default calibaration.
3726 setting.JoyCalMin=-32767;
3727 setting.JoyCalMax=32767;
3728 setting.JoyCalLowJitter=-20;
3729 setting.JoyCalHighJitter=20;
3730 //Default starting difficulty
3731 player.difficulty = NORMAL;
3732
3733 setting.fps=120;
3734 int maxFrameAge= (1000/setting.fps); //When frame has been displayed this long
3735
3736
3737 GLfloat mousex,mousey;
3738
3739 static_difficulty.ballspeed[EASY] = 0.7f;
3740 static_difficulty.ballspeed[NORMAL] = 1.3f;
3741 static_difficulty.ballspeed[HARD] = 1.6f;
3742
3743 static_difficulty.maxballspeed[EASY] = 1.5f;
3744 static_difficulty.maxballspeed[NORMAL] = 2.2f;
3745 static_difficulty.maxballspeed[HARD] = 3.0f;
3746
3747 static_difficulty.hitbrickinc[EASY] = 0.0025;
3748 static_difficulty.hitbrickinc[NORMAL] = 0.003;
3749 static_difficulty.hitbrickinc[HARD] = 0.004;
3750
3751 static_difficulty.hitpaddleinc[EASY] = -0.001;
3752 static_difficulty.hitpaddleinc[NORMAL] = -0.0005;
3753 static_difficulty.hitpaddleinc[HARD] = -0.0007;
3754
3755 //Percentage
3756 static_difficulty.speedup[EASY] = 10.0f;
3757 static_difficulty.speedup[NORMAL] = 20.0f;
3758 static_difficulty.speedup[HARD] = 30.0f;
3759
3760 difficulty = static_difficulty;
3761
3762 cout << "SDL-Ball v " VERSION << endl;
3763
3764 // default to "" (If this have a 0 len after trying to getenv, it defaults to ./)
3765 privFile.programRoot = "";
3766 #ifndef WIN32
3767 if(getenv("XDG_CONFIG_HOME") != NULL)
3768 {
3769 privFile.programRoot = getenv("XDG_CONFIG_HOME");
3770 } else if(getenv("HOME") != NULL) {
3771 privFile.programRoot = getenv("HOME");
3772 privFile.programRoot.append("/.config");
3773 }
3774 #endif
3775
3776 //Default places if it can't place files another place.
3777 privFile.saveGameFile = "./savegames.sav";
3778 privFile.settingsFile ="./settings.cfg";
3779 privFile.highScoreFile = "./highscores.txt";
3780 privFile.screenshotDir = "./";
3781
3782 if(privFile.programRoot.length()==0)
3783 {
3784 cout << "Could not locate home directory defaulting to ./" << endl;
3785 } else {
3786
3787 if( checkDir(privFile.programRoot))
3788 {
3789 privFile.programRoot.append("/sdl-ball");
3790 if( checkDir(privFile.programRoot) )
3791 {
3792 privFile.saveGameFile = privFile.programRoot;
3793 privFile.settingsFile = privFile.programRoot;
3794 privFile.highScoreFile = privFile.programRoot;
3795 privFile.saveGameFile.append("/savegame.sav");
3796 privFile.settingsFile.append("/settings.cfg");
3797 privFile.highScoreFile.append("/highscores.txt");
3798
3799 privFile.screenshotDir = privFile.programRoot;
3800 privFile.screenshotDir.append("/screenshots");
3801 if( !checkDir(privFile.screenshotDir) )
3802 {
3803 cout << "Screenshots are saved in current directory." << endl;
3804 privFile.screenshotDir = "./";
3805 }
3806
3807 }
3808 }
3809 }
3810 srand((unsigned)time(0));
3811
3812 //Load settings
3813 ifstream conf;
3814 string line,set,val;
3815 conf.open( privFile.settingsFile.data() );
3816 if(conf.is_open())
3817 {
3818 while(!conf.eof())
3819 {
3820 getline(conf, line);
3821 if(line.find('=') != string::npos)
3822 {
3823 set=line.substr(0,line.find('='));
3824 val=line.substr(line.find('=')+1);
3825
3826 if(set=="eyecandy")
3827 {
3828 setting.eyeCandy=atoi(val.data());
3829 } else if(set=="resx")
3830 {
3831 setting.cfgRes[0]=1;
3832 setting.resx=atoi(val.data());
3833 } else if(set=="resy")
3834 {
3835 setting.cfgRes[1]=1;
3836 setting.resy=atoi(val.data());
3837 } else if(set=="showbg")
3838 {
3839 setting.showBg=atoi(val.data());
3840 } else if(set=="fullscreen")
3841 {
3842 setting.fullscreen=atoi(val.data());
3843 } else if(set=="particlecollide")
3844 {
3845 setting.particleCollide=atoi(val.data());
3846 } else if(set=="sound")
3847 {
3848 setting.sound=atoi(val.data());
3849 } else if(set=="stereo")
3850 {
3851 setting.stereo=atoi(val.data());
3852 } else if(set=="controlmaxspeed")
3853 {
3854 setting.controlMaxSpeed = atof(val.data());
3855 } else if(set=="controlaccel")
3856 {
3857 setting.controlAccel = atof(val.data());
3858 } else if(set=="controlstartspeed")
3859 {
3860 setting.controlStartSpeed = atof(val.data());
3861 } else if(set=="rightkey")
3862 {
3863 setting.keyRight = (SDLKey)atoi(val.data());
3864 } else if(set=="leftkey")
3865 {
3866 setting.keyLeft = (SDLKey)atoi(val.data());
3867 } else if(set=="shootkey")
3868 {
3869 setting.keyShoot = (SDLKey)atoi(val.data());
3870 } else if(set=="nextkey")
3871 {
3872 setting.keyNextPo = (SDLKey)atoi(val.data());
3873 } else if(set=="buykey")
3874 {
3875 setting.keyBuyPo = (SDLKey)atoi(val.data());
3876 } else if(set=="prevkey")
3877 {
3878 setting.keyPrevPo = (SDLKey)atoi(val.data());
3879 } else if(set=="joyenabled")
3880 {
3881 setting.joyEnabled = atoi(val.data());
3882 } else if(set=="joyisdigital")
3883 {
3884 setting.joyIsDigital = atoi(val.data());
3885 } else if(set=="joycalhighjitter")
3886 {
3887 setting.JoyCalHighJitter = atoi(val.data());
3888 } else if(set=="joycallowjitter")
3889 {
3890 setting.JoyCalLowJitter = atoi(val.data());
3891 } else if(set=="joycalmax")
3892 {
3893 setting.JoyCalMax = atoi(val.data());
3894 } else if(set=="joycalmin")
3895 {
3896 setting.JoyCalMin = atoi(val.data());
3897 } else if(set=="lvltheme")
3898 {
3899 setting.lvlTheme = val;
3900 } else if(set=="sndtheme")
3901 {
3902 setting.sndTheme = val;
3903 } else if(set=="gfxtheme")
3904 {
3905 setting.gfxTheme = val;
3906 } else if(set=="startingdifficulty")
3907 {
3908 player.difficulty=atoi(val.data());
3909 } else if(set=="showclock")
3910 {
3911 setting.showClock=atoi(val.data());
3912 } else if(set=="fps")
3913 {
3914 setting.fps=atoi(val.data());
3915 maxFrameAge= (1000/setting.fps); }
3916 else
3917 {
3918 cout << "I did not understand '"<<set<<"' in settings.cfg" << endl;
3919 }
3920 }
3921 }
3922 conf.close();
3923 } else {
3924 cout << "No config file found, using default settings." << endl;
3925 }
3926
3927 //Initialize SDL
3928 #ifndef NOSOUND
3929 if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) <0 )
3930 #else
3931 if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_JOYSTICK) <0 )
3932 #endif
3933 {
3934 printf("\nError: Unable to initialize SDL:%s\n", SDL_GetError());
3935 }
3936
3937 //Save current resolution so it can be restored at exit
3938 int oldResX = SDL_GetVideoInfo()->current_w;
3939 int oldResY = SDL_GetVideoInfo()->current_h;
3940 int oldColorDepth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
3941
3942 /* Handle those situations where sdl gets a void resolution */
3943 if(oldResX < 128 || oldResY < 96)
3944 {
3945 cout << "SDL Reported a screen resolution below 128x96."<< endl;
3946 cout << "Assuming this is a bug in SDL or driver." << endl;
3947 cout << "Falling back on 128x96";
3948 oldResX=128;
3949 oldResY=96;
3950 if(!setting.cfgRes[0] || !setting.cfgRes[1])
3951 {
3952 setting.fullscreen=0;
3953 cout << ", windowed mode.";
3954 }
3955 cout << endl;
3956 }
3957 /* The above code is not tested and might not work */
3958
3959 if(!setting.cfgRes[0] || !setting.cfgRes[1])
3960 {
3961 setting.resx = oldResX;
3962 setting.resy = oldResY;
3963 }
3964
3965 SDL_Event sdlevent;
3966
3967 SDL_WM_GrabInput(SDL_GRAB_ON);
3968 SDL_ShowCursor(SDL_DISABLE);
3969
3970 SDL_EnableUNICODE (1);
3971
3972 initScreen();
3973 initGL();
3974
3975 glText = new glTextClass; // instantiate the class now that settings have been read.
3976
3977 soundMan.init();
3978
3979 SDL_WM_SetCaption("SDL-Ball", "SDL-Ball" );
3980 SDL_WM_SetIcon( IMG_Load( useTheme("icon32.png", setting.gfxTheme).data() ), 0 );
3981 SDL_WarpMouse(var.halfresx, var.halfresy);
3982
3983 textureManager texMgr;
3984
3985 textureClass texPaddleBase;
3986 textureClass texPaddleLayers[2];
3987 textureClass texBall[3];
3988 textureClass texLvl[13];
3989 texExplosiveBrick = &texLvl[0]; //Pointer to explosive texture..
3990
3991 textureClass texBorder;
3992 textureClass texPowerup[MAXPOTEXTURES];
3993 textureClass texBullet;
3994 textureClass texParticle;
3995
3996
3997
3998 texMgr.readTexProps(useTheme("gfx/paddle/base.txt",setting.gfxTheme), texPaddleBase);
3999 texMgr.readTexProps(useTheme("gfx/paddle/glue.txt",setting.gfxTheme), texPaddleLayers[0]);
4000 texMgr.readTexProps(useTheme("gfx/paddle/gun.txt",setting.gfxTheme), texPaddleLayers[1]);
4001
4002
4003 texMgr.readTexProps(useTheme("gfx/ball/normal.txt",setting.gfxTheme), texBall[0]);
4004 texMgr.readTexProps(useTheme("gfx/ball/fireball.txt",setting.gfxTheme), texBall[1]);
4005 texMgr.readTexProps(useTheme("gfx/ball/tail.txt",setting.gfxTheme), texBall[2]);
4006
4007 texMgr.readTexProps(useTheme("gfx/brick/explosive.txt", setting.gfxTheme), texLvl[0]);
4008 texMgr.readTexProps(useTheme("gfx/brick/base.txt", setting.gfxTheme), texLvl[1]);
4009 texMgr.readTexProps(useTheme("gfx/brick/cement.txt", setting.gfxTheme), texLvl[2]);
4010 texMgr.readTexProps(useTheme("gfx/brick/doom.txt", setting.gfxTheme), texLvl[3]);
4011 texMgr.readTexProps(useTheme("gfx/brick/glass.txt", setting.gfxTheme), texLvl[4]);
4012 texMgr.readTexProps(useTheme("gfx/brick/invisible.txt", setting.gfxTheme), texLvl[5]);
4013 texMgr.readTexProps(useTheme("gfx/brick/blue.txt", setting.gfxTheme), texLvl[6]);
4014 texMgr.readTexProps(useTheme("gfx/brick/yellow.txt", setting.gfxTheme), texLvl[7]);
4015 texMgr.readTexProps(useTheme("gfx/brick/green.txt", setting.gfxTheme), texLvl[8]);
4016 texMgr.readTexProps(useTheme("gfx/brick/grey.txt", setting.gfxTheme), texLvl[9]);
4017 texMgr.readTexProps(useTheme("gfx/brick/purple.txt", setting.gfxTheme), texLvl[10]);
4018 texMgr.readTexProps(useTheme("gfx/brick/white.txt", setting.gfxTheme), texLvl[11]);
4019 texMgr.readTexProps(useTheme("gfx/brick/red.txt", setting.gfxTheme), texLvl[12]);
4020
4021
4022 texMgr.load(useTheme("gfx/border.png",setting.gfxTheme), texBorder);
4023
4024 texMgr.readTexProps(useTheme("gfx/powerup/coin.txt",setting.gfxTheme),texPowerup[PO_COIN]);
4025 texMgr.readTexProps(useTheme("gfx/powerup/glue.txt",setting.gfxTheme),texPowerup[PO_GLUE]);
4026 texMgr.readTexProps(useTheme("gfx/powerup/multiball.txt",setting.gfxTheme),texPowerup[PO_MULTIBALL]);
4027 texMgr.readTexProps(useTheme("gfx/powerup/bigball.txt",setting.gfxTheme),texPowerup[PO_BIGBALL]);
4028 texMgr.readTexProps(useTheme("gfx/powerup/normalball.txt",setting.gfxTheme),texPowerup[PO_NORMALBALL]);
4029 texMgr.readTexProps(useTheme("gfx/powerup/smallball.txt",setting.gfxTheme),texPowerup[PO_SMALLBALL]);
4030 texMgr.readTexProps(useTheme("gfx/powerup/aim.txt",setting.gfxTheme),texPowerup[PO_AIM]);
4031 texMgr.readTexProps(useTheme("gfx/powerup/explosive.txt",setting.gfxTheme),texPowerup[PO_EXPLOSIVE]);
4032 texMgr.readTexProps(useTheme("gfx/powerup/gun.txt",setting.gfxTheme),texPowerup[PO_GUN]);
4033 texMgr.readTexProps(useTheme("gfx/powerup/go-thru.txt",setting.gfxTheme),texPowerup[PO_THRU]);
4034 texMgr.readTexProps(useTheme("gfx/powerup/laser.txt",setting.gfxTheme),texPowerup[PO_LASER]);
4035 texMgr.readTexProps(useTheme("gfx/powerup/life.txt",setting.gfxTheme),texPowerup[PO_LIFE]);
4036 texMgr.readTexProps(useTheme("gfx/powerup/die.txt",setting.gfxTheme),texPowerup[PO_DIE]);
4037 texMgr.readTexProps(useTheme("gfx/powerup/drop.txt",setting.gfxTheme),texPowerup[PO_DROP]);
4038 texMgr.readTexProps(useTheme("gfx/powerup/detonate.txt",setting.gfxTheme),texPowerup[PO_DETONATE]);
4039 texMgr.readTexProps(useTheme("gfx/powerup/explosive-grow.txt",setting.gfxTheme),texPowerup[PO_EXPLOSIVE_GROW]);
4040 texMgr.readTexProps(useTheme("gfx/powerup/easybrick.txt",setting.gfxTheme),texPowerup[PO_EASYBRICK]);
4041 texMgr.readTexProps(useTheme("gfx/powerup/nextlevel.txt",setting.gfxTheme),texPowerup[PO_NEXTLEVEL]);
4042 texMgr.readTexProps(useTheme("gfx/powerup/aimhelp.txt",setting.gfxTheme),texPowerup[PO_AIMHELP]);
4043 texMgr.readTexProps(useTheme("gfx/powerup/growbat.txt",setting.gfxTheme), texPowerup[PO_GROWPADDLE]);
4044 texMgr.readTexProps(useTheme("gfx/powerup/shrinkbat.txt",setting.gfxTheme), texPowerup[PO_SHRINKPADDLE]);
4045 texMgr.readTexProps(useTheme("gfx/powerup/bullet.txt",setting.gfxTheme), texBullet);
4046 pMan.init(texPowerup);
4047
4048 texMgr.load(useTheme("gfx/particle.png",setting.gfxTheme), texParticle);
4049
4050 GLuint sceneDL;
4051
4052 mkDLscene(&sceneDL, texBorder);
4053
4054 brick bricks[598];
4055
4056 string levelfile = useTheme("levels.txt",setting.lvlTheme);
4057
4058
4059
4060 int i=0; //bruges i for loop xD
4061 glScoreBoard scoreboard;
4062 menuClass menu;
4063
4064
4065 paddle_class paddle;
4066
4067 paddle.tex = texPaddleBase;
4068 paddle.layerTex = texPaddleLayers;
4069
4070 struct pos p; //kordinater for hvor den stødte sammen
4071
4072 effectManager fxMan;
4073 fxMan.set(FX_VAR_TEXTURE, texParticle);
4074 fxMan.set(FX_VAR_GRAVITY, 0.6f);
4075
4076 titleScreenClass titleScreen(&fxMan, texPowerup, &menu);
4077
4078 ballManager bMan(texBall);
4079
4080 initNewGame();
4081 paddle.posy = -1.15;
4082
4083 highScoreClass hKeeper;
4084 backgroundClass bg;
4085
4086 bulletsClass bullet(texBullet);
4087
4088 speedometerClass speedo;
4089
4090 hudClass hud(texBall[0], texPowerup); //This is GOING to be containing the "hud" (score, borders, lives left, level, speedometer)
4091
4092 var.effectnum=-1;
4093
4094 int lastTick = SDL_GetTicks();
4095 int nonpausingLastTick = lastTick;
4096 char txt[256];
4097 int frameAge=0; //How long have the current frame been shown
4098
4099 // #define performanceTimer
4100
4101 #ifdef performanceTimer
4102 struct timeval timeStart,timeStop;
4103 int renderTime;
4104 #endif
4105
4106 controllerClass control(&paddle, &bullet, &bMan);
4107
4108
4109 soundMan.add(SND_START,0);
4110
4111 while(!var.quit)
4112 {
4113 #ifdef performanceTimer
4114 gettimeofday(&timeStart, NULL);
4115 #endif
4116
4117 nonpausingGlobalTicks = SDL_GetTicks() - nonpausingLastTick;
4118 frameAge += nonpausingGlobalTicks;
4119
4120 nonpausingGlobalMilliTicks = nonpausingGlobalTicks/1000.0;
4121 nonpausingLastTick = SDL_GetTicks();
4122
4123 if(!var.paused)
4124 {
4125 globalTicks = SDL_GetTicks() - lastTick;
4126 globalMilliTicks = globalTicks/1000.0;
4127 } else {
4128 globalTicks = globalMilliTicks = 0;
4129 }
4130 lastTick = SDL_GetTicks();
4131
4132 globalTicksSinceLastDraw += nonpausingGlobalTicks;
4133 globalMilliTicksSinceLastDraw += nonpausingGlobalMilliTicks;
4134
4135 gVar.deadTime += globalTicks;
4136
4137 //really ugly... but easy
4138 if(!var.titleScreenShow)
4139 {
4140
4141 if(gVar.deadTime > 20000)
4142 {
4143 gVar.deadTime=0;
4144 bMan.powerup(PO_EXPLOSIVE); //give the balls explosive ability, in order to blow up cement block and get on with the game
4145 }
4146
4147 if(bMan.activeBalls == 0 && !gVar.newLevel) //check kun om vi er døde hvis vi faktisk er kommet igang med at spille
4148 {
4149 player.lives--;
4150 if(player.lives > 0)
4151 {
4152 resetPlayerPowerups();
4153 gVar.newLife=1;
4154 if(!paddle.dead)
4155 player.explodePaddle=1;
4156 pMan.die(fxMan);
4157 } else if(!gVar.gameOver) {
4158 gVar.gameOver=1;
4159 pauseGame();
4160 if( hKeeper.isHighScore() )
4161 {
4162 // announce.write(string text, int mslife, int fontnum);
4163 announce.write("Highscore!", 3000,FONT_ANNOUNCE_GOOD);
4164 var.showHighScores=1;
4165 soundMan.add(SND_HIGHSCORE, 0);
4166 }
4167 } else if(gVar.gameOver && !var.showHighScores)
4168 {
4169 //Only ran if there is gameover and no highscore
4170 if(var.effectnum == -1)
4171 {
4172 fxMan.set(FX_VAR_TYPE, FX_TRANSIT);
4173 fxMan.set(FX_VAR_LIFE, 3000);
4174 fxMan.set(FX_VAR_COLOR, 0.0,0.0,0.0);
4175 p.x = 0.0;
4176 p.y = 0.0;
4177
4178 //Kør en transition effekt
4179 var.effectnum = fxMan.spawn(p);
4180 announce.write("GameOver!", 1500,FONT_ANNOUNCE_BAD);
4181 soundMan.add(SND_GAMEOVER, 0);
4182 } else {
4183
4184 if(var.transition_half_done)
4185 {
4186 var.titleScreenShow=1;
4187 fxMan.kill(var.effectnum);
4188 var.effectnum = -1;
4189 initNewGame();
4190 resumeGame();
4191 }
4192 }
4193
4194
4195 }
4196 }
4197
4198 if(gVar.nextlevel)
4199 {
4200 if(var.effectnum == -1)
4201 {
4202
4203 announce.write("Well Done!", 1000, FONT_ANNOUNCE_GOOD);
4204 soundMan.add(SND_NEXTLEVEL, 0);
4205
4206 if(bMan.activeBalls > 1)
4207 {
4208 sprintf(txt, "Bonus: %i", bMan.activeBalls*150);
4209 player.score += (bMan.activeBalls*150)*player.multiply;
4210 announce.write(txt, 2000, FONT_ANNOUNCE_GOOD);
4211 }
4212
4213 fxMan.set(FX_VAR_TYPE, FX_TRANSIT);
4214 fxMan.set(FX_VAR_LIFE, 1600);
4215 fxMan.set(FX_VAR_COLOR, 0.0,0.0,0.0);
4216 p.x = 0.0;
4217 p.y = 0.0;
4218
4219 //Kør en transition effekt
4220 var.effectnum = fxMan.spawn(p);
4221
4222 var.idiotlock = 0;
4223
4224 } else {
4225 if(var.transition_half_done)
4226 {
4227
4228 if(!var.idiotlock)
4229 {
4230 var.idiotlock=1;
4231 player.level++;
4232 SOLPlayer = player; // Capture how player is at the start of this level
4233 //If player completed all levels, restart the game with higher multiplier
4234 if(player.level == var.numlevels)
4235 {
4236 player.multiply += player.multiply*3;
4237 player.level=0;
4238 announce.write("Finished!",3500,FONT_ANNOUNCE_GOOD);
4239 }
4240
4241 sprintf(txt, "Level %i",player.level+1); //+1 fordi levels starter fra 0
4242 announce.write(txt,1500,FONT_ANNOUNCE_GOOD);
4243
4244 //check om vi skal fjerne powerups
4245 if(player.difficulty > EASY)
4246 {
4247 resetPlayerPowerups();
4248 }
4249 gVar.newLevel = 1;
4250 var.paused=0;
4251 }
4252
4253 }
4254
4255 if(!fxMan.isActive(var.effectnum))
4256 {
4257 var.effectnum = -1; //nulstil så den er klar igen
4258 gVar.nextlevel = 0;
4259 var.paused = 0;
4260 var.idiotlock=0;
4261 }
4262 }
4263 }
4264
4265 if(gVar.newLevel)
4266 {
4267 var.bricksHit = 1;
4268 gVar.newLevel=0;
4269 loadlevel(levelfile, bricks,player.level);
4270 initlevels(bricks,texLvl);
4271 gVar.gameOver=0;
4272 gVar.newLife=1;
4273 pMan.clear();
4274 bullet.clear();
4275 paddle.posx = 0.0;
4276 var.startedPlaying=0;
4277 bg.init(texMgr);
4278 hud.clearShop();
4279 }
4280
4281 if(gVar.newLife)
4282 {
4283 gVar.newLife=0;
4284 paddle.init();
4285 p.x=paddle.posx;
4286
4287 p.y=paddle.posy+paddle.height+0.025;
4288
4289 bMan.clear();
4290 bMan.spawn(p,1,paddle.width,difficulty.ballspeed[player.difficulty],1.57100000f); //Not exactly 90 degree, so the ball will always fall a bit to the side
4291 }
4292
4293 if(frameAge >= maxFrameAge)
4294 {
4295
4296 if(var.clearScreen)
4297 {
4298 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
4299 }
4300
4301 //Update player score
4302 scoreboard.update(player.score);
4303
4304 //background
4305 if(setting.showBg)
4306 bg.draw();
4307 //borders
4308 glCallList(sceneDL);
4309
4310
4311 if(var.scrollInfo.drop)
4312 {
4313 if( (SDL_GetTicks() - var.scrollInfo.lastTick ) > var.scrollInfo.dropspeed )
4314 {
4315 var.scrollInfo.lastTick=SDL_GetTicks();
4316 dropBoard(bricks);
4317 }
4318 }
4319
4320
4321 if(gVar.bricksleft==1)
4322 {
4323 player.powerup[PO_AIMHELP]=1;
4324 }
4325 }
4326
4327 bullet.move();
4328
4329 gVar.bricksleft=0;
4330
4331 //Update nbrick here
4332 if(var.bricksHit)
4333 {
4334 memcpy(nbrick, updated_nbrick, sizeof(updated_nbrick));
4335 var.bricksHit = 0;
4336 }
4337
4338 for(i=0; i <598; i++)
4339 {
4340 if(bricks[i].active)
4341 {
4342 if(bricks[i].destroytowin && bricks[i].hitsLeft)
4343 {
4344 gVar.bricksleft++;
4345 }
4346
4347 if(bricks[i].collide)
4348 {
4349 bMan.bcoldet(bricks[i], fxMan);
4350 //bullets
4351 if(player.powerup[PO_GUN])
4352 {
4353 bullet.coldet(bricks[i], fxMan);
4354 }
4355
4356 //check kollision på effekterne
4357 if(setting.particleCollide && setting.eyeCandy && frameAge >= maxFrameAge)
4358 fxMan.coldet(bricks[i]);
4359 }
4360 if(frameAge >= maxFrameAge)
4361 bricks[i].draw(bricks,fxMan);
4362 } //aktiv brik
4363 } // for loop
4364
4365 //Collission between paddle and balls
4366 if( bMan.pcoldet(paddle, fxMan) )
4367 {
4368 if(player.powerup[PO_DROP])
4369 {
4370 dropBoard(bricks);
4371 }
4372 }
4373
4374 bMan.move();
4375
4376 if(setting.particleCollide && setting.eyeCandy && frameAge >= maxFrameAge)
4377 fxMan.pcoldet(paddle);
4378
4379 pMan.move();
4380 if(pMan.coldet(paddle, fxMan, bMan))
4381 {
4382 if(player.powerup[PO_DETONATE])
4383 {
4384 player.powerup[PO_DETONATE]=0;
4385 detonateExplosives(bricks, fxMan);
4386 }
4387
4388 if(player.powerup[PO_EASYBRICK])
4389 {
4390 player.powerup[PO_EASYBRICK]=0;
4391 easyBrick(bricks);
4392 }
4393
4394 if(player.powerup[PO_NEXTLEVEL])
4395 {
4396 player.powerup[PO_NEXTLEVEL]=0;
4397 gVar.nextlevel=1;
4398 var.paused=1;
4399 }
4400
4401 if(player.powerup[PO_EXPLOSIVE_GROW])
4402 {
4403 player.powerup[PO_EXPLOSIVE_GROW]=0;
4404 explosiveGrow(bricks);
4405 }
4406 }
4407
4408 if(frameAge >= maxFrameAge)
4409 {
4410
4411 soundMan.play();
4412
4413 if(player.explodePaddle)
4414 {
4415 player.explodePaddle=0;
4416 soundMan.add(SND_DIE,0);
4417 if(setting.eyeCandy)
4418 {
4419 fxMan.set(FX_VAR_TYPE, FX_PARTICLEFIELD);
4420
4421 p.x=paddle.width*2;
4422 p.y=paddle.height*2;
4423 fxMan.set(FX_VAR_RECTANGLE, p);
4424
4425 p.x=paddle.posx;
4426 p.y=paddle.posy;
4427
4428 fxMan.set(FX_VAR_LIFE, 2000);
4429 fxMan.set(FX_VAR_NUM, 20);
4430 fxMan.set(FX_VAR_SIZE, 0.025f);
4431 fxMan.set(FX_VAR_SPEED, 0.35f);
4432 fxMan.set(FX_VAR_GRAVITY, -0.7f);
4433 fxMan.set(FX_VAR_COLOR, 1.0f, 0.7f, 0.0f);
4434 fxMan.spawn(p);
4435 fxMan.set(FX_VAR_COLOR, 1.0f, 0.8f, 0.0f);
4436 fxMan.spawn(p);
4437 fxMan.set(FX_VAR_COLOR, 1.0f, 0.9f, 0.0f);
4438 fxMan.spawn(p);
4439 fxMan.set(FX_VAR_COLOR, 1.0f, 1.0f, 0.0f);
4440 fxMan.spawn(p);
4441
4442 fxMan.set(FX_VAR_NUM, 32);
4443 fxMan.set(FX_VAR_SIZE, 0.05f);
4444 fxMan.set(FX_VAR_LIFE, 1500);
4445 fxMan.set(FX_VAR_SPEED, 0.7f);
4446 fxMan.set(FX_VAR_GRAVITY, 0.0f);
4447
4448 fxMan.set(FX_VAR_COLOR, 0.5f, 0.5f, 0.5f);
4449 fxMan.spawn(p);
4450 fxMan.set(FX_VAR_COLOR, 1.0f, 1.0f, 1.0f);
4451 fxMan.spawn(p);
4452 }
4453 }
4454
4455 bMan.updatelast();
4456 glColor3d(255,255,255);
4457 bullet.draw();
4458 paddle.draw();
4459
4460 pMan.draw();
4461 bMan.draw(paddle);
4462 scoreboard.draw();
4463 speedo.draw();
4464 hud.draw();
4465 fxMan.draw();
4466
4467 if(var.showHighScores)
4468 hKeeper.draw();
4469
4470 if(var.menu>0)
4471 {
4472 if(var.menu==10 || var.menu==11)
4473 {
4474 control.calibrate();
4475 }
4476 menu.doMenu();
4477 }
4478
4479 announce.draw();
4480
4481 SDL_GL_SwapBuffers( );
4482
4483 frameAge = 0;
4484
4485 globalTicksSinceLastDraw=0;
4486 globalMilliTicksSinceLastDraw=0;
4487 #ifdef performanceTimer
4488 cout << "FrameAge:";
4489 } else {
4490 cout << "LoopAge:";
4491 }
4492 gettimeofday(&timeStop, NULL);
4493 renderTime = timeStop.tv_usec - timeStart.tv_usec;
4494 cout << renderTime << endl;
4495 #else
4496 }
4497 #endif
4498
4499
4500 if(!gVar.bricksleft)
4501 {
4502 gVar.nextlevel=1;
4503 var.paused=1;
4504 }
4505 } else {
4506 //Show the title screen
4507 titleScreen.draw(&frameAge, &maxFrameAge);
4508 }
4509
4510
4511 control.get(); //Check for keypresses and joystick events
4512 while (SDL_PollEvent(&sdlevent) )
4513 {
4514 if( sdlevent.type == SDL_KEYDOWN ) {
4515
4516 if(var.showHighScores)
4517 {
4518 hKeeper.type(sdlevent, menu);
4519 } else if(var.enterSaveGameName)
4520 {
4521 menu.enterSaveGameName(sdlevent);
4522 } else {
4523 if( sdlevent.key.keysym.sym==SDLK_p || sdlevent.key.keysym.sym==SDLK_PAUSE)
4524 {
4525 var.paused ? resumeGame() : pauseGame();
4526 }
4527
4528 if( sdlevent.key.keysym.sym == SDLK_q )
4529 {
4530 var.quit=1;
4531 } else if( sdlevent.key.keysym.sym == SDLK_s )
4532 {
4533 screenShot();
4534 } else if( sdlevent.key.keysym.sym == setting.keyNextPo)
4535 {
4536 gVar.shopPrevItem=1;
4537 } else if( sdlevent.key.keysym.sym == setting.keyBuyPo)
4538 {
4539 gVar.shopBuyItem=1;
4540 } else if( sdlevent.key.keysym.sym == setting.keyPrevPo)
4541 {
4542 gVar.shopNextItem=1;
4543 } else if(sdlevent.key.keysym.sym == SDLK_u)
4544 {
4545 var.clearScreen ? var.clearScreen=0:var.clearScreen=1;
4546 } else if(sdlevent.key.keysym.sym == SDLK_c)
4547 {
4548 setting.showClock ? setting.showClock=0 : setting.showClock=1;
4549 writeSettings();
4550 }
4551
4552 #ifdef WITH_WIIUSE
4553 if( sdlevent.key.keysym.sym == SDLK_w )
4554 {
4555 var.titleScreenShow=0;
4556 pauseGame();
4557 var.menu=11;
4558 var.menuJoyCalStage=-1;
4559 }
4560 #endif
4561 }
4562
4563 //Toggle menu
4564 if( sdlevent.key.keysym.sym == SDLK_ESCAPE)
4565 {
4566 if(var.titleScreenShow)
4567 var.titleScreenShow=0;
4568 switch(var.menu)
4569 {
4570 case 0:
4571 var.menu=1;
4572 pauseGame();
4573 break;
4574 case 1:
4575 resumeGame();
4576 break;
4577 default:
4578 var.menu=1;
4579 break;
4580 }
4581 } else if( sdlevent.key.keysym.sym == SDLK_F1 )
4582 {
4583 if(!var.titleScreenShow)
4584 {
4585 var.titleScreenShow=1;
4586 pauseGame();
4587 } else {
4588 var.titleScreenShow=0;
4589 resumeGame();
4590 }
4591 }
4592 #ifndef WIN32
4593 else if( sdlevent.key.keysym.sym == SDLK_F11 )
4594 {
4595 if(setting.fullscreen)
4596 setting.fullscreen=0;
4597 else
4598 setting.fullscreen=1;
4599
4600 initScreen();
4601 }
4602 #endif
4603 }
4604
4605 if( sdlevent.type == SDL_MOUSEMOTION )
4606 {
4607 mousex = (sdlevent.motion.x - var.halfresx) * var.glunits_per_xpixel;
4608 mousey = (sdlevent.motion.y - var.halfresy) * var.glunits_per_ypixel * -1;
4609 if(var.menu)
4610 {
4611 if(mousex > -0.5 && mousex < 0.5 && mousey < (-0.78)+(0.07) && mousey > (-0.78)-(0.07) )
4612 var.menuItem = 1;
4613 else if(mousex > -0.5 && mousex < 0.5 && mousey < (-0.56)+(0.07) && mousey > (-0.56)-(0.07) )
4614 var.menuItem = 2;
4615 else if(mousex > -0.5 && mousex < 0.5 && mousey < (-0.34)+(0.07) && mousey > (-0.34)-(0.07) )
4616 var.menuItem = 3;
4617 else if(mousex > -0.5 && mousex < 0.5 && mousey < (-0.12)+(0.07) && mousey > (-0.12)-(0.07) )
4618 var.menuItem = 4;
4619 else if(mousex > -0.5 && mousex < 0.5 && mousey < (0.1)+(0.07) && mousey > (0.1)-(0.07) )
4620 var.menuItem = 5;
4621 else if(mousex > -0.5 && mousex < 0.5 && mousey < (0.32)+(0.07) && mousey > (0.32)-(0.07) )
4622 var.menuItem = 6;
4623 else if(mousex > -0.5 && mousex < 0.5 && mousey < (0.54)+(0.07) && mousey > (0.54)-(0.07) )
4624 var.menuItem = 7;
4625 else
4626 var.menuItem = 0;
4627 } else {
4628 control.movePaddle(paddle.posx + (sdlevent.motion.xrel * var.glunits_per_xpixel));
4629 }
4630 } else if( sdlevent.type == SDL_MOUSEBUTTONDOWN )
4631 {
4632 if(sdlevent.button.button == SDL_BUTTON_LEFT )
4633 {
4634 if(var.menu)
4635 {
4636 var.menuPressed=1;
4637 if(var.menuItem > 0)
4638 soundMan.add(SND_MENUCLICK, 0);
4639 }
4640
4641 control.btnPress();
4642 } else if(sdlevent.button.button == SDL_BUTTON_RIGHT )
4643 {
4644 gVar.shopBuyItem=1;
4645 } else if(sdlevent.button.button == 4)
4646 {
4647 gVar.shopPrevItem=1;
4648 } else if(sdlevent.button.button == 5)
4649 {
4650 gVar.shopNextItem=1;
4651 }
4652 }
4653 if( sdlevent.type == SDL_QUIT ) {
4654 var.quit = 1;
4655 } else if( sdlevent.type == SDL_VIDEORESIZE )
4656 {
4657 setting.resx = sdlevent.resize.w;
4658 setting.resy = sdlevent.resize.h;
4659 initScreen();
4660 }
4661 }
4662 #ifdef WIN32
4663 Sleep( 1 );
4664 #else
4665 usleep( 1000 );
4666 #endif
4667 }
4668
4669 #ifndef WIN32
4670 if(setting.fullscreen)
4671 SDL_SetVideoMode(oldResX,oldResY,oldColorDepth, SDL_OPENGL);
4672 #endif
4673
4674 SDL_WM_GrabInput(SDL_GRAB_OFF);
4675 SDL_ShowCursor(SDL_ENABLE);
4676 SDL_FreeSurface(screen);
4677 SDL_Quit();
4678 cout << "Thank you for playing sdl-ball ;)" << endl;
4679 return EXIT_SUCCESS;
4680 }
4681