diff options
Diffstat (limited to 'src/enemies/hydra.c')
-rw-r--r-- | src/enemies/hydra.c | 1127 |
1 files changed, 1127 insertions, 0 deletions
diff --git a/src/enemies/hydra.c b/src/enemies/hydra.c new file mode 100644 index 0000000..d770c9d --- /dev/null +++ b/src/enemies/hydra.c @@ -0,0 +1,1127 @@ +#include "hydra.h" +#include "../game.h" +#include "../hero.h" +#include <stdlib.h> +#include <math.h> + +const double PI = 3.14159; + +double headRot = 0; + +void hydraStep(Hydra* h); +void hydraDraw(Hydra* h); + +void hydraDestroy(Hydra* h); + +void hydraheadStep(Hydrahead* h); +void hydraheadDraw(Hydrahead* h); + +void hydragoopStep(Hydragoop* h); +void hydragoopDraw(Hydragoop* h); + +void hydrarockStep(Hydrarock* h); +void hydrarockDraw(Hydrarock* h); + +void hydrashockStep(Hydrashock* h); +void hydrashockDraw(Hydrashock* h); + +double getHydraX(Hydrahead* h); +double getHydraY(Hydrahead* h); + +Mask getHydraMask(Hydra* h); +int checkWeaponCollision(Mask m); + +double lengthdir_x(double ang, double len); +double lengthdir_y(double ang, double len); + +void setHeadState(int headid, int state); + + +//#hydra +void createHydra(int x) +{ + PHL_FreeSurface(images[imgBoss]); + images[imgBoss] = PHL_LoadQDA("lboss01.bmp"); + + int i; + for (i = 4; i < MAX_ENEMIES; i++) { + if (enemies[i] == NULL) { + setBossRoom(); + + Enemy* e = malloc(sizeof *e); + Hydra* h = malloc(sizeof *h); + h->id = i; + + h->hp = 10; + //h->hp = 1; + h->blink = 0; + + h->x = x; + h->y = -64; + + h->hsp = 0; + h->vsp = 0; + + h->imageIndex = 0; + + h->state = 0; + h->timer = 0; + + h->patternCounter = 0; + + h->onground = 0; + h->noheads = 0; + + e->data = h; + e->enemyStep = hydraStep; + e->enemyDraw = hydraDraw; + e->type = 47; + + enemies[i] = e; + + h->headid[0] = createHydrahead(-1, 0, i); + h->headid[1] = createHydrahead(1, 0, i); + h->headid[2] = createHydrahead(1, 1, i); + h->headid[3] = createHydrahead(-1, 1, i); + + i = MAX_ENEMIES; + } + } +} + +void hydraStep(Hydra* h) +{ + double grav = 0.2; + double fric = 0.1; + + //Death + if (h->state == 6) { + h->y += 0.2; + + h->timer -= 1; + h->blink -= 1; + + if (h->timer % 12 == 0) { + createEffect(2, h->x - 64 + (rand() % 128) - 32, h->y - 64 + (rand() % 128)); + } + + if (h->timer <= 0) { + hydraDestroy(h); + } + } + else{ + //Setup Mask + Mask mask = getHydraMask(h); + + //States with hydra heads + if (h->noheads == 0) { + //Fall in intro + if (h->state == 0) { + h->hsp = 0; + h->timer += 1; + if (h->timer >= 50) { + h->timer = 50; + h->imageIndex = 2; + + if (h->onground == 1) { + h->state = 1; + h->timer = 0; + } + }else{ + grav = 0; + } + } + + //Wait/Pattern activate + else if (h->state == 1) + { + h->timer += 1; + + //Stop speed animation + if (h->timer >= 120) { + int patternSize = 9; + int pattern[9] = {4, 0, 4, 1, 4, 2, 4, 3, 2}; + + //Head seizure + if (pattern[h->patternCounter] == 4) { + h->state = 4; + h->timer = 0; + } + //Small hop + if (pattern[h->patternCounter] == 0) { + h->state = 2; + h->timer = 0; + } + + //Goop + if (pattern[h->patternCounter] == 1) { + h->timer = -120; + setHeadState(h->headid[0], 2); + setHeadState(h->headid[1], 2); + } + + //Big Hop + if (pattern[h->patternCounter] == 2) { + h->state = 3; + h->timer = 0; + } + + //Electricity + if (pattern[h->patternCounter] == 3) { + h->timer = -40; + setHeadState(h->headid[2], 3); + setHeadState(h->headid[3], 3); + } + + h->patternCounter += 1; + if (h->patternCounter >= patternSize) { + h->patternCounter = 0; + } + } + } + + //Head seizure state + else if (h->state == 4) { + //Speed up head animation + if (h->timer == 0) { + setHeadState(h->headid[0], 1); + setHeadState(h->headid[1], 1); + setHeadState(h->headid[2], 1); + setHeadState(h->headid[3], 1); + } + + h->timer += 1; + + //Stop speed animation + if (h->timer == 120) { + setHeadState(h->headid[0], 0); + setHeadState(h->headid[1], 0); + setHeadState(h->headid[2], 0); + setHeadState(h->headid[3], 0); + + //Pattern + h->state = 1; + h->timer = 120; + } + } + + //Switch to noheads mode + if (h->onground == 1 && + enemies[h->headid[0]] == NULL && + enemies[h->headid[1]] == NULL && + enemies[h->headid[2]] == NULL && + enemies[h->headid[3]] == NULL) + { + h->noheads = 1; + h->state = 1; + h->timer = -15; + h->patternCounter = 0; + } + } + + //States without hydra heads + else{ + //Wait/pattern activate + if (h->state == 1) { + h->timer += 1; + + if (h->timer >= 0) { + int patternSize = 3; + int pattern[3] = {0, 0, 2}; + + //Small hop + if (pattern[h->patternCounter] == 0) { + h->state = 2; + h->timer = 0; + } + + //Big Hop + if (pattern[h->patternCounter] == 2) { + h->state = 3; + h->timer = 0; + } + + h->patternCounter += 1; + if (h->patternCounter >= patternSize) { + h->patternCounter = 0; + } + } + } + } + + //States used by both modes + { + //Small hop + if (h->state == 2) { + //Setup + if (h->timer == 0) { + h->vsp = -2; + h->onground = 0; + h->hsp = 2.5; + if (herox < h->x) { + h->hsp *= -1; + } + } + + h->timer += 1; + + if (h->onground == 1) { + if (h->noheads == 0 || h->hsp == 0) { + h->state = 1; + h->timer = 0; + } + } + } + + //Large Hop + else if (h->state == 3) { + h->hsp = 0; + + //Setup + if (h->timer == 0) { + h->timer = 1; + if (h->noheads == 0) { + h->vsp = -8; + }else{ + h->vsp = -5; + } + h->onground = 0; + } + + if (h->onground == 1) { + h->timer += 1; + + if (h->timer % 20 == 0) { + createHydrarock(); + } + + if (h->timer >= 220) { + h->state = 1; + h->timer = -15; + } + } + } + } + + //Animate + { + if (h->onground == 1) { + h->imageIndex += 0.1; + if (h->imageIndex >= 2) { + h->imageIndex -= 2; + } + }else{ + if (h->vsp < 0) { + h->imageIndex = 3; + } + else { + h->imageIndex = 2; + } + } + + //Blink + if (h->blink > 0) { + h->blink -= 1; + } + } + + //Movement + { + //Horizontal + if (h->hsp != 0) { + h->x += h->hsp; + mask = getHydraMask(h); + + PHL_Rect collide = getTileCollision(1, mask); + if (collide.x != -1) { + int dir = 1; + if (h->hsp < 0) { + dir = -1; + } + h->x = collide.x + 20 - ((20 + (mask.w / 2)) * dir); + + h->hsp *= -1; + } + } + + //Friction + { + if (h->onground == 1) { + if (h->hsp > 0) { + h->hsp -= fric; + if (h->hsp < 0) { + h->hsp = 0; + } + } + if (h->hsp < 0) { + h->hsp += fric; + if (h->hsp > 0) { + h->hsp = 0; + } + } + } + } + + //Vertical + { + int maxVsp = 9; + + if (h->onground == 0) { + h->y += h->vsp; + h->vsp += grav; + mask = getHydraMask(h); + + //Limit vsp + { + if (h->vsp > maxVsp) { + h->vsp = maxVsp; + } + } + + //Collide with floor + { + PHL_Rect collide = getTileCollision(1, mask); + if (collide.x != -1) { + h->y = collide.y - 64; + h->vsp = 0; + h->onground = 1; + PHL_PlaySound(sounds[sndHit04], CHN_ENEMIES); + quakeTimer = 30; + createEffectExtra(3, h->x - 30, h->y + 32, -1, 0, 0); + createEffectExtra(3, h->x - 10, h->y + 32, 1, 0, 0); + } + } + } + } + + } + + //Update mask + mask = getHydraMask(h); + + //Hero Collision + { + if (checkCollision(mask, getHeroMask()) == 1) { + heroHit(25, h->x); + } + } + + //Weapon Collision + { + int wid = checkWeaponCollision(mask); + if (wid != -1) { + //Pushed back + if (h->noheads == 0) { + h->hsp = weapons[wid]->dir; + PHL_PlaySound(sounds[sndPi05], CHN_ENEMIES); + }else{ + h->hp -= 1; + h->blink = 15; + } + weaponHit(weapons[wid]); + //Die + if (h->hp <= 0) { + h->state = 6; + h->timer = 180; + h->blink = 200; + } + + } + } + } + +} + +void hydraDraw(Hydra* h) +{ + if (h->blink % 2 == 0) { + int cropX = (int)h->imageIndex * 128; + int cropY = 128; + + if (h->noheads == 1) { + cropY += 128; + } + + PHL_DrawSurfacePart(h->x - 64, h->y - 64, cropX, cropY, 128, 128, images[imgBoss]); + } +} + +void hydraDestroy(Hydra* h) +{ + enemyDestroy(h->id); + bossDefeatedFlag = 1; + roomSecret = 1; + + PHL_StopMusic(); +} + +Mask getHydraMask(Hydra* h) +{ + Mask mask; + + mask.unused = mask.circle = 0; + mask.w = 84; + mask.h = 84; + mask.x = h->x - (mask.w / 2); + mask.y = h->y - 64 + (128 - mask.h); + + return mask; +} + +//#heads +int createHydrahead(int dir, int position, int bodyid) +{ + int result = -1; + + int i; + for (i = 0; i < MAX_ENEMIES; i++) { + if (enemies[i] == NULL) { + Enemy* e = malloc(sizeof *e); + Hydrahead* h = malloc(sizeof *h); + + h->id = i; + result = i; + + h->hp = 25; + //h->hp = 1; + h->blink = 0; + + h->dir = dir; + h->position = position; + + h->imageIndex = 0; + + h->neckRot = 0; + if (position != 0) { + h->neckRot -= 45; + } + + h->state = 0; + h->timer = 0; + h->counter = 0; + + h->bodyid = bodyid; + + int a; + for (a = 0; a < 7; a++) { + h->bodyposX[a] = 0; + h->bodyposY[a] = 0; + } + + e->data = h; + e->enemyStep = hydraheadStep; + e->enemyDraw = hydraheadDraw; + e->type = -1; + + enemies[i] = e; + i = MAX_ENEMIES; + } + } + + return result; +} + +void hydraheadStep(Hydrahead* h) +{ + char dead = 0; + + //Animate + { + h->imageIndex += 0.1; + if (h->imageIndex >= 2) { + h->imageIndex -= 2; + } + + if (h->blink > 0) { + h->blink -= 1; + } + + h->neckRot += 2; + if (h->neckRot >= 360) { + h->neckRot -= 360; + } + } + + //States + { + //Death + if (h->state == 4) { + h->timer += 1; + if (h->timer % 6 == 0) { + createEffect(2, h->bodyposX[6 - h->counter] - 32, h->bodyposY[6 - h->counter] - 32); + h->counter += 1; + } + + if (h->counter >= 7) { + dead = 1; + } + } + else{ + if (h->state == 0) { + //Do nothing special + } + + //Fast movements + else if (h->state == 1) { + h->neckRot += 2; + } + + //Shoot goop + else if (h->state == 2) { + h->neckRot += 2; + h->timer += 1; + + //Create Goop + if (h->timer % 15 == 0) { + int ghsp = -4 + (rand() % 9), + gvsp = -6; + + createHydragoop(h->bodyposX[6], h->bodyposY[6], ghsp, gvsp); + } + + if (h->timer >= 120) { + h->state = 0; + } + } + + //Shoot electricity + else if (h->state == 3) { + if (h->timer == 0) { + h->timer = 1; + } + + if (h->timer % 20 == 0) { + if (h->counter == 0) { + createHydrashock(h->bodyposX[6] + (70 * h->dir), h->bodyposY[6] + 20); + } + h->neckRot -= 2; + h->counter += 1; + if (h->counter >= 20) { + h->counter = 0; + h->timer += 1; + } + }else{ + h->neckRot += 2; + h->timer += 1; + } + + if (h->timer > 80) { + h->state = 0; + /* + Hydra* body = enemies[h->bodyid]->data; + body->state = 1; + body->timer = 239; + */ + } + + } + + Mask mask; + mask.circle = mask.unused = 0; + + //Collide with player + { + int i; + for (i = 0; i < 7; i+=2) { + //Setup mask + { + mask.w = 48; + mask.h = 48; + + //Head + if (i == 6) { + mask.w = 60; + mask.h = 36; + } + + mask.x = h->bodyposX[i] - (mask.w / 2); + mask.y = h->bodyposY[i] - (mask.h / 2); + } + + //Collide + if (checkCollision(getHeroMask(), mask) == 1) { + heroHit(25, getHydraX(h)); + } + } + } + + //Weapon collision + { + //Mask should still be on the head + int wid = checkWeaponCollision(mask); + if (wid != -1) { + h->blink = 15; + h->hp -= 1; + weaponHit(weapons[wid]); + + if (h->hp <= 0) { + h->state = 4; + h->timer = 0; + h->counter = 0; + } + } + } + + + } + + } + + //Destroy object + if (dead == 1) { + enemyDestroy(h->id); + } +} + +void hydraheadDraw(Hydrahead* h) +{ + /* + char c[10]; + sprintf(c, "%02d", h->timer); + PHL_DrawTextBold(c, h->bodyposX[6], 0, 0); + */ + + h->bodyposX[0] = getHydraX(h) + 20; + h->bodyposY[0] = getHydraY(h); + + double drawX = getHydraX(h) + 20; + double drawY = getHydraY(h); + + int dis = 24; + int angle = -25; + + if (h->position == 1) { + angle = -60; + + drawX -= 5; + drawY -= 20; + } + + int i; + for (i = 0; i < 7; i++) { + double wavlen = sin((h->neckRot + (45 * i)) * PI / 180); + + double incang = 45; + + if (h->position != 0) { + incang = 45; + } + + if (i == 6) { + //incang += 15; + incang = 50; + + if (h->position == 1) { + incang = 80; + } + } + + drawX += lengthdir_x(angle + (incang * wavlen), dis); + drawY += lengthdir_y(angle + (incang * wavlen), dis); + + h->bodyposX[i] = drawX; + h->bodyposY[i] = drawY; + + if (h->dir == -1) { + double difference = h->bodyposX[i] - getHydraX(h); + h->bodyposX[i] = getHydraX(h) - difference; + } + + if (h->blink % 2 == 0) { + if (h->state != 4 || (6 - h->counter >= i)) { + if (i != 6) { + int cropX = 0; + + if (h->dir == -1) { + cropX += 64; + } + + PHL_DrawSurfacePart(h->bodyposX[i] - 32, h->bodyposY[i] - 32, cropX, 64, 64, 64, images[imgBoss]); + }else{ + int cropX = 0; + + if (h->dir == -1) { + cropX += 320; + } + + cropX += (int)h->imageIndex * 80; + + PHL_DrawSurfacePart(h->bodyposX[i] - 40, h->bodyposY[i] - 32, cropX, 0, 80, 64, images[imgBoss]); + } + } + } + } + +} + +int checkWeaponCollision(Mask m) +{ + int i; + for (i = 0; i < MAX_WEAPONS; i++) { + if (weapons[i] != NULL) { + if (weapons[i]->cooldown == 0) { + if (checkCollision(weapons[i]->weaponMask, m) == 1) { + return i; + } + } + } + } + + return -1; +} + +double lengthdir_x(double ang, double len) +{ + return cos(ang * PI / 180) * len; +} + +double lengthdir_y(double ang, double len) +{ + return sin(ang * PI / 180) * len; +} + +double getHydraX(Hydrahead* h) +{ + if (enemies[h->bodyid] != NULL) { + Hydra* hbody = enemies[h->bodyid]->data; + return hbody->x; + } + + return -1; +} + +double getHydraY(Hydrahead* h) +{ + if (enemies[h->bodyid] != NULL) { + Hydra* hbody = enemies[h->bodyid]->data; + return hbody->y; + } + + return -1; +} + +void setHeadState(int headid, int state) +{ + if (enemies[headid] != NULL) { + Hydrahead* h = enemies[headid]->data; + if (h->state != 4) { + h->state = state; + h->timer = 0; + h->counter = 0; + } + } +} + +//#goop +void createHydragoop(int x, int y, int hsp, int vsp) +{ + int i; + for (i = 0; i < MAX_ENEMIES; i++) { + if (enemies[i] == NULL) { + Enemy* e = malloc(sizeof *e); + Hydragoop* h = malloc(sizeof *h); + h->id = i; + + h->x = x; + h->y = y; + + h->hsp = hsp; + h->vsp = vsp; + + h->inwall = 0; + h->bounce = 0; + + h->imageIndex = 0; + + e->data = h; + e->enemyStep = hydragoopStep; + e->enemyDraw = hydragoopDraw; + e->type = -1; + + enemies[i] = e; + i = MAX_ENEMIES; + + PHL_PlaySound(sounds[sndPi06], CHN_ENEMIES); + } + } +} + +void hydragoopStep(Hydragoop* h) +{ + char dead = 0; + + //Animate + { + h->imageIndex += 0.16; + if (h->imageIndex >= 3) { + h->imageIndex -= 3; + } + } + + //Setup Mask + Mask mask; + { + mask.circle = mask.unused = 0; + mask.w = 36; + mask.h = 36; + mask.x = h->x - mask.w / 2; + mask.y = h->y - mask.h / 2; + } + + //Movement + { + double grav = 0.2; + + h->x += h->hsp; + mask.x = h->x - mask.w / 2; + + if (checkTileCollision(1, mask) == 1) { + h->inwall = 1; + } + + h->y += h->vsp; + h->vsp += grav; + mask.y = h->y - mask.h / 2; + + if (h->inwall == 0 && h->bounce == 0) { + if (checkTileCollision(1, mask) == 1) { + h->bounce = 1; + h->vsp = -2; + } + } + } + + //Outside of room + { + if ( (h->y > 500 && h->vsp >= 0) || + (h->x < -20 && h->hsp <= 0) || + (h->x > 660 && h->hsp >= 0) ) + { + dead = 1; + } + } + + //Collide with hero + { + //Collide with shield + if (checkCollision(mask, shieldMask) == 1) { + createEffect(1, h->x - 20, h->y - 20); + PHL_PlaySound(sounds[sndHit07], CHN_EFFECTS); + dead = 1; + } + else if (checkCollision(mask, getHeroMask()) == 1) { + if (heroHit(25, h->x) == 1) { + heroPoison(); + } + } + } + + //Destroy object + { + if (dead == 1) { + enemyDestroy(h->id); + } + } + +} + +void hydragoopDraw(Hydragoop* h) +{ + int cropX = 320; + + cropX += (int)h->imageIndex * 40; + + PHL_DrawSurfacePart(h->x - 20, h->y - 20, cropX, 480, 40, 40, images[imgMisc20]); +} + +//#rock +void createHydrarock() +{ + int i; + for (i = 0; i < MAX_ENEMIES; i++) { + if (enemies[i] == NULL) { + Enemy* e = malloc(sizeof *e); + Hydrarock* h = malloc(sizeof *h); + h->id = i; + + h->x = 70 + (rand() % 26) * 20; + h->y = -24; + + h->vsp = 0; + + h->bounce = 0; + + h->imageIndex = 0; + + e->data = h; + e->enemyStep = hydrarockStep; + e->enemyDraw = hydrarockDraw; + e->type = -1; + + enemies[i] = e; + i = MAX_ENEMIES; + } + } +} + +void hydrarockStep(Hydrarock* h) +{ + //Animate + { + h->imageIndex += 0.25; + if (h->imageIndex >= 8) { + h->imageIndex -= 8; + } + } + + //Movement + { + double grav = 0.15; + + h->y += h->vsp; + h->vsp += grav; + } + + //Setup Mask + Mask mask; + { + mask.circle = mask.unused = 0; + mask.w = 44; + mask.h = 44; + mask.x = h->x - mask.w / 2; + mask.y = h->y - mask.h / 2; + } + + if (h->bounce == 0) { + if (checkTileCollision(1, mask) == 1) { + h->bounce = 1; + h->vsp = -2; + PHL_PlaySound(sounds[sndHit06], CHN_ENEMIES); + } + } + + //Hero collision + { + if (checkCollision(mask, getHeroMask()) == 1) { + heroHit(30, h->x); + } + } + + //Weapon Collision + { + int wid = checkWeaponCollision(mask); + if (wid != -1) { + weaponHit(weapons[wid]); + PHL_PlaySound(sounds[sndHit03], CHN_WEAPONS); + } + } + + if (h->y >= 520) { + enemyDestroy(h->id); + } +} + +void hydrarockDraw(Hydrarock* h) +{ + int cropX = 128; + + cropX += (int)h->imageIndex * 64; + + PHL_DrawSurfacePart(h->x - 32, h->y - 32, cropX, 128, 64, 64, images[imgMisc32]); +} + +//#electricity +void createHydrashock(int x, int y) +{ + int i; + for (i = 0; i < MAX_ENEMIES; i++) { + if (enemies[i] == NULL) { + Enemy* e = malloc(sizeof *e); + Hydrashock* h = malloc(sizeof *h); + h->id = i; + + h->timer = 0; + + h->x = x; + h->y = y; + + h->angle = 0; + + h->imageIndex = 0; + + e->data = h; + e->enemyStep = hydrashockStep; + e->enemyDraw = hydrashockDraw; + e->type = -1; + + enemies[i] = e; + i = MAX_ENEMIES; + + PHL_PlaySound(sounds[sndShot03], CHN_ENEMIES); + } + } +} + +void hydrashockStep(Hydrashock* h) +{ + //Animate + { + h->imageIndex += 0.5; + if (h->imageIndex >= 4) { + h->imageIndex -= 4; + } + } + + h->timer += 1; + + if (h->timer >= 20) { + if (h->timer == 20) { + //Set angle + h->angle = (atan2(h->x - (herox), heroy + 20 - h->y) * 180 / PI) + 90; + } + + h->timer = 22; + + //Movement + { + int spd = 5; + h->x += lengthdir_x(h->angle, spd); + h->y += lengthdir_y(h->angle, spd); + } + } + + //Setup mask + Mask mask; + { + mask.unused = mask.circle = 0; + mask.w = 28; + mask.h = 28; + mask.x = h->x - mask.w / 2; + mask.y = h->y - mask.h / 2; + } + + //Hero Collision + { + if (checkCollision(mask, getHeroMask()) == 1) { + if (heroHit(25, h->x) == 1) { + heroStun(); + } + } + } + + //Destroy if outside of room + { + if (mask.x > 660 || mask.x + mask.w < -20 || mask.y > 500 || mask.y + mask.h < -20) { + enemyDestroy(h->id); + } + } +} + +void hydrashockDraw(Hydrashock* h) +{ + if (h->timer % 2 == 0) { + int cropX = (int)h->imageIndex * 64; + + PHL_DrawSurfacePart(h->x - 32, h->y - 32, cropX, 192, 64, 64, images[imgMisc32]); + } +}
\ No newline at end of file |