shit
This commit is contained in:
parent
417cae168f
commit
a8bc01bedd
59 changed files with 2053 additions and 1054 deletions
143
src/global.h
143
src/global.h
|
|
@ -5,6 +5,7 @@ void sfxEnemyShotB();
|
|||
void sfxEnemyShotC();
|
||||
void sfxExplosion();
|
||||
void sfxPickup();
|
||||
void sfxGraze();
|
||||
void loadMap();
|
||||
void loadGame();
|
||||
|
||||
|
|
@ -21,12 +22,34 @@ u32 clock;
|
|||
#define GAME_WRAP (SECTION_SIZE * SECTION_COUNT)
|
||||
|
||||
#define CULL_LIMIT FIX32(240)
|
||||
#define SCREEN_LIMIT FIX32(208) // max player-to-screen-edge distance (320 - CAMERA_X)
|
||||
|
||||
#define MUSIC_VOLUME 50
|
||||
// #define MUSIC_VOLUME 0
|
||||
// #define MUSIC_VOLUME 50
|
||||
#define MUSIC_VOLUME 0
|
||||
|
||||
u32 score;
|
||||
u32 highScore;
|
||||
u32 tempHighScore;
|
||||
u32 grazeCount;
|
||||
u32 nextExtendScore;
|
||||
#define EXTEND_SCORE 25000
|
||||
#define SCORE_LENGTH 8
|
||||
#define GRAZE_RADIUS 16
|
||||
|
||||
#define SCORE_SRAM 0x0033
|
||||
|
||||
void getHighScore(){
|
||||
SRAM_enable();
|
||||
tempHighScore = SRAM_readLong(SCORE_SRAM);
|
||||
if(tempHighScore > 0 && tempHighScore < 1000000) highScore = tempHighScore;
|
||||
SRAM_disable();
|
||||
}
|
||||
|
||||
static void saveHighScore(){
|
||||
SRAM_enable();
|
||||
SRAM_writeLong(SCORE_SRAM, highScore);
|
||||
SRAM_disable();
|
||||
}
|
||||
|
||||
#define FIRST_ROTATING_BULLET 3
|
||||
|
||||
|
|
@ -34,12 +57,20 @@ u32 score;
|
|||
#define MAP_Y 1
|
||||
#define MAP_W 38
|
||||
#define MAP_H 3
|
||||
#define MAP_SCALE (F32_toInt(GAME_WRAP) / MAP_W)
|
||||
|
||||
void EMPTY(s16 i){(void)i;}
|
||||
|
||||
bool started;
|
||||
bool gameOver;
|
||||
bool paused, isPausing;
|
||||
bool isAttract;
|
||||
u16 attractClock;
|
||||
#define ATTRACT_LIMIT 900 // frames of title idle before attract triggers
|
||||
#define ATTRACT_DURATION 1800 // 30 seconds of demo gameplay
|
||||
#define ATTRACT_LEVEL 1 // level index for attract mode (L12: Boss 4, 3 gunners)
|
||||
#define START_LEVEL 2 // offset added to starting level (0 = normal start)
|
||||
// #define START_LEVEL 0 // offset added to starting level (0 = normal start)
|
||||
s16 enemyCount, bulletCount;
|
||||
u8 level;
|
||||
s16 pendingBossHp;
|
||||
|
|
@ -59,6 +90,7 @@ struct controls {
|
|||
bool left, right, up, down, a, b, c, start;
|
||||
};
|
||||
struct controls ctrl;
|
||||
struct controls ctrlHW; // hardware-only copy — never overridden by AI
|
||||
void updateControls(u16 joy, u16 changed, u16 state){
|
||||
(void)changed; // Unused parameter
|
||||
if(joy == JOY_1){
|
||||
|
|
@ -70,6 +102,7 @@ void updateControls(u16 joy, u16 changed, u16 state){
|
|||
ctrl.b = (state & BUTTON_B);
|
||||
ctrl.c = (state & BUTTON_C);
|
||||
ctrl.start = (state & BUTTON_START);
|
||||
ctrlHW = ctrl;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -79,10 +112,13 @@ struct playerStruct {
|
|||
Vect2D_f32 pos, vel;
|
||||
s16 shotAngle;
|
||||
u8 lives, recoveringClock, respawnClock;
|
||||
bool recoverFlash; // TRUE only after death, not on level-start grace
|
||||
bool pendingShow; // show sprite after next position update (avoids 1-frame position flicker)
|
||||
fix32 camera;
|
||||
Sprite* image;
|
||||
};
|
||||
struct playerStruct player;
|
||||
fix32 playerScrollVelY; // player.vel.y zeroed when clamped at top/bottom bound
|
||||
bool killBullets;
|
||||
|
||||
|
||||
|
|
@ -93,14 +129,17 @@ struct bulletSpawner {
|
|||
fix32 x, y, speed;
|
||||
Vect2D_f32 vel;
|
||||
s16 angle, anim, frame;
|
||||
s16 ints[PROP_COUNT];
|
||||
bool top, player;
|
||||
};
|
||||
struct bullet {
|
||||
bool active, player, vFlip, hFlip, explosion;
|
||||
fix32 speed;
|
||||
bool active, player, vFlip, hFlip, explosion, grazed;
|
||||
Vect2D_f32 pos, vel;
|
||||
Sprite* image;
|
||||
s16 clock, angle, anim, frame;
|
||||
s16 dist;
|
||||
s16 ints[PROP_COUNT];
|
||||
void (*updater)(s16);
|
||||
};
|
||||
struct bullet bullets[BULLET_COUNT];
|
||||
|
|
@ -119,13 +158,14 @@ struct bullet bullets[BULLET_COUNT];
|
|||
struct enemy {
|
||||
bool active, onScreen;
|
||||
u8 type;
|
||||
s16 hp;
|
||||
s16 hp, frame, anim;
|
||||
s16 angle, off;
|
||||
u32 clock;
|
||||
fix32 speed;
|
||||
Vect2D_f32 vel, pos;
|
||||
Sprite* image;
|
||||
s16 ints[PROP_COUNT];
|
||||
fix16 fixes[PROP_COUNT];
|
||||
};
|
||||
struct enemy enemies[ENEMY_COUNT];
|
||||
|
||||
|
|
@ -148,6 +188,9 @@ struct treasure {
|
|||
struct treasure treasures[TREASURE_COUNT];
|
||||
bool treasureBeingCarried;
|
||||
s16 collectedCount;
|
||||
u16 levelEnemiesKilled;
|
||||
u16 statEnemiesKilled;
|
||||
s16 statTreasures;
|
||||
|
||||
void killTreasure(u8 i){
|
||||
if(treasures[i].state == TREASURE_CARRIED && treasures[i].carriedBy >= 0){
|
||||
|
|
@ -160,19 +203,17 @@ void killTreasure(u8 i){
|
|||
|
||||
void killBullet(u8 i, bool explode){
|
||||
if(explode){
|
||||
s16 a = bullets[i].anim;
|
||||
s16 explosionAnim;
|
||||
if(bullets[i].player){
|
||||
SPR_setAnim(bullets[i].image, 1);
|
||||
explosionAnim = 16;
|
||||
} else if(a < FIRST_ROTATING_BULLET){
|
||||
explosionAnim = 13 + bullets[i].frame;
|
||||
} else {
|
||||
s16 a = bullets[i].anim;
|
||||
s16 explosionAnim;
|
||||
if(a < FIRST_ROTATING_BULLET){
|
||||
explosionAnim = 13 + bullets[i].frame;
|
||||
} else {
|
||||
s16 mod = a % 3;
|
||||
explosionAnim = 13 + mod;
|
||||
}
|
||||
SPR_setAnim(bullets[i].image, explosionAnim);
|
||||
s16 mod = a % 3;
|
||||
explosionAnim = 13 + mod;
|
||||
}
|
||||
SPR_setAnim(bullets[i].image, explosionAnim);
|
||||
bullets[i].clock = 0;
|
||||
bullets[i].frame = 0;
|
||||
bullets[i].explosion = TRUE;
|
||||
|
|
@ -186,6 +227,7 @@ void killBullet(u8 i, bool explode){
|
|||
}
|
||||
|
||||
void killEnemy(u8 i){
|
||||
if(isAttract) return;
|
||||
enemies[i].hp--;
|
||||
if(enemies[i].hp > 0) return;
|
||||
if(enemies[i].ints[3] >= 0){
|
||||
|
|
@ -200,6 +242,7 @@ void killEnemy(u8 i){
|
|||
}
|
||||
enemies[i].active = FALSE;
|
||||
SPR_releaseSprite(enemies[i].image);
|
||||
levelEnemiesKilled++;
|
||||
}
|
||||
|
||||
static fix32 getWrappedDelta(fix32 a, fix32 b) {
|
||||
|
|
@ -214,37 +257,61 @@ static fix32 getWrappedDelta(fix32 a, fix32 b) {
|
|||
|
||||
static s16 getScreenX(fix32 worldX, fix32 camera) {
|
||||
fix32 screenX = worldX - camera;
|
||||
if (screenX < FIX32(-256)) {
|
||||
if (screenX < -(GAME_WRAP / 2)) {
|
||||
screenX += GAME_WRAP;
|
||||
} else if (screenX > FIX32(256)) {
|
||||
} else if (screenX > (GAME_WRAP / 2)) {
|
||||
screenX -= GAME_WRAP;
|
||||
}
|
||||
return fix32ToInt(screenX);
|
||||
return F32_toInt(screenX);
|
||||
}
|
||||
|
||||
|
||||
// homing
|
||||
#define PI_MOD 2.84444444444
|
||||
#define PI_F FIX16(3.14159265358 * PI_MOD)
|
||||
#define PI_F_2 FIX16(1.57079632679 * PI_MOD)
|
||||
#define PI_F_4 FIX16(0.78539816339 * PI_MOD)
|
||||
fix16 arctan(fix16 x) {
|
||||
return fix16Mul(PI_F_4, x) - fix16Mul(fix16Mul(x, (abs(x) - 1)), (FIX16(0.245) + fix16Mul(FIX16(0.066), abs(x))));
|
||||
// homing -- degree-based using SGDK F16_atan2 (returns fix16 degrees)
|
||||
static fix16 getAngle(fix32 dx, fix32 dy){
|
||||
s16 ix = (s16)(F32_toInt(dx) >> 2);
|
||||
s16 iy = (s16)(F32_toInt(dy) >> 2);
|
||||
if(ix == 0 && iy == 0) return 0;
|
||||
return F16_normalizeAngle(F16_atan2(FIX16(iy), FIX16(ix)));
|
||||
}
|
||||
fix16 arctan2(fix16 y, fix16 x) {
|
||||
return x >= 0 ?
|
||||
(y >= 0 ? (y < x ? arctan(fix16Div(y, x)) : PI_F_2 - arctan(fix16Div(x, y))) : (-y < x ? arctan(fix16Div(y, x)) : -PI_F_2 - arctan(fix16Div(x, y)))) :
|
||||
(y >= 0 ? (y < -x ? arctan(fix16Div(y, x)) + PI_F : PI_F_2 - arctan(fix16Div(x, y))) : (-y < -x ? arctan(fix16Div(y, x)) - PI_F : -PI_F_2 - arctan(fix16Div(x, y))));
|
||||
|
||||
// safe angle accumulation -- keeps angle in [-180, 180) so adding up to 180° can't overflow s16
|
||||
static s16 angleAdd(s16 a, s16 step){
|
||||
if(a >= FIX16(180)) a -= FIX16(360);
|
||||
return a + step;
|
||||
}
|
||||
s16 arcAngle;
|
||||
s16 honeAngle(fix16 x1, fix16 x2, fix16 y1, fix16 y2){
|
||||
arcAngle = arctan2(y2 - y1, x2 - x1);
|
||||
if(arcAngle >= 128) arcAngle -= 32;
|
||||
if(arcAngle >= 384) arcAngle -= 32;
|
||||
if(arcAngle < 0){
|
||||
arcAngle = 1024 + arcAngle;
|
||||
if(arcAngle < 896) arcAngle += 32;
|
||||
if(arcAngle < 640) arcAngle += 32;
|
||||
|
||||
static bool isBossLevel(u8 lvl){
|
||||
return (lvl >= 2) && ((lvl + 1) % 3 == 0);
|
||||
}
|
||||
|
||||
#define FONT_THEME_RED 0
|
||||
#define FONT_THEME_GREEN 1
|
||||
#define FONT_THEME_BLUE 2
|
||||
|
||||
u16 fontPal[16];
|
||||
void loadFontPalette(u8 theme) {
|
||||
u16 coloredPalette[16];
|
||||
u8 i;
|
||||
for(i = 0; i < 16; i++) {
|
||||
u16 color = font.palette->data[i];
|
||||
u16 r = color & 0xF;
|
||||
u16 g = (color >> 4) & 0xF;
|
||||
u16 b = (color >> 8) & 0xF;
|
||||
switch(theme) {
|
||||
case FONT_THEME_GREEN:
|
||||
coloredPalette[i] = (b << 8) | (r << 4) | g;
|
||||
break;
|
||||
case FONT_THEME_BLUE: {
|
||||
u16 newB = r > b ? r : b;
|
||||
coloredPalette[i] = (newB << 8) | (g << 4) | (r >> 1);
|
||||
break;
|
||||
}
|
||||
default: // FONT_THEME_RED
|
||||
coloredPalette[i] = color;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return arcAngle;
|
||||
memcpy(fontPal, coloredPalette, 16 * sizeof(u16));
|
||||
PAL_setPalette(PAL3, coloredPalette, DMA_QUEUE);
|
||||
VDP_setTextPalette(PAL3);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue