WID comments
[Lilanci.git] / elilanci.c
blob5c59f888b8da5a08f6e827533a14594fd6153bf6
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"
11 #include "font.h"
14 int gamestate=0;
16 typedef struct{
17 int Up;
18 int Down;
19 int Left;
20 int Right;
21 int Shoot;
22 int Suicide;
23 int Switch;
24 }TKeyBinding;//TODO: s/int/real data type for a key
26 typedef struct{
27 Vect Pos; //where he is
28 Vect Move; //how he want to move
29 Vect BSize; //Size of bounding rect
30 Area *Shape; //how fat he is
31 //Area *TrShape; //translated Shape -- don't optimize yet
32 int Frags; //no comment
33 int Deaths; //R.I.P.
34 double Speed; //meters per second
35 int Orientation; //1-up 2-left 3-down 4-right 0-down
36 int WannaShoot; //1-want 0-don't want
37 double ReloadTime; //time from last shot
38 int WannaDie; //1-want suicide 2-died and still holding suicide 0-don't want
39 double AnimationTime; //in seconds
40 TKeyBinding Keys;
41 int *Ammo;
42 int ActiveWeapon;
43 int SwitchLock;
44 int Alive;
45 char Name[16];
46 SDL_Color Color;
47 }TLilanek;
50 typedef struct{
51 Vect Pos;
52 Area *Shape;
53 int WID; //Weapon ID
54 int Exists; // 0- doesn't exist 1-exists
55 int Ammo;
56 int MaxAmmo;
57 int Burst;
58 int RandomWeight;
59 double ReloadTime;
60 }TWeapon;
62 typedef struct{
63 Vect Pos;
64 Area *Shape;
65 Vect Vel; //velocity i m/s
66 double Speed; //for Templates
67 double Range; //How far it can travel
68 int WID; //Weapon ID
69 int lid; //who shoot this bullet?
70 int Exists; // 0- doesn't exist 1-exists
71 double SFuzzy; // Fuzzy factor for spawning 0-1 :)
72 double VFuzzy; // Fuzzy factor for traveling 0-1 :)
73 }TBullet;
76 typedef struct{
77 TMap *Map; //where we are playing
78 TLilanek *Lilanek; //our heroes-ehm bad guys
79 int noLilaneks;
81 TWeapon *Weapon; //Weapons lying on floor
82 int noWeapons;
83 TWeapon *WeaponTemplate;
84 TBullet *BulletTemplate;
85 int noWID; //biggest WID, also number of WeaponTemplates
86 TBullet *Bullet;
87 int noBullets;
88 double PWeapondrop; // Probability of weapon drop per second
89 }Game;
91 Vect Orientations[5];
93 Sprite *lil[5];
94 Sprite *bg;
95 Sprite *kul;
96 Sprite *explo;
97 Sprite *dust;
98 Sprite *blood;
99 Sprite *brok;
100 Sprite *sniper;
101 Sprite *kulka;
102 Sprite *mine;
103 Sprite *mines;
104 Sprite *hud;
105 Sprite *hud_mine;
106 Sprite *hud_kul;
107 Sprite *hud_brok;
108 Sprite *hud_sniper;
109 Sprite *hud_ammo;
110 Sprite *hud_reload;
111 int s_die;
112 int s_bonus;
113 int s_expl;
114 int s_shoot;
115 int s_mine;
117 int frames=0;
118 void SwitchNextWeapon(Game *g, int lid);
120 int InitBase(){
121 Orientations[0].x=0;
122 Orientations[0].y=0;
123 Orientations[1].x=0;
124 Orientations[1].y=-1;
125 Orientations[2].x=-1;
126 Orientations[2].y=0;
127 Orientations[3].x=0;
128 Orientations[3].y=1;
129 Orientations[4].x=1;
130 Orientations[4].y=0;
131 //TODO: write code
133 return 0;
136 void SpawnLilanek(Game *g, int lid){
137 Vect Pos;
138 int tries;
139 Area *tp, *oltp;
140 int good;
141 int olid;
143 oltp = 0;
144 tp = 0;
145 for(tries=0; tries <1000; tries++){ //TODO: remove exact number
146 Pos.x = RandD(0,g->Map->XX);
147 Pos.y = RandD(0,g->Map->YY);
148 good=1;
149 tp = TranslateArea(g->Lilanek[lid].Shape, &Pos);
150 printf("%s\n", Area2String(tp));
151 if(!AreaInMap(g->Map, tp,0,1)){
152 good=0;
155 for(olid=0; olid < g->noLilaneks; olid++){
156 if(olid == lid)
157 continue;
158 if(!g->Lilanek[olid].Alive){
159 continue;
161 oltp = TranslateArea(g->Lilanek[olid].Shape, &g->Lilanek[olid].Pos);
162 if(AreaInArea(tp, oltp)){
163 good=0;
165 FreeArea(oltp);
166 oltp = 0;
169 if(good){
170 FreeArea(tp);
171 tp=0;
172 g->Lilanek[lid].Pos.x = Pos.x;
173 g->Lilanek[lid].Pos.y = Pos.y;
174 g->Lilanek[lid].Alive = 1;
175 break;
177 FreeArea(tp);
178 tp=0;
182 int RandWID(Game *g) {
183 int SumRandWeight = 0;
184 int i, j;
186 for (i=0; i < g->noWID; i++) {
187 SumRandWeight += g->WeaponTemplate[i].RandomWeight;
189 j = RandI(0, SumRandWeight);
190 for (i=0; i < g->noWID; i++) {
191 j -= g->WeaponTemplate[i].RandomWeight;
192 if (j <= 0)
193 return i;
195 return 0;
198 void DropWeapon(Game *g, int weapon){
199 Vect Pos;
200 int tries;
201 int WID;
202 Area *tp;
204 for(tries=0; tries <100; tries++){ //TODO: remove exact number
205 Pos.x = RandD(0,g->Map->XX);
206 Pos.y = RandD(0,g->Map->YY);
207 WID = RandWID(g);
208 tp = TranslateArea(g->WeaponTemplate[WID].Shape, &Pos);
209 if(AreaInMap(g->Map, tp, 0, g->Map->noLayer)){
210 FreeArea(tp);
211 tp=0;
212 memcpy(&g->Weapon[weapon], &g->WeaponTemplate[WID], sizeof(TWeapon));
213 g->Weapon[weapon].Shape = g->WeaponTemplate[WID].Shape;
214 g->Weapon[weapon].Pos.x = Pos.x;
215 g->Weapon[weapon].Pos.y = Pos.y;
216 g->Weapon[weapon].WID = WID;
217 g->Weapon[weapon].Exists = 1;
218 break;
220 FreeArea(tp);
221 tp=0;
225 void DropWeapons(Game *g, double dtime){
226 int i;
228 if( RandD(0.0, 1.0) >= (g->PWeapondrop*dtime))
229 return;
230 for(i=0; i < g->noWeapons; i++){
231 if(g->Weapon[i].Exists)continue; //we don't like teleporting weapons :)
233 printf("A Weapon drop!\n");
234 DropWeapon(g, i);
235 break; //spawn max one weapon per update
239 void WeaponPickedUp(Game *g, double dtime, int lid, int wid){
240 TLilanek *l;
241 TWeapon *w;
243 l = &g->Lilanek[lid];
244 w = &g->Weapon[wid];
246 l->Ammo[w->WID] += w->Ammo;
247 if(l->Ammo[w->WID] > w->MaxAmmo)
248 l->Ammo[w->WID] = w->MaxAmmo;
249 printf("Ammo: %d\n",l->Ammo[w->WID]);
250 l->ActiveWeapon = w->WID;
251 printf("AW: %d\n",l->ActiveWeapon);
253 w->Exists = 0;
255 PlaySound(s_bonus);
258 void PickUpWeapons(Game *g, double dtime){
259 int lid,wid;
260 Area *WArea, *LArea;
262 for(lid=0; lid<g->noLilaneks; lid++){
263 LArea = TranslateArea(g->Lilanek[lid].Shape, &g->Lilanek[lid].Pos);
264 for(wid=0; wid < g->noWeapons; wid++){
265 if(!g->Weapon[wid].Exists)
266 continue;
267 WArea = TranslateArea(g->Weapon[wid].Shape, &g->Weapon[wid].Pos);
268 if(!AreaInArea( WArea, LArea)){
269 FreeArea(WArea);
270 continue;
272 WeaponPickedUp(g, dtime, lid, wid);
273 FreeArea(WArea);
275 FreeArea(LArea);
279 void BulletExplodes(Game *g, int i){
280 g->Bullet[i].Exists=0;
281 //TODO: some effects
282 PlaySound (s_expl);
285 void MoveBullet(Game *g, double dtime, int i){
286 double ff;
287 Vect dp;
288 dp.x = g->Bullet[i].Pos.x;
289 dp.y = g->Bullet[i].Pos.y;
290 ff= g->Bullet[i].Speed*g->Bullet[i].VFuzzy;
291 g->Bullet[i].Pos.x += (g->Bullet[i].Vel.x += RandD(-ff,ff))* dtime;
292 g->Bullet[i].Pos.y += (g->Bullet[i].Vel.y += RandD(-ff,ff))* dtime;
293 dp.x -= g->Bullet[i].Pos.x;
294 dp.y -= g->Bullet[i].Pos.y;
295 g->Bullet[i].Range -= sqrt(DotProduct(&dp, &dp));
298 void CollideBulletMap(Game *g, double dtime, int i){
299 Area *p;
301 p=TranslateArea(g->Bullet[i].Shape, &g->Bullet[i].Pos);
302 if(AreaInMap(g->Map, p, 1,1)==0)
303 BulletExplodes(g, i);
304 FreeArea(p);
307 void BloodColorFunc(double temp, SDL_Color *c)
309 SDL_Color col={255,255,255,255};
310 col.r *=(0.5+0.5*temp);
311 //col.g *=temp;
312 //col.b *=temp;
313 //col.unused *=temp*temp;
314 if (c != 0) memcpy(c, &col, sizeof(SDL_Color));
317 void BloodParticles(Game *g, double dtime, int lid)
319 int i;
320 double a;
321 double v;
322 Particle *p;
324 for(i = 0; i < 5; i ++){
325 p = malloc(sizeof(Particle));
326 memset(p, 0, sizeof(Particle));
327 a = RandD(0.0, 20.0);
328 v = RandD(0.0, 2.0);
329 p->x = g->Lilanek[lid].Pos.x-g->Lilanek[lid].BSize.x*0.5;
330 p->y = g->Lilanek[lid].Pos.y-g->Lilanek[lid].BSize.y*0.5;
331 p->t = 1.0;
332 p->vx = v*sin(a) + g->Lilanek[lid].Move.x;
333 p->vy = v*cos(a) + g->Lilanek[lid].Move.y;
334 p->fx = 1.5;
335 p->fy = 1.5;
336 p->vt = 0.0-1.0;
337 p->s = blood;
338 p->tf = &BloodColorFunc;
339 p->z = 1;
340 AddParticle(p);
344 void LilanekKilled(Game *g, double dtime, int BulletID, int LilanekID){
345 int i;
346 g->Bullet[BulletID].Exists = 0;
347 g->Lilanek[LilanekID].Deaths ++;
348 if (LilanekID != g->Bullet[BulletID].lid) {
349 g->Lilanek[g->Bullet[BulletID].lid].Frags ++;
350 }else{ //self-kill
351 g->Lilanek[g->Bullet[BulletID].lid].Frags --;
353 BloodParticles(g, dtime, LilanekID);
354 SpawnLilanek(g, LilanekID);
355 for(i=0; i<g->noWID; i++){
356 g->Lilanek[LilanekID].Ammo[i] = 0;
358 PlaySound(s_die);
361 #define NO_EXPLOSIONS 10 //MAGIC_NUMBER
362 #define EXPLOSION_SPEED 5 //MAGIC_NUMBER
363 #define EXPLOSION_RANGE 1.0 //MAGIC_NUMBER
365 void SpawnExplosions(Game *g, double dtime, int BulletID){
366 int bid = 0;
367 int i = 0;
368 TBullet *b;
369 Vect Pos;
370 double speed;
372 Pos.x = g->Bullet[BulletID].Pos.x;
373 Pos.y = g->Bullet[BulletID].Pos.y;
374 for(i=0; i<NO_EXPLOSIONS; i++){
375 for(bid=0; bid<g->noBullets; bid++){
376 if(g->Bullet[bid].Exists)
377 continue;
378 b = &g->Bullet[bid];
379 b->Pos.x = Pos.x;
380 b->Pos.y = Pos.y;
381 b->Vel.x = RandD(0.0, 1.0)*(RandI(0,100)>50?-1:1);
382 b->Vel.y = RandD(0.0, 1.0)*(RandI(0,100)>50?-1:1);
383 NormV(&b->Vel);
384 speed = RandD(0.3, 1.0)*EXPLOSION_SPEED;
385 b->Speed = speed;
386 b->Vel.x *= speed;
387 b->Vel.y *= speed;
388 b->WID = -1;
389 b->lid = g->Bullet[BulletID].lid;
390 b->Exists = 1;
391 b->SFuzzy = 0;
392 b->VFuzzy = 0;
393 b->Range = EXPLOSION_RANGE;
394 b->Shape = g->Bullet[BulletID].Shape;
395 printf("%lf ", speed);
396 break;
399 g->Bullet[BulletID].Exists = 0;
400 PlaySound(s_expl);
403 void CollideBulletLilanek(Game *g, double dtime, int BulletID){
404 Area *BArea, *LArea;
405 int LilanekID;
407 BArea=TranslateArea(g->Bullet[BulletID].Shape, &g->Bullet[BulletID].Pos);
408 for(LilanekID=0; LilanekID<g->noLilaneks; LilanekID++){
409 LArea=TranslateArea(g->Lilanek[LilanekID].Shape, &g->Lilanek[LilanekID].Pos);
410 if(AreaInArea(LArea,BArea)){
411 //if it is a mine, spawn an explosion instead of killing instantly
412 if(g->Bullet[BulletID].WID == 1){
413 SpawnExplosions(g, dtime, BulletID);
414 }else{
415 LilanekKilled(g, dtime, BulletID, LilanekID);
418 FreeArea(LArea);
419 LArea=0;
421 FreeArea(BArea);
422 BArea=0;
425 void UpdateBullets(Game *g, double dtime){
426 int BulletID;
427 for(BulletID=0; BulletID<g->noBullets; BulletID++){
428 if(g->Bullet[BulletID].Exists==0)
429 continue; //We won't update non-existending bullets
430 MoveBullet(g, dtime, BulletID);
431 if(g->Bullet[BulletID].Range < 0){
432 g->Bullet[BulletID].Exists = 0;
433 continue;
435 CollideBulletMap(g, dtime, BulletID);
436 CollideBulletLilanek(g, dtime, BulletID);
440 int CheckLilanekvsLilaneks(Game *g, Area *a, int LilanekID){ //returns 0 if he collides with others, 1 if it's OK to move there
441 int i;
442 Area *nb;
443 int rval=1;
445 nb=0;
446 for(i=0; i<g->noLilaneks && rval==1; i++){
447 if(i==LilanekID)
448 continue;
449 nb = TranslateArea(g->Lilanek[i].Shape, &g->Lilanek[i].Pos);
450 if(AreaInArea(nb, a))
451 rval=0;
452 FreeArea(nb);
453 nb=0;
455 return rval;
458 void MoveLilaneks(Game *g, double dtime){
459 int i, steps;
460 Area *pa;
461 Vect va;
462 double dt;
464 pa=0;
465 for(i=0; i<g->noLilaneks; i++){
466 //skip this Lilanek if he doesn't wanna move
467 if(g->Lilanek[i].Move.x == 0.0 && g->Lilanek[i].Move.y == 0.0)
468 continue;
469 for(dt=dtime, steps=0; steps<4; dt/=2.0, steps++){ //TODO: get rid of exact number
470 //make future Area
471 va.x = g->Lilanek[i].Pos.x + dt*g->Lilanek[i].Move.x;
472 va.y = g->Lilanek[i].Pos.y + dt*g->Lilanek[i].Move.y;
473 FreeArea(pa); //we don't want memory leaks
474 pa = TranslateArea(g->Lilanek[i].Shape, &va);
475 //check for collision with map
476 if(AreaInMap(g->Map, pa, 0, 1)==0)
477 continue; //try smaller dt if he collided with map
478 //check for collision with other Lilaneks
479 if(CheckLilanekvsLilaneks(g, pa, i)==0)
480 continue;
481 //move him if we got here
482 g->Lilanek[i].Pos.x += dt*g->Lilanek[i].Move.x;
483 g->Lilanek[i].Pos.y += dt*g->Lilanek[i].Move.y;
484 FreeArea(pa);
485 pa=0;
487 FreeArea(pa); //For sure
488 pa=0;
492 void ParseInput(Game *g, double dtime){
493 int i;
494 Uint8 *keystate;
495 TLilanek *curlil;
496 int wannamove;
498 keystate = SDL_GetKeyState(NULL);
499 //pause
500 if(gamestate == 1){
501 if(keystate['o']){
502 printf("unpause\n");
503 gamestate = 0;
504 }else return;
506 if(keystate['p']){
507 printf("pause\n");
508 gamestate = 1;
511 for(i=0; i< g->noLilaneks; i++){
512 curlil = &g->Lilanek[i];
513 wannamove=0;
514 // Up;
515 if(keystate[curlil->Keys.Up]){
516 curlil->Orientation = 1;
517 curlil->Move.x = curlil->Speed * Orientations[1].x;
518 curlil->Move.y = curlil->Speed * Orientations[1].y;
519 wannamove=1;
521 // Down;
522 if(keystate[curlil->Keys.Down]){
523 curlil->Orientation = 3;
524 curlil->Move.x = curlil->Speed * Orientations[3].x;
525 curlil->Move.y = curlil->Speed * Orientations[3].y;
526 wannamove=1;
528 // Left;
529 if(keystate[curlil->Keys.Left]){
530 curlil->Orientation = 2;
531 curlil->Move.x = curlil->Speed * Orientations[2].x;
532 curlil->Move.y = curlil->Speed * Orientations[2].y;
533 wannamove=1;
535 // Right;
536 if(keystate[curlil->Keys.Right]){
537 curlil->Orientation = 4;
538 curlil->Move.x = curlil->Speed * Orientations[4].x;
539 curlil->Move.y = curlil->Speed * Orientations[4].y;
540 wannamove=1;
543 if(!wannamove){
544 curlil->Move.x = 0;
545 curlil->Move.y = 0;
547 // Shoot;
548 if(keystate[curlil->Keys.Shoot]){
549 curlil->WannaShoot = 1;
550 }else{
551 curlil->WannaShoot = 0;
553 // Suicide;
554 if(keystate[curlil->Keys.Suicide]){
555 if(curlil->WannaDie != 2){
556 curlil->WannaDie = 1;
558 }else{
559 curlil->WannaDie = 0;
561 // Switch;
562 if(keystate[curlil->Keys.Switch]){
563 if(!curlil->SwitchLock){
564 SwitchNextWeapon(g, i);
565 curlil->SwitchLock = 1;
567 }else{
568 curlil->SwitchLock = 0;
573 void SpawnBullet(Game *g, double dtime, int lid, int bid){
574 Area *LArea, *BArea;
575 TBullet *b, *bt;
576 double vx, vy; //because we need to spawn also mines with no velocity
579 LArea = TranslateArea(g->Lilanek[lid].Shape, &g->Lilanek[lid]. Pos);
580 b = &g->Bullet[bid];
581 bt = &g->BulletTemplate[g->Lilanek[lid].ActiveWeapon];
582 memcpy (b, bt, sizeof(TBullet));
583 b->Exists = 1;
584 b->Pos.x = g->Lilanek[lid].Pos.x+g->Lilanek[lid].BSize.x*0.5;
585 b->Pos.y = g->Lilanek[lid].Pos.y+g->Lilanek[lid].BSize.y*0.5;
586 b->WID = bt->WID;
587 b->Range = bt->Range;
588 b->Vel.x = Orientations[g->Lilanek[lid].Orientation].x * b->Speed +RandD(-b->Speed*b->SFuzzy, b->Speed*b->SFuzzy);
589 b->Vel.y = Orientations[g->Lilanek[lid].Orientation].y * b->Speed +RandD(-b->Speed*b->SFuzzy, b->Speed*b->SFuzzy);
590 if(DotProduct(&b->Vel, &b->Vel) <=0.01){
591 vx = -1*Orientations[g->Lilanek[lid].Orientation].x;
592 vy = -1*Orientations[g->Lilanek[lid].Orientation].y;
593 }else{
594 vx = b->Vel.x;
595 vy = b->Vel.y;
597 b->lid =lid;
598 while(1){
599 BArea = TranslateArea(b->Shape, &b->Pos);
600 if(!AreaInArea(BArea, LArea))
601 break;
602 b->Pos.x += vx* dtime*0.5;
603 b->Pos.y += vy* dtime*0.5;
605 FreeArea(LArea);
608 void DustColorFunc(double temp, SDL_Color *c)
610 SDL_Color col={255,255,255,255};
611 col.r *=temp;
612 col.g *=temp;
613 col.b *=temp;
614 col.unused *=temp*temp;
615 if (c != 0) memcpy(c, &col, sizeof(SDL_Color));
618 void ShootParticles(Game *g, double dtime, int lid)
620 int i;
621 double a;
622 double v;
623 Particle *p;
625 for(i = 1; i < 10; i ++){
626 p = malloc(sizeof(Particle));
627 memset(p, 0, sizeof(Particle));
628 a = RandD(0.0, 2*M_PI);
629 v = RandD(0.0, 2.0);
630 p->x = g->Lilanek[lid].Pos.x-g->Lilanek[lid].BSize.x*0.5;
631 p->y = g->Lilanek[lid].Pos.y-g->Lilanek[lid].BSize.y*0.5;
632 p->t = 1.0;
633 p->vx = v*sin(a) + g->Lilanek[lid].Move.x;
634 p->vy = v*cos(a) + g->Lilanek[lid].Move.y;
635 p->vt = 0.0-2.0;
636 p->s = dust;
637 p->z = 1;
638 p->tf = &DustColorFunc;
639 AddParticle(p);
643 void Shoot(Game *g, double dtime, int lid){
644 int bid;
645 int i;
647 for(i=0; i<g->WeaponTemplate[g->Lilanek[lid].ActiveWeapon].Burst; i++){
648 if(g->Lilanek[lid].Ammo[g->Lilanek[lid].ActiveWeapon] == 0)
649 return;
650 for(bid=0; bid<g->noBullets; bid++){
651 if(g->Bullet[bid].Exists)
652 continue;
653 SpawnBullet(g, dtime, lid, bid);
654 g->Lilanek[lid].Ammo[g->Lilanek[lid].ActiveWeapon]--;
655 g->Lilanek[lid].ReloadTime = 0;
656 break;
659 ShootParticles(g, dtime, lid);
660 switch(g->Lilanek[lid].ActiveWeapon){
661 case 0: PlaySound(s_shoot); break;
662 case 1: PlaySound(s_mine); break;
663 case 2: PlaySound(s_shoot); break;
664 default: break;
668 void SwitchNextWeapon(Game *g, int lid){
669 int i;
670 TLilanek *l;
671 l = &g->Lilanek[lid];
672 for(i = 1; i < g->noWID; i++){
673 if(l->Ammo[(l->ActiveWeapon+i)%(g->noWID)]){
674 l->ActiveWeapon = (l->ActiveWeapon+i)%(g->noWID);
675 return;
680 void ShootIfTheyWantTo(Game *g, double dtime){
681 int lid;
683 for(lid=0; lid<g->noLilaneks; lid++){
684 //if(!g->Lilanek[lid].Exists)
685 //continue;
686 if(g->Lilanek[lid].Ammo[g->Lilanek[lid].ActiveWeapon] == 0)
687 SwitchNextWeapon(g,lid);
689 if(g->Lilanek[lid].ReloadTime < g->WeaponTemplate[g->Lilanek[lid].ActiveWeapon].ReloadTime){
690 g->Lilanek[lid].ReloadTime += dtime;
691 }else{
692 if(!g->Lilanek[lid].WannaShoot)
693 continue;
694 Shoot(g, dtime, lid);
699 int UpdateLogic(Game *g,double dtime){
700 if(gamestate == 0){
701 DropWeapons(g, dtime);
702 UpdateBullets(g, dtime);
704 ParseInput(g, dtime);
705 if(gamestate == 0){
706 MoveLilaneks(g, dtime);
707 PickUpWeapons(g, dtime);
708 ShootIfTheyWantTo(g, dtime);
710 return 0; //TODO: return something useful
713 Game *testgame(){ //return testing game, function for use before we have some menu/loading mechanism
714 Game *g;
715 Poly *p, *pp;
716 Area *a;
717 int i;
718 Config conf = GetConfig();
720 g = malloc(sizeof(Game));
721 memset(g, 0, sizeof(Game));
722 g->noWID=4;
723 g->Map = malloc(sizeof(TMap));
724 g->Map->noLayer=2;
725 g->Map->Layer = malloc(sizeof(TMapLayer *)*g->Map->noLayer);
726 g->Map->Layer[0] = malloc(sizeof(TMapLayer));
727 g->Map->Layer[0]->noFArea = 1;
728 g->Map->Layer[0]->FArea = malloc(sizeof(Area *) * g->Map->Layer[0]->noFArea);
729 p = NewRect(4,2.5,3,2);
730 a = NewArea();
731 AddToArea(a, p);
732 FreePoly(p);
733 g->Map->Layer[0]->FArea[0] = a;
735 g->Map->Layer[1] = malloc(sizeof(TMapLayer));
736 g->Map->Layer[1]->noFArea = 1;
737 g->Map->Layer[1]->FArea = malloc(sizeof(Area *) * g->Map->Layer[1]->noFArea);
738 p = NewPoly();
739 AddToPolyXY(p, 0.30, 0.41);
740 AddToPolyXY(p, 0.73, 0.41);
741 AddToPolyXY(p, 0.77, 0.79);
742 AddToPolyXY(p, 0.65, 0.955);
743 AddToPolyXY(p, 0.365, 0.965);
744 AddToPolyXY(p, 0.235, 0.785);
745 MultiplyPoly(p, 4, 4);
746 pp = TranslatePolyXY(p, 7, 7);
747 a = NewArea();
748 AddToArea(a, pp);
749 FreePoly(pp);
750 FreePoly(p);
751 g->Map->Layer[1]->FArea[0] = a;
752 p = NewRect(1,1,16,15);
753 a = NewArea();
754 AddToArea(a, p);
755 FreePoly(p);
756 g->Map->BoundingArea = a;
757 g->Map->XX = 16;
758 g->Map->YY = 15;
759 g->Map->X = 0;
760 g->Map->Y = 0;
762 SetParticleBoundingBox(0,0,16,15);
766 g->Map->noSprites = 2;
767 g->Map->Sprites = (Sprite **) malloc(sizeof(Sprite*)*g->Map->noSprites);
768 g->Map->SpritePos = (Vect *) malloc(sizeof(Vect)*g->Map->noSprites);
769 g->Map->SpritePos[0].x = 3.0;
770 g->Map->SpritePos[0].y = 1.0;
771 g->Map->SpritePos[1].x = 6.0;
772 g->Map->SpritePos[1].y = 6.0;
774 g->noWeapons = 8;
775 g->Weapon = malloc(sizeof(TWeapon) * g->noWeapons);
776 if(!g->Weapon){
777 fprintf(stderr, "Cannot allocate memory for Weapons\n");
779 for(i=0; i<g->noWeapons; i++){
780 g->Weapon[i].Exists = 0;
781 g->Weapon[i].Shape = 0;
784 g->noLilaneks = 2;
785 g->Lilanek = malloc(sizeof(TLilanek) * g->noLilaneks);
786 memset(g->Lilanek, 0, sizeof(TLilanek) * g->noLilaneks);
787 g->Lilanek[0].BSize.x = 1;
788 g->Lilanek[0].BSize.y = 1;
789 //g->Lilanek[0].Shape = NewRect(0.6,0.2,0.8,1.6);
790 p = NewPoly();
791 AddToPolyXY(p, 1, 0);
792 AddToPolyXY(p, 1.4, 0.2);
793 AddToPolyXY(p, 1.66, 1.38);
794 AddToPolyXY(p, 1.42, 2);
795 AddToPolyXY(p, 0.6, 2);
796 AddToPolyXY(p, 0.4, 1.46);
797 AddToPolyXY(p, 0.66, 0.2);
798 MultiplyPoly(p, 0.5*g->Lilanek[0].BSize.x, 0.5*g->Lilanek[0].BSize.y);
799 a = NewArea();
800 AddToArea(a, p);
801 FreePoly(p);
802 g->Lilanek[0].Shape = a;
803 g->Lilanek[0].Pos.x = 12;
804 g->Lilanek[0].Pos.y = 4;
805 g->Lilanek[0].Speed = 4;
806 g->Lilanek[0].Alive = 0;
807 g->Lilanek[0].Keys.Up = conf.pl1_key_up;
808 g->Lilanek[0].Keys.Down = conf.pl1_key_down;
809 g->Lilanek[0].Keys.Left = conf.pl1_key_left;
810 g->Lilanek[0].Keys.Right = conf.pl1_key_right;
811 g->Lilanek[0].Keys.Shoot = conf.pl1_key_fire;
812 g->Lilanek[0].Keys.Suicide = conf.pl1_key_suicide;
813 g->Lilanek[0].Keys.Switch = conf.pl1_key_switch;
814 g->Lilanek[0].Ammo = malloc(sizeof(int)*g->noWID);
815 for(i=0; i<g->noWID; i++){
816 g->Lilanek[0].Ammo[i] = 0;
818 g->Lilanek[0].ActiveWeapon = 0;
820 SDL_Color red = {255,211,211,255};
821 char redn[8]="Red";
822 g->Lilanek[0].Color = red;
823 strcpy(g->Lilanek[0].Name, redn);
825 g->Lilanek[1].Alive = 0; // little hack for SpawnLilanek to work
826 SpawnLilanek(g, 0);
828 p = g->Lilanek[0].Shape->p[0];
829 a = NewArea();
830 AddToArea(a, p);
831 g->Lilanek[1].Shape = a;
832 g->Lilanek[1].BSize.x = g->Lilanek[0].BSize.x;
833 g->Lilanek[1].BSize.y = g->Lilanek[0].BSize.y;
834 g->Lilanek[1].Pos.x = 14;
835 g->Lilanek[1].Pos.y = 4;
836 g->Lilanek[1].Speed = 4;
837 g->Lilanek[1].Alive = 0;
838 g->Lilanek[1].Keys.Up = conf.pl2_key_up;
839 g->Lilanek[1].Keys.Down = conf.pl2_key_down;
840 g->Lilanek[1].Keys.Left = conf.pl2_key_left;
841 g->Lilanek[1].Keys.Right = conf.pl2_key_right;
842 g->Lilanek[1].Keys.Shoot = conf.pl2_key_fire;
843 g->Lilanek[1].Keys.Suicide = conf.pl2_key_suicide;
844 g->Lilanek[1].Keys.Switch = conf.pl2_key_switch;
845 g->Lilanek[1].Ammo = malloc(sizeof(int)*g->noWID);
846 for(i=0; i<g->noWID; i++){
847 g->Lilanek[1].Ammo[i] = 0;
849 g->Lilanek[1].ActiveWeapon = 0;
851 SDL_Color blue = {180,180,255, 255};
852 char bluen[8]="Blue";
853 g->Lilanek[1].Color = blue;
854 strcpy(g->Lilanek[1].Name, bluen);
856 SpawnLilanek(g, 1);
858 g->WeaponTemplate = malloc(sizeof(TWeapon)*g->noWID);
859 p = NewRect(0,0,0.5,0.5);
860 a = NewArea();
861 AddToArea(a, p);
862 FreePoly(p);
863 g->WeaponTemplate[0].Shape = a;
864 g->WeaponTemplate[0].WID = 0;
865 g->WeaponTemplate[0].Exists = 1;
866 g->WeaponTemplate[0].Ammo = 30;
867 g->WeaponTemplate[0].MaxAmmo = 120;
868 g->WeaponTemplate[0].ReloadTime = 0.7;
869 g->WeaponTemplate[0].Burst = 10;
870 g->WeaponTemplate[0].RandomWeight = 10;
872 g->BulletTemplate = malloc(sizeof(TBullet) * g->noWID);
874 // shotgun
875 p = NewRect(0,0,0.1,0.1);
876 a = NewArea();
877 AddToArea(a, p);
878 FreePoly(p);
879 g->BulletTemplate[0].Shape = a;
880 g->BulletTemplate[0].WID = 0;
881 g->BulletTemplate[0].Speed = 20;
882 g->BulletTemplate[0].Range = 20;
883 g->BulletTemplate[0].SFuzzy = 0.160;
884 g->BulletTemplate[0].VFuzzy = 0.000;
886 // mine
887 p = NewRect(0,0,0.5,0.5);
888 a = NewArea();
889 AddToArea(a, p);
890 FreePoly(p);
891 g->WeaponTemplate[1].Shape = a;
892 g->WeaponTemplate[1].WID = 1;
893 g->WeaponTemplate[1].Exists = 1;
894 g->WeaponTemplate[1].Ammo = 3;
895 g->WeaponTemplate[1].MaxAmmo = 6;
896 g->WeaponTemplate[1].ReloadTime = 0.5;
897 g->WeaponTemplate[1].Burst = 1;
898 g->WeaponTemplate[1].RandomWeight = 5;
900 p = NewRect(0,0,0.5,0.5);
901 a = NewArea();
902 AddToArea(a, p);
903 FreePoly(p);
904 g->BulletTemplate[1].Shape = a;
905 g->BulletTemplate[1].WID = 1;
906 g->BulletTemplate[1].Speed = 0;
907 g->BulletTemplate[1].Range = 20;
908 g->BulletTemplate[1].SFuzzy = 0.0;
909 g->BulletTemplate[1].VFuzzy = 0.0;
911 // uzi
912 p = NewRect(0,0,0.5,0.5);
913 a = NewArea();
914 AddToArea(a, p);
915 FreePoly(p);
916 g->WeaponTemplate[2].Shape = a;
917 g->WeaponTemplate[2].WID = 0;
918 g->WeaponTemplate[2].Exists = 1;
919 g->WeaponTemplate[2].Ammo = 10;
920 g->WeaponTemplate[2].MaxAmmo = 50;
921 g->WeaponTemplate[2].ReloadTime = 0.1;
922 g->WeaponTemplate[2].Burst = 1;
923 g->WeaponTemplate[2].RandomWeight = 15;
925 p = NewRect(0,0,0.1,0.1);
926 a = NewArea();
927 AddToArea(a, p);
928 FreePoly(p);
929 g->BulletTemplate[2].Shape = a;
930 g->BulletTemplate[2].WID = 0;
931 g->BulletTemplate[2].Speed = 20;
932 g->BulletTemplate[2].Range = 20;
933 g->BulletTemplate[2].SFuzzy = 0.040;
934 g->BulletTemplate[2].VFuzzy = 0.010;
936 // sniper rifle
937 p = NewRect(0,0,0.5,0.5);
938 a = NewArea();
939 AddToArea(a, p);
940 FreePoly(p);
941 g->WeaponTemplate[3].Shape = a;
942 g->WeaponTemplate[3].WID = 0;
943 g->WeaponTemplate[3].Exists = 1;
944 g->WeaponTemplate[3].Ammo = 5;
945 g->WeaponTemplate[3].MaxAmmo = 20;
946 g->WeaponTemplate[3].ReloadTime = 1.1;
947 g->WeaponTemplate[3].Burst = 1;
948 g->WeaponTemplate[3].RandomWeight = 10;
950 p = NewRect(0,0,0.1,0.1);
951 a = NewArea();
952 AddToArea(a, p);
953 FreePoly(p);
954 g->BulletTemplate[3].Shape = a;
955 g->BulletTemplate[3].WID = 0;
956 g->BulletTemplate[3].Speed = 50;
957 g->BulletTemplate[3].Range = 200;
958 g->BulletTemplate[3].SFuzzy = 0.000;
959 g->BulletTemplate[3].VFuzzy = 0.000;
961 g->noBullets = 64;
962 g->Bullet = malloc(sizeof(TBullet) * g->noBullets);
963 for(i=0; i<g->noBullets; i++){
964 g->Bullet[i].Exists = 0;
965 g->Bullet[i].Shape = 0;
968 g->PWeapondrop = 0.4;
970 return g;
974 void onExit()
976 GrKill();
977 SDL_Quit();
980 Uint32 callback_fps(Uint32 interval, void *param)
982 SDL_Event event;
983 event.type = SDL_USEREVENT;
984 SDL_PushEvent(&event);
986 return 1000;
989 SDL_Color InvertColor(SDL_Color c) {
990 SDL_Color t;
991 t.r = 255 - c.r;
992 t.g = 255 - c.g;
993 t.b = 255 - c.b;
994 t.unused = c.unused;
995 return t;
998 void Draw(Game *g){
999 int i;
1001 QueueDrawSprite(bg, 0.0, 0.0,-1.0);
1002 for(i=0; i < g->Map->noSprites; i++)
1003 QueueDrawSprite(g->Map->Sprites[i], g->Map->SpritePos[i].x, g->Map->SpritePos[i].y, g->Map->Sprites[i]->z);
1004 //Lilaneks
1005 for(i=0; i < g->noLilaneks; i++){
1006 SDL_Color c;
1007 double pd;
1008 char fragsbuf[16];
1009 c =g->Lilanek[i].Color;
1010 if(g->Lilanek[i].ReloadTime < g->WeaponTemplate[g->Lilanek[i].ActiveWeapon].ReloadTime){
1011 c.r *= 0.5;
1012 c.g *= 0.5;
1013 c.b *= 0.5;
1014 c.unused *= 0.8;
1016 QueueDrawSpriteColorize(lil[g->Lilanek[i].Orientation], g->Lilanek[i].Pos.x-1.0, g->Lilanek[i].Pos.y-1.0, 1, c );
1017 QueueDrawSpriteColorize(hud,16.0,4.0*i, 1.0, c );
1018 switch(g->Lilanek[i].ActiveWeapon){
1019 case 0: QueueDrawSprite(hud_brok, 16.0, 0.0+4.0*i,0.0);
1020 break;
1021 case 1: QueueDrawSprite(hud_mine, 16.0, 0.0+4.0*i,0.0);
1022 break;
1023 case 2: QueueDrawSprite(hud_kul, 16.0, 0.0+4.0*i,0.0);
1024 break;
1025 case 3: QueueDrawSprite(hud_sniper, 16.0, 0.0+4.0*i,0.0);
1026 break;
1028 pd = (double)g->Lilanek[i].Ammo[g->Lilanek[i].ActiveWeapon]/(double)g->WeaponTemplate[g->Lilanek[i].ActiveWeapon].MaxAmmo;
1029 QueueDrawSpriteColorizeStretch(hud_ammo, 18.0-2.0*pd, 0.0+4.0*i,4.0*pd, 4.0, 2.0,c);
1030 pd = (double)g->Lilanek[i].ReloadTime/(double)g->WeaponTemplate[g->Lilanek[i].ActiveWeapon].ReloadTime;
1031 if(pd>1.0)pd=1.0;
1032 QueueDrawSpriteColorizeStretch(hud_reload, 18.0-2.0*pd, 0.0+4.0*i,4.0*pd, 4.0, 2.0,c);
1033 snprintf (fragsbuf, 16, "F: %d", g->Lilanek[i].Frags);
1034 QueueDrawTextColorize (fragsbuf, 18.1, 4.0*i+0.5, 4.0, InvertColor(g->Lilanek[i].Color));
1035 snprintf (fragsbuf, 16, "D: %d", g->Lilanek[i].Deaths);
1036 QueueDrawTextColorize (fragsbuf, 18.1, 4.0*i+0.5*2.0, 4.0, InvertColor(g->Lilanek[i].Color));
1038 //Weapons
1039 for(i=0; i < g->noWeapons; i++)
1040 if(g->Weapon[i].Exists)
1041 switch(g->Weapon[i].WID){
1042 case 0: QueueDrawSprite(brok, g->Weapon[i].Pos.x - 1.0, g->Weapon[i].Pos.y - 1.0,1.0);
1043 break;
1044 case 1: QueueDrawSprite(mines, g->Weapon[i].Pos.x - 1.0, g->Weapon[i].Pos.y - 1.0,1.0);
1045 break;
1046 case 2: QueueDrawSprite(kul, g->Weapon[i].Pos.x - 1.0, g->Weapon[i].Pos.y - 1.0,1.0);
1047 break;
1048 case 3: QueueDrawSprite(sniper, g->Weapon[i].Pos.x - 1.0, g->Weapon[i].Pos.y - 1.0,1.0);
1049 break;
1052 for(i=0; i < g->noBullets; i++)
1053 if(g->Bullet[i].Exists)
1054 switch(g->Bullet[i].WID){
1055 case 0: QueueDrawSprite(kulka, g->Bullet[i].Pos.x - 1.0, g->Bullet[i].Pos.y - 1.0,1.0);break;
1056 case 1: QueueDrawSprite(mine, g->Bullet[i].Pos.x - 1.0, g->Bullet[i].Pos.y - 1.0,1.0);break;
1057 case 2: QueueDrawSprite(kulka, g->Bullet[i].Pos.x - 1.0, g->Bullet[i].Pos.y - 1.0,1.0);break;
1058 case -1: QueueDrawSprite(explo, g->Bullet[i].Pos.x - 1.0, g->Bullet[i].Pos.y - 1.0,1.0);break;
1063 int InitAll(Game **g){
1064 Config conf;
1065 conf = GetConfig();
1066 SaveConfig();
1067 //TODO: odstranit SaveConfig... je to tu jenom kvuli debugovani
1070 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER |SDL_INIT_AUDIO ) < 0) {
1071 fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
1072 return 1;
1074 atexit(onExit);
1076 InitBase();
1077 GrInit();
1078 SoundInit();
1079 FontInit();
1080 *g = testgame();
1081 printf(PATH_GRAPHICS "lil.svg");
1082 lil[0] = LoadSpriteSVG(PATH_GRAPHICS "lil.svg", 1.0, 1.0);
1083 lil[1] = LoadSpriteSVG(PATH_GRAPHICS "lilb.svg", 1.0, 1.0);
1084 lil[2] = LoadSpriteSVG(PATH_GRAPHICS "lill.svg", 1.0, 1.0);
1085 lil[3] = LoadSpriteSVG(PATH_GRAPHICS "lil.svg", 1.0, 1.0);
1086 lil[4] = LoadSpriteSVG(PATH_GRAPHICS "lilr.svg", 1.0, 1.0);
1087 (*g)->Map->Sprites[0] = LoadSpriteSVG(PATH_GRAPHICS "prek1.svg", 3.0, 3.0);
1088 (*g)->Map->Sprites[1] = LoadSpriteSVG(PATH_GRAPHICS "prek2.svg", 4.0, 4.0);
1089 (*g)->Map->Sprites[0]->z = 1;
1090 (*g)->Map->Sprites[1]->z = 1;
1091 bg=0;
1092 bg = LoadSpriteSVG(PATH_GRAPHICS "bg.svg", 16.0, 15.0);
1093 kul = LoadSpriteSVG(PATH_GRAPHICS "kul.svg", 0.5, 0.5);
1094 explo = LoadSpriteSVG(PATH_GRAPHICS "exp.svg", 0.5, 0.5);
1095 dust = LoadSpriteSVG(PATH_GRAPHICS "dust.svg", 0.5, 0.5);
1096 blood = LoadSpriteSVG(PATH_GRAPHICS "blood.svg", 0.5, 0.5);
1097 brok = LoadSpriteSVG(PATH_GRAPHICS "brok.svg", 0.5, 0.5);
1098 sniper = LoadSpriteSVG(PATH_GRAPHICS "sniper.svg", 0.5, 0.5);
1099 kulka = LoadSpriteSVG(PATH_GRAPHICS "kulka.svg", 0.1, 0.1);
1100 mine = LoadSpriteSVG(PATH_GRAPHICS "mine.svg", 0.5, 0.5);
1101 mines = LoadSpriteSVG(PATH_GRAPHICS "mines.svg", 0.5, 0.5);
1102 hud = LoadSpriteSVG(PATH_GRAPHICS "hud.svg", 4.0, 4.0);
1103 hud_mine = LoadSpriteSVG(PATH_GRAPHICS "mines.svg", 2.2, 2.2);
1104 hud_kul = LoadSpriteSVG(PATH_GRAPHICS "kul.svg", 2.2, 2.2);
1105 hud_brok = LoadSpriteSVG(PATH_GRAPHICS "brok.svg", 2.2, 2.2);
1106 hud_sniper = LoadSpriteSVG(PATH_GRAPHICS "sniper.svg", 2.2, 2.2);
1107 hud_ammo = LoadSpriteSVG(PATH_GRAPHICS "hud_ammo.svg", 4.0, 4.0);
1108 hud_reload = LoadSpriteSVG(PATH_GRAPHICS "hud_reload.svg", 4.0, 4.0);
1110 s_die = LoadSound(PATH_SOUNDS "die.wav");
1111 s_bonus = LoadSound(PATH_SOUNDS "bonus.wav");
1112 s_expl = LoadSound(PATH_SOUNDS "expl.wav");
1113 s_shoot = LoadSound(PATH_SOUNDS "shoot.wav");
1114 s_mine = LoadSound(PATH_SOUNDS "mine.wav");
1116 SDL_AddTimer(1000, callback_fps, NULL);
1118 return 0;
1121 int GameLoop(Game *g){
1122 SDL_Event event;
1123 Config conf;
1124 double lasttime, dtime;
1126 lasttime = SDL_GetTicks()*0.001;
1127 while (1) {
1128 while (SDL_PollEvent(&event)) {
1129 switch (event.type) {
1130 case SDL_KEYDOWN:
1131 if (event.key.keysym.sym == SDLK_q) {
1132 return 0;
1134 break;
1136 case SDL_QUIT:
1137 return 0;
1138 break;
1140 case SDL_VIDEORESIZE:
1141 /* Resize the screen and redraw */
1142 conf=GetConfig();
1143 conf.screen_width=event.resize.w;
1144 conf.screen_height=event.resize.h;
1145 SetConfig(conf);
1147 InvalidateSprites();
1148 break;
1150 case SDL_USEREVENT:
1151 printf("%d frames\n",frames);
1152 frames=0;
1153 break;
1155 default:
1156 break;
1159 dtime = SDL_GetTicks()*0.001-lasttime;
1160 lasttime += dtime;
1161 if(dtime < 0)
1162 dtime=0.0;
1163 if(dtime > 0.1)
1164 dtime=0.1;
1165 UpdateLogic(g, dtime*0.5);
1166 UpdateLogic(g, dtime*0.5);
1167 ClrScr();
1168 Draw(g);
1169 UpdateAndQueueDrawParticles(dtime);
1170 DrawSprites();
1171 frames++;
1172 //we don't want to waste cpu...
1173 if(frames >=50){
1174 SDL_Delay(10);
1177 return 0;
1180 int main(int argc, char **argv){
1181 Game *g;
1182 srand(time(0));
1183 InitAll(&g);
1184 GameLoop(g);
1185 return 0;