shit!
BIN
res/fontbig.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
res/fontbigshadow.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
res/ground.png
|
Before Width: | Height: | Size: 3 KiB After Width: | Height: | Size: 5.5 KiB |
BIN
res/human.png
Normal file
|
After Width: | Height: | Size: 4 KiB |
BIN
res/life.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
res/life2.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
|
|
@ -20,7 +20,13 @@ SPRITE butterflySprite "butterfly.png" 4 4 NONE 8
|
||||||
// SPRITE fairySprite "fairy.png" 4 4 NONE 8
|
// SPRITE fairySprite "fairy.png" 4 4 NONE 8
|
||||||
SPRITE fairySprite "fairy2.png" 4 4 NONE 8
|
SPRITE fairySprite "fairy2.png" 4 4 NONE 8
|
||||||
SPRITE aliceSprite "alice.png" 6 6 NONE 0
|
SPRITE aliceSprite "alice.png" 6 6 NONE 0
|
||||||
|
SPRITE humanSprite "human.png" 2 2 NONE 0
|
||||||
|
|
||||||
// IMAGE mapPlayer "mapplayer.png" NONE NONE
|
// IMAGE mapPlayer "mapplayer.png" NONE NONE
|
||||||
IMAGE mapIndicator "mapindicator.png" NONE NONE
|
IMAGE mapIndicator "mapindicator.png" NONE NONE
|
||||||
// IMAGE mapFrame "mapframe.png" NONE NONE
|
// IMAGE mapFrame "mapframe.png" NONE NONE
|
||||||
|
|
||||||
|
IMAGE imageFontBig "fontbig.png" NONE NONE
|
||||||
|
IMAGE imageFontBigShadow "fontbigshadow.png" NONE NONE
|
||||||
|
IMAGE imageChromeLife "life.png" NONE NONE
|
||||||
|
IMAGE imageChromeLife2 "life2.png" NONE NONE
|
||||||
BIN
res/sky.png
|
Before Width: | Height: | Size: 5 KiB After Width: | Height: | Size: 5 KiB |
|
|
@ -2,7 +2,7 @@
|
||||||
// #define FADE_TOP_I BG_I + 64
|
// #define FADE_TOP_I BG_I + 64
|
||||||
// #define FADE_BOTTOM_I FADE_TOP_I + 64
|
// #define FADE_BOTTOM_I FADE_TOP_I + 64
|
||||||
|
|
||||||
#define BG_OFF 112
|
#define BG_OFF 24
|
||||||
|
|
||||||
void loadBackground(){
|
void loadBackground(){
|
||||||
VDP_loadTileSet(sky.tileset, BG_I, DMA);
|
VDP_loadTileSet(sky.tileset, BG_I, DMA);
|
||||||
|
|
@ -11,7 +11,7 @@ void loadBackground(){
|
||||||
// VDP_loadTileSet(fadeBottom.tileset, FADE_BOTTOM_I, DMA);
|
// VDP_loadTileSet(fadeBottom.tileset, FADE_BOTTOM_I, DMA);
|
||||||
for(u8 y = 0; y < 4; y++){
|
for(u8 y = 0; y < 4; y++){
|
||||||
for(u8 x = 0; x < 16; x++){
|
for(u8 x = 0; x < 16; x++){
|
||||||
VDP_fillTileMapRectInc(BG_B, TILE_ATTR_FULL(PAL1, 0, 0, 0, BG_I), x * 8, y * 8, 8, 8);
|
VDP_fillTileMapRectInc(BG_B, TILE_ATTR_FULL(PAL1, 0, 0, 0, BG_I + (y > 2 ? 64 : 0)), x * 8, y * 8, 8, 8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// for(u8 x = 0; x < 5; x++){
|
// for(u8 x = 0; x < 5; x++){
|
||||||
|
|
@ -22,5 +22,5 @@ void loadBackground(){
|
||||||
|
|
||||||
void updateBackground(){
|
void updateBackground(){
|
||||||
VDP_setHorizontalScroll(BG_B, fix32ToInt(-player.camera));
|
VDP_setHorizontalScroll(BG_B, fix32ToInt(-player.camera));
|
||||||
VDP_setVerticalScroll(BG_B, (fix32ToInt(player.pos.y) - BG_OFF) >> 2);
|
VDP_setVerticalScroll(BG_B, (fix32ToInt(player.pos.y) - BG_OFF) >> 3);
|
||||||
}
|
}
|
||||||
|
|
@ -57,6 +57,7 @@ static void doBulletRotation(u8 i){
|
||||||
}
|
}
|
||||||
|
|
||||||
void spawnBullet(struct bulletSpawner spawner, void(*updater)){
|
void spawnBullet(struct bulletSpawner spawner, void(*updater)){
|
||||||
|
if(player.recoveringClock > 0 && !spawner.player) return;
|
||||||
// Don't spawn if offscreen
|
// Don't spawn if offscreen
|
||||||
fix32 dx = getWrappedDelta(spawner.x, player.pos.x);
|
fix32 dx = getWrappedDelta(spawner.x, player.pos.x);
|
||||||
bool offScreenX = (dx < -CULL_LIMIT || dx > CULL_LIMIT);
|
bool offScreenX = (dx < -CULL_LIMIT || dx > CULL_LIMIT);
|
||||||
|
|
@ -124,6 +125,7 @@ static void collideWithEnemy(u8 i){
|
||||||
deltaX >= -BULLET_CHECK && deltaX <= BULLET_CHECK){
|
deltaX >= -BULLET_CHECK && deltaX <= BULLET_CHECK){
|
||||||
bulletDist = getApproximatedDistance(fix32ToInt(deltaX), fix32ToInt(deltaY));
|
bulletDist = getApproximatedDistance(fix32ToInt(deltaX), fix32ToInt(deltaY));
|
||||||
if(bulletDist <= bullets[i].dist){
|
if(bulletDist <= bullets[i].dist){
|
||||||
|
score += (enemies[j].ints[3] >= 0) ? 200 : 100;
|
||||||
killBullet(i, TRUE);
|
killBullet(i, TRUE);
|
||||||
killEnemy(j);
|
killEnemy(j);
|
||||||
sfxExplosion();
|
sfxExplosion();
|
||||||
|
|
@ -134,6 +136,7 @@ static void collideWithEnemy(u8 i){
|
||||||
}
|
}
|
||||||
|
|
||||||
static void collideWithPlayer(u8 i){
|
static void collideWithPlayer(u8 i){
|
||||||
|
if(player.recoveringClock > 0) return;
|
||||||
fix32 deltaX = getWrappedDelta(bullets[i].pos.x, player.pos.x);
|
fix32 deltaX = getWrappedDelta(bullets[i].pos.x, player.pos.x);
|
||||||
fix32 deltaY = bullets[i].pos.y - player.pos.y;
|
fix32 deltaY = bullets[i].pos.y - player.pos.y;
|
||||||
|
|
||||||
|
|
@ -143,8 +146,13 @@ static void collideWithPlayer(u8 i){
|
||||||
if(dist <= 4){
|
if(dist <= 4){
|
||||||
killBullet(i, TRUE);
|
killBullet(i, TRUE);
|
||||||
sfxExplosion();
|
sfxExplosion();
|
||||||
// player.lives--;
|
player.lives--;
|
||||||
// if(player.lives <= 0) gameOver = TRUE;
|
if(player.lives == 0){
|
||||||
|
gameOver = TRUE;
|
||||||
|
} else {
|
||||||
|
player.recoveringClock = 120;
|
||||||
|
killBullets = TRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -195,7 +203,7 @@ static void updateBullet(u8 i){
|
||||||
}
|
}
|
||||||
if(bullets[i].clock > 0) bullets[i].updater(i);
|
if(bullets[i].clock > 0) bullets[i].updater(i);
|
||||||
if(bullets[i].player) collideWithEnemy(i);
|
if(bullets[i].player) collideWithEnemy(i);
|
||||||
else collideWithPlayer(i);
|
else if(!gameOver) collideWithPlayer(i);
|
||||||
if(bullets[i].active){
|
if(bullets[i].active){
|
||||||
s16 sx = getScreenX(bullets[i].pos.x, player.camera);
|
s16 sx = getScreenX(bullets[i].pos.x, player.camera);
|
||||||
s16 sy = fix32ToInt(bullets[i].pos.y);
|
s16 sy = fix32ToInt(bullets[i].pos.y);
|
||||||
|
|
@ -209,6 +217,11 @@ static void updateBullet(u8 i){
|
||||||
|
|
||||||
void updateBullets(){
|
void updateBullets(){
|
||||||
bulletCount = 0;
|
bulletCount = 0;
|
||||||
|
if(killBullets){
|
||||||
|
killBullets = FALSE;
|
||||||
|
for(s16 i = 0; i < BULLET_COUNT; i++)
|
||||||
|
if(bullets[i].active && !bullets[i].player) killBullet(i, TRUE);
|
||||||
|
}
|
||||||
for(s16 i = 0; i < BULLET_COUNT; i++) if(bullets[i].active)
|
for(s16 i = 0; i < BULLET_COUNT; i++) if(bullets[i].active)
|
||||||
updateBullet(i);
|
updateBullet(i);
|
||||||
// intToStr(bulletCount, debugStr, 1);
|
// intToStr(bulletCount, debugStr, 1);
|
||||||
|
|
|
||||||
117
src/chrome.h
|
|
@ -2,18 +2,55 @@
|
||||||
#define MAP_TILE TILE_ATTR_FULL(PAL1, 1, 0, 0, MAP_I)
|
#define MAP_TILE TILE_ATTR_FULL(PAL1, 1, 0, 0, MAP_I)
|
||||||
#define MAP_PLAYER_TILE TILE_ATTR_FULL(PAL0, 1, 0, 0, MAP_I + 1)
|
#define MAP_PLAYER_TILE TILE_ATTR_FULL(PAL0, 1, 0, 0, MAP_I + 1)
|
||||||
#define MAP_ENEMY_TILE TILE_ATTR_FULL(PAL0, 1, 0, 0, MAP_I + 2)
|
#define MAP_ENEMY_TILE TILE_ATTR_FULL(PAL0, 1, 0, 0, MAP_I + 2)
|
||||||
#define MAP_BORDER_X_TILE TILE_ATTR_FULL(PAL0, 1, 0, 0, MAP_I + 3)
|
#define MAP_HUMAN_TILE TILE_ATTR_FULL(PAL0, 1, 0, 0, MAP_I + 3)
|
||||||
|
#define MAP_BORDER_X_TILE TILE_ATTR_FULL(PAL0, 1, 0, 0, MAP_I + 4)
|
||||||
|
|
||||||
|
#define FONT_BIG_I 256
|
||||||
|
|
||||||
|
void bigText(char* str, u16 x, u16 y, bool shadow){
|
||||||
|
for(u8 i = 0; i < strlen(str); i++){
|
||||||
|
if(str[i] >= 48){
|
||||||
|
VDP_setTileMapXY(BG_A, TILE_ATTR_FULL(PAL0, 1, 0, 0, (shadow ? 32 : 0) + FONT_BIG_I + str[i] - 48), x + i, y);
|
||||||
|
VDP_setTileMapXY(BG_A, TILE_ATTR_FULL(PAL0, 1, 0, 0, (shadow ? 32 : 0) + FONT_BIG_I + 16 + str[i] - 48), x + i, y + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
char scoreStr[SCORE_LENGTH];
|
char scoreStr[SCORE_LENGTH];
|
||||||
u32 lastScore;
|
u32 lastScore;
|
||||||
|
s16 scoreLength;
|
||||||
|
|
||||||
|
#define SCORE_X 1
|
||||||
|
#define SCORE_Y 5
|
||||||
|
|
||||||
|
#define LIFE_I (FONT_BIG_I + 64)
|
||||||
|
#define LIVES_X 38
|
||||||
|
#define LIVES_Y 5
|
||||||
|
s16 lastLives;
|
||||||
|
|
||||||
|
static void drawLives(){
|
||||||
|
VDP_clearTileMapRect(BG_A, LIVES_X, LIVES_Y, 1, 16);
|
||||||
|
for(u8 i = 0; i < (player.lives - 1); i++)
|
||||||
|
VDP_fillTileMapRectInc(BG_A, TILE_ATTR_FULL(PAL0, 1, 0, 0, LIFE_I + (i > 0 ? 2 : 0)), LIVES_X, LIVES_Y + i, 1, 2);
|
||||||
|
lastLives = player.lives;
|
||||||
|
}
|
||||||
|
|
||||||
// previous map positions: -1 means not drawn
|
// previous map positions: -1 means not drawn
|
||||||
s16 mapEnemyCol[ENEMY_COUNT], mapEnemyRow[ENEMY_COUNT];
|
s16 mapEnemyCol[ENEMY_COUNT], mapEnemyRow[ENEMY_COUNT];
|
||||||
|
s16 mapHumanCol[HUMAN_COUNT], mapHumanRow[HUMAN_COUNT];
|
||||||
s16 mapPlayerRow;
|
s16 mapPlayerRow;
|
||||||
|
|
||||||
static void drawScore(){
|
static void drawScore(){
|
||||||
uintToStr(score, scoreStr, 1);
|
if(lastScore < 10) scoreLength = 1;
|
||||||
VDP_drawText(scoreStr, 1, 5);
|
else if(lastScore < 100) scoreLength = 2;
|
||||||
|
else if(lastScore < 1000) scoreLength = 3;
|
||||||
|
else if(lastScore < 10000) scoreLength = 4;
|
||||||
|
else if(lastScore < 100000) scoreLength = 5;
|
||||||
|
else if(lastScore < 1000000) scoreLength = 6;
|
||||||
|
else if(lastScore < 10000000) scoreLength = 7;
|
||||||
|
else scoreLength = 8;
|
||||||
|
uintToStr(lastScore, scoreStr, scoreLength);
|
||||||
|
bigText(scoreStr, SCORE_X, SCORE_Y, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// load map when stage does so we have all enemies + player
|
// load map when stage does so we have all enemies + player
|
||||||
|
|
@ -29,17 +66,24 @@ void loadMap(){
|
||||||
mapEnemyCol[i] = -1;
|
mapEnemyCol[i] = -1;
|
||||||
mapEnemyRow[i] = -1;
|
mapEnemyRow[i] = -1;
|
||||||
}
|
}
|
||||||
|
for(s16 i = 0; i < HUMAN_COUNT; i++){
|
||||||
|
mapHumanCol[i] = -1;
|
||||||
|
mapHumanRow[i] = -1;
|
||||||
|
}
|
||||||
mapPlayerRow = -1;
|
mapPlayerRow = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// temp arrays for new positions
|
// temp arrays for new positions
|
||||||
s16 mapNewCol[ENEMY_COUNT], mapNewRow[ENEMY_COUNT];
|
s16 mapNewCol[ENEMY_COUNT], mapNewRow[ENEMY_COUNT];
|
||||||
|
s16 mapNewHumanCol[HUMAN_COUNT], mapNewHumanRow[HUMAN_COUNT];
|
||||||
|
|
||||||
static bool mapTileOccupied(s16 col, s16 row, s16 pRow){
|
static bool mapTileOccupied(s16 col, s16 row, s16 pRow){
|
||||||
// player always at center column
|
// player always at center column
|
||||||
if(col == MAP_W / 2 && row == pRow) return TRUE;
|
if(col == MAP_W / 2 && row == pRow) return TRUE;
|
||||||
for(s16 i = 0; i < ENEMY_COUNT; i++)
|
for(s16 i = 0; i < ENEMY_COUNT; i++)
|
||||||
if(mapNewCol[i] == col && mapNewRow[i] == row) return TRUE;
|
if(mapNewCol[i] == col && mapNewRow[i] == row) return TRUE;
|
||||||
|
for(s16 i = 0; i < HUMAN_COUNT; i++)
|
||||||
|
if(mapNewHumanCol[i] == col && mapNewHumanRow[i] == row) return TRUE;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -67,6 +111,24 @@ static void updateMap(){
|
||||||
mapNewRow[i] = row;
|
mapNewRow[i] = row;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// compute new human positions
|
||||||
|
for(s16 i = 0; i < HUMAN_COUNT; i++){
|
||||||
|
if(!humans[i].active || humans[i].image == NULL){
|
||||||
|
mapNewHumanCol[i] = -1;
|
||||||
|
mapNewHumanRow[i] = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
fix32 dx = getWrappedDelta(humans[i].pos.x, player.pos.x);
|
||||||
|
s16 col = fix32ToInt(dx) / 54 + MAP_W / 2;
|
||||||
|
if(col < 0) col = 0;
|
||||||
|
if(col >= MAP_W) col = MAP_W - 1;
|
||||||
|
s16 row = fix32ToInt(humans[i].pos.y) / 75;
|
||||||
|
if(row < 0) row = 0;
|
||||||
|
if(row >= MAP_H) row = MAP_H - 1;
|
||||||
|
mapNewHumanCol[i] = col;
|
||||||
|
mapNewHumanRow[i] = row;
|
||||||
|
}
|
||||||
|
|
||||||
// clear old player tile if it moved and nothing new occupies it
|
// clear old player tile if it moved and nothing new occupies it
|
||||||
if(mapPlayerRow >= 0 && mapPlayerRow != pRow)
|
if(mapPlayerRow >= 0 && mapPlayerRow != pRow)
|
||||||
if(!mapTileOccupied(MAP_W / 2, mapPlayerRow, pRow))
|
if(!mapTileOccupied(MAP_W / 2, mapPlayerRow, pRow))
|
||||||
|
|
@ -80,6 +142,23 @@ static void updateMap(){
|
||||||
VDP_setTileMapXY(BG_A, MAP_TILE, MAP_X + mapEnemyCol[i], MAP_Y + mapEnemyRow[i]);
|
VDP_setTileMapXY(BG_A, MAP_TILE, MAP_X + mapEnemyCol[i], MAP_Y + mapEnemyRow[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clear old human tiles that moved or disappeared
|
||||||
|
for(s16 i = 0; i < HUMAN_COUNT; i++){
|
||||||
|
if(mapHumanCol[i] < 0) continue;
|
||||||
|
if(mapHumanCol[i] == mapNewHumanCol[i] && mapHumanRow[i] == mapNewHumanRow[i]) continue;
|
||||||
|
if(!mapTileOccupied(mapHumanCol[i], mapHumanRow[i], pRow))
|
||||||
|
VDP_setTileMapXY(BG_A, MAP_TILE, MAP_X + mapHumanCol[i], MAP_Y + mapHumanRow[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw human dots (skip if player occupies same tile)
|
||||||
|
for(s16 i = 0; i < HUMAN_COUNT; i++){
|
||||||
|
mapHumanCol[i] = mapNewHumanCol[i];
|
||||||
|
mapHumanRow[i] = mapNewHumanRow[i];
|
||||||
|
if(mapNewHumanCol[i] < 0) continue;
|
||||||
|
if(mapNewHumanCol[i] == MAP_W / 2 && mapNewHumanRow[i] == pRow) continue;
|
||||||
|
VDP_setTileMapXY(BG_A, MAP_HUMAN_TILE, MAP_X + mapNewHumanCol[i], MAP_Y + mapNewHumanRow[i]);
|
||||||
|
}
|
||||||
|
|
||||||
// draw enemy dots (skip if player occupies same tile)
|
// draw enemy dots (skip if player occupies same tile)
|
||||||
for(s16 i = 0; i < ENEMY_COUNT; i++){
|
for(s16 i = 0; i < ENEMY_COUNT; i++){
|
||||||
mapEnemyCol[i] = mapNewCol[i];
|
mapEnemyCol[i] = mapNewCol[i];
|
||||||
|
|
@ -95,18 +174,42 @@ static void updateMap(){
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadChrome(){
|
void loadChrome(){
|
||||||
|
VDP_loadTileSet(imageFontBig.tileset, FONT_BIG_I, DMA);
|
||||||
|
VDP_loadTileSet(imageFontBigShadow.tileset, FONT_BIG_I + 32, DMA);
|
||||||
|
VDP_loadTileSet(imageChromeLife.tileset, LIFE_I, DMA);
|
||||||
|
VDP_loadTileSet(imageChromeLife2.tileset, LIFE_I + 2, DMA);
|
||||||
VDP_loadTileSet(mapIndicator.tileset, MAP_I, DMA);
|
VDP_loadTileSet(mapIndicator.tileset, MAP_I, DMA);
|
||||||
|
lastScore = 1;
|
||||||
drawScore();
|
drawScore();
|
||||||
|
drawLives();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool didGameOver;
|
||||||
|
static void doGameOver(){
|
||||||
|
didGameOver = TRUE;
|
||||||
|
for(s16 i = 0; i < BULLET_COUNT; i++) if(bullets[i].active) SPR_setPalette(bullets[i].image, PAL1);
|
||||||
|
for(s16 i = 0; i < ENEMY_COUNT; i++) if(enemies[i].active) SPR_setPalette(enemies[i].image, PAL1);
|
||||||
|
for(s16 i = 0; i < HUMAN_COUNT; i++) if(humans[i].active) SPR_setPalette(humans[i].image, PAL1);
|
||||||
|
SPR_releaseSprite(player.image);
|
||||||
|
// clear minimap
|
||||||
|
VDP_clearTileMapRect(BG_A, MAP_X, MAP_Y, MAP_W, MAP_H);
|
||||||
|
// clear score
|
||||||
|
VDP_clearTileMapRect(BG_A, SCORE_X, SCORE_Y, SCORE_LENGTH, 2);
|
||||||
|
|
||||||
|
// clear lives
|
||||||
|
VDP_clearTileMapRect(BG_A, LIVES_X, LIVES_Y, 1, 16);
|
||||||
|
|
||||||
|
VDP_drawText("GAME OVER", 15, 13);
|
||||||
|
VDP_drawText("PRESS ANY BUTTON", 12, 14);
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateChrome(){
|
void updateChrome(){
|
||||||
score++;
|
if(gameOver && !didGameOver) doGameOver();
|
||||||
if(score > 99999999) score = 0;
|
if(didGameOver) return;
|
||||||
if(lastScore != score){
|
if(lastScore != score){
|
||||||
lastScore = score;
|
lastScore = score;
|
||||||
drawScore();
|
drawScore();
|
||||||
}
|
}
|
||||||
|
if(lastLives != player.lives) drawLives();
|
||||||
if(clock % 4 == 0) updateMap();
|
if(clock % 4 == 0) updateMap();
|
||||||
// VDP_clearText(1, 26, 4);
|
|
||||||
// VDP_drawText(debugStr, 1, 26);
|
|
||||||
}
|
}
|
||||||
|
|
@ -34,7 +34,7 @@ void spawnEnemy(u8 type, u8 zone){
|
||||||
do {
|
do {
|
||||||
// Random X within zone: zoneStart + random(0-511)
|
// Random X within zone: zoneStart + random(0-511)
|
||||||
randX = zoneStart + FIX32(random() % 512);
|
randX = zoneStart + FIX32(random() % 512);
|
||||||
randY = FIX32(16 + (random() % 192));
|
randY = FIX32(16 + (random() % 128));
|
||||||
attempts++;
|
attempts++;
|
||||||
} while(!isValidEnemyPosition(randX, randY) && attempts < 100);
|
} while(!isValidEnemyPosition(randX, randY) && attempts < 100);
|
||||||
|
|
||||||
|
|
@ -61,8 +61,22 @@ void spawnEnemy(u8 type, u8 zone){
|
||||||
}
|
}
|
||||||
|
|
||||||
static void boundsEnemy(u8 i){
|
static void boundsEnemy(u8 i){
|
||||||
|
if(enemies[i].ints[3] >= 0){
|
||||||
|
// carrying: only check for reaching the top
|
||||||
|
if(enemies[i].pos.y <= FIX32(0)){
|
||||||
|
s16 h = enemies[i].ints[3];
|
||||||
|
if(humans[h].active) killHuman(h);
|
||||||
|
enemies[i].ints[3] = -1;
|
||||||
|
humanBeingCarried = FALSE;
|
||||||
|
// TODO: spawn mutant here
|
||||||
|
killEnemy(i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// not carrying: bounce off top and bottom
|
||||||
if(enemies[i].pos.y >= GAME_H_F - FIX32(enemies[i].off) || enemies[i].pos.y <= FIX32(enemies[i].off))
|
if(enemies[i].pos.y >= GAME_H_F - FIX32(enemies[i].off) || enemies[i].pos.y <= FIX32(enemies[i].off))
|
||||||
enemies[i].vel.y *= -1;
|
enemies[i].vel.y *= -1;
|
||||||
|
}
|
||||||
|
|
||||||
if(enemies[i].pos.x >= GAME_WRAP){
|
if(enemies[i].pos.x >= GAME_WRAP){
|
||||||
enemies[i].pos.x -= GAME_WRAP;
|
enemies[i].pos.x -= GAME_WRAP;
|
||||||
|
|
@ -73,7 +87,6 @@ static void boundsEnemy(u8 i){
|
||||||
}
|
}
|
||||||
|
|
||||||
static void updateEnemy(u8 i){
|
static void updateEnemy(u8 i){
|
||||||
boundsEnemy(i);
|
|
||||||
enemies[i].pos.x += enemies[i].vel.x;
|
enemies[i].pos.x += enemies[i].vel.x;
|
||||||
enemies[i].pos.y += enemies[i].vel.y;
|
enemies[i].pos.y += enemies[i].vel.y;
|
||||||
|
|
||||||
|
|
@ -83,6 +96,9 @@ static void updateEnemy(u8 i){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boundsEnemy(i);
|
||||||
|
if(!enemies[i].active) return;
|
||||||
|
|
||||||
s16 sx = getScreenX(enemies[i].pos.x, player.camera);
|
s16 sx = getScreenX(enemies[i].pos.x, player.camera);
|
||||||
s16 sy = fix32ToInt(enemies[i].pos.y);
|
s16 sy = fix32ToInt(enemies[i].pos.y);
|
||||||
fix32 dx = getWrappedDelta(enemies[i].pos.x, player.pos.x);
|
fix32 dx = getWrappedDelta(enemies[i].pos.x, player.pos.x);
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,81 @@
|
||||||
void loadEnemyOne(u8 i){
|
void loadEnemyOne(u8 i){
|
||||||
enemies[i].ints[0] = random() % 40;
|
enemies[i].ints[0] = random() % 60;
|
||||||
|
enemies[i].ints[2] = -1; // target human index
|
||||||
|
enemies[i].ints[3] = -1; // carried human index
|
||||||
enemies[i].angle = ((random() % 4) * 256) + 128;
|
enemies[i].angle = ((random() % 4) * 256) + 128;
|
||||||
enemies[i].speed = FIX32(2);
|
enemies[i].speed = FIX32(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateEnemyOne(u8 i){
|
void updateEnemyOne(u8 i){
|
||||||
if(enemies[i].clock % 40 == enemies[i].ints[0] && enemies[i].onScreen){
|
// carrying behavior: move upward, skip shooting
|
||||||
enemies[i].clock % 80 == enemies[i].ints[0] ? sfxEnemyShotB() : sfxEnemyShotA();
|
if(enemies[i].ints[3] >= 0){
|
||||||
|
// enemies[i].vel.x = (enemies[i].vel.x > 0) ? FIX32(0.3) : FIX32(-0.3);
|
||||||
|
// enemies[i].vel.y = FIX32(-1.5);
|
||||||
|
enemies[i].angle = 704 + (random() % 128);
|
||||||
|
enemies[i].vel.x = fix32Mul(fix16ToFix32(cosFix16(enemies[i].angle)), enemies[i].speed);
|
||||||
|
enemies[i].vel.y = fix32Mul(fix16ToFix32(sinFix16(enemies[i].angle)), enemies[i].speed);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cancel any target if a human is already being carried
|
||||||
|
if(humanBeingCarried && enemies[i].ints[2] >= 0){
|
||||||
|
enemies[i].ints[2] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// seeking behavior: periodically look for a human to grab
|
||||||
|
if(!humanBeingCarried && enemies[i].clock % 30 == (u32)(enemies[i].ints[0]) % 30){
|
||||||
|
s16 bestHuman = -1;
|
||||||
|
fix32 bestDist = FIX32(9999);
|
||||||
|
for(s16 j = 0; j < HUMAN_COUNT; j++){
|
||||||
|
if(!humans[j].active || humans[j].state != HUMAN_WALKING) continue;
|
||||||
|
fix32 dx = getWrappedDelta(enemies[i].pos.x, humans[j].pos.x);
|
||||||
|
fix32 dy = enemies[i].pos.y - humans[j].pos.y;
|
||||||
|
fix32 dist = (dx < 0 ? -dx : dx) + (dy < 0 ? -dy : dy);
|
||||||
|
if(dist < bestDist && dist < FIX32(256)){
|
||||||
|
bestDist = dist;
|
||||||
|
bestHuman = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enemies[i].ints[2] = bestHuman;
|
||||||
|
}
|
||||||
|
|
||||||
|
// steer toward target human
|
||||||
|
if(enemies[i].ints[2] >= 0){
|
||||||
|
s16 t = enemies[i].ints[2];
|
||||||
|
if(!humans[t].active || humans[t].state != HUMAN_WALKING){
|
||||||
|
enemies[i].ints[2] = -1;
|
||||||
|
} else {
|
||||||
|
fix32 dx = getWrappedDelta(humans[t].pos.x, enemies[i].pos.x);
|
||||||
|
fix32 dy = humans[t].pos.y - enemies[i].pos.y;
|
||||||
|
|
||||||
|
// hone toward human's current position at base speed
|
||||||
|
s16 angle = honeAngle(
|
||||||
|
fix32ToFix16(enemies[i].pos.x), fix32ToFix16(humans[t].pos.x),
|
||||||
|
fix32ToFix16(enemies[i].pos.y), fix32ToFix16(humans[t].pos.y));
|
||||||
|
enemies[i].vel.x = fix32Mul(fix16ToFix32(cosFix16(angle)), enemies[i].speed);
|
||||||
|
enemies[i].vel.y = fix32Mul(fix16ToFix32(sinFix16(angle)), enemies[i].speed);
|
||||||
|
|
||||||
|
// grab check: within 16px
|
||||||
|
fix32 adx = dx < 0 ? -dx : dx;
|
||||||
|
fix32 ady = dy < 0 ? -dy : dy;
|
||||||
|
if(adx < FIX32(16) && ady < FIX32(16)){
|
||||||
|
enemies[i].ints[3] = t;
|
||||||
|
enemies[i].ints[2] = -1;
|
||||||
|
humanBeingCarried = TRUE;
|
||||||
|
humans[t].state = HUMAN_CARRIED;
|
||||||
|
humans[t].carriedBy = i;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// normal shooting
|
||||||
|
if(enemies[i].clock % 60 == enemies[i].ints[0] && enemies[i].onScreen){
|
||||||
|
enemies[i].clock % 120 == enemies[i].ints[0] ? sfxEnemyShotB() : sfxEnemyShotA();
|
||||||
struct bulletSpawner spawner = {
|
struct bulletSpawner spawner = {
|
||||||
.x = enemies[i].pos.x,
|
.x = enemies[i].pos.x,
|
||||||
.y = enemies[i].pos.y,
|
.y = enemies[i].pos.y,
|
||||||
.anim = 3 + (random() % 3),
|
.anim = 3 + (random() % 3),
|
||||||
// .anim = 6,
|
|
||||||
// .frame = 1,
|
|
||||||
.speed = FIX32(2) + FIX16(random() % 4),
|
.speed = FIX32(2) + FIX16(random() % 4),
|
||||||
.angle = random() % 128,
|
.angle = random() % 128,
|
||||||
};
|
};
|
||||||
|
|
@ -26,16 +89,3 @@ void updateEnemyOne(u8 i){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateLander(u8 i){}
|
|
||||||
|
|
||||||
void updateMutant(u8 i){}
|
|
||||||
|
|
||||||
void updateSwarmer(u8 i){}
|
|
||||||
|
|
||||||
void updatePod(u8 i){}
|
|
||||||
|
|
||||||
void updateBomber(u8 i){}
|
|
||||||
|
|
||||||
void updateBaiter(u8 i){}
|
|
||||||
|
|
||||||
|
|
|
||||||
67
src/global.h
|
|
@ -50,15 +50,16 @@ void updateControls(u16 joy, u16 changed, u16 state){
|
||||||
struct playerStruct {
|
struct playerStruct {
|
||||||
Vect2D_f32 pos, vel;
|
Vect2D_f32 pos, vel;
|
||||||
s16 shotAngle;
|
s16 shotAngle;
|
||||||
u8 lives;
|
u8 lives, recoveringClock;
|
||||||
fix32 camera, yCamera;
|
fix32 camera, yCamera;
|
||||||
Sprite* image;
|
Sprite* image;
|
||||||
};
|
};
|
||||||
struct playerStruct player;
|
struct playerStruct player;
|
||||||
|
bool killBullets;
|
||||||
|
|
||||||
|
|
||||||
// bullets
|
// bullets
|
||||||
#define BULLET_COUNT 64
|
#define BULLET_COUNT 70
|
||||||
|
|
||||||
struct bulletSpawner {
|
struct bulletSpawner {
|
||||||
fix32 x, y, speed;
|
fix32 x, y, speed;
|
||||||
|
|
@ -92,6 +93,31 @@ struct enemy {
|
||||||
};
|
};
|
||||||
struct enemy enemies[ENEMY_COUNT];
|
struct enemy enemies[ENEMY_COUNT];
|
||||||
|
|
||||||
|
// humans
|
||||||
|
#define HUMAN_COUNT 8
|
||||||
|
#define HUMAN_WALKING 0
|
||||||
|
#define HUMAN_CARRIED 1
|
||||||
|
#define HUMAN_FALLING 2
|
||||||
|
|
||||||
|
struct human {
|
||||||
|
bool active;
|
||||||
|
u8 state;
|
||||||
|
s16 carriedBy;
|
||||||
|
Vect2D_f32 pos, vel;
|
||||||
|
Sprite* image;
|
||||||
|
};
|
||||||
|
struct human humans[HUMAN_COUNT];
|
||||||
|
bool humanBeingCarried;
|
||||||
|
|
||||||
|
void killHuman(u8 i){
|
||||||
|
if(humans[i].state == HUMAN_CARRIED && humans[i].carriedBy >= 0){
|
||||||
|
enemies[humans[i].carriedBy].ints[3] = -1;
|
||||||
|
humanBeingCarried = FALSE;
|
||||||
|
}
|
||||||
|
humans[i].active = FALSE;
|
||||||
|
SPR_releaseSprite(humans[i].image);
|
||||||
|
}
|
||||||
|
|
||||||
void killBullet(u8 i, bool explode){
|
void killBullet(u8 i, bool explode){
|
||||||
if(explode){
|
if(explode){
|
||||||
if(bullets[i].player){
|
if(bullets[i].player){
|
||||||
|
|
@ -120,6 +146,16 @@ void killBullet(u8 i, bool explode){
|
||||||
}
|
}
|
||||||
|
|
||||||
void killEnemy(u8 i){
|
void killEnemy(u8 i){
|
||||||
|
if(enemies[i].ints[3] >= 0){
|
||||||
|
s16 h = enemies[i].ints[3];
|
||||||
|
if(humans[h].active){
|
||||||
|
humans[h].state = HUMAN_FALLING;
|
||||||
|
humans[h].carriedBy = -1;
|
||||||
|
humans[h].vel.x = 0;
|
||||||
|
humans[h].vel.y = FIX32(2);
|
||||||
|
}
|
||||||
|
humanBeingCarried = FALSE;
|
||||||
|
}
|
||||||
enemies[i].active = FALSE;
|
enemies[i].active = FALSE;
|
||||||
SPR_releaseSprite(enemies[i].image);
|
SPR_releaseSprite(enemies[i].image);
|
||||||
}
|
}
|
||||||
|
|
@ -143,3 +179,30 @@ static s16 getScreenX(fix32 worldX, fix32 camera) {
|
||||||
}
|
}
|
||||||
return fix32ToInt(screenX);
|
return fix32ToInt(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))));
|
||||||
|
}
|
||||||
|
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))));
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
return arcAngle;
|
||||||
|
}
|
||||||
96
src/humans.h
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
|
||||||
|
void spawnHuman(u8 zone){
|
||||||
|
s16 i = -1;
|
||||||
|
for(s16 j = 0; j < HUMAN_COUNT; j++) if(!humans[j].active) { i = j; break; }
|
||||||
|
if(i == -1) return;
|
||||||
|
|
||||||
|
humans[i].active = TRUE;
|
||||||
|
humans[i].state = HUMAN_WALKING;
|
||||||
|
humans[i].carriedBy = -1;
|
||||||
|
|
||||||
|
fix32 zoneStart = FIX32(zone * 512);
|
||||||
|
humans[i].pos.x = zoneStart + FIX32(random() % 512);
|
||||||
|
humans[i].pos.y = GAME_H_F - FIX32(24);
|
||||||
|
|
||||||
|
fix32 speeds[] = { FIX32(0.3), FIX32(0.4), FIX32(0.5) };
|
||||||
|
humans[i].vel.x = (random() % 2 == 0) ? speeds[random() % 3] : -speeds[random() % 3];
|
||||||
|
humans[i].vel.y = (random() % 2 == 0) ? FIX32(0.1) : FIX32(-0.1);
|
||||||
|
|
||||||
|
humans[i].image = SPR_addSprite(&humanSprite,
|
||||||
|
getScreenX(humans[i].pos.x, player.camera), fix32ToInt(humans[i].pos.y),
|
||||||
|
TILE_ATTR(PAL0, 0, 0, 0));
|
||||||
|
if(!humans[i].image){
|
||||||
|
humans[i].active = FALSE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void updateHuman(u8 i){
|
||||||
|
switch(humans[i].state){
|
||||||
|
case HUMAN_WALKING:
|
||||||
|
// Y bounce: bob 4px around ground level
|
||||||
|
if(humans[i].pos.y >= GAME_H_F - FIX32(20) || humans[i].pos.y <= GAME_H_F - FIX32(28))
|
||||||
|
humans[i].vel.y *= -1;
|
||||||
|
|
||||||
|
// X wrap
|
||||||
|
if(humans[i].pos.x >= GAME_WRAP)
|
||||||
|
humans[i].pos.x -= GAME_WRAP;
|
||||||
|
if(humans[i].pos.x < 0)
|
||||||
|
humans[i].pos.x += GAME_WRAP;
|
||||||
|
|
||||||
|
humans[i].pos.x += humans[i].vel.x;
|
||||||
|
humans[i].pos.y += humans[i].vel.y;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HUMAN_CARRIED:
|
||||||
|
// follow carrier enemy position
|
||||||
|
if(humans[i].carriedBy >= 0 && enemies[humans[i].carriedBy].active){
|
||||||
|
humans[i].pos.x = enemies[humans[i].carriedBy].pos.x;
|
||||||
|
humans[i].pos.y = enemies[humans[i].carriedBy].pos.y + FIX32(16);
|
||||||
|
} else {
|
||||||
|
// carrier died (shouldn't normally reach here, killEnemy handles it)
|
||||||
|
humans[i].state = HUMAN_FALLING;
|
||||||
|
humans[i].carriedBy = -1;
|
||||||
|
humans[i].vel.x = 0;
|
||||||
|
humans[i].vel.y = FIX32(2);
|
||||||
|
humanBeingCarried = FALSE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HUMAN_FALLING:
|
||||||
|
humans[i].pos.y += humans[i].vel.y;
|
||||||
|
// land on ground
|
||||||
|
if(humans[i].pos.y >= GAME_H_F - FIX32(24)){
|
||||||
|
humans[i].pos.y = GAME_H_F - FIX32(24);
|
||||||
|
humans[i].state = HUMAN_WALKING;
|
||||||
|
fix32 speeds[] = { FIX32(0.3), FIX32(0.4), FIX32(0.5) };
|
||||||
|
humans[i].vel.x = (random() % 2 == 0) ? speeds[random() % 3] : -speeds[random() % 3];
|
||||||
|
humans[i].vel.y = (random() % 2 == 0) ? FIX32(0.1) : FIX32(-0.1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// collect: check overlap with player (walking or falling only)
|
||||||
|
fix32 dx = getWrappedDelta(humans[i].pos.x, player.pos.x);
|
||||||
|
if(humans[i].state != HUMAN_CARRIED){
|
||||||
|
fix32 dy = humans[i].pos.y - player.pos.y;
|
||||||
|
if(dx >= FIX32(-24) && dx <= FIX32(24) && dy >= FIX32(-24) && dy <= FIX32(24)){
|
||||||
|
score += (humans[i].state == HUMAN_FALLING) ? 2000 : 1000;
|
||||||
|
sfxPickup();
|
||||||
|
killHuman(i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s16 sx = getScreenX(humans[i].pos.x, player.camera);
|
||||||
|
s16 sy = fix32ToInt(humans[i].pos.y);
|
||||||
|
bool visible = (dx >= -CULL_LIMIT && dx <= CULL_LIMIT);
|
||||||
|
SPR_setVisibility(humans[i].image, visible ? VISIBLE : HIDDEN);
|
||||||
|
SPR_setPosition(humans[i].image, sx, sy);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateHumans(){
|
||||||
|
for(s16 i = 0; i < HUMAN_COUNT; i++)
|
||||||
|
if(humans[i].active)
|
||||||
|
updateHuman(i);
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
#include "background.h"
|
#include "background.h"
|
||||||
#include "bullets.h"
|
#include "bullets.h"
|
||||||
#include "enemies.h"
|
#include "enemies.h"
|
||||||
|
#include "humans.h"
|
||||||
#include "player.h"
|
#include "player.h"
|
||||||
#include "stage.h"
|
#include "stage.h"
|
||||||
#include "chrome.h"
|
#include "chrome.h"
|
||||||
|
|
@ -35,6 +36,8 @@ static void updateGame(){
|
||||||
updateSfx();
|
updateSfx();
|
||||||
if(clock % 2 == 0){
|
if(clock % 2 == 0){
|
||||||
updateEnemies();
|
updateEnemies();
|
||||||
|
if(!gameOver && enemyCount == 0) gameOver = TRUE;
|
||||||
|
updateHumans();
|
||||||
} else {
|
} else {
|
||||||
updateBackground();
|
updateBackground();
|
||||||
updateBullets();
|
updateBullets();
|
||||||
|
|
|
||||||
22
src/player.h
|
|
@ -9,8 +9,8 @@
|
||||||
#define PLAYER_BOUND_Y FIX32(PLAYER_OFF)
|
#define PLAYER_BOUND_Y FIX32(PLAYER_OFF)
|
||||||
#define PLAYER_BOUND_H FIX32(224 - PLAYER_OFF)
|
#define PLAYER_BOUND_H FIX32(224 - PLAYER_OFF)
|
||||||
|
|
||||||
#define CAMERA_X FIX32(80)
|
#define CAMERA_X FIX32(96)
|
||||||
#define CAMERA_W FIX32(240)
|
#define CAMERA_W FIX32(224)
|
||||||
|
|
||||||
#define SHOT_INTERVAL 15
|
#define SHOT_INTERVAL 15
|
||||||
|
|
||||||
|
|
@ -106,7 +106,10 @@ static void shootPlayer(){
|
||||||
.angle = player.shotAngle,
|
.angle = player.shotAngle,
|
||||||
.player = TRUE
|
.player = TRUE
|
||||||
};
|
};
|
||||||
spawnBullet(spawner, EMPTY);
|
void updater(s16 i){
|
||||||
|
if(bullets[i].clock == 5) killBullet(i, TRUE);
|
||||||
|
}
|
||||||
|
spawnBullet(spawner, updater);
|
||||||
sfxPlayerShot();
|
sfxPlayerShot();
|
||||||
shotClock = SHOT_INTERVAL;
|
shotClock = SHOT_INTERVAL;
|
||||||
} else if(shotClock > 0) shotClock--;
|
} else if(shotClock > 0) shotClock--;
|
||||||
|
|
@ -127,16 +130,21 @@ void loadPlayer(){
|
||||||
}
|
}
|
||||||
|
|
||||||
void updatePlayer(){
|
void updatePlayer(){
|
||||||
|
if(!gameOver){
|
||||||
|
if(player.recoveringClock > 0){
|
||||||
|
if(player.recoveringClock % 10 == 1)
|
||||||
|
SPR_setVisibility(player.image, player.recoveringClock % 20 == 1 ? VISIBLE : HIDDEN);
|
||||||
|
player.recoveringClock--;
|
||||||
|
if(player.recoveringClock == 0)
|
||||||
|
SPR_setVisibility(player.image, VISIBLE);
|
||||||
|
}
|
||||||
movePlayer();
|
movePlayer();
|
||||||
boundsPlayer();
|
boundsPlayer();
|
||||||
cameraPlayer();
|
cameraPlayer();
|
||||||
shootPlayer();
|
shootPlayer();
|
||||||
|
|
||||||
s16 sx = getScreenX(player.pos.x, player.camera);
|
s16 sx = getScreenX(player.pos.x, player.camera);
|
||||||
s16 sy = fix32ToInt(player.pos.y);
|
s16 sy = fix32ToInt(player.pos.y);
|
||||||
|
|
||||||
|
|
||||||
SPR_setPosition(player.image, sx - PLAYER_OFF, sy - PLAYER_OFF);
|
SPR_setPosition(player.image, sx - PLAYER_OFF, sy - PLAYER_OFF);
|
||||||
|
|
||||||
intToStr(fix32ToInt(player.pos.x), debugStr, 1);
|
intToStr(fix32ToInt(player.pos.x), debugStr, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
45
src/sfx.h
|
|
@ -1,10 +1,12 @@
|
||||||
static s16 sfxShotClock;
|
static s16 sfxShotClock;
|
||||||
static u16 sfxShotFreq;
|
static u16 sfxShotFreq;
|
||||||
|
|
||||||
|
#define SFX_VOL 2
|
||||||
|
|
||||||
void sfxPlayerShot(){
|
void sfxPlayerShot(){
|
||||||
sfxShotClock = 4;
|
sfxShotClock = 4;
|
||||||
sfxShotFreq = 150;
|
sfxShotFreq = 150;
|
||||||
PSG_setEnvelope(2, 2);
|
PSG_setEnvelope(2, SFX_VOL);
|
||||||
PSG_setFrequency(2, sfxShotFreq);
|
PSG_setFrequency(2, sfxShotFreq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -14,43 +16,56 @@ static u8 sfxEnemyShotType;
|
||||||
|
|
||||||
// high sharp zap - quick descending chirp
|
// high sharp zap - quick descending chirp
|
||||||
void sfxEnemyShotA(){
|
void sfxEnemyShotA(){
|
||||||
|
if(player.recoveringClock > 0) return;
|
||||||
sfxEnemyShotClock = 3;
|
sfxEnemyShotClock = 3;
|
||||||
sfxEnemyShotFreq = 1200;
|
sfxEnemyShotFreq = 1200;
|
||||||
sfxEnemyShotType = 0;
|
sfxEnemyShotType = 0;
|
||||||
PSG_setEnvelope(1, 3);
|
PSG_setEnvelope(1, SFX_VOL);
|
||||||
PSG_setFrequency(1, sfxEnemyShotFreq);
|
PSG_setFrequency(1, sfxEnemyShotFreq);
|
||||||
}
|
}
|
||||||
|
|
||||||
// mid buzzy pulse - sits in the midrange
|
// mid buzzy pulse - sits in the midrange
|
||||||
void sfxEnemyShotB(){
|
void sfxEnemyShotB(){
|
||||||
|
if(player.recoveringClock > 0) return;
|
||||||
sfxEnemyShotClock = 5;
|
sfxEnemyShotClock = 5;
|
||||||
sfxEnemyShotFreq = 400;
|
sfxEnemyShotFreq = 400;
|
||||||
sfxEnemyShotType = 1;
|
sfxEnemyShotType = 1;
|
||||||
PSG_setEnvelope(1, 3);
|
PSG_setEnvelope(1, SFX_VOL);
|
||||||
PSG_setFrequency(1, sfxEnemyShotFreq);
|
PSG_setFrequency(1, sfxEnemyShotFreq);
|
||||||
}
|
}
|
||||||
|
|
||||||
// quick rising ping - sweeps upward
|
// quick rising ping - sweeps upward
|
||||||
void sfxEnemyShotC(){
|
void sfxEnemyShotC(){
|
||||||
|
if(player.recoveringClock > 0) return;
|
||||||
sfxEnemyShotClock = 4;
|
sfxEnemyShotClock = 4;
|
||||||
sfxEnemyShotFreq = 300;
|
sfxEnemyShotFreq = 300;
|
||||||
sfxEnemyShotType = 2;
|
sfxEnemyShotType = 2;
|
||||||
PSG_setEnvelope(1, 3);
|
PSG_setEnvelope(1, SFX_VOL);
|
||||||
PSG_setFrequency(1, sfxEnemyShotFreq);
|
PSG_setFrequency(1, sfxEnemyShotFreq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static s16 sfxPickupClock;
|
||||||
|
static u16 sfxPickupFreq;
|
||||||
|
|
||||||
|
void sfxPickup(){
|
||||||
|
sfxPickupClock = 12;
|
||||||
|
sfxPickupFreq = 800;
|
||||||
|
PSG_setEnvelope(0, SFX_VOL);
|
||||||
|
PSG_setFrequency(0, sfxPickupFreq);
|
||||||
|
}
|
||||||
|
|
||||||
static s16 sfxExpClock;
|
static s16 sfxExpClock;
|
||||||
|
|
||||||
void sfxExplosion(){
|
void sfxExplosion(){
|
||||||
sfxExpClock = 18;
|
sfxExpClock = 18;
|
||||||
PSG_setNoise(PSG_NOISE_TYPE_WHITE, PSG_NOISE_FREQ_CLOCK2);
|
PSG_setNoise(PSG_NOISE_TYPE_WHITE, PSG_NOISE_FREQ_CLOCK2);
|
||||||
PSG_setEnvelope(3, 0);
|
PSG_setEnvelope(3, SFX_VOL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateSfx(){
|
void updateSfx(){
|
||||||
if(sfxExpClock > 0){
|
if(sfxExpClock > 0){
|
||||||
sfxExpClock--;
|
sfxExpClock--;
|
||||||
PSG_setEnvelope(3, (18 - sfxExpClock) * 15 / 18);
|
PSG_setEnvelope(3, SFX_VOL + (18 - sfxExpClock) * (15 - SFX_VOL) / 18);
|
||||||
if(sfxExpClock == 0){
|
if(sfxExpClock == 0){
|
||||||
PSG_setEnvelope(3, 15);
|
PSG_setEnvelope(3, 15);
|
||||||
}
|
}
|
||||||
|
|
@ -61,18 +76,28 @@ void updateSfx(){
|
||||||
else if(sfxEnemyShotType == 1) sfxEnemyShotFreq -= 50;
|
else if(sfxEnemyShotType == 1) sfxEnemyShotFreq -= 50;
|
||||||
else sfxEnemyShotFreq += 150;
|
else sfxEnemyShotFreq += 150;
|
||||||
PSG_setFrequency(1, sfxEnemyShotFreq);
|
PSG_setFrequency(1, sfxEnemyShotFreq);
|
||||||
PSG_setEnvelope(1, 3 + (sfxEnemyShotType == 0 ? (3 - sfxEnemyShotClock) * 4 :
|
PSG_setEnvelope(1, SFX_VOL + (sfxEnemyShotType == 0 ? (3 - sfxEnemyShotClock) * (15 - SFX_VOL) / 3 :
|
||||||
sfxEnemyShotType == 1 ? (5 - sfxEnemyShotClock) * 2 :
|
sfxEnemyShotType == 1 ? (5 - sfxEnemyShotClock) * (15 - SFX_VOL) / 5 :
|
||||||
(4 - sfxEnemyShotClock) * 3));
|
(4 - sfxEnemyShotClock) * (15 - SFX_VOL) / 4));
|
||||||
if(sfxEnemyShotClock == 0){
|
if(sfxEnemyShotClock == 0){
|
||||||
PSG_setEnvelope(1, 15);
|
PSG_setEnvelope(1, 15);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(sfxPickupClock > 0){
|
||||||
|
sfxPickupClock--;
|
||||||
|
// rising staircase: jump up every 3 frames
|
||||||
|
if(sfxPickupClock % 3 == 0) sfxPickupFreq += 200;
|
||||||
|
PSG_setFrequency(0, sfxPickupFreq);
|
||||||
|
PSG_setEnvelope(0, SFX_VOL);
|
||||||
|
if(sfxPickupClock == 0){
|
||||||
|
PSG_setEnvelope(0, 15);
|
||||||
|
}
|
||||||
|
}
|
||||||
if(sfxShotClock > 0){
|
if(sfxShotClock > 0){
|
||||||
sfxShotClock--;
|
sfxShotClock--;
|
||||||
sfxShotFreq -= 30;
|
sfxShotFreq -= 30;
|
||||||
PSG_setFrequency(2, sfxShotFreq);
|
PSG_setFrequency(2, sfxShotFreq);
|
||||||
PSG_setEnvelope(2, 2 + (4 - sfxShotClock) * 3);
|
PSG_setEnvelope(2, SFX_VOL + (4 - sfxShotClock) * (15 - SFX_VOL) / 4);
|
||||||
if(sfxShotClock == 0){
|
if(sfxShotClock == 0){
|
||||||
PSG_setEnvelope(2, 15);
|
PSG_setEnvelope(2, 15);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,15 @@
|
||||||
void loadStage(){
|
void loadStage(){
|
||||||
// Spawn 2 enemies per zone (4 zones = 8 total)
|
// Spawn 3 enemies per zone (4 zones = 12 total)
|
||||||
for(u8 zone = 0; zone < 4; zone++){
|
for(u8 zone = 0; zone < 4; zone++){
|
||||||
for(u8 i = 0; i < 3; i++){
|
for(u8 i = 0; i < 3; i++){
|
||||||
spawnEnemy(0, zone);
|
spawnEnemy(0, zone);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Spawn 2 humans per zone (4 zones = 8 total)
|
||||||
|
for(u8 zone = 0; zone < 4; zone++){
|
||||||
|
for(u8 i = 0; i < 2; i++){
|
||||||
|
spawnHuman(zone);
|
||||||
|
}
|
||||||
|
}
|
||||||
loadMap();
|
loadMap();
|
||||||
}
|
}
|
||||||