little step in map saving & TODO update
[Lilanci.git] / ebulanci.c
blobbbb71563ad0821d0a419e23aa2ff12237526cf26
1 #include <math.h>
2 #include <time.h>
3 #include "geometry.h"
4 #include "util.h"
5 #include "config.h"
6 #include "gr.h"
7 #include "map.h"
8 #include "snd.h"
9 #include "particle.h"
10 #include "path.h"
13 int gamestate=0;
15 typedef struct{
16 int Up;
17 int Down;
18 int Left;
19 int Right;
20 int Shoot;
21 int Suicide;
22 int Switch;
23 }TKeyBinding;//TODO: s/int/real data type for a key
25 typedef struct{
26 Vect Pos; //where he is
27 Vect Move; //how he want to move
28 Vect BSize; //Size of bounding rect
29 Area *Shape; //how fat he is
30 //Area *TrShape; //translated Shape -- don't optimize yet
31 int Frags; //no comment
32 int Deaths; //R.I.P.
33 double Speed; //meters per second
34 int Orientation; //1-up 2-left 3-down 4-right 0-down
35 int WannaShoot; //1-want 0-don't want
36 double ReloadTime; //time from last shot
37 int WannaDie; //1-want suicide 2-died and still holding suicide 0-don't want
38 double AnimationTime; //in seconds
39 TKeyBinding Keys;
40 int *Ammo;
41 int ActiveWeapon;
42 int SwitchLock;
43 int Alive;
44 char Name[16];
45 SDL_Color Color;
46 }TLilanek;
49 typedef struct{
50 Vect Pos;
51 Area *Shape;
52 int WID; //Weapon ID
53 int Exists; // 0- doesn't exist 1-exists
54 int Ammo;
55 int MaxAmmo;
56 int Burst;
57 double ReloadTime;
58 }TWeapon;
60 typedef struct{
61 Vect Pos;
62 Area *Shape;
63 Vect Vel; //velocity i m/s
64 double Speed; //for Templates
65 double Range; //How far it can travel
66 int WID; //Weapon ID
67 int lid; //who shoot this bullet?
68 int Exists; // 0- doesn't exist 1-exists
69 double SFuzzy; // Fuzzy factor for spawning 0-1 :)
70 double VFuzzy; // Fuzzy factor for traveling 0-1 :)
71 }TBullet;
74 typedef struct{
75 TMap *Map; //where we are playing
76 TLilanek *Lilanek; //our heroes-ehm bad guys
77 int noLilaneks;
79 TWeapon *Weapon; //Weapons lying on floor
80 int noWeapons;
81 TWeapon *WeaponTemplate;
82 TBullet *BulletTemplate;
83 int noWID; //biggest WID, also number of WeaponTemplates
84 TBullet *Bullet;
85 int noBullets;
86 double PWeapondrop; // Probability of weapon drop per second
87 }Game;
89 Vect Orientations[5];
91 Sprite *lil[5];
92 Sprite *bg;
93 Sprite *kul;
94 Sprite *explo;
95 Sprite *dust;
96 Sprite *blood;
97 Sprite *brok;
98 Sprite *kulka;
99 Sprite *mine;
100 Sprite *mines;
101 Sprite *hud;
102 Sprite *hud_mine;
103 Sprite *hud_kul;
104 Sprite *hud_brok;
105 Sprite *hud_ammo;
106 Sprite *hud_reload;
107 int s_die;
108 int s_bonus;
109 int s_expl;
110 int s_shoot;
111 int s_mine;
113 int frames=0;
114 void SwitchNextWeapon(Game *g, int lid);
116 int InitBase(){
117 Orientations[0].x=0;
118 Orientations[0].y=0;
119 Orientations[1].x=0;
120 Orientations[1].y=-1;
121 Orientations[2].x=-1;
122 Orientations[2].y=0;
123 Orientations[3].x=0;
124 Orientations[3].y=1;
125 Orientations[4].x=1;
126 Orientations[4].y=0;
127 //TODO: write code
129 return 0;
132 void SpawnLilanek(Game *g, int lid){
133 Vect Pos;
134 int tries;
135 Area *tp, *oltp;
136 int good;
137 int olid;
139 oltp = 0;
140 tp = 0;
141 for(tries=0; tries <1000; tries++){ //TODO: remove exact number
142 Pos.x = RandD(0,g->Map->XX);
143 Pos.y = RandD(0,g->Map->YY);
144 good=1;
145 tp = TranslateArea(g->Lilanek[lid].Shape, &Pos);
146 printf("%s\n", Area2String(tp));
147 if(!AreaInMap(g->Map, tp,0,1)){
148 good=0;
151 for(olid=0; olid < g->noLilaneks; olid++){
152 if(olid == lid)
153 continue;
154 if(!g->Lilanek[olid].Alive){
155 continue;
157 oltp = TranslateArea(g->Lilanek[olid].Shape, &g->Lilanek[olid].Pos);
158 if(AreaInArea(tp, oltp)){
159 good=0;
161 FreeArea(oltp);
162 oltp = 0;
165 if(good){
166 FreeArea(tp);
167 tp=0;
168 g->Lilanek[lid].Pos.x = Pos.x;
169 g->Lilanek[lid].Pos.y = Pos.y;
170 g->Lilanek[lid].Alive = 1;
171 break;
173 FreeArea(tp);
174 tp=0;
178 void DropWeapon(Game *g, int weapon){
179 Vect Pos;
180 int tries;
181 int WID;
182 Area *tp;
184 for(tries=0; tries <100; tries++){ //TODO: remove exact number
185 Pos.x = RandD(0,g->Map->XX);
186 Pos.y = RandD(0,g->Map->YY);
187 WID = RandI(0, g->noWID);
188 tp = TranslateArea(g->WeaponTemplate[WID].Shape, &Pos);
189 if(AreaInMap(g->Map, tp, 0, g->Map->noLayer)){
190 FreeArea(tp);
191 tp=0;
192 memcpy(&g->Weapon[weapon], &g->WeaponTemplate[WID], sizeof(TWeapon));
193 g->Weapon[weapon].Shape = g->WeaponTemplate[WID].Shape;
194 g->Weapon[weapon].Pos.x = Pos.x;
195 g->Weapon[weapon].Pos.y = Pos.y;
196 g->Weapon[weapon].WID = WID;
197 g->Weapon[weapon].Exists = 1;
198 break;
200 FreeArea(tp);
201 tp=0;
205 void DropWeapons(Game *g, double dtime){
206 int i;
208 if( RandD(0.0, 1.0) >= (g->PWeapondrop*dtime))
209 return;
210 for(i=0; i < g->noWeapons; i++){
211 if(g->Weapon[i].Exists)continue; //we don't like teleporting weapons :)
213 printf("A Weapon drop!\n");
214 DropWeapon(g, i);
215 break; //spawn max one weapon per update
219 void WeaponPickedUp(Game *g, double dtime, int lid, int wid){
220 TLilanek *l;
221 TWeapon *w;
223 l = &g->Lilanek[lid];
224 w = &g->Weapon[wid];
226 l->Ammo[w->WID] += w->Ammo;
227 if(l->Ammo[w->WID] > w->MaxAmmo)
228 l->Ammo[w->WID] = w->MaxAmmo;
229 printf("Ammo: %d\n",l->Ammo[w->WID]);
230 l->ActiveWeapon = w->WID;
231 printf("AW: %d\n",l->ActiveWeapon);
233 w->Exists = 0;
235 PlaySound(s_bonus);
238 void PickUpWeapons(Game *g, double dtime){
239 int lid,wid;
240 Area *WArea, *LArea;
242 for(lid=0; lid<g->noLilaneks; lid++){
243 LArea = TranslateArea(g->Lilanek[lid].Shape, &g->Lilanek[lid].Pos);
244 for(wid=0; wid < g->noWeapons; wid++){
245 if(!g->Weapon[wid].Exists)
246 continue;
247 WArea = TranslateArea(g->Weapon[wid].Shape, &g->Weapon[wid].Pos);
248 if(!AreaInArea( WArea, LArea)){
249 FreeArea(WArea);
250 continue;
252 WeaponPickedUp(g, dtime, lid, wid);
253 FreeArea(WArea);
255 FreeArea(LArea);
259 void BulletExplodes(Game *g, int i){
260 g->Bullet[i].Exists=0;
261 //TODO: some effects
264 void MoveBullet(Game *g, double dtime, int i){
265 double ff;
266 Vect dp;
267 dp.x = g->Bullet[i].Pos.x;
268 dp.y = g->Bullet[i].Pos.y;
269 ff= g->Bullet[i].Speed*g->Bullet[i].VFuzzy;
270 g->Bullet[i].Pos.x += (g->Bullet[i].Vel.x += RandD(-ff,ff))* dtime;
271 g->Bullet[i].Pos.y += (g->Bullet[i].Vel.y += RandD(-ff,ff))* dtime;
272 dp.x -= g->Bullet[i].Pos.x;
273 dp.y -= g->Bullet[i].Pos.y;
274 g->Bullet[i].Range -= sqrt(DotProduct(&dp, &dp));
277 void CollideBulletMap(Game *g, double dtime, int i){
278 Area *p;
280 p=TranslateArea(g->Bullet[i].Shape, &g->Bullet[i].Pos);
281 if(AreaInMap(g->Map, p, 1,1)==0)
282 BulletExplodes(g, i);
283 FreeArea(p);
286 void BloodColorFunc(double temp, SDL_Color *c)
288 SDL_Color col={255,255,255,255};
289 col.r *=(0.5+0.5*temp);
290 //col.g *=temp;
291 //col.b *=temp;
292 //col.unused *=temp*temp;
293 if (c != 0) memcpy(c, &col, sizeof(SDL_Color));
296 void BloodParticles(Game *g, double dtime, int lid)
298 int i;
299 double a;
300 double v;
301 Particle *p;
303 for(i = 0; i < 5; i ++){
304 p = malloc(sizeof(Particle));
305 memset(p, 0, sizeof(Particle));
306 a = RandD(0.0, 20.0);
307 v = RandD(0.0, 2.0);
308 p->x = g->Lilanek[lid].Pos.x-g->Lilanek[lid].BSize.x*0.5;
309 p->y = g->Lilanek[lid].Pos.y-g->Lilanek[lid].BSize.y*0.5;
310 p->t = 1.0;
311 p->vx = v*sin(a) + g->Lilanek[lid].Move.x;
312 p->vy = v*cos(a) + g->Lilanek[lid].Move.y;
313 p->fx = 1.5;
314 p->fy = 1.5;
315 p->vt = 0.0-1.0;
316 p->s = blood;
317 p->tf = &BloodColorFunc;
318 p->z = 1;
319 AddParticle(p);
323 void LilanekKilled(Game *g, double dtime, int BulletID, int LilanekID){
324 int i;
325 g->Bullet[BulletID].Exists = 0;
326 g->Lilanek[LilanekID].Deaths ++;
327 g->Lilanek[g->Bullet[BulletID].lid].Frags ++;
328 BloodParticles(g, dtime, LilanekID);
329 SpawnLilanek(g, LilanekID);
330 for(i=0; i<g->noWID; i++){
331 g->Lilanek[LilanekID].Ammo[i] = 0;
333 PlaySound(s_die);
336 #define NO_EXPLOSIONS 10 //MAGIC_NUMBER
337 #define EXPLOSION_SPEED 5 //MAGIC_NUMBER
338 #define EXPLOSION_RANGE 1.0 //MAGIC_NUMBER
340 void SpawnExplosions(Game *g, double dtime, int BulletID){
341 int bid = 0;
342 int i = 0;
343 TBullet *b;
344 Vect Pos;
345 double speed;
347 Pos.x = g->Bullet[BulletID].Pos.x;
348 Pos.y = g->Bullet[BulletID].Pos.y;
349 for(i=0; i<NO_EXPLOSIONS; i++){
350 for(bid=0; bid<g->noBullets; bid++){
351 if(g->Bullet[bid].Exists)
352 continue;
353 b = &g->Bullet[bid];
354 b->Pos.x = Pos.x;
355 b->Pos.y = Pos.y;
356 b->Vel.x = RandD(0.0, 1.0)*(RandI(0,100)>50?-1:1);
357 b->Vel.y = RandD(0.0, 1.0)*(RandI(0,100)>50?-1:1);
358 NormV(&b->Vel);
359 speed = RandD(0.3, 1.0)*EXPLOSION_SPEED;
360 b->Speed = speed;
361 b->Vel.x *= speed;
362 b->Vel.y *= speed;
363 b->WID = -1;
364 b->lid = g->Bullet[BulletID].lid;
365 b->Exists = 1;
366 b->SFuzzy = 0;
367 b->VFuzzy = 0;
368 b->Range = EXPLOSION_RANGE;
369 b->Shape = g->Bullet[BulletID].Shape;
370 printf("%lf ", speed);
371 break;
374 g->Bullet[BulletID].Exists = 0;
375 PlaySound(s_expl);
378 void CollideBulletLilanek(Game *g, double dtime, int BulletID){
379 Area *BArea, *LArea;
380 int LilanekID;
382 BArea=TranslateArea(g->Bullet[BulletID].Shape, &g->Bullet[BulletID].Pos);
383 for(LilanekID=0; LilanekID<g->noLilaneks; LilanekID++){
384 LArea=TranslateArea(g->Lilanek[LilanekID].Shape, &g->Lilanek[LilanekID].Pos);
385 if(AreaInArea(LArea,BArea)){
386 //if it is a mine, spawn explosion instead of killing instantly
387 if(g->Bullet[BulletID].WID == 1){
388 SpawnExplosions(g, dtime, BulletID);
389 }else{
390 LilanekKilled(g, dtime, BulletID, LilanekID);
393 FreeArea(LArea);
394 LArea=0;
396 FreeArea(BArea);
397 BArea=0;
400 void UpdateBullets(Game *g, double dtime){
401 int BulletID;
402 for(BulletID=0; BulletID<g->noBullets; BulletID++){
403 if(g->Bullet[BulletID].Exists==0)
404 continue; //We won't update non-existending bullets
405 MoveBullet(g, dtime, BulletID);
406 if(g->Bullet[BulletID].Range < 0){
407 g->Bullet[BulletID].Exists = 0;
408 continue;
410 CollideBulletMap(g, dtime, BulletID);
411 CollideBulletLilanek(g, dtime, BulletID);
415 int CheckLilanekvsLilaneks(Game *g, Area *a, int LilanekID){ //returns 0 if he collides with others, 1 if it's OK to move there
416 int i;
417 Area *nb;
418 int rval=1;
420 nb=0;
421 for(i=0; i<g->noLilaneks && rval==1; i++){
422 if(i==LilanekID)
423 continue;
424 nb = TranslateArea(g->Lilanek[i].Shape, &g->Lilanek[i].Pos);
425 if(AreaInArea(nb, a))
426 rval=0;
427 FreeArea(nb);
428 nb=0;
430 return rval;
433 void MoveLilaneks(Game *g, double dtime){
434 int i, steps;
435 Area *pa;
436 Vect va;
437 double dt;
439 pa=0;
440 for(i=0; i<g->noLilaneks; i++){
441 //skip this Lilanek if he doesn't wanna move
442 if(g->Lilanek[i].Move.x == 0.0 && g->Lilanek[i].Move.y == 0.0)
443 continue;
444 for(dt=dtime, steps=0; steps<4; dt/=2.0, steps++){ //TODO: get rid of exact number
445 //make future Area
446 va.x = g->Lilanek[i].Pos.x + dt*g->Lilanek[i].Move.x;
447 va.y = g->Lilanek[i].Pos.y + dt*g->Lilanek[i].Move.y;
448 FreeArea(pa); //we don't want memory leaks
449 pa = TranslateArea(g->Lilanek[i].Shape, &va);
450 //check for collision with map
451 if(AreaInMap(g->Map, pa, 0, 1)==0)
452 continue; //try smaller dt if he collided with map
453 //check for collision with other Lilaneks
454 if(CheckLilanekvsLilaneks(g, pa, i)==0)
455 continue;
456 //move him if we got here
457 g->Lilanek[i].Pos.x += dt*g->Lilanek[i].Move.x;
458 g->Lilanek[i].Pos.y += dt*g->Lilanek[i].Move.y;
459 FreeArea(pa);
460 pa=0;
462 FreeArea(pa); //For sure
463 pa=0;
467 void ParseInput(Game *g, double dtime){
468 int i;
469 Uint8 *keystate;
470 TLilanek *curlil;
471 int wannamove;
473 keystate = SDL_GetKeyState(NULL);
474 //pause
475 if(gamestate == 1){
476 if(keystate['o']){
477 printf("unpause\n");
478 gamestate = 0;
479 }else return;
481 if(keystate['p']){
482 printf("pause\n");
483 gamestate = 1;
486 for(i=0; i< g->noLilaneks; i++){
487 curlil = &g->Lilanek[i];
488 wannamove=0;
489 // Up;
490 if(keystate[curlil->Keys.Up]){
491 curlil->Orientation = 1;
492 curlil->Move.x = curlil->Speed * Orientations[1].x;
493 curlil->Move.y = curlil->Speed * Orientations[1].y;
494 wannamove=1;
496 // Down;
497 if(keystate[curlil->Keys.Down]){
498 curlil->Orientation = 3;
499 curlil->Move.x = curlil->Speed * Orientations[3].x;
500 curlil->Move.y = curlil->Speed * Orientations[3].y;
501 wannamove=1;
503 // Left;
504 if(keystate[curlil->Keys.Left]){
505 curlil->Orientation = 2;
506 curlil->Move.x = curlil->Speed * Orientations[2].x;
507 curlil->Move.y = curlil->Speed * Orientations[2].y;
508 wannamove=1;
510 // Right;
511 if(keystate[curlil->Keys.Right]){
512 curlil->Orientation = 4;
513 curlil->Move.x = curlil->Speed * Orientations[4].x;
514 curlil->Move.y = curlil->Speed * Orientations[4].y;
515 wannamove=1;
518 if(!wannamove){
519 curlil->Move.x = 0;
520 curlil->Move.y = 0;
522 // Shoot;
523 if(keystate[curlil->Keys.Shoot]){
524 curlil->WannaShoot = 1;
525 }else{
526 curlil->WannaShoot = 0;
528 // Suicide;
529 if(keystate[curlil->Keys.Suicide]){
530 if(curlil->WannaDie != 2){
531 curlil->WannaDie = 1;
533 }else{
534 curlil->WannaDie = 0;
536 // Switch;
537 if(keystate[curlil->Keys.Switch]){
538 if(!curlil->SwitchLock){
539 SwitchNextWeapon(g, i);
540 curlil->SwitchLock = 1;
542 }else{
543 curlil->SwitchLock = 0;
548 void SpawnBullet(Game *g, double dtime, int lid, int bid){
549 Area *LArea, *BArea;
550 TBullet *b, *bt;
551 double vx, vy; //because we need to spawn also mines with no velocity
554 LArea = TranslateArea(g->Lilanek[lid].Shape, &g->Lilanek[lid]. Pos);
555 b = &g->Bullet[bid];
556 bt = &g->BulletTemplate[g->Lilanek[lid].ActiveWeapon];
557 memcpy (b, bt, sizeof(TBullet));
558 b->Exists = 1;
559 b->Pos.x = g->Lilanek[lid].Pos.x+g->Lilanek[lid].BSize.x*0.5;
560 b->Pos.y = g->Lilanek[lid].Pos.y+g->Lilanek[lid].BSize.y*0.5;
561 b->WID = bt->WID;
562 b->Range = bt->Range;
563 b->Vel.x = Orientations[g->Lilanek[lid].Orientation].x * b->Speed +RandD(-b->Speed*b->SFuzzy, b->Speed*b->SFuzzy);
564 b->Vel.y = Orientations[g->Lilanek[lid].Orientation].y * b->Speed +RandD(-b->Speed*b->SFuzzy, b->Speed*b->SFuzzy);
565 if(DotProduct(&b->Vel, &b->Vel) <=0.01){
566 vx = -1*Orientations[g->Lilanek[lid].Orientation].x;
567 vy = -1*Orientations[g->Lilanek[lid].Orientation].y;
568 }else{
569 vx = b->Vel.x;
570 vy = b->Vel.y;
572 b->lid =lid;
573 while(1){
574 BArea = TranslateArea(b->Shape, &b->Pos);
575 if(!AreaInArea(BArea, LArea))
576 break;
577 b->Pos.x += vx* dtime*0.5;
578 b->Pos.y += vy* dtime*0.5;
580 FreeArea(LArea);
583 void DustColorFunc(double temp, SDL_Color *c)
585 SDL_Color col={255,255,255,255};
586 col.r *=temp;
587 col.g *=temp;
588 col.b *=temp;
589 col.unused *=temp*temp;
590 if (c != 0) memcpy(c, &col, sizeof(SDL_Color));
593 void ShootParticles(Game *g, double dtime, int lid)
595 int i;
596 double a;
597 double v;
598 Particle *p;
600 for(i = 1; i < 10; i ++){
601 p = malloc(sizeof(Particle));
602 memset(p, 0, sizeof(Particle));
603 a = RandD(0.0, 2*M_PI);
604 v = RandD(0.0, 2.0);
605 p->x = g->Lilanek[lid].Pos.x-g->Lilanek[lid].BSize.x*0.5;
606 p->y = g->Lilanek[lid].Pos.y-g->Lilanek[lid].BSize.y*0.5;
607 p->t = 1.0;
608 p->vx = v*sin(a) + g->Lilanek[lid].Move.x;
609 p->vy = v*cos(a) + g->Lilanek[lid].Move.y;
610 p->vt = 0.0-2.0;
611 p->s = dust;
612 p->z = 1;
613 p->tf = &DustColorFunc;
614 AddParticle(p);
618 void Shoot(Game *g, double dtime, int lid){
619 int bid;
620 int i;
622 for(i=0; i<g->WeaponTemplate[g->Lilanek[lid].ActiveWeapon].Burst; i++){
623 if(g->Lilanek[lid].Ammo[g->Lilanek[lid].ActiveWeapon] == 0)
624 return;
625 for(bid=0; bid<g->noBullets; bid++){
626 if(g->Bullet[bid].Exists)
627 continue;
628 SpawnBullet(g, dtime, lid, bid);
629 g->Lilanek[lid].Ammo[g->Lilanek[lid].ActiveWeapon]--;
630 g->Lilanek[lid].ReloadTime = 0;
631 break;
634 ShootParticles(g, dtime, lid);
635 switch(g->Lilanek[lid].ActiveWeapon){
636 case 0: PlaySound(s_shoot); break;
637 case 1: PlaySound(s_mine); break;
638 case 2: PlaySound(s_shoot); break;
639 default: break;
643 void SwitchNextWeapon(Game *g, int lid){
644 int i;
645 TLilanek *l;
646 l = &g->Lilanek[lid];
647 for(i = 1; i < g->noWID; i++){
648 if(l->Ammo[(l->ActiveWeapon+i)%(g->noWID)]){
649 l->ActiveWeapon = (l->ActiveWeapon+i)%(g->noWID);
650 return;
655 void ShootIfTheyWantTo(Game *g, double dtime){
656 int lid;
658 for(lid=0; lid<g->noLilaneks; lid++){
659 //if(!g->Lilanek[lid].Exists)
660 //continue;
661 if(g->Lilanek[lid].Ammo[g->Lilanek[lid].ActiveWeapon] == 0)
662 SwitchNextWeapon(g,lid);
664 if(g->Lilanek[lid].ReloadTime < g->WeaponTemplate[g->Lilanek[lid].ActiveWeapon].ReloadTime){
665 g->Lilanek[lid].ReloadTime += dtime;
666 }else{
667 if(!g->Lilanek[lid].WannaShoot)
668 continue;
669 Shoot(g, dtime, lid);
674 int UpdateLogic(Game *g,double dtime){
675 if(gamestate == 0){
676 DropWeapons(g, dtime);
677 UpdateBullets(g, dtime);
679 ParseInput(g, dtime);
680 if(gamestate == 0){
681 MoveLilaneks(g, dtime);
682 PickUpWeapons(g, dtime);
683 ShootIfTheyWantTo(g, dtime);
685 return 0; //TODO: return something useful
688 Game *testgame(){ //return testing game, function for use before we have some menu/loading mechanism
689 Game *g;
690 Poly *p, *pp;
691 Area *a;
692 int i;
693 Config conf = GetConfig();
695 g = malloc(sizeof(Game));
696 memset(g, 0, sizeof(Game));
697 g->noWID=3;
698 g->Map = malloc(sizeof(TMap));
699 g->Map->noLayer=2;
700 g->Map->Layer = malloc(sizeof(TMapLayer *)*g->Map->noLayer);
701 g->Map->Layer[0] = malloc(sizeof(TMapLayer));
702 g->Map->Layer[0]->noFArea = 1;
703 g->Map->Layer[0]->FArea = malloc(sizeof(Area *) * g->Map->Layer[0]->noFArea);
704 p = NewRect(4,2.5,3,2);
705 a = NewArea();
706 AddToArea(a, p);
707 FreePoly(p);
708 g->Map->Layer[0]->FArea[0] = a;
710 g->Map->Layer[1] = malloc(sizeof(TMapLayer));
711 g->Map->Layer[1]->noFArea = 1;
712 g->Map->Layer[1]->FArea = malloc(sizeof(Area *) * g->Map->Layer[1]->noFArea);
713 p = NewPoly();
714 AddToPolyXY(p, 0.30, 0.41);
715 AddToPolyXY(p, 0.73, 0.41);
716 AddToPolyXY(p, 0.77, 0.79);
717 AddToPolyXY(p, 0.65, 0.955);
718 AddToPolyXY(p, 0.365, 0.965);
719 AddToPolyXY(p, 0.235, 0.785);
720 MultiplyPoly(p, 4, 4);
721 pp = TranslatePolyXY(p, 7, 7);
722 a = NewArea();
723 AddToArea(a, pp);
724 FreePoly(pp);
725 FreePoly(p);
726 g->Map->Layer[1]->FArea[0] = a;
727 p = NewRect(1,1,16,15);
728 a = NewArea();
729 AddToArea(a, p);
730 FreePoly(p);
731 g->Map->BoundingArea = a;
732 g->Map->XX = 16;
733 g->Map->YY = 15;
734 g->Map->X = 0;
735 g->Map->Y = 0;
737 SetParticleBoundingBox(0,0,16,15);
741 g->Map->noSprites = 2;
742 g->Map->Sprites = (Sprite **) malloc(sizeof(Sprite*)*g->Map->noSprites);
743 g->Map->SpritePos = (Vect *) malloc(sizeof(Vect)*g->Map->noSprites);
744 g->Map->SpritePos[0].x = 3.0;
745 g->Map->SpritePos[0].y = 1.0;
746 g->Map->SpritePos[1].x = 6.0;
747 g->Map->SpritePos[1].y = 6.0;
749 g->noWeapons = 8;
750 g->Weapon = malloc(sizeof(TWeapon) * g->noWeapons);
751 if(!g->Weapon){
752 fprintf(stderr, "Cannot allocate memory for Weapons\n");
754 for(i=0; i<g->noWeapons; i++){
755 g->Weapon[i].Exists = 0;
756 g->Weapon[i].Shape = 0;
759 g->noLilaneks = 2;
760 g->Lilanek = malloc(sizeof(TLilanek) * g->noLilaneks);
761 memset(g->Lilanek, 0, sizeof(TLilanek) * g->noLilaneks);
762 g->Lilanek[0].BSize.x = 1;
763 g->Lilanek[0].BSize.y = 1;
764 //g->Lilanek[0].Shape = NewRect(0.6,0.2,0.8,1.6);
765 p = NewPoly();
766 AddToPolyXY(p, 1, 0);
767 AddToPolyXY(p, 1.4, 0.2);
768 AddToPolyXY(p, 1.66, 1.38);
769 AddToPolyXY(p, 1.42, 2);
770 AddToPolyXY(p, 0.6, 2);
771 AddToPolyXY(p, 0.4, 1.46);
772 AddToPolyXY(p, 0.66, 0.2);
773 MultiplyPoly(p, 0.5*g->Lilanek[0].BSize.x, 0.5*g->Lilanek[0].BSize.y);
774 a = NewArea();
775 AddToArea(a, p);
776 FreePoly(p);
777 g->Lilanek[0].Shape = a;
778 g->Lilanek[0].Pos.x = 12;
779 g->Lilanek[0].Pos.y = 4;
780 g->Lilanek[0].Speed = 4;
781 g->Lilanek[0].Alive = 0;
782 g->Lilanek[0].Keys.Up = conf.pl1_key_up;
783 g->Lilanek[0].Keys.Down = conf.pl1_key_down;
784 g->Lilanek[0].Keys.Left = conf.pl1_key_left;
785 g->Lilanek[0].Keys.Right = conf.pl1_key_right;
786 g->Lilanek[0].Keys.Shoot = conf.pl1_key_fire;
787 g->Lilanek[0].Keys.Suicide = conf.pl1_key_suicide;
788 g->Lilanek[0].Keys.Switch = conf.pl1_key_switch;
789 g->Lilanek[0].Ammo = malloc(sizeof(int)*g->noWID);
790 for(i=0; i<g->noWID; i++){
791 g->Lilanek[0].Ammo[i] = 0;
793 g->Lilanek[0].ActiveWeapon = 0;
795 SDL_Color red = {255,211,211,255};
796 char redn[8]="Red";
797 g->Lilanek[0].Color = red;
798 strcpy(g->Lilanek[0].Name, redn);
800 g->Lilanek[1].Alive = 0; // little hack for SpawnLilanek to work
801 SpawnLilanek(g, 0);
803 p = g->Lilanek[0].Shape->p[0];
804 a = NewArea();
805 AddToArea(a, p);
806 g->Lilanek[1].Shape = a;
807 g->Lilanek[1].BSize.x = g->Lilanek[0].BSize.x;
808 g->Lilanek[1].BSize.y = g->Lilanek[0].BSize.y;
809 g->Lilanek[1].Pos.x = 14;
810 g->Lilanek[1].Pos.y = 4;
811 g->Lilanek[1].Speed = 4;
812 g->Lilanek[1].Alive = 0;
813 g->Lilanek[1].Keys.Up = conf.pl2_key_up;
814 g->Lilanek[1].Keys.Down = conf.pl2_key_down;
815 g->Lilanek[1].Keys.Left = conf.pl2_key_left;
816 g->Lilanek[1].Keys.Right = conf.pl2_key_right;
817 g->Lilanek[1].Keys.Shoot = conf.pl2_key_fire;
818 g->Lilanek[1].Keys.Suicide = conf.pl2_key_suicide;
819 g->Lilanek[1].Keys.Switch = conf.pl2_key_switch;
820 g->Lilanek[1].Ammo = malloc(sizeof(int)*g->noWID);
821 for(i=0; i<g->noWID; i++){
822 g->Lilanek[1].Ammo[i] = 0;
824 g->Lilanek[1].ActiveWeapon = 0;
826 SDL_Color blue = {180,180,255, 255};
827 char bluen[8]="Blue";
828 g->Lilanek[1].Color = blue;
829 strcpy(g->Lilanek[1].Name, bluen);
831 SpawnLilanek(g, 1);
833 g->WeaponTemplate = malloc(sizeof(TWeapon)*g->noWID);
834 p = NewRect(0,0,0.5,0.5);
835 a = NewArea();
836 AddToArea(a, p);
837 FreePoly(p);
838 g->WeaponTemplate[0].Shape = a;
839 g->WeaponTemplate[0].WID = 0;
840 g->WeaponTemplate[0].Exists = 1;
841 g->WeaponTemplate[0].Ammo = 30;
842 g->WeaponTemplate[0].MaxAmmo = 120;
843 g->WeaponTemplate[0].ReloadTime = 0.7;
844 g->WeaponTemplate[0].Burst = 10;
846 g->BulletTemplate = malloc(sizeof(TBullet) * g->noWID);
847 p = NewRect(0,0,0.1,0.1);
848 a = NewArea();
849 AddToArea(a, p);
850 FreePoly(p);
851 g->BulletTemplate[0].Shape = a;
852 g->BulletTemplate[0].WID = 0;
853 g->BulletTemplate[0].Speed = 20;
854 g->BulletTemplate[0].Range = 20;
855 g->BulletTemplate[0].SFuzzy = 0.160;
856 g->BulletTemplate[0].VFuzzy = 0.000;
858 p = NewRect(0,0,0.5,0.5);
859 a = NewArea();
860 AddToArea(a, p);
861 FreePoly(p);
862 g->WeaponTemplate[1].Shape = a;
863 g->WeaponTemplate[1].WID = 1;
864 g->WeaponTemplate[1].Exists = 1;
865 g->WeaponTemplate[1].Ammo = 3;
866 g->WeaponTemplate[1].MaxAmmo = 6;
867 g->WeaponTemplate[1].ReloadTime = 0.5;
868 g->WeaponTemplate[1].Burst = 1;
870 p = NewRect(0,0,0.5,0.5);
871 a = NewArea();
872 AddToArea(a, p);
873 FreePoly(p);
874 g->BulletTemplate[1].Shape = a;
875 g->BulletTemplate[1].WID = 1;
876 g->BulletTemplate[1].Speed = 0;
877 g->BulletTemplate[1].Range = 20;
878 g->BulletTemplate[1].SFuzzy = 0.0;
879 g->BulletTemplate[1].VFuzzy = 0.0;
881 p = NewRect(0,0,0.5,0.5);
882 a = NewArea();
883 AddToArea(a, p);
884 FreePoly(p);
885 g->WeaponTemplate[2].Shape = a;
886 g->WeaponTemplate[2].WID = 0;
887 g->WeaponTemplate[2].Exists = 1;
888 g->WeaponTemplate[2].Ammo = 10;
889 g->WeaponTemplate[2].MaxAmmo = 50;
890 g->WeaponTemplate[2].ReloadTime = 0.1;
891 g->WeaponTemplate[2].Burst = 1;
893 p = NewRect(0,0,0.1,0.1);
894 a = NewArea();
895 AddToArea(a, p);
896 FreePoly(p);
897 g->BulletTemplate[2].Shape = a;
898 g->BulletTemplate[2].WID = 0;
899 g->BulletTemplate[2].Speed = 20;
900 g->BulletTemplate[2].Range = 20;
901 g->BulletTemplate[2].SFuzzy = 0.040;
902 g->BulletTemplate[2].VFuzzy = 0.010;
903 g->noBullets = 64;
904 g->Bullet = malloc(sizeof(TBullet) * g->noBullets);
905 for(i=0; i<g->noBullets; i++){
906 g->Bullet[i].Exists = 0;
907 g->Bullet[i].Shape = 0;
910 g->PWeapondrop = 0.4;
912 return g;
916 void onExit()
918 GrKill();
919 SDL_Quit();
922 Uint32 callback_fps(Uint32 interval, void *param)
924 SDL_Event event;
925 event.type = SDL_USEREVENT;
926 SDL_PushEvent(&event);
928 return 1000;
931 void Draw(Game *g){
932 int i;
934 QueueDrawSprite(bg, 0.0, 0.0,-1.0);
935 for(i=0; i < g->Map->noSprites; i++)
936 QueueDrawSprite(g->Map->Sprites[i], g->Map->SpritePos[i].x, g->Map->SpritePos[i].y, g->Map->Sprites[i]->z);
937 //Lilaneks
938 for(i=0; i < g->noLilaneks; i++){
939 SDL_Color c;
940 double pd;
941 c =g->Lilanek[i].Color;
942 if(g->Lilanek[i].ReloadTime < g->WeaponTemplate[g->Lilanek[i].ActiveWeapon].ReloadTime){
943 c.r *= 0.5;
944 c.g *= 0.5;
945 c.b *= 0.5;
946 c.unused *= 0.8;
948 QueueDrawSpriteColorize(lil[g->Lilanek[i].Orientation], g->Lilanek[i].Pos.x-1.0, g->Lilanek[i].Pos.y-1.0, 1, c );
949 QueueDrawSpriteColorize(hud,16.0,4.0*i, 1.0, c );
950 switch(g->Lilanek[i].ActiveWeapon){
951 case 0: QueueDrawSprite(hud_brok, 16.0, 0.0+4.0*i,0.0);
952 break;
953 case 1: QueueDrawSprite(hud_mine, 16.0, 0.0+4.0*i,0.0);
954 break;
955 case 2: QueueDrawSprite(hud_kul, 16.0, 0.0+4.0*i,0.0);
956 break;
958 pd = (double)g->Lilanek[i].Ammo[g->Lilanek[i].ActiveWeapon]/(double)g->WeaponTemplate[g->Lilanek[i].ActiveWeapon].MaxAmmo;
959 QueueDrawSpriteColorizeStretch(hud_ammo, 18.0-2.0*pd, 0.0+4.0*i,4.0*pd, 4.0, 2.0,c);
960 pd = (double)g->Lilanek[i].ReloadTime/(double)g->WeaponTemplate[g->Lilanek[i].ActiveWeapon].ReloadTime;
961 if(pd>1.0)pd=1.0;
962 QueueDrawSpriteColorizeStretch(hud_reload, 18.0-2.0*pd, 0.0+4.0*i,4.0*pd, 4.0, 2.0,c);
964 //Weapons
965 for(i=0; i < g->noWeapons; i++)
966 if(g->Weapon[i].Exists)
967 switch(g->Weapon[i].WID){
968 case 0: QueueDrawSprite(brok, g->Weapon[i].Pos.x - 1.0, g->Weapon[i].Pos.y - 1.0,1.0);
969 break;
970 case 1: QueueDrawSprite(mines, g->Weapon[i].Pos.x - 1.0, g->Weapon[i].Pos.y - 1.0,1.0);
971 break;
972 case 2: QueueDrawSprite(kul, g->Weapon[i].Pos.x - 1.0, g->Weapon[i].Pos.y - 1.0,1.0);
973 break;
976 for(i=0; i < g->noBullets; i++)
977 if(g->Bullet[i].Exists)
978 switch(g->Bullet[i].WID){
979 case 0: QueueDrawSprite(kulka, g->Bullet[i].Pos.x - 1.0, g->Bullet[i].Pos.y - 1.0,1.0);break;
980 case 1: QueueDrawSprite(mine, g->Bullet[i].Pos.x - 1.0, g->Bullet[i].Pos.y - 1.0,1.0);break;
981 case 2: QueueDrawSprite(kulka, g->Bullet[i].Pos.x - 1.0, g->Bullet[i].Pos.y - 1.0,1.0);break;
982 case -1: QueueDrawSprite(explo, g->Bullet[i].Pos.x - 1.0, g->Bullet[i].Pos.y - 1.0,1.0);break;
987 int InitAll(Game **g){
988 Config conf;
989 conf = GetConfig();
990 SaveConfig();
991 //TODO: odstranit SaveConfig... je to tu jenom kvuli debugovani
994 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER |SDL_INIT_AUDIO ) < 0) {
995 fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
996 return 1;
998 atexit(onExit);
1000 InitBase();
1001 GrInit();
1002 SoundInit();
1003 *g = testgame();
1004 printf(PATH_GRAPHICS "lil.svg");
1005 lil[0] = LoadSpriteSVG(PATH_GRAPHICS "lil.svg", 1.0, 1.0);
1006 lil[1] = LoadSpriteSVG(PATH_GRAPHICS "lilb.svg", 1.0, 1.0);
1007 lil[2] = LoadSpriteSVG(PATH_GRAPHICS "lill.svg", 1.0, 1.0);
1008 lil[3] = LoadSpriteSVG(PATH_GRAPHICS "lil.svg", 1.0, 1.0);
1009 lil[4] = LoadSpriteSVG(PATH_GRAPHICS "lilr.svg", 1.0, 1.0);
1010 (*g)->Map->Sprites[0] = LoadSpriteSVG(PATH_GRAPHICS "prek1.svg", 3.0, 3.0);
1011 (*g)->Map->Sprites[1] = LoadSpriteSVG(PATH_GRAPHICS "prek2.svg", 4.0, 4.0);
1012 (*g)->Map->Sprites[0]->z = 1;
1013 (*g)->Map->Sprites[1]->z = 1;
1014 bg=0;
1015 bg = LoadSpriteSVG(PATH_GRAPHICS "bg.svg", 16.0, 15.0);
1016 kul = LoadSpriteSVG(PATH_GRAPHICS "kul.svg", 0.5, 0.5);
1017 explo = LoadSpriteSVG(PATH_GRAPHICS "exp.svg", 0.5, 0.5);
1018 dust = LoadSpriteSVG(PATH_GRAPHICS "dust.svg", 0.5, 0.5);
1019 blood = LoadSpriteSVG(PATH_GRAPHICS "blood.svg", 0.5, 0.5);
1020 brok = LoadSpriteSVG(PATH_GRAPHICS "brok.svg", 0.5, 0.5);
1021 kulka = LoadSpriteSVG(PATH_GRAPHICS "kulka.svg", 0.1, 0.1);
1022 mine = LoadSpriteSVG(PATH_GRAPHICS "mine.svg", 0.5, 0.5);
1023 mines = LoadSpriteSVG(PATH_GRAPHICS "mines.svg", 0.5, 0.5);
1024 hud = LoadSpriteSVG(PATH_GRAPHICS "hud.svg", 4.0, 4.0);
1025 hud_mine = LoadSpriteSVG(PATH_GRAPHICS "mines.svg", 2.2, 2.2);
1026 hud_kul = LoadSpriteSVG(PATH_GRAPHICS "kul.svg", 2.2, 2.2);
1027 hud_brok = LoadSpriteSVG(PATH_GRAPHICS "brok.svg", 2.2, 2.2);
1028 hud_ammo = LoadSpriteSVG(PATH_GRAPHICS "hud_ammo.svg", 4.0, 4.0);
1029 hud_reload = LoadSpriteSVG(PATH_GRAPHICS "hud_reload.svg", 4.0, 4.0);
1031 s_die = LoadSound(PATH_SOUNDS "die.wav");
1032 s_bonus = LoadSound(PATH_SOUNDS "bonus.wav");
1033 s_expl = LoadSound(PATH_SOUNDS "expl.wav");
1034 s_shoot = LoadSound(PATH_SOUNDS "shoot.wav");
1035 s_mine = LoadSound(PATH_SOUNDS "mine.wav");
1037 SDL_AddTimer(1000, callback_fps, NULL);
1039 return 0;
1042 int GameLoop(Game *g){
1043 SDL_Event event;
1044 Config conf;
1045 double lasttime, dtime;
1047 lasttime = SDL_GetTicks()*0.001;
1048 while (1) {
1049 while (SDL_PollEvent(&event)) {
1050 switch (event.type) {
1051 case SDL_KEYDOWN:
1052 if (event.key.keysym.sym == SDLK_q) {
1053 return 0;
1055 break;
1057 case SDL_QUIT:
1058 return 0;
1059 break;
1061 case SDL_VIDEORESIZE:
1062 /* Resize the screen and redraw */
1063 conf=GetConfig();
1064 conf.screen_width=event.resize.w;
1065 conf.screen_height=event.resize.h;
1066 SetConfig(conf);
1068 InvalidateSprites();
1069 break;
1071 case SDL_USEREVENT:
1072 printf("%d frames\n",frames);
1073 frames=0;
1074 break;
1076 default:
1077 break;
1080 dtime = SDL_GetTicks()*0.001-lasttime;
1081 lasttime += dtime;
1082 if(dtime < 0)
1083 dtime=0.0;
1084 if(dtime > 0.1)
1085 dtime=0.1;
1086 UpdateLogic(g, dtime*0.5);
1087 UpdateLogic(g, dtime*0.5);
1088 ClrScr();
1089 Draw(g);
1090 UpdateAndQueueDrawParticles(dtime);
1091 DrawSprites();
1092 frames++;
1093 //we don't want to waste cpu...
1094 if(frames >=50){
1095 SDL_Delay(10);
1098 return 0;
1101 int main(int argc, char **argv){
1102 Game *g;
1103 srand(time(0));
1104 InitAll(&g);
1105 GameLoop(g);
1106 return 0;