/* ************************************************************************* * SDL-Ball - DX-Ball/Breakout remake with openGL and SDL for Linux Copyright (C) 2008 Jimmy Christensen ( dusted at dusted dot dk ) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . * ************************************************************************* */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef WIN32 #include #include #endif /* ******************************************** * Here are the compile-time options !! ;) * ******************************************** */ //WIN32 #ifndef DATADIR #define DATADIR "themes/" #endif //To disable sound support: //#define NOSOUND #ifdef WITH_WIIUSE #include #define MAX_WIIMOTES 1 #endif #ifndef NOSOUND #define MIX_CHANNELS 16 #include #endif #define VERSION "1.01" #define SAVEGAMEVERSION 2 #include "declerations.h" #define PI 3.14159265 #define RAD 6.28318531 #define BALL_MAX_DEGREE 2.61799388 //150+15 = 165 degrees #define BALL_MIN_DEGREE 0.261799388 //15 degrees #define FALSE 0 #define TRUE 1 //#define debugBall 1 // #define DEBUG_DRAW_BALL_QUAD #define PO_COIN 0 #define PO_BIGBALL 1 #define PO_NORMALBALL 2 #define PO_SMALLBALL 3 #define PO_EXPLOSIVE 4 #define PO_GLUE 5 #define PO_MULTIBALL 6 #define PO_GROWPADDLE 7 #define PO_SHRINKPADDLE 8 #define PO_AIM 9 #define PO_GUN 10 #define PO_THRU 11 #define PO_LASER 12 #define PO_LIFE 13 #define PO_DIE 14 #define PO_DROP 15 #define PO_DETONATE 16 #define PO_EXPLOSIVE_GROW 17 #define PO_EASYBRICK 18 #define PO_NEXTLEVEL 19 #define PO_AIMHELP 20 //"Max powerups" #define MAXPOTEXTURES 21 #define EASY 0 #define NORMAL 1 #define HARD 2 //Sound effects #define SND_START 0 #define SND_BALL_HIT_BORDER 1 #define SND_BALL_HIT_PADDLE 2 #define SND_NORM_BRICK_BREAK 3 #define SND_EXPL_BRICK_BREAK 4 #define SND_GLASS_BRICK_HIT 5 #define SND_GLASS_BRICK_BREAK 6 #define SND_CEMENT_BRICK_HIT 7 #define SND_PO_HIT_BORDER 8 #define SND_GOOD_PO_HIT_PADDLE 9 #define SND_EVIL_PO_HIT_PADDLE 10 #define SND_SHOT 11 #define SND_DIE 12 #define SND_NEXTLEVEL 13 #define SND_GAMEOVER 14 #define SND_MENUCLICK 15 #define SND_DOOM_BRICK_BREAK 16 #define SND_GLUE_BALL_HIT_PADDLE 17 #define SND_INVISIBLE_BRICK_APPEAR 18 #define SND_HIGHSCORE 19 #define SND_BUY_POWERUP 20 #define SND_NORM_BRICK_BREAKB 21 #define SND_NORM_BRICK_BREAKC 22 #define SND_NORM_BRICK_BREAKD 23 #define SND_NORM_BRICK_BREAKE 24 #define SNDSAMPLES 25 using namespace std; void writeSettings(); bool initScreen(); void initNewGame(); void pauseGame(); void resumeGame(); float rndflt(float total, float negative); class ball; class paddle_class; float bounceOffAngle(GLfloat width, GLfloat posx, GLfloat hitx); int globalTicks; float globalMilliTicks; int nonpausingGlobalTicks; float nonpausingGlobalMilliTicks; int globalTicksSinceLastDraw; float globalMilliTicksSinceLastDraw; struct pos { GLfloat x; GLfloat y; }; struct difficultyStruct { GLfloat ballspeed[3]; GLfloat maxballspeed[3]; GLfloat hitbrickinc[3]; GLfloat hitpaddleinc[3]; GLfloat slowdown[3]; GLfloat speedup[3]; }; struct difficultyStruct static_difficulty, difficulty; struct settings { string sndTheme,gfxTheme,lvlTheme; bool cfgRes[2]; int resx; int resy; int fps; bool showClock; bool fullscreen; bool showBg; bool sound; bool stereo; bool eyeCandy; bool particleCollide; //Add to menu: SDLKey keyLeft, keyRight, keyShoot, keyNextPo, keyPrevPo, keyBuyPo; float controlAccel; float controlStartSpeed; float controlMaxSpeed; bool joyEnabled, joyIsDigital; int JoyCalMin, JoyCalMax, JoyCalHighJitter, JoyCalLowJitter; }; struct scrollInfoScruct { bool drop; //0 right, 1 left, 2 up, 3 down unsigned int dropspeed; unsigned int lastTick; // what was the time last they moved }; struct privFileStruct { string programRoot; string settingsFile; string saveGameFile; string highScoreFile; string screenshotDir; }; struct privFileStruct privFile; struct vars { bool titleScreenShow; int frame; int halfresx; int halfresy; GLfloat glunits_per_xpixel, glunits_per_ypixel; bool paused; int menu; int menuItem; bool menuPressed; int menuNumItems; int menuJoyCalStage; bool quit; bool wiiConnect; int numlevels; bool transition_half_done; bool clearScreen; bool idiotlock; //transition bool bricksHit; //tells the mainloop if it should copy the updated array of brick status. GLfloat averageBallSpeed; int showHighScores; bool enterSaveGameName; bool startedPlaying; int effectnum; struct scrollInfoScruct scrollInfo; }; //Ting der har med spillogik at gøre struct gameVars { bool shopNextItem, shopPrevItem, shopBuyItem; //When set to 1 shop goes next or prev int deadTime; //I hvor mange millisekunder har bolden intet rørt bool nextlevel; bool gameOver; bool newLife; bool newLevel; //Start en ny level int bricksleft; //hvor mange brikker er der tilbage }; struct gameVars gVar; struct player_struct { int coins; int multiply; bool powerup[MAXPOTEXTURES]; bool explodePaddle; //This lock makes the paddle explode and it won't come back until newlife. int level; int lives; int difficulty; int score; }; int listSaveGames(string slotName[]); void loadGame(int slot); void saveGame(int slot, string name); struct settings setting; struct player_struct player; struct player_struct SOLPlayer; struct vars var; typedef GLfloat texPos[8]; #ifndef uint // WIN32 typedef unsigned int uint; #endif struct texProp { GLuint texture; //Den GLtexture der er loaded GLfloat xoffset;// Hvor stort er springet mellem hver subframe GLfloat yoffset; // int cols,rows; //hvor mange rækker og kolonner er der i denne textur int ticks; uint frames; //This many frames in each se bool bidir; //Går Looper den fra 0 -> X - 0 eller fra 0 -> X -> 0 bool playing; 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 float pxw, pxh; //pixels width, and height GLfloat glTexColorInfo[4]; GLfloat glParColorInfo[3]; //This and above replaced object::color and particle colors string fileName; //Quite the fugly.. This will be set by readTexProps(); }; /* This function attempts to open path It will first look for the file in ~/.config/sdl-ball/themes/theme/path Then in DATADIR/themes/setting.theme/path This way, each user can even override a part of a theme that exist both in their own homedir and in the global themes dir. If still no luck it will use the file from DATADIR/path It will return the full qualified filename */ string useTheme(string path, string theme) { struct stat st; string name; if(theme.compare("default") != 0) { //Try in ~/.config/sdl-ball/themes/themename name = privFile.programRoot+"/themes/"+ theme+"/"+path; if( stat(name.data(), &st) == 0) { return(name); } //Try in DATADIR/themename/ name = DATADIR + theme+"/"+path; if( stat(name.data(), &st) == 0) { return(name); } } //Fall back on default file. name = DATADIR"default/" + path; if( stat(name.data(), &st) == 0) { return(name); } else { cout << "File Error: Could not find '" << path << "'" << endl; return(name); } } struct themeInfo { string name; bool snd,gfx,lvl,valid; //Valid means that there seems to be data of some kind (ie. not just an empty folder) }; /* This function looks in ~/.config/sdl-ball/themes/ and in DATADIR/themes for directories, it looks inside the dir to decide if a theme contains: gfx folder - this theme contains graphics snd folder - this theme contains sound level.txt - this theme contains levels. It will return info even if the theme is not valid It returns a vector of structs with info */ vector getThemes() { DIR *pdir; struct dirent *pent; struct stat st; struct themeInfo ti; string themeDir; string temp; vector v; for(int i=0; i < 2; i++) { if(i==0) { themeDir = privFile.programRoot + "/themes"; } else if(i==1) { themeDir = DATADIR; } pdir = opendir(themeDir.data()); if (pdir) { themeDir.append("/"); while ((pent=readdir(pdir))){ temp=pent->d_name; //We're not going to read hidden files if(temp[0] != '.') { temp= themeDir + pent->d_name; //Check if file is a dir. if(stat(temp.data(), &st) == 0) { ti.name = pent->d_name; ti.valid = 0; //Check if theme have graphics temp=themeDir + pent->d_name +"/gfx"; if(stat(temp.data(), &st) == 0) { ti.gfx=1; ti.valid=1; } else { ti.gfx=0; } //Check if theme have sound temp=themeDir + pent->d_name +"/snd"; if(stat(temp.data(), &st) == 0) { ti.snd=1; ti.valid=1; } else { ti.snd=0; } //Check if theme have levels temp=themeDir + pent->d_name +"/levels.txt"; if(stat(temp.data(), &st) == 0) { ti.lvl=1; ti.valid=1; } else { ti.lvl=0; } v.push_back(ti); } } } } } return(v); } #include "text.cpp" glTextClass *glText; //Pointer to the object, since we can't init (load fonts) because the settings have not been read yet. class textureClass { private: float age; //Hvor gammel er den frame vi er ved? bool dir; //hvis dette er en animation der går frem og tilbage hvilken retning uint lastframe; //check om det er den samme frame som sidst, så vi kan vide om vis skal opdatere cords public: uint frame; //hvilken frame er vi nået til i texturen (den er public så vi kan lave offset) bool playing; //spiller vi? bool firstFrame; //If this is the first frame texPos pos; //Kordinater for den frame på texturen der er nu texProp prop; //Properties for den textur som dette objekt har textureClass() { age=10000; firstFrame=1; lastframe=1000; frame=1; dir=0; } void play() { int col=0,row=0; if(prop.playing) { //Skal vi skifte frame? age += globalTicksSinceLastDraw; if(age >= prop.ticks) //Denne frame har været vist længe nok { age=0.0; if(!dir) { if(frame == prop.frames) { if(prop.bidir) { dir=1; } else { frame=1; } } else { frame++; } } if(dir) { if(frame == 1) { dir=0; frame=2; } else { frame--; } } } } uint f=0; if(frame != lastframe || firstFrame) { lastframe=frame; firstFrame=0; //hvor mange kolonner er der på en række for(row=0; row < prop.rows; row++) { for(col=0; col < prop.cols; col ++) { f++; if(f == frame) { //Øverst Venstre pos[0] = (prop.xoffset*(float)col); //0.0; pos[1] = (prop.yoffset*(float)row);//0.0; //Øverst højre pos[2] = (prop.xoffset*(float)col) + prop.xoffset; pos[3] = (prop.yoffset*(float)row);//0.0; //Nederst højre pos[4] = (prop.xoffset*(float)col) + prop.xoffset; // 1 pos[5] = (prop.yoffset*(float)row) + prop.yoffset; // 1 //Nederst venstre pos[6] = (prop.xoffset*(float)col);//0.0; pos[7] = (prop.yoffset*(float)row) + prop.yoffset; //1 if(prop.padding) { pos[0] += 1.0 / prop.pxw; pos[1] += 1.0 / prop.pxh; pos[2] -= 1.0 / prop.pxw; pos[3] += 1.0 / prop.pxh; pos[4] -= 1.0 / prop.pxw; pos[5] -= 1.0 / prop.pxh; pos[6] += 1.0 / prop.pxw; pos[7] -= 1.0 / prop.pxh; } } } } } } }; /* This function reads textureProperties from fileName and applies them to *tex */ class textureManager { public: bool load(string file, textureClass & tex) { SDL_Surface *temp = NULL; GLint maxTexSize; GLuint glFormat = GL_RGBA; if(file.substr(file.length()-3,3).compare("jpg") == 0) { glFormat = GL_RGB; } glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize); temp = IMG_Load(file.data()); if(temp == NULL) { cout << "Texture manager: " << file << " : "<< SDL_GetError() << endl; SDL_FreeSurface( temp ); return(FALSE); } //Hvis større end tilladt: if(temp->w > maxTexSize) { cout << "Texture manager: '" << file << "' texturesize too large." << endl; SDL_FreeSurface( temp ); return(FALSE); } glGenTextures(1, &tex.prop.texture); glBindTexture(GL_TEXTURE_2D, tex.prop.texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); glTexImage2D(GL_TEXTURE_2D, 0, glFormat, temp->w, temp->h, 0, glFormat, GL_UNSIGNED_BYTE, temp->pixels); tex.prop.pxw = temp->w; tex.prop.pxh = temp->h; SDL_FreeSurface( temp ); return(TRUE); } void readTexProps(string fileName, textureClass & tex) { char rgba[4][5]; ifstream f; string line,set,val; f.open( fileName.data() ); if(f.is_open()) { while(!f.eof()) { getline(f, line); if(line.find('=') != string::npos) { set=line.substr(0,line.find('=')); val=line.substr(line.find('=')+1); if(set=="xoffset") { tex.prop.xoffset=atof(val.data()); } else if(set=="yoffset") { tex.prop.yoffset=atof(val.data()); } else if(set=="cols") { tex.prop.cols=atoi(val.data()); } else if(set=="rows") { tex.prop.rows=atoi(val.data()); } else if(set=="ticks") { tex.prop.ticks=atoi(val.data()); } else if(set=="frames") { tex.prop.frames=atoi(val.data()); } else if(set=="bidir") { tex.prop.bidir=atoi(val.data()); } else if(set=="playing") { tex.prop.playing=atoi(val.data()); } else if(set=="padding") { tex.prop.padding=atoi(val.data()); } else if(set=="texcolor") { //Color in hex RGBA //Example:color=FFFFFFFF sprintf(rgba[0], "0x%c%c", val[0], val[1]); sprintf(rgba[1], "0x%c%c", val[2], val[3]); sprintf(rgba[2], "0x%c%c", val[4], val[5]); sprintf(rgba[3], "0x%c%c", val[6], val[7]); tex.prop.glTexColorInfo[0] = 0.003921569 * strtol(rgba[0], NULL,16); tex.prop.glTexColorInfo[1] = 0.003921569 * strtol(rgba[1], NULL,16); tex.prop.glTexColorInfo[2] = 0.003921569 * strtol(rgba[2], NULL,16); tex.prop.glTexColorInfo[3] = 0.003921569 * strtol(rgba[3], NULL,16); } else if(set=="parcolor") { //Color in hex RGBA //Example:color=FFFFFFFF sprintf(rgba[0], "0x%c%c", val[0], val[1]); sprintf(rgba[1], "0x%c%c", val[2], val[3]); sprintf(rgba[2], "0x%c%c", val[4], val[5]); tex.prop.glParColorInfo[0] = 0.003921569 * strtol(rgba[0], NULL,16); tex.prop.glParColorInfo[1] = 0.003921569 * strtol(rgba[1], NULL,16); tex.prop.glParColorInfo[2] = 0.003921569 * strtol(rgba[2], NULL,16); } else if(set=="file") { tex.prop.fileName = val; } else { cout << "Error: '"< 1) { string name = "gfx/"+tex.prop.fileName; load(useTheme(name,setting.gfxTheme), tex); } } else { cout << "readTexProps: Cannot open '" << fileName << "'"<= destwidth) { width = destwidth; height = aspect*destwidth; growing=0; } } glLoadIdentity(); glTranslatef( posx, posy, -3.0 ); tex.play(); glBindTexture(GL_TEXTURE_2D, tex.prop.texture); glColor4f( tex.prop.glTexColorInfo[0], tex.prop.glTexColorInfo[1], tex.prop.glTexColorInfo[2], tex.prop.glTexColorInfo[3] ); glBegin( GL_QUADS ); glTexCoord2f(tex.pos[0], tex.pos[1]); glVertex3f(-width,height, 0.0f ); glTexCoord2f(tex.pos[2], tex.pos[3]); glVertex3f( width,height, 0.0f ); glTexCoord2f(tex.pos[4], tex.pos[5]); glVertex3f( width,-height, 0.0f ); glTexCoord2f(tex.pos[6], tex.pos[7]); glVertex3f(-width,-height, 0.0f ); glEnd( ); //Hvis glue? if(player.powerup[PO_GLUE]) { glBindTexture(GL_TEXTURE_2D, layerTex[0].prop.texture); glColor4f( layerTex[0].prop.glTexColorInfo[0], layerTex[0].prop.glTexColorInfo[1], layerTex[0].prop.glTexColorInfo[2], layerTex[0].prop.glTexColorInfo[3] ); glBegin( GL_QUADS ); glTexCoord2f(0.0f, 0.0f); glVertex3f(-width, height, 0.0f ); glTexCoord2f(1.0f, 0.0f); glVertex3f( width, height, 0.0f ); glTexCoord2f(1.0f, 0.99f); glVertex3f( width,-height, 0.0f ); glTexCoord2f(0.0f, 0.99f); glVertex3f(-width,-height, 0.0f ); glEnd( ); } //Hvis gun if(player.powerup[PO_GUN]) { layerTex[1].play(); glBindTexture(GL_TEXTURE_2D, layerTex[1].prop.texture); glColor4f( layerTex[1].prop.glTexColorInfo[0], layerTex[1].prop.glTexColorInfo[1], layerTex[1].prop.glTexColorInfo[2], layerTex[1].prop.glTexColorInfo[3] ); glBegin( GL_QUADS ); glTexCoord2f(layerTex[1].pos[0], layerTex[1].pos[1]); glVertex3f(-width, height*4, 0.0f ); glTexCoord2f(layerTex[1].pos[2], layerTex[1].pos[3]); glVertex3f( width, height*4, 0.0f ); glTexCoord2f(layerTex[1].pos[4], layerTex[1].pos[5]-0.01); glVertex3f( width,height, 0.0f ); glTexCoord2f(layerTex[1].pos[6], layerTex[1].pos[7]-0.01); glVertex3f(-width,height, 0.0f ); glEnd( ); } } } }; //nasty fix to a problem int nbrick[23][26]; int updated_nbrick[23][26]; class brick; void makeExplosive(brick & b); textureClass * texExplosiveBrick; //NOTE:Ugly class brick : public object { public: int score; //Hvor meget gir den bool destroytowin; // Skal den smadres for at man kan vinde? char powerup; char type; GLfloat fade; //hvor meget brik GLfloat fadespeed; GLfloat zoomspeed; GLfloat zoom; bool isdyingnormally; bool isexploding; //springer den i luften int row; //what row is this brick in int bricknum; //brick in this row int hitsLeft; //Hvor mange gange skal denne brik rammes før den dør? bool justBecomeExplosive; //If this brick just become a explosive one. bool n(int dir) { switch(dir) { case 0: //Er der en brik til venstre for dig? if(bricknum > 0) { if(nbrick[row][bricknum-1] != -1) return(1); } break; case 1: //Er der en brik til højre for dig? if(bricknum < 25) //26 { if(nbrick[row][bricknum+1] != -1) return(1); } break; case 2: //Er der en brik Ovenpå dig if(row > 0) { if(nbrick[row-1][bricknum] != -1) return(1); } break; case 3: //Er der en brik nedenunder dig if(row < 22) //23 { if(nbrick[row+1][bricknum] != -1) return(1); } break; } return(0); } void hit(effectManager & fxMan, pos poSpawnPos, pos poSpawnVel, bool ballHitMe); void draw(brick bricks[], effectManager & fxMan) { if(isdyingnormally) { fade -= fadespeed * globalMilliTicksSinceLastDraw; opacity = fade; zoom -= zoomspeed * globalMilliTicksSinceLastDraw; if(fade < 0.0) active=0; } if(isexploding && !var.paused) { fade -= 7.0 * globalMilliTicksSinceLastDraw; opacity = fade; if(fade<0.0) { active=0; pos spos,svel; spos.x=posx; spos.y=posy; if(bricknum > 0) { if(nbrick[row][bricknum-1] != -1) { svel.x=rndflt(2,0)/3.0; svel.y=rndflt(2,0)/3.0; bricks[nbrick[row][bricknum-1]].hit(fxMan,spos,svel,0); } } if(bricknum < 25) { if(nbrick[row][bricknum+1] != -1) { svel.x=rndflt(2,0)/3.0; svel.y=rndflt(2,0)/3.0; bricks[nbrick[row][bricknum+1]].hit(fxMan,spos,svel,0); } } if(row > 0) { if(nbrick[row-1][bricknum] != -1) { svel.x=rndflt(2,0)/3.0; svel.y=rndflt(2,0)/3.0; bricks[nbrick[row-1][bricknum]].hit(fxMan,spos,svel,0); } } if(row < 22) { if(nbrick[row+1][bricknum] != -1) { svel.x=rndflt(2,0)/3.0; svel.y=rndflt(2,0)/3.0; bricks[nbrick[row+1][bricknum]].hit(fxMan,spos,svel,0); } } if(row > 0 && bricknum > 0) { if(nbrick[row-1][bricknum-1] != -1) { svel.x=rndflt(2,0)/3.0; svel.y=rndflt(2,0)/3.0; bricks[nbrick[row-1][bricknum-1]].hit(fxMan,spos,svel,0); } } if(row > 0 && bricknum < 25) { if(nbrick[row-1][bricknum+1] != -1) { svel.x=rndflt(2,0)/3.0; svel.y=rndflt(2,0)/3.0; bricks[nbrick[row-1][bricknum+1]].hit(fxMan,spos,svel,0); } } if(row < 22 && bricknum > 0) { if(nbrick[row+1][bricknum-1] != -1) { svel.x=rndflt(2,0)/3.0; svel.y=rndflt(2,0)/3.0; bricks[nbrick[row+1][bricknum-1]].hit(fxMan,spos,svel,0); } } if(row < 22 && bricknum < 25) { if(nbrick[row+1][bricknum+1] != -1) { svel.x=rndflt(2,0)/3.0; svel.y=rndflt(2,0)/3.0; bricks[nbrick[row+1][bricknum+1]].hit(fxMan,spos,svel,0); } } } } tex.play(); glColor4f( tex.prop.glTexColorInfo[0], tex.prop.glTexColorInfo[1], tex.prop.glTexColorInfo[2], opacity ); glBindTexture(GL_TEXTURE_2D, tex.prop.texture); glBegin( GL_QUADS ); glTexCoord2f(tex.pos[0],tex.pos[1]);glVertex3f( posx + (-0.0616*zoom), posy + (0.035*zoom), 0.00 ); // øverst venst glTexCoord2f(tex.pos[2],tex.pos[3]);glVertex3f( posx + ( 0.0616*zoom), posy + (0.035*zoom), 0.00 ); // øverst højre glTexCoord2f(tex.pos[4],tex.pos[5]);glVertex3f( posx + ( 0.0616*zoom), posy + (-0.035*zoom), 0.00 ); // nederst højre glTexCoord2f(tex.pos[6],tex.pos[7]);glVertex3f( posx + (-0.0616*zoom), posy + (-0.035*zoom), 0.00 ); // nederst venstre glEnd( ); } void growExplosive(brick bricks[]) { if(type!='B' || justBecomeExplosive) { return; } if(bricknum > 0) { if(nbrick[row][bricknum-1] != -1) { makeExplosive(bricks[nbrick[row][bricknum-1]]); } } if(bricknum < 25) { if(nbrick[row][bricknum+1] != -1) { makeExplosive(bricks[nbrick[row][bricknum+1]]); } } if(row > 0) { if(nbrick[row-1][bricknum] != -1) { makeExplosive(bricks[nbrick[row-1][bricknum]]); } } if(row < 22) { if(nbrick[row+1][bricknum] != -1) { makeExplosive(bricks[nbrick[row+1][bricknum]]); } } if(row > 0 && bricknum > 0) { if(nbrick[row-1][bricknum-1] != -1) { makeExplosive(bricks[nbrick[row-1][bricknum-1]]); } } if(row > 0 && bricknum < 25) { if(nbrick[row-1][bricknum+1] != -1) { makeExplosive(bricks[nbrick[row-1][bricknum+1]]); } } if(row < 22 && bricknum > 0) { if(nbrick[row+1][bricknum-1] != -1) { makeExplosive(bricks[nbrick[row+1][bricknum-1]]); } } if(row < 22 && bricknum < 25) { if(nbrick[row+1][bricknum+1] != -1) { makeExplosive(bricks[nbrick[row+1][bricknum+1]]); } } } void breakable() { if(type == '3') { score=300; hitsLeft=1; type='1'; //hehe.. tex.frame=2; tex.play(); } else if(type=='4') { hitsLeft=1; tex.frame=2; tex.play(); } else if(type=='9') { hitsLeft=1; tex.frame=3; tex.play(); } } }; void makeExplosive(brick & b) { if(b.type != 'B') { b.type='B'; b.tex=*texExplosiveBrick; //NOTE: for some reason, the color of the object was changed, why?? b.justBecomeExplosive=1; } } #include "loadlevel.cpp" class moving_object : public object { public: GLfloat xvel,yvel,velocity; moving_object () { xvel=0.0; yvel=0.0; } }; #include "effects.cpp" #include "background.cpp" void spawnpowerup(char powerup, pos a, pos b); class bulletsClass { private: moving_object bullets[16]; public: int active; bulletsClass(textureClass & texBullet) { int i; for(i=0; i < 16; i++) { bullets[i].active=0; bullets[i].tex = texBullet; bullets[i].width = 0.02; bullets[i].height = 0.02; } } void shoot(pos p) { int i; //Find ledig bullet for(i=0; i < 16; i++) { if(!bullets[i].active) { soundMan.add(SND_SHOT, p.x); bullets[i].active=1; bullets[i].posx = p.x; bullets[i].posy = p.y; bullets[i].xvel =0; bullets[i].yvel =1.0; break; } } } void move() { int i; for(i=0; i < 16; i++) { if(bullets[i].active) { //Flyt bullets[i].posy += bullets[i].yvel * globalMilliTicks; } } } void draw() { int i; glColor4f(1,1,1,1); for(i=0; i < 16; i++) { if(bullets[i].active) { //draw bullets[i].tex.play(); glLoadIdentity(); glTranslatef( bullets[i].posx, bullets[i].posy, -3.0 ); glBindTexture(GL_TEXTURE_2D, bullets[i].tex.prop.texture); glBegin( GL_QUADS ); glTexCoord2f(bullets[i].tex.pos[0],bullets[i].tex.pos[1]); glVertex3f( -bullets[i].width, bullets[i].height, 0.0 ); glTexCoord2f(bullets[i].tex.pos[2],bullets[i].tex.pos[3]); glVertex3f( bullets[i].width, bullets[i].height, 0.0 ); glTexCoord2f(bullets[i].tex.pos[4],bullets[i].tex.pos[5]); glVertex3f( bullets[i].width,-bullets[i].height, 0.0 ); glTexCoord2f(bullets[i].tex.pos[6],bullets[i].tex.pos[7]); glVertex3f( -bullets[i].width,-bullets[i].height, 0.0 ); glEnd( ); } } } void clear() { int i; for(i=0; i < 16; i++) { bullets[i].active=0; } } void coldet(brick & b, effectManager & fxMan) { int i; bool hit; pos v,p; v.x=0; v.y=bullets[0].xvel; for(i=0; i < 16; i++) { if(bullets[i].active) { hit=0; //y 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) { p.x = b.posx; p.y = b.posy; //Venstre side: if(bullets[i].posx > b.posx-b.width && bullets[i].posx < b.posx+b.width) { hit=1; } if(hit) { b.hit(fxMan, p, v,1); if(!player.powerup[PO_THRU]) { bullets[i].active=0; } p.x = bullets[i].posx; p.y = bullets[i].posy; if(setting.eyeCandy) { fxMan.set(FX_VAR_TYPE, FX_SPARKS); fxMan.set(FX_VAR_COLDET,1); fxMan.set(FX_VAR_LIFE, 1000); fxMan.set(FX_VAR_NUM, 16); fxMan.set(FX_VAR_SIZE, 0.015f); fxMan.set(FX_VAR_SPEED, 0.4f); fxMan.set(FX_VAR_GRAVITY, 1.0f); fxMan.set(FX_VAR_COLOR, 1.0f, 0.7f, 0.0f); fxMan.spawn(p); fxMan.set(FX_VAR_COLOR, 1.0f, 0.8f, 0.0f); fxMan.spawn(p); fxMan.set(FX_VAR_COLOR, 1.0f, 0.9f, 0.0f); fxMan.spawn(p); fxMan.set(FX_VAR_COLOR, 1.0f, 1.0f, 0.0f); fxMan.spawn(p); } } } else if(bullets[i].posy > 1.6) { bullets[i].active=0; } } } } }; void brick::hit(effectManager & fxMan, pos poSpawnPos, pos poSpawnVel, bool ballHitMe) { pos p,s; if(type!='3' || player.powerup[PO_THRU]) hitsLeft--; //We don't want to play a sound if this brick is not an explosive, and was hit by an explosion if(ballHitMe || type=='B') { if(type=='3') //cement { soundMan.add(SND_CEMENT_BRICK_HIT, posx); } else if(type=='4' || type=='9') //glass or invisible { if(hitsLeft == 2) { soundMan.add(SND_INVISIBLE_BRICK_APPEAR, posx); } else if(hitsLeft == 1) { soundMan.add(SND_GLASS_BRICK_HIT, posx); } else { soundMan.add(SND_GLASS_BRICK_BREAK, posx); } } else if(type=='B') //explosive { soundMan.add(SND_EXPL_BRICK_BREAK, posx); } else if(type=='C') //Doom brick { soundMan.add(SND_DOOM_BRICK_BREAK, posx); } else { //All the other bricks soundMan.add(SND_NORM_BRICK_BREAK, posx); } } if(type != '3' || player.powerup[PO_THRU]) { //Brick was hit, dont do anything if(isdyingnormally || isexploding) { return; } player.score += (brick::score*player.multiply)* var.averageBallSpeed; //Speed bonus if(hitsLeft < 1 || type == 'B') //Hvis brikken er explosiv kan den ikke have nogle hits tilbage { collide=0; updated_nbrick[row][bricknum]=-1; var.bricksHit = 1; gVar.deadTime=0; spawnpowerup(powerup, poSpawnPos, poSpawnVel); powerup='0'; if(setting.eyeCandy) { p.x=posx; p.y=posy; s.x=width*2; s.y=height*2; fxMan.set(FX_VAR_TYPE, FX_PARTICLEFIELD); fxMan.set(FX_VAR_COLDET, 1); fxMan.set(FX_VAR_LIFE, 1000); fxMan.set(FX_VAR_NUM, 20); fxMan.set(FX_VAR_SIZE, 0.03f); fxMan.set(FX_VAR_SPEED, 0.6f); fxMan.set(FX_VAR_GRAVITY, 0.7f); fxMan.set(FX_VAR_RECTANGLE, s); fxMan.set(FX_VAR_COLOR, tex.prop.glParColorInfo[0],tex.prop.glParColorInfo[1],tex.prop.glParColorInfo[2]); fxMan.spawn(p); } if(type=='B') { isexploding=1; if(setting.eyeCandy) { p.x = posx; p.y = posy; fxMan.set(FX_VAR_TYPE, FX_PARTICLEFIELD); fxMan.set(FX_VAR_COLDET,1); fxMan.set(FX_VAR_LIFE, 1200); fxMan.set(FX_VAR_NUM, 10); fxMan.set(FX_VAR_SIZE, 0.08f); fxMan.set(FX_VAR_SPEED, 0.4f); fxMan.set(FX_VAR_GRAVITY, -1.3f); fxMan.set(FX_VAR_COLOR, 1.0f, 0.7f, 0.0f); fxMan.spawn(p); fxMan.set(FX_VAR_COLOR, 1.0f, 0.8f, 0.0f); fxMan.spawn(p); fxMan.set(FX_VAR_COLOR, 1.0f, 0.9f, 0.0f); fxMan.spawn(p); fxMan.set(FX_VAR_COLOR, 1.0f, 1.0f, 0.0f); fxMan.spawn(p); } } else { isdyingnormally=1; } } else { //No hits left tex.frame++; tex.play(); } //Hits left } } glAnnounceTextClass announce; //Slet mig måske float abs2(float x) { if (x<0) {return -x;} return x; } int LinesCross(float x0,float y0,float x1,float y1,float x2,float y2,float x3,float y3, GLfloat *linx, GLfloat *liny) { float d=(x1-x0)*(y3-y2)-(y1-y0)*(x3-x2); if (abs2(d)<0.001f) {return -1;} float AB=((y0-y2)*(x3-x2)-(x0-x2)*(y3-y2))/d; if (AB>0.0 && AB<1.0) { float CD=((y0-y2)*(x1-x0)-(x0-x2)*(y1-y0))/d; if (CD>0.0 && CD<1.0) { *linx=x0+AB*(x1-x0); *liny=y0+AB*(y1-y0); return 1; } } return 0; } //Leaves an trail of the ball class tracer { private: GLfloat x[100], y[100], r[100], g[100], b[100], a[100],s[100], cr,cg,cb,; bool active[100]; int color; GLfloat lastX, lastY; //Last position where we spawned one public: GLfloat height, width; // GLuint texture; textureClass *tex; int len; void draw() { int i; for(i=0; i < len; i++) { if(active[i]) { a[i] -= 4.0*globalMilliTicksSinceLastDraw; s[i] += 4.0*globalMilliTicksSinceLastDraw; if(a[i] < 0.0) active[i]=0; tex->play(); glBindTexture(GL_TEXTURE_2D, tex->prop.texture); glLoadIdentity(); glTranslatef(x[i],y[i],-3.0); glColor4f(r[i], g[i], b[i], a[i]); glBegin( GL_QUADS ); glTexCoord2f(tex->pos[0],tex->pos[1]);glVertex3f( -width*s[i], height*s[i], 0.00 ); // øverst venst glTexCoord2f(tex->pos[2],tex->pos[3]);glVertex3f( width*s[i], height*s[i], 0.00 ); // øverst højre glTexCoord2f(tex->pos[4],tex->pos[5]);glVertex3f( width*s[i],-height*s[i], 0.00 ); // nederst højre glTexCoord2f(tex->pos[6],tex->pos[7]);glVertex3f( -width*s[i],-height*s[i], 0.00 ); // nederst venstre glEnd( ); } } } void colorRotate(bool explosive, GLfloat c[]) { color++; if(color > 5) color=0; if(!explosive) { cr=c[0]; cg=c[1]; cb=c[2]; } else { cr=1.0; cg=0.6; cb=0.0; } } tracer() { len=100; lastX=0; lastY=0; cr=1; cg=0; cb=0; height = 0.01; width = 0.01; int i; for(i=0; i < 100; i++) { active[i]=0; } } void update(GLfloat nx, GLfloat ny) { //If long enough away GLfloat dist = sqrt( pow(nx-lastX, 2) + pow(ny-lastY, 2) ); if(dist > 0.01) { lastX = nx; lastY = ny; //find a non-active trail-part int i; for(i=0; i < len; i++) { if(!active[i]) { active[i]=1; a[i]=1.0; //tweak me x[i]=nx; y[i]=ny; s[i]=1.0; r[i]=cr; g[i]=cg; b[i]=cb; break; } } } } }; class ball : public moving_object { private: GLfloat rad; bool growing,shrinking; GLfloat destwidth, growspeed; public: tracer tail; bool explosive; //Makes brick explosive (to get a explosion effect) and explode it bool glued; //Sidder vi fast på padden for øjeblikket? GLfloat gluedX; //Variabler med forududregnede værdier GLfloat bsin[32], bcos[32]; bool aimdir; textureClass fireTex; GLfloat lastX,lastY; ball() { growing=0; growspeed=0.1; width=0.0; height=0.0; glued=0; posx=0.0f; posy=0.0f; aimdir=0; } void hit(GLfloat c[]) { if(setting.eyeCandy) tail.colorRotate(explosive, c); } void move() { //vi laver lige den her coldet her... if(posx+width > 1.6 && xvel > 0.0) { soundMan.add(SND_BALL_HIT_BORDER, posx); xvel *= -1; } else if(posx-width < -1.6 && xvel < 0.0) { soundMan.add(SND_BALL_HIT_BORDER, posx); xvel *= -1; } else if(posy+width > 1.25 && yvel > 0.0) { soundMan.add(SND_BALL_HIT_BORDER, posx); yvel *= -1; } else if(posy-width < -1.24) { active=0; } posx +=xvel*globalMilliTicks; if(!glued) { posy +=yvel*globalMilliTicks; } else { gVar.deadTime = 0; } if(setting.eyeCandy) tail.update(posx,posy); } void draw(paddle_class &paddle) { GLfloat newsize; if(setting.eyeCandy) tail.draw(); if(growing) { newsize = growspeed * globalMilliTicksSinceLastDraw; width += newsize; height += newsize; if(width >= destwidth) { width=destwidth; height=destwidth; growing=0; } tail.width = width; tail.height = height; } else if(shrinking) { newsize = growspeed * globalMilliTicksSinceLastDraw; width -= newsize; height -= newsize; if(width <= destwidth) { width=destwidth; height=destwidth; shrinking=0; } tail.width = width; tail.height = height; } if(glued && player.powerup[PO_LASER]) { if(player.powerup[PO_AIM]) { if(aimdir==0) { rad -= 1.2*globalMilliTicksSinceLastDraw; if(rad < BALL_MIN_DEGREE) aimdir=1; } else { rad += 1.2*globalMilliTicksSinceLastDraw; if(rad > BALL_MAX_DEGREE+BALL_MIN_DEGREE) aimdir=0; } setangle(rad); } else { getRad(); } GLfloat bxb = cos(rad)*0.5, byb = sin(rad)*0.5; glLoadIdentity(); glTranslatef( posx, posy, -3.0); glDisable(GL_TEXTURE_2D); glLineWidth ( 1.0 ); glEnable( GL_LINE_SMOOTH ); glBegin( GL_LINES ); glColor4f(rndflt(2,0), rndflt(1,0), 0.0, 0.0); glVertex3f( 0.0, 0.0, 0.0 ); glColor4f(rndflt(2,0), 0.0, 0.0, 1.0); glVertex3f( bxb, byb, 0.0 ); glEnd(); glPointSize( 5.0f ); glColor4f(1.0, 0.0, 0.0, 1.0); glEnable(GL_POINT_SMOOTH); glBegin( GL_POINTS ); glVertex3f(bxb, byb, 0.0); glEnd( ); } if(!glued && player.powerup[PO_AIMHELP]) { //Use line intersect to determine if this ball will collide with the paddle getRad(); GLfloat p[4], b[4], o[2]; //Paddle line, ball line, bounceoff endpoint p[0] = paddle.posx - paddle.width; p[1] = paddle.posx + paddle.width; p[2] = paddle.posy + paddle.height + height; p[3] = paddle.posy + paddle.height + height; b[0] = posx; b[1] = posx + (cos(rad) * 3.0); b[2] = posy; b[3] = posy + (sin(rad) * 3.0); GLfloat cx,cy, R; if(LinesCross(p[0], p[2], p[1],p[3], b[0], b[2], b[1], b[3], &cx, &cy)) { R = bounceOffAngle(paddle.width, paddle.posx, cx); o[0] = cx+(cos(R)*2.0); o[1] = cy+(sin(R)*2.0); glLoadIdentity(); glTranslatef( 0.0, 0.0, -3.0); glDisable(GL_TEXTURE_2D); glLineWidth ( 2.0 ); glEnable( GL_LINE_SMOOTH ); glBegin( GL_LINE_STRIP ); //Line from ball to paddle glColor4f(1.0, 0.0, 0.0, 0.0); glVertex3f( b[0], b[2], 0.0 ); glColor4f(1.0, 1.0, 0.0, 1.0); glVertex3f( cx, cy, 0.0 ); //Bounce off line. glColor4f(1.0, 0.0, 0.0, 0.0); glVertex3f( o[0], o[1], 0.0 ); glEnd( ); } } glLoadIdentity(); glTranslatef( posx, posy, -3.0); glEnable(GL_TEXTURE_2D); glColor4f(1.0, 1.0, 1.0, 1.0); if(explosive) { fireTex.play(); glBindTexture(GL_TEXTURE_2D, fireTex.prop.texture); glColor4f( fireTex.prop.glTexColorInfo[0], fireTex.prop.glTexColorInfo[1], fireTex.prop.glTexColorInfo[2], fireTex.prop.glTexColorInfo[3] ); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBegin( GL_QUADS ); glTexCoord2f(fireTex.pos[0],fireTex.pos[1]); glVertex3f( -width, height, 0.0 ); glTexCoord2f(fireTex.pos[2],fireTex.pos[3]); glVertex3f( width, height, 0.0 ); glTexCoord2f(fireTex.pos[4],fireTex.pos[5]); glVertex3f( width,-height, 0.0 ); glTexCoord2f(fireTex.pos[6],fireTex.pos[7]); glVertex3f( -width,-height, 0.0 ); glEnd( ); } else { tex.play(); glBindTexture(GL_TEXTURE_2D, tex.prop.texture); glColor4f( tex.prop.glTexColorInfo[0], tex.prop.glTexColorInfo[1], tex.prop.glTexColorInfo[2], tex.prop.glTexColorInfo[3] ); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBegin( GL_QUADS ); glTexCoord2f(tex.pos[0],tex.pos[1]); glVertex3f( -width, height, 0.0 ); glTexCoord2f(tex.pos[2],tex.pos[3]); glVertex3f( width, height, 0.0 ); glTexCoord2f(tex.pos[4],tex.pos[5]); glVertex3f( width,-height, 0.0 ); glTexCoord2f(tex.pos[6],tex.pos[7]); glVertex3f( -width,-height, 0.0 ); glEnd( ); } #ifdef DEBUG_DRAW_BALL_QUAD glLoadIdentity(); glTranslatef(posx, posy, -3.0); glDisable( GL_TEXTURE_2D ); glColor4f(1.0,1.0,1.0,1.0); glBegin( GL_LINES ); glVertex3f( -width, height, 0); glVertex3f( width, height, 0); glVertex3f( -width, -height, 0); glVertex3f( width, -height,0); glVertex3f( -width, height, 0); glVertex3f( -width, -height, 0); glVertex3f( width, height, 0); glVertex3f( width, -height, 0 ); glEnd(); glEnable(GL_TEXTURE_2D); #endif } GLfloat getRad() { rad = atan2(yvel,xvel); return(rad); } void setangle(GLfloat o) { if(o < BALL_MIN_DEGREE) { o=BALL_MIN_DEGREE; } if( o > BALL_MAX_DEGREE + BALL_MIN_DEGREE) { o=BALL_MAX_DEGREE + BALL_MIN_DEGREE; } rad=o; xvel = velocity * cos(rad); yvel = velocity * sin(rad); } void setspeed(GLfloat v) { if(v > difficulty.maxballspeed[player.difficulty]) { velocity = difficulty.maxballspeed[player.difficulty]; } else { velocity = v; } getRad(); xvel = velocity * cos(rad); yvel = velocity * sin(rad); } void setSize(GLfloat s) { float rad; if(s > width) growing=1; else if(s < width) shrinking=1; destwidth=s; int i=0; //opdater points for(rad=0.0; rad < 6.3; rad +=0.2) { if(i < 32) { bsin[i] = sin(rad)*s; bcos[i] = cos(rad)*s; } i++; } } }; void coldet(brick & br, ball & ba, pos & p, effectManager & fxMan); void padcoldet(ball & b, paddle_class & p, pos & po); #define MAXBALLS 16 class ballManager { public: int activeBalls; ball b[MAXBALLS]; textureClass tex[3]; void initBalls() { activeBalls=0; clear(); } ballManager(textureClass btex[]) { int i; tex[0] = btex[0]; tex[1] = btex[1]; tex[2] = btex[2]; for(i=0; i < MAXBALLS; i++) { b[i].tex=tex[0]; b[i].fireTex=tex[1]; b[i].tail.tex = &tex[2]; } initBalls(); } void getSpeed() { int i; var.averageBallSpeed = 0.0; for(i=0; i < MAXBALLS; i++) { if(b[i].active) { var.averageBallSpeed += b[i].velocity; } } var.averageBallSpeed /= activeBalls; } //klon alle aktive bolde void multiply() { pos op; int a=0,c=0; int i; //How many balls are active? for(i=0; i < MAXBALLS; i++) { if(b[i].active) { a++; } } for(i=0; i < MAXBALLS; i++) { if(b[i].active && c != a) { c++; op.y = b[i].posy; op.x = b[i].posx; spawn(op,0,0.0f,b[i].velocity, rndflt( BALL_MAX_DEGREE+BALL_MIN_DEGREE,0)); } } } void unglue() { int i; for(i=0; i < MAXBALLS; i++) { b[i].glued=0; } } void spawn(pos p, bool glued, GLfloat gx ,GLfloat speed, GLfloat angle) { int i; for(i=0; i < MAXBALLS; i++) { if(!b[i].active) { activeBalls++; b[i].tex = tex[0]; b[i].fireTex = tex[1]; b[i].glued=glued; b[i].width=0.0; b[i].height=0.0; b[i].gluedX=gx; b[i].active=1; b[i].collide=1; b[i].reflect=1; b[i].lastX = p.x; b[i].lastY = p.y; b[i].posx = p.x; b[i].posy = p.y; b[i].explosive=0; b[i].setspeed(speed); b[i].setangle(angle); b[i].setSize(0.025); //New balls get already applied powerups if not hard if(player.difficulty < HARD) { b[i].explosive = player.powerup[PO_EXPLOSIVE]; if(player.powerup[PO_SMALLBALL]) { powerup(PO_SMALLBALL); } if(player.powerup[PO_BIGBALL]) { powerup(PO_BIGBALL); } } getSpeed(); break; } } } void clear() { int i; activeBalls=0; for(i=0; i < MAXBALLS; i++) { b[i].active=0; } getSpeed(); } void move() { int a=0; int i; for(i=0; i < MAXBALLS; i++) { if(b[i].active) { b[i].move(); a++; } } activeBalls=a; } void draw(paddle_class &paddle) { int i; for(i=0; i < MAXBALLS; i++) { if(b[i].active) { b[i].draw(paddle); } } } void bcoldet(brick & bri,effectManager & fxMan) { int i; pos p; for(i=0; i < MAXBALLS; i++) { if(b[i].active) { p.x=100; coldet(bri, b[i], p, fxMan); if(p.x < 50) //we totally hit?? :P { getSpeed(); if(setting.eyeCandy) { //spawn partikler fxMan.set(FX_VAR_TYPE, FX_SPARKS); fxMan.set(FX_VAR_COLDET,1); fxMan.set(FX_VAR_SPEED, 1.0f); fxMan.set(FX_VAR_LIFE, 1500); fxMan.set(FX_VAR_NUM, 16); fxMan.set(FX_VAR_SIZE, 0.015f); fxMan.set(FX_VAR_COLOR, 1.0,1.0,0.8); fxMan.spawn(p); } } } } } int pcoldet(paddle_class & paddle,effectManager & fxMan) { int i, hits=0; pos p; for(i=0; i < MAXBALLS; i++) { if(b[i].active) { if(b[i].glued) b[i].posx=paddle.posx+paddle.width-b[i].gluedX; p.x=100; padcoldet(b[i], paddle, p); if(p.x < 50) { hits++; getSpeed(); if(player.powerup[PO_GLUE]) { soundMan.add(SND_GLUE_BALL_HIT_PADDLE, p.x); } else { soundMan.add(SND_BALL_HIT_PADDLE, p.x); } if(setting.eyeCandy) { //spawn partikler fxMan.set(FX_VAR_TYPE, FX_SPARKS); fxMan.set(FX_VAR_LIFE, 2000); fxMan.set(FX_VAR_GRAVITY, 0.6f); fxMan.set(FX_VAR_NUM, 16); fxMan.set(FX_VAR_COLDET,1); fxMan.set(FX_VAR_SIZE, 0.01f); fxMan.set(FX_VAR_COLOR, 1.0,1.0,0.8); p.y = paddle.posy+paddle.height; fxMan.set(FX_VAR_SPEED, 0.5f); fxMan.spawn(p); } //eyecandy } // if col } //if active } //for loop return(hits); } //pcoldet void updatelast() { int i; for(i=0; i < MAXBALLS; i++) { if(b[i].active) { b[i].lastX=b[i].posx; b[i].lastY=b[i].posy; } } } void powerup(int powerup) { int i; for(i=0; i < MAXBALLS; i++) { if(b[i].active) { switch(powerup) { case PO_BIGBALL: //big balls b[i].setSize(0.04); b[i].setspeed(difficulty.ballspeed[player.difficulty]); break; case PO_SMALLBALL: //small balls b[i].setSize(0.015); //speed bolden op b[i].setspeed( b[i].velocity + ((b[i].velocity/100.f)*difficulty.speedup[player.difficulty]) ); break; case PO_NORMALBALL: // normal balls b[i].setSize(0.025); b[i].setspeed(difficulty.ballspeed[player.difficulty]); break; case PO_EXPLOSIVE: //exploderer brikker b[i].explosive=1; b[i].tail.colorRotate(TRUE, 0 ); break; } } } } }; float bounceOffAngle(GLfloat width, GLfloat posx, GLfloat hitx) { return ( (BALL_MAX_DEGREE/(width*2.0))*(posx+width-hitx) + BALL_MIN_DEGREE ); } class powerupClass : public moving_object { public: int score; int type; int level, maxlevel; GLfloat gravity; powerupClass() { posx=0.0; posy=0.0; xvel=0.0; yvel=0.0; width=0.055; height=0.055; } void move() { //grav yvel -= gravity*globalMilliTicks; //cout << yvel << endl; posx +=xvel*globalMilliTicks; posy +=yvel*globalMilliTicks; } bool coldet(paddle_class & p, effectManager & fxMan, ballManager & bMan) { bool col=0; if(posx+width > 1.6 && xvel > 0.0) { col=1; xvel *= -1; } else if(posx-width < -1.6 && xvel < 0.0) { col=1; xvel *= -1; } else if(posy+width > 1.25 && yvel > 0.0) { col=1; yvel *= -1; } else if(posy-width < -1.24) { active=0; } if(col) { soundMan.add(SND_PO_HIT_BORDER, posx); } //idiotisk lavet... bool ycol=0; bool xcol=0; pos fxpos, fxSize; //En side if(posx+width > p.posx-p.width && posx+width < p.posx+p.width) { xcol=1; } if(posx-width > p.posx-p.width && posx-width < p.posx+p.width) { xcol=1; } if(posy-height < p.posy+p.height && posy-height > p.posy-p.height) { ycol=1; } if(posy+height < p.posy+p.height && posy+height > p.posy-p.height) { ycol=1; } if(xcol && ycol) { if(setting.eyeCandy) { fxpos.x = posx; fxpos.y = posy; fxSize.x=width; fxSize.y=height; fxMan.set(FX_VAR_TYPE, FX_PARTICLEFIELD); fxMan.set(FX_VAR_COLDET,1); fxMan.set(FX_VAR_SPEED, yvel/1.5f); fxMan.set(FX_VAR_LIFE, 1500); fxMan.set(FX_VAR_GRAVITY, 0.7f); fxMan.set(FX_VAR_NUM, 20); fxMan.set(FX_VAR_SIZE, 0.03f); fxMan.set(FX_VAR_RECTANGLE, fxSize); fxMan.set(FX_VAR_COLOR, tex.prop.glParColorInfo[0],tex.prop.glParColorInfo[1],tex.prop.glParColorInfo[2]); fxMan.spawn(fxpos); } active=0; //Score player.score += score*player.multiply; //Apply powerup: switch(type) { case PO_COIN: player.coins += 1000; soundMan.add(SND_GOOD_PO_HIT_PADDLE, posx); break; case PO_GLUE: player.coins += 150; player.powerup[PO_GLUE] = 1; soundMan.add(SND_GOOD_PO_HIT_PADDLE, posx); break; case PO_BIGBALL: player.coins += 30; bMan.powerup(PO_BIGBALL); player.powerup[PO_BIGBALL]=1; player.powerup[PO_NORMALBALL]=0; player.powerup[PO_SMALLBALL]=0; soundMan.add(SND_GOOD_PO_HIT_PADDLE, posx); break; case PO_NORMALBALL: player.coins += 50; bMan.powerup(PO_NORMALBALL); player.powerup[PO_NORMALBALL]=1; player.powerup[PO_BIGBALL]=0; player.powerup[PO_SMALLBALL]=0; soundMan.add(SND_GOOD_PO_HIT_PADDLE, posx); break; case PO_SMALLBALL: player.coins += 10; bMan.powerup(PO_SMALLBALL); player.powerup[PO_SMALLBALL]=1; player.powerup[PO_BIGBALL]=0; player.powerup[PO_NORMALBALL]=0; soundMan.add(SND_EVIL_PO_HIT_PADDLE, posx); break; case PO_MULTIBALL: player.coins += 100; bMan.multiply(); soundMan.add(SND_GOOD_PO_HIT_PADDLE, posx); break; case PO_AIM: player.coins += 50; if(player.difficulty==0) { player.powerup[PO_GLUE]=1; } if(!player.powerup[PO_AIM]) { player.powerup[PO_AIM]=1; player.powerup[PO_LASER]=1; } else { player.powerup[PO_GLUE]=1; } soundMan.add(SND_GOOD_PO_HIT_PADDLE, posx); break; case PO_GROWPADDLE: player.coins += 100; if(p.width < 0.4) p.grow(p.width+0.03); soundMan.add(SND_GOOD_PO_HIT_PADDLE, posx); break; case PO_SHRINKPADDLE: player.coins += 10; if(p.width > 0.02) p.grow(p.width-0.02); soundMan.add(SND_EVIL_PO_HIT_PADDLE, posx); break; case PO_EXPLOSIVE: player.coins += 150; bMan.powerup(PO_EXPLOSIVE); player.powerup[PO_EXPLOSIVE]=1; soundMan.add(SND_GOOD_PO_HIT_PADDLE, posx); break; case PO_GUN: player.coins += 200; player.powerup[PO_GUN]=1; soundMan.add(SND_GOOD_PO_HIT_PADDLE, posx); break; case PO_THRU: player.coins += 300; player.powerup[PO_THRU]=1; soundMan.add(SND_GOOD_PO_HIT_PADDLE, posx); break; case PO_LASER: player.coins += 40; player.powerup[PO_LASER]=1; soundMan.add(SND_GOOD_PO_HIT_PADDLE, posx); break; case PO_LIFE: player.coins += 400; player.lives++; soundMan.add(SND_GOOD_PO_HIT_PADDLE, posx); break; case PO_DIE: player.coins += 1; player.explodePaddle=1; player.powerup[PO_DIE]=1; //NOTE: no sound here, SND_DIE is played when paddle dissapers break; case PO_DROP: player.coins += 1; player.powerup[PO_DROP]=1; soundMan.add(SND_EVIL_PO_HIT_PADDLE, posx); break; case PO_DETONATE: player.coins += 200; player.powerup[PO_DETONATE]=1; soundMan.add(SND_GOOD_PO_HIT_PADDLE, posx); break; case PO_EXPLOSIVE_GROW: player.coins += 100; player.powerup[PO_EXPLOSIVE_GROW]=1; soundMan.add(SND_GOOD_PO_HIT_PADDLE, posx); break; case PO_EASYBRICK: player.coins += 90; player.powerup[PO_EASYBRICK]=1; soundMan.add(SND_GOOD_PO_HIT_PADDLE, posx); break; case PO_NEXTLEVEL: player.coins += 100; player.powerup[PO_NEXTLEVEL]=1; //NOTE: no sound here, SND_NEXTLEVEL is played when changing level break; case PO_AIMHELP: player.coins += 50; player.powerup[PO_AIMHELP]=1; soundMan.add(SND_GOOD_PO_HIT_PADDLE, posx); break; } return(1); } return(0); } void die(effectManager & fxMan) { active=0; if(setting.eyeCandy) { struct pos p; p.x = posx; p.y = posy; fxMan.set(FX_VAR_TYPE, FX_SPARKS); fxMan.set(FX_VAR_COLDET,1); fxMan.set(FX_VAR_LIFE, 1000); fxMan.set(FX_VAR_NUM, 16); fxMan.set(FX_VAR_SPEED, 0.8f); fxMan.set(FX_VAR_GRAVITY, 0.6f); fxMan.set(FX_VAR_SIZE, 0.025f); fxMan.set(FX_VAR_COLOR, tex.prop.glParColorInfo[0],tex.prop.glParColorInfo[1],tex.prop.glParColorInfo[2]); fxMan.spawn(p); fxMan.set(FX_VAR_SPEED, 0.4f); fxMan.set(FX_VAR_SIZE, 0.05f); fxMan.set(FX_VAR_GRAVITY, -1.0f); fxMan.set(FX_VAR_COLOR, 1.0f, 0.7f, 0.0f); fxMan.spawn(p); fxMan.set(FX_VAR_COLOR, 1.0f, 0.8f, 0.0f); fxMan.spawn(p); fxMan.set(FX_VAR_COLOR, 1.0f, 0.9f, 0.0f); fxMan.spawn(p); fxMan.set(FX_VAR_COLOR, 1.0f, 1.0f, 0.0f); fxMan.spawn(p); } } void draw() { tex.play(); glBindTexture( GL_TEXTURE_2D, tex.prop.texture); glColor4f(tex.prop.glTexColorInfo[0],tex.prop.glTexColorInfo[1],tex.prop.glTexColorInfo[2],tex.prop.glTexColorInfo[3]); glLoadIdentity(); glTranslatef( posx, posy, -3.0f); glBegin( GL_QUADS ); glTexCoord2f(tex.pos[0],tex.pos[1]);glVertex3f( -width, height, 0.00 ); // øverst venst glTexCoord2f(tex.pos[2],tex.pos[3]);glVertex3f( width, height, 0.00 ); // øverst højre glTexCoord2f(tex.pos[4],tex.pos[5]);glVertex3f( width,-height, 0.00 ); // nederst højre glTexCoord2f(tex.pos[6],tex.pos[7]);glVertex3f( -width,-height, 0.00 ); // nederst venstre glEnd( ); } }; #define MAXPOWERUPS 64 class powerupManager { private: int i; powerupClass p[MAXPOWERUPS]; textureClass* tex; public: void init(textureClass texPowerup[]) { tex = new textureClass[40]; tex = texPowerup; } powerupManager() { clear(); } void clear() { for(i=0; i < MAXPOWERUPS; i++) { p[i].active=0; } } void die(effectManager & fxMan) { for(i=0; i < MAXPOWERUPS; i++) { if(p[i].active) { p[i].die(fxMan); } } } void spawn(pos spawnpos, pos velocity, int type) { for(i=0; i < MAXPOWERUPS; i++) { if(!p[i].active) { p[i].gravity = 0.7; p[i].type = type; p[i].posx = spawnpos.x; p[i].posy = spawnpos.y; p[i].xvel = velocity.x*-1; p[i].yvel = velocity.y*-1; p[i].active=1; //Give texture that this type has. p[i].tex = tex[type]; //FIXME: rewrite as a switch //Set colors and score if(type==PO_GLUE) { p[i].score = 500; } if(type==PO_MULTIBALL) { p[i].score = 500; } if(type==PO_BIGBALL) { p[i].score = 300; } if(type==PO_NORMALBALL) { p[i].score = 400; } if(type==PO_SMALLBALL) { p[i].score = 100; } if(type==PO_AIM) { p[i].score = 1600; } if(type==PO_GROWPADDLE) { p[i].score = 500; } if(type==PO_SHRINKPADDLE) { p[i].score = -1000; } if(type==PO_EXPLOSIVE) { p[i].score = 1400; } if(type==PO_GUN) { p[i].score = 1800; } if(type==PO_THRU) { p[i].score = 1000; } if(type==PO_LASER) { p[i].score = 500; } if(type==PO_LIFE) { p[i].score = 1000; } if(type==PO_DIE) { p[i].score = -1000; } if(type==PO_DROP) { p[i].score = -1000; } if(type==PO_DETONATE) { p[i].score = 1000; } if(type==PO_EXPLOSIVE_GROW) { p[i].score = 1000; } if(type==PO_EASYBRICK) { p[i].score = 1000; } if(type==PO_NEXTLEVEL) { p[i].score = 1000; } if(type==PO_AIMHELP) { p[i].score = 1000; } break; //Whats this doing? } } } int coldet(paddle_class & paddle, effectManager & fxMan, ballManager & bMan) { int hits=0; for(i=0; i < MAXPOWERUPS; i++) { if(p[i].active) { if(p[i].coldet(paddle, fxMan, bMan)) { hits++; } } } return(hits); } void move() { for(i=0; i < MAXPOWERUPS; i++) { if(p[i].active) { p[i].move(); } } } void draw() { for(i=0; i < MAXPOWERUPS; i++) { if(p[i].active) { p[i].draw(); } } } }; powerupManager pMan; void spawnpowerup(char powerup, pos a, pos b) { if(powerup == '1') { pMan.spawn(a,b,PO_GROWPADDLE); } if(powerup == '2') { pMan.spawn(a,b,PO_SHRINKPADDLE); } if(powerup == '3') { pMan.spawn(a,b,PO_DIE); } if(powerup == '4') { pMan.spawn(a,b,PO_GLUE); } if(powerup == 'A') { pMan.spawn(a,b,PO_EASYBRICK); } if(powerup == 'B') { pMan.spawn(a,b,PO_EXPLOSIVE); } if(powerup == 'C') { pMan.spawn(a,b,PO_NEXTLEVEL); } if(powerup == 'D') { pMan.spawn(a,b,PO_AIMHELP); } if(powerup == 'E') { pMan.spawn(a,b,PO_COIN); } if(powerup == '5') { pMan.spawn(a,b,PO_MULTIBALL); } if(powerup == '6') { pMan.spawn(a,b,PO_THRU); } if(powerup == '7') { pMan.spawn(a,b,PO_DROP); } if(powerup == '8') { pMan.spawn(a,b,PO_DETONATE); } if(powerup == '9') { pMan.spawn(a,b,PO_EXPLOSIVE_GROW); } if(powerup == 'F') { pMan.spawn(a,b,PO_BIGBALL); } if(powerup == 'G') { pMan.spawn(a,b,PO_NORMALBALL); } if(powerup == 'H') { pMan.spawn(a,b,PO_SMALLBALL); } if(powerup == 'I') { pMan.spawn(a,b,PO_AIM); } if(powerup == 'P') { pMan.spawn(a,b,PO_GUN); } if(powerup == 'R') { pMan.spawn(a,b,PO_LASER); } if(powerup == 'O') { pMan.spawn(a,b,PO_LIFE); } } SDL_Surface *screen = NULL; /* function to reset our viewport after a window resize */ void resizeWindow( int width, int height ) { /* Height / width ration */ GLfloat ratio; /* Protect against a divide by zero */ if ( height == 0 ) height = 1; ratio = ( GLfloat )width / ( GLfloat )height; var.glunits_per_xpixel = (2.485281374*ratio) / setting.resx; var.glunits_per_ypixel = 2.485281374 / setting.resy; /* Setup our viewport. */ glViewport( 0, 0, ( GLsizei )width, ( GLsizei )height ); /* change to the projection matrix and set our viewing volume. */ glMatrixMode( GL_PROJECTION ); glLoadIdentity( ); /* Set our perspective */ gluPerspective( 45.0f, ratio, 0.1f, 10.0f ); /* Make sure we're chaning the model view and not the projection */ glMatrixMode( GL_MODELVIEW ); /* Reset The View */ glLoadIdentity(); } void initGL() { // printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER)); // printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION)); // printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR)); //printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS)); /* Enable smooth shading */ glShadeModel( GL_SMOOTH ); /* Set the background black */ glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); /* Depth buffer setup */ glClearDepth( 1.0f ); /* Enables Depth Testing */ // glEnable( GL_DEPTH_TEST ); /* The Type Of Depth Test To Do */ glDepthFunc( GL_LEQUAL ); glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } float rndflt(float total, float negative) { return (rand()/(float(RAND_MAX)+1)*total)-negative; } bool initScreen() { bool success=1; int SDL_videomodeSettings = SDL_OPENGL|SDL_RESIZABLE; if(setting.fullscreen) SDL_videomodeSettings |= SDL_FULLSCREEN; /* Free the previously allocated surface */ if(screen != NULL) { SDL_FreeSurface( screen ); } screen = SDL_SetVideoMode(setting.resx,setting.resy,32, SDL_videomodeSettings); resizeWindow(setting.resx,setting.resy); if( screen == NULL ) { cout << "Error:" << SDL_GetError() << endl; success=0; var.quit=1; } SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); var.halfresx = setting.resx /2; var.halfresy = setting.resy / 2; return(success); } void resetPlayerPowerups() { for(int i=0; i < MAXPOTEXTURES; i++) { player.powerup[i] = 0; } } void initNewGame() { player.level=0; player.score=0; gVar.deadTime=0; gVar.newLevel=1; gVar.newLife=1; player.multiply = 1; switch(player.difficulty) { case EASY: player.coins = 600; player.lives = 5; break; case NORMAL: player.coins = 0; player.lives = 3; break; case HARD: player.coins = 0; player.lives = 3; break; } resetPlayerPowerups(); } void pauseGame() { var.paused=1; #ifndef WIN32 SDL_WM_GrabInput(SDL_GRAB_OFF); #endif SDL_ShowCursor(SDL_ENABLE); } void resumeGame() { #ifndef WIN32 SDL_WM_GrabInput(SDL_GRAB_ON); #endif SDL_ShowCursor(SDL_DISABLE); var.paused=0; var.menu=0; } void mkDLscene(GLuint *dl,textureClass tex) { //Scenen *dl = glGenLists(1); glNewList(*dl,GL_COMPILE); glLoadIdentity(); glTranslatef( 0.0f, 0.0f, -3.0 ); glColor4f(1.0, 1.0, 1.0, 1.0); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, tex.prop.texture); glBegin( GL_POINTS ); glVertex3f( -1.60, 1.25, 0.0 ); glEnd( ); glBegin( GL_QUADS ); //venstre kant glTexCoord2f(0.0f,0.0f);glVertex3f( -1.66, 1.25, 0.0 ); glTexCoord2f(1.0f,0.0f);glVertex3f( -1.60, 1.25, 0.0 ); glTexCoord2f(1.0f,-1.0f);glVertex3f( -1.60,-1.25, 0.0 ); glTexCoord2f(0.0f,-1.0f);glVertex3f( -1.66,-1.25, 0.0 ); //højre kant glTexCoord2f(0.0f,0.0f);glVertex3f( 1.66, 1.25, 0.0 ); glTexCoord2f(1.0f,0.0f);glVertex3f( 1.60, 1.25, 0.0 ); glTexCoord2f(1.0f,-1.0f);glVertex3f( 1.60,-1.25, 0.0 ); glTexCoord2f(0.0f,-1.0f);glVertex3f( 1.66,-1.25, 0.0 ); glEnd( ); glEndList(); } void coldet(brick & br, ball &ba, pos & p, effectManager & fxMan) { GLfloat x,y; int i=0; int points=0; GLfloat px=0,py=0; bool col=0; bool dirfound=0; 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 //vi tager y først da der er mindst brikker if(ba.posy < br.posy+br.height+ba.height && ba.posy > br.posy-br.height-ba.height) { //cout << " y " << endl; if(ba.posx > br.posx-br.width-ba.width && ba.posx < br.posx+br.width+ba.width) { //cout << " x " << endl; for(i=0; i < 32; i++) // 32 punkter præcis { x = ba.bsin[i]; y = ba.bcos[i]; if(ba.posx+x >= br.posx-br.width && ba.posx+x <= br.posx+br.width) { if(ba.posy+y <= br.posy+br.height && ba.posy+y >= br.posy-br.height) { //Vi har helt sikkert ramt points++; px += x; py += y; col=1; } //y } //x } //32 punkters for loop if(col) { px /= points; py /= points; if(ba.lastX-px <= br.posx-br.width && !br.n(0)) // { dirfound=1; // cout << "På venstre"<= br.posx+br.width && !br.n(1)) { dirfound=1; // cout << "På højre"<= br.posy+br.height && !br.n(2)) // && { dirfound=1; // cout << "På toppen"<< endl; dist[3] = sqrt( pow( (ba.posx+px) - (ba.lastX+px), 2) + pow( br.posy+br.height - (ba.lastY+py), 2) ); } //Was hit on left if(dist[0] < dist[1] && dist[0] < dist[2] && dist[0] < dist[3]) { ba.posx = br.posx - br.width - ba.width; if(ba.xvel > 0.0 && !player.powerup[PO_THRU]) ba.xvel *=-1; } //Was hit on right if(dist[1] < dist[0] && dist[1] < dist[2] && dist[1] < dist[3]) { ba.posx = br.posx + br.width + ba.width; if(ba.xvel < 0 && !player.powerup[PO_THRU]) ba.xvel *=-1; } //Was hit on bottom if(dist[2] < dist[0] && dist[2] < dist[1] && dist[2] < dist[3]) { ba.posy = br.posy - br.height - ba.height; if(ba.yvel > 0 && !player.powerup[PO_THRU]) ba.yvel *=-1; } //Was hit on top if(dist[3] < dist[0] && dist[3] < dist[1] && dist[3] < dist[2]) { ba.posy = br.posy + br.height + ba.height; if(ba.yvel < 0 && !player.powerup[PO_THRU]) ba.yvel *=-1; } //Setup vars for spawning powerups pos a,b; a.x = br.posx; a.y = br.posy; //Hastigheden en powerup blier sendt afsted med if(player.difficulty == EASY) { b.x = ba.xvel/2.0; b.y = ba.yvel/2.0; } else if(player.difficulty == NORMAL) { b.x = ba.xvel/1.5; b.y = ba.yvel/1.5; } else //if(player.difficulty == HARD) { b.x = ba.xvel/1.25; b.y = ba.yvel/1.25; } if(dirfound) { if(ba.explosive) { br.type='B'; } //Update p, used by caller to find out if we hit anything.. p.x = ba.posx+px; p.y = ba.posy+py; ba.hit(br.tex.prop.glParColorInfo); if(!player.powerup[PO_THRU] || player.difficulty == HARD) { ba.setspeed(ba.velocity + difficulty.hitbrickinc[player.difficulty]); } } else { cout << "Collision detection error: Dont know where the ball hit." < p.posy-p.height) { if(b.posx > p.posx-(p.width*2.0)-b.width && b.posx < p.posx+(p.width*2.0)+b.width) { for(i=0; i < 32; i++) { x = b.bsin[i]; y = b.bcos[i]; //Find de punkter der er inden i padden if(b.posx+x > p.posx-p.width && b.posx+x < p.posx+p.width) { if(b.posy+y < p.posy+p.height && b.posy+y > p.posy-p.height) { col=1; px +=x; py +=y; points++; } } } //For loop if(col) { col=0; gVar.deadTime=0; px /= (float)points; py /= (float)points; px = b.posx+px; //Ved at reagere herinde fungerer yvel som en switch, så det kun sker een gang ;) if(b.yvel < 0) { b.posy=p.posy+p.height+b.height; //løft op over pad //Only decrease speed if the player does not have the go-thru powerup if(!player.powerup[PO_THRU]) { b.setspeed(b.velocity + difficulty.hitpaddleinc[player.difficulty]); } b.setangle(bounceOffAngle(p.width, p.posx, b.posx)); if(player.powerup[PO_GLUE]) { b.gluedX = p.posx+p.width - px; b.glued=1; } po.x = px; po.y = py; } } } } } #include "highscores.cpp" struct shopItemStruct { int price; int type; }; class hudClass { private: textureClass texBall; //For the hud text int ticksSinceLastClockCheck; time_t nixTime; //Seconds since epoch tm timeStruct; //Time struct char clockString[13]; //Clock: 00:00\0 //For the powerup "shop" textureClass *texPowerup; //Pointer to array of powerup textures int shopItemSelected; #define NUMITEMSFORSALE 13 struct shopItemStruct item[NUMITEMSFORSALE]; bool shopItemBlocked[NUMITEMSFORSALE]; //One can only buy each powerup one time each life/level public: hudClass(textureClass texB, textureClass texPo[]) { texPowerup = texPo; texBall=texB; ticksSinceLastClockCheck=1001; item[0].type = PO_LASER; item[0].price = 600; item[1].type = PO_NORMALBALL; item[1].price = 750; item[2].type = PO_BIGBALL; item[2].price = 800; item[3].type = PO_AIMHELP; item[3].price = 900; item[4].type = PO_GROWPADDLE; item[4].price = 960; item[5].type = PO_MULTIBALL; item[5].price = 980; item[6].type = PO_EXPLOSIVE_GROW; item[6].price = 990; item[7].type = PO_EXPLOSIVE; item[7].price = 1000; item[8].type = PO_GLUE; item[8].price = 1000; item[9].type = PO_EASYBRICK; item[9].price = 2000; item[10].type = PO_GUN; item[10].price = 3000; item[11].type = PO_THRU; item[11].price = 4000; item[12].type = PO_LIFE; item[12].price = 6000; shopItemSelected=0; } void draw() { int i; //Draw lives left. glLoadIdentity(); glTranslatef(0,0,-3.0); glColor4f( texBall.prop.glTexColorInfo[0],texBall.prop.glTexColorInfo[1],texBall.prop.glTexColorInfo[2],texBall.prop.glTexColorInfo[3]); glBindTexture(GL_TEXTURE_2D, texBall.prop.texture); texBall.play(); glBegin( GL_QUADS ); for(i=0; i < player.lives-1; i++) { glTexCoord2f(texBall.pos[0],texBall.pos[1]); glVertex3f(1.55-(0.05*i), 1.2, 0.0); glTexCoord2f(texBall.pos[2],texBall.pos[3]); glVertex3f(1.5 -(0.05*i), 1.2, 0.0); glTexCoord2f(texBall.pos[4],texBall.pos[5]); glVertex3f(1.5 -(0.05*i),1.15, 0.0); glTexCoord2f(texBall.pos[6],texBall.pos[7]); glVertex3f(1.55 -(0.05*i), 1.15, 0.0); } glEnd( ); if(setting.showClock) { ticksSinceLastClockCheck += globalTicksSinceLastDraw; if(ticksSinceLastClockCheck > 1000) { ticksSinceLastClockCheck=0; time(&nixTime); timeStruct = *(localtime(&nixTime)); sprintf(clockString, "Clock: %02i:%02i", timeStruct.tm_hour, timeStruct.tm_min); //Array is exactly 13 chars wide } glColor4f(1.0,1.0,1.0,1.0); glText->write(clockString, FONT_INTRODESCRIPTION, 0, 1.0, -1.58, -1.25 + glText->getHeight(FONT_INTRODESCRIPTION)); } //Draw the "shop" //First, find out how many items the player can afford, so we can center them int canAfford=0; for(i=0; i < NUMITEMSFORSALE; i++) { if(item[i].price <= player.coins) { canAfford++; } } if(shopItemSelected > canAfford || shopItemSelected < 0) { shopItemSelected=canAfford-1; } GLfloat shopListStartX = -((0.11*canAfford)/2.0); if(gVar.shopNextItem) { gVar.shopNextItem=0; shopItemSelected++; if(shopItemSelected > canAfford-1) { shopItemSelected=0; } } else if(gVar.shopPrevItem) { gVar.shopPrevItem=0; shopItemSelected--; if(shopItemSelected < 0) { shopItemSelected=canAfford-1; if(shopItemSelected < 0) { shopItemSelected=0; } } } else if(gVar.shopBuyItem) { gVar.shopBuyItem=0; if(item[shopItemSelected].price <= player.coins && !shopItemBlocked[shopItemSelected]) { struct pos a,b; a.x = shopListStartX + (0.11*shopItemSelected); a.y = 1.15; b.x = 0.0; b.y = 0.0; pMan.spawn(a,b,item[shopItemSelected].type); player.coins -= item[shopItemSelected].price; shopItemBlocked[shopItemSelected]=1; gVar.shopNextItem=1; soundMan.add(SND_BUY_POWERUP, 0.0); } } glTranslatef( shopListStartX, 1.15, 0.0f); for(i=0; i < canAfford; i++) { if(i==shopItemSelected) { if(shopItemBlocked[i]) { glColor4f(1.0, 0.0, 0.0, 1.0); } else { glColor4f(1.0, 1.0, 1.0, 1.0); } } else { if(shopItemBlocked[i]) { glColor4f(1.0, 0.0, 0.0, 0.4); } else { glColor4f(1.0, 1.0, 1.0, 0.4); } } texPowerup[item[i].type].play(); glBindTexture( GL_TEXTURE_2D, texPowerup[item[i].type].prop.texture); glBegin( GL_QUADS ); glTexCoord2f(texPowerup[item[i].type].pos[0],texPowerup[item[i].type].pos[1]);glVertex3f( -0.055, 0.055, 0.00 ); glTexCoord2f(texPowerup[item[i].type].pos[2],texPowerup[item[i].type].pos[3]);glVertex3f( 0.055, 0.055, 0.00 ); glTexCoord2f(texPowerup[item[i].type].pos[4],texPowerup[item[i].type].pos[5]);glVertex3f( 0.055,-0.055, 0.00 ); glTexCoord2f(texPowerup[item[i].type].pos[6],texPowerup[item[i].type].pos[7]);glVertex3f( -0.055,-0.055, 0.00 ); glEnd( ); glTranslatef( 0.11, 0.0, 0.0f); } } void clearShop() { for(int i=0; i < NUMITEMSFORSALE; i++) { shopItemBlocked[i]=0; } } }; void writeSettings() { ofstream conf; conf.open(privFile.settingsFile.data(),ios::out | ios::trunc); //homeDirFiles.settingsFile.data() if(conf.is_open()) { conf << "eyecandy="<current_w; int oldResY = SDL_GetVideoInfo()->current_h; int oldColorDepth = SDL_GetVideoInfo()->vfmt->BitsPerPixel; /* Handle those situations where sdl gets a void resolution */ if(oldResX < 128 || oldResY < 96) { cout << "SDL Reported a screen resolution below 128x96."<< endl; cout << "Assuming this is a bug in SDL or driver." << endl; cout << "Falling back on 128x96"; oldResX=128; oldResY=96; if(!setting.cfgRes[0] || !setting.cfgRes[1]) { setting.fullscreen=0; cout << ", windowed mode."; } cout << endl; } /* The above code is not tested and might not work */ if(!setting.cfgRes[0] || !setting.cfgRes[1]) { setting.resx = oldResX; setting.resy = oldResY; } SDL_Event sdlevent; #ifndef WIN32 SDL_WM_GrabInput(SDL_GRAB_ON); #endif SDL_ShowCursor(SDL_DISABLE); SDL_EnableUNICODE (1); initScreen(); initGL(); glText = new glTextClass; // instantiate the class now that settings have been read. soundMan.init(); SDL_WM_SetCaption("SDL-Ball", "SDL-Ball" ); SDL_WM_SetIcon( IMG_Load( useTheme("icon32.png", setting.gfxTheme).data() ), 0 ); SDL_WarpMouse(var.halfresx, var.halfresy); textureManager texMgr; textureClass texPaddleBase; textureClass texPaddleLayers[2]; textureClass texBall[3]; textureClass texLvl[13]; texExplosiveBrick = &texLvl[0]; //Pointer to explosive texture.. textureClass texBorder; textureClass texPowerup[MAXPOTEXTURES]; textureClass texBullet; textureClass texParticle; texMgr.readTexProps(useTheme("gfx/paddle/base.txt",setting.gfxTheme), texPaddleBase); texMgr.readTexProps(useTheme("gfx/paddle/glue.txt",setting.gfxTheme), texPaddleLayers[0]); texMgr.readTexProps(useTheme("gfx/paddle/gun.txt",setting.gfxTheme), texPaddleLayers[1]); texMgr.readTexProps(useTheme("gfx/ball/normal.txt",setting.gfxTheme), texBall[0]); texMgr.readTexProps(useTheme("gfx/ball/fireball.txt",setting.gfxTheme), texBall[1]); texMgr.readTexProps(useTheme("gfx/ball/tail.txt",setting.gfxTheme), texBall[2]); texMgr.readTexProps(useTheme("gfx/brick/explosive.txt", setting.gfxTheme), texLvl[0]); texMgr.readTexProps(useTheme("gfx/brick/base.txt", setting.gfxTheme), texLvl[1]); texMgr.readTexProps(useTheme("gfx/brick/cement.txt", setting.gfxTheme), texLvl[2]); texMgr.readTexProps(useTheme("gfx/brick/doom.txt", setting.gfxTheme), texLvl[3]); texMgr.readTexProps(useTheme("gfx/brick/glass.txt", setting.gfxTheme), texLvl[4]); texMgr.readTexProps(useTheme("gfx/brick/invisible.txt", setting.gfxTheme), texLvl[5]); texMgr.readTexProps(useTheme("gfx/brick/blue.txt", setting.gfxTheme), texLvl[6]); texMgr.readTexProps(useTheme("gfx/brick/yellow.txt", setting.gfxTheme), texLvl[7]); texMgr.readTexProps(useTheme("gfx/brick/green.txt", setting.gfxTheme), texLvl[8]); texMgr.readTexProps(useTheme("gfx/brick/grey.txt", setting.gfxTheme), texLvl[9]); texMgr.readTexProps(useTheme("gfx/brick/purple.txt", setting.gfxTheme), texLvl[10]); texMgr.readTexProps(useTheme("gfx/brick/white.txt", setting.gfxTheme), texLvl[11]); texMgr.readTexProps(useTheme("gfx/brick/red.txt", setting.gfxTheme), texLvl[12]); texMgr.load(useTheme("gfx/border.png",setting.gfxTheme), texBorder); texMgr.readTexProps(useTheme("gfx/powerup/coin.txt",setting.gfxTheme),texPowerup[PO_COIN]); texMgr.readTexProps(useTheme("gfx/powerup/glue.txt",setting.gfxTheme),texPowerup[PO_GLUE]); texMgr.readTexProps(useTheme("gfx/powerup/multiball.txt",setting.gfxTheme),texPowerup[PO_MULTIBALL]); texMgr.readTexProps(useTheme("gfx/powerup/bigball.txt",setting.gfxTheme),texPowerup[PO_BIGBALL]); texMgr.readTexProps(useTheme("gfx/powerup/normalball.txt",setting.gfxTheme),texPowerup[PO_NORMALBALL]); texMgr.readTexProps(useTheme("gfx/powerup/smallball.txt",setting.gfxTheme),texPowerup[PO_SMALLBALL]); texMgr.readTexProps(useTheme("gfx/powerup/aim.txt",setting.gfxTheme),texPowerup[PO_AIM]); texMgr.readTexProps(useTheme("gfx/powerup/explosive.txt",setting.gfxTheme),texPowerup[PO_EXPLOSIVE]); texMgr.readTexProps(useTheme("gfx/powerup/gun.txt",setting.gfxTheme),texPowerup[PO_GUN]); texMgr.readTexProps(useTheme("gfx/powerup/go-thru.txt",setting.gfxTheme),texPowerup[PO_THRU]); texMgr.readTexProps(useTheme("gfx/powerup/laser.txt",setting.gfxTheme),texPowerup[PO_LASER]); texMgr.readTexProps(useTheme("gfx/powerup/life.txt",setting.gfxTheme),texPowerup[PO_LIFE]); texMgr.readTexProps(useTheme("gfx/powerup/die.txt",setting.gfxTheme),texPowerup[PO_DIE]); texMgr.readTexProps(useTheme("gfx/powerup/drop.txt",setting.gfxTheme),texPowerup[PO_DROP]); texMgr.readTexProps(useTheme("gfx/powerup/detonate.txt",setting.gfxTheme),texPowerup[PO_DETONATE]); texMgr.readTexProps(useTheme("gfx/powerup/explosive-grow.txt",setting.gfxTheme),texPowerup[PO_EXPLOSIVE_GROW]); texMgr.readTexProps(useTheme("gfx/powerup/easybrick.txt",setting.gfxTheme),texPowerup[PO_EASYBRICK]); texMgr.readTexProps(useTheme("gfx/powerup/nextlevel.txt",setting.gfxTheme),texPowerup[PO_NEXTLEVEL]); texMgr.readTexProps(useTheme("gfx/powerup/aimhelp.txt",setting.gfxTheme),texPowerup[PO_AIMHELP]); texMgr.readTexProps(useTheme("gfx/powerup/growbat.txt",setting.gfxTheme), texPowerup[PO_GROWPADDLE]); texMgr.readTexProps(useTheme("gfx/powerup/shrinkbat.txt",setting.gfxTheme), texPowerup[PO_SHRINKPADDLE]); texMgr.readTexProps(useTheme("gfx/powerup/bullet.txt",setting.gfxTheme), texBullet); pMan.init(texPowerup); texMgr.load(useTheme("gfx/particle.png",setting.gfxTheme), texParticle); GLuint sceneDL; mkDLscene(&sceneDL, texBorder); brick bricks[598]; string levelfile = useTheme("levels.txt",setting.lvlTheme); int i=0; //bruges i for loop xD glScoreBoard scoreboard; menuClass menu; paddle_class paddle; paddle.tex = texPaddleBase; paddle.layerTex = texPaddleLayers; struct pos p; //kordinater for hvor den stødte sammen effectManager fxMan; fxMan.set(FX_VAR_TEXTURE, texParticle); fxMan.set(FX_VAR_GRAVITY, 0.6f); titleScreenClass titleScreen(&fxMan, texPowerup, &menu); ballManager bMan(texBall); initNewGame(); paddle.posy = -1.15; highScoreClass hKeeper; backgroundClass bg; bulletsClass bullet(texBullet); speedometerClass speedo; hudClass hud(texBall[0], texPowerup); //This is GOING to be containing the "hud" (score, borders, lives left, level, speedometer) var.effectnum=-1; int lastTick = SDL_GetTicks(); int nonpausingLastTick = lastTick; char txt[256]; int frameAge=0; //How long have the current frame been shown // #define performanceTimer #ifdef performanceTimer struct timeval timeStart,timeStop; int renderTime; #endif controllerClass control(&paddle, &bullet, &bMan); soundMan.add(SND_START,0); while(!var.quit) { #ifdef performanceTimer gettimeofday(&timeStart, NULL); #endif nonpausingGlobalTicks = SDL_GetTicks() - nonpausingLastTick; frameAge += nonpausingGlobalTicks; nonpausingGlobalMilliTicks = nonpausingGlobalTicks/1000.0; nonpausingLastTick = SDL_GetTicks(); if(!var.paused) { globalTicks = SDL_GetTicks() - lastTick; globalMilliTicks = globalTicks/1000.0; } else { globalTicks = globalMilliTicks = 0; } lastTick = SDL_GetTicks(); globalTicksSinceLastDraw += nonpausingGlobalTicks; globalMilliTicksSinceLastDraw += nonpausingGlobalMilliTicks; gVar.deadTime += globalTicks; //really ugly... but easy if(!var.titleScreenShow) { if(gVar.deadTime > 20000) { gVar.deadTime=0; bMan.powerup(PO_EXPLOSIVE); //give the balls explosive ability, in order to blow up cement block and get on with the game } if(bMan.activeBalls == 0 && !gVar.newLevel) //check kun om vi er døde hvis vi faktisk er kommet igang med at spille { player.lives--; if(player.lives > 0) { resetPlayerPowerups(); gVar.newLife=1; if(!paddle.dead) player.explodePaddle=1; pMan.die(fxMan); } else if(!gVar.gameOver) { gVar.gameOver=1; pauseGame(); if( hKeeper.isHighScore() ) { // announce.write(string text, int mslife, int fontnum); announce.write("Highscore!", 3000,FONT_ANNOUNCE_GOOD); var.showHighScores=1; soundMan.add(SND_HIGHSCORE, 0); } } else if(gVar.gameOver && !var.showHighScores) { //Only ran if there is gameover and no highscore if(var.effectnum == -1) { fxMan.set(FX_VAR_TYPE, FX_TRANSIT); fxMan.set(FX_VAR_LIFE, 3000); fxMan.set(FX_VAR_COLOR, 0.0,0.0,0.0); p.x = 0.0; p.y = 0.0; //Kør en transition effekt var.effectnum = fxMan.spawn(p); announce.write("GameOver!", 1500,FONT_ANNOUNCE_BAD); soundMan.add(SND_GAMEOVER, 0); } else { if(var.transition_half_done) { var.titleScreenShow=1; fxMan.kill(var.effectnum); var.effectnum = -1; initNewGame(); resumeGame(); } } } } if(gVar.nextlevel) { if(var.effectnum == -1) { announce.write("Well Done!", 1000, FONT_ANNOUNCE_GOOD); soundMan.add(SND_NEXTLEVEL, 0); if(bMan.activeBalls > 1) { sprintf(txt, "Bonus: %i", bMan.activeBalls*150); player.score += (bMan.activeBalls*150)*player.multiply; announce.write(txt, 2000, FONT_ANNOUNCE_GOOD); } fxMan.set(FX_VAR_TYPE, FX_TRANSIT); fxMan.set(FX_VAR_LIFE, 1600); fxMan.set(FX_VAR_COLOR, 0.0,0.0,0.0); p.x = 0.0; p.y = 0.0; //Kør en transition effekt var.effectnum = fxMan.spawn(p); var.idiotlock = 0; } else { if(var.transition_half_done) { if(!var.idiotlock) { var.idiotlock=1; player.level++; SOLPlayer = player; // Capture how player is at the start of this level //If player completed all levels, restart the game with higher multiplier if(player.level == var.numlevels) { player.multiply += player.multiply*3; player.level=0; announce.write("Finished!",3500,FONT_ANNOUNCE_GOOD); } sprintf(txt, "Level %i",player.level+1); //+1 fordi levels starter fra 0 announce.write(txt,1500,FONT_ANNOUNCE_GOOD); //check om vi skal fjerne powerups if(player.difficulty > EASY) { resetPlayerPowerups(); } gVar.newLevel = 1; var.paused=0; } } if(!fxMan.isActive(var.effectnum)) { var.effectnum = -1; //nulstil så den er klar igen gVar.nextlevel = 0; var.paused = 0; var.idiotlock=0; } } } if(gVar.newLevel) { var.bricksHit = 1; gVar.newLevel=0; loadlevel(levelfile, bricks,player.level); initlevels(bricks,texLvl); gVar.gameOver=0; gVar.newLife=1; pMan.clear(); bullet.clear(); paddle.posx = 0.0; var.startedPlaying=0; bg.init(texMgr); hud.clearShop(); } if(gVar.newLife) { gVar.newLife=0; paddle.init(); p.x=paddle.posx; p.y=paddle.posy+paddle.height+0.025; bMan.clear(); 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 } if(frameAge >= maxFrameAge) { if(var.clearScreen) { glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } //Update player score scoreboard.update(player.score); //background if(setting.showBg) bg.draw(); //borders glCallList(sceneDL); if(var.scrollInfo.drop) { if( (SDL_GetTicks() - var.scrollInfo.lastTick ) > var.scrollInfo.dropspeed ) { var.scrollInfo.lastTick=SDL_GetTicks(); dropBoard(bricks); } } if(gVar.bricksleft==1) { player.powerup[PO_AIMHELP]=1; } } bullet.move(); gVar.bricksleft=0; //Update nbrick here if(var.bricksHit) { memcpy(nbrick, updated_nbrick, sizeof(updated_nbrick)); var.bricksHit = 0; } for(i=0; i <598; i++) { if(bricks[i].active) { if(bricks[i].destroytowin && bricks[i].hitsLeft) { gVar.bricksleft++; } if(bricks[i].collide) { bMan.bcoldet(bricks[i], fxMan); //bullets if(player.powerup[PO_GUN]) { bullet.coldet(bricks[i], fxMan); } //check kollision på effekterne if(setting.particleCollide && setting.eyeCandy && frameAge >= maxFrameAge) fxMan.coldet(bricks[i]); } if(frameAge >= maxFrameAge) bricks[i].draw(bricks,fxMan); } //aktiv brik } // for loop //Collission between paddle and balls if( bMan.pcoldet(paddle, fxMan) ) { if(player.powerup[PO_DROP]) { dropBoard(bricks); } } bMan.move(); if(setting.particleCollide && setting.eyeCandy && frameAge >= maxFrameAge) fxMan.pcoldet(paddle); pMan.move(); if(pMan.coldet(paddle, fxMan, bMan)) { if(player.powerup[PO_DETONATE]) { player.powerup[PO_DETONATE]=0; detonateExplosives(bricks, fxMan); } if(player.powerup[PO_EASYBRICK]) { player.powerup[PO_EASYBRICK]=0; easyBrick(bricks); } if(player.powerup[PO_NEXTLEVEL]) { player.powerup[PO_NEXTLEVEL]=0; gVar.nextlevel=1; var.paused=1; } if(player.powerup[PO_EXPLOSIVE_GROW]) { player.powerup[PO_EXPLOSIVE_GROW]=0; explosiveGrow(bricks); } } if(frameAge >= maxFrameAge) { soundMan.play(); if(player.explodePaddle) { player.explodePaddle=0; soundMan.add(SND_DIE,0); if(setting.eyeCandy) { fxMan.set(FX_VAR_TYPE, FX_PARTICLEFIELD); p.x=paddle.width*2; p.y=paddle.height*2; fxMan.set(FX_VAR_RECTANGLE, p); p.x=paddle.posx; p.y=paddle.posy; fxMan.set(FX_VAR_LIFE, 2000); fxMan.set(FX_VAR_NUM, 20); fxMan.set(FX_VAR_SIZE, 0.025f); fxMan.set(FX_VAR_SPEED, 0.35f); fxMan.set(FX_VAR_GRAVITY, -0.7f); fxMan.set(FX_VAR_COLOR, 1.0f, 0.7f, 0.0f); fxMan.spawn(p); fxMan.set(FX_VAR_COLOR, 1.0f, 0.8f, 0.0f); fxMan.spawn(p); fxMan.set(FX_VAR_COLOR, 1.0f, 0.9f, 0.0f); fxMan.spawn(p); fxMan.set(FX_VAR_COLOR, 1.0f, 1.0f, 0.0f); fxMan.spawn(p); fxMan.set(FX_VAR_NUM, 32); fxMan.set(FX_VAR_SIZE, 0.05f); fxMan.set(FX_VAR_LIFE, 1500); fxMan.set(FX_VAR_SPEED, 0.7f); fxMan.set(FX_VAR_GRAVITY, 0.0f); fxMan.set(FX_VAR_COLOR, 0.5f, 0.5f, 0.5f); fxMan.spawn(p); fxMan.set(FX_VAR_COLOR, 1.0f, 1.0f, 1.0f); fxMan.spawn(p); } } bMan.updatelast(); glColor3d(255,255,255); bullet.draw(); paddle.draw(); pMan.draw(); bMan.draw(paddle); scoreboard.draw(); speedo.draw(); hud.draw(); fxMan.draw(); if(var.showHighScores) hKeeper.draw(); if(var.menu>0) { if(var.menu==10 || var.menu==11) { control.calibrate(); } menu.doMenu(); } announce.draw(); SDL_GL_SwapBuffers( ); frameAge = 0; globalTicksSinceLastDraw=0; globalMilliTicksSinceLastDraw=0; #ifdef performanceTimer cout << "FrameAge:"; } else { cout << "LoopAge:"; } gettimeofday(&timeStop, NULL); renderTime = timeStop.tv_usec - timeStart.tv_usec; cout << renderTime << endl; #else } #endif if(!gVar.bricksleft) { gVar.nextlevel=1; var.paused=1; } } else { //Show the title screen titleScreen.draw(&frameAge, &maxFrameAge); } control.get(); //Check for keypresses and joystick events while (SDL_PollEvent(&sdlevent) ) { if( sdlevent.type == SDL_KEYDOWN ) { if(var.showHighScores) { hKeeper.type(sdlevent, menu); } else if(var.enterSaveGameName) { menu.enterSaveGameName(sdlevent); } else { if( sdlevent.key.keysym.sym==SDLK_p || sdlevent.key.keysym.sym==SDLK_PAUSE) { var.paused ? resumeGame() : pauseGame(); } if( sdlevent.key.keysym.sym == SDLK_q ) { var.quit=1; } else if( sdlevent.key.keysym.sym == SDLK_s ) { screenShot(); } else if( sdlevent.key.keysym.sym == setting.keyNextPo) { gVar.shopPrevItem=1; } else if( sdlevent.key.keysym.sym == setting.keyBuyPo) { gVar.shopBuyItem=1; } else if( sdlevent.key.keysym.sym == setting.keyPrevPo) { gVar.shopNextItem=1; } else if(sdlevent.key.keysym.sym == SDLK_u) { var.clearScreen ? var.clearScreen=0:var.clearScreen=1; } else if(sdlevent.key.keysym.sym == SDLK_c) { setting.showClock ? setting.showClock=0 : setting.showClock=1; writeSettings(); } #ifdef WITH_WIIUSE if( sdlevent.key.keysym.sym == SDLK_w ) { var.titleScreenShow=0; pauseGame(); var.menu=11; var.menuJoyCalStage=-1; } #endif } //Toggle menu if( sdlevent.key.keysym.sym == SDLK_ESCAPE) { if(var.titleScreenShow) var.titleScreenShow=0; switch(var.menu) { case 0: var.menu=1; pauseGame(); break; case 1: resumeGame(); break; default: var.menu=1; break; } } else if( sdlevent.key.keysym.sym == SDLK_F1 ) { if(!var.titleScreenShow) { var.titleScreenShow=1; } else { var.titleScreenShow=0; } } #ifndef WIN32 else if( sdlevent.key.keysym.sym == SDLK_F11 ) { if(setting.fullscreen) setting.fullscreen=0; else setting.fullscreen=1; initScreen(); } #endif } if( sdlevent.type == SDL_MOUSEMOTION ) { mousex = (sdlevent.motion.x - var.halfresx) * var.glunits_per_xpixel; mousey = (sdlevent.motion.y - var.halfresy) * var.glunits_per_ypixel * -1; if(var.menu) { if(mousex > -0.5 && mousex < 0.5 && mousey < (-0.78)+(0.07) && mousey > (-0.78)-(0.07) ) var.menuItem = 1; else if(mousex > -0.5 && mousex < 0.5 && mousey < (-0.56)+(0.07) && mousey > (-0.56)-(0.07) ) var.menuItem = 2; else if(mousex > -0.5 && mousex < 0.5 && mousey < (-0.34)+(0.07) && mousey > (-0.34)-(0.07) ) var.menuItem = 3; else if(mousex > -0.5 && mousex < 0.5 && mousey < (-0.12)+(0.07) && mousey > (-0.12)-(0.07) ) var.menuItem = 4; else if(mousex > -0.5 && mousex < 0.5 && mousey < (0.1)+(0.07) && mousey > (0.1)-(0.07) ) var.menuItem = 5; else if(mousex > -0.5 && mousex < 0.5 && mousey < (0.32)+(0.07) && mousey > (0.32)-(0.07) ) var.menuItem = 6; else if(mousex > -0.5 && mousex < 0.5 && mousey < (0.54)+(0.07) && mousey > (0.54)-(0.07) ) var.menuItem = 7; else var.menuItem = 0; } else { control.movePaddle(mousex); } } else if( sdlevent.type == SDL_MOUSEBUTTONDOWN ) { if(sdlevent.button.button == SDL_BUTTON_LEFT ) { if(var.menu) { var.menuPressed=1; if(var.menuItem > 0) soundMan.add(SND_MENUCLICK, 0); } control.btnPress(); } else if(sdlevent.button.button == SDL_BUTTON_RIGHT ) { gVar.shopBuyItem=1; } else if(sdlevent.button.button == 4) { gVar.shopPrevItem=1; } else if(sdlevent.button.button == 5) { gVar.shopNextItem=1; } } if( sdlevent.type == SDL_QUIT ) { var.quit = 1; } else if( sdlevent.type == SDL_VIDEORESIZE ) { setting.resx = sdlevent.resize.w; setting.resy = sdlevent.resize.h; initScreen(); } } #ifdef WIN32 Sleep( 1 ); #else usleep( 1000 ); #endif } #ifndef WIN32 if(setting.fullscreen) SDL_SetVideoMode(oldResX,oldResY,oldColorDepth, SDL_OPENGL); #endif #ifndef WIN32 SDL_WM_GrabInput(SDL_GRAB_OFF); #endif SDL_ShowCursor(SDL_ENABLE); SDL_FreeSurface(screen); SDL_Quit(); cout << "Thank you for playing sdl-ball ;)" << endl; return EXIT_SUCCESS; }