explosion and more graphics
This commit is contained in:
		
							parent
							
								
									0750aef980
								
							
						
					
					
						commit
						600d04f3c9
					
				
					 14 changed files with 327 additions and 99 deletions
				
			
		
							
								
								
									
										
											BIN
										
									
								
								res/chrome/boss.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								res/chrome/boss.png
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 1.8 KiB | 
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								res/enemies/cirno.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								res/enemies/cirno.png
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 6.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								res/explosions.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								res/explosions.png
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 3.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								res/font.png
									
										
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								res/font.png
									
										
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB | 
|  | @ -1,15 +1,22 @@ | |||
| IMAGE font "font.png" BEST NONE | ||||
| 
 | ||||
| 
 | ||||
| // start | ||||
| 
 | ||||
| IMAGE startBg1 "start/bg1.png" FAST | ||||
| IMAGE startLogo1 "start/logo1.png" FAST | ||||
| 
 | ||||
| IMAGE frame "chrome/frame.png" FAST | ||||
| 
 | ||||
| // chrome | ||||
| 
 | ||||
| IMAGE bossBar "chrome/boss.png" FAST | ||||
| 
 | ||||
| 
 | ||||
| // background | ||||
| 
 | ||||
| IMAGE bg1 "bg/1.png" FAST | ||||
| 
 | ||||
| 
 | ||||
| // player and enemies | ||||
| 
 | ||||
| SPRITE sunny "player/sunny.png" 6 5 FAST 10 | ||||
|  | @ -19,9 +26,15 @@ SPRITE fairyRed "enemies/fairyred.png" 4 4 FAST 10 | |||
| SPRITE fairyBlue "enemies/fairyblue.png" 4 4 FAST 10 | ||||
| SPRITE fairyYellow "enemies/fairyyellow.png" 4 4 FAST 10 | ||||
| SPRITE fairyGreen "enemies/fairygreen.png" 4 4 FAST 10 | ||||
| SPRITE cirno "enemies/cirno.png" 6 7 FAST 0 | ||||
| 
 | ||||
| SPRITE smallBullet "bullets/small.png" 1 1 FAST 5 | ||||
| SPRITE bigBullet "bullets/big.png" 2 2 FAST 5 | ||||
| SPRITE hugeBullet "bullets/huge.png" 4 4 FAST 5 | ||||
| 
 | ||||
| SPRITE playerBullet "bullets/player.png" 4 3 FAST 5 | ||||
| SPRITE playerBullet "bullets/player.png" 4 3 FAST 5 | ||||
| 
 | ||||
| 
 | ||||
| // explosion | ||||
| 
 | ||||
| SPRITE explosion "explosions.png" 4 4 FAST 5 | ||||
|  | @ -20,7 +20,7 @@ void spawnBullet(struct bulletSpawner spawner, void(*updater)){ | |||
| 		bullets[i].active = TRUE; | ||||
| 		bullets[i].pos.x = spawner.x; | ||||
| 		bullets[i].pos.y = spawner.y; | ||||
| 		bullets[i].dist = fix16ToFix32(spawner.huge ? BULLET_DIST_HUGE : (spawner.big ? BULLET_DIST_BIG : BULLET_DIST)); | ||||
| 		bullets[i].dist = spawner.player ? BULLET_DIST_HUGE : (spawner.huge ? BULLET_DIST_HUGE : (spawner.big ? BULLET_DIST_BIG : BULLET_DIST)); | ||||
| 		bullets[i].speed = spawner.speed; | ||||
| 		bullets[i].angle = spawner.angle; | ||||
| 		bullets[i].player = spawner.player; | ||||
|  | @ -28,6 +28,7 @@ void spawnBullet(struct bulletSpawner spawner, void(*updater)){ | |||
| 		bullets[i].dead = FALSE; | ||||
| 		bullets[i].big = spawner.big; | ||||
| 		bullets[i].huge = spawner.huge; | ||||
| 		bullets[i].light = spawner.light; | ||||
| 		for(u8 j = 0; j < COUNT_INT; j++){ | ||||
| 			bullets[i].bools[j] = spawner.bools[j]; | ||||
| 			bullets[i].ints[j] = spawner.ints[j]; | ||||
|  | @ -55,7 +56,7 @@ static void killBullet(s16 i){ | |||
| 	bullets[i].active = FALSE; | ||||
| 	SPR_releaseSprite(bullets[i].image); | ||||
| 	if(bullets[i].dead){ | ||||
| 		// spawnExplosion(bullets[i].pos.x, bullets[i].pos.y, 0);
 | ||||
| 		spawnExplosion(bullets[i].pos.x, bullets[i].pos.y, bullets[i].light ? 1 : 0); | ||||
| 		bullets[i].dead = FALSE; | ||||
| 	} | ||||
| } | ||||
|  | @ -68,6 +69,20 @@ void updateBulletVel(s16 i){ | |||
| 
 | ||||
| // collision
 | ||||
| 
 | ||||
| fix32 bulletDist; | ||||
| static void collideBulletWithEnemy(s16 i){ | ||||
| 	for(s16 j = 0; j < ENEMY_COUNT; j++) if(enemies[j].active && enemies[j].pos.y >= FIX16(8)){ | ||||
| 		bulletDist = getApproximatedDistance( | ||||
| 			fix16ToFix32(fix16Sub(enemies[j].pos.x, bullets[i].pos.x)), | ||||
| 			fix16ToFix32(fix16Sub(enemies[j].pos.y, bullets[i].pos.y))); | ||||
| 		if(bulletDist <= fix32Add(enemies[j].dist, bullets[i].dist)){ | ||||
| 			spawnExplosion(bullets[i].pos.x, fix16Add(enemies[j].pos.y, FIX16(8)), 2); | ||||
| 			killBullet(i); | ||||
| 			if(enemies[j].clock > 0) enemies[j].health--; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| #define BULLET_LIMIT FIX16(0 - BULLET_OFF) | ||||
| #define BULLET_LIMIT_W FIX16(GAME_W + BULLET_OFF) | ||||
| #define BULLET_LIMIT_H FIX16(GAME_H + BULLET_OFF) | ||||
|  | @ -86,7 +101,7 @@ static void collideBullet(s16 i){ | |||
| 		bullets[i].pos.y < (bullets[i].huge ? BULLET_LIMIT_HUGE : (bullets[i].big ? BULLET_LIMIT_BIG : BULLET_LIMIT)) || | ||||
| 		bullets[i].pos.y > (bullets[i].huge ? BULLET_LIMIT_H_HUGE : (bullets[i].big ? BULLET_LIMIT_H_BIG : BULLET_LIMIT_H))){ | ||||
| 		killBullet(i); | ||||
| 	} | ||||
| 	} else if(bullets[i].player) collideBulletWithEnemy(i); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -107,7 +122,7 @@ static void updateBullet(s16 i){ | |||
| void updateBullets(){ | ||||
| 	if(killBullets){ | ||||
| 		for(s16 i = 0; i < BULLET_COUNT; i++) if(bullets[i].active){ | ||||
| 			if(i % 4 == 0) bullets[i].dead = TRUE; | ||||
| 			if(i % 3 == 0) bullets[i].dead = TRUE; | ||||
| 			killBullet(i); | ||||
| 		} | ||||
| 		killBullets = FALSE; | ||||
|  |  | |||
							
								
								
									
										64
									
								
								src/chrome.h
									
										
									
									
									
								
							
							
						
						
									
										64
									
								
								src/chrome.h
									
										
									
									
									
								
							|  | @ -2,13 +2,6 @@ | |||
| 
 | ||||
| #define CHROME_I 64 | ||||
| 
 | ||||
| // frame
 | ||||
| 
 | ||||
| static void loadFrame(){ | ||||
| 	// VDP_loadTileSet(frame.tileset, CHROME_I, DMA);
 | ||||
| 	// VDP_fillTileMapRect(BG_A, TILE_ATTR_FULL(PAL2, 1, 0, 0, CHROME_I), 0, 0, GAME_W_T, 4);
 | ||||
| } | ||||
| 
 | ||||
| // score
 | ||||
| 
 | ||||
| #define SCORE_X 1 | ||||
|  | @ -19,7 +12,7 @@ u32 lastScore; | |||
| char scoreStr[SCORE_LENGTH]; | ||||
| 
 | ||||
| static void loadScore(){ | ||||
| 	VDP_drawText("00000000", SCORE_X, SCORE_Y); | ||||
| 	VDP_drawText("0000000000", SCORE_X, SCORE_Y); | ||||
| } | ||||
| 
 | ||||
| // static void updateScore(){
 | ||||
|  | @ -42,27 +35,64 @@ static void loadTime(){ | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| // heat
 | ||||
| // boss
 | ||||
| 
 | ||||
| #define RANK_X 28 | ||||
| #define RANK_Y 2 | ||||
| #define RANK_LABEL_X 25 | ||||
| #define BOSS_TILE_X 1 | ||||
| #define BOSS_TILE_Y 2 | ||||
| #define BOSS_TILE_COUNT 30 | ||||
| #define BOSS_TILE_PX 30 * 8 | ||||
| 
 | ||||
| static void loadRank(){ | ||||
| 	// VDP_drawText("RANK 1", RANK_LABEL_X, RANK_Y);
 | ||||
| 	// VDP_drawText("100", RANK_X, HEAT_Y);
 | ||||
| s16 lastBossHealth; | ||||
| fix16 bossLimit; | ||||
| 
 | ||||
| static void updateBoss(){ | ||||
| 	if(lastBossHealth != bossHealth){ | ||||
| 		bossLimit = fix16Div(fix16Mul(fix16Div(FIX16(bossHealth), FIX16(bossMax)), BOSS_TILE_PX), 8); | ||||
| 		for(s16 x = 0; x < BOSS_TILE_COUNT; x++){ | ||||
| 			if(bossHealth <= 0 || FIX16(x) >= bossLimit){ | ||||
| 				VDP_clearText(x + BOSS_TILE_X, BOSS_TILE_Y, 1); | ||||
| 			} | ||||
| 		} | ||||
| 		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, CHROME_I), x + BOSS_TILE_X, BOSS_TILE_Y); | ||||
| 		} | ||||
| 		lastBossHealth = bossHealth; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // lives
 | ||||
| 
 | ||||
| #define LIVES_X 1 | ||||
| #define LIVES_Y 26 | ||||
| 
 | ||||
| static void loadLives(){ | ||||
| 	VDP_drawText("##", LIVES_X, LIVES_Y); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // bombs
 | ||||
| 
 | ||||
| #define BOMBS_X 28 | ||||
| #define BOMBS_Y 26 | ||||
| 
 | ||||
| static void loadBombs(){ | ||||
| 	VDP_drawText("***", BOMBS_X, BOMBS_Y); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // loop
 | ||||
| 
 | ||||
| void loadChrome(){ | ||||
| 	// loadFrame();
 | ||||
| 	VDP_loadTileSet(bossBar.tileset, CHROME_I, DMA); | ||||
| 	loadScore(); | ||||
| 	loadTime(); | ||||
| 	// loadRank();
 | ||||
| 	loadLives(); | ||||
| 	loadBombs(); | ||||
| } | ||||
| 
 | ||||
| void updateChrome(){ | ||||
| 	updateBoss(); | ||||
| 	// VDP_drawText(debugStr, 0, 27);
 | ||||
| 	// updateScore();
 | ||||
| } | ||||
|  | @ -11,13 +11,15 @@ void spawnEnemy(struct enemySpawner spawner, void(*updater), void(*suicide)){ | |||
| 		enemies[i].off.y = FIX16(spawner.offY); | ||||
| 		enemies[i].pos.x = FIX16(spawner.x); | ||||
| 		enemies[i].pos.y = FIX16(spawner.y); | ||||
| 		enemies[i].last.x = FIX16(spawner.x); | ||||
| 		enemies[i].last.y = FIX16(spawner.y); | ||||
| 		enemies[i].dist = intToFix32(spawner.offX - 2); | ||||
| 		enemies[i].speed = spawner.speed; | ||||
| 		enemies[i].angle = spawner.angle; | ||||
| 		enemies[i].boss = spawner.boss; | ||||
| 		enemies[i].shotClock = 0; | ||||
| 		enemies[i].dead = FALSE; | ||||
| 		enemies[i].health = spawner.health ? spawner.health : 1; | ||||
| 		enemies[i].flipClock = 0; | ||||
| 		if(spawner.vel.x && spawner.vel.y){ | ||||
| 			enemies[i].vel.x = spawner.vel.x; | ||||
| 			enemies[i].vel.y = spawner.vel.y; | ||||
|  | @ -45,10 +47,6 @@ void spawnEnemy(struct enemySpawner spawner, void(*updater), void(*suicide)){ | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| void killEnemy(s16 i){ | ||||
| 	enemies[i].dead = TRUE; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // helpers
 | ||||
| 
 | ||||
|  | @ -57,15 +55,38 @@ void updateEnemyVel(s16 i){ | |||
| 	enemies[i].vel.y = fix16Mul(sinFix16(enemies[i].angle), enemies[i].speed); | ||||
| } | ||||
| 
 | ||||
| #define FLIP_MOD 15 | ||||
| static void enemyAnimate(s16 i){ | ||||
| 	if(enemies[i].flipClock == 0){ | ||||
| 		if(enemies[i].last.x > enemies[i].pos.x){ | ||||
| 			enemies[i].flipClock = FLIP_MOD; | ||||
| 			SPR_setAnim(enemies[i].image, 1); | ||||
| 			SPR_setHFlip(enemies[i].image, 0); | ||||
| 		} else if(enemies[i].last.x < enemies[i].pos.x){ | ||||
| 			enemies[i].flipClock = FLIP_MOD; | ||||
| 			SPR_setAnim(enemies[i].image, 1); | ||||
| 			SPR_setHFlip(enemies[i].image, 1); | ||||
| 		} else { | ||||
| 			enemies[i].flipClock = FLIP_MOD; | ||||
| 			SPR_setAnim(enemies[i].image, 0); | ||||
| 			SPR_setHFlip(enemies[i].image, 0); | ||||
| 		} | ||||
| 	} | ||||
| 	if(enemies[i].flipClock > 0){ | ||||
| 		enemies[i].flipClock--; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // loop
 | ||||
| 
 | ||||
| static void updateEnemy(s16 i){ | ||||
| 	enemies[i].last.x = enemies[i].pos.x; | ||||
| 	enemies[i].last.y = enemies[i].pos.y; | ||||
| 	if(enemies[i].seen && (enemies[i].pos.x < fix16Sub(0, enemies[i].off.x) || | ||||
| 		enemies[i].pos.x > fix16Add(FIX16(GAME_W), enemies[i].off.x) || | ||||
| 		enemies[i].pos.y < fix16Sub(0, enemies[i].off.y) || | ||||
| 		enemies[i].pos.y > fix16Add(FIX16(GAME_H), enemies[i].off.y))){ | ||||
| 		killEnemy(i); | ||||
| 		enemies[i].dead = TRUE; | ||||
| 		enemies[i].suicide(i); | ||||
| 	} else { | ||||
| 		if(!enemies[i].seen && enemies[i].pos.y >= fix16Sub(0, enemies[i].off.y)){ | ||||
|  | @ -76,14 +97,18 @@ static void updateEnemy(s16 i){ | |||
| 		enemies[i].pos.y = fix16Add(enemies[i].pos.y, enemies[i].vel.y); | ||||
| 		if(enemies[i].seen){ | ||||
| 			enemies[i].updater(i); | ||||
| 			if(enemies[i].boss) bossHealth = enemies[i].health; | ||||
| 			// collideEnemy(i);
 | ||||
| 			if(!enemies[i].boss) enemyAnimate(i); | ||||
| 			enemies[i].clock++; | ||||
| 			if(enemies[i].clock >= CLOCK_LIMIT) enemies[i].clock -= CLOCK_LIMIT; | ||||
| 			SPR_setPosition(enemies[i].image, | ||||
| 				fix16ToInt(fix16Sub(enemies[i].pos.x, enemies[i].off.x)), | ||||
| 				fix16ToInt(fix16Sub(enemies[i].pos.y, enemies[i].off.y))); | ||||
| 		} | ||||
| 		if(enemies[i].health <= 0){ | ||||
| 			enemies[i].suicide(i); | ||||
| 			enemies[i].dead = TRUE; | ||||
| 			// SND_startPlayPCM_XGM(SFX_EXPLOSION_2, 15, SOUND_PCM_CH2);
 | ||||
| 		} | ||||
| 	} | ||||
| 	if(enemies[i].dead){ | ||||
| 		enemies[i].active = FALSE; | ||||
|  |  | |||
							
								
								
									
										29
									
								
								src/explosions.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/explosions.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,29 @@ | |||
| // explosions
 | ||||
| 
 | ||||
| #define EXPLOSION_OFFSET FIX16(16) | ||||
| #define EXPLOSION_TIME 20 | ||||
| 
 | ||||
| void spawnExplosion(fix16 x, fix16 y, u8 type){ | ||||
| 	s16 i = -1; | ||||
| 	for(s16 j = 0; j < EXPLOSION_COUNT; j++) if(!explosions[j].active && i == -1) i = j; | ||||
| 	explosions[i].active = TRUE; | ||||
| 	explosions[i].clock = 0; | ||||
| 	explosions[i].image = SPR_addSprite(&explosion, | ||||
| 		fix16ToInt(fix16Sub(x, EXPLOSION_OFFSET)), | ||||
| 		fix16ToInt(fix16Sub(y, EXPLOSION_OFFSET)), | ||||
| 		TILE_ATTR(PAL1, 1, 0, 0)); | ||||
| 	SPR_setAnim(explosions[i].image, type); | ||||
| 	SPR_setDepth(explosions[i].image, 3); | ||||
| } | ||||
| 
 | ||||
| static void updateExplosion(s16 i){ | ||||
| 	if(explosions[i].clock >= EXPLOSION_TIME){ | ||||
| 		explosions[i].active = FALSE; | ||||
| 		SPR_releaseSprite(explosions[i].image); | ||||
| 	} | ||||
| 	explosions[i].clock++; | ||||
| } | ||||
| 
 | ||||
| void updateExplosions(){ | ||||
| 	for(s16 i = 0; i < EXPLOSION_COUNT; i++) if(explosions[i].active) updateExplosion(i); | ||||
| } | ||||
|  | @ -21,9 +21,11 @@ | |||
| bool killBullets, | ||||
| 	started; | ||||
| 
 | ||||
| s16 clock, | ||||
| s16 clock, timeLeft, | ||||
| 	bossHealth, bossMax; | ||||
| 
 | ||||
| char debugStr[8]; | ||||
| 
 | ||||
| u32 score, | ||||
| 	highScore; | ||||
| 
 | ||||
|  |  | |||
|  | @ -8,7 +8,7 @@ | |||
| #include "controls.h" | ||||
| #include "start.h" | ||||
| #include "background.h" | ||||
| // #include "foreground.h"
 | ||||
| #include "explosions.h" | ||||
| #include "bullets.h" | ||||
| #include "player.h" | ||||
| #include "enemies.h" | ||||
|  | @ -41,6 +41,7 @@ static void updateGame(){ | |||
| 	updateBullets(); | ||||
| 	updateBg(); | ||||
| 	updateChrome(); | ||||
| 	updateExplosions(); | ||||
| 	clock++; | ||||
| 	if(clock >= CLOCK_LIMIT) clock -= CLOCK_LIMIT; | ||||
| } | ||||
|  |  | |||
							
								
								
									
										225
									
								
								src/stage.h
									
										
									
									
									
								
							
							
						
						
									
										225
									
								
								src/stage.h
									
										
									
									
									
								
							|  | @ -28,20 +28,19 @@ final boss at 30 seconds left | |||
| 
 | ||||
| */ | ||||
| 
 | ||||
| #define SPAWN_MID 128 | ||||
| 
 | ||||
| 
 | ||||
| // groups
 | ||||
| 
 | ||||
| static void waveSine(bool right){ | ||||
| 	struct enemySpawner spawner = { | ||||
| 		.angle = 256, | ||||
| 		.speed = FIX16(0.8), | ||||
| 		.speed = FIX16(1), | ||||
| 		.x = GAME_W / 5 * (right ? 3 : 2), | ||||
| 		.y = -16, | ||||
| 		.image = right ? &fairyRed : &fairyBlue, | ||||
| 		.offX = 16, | ||||
| 		.offY = 16 | ||||
| 		.offY = 16, | ||||
| 		.health = 2 | ||||
| 	}; | ||||
| 	spawner.fixes[0] = FIX16(spawner.x); | ||||
| 	spawner.fixes[1] = FIX16(32); | ||||
|  | @ -58,15 +57,16 @@ static void waveSine(bool right){ | |||
| static void waveBig1(){ | ||||
| 	struct enemySpawner spawner = { | ||||
| 		.angle = 256, | ||||
| 		.speed = FIX16(0.6), | ||||
| 		.speed = FIX16(0.75), | ||||
| 		.x = GAME_W / 2, | ||||
| 		.y = -16, | ||||
| 		.image = &fairyGreen, | ||||
| 		.offX = 16, | ||||
| 		.offY = 16 | ||||
| 		.offY = 16, | ||||
| 		.health = 8 | ||||
| 	}; | ||||
| 	void updater(s16 i){ | ||||
| 		if(enemies[i].clock == 60){ | ||||
| 		if(enemies[i].clock == 40){ | ||||
| 			struct bulletSpawner spawner = { | ||||
| 				.x = enemies[i].pos.x, | ||||
| 				.y = enemies[i].pos.y, | ||||
|  | @ -80,6 +80,10 @@ static void waveBig1(){ | |||
| 				spawner.angle += 64; | ||||
| 			} | ||||
| 		} | ||||
| 		else if(enemies[i].clock == 120){ | ||||
| 			enemies[i].speed = FIX16(0.5); | ||||
| 			updateEnemyVel(i); | ||||
| 		} | ||||
| 	} | ||||
| 	spawnEnemy(spawner, updater, EMPTY); | ||||
| } | ||||
|  | @ -87,12 +91,13 @@ static void waveBig1(){ | |||
| static void waveBig2(bool left){ | ||||
| 	struct enemySpawner spawner = { | ||||
| 		.angle = 256, | ||||
| 		.speed = FIX16(0.6), | ||||
| 		.speed = FIX16(0.5), | ||||
| 		.x = left ? GAME_W / 5 - 16 : GAME_W / 5 * 4 + 16, | ||||
| 		.y = -16, | ||||
| 		.image = left ? &fairyGreen : &fairyYellow, | ||||
| 		.offX = 16, | ||||
| 		.offY = 16 | ||||
| 		.offY = 16, | ||||
| 		.health = 6 | ||||
| 	}; | ||||
| 	spawner.bools[0] = left; | ||||
| 	void updater(s16 i){ | ||||
|  | @ -132,15 +137,16 @@ static void waveBig2(bool left){ | |||
| static void waveBig3(){ | ||||
| 	struct enemySpawner spawner = { | ||||
| 		.angle = 256, | ||||
| 		.speed = FIX16(0.6), | ||||
| 		.speed = FIX16(0.75), | ||||
| 		.x = GAME_W / 2, | ||||
| 		.y = -16, | ||||
| 		.image = &fairyGreen, | ||||
| 		.offX = 16, | ||||
| 		.offY = 16 | ||||
| 		.offY = 16, | ||||
| 		.health = 8 | ||||
| 	}; | ||||
| 	void updater(s16 i){ | ||||
| 		if(enemies[i].clock >= 30 && enemies[i].clock <= 90 && enemies[i].clock % 30 == 0){ | ||||
| 		if(enemies[i].clock > 0 && enemies[i].clock < 120 && enemies[i].clock % 40 == 20){ | ||||
| 			struct bulletSpawner spawner = { | ||||
| 				.x = enemies[i].pos.x, | ||||
| 				.y = enemies[i].pos.y, | ||||
|  | @ -159,6 +165,10 @@ static void waveBig3(){ | |||
| 				spawner.angle += 64; | ||||
| 			} | ||||
| 		} | ||||
| 		else if(enemies[i].clock == 120){ | ||||
| 			enemies[i].speed = FIX16(0.5); | ||||
| 			updateEnemyVel(i); | ||||
| 		} | ||||
| 	} | ||||
| 	spawnEnemy(spawner, updater, EMPTY); | ||||
| } | ||||
|  | @ -171,7 +181,8 @@ static void waveSwarm(bool right, bool color){ | |||
| 		.y = -16, | ||||
| 		.image = color ? &fairyRed : &fairyBlue, | ||||
| 		.offX = 16, | ||||
| 		.offY = 16 | ||||
| 		.offY = 16, | ||||
| 		.health = 2 | ||||
| 	}; | ||||
| 	spawner.x += right ? (GAME_W / 2) : 64; | ||||
| 	spawnEnemy(spawner, EMPTY, EMPTY); | ||||
|  | @ -185,7 +196,8 @@ static void waveBig4(bool right, bool second){ | |||
| 		.y = -16, | ||||
| 		.image = right ? &fairyYellow : &fairyGreen, | ||||
| 		.offX = 16, | ||||
| 		.offY = 16 | ||||
| 		.offY = 16, | ||||
| 		.health = 4 | ||||
| 	}; | ||||
| 	spawner.bools[0] = right; | ||||
| 	spawner.bools[1] = second; | ||||
|  | @ -234,14 +246,16 @@ static void waveBig4(bool right, bool second){ | |||
| fix16 bossLimitY, bossLimitH, bossLimitX, bossLimitW; | ||||
| 
 | ||||
| static void bossIntro(s16 i){ | ||||
| 	if(enemies[i].clock > 0 && enemies[i].clock % 30 == 0){ | ||||
| 	enemies[i].last.x = enemies[i].pos.x; | ||||
| 	enemies[i].clock = -1; | ||||
| 	if(clock % 30 == 0){ | ||||
| 		enemies[i].speed = fix16Sub(enemies[i].speed, FIX16(0.25)); | ||||
| 		if(enemies[i].speed <= 0){ | ||||
| 			bossLimitY = fix16Sub(enemies[i].pos.y, BOSS_MOD_Y); | ||||
| 			bossLimitH = fix16Add(enemies[i].pos.y, BOSS_MOD_Y); | ||||
| 			bossLimitX = fix16Sub(enemies[i].pos.x, BOSS_MOD_X); | ||||
| 			bossLimitW = fix16Add(enemies[i].pos.x, BOSS_MOD_X); | ||||
| 			enemies[i].speed = FIX16(0.4); | ||||
| 			// enemies[i].speed = FIX16(0.5);
 | ||||
| 			enemies[i].angle = 32; | ||||
| 			enemies[i].bools[0] = TRUE; | ||||
| 			enemies[i].clock = -1; | ||||
|  | @ -250,6 +264,25 @@ static void bossIntro(s16 i){ | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| s16 bossAnimateClock; | ||||
| static void bossAnimate(s16 i){ | ||||
| 
 | ||||
| 	if(enemies[i].last.x > enemies[i].pos.x){ | ||||
| 		SPR_setAnim(enemies[i].image, 1); | ||||
| 		SPR_setFrame(enemies[i].image, 0); | ||||
| 		SPR_setHFlip(enemies[i].image, 0); | ||||
| 	} else if(enemies[i].last.x < enemies[i].pos.x){ | ||||
| 		SPR_setAnim(enemies[i].image, 1); | ||||
| 		SPR_setFrame(enemies[i].image, 0); | ||||
| 		SPR_setHFlip(enemies[i].image, 1); | ||||
| 	} else { | ||||
| 		if(bossAnimateClock % 10 == 0) SPR_nextFrame(enemies[i].image); | ||||
| 		SPR_setAnim(enemies[i].image, 0); | ||||
| 		SPR_setHFlip(enemies[i].image, 0); | ||||
| 	} | ||||
| 	bossAnimateClock++; | ||||
| } | ||||
| 
 | ||||
| static void bossMove(s16 i){ | ||||
| 	if(enemies[i].pos.x > bossLimitW || enemies[i].pos.x < bossLimitX){ | ||||
| 		enemies[i].pos.x = enemies[i].pos.x > bossLimitW ? bossLimitW : bossLimitX; | ||||
|  | @ -261,64 +294,132 @@ static void bossMove(s16 i){ | |||
| 		enemies[i].angle = 1024 - enemies[i].angle; | ||||
| 		updateEnemyVel(i); | ||||
| 	} | ||||
| 	if(enemies[i].clock % 120 == 119){ | ||||
| 		enemies[i].speed = enemies[i].speed == 0 ? FIX16(0.5) : 0; | ||||
| 		updateEnemyVel(i); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void waveMidboss1(){ | ||||
| 	bossAnimateClock = 0; | ||||
| 	struct enemySpawner spawner = { | ||||
| 		.angle = 256, | ||||
| 		.speed = FIX16(1), | ||||
| 		.x = GAME_W / 2, | ||||
| 		.y = -16, | ||||
| 		.image = &fairyGreen, | ||||
| 		.offX = 16, | ||||
| 		.offY = 16 | ||||
| 		.image = &cirno, | ||||
| 		.offX = 24, | ||||
| 		.offY = 28, | ||||
| 		.boss = TRUE, | ||||
| 		.health = 50 | ||||
| 	}; | ||||
| 	bossMax = spawner.health; | ||||
| 	void updater(s16 i){ | ||||
| 		bossAnimate(i); | ||||
| 		if(enemies[i].bools[0]){ | ||||
| 
 | ||||
| 			bossHealth = enemies[i].health; | ||||
| 			intToStr(bossHealth, debugStr, 2); | ||||
| 			bossMove(i); | ||||
| 
 | ||||
| 			// ring
 | ||||
| 			if(enemies[i].clock % 90 == 0){ | ||||
| 				struct bulletSpawner spawner = { | ||||
| 					.x = enemies[i].pos.x, | ||||
| 					.y = enemies[i].pos.y, | ||||
| 					.image = &bigBullet, | ||||
| 					.big = TRUE, | ||||
| 					.speed = FIX16(1.25), | ||||
| 					.angle = 80 + random() % 32, | ||||
| 					.light = TRUE | ||||
| 				}; | ||||
| 				for(u8 j = 3; j < 15; j++){ | ||||
| 					if(j % 3 < 2) spawnBullet(spawner, EMPTY); | ||||
| 					spawner.angle += 32; | ||||
| 			if(enemies[i].health >= 25){ | ||||
| 				// ring
 | ||||
| 				if(enemies[i].clock % 90 == 0){ | ||||
| 					struct bulletSpawner spawner = { | ||||
| 						.x = enemies[i].pos.x, | ||||
| 						.y = enemies[i].pos.y, | ||||
| 						.image = &bigBullet, | ||||
| 						.big = TRUE, | ||||
| 						.speed = FIX16(1.5), | ||||
| 						.angle = 80 + random() % 32, | ||||
| 						.light = TRUE | ||||
| 					}; | ||||
| 					for(u8 j = 3; j < 15; j++){ | ||||
| 						if(j % 3 < 2) spawnBullet(spawner, EMPTY); | ||||
| 						spawner.angle += 32; | ||||
| 					} | ||||
| 				} | ||||
| 				// puke
 | ||||
| 				else if(enemies[i].clock % 20 == 0){ | ||||
| 					struct bulletSpawner spawner = { | ||||
| 						.x = FIX16(enemies[i].clock % 180 < 90 ? 32 : GAME_W - 32), | ||||
| 						.y = FIX16(48), | ||||
| 						.image = &bigBullet, | ||||
| 						.big = TRUE, | ||||
| 						.top = TRUE, | ||||
| 						.speed = FIX16(2) | ||||
| 					}; | ||||
| 					velPos.x = spawner.x; | ||||
| 					velPos.y = spawner.y; | ||||
| 					spawner.vel = hone(velPos, player.pos, spawner.speed, 32); | ||||
| 					spawnBullet(spawner, EMPTY); | ||||
| 					spawnExplosion(spawner.x, spawner.y, 3); | ||||
| 				} | ||||
| 			} else { | ||||
| 				if(!enemies[i].bools[7]){ | ||||
| 					killBullets = TRUE; | ||||
| 					enemies[i].bools[7] = TRUE; | ||||
| 					enemies[i].clock = -60; | ||||
| 				} | ||||
| 				if(enemies[i].clock >= 0){ | ||||
| 					// swash
 | ||||
| 					if(enemies[i].clock % 8 == 0){ | ||||
| 						struct bulletSpawner spawner = { | ||||
| 							.x = enemies[i].pos.x, | ||||
| 							.y = enemies[i].pos.y, | ||||
| 							.image = &smallBullet, | ||||
| 							.speed = FIX16(1.75), | ||||
| 							.light = TRUE, | ||||
| 							.top = TRUE, | ||||
| 							.angle = enemies[i].ints[0] | ||||
| 						}; | ||||
| 						if(enemies[i].clock % 16 == 8){ | ||||
| 							spawner.image = &bigBullet; | ||||
| 							spawner.big = TRUE; | ||||
| 						} | ||||
| 						void updater(s16 j){ | ||||
| 							if(bullets[j].bools[0] && bullets[j].clock == 15){ | ||||
| 								bullets[j].angle = 64 + random() % 384; | ||||
| 								bullets[j].speed = FIX16(1.75); | ||||
| 								updateBulletVel(j); | ||||
| 							} else if(!bullets[j].bools[0] && bullets[j].clock >= 0 && bullets[j].clock % 10 == 0){ | ||||
| 								bullets[j].speed = fix16Sub(bullets[j].speed, FIX16(0.25)); | ||||
| 								if(bullets[j].speed <= 0){ | ||||
| 									bullets[j].speed = 0; | ||||
| 									bullets[j].clock = -1; | ||||
| 									bullets[j].bools[0] = TRUE; | ||||
| 								} | ||||
| 								updateBulletVel(j); | ||||
| 							}	 | ||||
| 						} | ||||
| 						spawnBullet(spawner, updater); | ||||
| 						enemies[i].ints[0] += enemies[i].bools[4] ? -64 : 56; | ||||
| 						if(enemies[i].ints[0] > 512 || enemies[i].ints[0] < 0) enemies[i].bools[4] = !enemies[i].bools[4]; | ||||
| 					} | ||||
| 					// balls
 | ||||
| 					if(enemies[i].clock % 45 == 0 && enemies[i].clock > 0){ | ||||
| 						struct bulletSpawner spawner = { | ||||
| 							.x = enemies[i].pos.x, | ||||
| 							.y = enemies[i].pos.y, | ||||
| 							.image = &hugeBullet, | ||||
| 							.speed = FIX16(1.75), | ||||
| 							.huge = TRUE | ||||
| 						}; | ||||
| 						spawner.vel = hone(enemies[i].pos, player.pos, spawner.speed, 16); | ||||
| 						spawnBullet(spawner, EMPTY); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			// puke
 | ||||
| 			else if(enemies[i].clock % 20 == 0){ | ||||
| 				struct bulletSpawner spawner = { | ||||
| 					.x = FIX16(enemies[i].clock % 180 < 90 ? 32 : GAME_W - 32), | ||||
| 					.y = FIX16(40), | ||||
| 					.image = &bigBullet, | ||||
| 					.big = TRUE, | ||||
| 					.speed = FIX16(1.75) | ||||
| 				}; | ||||
| 				velPos.x = spawner.x; | ||||
| 				velPos.y = spawner.y; | ||||
| 				spawner.vel = hone(velPos, player.pos, spawner.speed, 32); | ||||
| 				spawnBullet(spawner, EMPTY); | ||||
| 			} | ||||
| 
 | ||||
| 		} else bossIntro(i); | ||||
| 	} | ||||
| 	spawnEnemy(spawner, updater, EMPTY); | ||||
| 	void suicide(s16 i){ | ||||
| 		bossHealth = 0; | ||||
| 		killBullets = TRUE; | ||||
| 	} | ||||
| 	spawnEnemy(spawner, updater, suicide); | ||||
| } | ||||
| 
 | ||||
| // loop
 | ||||
| 
 | ||||
| #define OBS_INTERVAL 15 | ||||
| 
 | ||||
| s16 stageClock, | ||||
| 	nextClock; | ||||
| 
 | ||||
|  | @ -332,13 +433,13 @@ static void updateWaves(){ | |||
| 		// sine from left
 | ||||
| 		if(currentWave < 6){ | ||||
| 			waveSine(FALSE); | ||||
| 			nextClock += currentWave == 5 ? 90 : 40; | ||||
| 			nextClock += currentWave == 5 ? 60 : 30; | ||||
| 		} | ||||
| 
 | ||||
| 		// sine from right
 | ||||
| 		else if(currentWave < 12){ | ||||
| 			waveSine(TRUE); | ||||
| 			nextClock += currentWave == 11 ? 90 : 40; | ||||
| 			nextClock += currentWave == 11 ? 60 : 30; | ||||
| 		} | ||||
| 
 | ||||
| 		// big middle
 | ||||
|  | @ -350,21 +451,21 @@ static void updateWaves(){ | |||
| 		// sine from left, big right
 | ||||
| 		else if(currentWave < 18){ | ||||
| 			waveSine(FALSE); | ||||
| 			if(currentWave == 14) waveBig2(FALSE); | ||||
| 			nextClock += currentWave == 17 ? 90 : 40; | ||||
| 			if(currentWave == 16) waveBig2(FALSE); | ||||
| 			nextClock += currentWave == 17 ? 90 : 30; | ||||
| 		} | ||||
| 
 | ||||
| 		// sine from right, big left
 | ||||
| 		else if(currentWave < 24){ | ||||
| 			waveSine(TRUE); | ||||
| 			if(currentWave == 20) waveBig2(TRUE); | ||||
| 			nextClock += currentWave == 23 ? 90 : 40; | ||||
| 			if(currentWave == 22) waveBig2(TRUE); | ||||
| 			nextClock += currentWave == 23 ? 120 : 30; | ||||
| 		} | ||||
| 
 | ||||
| 		// big middle
 | ||||
| 		else if(currentWave == 24){ | ||||
| 			waveBig3(); | ||||
| 			nextClock += 180; | ||||
| 			nextClock += 210; | ||||
| 		} | ||||
| 
 | ||||
| 		// swarm (8)
 | ||||
|  | @ -390,7 +491,7 @@ static void updateWaves(){ | |||
| 		else if(currentWave < 42){ | ||||
| 			waveSwarm(TRUE, currentWave % 2 < 1); | ||||
| 			if(currentWave == 39) waveBig4(FALSE, TRUE); | ||||
| 			nextClock += currentWave == 41 ? 60 : 30; | ||||
| 			nextClock += currentWave == 41 ? 210 : 30; | ||||
| 		} | ||||
| 
 | ||||
| 		else if(currentWave == 42){ | ||||
|  |  | |||
|  | @ -15,7 +15,7 @@ struct bulletSpawner { | |||
| 	fix16 fixes[COUNT_INT]; | ||||
| }; | ||||
| struct bullet { | ||||
| 	bool active, player, dead, big, huge; | ||||
| 	bool active, player, dead, big, huge, light; | ||||
| 	fix16 speed; | ||||
| 	fix32 dist; | ||||
| 	Vect2D_f16 pos, vel; | ||||
|  | @ -59,8 +59,8 @@ struct enemy { | |||
| 	bool active, boss, seen, seal, dead; | ||||
| 	fix16 speed; | ||||
| 	fix32 dist; | ||||
| 	Vect2D_f16 pos, vel, off; | ||||
| 	s16 angle, clock, health, shotClock; | ||||
| 	Vect2D_f16 pos, vel, off, last; | ||||
| 	s16 angle, clock, health, flipClock; | ||||
| 	Sprite* image; | ||||
| 	Sprite* sealImage; | ||||
| 	void (*updater)(s16); | ||||
|  | @ -70,4 +70,16 @@ struct enemy { | |||
| 	s16 ints[COUNT_INT]; | ||||
| 	fix16 fixes[COUNT_INT]; | ||||
| }; | ||||
| struct enemy enemies[ENEMY_COUNT]; | ||||
| struct enemy enemies[ENEMY_COUNT]; | ||||
| 
 | ||||
| 
 | ||||
| // explosion
 | ||||
| 
 | ||||
| #define EXPLOSION_COUNT 16 | ||||
| 
 | ||||
| struct explosion { | ||||
| 	bool active; | ||||
| 	s16 clock; | ||||
| 	Sprite* image; | ||||
| }; | ||||
| struct explosion explosions[EXPLOSION_COUNT]; | ||||
		Reference in a new issue