1 /* ************************************************************************* *
2     OldSkoolGravityGame (OSGG) Lunar Lander-like game for linux.
3     Copyright (C) 2008 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 <unistd.h>
20 #include <iostream>
21 #include <SDL/SDL.h>
22 #include <SDL/SDL_image.h>
23 #include <GL/gl.h>
24 #include <vector>
25 #include <list>
26 #include <math.h>
27 #include <fstream>
28 #include <iostream>
29 #include <sstream>
30 
31 #include <sys/time.h>
32 
33 #if defined(WIN32)
34     typedef unsigned int uint;
35     #include <windows.h>
36     #include <GL/glext.h>
37 #elif defined(__FreeBSD__) || defined(__DragonFly__)
38     #include <sys/endian.h>
39 #else
40     #include <endian.h>
41 #endif
42 
43 
44 #define VERSION "1.0"
45 
46 #ifndef DATADIR
47     #define DATADIR "./"
48 #endif
49 
50 using namespace std;
51 
52 
53 bool soundOn,intermediateSave, vsync,showfps;
54 
55 #include "sound.hpp"
56 #include "text.hpp"
57 glTextClass* glText = NULL;
58 soundClass* soundMan = NULL;
59 
60 bool showHelp=true;
61 bool booted=true;
62 
63 #define THRUSTINCRATE 0.01
64 #define GRAVITY 0.002
65 #define TURNINCRATE 0.15
66 
swapbytes32(uint32_t value)67 uint32_t swapbytes32(uint32_t value)
68 {
69   uint32_t result;
70   ((uint8_t*) &result)[0] = ((uint8_t*) &value)[3];
71   ((uint8_t*) &result)[1] = ((uint8_t*) &value)[2];
72   ((uint8_t*) &result)[2] = ((uint8_t*) &value)[1];
73   ((uint8_t*) &result)[3] = ((uint8_t*) &value)[0];
74   return result;
75 }
76 
77 enum entTypes { entLine, entShip, entBase, entWp, entEnemy };
78 enum gameStateEnum { GameStateEditor, GameStatePlaying, GameStatePause, GameStateQuit, GameStateNewGame, GameStateGameOver, GameStateNextLevel, GameStateStartEditor };
79 uint gameState = GameStateEditor;
80 
81 
82 struct demoFrameStruct {
83   Uint8 left,right,up,shoot;
84 };
85 
86 struct pStruct {
87   int x,y;
88 };
89 
90 string levelFile, saveDemoFile;
91 
92 struct glPstruct {
93   GLfloat x, y;
94 };
95 
96 struct structVert {
97   GLfloat color[3];
98   struct glPstruct p;
99   int collision; // 0 = none, 1 = normal(damage), 2 = platform/Landing gear
100 };
101 
102 typedef struct structVert vert;
103 typedef struct glPstruct gPs;
104 typedef struct pStruct pS;
105 typedef struct demoFrameStruct demoFrame;
106 vector<demoFrame>demoFrames;
107 struct structEnt {
108   struct glPstruct p; //position
109   GLfloat rotation; //In DEG
110   gPs vel; //Velocity, only used for enemies right now
111   gPs baseP; //Base (start) position, used for nme
112   int type; //type
113   int id;
114   bool base; // If it's a base, don't translate it every time..
115 };
116 typedef struct structEnt entity;
117 
118 struct structDispInfo {
119   gPs mousePos;
120   bool mouseDrag; //Is user holding btn
121   bool mouseRightDrag;
122 
123   bool fullScreen;
124 
125   pS dispSize; //Window size in pixels
126   pS dispHalfSize;
127   gPs glSceneSize;
128   gPs camPos; //The is where the camera is.
129 
130   GLfloat glZoom;
131   GLfloat glBaseZoom;
132   GLfloat glUnitsPrPixel;
133   GLdouble aspect;
134 
135   pS screenRes; //The current resolution ) SDL_GetVideoInfo() );
136   GLfloat bgColor[3];
137 
138   bool enableZoom;
139 
140 };
141 struct structDispInfo dispInfo;
142 
143 struct structGameRules {
144   int startLevel; //what level to start in
145   GLfloat maxLandingRotForce;
146   GLfloat maxLandingYel;
147   GLfloat maxLandingXvel;
148   int fuelConsumptionThrust;
149   int fuelConsumptionTurn;
150   int fuelMaxFuel;
151   int ammoMaxAmmo;
152 };
153 
154 struct structGameRules gameRules;
155 
156 struct gameInfoStruct {
157   bool recording; //recording demo?
158   bool playing; //playing a demo?
159   int  demoFrame;
160 
161   GLfloat thrust;
162   gPs velocity;
163   GLfloat speed; //Relative speed
164   GLfloat distance;
165 
166   GLfloat rotationForce;
167 
168   int fuel;
169   int reloadTime; //After this amount of fames (60th's of 1 sec) player can shoot again
170   int ammo;
171 
172   gPs radarDest; //Destination for package, points to the base where package should be delivered
173   int destBase; // 0 = no package, id of base.
174   int numBases; // Number of bases on map, set by loadMap
175   int score;
176   int numMissions; //number of finished missions
177   int level;
178   int lives;
179 
180   vector<vert> shipVerts;
181   vector<vert> baseVerts;
182   vector<vert> enemyVerts;
183 
184   vector<vert> shipStaticVerts;
185   vector<vert> baseStaticVerts;
186   vector<vert> enemyStaticVerts;
187 
188   vector<int> nextObjective; //Where to deliver to next.
189   int currentObjective; //What right now?
190 
191 };
192 struct gameInfoStruct gameInfo;
193 
abs2(GLfloat x)194 GLfloat abs2(GLfloat x)
195 {
196       if (x<0) {return -x;}
197       return x;
198 }
199 
LinesCross(gPs aLineA,gPs aLineB,gPs bLineA,gPs bLineB)200 bool LinesCross(gPs aLineA, gPs aLineB, gPs bLineA, gPs bLineB)
201 {
202         //First line, first point
203         GLfloat x0 = aLineA.x;
204         GLfloat y0 = aLineA.y;
205         //First Line, second point
206         GLfloat x1 = aLineB.x;
207         GLfloat y1 = aLineB.y;
208         //Second Line, First point
209         GLfloat x2 = bLineA.x;
210         GLfloat y2 = bLineA.y;
211         //Second Line, Second point
212         GLfloat x3 = bLineB.x;
213         GLfloat y3 = bLineB.y;
214 
215 
216 	GLfloat d=(x1-x0)*(y3-y2)-(y1-y0)*(x3-x2);
217 	if (abs2(d)<0.001f) {return 0;}
218 	GLfloat AB=((y0-y2)*(x3-x2)-(x0-x2)*(y3-y2))/d;
219 	if (AB>0.0 && AB<1.0)
220 	{
221 		GLfloat CD=((y0-y2)*(x1-x0)-(x0-x2)*(y1-y0))/d;
222 		if (CD>0.0 && CD<1.0)
223                 {
224                   return 1;
225                 }
226         }
227 
228   return 0;
229 }
230 
231 struct structSpark {
232   gPs pa,pb, v; //Position and velocity
233   GLfloat color[4];
234   int life; //in frames
235   int age; //in frames
236 };
237 
238 class classSparkler
239 {
240   private:
241     list<struct structSpark> sparks;
242   public:
243     void spawn(gPs p, GLfloat rotation, int degree, GLfloat velocity, int num);
244     void render();
245 };
246 classSparkler sparkler;
247 
248 //Spawn sparks, used for the thruster and explotions
249 //gPs position, rotation (angle of emitting), degrees of freedom, gPs velocity, number of sparks, maxLife
spawn(gPs p,GLfloat rotation,int degree,GLfloat velocity,int num)250 void classSparkler::spawn(gPs p, GLfloat rotation, int degree, GLfloat velocity, int num)
251 {
252   struct structSpark tS;
253   for(int i = 0; i != num; i++)
254   {
255     GLfloat rotRad = ((rotation-(degree/2))+rand()%degree ) * 0.0174532925;
256     tS.life = rand()%60;
257     tS.age = 0;
258     tS.color[0] = 1;
259     tS.color[1] = float(rand()%1000) / 1000.0 ;
260     tS.color[2] = 0;
261     tS.color[3] = 1.0;
262     tS.pa.x = p.x;
263     tS.pa.y = p.y;
264     int r=rand()%5;
265     tS.pb.x = p.x + float(r) *cos( rotRad );
266     tS.pb.y = p.y + float(r) *sin( rotRad );
267     tS.v.x = velocity*cos( rotRad );
268     tS.v.y = velocity*sin( rotRad );
269 
270     sparks.push_back(tS);
271   }
272 }
273 
render()274 void classSparkler::render()
275 {
276   glBegin( GL_LINES );
277     for(list <struct structSpark>::iterator it = sparks.begin(); it != sparks.end(); ++it)
278     {
279       //Move spark.
280       it->pa.x += it->v.x;
281       it->pa.y += it->v.y;
282       it->pb.x += it->v.x;
283       it->pb.y += it->v.y;
284 
285       //change color
286       it->color[1] -= float(rand()%20/1000.0);
287       it->color[3] = (1.0/it->life)*(it->life-it->age);
288 
289       glColor4f( it->color[0],it->color[1],it->color[2], it->color[3] );
290       glVertex2f(it->pa.x - dispInfo.camPos.x, it->pa.y - dispInfo.camPos.y);
291       glVertex2f(it->pb.x - dispInfo.camPos.x, it->pb.y - dispInfo.camPos.y);
292 
293       it->age++;
294       if(it->age > it->life)
295       {
296         it = sparks.erase(it);
297       }
298     }
299   glEnd( );
300 }
301 
302 struct structShot {
303   gPs pa,pb;
304   gPs v;
305   int age, life;
306   bool fromShip; //if 1, wont collide with ship
307 };
308 
309 class classBullets {
310   private:
311   vector<struct structShot> shots;
312   public:
313   void shoot(entity owner, gPs velocity);
314   void render();
315   bool col(vector<vert> target, bool isShip);
316   void envCol(vector< vector<vert> > polys);
317 };
318 
envCol(vector<vector<vert>> polys)319 void classBullets::envCol(vector< vector<vert> > polys)
320 {
321   for(vector< vector<vert> >::iterator PolyIt = polys.begin(); PolyIt != polys.end(); ++PolyIt)
322   {
323     classBullets::col(*PolyIt, 0);
324   }
325 }
326 
col(vector<vert> target,bool isShip)327 bool classBullets::col(vector<vert> target, bool isShip)
328 {
329   gPs tLineA, tLineB;
330   for(vector<struct structShot>::iterator it = shots.begin(); it != shots.end(); ++it)
331   {
332     if(it->fromShip != isShip)
333     {
334       for(int ii=0; ii < target.size(); ii++)
335       {
336         if(ii==0)
337         {
338           tLineB = target[ii].p;
339         } else {
340           tLineA = tLineB;
341           tLineB = target[ii].p;
342 
343           if(LinesCross(tLineA, tLineB, it->pa, it->pb))
344           {
345             //Remove bullet.
346             it = shots.erase(it);
347             return(1);
348           }
349         }
350       }
351     }
352   }
353   return false;
354 }
355 
shoot(entity owner,gPs velocity)356 void classBullets::shoot(entity owner, gPs velocity)
357 {
358   struct structShot ts;
359 
360   ts.pb = owner.p;
361   ts.pa.x = owner.p.x + 6.0* cos( owner.rotation * 0.0174532925 );
362   ts.pa.y = owner.p.y + 6.0* sin( owner.rotation * 0.0174532925 );
363 
364   ts.v.x = velocity.x + 1.0 * cos( owner.rotation * 0.0174532925 );
365   ts.v.y = velocity.y + 1.0 * sin( owner.rotation * 0.0174532925 );
366 
367   ts.age = 0;
368   ts.life = 40;
369 
370   if(owner.type == entShip)
371   {
372     ts.fromShip=1;
373   } else {
374     ts.fromShip=0;
375   }
376 
377   shots.push_back(ts);
378   soundMan->add(sfxLaser);
379 }
380 
render()381 void classBullets::render()
382 {
383 
384   glBegin( GL_LINES );
385   for(vector<struct structShot>::iterator it = shots.begin(); it != shots.end(); ++it)
386   {
387     it->pa.x += it->v.x;
388     it->pa.y += it->v.y;
389     it->pb.x += it->v.x;
390     it->pb.y += it->v.y;
391 
392     glColor4f( 1.0, 0.5,0.0, 1.0 );
393     glVertex2f(it->pa.x - dispInfo.camPos.x, it->pa.y - dispInfo.camPos.y);
394     glVertex2f(it->pb.x - dispInfo.camPos.x, it->pb.y - dispInfo.camPos.y);
395 
396     it->age++;
397     if(it->age > it->life)
398     {
399        it = shots.erase(it);
400        if(shots.size() < 1)
401         break;
402     }
403   }
404   glEnd( );
405 }
406 class classBullets bullets;
407 
setSeneSize()408 void setSeneSize()
409 {
410   glMatrixMode(GL_PROJECTION);
411   glLoadIdentity();
412   GLfloat glSceneRes = dispInfo.glZoom;;
413   dispInfo.glSceneSize.x = glSceneRes * dispInfo.aspect;
414   dispInfo.glSceneSize.y = glSceneRes;
415   dispInfo.glUnitsPrPixel = (glSceneRes / float(dispInfo.dispSize.y)) * 2.0;
416   glOrtho( -dispInfo.glSceneSize.x, dispInfo.glSceneSize.x, -dispInfo.glSceneSize.y, dispInfo.glSceneSize.y, 0,1);
417   glMatrixMode(GL_MODELVIEW);
418 
419   glEnable(GL_BLEND);
420   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
421   glEnable(GL_LINE_SMOOTH);
422   glEnable(GL_POINT_SMOOTH );
423 
424   glLineWidth ( 1.0 );
425 }
426 
setRes(int x,int y)427 void setRes(int x, int y)
428 {
429   SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, 1 );
430 
431   /** Try to enable vsync **/
432   if(vsync)
433   {
434     SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);
435   }
436 
437   int more=0;
438   dispInfo.fullScreen ? more=SDL_FULLSCREEN : more=0;
439 
440   /*SDL_Surface *screen =*/ SDL_SetVideoMode(x,y,32, SDL_OPENGL|SDL_RESIZABLE|more);
441   glDisable(GL_DEPTH_TEST);
442 
443   dispInfo.aspect = float(x) / float(y);
444   dispInfo.dispSize.x = x;
445   dispInfo.dispSize.y = y;
446   dispInfo.dispHalfSize.x = float(x)/2.0;
447   dispInfo.dispHalfSize.y = float(y)/2.0;
448 
449 
450   glViewport(0,0,x,y);
451 
452 
453   glClearStencil(0); //stencil
454   setSeneSize();
455 
456   glLineStipple (1, 0xCCCC);
457   glClearColor(dispInfo.bgColor[0],dispInfo.bgColor[1],dispInfo.bgColor[2],1.0f);
458   if(glText != NULL)
459     delete glText;
460 
461   glText = new glTextClass;
462   glDisable( GL_TEXTURE_2D );
463 
464 }
465 
466 /*  It almost work, except when two verticies are both outside the screen, but the line between them crosses into the screen. */
467 /*
468 void isOnScreen(vector <vector<vert> >& polys, vector< vector<vert> >& onScreenPolys, gPs scrP, gPs scrN)
469 {
470   bool polyNotEmpty, lastVis; //is this going to be visible? was the last one ?
471   int numVert; //number of verticies, number of submitted (to the list to render)
472   vector<vert> tPoly;
473   onScreenPolys.clear();
474 
475   //Loop through polys.
476   for(vector <vector <vert> >::iterator polyIt = polys.begin(); polyIt != polys.end(); ++polyIt)
477   {
478     numVert=0;
479     lastVis=0;
480     tPoly.clear();
481     polyNotEmpty=0;
482     for(vector <vert>::iterator vertIt = polyIt->begin(); vertIt != polyIt->end(); ++vertIt)
483     {
484       //Visible?
485       if(vertIt->p.x > scrN.x && vertIt->p.x < scrP.x && vertIt->p.y < scrP.y && vertIt->p.y > scrN.y)
486       {
487         polyNotEmpty=1;
488         //Was the one before me on ?
489         if(numVert!=0 && lastVis==0)
490         {
491           //Put it on
492           tPoly.push_back( polyIt->at(numVert-1) );
493         }
494         lastVis=1; //Telling it to the next.
495         tPoly.push_back( *vertIt );
496       } else {
497         if(lastVis)
498         {
499           lastVis=0;
500           tPoly.push_back( *vertIt );
501 
502           polyNotEmpty=0;
503           onScreenPolys.push_back( tPoly );
504           tPoly.clear();
505 
506         }
507       }
508         numVert++;
509     }
510     //That was one poly, check if any verts is there.
511     if(polyNotEmpty)
512     {
513       onScreenPolys.push_back( tPoly );
514     }
515   }
516 }*/
517 
renderPolys(vector<vector<vert>> polys)518 void renderPolys(vector< vector<vert> > polys)
519 {
520   int pc=0;
521   int pp=0;
522   for(vector <vector <vert> >::iterator it = polys.begin(); it != polys.end(); ++it)
523   {
524     glBegin( GL_LINE_STRIP );
525     for(vector <vert>::iterator itt = it->begin(); itt != it->end(); ++itt)
526     {
527       if(itt->color[0] == -1.0)
528       {
529         glColor4f(0,0,0,0);
530       } else {
531         glColor4f(itt->color[0], itt->color[1], itt->color[2], 1.0);
532       }
533 
534       glVertex2f(itt->p.x-dispInfo.camPos.x, itt->p.y-dispInfo.camPos.y);
535 
536     }
537     glEnd();
538   }
539 
540   //Draw verts if in editor
541   if(gameState == GameStateEditor)
542   {
543     glPointSize( 3.0 );
544     for(vector <vector <vert> >::iterator it = polys.begin(); it != polys.end(); ++it)
545     {
546       glColor4f(1,1,1,1);
547       glBegin( GL_POINTS );
548       for(vector <vert>::iterator itt = it->begin(); itt != it->end(); ++itt)
549       {
550         glVertex2f(itt->p.x-dispInfo.camPos.x, itt->p.y-dispInfo.camPos.y);
551       }
552       glEnd();
553     }
554   }
555 
556 
557 }
558 
559 
560 //Move and rotate an entity according to ent.p and ent.rotation
updateEntVerts(entity ent,vector<vert> & entverts,vector<vert> statV)561 void updateEntVerts(entity ent, vector<vert>& entverts, vector<vert> statV )
562 {
563   entverts = statV;
564 
565   GLfloat tx, ty;
566 
567   for(vector<vert>::iterator i = entverts.begin(); i != entverts.end(); ++i)
568   {
569     tx = i->p.x * cos( (ent.rotation-90.0) * 0.0174532925 ) - ( i->p.y *sin( (ent.rotation-90.0) * 0.0174532925 )) ;
570     ty = i->p.x * sin( (ent.rotation-90.0) * 0.0174532925 ) + ( i->p.y *cos( (ent.rotation-90.0) * 0.0174532925 ));
571     i->p.x=tx;
572     i->p.y=ty;
573     i->p.x += ent.p.x;
574     i->p.y += ent.p.y;
575   }
576 
577 }
578 
579 
580 #define PI 3.14159265
renderEntities(vector<entity> ents)581 void renderEntities(vector<entity> ents)
582 {
583   for(vector<entity>::iterator it = ents.begin(); it != ents.end(); ++it)
584   {
585     if(it->type==entShip)
586     {
587       updateEntVerts(*it, gameInfo.shipVerts, gameInfo.shipStaticVerts);
588 
589       if(gameState == GameStateEditor)
590       {
591         glColor3f(1,0,1);
592         glBegin(GL_POINTS);
593           glVertex2f(it->p.x - dispInfo.camPos.x, it->p.y - dispInfo.camPos.y);
594         glEnd( );
595         glPointSize(1.0);
596       }
597 
598       if(gameInfo.thrust > 0)
599       {
600         gPs tP = it->p;
601         tP.x += -1.3 * cos(it->rotation* 0.0174532925);
602         tP.y += -1.3 * sin(it->rotation* 0.0174532925);
603 
604         sparkler.spawn(tP, it->rotation+180, 40, 0.7, 7);
605       }
606 
607 
608       glBegin(GL_LINE_STRIP);
609       for(vector<vert>::iterator shipIt = gameInfo.shipVerts.begin(); shipIt != gameInfo.shipVerts.end(); ++shipIt)
610       {
611         glColor3f( shipIt->color[0],shipIt->color[1],shipIt->color[2] );
612         glVertex2f( shipIt->p.x - dispInfo.camPos.x, shipIt->p.y - dispInfo.camPos.y );
613       }
614       glEnd( );
615 
616 
617     }
618     if(it->type==entBase)
619     {
620 
621       updateEntVerts(*it, gameInfo.baseVerts, gameInfo.baseStaticVerts);
622 
623       if(gameState == GameStateEditor)
624       {
625         glPointSize(2.0);
626         glColor3f(0,1,1);
627         glBegin(GL_POINTS);
628           glVertex2f(it->p.x - dispInfo.camPos.x, it->p.y - dispInfo.camPos.y);
629         glEnd( );
630         glPointSize(1.0);
631       }
632 
633       glBegin(GL_LINE_STRIP);
634       for(vector<vert>::iterator baseIt = gameInfo.baseVerts.begin(); baseIt != gameInfo.baseVerts.end(); ++baseIt)
635       {
636         glColor3f( baseIt->color[0],baseIt->color[1],baseIt->color[2] );
637         glVertex2f( baseIt->p.x - dispInfo.camPos.x, baseIt->p.y - dispInfo.camPos.y );
638       }
639       glEnd( );
640     }
641 
642     if(it->type==entEnemy)
643     {
644 
645       updateEntVerts(*it, gameInfo.enemyVerts, gameInfo.enemyStaticVerts);
646 
647       if(gameState == GameStateEditor)
648       {
649         glPointSize(2.0);
650         glColor3f(0,1,1);
651         glBegin(GL_POINTS);
652           glVertex2f(it->p.x - dispInfo.camPos.x, it->p.y - dispInfo.camPos.y);
653         glEnd( );
654         glPointSize(1.0);
655       }
656 
657       glBegin(GL_LINE_STRIP);
658       for(vector<vert>::iterator It = gameInfo.enemyVerts.begin(); It != gameInfo.enemyVerts.end(); ++It)
659       {
660         glColor3f( It->color[0],It->color[1],It->color[2] );
661         glVertex2f( It->p.x - dispInfo.camPos.x, It->p.y - dispInfo.camPos.y );
662       }
663       glEnd( );
664     }
665 
666   }
667 }
668 
669 GLuint gridDL;
670 
genGrid()671 void genGrid()
672 {
673 	GLfloat step = 4.95946, steps=1000;
674 	GLfloat len=step*steps;
675 	GLfloat f=0;
676 
677 	gridDL = glGenLists(1);
678 	glNewList( gridDL, GL_COMPILE );
679 	glColor3f(0.3,0.3,0.3);
680 	glBegin(GL_LINES);
681 
682 	f = -( len/2.0 );
683         while(f <= (len)/2.0 )
684         {
685           glVertex2f(f, (len/2.0) );
686           glVertex2f(f, -(len/2.0) );
687           f+=step;
688         }
689 
690 	f = -( len/2.0 );
691         while(f <= (len)/2.0 )
692         {
693           glVertex2f( (len/2.0), f );
694           glVertex2f( -(len/2.0), f );
695           f+=step;
696         }
697 
698 	glEnd( );
699 	glEndList();
700 }
701 
drawGrid()702 void drawGrid()
703 {
704 	glPushMatrix();
705 	glLoadIdentity();
706 	glTranslatef( -dispInfo.camPos.x, -dispInfo.camPos.y, 0 );
707 	glCallList(gridDL);
708 	glPopMatrix();
709 }
710 
saveMap(vector<vector<vert>> verts,vector<entity> ents,string FileName)711 void saveMap(vector< vector<vert> >verts, vector<entity> ents, string FileName)
712 {
713   //Open file stream
714   ofstream save;
715   save.open( FileName.data() , ios::out | ios::trunc);
716 
717   if(!save.is_open())
718   {
719     cout << "File open err."<<endl;
720     return;
721   }
722   //Save polys:
723   for(vector< vector<vert> >::iterator it = verts.begin(); it != verts.end(); ++it)
724   {
725     save << "StartPoly" << endl;
726     for(vector<vert>::iterator itt = it->begin(); itt != it->end(); ++itt)
727     {
728       save << "StartVert" << endl;
729       save << itt->p.x << endl;
730       save << itt->p.y << endl;
731       save << itt->color[0] << endl;
732       save << itt->color[1] << endl;
733       save << itt->color[2] << endl;
734       save << itt->collision << endl;
735       save << "EndVert" << endl;
736     }
737     save << "EndPoly" << endl;
738   }
739 
740   //Save ents
741   for(vector<entity>::iterator it = ents.begin(); it != ents.end(); ++it)
742   {
743     {
744       save << "StartEntity" << endl;
745       save << it->p.x << endl;
746       save << it->p.y << endl;
747       save << it->type << endl;
748       save << it->rotation << endl;
749       save << it->id << endl;
750       save << "EndEntity" << endl;
751     }
752 
753   }
754 
755 
756   //Save mission
757   if(gameInfo.nextObjective.size() > 1)
758   {
759     save << "StartMission" << endl;
760     for(int i = 0; i < gameInfo.nextObjective.size(); i++)
761     {
762       save << gameInfo.nextObjective[i] << endl;
763     }
764     save << "EndMission" << endl;
765   }
766 
767   save.close();
768 }
769 
770 
loadMap(vector<vector<vert>> & polys,vector<entity> & ents)771 void loadMap(vector< vector<vert> >& polys, vector<entity>& ents)
772 {
773   polys.clear();
774   ents.clear();
775   string line;
776   ifstream load;
777   vector<vert> tvs; //temp to store the poly as we read it
778   vert tv; //temp to store the vert as we read it
779   entity te; //temp to store the entity while we read it
780   gameInfo.numBases=0;
781   gameInfo.nextObjective.clear();
782   load.open(levelFile.data());
783 
784   if(!load.is_open())
785   {
786     cout << "could not load '" << levelFile << "'" << endl;
787     return;
788   }
789 
790   int parseState=0, dataNum=0;
791 
792   while(!load.eof())
793   {
794     getline(load, line);
795     if(line == "StartPoly")
796     {
797       parseState=1;
798     } else if(line=="EndPoly")
799     {
800       parseState=0;
801       polys.push_back(tvs);
802       tvs.clear();
803     } else if(parseState==1)
804     {
805       if(line == "StartVert")
806       {
807         parseState=2;
808         dataNum=0;
809       }
810     } else if(parseState==2)
811     {
812       if(line == "EndVert")
813       {
814         tvs.push_back(tv);
815         parseState=1;
816       } else {
817         dataNum++;
818         switch(dataNum)
819         {
820           case 1:
821           tv.p.x = atof(line.data());
822           break;
823           case 2:
824           tv.p.y = atof(line.data());
825           break;
826           case 3:
827           tv.color[0] = atof(line.data());
828           break;
829           case 4:
830           tv.color[1] = atof(line.data());
831           break;
832           case 5:
833           tv.color[2] = atof(line.data());
834           break;
835           case 6:
836           tv.collision = atoi(line.data());
837           break;
838           default:
839           cout << "??" << line << endl;
840           break;
841         }
842       }
843     } else if(line =="StartEntity")
844     {
845       parseState=3;
846       dataNum=0;
847     } else if(parseState==3)
848     {
849       if(line=="EndEntity")
850       {
851         dataNum=0;
852         te.baseP = te.p;
853         ents.push_back(te);
854         parseState=0;
855       } else {
856         dataNum++;
857         switch(dataNum)
858         {
859           case 1:
860             te.p.x = atof(line.data());
861             break;
862           case 2:
863             te.p.y = atof(line.data());
864             break;
865           case 3:
866             te.type = atoi(line.data());
867             if(te.type==entBase)
868             {
869               gameInfo.numBases++;
870             }
871             break;
872           case 4:
873             te.rotation = atof(line.data());
874             break;
875           case 5:
876             te.id = atoi(line.data());
877             if(te.type==entBase && te.id != gameInfo.numBases)
878             {
879               cout << "error: base entity have id:" << te.id << " but numBases is:" << gameInfo.numBases << endl;
880             }
881             break;
882           default:
883             cout << ">?" << line << endl;
884             break;
885         }
886       }
887     } else if(line=="StartMission")
888     {
889       parseState=4;
890     } else if(parseState==4)
891     {
892       if(line=="EndMission")
893       {
894         parseState=0;
895       } else {
896         gameInfo.nextObjective.push_back( atoi(line.data()) );
897       }
898     }
899   }
900 
901 
902 }
903 
readEnt(string File,vector<vert> & verts)904 void readEnt(string File, vector<vert>& verts)
905 {
906   string line;
907   ifstream f;
908   vert tv; //temp to store the vert as we read it
909 
910   f.open(File.data());
911   if(!f.is_open())
912   {
913     cout << "Failed to open file" << endl;
914     return;
915   }
916 
917   int parseState=0, dataNum=0;
918 
919   while(!f.eof())
920   {
921     getline(f, line);
922     if(line == "StartVert")
923     {
924       parseState=1;
925       dataNum=0;
926     } else if(parseState==1)
927     {
928       if(line == "EndVert")
929       {
930         parseState=0;
931         verts.push_back(tv);
932       } else {
933         dataNum++;
934         switch(dataNum)
935         {
936           case 1:
937           tv.p.x = atof(line.data());
938           break;
939           case 2:
940           tv.p.y = atof(line.data());
941           case 3:
942           tv.color[0] = atof(line.data());
943           break;
944           case 4:
945           tv.color[1] = atof(line.data());
946           break;
947           case 5:
948           tv.color[2] = atof(line.data());
949           break;
950           case 6:
951           tv.collision = atoi(line.data());
952           break;
953           default:
954           cout << "??" << line << endl;
955           break;
956         }
957 
958       }
959     }
960   }
961 
962 }
963 
boxCol(gPs posa,gPs posb,GLfloat dist)964 bool boxCol(gPs posa, gPs posb, GLfloat dist)
965 {
966   if(posa.x < posb.x+dist && posa.x > posb.x-dist)
967   {
968     if(posa.y < posb.y+dist && posa.y > posb.y-dist)
969     {
970       return(1);
971     }
972   }
973   return(0);
974 }
975 
PolyCol(vector<vert> PolyA,vector<vert> PolyB)976 bool PolyCol( vector<vert> PolyA, vector<vert> PolyB  )
977 {
978   gPs paLineA, paLineB, pbLineA, pbLineB;
979   bool paFirst=1, pbFirst=1;
980   int prevColType=0;
981   int checks=0;
982 
983   for( vector<vert>::iterator paVertIt = PolyA.begin(); paVertIt != PolyA.end(); ++paVertIt)
984   {
985     if(paVertIt->collision)
986     {
987       if(paFirst || prevColType == 2) //if the last one was a 2, this one is the start of the next line to collision detect
988       {
989         paFirst=0;
990         paLineB=paVertIt->p;
991       } else {
992         paLineA=paLineB;
993         paLineB=paVertIt->p;
994 
995 
996         pbFirst=1;
997         //Great now we have a line, lets check it against every line in the other poly.
998         for(vector<vert>::iterator pbVertIt = PolyB.begin(); pbVertIt != PolyB.end(); ++pbVertIt)
999         {
1000           if(pbVertIt->collision)
1001           {
1002             if(pbFirst)
1003             {
1004               pbFirst=0;
1005               pbLineB=pbVertIt->p;
1006             } else {
1007               pbLineA=pbLineB;
1008               pbLineB=pbVertIt->p;
1009 
1010               //Here we have two lines. paLineA, paLineB, and pbLineA, pbLineB.
1011               checks++;
1012               if(LinesCross(paLineA, paLineB, pbLineA, pbLineB))
1013               {
1014                 return(1);
1015               }
1016 
1017             }
1018           }
1019         }
1020 
1021       }
1022     }
1023     prevColType = paVertIt->collision;
1024   }
1025   return(0);
1026 }
1027 
1028 
landCol(vector<vert> baseVerts,vector<vert> shipVerts)1029 bool landCol(vector<vert> baseVerts, vector<vert> shipVerts)
1030 {
1031 
1032   gPs baseA, baseB;
1033   gPs shipA, shipB;
1034   int prevColType=0;
1035 
1036   //Find points on ship
1037   for(vector<vert>::iterator shipIt = shipVerts.begin(); shipIt != shipVerts.end(); ++shipIt)
1038   {
1039     if(shipIt->collision == 2)
1040     {
1041       if(prevColType == 0)
1042       {
1043         shipA = shipIt->p;
1044         prevColType++;
1045       } else {
1046         shipB = shipIt->p;
1047         prevColType++;
1048       }
1049     }
1050   }
1051 
1052   prevColType=0;
1053   for(vector<vert>::iterator baseIt = baseVerts.begin(); baseIt != baseVerts.end(); ++baseIt)
1054   {
1055     //Find the line to check with
1056     if(prevColType==2)
1057     {
1058       baseB = baseIt->p;
1059       if(shipA.x > baseA.x && shipA.x < baseB.x) //Is left side inside
1060       {
1061         if(shipB.x > baseA.x && shipB.x < baseB.x) // Is right side inside
1062         {
1063           if(shipA.y < baseA.y && shipB.y < baseB.y) //Is left side under the line
1064           {
1065             if(shipB.y < baseA.y && shipB.y < baseB.y) //Is right side under the line
1066             {
1067               if(shipA.y > baseA.y-1.0 && shipB.y > baseA.y-1.0) //Check that left side is above the height
1068               {
1069                 //check velocity:
1070                 //cout << "Impact:"<<endl<<"Xvel:" << gameInfo.velocity.x<<" Yvel: " << gameInfo.velocity.y << endl << "Rot:" << gameInfo.rotationForce << "." << endl;
1071 
1072                 if(gameInfo.velocity.y >= gameRules.maxLandingYel) //If it's not smaller, it's not faster
1073                 {
1074                   GLfloat temp = gameInfo.velocity.x;
1075                   if(temp < 0)
1076                     temp *= -1.0;
1077 
1078                   if(temp <= gameRules.maxLandingXvel) //it have to be slower
1079                   {
1080 
1081                     temp = gameInfo.rotationForce;
1082                     if(temp < 0)
1083                       temp *= -1.0;
1084                     if(temp <= gameRules.maxLandingRotForce)
1085                     {
1086                       return(1);
1087                     }
1088                   }
1089                 }
1090               }
1091             }
1092           }
1093         }
1094       }
1095     }
1096     prevColType = baseIt->collision;
1097     if(prevColType==2)
1098       baseA = baseIt->p;
1099   }
1100   return(0);
1101 }
1102 
1103 static char plInfo[] =
1104 "                         -= Welcome to OSGG =-\n\n"
1105 "  Your objective: Land on platforms as shown on radar.\n\n"
1106 "  Game Controls:\n"
1107 "    Arrows keys: Thrust/turn\n"
1108 "    Mouse wheel: Zoom in/Out\n"
1109 "    h: show/hide this screen\n"
1110 "    t: Restart Level\n"
1111 "    s: Go to level editor\n"
1112 "    F1: Start recording demo\n"
1113 "    F2: Stop demo record (save to ./demo.bin)\n"
1114 "    F10: Toggle sound\n"
1115 "    F11: Toggle fullscreen\n"
1116 "    F12: Screenshot\n"
1117 "    Pause: Pause the game\n"
1118 "    ESC: Exit the program";
1119 
1120 static char edInfo[] =
1121 "                       -= The OSGG Level Editor =-\n\n"
1122 "  ESC = Cancel poly creation, or exit program\n"
1123 "  Left mouse button: Add/Edit/Drag\n"
1124 "  Right mouse button: Move around the board\n"
1125 "  Mouse wheel: Zoom in/Out\n"
1126 "  0: Adding: Polygons\n"
1127 "  1: Collision detection on for next verticies\n"
1128 "  2: Collision detection off for the next verticies\n"
1129 "  4: Next vertices are white - 5: Grey - 6: Invisible\n"
1130 "  7: Red - 8: Green - 9: Blue\n"
1131 "  q: Adding: The ship (Player start position)\n"
1132 "  w: Adding: Bases\n"
1133 "  e: Adding: enemies\n"
1134 "  m: Adding: Mission waypoints.\n"
1135 "  n: Enable defined waypoints. (Press before saving)\n"
1136 "  g: save map - t: start new game from starting level\n"
1137 "  s: Back to game\n"
1138 "  del: remove polygon or entity\n"
1139 "  /* 3: Landing platform (not for levels, only verts.txt)     *\n"
1140 "   * d: Write the first polygon to verts.txt (not for levels) */";
1141 
renderHelp()1142 void renderHelp() {
1143   if(showHelp) {
1144     char* info;
1145     char buf[1024];
1146     if( gameState == GameStatePlaying || gameState == GameStatePause )
1147     {
1148       info = plInfo;
1149       buf[0]=0;
1150     } else if( gameState == GameStateEditor )
1151     {
1152       info = edInfo;
1153       sprintf(buf, "File: %s", levelFile.c_str() );
1154     } else {
1155       return;
1156     }
1157 
1158     //Whoa, I was crazy back then (too)
1159     GLfloat scale = dispInfo.glZoom/100.0;
1160 
1161     glColor4f(0.05,0.05,0.05,0.8);
1162     glBegin( GL_QUADS );
1163       glVertex2f(-125.0*scale, 95.0*scale );
1164       glVertex2f(125.0*scale, 95.0*scale );
1165       glVertex2f(125.0*scale, -95.0*scale );
1166       glVertex2f(-125.0*scale, -95.0*scale );
1167     glEnd( );
1168 
1169     glColor4f(1,1,1,1);
1170     glText->write(info, FONT_DEFAULT, 50.0*scale, -120*scale, 85*scale );
1171     glColor4f(1,0,0,1);
1172     glText->write(buf, FONT_DEFAULT, 40.0*scale, -120*scale, -90*scale );
1173 
1174   }
1175 }
1176 
renderRadar(vector<entity> ents,vector<vector<vert>> Poly)1177 void renderRadar(vector<entity> ents, vector<vector <vert> > Poly)
1178 {
1179   //The radar and everything should be the same size regardless of zoom
1180   //assume
1181   char txt[32];
1182 
1183   GLfloat scale = dispInfo.glZoom/100.0;
1184   GLfloat mapScale = scale / 10.0;
1185 
1186   //translate into place.
1187   glTranslatef(90.0*scale,-80.0*scale,0.0);
1188 
1189   glEnable(GL_STENCIL_TEST);
1190   glStencilFunc(GL_ALWAYS, 1, 1); // Always Passes, 1 Bit Plane, 1 As Mask
1191   glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); // We Set The Stencil Buffer To 1 Where We Draw Any Polygon
1192 
1193   glColor4f(0,0,0, 0.8);
1194   glBegin( GL_QUADS );
1195     glVertex2f(15.0*scale, 15.0*scale );
1196     glVertex2f(-15.0*scale, 15.0*scale );
1197     glVertex2f(-15.0*scale, -15.0*scale );
1198     glVertex2f(15.0*scale, -15.0*scale );
1199   glEnd( );
1200 
1201 
1202   glStencilFunc(GL_EQUAL, 1, 1);
1203   glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1204 
1205 
1206   glPushMatrix(); //Push matrix onto the stack
1207   //Draw the map, scale it down.
1208   for(vector< vector<vert> >::iterator PolyIt = Poly.begin(); PolyIt != Poly.end(); ++PolyIt)
1209   {
1210     glBegin( GL_LINE_STRIP );
1211       for(vector<vert>::iterator vertIt = PolyIt->begin(); vertIt != PolyIt->end(); ++vertIt)
1212       {
1213         if(vertIt->color[0] == -1.0)
1214         {
1215           glColor4f(0,0,0,0);
1216         } else {
1217           glColor4f(1,1,1,1);
1218         }
1219         glVertex2f( (vertIt->p.x-dispInfo.camPos.x)*mapScale,  (vertIt->p.y-dispInfo.camPos.y)*mapScale);
1220       }
1221     glEnd( );
1222   }
1223 
1224   //Draw destination (if any)
1225   if(gameInfo.destBase)
1226   {
1227     glColor3f(1,1,0);
1228      glEnable (GL_LINE_STIPPLE);
1229     glBegin( GL_LINES );
1230       glVertex2f(0,0);
1231       glVertex2f( (gameInfo.radarDest.x-dispInfo.camPos.x)*mapScale, (gameInfo.radarDest.y-dispInfo.camPos.y)*mapScale );
1232     glEnd( );
1233      glDisable (GL_LINE_STIPPLE);
1234   }
1235 
1236   glPointSize( 3.0 );
1237   for(vector<entity>::iterator entIt = ents.begin(); entIt != ents.end(); ++entIt)
1238   {
1239     glBegin(GL_POINTS);
1240     if(entIt->type==entShip)
1241     {
1242       glColor3f(0,0,1);
1243     } else if(entIt->type==entBase)
1244     {
1245       glColor3f(0,1,0);
1246     } else if(entIt->type==entEnemy) {
1247       glColor3f(1,0,0);
1248     } else {
1249       glColor3f(1,0,1);
1250     }
1251     glVertex2f((entIt->p.x-dispInfo.camPos.x)*mapScale,(entIt->p.y-dispInfo.camPos.y)*mapScale);
1252     glEnd( );
1253   }
1254 
1255   glEnd( );
1256 
1257   glPopMatrix();
1258   glDisable(GL_STENCIL_TEST);
1259 
1260   glColor3f( 0,1,0 );
1261   //Draw box around
1262   glBegin( GL_LINE_STRIP );
1263     glVertex2f(15*scale, 15*scale );
1264     glVertex2f(-15*scale, 15*scale );
1265     glVertex2f(-15*scale, -15*scale );
1266     glVertex2f(15*scale, -15*scale );
1267     glVertex2f(15*scale, 15*scale );
1268   glEnd( );
1269 
1270   //draw destination distance
1271   sprintf(txt, "> %0.1f u", gameInfo.distance );
1272   glColor4f(0,1,0,1);
1273   glText->write(txt, FONT_DEFAULT, 40.0*scale, -15*scale, 15*scale+(glText->getHeight(FONT_DEFAULT)*20.0*scale));
1274 
1275   glTranslatef(-35*scale, 0, 0);
1276 
1277   GLfloat S = 15.0*scale;
1278   glColor4f(0,0,0, 0.8);
1279   glBegin( GL_QUADS );
1280     glVertex2f(S, S );
1281     glVertex2f(-S, S );
1282     glVertex2f(-S, -S );
1283     glVertex2f(S, -S );
1284   glEnd( );
1285 
1286   //Draw velocities
1287   gPs vel, maxL;
1288   vel.x = (S/gameRules.maxLandingXvel) * (gameInfo.velocity.x/2.0);
1289   vel.y = (S/gameRules.maxLandingYel) * (gameInfo.velocity.y/2.0);
1290   vel.y *= -1;
1291 
1292   if(vel.x > S)
1293   {
1294     vel.x = S;
1295   } else if(vel.x < -S)
1296   {
1297     vel.x = -S;
1298   }
1299 
1300   if(vel.y > S)
1301   {
1302     vel.y = S;
1303   } else if(vel.y < -S)
1304   {
1305     vel.y = -S;
1306   }
1307 
1308   glColor4f( 1,1,1,1 );
1309   glBegin( GL_LINES );
1310     glVertex2f( 0,0 );
1311     glVertex2f( vel.x, 0 );
1312     glVertex2f( 0,0 );
1313     glVertex2f( 0, vel.y );
1314 
1315     glVertex2f( 0,0 );
1316     glVertex2f( vel.x,vel.y );
1317 
1318     if(gameInfo.velocity.y > 0)
1319     {
1320       vel.y = (gameRules.maxLandingYel-gameInfo.velocity.y);
1321     } else {
1322       vel.y = (gameRules.maxLandingYel+gameInfo.velocity.y);
1323     }
1324 
1325     if(gameInfo.velocity.x > 0)
1326     {
1327       vel.x = (gameRules.maxLandingXvel-gameInfo.velocity.x);
1328     } else {
1329       vel.x = (gameRules.maxLandingXvel+gameInfo.velocity.x);
1330     }
1331 
1332     glColor3f(1,0,0);
1333     glVertex2f( S/2.0 +(vel.x*scale), -S);
1334     glVertex2f( S/2.0 +(vel.x*scale),  S);
1335     glVertex2f( -S/2.0 -(vel.x*scale), -S);
1336     glVertex2f( -S/2.0 -(vel.x*scale),  S);
1337     glVertex2f(-S,  S/2.0 + (vel.y*scale) );
1338     glVertex2f( S, S/2.0 + (vel.y*scale) );
1339     glVertex2f(-S, -S/2.0- (vel.y*scale)  );
1340     glVertex2f( S, -S/2.0- (vel.y*scale)  );
1341 
1342     //reuse for drawing fuel
1343     vel.y = (double(S)/double(gameRules.fuelMaxFuel) * double(gameInfo.fuel))*2.0;
1344     glColor3f( 1,1,0 );
1345     glVertex2f(-14*scale, -S );
1346     glVertex2f(-14*scale, -S+vel.y);
1347 
1348     //and for drawing ammo
1349     vel.y = (double(S)/double(gameRules.ammoMaxAmmo) * double(gameInfo.ammo))*2.0;
1350     glColor3f( 1,0,1 );
1351     glVertex2f(-13*scale, -S );
1352     glVertex2f(-13*scale, -S+vel.y);
1353   glEnd( );
1354 
1355   glColor3f( 0, 1, 0);
1356   glBegin( GL_LINE_STRIP );
1357     glVertex2f(15*scale, 15*scale );
1358     glVertex2f(-15*scale, 15*scale );
1359     glVertex2f(-15*scale, -15*scale );
1360     glVertex2f(15*scale, -15*scale );
1361     glVertex2f(15*scale, 15*scale );
1362   glEnd( );
1363 
1364   //Draw speed
1365   sprintf(txt, "%0.1f u/T", gameInfo.speed);
1366   glText->write(txt, FONT_DEFAULT, 40.0*scale, -15*scale, 15*scale+(glText->getHeight(FONT_DEFAULT)*20.0*scale));
1367 
1368   glLoadIdentity();
1369 
1370 }
1371 
setMission(int missionId,vector<entity> ents)1372 void setMission(int missionId, vector<entity> ents)
1373 {
1374   gameInfo.destBase = gameInfo.nextObjective[missionId];
1375 
1376   //Set destination on radar.
1377   for(vector<entity>::iterator searchIt = ents.begin(); searchIt != ents.end(); ++searchIt)
1378   {
1379     if(searchIt->id == gameInfo.destBase)
1380     {
1381       gameInfo.radarDest = searchIt->p;
1382     }
1383   }
1384 }
1385 
initGame(vector<vector<vert>> & polys,vector<entity> & ents)1386 void initGame(vector< vector<vert> >& polys, vector<entity>& ents)
1387 {
1388   loadMap(polys, ents);
1389 
1390   gameInfo.currentObjective=0;
1391   gameInfo.score=0;
1392   gameInfo.destBase=0;
1393   gameInfo.fuel = gameRules.fuelMaxFuel;
1394   gameInfo.ammo = gameRules.ammoMaxAmmo;
1395 
1396   if(gameInfo.nextObjective.size() > 1)
1397     setMission(0,ents);
1398 
1399 
1400 
1401 }
1402 
advanceLevel(vector<vector<vert>> & polys,vector<entity> & ents)1403 void advanceLevel(vector< vector<vert> >& polys, vector<entity>& ents)
1404 {
1405   ostringstream t;
1406   t.clear();
1407   cout << endl;
1408   cout << "Completed" << endl;
1409   cout << "File " << levelFile <<endl;
1410   cout << "Time " << gameInfo.score/60 <<"." << int(((gameInfo.score%60)*2)) << endl;
1411 
1412   gameInfo.level++;
1413   t << "./levels/" << gameInfo.level << ".level";
1414   levelFile = t.str();
1415   initGame(polys,ents);
1416   gameState = GameStatePlaying;
1417 }
1418 
initNewGame(vector<vector<vert>> & polys,vector<entity> & ents)1419 void initNewGame(vector< vector<vert> >& polys, vector<entity>& ents)
1420 {
1421   gameRules.maxLandingRotForce = 1.0; //degrees, both ways
1422   gameRules.maxLandingYel = -0.20; //downward
1423   gameRules.maxLandingXvel= 0.15; //both sides
1424   gameRules.fuelConsumptionThrust = 15;
1425   gameRules.fuelConsumptionTurn = 4;
1426   gameRules.fuelMaxFuel = 5500;
1427   gameRules.ammoMaxAmmo = 1000;
1428 
1429   if(dispInfo.enableZoom)
1430     dispInfo.glBaseZoom = 18;
1431   else
1432     dispInfo.glBaseZoom = 28;
1433 
1434   dispInfo.glZoom = dispInfo.glBaseZoom;
1435   setSeneSize();
1436   gameState = GameStatePlaying;
1437 
1438   gameInfo.numMissions=0; //Amount of missions taken
1439   gameInfo.level=gameRules.startLevel;
1440   initGame(polys, ents);
1441 
1442 }
1443 
shipCrash(entity ship)1444 void shipCrash(entity ship)
1445 {
1446   soundMan->add(sfxBoom);
1447   sparkler.spawn(ship.p, 0, 360, 1, 100);
1448   gameInfo.velocity.x=0;
1449   gameInfo.velocity.y=0;
1450   gameInfo.thrust=0;
1451   gameInfo.rotationForce=0;
1452   gameState = GameStateGameOver;
1453 
1454   cout << endl;
1455   cout << "Dead" << endl;
1456   cout << "Level "<<gameInfo.level << endl;
1457 }
1458 
1459 struct gameInfoStruct snap;
1460 gPs snapPos;
1461 entity snapShip;
loadState(vector<entity> & entVect)1462 void loadState(vector<entity>& entVect)
1463 {
1464   int t=gameInfo.score;
1465   gameInfo = snap;
1466   gameInfo.score=t;
1467   for(vector<entity>::iterator it=entVect.begin(); it != entVect.end(); ++it)
1468   {
1469     if(it->type==entShip)
1470     {
1471       *it = snapShip;
1472     }
1473   }
1474 
1475   gameInfo.velocity.x=0;
1476   gameInfo.velocity.y=0;
1477   gameInfo.thrust=0;
1478   gameInfo.rotationForce=0;
1479 
1480 }
1481 
saveState(vector<entity> entVect)1482 void saveState(vector<entity> entVect)
1483 {
1484   snap = gameInfo;
1485   for(vector<entity>::iterator it=entVect.begin(); it != entVect.end(); ++it)
1486   {
1487     if(it->type==entShip)
1488     {
1489       snapPos = it->p;
1490       snapShip = *it;
1491     }
1492   }
1493 }
1494 
screenShot()1495 bool screenShot()
1496 {
1497   FILE *fscreen;
1498 
1499   char cName[256];
1500   int i = 0;
1501   bool found=0;
1502   while(!found)
1503   {
1504     sprintf(cName, "screenshot_%i.tga",i);
1505     fscreen = fopen(cName,"rb");
1506     if(fscreen==NULL)
1507       found=1;
1508     else
1509       fclose(fscreen);
1510       i++;
1511   }
1512   int nS = dispInfo.dispSize.x * dispInfo.dispSize.y * 3;
1513   GLubyte *px = new GLubyte[nS];
1514   if(px == NULL)
1515   {
1516     cout << "Alloc err, screenshot failed." <<endl;
1517     return 0;
1518   }
1519   fscreen = fopen(cName,"wb");
1520 
1521   glPixelStorei(GL_PACK_ALIGNMENT,1);
1522 
1523   glReadPixels(0, 0, dispInfo.dispSize.x, dispInfo.dispSize.y, GL_BGR, GL_UNSIGNED_BYTE, px);
1524 
1525 
1526   unsigned char TGAheader[12]={0,0,2,0,0,0,0,0,0,0,0,0};
1527   unsigned char header[6] = { (unsigned char)(dispInfo.dispSize.x%256),(unsigned char)(dispInfo.dispSize.x/256),(unsigned char)(dispInfo.dispSize.y%256),(unsigned char)(dispInfo.dispSize.y/256),24,0};
1528   fwrite(TGAheader, sizeof(unsigned char), 12, fscreen);
1529   fwrite(header, sizeof(unsigned char), 6, fscreen);
1530 
1531   fwrite(px, sizeof(GLubyte), nS, fscreen);
1532   fclose(fscreen);
1533   delete [] px;
1534   cout << "Wrote screenshot to '" << cName << "'" <<endl;
1535   return 1;
1536 }
1537 
1538 
demoRec(Uint8 * ks)1539 void demoRec(Uint8* ks)
1540 {
1541   demoFrame tf;
1542   tf.up = ks[SDLK_UP];
1543   tf.left = ks[SDLK_LEFT];
1544   tf.right = ks[SDLK_RIGHT];
1545   tf.shoot = ks[SDLK_SPACE];
1546 
1547   demoFrames.push_back(tf);
1548 }
1549 
saveDemo()1550 void saveDemo()
1551 {
1552   if(gameInfo.recording != 1)
1553     return;
1554 
1555   gameInfo.recording=0;
1556 
1557   fstream demo;
1558   demo.open( saveDemoFile.data(), ios::out | ios::trunc | ios::binary );
1559 
1560   if(!demo.is_open())
1561     return;
1562 
1563   demoFrame df;
1564   uint32_t dSize= (uint32_t)demoFrames.size();
1565 #if __BYTE_ORDER == __BIG_ENDIAN
1566   dSize = swapbytes32(dSize);
1567 #endif
1568 
1569   demo.write( (char *)(&dSize), sizeof(uint32_t) );
1570   cout << "Demo saved frames:" << demoFrames.size() << endl;
1571 
1572   for(int i = 0; i < demoFrames.size(); i++)
1573   {
1574     df = demoFrames[i];
1575     demo.write((char *)(&df), sizeof(demoFrame));
1576   }
1577 
1578   demo.write((char *)(levelFile.data()), sizeof(char)*levelFile.length() );
1579 
1580   demo.close();
1581 }
1582 
loadDemo(char * demoFile)1583 void loadDemo(char *demoFile)
1584 {
1585   demoFrames.clear();
1586   fstream demo;
1587   demo.open( demoFile, ios::in | ios:: binary );
1588   if(!demo.is_open())
1589   {
1590     cout << "Could not open" << demoFile <<endl;
1591     return;
1592   }
1593   gameInfo.recording=0;
1594 
1595   uint32_t dSize=-1;
1596   demo.read( (char *)(&dSize), sizeof(uint32_t) );
1597 #if __BYTE_ORDER == __BIG_ENDIAN
1598   dSize = swapbytes32(dSize);
1599 #endif
1600   cout  << "Demo Load frames:" << dSize << endl;
1601 
1602   demoFrame df;
1603   while(demoFrames.size() != dSize)
1604   {
1605     demo.read( (char *)(&df), sizeof(demoFrame));
1606     demoFrames.push_back(df);
1607   }
1608   cout << "Loaded frames:" << demoFrames.size() << endl;
1609   gameInfo.playing=1;
1610   gameInfo.demoFrame=0;
1611 
1612 }
1613 
demoPlay(Uint8 * ks)1614 void demoPlay(Uint8* ks)
1615 {
1616   //advance one frame
1617   if(gameInfo.demoFrame != demoFrames.size() )
1618   {
1619     ks[SDLK_UP]= demoFrames[gameInfo.demoFrame].up;
1620     ks[SDLK_LEFT]= demoFrames[gameInfo.demoFrame].left;
1621     ks[SDLK_RIGHT]= demoFrames[gameInfo.demoFrame].right;
1622     ks[SDLK_SPACE]= demoFrames[gameInfo.demoFrame].shoot;
1623     gameInfo.demoFrame++;
1624   } else {
1625     gameInfo.demoFrame=0;
1626     gameInfo.playing=0;
1627   }
1628 }
1629 
parseCmdLine(int argc,char ** argv)1630 bool parseCmdLine(int argc, char **argv)
1631 {
1632   bool chosenLevel=0, chosenDemo=0;
1633   for(int i=1; i < argc; i++)
1634   {
1635     if( i == 1)
1636     {
1637       if(argv[1][0] != '-')
1638       {
1639         gameRules.startLevel = atoi(argv[1]);
1640         levelFile = DATADIR"levels/";
1641         levelFile.append(argv[1]);
1642         levelFile.append(".level");
1643         chosenLevel=1;
1644       }
1645     }
1646 
1647     if( strcmp(argv[i], "--levelfile") == 0 )
1648     {
1649       i++;
1650       if(i > argc)
1651       {
1652         cout << "Error: Specify level file." << endl;
1653         return(0);
1654       }
1655       chosenLevel=1;
1656       levelFile = argv[i];
1657     } else if( strcmp(argv[i], "--playdemo") == 0 )
1658     {
1659       i++;
1660       if(i > argc)
1661       {
1662         cout  << "Error: Specify demo file to play." << endl;
1663         return(0);
1664       }
1665       cout << "Loading demo '" << argv[i] << "'..."<<endl;
1666       loadDemo(argv[i]);
1667       chosenDemo=1;
1668     } else if( strcmp(argv[i], "--savedemo") == 0)
1669     {
1670       i++;
1671       if(i > argc)
1672       {
1673         cout << "Error: Specify name of demo to record." << endl;
1674         return(0);
1675       }
1676       saveDemoFile = argv[i];
1677     } else if( strcmp(argv[i], "--nosound") == 0 )
1678     {
1679       soundOn=0;
1680     } else if( strcmp(argv[i], "--fullscreen") == 0)
1681     {
1682       dispInfo.fullScreen=1;
1683     } else if( strcmp(argv[i], "--bgcolor") == 0)
1684     {
1685       i++;
1686       if(i > argc)
1687       {
1688         cout << "Error: Specify background color, in hex, RRGGBB, 000000 is black, FF0000 is red." << endl;
1689         return(0);
1690       }
1691       char rgb[5];
1692 
1693       //Red
1694       sprintf(rgb, "0x%c%c", argv[i][0], argv[i][1]);
1695       dispInfo.bgColor[0] = 0.003921569*strtol(rgb, NULL, 16);
1696       //Green
1697       sprintf(rgb, "0x%c%c", argv[i][2], argv[i][3]);
1698       dispInfo.bgColor[1] = 0.003921569*strtol(rgb, NULL, 16);
1699       //Blue
1700       sprintf(rgb, "0x%c%c", argv[i][4], argv[i][5]);
1701       dispInfo.bgColor[2] = 0.003921569*strtol(rgb, NULL, 16);
1702     } else if( strcmp(argv[i], "--edit" ) == 0)
1703     {
1704       gameState=GameStateStartEditor;
1705     } else if( strcmp(argv[i], "--is") == 0 )
1706     {
1707        intermediateSave=1;
1708     } else if( strcmp(argv[i], "--sleep") == 0)
1709     {
1710       vsync=0;
1711     } else if( strcmp(argv[i], "--showfps") == 0)
1712     {
1713       showfps=1;
1714     } else if( strcmp(argv[i], "--nozoom") == 0)
1715     {
1716       dispInfo.enableZoom = 0;
1717     } else if(i!=1) {
1718       cout << "Error: unknown argument '" << argv[i] << "'" << endl;
1719       return(0);
1720     }
1721 
1722 
1723   }
1724 
1725 
1726   if(!chosenLevel && chosenDemo)
1727   {
1728     cout  << "You must choose in which level to play the demo." << endl;
1729     return(0);
1730   }
1731 
1732   return(1);
1733 }
1734 
main(int argc,char ** argv)1735 int main(int argc, char **argv)
1736 {
1737 
1738   srand ( time(NULL) );
1739 
1740   /* These can be overwritten by the call to parseCmdLine */
1741   dispInfo.enableZoom=1;
1742   soundOn=1;
1743   intermediateSave=0;
1744   levelFile = DATADIR"levels/0.level";
1745   saveDemoFile = DATADIR"demo.bin";
1746   dispInfo.fullScreen=0;
1747   dispInfo.bgColor[0] = 0.0;
1748   dispInfo.bgColor[1] = 0.0;
1749   dispInfo.bgColor[2] = 0.0;
1750   showfps=0;
1751   vsync=1;
1752   gameState = GameStateNewGame;
1753 
1754   if(!parseCmdLine(argc, argv))
1755   {
1756     return(1);
1757   }
1758 
1759   SDL_Event event;
1760   //Init sdl and screen
1761   if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_AUDIO) <0 )
1762   {
1763     cout << SDL_GetError() << endl;
1764   }
1765   SDL_WM_SetCaption("OldSkoolGravityGame " VERSION, "OSGG");
1766   SDL_ShowCursor(SDL_DISABLE);
1767   SDL_WM_SetIcon( IMG_Load( DATADIR"icon.png" ), 0 );
1768 
1769   cout << "Old Skool Gravity Game " VERSION ". GPL v3"<<endl;
1770   cout << " ./osgg [NUM] [--levelfile FILE] [--playdemo FILE] [--savedemo FILE] [--nosound] [--fullscreen] [--bgcolor RRGGBB] [--edit] [--is] [--sleep] [--showfps] [--nozoom]" << endl;
1771   cout << "Editor controls:\n esc = cancel poly creation, or exit program. \n del = remove.\n 1 = collision on, 2 = collision off, 3 Platform\n";
1772   cout << " 4 = white, 5 = grey, 6=Invisible, 7 = red, 8 = green, 9 = blue\n";
1773   cout << " 0 = line. q = ship, w = base, e = enemy\n d = write first poly to verts.txt\n";
1774   cout << " m = define mission waypoints, n=use waypoints\n";
1775   cout << " s = toggle editor and game\n g = save map to '"<<levelFile<<"', l = load map\n";
1776   cout << " t = Start new game, F11 fullscreen" << endl <<"F12 = screenshot" << endl;
1777   cout << " F1 = start demo recording, F2 = stop demo recording and save to '"<<saveDemoFile<<"'" << endl;
1778   cout << "F10 toggle sound" << endl;
1779   cout << "Using level file '" << levelFile << "'" << endl;
1780 
1781   //Set initial resolution
1782   dispInfo.glBaseZoom=100.0;
1783 
1784   dispInfo.screenRes.x = SDL_GetVideoInfo()->current_w;
1785   dispInfo.screenRes.y = SDL_GetVideoInfo()->current_h;
1786 
1787 
1788   if(dispInfo.fullScreen)
1789   {
1790     setRes(dispInfo.screenRes.x,dispInfo.screenRes.y);
1791   } else {
1792     setRes(800,600);
1793   }
1794 
1795   genGrid();
1796 
1797   soundMan = new soundClass;
1798   soundMan->init();
1799 
1800   /* for fps */
1801   struct timeval timeStart,timeStop;
1802   int renderTime;
1803   int ticks=0, lastTicks=0, fps=0, lastFps=0;
1804 
1805 
1806 /** Editor vars **/
1807   vector<gPs> editorWayPoints;
1808   vector<int> editorIntWayPoints;
1809 
1810   vector<entity> ents; //entities
1811   vector<vert> activeVerts;
1812   vector< vector<vert> > polys;
1813   int editMode=0; // 0 = Start Poly 1 = Insert Verts, 2 = Cancel Poly, 3 = SelectPoly, 4 = move poly
1814   gPs* dragVert; //Pointer to the verticies position
1815   GLfloat crossColor[3];
1816   GLfloat lineColor[3] = { 1, 1, 1 };
1817   gameInfo.numBases = 0;
1818 
1819   int newType=entLine;
1820   int newCol=1; //collision on new lines.
1821   int editorDeletePoly=0; //0= none, 1= remove key pressed, 2=remove it;
1822 
1823 /** GameVars **/
1824   vector<vert> testVerts;
1825   vert tempVert;
1826   gPs collisionPoint;
1827   bool crashed=0;
1828   char score[256];
1829 
1830   GLfloat scale;
1831 
1832   readEnt(DATADIR "ship.txt", gameInfo.shipStaticVerts);
1833   readEnt(DATADIR "base.txt", gameInfo.baseStaticVerts);
1834   readEnt(DATADIR "enemy.txt", gameInfo.enemyStaticVerts);
1835 
1836   //Enter Main loop
1837   while(gameState != GameStateQuit)
1838   {
1839     if(!vsync)
1840     {
1841       gettimeofday(&timeStart, NULL);
1842     }
1843 
1844     while(SDL_PollEvent(&event))
1845     {
1846       switch(event.type)
1847       {
1848         case SDL_QUIT:
1849           gameState = GameStateQuit;
1850         break;
1851         case SDL_KEYDOWN:
1852 
1853           if(gameState==GameStateGameOver)
1854           {
1855             if(intermediateSave)
1856             {
1857               loadState(ents);
1858             } else {
1859               initGame(polys, ents);
1860             }
1861             gameState=GameStatePlaying;
1862           }
1863 
1864           switch(event.key.keysym.sym)
1865           {
1866             case SDLK_PAUSE:
1867               (gameState==GameStatePause) ? gameState=GameStatePlaying : gameState=GameStatePause;
1868               break;
1869             case SDLK_ESCAPE:
1870 
1871               if(showHelp)
1872               {
1873                 if(gameState==GameStatePause) {
1874                   gameState=GameStatePlaying;
1875                 }
1876                 showHelp=false;
1877               } else if(editMode==1)
1878               {
1879                 editMode=2;
1880               } else {
1881                 gameState = GameStateQuit;
1882               }
1883             break;
1884             case SDLK_DELETE:
1885               editorDeletePoly=1;
1886             break;
1887             case SDLK_1:
1888               newCol=1;
1889                cout << "Collision on the next lines." << endl;
1890              break;
1891             case SDLK_2:
1892               newCol=0;
1893               cout << "Collision off the next lines." << endl;
1894               break;
1895             case SDLK_3:
1896               newCol=2;
1897               cout << "Next Lines are platforms." << endl;
1898               break;
1899             case SDLK_4:
1900               lineColor[0] = 1.0;
1901               lineColor[1] = 1.0;
1902               lineColor[2] = 1.0;
1903               break;
1904             case SDLK_5:
1905               lineColor[0] = 0.4;
1906               lineColor[1] = 0.4;
1907               lineColor[2] = 0.4;
1908               break;
1909             case SDLK_6:
1910               lineColor[0] = -1.0;
1911               lineColor[1] =  1.0;
1912               lineColor[2] =  1.0;
1913               break;
1914             case SDLK_7:
1915               lineColor[0] = 1.0;
1916               lineColor[1] = 0.0;
1917               lineColor[2] = 0.0;
1918               break;
1919             case SDLK_8:
1920               lineColor[0] = 0.0;
1921               lineColor[1] = 1.0;
1922               lineColor[2] = 0.0;
1923               break;
1924             case SDLK_9:
1925               lineColor[0] = 0.0;
1926               lineColor[1] = 0.0;
1927               lineColor[2] = 1.0;
1928               break;
1929             case SDLK_0:
1930               newType=entLine;
1931               break;
1932             case SDLK_q:
1933               newType=entShip;
1934               break;
1935             case SDLK_w:
1936               newType=entBase;
1937               break;
1938             case SDLK_m:
1939               newType=entWp;
1940               break;
1941             case SDLK_n:
1942               gameInfo.nextObjective = editorIntWayPoints;
1943               break;
1944             case SDLK_h:
1945               if(showHelp && gameState==GameStatePause) {
1946                 gameState=GameStatePlaying;
1947               } else if( gameState == GameStatePlaying )
1948               {
1949                 gameState = GameStatePause;
1950               }
1951               showHelp = !showHelp;
1952               break;
1953             case SDLK_e:
1954               newType=entEnemy;
1955               break;
1956             case SDLK_o:
1957               loadState(ents);
1958               break;
1959             case SDLK_p:
1960               saveState(ents);
1961               break;
1962 
1963             case SDLK_d:
1964               saveMap(polys, ents, DATADIR "verts.txt");
1965             break;
1966 
1967             case SDLK_s:
1968               if(gameState == GameStateEditor)
1969                 gameState = GameStatePlaying;
1970                 else
1971                 gameState = GameStateEditor;
1972             break;
1973             case SDLK_g:
1974               saveMap(polys, ents, levelFile.data());
1975               break;
1976             case SDLK_l:
1977               loadMap(polys, ents);
1978               break;
1979             case SDLK_t:
1980               gameState=GameStateNewGame;
1981               break;
1982             case SDLK_F10:
1983               soundOn ? soundOn=0:soundOn=1;
1984               break;
1985             case SDLK_F11:
1986               dispInfo.fullScreen ? dispInfo.fullScreen=0 : dispInfo.fullScreen=1;
1987               if(dispInfo.fullScreen)
1988               {
1989                 setRes(dispInfo.screenRes.x,dispInfo.screenRes.y);
1990               } else {
1991                 setRes(800,600);
1992               }
1993               break;
1994             case SDLK_F1:
1995               gameInfo.recording=1;
1996               demoFrames.clear();
1997               break;
1998             case SDLK_F2:
1999               saveDemo();
2000               break;
2001             case SDLK_F12:
2002               screenShot();
2003               break;
2004           }
2005         break;//case sdlkeydown
2006         case SDL_VIDEORESIZE:
2007           setRes(event.resize.w, event.resize.h);
2008         break;
2009         case SDL_MOUSEMOTION:
2010           dispInfo.mousePos.x = (event.motion.x - dispInfo.dispHalfSize.x) * dispInfo.glUnitsPrPixel;
2011           dispInfo.mousePos.y = (event.motion.y - dispInfo.dispHalfSize.y) * dispInfo.glUnitsPrPixel * -1;
2012           dispInfo.mousePos.x += dispInfo.camPos.x;
2013           dispInfo.mousePos.y += dispInfo.camPos.y;
2014         break;
2015         case SDL_MOUSEBUTTONDOWN:
2016           if(event.button.button == SDL_BUTTON_LEFT)
2017           {
2018             dispInfo.mouseDrag=1;
2019           }
2020           else if(event.button.button == SDL_BUTTON_RIGHT)
2021           {
2022           dispInfo.mouseRightDrag=1;
2023           }
2024           else if(event.button.button == SDL_BUTTON_WHEELDOWN)
2025           {
2026           dispInfo.glBaseZoom += 2;
2027 	  dispInfo.glZoom = dispInfo.glBaseZoom;
2028 	  setSeneSize();
2029           }
2030           else if(event.button.button == SDL_BUTTON_WHEELUP)
2031           {
2032           dispInfo.glBaseZoom -= 2;
2033 	  dispInfo.glZoom = dispInfo.glBaseZoom;
2034 	  setSeneSize();
2035           }
2036 
2037         break;
2038         case SDL_MOUSEBUTTONUP:
2039           if(event.button.button == SDL_BUTTON_LEFT)
2040           dispInfo.mouseDrag=0;
2041           else if(event.button.button == SDL_BUTTON_RIGHT)
2042           dispInfo.mouseRightDrag=0;
2043         break;
2044       }
2045     }
2046 
2047     glClear( GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
2048     glLoadIdentity();
2049 
2050     soundMan->play();
2051 
2052     switch(gameState)
2053     {
2054       case GameStateNewGame:
2055         initNewGame(polys,ents);
2056         if(booted) {
2057           gameState = GameStatePause;
2058           booted=false;
2059         } else {
2060           gameState=GameStatePlaying;
2061         }
2062       break;
2063 
2064       case GameStateStartEditor:
2065         initNewGame(polys, ents);
2066         gameState=GameStateEditor;
2067       break;
2068 
2069       case GameStateNextLevel:
2070         advanceLevel(polys, ents);
2071       break;
2072 
2073       case GameStatePause:
2074       case GameStateGameOver: //This is the same as pause
2075         renderPolys(polys);
2076         renderEntities(ents);
2077         renderRadar(ents,polys);
2078         sparkler.render();
2079 
2080       break;
2081       case GameStatePlaying:
2082         renderPolys(polys);
2083         renderEntities(ents);
2084         renderRadar(ents,polys);
2085         sparkler.render();
2086 
2087         //Check if any bullets hit the enviroment:
2088         bullets.envCol(polys);
2089         bullets.render();
2090 
2091         //Render HUD.
2092         gameInfo.score += 1;
2093         glColor4f( 0,1,0,1 );
2094         scale = dispInfo.glZoom/100.0;
2095 
2096         sprintf(score, "%i.%i", gameInfo.score/60,  int(((gameInfo.score%60)*2)));
2097         glText->write(score, FONT_DEFAULT, 50.0*scale, 0.0, dispInfo.glSceneSize.y- (glText->getHeight(FONT_DEFAULT)*30.0)*scale );
2098 
2099         if(showfps)
2100         {
2101           sprintf(score, "%i fps", lastFps);
2102           glText->write(score, FONT_DEFAULT, 40.0*scale, -120*scale, dispInfo.glSceneSize.y- (glText->getHeight(FONT_DEFAULT)*30.0)*scale );
2103         }
2104 
2105         //Ents:
2106         for(vector<entity>::iterator it = ents.begin(); it != ents.end(); ++it)
2107         {
2108           if(it->type == entShip)
2109           {
2110             Uint8* keyStates = SDL_GetKeyState( NULL );
2111 
2112             //Record?
2113             if(gameInfo.recording)
2114             {
2115               demoRec(keyStates);
2116 
2117               //Write on screen
2118               sprintf(score, "Recording: %zu KiB...", (demoFrames.size()*(sizeof(demoFrame)))/1024 );
2119               glText->write(score, FONT_DEFAULT, 40.0*scale, 50*scale, dispInfo.glSceneSize.y- (glText->getHeight(FONT_DEFAULT)*30.0)*scale );
2120 
2121             //Override input
2122             }
2123             else if(gameInfo.playing)
2124             {
2125               demoPlay(keyStates);
2126             }
2127 
2128             if(keyStates[SDLK_LEFT])
2129             {
2130               if(gameInfo.fuel > 0)
2131               {
2132                 gameInfo.rotationForce += TURNINCRATE;
2133                 gameInfo.fuel -= gameRules.fuelConsumptionTurn;
2134               }
2135             } else if(keyStates[SDLK_RIGHT])
2136             {
2137               if(gameInfo.fuel > 0)
2138               {
2139                 gameInfo.rotationForce -= TURNINCRATE;
2140                 gameInfo.fuel -= gameRules.fuelConsumptionTurn;
2141               }
2142             }
2143 
2144             if(keyStates[SDLK_UP])
2145             {
2146               if(gameInfo.fuel > 0)
2147               {
2148                 gameInfo.thrust = THRUSTINCRATE;
2149                 gameInfo.fuel -= gameRules.fuelConsumptionThrust;
2150               } else {
2151                 gameInfo.thrust = 0;
2152               }
2153             } else
2154             {
2155               gameInfo.thrust = 0;
2156             }
2157 
2158             if(gameInfo.reloadTime != 0)
2159             {
2160               gameInfo.reloadTime--;
2161             }
2162             if(keyStates[SDLK_SPACE])
2163             {
2164               if(gameInfo.reloadTime == 0 && gameInfo.ammo >= 100)
2165               {
2166                 gameInfo.ammo -= 100;
2167                 gameInfo.reloadTime = 25;
2168                 bullets.shoot(*it, gameInfo.velocity);
2169               }
2170             }
2171 
2172 	    //Update the speed
2173 	    gameInfo.speed = abs2(gameInfo.velocity.x*100)+abs2(gameInfo.velocity.y*100);
2174 	    //Update distance to destination
2175 	    gameInfo.distance = (sqrt( pow( dispInfo.camPos.x - gameInfo.radarDest.x, 2) + pow( dispInfo.camPos.y - gameInfo.radarDest.y, 2 ) ));
2176 
2177 	    //Update velocities
2178             gameInfo.velocity.x += gameInfo.thrust * cos( (it->rotation*0.0174532925) );
2179             gameInfo.velocity.y += gameInfo.thrust * sin( (it->rotation*0.0174532925) );
2180 
2181             gameInfo.velocity.y -= GRAVITY;
2182 
2183 	    //Zoom in/out
2184 	    if( dispInfo.enableZoom )
2185 	    {
2186 	      static GLfloat optimalZoom=0.0;
2187 	      optimalZoom = dispInfo.glBaseZoom + (gameInfo.speed*1.25);
2188 
2189 	      if( gameInfo.distance < 40 )
2190 		optimalZoom = dispInfo.glBaseZoom - (10-gameInfo.distance);
2191 
2192 	      if( dispInfo.glZoom != optimalZoom )
2193 	      {
2194 		if(optimalZoom > dispInfo.glZoom)
2195 		{
2196 		  dispInfo.glZoom += (optimalZoom-dispInfo.glZoom)/25.0;
2197 		  if( dispInfo.glZoom > optimalZoom )
2198 		    dispInfo.glZoom = optimalZoom;
2199 		} else {
2200 		  dispInfo.glZoom -= (dispInfo.glZoom-optimalZoom)/25.0;
2201 		  if( dispInfo.glZoom < optimalZoom )
2202 		    dispInfo.glZoom = optimalZoom;
2203 		}
2204 		setSeneSize();
2205 	      }
2206 	    }
2207 
2208 
2209             if(gameInfo.rotationForce > 0)
2210             {
2211 
2212               gameInfo.rotationForce /= 1.01;
2213               if(gameInfo.rotationForce < 0)
2214               {
2215                 gameInfo.rotationForce = 0;
2216               }
2217             } else if(gameInfo.rotationForce < 0)
2218             {
2219               gameInfo.rotationForce /= 1.01;
2220               if(gameInfo.rotationForce > 0)
2221               {
2222                 gameInfo.rotationForce = 0;
2223               }
2224             }
2225 
2226             //sound
2227             if(gameInfo.thrust != 0)
2228             {
2229               soundMan->add(sfxNozzle);
2230             }
2231 
2232             //Collision with terrain
2233             for(vector< vector<vert> >::iterator PolyIt = polys.begin(); PolyIt != polys.end(); ++PolyIt)
2234             {
2235               if(PolyCol(*PolyIt, gameInfo.shipVerts))
2236               {
2237                 shipCrash(*it);
2238               }
2239             }
2240 
2241             crashed=0;
2242            //Collision with ents
2243             for(vector<entity>::iterator entIt = ents.begin(); entIt != ents.end(); ++entIt)
2244             {
2245               //Collition with entities
2246               if(entIt->type==entBase)
2247               {
2248                 updateEntVerts(*entIt, gameInfo.baseVerts, gameInfo.baseStaticVerts);
2249                 crashed=PolyCol(gameInfo.baseVerts, gameInfo.shipVerts);
2250               } else if(entIt->type==entEnemy)
2251               {
2252                 updateEntVerts(*entIt, gameInfo.enemyVerts, gameInfo.enemyStaticVerts);
2253                 crashed=PolyCol(gameInfo.enemyVerts, gameInfo.shipVerts);
2254 
2255                 //check if this enemy is being hit
2256                 if(bullets.col(gameInfo.enemyVerts, 0))
2257                 {
2258                   soundMan->add(sfxBoom);
2259                   sparkler.spawn(entIt->p, 0, 360, 1, 100);
2260                   entIt = ents.erase(entIt);
2261 //                   gameInfo.score -= 3000;
2262                   break;
2263                 }
2264               }
2265 
2266               if(crashed)
2267               {
2268                 shipCrash(*it);
2269               } else {
2270                 //Is he landing on a base?
2271                 if(entIt->type==entBase)
2272                 {
2273                   if(landCol(gameInfo.baseVerts, gameInfo.shipVerts))
2274                   {
2275                     //Save state
2276                     if(intermediateSave)
2277                       saveState(ents);
2278 
2279                     //Subtract 1 from score again
2280 //                     gameInfo.score -= 1;
2281 
2282                     if(gameInfo.fuel < gameRules.fuelMaxFuel)
2283                     gameInfo.fuel += 15;
2284                     if(gameInfo.fuel > gameRules.fuelMaxFuel)
2285                     gameInfo.fuel = gameRules.fuelMaxFuel;
2286 
2287                     if(gameInfo.ammo < gameRules.ammoMaxAmmo)
2288                     gameInfo.ammo += 3;
2289                     if(gameInfo.ammo > gameRules.ammoMaxAmmo)
2290                     gameInfo.ammo = gameRules.ammoMaxAmmo;
2291 
2292 
2293                     it->rotation=90.0;
2294 
2295                     if(gameInfo.velocity.y < 0.0)
2296                       gameInfo.velocity.y=0;
2297 
2298                     gameInfo.velocity.x=0;
2299                     gameInfo.rotationForce=0;
2300 
2301                     if(gameInfo.numBases > 1)
2302                     {
2303                       //Is this the destination base?
2304                       if(gameInfo.destBase == entIt->id)
2305                       {
2306 //                         gameInfo.score -= 1000;
2307                         gameInfo.numMissions++;
2308 
2309                         //Do he have more missions left?
2310                         gameInfo.currentObjective++;
2311                         if(gameInfo.currentObjective < gameInfo.nextObjective.size())
2312                         {
2313                           //Give it to him
2314                           setMission(gameInfo.currentObjective, ents);
2315                         } else {
2316                           gameState = GameStateNextLevel;
2317                         }
2318                       }
2319                     }
2320                   }
2321                 }
2322               } //not crashing
2323             }
2324 
2325             it->rotation += gameInfo.rotationForce;
2326             it->p.x += gameInfo.velocity.x;
2327             it->p.y += gameInfo.velocity.y;
2328 
2329             dispInfo.camPos = it->p;
2330           } else
2331           /** Update enemies **/
2332           if(it->type == entEnemy)
2333           {
2334             //Only do this if they are in the screen
2335             if(boxCol(dispInfo.camPos, it->p, dispInfo.glSceneSize.x+3) )
2336             {
2337 
2338               it->vel.y -= GRAVITY;
2339 
2340               if(it->p.y <= it->baseP.y-0.3)
2341               {
2342                 it->vel.y += 0.01;
2343                 sparkler.spawn(it->p, it->rotation+180, 40, 0.7, 5);
2344               }
2345 
2346               it->p.y += it->vel.y;
2347 
2348             }
2349           }
2350         }
2351 
2352 
2353 
2354       break;
2355 
2356       /** END OF GAME **/
2357 
2358       case GameStateEditor:
2359       crossColor[0] = 1.0;
2360       crossColor[1] = 1.0;
2361       crossColor[2] = 1.0;
2362       //Search all polygons for verticies to see if player wish to edit it
2363       if(editMode != 4)
2364       {
2365         if(editMode==3)
2366         editMode=0;
2367         for(vector <vector <vert> >::iterator it = polys.begin(); it != polys.end(); ++it)
2368         {
2369           for(vector <vert>::iterator itt = it->begin(); itt != it->end(); ++itt)
2370           {
2371             if(boxCol(dispInfo.mousePos, itt->p, (dispInfo.glZoom+1)/100))
2372             {
2373               crossColor[0] = 1.0;
2374               crossColor[1] = 0.0;
2375               crossColor[2] = 0.0;
2376 
2377               if(editorDeletePoly)
2378               {
2379                 editorDeletePoly=2;
2380 
2381                 break;
2382               }
2383 
2384               if(dispInfo.mouseDrag)
2385               {
2386                 editMode=4;
2387                 dragVert = &itt->p;
2388               }
2389             }
2390           }
2391           if(editorDeletePoly==2)
2392           {
2393             polys.erase(it);
2394             break;
2395           }
2396         }
2397 
2398         //Do the same for ents
2399         for(vector<entity>::iterator it = ents.begin(); it != ents.end(); ++it)
2400         {
2401           if(boxCol(dispInfo.mousePos, it->p, (dispInfo.glZoom+1)/100))
2402           {
2403             if(newType==entWp)
2404            {
2405               crossColor[0] = 0.0;
2406               crossColor[1] = 1.0;
2407               crossColor[2] = 0.0;
2408               if(dispInfo.mouseDrag)
2409               {
2410                 editorWayPoints.push_back( it->p );
2411                 editorIntWayPoints.push_back(it->id );
2412                 dispInfo.mouseDrag = 0;
2413               }
2414            } else {
2415               crossColor[0] = 1.0;
2416               crossColor[1] = 0.0;
2417               crossColor[2] = 1.0;
2418               if(dispInfo.mouseDrag)
2419               {
2420                 editMode=4;
2421                 dragVert = &it->p;
2422               }
2423 
2424               if(editorDeletePoly)
2425               {
2426                 editorDeletePoly=2;
2427               }
2428               if(editorDeletePoly==2)
2429               {
2430                 ents.erase(it);
2431                 break;
2432               }
2433             }
2434           }
2435 
2436         }
2437 
2438       }
2439 
2440       editorDeletePoly=0;
2441 
2442       if(editMode==4)
2443       {
2444         crossColor[0] = 1.0;
2445         crossColor[1] = 0.0;
2446         crossColor[2] = 0.0;
2447 
2448         if(!dispInfo.mouseDrag)
2449         {
2450           editMode=0;
2451         } else {
2452           *dragVert = dispInfo.mousePos;
2453         }
2454       }
2455 
2456       //Add stuff
2457       if(dispInfo.mouseDrag && (editMode == 0 || editMode ==1) )
2458       {
2459         editMode = 1;
2460         dispInfo.mouseDrag = 0;
2461         //Add line to poly
2462         if(newType==entLine)
2463         {
2464           vert tVert;
2465           tVert.color[0] = lineColor[0];
2466           tVert.color[1] = lineColor[1];
2467           tVert.color[2] = lineColor[2];
2468           tVert.collision = newCol;
2469 
2470           //Finished the poly
2471           if(activeVerts.size() > 1 && boxCol(dispInfo.mousePos, activeVerts[0].p, (dispInfo.glZoom+1)/100))
2472           {
2473             editMode = 0;
2474             tVert.p = activeVerts[0].p;
2475             activeVerts.push_back(tVert);
2476 
2477             polys.push_back(activeVerts);
2478             activeVerts.clear();
2479           } else {
2480             tVert.p = dispInfo.mousePos;
2481             activeVerts.push_back(tVert);
2482           }
2483 
2484         }
2485 
2486         //Add ship starting point
2487         if(newType==entShip)
2488         {
2489 
2490           //Search for an existing ship and remove that if found
2491           for(vector<entity>::iterator it = ents.begin(); it != ents.end(); ++it)
2492           {
2493             if(it->type == entShip)
2494             {
2495               ents.erase(it);
2496               break;
2497             }
2498           }
2499           entity tEnt;
2500           tEnt.p = dispInfo.mousePos;
2501           tEnt.type=newType;
2502           tEnt.rotation = 90.0;
2503           tEnt.id=-1; // ship don't have
2504           ents.push_back(tEnt);
2505           editMode = 0;
2506         }
2507 
2508         //Add base entity
2509         if(newType==entBase)
2510         {
2511           entity tEnt;
2512           tEnt.p = dispInfo.mousePos;
2513           tEnt.type=newType;
2514           tEnt.rotation = 90.0;
2515           gameInfo.numBases++;
2516           tEnt.id = gameInfo.numBases;
2517           ents.push_back(tEnt);
2518           editMode = 0;
2519         }
2520 
2521         if(newType==entEnemy)
2522         {
2523           entity tEnt;
2524           tEnt.p = dispInfo.mousePos;
2525           tEnt.baseP = tEnt.p;
2526           tEnt.type=newType;
2527           tEnt.rotation = 90.0;
2528           tEnt.id = -1;
2529           ents.push_back(tEnt);
2530           editMode = 0;
2531         }
2532 
2533       }
2534 
2535       if(editMode==1)
2536       {
2537         crossColor[0] = 0.0;
2538         crossColor[1] = 1.0;
2539         crossColor[2] = 0.0;
2540       }
2541 
2542 
2543       if( editMode == 2 )
2544       {
2545         activeVerts.clear();
2546         editMode = 0;
2547       }
2548 
2549       //Moving around
2550       if( dispInfo.mouseRightDrag )
2551       {
2552         dispInfo.mouseRightDrag=0;
2553         dispInfo.camPos.x += dispInfo.mousePos.x - dispInfo.camPos.x;
2554         dispInfo.camPos.y += dispInfo.mousePos.y - dispInfo.camPos.y;
2555 
2556         SDL_WarpMouse( dispInfo.dispHalfSize.x, dispInfo.dispHalfSize.y );
2557       }
2558 
2559       drawGrid();
2560 
2561 
2562       if(activeVerts.size() > 1)
2563       {
2564         if( boxCol(dispInfo.mousePos, activeVerts[0].p, (dispInfo.glZoom+1)/100) )
2565         {
2566           crossColor[0] = 0.0;
2567           crossColor[1] = 0.0;
2568           crossColor[2] = 1.0;
2569         }
2570       }
2571 
2572       if(crossColor[0] == 1 && crossColor[1] == 1 && crossColor[2] == 1)
2573       {
2574         crossColor[0] = lineColor[0];
2575         crossColor[1] = lineColor[1];
2576         crossColor[2] = lineColor[2];
2577       }
2578 
2579       glColor3f(crossColor[0], crossColor[1], crossColor[2]);
2580       //Draw the cross
2581       glBegin( GL_LINES );
2582         // -
2583         glVertex2f( dispInfo.mousePos.x-dispInfo.camPos.x - 5.0, dispInfo.mousePos.y-dispInfo.camPos.y );
2584         glVertex2f( dispInfo.mousePos.x-dispInfo.camPos.x - 1.0, dispInfo.mousePos.y-dispInfo.camPos.y );
2585         glVertex2f( dispInfo.mousePos.x-dispInfo.camPos.x + 5.0, dispInfo.mousePos.y-dispInfo.camPos.y );
2586         glVertex2f( dispInfo.mousePos.x-dispInfo.camPos.x + 1.0, dispInfo.mousePos.y-dispInfo.camPos.y );
2587         // |
2588         glVertex2f( dispInfo.mousePos.x-dispInfo.camPos.x, dispInfo.mousePos.y-dispInfo.camPos.y + 5.0 );
2589         glVertex2f( dispInfo.mousePos.x-dispInfo.camPos.x, dispInfo.mousePos.y-dispInfo.camPos.y + 1.0 );
2590         glVertex2f( dispInfo.mousePos.x-dispInfo.camPos.x, dispInfo.mousePos.y-dispInfo.camPos.y - 5.0 );
2591         glVertex2f( dispInfo.mousePos.x-dispInfo.camPos.x, dispInfo.mousePos.y-dispInfo.camPos.y - 1.0 );
2592       glEnd( );
2593 
2594       glColor3f( 1, 1,1);
2595       glBegin( GL_POINTS );
2596         glVertex2f( dispInfo.mousePos.x-dispInfo.camPos.x, dispInfo.mousePos.y-dispInfo.camPos.y );
2597       glEnd( );
2598 
2599       glBegin( GL_POINTS );
2600         glVertex2f( 0,0 );
2601         glVertex2f( -2.5,2.5 );
2602         glVertex2f(  2.5,2.5 );
2603         glVertex2f(  2.5,-2.5);
2604         glVertex2f( -2.5,-2.5);
2605       glEnd( );
2606 
2607       //Draw the line not placed yet
2608       if( editMode == 1)
2609       {
2610         if(activeVerts.size() > 0)
2611         {
2612           glBegin( GL_LINES );
2613           glColor3f(activeVerts.back().color[0], activeVerts.back().color[1], activeVerts.back().color[2]);
2614           glVertex2f( activeVerts.back().p.x-dispInfo.camPos.x, activeVerts.back().p.y-dispInfo.camPos.y );
2615           glColor3f( lineColor[0], lineColor[1], lineColor[2]);
2616           glVertex2f( dispInfo.mousePos.x-dispInfo.camPos.x, dispInfo.mousePos.y-dispInfo.camPos.y );
2617           glEnd() ;
2618         }
2619       }
2620 
2621       //Render active verticies
2622       glBegin( GL_LINE_STRIP | GL_POINTS );
2623       for(vector<vert>::iterator it = activeVerts.begin(); it != activeVerts.end(); ++it)
2624       {
2625         glColor3f(it->color[0], it->color[1], it->color[2]);
2626         glVertex2f(it->p.x-dispInfo.camPos.x, it->p.y-dispInfo.camPos.y);
2627       }
2628       glEnd( );
2629 
2630       //Render mission path
2631       glBegin( GL_LINE_STRIP );
2632       glColor4f( 1,1,0,1 );
2633       for(int i=0; i < editorWayPoints.size(); i++)
2634       {
2635        glVertex2f(editorWayPoints[i].x - dispInfo.camPos.x, editorWayPoints[i].y - dispInfo.camPos.y);
2636       }
2637       glEnd( );
2638 
2639       //Render gameworld
2640       renderPolys(polys);
2641       renderEntities(ents);
2642       break;
2643     }
2644 
2645 
2646 
2647     renderHelp();
2648 
2649     /* Swap buffers, it should block to wait for vsync */
2650     SDL_GL_SwapBuffers( );
2651 
2652     if(!vsync)
2653     {
2654       gettimeofday(&timeStop, NULL);
2655       /* each second, it resets, if we are in the middle of that, things get messy */
2656       if(timeStop.tv_usec < timeStart.tv_usec)
2657         timeStop.tv_usec += 1000000;
2658 
2659       renderTime= timeStop.tv_usec - timeStart.tv_usec;
2660 
2661       if(renderTime < 16666)
2662       {
2663         #ifdef WIN32
2664         Sleep( 16 - renderTime/1000 );
2665         #else
2666         usleep(16666-renderTime); // around 60 fps
2667         #endif
2668       }
2669     }
2670 
2671     fps++;
2672     ticks += SDL_GetTicks() - lastTicks;
2673     lastTicks = SDL_GetTicks();
2674     if(ticks >= 1000)
2675     {
2676       ticks = 0;
2677       if(fps > 64 && lastFps > 64 && vsync)
2678       {
2679         vsync=0;
2680         cout << "Vsync:Framerate too high (over 64 fps) falling back on sleep based limiting." << endl;
2681         cout << "Enable vsync in your driver and set monitor refresh rate to 60 hz." << endl;
2682       }
2683       lastFps=fps;
2684       fps=0;
2685     }
2686 
2687   }
2688 
2689 
2690   SDL_ShowCursor(SDL_ENABLE);
2691 
2692   return(0);
2693 }
2694