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