here you go
This commit is contained in:
commit
3ea8481a27
117 changed files with 3190 additions and 0 deletions
48
src/background.c
Normal file
48
src/background.c
Normal file
|
@ -0,0 +1,48 @@
|
|||
#include <genesis.h>
|
||||
#include <resources.h>
|
||||
|
||||
#include "main.h"
|
||||
#include "background.h"
|
||||
|
||||
|
||||
void resetBackground(){
|
||||
for(s8 y = 0; y < BG_TILES_HEIGHT; y++){
|
||||
for(s8 x = 0; x < BG_TILES_WIDTH; x++){
|
||||
if(x % 8 == 0 && y % 8 == 0){
|
||||
if(currentZone < 5) VDP_drawImageEx(BG_B, &ground1, TILE_ATTR_FULL(PAL1, 0, 0, 0, 16), x, y, 0, DMA_QUEUE);
|
||||
else if(currentZone == 5) VDP_drawImageEx(BG_B, &ground2, TILE_ATTR_FULL(PAL1, 0, 0, 0, 16), x, y, 0, DMA_QUEUE);
|
||||
else if(currentZone > 5 && currentZone < 10) VDP_drawImageEx(BG_B, &ground3, TILE_ATTR_FULL(PAL1, 0, 0, 0, 16), x, y, 0, DMA_QUEUE);
|
||||
else if(currentZone == 10) VDP_drawImageEx(BG_B, &ground4, TILE_ATTR_FULL(PAL1, 0, 0, 0, 16), x, y, 0, DMA_QUEUE);
|
||||
else if(currentZone > 10 && currentZone < 15) VDP_drawImageEx(BG_B, &ground5, TILE_ATTR_FULL(PAL1, 0, 0, 0, 16), x, y, 0, DMA_QUEUE);
|
||||
else if(currentZone == 15) VDP_drawImageEx(BG_B, &ground6, TILE_ATTR_FULL(PAL1, 0, 0, 0, 16), x, y, 0, DMA_QUEUE);
|
||||
else if(currentZone > 15 && currentZone < 20) VDP_drawImageEx(BG_B, &ground7, TILE_ATTR_FULL(PAL1, 0, 0, 0, 16), x, y, 0, DMA_QUEUE);
|
||||
else if(currentZone == 20) VDP_drawImageEx(BG_B, &ground8, TILE_ATTR_FULL(PAL1, 0, 0, 0, 16), x, y, 0, DMA_QUEUE);
|
||||
}
|
||||
VDP_setTileMapXY(BG_A, TILE_ATTR_FULL(PAL1, 0, 0, 0, 11), x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// stage
|
||||
|
||||
void loadBackgroundStage(){
|
||||
for(s8 i = 0; i < BG_SCROLL_WIDTH; i++){
|
||||
backgroundSpeeds[i] = i < 8 ? BG_SCROLL_WIDTH - i - 2 : i - 1;
|
||||
backgroundSpeeds[i]--;
|
||||
}
|
||||
VDP_setScrollingMode(HSCROLL_PLANE, VSCROLL_2TILE);
|
||||
resetBackground();
|
||||
}
|
||||
|
||||
void updateBackgroundStage(){
|
||||
for(s8 i = 0; i < BG_SCROLL_WIDTH; i++) backgroundScrolls[i] -= fix16ToRoundedInt(FIX16(backgroundSpeeds[i] / 2)) - 1;
|
||||
VDP_setVerticalScrollTile(BG_B, 0, backgroundScrolls, BG_SCROLL_WIDTH, DMA_QUEUE);
|
||||
}
|
||||
|
||||
|
||||
// loop
|
||||
|
||||
void updateBackground(){
|
||||
if(gameStarting) loadBackgroundStage();
|
||||
else updateBackgroundStage();
|
||||
}
|
15
src/background.h
Normal file
15
src/background.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#define BG_TILES_WIDTH 32
|
||||
#define BG_TILES_HEIGHT 32
|
||||
#define BG_SCROLL_WIDTH 16
|
||||
|
||||
s16 backgroundY;
|
||||
s16 backgroundScrolls[BG_SCROLL_WIDTH],
|
||||
backgroundSpeeds[BG_SCROLL_WIDTH];
|
||||
|
||||
void loadBackgroundStage(),
|
||||
loadBackgroundBoss(),
|
||||
loadBackgroundTiles(),
|
||||
resetBackground(),
|
||||
updateBackgroundStage(),
|
||||
updateBackgroundBoss(),
|
||||
updateBackground();
|
565
src/boss.c
Normal file
565
src/boss.c
Normal file
|
@ -0,0 +1,565 @@
|
|||
#include <genesis.h>
|
||||
#include <resources.h>
|
||||
|
||||
#include "main.h"
|
||||
#include "enemies.h"
|
||||
#include "explosion.h"
|
||||
#include "player.h"
|
||||
#include "chrome.h"
|
||||
#include "boss.h"
|
||||
|
||||
|
||||
// shooting
|
||||
|
||||
void bossPatternOne(){
|
||||
if(bossClock % 10 == 0 && bossClock % 60 <= 50){
|
||||
if(bossClock % 60 == 0) bossInt1 = random() % 1024;
|
||||
struct bulletSpawner bSpawn = {
|
||||
.x = FIX16(bossClock % 120 < 60 ? 208 : 48),
|
||||
.y = BOSS_B_Y,
|
||||
.type = 1,
|
||||
.angle = bossInt1,
|
||||
.speed = FIX16(5)
|
||||
};
|
||||
for(s8 b = 0; b < 6; b++){
|
||||
if(bSpawn.angle % 1024 >= 0 && bSpawn.angle % 1024 <= 512) spawnEnemyBullet(bSpawn, eUpdate);
|
||||
bSpawn.angle += 170;
|
||||
}
|
||||
XGM_startPlayPCM(SFX_BULLET_1, 0, SOUND_PCM_CH3);
|
||||
bossInt1 += bossClock % 120 < 60 ? 32 : -32;
|
||||
if(bossClock % 30 == 0) spawnExplosion(fix16ToInt(bSpawn.x), fix16ToInt(bSpawn.y), FALSE);
|
||||
if(bossClock % 20 == 10){
|
||||
bSpawn.velocityX = honeEnemyBullet(bSpawn.x, bSpawn.y, 4, 96, TRUE);
|
||||
bSpawn.velocityY = honeEnemyBullet(bSpawn.x, bSpawn.y, 4, 16, FALSE);
|
||||
bSpawn.type = 4;
|
||||
spawnEnemyBullet(bSpawn, eUpdate);
|
||||
XGM_startPlayPCM(SFX_BULLET_1, 1, SOUND_PCM_CH3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bossPatternTwo(){
|
||||
if(bossClock % 60 == 0){
|
||||
bossInt1 = 240 + random() % 32;
|
||||
bossInt2 = bossClock % 120 == 0 ? 48 : -48;
|
||||
bossInt3 = bossInt2 / 2;
|
||||
}
|
||||
if(bossClock % 8 == 0){
|
||||
struct bulletSpawner bSpawn = {
|
||||
.x = FIX16(bossClock % 120 < 60 ? 208 : 48),
|
||||
.y = BOSS_B_Y,
|
||||
.type = 4,
|
||||
.angle = bossInt1 - bossInt2,
|
||||
.speed = FIX16(5.5)
|
||||
};
|
||||
spawnExplosion(fix16ToInt(bSpawn.x), fix16ToInt(bSpawn.y), FALSE);
|
||||
for(s8 b = 0; b < 3; b++){
|
||||
spawnEnemyBullet(bSpawn, eUpdate);
|
||||
bSpawn.speed = fix16Add(bSpawn.speed, FIX16(1.5));
|
||||
bSpawn.angle += bossInt3;
|
||||
}
|
||||
XGM_startPlayPCM(SFX_BULLET_1, 0, SOUND_PCM_CH3);
|
||||
bossInt1 += bossInt2;
|
||||
}
|
||||
}
|
||||
|
||||
void bossPatternThree(){
|
||||
if(bossClock % 60 < 18 && bossClock % 6 == 0){
|
||||
if(bossClock % 60 == 0){
|
||||
bossInt1 = 3;
|
||||
bossInt2 = bossClock % 120 == 0 ? 68 : -68;
|
||||
bossInt3 = bossClock % 120 == 0 ? 224 : 288;
|
||||
bossFix1 = FIX16(bossClock % 120 < 60 ? 208 : 48);
|
||||
}
|
||||
struct bulletSpawner bSpawn = {
|
||||
.x = bossFix1,
|
||||
.y = BOSS_B_Y,
|
||||
.type = 3,
|
||||
.angle = bossInt3,
|
||||
.speed = FIX16(bossInt1)
|
||||
};
|
||||
if(bossClock % 60 == 0) spawnExplosion(fix16ToInt(bSpawn.x), fix16ToInt(bSpawn.y), FALSE);
|
||||
for(s8 b = 0; b < 4; b++){
|
||||
spawnEnemyBullet(bSpawn, eUpdate);
|
||||
bSpawn.angle += bossInt2;
|
||||
}
|
||||
XGM_startPlayPCM(SFX_BULLET_1, 0, SOUND_PCM_CH3);
|
||||
bossInt1++;
|
||||
}
|
||||
else if(bossClock % 60 >= 30 && bossClock % 5 == 0){
|
||||
if(bossClock % 60 == 30){
|
||||
bossFix1 = FIX16(32 + random() % 192);
|
||||
spawnExplosion(fix16ToInt(bossFix1), fix16ToInt(BOSS_B_Y), FALSE);
|
||||
}
|
||||
struct bulletSpawner bSpawn = {
|
||||
.x = bossFix1,
|
||||
.y = BOSS_B_Y,
|
||||
.type = 2
|
||||
};
|
||||
bSpawn.velocityX = honeEnemyBullet(bSpawn.x, bSpawn.y, 4, 96, TRUE);
|
||||
bSpawn.velocityY = honeEnemyBullet(bSpawn.x, bSpawn.y, 4, 16, FALSE);
|
||||
spawnEnemyBullet(bSpawn, eUpdate);
|
||||
XGM_startPlayPCM(SFX_BULLET_1, 1, SOUND_PCM_CH3);
|
||||
}
|
||||
}
|
||||
|
||||
void bossPatternFour(){
|
||||
if(bossClock % 60 <= 10 && bossClock % 5 == 0){
|
||||
if(bossClock % 60 == 0) bossInt1 = 4;
|
||||
struct bulletSpawner bSpawn = {
|
||||
.x = BOSS_B_X,
|
||||
.y = BOSS_B_Y,
|
||||
.speed = FIX16(bossInt1)
|
||||
};
|
||||
bSpawn.angle = bossClock % 60 == 5 ? 32 : 0;
|
||||
bSpawn.type = bossClock % 60 == 0 ? 3 : 4;
|
||||
for(s8 b = 0; b < (bossClock % 60 == 5 ? 5 : 6); b++){
|
||||
bSpawn.angle += 64;
|
||||
if(b > 0) spawnEnemyBullet(bSpawn, eUpdate);
|
||||
}
|
||||
XGM_startPlayPCM(SFX_BULLET_1, 0, SOUND_PCM_CH3);
|
||||
bossInt1++;
|
||||
} else if(bossClock % 60 >= 30 && bossClock % 5 == 0){
|
||||
struct bulletSpawner bSpawn = {
|
||||
.x = FIX16(bossClock % 10 == 0 ? 208 : 48),
|
||||
.y = BOSS_B_Y,
|
||||
.type = 1
|
||||
};
|
||||
bSpawn.velocityX = honeEnemyBullet(bSpawn.x, bSpawn.y, 4, 96, TRUE);
|
||||
bSpawn.velocityY = honeEnemyBullet(bSpawn.x, bSpawn.y, 4, 16, FALSE);
|
||||
spawnEnemyBullet(bSpawn, eUpdate);
|
||||
XGM_startPlayPCM(SFX_BULLET_1, 1, SOUND_PCM_CH3);
|
||||
spawnExplosion(fix16ToInt(bSpawn.x), fix16ToInt(bSpawn.y), FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
void bossPatternFive(){
|
||||
if(bossClock % 60 == 0){
|
||||
struct bulletSpawner bSpawn = {
|
||||
.x = BOSS_B_X,
|
||||
.y = BOSS_B_Y,
|
||||
.angle = random() % 1024,
|
||||
.speed = FIX16(4),
|
||||
.type = 4
|
||||
};
|
||||
for(s8 b = 0; b < 16; b++){
|
||||
if(bSpawn.angle % 1024 > 0 && bSpawn.angle % 1024 < 512){
|
||||
spawnEnemyBullet(bSpawn, eUpdate);
|
||||
}
|
||||
bSpawn.angle += 64;
|
||||
}
|
||||
XGM_startPlayPCM(SFX_BULLET_1, 0, SOUND_PCM_CH3);
|
||||
} else if(bossClock % 60 >= 30 && bossClock % 60 < 45 && bossClock % 5 == 0){
|
||||
struct bulletSpawner bSpawn = {
|
||||
.x = BOSS_B_X,
|
||||
.y = BOSS_B_Y,
|
||||
.type = bossClock % 60 >= 38 ? 3 : 4
|
||||
};
|
||||
bSpawn.velocityX = honeEnemyBullet(bSpawn.x, bSpawn.y, 5, 128, TRUE);
|
||||
bSpawn.velocityY = honeEnemyBullet(bSpawn.x, bSpawn.y, 5, 16, FALSE);
|
||||
spawnEnemyBullet(bSpawn, eUpdate);
|
||||
XGM_startPlayPCM(SFX_BULLET_1, 0, SOUND_PCM_CH3);
|
||||
}
|
||||
if(bossClock % 60 >= 30 && bossClock % 5 == 3){
|
||||
struct bulletSpawner bSpawn = {
|
||||
.x = FIX16(bossClock % 30 < 15 ? 208 : 48),
|
||||
.y = BOSS_B_Y,
|
||||
.type = bossClock % 15 > 6 ? 1 : 2
|
||||
};
|
||||
if(bossClock % 15 == 0){
|
||||
bossFix1 = bSpawn.x;
|
||||
bossFix2 = bSpawn.y;
|
||||
}
|
||||
spawnExplosion(fix16ToInt(bSpawn.x), fix16ToInt(bSpawn.y), FALSE);
|
||||
bSpawn.velocityX = honeEnemyBullet(bossFix1, bossFix2, 4, 32, TRUE);
|
||||
bSpawn.velocityY = honeEnemyBullet(bossFix1, bossFix2, 4, 16, FALSE);
|
||||
spawnEnemyBullet(bSpawn, eUpdate);
|
||||
XGM_startPlayPCM(SFX_BULLET_1, 1, SOUND_PCM_CH3);
|
||||
}
|
||||
}
|
||||
|
||||
void bossPatternSix(){
|
||||
if(bossClock % 5 == 0 && bossClock % 120 < 110){
|
||||
if(bossClock % 120 == 0){
|
||||
bossInt1 = 0 + random() % 32;
|
||||
bossInt2 = 512 - random() % 32;
|
||||
bossInt3 = 1;
|
||||
}
|
||||
struct bulletSpawner bSpawn = {
|
||||
.x = FIX16(48),
|
||||
.y = BOSS_B_Y,
|
||||
.angle = bossInt1,
|
||||
.speed = FIX16(7),
|
||||
.type = bossClock % 240 < 120 ? 4 : 2
|
||||
};
|
||||
if(bossClock % 10 == 0) spawnExplosion(fix16ToInt(bSpawn.x), fix16ToInt(bSpawn.y), FALSE);
|
||||
for(s8 b = 0; b < 2; b++){
|
||||
if(bSpawn.angle % 1024 < 512) spawnEnemyBullet(bSpawn, eUpdate);
|
||||
bSpawn.angle += 512;
|
||||
}
|
||||
XGM_startPlayPCM(SFX_BULLET_1, 0, SOUND_PCM_CH3);
|
||||
bSpawn.x = FIX16(208);
|
||||
bSpawn.angle = bossInt2;
|
||||
if(bossClock % 10 == 5) spawnExplosion(fix16ToInt(bSpawn.x), fix16ToInt(bSpawn.y), FALSE);
|
||||
for(s8 b = 0; b < 2; b++){
|
||||
if((bSpawn.angle < 0 && abs(bSpawn.angle) % 1024 > 512) || (bSpawn.angle >= 0 && bSpawn.angle < 512)) spawnEnemyBullet(bSpawn, eUpdate);
|
||||
bSpawn.angle += 512;
|
||||
}
|
||||
bossInt1 += 5 * bossInt3;
|
||||
bossInt2 -= 10 * bossInt3;
|
||||
bossInt3++;
|
||||
}
|
||||
}
|
||||
|
||||
void bossPatternSeven(){
|
||||
if(bossClock % 120 < 100){
|
||||
if(bossClock % 120 == 0) bossInt1 = 0;
|
||||
if(bossClock % 15 == 0){
|
||||
struct bulletSpawner bSpawn = {
|
||||
.x = BOSS_B_X,
|
||||
.y = BOSS_B_Y,
|
||||
.angle = 0 + bossInt1,
|
||||
.speed = FIX16(8),
|
||||
.type = 2
|
||||
};
|
||||
for(s8 b = 0; b < 16; b++){
|
||||
if(bSpawn.angle % 1024 > 32 && bSpawn.angle % 1024 < 480) spawnEnemyBullet(bSpawn, eUpdate);
|
||||
bSpawn.angle += 64;
|
||||
}
|
||||
XGM_startPlayPCM(SFX_BULLET_1, 0, SOUND_PCM_CH3);
|
||||
bossInt1 += 24;
|
||||
}
|
||||
if(bossClock % 10 == 5){
|
||||
struct bulletSpawner bSpawn = {
|
||||
.x = BOSS_B_X,
|
||||
.y = BOSS_B_Y,
|
||||
.type = 3
|
||||
};
|
||||
bSpawn.velocityX = honeEnemyBullet(bSpawn.x, bSpawn.y, 5, 128, TRUE);
|
||||
bSpawn.velocityY = honeEnemyBullet(bSpawn.x, bSpawn.y, 5, 16, FALSE);
|
||||
spawnEnemyBullet(bSpawn, eUpdate);
|
||||
XGM_startPlayPCM(SFX_BULLET_1, 1, SOUND_PCM_CH3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bossPatternEight(){
|
||||
if(bossClock % 30 == 0){
|
||||
struct bulletSpawner bSpawn = {
|
||||
.x = FIX16(bossClock % 60 == 0 ? 208 : 48),
|
||||
.y = BOSS_B_Y,
|
||||
.angle = random() % 1024,
|
||||
.speed = FIX16(8),
|
||||
.type = 1
|
||||
};
|
||||
spawnExplosion(fix16ToInt(bSpawn.x), fix16ToInt(bSpawn.y), FALSE);
|
||||
for(s8 b = 0; b < 8; b++){
|
||||
if(bSpawn.angle % 1024 > 0 && bSpawn.angle % 1024 < 512){
|
||||
spawnEnemyBullet(bSpawn, eUpdate);
|
||||
bSpawn.angle += 48;
|
||||
spawnEnemyBullet(bSpawn, eUpdate);
|
||||
} else bSpawn.angle += 48;
|
||||
bSpawn.angle += 80;
|
||||
}
|
||||
XGM_startPlayPCM(SFX_BULLET_1, 0, SOUND_PCM_CH3);
|
||||
} else if(bossClock % 30 == 15){
|
||||
struct bulletSpawner bSpawn = {
|
||||
.x = FIX16(bossClock % 60 == 15 ? 192 : 64),
|
||||
.y = BOSS_B_Y,
|
||||
.angle = random() % 1024,
|
||||
.speed = FIX16(6),
|
||||
.type = 4
|
||||
};
|
||||
spawnExplosion(fix16ToInt(bSpawn.x), fix16ToInt(bSpawn.y), FALSE);
|
||||
for(s8 b = 0; b < 16; b++){
|
||||
if(bSpawn.angle % 1024 > 0 && bSpawn.angle % 1024 < 512) spawnEnemyBullet(bSpawn, eUpdate);
|
||||
bSpawn.angle += 64;
|
||||
}
|
||||
XGM_startPlayPCM(SFX_BULLET_1, 1, SOUND_PCM_CH3);
|
||||
}
|
||||
}
|
||||
|
||||
void bossPatternNine(){
|
||||
if(bossClock % 60 < 40 && bossClock % 6 == 0){
|
||||
struct bulletSpawner bSpawn = {
|
||||
.x = FIX16(64 + random() % 128),
|
||||
.y = BOSS_B_Y,
|
||||
.type = 3
|
||||
};
|
||||
spawnExplosion(fix16ToInt(bSpawn.x), fix16ToInt(bSpawn.y), FALSE);
|
||||
for(s8 b = 0; b < 4; b++){
|
||||
bSpawn.type = b % 2 == 0 ? 3 : 4;
|
||||
bSpawn.velocityX = honeEnemyBullet(bSpawn.x, bSpawn.y, 5, 192, TRUE);
|
||||
bSpawn.velocityY = honeEnemyBullet(bSpawn.x, bSpawn.y, 5, 8, FALSE);
|
||||
spawnEnemyBullet(bSpawn, eUpdate);
|
||||
}
|
||||
XGM_startPlayPCM(SFX_BULLET_1, 0, SOUND_PCM_CH3);
|
||||
}
|
||||
}
|
||||
|
||||
void bossPatternTen(){
|
||||
if(bossClock % 15 == 0){
|
||||
struct bulletSpawner bSpawn = {
|
||||
.x = FIX16(64 + random() % 128),
|
||||
.y = BOSS_B_Y,
|
||||
.type = bossClock % 30 == 0 ? 4 : 3,
|
||||
.angle = random() % 1024,
|
||||
.speed = FIX16(bossClock % 30 == 0 ? 7 : 5)
|
||||
};
|
||||
spawnExplosion(fix16ToInt(bSpawn.x), fix16ToInt(bSpawn.y), FALSE);
|
||||
for(s8 b = 0; b < 16; b++){
|
||||
if(bSpawn.angle % 1024 > 0 && bSpawn.angle % 1024 < 512) spawnEnemyBullet(bSpawn, eUpdate);
|
||||
bSpawn.angle += 64;
|
||||
}
|
||||
XGM_startPlayPCM(SFX_BULLET_1, 0, SOUND_PCM_CH3);
|
||||
}
|
||||
else if(bossClock % 60 > 15 && bossClock % 60 < 30 && bossClock % 2 == 0){
|
||||
struct bulletSpawner bSpawn = {
|
||||
.x = BOSS_B_X,
|
||||
.y = BOSS_B_Y,
|
||||
.type = bossClock % 4 == 0 ? 2 : 1
|
||||
};
|
||||
bSpawn.velocityX = honeEnemyBullet(bSpawn.x, bSpawn.y, 6, 96, TRUE);
|
||||
bSpawn.velocityY = honeEnemyBullet(bSpawn.x, bSpawn.y, 6, 8, FALSE);
|
||||
spawnEnemyBullet(bSpawn, eUpdate);
|
||||
XGM_startPlayPCM(SFX_BULLET_1, 1, SOUND_PCM_CH3);
|
||||
}
|
||||
}
|
||||
|
||||
void bossPatternEleven(){
|
||||
if(bossClock % 60 < 30 && bossClock % 4 == 0){
|
||||
struct bulletSpawner bSpawn = {
|
||||
.x = FIX16(bossClock % 120 < 60 ? 208 : 48),
|
||||
.y = BOSS_B_Y,
|
||||
.type = 3
|
||||
};
|
||||
if(bossClock % 60 == 0) bossInt1 = 4;
|
||||
if(bossClock % 60 == 0 || bossClock % 60 == 12) spawnExplosion(fix16ToInt(bSpawn.x), fix16ToInt(bSpawn.y), FALSE);
|
||||
bSpawn.velocityX = honeEnemyBullet(bSpawn.x, bSpawn.y, bossInt1, 64, TRUE);
|
||||
bSpawn.velocityY = honeEnemyBullet(bSpawn.x, bSpawn.y, bossInt1, 8, FALSE);
|
||||
spawnEnemyBullet(bSpawn, eUpdate);
|
||||
XGM_startPlayPCM(SFX_BULLET_1, 0, SOUND_PCM_CH3);
|
||||
bossInt1++;
|
||||
}
|
||||
if(bossClock % 15 == 5){
|
||||
struct bulletSpawner bSpawn = {
|
||||
.x = BOSS_B_X,
|
||||
.y = BOSS_B_Y,
|
||||
.type = 2,
|
||||
.angle = bossClock % 30 == 5 ? 32 : 0,
|
||||
.speed = FIX16(6)
|
||||
};
|
||||
for(s8 b = 0; b < 16; b++){
|
||||
if(bSpawn.angle % 1024 > 0 && bSpawn.angle % 1024 < 512) spawnEnemyBullet(bSpawn, eUpdate);
|
||||
bSpawn.angle += 64;
|
||||
}
|
||||
XGM_startPlayPCM(SFX_BULLET_1, 1, SOUND_PCM_CH3);
|
||||
}
|
||||
}
|
||||
|
||||
void bossPatternTwelve(){
|
||||
if(bossClock % 60 < 35 && bossClock % 6 == 0){
|
||||
if(bossClock % 60 == 0){
|
||||
bossInt1 = 320;
|
||||
bossInt2 = 192;
|
||||
}
|
||||
struct bulletSpawner bSpawn = {
|
||||
.x = FIX16(bossClock % 12 == 0 ? 208 : 48),
|
||||
.y = BOSS_B_Y,
|
||||
.speed = FIX16(7),
|
||||
.angle = bossClock % 12 == 0 ? bossInt2 : bossInt1,
|
||||
.type = 4
|
||||
};
|
||||
for(s8 b = 0; b < 4; b++){
|
||||
spawnEnemyBullet(bSpawn, eUpdate);
|
||||
bSpawn.angle += bossClock % 12 == 0 ? 64 : -64;
|
||||
}
|
||||
XGM_startPlayPCM(SFX_BULLET_1, 0, SOUND_PCM_CH3);
|
||||
bossInt1 -= 8;
|
||||
bossInt2 += 8;
|
||||
}
|
||||
if(bossClock % 3 == 1 && bossClock % 30 < 15){
|
||||
struct bulletSpawner bSpawn = {
|
||||
.x = BOSS_B_X,
|
||||
.y = BOSS_B_Y,
|
||||
.type = 1
|
||||
};
|
||||
if(bossClock % 30 == 1){
|
||||
bossFix1 = honeEnemyBullet(bSpawn.x, bSpawn.y, 7, 0, TRUE);
|
||||
bossFix2 = honeEnemyBullet(bSpawn.x, bSpawn.y, 7, 0, FALSE);
|
||||
}
|
||||
bSpawn.velocityX = bossFix1;
|
||||
bSpawn.velocityY = bossFix2;
|
||||
spawnEnemyBullet(bSpawn, eUpdate);
|
||||
XGM_startPlayPCM(SFX_BULLET_1, 1, SOUND_PCM_CH3);
|
||||
}
|
||||
}
|
||||
|
||||
void bossPatternThirteen(){
|
||||
if(bossClock % 5 == 0){
|
||||
if(bossClock == 0){
|
||||
bossInt1 = 0;
|
||||
bossInt2 = 1024;
|
||||
}
|
||||
struct bulletSpawner bSpawn = {
|
||||
.x = FIX16(bossClock % 10 == 0 ? 208 : 48),
|
||||
.y = BOSS_B_Y,
|
||||
.type = 3,
|
||||
.angle = bossClock % 10 == 0 ? bossInt2 : bossInt1,
|
||||
.speed = FIX16(6)
|
||||
};
|
||||
spawnExplosion(fix16ToInt(bSpawn.x), fix16ToInt(bSpawn.y), FALSE);
|
||||
for(s8 b = 0; b < 5; b++){
|
||||
if(bSpawn.angle % 1024 > 0 && bSpawn.angle % 1024 < 512) spawnEnemyBullet(bSpawn, eUpdate);
|
||||
bSpawn.angle += 205;
|
||||
}
|
||||
XGM_startPlayPCM(SFX_BULLET_1, 0, SOUND_PCM_CH3);
|
||||
bossInt1 += 19;
|
||||
bossInt2 -= 15;
|
||||
if(bossInt1 >= 1024) bossInt1 = 0;
|
||||
if(bossInt2 <= 0) bossInt2 = 1024;
|
||||
}
|
||||
if(bossClock % 60 == 35 || bossClock % 60 == 36){
|
||||
struct bulletSpawner bSpawn = {
|
||||
.x = BOSS_B_X,
|
||||
.y = BOSS_B_Y,
|
||||
.type = bossClock % 60 == 35 ? 2 : 1,
|
||||
.angle = bossClock % 60 == 35 ? 0 : 32,
|
||||
.speed = FIX16(bossClock % 60 == 35 ? 5 : 8)
|
||||
};
|
||||
for(s8 b = 0; b < 8; b++){
|
||||
if(b > 0 && (bossClock % 60 == 35 || (bossClock % 60 == 36 && b < 7))) spawnEnemyBullet(bSpawn, eUpdate);
|
||||
bSpawn.angle += 64;
|
||||
}
|
||||
XGM_startPlayPCM(SFX_BULLET_1, 1, SOUND_PCM_CH3);
|
||||
}
|
||||
}
|
||||
|
||||
void hitBossPattern(u8 i){
|
||||
if(!hitBossPatterns[i]){
|
||||
hitBossPatterns[i] = TRUE;
|
||||
bossClock = BOSS_SWITCH_TIME;
|
||||
killBullets = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
void shootBoss(){
|
||||
switch(bossType){
|
||||
case 1:
|
||||
if(bossHealth < 50){
|
||||
hitBossPattern(0);
|
||||
if(bossClock >= 0) bossPatternTwo();
|
||||
} else if(bossClock >= 0) bossPatternOne();
|
||||
break;
|
||||
case 2:
|
||||
if(bossHealth < 50){
|
||||
hitBossPattern(2);
|
||||
if(bossClock >= 0) bossPatternFour();
|
||||
} else if(bossHealth < 100){
|
||||
hitBossPattern(1);
|
||||
if(bossClock >= 0) bossPatternFive();
|
||||
} else if(bossClock >= 0) bossPatternThree();
|
||||
break;
|
||||
case 3:
|
||||
if(bossHealth < 50){
|
||||
hitBossPattern(4);
|
||||
if(bossClock >= 0) bossPatternEight();
|
||||
} else if(bossHealth < 100){
|
||||
hitBossPattern(3);
|
||||
if(bossClock >= 0) bossPatternSeven();
|
||||
} else if(bossClock >= 0) bossPatternSix();
|
||||
break;
|
||||
case 4:
|
||||
if(bossHealth < 50){
|
||||
hitBossPattern(8);
|
||||
if(bossClock >= 0) bossPatternThirteen();
|
||||
} else if(bossHealth < 100){
|
||||
hitBossPattern(7);
|
||||
if(bossClock >= 0) bossPatternTwelve();
|
||||
} else if(bossHealth < 150){
|
||||
hitBossPattern(6);
|
||||
if(bossClock >= 0) bossPatternEleven();
|
||||
} else if(bossHealth < 200){
|
||||
hitBossPattern(5);
|
||||
if(bossClock >= 0) bossPatternTen();
|
||||
} else if(bossClock >= 0) bossPatternNine();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// collision
|
||||
|
||||
void hitBoss(){
|
||||
bossHealth--;
|
||||
// bossHealth -= 10;
|
||||
if(bossHealth <= 0) finishBoss();
|
||||
}
|
||||
|
||||
void collideBoss(){
|
||||
if(bombing && bossClock % 10 == 0) bossHealth--;
|
||||
for(s16 j = 0; j < PLAYER_BULLET_LIMIT; j++) if(playerBullets[j].active) {
|
||||
bossCollisionDistance = getApproximatedDistance(
|
||||
fix32Sub(fix16ToFix32(playerBullets[j].pos.x), BOSS_X),
|
||||
fix32Sub(fix16ToFix32(playerBullets[j].pos.y), BOSS_Y));
|
||||
if(bossCollisionDistance < BOSS_COLLIDE_OFFSET){
|
||||
spawnExplosion(fix16ToInt(playerBullets[j].pos.x), fix16ToInt(playerBullets[j].pos.y), TRUE);
|
||||
hitBoss();
|
||||
removePlayerBullet(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void finishBoss(){
|
||||
bossActive = FALSE;
|
||||
bossLoaded = FALSE;
|
||||
zoneOver = TRUE;
|
||||
bossClock = BOSS_SWITCH_TIME;
|
||||
for(s8 x = 0; x < 8; x++) for(s8 y = 0; y < 8; y++) VDP_setTileMapXY(BG_A, TILE_ATTR_FULL(PAL1, 0, 0, 0, 11), x + 12, y + 4);
|
||||
for(s8 x = 0; x < BOSS_TILE_COUNT; x++) VDP_setTileMapXY(BG_A, TILE_ATTR_FULL(PAL1, 0, 0, 0, 11), x + 1, BOSS_TILE_Y);
|
||||
|
||||
|
||||
// VDP_drawImageEx(BG_A, &chromeEnemy, TILE_ATTR_FULL(PAL1, 1, 0, 0, 190), 1, BOSS_TILE_Y, 0, DMA_QUEUE);
|
||||
}
|
||||
|
||||
|
||||
// loop
|
||||
|
||||
void loadBoss(){
|
||||
bossType++;
|
||||
// bossType = 4;
|
||||
switch(bossType){
|
||||
case 1:
|
||||
bossHealth = 100;
|
||||
break;
|
||||
case 2:
|
||||
bossHealth = 150;
|
||||
break;
|
||||
case 3:
|
||||
bossHealth = 150;
|
||||
break;
|
||||
case 4:
|
||||
bossHealth = 250;
|
||||
break;
|
||||
}
|
||||
bossLoaded = FALSE;
|
||||
bossActive = TRUE;
|
||||
bossMax = bossHealth;
|
||||
}
|
||||
|
||||
void updateBoss(){
|
||||
if(bossActive) {
|
||||
if(bossLoaded){
|
||||
collideBoss();
|
||||
if(!gameOver) shootBoss();
|
||||
} else if(bossClock == BOSS_LOAD_TIME){
|
||||
VDP_drawImageEx(BG_A,
|
||||
(bossType == 1 ? &roll : (bossType == 2 ? &waffle : (bossType == 3 ? &cake : &parfait))),
|
||||
TILE_ATTR_FULL(PAL1, 0, 0, 0, 92), 12, 4, 0, DMA_QUEUE);
|
||||
bossLoaded = TRUE;
|
||||
bossClock = -1;
|
||||
}
|
||||
bossClock++;
|
||||
if(bossClock >= 600) bossClock = 0;
|
||||
}
|
||||
}
|
47
src/boss.h
Normal file
47
src/boss.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
#define BOSS_LOAD_TIME 15
|
||||
|
||||
#define BOSS_X FIX32(16 * 8)
|
||||
#define BOSS_Y FIX32(8 * 8)
|
||||
#define BOSS_B_X fix32ToFix16(BOSS_X)
|
||||
#define BOSS_B_Y fix32ToFix16(BOSS_Y)
|
||||
#define BOSS_X_OFFSET FIX16(8 * 10)
|
||||
#define BOSS_X_OFFSET_NEG fix16Sub(FIX16(0), BOSS_X_OFFSET)
|
||||
|
||||
#define BOSS_COLLIDE_OFFSET FIX32(40)
|
||||
|
||||
#define BOSS_SWITCH_TIME -90
|
||||
|
||||
s16 bossClock, bossInt1, bossInt2, bossInt3, bossType, bossHealth, bossMax;
|
||||
f16 bossFix1, bossFix2;
|
||||
s32 bossCollisionDistance;
|
||||
|
||||
bool hitBossPatterns[8];
|
||||
bool bossActive, bossLoaded;
|
||||
|
||||
void loadBoss(),
|
||||
|
||||
bossPatternOne(),
|
||||
bossPatternTwo(),
|
||||
|
||||
bossPatternThree(),
|
||||
bossPatternFour(),
|
||||
bossPatternFive(),
|
||||
|
||||
bossPatternSix(),
|
||||
bossPatternSeven(),
|
||||
bossPatternEight(),
|
||||
|
||||
bossPatternNine(),
|
||||
bossPatternTen(),
|
||||
bossPatternEleven(),
|
||||
bossPatternTwelve(),
|
||||
bossPatternThirteen(),
|
||||
|
||||
hitBossPattern(u8),
|
||||
|
||||
drawBoss(),
|
||||
collideBoss(),
|
||||
hitBoss(),
|
||||
finishBoss(),
|
||||
shootBoss(),
|
||||
updateBoss();
|
195
src/centipede.c
Normal file
195
src/centipede.c
Normal file
|
@ -0,0 +1,195 @@
|
|||
#include <genesis.h>
|
||||
#include <resources.h>
|
||||
|
||||
#include "main.h"
|
||||
#include "enemies.h"
|
||||
#include "centipede.h"
|
||||
#include "player.h"
|
||||
#include "pod.h"
|
||||
#include "explosion.h"
|
||||
|
||||
|
||||
// spawn
|
||||
|
||||
void spawnCentipede(){}
|
||||
|
||||
|
||||
// movement
|
||||
|
||||
void moveCentipede(s16 i){
|
||||
if(centipedes[i].flipping){
|
||||
centipedes[i].pos.y = fix16Add(centipedes[i].pos.y, (centipedes[i].flippedY ? fix16Sub(FIX16(0), centipedes[i].speed) : centipedes[i].speed));
|
||||
centipedes[i].flipClock++;
|
||||
if((centipedes[i].flippedY && centipedes[i].pos.y <= centipedes[i].nextY) || (!centipedes[i].flippedY && centipedes[i].pos.y >= centipedes[i].nextY)){
|
||||
centipedes[i].flipping = FALSE;
|
||||
centipedes[i].pos.y = centipedes[i].nextY;
|
||||
}
|
||||
} else {
|
||||
centipedes[i].pos.x = fix16Add(centipedes[i].pos.x, (centipedes[i].flippedX ? fix16Sub(FIX16(0), centipedes[i].speed) : centipedes[i].speed));
|
||||
if(centipedes[i].pos.x >= CENTIPEDE_LIMIT_RIGHT || centipedes[i].pos.x <= CENTIPEDE_LIMIT_LEFT){
|
||||
centipedes[i].flippedX = centipedes[i].pos.x >= CENTIPEDE_LIMIT_RIGHT;
|
||||
if(!centipedes[i].flippedY && centipedes[i].pos.y >= CENTIPEDE_LIMIT_BOTTOM){
|
||||
centipedes[i].flippedY = TRUE;
|
||||
if(i == lastCentipede && lastCentipede < centipedeCount){
|
||||
struct podSpawner pSpawn = {
|
||||
.x = FIX16(fix16ToInt(centipedes[i].pos.x) / 16 * 16),
|
||||
.y = FIX16(fix16ToInt(centipedes[i].pos.y) / 16 * 16),
|
||||
.random = FALSE
|
||||
};
|
||||
spawnPod(pSpawn);
|
||||
}
|
||||
// can add another head
|
||||
}else if(centipedes[i].flippedY && centipedes[i].pos.y <= CENTIPEDE_LIMIT_TOP) centipedes[i].flippedY = FALSE;
|
||||
centipedes[i].flipping = TRUE;
|
||||
centipedes[i].nextY = centipedes[i].flippedY ? fix16Sub(centipedes[i].pos.y, FIX16(16)) : fix16Add(centipedes[i].pos.y, FIX16(16));
|
||||
}
|
||||
if(centipedes[i].flipClock > 0) centipedes[i].flipClock = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// change sprite
|
||||
|
||||
void animateCentipede(s16 i){
|
||||
if(centipedes[i].definition > 0){
|
||||
switch(centipedes[i].definition){
|
||||
case 1:
|
||||
SPR_setDefinition(centipedes[i].image, &imgGumdropRed);
|
||||
break;
|
||||
case 2:
|
||||
SPR_setDefinition(centipedes[i].image, &imgGumdropGreen);
|
||||
break;
|
||||
case 3:
|
||||
SPR_setDefinition(centipedes[i].image, &imgGumdropBlue);
|
||||
break;
|
||||
}
|
||||
centipedes[i].definition = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// collision against centipede
|
||||
|
||||
void hitCentipede(s16 i){
|
||||
spawnExplosion(fix16ToInt(centipedes[i].pos.x), fix16ToInt(centipedes[i].pos.y), TRUE);
|
||||
centipedes[i].health -= CENTIPEDE_HIT;
|
||||
XGM_startPlayPCM(random() % 2 < 1 ? SFX_EXPLOSION_1 : SFX_EXPLOSION_2, 1, SOUND_PCM_CH4);
|
||||
currentScore += 7;
|
||||
if(centipedes[i].health < 0){
|
||||
struct podSpawner pSpawn = {
|
||||
.x = FIX16(fix16ToInt(centipedes[i].pos.x) / 16 * 16),
|
||||
.y = FIX16(fix16ToInt(centipedes[i].pos.y) / 16 * 16),
|
||||
.random = FALSE
|
||||
};
|
||||
spawnPod(pSpawn);
|
||||
destroyCentipede(i);
|
||||
currentScore += currentZone >= 10 ? 2500 : 1500;
|
||||
XGM_startPlayPCM(SFX_EXPLOSION_3, 2, SOUND_PCM_CH4);
|
||||
} else if(centipedes[i].health < 33) centipedes[i].definition = 1;
|
||||
else if(centipedes[i].health < 67) centipedes[i].definition = 2;
|
||||
}
|
||||
|
||||
void turnCentipede(s16 i, s16 j){
|
||||
centipedes[i].flippedX = centipedes[i].flippedX ? FALSE : TRUE;
|
||||
centipedes[i].turning = TRUE;
|
||||
centipedes[i].turnClock = 0;
|
||||
if(centipedes[i].pos.x < pods[j].pos.x) centipedes[i].pos.x = fix16Sub(pods[j].pos.x, FIX16(8));
|
||||
else if(centipedes[i].pos.x >= pods[j].pos.x) centipedes[i].pos.x = fix16Add(pods[j].pos.x, FIX16(8));
|
||||
}
|
||||
|
||||
void collideCentipede(s16 i){
|
||||
// against pods
|
||||
for(s16 j = 0; j < POD_COUNT; j++) if(pods[j].active) {
|
||||
centipedePodCheck = getApproximatedDistance(
|
||||
fix16ToFix32(centipedes[i].pos.x) - fix16ToFix32(pods[j].pos.x),
|
||||
fix16ToFix32(centipedes[i].pos.y) - fix16ToFix32(pods[j].pos.y));
|
||||
if(centipedePodCheck < CENTIPEDE_POD_OFFSET) turnCentipede(i, j);
|
||||
}
|
||||
|
||||
if(bombing && centipedes[i].clock % 20 == 0) hitCentipede(i);
|
||||
// against player bullet
|
||||
centipedeCollided = FALSE;
|
||||
for(s16 j = 0; j < PLAYER_BULLET_LIMIT; j++) if(playerBullets[j].active) {
|
||||
if(fix16Sub(playerBullets[j].pos.y, CENTIPEDE_BULLET_OFFSET) <= fix16Add(centipedes[i].pos.y, CENTIPEDE_COLLIDE_OFFSET) &&
|
||||
fix16Add(playerBullets[j].pos.y, CENTIPEDE_BULLET_OFFSET) >= fix16Sub(centipedes[i].pos.y, CENTIPEDE_COLLIDE_OFFSET) &&
|
||||
fix16Sub(playerBullets[j].pos.x, CENTIPEDE_BULLET_OFFSET) <= fix16Add(centipedes[i].pos.x, CENTIPEDE_COLLIDE_OFFSET) &&
|
||||
fix16Add(playerBullets[j].pos.x, CENTIPEDE_BULLET_OFFSET) >= fix16Sub(centipedes[i].pos.x, CENTIPEDE_COLLIDE_OFFSET)){
|
||||
centipedeCollided = TRUE;
|
||||
hitCentipede(i);
|
||||
removePlayerBullet(j);
|
||||
}
|
||||
}
|
||||
// against player
|
||||
if(centipedes[i].clock % 4 == 0 && (!centipedeCollided && centipedes[i].pos.y >= fix16Sub(playerPos.y, FIX16(32)))){
|
||||
if(fix16Sub(playerPos.y, CENTIPEDE_PLAYER_OFFSET) <= fix16Add(centipedes[i].pos.y, CENTIPEDE_COLLIDE_OFFSET) &&
|
||||
fix16Add(playerPos.y, CENTIPEDE_PLAYER_OFFSET) >= fix16Sub(centipedes[i].pos.y, CENTIPEDE_COLLIDE_OFFSET) &&
|
||||
fix16Sub(playerPos.x, CENTIPEDE_PLAYER_OFFSET) <= fix16Add(centipedes[i].pos.x, CENTIPEDE_COLLIDE_OFFSET) &&
|
||||
fix16Add(playerPos.x, CENTIPEDE_PLAYER_OFFSET) >= fix16Sub(centipedes[i].pos.x, CENTIPEDE_COLLIDE_OFFSET)){
|
||||
// hitCentipede(i);
|
||||
// turnCentipede(i);
|
||||
// hit player here
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void destroyCentipede(s16 i){
|
||||
centipedes[i].active = FALSE;
|
||||
centipedes[i].flippedX = FALSE;
|
||||
centipedes[i].flippedY = FALSE;
|
||||
centipedes[i].flipping = FALSE;
|
||||
centipedes[i].flag1 = FALSE;
|
||||
centipedes[i].pos.x = CENTIPEDE_DUMP_X;
|
||||
centipedes[i].pos.y = CENTIPEDE_DUMP_Y;
|
||||
SPR_releaseSprite(centipedes[i].image);
|
||||
}
|
||||
|
||||
|
||||
// loop
|
||||
|
||||
void loadCentipede(){
|
||||
centipedeCount = 4;
|
||||
if(currentZone >= 5) centipedeCount++;
|
||||
if(currentZone >= 10) centipedeCount++;
|
||||
if(currentZone >= 15) centipedeCount++;
|
||||
for(s16 i = 0; i < centipedeCount; i++){
|
||||
centipedes[i].active = TRUE;
|
||||
centipedes[i].pos.x = FIX16(16 + 16 * i);
|
||||
centipedes[i].pos.y = CENTIPEDE_LIMIT_TOP;
|
||||
// centipedes[i].speed = FIX16(currentZone >= 10 ? 4 : 2);
|
||||
centipedes[i].speed = FIX16(2);
|
||||
centipedes[i].image = SPR_addSprite(&imgGumdropRed, fix16ToInt(centipedes[i].pos.x), fix16ToInt(centipedes[i].pos.y), TILE_ATTR(PAL1, 0, FALSE, FALSE));
|
||||
centipedes[i].definition = 3;
|
||||
centipedes[i].health = i % 2 == 0 ? 80 : 100;
|
||||
centipedes[i].opposite = i % 2 == 1;
|
||||
SPR_setDepth(centipedes[i].image, 3);
|
||||
}
|
||||
}
|
||||
|
||||
void resetCentipede(){
|
||||
for(s16 i = 0; i < centipedeCount; i++) destroyCentipede(i);
|
||||
}
|
||||
|
||||
void updateCentipede(){
|
||||
zoneOverCheck = TRUE;
|
||||
tempLastCentipede = 0;
|
||||
for(s16 i = 0; i < centipedeCount; i++) if(centipedes[i].active) {
|
||||
tempLastCentipede++;
|
||||
zoneOverCheck = FALSE;
|
||||
moveCentipede(i);
|
||||
collideCentipede(i);
|
||||
animateCentipede(i);
|
||||
if(centipedes[i].turning){
|
||||
centipedes[i].turnClock++;
|
||||
if(centipedes[i].turnClock >= 30) centipedes[i].turning = FALSE;
|
||||
}
|
||||
SPR_setPosition(centipedes[i].image, fix16ToInt(centipedes[i].pos.x) - CENTIPEDE_OFFSET, fix16ToInt(centipedes[i].pos.y) - CENTIPEDE_OFFSET);
|
||||
if(centipedes[i].opposite){
|
||||
if(centipedes[i].clock % 40 == 0) SPR_setFrame(centipedes[i].image, 1);
|
||||
else if(centipedes[i].clock % 40 == 20) SPR_setFrame(centipedes[i].image, 0);
|
||||
}
|
||||
centipedes[i].clock++;
|
||||
if(centipedes[i].clock >= 600) centipedes[i].clock = 120;
|
||||
}
|
||||
lastCentipede = tempLastCentipede;
|
||||
if(zoneOverCheck) zoneOver = TRUE;
|
||||
}
|
43
src/centipede.h
Normal file
43
src/centipede.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
#define CENTIPEDE_MAX 8
|
||||
#define CENTIPEDE_OFFSET 8
|
||||
#define CENTIPEDE_LIMIT_LEFT FIX16(8)
|
||||
#define CENTIPEDE_LIMIT_RIGHT FIX16(GAME_WIDTH - 8)
|
||||
#define CENTIPEDE_LIMIT_TOP FIX16(32)
|
||||
#define CENTIPEDE_LIMIT_BOTTOM FIX16(GAME_HEIGHT - 16)
|
||||
|
||||
#define CENTIPEDE_COLLIDE_OFFSET FIX16(8)
|
||||
#define CENTIPEDE_BULLET_OFFSET FIX16(8)
|
||||
#define CENTIPEDE_PLAYER_OFFSET FIX16(2)
|
||||
#define CENTIPEDE_POD_OFFSET FIX32(4)
|
||||
|
||||
#define CENTIPEDE_DUMP_X FIX16(GAME_WIDTH + 64)
|
||||
#define CENTIPEDE_DUMP_Y FIX16(0 - 64)
|
||||
|
||||
#define CENTIPEDE_HIT 6
|
||||
// #define CENTIPEDE_HIT 100
|
||||
|
||||
struct centipede {
|
||||
Sprite* image;
|
||||
Vect2D_f16 pos;
|
||||
bool flippedX, flippedY, flipping, active, flag1, turning, opposite;
|
||||
s16 clock, flipClock, definition, health, turnClock;
|
||||
f16 speed, nextY;
|
||||
};
|
||||
|
||||
s16 centipedeCount, lastCentipede, tempLastCentipede;
|
||||
s32 centipedePodCheck;
|
||||
f16 centipedeSpeed;
|
||||
|
||||
struct centipede centipedes[CENTIPEDE_MAX];
|
||||
|
||||
bool centipedeCollided, zoneOverCheck;
|
||||
|
||||
void loadCentipede(),
|
||||
moveCentipede(s16),
|
||||
collideCentipede(s16),
|
||||
animateCentipede(s16),
|
||||
destroyCentipede(s16),
|
||||
splitCentipede(s16),
|
||||
turnCentipede(s16, s16),
|
||||
resetCentipede(),
|
||||
updateCentipede();
|
178
src/chrome.c
Normal file
178
src/chrome.c
Normal file
|
@ -0,0 +1,178 @@
|
|||
#include <genesis.h>
|
||||
#include <resources.h>
|
||||
|
||||
#include "main.h"
|
||||
#include "chrome.h"
|
||||
#include "boss.h"
|
||||
#include "player.h"
|
||||
|
||||
|
||||
// lives
|
||||
|
||||
void loadChromeLives(){
|
||||
VDP_drawImageEx(BG_A, &chromePlayer, TILE_ATTR_FULL(PAL1, 1, 0, 0, 160), 1, 1, 0, DMA_QUEUE);
|
||||
}
|
||||
|
||||
void updateChromePlayerLives(){
|
||||
if(chromePlayerLives != playerLives){
|
||||
for(s8 x = 0; x < 6; x++){
|
||||
VDP_setTileMapXY(BG_A, TILE_ATTR_FULL(PAL1, 0, 0, 0, 11), x + 6, 1);
|
||||
if(x < playerLives) VDP_drawText("#", x + 6, 1);
|
||||
}
|
||||
chromePlayerLives = playerLives;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// bombs
|
||||
|
||||
void updateChromePlayerBombs(){
|
||||
if(chromePlayerBombs != playerBombs){
|
||||
for(s8 x = 0; x < 6; x++){
|
||||
VDP_setTileMapXY(BG_A, TILE_ATTR_FULL(PAL1, 0, 0, 0, 11), x + 1, PLAYER_BOMBS_Y);
|
||||
if(x < playerBombs) VDP_drawText("*", x + 1, PLAYER_BOMBS_Y);
|
||||
}
|
||||
chromePlayerBombs = playerBombs;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// score
|
||||
|
||||
void updateChromeScore(){
|
||||
chromeCurrentScore = currentScore;
|
||||
intToStr(chromeCurrentScore, chromeScoreStr, 8);
|
||||
VDP_drawText(chromeScoreStr, 12, 1);
|
||||
}
|
||||
|
||||
|
||||
// zone
|
||||
|
||||
void loadChromeZone(){
|
||||
intToStr(currentZone, zoneHudStr, 2);
|
||||
VDP_drawText(zoneHudStr, 29, 1);
|
||||
VDP_drawImageEx(BG_A, &chromeStage, TILE_ATTR_FULL(PAL1, 1, 0, 0, 170), 24, 1, 0, DMA_QUEUE);
|
||||
}
|
||||
|
||||
|
||||
// states
|
||||
|
||||
void loadChromeZoneOver(){
|
||||
chromePlayerLives = 0;
|
||||
chromePlayerBombs = 0;
|
||||
intToStr(currentZone, currentZoneStr, 2);
|
||||
VDP_drawText("stage", 7, 8);
|
||||
VDP_drawText(currentZoneStr, 13, 8);
|
||||
VDP_drawText("complete!", 16, 8);
|
||||
VDP_drawText("NO-MISS", 7, 12);
|
||||
VDP_drawText(noMiss ? (currentZone >= 10 ? "35000" : "25000") : "00000", 20, 12);
|
||||
VDP_drawText("STAGE", 7, 14);
|
||||
VDP_drawText(currentZone >= 10 ? "15000" : "10000", 20, 14);
|
||||
if(currentZone % 5 == 0){
|
||||
VDP_drawText("BOSS", 7, 16);
|
||||
VDP_drawText(currentZone >= 10 ? "30000" : "20000", 20, 16);
|
||||
currentScore += currentZone >= 10 ? 30000 : 20000;
|
||||
}
|
||||
if(currentZone == 10) XGM_stopPlay();
|
||||
currentZone++;
|
||||
VDP_drawText("next stage", 7, 21);
|
||||
loadedZoneOver = TRUE;
|
||||
if(noMiss) currentScore += currentZone >= 10 ? 35000 : 25000;
|
||||
currentScore += currentZone >= 10 ? 15000 : 10000;
|
||||
updateChromeScore();
|
||||
XGM_startPlayPCM(SFX_ZONE_OVER, 1, SOUND_PCM_CH2);
|
||||
}
|
||||
|
||||
void updateChromeZoneOver(){ // what the fuck am i on to do this
|
||||
strcpy(zoneOverTime, zoneOverClock >= 180 ? "3" : (zoneOverClock >= 120 ? "2" : (zoneOverClock >= 60 ? "1" : "0")));
|
||||
strcat(zoneOverTime, ";");
|
||||
if(zoneOverClock % 60 < 10) strcat(zoneOverTime, "0");
|
||||
else if(zoneOverClock % 60 < 20) strcat(zoneOverTime, "1");
|
||||
else if(zoneOverClock % 60 < 30) strcat(zoneOverTime, "2");
|
||||
else if(zoneOverClock % 60 < 40) strcat(zoneOverTime, "3");
|
||||
else if(zoneOverClock % 60 < 50) strcat(zoneOverTime, "4");
|
||||
else if(zoneOverClock % 60 < 60) strcat(zoneOverTime, "5");
|
||||
switch(zoneOverClock % 6){
|
||||
case 0: strcat(zoneOverTime, "0"); break;
|
||||
case 1: strcat(zoneOverTime, "1"); break;
|
||||
case 2: strcat(zoneOverTime, "2"); break;
|
||||
case 3: strcat(zoneOverTime, "3"); break;
|
||||
case 4: strcat(zoneOverTime, "4"); break;
|
||||
case 5: strcat(zoneOverTime, "5"); break;
|
||||
case 6: strcat(zoneOverTime, "6"); break;
|
||||
case 7: strcat(zoneOverTime, "7"); break;
|
||||
case 8: strcat(zoneOverTime, "8"); break;
|
||||
case 9: strcat(zoneOverTime, "9"); break;
|
||||
}
|
||||
VDP_drawText(zoneOverTime, 21, 21);
|
||||
zoneOverClock--;
|
||||
if(zoneOverClock <= 0) nextZone();
|
||||
}
|
||||
|
||||
void loadChromeGameOver(bool beatIt){
|
||||
XGM_stopPlay();
|
||||
loadedChromeGameOver = TRUE;
|
||||
VDP_drawText(beatIt ? "beat game!" : "game over!", 11, 10);
|
||||
VDP_drawText(currentScore > highScore ? "NEW HI SCORE" : "FINAL SCORE;", 10, 13);
|
||||
VDP_drawText(chromeScoreStr, 12, 15);
|
||||
if(beatIt){
|
||||
VDP_drawText("special thanks", 9, 19);
|
||||
VDP_drawText("TOUHOU GAMEDEV DISCORD", 5, 21);
|
||||
} else VDP_drawText("press any button", 8, 18);
|
||||
if(currentScore > highScore) highScore = currentScore;
|
||||
XGM_startPlayPCM(beatIt ? SFX_BEAT_GAME : SFX_GAME_OVER, 2, SOUND_PCM_CH2);
|
||||
}
|
||||
|
||||
void loadChromeBeatGame(){
|
||||
gameOver = TRUE;
|
||||
loadChromeGameOver(TRUE);
|
||||
}
|
||||
|
||||
|
||||
// boss
|
||||
|
||||
void updateChromeBoss(){
|
||||
if(bossActive){
|
||||
if(lastBossHealth != bossHealth){
|
||||
VDP_drawImageEx(BG_A, &chromeEnemy, TILE_ATTR_FULL(PAL1, 1, 0, 0, 190), 1, BOSS_TILE_Y, 0, DMA_QUEUE);
|
||||
bossLimit = fix16Div(fix16Mul(fix16Div(FIX16(bossHealth), FIX16(bossMax)), BOSS_TILE_PX), 8);
|
||||
for(s16 x = 0; x < BOSS_TILE_COUNT; x++){
|
||||
if(bossHealth <= 1 || FIX16(x) >= bossLimit){
|
||||
VDP_setTileMapXY(BG_A, TILE_ATTR_FULL(PAL1, 0, 0, 0, 11), x + BOSS_TILE_X, BOSS_TILE_Y);
|
||||
}
|
||||
}
|
||||
for(s16 x = 0; x < BOSS_TILE_COUNT; x++){
|
||||
if(bossHealth > 1 && FIX16(x) < bossLimit) VDP_setTileMapXY(BG_A, TILE_ATTR_FULL(PAL1, 1, 0, 0, 8), x + BOSS_TILE_X, BOSS_TILE_Y);
|
||||
}
|
||||
lastBossHealth = bossHealth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// loop
|
||||
|
||||
void loadChrome(){
|
||||
VDP_loadTileSet(bossBar.tileset, 8, DMA);
|
||||
updateChromeScore();
|
||||
loadChromeZone();
|
||||
loadChromeLives();
|
||||
zoneOverClock = ZONE_OVER_CHROME_LIMIT;
|
||||
}
|
||||
|
||||
void updateChrome(){
|
||||
if(zoneStarting) loadChrome();
|
||||
else {
|
||||
if(zoneOver){
|
||||
if(!loadedZoneOver) currentZone == 20 ? loadChromeBeatGame() : loadChromeZoneOver();
|
||||
updateChromeZoneOver();
|
||||
} else if(gameOver){
|
||||
if(!loadedChromeGameOver) loadChromeGameOver(FALSE);
|
||||
} else {
|
||||
updateChromePlayerLives();
|
||||
updateChromePlayerBombs();
|
||||
updateChromeBoss();
|
||||
if(chromeCurrentScore < currentScore) updateChromeScore();
|
||||
}
|
||||
}
|
||||
}
|
36
src/chrome.h
Normal file
36
src/chrome.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
// #define ZONE_OVER_CHROME_LIMIT 1
|
||||
#define ZONE_OVER_CHROME_LIMIT 240
|
||||
// #define ZONE_OVER_CHROME_LIMIT 60
|
||||
|
||||
#define BOSS_TILE_X 6
|
||||
#define BOSS_TILE_Y 3
|
||||
#define BOSS_TILE_COUNT 25
|
||||
#define BOSS_TILE_PX BOSS_TILE_COUNT * 8
|
||||
|
||||
#define PLAYER_BOMBS_Y 26
|
||||
|
||||
s16 frameTileIndex, zoneOverClock, zoneOverStage, lastBossHealth, bossTileIndex;
|
||||
s8 chromePlayerLives, chromePlayerBombs;
|
||||
s32 chromeCurrentScore;
|
||||
|
||||
fix16 bossLimit, lastBossLimit;
|
||||
|
||||
bool loadedZoneOver, loadedChromeGameOver;
|
||||
|
||||
char currentZoneStr[2],
|
||||
zoneHudStr[2],
|
||||
currentZoneApp[1],
|
||||
zoneOverTime[8],
|
||||
chromeScoreStr[10];
|
||||
|
||||
void loadChrome(),
|
||||
loadChromeZoneOver(),
|
||||
loadChromeLives(),
|
||||
loadChromeGameOver(bool),
|
||||
updateChromeZoneOver(),
|
||||
updateChromeScore(),
|
||||
loadChromeBeatGame(),
|
||||
updateChromePlayerLives(),
|
||||
updateChromePlayerBombs(),
|
||||
updateChromeBoss(),
|
||||
updateChrome();
|
16
src/controls.c
Normal file
16
src/controls.c
Normal file
|
@ -0,0 +1,16 @@
|
|||
#include <genesis.h>
|
||||
#include "controls.h"
|
||||
|
||||
void updateControls(u16 joy, u16 changed, u16 state){
|
||||
if(joy == JOY_1){
|
||||
if(changed){}
|
||||
controls.left = (state & BUTTON_LEFT);
|
||||
controls.right = (state & BUTTON_RIGHT);
|
||||
controls.up = (state & BUTTON_UP);
|
||||
controls.down = (state & BUTTON_DOWN);
|
||||
controls.a = (state & BUTTON_A);
|
||||
controls.b = (state & BUTTON_B);
|
||||
controls.c = (state & BUTTON_C);
|
||||
controls.start = (state & BUTTON_START);
|
||||
}
|
||||
}
|
7
src/controls.h
Normal file
7
src/controls.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
struct controls {
|
||||
bool left, right, up, down, a, b, c, x, y, z, start, mode;
|
||||
};
|
||||
|
||||
struct controls controls;
|
||||
|
||||
void updateControls(u16, u16, u16);
|
177
src/enemies.c
Normal file
177
src/enemies.c
Normal file
|
@ -0,0 +1,177 @@
|
|||
#include <genesis.h>
|
||||
#include <resources.h>
|
||||
|
||||
#include "main.h"
|
||||
#include "enemies.h"
|
||||
#include "player.h"
|
||||
#include "yin.h"
|
||||
#include "centipede.h"
|
||||
#include "pod.h"
|
||||
#include "boss.h"
|
||||
|
||||
|
||||
// bullets
|
||||
|
||||
void spawnEnemyBullet(struct bulletSpawner spawner, void(*updater)){
|
||||
s16 i = -1;
|
||||
for(s16 h = 0; h < ENEMY_BULLET_LIMIT; h++) if(!bullets[h].active && i == -1) i = h;
|
||||
if(i > -1 && !gameOver){
|
||||
bullets[i].active = TRUE;
|
||||
bullets[i].grazed = FALSE;
|
||||
bullets[i].pos.x = spawner.x;
|
||||
bullets[i].pos.y = spawner.y;
|
||||
bullets[i].speed = spawner.speed ? spawner.speed : FIX16(2);
|
||||
bullets[i].angle = spawner.angle ? spawner.angle : 0;
|
||||
bullets[i].flag1 = spawner.flag1 ? TRUE : FALSE;
|
||||
bullets[i].flag2 = spawner.flag2 ? TRUE : FALSE;
|
||||
bullets[i].flag3 = spawner.flag3 ? TRUE : FALSE;
|
||||
bullets[i].flag4 = spawner.flag4 ? TRUE : FALSE;
|
||||
bullets[i].int1 = spawner.int1 ? spawner.int1 : 0;
|
||||
bullets[i].int2 = spawner.int2 ? spawner.int2 : 0;
|
||||
bullets[i].int3 = spawner.int3 ? spawner.int3 : 0;
|
||||
bullets[i].int4 = spawner.int4 ? spawner.int4 : 0;
|
||||
bullets[i].velocity.x = spawner.velocityX ? spawner.velocityX : fix16Mul(cosFix16(spawner.angle), spawner.speed);
|
||||
bullets[i].velocity.y = spawner.velocityY ? spawner.velocityY : fix16Mul(sinFix16(spawner.angle), spawner.speed);
|
||||
bullets[i].updater = updater;
|
||||
bullets[i].clock = 0;
|
||||
switch(spawner.type){
|
||||
case 1: bullets[i].image = SPR_addSprite(&imgSmallRedBullet, bullets[i].pos.x, bullets[i].pos.y, TILE_ATTR(PAL1, 0, FALSE, FALSE)); break;
|
||||
case 2: bullets[i].image = SPR_addSprite(&imgBigRedBullet, bullets[i].pos.x, bullets[i].pos.y, TILE_ATTR(PAL1, 0, FALSE, FALSE)); break;
|
||||
case 3: bullets[i].image = SPR_addSprite(&imgSmallBlueBullet, bullets[i].pos.x, bullets[i].pos.y, TILE_ATTR(PAL1, 0, FALSE, FALSE)); break;
|
||||
case 4: bullets[i].image = SPR_addSprite(&imgBigBlueBullet, bullets[i].pos.x, bullets[i].pos.y, TILE_ATTR(PAL1, 0, FALSE, FALSE)); break;
|
||||
case 5: bullets[i].image = SPR_addSprite(&imgSmallPinkBullet, bullets[i].pos.x, bullets[i].pos.y, TILE_ATTR(PAL1, 0, FALSE, FALSE)); break;
|
||||
case 6: bullets[i].image = SPR_addSprite(&imgBigPinkBullet, bullets[i].pos.x, bullets[i].pos.y, TILE_ATTR(PAL1, 0, FALSE, FALSE)); break;
|
||||
}
|
||||
if(spawner.type % 2 == 0){
|
||||
bullets[i].xOffset = 8;
|
||||
bullets[i].yOffset = 8;
|
||||
SPR_setDepth(bullets[i].image, 2);
|
||||
} else if(spawner.type % 2 == 1){
|
||||
bullets[i].xOffset = 4;
|
||||
bullets[i].yOffset = 4;
|
||||
SPR_setDepth(bullets[i].image, 1);
|
||||
}
|
||||
SPR_setPosition(bullets[i].image, fix16ToInt(bullets[i].pos.x) - bullets[i].xOffset, fix16ToInt(bullets[i].pos.y) - bullets[i].yOffset);
|
||||
}
|
||||
}
|
||||
|
||||
void checkEnemyBulletCollision(s16 i){
|
||||
enemyBulletCollisionDistance = getApproximatedDistance(
|
||||
fix16ToFix32(playerPos.x) - fix16ToFix32(bullets[i].pos.x),
|
||||
fix16ToFix32(playerPos.y) - fix16ToFix32(bullets[i].pos.y));
|
||||
if(enemyBulletCollisionDistance < intToFix32(bullets[i].xOffset) && !playerRecovering){
|
||||
spawnExplosion(fix16ToInt(bullets[i].pos.x), fix16ToInt(bullets[i].pos.y), TRUE);
|
||||
destroyEnemyBullet(i);
|
||||
hitPlayer = TRUE;
|
||||
killBullets = TRUE;
|
||||
// SND_startPlayPCM_XGM(SFX_EXPLOSION2, 15, SOUND_PCM_CH2);
|
||||
} else if(!bullets[i].grazed){
|
||||
bullets[i].grazed = TRUE;
|
||||
currentScore += 50;
|
||||
// SND_startPlayPCM_XGM(SFX_GRAZE, 15, SOUND_PCM_CH2);
|
||||
}
|
||||
}
|
||||
|
||||
void updateEnemyBullet(s16 i){
|
||||
bullets[i].pos.x = fix16Add(bullets[i].pos.x, bullets[i].velocity.x);
|
||||
bullets[i].pos.y = fix16Add(bullets[i].pos.y, bullets[i].velocity.y);
|
||||
bullets[i].updater(i);
|
||||
enemyBulletCount++;
|
||||
bullets[i].clock++;
|
||||
if(bullets[i].pos.x < FIX16(0 - bullets[i].xOffset) || bullets[i].pos.x > FIX16(256 + bullets[i].xOffset) ||
|
||||
bullets[i].pos.y < FIX16(0 - bullets[i].yOffset) || bullets[i].pos.y > FIX16(224 + bullets[i].yOffset) ||
|
||||
killBullets || bullets[i].clock >= 600 || zoneOver){
|
||||
destroyEnemyBullet(i);
|
||||
}
|
||||
}
|
||||
|
||||
void destroyEnemyBullet(s16 i){
|
||||
SPR_releaseSprite(bullets[i].image);
|
||||
bullets[i].active = FALSE;
|
||||
bullets[i].clock = 0;
|
||||
bullets[i].pos.x = FIX16(GAME_WIDTH);
|
||||
bullets[i].pos.y = FIX16(32);
|
||||
}
|
||||
|
||||
void drawEnemyBullet(s16 i){
|
||||
SPR_setPosition(bullets[i].image,
|
||||
fix16ToInt(bullets[i].pos.x) - bullets[i].xOffset, fix16ToInt(bullets[i].pos.y) - bullets[i].yOffset);
|
||||
if(bullets[i].pos.y > fix16Sub(playerPos.y, ENEMY_BULLET_COLLISION_CHECK) &&
|
||||
bullets[i].pos.y < fix16Add(playerPos.y, ENEMY_BULLET_COLLISION_CHECK) &&
|
||||
bullets[i].pos.x > fix16Sub(playerPos.x, ENEMY_BULLET_COLLISION_CHECK) &&
|
||||
bullets[i].pos.x < fix16Add(playerPos.x, ENEMY_BULLET_COLLISION_CHECK)){
|
||||
checkEnemyBulletCollision(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// utils
|
||||
|
||||
void eUpdate(s16 i){if(i){}}
|
||||
|
||||
void updateEnemyBulletVelocity(s16 i){
|
||||
bullets[i].velocity.x = fix16Mul(cosFix16(bullets[i].angle), bullets[i].speed);
|
||||
bullets[i].velocity.y = fix16Mul(sinFix16(bullets[i].angle), bullets[i].speed);
|
||||
}
|
||||
|
||||
fix16 honeEnemyBullet(fix16 x, fix16 y, s16 speed, s16 lerp, bool isX){
|
||||
honeX = playerPos.x;
|
||||
honeY = playerPos.y;
|
||||
if(lerp > 0){
|
||||
honeX = fix16Add(fix16Sub(honeX, FIX16(lerp)), FIX16(random() % (lerp * 2)));
|
||||
honeY = fix16Add(fix16Sub(honeY, FIX16(lerp)), FIX16(random() % (lerp * 2)));
|
||||
}
|
||||
honeSpeed = fix32ToFix16(getApproximatedDistance(fix16ToFix32(x) - fix16ToFix32(honeX), fix16ToFix32(y) - fix16ToFix32(honeY)));
|
||||
return isX ? fix16Mul(fix16Div(fix16Sub(honeX, x), honeSpeed), FIX16(speed)) : fix16Mul(fix16Div(fix16Sub(honeY, y), honeSpeed), FIX16(speed));
|
||||
}
|
||||
|
||||
|
||||
// kill bullets dramatically
|
||||
|
||||
void updateKillBullets(){
|
||||
if(enemyBulletCount >= ENEMY_BULLET_LIMIT) killBullets = TRUE;
|
||||
if(killBullets){
|
||||
if(killBulletsClock % 4 == 0 && killBulletsClock < 20){
|
||||
spawnExplosion(32 + random() % 192, 32 + random() % 128, FALSE);
|
||||
}
|
||||
killBulletsClock++;
|
||||
if(killBulletsClock >= 30){
|
||||
killBullets = FALSE;
|
||||
killBulletsClock = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// loop
|
||||
|
||||
void loadEnemies(){
|
||||
loadYins();
|
||||
loadCentipede();
|
||||
loadPod();
|
||||
}
|
||||
|
||||
void resetEnemies(){
|
||||
resetYins();
|
||||
resetCentipede();
|
||||
resetPod();
|
||||
for(s16 i = 0; i < ENEMY_BULLET_LIMIT; i++) destroyEnemyBullet(i);
|
||||
}
|
||||
|
||||
void updateEnemies(){
|
||||
if(zoneStarting && !bossActive) loadEnemies();
|
||||
else {
|
||||
if(bossActive) updateBoss();
|
||||
else {
|
||||
updateYins();
|
||||
updateCentipede();
|
||||
updatePod();
|
||||
}
|
||||
if(gameClock % 2 == 0){
|
||||
enemyBulletCount = 0;
|
||||
// for(s16 i = 0; i < ENEMY_LIMIT; i++) if(enemies[i].active) updateEnemy(i);
|
||||
for(s16 i = 0; i < ENEMY_BULLET_LIMIT; i++) if(bullets[i].active) updateEnemyBullet(i);
|
||||
updateKillBullets();
|
||||
} else for(s16 i = 0; i < ENEMY_BULLET_LIMIT; i++) if(bullets[i].active) drawEnemyBullet(i);
|
||||
}
|
||||
}
|
39
src/enemies.h
Normal file
39
src/enemies.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
#define ENEMY_BULLET_LIMIT 64
|
||||
#define ENEMY_BULLET_COLLISION_CHECK FIX16(14)
|
||||
|
||||
struct enemyBullet {
|
||||
bool active, flag1, flag2, flag3, flag4, grazed;
|
||||
Vect2D_f16 pos, velocity;
|
||||
fix16 speed;
|
||||
Sprite* image;
|
||||
s16 xOffset, yOffset, clock, angle, int1, int2, int3, int4;
|
||||
void (*updater)(s16);
|
||||
};
|
||||
|
||||
struct bulletSpawner {
|
||||
bool flag1, flag2, flag3, flag4;
|
||||
fix16 speed, velocityX, velocityY, x, y;
|
||||
s16 angle, type, int1, int2, int3, int4;
|
||||
};
|
||||
|
||||
struct enemyBullet bullets[ENEMY_BULLET_LIMIT];
|
||||
|
||||
bool killBullets;
|
||||
|
||||
s32 enemyBulletCollisionDistance;
|
||||
s16 killBulletsClock, enemyBulletCount;
|
||||
s8 podBulletSpeed, yinBulletSpeed;
|
||||
|
||||
fix16 honeX, honeY, honeSpeed,
|
||||
honeEnemyBullet(fix16, fix16, s16, s16, bool);
|
||||
|
||||
void loadEnemies(),
|
||||
spawnEnemyBullet(struct bulletSpawner, void *),
|
||||
checkEnemyBulletCollision(s16),
|
||||
updateEnemyBullet(s16),
|
||||
drawEnemyBullet(s16),
|
||||
updateKillBullets(),
|
||||
eUpdate(s16),
|
||||
destroyEnemyBullet(s16),
|
||||
resetEnemies(),
|
||||
updateEnemies();
|
28
src/explosion.c
Normal file
28
src/explosion.c
Normal file
|
@ -0,0 +1,28 @@
|
|||
#include <genesis.h>
|
||||
#include <resources.h>
|
||||
#include "main.h"
|
||||
#include "explosion.h"
|
||||
|
||||
void loadExplosion(){
|
||||
explosionClock = 0;
|
||||
explosionClockPlayerShot = 0;
|
||||
explosionImage = SPR_addSprite(&imgExplosionPlayer, EXPLOSION_DUMP_X, EXPLOSION_DUMP_Y, TILE_ATTR(PAL1, 0, FALSE, FALSE));
|
||||
explosionImagePlayerShot = SPR_addSprite(&imgExplosionPlayer, EXPLOSION_DUMP_X, EXPLOSION_DUMP_Y, TILE_ATTR(PAL1, 0, FALSE, FALSE));
|
||||
SPR_setDepth(explosionImage, 3);
|
||||
SPR_setDepth(explosionImagePlayerShot, 1);
|
||||
}
|
||||
|
||||
void spawnExplosion(s16 x, s16 y, bool isPlayerShot){
|
||||
SPR_setPosition(isPlayerShot ? explosionImagePlayerShot : explosionImage, x - EXPLOSION_SPRITE_OFFSET, y - EXPLOSION_SPRITE_OFFSET);
|
||||
isPlayerShot ? (explosionClockPlayerShot = 0) : (explosionClock = 0);
|
||||
// XGM_startPlayPCM(random() % 2 < 1 ? SFX_EXPLOSION_1 : SFX_EXPLOSION_2, 1, SOUND_PCM_CH4);
|
||||
}
|
||||
|
||||
void updateExplosion(){
|
||||
if(explosionClock >= EXPLOSION_LIMIT || paused) SPR_setPosition(explosionImage, EXPLOSION_DUMP_X, EXPLOSION_DUMP_Y);
|
||||
if(explosionClockPlayerShot >= EXPLOSION_LIMIT || paused) SPR_setPosition(explosionImagePlayerShot, EXPLOSION_DUMP_X, EXPLOSION_DUMP_Y);
|
||||
explosionClock++;
|
||||
explosionClockPlayerShot++;
|
||||
if(explosionClock >= 600) explosionClock = 60;
|
||||
if(explosionClockPlayerShot >= 600) explosionClockPlayerShot = 60;
|
||||
}
|
15
src/explosion.h
Normal file
15
src/explosion.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#define EXPLOSION_DUMP_X GAME_WIDTH + 32
|
||||
#define EXPLOSION_DUMP_Y GAME_HEIGHT + 64
|
||||
|
||||
#define EXPLOSION_SPRITE_OFFSET 12
|
||||
#define EXPLOSION_LIMIT 20
|
||||
|
||||
s16 explosionClock,
|
||||
explosionClockPlayerShot;
|
||||
|
||||
Sprite* explosionImage;
|
||||
Sprite* explosionImagePlayerShot;
|
||||
|
||||
void loadExplosion(),
|
||||
spawnExplosion(s16, s16, bool),
|
||||
updateExplosion();
|
140
src/main.c
Normal file
140
src/main.c
Normal file
|
@ -0,0 +1,140 @@
|
|||
#include <genesis.h>
|
||||
#include <resources.h>
|
||||
|
||||
#include "main.h"
|
||||
#include "controls.h"
|
||||
#include "chrome.h"
|
||||
#include "start.h"
|
||||
#include "boss.h"
|
||||
#include "background.h"
|
||||
#include "enemies.h"
|
||||
#include "player.h"
|
||||
#include "explosion.h"
|
||||
|
||||
void loadResources(){
|
||||
VDP_loadFont(font.tileset, DMA);
|
||||
VDP_loadTileSet(half.tileset, 10, DMA);
|
||||
VDP_loadTileSet(least.tileset, 11, DMA);
|
||||
VDP_loadTileSet(full.tileset, 12, DMA);
|
||||
VDP_setPalette(PAL1, font.palette -> data);
|
||||
VDP_setTextPalette(1);
|
||||
|
||||
XGM_setPCM(SFX_MENU_SELECT, sfxMenuSelect, sizeof(sfxMenuSelect)); // shit
|
||||
XGM_setPCM(SFX_MENU_CHOOSE, sfxMenuChoose, sizeof(sfxMenuChoose));
|
||||
XGM_setPCM(SFX_START_GAME, sfxStartGame, sizeof(sfxStartGame));
|
||||
XGM_setPCM(SFX_PLAYER_SHOT, sfxPlayerShot, sizeof(sfxPlayerShot));
|
||||
XGM_setPCM(SFX_ZONE_OVER, sfxZoneOver, sizeof(sfxZoneOver));
|
||||
|
||||
XGM_setPCM(SFX_BULLET_1, sfxBullet1, sizeof(sfxBullet1));
|
||||
|
||||
XGM_setPCM(SFX_EXPLOSION_1, sfxExplosion1, sizeof(sfxExplosion1));
|
||||
XGM_setPCM(SFX_EXPLOSION_2, sfxExplosion2, sizeof(sfxExplosion2));
|
||||
XGM_setPCM(SFX_EXPLOSION_3, sfxExplosion3, sizeof(sfxExplosion3));
|
||||
|
||||
XGM_setPCM(SFX_GAME_OVER, sfxGameOver, sizeof(sfxGameOver));
|
||||
XGM_setPCM(SFX_BEAT_GAME, sfxBeatGame, sizeof(sfxBeatGame));
|
||||
|
||||
}
|
||||
|
||||
void loadGame(){
|
||||
currentZone = 1;
|
||||
started = TRUE;
|
||||
zoneStarting = TRUE;
|
||||
gameStarting = TRUE;
|
||||
noMiss = TRUE;
|
||||
yinBulletSpeed = 4;
|
||||
podBulletSpeed = 3;
|
||||
currentScore = 0;
|
||||
loadExplosion();
|
||||
XGM_startPlay(&bgmStage1);
|
||||
}
|
||||
|
||||
void resetGame(){
|
||||
VDP_clearPlane(BG_A, TRUE);
|
||||
VDP_clearPlane(BG_B, TRUE);
|
||||
DMA_waitCompletion();
|
||||
startClock = 0;
|
||||
zoneOver = FALSE;
|
||||
started = FALSE;
|
||||
gameOverClock = 0;
|
||||
paused = FALSE;
|
||||
gameOver = FALSE;
|
||||
loadedChromeGameOver = FALSE;
|
||||
loadedZoneOver = FALSE;
|
||||
zoneStarting = FALSE;
|
||||
gameClock = 0;
|
||||
playerLives = 2;
|
||||
playerBombs = 3;
|
||||
bossType = 0;
|
||||
noMiss = TRUE;
|
||||
SPR_reset();
|
||||
for(s8 i = 0; i < BG_SCROLL_WIDTH; i++) backgroundScrolls[i] = 0;
|
||||
VDP_setVerticalScrollTile(BG_B, 0, backgroundScrolls, BG_SCROLL_WIDTH, DMA_QUEUE);
|
||||
VDP_setScreenWidth320();
|
||||
loadStart();
|
||||
}
|
||||
|
||||
|
||||
void updateGame(){
|
||||
if(started && !paused){
|
||||
updateBackground();
|
||||
updateEnemies();
|
||||
updatePlayer();
|
||||
updateExplosion();
|
||||
gameClock++;
|
||||
if(gameClock >= 1800) gameClock = 0;
|
||||
}
|
||||
updateChrome();
|
||||
if(zoneStarting) zoneStarting = FALSE;
|
||||
if(gameStarting) gameStarting = FALSE;
|
||||
if(doZoneStart){
|
||||
zoneStarting = TRUE;
|
||||
doZoneStart = FALSE;
|
||||
}
|
||||
if(!gameOver && started && gameClock >= 15 && !zoneOver){
|
||||
if(controls.start && !pausing){
|
||||
pausing = TRUE;
|
||||
paused = paused ? FALSE : TRUE;
|
||||
} else if(!controls.start && pausing) pausing = FALSE;
|
||||
} else if(gameOver){
|
||||
if(gameOverClock < 600) gameOverClock++;
|
||||
if(gameOverClock >= 120 && (controls.a || controls.b || controls.c || controls.start)) resetGame();
|
||||
}
|
||||
};
|
||||
|
||||
void nextZone(){
|
||||
if(currentZone == 21){
|
||||
resetGame();
|
||||
} else {
|
||||
SPR_reset();
|
||||
loadExplosion();
|
||||
if(currentZone % 5 == 0) loadBoss();
|
||||
resetBackground();
|
||||
resetEnemies();
|
||||
resetPlayer();
|
||||
doZoneStart = TRUE;
|
||||
zoneOver = FALSE;
|
||||
loadedZoneOver = FALSE;
|
||||
gameClock = -5;
|
||||
noMiss = TRUE;
|
||||
XGM_startPlayPCM(SFX_START_GAME, 1, SOUND_PCM_CH2);
|
||||
if(currentZone == 11) XGM_startPlay(&bgmStage2);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
XGM_setLoopNumber(-1);
|
||||
JOY_init();
|
||||
JOY_setEventHandler(&updateControls);
|
||||
loadResources();
|
||||
SPR_init(0, 0, 0);
|
||||
loadStart();
|
||||
playerLives = 2;
|
||||
playerBombs = 3;
|
||||
while(1){
|
||||
started ? updateGame() : updateStart();
|
||||
SPR_update();
|
||||
SYS_doVBlankProcess();
|
||||
}
|
||||
return (0);
|
||||
}
|
29
src/main.h
Normal file
29
src/main.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#define GAME_WIDTH 256
|
||||
#define GAME_HEIGHT 224
|
||||
|
||||
#define SFX_MENU_SELECT 64
|
||||
#define SFX_MENU_CHOOSE 65
|
||||
#define SFX_START_GAME 66
|
||||
#define SFX_PLAYER_SHOT 67
|
||||
#define SFX_ZONE_OVER 68
|
||||
|
||||
#define SFX_BULLET_1 69
|
||||
|
||||
#define SFX_EXPLOSION_1 73
|
||||
#define SFX_EXPLOSION_2 74
|
||||
#define SFX_EXPLOSION_3 75
|
||||
|
||||
#define SFX_GAME_OVER 76
|
||||
#define SFX_BEAT_GAME 77
|
||||
|
||||
bool gameOver, noMiss, paused, pausing, zoneOver, zoneStarting, gameStarting, noMiss, doZoneStart;
|
||||
|
||||
s16 gameClock, currentZone, gameOverClock;
|
||||
s32 currentScore, highScore;
|
||||
|
||||
void loadResources(),
|
||||
loadGame(),
|
||||
resetGame(),
|
||||
updateGame();
|
||||
|
||||
int main();
|
173
src/player.c
Normal file
173
src/player.c
Normal file
|
@ -0,0 +1,173 @@
|
|||
#include <genesis.h>
|
||||
#include <resources.h>
|
||||
#include "player.h"
|
||||
#include "main.h"
|
||||
#include "enemies.h"
|
||||
#include "controls.h"
|
||||
|
||||
|
||||
// movement
|
||||
|
||||
void updatePlayerBounds(){
|
||||
if(playerPos.x < PLAYER_LIMIT_LEFT) playerPos.x = PLAYER_LIMIT_LEFT;
|
||||
else if(playerPos.x > PLAYER_LIMIT_RIGHT) playerPos.x = PLAYER_LIMIT_RIGHT;
|
||||
if(playerPos.y < PLAYER_LIMIT_TOP) playerPos.y = PLAYER_LIMIT_TOP;
|
||||
else if(playerPos.y > PLAYER_LIMIT_BOTTOM) playerPos.y = PLAYER_LIMIT_BOTTOM;
|
||||
}
|
||||
|
||||
void updatePlayerMove(){
|
||||
playerVelocity.x = FIX16(0);
|
||||
playerVelocity.y = FIX16(0);
|
||||
if(controls.left){
|
||||
if(controls.down){
|
||||
playerVelocity.x = MOVEMENT_NORMALIZE_NEG;
|
||||
playerVelocity.y = MOVEMENT_NORMALIZE;
|
||||
}
|
||||
else if(controls.up){
|
||||
playerVelocity.x = MOVEMENT_NORMALIZE_NEG;
|
||||
playerVelocity.y = MOVEMENT_NORMALIZE_NEG;
|
||||
}
|
||||
else playerVelocity.x = MOVEMENT_NEG;
|
||||
} else if(controls.right){
|
||||
if(controls.down){
|
||||
playerVelocity.x = MOVEMENT_NORMALIZE;
|
||||
playerVelocity.y = MOVEMENT_NORMALIZE;
|
||||
}
|
||||
else if(controls.up){
|
||||
playerVelocity.x = MOVEMENT_NORMALIZE;
|
||||
playerVelocity.y = MOVEMENT_NORMALIZE_NEG;
|
||||
}
|
||||
else playerVelocity.x = MOVEMENT_POS;
|
||||
} else if(controls.up || controls.down) playerVelocity.y = controls.up ? MOVEMENT_NEG : MOVEMENT_POS;
|
||||
playerPos.x += fix16Mul(playerVelocity.x, controls.b ? PLAYER_SPEED_FOCUS : PLAYER_SPEED);
|
||||
playerPos.y += fix16Mul(playerVelocity.y, controls.b ? PLAYER_SPEED_FOCUS : PLAYER_SPEED);
|
||||
updatePlayerBounds();
|
||||
SPR_setPosition(playerSprite, fix16ToInt(playerPos.x) - 11, fix16ToInt(playerPos.y) - 16);
|
||||
}
|
||||
|
||||
|
||||
// shooting
|
||||
|
||||
void spawnPlayerBullet(){
|
||||
static s16 i = 0;
|
||||
for(s16 j = 0; j < PLAYER_BULLET_LIMIT; j++) if(!playerBullets[j].active) i = j;
|
||||
playerBullets[i].active = TRUE;
|
||||
playerBullets[i].pos.x = playerPos.x;
|
||||
playerBullets[i].pos.y = fix16Sub(playerPos.y, FIX16(8));
|
||||
XGM_startPlayPCM(SFX_PLAYER_SHOT, 0, SOUND_PCM_CH4);
|
||||
}
|
||||
|
||||
void removePlayerBullet(s16 i){
|
||||
playerBullets[i].pos.x = FIX16(PLAYER_BULLET_DUMP_X);
|
||||
playerBullets[i].pos.y = FIX16(PLAYER_BULLET_DUMP_Y);
|
||||
SPR_setPosition(playerBullets[i].image, PLAYER_BULLET_DUMP_X, PLAYER_BULLET_DUMP_Y);
|
||||
playerBullets[i].active = FALSE;
|
||||
}
|
||||
|
||||
void updatePlayerBullets(){
|
||||
for(s16 i = 0; i < PLAYER_BULLET_LIMIT; i++) if(playerBullets[i].active){
|
||||
playerBullets[i].pos.y = fix16Sub(playerBullets[i].pos.y, PLAYER_BULLET_SPEED);
|
||||
SPR_setPosition(playerBullets[i].image, fix16ToInt(playerBullets[i].pos.x) - 8, fix16ToInt(playerBullets[i].pos.y) - 8);
|
||||
if(playerBullets[i].pos.y <= PLAYER_BULLET_UP_LIMIT || playerBullets[i].pos.y >= PLAYER_BULLET_DOWN_LIMIT || zoneOver) removePlayerBullet(i);
|
||||
}
|
||||
}
|
||||
|
||||
void updatePlayerShot(){
|
||||
if(playerShotClock >= PLAYER_SHOT_INTERVAL && controls.a) playerShotClock = 0;
|
||||
if(playerShotClock == 0 && !zoneOver) spawnPlayerBullet();
|
||||
playerShotClock++;
|
||||
if(playerShotClock >= 600) playerShotClock = PLAYER_SHOT_INTERVAL;
|
||||
}
|
||||
|
||||
|
||||
// bomb
|
||||
|
||||
void spawnBomb(){
|
||||
killBullets = TRUE;
|
||||
SND_startPlayPCM_XGM(random() % 2 < 1 ? SFX_EXPLOSION_1 : SFX_EXPLOSION_2, 15, SOUND_PCM_CH2);
|
||||
spawnExplosion(random() % GAME_WIDTH, random() % GAME_HEIGHT, FALSE);
|
||||
}
|
||||
|
||||
void updatePlayerBomb(){
|
||||
if(bombing){
|
||||
if(bombClock % BOMB_INTERVAL == 0) spawnBomb();
|
||||
bombClock++;
|
||||
if(bombClock >= BOMB_LIMIT){
|
||||
bombClock = 0;
|
||||
bombing = FALSE;
|
||||
}
|
||||
} else if(controls.c && playerBombs > 0){
|
||||
bombing = TRUE;
|
||||
playerBombs -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// get hit
|
||||
|
||||
void updatePlayerHit(){
|
||||
if(hitPlayer){
|
||||
hitPlayer = FALSE;
|
||||
playerRecovering = TRUE;
|
||||
playerPos.x = PLAYER_INIT_X;
|
||||
playerPos.y = PLAYER_INIT_Y;
|
||||
playerLives -= 1;
|
||||
noMiss = FALSE;
|
||||
XGM_startPlayPCM(random() % 2 < 1 ? SFX_EXPLOSION_1 : SFX_EXPLOSION_2, 1, SOUND_PCM_CH4);
|
||||
spawnExplosion(fix16ToInt(playerPos.x), fix16ToInt(playerPos.y), TRUE);
|
||||
// if(playerLives < 0) playerLives = 0;
|
||||
if(playerLives < 0) gameOver = TRUE;
|
||||
}
|
||||
if(!gameOver && playerRecovering){
|
||||
if(recoverClock % RECOVER_INTERVAL == 0) SPR_setVisibility(playerSprite, HIDDEN);
|
||||
else if(recoverClock % RECOVER_INTERVAL == RECOVER_INTERVAL_HALF) SPR_setVisibility(playerSprite, VISIBLE);
|
||||
recoverClock++;
|
||||
if(recoverClock >= RECOVER_MAX){
|
||||
SPR_setVisibility(playerSprite, VISIBLE);
|
||||
recoverClock = 0;
|
||||
playerRecovering = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// loop
|
||||
|
||||
|
||||
void loadPlayer(){
|
||||
playerShotClock = PLAYER_SHOT_INTERVAL;
|
||||
playerPos.x = PLAYER_INIT_X;
|
||||
playerPos.y = PLAYER_INIT_Y;
|
||||
playerSprite = SPR_addSprite(&imgPlayer, playerPos.x, playerPos.y, TILE_ATTR(PAL1, 1, FALSE, FALSE));
|
||||
SPR_setDepth(playerSprite, 4);
|
||||
for(s16 i = 0; i < PLAYER_BULLET_LIMIT; i++){
|
||||
playerBullets[i].image = SPR_addSprite(&imgBullet, PLAYER_BULLET_DUMP_X, PLAYER_BULLET_DUMP_Y, TILE_ATTR(PAL1, 1, FALSE, FALSE));
|
||||
SPR_setDepth(playerBullets[i].image, 4);
|
||||
}
|
||||
}
|
||||
|
||||
void resetPlayer(){
|
||||
playerPos.x = PLAYER_INIT_X;
|
||||
playerPos.y = PLAYER_INIT_Y;
|
||||
SPR_releaseSprite(playerSprite);
|
||||
for(s16 i = 0; i < PLAYER_BULLET_LIMIT; i++) if(playerBullets[i].active){
|
||||
playerBullets[i].active = FALSE;
|
||||
SPR_releaseSprite(playerBullets[i].image);
|
||||
}
|
||||
}
|
||||
|
||||
void updatePlayer(){
|
||||
if(zoneStarting) loadPlayer();
|
||||
else {
|
||||
updatePlayerBullets();
|
||||
if(!gameOver && !paused){
|
||||
if(zoneOver) SPR_setVisibility(playerSprite, HIDDEN);
|
||||
else {
|
||||
updatePlayerMove();
|
||||
updatePlayerHit();
|
||||
}
|
||||
updatePlayerShot();
|
||||
updatePlayerBomb();
|
||||
} else if(gameOver) resetPlayer();
|
||||
}
|
||||
}
|
61
src/player.h
Normal file
61
src/player.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
#define PLAYER_LIMIT_LEFT FIX16(4)
|
||||
#define PLAYER_LIMIT_RIGHT fix16Sub(FIX16(GAME_WIDTH), PLAYER_LIMIT_LEFT)
|
||||
#define PLAYER_LIMIT_TOP PLAYER_LIMIT_LEFT
|
||||
#define PLAYER_LIMIT_BOTTOM fix16Sub(FIX16(GAME_HEIGHT), PLAYER_LIMIT_LEFT)
|
||||
|
||||
#define MOVEMENT_NORMALIZE FIX16(0.707)
|
||||
#define MOVEMENT_NORMALIZE_NEG FIX16(-0.707)
|
||||
#define MOVEMENT_POS FIX16(1)
|
||||
#define MOVEMENT_NEG FIX16(-1)
|
||||
|
||||
#define PLAYER_SPEED FIX16(3.25)
|
||||
#define PLAYER_SPEED_FOCUS FIX16(2)
|
||||
|
||||
#define PLAYER_INIT_X FIX16(GAME_WIDTH / 2)
|
||||
#define PLAYER_INIT_Y FIX16(GAME_HEIGHT - 32)
|
||||
|
||||
#define PLAYER_BULLET_LIMIT 3
|
||||
#define PLAYER_SHOT_INTERVAL 10
|
||||
#define PLAYER_BULLET_SPEED FIX16(8 * 4)
|
||||
|
||||
#define PLAYER_BULLET_UP_LIMIT FIX16(8)
|
||||
#define PLAYER_BULLET_DOWN_LIMIT FIX16(GAME_HEIGHT + 16)
|
||||
|
||||
#define PLAYER_BULLET_DUMP_X GAME_WIDTH + 16
|
||||
#define PLAYER_BULLET_DUMP_Y GAME_HEIGHT + 16
|
||||
|
||||
#define RECOVER_INTERVAL 30
|
||||
#define RECOVER_INTERVAL_HALF 15
|
||||
#define RECOVER_MAX RECOVER_INTERVAL * 6
|
||||
|
||||
#define BOMB_LIMIT 200
|
||||
#define BOMB_INTERVAL 10
|
||||
|
||||
struct playerBullet {
|
||||
bool active, downward;
|
||||
Vect2D_f16 pos;
|
||||
Sprite* image;
|
||||
};
|
||||
struct playerBullet playerBullets[PLAYER_BULLET_LIMIT];
|
||||
|
||||
Sprite* playerSprite;
|
||||
|
||||
Vect2D_f16 playerPos, playerVelocity;
|
||||
|
||||
s16 playerShotClock, recoverClock, bombClock;
|
||||
s8 playerLives, playerBombs;
|
||||
|
||||
bool hitPlayer, playerRecovering, bombing;
|
||||
|
||||
void loadPlayer(),
|
||||
updatePlayer(),
|
||||
updatePlayerBounds(),
|
||||
updatePlayerMove(),
|
||||
updatePlayerShot(),
|
||||
updatePlayerBullets(),
|
||||
spawnPlayerBullet(),
|
||||
spawnBomb(),
|
||||
updatePlayerBomb(),
|
||||
resetPlayer(),
|
||||
updatePlayerHit(),
|
||||
removePlayerBullet(s16);
|
125
src/pod.c
Normal file
125
src/pod.c
Normal file
|
@ -0,0 +1,125 @@
|
|||
#include <genesis.h>
|
||||
#include <resources.h>
|
||||
|
||||
#include "main.h"
|
||||
#include "enemies.h"
|
||||
#include "pod.h"
|
||||
#include "explosion.h"
|
||||
#include "boss.h"
|
||||
|
||||
|
||||
// spawn
|
||||
|
||||
void spawnPod(struct podSpawner spawner){
|
||||
s16 i = -1;
|
||||
for(s16 h = 0; h < POD_COUNT; h++) if(!pods[h].active && i == -1) i = h;
|
||||
if(i > -1){
|
||||
pods[i].active = TRUE;
|
||||
pods[i].pos.x = spawner.x;
|
||||
pods[i].pos.y = spawner.y;
|
||||
pods[i].clock = 0;
|
||||
pods[i].random = spawner.random;
|
||||
pods[i].image = SPR_addSprite(&imgSpider, fix16ToInt(POD_DUMP_X), fix16ToInt(POD_DUMP_Y), TILE_ATTR(PAL1, 0, FALSE, FALSE));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// shoot
|
||||
|
||||
void podPatternOne(s16 i){
|
||||
struct bulletSpawner bSpawn = {
|
||||
.x = pods[i].pos.x,
|
||||
.y = pods[i].pos.y,
|
||||
.type = 4,
|
||||
.angle = random() % 1024,
|
||||
.speed = FIX16(podBulletSpeed)
|
||||
};
|
||||
for(s8 b = 0; b < 3; b++){
|
||||
spawnEnemyBullet(bSpawn, eUpdate);
|
||||
bSpawn.angle += 341;
|
||||
}
|
||||
XGM_startPlayPCM(SFX_BULLET_1, 0, SOUND_PCM_CH3);
|
||||
}
|
||||
|
||||
void podPatternTwo(s8 i, s8 mod, s16 aMod){
|
||||
struct bulletSpawner bSpawn = {
|
||||
.x = pods[i].pos.x,
|
||||
.y = pods[i].pos.y,
|
||||
.type = 4,
|
||||
.angle = random() % 1024,
|
||||
.speed = FIX16(podBulletSpeed)
|
||||
};
|
||||
for(s8 b = 0; b < 3 + mod; b++){
|
||||
spawnEnemyBullet(bSpawn, eUpdate);
|
||||
bSpawn.angle += aMod;
|
||||
}
|
||||
bSpawn.speed = FIX16(podBulletSpeed + 1);
|
||||
bSpawn.type = 3;
|
||||
bSpawn.angle += aMod / 2;
|
||||
for(s8 b = 0; b < 3 + mod; b++){
|
||||
spawnEnemyBullet(bSpawn, eUpdate);
|
||||
bSpawn.angle += aMod;
|
||||
}
|
||||
}
|
||||
|
||||
void shootPod(s16 i){
|
||||
if(currentZone == 1) podPatternOne(i);
|
||||
else if(currentZone < 5) podPatternTwo(i, 0, 342);
|
||||
else if(currentZone < 10) podPatternTwo(i, 1, 256);
|
||||
else podPatternTwo(i, 2, 204);
|
||||
}
|
||||
|
||||
|
||||
// die
|
||||
|
||||
void killPod(s16 i){
|
||||
pods[i].active = FALSE;
|
||||
pods[i].pos.x = POD_DUMP_X;
|
||||
pods[i].pos.y = POD_DUMP_Y;
|
||||
SPR_releaseSprite(pods[i].image);
|
||||
}
|
||||
|
||||
|
||||
// loop
|
||||
|
||||
void loadPod(){
|
||||
if(currentZone % 5 == 1 && currentZone > 1) podBulletSpeed++;
|
||||
currentPodCount = 0;
|
||||
if(currentZone >= 3) currentPodCount = 1;
|
||||
if(currentZone >= 6) currentPodCount = 2;
|
||||
if(currentZone >= 11) currentPodCount = 3;
|
||||
if(currentZone >= 16) currentPodCount = 4;
|
||||
if(currentPodCount > 0){
|
||||
for(s16 i = 0; i < POD_COUNT; i++){
|
||||
pods[i].pos.x = POD_DUMP_X;
|
||||
pods[i].pos.y = POD_DUMP_Y;
|
||||
pods[i].random = FALSE;
|
||||
pods[i].clock = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void resetPod(){
|
||||
for(s16 i = 0; i < POD_COUNT; i++){
|
||||
pods[i].active = FALSE;
|
||||
pods[i].pos.x = POD_DUMP_X;
|
||||
pods[i].pos.y = POD_DUMP_Y;
|
||||
SPR_releaseSprite(pods[i].image);
|
||||
}
|
||||
}
|
||||
|
||||
void updatePod(){
|
||||
for(s16 i = 0; i < POD_COUNT; i++) if(pods[i].active) {
|
||||
if(pods[i].clock >= POD_TIME_LIMIT){
|
||||
if(!gameOver) shootPod(i);
|
||||
killPod(i);
|
||||
spawnExplosion(fix16ToInt(pods[i].pos.x), fix16ToInt(pods[i].pos.y), FALSE);
|
||||
XGM_startPlayPCM(SFX_BULLET_1, 1, SOUND_PCM_CH3);
|
||||
} else {
|
||||
if(pods[i].clock % 60 == 0 && pods[i].clock > 0) SPR_setAnimAndFrame(pods[i].image, pods[i].clock / 60, pods[i].clock % 40 == 0 ? 0 : 1);
|
||||
SPR_setPosition(pods[i].image, fix16ToInt(pods[i].pos.x) - 8, fix16ToInt(pods[i].pos.y) - 8);
|
||||
}
|
||||
if(zoneOver) killPod(i);
|
||||
pods[i].clock++;
|
||||
}
|
||||
}
|
35
src/pod.h
Normal file
35
src/pod.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
#define POD_COUNT 16
|
||||
|
||||
#define POD_DUMP_X FIX16(GAME_WIDTH + 32)
|
||||
#define POD_DUMP_Y FIX16(GAME_HEIGHT + 32)
|
||||
|
||||
#define POD_TIME_LIMIT 150
|
||||
|
||||
struct pod {
|
||||
bool active, random;
|
||||
s16 clock;
|
||||
Vect2D_f16 pos;
|
||||
Sprite* image;
|
||||
};
|
||||
|
||||
struct podSpawner {
|
||||
f16 x, y;
|
||||
bool random;
|
||||
};
|
||||
|
||||
struct pod pods[POD_COUNT];
|
||||
|
||||
s16 currentPodCount;
|
||||
|
||||
Vect2D_f16 currentPodPos[POD_COUNT];
|
||||
|
||||
bool foundRandomPodMatch;
|
||||
|
||||
void loadPod(),
|
||||
podPatternOne(s16),
|
||||
podPatternTwo(s8, s8, s16),
|
||||
shootPod(s16),
|
||||
destroyPod(s16),
|
||||
killPod(s16),
|
||||
resetPod(),
|
||||
updatePod();
|
245
src/start.c
Normal file
245
src/start.c
Normal file
|
@ -0,0 +1,245 @@
|
|||
#include <genesis.h>
|
||||
#include <resources.h>
|
||||
|
||||
#include "main.h"
|
||||
#include "controls.h"
|
||||
#include "player.h"
|
||||
#include "start.h"
|
||||
|
||||
|
||||
// background
|
||||
|
||||
void loadStartBg(){
|
||||
for(s8 y = 0; y < START_BG_HEIGHT; y++)
|
||||
for(s8 x = -1; x < START_BG_WIDTH; x++) if(y > START_BG_HEIGHT - 2) VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL1, 0, 0, 0, 14), x, y);
|
||||
loadStartGradient();
|
||||
}
|
||||
|
||||
void loadStartGradient(){
|
||||
for(s8 x = 0; x < START_BG_WIDTH; x++){
|
||||
VDP_drawImageEx(BG_B, &startGradient, TILE_ATTR_FULL(PAL1, 0, 0, 0, 200), x, START_GRADIENT_Y, 0, DMA_QUEUE);
|
||||
for(s8 y = 0; y < 12; y++) VDP_setTileMapXY(BG_A, TILE_ATTR_FULL(PAL1, 0, 0, 0, 11), x, y + START_GRADIENT_Y);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// logo
|
||||
|
||||
void loadStartLogo(){
|
||||
s8 logoCount = 0;
|
||||
for(s8 i = 0; i < START_LOGO_LINES; i++) startLogoScrolls[i] = random() % 4 - 2;
|
||||
VDP_setScrollingMode(HSCROLL_LINE, VSCROLL_2TILE);
|
||||
VDP_drawImageEx(BG_B, &startLogo, TILE_ATTR_FULL(PAL1, 0, 0, 0, 15), 3, START_LOGO_Y, 0, DMA_QUEUE);
|
||||
VDP_drawImageEx(BG_B, &startLogoV, TILE_ATTR_FULL(PAL1, 0, 0, 0, 100), 3, START_LOGO_Y + 4, 0, DMA_QUEUE);
|
||||
animateStartLogo();
|
||||
}
|
||||
|
||||
void animateStartLogo(){
|
||||
if(startClock % 8 == 0){
|
||||
for(s8 i = 0; i < START_LOGO_LINES; i++){
|
||||
if(aboutShowing){
|
||||
startLogoScrolls[i] = 0;
|
||||
} else {
|
||||
if(i < START_LOGO_LINES / 3 || (i >= START_LOGO_LINES / 3 && i < START_LOGO_LINES / 3 * 2 && startClock % 16 == 0) ||
|
||||
(i >= START_LOGO_LINES / 3 * 2 && startClock % 32 == 0)){
|
||||
startLogoScrollsFlip[i] ? startLogoScrolls[i]-- : startLogoScrolls[i]++;
|
||||
if(startLogoScrolls[i] >= (2)) startLogoScrollsFlip[i] = TRUE;
|
||||
else if(startLogoScrolls[i] <= ( -2)) startLogoScrollsFlip[i] = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
VDP_setHorizontalScrollLine(BG_B, 72, startLogoScrolls, START_LOGO_LINES, DMA_QUEUE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// menu
|
||||
|
||||
void loadStartMenu(){
|
||||
VDP_drawText(">", START_MENU_X - 1, START_MENU_Y);
|
||||
VDP_drawText("START GAME", START_MENU_X, START_MENU_Y);
|
||||
VDP_drawText("ABOUT", START_MENU_X, START_MENU_Y + 2);
|
||||
VDP_drawText("LIVES", START_MENU_X, START_MENU_Y + 4);
|
||||
VDP_drawText("BOMBS", START_MENU_X, START_MENU_Y + 6);
|
||||
}
|
||||
|
||||
void updateStartLives(){
|
||||
if(currentStartMenu == 2 && (controls.left || controls.right) && !updatingStartCount){
|
||||
if(controls.right && playerLives < 6) playerLives++;
|
||||
else if(controls.left && playerLives > 0) playerLives--;
|
||||
updatingStartCount = TRUE;
|
||||
} else if(!controls.left && !controls.right && updatingStartCount) updatingStartCount = FALSE;
|
||||
if(startCurrentLives != playerLives){
|
||||
startCurrentLives = playerLives;
|
||||
VDP_clearTileMapRect(BG_A, START_MENU_X + 6, START_MENU_Y + 4, 6, 1);
|
||||
for(s8 x = 0; x < playerLives; x++) VDP_drawText("#", x + START_MENU_X + 6, START_MENU_Y + 4);
|
||||
}
|
||||
}
|
||||
|
||||
void updateStartBombs(){
|
||||
if(currentStartMenu == 3 && (controls.left || controls.right) && !updatingStartCount){
|
||||
if(controls.right && playerBombs < 6) playerBombs++;
|
||||
else if(controls.left && playerBombs > 0) playerBombs--;
|
||||
updatingStartCount = TRUE;
|
||||
} else if(!controls.left && !controls.right && updatingStartCount) updatingStartCount = FALSE;
|
||||
if(startCurrentBombs != playerBombs){
|
||||
startCurrentBombs = playerBombs;
|
||||
VDP_clearTileMapRect(BG_A, START_MENU_X + 6, START_MENU_Y + 6, 6, 1);
|
||||
for(s8 x = 0; x < playerBombs; x++) VDP_drawText("*", x + START_MENU_X + 6, START_MENU_Y + 6);
|
||||
}
|
||||
}
|
||||
|
||||
void updateStartMenu(){
|
||||
if(currentStartMenu != lastStartMenu && !aboutShowing){
|
||||
VDP_clearTileMapRect(BG_A, START_MENU_X - 1, START_MENU_Y + lastStartMenu * 2, 1, 1);
|
||||
VDP_drawText(">", START_MENU_X - 1, START_MENU_Y + currentStartMenu * 2);
|
||||
lastStartMenu = currentStartMenu;
|
||||
}
|
||||
if((controls.up || controls.down) && !selectingStartMenu && !aboutShowing){
|
||||
currentStartMenu += controls.up ? -1 : 1;
|
||||
if(currentStartMenu > 3) currentStartMenu = 0;
|
||||
else if(currentStartMenu < 0) currentStartMenu = 3;
|
||||
selectingStartMenu = TRUE;
|
||||
XGM_startPlayPCM(SFX_MENU_SELECT, 1, SOUND_PCM_CH2);
|
||||
} else if(!controls.up && !controls.down && !controls.a && !controls.b && !controls.c && !controls.start && selectingStartMenu) selectingStartMenu = FALSE;
|
||||
updateStartLives();
|
||||
updateStartBombs();
|
||||
}
|
||||
|
||||
void selectStartMenu(){
|
||||
selectingStartMenu = TRUE;
|
||||
switch(currentStartMenu){
|
||||
case 0:
|
||||
resetStart();
|
||||
XGM_startPlayPCM(SFX_START_GAME, 1, SOUND_PCM_CH2);
|
||||
loadGame();
|
||||
break;
|
||||
case 1:
|
||||
loadStartAbout();
|
||||
XGM_startPlayPCM(SFX_MENU_CHOOSE, 1, SOUND_PCM_CH2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// about
|
||||
|
||||
void loadStartAbout(){
|
||||
aboutShowing = TRUE;
|
||||
for(s8 x = 0; x < START_BG_WIDTH; x++)
|
||||
for(s8 y = 0; y < START_BG_HEIGHT; y++)
|
||||
VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL1, 0, 0, 0, 13), x, y);
|
||||
VDP_clearTileMapRect(BG_A, 0, 0, START_BG_WIDTH, START_BG_HEIGHT);
|
||||
aboutY = 2;
|
||||
VDP_drawText("the story so far", 8, aboutY);
|
||||
aboutY += 2;
|
||||
VDP_drawText("MOMOYO IS YOUR REGULAR HARD-", 2, aboutY); aboutY++;
|
||||
VDP_drawText("WORKING CENTIPEDE WHO LIVES IN", 1, aboutY); aboutY++;
|
||||
VDP_drawText("THE MOMENT... BUT DOES HER NEW", 1, aboutY); aboutY++;
|
||||
VDP_drawText("BOSS HAVE HER MAKING NEW PLANS", 1, aboutY); aboutY += 2;
|
||||
VDP_drawText("USE HER TOOLS OVER 20 STAGES &", 1, aboutY); aboutY++;
|
||||
VDP_drawText("DIG UP SOME SWEETS TO BRING TO", 1, aboutY); aboutY++;
|
||||
VDP_drawText("##MEGUMU##", 11, aboutY);
|
||||
aboutY += 2;
|
||||
VDP_drawText("how to play", 1, aboutY); aboutY += 2;
|
||||
VDP_drawText("d=pad MOVE", 1, aboutY); aboutY++;
|
||||
VDP_drawText("a SHOOT", 1, aboutY); aboutY++;
|
||||
VDP_drawText("b FOCUS/SLOW", 1, aboutY); aboutY++;
|
||||
VDP_drawText("c BOMB", 1, aboutY); aboutY++;
|
||||
VDP_drawText("start PAUSE", 1, aboutY);
|
||||
aboutY += 3;
|
||||
VDP_drawText("EVERYTHING BY T.BODDY", 1, aboutY); aboutY++;
|
||||
VDP_drawText("FOR touhou pride game jam iii", 1, aboutY); aboutY++;
|
||||
VDP_drawText("TOUHOU PROJECT COPYRIGHT ZUN?", 1, aboutY); aboutY += 2;
|
||||
VDP_drawText("press any button to go back", 1, aboutY); aboutY++;
|
||||
startClock = SEGA_LIMIT + 120;
|
||||
}
|
||||
|
||||
void startGoBack(){
|
||||
selectingStartMenu = TRUE;
|
||||
aboutShowing = FALSE;
|
||||
currentStartMenu = 0;
|
||||
VDP_clearTileMapRect(BG_B, 0, 0, START_BG_WIDTH, START_BG_HEIGHT);
|
||||
VDP_clearTileMapRect(BG_A, 0, 0, START_BG_WIDTH, START_BG_HEIGHT);
|
||||
startCurrentBombs = -1;
|
||||
startCurrentLives = -1;
|
||||
for(s8 y = 0; y < START_BG_HEIGHT; y++)
|
||||
for(s8 x = -1; x < START_BG_WIDTH; x++) VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL1, 0, 0, 0, 13), x, y);
|
||||
loadStartBg();
|
||||
loadStartLogo();
|
||||
loadStartMenu();
|
||||
loadStartScore();
|
||||
loadStartCredit();
|
||||
}
|
||||
|
||||
void updateStartAbout(){
|
||||
if(startClock % 120 == 0) VDP_drawImageEx(BG_B, &startAbout, TILE_ATTR_FULL(PAL1, 0, 0, 0, 64), 22, 12, 0, DMA_QUEUE);
|
||||
else if(startClock % 120 == 60) VDP_drawImageEx(BG_B, &startAbout2, TILE_ATTR_FULL(PAL1, 0, 0, 0, 128), 22, 12, 0, DMA_QUEUE);
|
||||
}
|
||||
|
||||
|
||||
// score & credit
|
||||
|
||||
void loadStartScore(){
|
||||
intToStr(highScore, startHighScoreStr, 8);
|
||||
VDP_drawText("HI", 1, 26);
|
||||
VDP_drawText(startHighScoreStr, 4, 26);
|
||||
}
|
||||
|
||||
void loadStartCredit(){
|
||||
VDP_drawText("06.2021 T.BODDY", 16, 26);
|
||||
}
|
||||
|
||||
|
||||
// loop
|
||||
|
||||
void loadStart(){
|
||||
VDP_loadTileSet(startTop.tileset, 13, DMA);
|
||||
VDP_loadTileSet(startBottom.tileset, 14, DMA);
|
||||
for(s8 y = 0; y < START_BG_HEIGHT; y++)
|
||||
for(s8 x = -1; x < START_BG_WIDTH; x++) VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL1, 0, 0, 0, 13), x, y);
|
||||
segaImage1 = SPR_addSprite(&startBoddy1, SEGA_X - 56, SEGA_Y, TILE_ATTR(PAL1, 0, 0, 0));
|
||||
segaImage2 = SPR_addSprite(&startBoddy2, SEGA_X, SEGA_Y, TILE_ATTR(PAL1, 0, 0, 0));
|
||||
// VDP_drawImage(BG_B, &startBoddy, 0, 0);
|
||||
}
|
||||
|
||||
void resetStart(){
|
||||
VDP_clearTileMapRect(BG_B, 0, 0, START_BG_WIDTH, START_BG_HEIGHT);
|
||||
VDP_clearTileMapRect(BG_A, 0, 0, START_BG_WIDTH, START_BG_HEIGHT);
|
||||
}
|
||||
|
||||
void updateStart(){
|
||||
if(startClock >= SEGA_LIMIT + 15){
|
||||
updateStartMenu();
|
||||
animateStartLogo();
|
||||
if((controls.a || controls.b || controls.c || controls.start) && aboutShowing && !selectingStartMenu) startGoBack();
|
||||
else if((controls.a || controls.start) && !aboutShowing && !selectingStartMenu) selectStartMenu();
|
||||
if(aboutShowing) updateStartAbout();
|
||||
} else if(startClock == SEGA_LIMIT - 25){
|
||||
for(s8 y = 0; y < START_BG_HEIGHT; y++)
|
||||
for(s8 x = -1; x < START_BG_WIDTH; x++) VDP_setTileMapXY(BG_A, TILE_ATTR_FULL(PAL1, 1, 0, 0, 10), x, y);
|
||||
} else if(startClock == SEGA_LIMIT - 20){
|
||||
for(s8 y = 0; y < START_BG_HEIGHT; y++)
|
||||
for(s8 x = -1; x < START_BG_WIDTH; x++) VDP_setTileMapXY(BG_A, TILE_ATTR_FULL(PAL1, 1, 0, 0, 11), x, y);
|
||||
} else if(startClock == SEGA_LIMIT - 15){
|
||||
SPR_releaseSprite(segaImage1);
|
||||
SPR_releaseSprite(segaImage2);
|
||||
} else if(startClock == SEGA_LIMIT - 10){
|
||||
VDP_setScreenWidth256();
|
||||
} else if(startClock == SEGA_LIMIT - 5){
|
||||
loadStartBg();
|
||||
} else if(startClock == SEGA_LIMIT){
|
||||
for(s8 y = 0; y < START_BG_HEIGHT; y++)
|
||||
for(s8 x = -1; x < START_BG_WIDTH; x++) VDP_setTileMapXY(BG_A, TILE_ATTR_FULL(PAL1, 1, 0, 0, 10), x, y);
|
||||
} else if(startClock == SEGA_LIMIT + 5){
|
||||
VDP_clearTileMapRect(BG_A, -1, 0, START_BG_WIDTH, START_BG_HEIGHT);
|
||||
} else if(startClock == SEGA_LIMIT + 10){
|
||||
loadStartLogo();
|
||||
loadStartMenu();
|
||||
loadStartScore();
|
||||
loadStartCredit();
|
||||
XGM_startPlay(&bgmStart);
|
||||
}
|
||||
startClock++;
|
||||
if(startClock >= 1800) startClock = SEGA_LIMIT + 120;
|
||||
}
|
48
src/start.h
Normal file
48
src/start.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
#define START_BG_HEIGHT 28
|
||||
#define START_BG_WIDTH 40
|
||||
|
||||
#define START_MENU_X 11
|
||||
#define START_MENU_Y 15
|
||||
|
||||
#define START_LOGO_LINES 32
|
||||
#define START_LOGO_Y 5
|
||||
|
||||
#define START_GRADIENT_Y 23
|
||||
|
||||
// #define SEGA_LIMIT 90
|
||||
#define SEGA_LIMIT 60 * 4
|
||||
|
||||
#define SEGA_X 320 / 2
|
||||
#define SEGA_Y GAME_HEIGHT / 2 - 16
|
||||
|
||||
bool started, selectingStartMenu, aboutShowing, loadedStart;
|
||||
|
||||
s16 currentStartMenu, lastStartMenu, startClock, aboutY;
|
||||
|
||||
s16 startLogoScrolls[START_LOGO_LINES];
|
||||
bool startLogoScrollsFlip[START_LOGO_LINES], updatingStartCount;
|
||||
|
||||
s8 startCurrentLives, startCurrentBombs;
|
||||
|
||||
char startHighScoreStr[10];
|
||||
|
||||
Sprite* segaImage1;
|
||||
Sprite* segaImage2;
|
||||
|
||||
void loadStartBg(),
|
||||
loadStart(),
|
||||
loadStartLogo(),
|
||||
loadStartMenu(),
|
||||
loadStartGradient(),
|
||||
resetStart(),
|
||||
animateStartLogo(),
|
||||
startGoBack(),
|
||||
selectStartMenu(),
|
||||
updateStartMenu(),
|
||||
loadStartScore(),
|
||||
updateStartLives(),
|
||||
updateStartBombs(),
|
||||
updateStartAbout(),
|
||||
loadStartCredits(),
|
||||
loadStartAbout(),
|
||||
updateStart();
|
132
src/yin.c
Normal file
132
src/yin.c
Normal file
|
@ -0,0 +1,132 @@
|
|||
#include <genesis.h>
|
||||
#include <resources.h>
|
||||
|
||||
#include "main.h"
|
||||
#include "explosion.h"
|
||||
#include "enemies.h"
|
||||
#include "yin.h"
|
||||
|
||||
|
||||
// movement
|
||||
|
||||
void moveYinHorizontal(s8 i){
|
||||
yins[i].pos.x += yins[i].flag1 ? 0 - YIN_SPEED : YIN_SPEED;
|
||||
if(yins[i].pos.x >= GAME_WIDTH - 10){
|
||||
yins[i].flag1 = TRUE;
|
||||
SPR_setHFlip(yins[i].image, 1);
|
||||
} else if(yins[i].pos.x <= 10){
|
||||
yins[i].flag1 = FALSE;
|
||||
SPR_setHFlip(yins[i].image, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void moveYinVertical(s8 i){
|
||||
yins[i].pos.y += yins[i].flag1 ? 0 - YIN_SPEED : YIN_SPEED;
|
||||
if(yins[i].pos.y >= 112){
|
||||
yins[i].flag1 = TRUE;
|
||||
} else if(yins[i].pos.y <= 56){
|
||||
yins[i].flag1 = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// shooting
|
||||
|
||||
void yinPatternOne(s8 i){
|
||||
if(yins[i].clock % 80 == 40){
|
||||
struct bulletSpawner bSpawn = {
|
||||
.x = FIX16(yins[i].pos.x),
|
||||
.y = FIX16(yins[i].pos.y),
|
||||
.type = 1
|
||||
};
|
||||
bSpawn.velocityX = honeEnemyBullet(bSpawn.x, bSpawn.y, yinBulletSpeed, 0, TRUE);
|
||||
bSpawn.velocityY = honeEnemyBullet(bSpawn.x, bSpawn.y, yinBulletSpeed, 0, FALSE);
|
||||
spawnEnemyBullet(bSpawn, eUpdate);
|
||||
XGM_startPlayPCM(SFX_BULLET_1, 0, SOUND_PCM_CH3);
|
||||
spawnExplosion(yins[i].pos.x, yins[i].pos.y, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
void yinPatternTwo(s8 i){
|
||||
if(yins[i].clock % 40 == 20){
|
||||
struct bulletSpawner bSpawn = {
|
||||
.x = FIX16(yins[i].pos.x),
|
||||
.y = FIX16(yins[i].pos.y),
|
||||
.type = yins[i].clock % 80 == 20 ? 2 : 1
|
||||
};
|
||||
bSpawn.velocityX = honeEnemyBullet(bSpawn.x, bSpawn.y, yinBulletSpeed, bSpawn.type == 1 ? 32 : 0, TRUE);
|
||||
bSpawn.velocityY = honeEnemyBullet(bSpawn.x, bSpawn.y, yinBulletSpeed, bSpawn.type == 1 ? 32 : 0, FALSE);
|
||||
spawnEnemyBullet(bSpawn, eUpdate);
|
||||
XGM_startPlayPCM(SFX_BULLET_1, 0, SOUND_PCM_CH3);
|
||||
spawnExplosion(yins[i].pos.x, yins[i].pos.y, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
void yinPatternThree(s8 i, s8 count){
|
||||
if(yins[i].clock % 80 >= 20 && yins[i].clock % 80 < 30 && yins[i].clock % 5 == 0){
|
||||
struct bulletSpawner bSpawn = {
|
||||
.x = FIX16(yins[i].pos.x),
|
||||
.y = FIX16(yins[i].pos.y),
|
||||
.type = yins[i].clock % 8 == 0 ? 2 : 1,
|
||||
.int1 = 64
|
||||
};
|
||||
for(s8 b = 0; b < count; b++){
|
||||
bSpawn.velocityX = honeEnemyBullet(bSpawn.x, bSpawn.y, yinBulletSpeed, yins[i].horizontal ? bSpawn.int1 : 0, TRUE);
|
||||
bSpawn.velocityY = honeEnemyBullet(bSpawn.x, bSpawn.y, yinBulletSpeed, yins[i].horizontal ? 0 : bSpawn.int1, FALSE);
|
||||
spawnEnemyBullet(bSpawn, eUpdate);
|
||||
bSpawn.type = bSpawn.type == 2 ? 1 : 2;
|
||||
bSpawn.int1 += 16;
|
||||
}
|
||||
XGM_startPlayPCM(SFX_BULLET_1, 0, SOUND_PCM_CH3);
|
||||
}
|
||||
}
|
||||
|
||||
void yinShoot(s8 i){
|
||||
if((!yins[i].horizontal && !yins[i].last && yins[i].clock % 240 < 80) ||
|
||||
(yins[i].horizontal && yins[i].clock % 240 >= 80 && yins[i].clock % 240 < 160) ||
|
||||
(yins[i].last && yins[i].clock % 240 >= 160)){
|
||||
if(currentZone == 1) yinPatternOne(i);
|
||||
else if(currentZone < 5) yinPatternTwo(i);
|
||||
else if(currentZone < 10) yinPatternThree(i, 1);
|
||||
else if(currentZone < 15) yinPatternThree(i, 2);
|
||||
else yinPatternThree(i, 3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// loop
|
||||
|
||||
void loadYins(){
|
||||
if(currentZone % 5 == 1 && currentZone > 1) yinBulletSpeed++;
|
||||
for(s16 i = 0; i < YIN_COUNT; i++){
|
||||
yins[i].pos.x = i == 0 ? 6 : (i == 2 ? 251 : 128);
|
||||
yins[i].pos.y = i % 2 == 0 ? (i == 0 ? 64 : 96) : 21;
|
||||
yins[i].speed = 20;
|
||||
yins[i].horizontal = i % 2 == 1;
|
||||
yins[i].last = i % 3 == 2;
|
||||
yins[i].clock = 0;
|
||||
yins[i].image = SPR_addSprite(&imgYin1, yins[i].pos.x, yins[i].pos.y, TILE_ATTR(PAL1, 0, FALSE, FALSE));
|
||||
if(yins[i].last) yins[i].flag1 = TRUE;
|
||||
SPR_setDepth(yins[i].image, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void resetYins(){
|
||||
for(s16 i = 0; i < YIN_COUNT; i++){
|
||||
yins[i].pos.x = i == 0 ? 6 : (i == 2 ? 251 : 128);
|
||||
yins[i].pos.y = i % 2 == 0 ? (i == 0 ? 64 : 96) : 21;
|
||||
SPR_releaseSprite(yins[i].image);
|
||||
}
|
||||
}
|
||||
|
||||
void updateYins(){
|
||||
for(s16 i = 0; i < YIN_COUNT; i++){
|
||||
if(yins[i].clock % yins[i].speed == 0) yins[i].horizontal ? moveYinHorizontal(i) : moveYinVertical(i);
|
||||
else if(yins[i].clock % yins[i].speed == 1) SPR_setPosition(yins[i].image, yins[i].pos.x - 4, yins[i].pos.y - 4);
|
||||
if(yins[i].clock % 5 == 0 && yins[i].speed > 2) yins[i].speed--;
|
||||
if(zoneOver) SPR_setVisibility(yins[i].image, HIDDEN);
|
||||
else if(!gameOver) yinShoot(i);
|
||||
if(!zoneOver) yins[i].clock++;
|
||||
if(yins[i].clock >= 240) yins[i].clock = 0;
|
||||
}
|
||||
}
|
23
src/yin.h
Normal file
23
src/yin.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#define YIN_COUNT 3
|
||||
#define YIN_SPEED 2
|
||||
|
||||
struct yin {
|
||||
Sprite* image;
|
||||
Vect2D_s16 pos;
|
||||
bool horizontal, last, flag1, flag2;
|
||||
s16 clock, speed, int1, int2, int3;
|
||||
};
|
||||
|
||||
struct yin yins[YIN_COUNT];
|
||||
|
||||
void loadYins(),
|
||||
moveYinHorizontal(s8),
|
||||
moveYinVertical(s8),
|
||||
yinPatternOne(s8),
|
||||
yinPatternTwo(s8),
|
||||
yinPatternThree(s8, s8),
|
||||
yinPatternFour(s8),
|
||||
yinPatternFive(s8),
|
||||
yinShoot(s8),
|
||||
resetYins(),
|
||||
updateYins();
|
Loading…
Add table
Add a link
Reference in a new issue