// // demon.c // // Copyright 2007, 2008 Lancer-X/ASCEAI // // This file is part of Meritous. // // Meritous is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Meritous is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Meritous. If not, see . // #include #include #include #include #include #include #include "levelblit.h" #include "mapgen.h" #include "save.h" #include "audio.h" #include "boss.h" #include "tiles.h" SDL_Surface *reticle; SDL_Surface *inrange; SDL_Surface *invis_enemy; int searched[3000]; int searchdist[3000]; int csearch; int room_active[3000]; int fc_open = 0; int max_activate_dist = 0; // enemy int sqr(int x) { return x*x; } struct enemy { int x, y; int room; int lives; int deaths; int str; int curr_follow; int followdepth; int enemy_type; SDL_Surface *image; int blit_pos; int creationcost; int teleport_v; int speed; int t; int active; int fire_rate; int last_room; int p_last_room; float move_dir; int min_gems; int max_gems; struct enemy *next; struct enemy *next_active; int delete_me; int dying; struct RoomConnection *m_exit; }; // shot struct bullet { float x, y; struct enemy *firer; struct bullet *parent; int room; float speed; float dir; int img; // img: 0 = bullet // 1 = star // 2 = laser // 3 = ministar // 4 = rocket // 5 = replishot // 6 = laserstar // 7 = proxy // 8 = remote laser int t; int invuln; float natural_dir; int fire_time; int duration; float turn; int shield_damage; struct bullet *next; int dying; int delete_me; }; struct diamond { int x, y; int room; int t; struct diamond *next; struct diamond *next_in_room; struct diamond *prv_in_room; int value; int delete_me; }; struct enemyloc { struct enemy *e; struct enemyloc *n; }; int total_enemies = 0; int killed_enemies = 0; int total_bullets = 0; int active_enemies = 0; int total_gems = 0; struct enemy *enemy_stack = NULL; struct bullet *bullet_stack = NULL; struct enemy *active_stack = NULL; struct diamond *gem_stack = NULL; struct diamond *room_gems[3000] = {NULL}; struct enemyloc *enemy_loc_stack[20][20] = {{NULL}}; struct enemy *CreateEnemy(int enemy_x, int enemy_y, int enemy_room); struct enemy *CreateEnemyEx(int enemy_x, int enemy_y, int enemy_room, int enemy_type); void SCreateGem(int x, int y, int r, int v); void ActivateEnemies(int room); void SoupUpEnemies(); void SpawnLaser(int x, int y, float dir, int fire_time, int duration, float turn, int dmg); void DestroyThings() { struct enemy *ec, *ed; struct bullet *bc, *bd; struct diamond *dc, *dd; int i; ec = enemy_stack; bc = bullet_stack; dc = gem_stack; while (ec) { ed = ec; ec = ec->next; free(ed); } while (bc) { bd = bc; bc = bc->next; free(bd); } while (dc) { dd = dc; dc = dc->next; free(dd); } enemy_stack = NULL; bullet_stack = NULL; gem_stack = NULL; active_stack = NULL; for (i = 0; i < 3000; i++) { room_gems[i] = NULL; } } struct GRD_Box { int d[60][60]; }; int GetRoomDist(int room1, int room2); int FindRoomDist(int room1, int room2) { struct RoomConnection *follow; int mdist = 1000000; int cdist; if (room1 == room2) return 0; fc_open++; searched[room1] = csearch; follow = rooms[room1].con; while (follow != NULL) { if (searched[follow->c] != csearch) { cdist = GetRoomDist(follow->c, room2); if (cdist < mdist) { mdist = cdist; } } follow = follow->n; } fc_open--; return mdist; } int GetRoomDist(int room1, int room2) { int gx, gy, dx, dy; int temp; int ix, iy; static struct GRD_Box *g[50][50] = {{NULL}}; fc_open++; if (room2 < room1) { temp = room2; room2 = room1; room1 = temp; } gx = room1 / 60; dx = room1 % 60; gy = room2 / 60; dy = room2 % 60; if (g[gx][gy] == NULL) { g[gx][gy] = malloc(sizeof(struct GRD_Box)); for (iy = 0; iy < 60; iy++) { for (ix = 0; ix < 60; ix++) { g[gx][gy]->d[ix][iy] = -1; } } } if (g[gx][gy]->d[dx][dy] == -1) { g[gx][gy]->d[dx][dy] = FindRoomDist(room1, room2); } fc_open--; return g[gx][gy]->d[dx][dy]; } void AddEnemyLoc(struct enemy *e, int x, int y) { struct enemyloc *next; x+=1; y+=1; next = enemy_loc_stack[x][y]; enemy_loc_stack[x][y] = malloc(sizeof(struct enemyloc)); enemy_loc_stack[x][y]->n = next; enemy_loc_stack[x][y]->e = e; } struct enemyloc *GetEnemyLoc(int s_x, int s_y) { return enemy_loc_stack[s_x / 1100 + 1][s_y / 1100 + 1]; } void AddEnemyPos(struct enemy *e) { int x_loc, y_loc, ix, iy; x_loc = (e->x) / 1100; y_loc = (e->y) / 1100; AddEnemyLoc(e, x_loc, y_loc); ix = ((e->x - screen->w) / 1100); iy = ((e->y - screen->h) / 1100); if (x_loc != ix) { AddEnemyLoc(e, ix, y_loc); } if (y_loc != iy) { AddEnemyLoc(e, x_loc, iy); } if ((x_loc != ix) && (y_loc != iy)) { AddEnemyLoc(e, ix, iy); } } void WriteEnemyData() { struct enemy *ptr; int n = 0; int i = 0; ptr = enemy_stack; while (ptr != NULL) { if (!ptr->delete_me) n++; ptr = ptr->next; } FWInt(n); ptr = enemy_stack; while (ptr != NULL) { if (!ptr->delete_me) { FWInt(ptr->x); FWInt(ptr->y); FWInt(ptr->room); FWInt(ptr->enemy_type); i++; if (i % 100 == 99) { SavingScreen(2, (float)i / (float)n); } } ptr = ptr->next; } } void WriteGemData() { struct diamond *ptr; int n = 0; int i = 0; ptr = gem_stack; while (ptr != NULL) { if (!ptr->delete_me) n++; ptr = ptr->next; } FWInt(n); ptr = gem_stack; while (ptr != NULL) { if (!ptr->delete_me) { FWInt(ptr->x); FWInt(ptr->y); FWInt(ptr->room); FWInt(ptr->value); i++; if (i % 100 == 99) { SavingScreen(3, (float)i / (float)n); } } ptr = ptr->next; } } void WriteCreatureData() { FWInt(total_enemies); FWInt(killed_enemies); WriteEnemyData(); WriteGemData(); } void ReadEnemyData() { int i, n; int x, y, room, t; n = FRInt(); for (i = 0; i < n; i++) { x = FRInt(); y = FRInt(); room = FRInt(); t = FRInt(); CreateEnemyEx(x, y, room, t); total_enemies--; if (i % 100 == 99) { LoadingScreen(2, (float)i / (float)n); } } LoadingScreen(2, 1); } void ReadGemData() { int i, n; int x, y, room, value; n = FRInt(); for (i = 0; i < n; i++) { x = FRInt(); y = FRInt(); room = FRInt(); value = FRInt(); SCreateGem(x, y, room, value); if (i % 100 == 99) { LoadingScreen(3, (float)i / (float)n); } } LoadingScreen(3, 1); } void ActivateVisited() { int i; for (i = 0; i < 3000; i++) { if (rooms[i].visited) { ActivateEnemies(i); } if (i % 10 == 9) { LoadingScreen(4, (float)i / 3000.0); } } LoadingScreen(4, 1); } void ReadCreatureData() { total_enemies = FRInt(); killed_enemies = FRInt(); ReadEnemyData(); ReadGemData(); ActivateVisited(); } SDL_Surface *enemy_sprites[10]; struct enemy * AllocateEnemy() { return malloc(sizeof(struct enemy)); } struct bullet * AllocateBullet() { return malloc(sizeof(struct bullet)); } struct diamond * AllocateGem() { return malloc(sizeof(struct diamond)); } struct enemy *CreateEnemy(int enemy_x, int enemy_y, int enemy_room) { int enemy_type; enemy_type = rand() % (rooms[enemy_room].s_dist / 5 + 1); if (rooms[enemy_room].room_type == 5) enemy_type += rand()%3; if (enemy_type > 8) enemy_type = rand()%3+6; if (rooms[enemy_room].s_dist >= 15) { if (rand()%64 == 0) { enemy_type = 9; } } return CreateEnemyEx(enemy_x, enemy_y, enemy_room, enemy_type); } struct enemy *CreateEnemyEx(int enemy_x, int enemy_y, int enemy_room, int enemy_type) { struct enemy *new_enemy; new_enemy = AllocateEnemy(); new_enemy->x = enemy_x; new_enemy->y = enemy_y; new_enemy->room = enemy_room; rooms[enemy_room].enemies++; new_enemy->deaths = 0; new_enemy->t = rand() % 65536; new_enemy->active = 0; new_enemy->curr_follow = -1; new_enemy->teleport_v = 0; new_enemy->m_exit = NULL; new_enemy->dying = 0; new_enemy->delete_me = 0; new_enemy->last_room = -1; new_enemy->p_last_room = -1; new_enemy->enemy_type = enemy_type; new_enemy->followdepth = 4; switch (enemy_type) { case 0: new_enemy->image = enemy_sprites[0]; new_enemy->lives = 1; new_enemy->str = 20; new_enemy->speed = 3; new_enemy->fire_rate = 20; new_enemy->min_gems = 0; new_enemy->max_gems = 3; new_enemy->creationcost = 1; break; case 1: new_enemy->image = enemy_sprites[1]; new_enemy->lives = 1; new_enemy->str = 50; new_enemy->speed = 4; new_enemy->fire_rate = 25; new_enemy->min_gems = 2; new_enemy->max_gems = 6; new_enemy->creationcost = 1; break; case 2: new_enemy->image = enemy_sprites[2]; new_enemy->lives = 1; new_enemy->str = 180; new_enemy->speed = 5; new_enemy->fire_rate = 40; new_enemy->min_gems = 8; new_enemy->max_gems = 15; new_enemy->creationcost = 1; break; case 3: new_enemy->image = enemy_sprites[3]; new_enemy->lives = 2; new_enemy->str = 220; new_enemy->speed = 3; new_enemy->fire_rate = 24; new_enemy->min_gems = 12; new_enemy->max_gems = 20; new_enemy->creationcost = 1; break; case 4: new_enemy->image = enemy_sprites[4]; new_enemy->lives = 1; new_enemy->str = 360; new_enemy->speed = 3; new_enemy->fire_rate = 32; new_enemy->min_gems = 18; new_enemy->max_gems = 32; new_enemy->creationcost = 2; break; case 5: new_enemy->image = enemy_sprites[5]; new_enemy->lives = 1; new_enemy->str = 450; new_enemy->speed = 3; new_enemy->fire_rate = 2; new_enemy->min_gems = 32; new_enemy->max_gems = 64; new_enemy->creationcost = 2; break; case 6: new_enemy->image = enemy_sprites[6]; new_enemy->lives = 2; new_enemy->str = 450; new_enemy->speed = 4; new_enemy->fire_rate = 10; new_enemy->min_gems = 50; new_enemy->max_gems = 100; new_enemy->creationcost = 2; break; case 7: new_enemy->image = enemy_sprites[7]; new_enemy->lives = 1; new_enemy->str = 500; new_enemy->speed = 4; new_enemy->fire_rate = 27; new_enemy->min_gems = 80; new_enemy->max_gems = 160; new_enemy->creationcost = 3; break; case 8: new_enemy->image = enemy_sprites[8]; new_enemy->lives = 4; new_enemy->str = 500; new_enemy->speed = 2; new_enemy->fire_rate = 8; new_enemy->min_gems = 200; new_enemy->max_gems = 400; new_enemy->creationcost = 4; break; case 9: new_enemy->image = enemy_sprites[0]; new_enemy->lives = 1; new_enemy->str = rooms[enemy_room].s_dist * 20; new_enemy->speed = 3; new_enemy->fire_rate = 21; new_enemy->min_gems = 300; new_enemy->max_gems = 600; new_enemy->creationcost = 3; break; case 10: new_enemy->image = enemy_sprites[9]; new_enemy->lives = 8; new_enemy->str = 500; new_enemy->speed = 1; new_enemy->fire_rate = 4; new_enemy->min_gems = 5000; new_enemy->max_gems = 6000; new_enemy->followdepth = 8; new_enemy->creationcost = 6; break; } if (training) { new_enemy->str = new_enemy->str * 4 / 5; new_enemy->fire_rate += (new_enemy->fire_rate / 2); new_enemy->speed *= 2; } if (rooms[new_enemy->room].room_type == 5) { new_enemy->str = new_enemy->str * 3 / 2; if (new_enemy->str > 1500) new_enemy->str = 1500; new_enemy->fire_rate = new_enemy->fire_rate - 1; } new_enemy->blit_pos = (rand()%(new_enemy->image->w / (new_enemy->image->h/new_enemy->lives)))*(new_enemy->image->h/new_enemy->lives); new_enemy->next_active = NULL; new_enemy->next = enemy_stack; enemy_stack = new_enemy; AddEnemyPos(new_enemy); total_enemies++; return new_enemy; } void SCreateGem(int x, int y, int r, int v) { struct diamond *new_gem; if (TileData[Get(x / 32, y / 32)].Is_Solid) { return; } if (GetRoom(x / 32, y / 32) != r) { return; } if (v == 0) { return; } new_gem = AllocateGem(); new_gem->x = x; new_gem->y = y; new_gem->room = r; new_gem->delete_me = 0; new_gem->t = rand()%65536; new_gem->next = gem_stack; new_gem->next_in_room = room_gems[r]; if (room_gems[r] != NULL) { room_gems[r]->prv_in_room = new_gem; } new_gem->value = v; new_gem->prv_in_room = NULL; gem_stack = new_gem; room_gems[r] = new_gem; total_gems++; } void CreateGem(int x, int y, int r, int v) { if (v == 0) return; if ( (rand()%1000) < ((int)log(v)/4 + (player_hp == 1)*5 + 2) ) { SCreateGem(x, y, r, 31337); } else { SCreateGem(x, y, r, v); } } float PlayerDir(int x, int y) { float dy = player_y+12 - y; float dx = player_x+8 - x; return atan2(dy, dx); } int PlayerDist(int x, int y) { int d = sqrt(sqr(x-(player_x+8))+sqr(y-(player_y+12))); return d; } struct bullet *CreateBullet(int x, int y, struct enemy *firer, int bullet_type, float dir, float spd) { struct bullet *new_shot; new_shot = AllocateBullet(); new_shot->x = x; new_shot->y = y; new_shot->firer = firer; if (firer != NULL) { new_shot->room = firer->room; } else { new_shot->room = GetRoom(x / 32, y / 32); } new_shot->dying = 0; new_shot->delete_me = 0; new_shot->t = rand() % 65536; new_shot->dir = dir; new_shot->speed = spd; new_shot->invuln = 0; new_shot->parent = NULL; switch (bullet_type) { case 0: new_shot->img = 0; break; case 1: new_shot->img = 1; new_shot->invuln = 1; break; case 2: new_shot->img = 2; new_shot->invuln = 1; new_shot->t = 0; new_shot->fire_time = 30; new_shot->duration = 30; new_shot->turn = 0.0; new_shot->speed = 0.0; break; case 3: new_shot->img = 3; break; case 4: new_shot->img = 4; new_shot->invuln = 1; break; case 5: new_shot->img = 5; new_shot->t = 0; break; case 6: new_shot->img = 6; new_shot->invuln = 1; break; case 7: new_shot->img = 7; new_shot->invuln = 1; break; case 8: new_shot->img = 8; new_shot->invuln = 1; break; } if (training) { new_shot->speed *= 0.8; } new_shot->next = bullet_stack; bullet_stack = new_shot; total_bullets++; return new_shot; } struct bullet *FireLaser(int x, int y, struct enemy *firer, float dir, int fire_time, int duration, float turn, int dmg) { int f_total; struct bullet *b; b = CreateBullet(x, y, firer, 2, dir, 0); b->fire_time = fire_time; b->duration = duration; b->turn = turn; b->shield_damage = dmg; if (training) { f_total = b->fire_time + b->duration; if (b->duration > 1) { b->duration /= 2; b->fire_time = f_total - b->duration; } b->shield_damage = (b->shield_damage + 1) / 2; } return b; } void InitEnemySprites() { enemy_sprites[0] = IMG_Load("dat/i/mons1.png"); SDL_SetColorKey(enemy_sprites[0], SDL_SRCCOLORKEY | SDL_RLEACCEL, 255); enemy_sprites[1] = IMG_Load("dat/i/mons2.png"); SDL_SetColorKey(enemy_sprites[1], SDL_SRCCOLORKEY | SDL_RLEACCEL, 255); enemy_sprites[2] = IMG_Load("dat/i/mons3.png"); SDL_SetColorKey(enemy_sprites[2], SDL_SRCCOLORKEY | SDL_RLEACCEL, 255); enemy_sprites[3] = IMG_Load("dat/i/mons4.png"); SDL_SetColorKey(enemy_sprites[3], SDL_SRCCOLORKEY | SDL_RLEACCEL, 255); enemy_sprites[4] = IMG_Load("dat/i/mons5.png"); SDL_SetColorKey(enemy_sprites[4], SDL_SRCCOLORKEY | SDL_RLEACCEL, 255); enemy_sprites[5] = IMG_Load("dat/i/mons6.png"); SDL_SetColorKey(enemy_sprites[5], SDL_SRCCOLORKEY | SDL_RLEACCEL, 255); enemy_sprites[6] = IMG_Load("dat/i/mons7.png"); SDL_SetColorKey(enemy_sprites[6], SDL_SRCCOLORKEY | SDL_RLEACCEL, 255); enemy_sprites[7] = IMG_Load("dat/i/mons8.png"); SDL_SetColorKey(enemy_sprites[7], SDL_SRCCOLORKEY | SDL_RLEACCEL, 255); enemy_sprites[8] = IMG_Load("dat/i/mons9.png"); SDL_SetColorKey(enemy_sprites[8], SDL_SRCCOLORKEY | SDL_RLEACCEL, 255); enemy_sprites[9] = IMG_Load("dat/i/mons10.png"); SDL_SetColorKey(enemy_sprites[9], SDL_SRCCOLORKEY | SDL_RLEACCEL, 255); reticle = IMG_Load("dat/i/reticle.png"); SDL_SetColorKey(reticle, SDL_SRCCOLORKEY | SDL_RLEACCEL, 255); inrange = IMG_Load("dat/i/inrange.png"); SDL_SetColorKey(inrange, SDL_SRCCOLORKEY | SDL_RLEACCEL, 255); invis_enemy = IMG_Load("dat/i/hidden_monster.png"); SDL_SetColorKey(invis_enemy, SDL_SRCCOLORKEY | SDL_RLEACCEL, 255); } void ActivateSingleEnemy(struct enemy *t) { struct enemy *new_active; if (t->active) return; if (t->enemy_type != 10) { if (t->enemy_type == 9) { if (max_activate_dist < 10) return; } else { if (t->enemy_type > (max_activate_dist / 5 + 2)) return; } } new_active = t; new_active->next_active = active_stack; active_stack = new_active; active_enemies += 1; t->active = 1; } void XActivateSingleEnemy(struct enemy *t) { if (rooms[t->room].room_type == 2) return; if (rooms[t->room].room_type == 3) return; ActivateSingleEnemy(t); } void InitEnemies() { int c_room; int cr_w, cr_h, cr_x, cr_y; int room_size; int n_enemies; int i; int trying; int e_x, e_y; int nx, ny; max_activate_dist = 0; InitEnemySprites(); for (ny = 0; ny < 20; ny++) { for (nx = 0; nx < 20; nx++) { enemy_loc_stack[nx][ny] = NULL; } } total_enemies = 0; killed_enemies = 0; total_bullets = 0; active_enemies = 0; total_gems = 0; for (i = 0; i < 3000; i++) { room_active[i] = 0; } if (game_load) { ReadCreatureData(); if (current_boss > 0) SoupUpEnemies(); } else { for (c_room = 1; c_room < 3000; c_room++) { cr_x = rooms[c_room].x + 1; cr_y = rooms[c_room].y + 1; cr_w = rooms[c_room].w - 2; cr_h = rooms[c_room].h - 2; room_size = cr_w * cr_h; n_enemies = rand() % ((room_size / 4) + 1); if (rooms[c_room].room_type == 2) { n_enemies = 0; } if (rooms[c_room].room_type == 3) { n_enemies += (n_enemies + room_size) / 2; } if (rooms[c_room].room_type == 5) { n_enemies = 50; } while (n_enemies > 0) { trying = 1; while (trying) { e_x = cr_x * 32 + 32 + rand() % (cr_w * 32 - 64 + 1); e_y = cr_y * 32 + 32 + rand() % (cr_h * 32 - 64 + 1); if ((!IsSolid(Get( (e_x-16) /32, (e_y-16) /32)))&&(!IsSolid(Get( (e_x+16) /32, (e_y-16) /32)))) { if ((!IsSolid(Get( (e_x-16) /32, (e_y+16) /32)))&&(!IsSolid(Get( (e_x+16) /32, (e_y+16) /32)))) { n_enemies -= (CreateEnemy(e_x, e_y, c_room))->creationcost; trying = 0; } } } } if (c_room % 100 == 99) { LoadingScreen(2, (float)c_room / 3000.0); } } } } int EnemyMovement(struct enemy *e, int move_x, int move_y) { if (!IsSolid(Get( (move_x - 12)/32, (move_y - 12)/32))) { if (!IsSolid(Get( (move_x + 12)/32, (move_y - 12)/32))) { if (!IsSolid(Get( (move_x - 12)/32, (move_y + 12)/32))) { if (!IsSolid(Get( (move_x + 12)/32, (move_y + 12)/32))) { e->x = move_x; e->y = move_y; return 1; } } } } return 0; } // Only activate SOME enemies. A room can only be ZActivated once void ZActivateEnemies(int room) { struct enemy *t; struct RoomConnection *rc; if (room_active[room]) return; room_active[room] = 1; t = enemy_stack; while (t != NULL) { // 1/4 chance of activating each enemy if (rand()%4 == 0) { if (t->room == room) { if (t->active == 0) { XActivateSingleEnemy(t); } } } t = t->next; } // 1/3 chance of activating each adjacent room rc = rooms[room].con; while (rc != NULL) { if (rand()%3 == 0) { ZActivateEnemies(rc->c); } rc = rc->n; } } void ActivateEnemies(int room) { struct enemy *t; struct RoomConnection *rc; t = enemy_stack; if (rooms[room].s_dist > max_activate_dist) { max_activate_dist = rooms[room].s_dist; } while (t != NULL) { if (t->room == room) { if (t->active == 0) { ActivateSingleEnemy(t); if (rooms[room].room_type == 3) { t->teleport_v = (rand() % 1500) + 50; } } } t = t->next; } // 1/2 chance of activating each adjacent room rc = rooms[room].con; while (rc != NULL) { if (rand()%2 == 0) { if ((rooms[rc->c].room_type != 2) && (rooms[rc->c].room_type != 3)) { ZActivateEnemies(rc->c); } } rc = rc->n; } } int CanEnterRoom(int room) { if (room == 0) return 0; if (rooms[room].room_type == 2) return 0; if (rooms[room].room_type == 3) return 0; if (rooms[room].room_type == 5) return 0; if (rooms[room].room_type == 6) return 0; if (artifacts[11]) { if (rooms[room].enemies > 3) { return 0; } } return 1; } int CanLeaveRoom(int room) { if (room == 0) return 0; if (rooms[room].room_type == 2) return 0; if (rooms[room].room_type == 3) return 0; if (rooms[room].room_type == 5) return 0; if (rooms[room].room_type == 6) return 0; return 1; } int RecurseFind(struct enemy *e, int room, int depth) { struct RoomConnection *follow; int dpth; int mindpth = 1000000; follow = rooms[room].con; if (CanEnterRoom(room) == 0) return 0; if (room == player_room) return depth+1; if (searched[room] == csearch) { if (searchdist[room] < depth) return 0; } if (depth > e->followdepth) return 0; if ((e->last_room == room) && (e->p_last_room == player_room)) return 0; searched[room] = csearch; searchdist[room] = depth; while (follow != NULL) { if ((dpth = RecurseFind(e, follow->c, depth+1)) > 0) { if (dpth < mindpth) { mindpth = dpth; } } follow = follow->n; } if (mindpth != 1000000) { return mindpth; } return 0; } int FollowPlayer(struct enemy *e, struct RoomConnection **rcon) { struct RoomConnection *follow; int mindepth = 1000000; int newdepth; int mdist = 1000000; int ndist = 0; int rdepth[4000]; return 0; follow = rooms[e->room].con; while (follow != NULL) { if (follow->c == player_room) { if (CanEnterRoom(follow->c)) { *rcon = follow; e->curr_follow = (*rcon)->c; return 1; } } follow = follow->n; } // Recursively follow the player, to a certain depth follow = rooms[e->room].con; csearch = rand(); // Are we already following the player into a room? /*if (e->curr_follow != -1) { // See if this room is the best FIRST newdepth = RecurseFind(e, e->curr_follow, 0); if (newdepth > 0) { mindepth = newdepth; *rcon = follow; } }*/ while (follow != NULL) { if (CanEnterRoom(follow->c)) { newdepth = RecurseFind(e, follow->c, 0); rdepth[follow->c] = newdepth; if (newdepth > 0) { if (mindepth > newdepth) { mindepth = newdepth; *rcon = follow; } } } follow = follow->n; } if (mindepth != 1000000) { follow = rooms[e->room].con; while (follow != NULL) { if (CanEnterRoom(follow->c)) { newdepth = rdepth[follow->c]; if (newdepth == mindepth) { ndist = PlayerDist(follow->x*32+16, follow->y*32+16); if (ndist < mdist) { mdist = ndist; *rcon = follow; } } } follow = follow->n; } e->curr_follow = (*rcon)->c; return mindepth; } return 0; } void KillEnemy(struct enemy *t) { static int lastkill = 0; int ct; if (t->dying > 0) return; if (t->teleport_v > 0) return; if (t->delete_me) return; ct = SDL_GetTicks(); if ((ct - lastkill) > 100) { SND_Pos("dat/a/enemyhit.wav", 128, PlayerDist(t->x, t->y)); lastkill = ct; } t->dying = 1; } void ArtifactRoomUnlock(int room) { struct enemy *e; int x, y, rx, ry, rt; int placed; int tot_treasures; e = active_stack; while (e != NULL) { if ((e->delete_me == 0) && (e->room == room)) { return; } e = e->next_active; } // unlock doors for (y = 0; y < rooms[room].h; y++) { for (x = 0; x < rooms[room].w; x++) { rx = x + rooms[room].x; ry = y + rooms[room].y; rt = Get(rx, ry); if ((rt >= 21) && (rt <= 24)) { Put(rx, ry, rt - 21 + 13, room); } } } // place treasure placed = 0; tot_treasures = 2 + rand() % (rooms[room].s_dist / 8 + 1); while (placed < tot_treasures) { x = rooms[room].x + (rand() % (rooms[room].w - 2)); y = rooms[room].y + (rand() % (rooms[room].h - 2)); //printf("Attempting %d, %d\n", x, y); if ((x+y)%2 == (placed>0)) { //printf("Correct placement type\n"); if (!IsSolid(Get(x, y))) { //printf("Not solid\n"); Put(x, y, 26, room); placed++; } } fflush(stdout); } // sign room rooms[room].room_type = 4; } void EnemySound(int t, int dist) { static int last_e_sound = 0; static int last_delay = 150; int curr_e_sound = SDL_GetTicks(); if ((curr_e_sound - last_delay) < last_e_sound) { return; } switch (t) { case 0: SND_Pos("dat/a/mons0shot.wav", 48, dist); last_delay = 200; break; case 1: SND_Pos("dat/a/mons1shot.wav", 112, dist); last_delay = 500; break; case 2: SND_Pos("dat/a/mons2shot.wav", 110, dist); last_delay = 1000; break; case 3: SND_Pos("dat/a/mons3shot.wav", 110, dist); last_delay = 500; break; case 4: SND_Pos("dat/a/mons4shot.wav", 110, dist); last_delay = 900; break; case 5: SND_Pos("dat/a/mons5shot.wav", 80, dist); last_delay = 60; break; case 6: SND_Pos("dat/a/mons6shot.wav", 110, dist); last_delay = 1000; break; case 7: SND_Pos("dat/a/mons7shot.wav", 110, dist); last_delay = 600; break; case 8: SND_Pos("dat/a/mons8shot.wav", 110, dist); last_delay = 700; break; case 9: SND_Pos("dat/a/mons9shot.wav", 110, dist); last_delay = 242; break; case 10: SND_Pos("dat/a/mons10shot.wav", 110, dist); last_delay = 250; break; default: break; } last_e_sound = curr_e_sound; } void MoveEnemy(struct enemy *e) { int n_gems; int i; int move_x, move_y; int door_x=0, door_y=0; int enemy_fire_type; int actual_lives; int can_move = 0; struct RoomConnection *con_traverse; struct RoomConnection *rcon; int nearest; struct bullet *b; e->t++; float dp; float dpf; if (e->teleport_v > 0) { e->teleport_v--; return; } if (e->enemy_type < 10) { enemy_fire_type = e->enemy_type; } else { enemy_fire_type = rand()%10; } if (e->dying == 0) { if ((e->t % e->fire_rate) == 0) { if (e->room == player_room) { switch (enemy_fire_type) { case 0: EnemySound(0, PlayerDist(e->x, e->y)); CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y), 1.5); if (e->enemy_type==10) e->fire_rate = 20; break; case 1: EnemySound(1, PlayerDist(e->x, e->y)); CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y)+0.1, 2.1); CreateBullet(e->x, e->y, e, 3, PlayerDir(e->x, e->y), 2.4); CreateBullet(e->x, e->y, e, 3, PlayerDir(e->x, e->y)-0.1, 2.1); CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y), 1.7); if (e->enemy_type==10) e->fire_rate = 25; break; case 2: EnemySound(2, PlayerDist(e->x, e->y)); for (dp = 0; dp < M_PI*2; dp += 0.25) { CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y)+dp, 1.1); } dp = RandomDir(); for (i = 0; i < 20; i++) { CreateBullet(e->x, e->y, e, 0, dp, (float)i * 0.1 + 2.5); } if (e->enemy_type==10) e->fire_rate = 40; break; case 3: EnemySound(3, PlayerDist(e->x, e->y)); CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y), 2.5); CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y)+0.1, 2.5); CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y)+0.2, 2.5); CreateBullet(e->x, e->y, e, 1, PlayerDir(e->x, e->y), 1.5); CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y)-0.2, 2.2); CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y)-0.3, 2.2); if (e->enemy_type==10) e->fire_rate = 24; break; case 4: EnemySound(4, PlayerDist(e->x, e->y)); for (dp = 0; dp < M_PI * 0.66; dp += 0.2) { CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y)+0.5 - dp, 1.8+(dp/2)); CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y)-0.4 + dp, 1.8+(dp/2)); } FireLaser(e->x, e->y, e, PlayerDir(e->x, e->y), 24, 4, 20.0, 6); if (e->enemy_type==10) e->fire_rate = 32; break; case 5: EnemySound(5, PlayerDist(e->x, e->y)); CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y), 4); if (e->enemy_type==10) e->fire_rate = 2; break; case 6: EnemySound(6, PlayerDist(e->x, e->y)); CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y)+0.25, 6); CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y)+0.25, 4); CreateBullet(e->x, e->y, e, 5, PlayerDir(e->x, e->y) - 0.05, 4.99); CreateBullet(e->x, e->y, e, 5, PlayerDir(e->x, e->y), 4.99); CreateBullet(e->x, e->y, e, 5, PlayerDir(e->x, e->y) + 0.05, 4.99); CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y)-0.25, 5); CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y)-0.25, 3); if (e->enemy_type==10) e->fire_rate = 10; break; case 7: EnemySound(7, PlayerDist(e->x, e->y)); for (dp = 0; dp < M_PI * 0.66; dp += 0.1) { CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y)+0.5 - dp, 1.8+(dp/2)); CreateBullet(e->x, e->y, e, 3, PlayerDir(e->x, e->y)-0.4 + dp, 1.8+(dp/2)); CreateBullet(e->x, e->y, e, 3, PlayerDir(e->x, e->y)+0.5 - dp*2, 4+(dp*2)); CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y)-0.4 + dp*2, 4+(dp*2)); } FireLaser(e->x, e->y, e, (float)e->t / 25.0, 16, 10, 0.08, 4); FireLaser(e->x, e->y, e, (float)e->t / 25.0 + M_PI*2/4, 16, 10, 0.08, 4); FireLaser(e->x, e->y, e, (float)e->t / 25.0 + M_PI*4/4, 16, 10, 0.08, 4); FireLaser(e->x, e->y, e, (float)e->t / 25.0 + M_PI*6/4, 16, 10, 0.08, 4); if (e->enemy_type==10) e->fire_rate = 27; break; case 8: EnemySound(8, PlayerDist(e->x, e->y)); for (dp = 0; dp < 1; dp += 0.1) { CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y) + M_PI/2 + dp, 3 + dp/2); CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y), 4 + dp); CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y) - M_PI/2 - dp, 3 + dp/2); } CreateBullet(e->x, e->y, e, 6, (e->t / e->fire_rate)*0.7, 2); if (e->enemy_type==10) e->fire_rate = 8; break; case 9: i = rand()%((rand()%(PlayerDist(e->x, e->y)+1))+1); if (i < 15) { EnemySound(9, PlayerDist(e->x, e->y)); dpf = (float)(2000 - e->str) / 2500.0; for (dp = 0; dp < 1; dp += dpf) { (CreateBullet(e->x, e->y, e, 0, PlayerDir(e->x, e->y) + 0.1 - dp/5.0, 3.5 + dp/3.0)); 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); 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); CreateBullet(e->x, e->y, e, 4, PlayerDir(e->x, e->y) + 0.1 - dp/5.0, 7 + dp*5); CreateBullet(e->x, e->y, e, 4, PlayerDir(e->x, e->y) + (2*M_PI / 3) + 0.1 - dp/5.0, 7 + dp*5); CreateBullet(e->x, e->y, e, 4, PlayerDir(e->x, e->y) + (4*M_PI / 3) + 0.1 - dp/5.0, 7 + dp*5); } } if (e->enemy_type==10) e->fire_rate = 21; break; default: break; } } } if ((e->t % e->speed) == 0) { if (player_room == e->room) { e->m_exit = NULL; if (e->t % (e->speed * (8 + rand()%6)) == 0) { e->move_dir = (float)(rand()%256) / 256.0 * M_PI * 2.0; } move_x = e->x + cos(e->move_dir)*5; move_y = e->y + sin(e->move_dir)*5; EnemyMovement(e, move_x, move_y); } else { if (CanLeaveRoom(e->room)) { // Try to follow the player into the next room // Are we already moving towards an exit? if (e->m_exit != NULL) { rcon = e->m_exit; door_x = (rcon->x + (rcon->x - rcon->x2))*32+16; door_y = (rcon->y + (rcon->y - rcon->y2))*32+16; can_move = 1; } else { con_traverse = rooms[e->room].con; nearest = PlayerDist(e->x, e->y); rcon = NULL; while (con_traverse != NULL) { i = PlayerDist(con_traverse->x2 * 32 + 16, con_traverse->y2 * 32 + 16); if ((i < nearest) && CanEnterRoom(GetRoom(con_traverse->x2, con_traverse->y2))) { nearest = i; rcon = con_traverse; } con_traverse = con_traverse->n; } if (rcon != NULL) { door_x = (rcon->x + (rcon->x - rcon->x2))*32+16; door_y = (rcon->y + (rcon->y - rcon->y2))*32+16; e->m_exit = rcon; can_move = 1; } } // So, can we move? if (can_move) { // Are we near the door? if (( abs(door_x - e->x) + abs(door_y - e->y))<6) { // Go through the door e->last_room = e->room; e->p_last_room = player_room; e->x = (rcon->x2 + (rcon->x2 - rcon->x))*32+16; e->y = (rcon->y2 + (rcon->y2 - rcon->y))*32+16; rooms[e->room].enemies--; e->room = (rcon->c); rooms[e->room].enemies++; e->curr_follow = -1; e->m_exit = NULL; } else { // Move towards the door e->move_dir = atan2(door_y - e->y, door_x - e->x); move_x = e->x + cos(e->move_dir)*5; move_y = e->y + sin(e->move_dir)*5; EnemyMovement(e, move_x, move_y); } } } } } } if (e->dying > 0) { e->dying++; if (e->dying == 3) { b = bullet_stack; while (b != NULL) { if (!b->delete_me) { if (b->firer == e) { b->delete_me = 1; CreateGem(b->x, b->y, b->room, (e->max_gems + e->min_gems) / 5 + (artifacts[2] * (e->max_gems + e->min_gems) / 4)); } } b = b->next; } } if (e->dying >= 20) { if ((e->lives >= 4)&&training) { actual_lives = e->lives * 3 / 4; } else { actual_lives = e->lives; } e->deaths++; if (e->deaths >= actual_lives) { e->deaths--; e->delete_me = 1; e->dying = 0; killed_enemies++; rooms[e->room].enemies--; n_gems = e->min_gems + rand()%(e->max_gems - e->min_gems + 1); for (i = 0; i < n_gems; i++) { CreateGem(e->x - 16 + rand()%32, e->y - 16 + rand()%32, e->room, 1+rand()%4 + (artifacts[2]*rand()%3)); } if (rooms[e->room].room_type == 3) { ArtifactRoomUnlock(e->room); } } else { e->dying = 0; } } } } void MoveBullet(struct bullet *e) { int pdist; struct bullet *n; float fx, fy; static int last_shield_hit_sound = 0; int c_shield_hit_sound; e->t++; if ( (boss_fight_mode != 0) && (boss_fight_mode != 2) && (e->dying == 0) ) { e->dying = 1; } if (e->dying == 0) { if (e->img == 7) { if (proxy_seek) { e->speed = 10; e->img = 4; e->dir = (e->dir + PlayerDir(e->x, e->y)) / 2; } } e->x += cos(e->dir) * e->speed; e->y += sin(e->dir) * e->speed; if (e->img == 1) { if (e->t % 20 == 19) { if (e->t % 40 >= 20) CreateBullet(e->x, e->y, e->firer, 3, e->dir + M_PI/2, e->speed * 0.75); else CreateBullet(e->x, e->y, e->firer, 3, e->dir - M_PI/2, e->speed * 0.75); } } if (e->img == 6) { if (e->t % 40 == 39) { (FireLaser(e->x, e->y, e->firer, (float)e->t / 30.0, 20, 10, 0.05, 2))->parent = e; (FireLaser(e->x, e->y, e->firer, (float)e->t / 30.0 + M_PI*2/3, 20, 10, 0.05, 2))->parent = e; (FireLaser(e->x, e->y, e->firer, (float)e->t / 30.0 + M_PI*4/3, 20, 10, 0.05, 2))->parent = e; } } if (e->img == 5) { if (e->t < 100) { if (e->t % 20 == 9) { n = CreateBullet(e->x, e->y, e->firer, 5, e->dir + M_PI/4, e->speed); n->natural_dir = e->dir; n->t = e->t; e->natural_dir = e->dir; e->dir -= M_PI / 4; } if (e->t % 20 == 19) { e->dir = e->natural_dir; } } if (e->t == 100) { e->dir = PlayerDir(e->x, e->y); e->speed *= 1.5; } } if (IsSolid(Get(e->x/32, e->y/32))) { if (e->img == 3) { if (e->room == player_room) { e->dir = PlayerDir(e->x, e->y); 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; } else { e->dying = 1; } } else { e->dying = 1; } } if (e->img == 2) { if (e->parent != NULL) { e->x = e->parent->x; e->y = e->parent->y; } else { if (e->firer != NULL) { e->x = e->firer->x; e->y = e->firer->y; } } if (e->dying == 0) { if ((e->t > e->fire_time)&&(e->t <= (e->fire_time + e->duration))) { fx = e->x; fy = e->y; while (!IsSolid(Get((fx)/32, (fy)/32))) { if (player_dying == 0) { if (PlayerDist(fx, fy) < 30) { // hits player shield if ((player_shield > 0)&&(shield_hp > 0)) { shield_hp -= e->shield_damage; if (shield_hp >= 0) { e->dying = 1; break; } else { shield_hp = 0; } } if (PlayerDist(fx, fy) < 4 - (2 * artifacts[5])) { player_dying = 1; SND_Pos("dat/a/playerhurt.wav", 128, 0); e->dying = 1; break; } } } fx += cos(e->dir)*2; fy += sin(e->dir)*2; } } if (e->turn > 10) { if (e->dir > PlayerDir(e->x, e->y)) { e->dir -= (e->dir - PlayerDir(e->x, e->y)) / (e->turn - 9.00); e->dir -= (e->dir - PlayerDir(e->x, e->y)) / (e->turn - 9.00); } else { e->dir += (PlayerDir(e->x, e->y) - e->dir) / (e->turn - 9.00); } } else { e->dir += e->turn; } if (e->t > (e->fire_time + e->duration)) { e->dying = 1; } } } else { pdist = PlayerDist(e->x, e->y); if (pdist < 30) { if (player_dying == 0) { if (player_shield > 0) { if (shield_hp > 0) { shield_hp--; if (e->img == 4) { e->dying = 1; } else { e->dir += M_PI; c_shield_hit_sound = SDL_GetTicks(); if ((c_shield_hit_sound - 150) > last_shield_hit_sound) { SND_Pos("dat/a/shieldhit.wav", 50, 0); last_shield_hit_sound = c_shield_hit_sound; } while (PlayerDist(e->x, e->y) < 30) { e->x += cos(e->dir) * e->speed; e->y += sin(e->dir) * e->speed; } } } } } } if (e->dying == 0) { if (pdist < 6 - (2 * artifacts[5])) { if (player_dying == 0) { SND_Pos("dat/a/playerhurt.wav", 128, 0); player_dying = 1; } } } } } if ((e->dying == 1) && (e->img == 8)) { 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); } if (GetRoom((e->x)/32, (e->y)/32) != e->room) { e->delete_me = 1; } if (e->dying > 0) { e->dying++; if (e->dying >= 10) { e->delete_me = 1; e->dying = 0; } } } void DrawEnemy(struct enemy *e, SDL_Surface *scr) { SDL_Rect draw_pos; SDL_Rect surf_pos; static SDL_Surface *teleflash = NULL; if (e->delete_me) return; draw_pos.x = e->x - e->image->h/2/e->lives - scroll_x; draw_pos.y = e->y - e->image->h/2/e->lives - scroll_y; surf_pos.x = e->blit_pos; surf_pos.y = e->image->h/e->lives*e->deaths; surf_pos.w = e->image->h/e->lives; surf_pos.h = e->image->h/e->lives; if (e->teleport_v < 8) { if (e->dying == 0) { SDL_BlitSurface(e->image, &surf_pos, scr, &draw_pos); } else { if ((e->deaths+1) >= e->lives) { surf_pos.w = e->image->h/e->lives * (20 - e->dying) / 20; surf_pos.h = surf_pos.w; surf_pos.x += (e->image->h/e->lives - surf_pos.w)/2; surf_pos.y += (e->image->h/e->lives - surf_pos.w)/2; draw_pos.x += (e->image->h/e->lives - surf_pos.w)/2; draw_pos.y += (e->image->h/e->lives - surf_pos.w)/2; } else { surf_pos.w = e->image->h/e->lives * (20 - e->dying/2) / 20; surf_pos.h = surf_pos.w; surf_pos.x += (e->image->h/e->lives - surf_pos.w)/2; surf_pos.y += (e->image->h/e->lives - surf_pos.w)/2; draw_pos.x += (e->image->h/e->lives - surf_pos.w)/2; draw_pos.y += (e->image->h/e->lives - surf_pos.w)/2; } SDL_BlitSurface(e->image, &surf_pos, scr, &draw_pos); } if (((e->t % 8) == 1) && (!game_paused)) { e->blit_pos = (e->blit_pos + e->image->h/e->lives) % e->image->w; } draw_pos.x = e->x - e->image->h/e->lives/2 - scroll_x; draw_pos.y = e->y - e->image->h/e->lives/2 - scroll_y; draw_pos.x -= (128-e->image->h/e->lives)/2; draw_pos.y -= (128-e->image->h/e->lives)/2; if (magic_circuit >= e->str) { SDL_BlitSurface(reticle, NULL, scr, &draw_pos); } draw_pos.x = e->x - e->image->h/e->lives/2 - scroll_x; draw_pos.y = e->y - e->image->h/e->lives/2 - scroll_y; draw_pos.x -= (128-e->image->h/e->lives)/2; draw_pos.y -= (128-e->image->h/e->lives)/2; if (sqrt(sqr(e->x - player_x) + sqr(e->y - player_y)) < circuit_range) { SDL_BlitSurface(inrange, NULL, scr, &draw_pos); } } if (e->teleport_v < 24) { if (teleflash == NULL) { teleflash = IMG_Load("dat/i/teleflash.png"); SDL_SetColorKey(teleflash, SDL_SRCCOLORKEY | SDL_RLEACCEL, 0); } surf_pos.x = 48*((e->teleport_v) / 3); surf_pos.y = 0; surf_pos.w = 48; surf_pos.h = 48; draw_pos.x = e->x - 24 - scroll_x; draw_pos.y = e->y - 24 - scroll_y; SDL_BlitSurface(teleflash, &surf_pos, scr, &draw_pos); } } void DrawBullet(struct bullet *b) { int i; int x1, y1, x2, y2, xo1, yo1; int z; float fx, fy; static SDL_Surface *d_star_small = NULL, *d_star_big = NULL, *d_star_ls = NULL; SDL_Rect draw_pos, surf_pos; if (b->delete_me) return; if (b->img == 0) { if (b->dying > 0) { DrawCircle(b->x - scroll_x, b->y - scroll_y, 6+(b->dying / 2), b->dying*10); DrawCircle(b->x - scroll_x, b->y - scroll_y, 3+(b->dying / 2), 255-b->dying*10); } else { if ((b->t % 8) < 4) { DrawCircle(b->x - scroll_x, b->y - scroll_y, 6, 0); DrawCircle(b->x - scroll_x, b->y - scroll_y, 4, 255); } else { DrawCircle(b->x - scroll_x, b->y - scroll_y, 6, 255); DrawCircle(b->x - scroll_x, b->y - scroll_y, 4, 0); } } } if (b->img == 1) { if (d_star_big == NULL) { d_star_big = IMG_Load("dat/i/star1.png"); SDL_SetColorKey(d_star_big, SDL_SRCCOLORKEY | SDL_RLEACCEL, 255); } if (b->dying == 0) { surf_pos.x = b->x - 16 - scroll_x; surf_pos.y = b->y - 16 - scroll_y; draw_pos.x = (b->t % 8)*32; draw_pos.y = 0; draw_pos.w = 32; draw_pos.h = 32; SDL_BlitSurface(d_star_big, &draw_pos, screen, &surf_pos); } else { DrawCircle(b->x - scroll_x, b->y - scroll_y, 4+(b->dying), b->dying*10); DrawCircle(b->x - scroll_x, b->y - scroll_y, 2+(b->dying), 255-b->dying*10); } } if (b->img == 2) { // IMMA CHARGIN MAH LAZER if (b->t <= b->fire_time) { z = (b->t * 150 / (b->fire_time+1)) + 80; fx = b->x; fy = b->y; while (!IsSolid(Get((fx)/32, (fy)/32))) { DrawRect(fx-1-scroll_x, fy-1-scroll_y, 4, 4, z/2); fx += cos(b->dir)*2; fy += sin(b->dir)*2; if ((player_shield > 0)&&(shield_hp > 0)&&(PlayerDist(fx, fy) < 30)) break; if (PlayerDist(fx, fy) < 4) break; } DrawCircle(b->x - scroll_x, b->y - scroll_y, 5, (z+255)/2.4); DrawCircle(fx-cos(b->dir)*2 - scroll_x, fy-sin(b->dir)*2 - scroll_y, 4, z/2); fx = b->x; fy = b->y; while (!IsSolid(Get((fx)/32, (fy)/32))) { DrawRect(fx-scroll_x, fy-scroll_y, 2, 2, z); fx += cos(b->dir)*2; fy += sin(b->dir)*2; if ((player_shield > 0)&&(shield_hp > 0)&&(PlayerDist(fx, fy) < 30)) break; if (PlayerDist(fx, fy) < 4) break; } DrawCircle(b->x - scroll_x, b->y - scroll_y, 3, (z+255)/2); DrawCircle(fx-cos(b->dir)*2 - scroll_x, fy-sin(b->dir)*2 - scroll_y, 2, z); } // SHOOP DA WHOOP if ((b->t > b->fire_time) && (b->t <= b->fire_time + b->duration)) { z = 255 - ((b->t - b->fire_time) * 200 / (b->duration+1)); fx = b->x; fy = b->y; while (!IsSolid(Get((fx)/32, (fy)/32))) { DrawRect(fx-3-scroll_x, fy-3-scroll_y, 8, 8, z*2/3); fx += cos(b->dir)*2; fy += sin(b->dir)*2; if ((player_shield > 0)&&(shield_hp > 0)&&(PlayerDist(fx, fy) < 30)) break; if (PlayerDist(fx, fy) < 4) break; } DrawCircle(b->x - scroll_x, b->y - scroll_y, 9, (z+255)/2.4); DrawCircle(fx-cos(b->dir)*2 - scroll_x, fy-sin(b->dir)*2 - scroll_y, 8, z*2/3); fx = b->x; fy = b->y; while (!IsSolid(Get((fx)/32, (fy)/32))) { DrawRect(fx-2-scroll_x, fy-2-scroll_y, 6, 6, z); fx += cos(b->dir)*2; fy += sin(b->dir)*2; x1 = fx + rand()%12 - rand()%12 - scroll_x; y1 = fy + rand()%12 - rand()%12 - scroll_y; DrawRect(x1, y1, 2, 2, rand()%(z+1)); if ((player_shield > 0)&&(shield_hp > 0)&&(PlayerDist(fx, fy) < 30)) break; if (PlayerDist(fx, fy) < 4) break; } DrawCircle(b->x - scroll_x, b->y - scroll_y, 7, (z+255)/2); DrawCircle(fx-cos(b->dir)*2 - scroll_x, fy-sin(b->dir)*2 - scroll_y, 6, z); } } if (b->img == 3) { if (d_star_small == NULL) { d_star_small = IMG_Load("dat/i/star2.png"); SDL_SetColorKey(d_star_small, SDL_SRCCOLORKEY | SDL_RLEACCEL, 255); } if (b->dying == 0) { surf_pos.x = b->x - 8 - scroll_x; surf_pos.y = b->y - 8 - scroll_y; draw_pos.x = (b->t % 8)*16; draw_pos.y = 0; draw_pos.w = 16; draw_pos.h = 16; SDL_BlitSurface(d_star_small, &draw_pos, screen, &surf_pos); } else { DrawCircle(b->x - scroll_x, b->y - scroll_y, 4+(b->dying/2), b->dying*10); DrawCircle(b->x - scroll_x, b->y - scroll_y, 2+(b->dying/2), 255-b->dying*10); } } if (b->img == 4) { if (b->dying == 0) { x1 = b->x + cos(b->dir)*(2) - scroll_x; y1 = b->y + sin(b->dir)*(2) - scroll_y; x2 = b->x - cos(b->dir)*(80) - scroll_x; y2 = b->y - sin(b->dir)*(80) - scroll_y; for (i = 0; i < 40; i++) { xo1 = (x2 - x1)*i/40 + x1; yo1 = (y2 - y1)*i/40 + y1; z = (i/2); if (i > 10) z = (40 - i)/7; DrawRect(xo1 - z - 2, yo1 - z - 2, z*2 + 4, z*2 + 4, 200); } for (i = 0; i < 40; i++) { xo1 = (x2 - x1)*i/40 + x1; yo1 = (y2 - y1)*i/40 + y1; z = (i/2); if (i > 10) z = (40 - i)/7; DrawRect(xo1 - z, yo1 - z, z*2, z*2, 255); } } else{ DrawCircleEx(b->x - scroll_x, b->y - scroll_y, b->dying * 2 + 1, b->dying * 1.75 - 1, 230); DrawCircleEx(b->x - scroll_x, b->y - scroll_y, b->dying * 2, b->dying * 1.75, 255); } } if (b->img == 5) { if (b->dying > 0) { i = 4+(b->dying / 5); DrawRect(b->x - scroll_x - (i-1/2), b->y - scroll_y - (i-1/2), i, i, b->dying*10); i = 2+(b->dying / 5); DrawRect(b->x - scroll_x - (i-1/2), b->y - scroll_y - (i-1/2), i, i, 255-b->dying*10); } else { if ((b->t % 8) < 4) { DrawRect(b->x - scroll_x - 1, b->y - scroll_y - 1, 4, 4, 0); DrawRect(b->x - scroll_x, b->y - scroll_y, 2, 2, 255); } else { DrawRect(b->x - scroll_x - 1, b->y - scroll_y - 1, 4, 4, 255); DrawRect(b->x - scroll_x, b->y - scroll_y, 2, 2, 0); } } } if (b->img == 6) { if (d_star_ls == NULL) { d_star_ls = IMG_Load("dat/i/star3.png"); SDL_SetColorKey(d_star_ls, SDL_SRCCOLORKEY | SDL_RLEACCEL, 255); } if (b->dying == 0) { surf_pos.x = b->x - 16 - scroll_x; surf_pos.y = b->y - 16 - scroll_y; draw_pos.x = (b->t % 8)*32; draw_pos.y = 0; draw_pos.w = 32; draw_pos.h = 32; SDL_BlitSurface(d_star_ls, &draw_pos, screen, &surf_pos); } else { DrawCircle(b->x - scroll_x, b->y - scroll_y, 4+(b->dying), 255-b->dying*10); DrawCircle(b->x - scroll_x, b->y - scroll_y, 2+(b->dying), b->dying*10); } } if (b->img == 7) { if ((b->t % 8) < 4) { DrawCircle(b->x - scroll_x, b->y - scroll_y, 8, 0); DrawCircle(b->x - scroll_x, b->y - scroll_y, 5, 255); } else { DrawCircle(b->x - scroll_x, b->y - scroll_y, 8, 255); DrawCircle(b->x - scroll_x, b->y - scroll_y, 5, 0); } } if (b->img == 8) { if (b->dying > 0) { DrawCircle(b->x - scroll_x, b->y - scroll_y, 12+(b->dying), b->dying*10); DrawCircle(b->x - scroll_x, b->y - scroll_y, 6+(b->dying), 255-b->dying*10); } else { if ((b->t % 6) < 3) { DrawCircle(b->x - scroll_x, b->y - scroll_y, 12, 0); DrawCircle(b->x - scroll_x, b->y - scroll_y, 8, 255); } else { DrawCircle(b->x - scroll_x, b->y - scroll_y, 12, 255); DrawCircle(b->x - scroll_x, b->y - scroll_y, 8, 0); } } } } void DrawGem(struct diamond *g) { static SDL_Surface *d_sprite = NULL; int gemtype = 0; static char hp_icon[2]; SDL_Rect draw_pos; SDL_Rect surf_pos; unsigned char fxp = (SDL_GetTicks() / 300)%2 ? 255 : 0; if (g->delete_me) return; if (d_sprite == NULL) { d_sprite = IMG_Load("dat/i/gem.png"); SDL_SetColorKey(d_sprite, SDL_SRCCOLORKEY | SDL_RLEACCEL, 255); hp_icon[0] = 3; hp_icon[1] = 0; } if (g->value == 1) gemtype = 2; if ((g->value > 1)&&(g->value < 5)) gemtype = 1; if (g->value >= 5) gemtype = 0; if (g->value != 31337) { surf_pos.x = g->x - 4 - scroll_x; surf_pos.y = g->y - 4 - scroll_y; draw_pos.x = (g->t % 4) * 8 + 32 * gemtype; draw_pos.y = 0; draw_pos.w = 8; draw_pos.h = 8; SDL_BlitSurface(d_sprite, &draw_pos, screen, &surf_pos); } else { DrawCircle(g->x - scroll_x, g->y - scroll_y, 6, (rand()%64) ^ fxp); draw_text(g->x - 4 - scroll_x, g->y - 4 - scroll_y, hp_icon, (200+rand()%56) ^ fxp); } g->t++; } void xprintf(char *s) { printf(s); fflush(stdout); } void DrawInvisible(int x, int y) { SDL_Rect dest; dest.x = x - scroll_x - 24; dest.y = y - scroll_y - 24; SDL_BlitSurface(invis_enemy, NULL, screen, &dest); } void DrawEntities() { struct enemy *t; struct bullet *b; struct diamond *g; struct enemyloc *els; if ((rooms[player_room].room_type != 3)&&(rooms[player_room].room_type != 2)) { // Draw gems g = room_gems[player_room]; while (g != NULL) { if ((g->room == player_room)&&(g->delete_me == 0)&&(g->value != 31337)) { DrawGem(g); } g = g->next_in_room; } g = room_gems[player_room]; while (g != NULL) { if ((g->room == player_room)&&(g->delete_me == 0)&&(g->value == 31337)) { DrawGem(g); } g = g->next_in_room; } } t = active_stack; while (t != NULL) { if (!t->delete_me) { if ((t->room == player_room) && (t->enemy_type != 9)) { DrawEnemy(t, screen); } } t = t->next_active; } // Draw invisible enemies (if possible) if (artifacts[6]) { // Draw the actives t = active_stack; while (t != NULL) { if (!t->delete_me) { if (((!t->delete_me)&&((t->room != player_room)||(t->enemy_type == 9)))) { DrawInvisible(t->x, t->y); } } t = t->next_active; } // Draw the inactives if (!artifacts[11]) { els = GetEnemyLoc(scroll_x, scroll_y); while (els != NULL) { t = els->e; if (((!t->delete_me)&&((t->room != player_room)||(t->enemy_type == 9)))&&(t->active == 0)) { if ((t->x+24 >= scroll_x) && (t->y+24 >= scroll_y)) { if (t->x-24 <= (scroll_x+639)) { if (t->y-24 <= (scroll_y+479)) { if ((rooms[t->room].room_type != 2) && (rooms[t->room].room_type != 3)) { DrawInvisible(t->x, t->y); } } } } } els = els->n; } } } b = bullet_stack; while (b != NULL) { if (!b->delete_me) { if (b->room == player_room) { DrawBullet(b); } } b = b->next; } } void MoveEntities() { struct enemy *t; struct bullet *b; struct diamond *g; struct bullet *b_del; struct diamond *g_del; if ((rooms[player_room].room_type != 3)&&(rooms[player_room].room_type != 2)) { // gem stuff g = room_gems[player_room]; while (g != NULL) { if ((g->room == player_room)&&(g->delete_me == 0)) { if (artifacts[7]) { g->x += (player_x+4 - g->x)/10; g->y += (player_y+12 - g->y)/10; } if (PlayerDist(g->x, g->y) < 20) { g->delete_me = 1; total_gems--; if (g->value == 31337) { if (player_hp < (3 + (player_shield == 30)*3)) { SND_Pos("dat/a/crystal.wav", 64, 0); player_hp++; } else { if (!training) { SND_Pos("dat/a/tone.wav", 64, 0); if (player_lives == 1) { player_lives_part += 15; } else { if (player_lives < 10) { player_lives_part += 4; } else { player_lives_part += 1; } } if (player_lives_part >= 88) { player_lives_part -= 88; player_lives += 1; SND_Pos("dat/a/crystal2.wav", 100, 0); } } } } else { player_gems += g->value; } } } g = g->next_in_room; } } t = active_stack; while (t != NULL) { if (!t->delete_me) { if ((rooms[t->room].room_type != 3) || (t->room == player_room)) MoveEnemy(t); } t = t->next_active; } b = bullet_stack; while (b != NULL) { if (!b->delete_me) { MoveBullet(b); } b = b->next; } // delete old bullets b = bullet_stack; if ((b != NULL)&&(b->delete_me)) { b_del = b; b = b->next; free(b_del); bullet_stack = b; } while (b != NULL) { if (b->next != NULL) { if (b->next->delete_me) { b_del = b->next; b->next = b->next->next; free(b_del); } } b = b->next; } // delete old gems g = gem_stack; if ((g != NULL)&&(g->delete_me)) { // Remove room reference if (g == room_gems[g->room]) { room_gems[g->room] = g->next_in_room; if (room_gems[g->room] != NULL) { room_gems[g->room]->prv_in_room = NULL; } } else { if (g->prv_in_room != NULL) { g->prv_in_room->next_in_room = g->next_in_room; } if (g->next_in_room != NULL) { g->next_in_room->prv_in_room = g->prv_in_room; } } g_del = g; g = g->next; free(g_del); gem_stack = g; } while (g != NULL) { if (g->next != NULL) { if (g->next->delete_me) { // Remove room reference assert( (g->next->prv_in_room != NULL) || (room_gems[g->next->room] == g->next) ); if (g->next == room_gems[g->next->room]) { room_gems[g->next->room] = g->next->next_in_room; if (room_gems[g->next->room] != NULL) { room_gems[g->next->room]->prv_in_room = NULL; } } else { g->next->prv_in_room->next_in_room = g->next->next_in_room; if (g->next->next_in_room != NULL) { g->next->next_in_room->prv_in_room = g->next->prv_in_room; } } g_del = g->next; g->next = g->next->next; free(g_del); } } g = g->next; } // delete old monsters t = active_stack; if (t != NULL) { while (t->delete_me) { t = t->next_active; active_stack = t; if (t == NULL) break; } } while (t != NULL) { if (t == active_stack) assert(t->delete_me == 0); else assert(!t->delete_me); if (t->next_active != NULL) { while (t->next_active->delete_me) { t->next_active = t->next_active->next_active; if (t->next_active == NULL) break; } } t = t->next_active; } } void HurtEnemies(int x, int y, int range, int power) { struct enemy *t; int e_range; t = active_stack; while (t != NULL) { e_range = sqrt(sqr(t->x - x) + sqr(t->y - y)); if (e_range < range) { if (power >= t->str) { if (t->room == GetRoom(x/32, y/32)) { KillEnemy(t); } } } t = t->next_active; } } void CircuitBullets(int x, int y, int r) { struct bullet *b; b = bullet_stack; while (b != NULL) { if (!b->delete_me) { if (b->dying == 0) { if (b->invuln == 0) { if (sqrt(sqr(b->x - x) + sqr(b->y - y)) < r) { b->dying = 1; } } } } b = b->next; } } void CrystalSummon() { struct diamond *g; int rg_x, rg_y; int i; g = gem_stack; for (i = 0; i < 3000; i++) { room_gems[i] = NULL; } while (g != NULL) { if (!g->delete_me) { if (rooms[g->room].room_type != 3) { g->room = player_room; rg_x = rooms[player_room].x * 32 + 32 + rand()%(rooms[player_room].w*32-64); rg_y = rooms[player_room].y * 32 + 32 + rand()%(rooms[player_room].h*32-64); if (player_room == 0) { rg_x = (rooms[player_room].x+5) * 32 + 32 + rand()%(8*32); rg_y = (rooms[player_room].y+5) * 32 + 32 + rand()%(5*32); } while (IsSolid(Get(rg_x/32, rg_y/32))) { rg_x = rooms[player_room].x * 32 + 32 + rand()%(rooms[player_room].w*32-64); rg_y = rooms[player_room].y * 32 + 32 + rand()%(rooms[player_room].h*32-64); if (player_room == 0) { rg_x = (rooms[player_room].x+5) * 32 + 32 + rand()%(8*32); rg_y = (rooms[player_room].y+5) * 32 + 32 + rand()%(5*32); } } g->x = rg_x; g->y = rg_y; } } g->next_in_room = room_gems[g->room]; g->prv_in_room = NULL; if (room_gems[g->room] != NULL) { room_gems[g->room]->prv_in_room = g; } room_gems[g->room] = g; g = g->next; } } void ActivateRand() { struct enemy *e; struct enemy *en[20000]; int ent = 0; e = enemy_stack; while (e != NULL) { if (e->delete_me == 0) { if (e->active == 0) { en[ent++] = e; } } e = e->next; } if (ent > 0) { e = en[rand()%ent]; XActivateSingleEnemy(e); } } void ClearBossBullets() { struct bullet *b = bullet_stack; while (b != NULL) { if (!b->delete_me) { if (b->firer == NULL) { b->delete_me = 1; } } b = b->next; } } void SpawnBullet(int x, int y, int bullet_type, float dir, float spd, int invuln) { struct bullet *b; if ( (current_boss == 3) && (player_shield == 30) && (boss_fight_mode == 2) ) { spd *= 1.2; } b = CreateBullet(x, y, NULL, bullet_type, dir, spd); if (invuln) { b->invuln = 1; } } void SpawnLaser(int x, int y, float dir, int fire_time, int duration, float turn, int dmg) { FireLaser(x, y, NULL, dir, fire_time, duration, turn, dmg); } void CullEnemies(int nth) { struct enemy *e; int i = 0; e = enemy_stack; while (e != NULL) { if (e->delete_me == 0) { if (rooms[e->room].room_type == 0) { if ( (i % nth) == (nth - 1)) { e->delete_me = 1; killed_enemies++; e->dying = 0; rooms[e->room].enemies--; } i++; } } e = e->next; } } void SoupUpEnemies() { struct enemy *e; int str_limit; float str_multiplier; float fr_divider; e = enemy_stack; str_limit = 1500; if (circuit_size > 1500) { str_limit = 1500; } str_multiplier = 1.0 + (1.0/3.0)*(float)current_boss; fr_divider = 1.0 + (2.0/3.0)*(float)current_boss; while (e != NULL) { if (e->delete_me == 0) { if (e->enemy_type != 10) { if (e->str < str_limit) { if ((e->str * 2) < str_limit) { e->str = e->str * str_multiplier; } else { e->str = str_limit; } } e->fire_rate = (int)((float)e->fire_rate / fr_divider) + 1; e->speed = (int)((float)e->speed / fr_divider) + 1; e->min_gems *= str_multiplier; e->max_gems *= str_multiplier; } } e = e->next; } } void CurseSingleEnemy(struct enemy *e) { static int ActiveRooms[3000]; static int NActiveRooms = 0; int i; int rm; if (NActiveRooms == 0) { for (i = 0; i < 3000; i++) { if ((rooms[i].room_type == 0) || (rooms[i].room_type == 4)) { ActiveRooms[NActiveRooms++] = i; } } } rm = ActiveRooms[rand()%NActiveRooms]; while ((rooms[rm].enemies > 3) || (rooms[rm].visited == 0)) { rm = ActiveRooms[rand()%NActiveRooms]; } e->x = rooms[rm].w * 16 + rooms[rm].x * 32; e->y = rooms[rm].h * 16 + rooms[rm].y * 32; rooms[e->room].enemies--; e->room = rm; rooms[e->room].enemies++; e->image = enemy_sprites[9]; e->lives = 8; e->str = 500; e->speed = 1; e->fire_rate = (rand()%4)+1; e->min_gems = 5000; e->max_gems = 6000; e->followdepth = 12; e->creationcost = 6; e->enemy_type = 10; ActivateSingleEnemy(e); } void CurseEnemies() { struct enemy *e; int i = 0; e = enemy_stack; while (e != NULL) { if (e->delete_me == 0) { if ( (i % 5) == (4)) { CurseSingleEnemy(e); } else { e->delete_me = 1; killed_enemies++; e->dying = 0; rooms[e->room].enemies--; } i++; } e = e->next; } }