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 <iostream>
20 #include <SDL/SDL.h>
21 #include <vector>
22 #include <list>
23 #include <math.h>
24 #include <fstream>
25 #include <iostream>
26 #include <sstream>
27 
28 #include <sys/time.h>
29 
30 #define VERSION "1.0SVN"
31 
32 
33 
34 #ifndef DATADIR
35     #define DATADIR "./"
36 #endif
37 
38 using namespace std;
39 
40 #define THRUSTINCRATE 0.01
41 #define GRAVITY 0.002
42 #define TURNINCRATE 0.15
43 
44 enum entTypes { entLine, entShip, entBase, entWp, entEnemy };
45 enum gameStateEnum { GameStateEditor, GameStatePlaying, GameStatePause, GameStateQuit, GameStateNewGame, GameStateGameOver, GameStateNextLevel, GameStateStartEditor };
46 uint gameState = GameStateEditor;
47 
48 
49 struct pStruct {
50   int x,y;
51 };
52 
53 string levelFile;
54 
55 struct glPstruct {
56   float x, y;
57 };
58 
59 struct structVert {
60   float color[3];
61   struct glPstruct p;
62   int collision; // 0 = none, 1 = normal(damage), 2 = platform/Landing gear
63 };
64 
65 typedef struct structVert vert;
66 typedef struct glPstruct gPs;
67 typedef struct pStruct pS;
68 
69 struct structEnt {
70   struct glPstruct p; //position
71   float rotation; //In DEG
72   gPs vel; //Velocity, only used for enemies right now
73   gPs baseP; //Base (start) position, used for nme
74   int type; //type
75   int id;
76   bool base; // If it's a base, don't translate it every time..
77 };
78 typedef struct structEnt entity;
79 
80 
81 struct structGameRules {
82   int startLevel; //what level to start in
83   float maxLandingRotForce;
84   float maxLandingYel;
85   float maxLandingXvel;
86   int fuelConsumptionThrust;
87   int fuelConsumptionTurn;
88   int fuelMaxFuel;
89   int ammoMaxAmmo;
90 };
91 
92 struct structGameRules gameRules;
93 
94 struct gameInfoStruct {
95   float thrust;
96   gPs velocity;
97   float speed; //Relative speed
98 
99   float rotationForce;
100   float distance;
101 
102   int fuel;
103   int reloadTime; //After this amount of fames (60th's of 1 sec) player can shoot again
104   int ammo;
105 
106   gPs radarDest; //Destination for package, points to the base where package should be delivered
107   int destBase; // 0 = no package, id of base.
108   int numBases; // Number of bases on map, set by loadMap
109   int score;
110   int numMissions; //number of finished missions
111   int level;
112   int lives;
113 
114   vector<vert> shipVerts;
115   vector<vert> baseVerts;
116   vector<vert> enemyVerts;
117 
118   vector<vert> shipStaticVerts;
119   vector<vert> baseStaticVerts;
120   vector<vert> enemyStaticVerts;
121 
122   vector<int> nextObjective; //Where to deliver to next.
123   int currentObjective; //What right now?
124 
125 };
126 struct gameInfoStruct gameInfo;
127 
abs2(float x)128 float abs2(float x)
129 {
130       if (x<0) {return -x;}
131       return x;
132 }
133 
LinesCross(gPs aLineA,gPs aLineB,gPs bLineA,gPs bLineB)134 bool LinesCross(gPs aLineA, gPs aLineB, gPs bLineA, gPs bLineB)
135 {
136         //First line, first point
137         float x0 = aLineA.x;
138         float y0 = aLineA.y;
139         //First Line, second point
140         float x1 = aLineB.x;
141         float y1 = aLineB.y;
142         //Second Line, First point
143         float x2 = bLineA.x;
144         float y2 = bLineA.y;
145         //Second Line, Second point
146         float x3 = bLineB.x;
147         float y3 = bLineB.y;
148 
149 
150 	float d=(x1-x0)*(y3-y2)-(y1-y0)*(x3-x2);
151 	if (abs2(d)<0.001f) {return 0;}
152 	float AB=((y0-y2)*(x3-x2)-(x0-x2)*(y3-y2))/d;
153 	if (AB>0.0 && AB<1.0)
154 	{
155 		float CD=((y0-y2)*(x1-x0)-(x0-x2)*(y1-y0))/d;
156 		if (CD>0.0 && CD<1.0)
157                 {
158                   return 1;
159                 }
160         }
161 
162   return 0;
163 }
164 
165 
166 
167 struct structShot {
168   gPs pa,pb;
169   gPs v;
170   int age, life;
171   bool fromShip; //if 1, wont collide with ship
172 };
173 
174 class classBullets {
175   private:
176   vector<struct structShot> shots;
177   public:
178   void shoot(entity owner, gPs velocity);
179   void render();
180   bool col(vector<vert> target, bool isShip);
181   void envCol(vector< vector<vert> > polys);
182 };
183 
envCol(vector<vector<vert>> polys)184 void classBullets::envCol(vector< vector<vert> > polys)
185 {
186   for(vector< vector<vert> >::iterator PolyIt = polys.begin(); PolyIt != polys.end(); ++PolyIt)
187   {
188     classBullets::col(*PolyIt, 0);
189   }
190 }
191 
col(vector<vert> target,bool isShip)192 bool classBullets::col(vector<vert> target, bool isShip)
193 {
194   gPs tLineA, tLineB;
195   for(vector<struct structShot>::iterator it = shots.begin(); it != shots.end(); ++it)
196   {
197     if(it->fromShip != isShip)
198     {
199       for(int ii=0; ii < target.size(); ii++)
200       {
201         if(ii==0)
202         {
203           tLineB = target[ii].p;
204         } else {
205           tLineA = tLineB;
206           tLineB = target[ii].p;
207 
208           if(LinesCross(tLineA, tLineB, it->pa, it->pb))
209           {
210             //Remove bullet.
211             it = shots.erase(it);
212             return(1);
213           }
214         }
215       }
216     }
217   }
218 }
219 
shoot(entity owner,gPs velocity)220 void classBullets::shoot(entity owner, gPs velocity)
221 {
222   struct structShot ts;
223 
224   ts.pb = owner.p;
225   ts.pa.x = owner.p.x + 6.0* cos( owner.rotation * 0.0174532925 );
226   ts.pa.y = owner.p.y + 6.0* sin( owner.rotation * 0.0174532925 );
227 
228   ts.v.x = velocity.x + 1.0 * cos( owner.rotation * 0.0174532925 );
229   ts.v.y = velocity.y + 1.0 * sin( owner.rotation * 0.0174532925 );
230 
231   ts.age = 0;
232   ts.life = 40;
233 
234   if(owner.type == entShip)
235   {
236     ts.fromShip=1;
237   } else {
238     ts.fromShip=0;
239   }
240 
241   shots.push_back(ts);
242 }
243 
render()244 void classBullets::render()
245 {
246 
247   for(vector<struct structShot>::iterator it = shots.begin(); it != shots.end(); ++it)
248   {
249     it->pa.x += it->v.x;
250     it->pa.y += it->v.y;
251     it->pb.x += it->v.x;
252     it->pb.y += it->v.y;
253 
254     it->age++;
255     if(it->age > it->life)
256     {
257        it = shots.erase(it);
258        if(shots.size() < 1)
259         break;
260     }
261   }
262 }
263 class classBullets bullets;
264 
265 //Move and rotate an entity according to ent.p and ent.rotation
updateEntVerts(entity ent,vector<vert> & entverts,vector<vert> statV)266 void updateEntVerts(entity ent, vector<vert>& entverts, vector<vert> statV )
267 {
268   entverts = statV;
269 
270   float tx, ty;
271 
272   for(vector<vert>::iterator i = entverts.begin(); i != entverts.end(); ++i)
273   {
274     tx = i->p.x * cos( (ent.rotation-90.0) * 0.0174532925 ) - ( i->p.y *sin( (ent.rotation-90.0) * 0.0174532925 )) ;
275     ty = i->p.x * sin( (ent.rotation-90.0) * 0.0174532925 ) + ( i->p.y *cos( (ent.rotation-90.0) * 0.0174532925 ));
276     i->p.x=tx;
277     i->p.y=ty;
278     i->p.x += ent.p.x;
279     i->p.y += ent.p.y;
280   }
281 
282 }
283 
284 
285 #define PI 3.14159265
286 
loadMap(vector<vector<vert>> & polys,vector<entity> & ents)287 void loadMap(vector< vector<vert> >& polys, vector<entity>& ents)
288 {
289   polys.clear();
290   ents.clear();
291   string line;
292   ifstream load;
293   vector<vert> tvs; //temp to store the poly as we read it
294   vert tv; //temp to store the vert as we read it
295   entity te; //temp to store the entity while we read it
296   gameInfo.numBases=0;
297   gameInfo.nextObjective.clear();
298   load.open(levelFile.data());
299 
300   if(!load.is_open())
301   {
302     cout << "could not load '" << levelFile << "'" << endl;
303     return;
304   }
305 
306   int parseState=0, dataNum=0;
307 
308   while(!load.eof())
309   {
310     getline(load, line);
311     if(line == "StartPoly")
312     {
313       parseState=1;
314     } else if(line=="EndPoly")
315     {
316       parseState=0;
317       polys.push_back(tvs);
318       tvs.clear();
319     } else if(parseState==1)
320     {
321       if(line == "StartVert")
322       {
323         parseState=2;
324         dataNum=0;
325       }
326     } else if(parseState==2)
327     {
328       if(line == "EndVert")
329       {
330         tvs.push_back(tv);
331         parseState=1;
332       } else {
333         dataNum++;
334         switch(dataNum)
335         {
336           case 1:
337           tv.p.x = atof(line.data());
338           break;
339           case 2:
340           tv.p.y = atof(line.data());
341           break;
342           case 3:
343           tv.color[0] = atof(line.data());
344           break;
345           case 4:
346           tv.color[1] = atof(line.data());
347           break;
348           case 5:
349           tv.color[2] = atof(line.data());
350           break;
351           case 6:
352           tv.collision = atoi(line.data());
353           break;
354           default:
355           cout << "??" << line << endl;
356           break;
357         }
358       }
359     } else if(line =="StartEntity")
360     {
361       parseState=3;
362       dataNum=0;
363     } else if(parseState==3)
364     {
365       if(line=="EndEntity")
366       {
367         dataNum=0;
368         te.baseP = te.p;
369         ents.push_back(te);
370         parseState=0;
371       } else {
372         dataNum++;
373         switch(dataNum)
374         {
375           case 1:
376             te.p.x = atof(line.data());
377             break;
378           case 2:
379             te.p.y = atof(line.data());
380             break;
381           case 3:
382             te.type = atoi(line.data());
383             if(te.type==entBase)
384             {
385               gameInfo.numBases++;
386             }
387             break;
388           case 4:
389             te.rotation = atof(line.data());
390             break;
391           case 5:
392             te.id = atoi(line.data());
393             if(te.type==entBase && te.id != gameInfo.numBases)
394             {
395               cout << "error: base entity have id:" << te.id << " but numBases is:" << gameInfo.numBases << endl;
396             }
397             break;
398           default:
399             cout << ">?" << line << endl;
400             break;
401         }
402       }
403     } else if(line=="StartMission")
404     {
405       parseState=4;
406     } else if(parseState==4)
407     {
408       if(line=="EndMission")
409       {
410         parseState=0;
411       } else {
412         gameInfo.nextObjective.push_back( atoi(line.data()) );
413       }
414     }
415   }
416 
417 
418 }
419 
readEnt(string File,vector<vert> & verts)420 void readEnt(string File, vector<vert>& verts)
421 {
422   string line;
423   ifstream f;
424   vert tv; //temp to store the vert as we read it
425 
426   f.open(File.data());
427   if(!f.is_open())
428   {
429     cout << "Failed to open file" << endl;
430     return;
431   }
432 
433   int parseState=0, dataNum=0;
434 
435   while(!f.eof())
436   {
437     getline(f, line);
438     if(line == "StartVert")
439     {
440       parseState=1;
441       dataNum=0;
442     } else if(parseState==1)
443     {
444       if(line == "EndVert")
445       {
446         parseState=0;
447         verts.push_back(tv);
448       } else {
449         dataNum++;
450         switch(dataNum)
451         {
452           case 1:
453           tv.p.x = atof(line.data());
454           break;
455           case 2:
456           tv.p.y = atof(line.data());
457           case 3:
458           tv.color[0] = atof(line.data());
459           break;
460           case 4:
461           tv.color[1] = atof(line.data());
462           break;
463           case 5:
464           tv.color[2] = atof(line.data());
465           break;
466           case 6:
467           tv.collision = atoi(line.data());
468           break;
469           default:
470           cout << "??" << line << endl;
471           break;
472         }
473 
474       }
475     }
476   }
477 
478 }
479 
boxCol(gPs posa,gPs posb,float dist)480 bool boxCol(gPs posa, gPs posb, float dist)
481 {
482   if(posa.x < posb.x+dist && posa.x > posb.x-dist)
483   {
484     if(posa.y < posb.y+dist && posa.y > posb.y-dist)
485     {
486       return(1);
487     }
488   }
489   return(0);
490 }
491 
PolyCol(vector<vert> PolyA,vector<vert> PolyB)492 bool PolyCol( vector<vert> PolyA, vector<vert> PolyB  )
493 {
494   gPs paLineA, paLineB, pbLineA, pbLineB;
495   bool paFirst=1, pbFirst=1;
496   int prevColType=0;
497   int checks=0;
498 
499   for( vector<vert>::iterator paVertIt = PolyA.begin(); paVertIt != PolyA.end(); ++paVertIt)
500   {
501     if(paVertIt->collision)
502     {
503       if(paFirst || prevColType == 2) //if the last one was a 2, this one is the start of the next line to collision detect
504       {
505         paFirst=0;
506         paLineB=paVertIt->p;
507       } else {
508         paLineA=paLineB;
509         paLineB=paVertIt->p;
510 
511 
512         pbFirst=1;
513         //Great now we have a line, lets check it against every line in the other poly.
514         for(vector<vert>::iterator pbVertIt = PolyB.begin(); pbVertIt != PolyB.end(); ++pbVertIt)
515         {
516           if(pbVertIt->collision)
517           {
518             if(pbFirst)
519             {
520               pbFirst=0;
521               pbLineB=pbVertIt->p;
522             } else {
523               pbLineA=pbLineB;
524               pbLineB=pbVertIt->p;
525 
526               //Here we have two lines. paLineA, paLineB, and pbLineA, pbLineB.
527               checks++;
528               if(LinesCross(paLineA, paLineB, pbLineA, pbLineB))
529               {
530                 return(1);
531               }
532 
533             }
534           }
535         }
536 
537       }
538     }
539     prevColType = paVertIt->collision;
540   }
541   return(0);
542 }
543 
544 
landCol(vector<vert> baseVerts,vector<vert> shipVerts)545 bool landCol(vector<vert> baseVerts, vector<vert> shipVerts)
546 {
547 
548   gPs baseA, baseB;
549   gPs shipA, shipB;
550   int prevColType=0;
551 
552   //Find points on ship
553   for(vector<vert>::iterator shipIt = shipVerts.begin(); shipIt != shipVerts.end(); ++shipIt)
554   {
555     if(shipIt->collision == 2)
556     {
557       if(prevColType == 0)
558       {
559         shipA = shipIt->p;
560         prevColType++;
561       } else {
562         shipB = shipIt->p;
563         prevColType++;
564       }
565     }
566   }
567 
568   prevColType=0;
569   for(vector<vert>::iterator baseIt = baseVerts.begin(); baseIt != baseVerts.end(); ++baseIt)
570   {
571     //Find the line to check with
572     if(prevColType==2)
573     {
574       baseB = baseIt->p;
575       if(shipA.x > baseA.x && shipA.x < baseB.x) //Is left side inside
576       {
577         if(shipB.x > baseA.x && shipB.x < baseB.x) // Is right side inside
578         {
579           if(shipA.y < baseA.y && shipB.y < baseB.y) //Is left side under the line
580           {
581             if(shipB.y < baseA.y && shipB.y < baseB.y) //Is right side under the line
582             {
583               if(shipA.y > baseA.y-1.0 && shipB.y > baseA.y-1.0) //Check that left side is above the height
584               {
585                 //check velocity:
586                 //cout << "Impact:"<<endl<<"Xvel:" << gameInfo.velocity.x<<" Yvel: " << gameInfo.velocity.y << endl << "Rot:" << gameInfo.rotationForce << "." << endl;
587 
588                 if(gameInfo.velocity.y >= gameRules.maxLandingYel) //If it's not smaller, it's not faster
589                 {
590                   float temp = gameInfo.velocity.x;
591                   if(temp < 0)
592                     temp *= -1.0;
593 
594                   if(temp <= gameRules.maxLandingXvel) //it have to be slower
595                   {
596 
597                     temp = gameInfo.rotationForce;
598                     if(temp < 0)
599                       temp *= -1.0;
600                     if(temp <= gameRules.maxLandingRotForce)
601                     {
602                       return(1);
603                     }
604                   }
605                 }
606               }
607             }
608           }
609         }
610       }
611     }
612     prevColType = baseIt->collision;
613     if(prevColType==2)
614       baseA = baseIt->p;
615   }
616   return(0);
617 }
618 
setMission(int missionId,vector<entity> ents)619 void setMission(int missionId, vector<entity> ents)
620 {
621   gameInfo.destBase = gameInfo.nextObjective[missionId];
622 
623   //Set destination on radar.
624   for(vector<entity>::iterator searchIt = ents.begin(); searchIt != ents.end(); ++searchIt)
625   {
626     if(searchIt->id == gameInfo.destBase)
627     {
628       gameInfo.radarDest = searchIt->p;
629     }
630   }
631 }
632 
initGame(vector<vector<vert>> & polys,vector<entity> & ents)633 void initGame(vector< vector<vert> >& polys, vector<entity>& ents)
634 {
635   loadMap(polys, ents);
636 
637   gameInfo.currentObjective=0;
638   gameInfo.score=0;
639   gameInfo.destBase=0;
640   gameInfo.fuel = gameRules.fuelMaxFuel;
641   gameInfo.ammo = gameRules.ammoMaxAmmo;
642 
643   if(gameInfo.nextObjective.size() > 1)
644     setMission(0,ents);
645 
646 
647 
648 }
649 
650 
651 
initNewGame(vector<vector<vert>> & polys,vector<entity> & ents)652 void initNewGame(vector< vector<vert> >& polys, vector<entity>& ents)
653 {
654   gameRules.maxLandingRotForce = 1.0; //degrees, both ways
655   gameRules.maxLandingYel = -0.20; //downward
656   gameRules.maxLandingXvel= 0.15; //both sides
657   gameRules.fuelConsumptionThrust = 15;
658   gameRules.fuelConsumptionTurn = 4;
659   gameRules.fuelMaxFuel = 5500;
660   gameRules.ammoMaxAmmo = 1000;
661 
662 
663   gameState = GameStatePlaying;
664 
665   gameInfo.numMissions=0; //Amount of missions taken
666   gameInfo.level=gameRules.startLevel;
667   initGame(polys, ents);
668 
669 }
670 
shipCrash(entity ship)671 void shipCrash(entity ship)
672 {
673 
674   gameInfo.velocity.x=0;
675   gameInfo.velocity.y=0;
676   gameInfo.thrust=0;
677   gameInfo.rotationForce=0;
678   gameState = GameStateGameOver;
679 
680   cout << endl;
681   cout << "Dead" << endl;
682   cout << "Level "<<gameInfo.level << endl;
683 }
684 
685 struct gameInfoStruct snap;
686 
687 
parseCmdLine(int argc,char ** argv)688 bool parseCmdLine(int argc, char **argv)
689 {
690   bool chosenLevel=0, chosenDemo=0;
691   for(int i=1; i < argc; i++)
692   {
693     if( i == 1)
694     {
695       if(argv[1][0] != '-')
696       {
697         gameRules.startLevel = atoi(argv[1]);
698         levelFile = DATADIR"levels/";
699         levelFile.append(argv[1]);
700         levelFile.append(".level");
701         chosenLevel=1;
702       }
703     }
704 
705     if( strcmp(argv[i], "--levelfile") == 0 )
706     {
707       i++;
708       if(i > argc)
709       {
710         cout << "Error: Specify level file." << endl;
711         return(0);
712       }
713       chosenLevel=1;
714       levelFile = argv[i];
715     } else if(i!=1) {
716       cout << "Error: unknown argument '" << argv[i] << "'" << endl;
717       return(0);
718     }
719 
720 
721   }
722 
723   return(1);
724 }
725 
main(int argc,char ** argv)726 int main(int argc, char **argv)
727 {
728 
729   srand ( time(NULL) );
730 
731   /* These can be overwritten by the call to parseCmdLine */
732   levelFile = DATADIR"levels/0.level";
733 
734   gameState = GameStateNewGame;
735 
736   if(!parseCmdLine(argc, argv))
737   {
738     return(1);
739   }
740 
741   SDL_Event event;
742   //Init sdl and screen
743   if(SDL_Init(SDL_INIT_TIMER) <0 )
744   {
745     cout << SDL_GetError() << endl;
746   }
747 
748 
749   cout << "Osgg Server"<<endl;
750   cout << "Using level file '" << levelFile << "'" << endl;
751 
752 
753 
754   int ticks=0, lastTicks=0;
755 
756 
757 /** GameVars **/
758   vector<vert> testVerts;
759   vert tempVert;
760   gPs collisionPoint;
761   bool crashed=0;
762   char score[256];
763   vector<entity> ents; //entities
764   vector<vert> activeVerts;
765   vector< vector<vert> > polys;
766 
767   readEnt("ship.txt", gameInfo.shipStaticVerts);
768   readEnt("base.txt", gameInfo.baseStaticVerts);
769   readEnt("enemy.txt", gameInfo.enemyStaticVerts);
770 
771   //Enter Main loop
772   while(gameState != GameStateQuit)
773   {
774 
775     while(SDL_PollEvent(&event))
776     {
777 
778     switch(gameState)
779     {
780       case GameStateNewGame:
781         initNewGame(polys,ents);
782         gameState=GameStatePlaying;
783       break;
784 
785       case GameStatePlaying:
786 
787         //Check if any bullets hit the enviroment:
788         bullets.envCol(polys);
789         bullets.render();
790 
791         //Ents:
792         for(vector<entity>::iterator it = ents.begin(); it != ents.end(); ++it)
793         {
794           if(it->type == entShip)
795           {
796             Uint8* keyStates = SDL_GetKeyState( NULL );
797 
798             if(keyStates[SDLK_LEFT])
799             {
800               if(gameInfo.fuel > 0)
801               {
802                 gameInfo.rotationForce += TURNINCRATE;
803                 gameInfo.fuel -= gameRules.fuelConsumptionTurn;
804               }
805             } else if(keyStates[SDLK_RIGHT])
806             {
807               if(gameInfo.fuel > 0)
808               {
809                 gameInfo.rotationForce -= TURNINCRATE;
810                 gameInfo.fuel -= gameRules.fuelConsumptionTurn;
811               }
812             }
813 
814             if(keyStates[SDLK_UP])
815             {
816               if(gameInfo.fuel > 0)
817               {
818                 gameInfo.thrust = THRUSTINCRATE;
819                 gameInfo.fuel -= gameRules.fuelConsumptionThrust;
820               } else {
821                 gameInfo.thrust = 0;
822               }
823             } else
824             {
825               gameInfo.thrust = 0;
826             }
827 
828             if(gameInfo.reloadTime != 0)
829             {
830               gameInfo.reloadTime--;
831             }
832             if(keyStates[SDLK_SPACE])
833             {
834               if(gameInfo.reloadTime == 0 && gameInfo.ammo >= 100)
835               {
836                 gameInfo.ammo -= 100;
837                 gameInfo.reloadTime = 25;
838                 bullets.shoot(*it, gameInfo.velocity);
839               }
840             }
841 
842 	    //Update the speed
843 	    gameInfo.speed = abs2(gameInfo.velocity.x*100)+abs2(gameInfo.velocity.y*100);
844 
845 	    //Update velocities
846             gameInfo.velocity.x += gameInfo.thrust * cos( (it->rotation*0.0174532925) );
847             gameInfo.velocity.y += gameInfo.thrust * sin( (it->rotation*0.0174532925) );
848 
849             gameInfo.velocity.y -= GRAVITY;
850 
851 
852             if(gameInfo.rotationForce > 0)
853             {
854 
855               gameInfo.rotationForce /= 1.01;
856               if(gameInfo.rotationForce < 0)
857               {
858                 gameInfo.rotationForce = 0;
859               }
860             } else if(gameInfo.rotationForce < 0)
861             {
862               gameInfo.rotationForce /= 1.01;
863               if(gameInfo.rotationForce > 0)
864               {
865                 gameInfo.rotationForce = 0;
866               }
867             }
868 
869             //Collision with terrain
870             for(vector< vector<vert> >::iterator PolyIt = polys.begin(); PolyIt != polys.end(); ++PolyIt)
871             {
872               if(PolyCol(*PolyIt, gameInfo.shipVerts))
873               {
874                 shipCrash(*it);
875               }
876             }
877 
878             crashed=0;
879            //Collision with ents
880             for(vector<entity>::iterator entIt = ents.begin(); entIt != ents.end(); ++entIt)
881             {
882               //Collition with entities
883               if(entIt->type==entBase)
884               {
885                 updateEntVerts(*entIt, gameInfo.baseVerts, gameInfo.baseStaticVerts);
886                 crashed=PolyCol(gameInfo.baseVerts, gameInfo.shipVerts);
887               } else if(entIt->type==entEnemy)
888               {
889                 updateEntVerts(*entIt, gameInfo.enemyVerts, gameInfo.enemyStaticVerts);
890                 crashed=PolyCol(gameInfo.enemyVerts, gameInfo.shipVerts);
891 
892                 //check if this enemy is being hit
893                 if(bullets.col(gameInfo.enemyVerts, 0))
894                 {
895                   entIt = ents.erase(entIt);
896 //                   gameInfo.score -= 3000;
897                   break;
898                 }
899               }
900 
901               if(crashed)
902               {
903                 shipCrash(*it);
904               } else {
905                 //Is he landing on a base?
906                 if(entIt->type==entBase)
907                 {
908                   if(landCol(gameInfo.baseVerts, gameInfo.shipVerts))
909                   {
910 
911                     //Subtract 1 from score again
912 //                     gameInfo.score -= 1;
913 
914                     if(gameInfo.fuel < gameRules.fuelMaxFuel)
915                     gameInfo.fuel += 15;
916                     if(gameInfo.fuel > gameRules.fuelMaxFuel)
917                     gameInfo.fuel = gameRules.fuelMaxFuel;
918 
919                     if(gameInfo.ammo < gameRules.ammoMaxAmmo)
920                     gameInfo.ammo += 3;
921                     if(gameInfo.ammo > gameRules.ammoMaxAmmo)
922                     gameInfo.ammo = gameRules.ammoMaxAmmo;
923 
924 
925                     it->rotation=90.0;
926 
927                     if(gameInfo.velocity.y < 0.0)
928                       gameInfo.velocity.y=0;
929 
930                     gameInfo.velocity.x=0;
931                     gameInfo.rotationForce=0;
932 
933                     if(gameInfo.numBases > 1)
934                     {
935                       //Is this the destination base?
936                       if(gameInfo.destBase == entIt->id)
937                       {
938 
939                         gameInfo.numMissions++;
940 
941                         //Do he have more missions left?
942                         gameInfo.currentObjective++;
943                         if(gameInfo.currentObjective < gameInfo.nextObjective.size())
944                         {
945                           //Give it to him
946                           setMission(gameInfo.currentObjective, ents);
947                         } else {
948                           gameState = GameStateNextLevel;
949                         }
950                       }
951                     }
952                   }
953                 }
954               } //not crashing
955             }
956 
957             it->rotation += gameInfo.rotationForce;
958             it->p.x += gameInfo.velocity.x;
959             it->p.y += gameInfo.velocity.y;
960 
961           } else
962           /** Update enemies **/
963           if(it->type == entEnemy)
964           {
965             it->vel.y -= GRAVITY;
966 
967             if(it->p.y <= it->baseP.y-0.3)
968             {
969               it->vel.y += 0.01;
970             }
971             it->p.y += it->vel.y;
972           }
973         }
974 
975 
976 
977       break;
978 
979       /** END OF GAME **/
980 
981     }
982 
983 
984 
985 
986     }
987 
988     ticks += SDL_GetTicks() - lastTicks;
989     lastTicks = SDL_GetTicks();
990     SDL_Delay(10);
991   }
992 
993 
994   return(0);
995 }
996