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