1 //
2 // demon.c
3 //
4 // Copyright 2007, 2008 Lancer-X/ASCEAI
5 //
6 // This file is part of Meritous.
7 //
8 // Meritous is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation, either version 3 of the License, or
11 // (at your option) any later version.
12 //
13 // Meritous is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with Meritous. If not, see <http://www.gnu.org/licenses/>.
20 //
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <math.h>
25 #include <SDL.h>
26 #include <SDL_image.h>
27 #include <assert.h>
28
29 #include "levelblit.h"
30 #include "mapgen.h"
31 #include "save.h"
32 #include "audio.h"
33 #include "boss.h"
34 #include "tiles.h"
35
36 SDL_Surface *reticle;
37 SDL_Surface *inrange;
38 SDL_Surface *invis_enemy;
39
40 int searched[3000];
41 int searchdist[3000];
42 int csearch;
43 int room_active[3000];
44
45 int fc_open = 0;
46
47 int max_activate_dist = 0;
48
49 // enemy
50
sqr(int x)51 int sqr(int x)
52 {
53 return x*x;
54 }
55
56 struct enemy {
57 int x, y;
58 int room;
59 int lives;
60 int deaths;
61 int str;
62 int curr_follow;
63
64 int followdepth;
65
66 int enemy_type;
67
68 SDL_Surface *image;
69 int blit_pos;
70
71 int creationcost;
72
73 int teleport_v;
74 int speed;
75 int t;
76 int active;
77 int fire_rate;
78
79 int last_room;
80 int p_last_room;
81
82 float move_dir;
83
84 int min_gems;
85 int max_gems;
86
87 struct enemy *next;
88 struct enemy *next_active;
89
90 int delete_me;
91 int dying;
92
93 struct RoomConnection *m_exit;
94 };
95
96 // shot
97
98 struct bullet {
99 float x, y;
100 struct enemy *firer;
101 struct bullet *parent;
102 int room;
103 float speed;
104 float dir;
105 int img;
106 // img: 0 = bullet
107 // 1 = star
108 // 2 = laser
109 // 3 = ministar
110 // 4 = rocket
111 // 5 = replishot
112 // 6 = laserstar
113 // 7 = proxy
114 // 8 = remote laser
115 int t;
116
117 int invuln;
118 float natural_dir;
119
120 int fire_time;
121 int duration;
122 float turn;
123
124 int shield_damage;
125
126 struct bullet *next;
127
128 int dying;
129 int delete_me;
130 };
131
132 struct diamond {
133 int x, y;
134 int room;
135 int t;
136 struct diamond *next;
137 struct diamond *next_in_room;
138 struct diamond *prv_in_room;
139 int value;
140 int delete_me;
141 };
142
143 struct enemyloc {
144 struct enemy *e;
145 struct enemyloc *n;
146 };
147
148 int total_enemies = 0;
149 int killed_enemies = 0;
150 int total_bullets = 0;
151 int active_enemies = 0;
152 int total_gems = 0;
153
154 struct enemy *enemy_stack = NULL;
155 struct bullet *bullet_stack = NULL;
156 struct enemy *active_stack = NULL;
157 struct diamond *gem_stack = NULL;
158
159 struct diamond *room_gems[3000] = {NULL};
160
161 struct enemyloc *enemy_loc_stack[20][20] = {{NULL}};
162
163 struct enemy *CreateEnemy(int enemy_x, int enemy_y, int enemy_room);
164 struct enemy *CreateEnemyEx(int enemy_x, int enemy_y, int enemy_room, int enemy_type);
165 void SCreateGem(int x, int y, int r, int v);
166 void ActivateEnemies(int room);
167 void SoupUpEnemies();
168
169 void SpawnLaser(int x, int y, float dir, int fire_time, int duration, float turn, int dmg);
170
DestroyThings()171 void DestroyThings()
172 {
173 struct enemy *ec, *ed;
174 struct bullet *bc, *bd;
175 struct diamond *dc, *dd;
176 int i;
177
178 ec = enemy_stack;
179 bc = bullet_stack;
180 dc = gem_stack;
181
182 while (ec) {
183 ed = ec;
184 ec = ec->next;
185 free(ed);
186 }
187 while (bc) {
188 bd = bc;
189 bc = bc->next;
190 free(bd);
191 }
192 while (dc) {
193 dd = dc;
194 dc = dc->next;
195 free(dd);
196 }
197
198 enemy_stack = NULL;
199 bullet_stack = NULL;
200 gem_stack = NULL;
201 active_stack = NULL;
202
203 for (i = 0; i < 3000; i++) {
204 room_gems[i] = NULL;
205 }
206 }
207
208 struct GRD_Box {
209 int d[60][60];
210 };
211 int GetRoomDist(int room1, int room2);
FindRoomDist(int room1,int room2)212 int FindRoomDist(int room1, int room2)
213 {
214 struct RoomConnection *follow;
215 int mdist = 1000000;
216 int cdist;
217
218 if (room1 == room2) return 0;
219 fc_open++;
220
221 searched[room1] = csearch;
222
223 follow = rooms[room1].con;
224 while (follow != NULL) {
225 if (searched[follow->c] != csearch) {
226 cdist = GetRoomDist(follow->c, room2);
227
228 if (cdist < mdist) {
229 mdist = cdist;
230 }
231 }
232 follow = follow->n;
233 }
234 fc_open--;
235 return mdist;
236 }
237
GetRoomDist(int room1,int room2)238 int GetRoomDist(int room1, int room2)
239 {
240 int gx, gy, dx, dy;
241 int temp;
242 int ix, iy;
243 static struct GRD_Box *g[50][50] = {{NULL}};
244
245 fc_open++;
246
247 if (room2 < room1) {
248 temp = room2;
249 room2 = room1;
250 room1 = temp;
251 }
252
253 gx = room1 / 60;
254 dx = room1 % 60;
255 gy = room2 / 60;
256 dy = room2 % 60;
257
258 if (g[gx][gy] == NULL) {
259 g[gx][gy] = malloc(sizeof(struct GRD_Box));
260 for (iy = 0; iy < 60; iy++) {
261 for (ix = 0; ix < 60; ix++) {
262 g[gx][gy]->d[ix][iy] = -1;
263 }
264 }
265 }
266
267 if (g[gx][gy]->d[dx][dy] == -1) {
268 g[gx][gy]->d[dx][dy] = FindRoomDist(room1, room2);
269 }
270 fc_open--;
271 return g[gx][gy]->d[dx][dy];
272 }
273
AddEnemyLoc(struct enemy * e,int x,int y)274 void AddEnemyLoc(struct enemy *e, int x, int y)
275 {
276 struct enemyloc *next;
277 x+=1;
278 y+=1;
279 next = enemy_loc_stack[x][y];
280 enemy_loc_stack[x][y] = malloc(sizeof(struct enemyloc));
281 enemy_loc_stack[x][y]->n = next;
282 enemy_loc_stack[x][y]->e = e;
283 }
284
GetEnemyLoc(int s_x,int s_y)285 struct enemyloc *GetEnemyLoc(int s_x, int s_y)
286 {
287 return enemy_loc_stack[s_x / 1100 + 1][s_y / 1100 + 1];
288 }
289
AddEnemyPos(struct enemy * e)290 void AddEnemyPos(struct enemy *e)
291 {
292 int x_loc, y_loc, ix, iy;
293 x_loc = (e->x) / 1100;
294 y_loc = (e->y) / 1100;
295 AddEnemyLoc(e, x_loc, y_loc);
296 ix = ((e->x - screen->w) / 1100);
297 iy = ((e->y - screen->h) / 1100);
298 if (x_loc != ix) {
299 AddEnemyLoc(e, ix, y_loc);
300 }
301 if (y_loc != iy) {
302 AddEnemyLoc(e, x_loc, iy);
303 }
304 if ((x_loc != ix) && (y_loc != iy)) {
305 AddEnemyLoc(e, ix, iy);
306 }
307 }
308
WriteEnemyData()309 void WriteEnemyData()
310 {
311 struct enemy *ptr;
312 int n = 0;
313 int i = 0;
314
315 ptr = enemy_stack;
316 while (ptr != NULL) {
317 if (!ptr->delete_me) n++;
318 ptr = ptr->next;
319 }
320 FWInt(n);
321 ptr = enemy_stack;
322 while (ptr != NULL) {
323 if (!ptr->delete_me) {
324 FWInt(ptr->x);
325 FWInt(ptr->y);
326 FWInt(ptr->room);
327 FWInt(ptr->enemy_type);
328 i++;
329 if (i % 100 == 99) {
330 SavingScreen(2, (float)i / (float)n);
331 }
332 }
333 ptr = ptr->next;
334 }
335 }
336
WriteGemData()337 void WriteGemData()
338 {
339 struct diamond *ptr;
340 int n = 0;
341 int i = 0;
342
343 ptr = gem_stack;
344 while (ptr != NULL) {
345 if (!ptr->delete_me) n++;
346 ptr = ptr->next;
347 }
348 FWInt(n);
349 ptr = gem_stack;
350 while (ptr != NULL) {
351 if (!ptr->delete_me) {
352 FWInt(ptr->x);
353 FWInt(ptr->y);
354 FWInt(ptr->room);
355 FWInt(ptr->value);
356
357 i++;
358 if (i % 100 == 99) {
359 SavingScreen(3, (float)i / (float)n);
360 }
361 }
362 ptr = ptr->next;
363 }
364 }
365
WriteCreatureData()366 void WriteCreatureData()
367 {
368 FWInt(total_enemies);
369 FWInt(killed_enemies);
370
371 WriteEnemyData();
372 WriteGemData();
373 }
374
ReadEnemyData()375 void ReadEnemyData()
376 {
377 int i, n;
378 int x, y, room, t;
379
380 n = FRInt();
381
382 for (i = 0; i < n; i++) {
383 x = FRInt();
384 y = FRInt();
385 room = FRInt();
386 t = FRInt();
387 CreateEnemyEx(x, y, room, t);
388 total_enemies--;
389
390 if (i % 100 == 99) {
391 LoadingScreen(2, (float)i / (float)n);
392 }
393 }
394 LoadingScreen(2, 1);
395 }
396
ReadGemData()397 void ReadGemData()
398 {
399 int i, n;
400 int x, y, room, value;
401
402 n = FRInt();
403
404 for (i = 0; i < n; i++) {
405 x = FRInt();
406 y = FRInt();
407 room = FRInt();
408 value = FRInt();
409 SCreateGem(x, y, room, value);
410
411 if (i % 100 == 99) {
412 LoadingScreen(3, (float)i / (float)n);
413 }
414 }
415 LoadingScreen(3, 1);
416 }
417
ActivateVisited()418 void ActivateVisited()
419 {
420 int i;
421
422
423 for (i = 0; i < 3000; i++) {
424 if (rooms[i].visited) {
425 ActivateEnemies(i);
426 }
427 if (i % 10 == 9) {
428 LoadingScreen(4, (float)i / 3000.0);
429 }
430 }
431 LoadingScreen(4, 1);
432 }
433
ReadCreatureData()434 void ReadCreatureData()
435 {
436 total_enemies = FRInt();
437 killed_enemies = FRInt();
438
439 ReadEnemyData();
440 ReadGemData();
441 ActivateVisited();
442 }
443
444 SDL_Surface *enemy_sprites[10];
445
AllocateEnemy()446 struct enemy * AllocateEnemy()
447 {
448 return malloc(sizeof(struct enemy));
449 }
450
AllocateBullet()451 struct bullet * AllocateBullet()
452 {
453 return malloc(sizeof(struct bullet));
454 }
455
AllocateGem()456 struct diamond * AllocateGem()
457 {
458 return malloc(sizeof(struct diamond));
459 }
460
CreateEnemy(int enemy_x,int enemy_y,int enemy_room)461 struct enemy *CreateEnemy(int enemy_x, int enemy_y, int enemy_room)
462 {
463 int enemy_type;
464
465 enemy_type = rand() % (rooms[enemy_room].s_dist / 5 + 1);
466 if (rooms[enemy_room].room_type == 5) enemy_type += rand()%3;
467 if (enemy_type > 8) enemy_type = rand()%3+6;
468
469 if (rooms[enemy_room].s_dist >= 15) {
470 if (rand()%64 == 0) {
471 enemy_type = 9;
472 }
473 }
474
475
476 return CreateEnemyEx(enemy_x, enemy_y, enemy_room, enemy_type);
477 }
478
CreateEnemyEx(int enemy_x,int enemy_y,int enemy_room,int enemy_type)479 struct enemy *CreateEnemyEx(int enemy_x, int enemy_y, int enemy_room, int enemy_type)
480 {
481 struct enemy *new_enemy;
482
483 new_enemy = AllocateEnemy();
484 new_enemy->x = enemy_x;
485 new_enemy->y = enemy_y;
486 new_enemy->room = enemy_room;
487
488 rooms[enemy_room].enemies++;
489 new_enemy->deaths = 0;
490 new_enemy->t = rand() % 65536;
491 new_enemy->active = 0;
492 new_enemy->curr_follow = -1;
493 new_enemy->teleport_v = 0;
494
495 new_enemy->m_exit = NULL;
496
497 new_enemy->dying = 0;
498 new_enemy->delete_me = 0;
499
500 new_enemy->last_room = -1;
501 new_enemy->p_last_room = -1;
502
503 new_enemy->enemy_type = enemy_type;
504
505 new_enemy->followdepth = 4;
506
507 switch (enemy_type) {
508 case 0:
509 new_enemy->image = enemy_sprites[0];
510 new_enemy->lives = 1;
511 new_enemy->str = 20;
512 new_enemy->speed = 3;
513 new_enemy->fire_rate = 20;
514 new_enemy->min_gems = 0;
515 new_enemy->max_gems = 3;
516 new_enemy->creationcost = 1;
517 break;
518 case 1:
519 new_enemy->image = enemy_sprites[1];
520 new_enemy->lives = 1;
521 new_enemy->str = 50;
522 new_enemy->speed = 4;
523 new_enemy->fire_rate = 25;
524 new_enemy->min_gems = 2;
525 new_enemy->max_gems = 6;
526 new_enemy->creationcost = 1;
527 break;
528 case 2:
529 new_enemy->image = enemy_sprites[2];
530 new_enemy->lives = 1;
531 new_enemy->str = 180;
532 new_enemy->speed = 5;
533 new_enemy->fire_rate = 40;
534 new_enemy->min_gems = 8;
535 new_enemy->max_gems = 15;
536 new_enemy->creationcost = 1;
537 break;
538 case 3:
539 new_enemy->image = enemy_sprites[3];
540 new_enemy->lives = 2;
541 new_enemy->str = 220;
542 new_enemy->speed = 3;
543 new_enemy->fire_rate = 24;
544 new_enemy->min_gems = 12;
545 new_enemy->max_gems = 20;
546 new_enemy->creationcost = 1;
547 break;
548 case 4:
549 new_enemy->image = enemy_sprites[4];
550 new_enemy->lives = 1;
551 new_enemy->str = 360;
552 new_enemy->speed = 3;
553 new_enemy->fire_rate = 32;
554 new_enemy->min_gems = 18;
555 new_enemy->max_gems = 32;
556 new_enemy->creationcost = 2;
557 break;
558 case 5:
559 new_enemy->image = enemy_sprites[5];
560 new_enemy->lives = 1;
561 new_enemy->str = 450;
562 new_enemy->speed = 3;
563 new_enemy->fire_rate = 2;
564 new_enemy->min_gems = 32;
565 new_enemy->max_gems = 64;
566 new_enemy->creationcost = 2;
567 break;
568 case 6:
569 new_enemy->image = enemy_sprites[6];
570 new_enemy->lives = 2;
571 new_enemy->str = 450;
572 new_enemy->speed = 4;
573 new_enemy->fire_rate = 10;
574 new_enemy->min_gems = 50;
575 new_enemy->max_gems = 100;
576 new_enemy->creationcost = 2;
577 break;
578 case 7:
579 new_enemy->image = enemy_sprites[7];
580 new_enemy->lives = 1;
581 new_enemy->str = 500;
582 new_enemy->speed = 4;
583 new_enemy->fire_rate = 27;
584 new_enemy->min_gems = 80;
585 new_enemy->max_gems = 160;
586 new_enemy->creationcost = 3;
587 break;
588 case 8:
589 new_enemy->image = enemy_sprites[8];
590 new_enemy->lives = 4;
591 new_enemy->str = 500;
592 new_enemy->speed = 2;
593 new_enemy->fire_rate = 8;
594 new_enemy->min_gems = 200;
595 new_enemy->max_gems = 400;
596 new_enemy->creationcost = 4;
597 break;
598 case 9:
599 new_enemy->image = enemy_sprites[0];
600 new_enemy->lives = 1;
601 new_enemy->str = rooms[enemy_room].s_dist * 20;
602 new_enemy->speed = 3;
603 new_enemy->fire_rate = 21;
604 new_enemy->min_gems = 300;
605 new_enemy->max_gems = 600;
606 new_enemy->creationcost = 3;
607 break;
608 case 10:
609 new_enemy->image = enemy_sprites[9];
610 new_enemy->lives = 8;
611 new_enemy->str = 500;
612 new_enemy->speed = 1;
613 new_enemy->fire_rate = 4;
614 new_enemy->min_gems = 5000;
615 new_enemy->max_gems = 6000;
616 new_enemy->followdepth = 8;
617 new_enemy->creationcost = 6;
618 break;
619 }
620
621 if (training) {
622 new_enemy->str = new_enemy->str * 4 / 5;
623 new_enemy->fire_rate += (new_enemy->fire_rate / 2);
624 new_enemy->speed *= 2;
625 }
626
627 if (rooms[new_enemy->room].room_type == 5) {
628 new_enemy->str = new_enemy->str * 3 / 2;
629 if (new_enemy->str > 1500) new_enemy->str = 1500;
630 new_enemy->fire_rate = new_enemy->fire_rate - 1;
631 }
632
633 new_enemy->blit_pos = (rand()%(new_enemy->image->w / (new_enemy->image->h/new_enemy->lives)))*(new_enemy->image->h/new_enemy->lives);
634 new_enemy->next_active = NULL;
635
636 new_enemy->next = enemy_stack;
637 enemy_stack = new_enemy;
638
639 AddEnemyPos(new_enemy);
640
641 total_enemies++;
642
643 return new_enemy;
644 }
645
SCreateGem(int x,int y,int r,int v)646 void SCreateGem(int x, int y, int r, int v)
647 {
648 struct diamond *new_gem;
649
650 if (TileData[Get(x / 32, y / 32)].Is_Solid) {
651 return;
652 }
653 if (GetRoom(x / 32, y / 32) != r) {
654 return;
655 }
656 if (v == 0) {
657 return;
658 }
659
660 new_gem = AllocateGem();
661
662 new_gem->x = x;
663 new_gem->y = y;
664 new_gem->room = r;
665 new_gem->delete_me = 0;
666 new_gem->t = rand()%65536;
667 new_gem->next = gem_stack;
668 new_gem->next_in_room = room_gems[r];
669
670 if (room_gems[r] != NULL) {
671 room_gems[r]->prv_in_room = new_gem;
672 }
673
674 new_gem->value = v;
675 new_gem->prv_in_room = NULL;
676 gem_stack = new_gem;
677 room_gems[r] = new_gem;
678
679 total_gems++;
680 }
681
CreateGem(int x,int y,int r,int v)682 void CreateGem(int x, int y, int r, int v)
683 {
684 if (v == 0) return;
685 if ( (rand()%1000) < ((int)log(v)/4 + (player_hp == 1)*5 + 2) ) {
686 SCreateGem(x, y, r, 31337);
687 } else {
688 SCreateGem(x, y, r, v);
689 }
690 }
691
PlayerDir(int x,int y)692 float PlayerDir(int x, int y)
693 {
694 float dy = player_y+12 - y;
695 float dx = player_x+8 - x;
696 return atan2(dy, dx);
697 }
698
PlayerDist(int x,int y)699 int PlayerDist(int x, int y)
700 {
701 int d = sqrt(sqr(x-(player_x+8))+sqr(y-(player_y+12)));
702 return d;
703 }
704
CreateBullet(int x,int y,struct enemy * firer,int bullet_type,float dir,float spd)705 struct bullet *CreateBullet(int x, int y, struct enemy *firer, int bullet_type, float dir, float spd)
706 {
707 struct bullet *new_shot;
708
709 new_shot = AllocateBullet();
710 new_shot->x = x;
711 new_shot->y = y;
712 new_shot->firer = firer;
713 if (firer != NULL) {
714 new_shot->room = firer->room;
715 } else {
716 new_shot->room = GetRoom(x / 32, y / 32);
717 }
718 new_shot->dying = 0;
719 new_shot->delete_me = 0;
720 new_shot->t = rand() % 65536;
721 new_shot->dir = dir;
722 new_shot->speed = spd;
723 new_shot->invuln = 0;
724 new_shot->parent = NULL;
725
726 switch (bullet_type) {
727 case 0:
728 new_shot->img = 0;
729 break;
730 case 1:
731 new_shot->img = 1;
732 new_shot->invuln = 1;
733 break;
734 case 2:
735 new_shot->img = 2;
736 new_shot->invuln = 1;
737 new_shot->t = 0;
738 new_shot->fire_time = 30;
739 new_shot->duration = 30;
740 new_shot->turn = 0.0;
741 new_shot->speed = 0.0;
742 break;
743 case 3:
744 new_shot->img = 3;
745 break;
746 case 4:
747 new_shot->img = 4;
748 new_shot->invuln = 1;
749 break;
750 case 5:
751 new_shot->img = 5;
752 new_shot->t = 0;
753 break;
754 case 6:
755 new_shot->img = 6;
756 new_shot->invuln = 1;
757 break;
758 case 7:
759 new_shot->img = 7;
760 new_shot->invuln = 1;
761 break;
762 case 8:
763 new_shot->img = 8;
764 new_shot->invuln = 1;
765 break;
766 }
767 if (training) {
768 new_shot->speed *= 0.8;
769 }
770 new_shot->next = bullet_stack;
771 bullet_stack = new_shot;
772
773 total_bullets++;
774 return new_shot;
775 }
776
FireLaser(int x,int y,struct enemy * firer,float dir,int fire_time,int duration,float turn,int dmg)777 struct bullet *FireLaser(int x, int y, struct enemy *firer, float dir, int fire_time, int duration, float turn, int dmg)
778 {
779 int f_total;
780 struct bullet *b;
781 b = CreateBullet(x, y, firer, 2, dir, 0);
782 b->fire_time = fire_time;
783 b->duration = duration;
784 b->turn = turn;
785 b->shield_damage = dmg;
786
787 if (training) {
788 f_total = b->fire_time + b->duration;
789 if (b->duration > 1) {
790 b->duration /= 2;
791 b->fire_time = f_total - b->duration;
792 }
793 b->shield_damage = (b->shield_damage + 1) / 2;
794 }
795 return b;
796 }
797
InitEnemySprites()798 void InitEnemySprites()
799 {
800 enemy_sprites[0] = IMG_Load("/usr/local/share/meritous/i/mons1.png");
801 SDL_SetColorKey(enemy_sprites[0], SDL_SRCCOLORKEY | SDL_RLEACCEL, 255);
802 enemy_sprites[1] = IMG_Load("/usr/local/share/meritous/i/mons2.png");
803 SDL_SetColorKey(enemy_sprites[1], SDL_SRCCOLORKEY | SDL_RLEACCEL, 255);
804 enemy_sprites[2] = IMG_Load("/usr/local/share/meritous/i/mons3.png");
805 SDL_SetColorKey(enemy_sprites[2], SDL_SRCCOLORKEY | SDL_RLEACCEL, 255);
806 enemy_sprites[3] = IMG_Load("/usr/local/share/meritous/i/mons4.png");
807 SDL_SetColorKey(enemy_sprites[3], SDL_SRCCOLORKEY | SDL_RLEACCEL, 255);
808 enemy_sprites[4] = IMG_Load("/usr/local/share/meritous/i/mons5.png");
809 SDL_SetColorKey(enemy_sprites[4], SDL_SRCCOLORKEY | SDL_RLEACCEL, 255);
810 enemy_sprites[5] = IMG_Load("/usr/local/share/meritous/i/mons6.png");
811 SDL_SetColorKey(enemy_sprites[5], SDL_SRCCOLORKEY | SDL_RLEACCEL, 255);
812 enemy_sprites[6] = IMG_Load("/usr/local/share/meritous/i/mons7.png");
813 SDL_SetColorKey(enemy_sprites[6], SDL_SRCCOLORKEY | SDL_RLEACCEL, 255);
814 enemy_sprites[7] = IMG_Load("/usr/local/share/meritous/i/mons8.png");
815 SDL_SetColorKey(enemy_sprites[7], SDL_SRCCOLORKEY | SDL_RLEACCEL, 255);
816 enemy_sprites[8] = IMG_Load("/usr/local/share/meritous/i/mons9.png");
817 SDL_SetColorKey(enemy_sprites[8], SDL_SRCCOLORKEY | SDL_RLEACCEL, 255);
818 enemy_sprites[9] = IMG_Load("/usr/local/share/meritous/i/mons10.png");
819 SDL_SetColorKey(enemy_sprites[9], SDL_SRCCOLORKEY | SDL_RLEACCEL, 255);
820
821 reticle = IMG_Load("/usr/local/share/meritous/i/reticle.png");
822 SDL_SetColorKey(reticle, SDL_SRCCOLORKEY | SDL_RLEACCEL, 255);
823
824 inrange = IMG_Load("/usr/local/share/meritous/i/inrange.png");
825 SDL_SetColorKey(inrange, SDL_SRCCOLORKEY | SDL_RLEACCEL, 255);
826
827 invis_enemy = IMG_Load("/usr/local/share/meritous/i/hidden_monster.png");
828 SDL_SetColorKey(invis_enemy, SDL_SRCCOLORKEY | SDL_RLEACCEL, 255);
829 }
830
ActivateSingleEnemy(struct enemy * t)831 void ActivateSingleEnemy(struct enemy *t)
832 {
833 struct enemy *new_active;
834
835 if (t->active) return;
836
837 if (t->enemy_type != 10) {
838 if (t->enemy_type == 9) {
839 if (max_activate_dist < 10) return;
840 } else {
841
842 if (t->enemy_type > (max_activate_dist / 5 + 2)) return;
843
844 }
845 }
846
847 new_active = t;
848 new_active->next_active = active_stack;
849 active_stack = new_active;
850
851 active_enemies += 1;
852 t->active = 1;
853 }
854
XActivateSingleEnemy(struct enemy * t)855 void XActivateSingleEnemy(struct enemy *t)
856 {
857 if (rooms[t->room].room_type == 2) return;
858 if (rooms[t->room].room_type == 3) return;
859
860 ActivateSingleEnemy(t);
861 }
862
InitEnemies()863 void InitEnemies()
864 {
865 int c_room;
866 int cr_w, cr_h, cr_x, cr_y;
867 int room_size;
868 int n_enemies;
869 int i;
870 int trying;
871 int e_x, e_y;
872 int nx, ny;
873
874 max_activate_dist = 0;
875
876 InitEnemySprites();
877
878 for (ny = 0; ny < 20; ny++) {
879 for (nx = 0; nx < 20; nx++) {
880 enemy_loc_stack[nx][ny] = NULL;
881 }
882 }
883
884 total_enemies = 0;
885 killed_enemies = 0;
886 total_bullets = 0;
887 active_enemies = 0;
888 total_gems = 0;
889
890 for (i = 0; i < 3000; i++) {
891 room_active[i] = 0;
892 }
893
894 if (game_load) {
895 ReadCreatureData();
896 if (current_boss > 0) SoupUpEnemies();
897 } else {
898 for (c_room = 1; c_room < 3000; c_room++) {
899 cr_x = rooms[c_room].x + 1;
900 cr_y = rooms[c_room].y + 1;
901 cr_w = rooms[c_room].w - 2;
902 cr_h = rooms[c_room].h - 2;
903 room_size = cr_w * cr_h;
904
905 n_enemies = rand() % ((room_size / 4) + 1);
906
907 if (rooms[c_room].room_type == 2) {
908 n_enemies = 0;
909 }
910
911 if (rooms[c_room].room_type == 3) {
912 n_enemies += (n_enemies + room_size) / 2;
913 }
914
915 if (rooms[c_room].room_type == 5) {
916 n_enemies = 50;
917 }
918
919 while (n_enemies > 0) {
920 trying = 1;
921 while (trying) {
922 e_x = cr_x * 32 + 32 + rand() % (cr_w * 32 - 64 + 1);
923 e_y = cr_y * 32 + 32 + rand() % (cr_h * 32 - 64 + 1);
924
925 if ((!IsSolid(Get( (e_x-16) /32, (e_y-16) /32)))&&(!IsSolid(Get( (e_x+16) /32, (e_y-16) /32)))) {
926 if ((!IsSolid(Get( (e_x-16) /32, (e_y+16) /32)))&&(!IsSolid(Get( (e_x+16) /32, (e_y+16) /32)))) {
927 n_enemies -= (CreateEnemy(e_x, e_y, c_room))->creationcost;
928 trying = 0;
929 }
930 }
931 }
932 }
933 if (c_room % 100 == 99) {
934 LoadingScreen(2, (float)c_room / 3000.0);
935 }
936 }
937 }
938
939
940 }
941
EnemyMovement(struct enemy * e,int move_x,int move_y)942 int EnemyMovement(struct enemy *e, int move_x, int move_y)
943 {
944 if (!IsSolid(Get( (move_x - 12)/32, (move_y - 12)/32))) {
945 if (!IsSolid(Get( (move_x + 12)/32, (move_y - 12)/32))) {
946 if (!IsSolid(Get( (move_x - 12)/32, (move_y + 12)/32))) {
947 if (!IsSolid(Get( (move_x + 12)/32, (move_y + 12)/32))) {
948 e->x = move_x;
949 e->y = move_y;
950 return 1;
951 }
952 }
953 }
954 }
955 return 0;
956 }
957
958 // Only activate SOME enemies. A room can only be ZActivated once
ZActivateEnemies(int room)959 void ZActivateEnemies(int room)
960 {
961 struct enemy *t;
962 struct RoomConnection *rc;
963
964 if (room_active[room]) return;
965 room_active[room] = 1;
966
967 t = enemy_stack;
968
969 while (t != NULL) {
970 // 1/4 chance of activating each enemy
971 if (rand()%4 == 0) {
972 if (t->room == room) {
973 if (t->active == 0) {
974 XActivateSingleEnemy(t);
975 }
976 }
977 }
978 t = t->next;
979 }
980
981 // 1/3 chance of activating each adjacent room
982 rc = rooms[room].con;
983 while (rc != NULL) {
984 if (rand()%3 == 0) {
985 ZActivateEnemies(rc->c);
986 }
987 rc = rc->n;
988 }
989 }
990
ActivateEnemies(int room)991 void ActivateEnemies(int room)
992 {
993 struct enemy *t;
994 struct RoomConnection *rc;
995
996 t = enemy_stack;
997
998 if (rooms[room].s_dist > max_activate_dist) {
999 max_activate_dist = rooms[room].s_dist;
1000 }
1001
1002 while (t != NULL) {
1003 if (t->room == room) {
1004 if (t->active == 0) {
1005 ActivateSingleEnemy(t);
1006
1007 if (rooms[room].room_type == 3) {
1008 t->teleport_v = (rand() % 1500) + 50;
1009 }
1010 }
1011 }
1012 t = t->next;
1013 }
1014
1015 // 1/2 chance of activating each adjacent room
1016 rc = rooms[room].con;
1017 while (rc != NULL) {
1018 if (rand()%2 == 0) {
1019 if ((rooms[rc->c].room_type != 2) && (rooms[rc->c].room_type != 3)) {
1020 ZActivateEnemies(rc->c);
1021 }
1022 }
1023 rc = rc->n;
1024 }
1025 }
1026
CanEnterRoom(int room)1027 int CanEnterRoom(int room)
1028 {
1029 if (room == 0) return 0;
1030 if (rooms[room].room_type == 2) return 0;
1031 if (rooms[room].room_type == 3) return 0;
1032 if (rooms[room].room_type == 5) return 0;
1033 if (rooms[room].room_type == 6) return 0;
1034
1035 if (artifacts[11]) {
1036 if (rooms[room].enemies > 3) {
1037 return 0;
1038 }
1039 }
1040
1041 return 1;
1042 }
CanLeaveRoom(int room)1043 int CanLeaveRoom(int room)
1044 {
1045 if (room == 0) return 0;
1046 if (rooms[room].room_type == 2) return 0;
1047 if (rooms[room].room_type == 3) return 0;
1048 if (rooms[room].room_type == 5) return 0;
1049 if (rooms[room].room_type == 6) return 0;
1050
1051 return 1;
1052 }
1053
RecurseFind(struct enemy * e,int room,int depth)1054 int RecurseFind(struct enemy *e, int room, int depth)
1055 {
1056 struct RoomConnection *follow;
1057 int dpth;
1058 int mindpth = 1000000;
1059 follow = rooms[room].con;
1060
1061 if (CanEnterRoom(room) == 0) return 0;
1062
1063 if (room == player_room) return depth+1;
1064 if (searched[room] == csearch) {
1065 if (searchdist[room] < depth)
1066 return 0;
1067 }
1068 if (depth > e->followdepth) return 0;
1069 if ((e->last_room == room) && (e->p_last_room == player_room)) return 0;
1070
1071 searched[room] = csearch;
1072 searchdist[room] = depth;
1073
1074 while (follow != NULL) {
1075 if ((dpth = RecurseFind(e, follow->c, depth+1)) > 0) {
1076 if (dpth < mindpth) {
1077 mindpth = dpth;
1078 }
1079 }
1080 follow = follow->n;
1081 }
1082
1083 if (mindpth != 1000000) {
1084 return mindpth;
1085 }
1086
1087 return 0;
1088
1089 }
1090
FollowPlayer(struct enemy * e,struct RoomConnection ** rcon)1091 int FollowPlayer(struct enemy *e, struct RoomConnection **rcon)
1092 {
1093 struct RoomConnection *follow;
1094 int mindepth = 1000000;
1095 int newdepth;
1096 int mdist = 1000000;
1097 int ndist = 0;
1098 int rdepth[4000];
1099
1100 return 0;
1101 follow = rooms[e->room].con;
1102
1103 while (follow != NULL) {
1104 if (follow->c == player_room) {
1105 if (CanEnterRoom(follow->c)) {
1106 *rcon = follow;
1107 e->curr_follow = (*rcon)->c;
1108 return 1;
1109 }
1110 }
1111 follow = follow->n;
1112 }
1113
1114 // Recursively follow the player, to a certain depth
1115 follow = rooms[e->room].con;
1116 csearch = rand();
1117
1118 // Are we already following the player into a room?
1119
1120 /*if (e->curr_follow != -1) {
1121 // See if this room is the best FIRST
1122 newdepth = RecurseFind(e, e->curr_follow, 0);
1123 if (newdepth > 0) {
1124 mindepth = newdepth;
1125 *rcon = follow;
1126 }
1127 }*/
1128
1129 while (follow != NULL) {
1130 if (CanEnterRoom(follow->c)) {
1131 newdepth = RecurseFind(e, follow->c, 0);
1132 rdepth[follow->c] = newdepth;
1133 if (newdepth > 0) {
1134 if (mindepth > newdepth) {
1135 mindepth = newdepth;
1136 *rcon = follow;
1137 }
1138 }
1139 }
1140 follow = follow->n;
1141 }
1142 if (mindepth != 1000000) {
1143 follow = rooms[e->room].con;
1144 while (follow != NULL) {
1145 if (CanEnterRoom(follow->c)) {
1146 newdepth = rdepth[follow->c];
1147 if (newdepth == mindepth) {
1148 ndist = PlayerDist(follow->x*32+16, follow->y*32+16);
1149 if (ndist < mdist) {
1150 mdist = ndist;
1151 *rcon = follow;
1152 }
1153 }
1154 }
1155 follow = follow->n;
1156 }
1157
1158 e->curr_follow = (*rcon)->c;
1159 return mindepth;
1160 }
1161 return 0;
1162 }
1163
KillEnemy(struct enemy * t)1164 void KillEnemy(struct enemy *t)
1165 {
1166 static int lastkill = 0;
1167 int ct;
1168
1169 if (t->dying > 0) return;
1170 if (t->teleport_v > 0) return;
1171 if (t->delete_me) return;
1172
1173 ct = SDL_GetTicks();
1174
1175 if ((ct - lastkill) > 100) {
1176 SND_Pos("/usr/local/share/meritous/a/enemyhit.wav", 128, PlayerDist(t->x, t->y));
1177 lastkill = ct;
1178 }
1179
1180 t->dying = 1;
1181 }
1182
ArtifactRoomUnlock(int room)1183 void ArtifactRoomUnlock(int room)
1184 {
1185 struct enemy *e;
1186 int x, y, rx, ry, rt;
1187 int placed;
1188 int tot_treasures;
1189
1190 e = active_stack;
1191 while (e != NULL) {
1192 if ((e->delete_me == 0) && (e->room == room)) {
1193 return;
1194 }
1195 e = e->next_active;
1196 }
1197
1198 // unlock doors
1199
1200 for (y = 0; y < rooms[room].h; y++) {
1201 for (x = 0; x < rooms[room].w; x++) {
1202 rx = x + rooms[room].x;
1203 ry = y + rooms[room].y;
1204 rt = Get(rx, ry);
1205
1206 if ((rt >= 21) && (rt <= 24)) {
1207 Put(rx, ry, rt - 21 + 13, room);
1208 }
1209 }
1210 }
1211
1212 // place treasure
1213 placed = 0;
1214 tot_treasures = 2 + rand() % (rooms[room].s_dist / 8 + 1);
1215 while (placed < tot_treasures) {
1216 x = rooms[room].x + (rand() % (rooms[room].w - 2));
1217 y = rooms[room].y + (rand() % (rooms[room].h - 2));
1218 //printf("Attempting %d, %d\n", x, y);
1219 if ((x+y)%2 == (placed>0)) {
1220 //printf("Correct placement type\n");
1221 if (!IsSolid(Get(x, y))) {
1222 //printf("Not solid\n");
1223 Put(x, y, 26, room);
1224 placed++;
1225 }
1226 }
1227 fflush(stdout);
1228 }
1229
1230 // sign room
1231 rooms[room].room_type = 4;
1232 }
1233
EnemySound(int t,int dist)1234 void EnemySound(int t, int dist)
1235 {
1236 static int last_e_sound = 0;
1237 static int last_delay = 150;
1238 int curr_e_sound = SDL_GetTicks();
1239
1240 if ((curr_e_sound - last_delay) < last_e_sound) {
1241 return;
1242 }
1243
1244 switch (t) {
1245 case 0:
1246 SND_Pos("/usr/local/share/meritous/a/mons0shot.wav", 48, dist);
1247 last_delay = 200;
1248 break;
1249 case 1:
1250 SND_Pos("/usr/local/share/meritous/a/mons1shot.wav", 112, dist);
1251 last_delay = 500;
1252 break;
1253 case 2:
1254 SND_Pos("/usr/local/share/meritous/a/mons2shot.wav", 110, dist);
1255 last_delay = 1000;
1256 break;
1257 case 3:
1258 SND_Pos("/usr/local/share/meritous/a/mons3shot.wav", 110, dist);
1259 last_delay = 500;
1260 break;
1261 case 4:
1262 SND_Pos("/usr/local/share/meritous/a/mons4shot.wav", 110, dist);
1263 last_delay = 900;
1264 break;
1265 case 5:
1266 SND_Pos("/usr/local/share/meritous/a/mons5shot.wav", 80, dist);
1267 last_delay = 60;
1268 break;
1269 case 6:
1270 SND_Pos("/usr/local/share/meritous/a/mons6shot.wav", 110, dist);
1271 last_delay = 1000;
1272 break;
1273 case 7:
1274 SND_Pos("/usr/local/share/meritous/a/mons7shot.wav", 110, dist);
1275 last_delay = 600;
1276 break;
1277 case 8:
1278 SND_Pos("/usr/local/share/meritous/a/mons8shot.wav", 110, dist);
1279 last_delay = 700;
1280 break;
1281 case 9:
1282 SND_Pos("/usr/local/share/meritous/a/mons9shot.wav", 110, dist);
1283 last_delay = 242;
1284 break;
1285 case 10:
1286 SND_Pos("/usr/local/share/meritous/a/mons10shot.wav", 110, dist);
1287 last_delay = 250;
1288 break;
1289
1290
1291 default:
1292 break;
1293 }
1294
1295 last_e_sound = curr_e_sound;
1296 }
1297
MoveEnemy(struct enemy * e)1298 void MoveEnemy(struct enemy *e)
1299 {
1300 int n_gems;
1301 int i;
1302 int move_x, move_y;
1303 int door_x=0, door_y=0;
1304 int enemy_fire_type;
1305 int actual_lives;
1306 int can_move = 0;
1307 struct RoomConnection *con_traverse;
1308 struct RoomConnection *rcon;
1309 int nearest;
1310 struct bullet *b;
1311 e->t++;
1312 float dp;
1313 float dpf;
1314 if (e->teleport_v > 0) {
1315 e->teleport_v--;
1316 return;
1317 }
1318
1319 if (e->enemy_type < 10) {
1320 enemy_fire_type = e->enemy_type;
1321 } else {
1322 enemy_fire_type = rand()%10;
1323 }
1324
1325 if (e->dying == 0) {
1326 if ((e->t % e->fire_rate) == 0) {
1327 if (e->room == player_room) {
1328 switch (enemy_fire_type) {
1329 case 0:
1330 EnemySound(0, PlayerDist(e->x, e->y));
1331 CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y), 1.5);
1332 if (e->enemy_type==10) e->fire_rate = 20;
1333 break;
1334
1335 case 1:
1336 EnemySound(1, PlayerDist(e->x, e->y));
1337 CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y)+0.1, 2.1);
1338 CreateBullet(e->x, e->y, e, 3, PlayerDir(e->x, e->y), 2.4);
1339 CreateBullet(e->x, e->y, e, 3, PlayerDir(e->x, e->y)-0.1, 2.1);
1340 CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y), 1.7);
1341 if (e->enemy_type==10) e->fire_rate = 25;
1342 break;
1343
1344 case 2:
1345 EnemySound(2, PlayerDist(e->x, e->y));
1346 for (dp = 0; dp < M_PI*2; dp += 0.25) {
1347 CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y)+dp, 1.1);
1348 }
1349 dp = RandomDir();
1350 for (i = 0; i < 20; i++) {
1351 CreateBullet(e->x, e->y, e, 0, dp, (float)i * 0.1 + 2.5);
1352 }
1353 if (e->enemy_type==10) e->fire_rate = 40;
1354 break;
1355
1356 case 3:
1357 EnemySound(3, PlayerDist(e->x, e->y));
1358 CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y), 2.5);
1359 CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y)+0.1, 2.5);
1360 CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y)+0.2, 2.5);
1361 CreateBullet(e->x, e->y, e, 1, PlayerDir(e->x, e->y), 1.5);
1362 CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y)-0.2, 2.2);
1363 CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y)-0.3, 2.2);
1364 if (e->enemy_type==10) e->fire_rate = 24;
1365 break;
1366
1367 case 4:
1368 EnemySound(4, PlayerDist(e->x, e->y));
1369 for (dp = 0; dp < M_PI * 0.66; dp += 0.2) {
1370 CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y)+0.5 - dp, 1.8+(dp/2));
1371 CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y)-0.4 + dp, 1.8+(dp/2));
1372 }
1373 FireLaser(e->x, e->y, e, PlayerDir(e->x, e->y), 24, 4, 20.0, 6);
1374 if (e->enemy_type==10) e->fire_rate = 32;
1375 break;
1376
1377 case 5:
1378 EnemySound(5, PlayerDist(e->x, e->y));
1379 CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y), 4);
1380 if (e->enemy_type==10) e->fire_rate = 2;
1381 break;
1382
1383 case 6:
1384 EnemySound(6, PlayerDist(e->x, e->y));
1385 CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y)+0.25, 6);
1386 CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y)+0.25, 4);
1387
1388 CreateBullet(e->x, e->y, e, 5, PlayerDir(e->x, e->y) - 0.05, 4.99);
1389 CreateBullet(e->x, e->y, e, 5, PlayerDir(e->x, e->y), 4.99);
1390 CreateBullet(e->x, e->y, e, 5, PlayerDir(e->x, e->y) + 0.05, 4.99);
1391
1392 CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y)-0.25, 5);
1393 CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y)-0.25, 3);
1394 if (e->enemy_type==10) e->fire_rate = 10;
1395 break;
1396
1397 case 7:
1398 EnemySound(7, PlayerDist(e->x, e->y));
1399 for (dp = 0; dp < M_PI * 0.66; dp += 0.1) {
1400 CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y)+0.5 - dp, 1.8+(dp/2));
1401 CreateBullet(e->x, e->y, e, 3, PlayerDir(e->x, e->y)-0.4 + dp, 1.8+(dp/2));
1402
1403 CreateBullet(e->x, e->y, e, 3, PlayerDir(e->x, e->y)+0.5 - dp*2, 4+(dp*2));
1404 CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y)-0.4 + dp*2, 4+(dp*2));
1405 }
1406 FireLaser(e->x, e->y, e, (float)e->t / 25.0, 16, 10, 0.08, 4);
1407 FireLaser(e->x, e->y, e, (float)e->t / 25.0 + M_PI*2/4, 16, 10, 0.08, 4);
1408 FireLaser(e->x, e->y, e, (float)e->t / 25.0 + M_PI*4/4, 16, 10, 0.08, 4);
1409 FireLaser(e->x, e->y, e, (float)e->t / 25.0 + M_PI*6/4, 16, 10, 0.08, 4);
1410 if (e->enemy_type==10) e->fire_rate = 27;
1411 break;
1412
1413 case 8:
1414 EnemySound(8, PlayerDist(e->x, e->y));
1415 for (dp = 0; dp < 1; dp += 0.1) {
1416 CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y) + M_PI/2 + dp, 3 + dp/2);
1417 CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y), 4 + dp);
1418 CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y) - M_PI/2 - dp, 3 + dp/2);
1419 }
1420 CreateBullet(e->x, e->y, e, 6, (e->t / e->fire_rate)*0.7, 2);
1421 if (e->enemy_type==10) e->fire_rate = 8;
1422 break;
1423
1424 case 9:
1425 i = rand()%((rand()%(PlayerDist(e->x, e->y)+1))+1);
1426 if (i < 15) {
1427 EnemySound(9, PlayerDist(e->x, e->y));
1428 dpf = (float)(2000 - e->str) / 2500.0;
1429 for (dp = 0; dp < 1; dp += dpf) {
1430 (CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y) + 0.1 - dp/5.0, 3.5 + dp/3.0));
1431 CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y) + (2*M_PI / 3) + 0.1 - dp/5.0, 3.5 + dp/3.0);
1432 CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y) + (4*M_PI / 3) + 0.1 - dp/5.0, 3.5 + dp/3.0);
1433
1434 CreateBullet(e->x, e->y, e, 4, PlayerDir(e->x, e->y) + 0.1 - dp/5.0, 7 + dp*5);
1435 CreateBullet(e->x, e->y, e, 4, PlayerDir(e->x, e->y) + (2*M_PI / 3) + 0.1 - dp/5.0, 7 + dp*5);
1436 CreateBullet(e->x, e->y, e, 4, PlayerDir(e->x, e->y) + (4*M_PI / 3) + 0.1 - dp/5.0, 7 + dp*5);
1437 }
1438 }
1439 if (e->enemy_type==10) e->fire_rate = 21;
1440 break;
1441
1442 default:
1443 break;
1444 }
1445 }
1446 }
1447
1448 if ((e->t % e->speed) == 0) {
1449 if (player_room == e->room) {
1450 e->m_exit = NULL;
1451 if (e->t % (e->speed * (8 + rand()%6)) == 0) {
1452 e->move_dir = (float)(rand()%256) / 256.0 * M_PI * 2.0;
1453 }
1454 move_x = e->x + cos(e->move_dir)*5;
1455 move_y = e->y + sin(e->move_dir)*5;
1456
1457 EnemyMovement(e, move_x, move_y);
1458 } else {
1459 if (CanLeaveRoom(e->room)) {
1460 // Try to follow the player into the next room
1461
1462 // Are we already moving towards an exit?
1463
1464 if (e->m_exit != NULL) {
1465 rcon = e->m_exit;
1466
1467 door_x = (rcon->x + (rcon->x - rcon->x2))*32+16;
1468 door_y = (rcon->y + (rcon->y - rcon->y2))*32+16;
1469
1470 can_move = 1;
1471 } else {
1472 con_traverse = rooms[e->room].con;
1473 nearest = PlayerDist(e->x, e->y);
1474 rcon = NULL;
1475 while (con_traverse != NULL) {
1476 i = PlayerDist(con_traverse->x2 * 32 + 16, con_traverse->y2 * 32 + 16);
1477
1478 if ((i < nearest) && CanEnterRoom(GetRoom(con_traverse->x2, con_traverse->y2))) {
1479 nearest = i;
1480 rcon = con_traverse;
1481 }
1482 con_traverse = con_traverse->n;
1483 }
1484
1485 if (rcon != NULL) {
1486 door_x = (rcon->x + (rcon->x - rcon->x2))*32+16;
1487 door_y = (rcon->y + (rcon->y - rcon->y2))*32+16;
1488 e->m_exit = rcon;
1489 can_move = 1;
1490 }
1491 }
1492
1493 // So, can we move?
1494 if (can_move) {
1495 // Are we near the door?
1496 if (( abs(door_x - e->x) + abs(door_y - e->y))<6) {
1497 // Go through the door
1498 e->last_room = e->room;
1499 e->p_last_room = player_room;
1500 e->x = (rcon->x2 + (rcon->x2 - rcon->x))*32+16;
1501 e->y = (rcon->y2 + (rcon->y2 - rcon->y))*32+16;
1502 rooms[e->room].enemies--;
1503 e->room = (rcon->c);
1504 rooms[e->room].enemies++;
1505 e->curr_follow = -1;
1506
1507 e->m_exit = NULL;
1508
1509 } else {
1510 // Move towards the door
1511 e->move_dir = atan2(door_y - e->y, door_x - e->x);
1512 move_x = e->x + cos(e->move_dir)*5;
1513 move_y = e->y + sin(e->move_dir)*5;
1514
1515 EnemyMovement(e, move_x, move_y);
1516 }
1517 }
1518 }
1519 }
1520 }
1521 }
1522
1523 if (e->dying > 0) {
1524 e->dying++;
1525 if (e->dying == 3) {
1526 b = bullet_stack;
1527 while (b != NULL) {
1528 if (!b->delete_me) {
1529 if (b->firer == e) {
1530 b->delete_me = 1;
1531 CreateGem(b->x, b->y, b->room, (e->max_gems + e->min_gems) / 5 + (artifacts[2] * (e->max_gems + e->min_gems) / 4));
1532 }
1533 }
1534 b = b->next;
1535 }
1536 }
1537 if (e->dying >= 20) {
1538 if ((e->lives >= 4)&&training) {
1539 actual_lives = e->lives * 3 / 4;
1540 } else {
1541 actual_lives = e->lives;
1542 }
1543
1544 e->deaths++;
1545 if (e->deaths >= actual_lives) {
1546 e->deaths--;
1547 e->delete_me = 1;
1548 e->dying = 0;
1549 killed_enemies++;
1550 rooms[e->room].enemies--;
1551 n_gems = e->min_gems + rand()%(e->max_gems - e->min_gems + 1);
1552 for (i = 0; i < n_gems; i++) {
1553 CreateGem(e->x - 16 + rand()%32, e->y - 16 + rand()%32, e->room, 1+rand()%4 + (artifacts[2]*rand()%3));
1554 }
1555 if (rooms[e->room].room_type == 3) {
1556 ArtifactRoomUnlock(e->room);
1557 }
1558 } else {
1559 e->dying = 0;
1560 }
1561 }
1562 }
1563 }
1564
MoveBullet(struct bullet * e)1565 void MoveBullet(struct bullet *e)
1566 {
1567 int pdist;
1568 struct bullet *n;
1569 float fx, fy;
1570 static int last_shield_hit_sound = 0;
1571 int c_shield_hit_sound;
1572
1573 e->t++;
1574
1575 if ( (boss_fight_mode != 0) && (boss_fight_mode != 2) && (e->dying == 0) ) {
1576 e->dying = 1;
1577 }
1578
1579 if (e->dying == 0) {
1580 if (e->img == 7) {
1581 if (proxy_seek) {
1582 e->speed = 10;
1583 e->img = 4;
1584 e->dir = (e->dir + PlayerDir(e->x, e->y)) / 2;
1585 }
1586 }
1587
1588 e->x += cos(e->dir) * e->speed;
1589 e->y += sin(e->dir) * e->speed;
1590
1591 if (e->img == 1) {
1592 if (e->t % 20 == 19) {
1593 if (e->t % 40 >= 20)
1594 CreateBullet(e->x, e->y, e->firer, 3, e->dir + M_PI/2, e->speed * 0.75);
1595 else
1596 CreateBullet(e->x, e->y, e->firer, 3, e->dir - M_PI/2, e->speed * 0.75);
1597 }
1598 }
1599 if (e->img == 6) {
1600 if (e->t % 40 == 39) {
1601 (FireLaser(e->x, e->y, e->firer, (float)e->t / 30.0, 20, 10, 0.05, 2))->parent = e;
1602 (FireLaser(e->x, e->y, e->firer, (float)e->t / 30.0 + M_PI*2/3, 20, 10, 0.05, 2))->parent = e;
1603 (FireLaser(e->x, e->y, e->firer, (float)e->t / 30.0 + M_PI*4/3, 20, 10, 0.05, 2))->parent = e;
1604 }
1605 }
1606
1607
1608 if (e->img == 5) {
1609 if (e->t < 100) {
1610 if (e->t % 20 == 9) {
1611 n = CreateBullet(e->x, e->y, e->firer, 5, e->dir + M_PI/4, e->speed);
1612 n->natural_dir = e->dir;
1613 n->t = e->t;
1614 e->natural_dir = e->dir;
1615
1616 e->dir -= M_PI / 4;
1617 }
1618 if (e->t % 20 == 19) {
1619 e->dir = e->natural_dir;
1620 }
1621 }
1622 if (e->t == 100) {
1623 e->dir = PlayerDir(e->x, e->y);
1624 e->speed *= 1.5;
1625 }
1626 }
1627
1628 if (IsSolid(Get(e->x/32, e->y/32))) {
1629 if (e->img == 3) {
1630 if (e->room == player_room) {
1631 e->dir = PlayerDir(e->x, e->y);
1632
1633 if (IsSolid(Get((e->x + cos(e->dir) * e->speed * 1.5)/32, (e->y + sin(e->dir) * e->speed * 1.5)/32))) e->dying = 1;
1634
1635 } else {
1636 e->dying = 1;
1637 }
1638 } else {
1639 e->dying = 1;
1640 }
1641 }
1642
1643 if (e->img == 2) {
1644 if (e->parent != NULL) {
1645 e->x = e->parent->x;
1646 e->y = e->parent->y;
1647 } else {
1648 if (e->firer != NULL) {
1649 e->x = e->firer->x;
1650 e->y = e->firer->y;
1651 }
1652 }
1653 if (e->dying == 0) {
1654 if ((e->t > e->fire_time)&&(e->t <= (e->fire_time + e->duration))) {
1655 fx = e->x;
1656 fy = e->y;
1657 while (!IsSolid(Get((fx)/32, (fy)/32))) {
1658 if (player_dying == 0) {
1659 if (PlayerDist(fx, fy) < 30) {
1660 // hits player shield
1661 if ((player_shield > 0)&&(shield_hp > 0)) {
1662 shield_hp -= e->shield_damage;
1663 if (shield_hp >= 0) {
1664 e->dying = 1;
1665 break;
1666 } else {
1667 shield_hp = 0;
1668 }
1669 }
1670
1671 if (PlayerDist(fx, fy) < 4 - (2 * artifacts[5])) {
1672 player_dying = 1;
1673 SND_Pos("/usr/local/share/meritous/a/playerhurt.wav", 128, 0);
1674 e->dying = 1;
1675 break;
1676 }
1677 }
1678 }
1679 fx += cos(e->dir)*2;
1680 fy += sin(e->dir)*2;
1681 }
1682 }
1683 if (e->turn > 10) {
1684 if (e->dir > PlayerDir(e->x, e->y)) {
1685 e->dir -= (e->dir - PlayerDir(e->x, e->y)) / (e->turn - 9.00);
1686 e->dir -= (e->dir - PlayerDir(e->x, e->y)) / (e->turn - 9.00);
1687 } else {
1688 e->dir += (PlayerDir(e->x, e->y) - e->dir) / (e->turn - 9.00);
1689 }
1690 } else {
1691 e->dir += e->turn;
1692 }
1693 if (e->t > (e->fire_time + e->duration)) {
1694 e->dying = 1;
1695 }
1696 }
1697 } else {
1698
1699 pdist = PlayerDist(e->x, e->y);
1700
1701 if (pdist < 30) {
1702 if (player_dying == 0) {
1703 if (player_shield > 0) {
1704 if (shield_hp > 0) {
1705 shield_hp--;
1706 if (e->img == 4) {
1707 e->dying = 1;
1708 } else {
1709 e->dir += M_PI;
1710 c_shield_hit_sound = SDL_GetTicks();
1711
1712 if ((c_shield_hit_sound - 150) > last_shield_hit_sound) {
1713 SND_Pos("/usr/local/share/meritous/a/shieldhit.wav", 50, 0);
1714 last_shield_hit_sound = c_shield_hit_sound;
1715 }
1716 while (PlayerDist(e->x, e->y) < 30) {
1717 e->x += cos(e->dir) * e->speed;
1718 e->y += sin(e->dir) * e->speed;
1719 }
1720 }
1721 }
1722 }
1723 }
1724 }
1725 if (e->dying == 0) {
1726 if (pdist < 6 - (2 * artifacts[5])) {
1727 if (player_dying == 0) {
1728 SND_Pos("/usr/local/share/meritous/a/playerhurt.wav", 128, 0);
1729 player_dying = 1;
1730 }
1731 }
1732 }
1733 }
1734 }
1735
1736 if ((e->dying == 1) && (e->img == 8)) {
1737 SpawnLaser(e->x - cos(e->dir) * e->speed, e->y - sin(e->dir) * e->speed, PlayerDir(e->x, e->y), 10, 10, 0.0, player_shield / 6);
1738 }
1739
1740 if (GetRoom((e->x)/32, (e->y)/32) != e->room) {
1741 e->delete_me = 1;
1742 }
1743
1744 if (e->dying > 0) {
1745 e->dying++;
1746
1747 if (e->dying >= 10) {
1748 e->delete_me = 1;
1749 e->dying = 0;
1750 }
1751 }
1752 }
1753
DrawEnemy(struct enemy * e,SDL_Surface * scr)1754 void DrawEnemy(struct enemy *e, SDL_Surface *scr)
1755 {
1756 SDL_Rect draw_pos;
1757 SDL_Rect surf_pos;
1758 static SDL_Surface *teleflash = NULL;
1759
1760 if (e->delete_me) return;
1761 draw_pos.x = e->x - e->image->h/2/e->lives - scroll_x;
1762 draw_pos.y = e->y - e->image->h/2/e->lives - scroll_y;
1763
1764 surf_pos.x = e->blit_pos;
1765 surf_pos.y = e->image->h/e->lives*e->deaths;
1766 surf_pos.w = e->image->h/e->lives;
1767 surf_pos.h = e->image->h/e->lives;
1768
1769 if (e->teleport_v < 8) {
1770
1771 if (e->dying == 0) {
1772 SDL_BlitSurface(e->image, &surf_pos, scr, &draw_pos);
1773 } else {
1774 if ((e->deaths+1) >= e->lives) {
1775 surf_pos.w = e->image->h/e->lives * (20 - e->dying) / 20;
1776 surf_pos.h = surf_pos.w;
1777 surf_pos.x += (e->image->h/e->lives - surf_pos.w)/2;
1778 surf_pos.y += (e->image->h/e->lives - surf_pos.w)/2;
1779 draw_pos.x += (e->image->h/e->lives - surf_pos.w)/2;
1780 draw_pos.y += (e->image->h/e->lives - surf_pos.w)/2;
1781 } else {
1782 surf_pos.w = e->image->h/e->lives * (20 - e->dying/2) / 20;
1783 surf_pos.h = surf_pos.w;
1784 surf_pos.x += (e->image->h/e->lives - surf_pos.w)/2;
1785 surf_pos.y += (e->image->h/e->lives - surf_pos.w)/2;
1786 draw_pos.x += (e->image->h/e->lives - surf_pos.w)/2;
1787 draw_pos.y += (e->image->h/e->lives - surf_pos.w)/2;
1788 }
1789 SDL_BlitSurface(e->image, &surf_pos, scr, &draw_pos);
1790 }
1791
1792 if (((e->t % 8) == 1) && (!game_paused)) {
1793 e->blit_pos = (e->blit_pos + e->image->h/e->lives) % e->image->w;
1794 }
1795
1796 draw_pos.x = e->x - e->image->h/e->lives/2 - scroll_x;
1797 draw_pos.y = e->y - e->image->h/e->lives/2 - scroll_y;
1798
1799 draw_pos.x -= (128-e->image->h/e->lives)/2;
1800 draw_pos.y -= (128-e->image->h/e->lives)/2;
1801
1802 if (magic_circuit >= e->str) {
1803 SDL_BlitSurface(reticle, NULL, scr, &draw_pos);
1804 }
1805
1806 draw_pos.x = e->x - e->image->h/e->lives/2 - scroll_x;
1807 draw_pos.y = e->y - e->image->h/e->lives/2 - scroll_y;
1808
1809 draw_pos.x -= (128-e->image->h/e->lives)/2;
1810 draw_pos.y -= (128-e->image->h/e->lives)/2;
1811
1812 if (sqrt(sqr(e->x - player_x) + sqr(e->y - player_y)) < circuit_range) {
1813 SDL_BlitSurface(inrange, NULL, scr, &draw_pos);
1814 }
1815 }
1816
1817 if (e->teleport_v < 24) {
1818 if (teleflash == NULL) {
1819 teleflash = IMG_Load("/usr/local/share/meritous/i/teleflash.png");
1820 SDL_SetColorKey(teleflash, SDL_SRCCOLORKEY | SDL_RLEACCEL, 0);
1821 }
1822
1823 surf_pos.x = 48*((e->teleport_v) / 3);
1824 surf_pos.y = 0;
1825 surf_pos.w = 48;
1826 surf_pos.h = 48;
1827
1828 draw_pos.x = e->x - 24 - scroll_x;
1829 draw_pos.y = e->y - 24 - scroll_y;
1830 SDL_BlitSurface(teleflash, &surf_pos, scr, &draw_pos);
1831 }
1832 }
1833
DrawBullet(struct bullet * b)1834 void DrawBullet(struct bullet *b)
1835 {
1836 int i;
1837 int x1, y1, x2, y2, xo1, yo1;
1838 int z;
1839 float fx, fy;
1840 static SDL_Surface *d_star_small = NULL, *d_star_big = NULL, *d_star_ls = NULL;
1841 SDL_Rect draw_pos, surf_pos;
1842 if (b->delete_me) return;
1843 if (b->img == 0) {
1844 if (b->dying > 0) {
1845 DrawCircle(b->x - scroll_x, b->y - scroll_y, 6+(b->dying / 2), b->dying*10);
1846 DrawCircle(b->x - scroll_x, b->y - scroll_y, 3+(b->dying / 2), 255-b->dying*10);
1847 } else {
1848 if ((b->t % 8) < 4) {
1849 DrawCircle(b->x - scroll_x, b->y - scroll_y, 6, 0);
1850 DrawCircle(b->x - scroll_x, b->y - scroll_y, 4, 255);
1851 } else {
1852 DrawCircle(b->x - scroll_x, b->y - scroll_y, 6, 255);
1853 DrawCircle(b->x - scroll_x, b->y - scroll_y, 4, 0);
1854 }
1855 }
1856 }
1857 if (b->img == 1) {
1858 if (d_star_big == NULL) {
1859 d_star_big = IMG_Load("/usr/local/share/meritous/i/star1.png");
1860 SDL_SetColorKey(d_star_big, SDL_SRCCOLORKEY | SDL_RLEACCEL, 255);
1861 }
1862
1863 if (b->dying == 0) {
1864 surf_pos.x = b->x - 16 - scroll_x;
1865 surf_pos.y = b->y - 16 - scroll_y;
1866 draw_pos.x = (b->t % 8)*32;
1867 draw_pos.y = 0;
1868 draw_pos.w = 32;
1869 draw_pos.h = 32;
1870 SDL_BlitSurface(d_star_big, &draw_pos, screen, &surf_pos);
1871 } else {
1872 DrawCircle(b->x - scroll_x, b->y - scroll_y, 4+(b->dying), b->dying*10);
1873 DrawCircle(b->x - scroll_x, b->y - scroll_y, 2+(b->dying), 255-b->dying*10);
1874 }
1875 }
1876 if (b->img == 2) {
1877 // IMMA CHARGIN MAH LAZER
1878 if (b->t <= b->fire_time) {
1879 z = (b->t * 150 / (b->fire_time+1)) + 80;
1880
1881 fx = b->x;
1882 fy = b->y;
1883 while (!IsSolid(Get((fx)/32, (fy)/32))) {
1884 DrawRect(fx-1-scroll_x, fy-1-scroll_y, 4, 4, z/2);
1885 fx += cos(b->dir)*2;
1886 fy += sin(b->dir)*2;
1887
1888 if ((player_shield > 0)&&(shield_hp > 0)&&(PlayerDist(fx, fy) < 30)) break;
1889 if (PlayerDist(fx, fy) < 4) break;
1890 }
1891 DrawCircle(b->x - scroll_x, b->y - scroll_y, 5, (z+255)/2.4);
1892 DrawCircle(fx-cos(b->dir)*2 - scroll_x, fy-sin(b->dir)*2 - scroll_y, 4, z/2);
1893
1894 fx = b->x;
1895 fy = b->y;
1896 while (!IsSolid(Get((fx)/32, (fy)/32))) {
1897 DrawRect(fx-scroll_x, fy-scroll_y, 2, 2, z);
1898 fx += cos(b->dir)*2;
1899 fy += sin(b->dir)*2;
1900
1901 if ((player_shield > 0)&&(shield_hp > 0)&&(PlayerDist(fx, fy) < 30)) break;
1902 if (PlayerDist(fx, fy) < 4) break;
1903 }
1904
1905 DrawCircle(b->x - scroll_x, b->y - scroll_y, 3, (z+255)/2);
1906 DrawCircle(fx-cos(b->dir)*2 - scroll_x, fy-sin(b->dir)*2 - scroll_y, 2, z);
1907 }
1908
1909 // SHOOP DA WHOOP
1910 if ((b->t > b->fire_time) && (b->t <= b->fire_time + b->duration)) {
1911 z = 255 - ((b->t - b->fire_time) * 200 / (b->duration+1));
1912
1913 fx = b->x;
1914 fy = b->y;
1915 while (!IsSolid(Get((fx)/32, (fy)/32))) {
1916 DrawRect(fx-3-scroll_x, fy-3-scroll_y, 8, 8, z*2/3);
1917 fx += cos(b->dir)*2;
1918 fy += sin(b->dir)*2;
1919
1920 if ((player_shield > 0)&&(shield_hp > 0)&&(PlayerDist(fx, fy) < 30)) break;
1921 if (PlayerDist(fx, fy) < 4) break;
1922 }
1923 DrawCircle(b->x - scroll_x, b->y - scroll_y, 9, (z+255)/2.4);
1924 DrawCircle(fx-cos(b->dir)*2 - scroll_x, fy-sin(b->dir)*2 - scroll_y, 8, z*2/3);
1925 fx = b->x;
1926 fy = b->y;
1927 while (!IsSolid(Get((fx)/32, (fy)/32))) {
1928 DrawRect(fx-2-scroll_x, fy-2-scroll_y, 6, 6, z);
1929 fx += cos(b->dir)*2;
1930 fy += sin(b->dir)*2;
1931
1932 x1 = fx + rand()%12 - rand()%12 - scroll_x;
1933 y1 = fy + rand()%12 - rand()%12 - scroll_y;
1934 DrawRect(x1, y1, 2, 2, rand()%(z+1));
1935
1936 if ((player_shield > 0)&&(shield_hp > 0)&&(PlayerDist(fx, fy) < 30)) break;
1937 if (PlayerDist(fx, fy) < 4) break;
1938 }
1939
1940 DrawCircle(b->x - scroll_x, b->y - scroll_y, 7, (z+255)/2);
1941 DrawCircle(fx-cos(b->dir)*2 - scroll_x, fy-sin(b->dir)*2 - scroll_y, 6, z);
1942 }
1943 }
1944 if (b->img == 3) {
1945 if (d_star_small == NULL) {
1946 d_star_small = IMG_Load("/usr/local/share/meritous/i/star2.png");
1947 SDL_SetColorKey(d_star_small, SDL_SRCCOLORKEY | SDL_RLEACCEL, 255);
1948 }
1949 if (b->dying == 0) {
1950 surf_pos.x = b->x - 8 - scroll_x;
1951 surf_pos.y = b->y - 8 - scroll_y;
1952 draw_pos.x = (b->t % 8)*16;
1953 draw_pos.y = 0;
1954 draw_pos.w = 16;
1955 draw_pos.h = 16;
1956 SDL_BlitSurface(d_star_small, &draw_pos, screen, &surf_pos);
1957 } else {
1958 DrawCircle(b->x - scroll_x, b->y - scroll_y, 4+(b->dying/2), b->dying*10);
1959 DrawCircle(b->x - scroll_x, b->y - scroll_y, 2+(b->dying/2), 255-b->dying*10);
1960 }
1961 }
1962 if (b->img == 4) {
1963 if (b->dying == 0) {
1964 x1 = b->x + cos(b->dir)*(2) - scroll_x;
1965 y1 = b->y + sin(b->dir)*(2) - scroll_y;
1966
1967 x2 = b->x - cos(b->dir)*(80) - scroll_x;
1968 y2 = b->y - sin(b->dir)*(80) - scroll_y;
1969 for (i = 0; i < 40; i++) {
1970 xo1 = (x2 - x1)*i/40 + x1;
1971 yo1 = (y2 - y1)*i/40 + y1;
1972
1973 z = (i/2);
1974 if (i > 10) z = (40 - i)/7;
1975
1976 DrawRect(xo1 - z - 2, yo1 - z - 2, z*2 + 4, z*2 + 4, 200);
1977 }
1978 for (i = 0; i < 40; i++) {
1979 xo1 = (x2 - x1)*i/40 + x1;
1980 yo1 = (y2 - y1)*i/40 + y1;
1981
1982 z = (i/2);
1983 if (i > 10) z = (40 - i)/7;
1984
1985 DrawRect(xo1 - z, yo1 - z, z*2, z*2, 255);
1986 }
1987 } else{
1988 DrawCircleEx(b->x - scroll_x, b->y - scroll_y, b->dying * 2 + 1, b->dying * 1.75 - 1, 230);
1989 DrawCircleEx(b->x - scroll_x, b->y - scroll_y, b->dying * 2, b->dying * 1.75, 255);
1990 }
1991 }
1992 if (b->img == 5) {
1993 if (b->dying > 0) {
1994 i = 4+(b->dying / 5);
1995 DrawRect(b->x - scroll_x - (i-1/2), b->y - scroll_y - (i-1/2), i, i, b->dying*10);
1996 i = 2+(b->dying / 5);
1997 DrawRect(b->x - scroll_x - (i-1/2), b->y - scroll_y - (i-1/2), i, i, 255-b->dying*10);
1998 } else {
1999 if ((b->t % 8) < 4) {
2000 DrawRect(b->x - scroll_x - 1, b->y - scroll_y - 1, 4, 4, 0);
2001 DrawRect(b->x - scroll_x, b->y - scroll_y, 2, 2, 255);
2002 } else {
2003 DrawRect(b->x - scroll_x - 1, b->y - scroll_y - 1, 4, 4, 255);
2004 DrawRect(b->x - scroll_x, b->y - scroll_y, 2, 2, 0);
2005 }
2006 }
2007 }
2008 if (b->img == 6) {
2009 if (d_star_ls == NULL) {
2010 d_star_ls = IMG_Load("/usr/local/share/meritous/i/star3.png");
2011 SDL_SetColorKey(d_star_ls, SDL_SRCCOLORKEY | SDL_RLEACCEL, 255);
2012 }
2013 if (b->dying == 0) {
2014 surf_pos.x = b->x - 16 - scroll_x;
2015 surf_pos.y = b->y - 16 - scroll_y;
2016 draw_pos.x = (b->t % 8)*32;
2017 draw_pos.y = 0;
2018 draw_pos.w = 32;
2019 draw_pos.h = 32;
2020 SDL_BlitSurface(d_star_ls, &draw_pos, screen, &surf_pos);
2021 } else {
2022 DrawCircle(b->x - scroll_x, b->y - scroll_y, 4+(b->dying), 255-b->dying*10);
2023 DrawCircle(b->x - scroll_x, b->y - scroll_y, 2+(b->dying), b->dying*10);
2024 }
2025 }
2026
2027 if (b->img == 7) {
2028 if ((b->t % 8) < 4) {
2029 DrawCircle(b->x - scroll_x, b->y - scroll_y, 8, 0);
2030 DrawCircle(b->x - scroll_x, b->y - scroll_y, 5, 255);
2031 } else {
2032 DrawCircle(b->x - scroll_x, b->y - scroll_y, 8, 255);
2033 DrawCircle(b->x - scroll_x, b->y - scroll_y, 5, 0);
2034 }
2035 }
2036 if (b->img == 8) {
2037 if (b->dying > 0) {
2038 DrawCircle(b->x - scroll_x, b->y - scroll_y, 12+(b->dying), b->dying*10);
2039 DrawCircle(b->x - scroll_x, b->y - scroll_y, 6+(b->dying), 255-b->dying*10);
2040 } else {
2041 if ((b->t % 6) < 3) {
2042 DrawCircle(b->x - scroll_x, b->y - scroll_y, 12, 0);
2043 DrawCircle(b->x - scroll_x, b->y - scroll_y, 8, 255);
2044 } else {
2045 DrawCircle(b->x - scroll_x, b->y - scroll_y, 12, 255);
2046 DrawCircle(b->x - scroll_x, b->y - scroll_y, 8, 0);
2047 }
2048 }
2049 }
2050 }
2051
DrawGem(struct diamond * g)2052 void DrawGem(struct diamond *g)
2053 {
2054 static SDL_Surface *d_sprite = NULL;
2055 int gemtype = 0;
2056 static char hp_icon[2];
2057 SDL_Rect draw_pos;
2058 SDL_Rect surf_pos;
2059 unsigned char fxp = (SDL_GetTicks() / 300)%2 ? 255 : 0;
2060
2061 if (g->delete_me) return;
2062
2063 if (d_sprite == NULL) {
2064 d_sprite = IMG_Load("/usr/local/share/meritous/i/gem.png");
2065 SDL_SetColorKey(d_sprite, SDL_SRCCOLORKEY | SDL_RLEACCEL, 255);
2066 hp_icon[0] = 3;
2067 hp_icon[1] = 0;
2068 }
2069
2070 if (g->value == 1) gemtype = 2;
2071 if ((g->value > 1)&&(g->value < 5)) gemtype = 1;
2072 if (g->value >= 5) gemtype = 0;
2073
2074 if (g->value != 31337) {
2075
2076 surf_pos.x = g->x - 4 - scroll_x;
2077 surf_pos.y = g->y - 4 - scroll_y;
2078 draw_pos.x = (g->t % 4) * 8 + 32 * gemtype;
2079 draw_pos.y = 0;
2080 draw_pos.w = 8;
2081 draw_pos.h = 8;
2082
2083 SDL_BlitSurface(d_sprite, &draw_pos, screen, &surf_pos);
2084 } else {
2085 DrawCircle(g->x - scroll_x, g->y - scroll_y, 6, (rand()%64) ^ fxp);
2086 draw_text(g->x - 4 - scroll_x, g->y - 4 - scroll_y, hp_icon, (200+rand()%56) ^ fxp);
2087 }
2088
2089 g->t++;
2090 }
2091
xprintf(char * s)2092 void xprintf(char *s)
2093 {
2094 printf(s);
2095 fflush(stdout);
2096 }
2097
DrawInvisible(int x,int y)2098 void DrawInvisible(int x, int y)
2099 {
2100 SDL_Rect dest;
2101 dest.x = x - scroll_x - 24;
2102 dest.y = y - scroll_y - 24;
2103 SDL_BlitSurface(invis_enemy, NULL, screen, &dest);
2104 }
2105
DrawEntities()2106 void DrawEntities()
2107 {
2108 struct enemy *t;
2109 struct bullet *b;
2110 struct diamond *g;
2111 struct enemyloc *els;
2112
2113 if ((rooms[player_room].room_type != 3)&&(rooms[player_room].room_type != 2)) {
2114 // Draw gems
2115
2116 g = room_gems[player_room];
2117 while (g != NULL) {
2118 if ((g->room == player_room)&&(g->delete_me == 0)&&(g->value != 31337)) {
2119 DrawGem(g);
2120 }
2121 g = g->next_in_room;
2122 }
2123 g = room_gems[player_room];
2124 while (g != NULL) {
2125 if ((g->room == player_room)&&(g->delete_me == 0)&&(g->value == 31337)) {
2126 DrawGem(g);
2127 }
2128 g = g->next_in_room;
2129 }
2130 }
2131
2132 t = active_stack;
2133 while (t != NULL) {
2134 if (!t->delete_me) {
2135 if ((t->room == player_room) && (t->enemy_type != 9)) {
2136 DrawEnemy(t, screen);
2137 }
2138 }
2139 t = t->next_active;
2140 }
2141
2142 // Draw invisible enemies (if possible)
2143 if (artifacts[6]) {
2144 // Draw the actives
2145 t = active_stack;
2146 while (t != NULL) {
2147 if (!t->delete_me)
2148 {
2149 if (((!t->delete_me)&&((t->room != player_room)||(t->enemy_type == 9)))) {
2150 DrawInvisible(t->x, t->y);
2151 }
2152 }
2153 t = t->next_active;
2154 }
2155 // Draw the inactives
2156 if (!artifacts[11]) {
2157 els = GetEnemyLoc(scroll_x, scroll_y);
2158 while (els != NULL) {
2159 t = els->e;
2160 if (((!t->delete_me)&&((t->room != player_room)||(t->enemy_type == 9)))&&(t->active == 0)) {
2161 if ((t->x+24 >= scroll_x) && (t->y+24 >= scroll_y)) {
2162 if (t->x-24 <= (scroll_x+639)) {
2163 if (t->y-24 <= (scroll_y+479)) {
2164 if ((rooms[t->room].room_type != 2) && (rooms[t->room].room_type != 3)) {
2165 DrawInvisible(t->x, t->y);
2166 }
2167 }
2168 }
2169 }
2170 }
2171 els = els->n;
2172 }
2173 }
2174 }
2175
2176 b = bullet_stack;
2177 while (b != NULL) {
2178 if (!b->delete_me) {
2179 if (b->room == player_room) {
2180 DrawBullet(b);
2181 }
2182 }
2183 b = b->next;
2184 }
2185 }
2186
MoveEntities()2187 void MoveEntities()
2188 {
2189 struct enemy *t;
2190 struct bullet *b;
2191 struct diamond *g;
2192
2193 struct bullet *b_del;
2194 struct diamond *g_del;
2195
2196 if ((rooms[player_room].room_type != 3)&&(rooms[player_room].room_type != 2)) {
2197 // gem stuff
2198 g = room_gems[player_room];
2199 while (g != NULL) {
2200 if ((g->room == player_room)&&(g->delete_me == 0)) {
2201 if (artifacts[7]) {
2202 g->x += (player_x+4 - g->x)/10;
2203 g->y += (player_y+12 - g->y)/10;
2204 }
2205 if (PlayerDist(g->x, g->y) < 20) {
2206 g->delete_me = 1;
2207 total_gems--;
2208
2209 if (g->value == 31337) {
2210 if (player_hp < (3 + (player_shield == 30)*3)) {
2211 SND_Pos("/usr/local/share/meritous/a/crystal.wav", 64, 0);
2212 player_hp++;
2213 } else {
2214 if (!training) {
2215 SND_Pos("/usr/local/share/meritous/a/tone.wav", 64, 0);
2216
2217 if (player_lives == 1) {
2218 player_lives_part += 15;
2219 } else {
2220 if (player_lives < 10) {
2221 player_lives_part += 4;
2222 } else {
2223 player_lives_part += 1;
2224 }
2225 }
2226 if (player_lives_part >= 88) {
2227 player_lives_part -= 88;
2228 player_lives += 1;
2229 SND_Pos("/usr/local/share/meritous/a/crystal2.wav", 100, 0);
2230 }
2231 }
2232 }
2233
2234 } else {
2235 player_gems += g->value;
2236 }
2237 }
2238 }
2239 g = g->next_in_room;
2240 }
2241 }
2242
2243 t = active_stack;
2244 while (t != NULL) {
2245 if (!t->delete_me) {
2246 if ((rooms[t->room].room_type != 3) || (t->room == player_room))
2247 MoveEnemy(t);
2248 }
2249 t = t->next_active;
2250 }
2251
2252 b = bullet_stack;
2253 while (b != NULL) {
2254 if (!b->delete_me) {
2255 MoveBullet(b);
2256 }
2257 b = b->next;
2258 }
2259
2260 // delete old bullets
2261 b = bullet_stack;
2262 if ((b != NULL)&&(b->delete_me)) {
2263 b_del = b;
2264 b = b->next;
2265 free(b_del);
2266 bullet_stack = b;
2267 }
2268 while (b != NULL) {
2269 if (b->next != NULL) {
2270 if (b->next->delete_me) {
2271 b_del = b->next;
2272
2273 b->next = b->next->next;
2274 free(b_del);
2275 }
2276 }
2277 b = b->next;
2278 }
2279
2280 // delete old gems
2281 g = gem_stack;
2282 if ((g != NULL)&&(g->delete_me)) {
2283 // Remove room reference
2284
2285 if (g == room_gems[g->room]) {
2286 room_gems[g->room] = g->next_in_room;
2287 if (room_gems[g->room] != NULL) {
2288 room_gems[g->room]->prv_in_room = NULL;
2289 }
2290 } else {
2291 if (g->prv_in_room != NULL) {
2292 g->prv_in_room->next_in_room = g->next_in_room;
2293 }
2294
2295 if (g->next_in_room != NULL) {
2296 g->next_in_room->prv_in_room = g->prv_in_room;
2297 }
2298 }
2299
2300 g_del = g;
2301 g = g->next;
2302 free(g_del);
2303 gem_stack = g;
2304 }
2305 while (g != NULL) {
2306 if (g->next != NULL) {
2307 if (g->next->delete_me) {
2308 // Remove room reference
2309 assert( (g->next->prv_in_room != NULL) || (room_gems[g->next->room] == g->next) );
2310
2311 if (g->next == room_gems[g->next->room]) {
2312 room_gems[g->next->room] = g->next->next_in_room;
2313 if (room_gems[g->next->room] != NULL) {
2314 room_gems[g->next->room]->prv_in_room = NULL;
2315 }
2316 } else {
2317 g->next->prv_in_room->next_in_room = g->next->next_in_room;
2318 if (g->next->next_in_room != NULL) {
2319 g->next->next_in_room->prv_in_room = g->next->prv_in_room;
2320 }
2321 }
2322 g_del = g->next;
2323
2324 g->next = g->next->next;
2325 free(g_del);
2326 }
2327 }
2328 g = g->next;
2329 }
2330
2331 // delete old monsters
2332 t = active_stack;
2333 if (t != NULL) {
2334 while (t->delete_me) {
2335 t = t->next_active;
2336 active_stack = t;
2337
2338 if (t == NULL) break;
2339 }
2340 }
2341 while (t != NULL) {
2342 if (t == active_stack)
2343 assert(t->delete_me == 0);
2344 else
2345 assert(!t->delete_me);
2346
2347 if (t->next_active != NULL) {
2348 while (t->next_active->delete_me) {
2349 t->next_active = t->next_active->next_active;
2350 if (t->next_active == NULL) break;
2351 }
2352 }
2353 t = t->next_active;
2354 }
2355 }
2356
HurtEnemies(int x,int y,int range,int power)2357 void HurtEnemies(int x, int y, int range, int power)
2358 {
2359 struct enemy *t;
2360 int e_range;
2361
2362 t = active_stack;
2363 while (t != NULL) {
2364 e_range = sqrt(sqr(t->x - x) + sqr(t->y - y));
2365 if (e_range < range) {
2366 if (power >= t->str) {
2367 if (t->room == GetRoom(x/32, y/32)) {
2368 KillEnemy(t);
2369 }
2370 }
2371 }
2372 t = t->next_active;
2373 }
2374 }
2375
CircuitBullets(int x,int y,int r)2376 void CircuitBullets(int x, int y, int r)
2377 {
2378 struct bullet *b;
2379 b = bullet_stack;
2380 while (b != NULL) {
2381 if (!b->delete_me) {
2382 if (b->dying == 0) {
2383 if (b->invuln == 0) {
2384 if (sqrt(sqr(b->x - x) + sqr(b->y - y)) < r) {
2385 b->dying = 1;
2386 }
2387 }
2388 }
2389 }
2390 b = b->next;
2391 }
2392 }
2393
CrystalSummon()2394 void CrystalSummon()
2395 {
2396 struct diamond *g;
2397 int rg_x, rg_y;
2398 int i;
2399
2400 g = gem_stack;
2401
2402 for (i = 0; i < 3000; i++) {
2403 room_gems[i] = NULL;
2404 }
2405
2406 while (g != NULL) {
2407 if (!g->delete_me) {
2408 if (rooms[g->room].room_type != 3) {
2409 g->room = player_room;
2410 rg_x = rooms[player_room].x * 32 + 32 + rand()%(rooms[player_room].w*32-64);
2411 rg_y = rooms[player_room].y * 32 + 32 + rand()%(rooms[player_room].h*32-64);
2412 if (player_room == 0) {
2413 rg_x = (rooms[player_room].x+5) * 32 + 32 + rand()%(8*32);
2414 rg_y = (rooms[player_room].y+5) * 32 + 32 + rand()%(5*32);
2415 }
2416 while (IsSolid(Get(rg_x/32, rg_y/32))) {
2417 rg_x = rooms[player_room].x * 32 + 32 + rand()%(rooms[player_room].w*32-64);
2418 rg_y = rooms[player_room].y * 32 + 32 + rand()%(rooms[player_room].h*32-64);
2419 if (player_room == 0) {
2420 rg_x = (rooms[player_room].x+5) * 32 + 32 + rand()%(8*32);
2421 rg_y = (rooms[player_room].y+5) * 32 + 32 + rand()%(5*32);
2422 }
2423 }
2424 g->x = rg_x;
2425 g->y = rg_y;
2426 }
2427 }
2428 g->next_in_room = room_gems[g->room];
2429 g->prv_in_room = NULL;
2430 if (room_gems[g->room] != NULL) {
2431 room_gems[g->room]->prv_in_room = g;
2432 }
2433 room_gems[g->room] = g;
2434
2435 g = g->next;
2436 }
2437 }
2438
ActivateRand()2439 void ActivateRand()
2440 {
2441 struct enemy *e;
2442 struct enemy *en[20000];
2443 int ent = 0;
2444
2445 e = enemy_stack;
2446
2447 while (e != NULL) {
2448 if (e->delete_me == 0) {
2449 if (e->active == 0) {
2450 en[ent++] = e;
2451 }
2452 }
2453 e = e->next;
2454 }
2455 if (ent > 0) {
2456 e = en[rand()%ent];
2457
2458 XActivateSingleEnemy(e);
2459 }
2460 }
2461
ClearBossBullets()2462 void ClearBossBullets()
2463 {
2464 struct bullet *b = bullet_stack;
2465 while (b != NULL) {
2466 if (!b->delete_me) {
2467 if (b->firer == NULL) {
2468 b->delete_me = 1;
2469 }
2470 }
2471 b = b->next;
2472 }
2473 }
2474
SpawnBullet(int x,int y,int bullet_type,float dir,float spd,int invuln)2475 void SpawnBullet(int x, int y, int bullet_type, float dir, float spd, int invuln)
2476 {
2477 struct bullet *b;
2478
2479 if ( (current_boss == 3) && (player_shield == 30) && (boss_fight_mode == 2) ) {
2480 spd *= 1.2;
2481 }
2482 b = CreateBullet(x, y, NULL, bullet_type, dir, spd);
2483 if (invuln) {
2484 b->invuln = 1;
2485 }
2486 }
SpawnLaser(int x,int y,float dir,int fire_time,int duration,float turn,int dmg)2487 void SpawnLaser(int x, int y, float dir, int fire_time, int duration, float turn, int dmg)
2488 {
2489 FireLaser(x, y, NULL, dir, fire_time, duration, turn, dmg);
2490 }
2491
CullEnemies(int nth)2492 void CullEnemies(int nth)
2493 {
2494 struct enemy *e;
2495 int i = 0;
2496
2497 e = enemy_stack;
2498
2499 while (e != NULL) {
2500 if (e->delete_me == 0) {
2501 if (rooms[e->room].room_type == 0) {
2502 if ( (i % nth) == (nth - 1)) {
2503 e->delete_me = 1;
2504 killed_enemies++;
2505 e->dying = 0;
2506 rooms[e->room].enemies--;
2507 }
2508 i++;
2509 }
2510 }
2511 e = e->next;
2512 }
2513 }
2514
SoupUpEnemies()2515 void SoupUpEnemies()
2516 {
2517 struct enemy *e;
2518 int str_limit;
2519 float str_multiplier;
2520 float fr_divider;
2521
2522 e = enemy_stack;
2523 str_limit = 1500;
2524 if (circuit_size > 1500) {
2525 str_limit = 1500;
2526 }
2527
2528 str_multiplier = 1.0 + (1.0/3.0)*(float)current_boss;
2529 fr_divider = 1.0 + (2.0/3.0)*(float)current_boss;
2530
2531 while (e != NULL) {
2532 if (e->delete_me == 0) {
2533 if (e->enemy_type != 10) {
2534 if (e->str < str_limit) {
2535 if ((e->str * 2) < str_limit) {
2536 e->str = e->str * str_multiplier;
2537 } else {
2538 e->str = str_limit;
2539 }
2540 }
2541 e->fire_rate = (int)((float)e->fire_rate / fr_divider) + 1;
2542 e->speed = (int)((float)e->speed / fr_divider) + 1;
2543 e->min_gems *= str_multiplier;
2544 e->max_gems *= str_multiplier;
2545 }
2546 }
2547 e = e->next;
2548 }
2549 }
2550
CurseSingleEnemy(struct enemy * e)2551 void CurseSingleEnemy(struct enemy *e)
2552 {
2553 static int ActiveRooms[3000];
2554 static int NActiveRooms = 0;
2555 int i;
2556 int rm;
2557
2558 if (NActiveRooms == 0) {
2559 for (i = 0; i < 3000; i++) {
2560 if ((rooms[i].room_type == 0) || (rooms[i].room_type == 4)) {
2561 ActiveRooms[NActiveRooms++] = i;
2562 }
2563 }
2564 }
2565
2566 rm = ActiveRooms[rand()%NActiveRooms];
2567 while ((rooms[rm].enemies > 3) || (rooms[rm].visited == 0)) {
2568 rm = ActiveRooms[rand()%NActiveRooms];
2569 }
2570
2571 e->x = rooms[rm].w * 16 + rooms[rm].x * 32;
2572 e->y = rooms[rm].h * 16 + rooms[rm].y * 32;
2573 rooms[e->room].enemies--;
2574 e->room = rm;
2575 rooms[e->room].enemies++;
2576
2577 e->image = enemy_sprites[9];
2578 e->lives = 8;
2579 e->str = 500;
2580 e->speed = 1;
2581 e->fire_rate = (rand()%4)+1;
2582 e->min_gems = 5000;
2583 e->max_gems = 6000;
2584 e->followdepth = 12;
2585 e->creationcost = 6;
2586 e->enemy_type = 10;
2587
2588 ActivateSingleEnemy(e);
2589 }
2590
CurseEnemies()2591 void CurseEnemies()
2592 {
2593 struct enemy *e;
2594 int i = 0;
2595
2596 e = enemy_stack;
2597
2598 while (e != NULL) {
2599 if (e->delete_me == 0) {
2600 if ( (i % 5) == (4)) {
2601 CurseSingleEnemy(e);
2602 } else {
2603 e->delete_me = 1;
2604 killed_enemies++;
2605
2606 e->dying = 0;
2607 rooms[e->room].enemies--;
2608 }
2609 i++;
2610 }
2611 e = e->next;
2612 }
2613 }
2614