943 lines
23 KiB
C
943 lines
23 KiB
C
// stage
|
|
|
|
|
|
s16 stageClock,
|
|
nextClock;
|
|
|
|
|
|
// groups
|
|
|
|
static void waveSine(bool right){
|
|
struct enemySpawner spawner = {
|
|
.angle = 256,
|
|
.speed = FIX16(1),
|
|
.x = GAME_W / 5 * (right ? 3 : 2),
|
|
.y = -16,
|
|
.image = right ? &fairyRed : &fairyBlue,
|
|
.offX = 16,
|
|
.offY = 16,
|
|
.health = 2
|
|
};
|
|
spawner.fixes[0] = FIX16(spawner.x);
|
|
spawner.fixes[1] = FIX16(32);
|
|
spawner.fixes[2] = FIX16(64);
|
|
spawner.fixes[3] = FIX16(0.08);
|
|
spawner.bools[0] = right;
|
|
void updater(s16 i){
|
|
enemies[i].pos.x = fix16Sub(enemies[i].fixes[0], fix16Mul(sinFix16(enemies[i].fixes[1]), enemies[i].fixes[2]));
|
|
enemies[i].fixes[1] = enemies[i].bools[0] ? fix16Add(enemies[i].fixes[1], enemies[i].fixes[3]) : fix16Sub(enemies[i].fixes[1], enemies[i].fixes[3]);
|
|
}
|
|
for(u8 i = 0; i < 6; i++){
|
|
spawnEnemy(spawner, updater, EMPTY);
|
|
spawner.y -= 32;
|
|
}
|
|
}
|
|
|
|
static void waveBig1(){
|
|
struct enemySpawner spawner = {
|
|
.angle = 256,
|
|
.speed = FIX16(0.75),
|
|
.x = GAME_W / 2,
|
|
.y = -16,
|
|
.image = &fairyGreen,
|
|
.offX = 16,
|
|
.offY = 16,
|
|
.health = 8
|
|
};
|
|
void updater(s16 i){
|
|
if(enemies[i].clock == 40){
|
|
struct bulletSpawner spawner = {
|
|
.x = enemies[i].pos.x,
|
|
.y = enemies[i].pos.y,
|
|
.image = &bigBullet,
|
|
.angle = 128,
|
|
.speed = FIX16(1.5),
|
|
.big = TRUE
|
|
};
|
|
for(u8 j = 0; j < 5; j++){
|
|
spawnBullet(spawner, EMPTY);
|
|
spawner.angle += 64;
|
|
}
|
|
}
|
|
else if(enemies[i].clock == 120){
|
|
enemies[i].speed = FIX16(0.5);
|
|
updateEnemyVel(i);
|
|
}
|
|
}
|
|
spawnEnemy(spawner, updater, EMPTY);
|
|
}
|
|
|
|
static void waveBig2(bool left){
|
|
struct enemySpawner spawner = {
|
|
.angle = 256,
|
|
.speed = FIX16(0.5),
|
|
.x = left ? GAME_W / 5 - 16 : GAME_W / 5 * 4 + 16,
|
|
.y = -16,
|
|
.image = left ? &fairyGreen : &fairyYellow,
|
|
.offX = 16,
|
|
.offY = 16,
|
|
.health = 6
|
|
};
|
|
spawner.bools[0] = left;
|
|
void updater(s16 i){
|
|
if(enemies[i].clock >= 60 && enemies[i].clock < 180 && enemies[i].clock % 15 == 0){
|
|
if(enemies[i].clock == 60){
|
|
velPos.x = player.pos.x;
|
|
velPos.y = player.pos.y;
|
|
}
|
|
struct bulletSpawner spawner = {
|
|
.x = enemies[i].pos.x,
|
|
.y = enemies[i].pos.y,
|
|
.speed = FIX16(1.5),
|
|
.image = &smallBullet,
|
|
.light = enemies[i].clock % 30 == 0,
|
|
.top = TRUE
|
|
};
|
|
spawner.vel = hone(enemies[i].pos, velPos, spawner.speed, 48);
|
|
spawnBullet(spawner, EMPTY);
|
|
} else if(enemies[i].bools[0] && enemies[i].clock == 61){
|
|
struct bulletSpawner spawner = {
|
|
.x = enemies[i].pos.x,
|
|
.y = enemies[i].pos.y,
|
|
.image = &bigBullet,
|
|
.angle = 64,
|
|
.speed = FIX16(1.25),
|
|
.big = TRUE
|
|
};
|
|
for(u8 j = 0; j < 4; j++){
|
|
spawnBullet(spawner, EMPTY);
|
|
spawner.angle += 64;
|
|
}
|
|
}
|
|
}
|
|
spawnEnemy(spawner, updater, EMPTY);
|
|
}
|
|
|
|
static void waveBig3(){
|
|
struct enemySpawner spawner = {
|
|
.angle = 256,
|
|
.speed = FIX16(0.75),
|
|
.x = GAME_W / 2,
|
|
.y = -16,
|
|
.image = &fairyGreen,
|
|
.offX = 16,
|
|
.offY = 16,
|
|
.health = 8
|
|
};
|
|
void updater(s16 i){
|
|
if(enemies[i].clock > 0 && enemies[i].clock < 120 && enemies[i].clock % 40 == 20){
|
|
struct bulletSpawner spawner = {
|
|
.x = enemies[i].pos.x,
|
|
.y = enemies[i].pos.y,
|
|
.speed = FIX16(1.5)
|
|
};
|
|
if(enemies[i].clock == 60){
|
|
spawner.image = &smallBullet;
|
|
spawner.angle = 96;
|
|
} else {
|
|
spawner.image = &bigBullet;
|
|
spawner.big = TRUE;
|
|
spawner.angle = 128;
|
|
}
|
|
for(u8 j = 0; j < (enemies[i].clock == 60 ? 6 : 5); j++){
|
|
spawnBullet(spawner, EMPTY);
|
|
spawner.angle += 64;
|
|
}
|
|
}
|
|
else if(enemies[i].clock == 120){
|
|
enemies[i].speed = FIX16(0.5);
|
|
updateEnemyVel(i);
|
|
}
|
|
}
|
|
spawnEnemy(spawner, updater, EMPTY);
|
|
}
|
|
|
|
static void waveSwarm(u8 count){
|
|
struct enemySpawner spawner = {
|
|
.angle = 256,
|
|
.speed = FIX16(1.25),
|
|
.y = -16,
|
|
.offX = 16,
|
|
.offY = 16,
|
|
.health = 2
|
|
};
|
|
for(u8 i = 0; i < count; i++){
|
|
spawner.x = random() % (GAME_W / 2 - 48);
|
|
spawner.x += (i % 2 == 0) ? (GAME_W / 2) : 48;
|
|
spawner.image = i % 4 < 2 ? &fairyRed : &fairyBlue;
|
|
spawner.y -= 32;
|
|
spawnEnemy(spawner, EMPTY, EMPTY);
|
|
}
|
|
}
|
|
|
|
static void waveBig4(bool right, bool second){
|
|
struct enemySpawner spawner = {
|
|
.angle = 256,
|
|
.speed = FIX16(0.6),
|
|
.x = right ? (GAME_W / 4 * 3 + 24) : (GAME_W / 4 - 24),
|
|
.y = -16,
|
|
.image = right ? &fairyYellow : &fairyGreen,
|
|
.offX = 16,
|
|
.offY = 16,
|
|
.health = 4
|
|
};
|
|
if(right) spawner.y -= 24;
|
|
spawner.bools[0] = right;
|
|
spawner.bools[1] = second;
|
|
void updater(s16 i){
|
|
if(enemies[i].clock == 40){
|
|
struct bulletSpawner spawner = {
|
|
.x = enemies[i].pos.x,
|
|
.y = enemies[i].pos.y,
|
|
.image = &bigBullet,
|
|
.big = TRUE,
|
|
.speed = FIX16(1.25),
|
|
.angle = 32,
|
|
.light = enemies[i].bools[0]
|
|
};
|
|
if(enemies[i].bools[0]) spawner.angle = 512 - spawner.angle;
|
|
for(u8 j = 0; j < 5; j++){
|
|
spawnBullet(spawner, EMPTY);
|
|
spawner.angle += enemies[i].bools[0] ? -64 : 64;
|
|
}
|
|
} else if(enemies[i].clock >= 60 && enemies[i].clock < 150 && enemies[i].clock % 10 == 0 && enemies[i].bools[1]){
|
|
struct bulletSpawner spawner = {
|
|
.x = enemies[i].pos.x,
|
|
.y = enemies[i].pos.y,
|
|
.image = &smallBullet,
|
|
.speed = FIX16(2),
|
|
.light = !enemies[i].bools[0]
|
|
};
|
|
if(enemies[i].clock == 60){
|
|
velPos = hone(enemies[i].pos, player.pos, spawner.speed, 0);
|
|
enemies[i].fixes[0] = velPos.x;
|
|
enemies[i].fixes[1] = velPos.y;
|
|
}
|
|
spawner.vel.x = enemies[i].fixes[0];
|
|
spawner.vel.y = enemies[i].fixes[1];
|
|
// spawner.vel = velPos;
|
|
spawnBullet(spawner, EMPTY);
|
|
}
|
|
}
|
|
spawnEnemy(spawner, updater, EMPTY);
|
|
}
|
|
|
|
static void waveBig5(bool right){
|
|
struct enemySpawner spawner = {
|
|
.angle = 256,
|
|
.speed = FIX16(0.75),
|
|
.x = 80,
|
|
.y = -16,
|
|
.image = &fairyRed,
|
|
.offX = 16,
|
|
.offY = 16,
|
|
.health = 6
|
|
};
|
|
if(right){
|
|
spawner.x = GAME_W - spawner.x;
|
|
spawner.y -= 32;
|
|
}
|
|
spawner.bools[0] = right;
|
|
void updater(s16 i){
|
|
if(enemies[i].clock > 0 && enemies[i].clock % 60 == 30 && enemies[i].clock < 240){
|
|
struct bulletSpawner spawner = {
|
|
.x = enemies[i].pos.x,
|
|
.y = enemies[i].pos.y,
|
|
.image = &bigBullet,
|
|
.big = TRUE,
|
|
.angle = enemies[i].bools[0] ? 512 : 0,
|
|
.speed = FIX16(1.5)
|
|
};
|
|
spawner.angle += enemies[i].bools[0] ? enemies[i].ints[0] : -enemies[i].ints[0];
|
|
spawner.bools[0] = enemies[i].bools[0];
|
|
void updater(s16 j){
|
|
if(bullets[j].clock > 30 && bullets[j].clock % 16 == 0){
|
|
bullets[j].angle += bullets[j].bools[0] ? -32 : 32;
|
|
updateBulletVel(j);
|
|
}
|
|
}
|
|
for(u8 j = 0; j < 5; j++){
|
|
if(j > 0) spawnBullet(spawner, updater);
|
|
spawner.angle += enemies[i].bools[0] ? -64 : 64;
|
|
}
|
|
enemies[i].ints[0] += 56;
|
|
}
|
|
if(enemies[i].clock == 120){
|
|
enemies[i].speed = FIX16(0.5);
|
|
updateEnemyVel(i);
|
|
}
|
|
}
|
|
spawnEnemy(spawner, updater, EMPTY);
|
|
}
|
|
|
|
static void waveBig6(bool right){
|
|
struct enemySpawner spawner = {
|
|
.angle = right ? 512 : 0,
|
|
.speed = FIX16(1),
|
|
.x = right ? (GAME_W + 16) : -32,
|
|
.y = 40,
|
|
.image = right ? &fairyGreen : &fairyYellow,
|
|
.offX = 16,
|
|
.offY = 16,
|
|
.health = 4
|
|
};
|
|
spawner.bools[0] = right;
|
|
void updater(s16 i){
|
|
if(enemies[i].clock % 10 == 0 && enemies[i].clock >= 60 && enemies[i].clock < 180){
|
|
enemies[i].angle += enemies[i].bools[0] ? -24 : 24;
|
|
updateEnemyVel(i);
|
|
}
|
|
if(enemies[i].clock % 35 == 0 && enemies[i].clock > 0 && enemies[i].clock < 180){
|
|
struct bulletSpawner spawner = {
|
|
.x = enemies[i].pos.x,
|
|
.y = enemies[i].pos.y
|
|
};
|
|
for(u8 j = 0; j < 4; j++){
|
|
spawner.angle = random() % 256;
|
|
if(enemies[i].bools[0]) spawner.angle += 256;
|
|
if(j < 2){
|
|
spawner.speed = FIX16(1.25);
|
|
spawner.big = TRUE;
|
|
spawner.image = &bigBullet;
|
|
} else {
|
|
spawner.speed = FIX16(1.75);
|
|
spawner.image = &smallBullet;
|
|
spawner.top = TRUE;
|
|
}
|
|
spawnBullet(spawner, EMPTY);
|
|
}
|
|
}
|
|
|
|
}
|
|
spawnEnemy(spawner, updater, EMPTY);
|
|
}
|
|
|
|
static void waveFormation(bool right){
|
|
struct enemySpawner spawner = {
|
|
.angle = 256,
|
|
.speed = FIX16(1),
|
|
.x = right ? (GAME_W - 48) : 48,
|
|
.y = -16,
|
|
.image = right ? &fairyRed : &fairyBlue,
|
|
.offX = 16,
|
|
.offY = 16,
|
|
.health = 2
|
|
};
|
|
void updater(s16 i){
|
|
if(enemies[i].clock > 0 && enemies[i].clock % 60 == 0 && enemies[i].clock <= 180){
|
|
struct bulletSpawner spawner = {
|
|
.x = enemies[i].pos.x,
|
|
.y = enemies[i].pos.y,
|
|
.image = &smallBullet,
|
|
.light = TRUE,
|
|
.speed = FIX16(1.5)
|
|
};
|
|
spawner.vel = hone(enemies[i].pos, player.pos, spawner.speed, 16);
|
|
spawnBullet(spawner, updater);
|
|
}
|
|
if(enemies[i].clock == 90){
|
|
enemies[i].speed = FIX16(0.75);
|
|
updateEnemyVel(i);
|
|
}
|
|
}
|
|
for(u8 i = 0; i < 4; i++){
|
|
spawnEnemy(spawner, updater, EMPTY);
|
|
spawner.x += right ? -32 : 32;
|
|
spawner.y -= 32;
|
|
}
|
|
}
|
|
|
|
|
|
// bosses
|
|
|
|
#define BOSS_MOD_Y FIX16(8)
|
|
#define BOSS_MOD_X FIX16(64)
|
|
fix16 bossLimitY, bossLimitH, bossLimitX, bossLimitW;
|
|
|
|
static void bossIntro(s16 i){
|
|
enemies[i].last.x = enemies[i].pos.x;
|
|
enemies[i].clock = -1;
|
|
if(clock % 32 == 0){
|
|
enemies[i].speed = fix16Sub(enemies[i].speed, FIX16(0.25));
|
|
if(enemies[i].speed <= 0){
|
|
bossLimitY = fix16Sub(enemies[i].pos.y, BOSS_MOD_Y);
|
|
bossLimitH = fix16Add(enemies[i].pos.y, BOSS_MOD_Y);
|
|
bossLimitX = fix16Sub(enemies[i].pos.x, BOSS_MOD_X);
|
|
bossLimitW = fix16Add(enemies[i].pos.x, BOSS_MOD_X);
|
|
// enemies[i].speed = FIX16(0.5);
|
|
enemies[i].angle = 32;
|
|
enemies[i].bools[0] = TRUE;
|
|
enemies[i].clock = -1;
|
|
}
|
|
updateEnemyVel(i);
|
|
}
|
|
}
|
|
|
|
#define BOSS_FLIP_MOD 15
|
|
s16 bossAnimateClock, bossFlipClock;
|
|
static void bossAnimate(s16 i){
|
|
if(enemies[i].flipClock == 0){
|
|
if(enemies[i].last.x > enemies[i].pos.x){
|
|
enemies[i].flipClock = BOSS_FLIP_MOD;
|
|
SPR_setAnim(enemies[i].image, 1);
|
|
SPR_setFrame(enemies[i].image, 0);
|
|
SPR_setHFlip(enemies[i].image, 0);
|
|
} else if(enemies[i].last.x < enemies[i].pos.x){
|
|
enemies[i].flipClock = BOSS_FLIP_MOD;
|
|
SPR_setAnim(enemies[i].image, 1);
|
|
SPR_setFrame(enemies[i].image, 0);
|
|
SPR_setHFlip(enemies[i].image, 1);
|
|
} else {
|
|
enemies[i].flipClock = BOSS_FLIP_MOD;
|
|
bossFlipClock = 0;
|
|
SPR_setAnim(enemies[i].image, 0);
|
|
SPR_setHFlip(enemies[i].image, 0);
|
|
}
|
|
}
|
|
if(enemies[i].flipClock > 0)
|
|
enemies[i].flipClock--;
|
|
if(enemies[i].last.x == enemies[i].pos.x){
|
|
if(bossAnimateClock % 10 == 0) SPR_nextFrame(enemies[i].image);
|
|
} else {
|
|
if(bossFlipClock >= 90) SPR_setFrame(enemies[i].image, 0);
|
|
else if(bossFlipClock >= 30) SPR_setFrame(enemies[i].image, 1);
|
|
else SPR_setFrame(enemies[i].image, 0);
|
|
bossFlipClock++;
|
|
}
|
|
bossAnimateClock++;
|
|
}
|
|
|
|
static void bossMove(s16 i){
|
|
if(enemies[i].pos.x > bossLimitW || enemies[i].pos.x < bossLimitX){
|
|
enemies[i].pos.x = enemies[i].pos.x > bossLimitW ? bossLimitW : bossLimitX;
|
|
enemies[i].angle = 512 - enemies[i].angle;
|
|
updateEnemyVel(i);
|
|
}
|
|
if(enemies[i].pos.y > bossLimitH || enemies[i].pos.y < bossLimitY){
|
|
enemies[i].pos.y = enemies[i].pos.y > bossLimitH ? bossLimitH : bossLimitY;
|
|
enemies[i].angle = 1024 - enemies[i].angle;
|
|
updateEnemyVel(i);
|
|
}
|
|
if(enemies[i].clock % 120 == 119){
|
|
enemies[i].speed = enemies[i].speed == 0 ? FIX16(0.5) : 0;
|
|
updateEnemyVel(i);
|
|
}
|
|
}
|
|
|
|
static void waveMidboss1(){
|
|
bossAnimateClock = 0;
|
|
struct enemySpawner spawner = {
|
|
.angle = 256,
|
|
.speed = FIX16(1),
|
|
.x = GAME_W / 2,
|
|
.y = -16,
|
|
.image = &cirno,
|
|
.offX = 24,
|
|
.offY = 28,
|
|
.boss = TRUE,
|
|
.health = 40
|
|
};
|
|
bossMax = spawner.health;
|
|
void updater(s16 i){
|
|
bossAnimate(i);
|
|
if(enemies[i].bools[0]){
|
|
bossHealth = enemies[i].health;
|
|
bossMove(i);
|
|
if(enemies[i].health > 20){
|
|
// ring
|
|
if(enemies[i].clock % 90 == 0){
|
|
struct bulletSpawner spawner = {
|
|
.x = enemies[i].pos.x,
|
|
.y = enemies[i].pos.y,
|
|
.image = &bigBullet,
|
|
.big = TRUE,
|
|
.speed = FIX16(1.5),
|
|
.angle = 80 + random() % 32,
|
|
.light = TRUE
|
|
};
|
|
for(u8 j = 3; j < 15; j++){
|
|
if(j % 3 < 2) spawnBullet(spawner, EMPTY);
|
|
spawner.angle += 32;
|
|
}
|
|
}
|
|
// puke
|
|
else if(enemies[i].clock % 20 == 0){
|
|
struct bulletSpawner spawner = {
|
|
.x = FIX16(enemies[i].clock % 180 < 90 ? 32 : GAME_W - 32),
|
|
.y = FIX16(48),
|
|
.image = &bigBullet,
|
|
.big = TRUE,
|
|
.top = TRUE,
|
|
.speed = FIX16(2)
|
|
};
|
|
velPos.x = spawner.x;
|
|
velPos.y = spawner.y;
|
|
spawner.vel = hone(velPos, player.pos, spawner.speed, 32);
|
|
spawnBullet(spawner, EMPTY);
|
|
spawnExplosion(spawner.x, spawner.y, 3);
|
|
}
|
|
} else {
|
|
if(!enemies[i].bools[7]){
|
|
killBullets = TRUE;
|
|
enemies[i].bools[7] = TRUE;
|
|
enemies[i].clock = -60;
|
|
}
|
|
if(enemies[i].clock >= 0){
|
|
// swash
|
|
if(enemies[i].clock % 8 == 0){
|
|
struct bulletSpawner spawner = {
|
|
.x = enemies[i].pos.x,
|
|
.y = enemies[i].pos.y,
|
|
.image = &smallBullet,
|
|
.speed = FIX16(1.75),
|
|
.light = TRUE,
|
|
.top = TRUE,
|
|
.angle = enemies[i].ints[0]
|
|
};
|
|
if(enemies[i].clock % 16 == 8){
|
|
spawner.image = &bigBullet;
|
|
spawner.big = TRUE;
|
|
}
|
|
void updater(s16 j){
|
|
if(bullets[j].bools[0] && bullets[j].clock == 15){
|
|
bullets[j].angle = 64 + random() % 384;
|
|
bullets[j].speed = FIX16(1.75);
|
|
updateBulletVel(j);
|
|
} else if(!bullets[j].bools[0] && bullets[j].clock >= 0 && bullets[j].clock % 10 == 0){
|
|
bullets[j].speed = fix16Sub(bullets[j].speed, FIX16(0.25));
|
|
if(bullets[j].speed <= 0){
|
|
bullets[j].speed = 0;
|
|
bullets[j].clock = -1;
|
|
bullets[j].bools[0] = TRUE;
|
|
}
|
|
updateBulletVel(j);
|
|
}
|
|
}
|
|
spawnBullet(spawner, updater);
|
|
enemies[i].ints[0] += enemies[i].bools[4] ? -64 : 56;
|
|
if(enemies[i].ints[0] > 512 || enemies[i].ints[0] < 0) enemies[i].bools[4] = !enemies[i].bools[4];
|
|
}
|
|
// balls
|
|
if(enemies[i].clock % 45 == 0 && enemies[i].clock > 0){
|
|
struct bulletSpawner spawner = {
|
|
.x = enemies[i].pos.x,
|
|
.y = enemies[i].pos.y,
|
|
.image = &hugeBullet,
|
|
.speed = FIX16(1.75),
|
|
.huge = TRUE
|
|
};
|
|
spawner.vel = hone(enemies[i].pos, player.pos, spawner.speed, 16);
|
|
spawnBullet(spawner, EMPTY);
|
|
}
|
|
}
|
|
}
|
|
} else bossIntro(i);
|
|
}
|
|
void suicide(s16 i){
|
|
bossHealth = 0;
|
|
killBullets = TRUE;
|
|
}
|
|
spawnEnemy(spawner, updater, suicide);
|
|
}
|
|
|
|
static void waveMidboss2(){
|
|
bossAnimateClock = 0;
|
|
struct enemySpawner spawner = {
|
|
.angle = 256,
|
|
.speed = FIX16(1),
|
|
.x = GAME_W / 2,
|
|
.y = -16,
|
|
.image = &cirno,
|
|
.offX = 24,
|
|
.offY = 28,
|
|
.boss = TRUE,
|
|
.health = 60
|
|
};
|
|
bossMax = spawner.health;
|
|
void updater(s16 i){
|
|
bossAnimate(i);
|
|
if(enemies[i].bools[0]){
|
|
bossHealth = enemies[i].health;
|
|
bossMove(i);
|
|
if(enemies[i].health > 40){
|
|
// laser
|
|
if(enemies[i].clock % 30 == 0){
|
|
struct bulletSpawner spawner = {
|
|
.x = enemies[i].pos.x,
|
|
.y = enemies[i].pos.y,
|
|
.image = &hugeBullet,
|
|
.huge = TRUE,
|
|
.speed = FIX16(2),
|
|
.angle = 256,
|
|
.light = TRUE
|
|
};
|
|
spawnBullet(spawner, EMPTY);
|
|
}
|
|
// homing
|
|
if(enemies[i].clock > 0 && enemies[i].clock % 15 == 10){
|
|
struct bulletSpawner spawner = {
|
|
.x = FIX16(random() % (GAME_W - 64) + 32),
|
|
.y = FIX16(32 + random() % 32),
|
|
.image = &bigBullet,
|
|
.speed = FIX16(1.25),
|
|
.angle = 256
|
|
};
|
|
spawner.fixes[0] = spawner.speed;
|
|
void updater(s16 j){
|
|
if(bullets[j].clock == 10){
|
|
bullets[j].speed = 0;
|
|
updateBulletVel(j);
|
|
}
|
|
else if(bullets[j].clock >= 20 && bullets[j].clock % 20 == 0 && bullets[j].clock < 60)
|
|
bullets[j].vel = hone(bullets[j].pos, player.pos, bullets[j].fixes[0], 8);
|
|
}
|
|
spawnBullet(spawner, updater);
|
|
spawnExplosion(spawner.x, spawner.y, 3);
|
|
}
|
|
} else if(enemies[i].health > 20){
|
|
if(!enemies[i].bools[7]){
|
|
killBullets = TRUE;
|
|
enemies[i].bools[7] = TRUE;
|
|
enemies[i].clock = -60;
|
|
}
|
|
// ring
|
|
if(enemies[i].clock % 5 == 0){
|
|
struct bulletSpawner spawner = {
|
|
.x = enemies[i].pos.x,
|
|
.y = enemies[i].pos.y,
|
|
.image = &bigBullet,
|
|
.light = TRUE,
|
|
.speed = FIX16(2),
|
|
.top = TRUE,
|
|
.angle = random() % 128 + (enemies[i].clock % 10 == 0 ? 128 : 256)
|
|
};
|
|
void updater(s16 j){
|
|
if(bullets[j].clock == 20){
|
|
bullets[j].speed = FIX16(1.75);
|
|
updateBulletVel(j);
|
|
} else if(bullets[j].clock == 40){
|
|
bullets[j].speed = FIX16(1.5);
|
|
updateBulletVel(j);
|
|
}
|
|
}
|
|
spawnBullet(spawner, updater);
|
|
}
|
|
// lasers
|
|
if(enemies[i].clock % 15 == 0){
|
|
struct bulletSpawner spawner = {
|
|
.x = enemies[i].pos.x + FIX16(enemies[i].clock % 30 == 0 ? 32 : -32),
|
|
.y = enemies[i].pos.y,
|
|
.image = &hugeBullet,
|
|
.huge = TRUE,
|
|
.speed = FIX16(2),
|
|
.angle = 256
|
|
};
|
|
spawnBullet(spawner, EMPTY);
|
|
}
|
|
} else {
|
|
if(!enemies[i].bools[6]){
|
|
killBullets = TRUE;
|
|
enemies[i].bools[6] = TRUE;
|
|
enemies[i].clock = -60;
|
|
}
|
|
if(enemies[i].clock % 5 == 0){
|
|
struct bulletSpawner spawner = {
|
|
.x = enemies[i].pos.x,
|
|
.y = enemies[i].pos.y,
|
|
.image = &bigBullet,
|
|
.big = TRUE,
|
|
.light = TRUE,
|
|
.speed = FIX16(2),
|
|
.top = TRUE,
|
|
.angle = random() % 128 + (enemies[i].clock % 10 == 0 ? 128 : 256)
|
|
};
|
|
spawner.fixes[0] = FIX16(GAME_H - 8);
|
|
void updater(s16 j){
|
|
if(bullets[j].pos.y >= bullets[j].fixes[0] && !bullets[j].bools[0]){
|
|
bullets[j].bools[0] = TRUE;
|
|
SPR_setAnim(bullets[j].image, 0);
|
|
bullets[j].angle = 768;
|
|
updateBulletVel(j);
|
|
}
|
|
}
|
|
spawnBullet(spawner, updater);
|
|
}
|
|
}
|
|
} else bossIntro(i);
|
|
}
|
|
void suicide(s16 i){
|
|
bossHealth = 0;
|
|
killBullets = TRUE;
|
|
}
|
|
spawnEnemy(spawner, updater, suicide);
|
|
}
|
|
|
|
static void waveBoss1(){
|
|
|
|
bossAnimateClock = 0;
|
|
struct enemySpawner spawner = {
|
|
.angle = 256,
|
|
.speed = FIX16(1),
|
|
.x = GAME_W / 2,
|
|
.y = -16,
|
|
.image = &cirno,
|
|
.offX = 24,
|
|
.offY = 28,
|
|
.boss = TRUE,
|
|
.health = 20
|
|
};
|
|
bossMax = spawner.health;
|
|
void updater(s16 i){
|
|
bossAnimate(i);
|
|
if(enemies[i].bools[0]){
|
|
bossHealth = enemies[i].health;
|
|
bossMove(i);
|
|
if(enemies[i].health > 60){
|
|
// homing
|
|
if(enemies[i].clock % 15 == 10){
|
|
struct bulletSpawner spawner = {
|
|
.x = enemies[i].pos.x,
|
|
.y = enemies[i].pos.y,
|
|
.image = &bigBullet,
|
|
.big = TRUE,
|
|
.angle = 256,
|
|
.speed = FIX16(2),
|
|
.top = TRUE
|
|
};
|
|
spawner.vel = hone(enemies[i].pos, player.pos, spawner.speed, 32);
|
|
spawnBullet(spawner, EMPTY);
|
|
}
|
|
// puke
|
|
else if(enemies[i].clock % 15 == 0 || enemies[i].clock % 15 == 5){
|
|
struct bulletSpawner spawner = {
|
|
.x = enemies[i].pos.x,
|
|
.y = enemies[i].pos.y,
|
|
.image = &bigBullet,
|
|
.big = TRUE,
|
|
.angle = 64 + random() % 384,
|
|
.speed = FIX16(1.25),
|
|
.light = TRUE
|
|
};
|
|
spawnBullet(spawner, EMPTY);
|
|
}
|
|
} else if(enemies[i].health > 40){
|
|
if(!enemies[i].bools[3]){
|
|
enemies[i].bools[3] = TRUE;
|
|
struct bulletSpawner spawner = {
|
|
.x = enemies[i].pos.x,
|
|
.y = enemies[i].pos.y,
|
|
.image = &hugeBullet,
|
|
.huge = TRUE,
|
|
.angle = 768,
|
|
.speed = FIX16(2)
|
|
};
|
|
void updater(s16 j){
|
|
if(bullets[j].clock >= 20 && !bullets[j].bools[0]){
|
|
bullets[j].fixes[0] = bullets[j].pos.x;
|
|
bullets[j].fixes[1] = bullets[j].pos.y;
|
|
bullets[j].bools[0] = TRUE;
|
|
bullets[j].clock = -1;
|
|
bullets[j].angle = 0;
|
|
updateBulletVel(j);
|
|
} else if(bullets[j].bools[0]){
|
|
if(bullets[j].clock % 20 == 15){
|
|
bullets[j].angle += 64;
|
|
if(bullets[j].angle >= 1024){
|
|
bullets[j].angle -= 1024;
|
|
// bullets[j].pos.x = bullets[j].fixes[0];
|
|
// bullets[j].pos.y = bullets[j].fixes[1];
|
|
}
|
|
updateBulletVel(j);
|
|
}
|
|
if(bullets[j].clock % 20 == 0){
|
|
|
|
struct bulletSpawner spawner = {
|
|
.x = bullets[j].pos.x,
|
|
.y = bullets[j].pos.y,
|
|
.image = &bigBullet,
|
|
.big = TRUE,
|
|
// .angle = bullets[j].ints[2],
|
|
.angle = 0,
|
|
.light = bullets[j].clock % 40 == 0,
|
|
.top = TRUE,
|
|
.speed = FIX16(1.75)
|
|
};
|
|
for(u8 h = 0; h < 16; h++){
|
|
if(bullets[j].angle < 256){
|
|
if(spawner.angle >= 256 && spawner.angle < 512) spawnBullet(spawner, EMPTY);
|
|
} else if(bullets[j].angle < 512){
|
|
if(spawner.angle >= 512 && spawner.angle < 768) spawnBullet(spawner, EMPTY);
|
|
} else if(bullets[j].angle < 768){
|
|
if(spawner.angle >= 768) spawnBullet(spawner, EMPTY);
|
|
} else {
|
|
if(spawner.angle < 256) spawnBullet(spawner, EMPTY);
|
|
}
|
|
spawner.angle += 64;
|
|
}
|
|
bullets[j].ints[2] += 50;
|
|
if(bullets[j].ints[2] >= 1024) bullets[j].ints[2] -= 1024;
|
|
|
|
}
|
|
}
|
|
}
|
|
spawnBullet(spawner, updater);
|
|
}
|
|
} else if(enemies[i].health > 20){
|
|
if(enemies[i].clock % 3 == 0){
|
|
struct bulletSpawner spawner = {
|
|
.x = FIX16(random() % GAME_W),
|
|
.y = FIX16(32 + random() % 48),
|
|
.image = &bigBullet,
|
|
.big = TRUE,
|
|
.angle = 0,
|
|
.speed = FIX16(enemies[i].clock % 6 == 0 ? 2.5 : 3.5),
|
|
.light = enemies[i].clock % 6 == 0
|
|
};
|
|
for(u8 j = 0; j < 5; j++){
|
|
if(spawner.angle > 32 && spawner.angle < 480) spawnBullet(spawner, EMPTY);
|
|
spawner.angle += 205;
|
|
}
|
|
}
|
|
} else {
|
|
|
|
}
|
|
} else bossIntro(i);
|
|
}
|
|
void suicide(s16 i){
|
|
bossHealth = 0;
|
|
killBullets = TRUE;
|
|
}
|
|
spawnEnemy(spawner, updater, suicide);
|
|
}
|
|
|
|
// loop
|
|
|
|
s16 currentWave = 18;
|
|
|
|
void updateStage(){
|
|
if(enemyCount == 0){
|
|
switch(currentWave){
|
|
// sine from left
|
|
case 0:
|
|
waveSine(FALSE);
|
|
break;
|
|
// sine from right
|
|
case 1:
|
|
waveSine(TRUE);
|
|
break;
|
|
// big middle
|
|
case 2:
|
|
waveBig1();
|
|
break;
|
|
// sine from left, big right
|
|
case 3:
|
|
waveSine(FALSE);
|
|
waveBig2(FALSE);
|
|
break;
|
|
// sine from right, big left
|
|
case 4:
|
|
waveSine(TRUE);
|
|
waveBig2(TRUE);
|
|
break;
|
|
// big middle
|
|
case 5:
|
|
waveBig3();
|
|
break;
|
|
// swarm (8)
|
|
case 6:
|
|
waveSwarm(8);
|
|
break;
|
|
// big left and right
|
|
case 7:
|
|
waveBig4(TRUE, FALSE);
|
|
waveBig4(FALSE, FALSE);
|
|
break;
|
|
// swarm (2), big right
|
|
case 8:
|
|
waveSwarm(2);
|
|
waveBig4(TRUE, TRUE);
|
|
break;
|
|
// swarm (2), big left
|
|
case 9:
|
|
waveSwarm(2);
|
|
waveBig4(FALSE, TRUE);
|
|
break;
|
|
// midboss
|
|
case 10:
|
|
waveMidboss1();
|
|
break;
|
|
// big from left and right
|
|
case 11:
|
|
waveBig5(FALSE);
|
|
waveBig5(TRUE);
|
|
break;
|
|
// big from right and left
|
|
case 12:
|
|
waveBig6(TRUE);
|
|
waveBig6(FALSE);
|
|
break;
|
|
// big from left, small formation
|
|
case 13:
|
|
waveBig6(FALSE);
|
|
waveFormation(TRUE);
|
|
break;
|
|
// big from right, small formation
|
|
case 14:
|
|
waveBig6(TRUE);
|
|
waveFormation(FALSE);
|
|
break;
|
|
// big from left, small formation
|
|
case 15:
|
|
waveBig6(FALSE);
|
|
waveFormation(TRUE);
|
|
break;
|
|
// big from right, small formation
|
|
case 16:
|
|
waveBig6(TRUE);
|
|
waveFormation(FALSE);
|
|
break;
|
|
// midboss
|
|
case 17:
|
|
waveMidboss2();
|
|
break;
|
|
// midboss
|
|
case 18:
|
|
waveBoss1();
|
|
break;
|
|
|
|
}
|
|
currentWave++;
|
|
}
|
|
|
|
stageClock++;
|
|
if(stageClock >= CLOCK_LIMIT) stageClock -= CLOCK_LIMIT;
|
|
}
|
|
|
|
|
|
/*
|
|
|
|
sine from left
|
|
sine from right
|
|
big middle
|
|
sine from left, big right
|
|
sine from right, big left
|
|
big middle
|
|
swarm
|
|
big from left and right
|
|
swarm, big right
|
|
swarm, big left
|
|
|
|
midboss
|
|
|
|
big from left and right
|
|
big from right and left
|
|
big from left, small formation
|
|
big from right, small formation
|
|
big from left, small formation
|
|
big from right, small formation
|
|
|
|
midboss
|
|
|
|
final boss at 30 seconds left
|
|
|
|
*/ |