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