/*
	Sound effects and music are from https://mixkit.co/
*/
#include <stdio.h>
#include <stdbool.h> // C does not have a boolean type by default, so we need this
#include <string.h>

#define SDL_MAIN_HANDLED
#include <SDL.h>
#include <SDL_mixer.h>
#include <SDL_image.h>

// globals

	// Window
	SDL_Window* window = NULL; // Window that we will open.
	SDL_Surface* windowsurface = NULL; // Window canvas.
	const int window_width = 600;
	const int window_height = 600;

	// Resources
	SDL_Surface* image_player_ship = NULL;
	SDL_Surface* image_basic_enemy_ship = NULL;
	SDL_Surface* image_strong_enemy_ship = NULL;
	
	Mix_Music* music_vibes = NULL;
	
	Mix_Chunk* sound_player_shoot = NULL;
	Mix_Chunk* sound_enemy_shoot = NULL;
	Mix_Chunk* sound_strong_enemy_shoot = NULL;
	Mix_Chunk* sound_bullet_collide = NULL;
	Mix_Chunk* sound_player_explode = NULL;
	Mix_Chunk* sound_basic_enemy_explode = NULL;
	Mix_Chunk* sound_strong_enemy_explode = NULL;

	// Which inputs are held down
	bool input_shoot = false;
	bool input_up = false;
	bool input_down = false;
	bool input_left = false;
	bool input_right = false;

	// Game variables
	typedef enum {
		SHIP_NONE, // Having an invalid ship type as the 0 value can help detect bugs.
		SHIP_PLAYER,
		SHIP_BASIC_ENEMY,
		SHIP_STRONG_ENEMY,
	} SHIP;
	
	typedef struct {
		bool is_destroyed : 1;
		bool is_enemy : 1;
		SHIP type;
		
		float x;
		float y;
		float x_speed;
		float y_speed;
		float width;
		float height;
		
		short shoot_delay;
		short shoot_counter;
		short health;
		
		Uint32 color;
	} Ship;
	
	typedef struct {
		bool is_destroyed : 1;
		bool is_enemy : 1;
		
		float x;
		float y;
		float x_speed;
		float y_speed;
		float width;
		float height;
		
		short damage;
		
		Uint32 color;
	} Bullet;
	
	int time_delta = 16; // This is how much time passes per frame, usually you would use some kind of timer to get this value, but we can just hard code it for this example.
	int time_elapsed = 0; // time_delta is added to this every frame.
	
	int score = 0;
	int enemy_spawn_delay = 0; // How much time between enemy spawns. This will change depending on the current score.
	int enemy_spawn_counter = 0; // This reduces by time_delta every frame. When it goes to 0, an enemy spawns, and this value is set to enemy_spawn_delay.
	
	Ship* ships = NULL; // To get a pointer to the 2nd ship, you can just get an offset from this pointer:  ships + 1
	int max_ship_count = 100; // How many ships we'll allocate space for.
	int ship_count = 0; // How many ships are currently alive, this will increase as enemies spawn.
	
	Bullet* bullets = NULL; // Same as ships list.
	int max_bullet_count = 1000;
	int bullet_count = 0;

// Helpers and stuff

	float random_positive_float (unsigned int seed) {
		// This function generates a pseudo-random floating point value between 0 and 1. Sending the current time as the seed is a good way to create "random" seeds.
		seed = (seed << 13) ^ seed;
		seed = (seed * (seed * seed * 15731 + 789221) + 1376312589);
		seed = (seed ^ (seed >> 16)) & 0xffff;
		float f = (float)seed / 0xffff;
		return f;
	}
	float random_float (unsigned int seed) {
		// Same as above, except the value is between -1 and 1.
		return random_positive_float(seed) * 2 - 1;
	}
	Mix_Chunk* load_sound_effect (char* path, float volume) {
		Mix_Chunk* sound = Mix_LoadWAV(path);
		Mix_VolumeChunk(sound, MIX_MAX_VOLUME * volume);
		if (sound == NULL) {
			printf("Failed to load sound (%s)\n", path);
		}
		return sound;
	}
	void play_sound (Mix_Chunk* sound) {
		int res = Mix_PlayChannel(-1, sound, 0);
		if (res == -1) {
			printf("Failed to play sound!\n"); // This happens if there's too many sounds playing. I haven't looked into how to avoid it.
		}
	}
	void play_music (Mix_Music* music) {
		int res = Mix_PlayMusic(music, -1);
		if (res == -1) {
			printf("Failed to play music!\n");
		}
	}
	
	Ship* get_player_ship () {
		// The first ship in the ships list is the player's ship, unless they're dead.
		Ship* ship = ships;
		if (ship->type == SHIP_PLAYER) return ship;
		return NULL;
	}

// Rendering

	void draw_game () {
		// Fill the screen with darkness.
		Uint32 bgcolor = SDL_MapRGB(windowsurface->format, 20, 20, 20);
		SDL_FillRect(windowsurface, NULL, bgcolor);
		
		// Draw all ships.
		for (int i=0; i<ship_count; i++) {
			Ship* ship = ships + i;
			
			SDL_Rect rect = {
				.x = ship->x,
				.y = ship->y,
				.w = ship->width,
				.h = ship->height,
			};
			switch (ship->type) {
				case SHIP_PLAYER:
					rect.x -= 3; // The sprite is slightly larger than player's hitbox, so we need to adjust the position.
					rect.y -= 3;
					SDL_BlitSurface(image_player_ship, NULL, windowsurface, &rect);
					break;
				case SHIP_BASIC_ENEMY:
					rect.x -= 1;
					SDL_BlitSurface(image_basic_enemy_ship, NULL, windowsurface, &rect);
					break;
				case SHIP_STRONG_ENEMY:
					SDL_BlitSurface(image_strong_enemy_ship, NULL, windowsurface, &rect);
					break;
			}
			
			// Draw enemy HP, I've disabled this because the HP bar draws attention into itself, so they distract you from the game. You can uncomment this to see it though.
			/*if (ship->is_enemy) {
				Uint32 hpcolor = SDL_MapRGB(windowsurface->format, 255, 0, 0);
				int margin = 1;
				int bar_width = 2;
				int bar_height = 8;
				int x = ship->x;
				for (int i=0; i<ship->health; i++) {
					SDL_Rect rect = {
						.x = x,
						.y = ship->y - bar_height,
						.w = bar_width,
						.h = bar_height,
					};
					SDL_FillRect(windowsurface, &rect, hpcolor);
					x += bar_width + margin;
				}
			}*/
		}
		
		// Draw all bullets.
		for (int i=0; i<bullet_count; i++) {
			Bullet* bullet = bullets + i;
			
			SDL_Rect rect = {
				.x = bullet->x,
				.y = bullet->y,
				.w = bullet->width,
				.h = bullet->height,
			};
			SDL_FillRect(windowsurface, &rect, bullet->color);
		}
		
		// UI
		int margin = 10; // Margin from the edge of the window.
		int gap = 2; // Gap between bars.
		Uint32 hpcolor = SDL_MapRGB(windowsurface->format, 0, 255, 255);
		Uint32 tenscorecolor = SDL_MapRGB(windowsurface->format, 255, 255, 255);
		Uint32 scorecolor = SDL_MapRGB(windowsurface->format, 240, 220, 80);
		
		// HP at the bottom of the screen.
		int bar_width = (window_width-margin*2) * 0.1 - gap; // Each bar is about 10% of the window width.
		int bar_height = 6;
		int x = margin;
		int y = window_height - margin - bar_height; // Align to bottom.
		Ship* playership = get_player_ship();
		if (playership) {
			for (int i=0; i<playership->health; i++) {
				SDL_Rect rect = {
					.x = x,
					.y = y,
					.w = bar_width,
					.h = bar_height,
				};
				SDL_FillRect(windowsurface, &rect, hpcolor);
				x += bar_width + gap;
			}
		}
		
		// Score at the top of the screen, every 10 score gets "grouped" into a single white block, and the remaining score is drawn as yellow blocks.
		bar_width = 16;
		bar_height = 16;
		x = margin;
		y = margin;
		for (int i=0; i<score/10; i++) {
			SDL_Rect rect = {
				.x = x,
				.y = y,
				.w = bar_width,
				.h = bar_height,
			};
			SDL_FillRect(windowsurface, &rect, tenscorecolor);
			x += bar_width + gap;
			// It's very difficult to get a score so high that the score bar goes off-screen, but we can wrap just in case the next block doesn't fit in.
			if (x+bar_width > window_width-margin) {
				x = margin;
				y += bar_height + gap;
			}
		}
		for (int i=0; i<score%10; i++) {
			SDL_Rect rect = {
				.x = x,
				.y = y,
				.w = bar_width,
				.h = bar_height,
			};
			SDL_FillRect(windowsurface, &rect, scorecolor);
			x += bar_width + gap;
			// Wrap.
			if (x+bar_width > window_width-margin) {
				x = margin;
				y += bar_height + gap;
			}
		}
		
		// Draw the window's surface onto the window.
		SDL_UpdateWindowSurface(window);
	}

// Main game logic.

	Bullet* spawn_bullet (Ship* ship,   float width, float height,   float x_speed, float y_speed,   int damage,   Uint32 color) {
		if (bullet_count >= max_bullet_count) {
			// Too many bullets spawned. Note: we could re-allocate the bullets list here in order to allow infinite bullets. However, it is easier to just allocate a fixed size array at the start.
			printf("Max bullets reached.\n");
			return NULL;
		}
		
		Bullet* bullet = bullets + bullet_count; // Select the bullet after the last currently active bullet.
		*bullet = (Bullet){0}; // Zero the bullet memory since it may have old data in it.
		
		bullet->is_enemy = ship->is_enemy;
		bullet->width = width;
		bullet->height = height;
		bullet->x = ship->x - bullet->width/2 + ship->width/2; // This calculation will put the bullet at the center of the ship.
		bullet->y = ship->y - bullet->height/2 + ship->height/2;
		bullet->x_speed = x_speed;
		bullet->y_speed = y_speed;
		bullet->damage = damage;
		bullet->color = color;
		
		bullet_count ++;
		
		return bullet;
	}
	void ship_shoot (Ship* ship) {
		switch (ship->type) {
			case SHIP_PLAYER:
				spawn_bullet(ship,  6, 14,  0, -4,  1,  SDL_MapRGB(windowsurface->format, 0, 220, 255));
				play_sound(sound_player_shoot);
				break;
			case SHIP_BASIC_ENEMY:
				spawn_bullet(ship,  6, 14,  0, 4,  2,  SDL_MapRGB(windowsurface->format, 255, 190, 0));
				play_sound(sound_enemy_shoot);
				break;
			case SHIP_STRONG_ENEMY:
				spawn_bullet(ship,  16, 16,  0, 1.2,  3,  SDL_MapRGB(windowsurface->format, 255, 0, 255));
				spawn_bullet(ship,  16, 16,  -0.5, 1,  3,  SDL_MapRGB(windowsurface->format, 255, 0, 255));
				spawn_bullet(ship,  16, 16,  0.5, 1,  3,  SDL_MapRGB(windowsurface->format, 255, 0, 255));
				play_sound(sound_strong_enemy_shoot);
				break;
		}
	}
	void spawn_random_enemy () {
		if (ship_count == max_ship_count) {
			// Too many ships spawned. Note: we could re-allocate the ships list here in order to allow infinite ships. However, it is easier to just allocate a fixed size array at the start.
			printf("Max ships reached.\n");
			return;
		}
		
		Ship* enemy = ships + ship_count; // Select the ship after the last currently active ship.
		*enemy = (Ship){0}; // Zero the enemy memory since it may have old data in it.
		
		// 30% chance to spawn a strong enemy.
		float random = random_positive_float(time_elapsed+4);
		if (random < 0.3) {
			enemy->type = SHIP_STRONG_ENEMY;
			enemy->width = 40;
			enemy->height = 25;
			enemy->health = 10;
			enemy->shoot_delay = 3800;
			enemy->color = SDL_MapRGB(windowsurface->format, 200, 0, 100);
			enemy->x_speed = random_float(time_elapsed+5) * 0.4; // Slightly randomize speed.
			enemy->y_speed = random_positive_float(time_elapsed+2) * 0.2 + 0.4; // Y speed should be at least 0.4
		}
		else {
			enemy->type = SHIP_BASIC_ENEMY;
			enemy->width = 20;
			enemy->height = 30;
			enemy->health = 2;
			enemy->shoot_delay = 789;
			enemy->color = SDL_MapRGB(windowsurface->format, 255, 90, 15);
			enemy->x_speed = random_float(time_elapsed+7) * 1.2;
			enemy->y_speed = random_positive_float(time_elapsed+2) * 0.5 + 0.8;
		}
		int edge = 50;
		enemy->is_enemy = true;
		enemy->x = random_positive_float(time_elapsed+1) * (window_width-edge*2) + edge - enemy->width/2; // Random X position, stay 50 pixels away from the edges of the window.
		enemy->y = -enemy->height; // Spawn just outside the screen.
		enemy->shoot_counter += enemy->shoot_delay * 0.5;
		
		ship_count ++;
	}
	bool did_ship_and_bullet_collide (Ship* ship, Bullet* bullet) {
		// AABB collision check; each of these checks if the bullet is out of range to be colliding with the ship (for example right_edge_of_ship < left_edge_of_bullet).
		if (ship->x+ship->width < bullet->x) return false;
		if (ship->x > bullet->x+bullet->width) return false;
		if (ship->y+ship->height < bullet->y) return false;
		if (ship->y > bullet->y+bullet->height) return false;
		return true;
	}
	
	int game_logic () {
		// Adjust difficulty based on score.
		if (score >= 50)      enemy_spawn_delay = 750;
		else if (score >= 30) enemy_spawn_delay = 1000;
		else if (score >= 20) enemy_spawn_delay = 1500;
		else if (score >= 15) enemy_spawn_delay = 2000;
		else if (score >= 10) enemy_spawn_delay = 3000;
		else if (score >= 5)  enemy_spawn_delay = 4000;
		else                  enemy_spawn_delay = 5000;
		
		// Handle player movement.
		Ship* playership = get_player_ship();
		if (playership) {
			// Every frame, slow down to 90% of the current speed.
			playership->x_speed *= 0.9;
			playership->y_speed *= 0.9;
			// Accelerate if movement keys are held.
			if (input_left) {
				playership->x_speed -= 0.4;
			}
			if (input_right) {
				playership->x_speed += 0.4;
			}
			if (input_up) {
				playership->y_speed -= 0.4;
			}
			if (input_down) {
				playership->y_speed += 0.4;
			}
		}
		
		// Spawn enemy.
		enemy_spawn_counter -= time_delta;
		if (enemy_spawn_counter <= 0) {
			enemy_spawn_counter += enemy_spawn_delay;
			spawn_random_enemy();
		}
		
		// Handle ship behaviors.
		for (int i=0; i<ship_count; i++) {
			Ship* ship = ships + i;
			if (ship->is_destroyed) continue; // Skip ships that are marked as destroyed.
			
			// Move.
			ship->x += ship->x_speed;
			ship->y += ship->y_speed;
			
			if (ship->type == SHIP_PLAYER) {
				// Prevent moving off-screen.
				if (ship->x < 0) {
					ship->x = 0;
				}
				if (ship->x+ship->width > window_width) {
					ship->x = window_width - ship->width;
				}
				if (ship->y < 0) {
					ship->y = 0;
				}
				if (ship->y+ship->height > window_height) {
					ship->y = window_height - ship->height;
				}
				// Shoot counter.
				ship->shoot_counter -= time_delta;
				if (ship->shoot_counter <= 0) {
					if (input_shoot) {
						ship->shoot_counter += ship->shoot_delay;
						ship_shoot(ship);
					}
					else {
						ship->shoot_counter = 0; // Prevent this from becoming a crazy negative number while the attack button is not held.
					}
				}
			}
			else {
				// Bounce from the sides of the screen.
				if (ship->x < 0) {
					ship->x_speed = -ship->x_speed;
					ship->x = 0;
				}
				if (ship->x+ship->width > window_width) {
					ship->x_speed = -ship->x_speed;
					ship->x = window_width - ship->width;
				}
				// Destroy when passed the bottom of the screen.
				if (ship->y > window_height) {
					ship->is_destroyed = true;
				}
				// Shoot counter.
				ship->shoot_counter -= time_delta;
				if (ship->shoot_counter <= 0) {
					ship->shoot_counter += ship->shoot_delay;
					ship_shoot(ship);
				}
			}
		}
		
		// Handle bullet behaviors.
		for (int i=0; i<bullet_count; i++) {
			Bullet* bullet = bullets + i;
			if (bullet->is_destroyed) continue; // Skip bullets that are marked as destroyed.
			
			// Move.
			bullet->x += bullet->x_speed;
			bullet->y += bullet->y_speed;
			
			// Destroy when passed the top or bottom of the screen.
			if (bullet->y > window_height) {
				bullet->is_destroyed = true;
			}
			if (bullet->y+bullet->height < 0) {
				bullet->is_destroyed = true;
			}
		}
		
		// Handle collisions. You could also do this during one of the loops above, like right after a ship or bullet moves. I separated them for simplicity.
		for (int i=0; i<bullet_count; i++) {
			Bullet* bullet = bullets + i;
			if (bullet->is_destroyed) continue;
			
			for (int i=0; i<ship_count; i++) {
				Ship* ship = ships + i;
				if (ship->is_destroyed) continue;
				if (bullet->is_enemy == ship->is_enemy) continue; // Enemy bullets can't collide with enemies and player bullets can't collide with player.
				if (!did_ship_and_bullet_collide(ship, bullet)) continue; // Not colliding.
				
				ship->health -= bullet->damage;
				if (ship->health <= 0) {
					ship->is_destroyed = true;
					
					// Explode into particles.
					spawn_bullet(ship,  10, 10,  0, 1,  1,  ship->color);
					spawn_bullet(ship,  10, 10,  0, -1,  1,  ship->color);
					spawn_bullet(ship,  10, 10,  1, 0,  1,  ship->color);
					spawn_bullet(ship,  10, 10,  -1, 0,  1,  ship->color);
					spawn_bullet(ship,  10, 10,  0.7, 0.7,  1,  ship->color);
					spawn_bullet(ship,  10, 10,  -0.7, -0.7,  1,  ship->color);
					spawn_bullet(ship,  10, 10,  0.7, -0.7,  1,  ship->color);
					spawn_bullet(ship,  10, 10,  -0.7, 0.7,  1,  ship->color);
					
					switch (ship->type) {
						case SHIP_PLAYER:
							play_sound(sound_player_explode);
							// You lost The Game.
							break;
						case SHIP_BASIC_ENEMY:
							play_sound(sound_basic_enemy_explode);
							score += 1;
							break;
						case SHIP_STRONG_ENEMY:
							play_sound(sound_strong_enemy_explode);
							score += 1;
							break;
					}
				}
				else {
					play_sound(sound_bullet_collide);
				}
				bullet->is_destroyed = true;
				break; // Bullet can't collide with any more ships.
			}
		}
		
		// Remove destroyed ships from the ships list.
		// You could optimize by only doing this loop if a ship died during this frame. Just toggle a bool variable in the loops above when a ship is destroyed.
		for (int i=0; i<ship_count; i++) {
			Ship* ship = ships + i;
			if (!ship->is_destroyed) continue; // Ignore ships that haven't been destroyed.
			
			// Naive method: move all the memory after this backwards.
			// memmove(ships+i, ships+i+1, (ship_count-i-1)*sizeof(Ship));
			
			// Better method: move the last item on top of this one. Much faster since you're only moving the memory of 1 item. This changes the order of the items in the list though, but it doesn't matter in this case.
			memcpy(ships+i, ships+ship_count-1, sizeof(Ship));
			
			ship_count --;
			i --;
		}
		// Remove destroyed bullets from the bullets list.
		for (int i=0; i<bullet_count; i++) {
			Bullet* bullet = bullets + i;
			if (!bullet->is_destroyed) continue;
			
			memcpy(bullets+i, bullets+bullet_count-1, sizeof(Bullet));
			
			bullet_count --;
			i --;
		}
		
		return 0;
	}

// setup and stuff

	void restart_game () {
		// This function can be used to restart the game at any time.
		bullet_count = 0;
		ship_count = 0;
		score = 0;
		enemy_spawn_counter = 0;
		
		Ship playership = {0};
		playership.health = 10;
		playership.color = SDL_MapRGB(windowsurface->format, 60, 120, 255);
		playership.width = 20;
		playership.height = 20;
		playership.y = window_height - 100;
		playership.x = window_width/2 - playership.width/2; // Start from center of the screen horizontally.
		playership.shoot_delay = 300;
		playership.type = SHIP_PLAYER;
		
		ships[0] = playership;
		ship_count ++;
	}
	int handle_input_and_events () {
		// https://wiki.libsdl.org/SDL_Event
		// https://wiki.libsdl.org/SDL_EventType
		SDL_Event event;
		while (SDL_PollEvent(&event)) {
			switch (event.type) {
				case SDL_KEYDOWN: {
					switch (event.key.keysym.sym) {
						case SDLK_UP: case SDLK_w:
							input_up = true;
							break;
						case SDLK_DOWN: case SDLK_s:
							input_down = true;
							break;
						case SDLK_LEFT: case SDLK_a:
							input_left = true;
							break;
						case SDLK_RIGHT: case SDLK_d:
							input_right = true;
							break;
						case SDLK_SPACE:
							input_shoot = true;
							break;
						case SDLK_RETURN:
							restart_game();
							break;
						case SDLK_ESCAPE:
							return 1;
					}
					break;
				}
				case SDL_KEYUP: {
					switch (event.key.keysym.sym) {
						case SDLK_UP: case SDLK_w:
							input_up = false;
							break;
						case SDLK_DOWN: case SDLK_s:
							input_down = false;
							break;
						case SDLK_LEFT: case SDLK_a:
							input_left = false;
							break;
						case SDLK_RIGHT: case SDLK_d:
							input_right = false;
							break;
						case SDLK_SPACE:
							input_shoot = false;
							break;
					}
					break;
				}
				case SDL_QUIT: {
					return 1;
				}
			}
		}
		return 0;
	}
	int main () {
		// Initialize SDL.
		int res = SDL_Init(0);
		if (res == -1) {
			printf("SDL_Init failed!\n");
			return 1;
		}
		// Initialize SDL_Mixer.
		res = Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, 2, 4096);
		if ( res == -1 ) {
			printf("Mix_OpenAudio failed!\n");
			return 2;
		}
		
		// Open a window.
		window = SDL_CreateWindow("Example shooter", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, window_width, window_height, SDL_WINDOW_SHOWN);
		if (window == NULL) {
			printf("SDL_CreateWindow failed!\n");
			return 3;
		}
		// Create window surface, think of it as a canvas or an image where you can draw pixels.
		windowsurface = SDL_GetWindowSurface(window);
		if (windowsurface == NULL) {
			printf("SDL_GetWindowSurface failed!\n");
			return 4;
		}
		
		// Load resources. Usually I make new functions for these just like I've done with load_sound_effect() because it's easier to handle errors and do other things, but I kept most of the code here for simplicity.
		image_player_ship = IMG_Load("player.png");
		if (!image_player_ship) printf("Failed to load sprite!\n");
		image_basic_enemy_ship = IMG_Load("basic_enemy.png");
		if (!image_basic_enemy_ship) printf("Failed to load sprite!\n");
		image_strong_enemy_ship = IMG_Load("strong_enemy.png");
		if (!image_strong_enemy_ship) printf("Failed to load sprite!\n");
		
		music_vibes = Mix_LoadMUS("mixkit-tech-house-vibes-130.mp3");
		if (!music_vibes) printf("Failed to load music!\n");
		
		sound_player_shoot = load_sound_effect("mixkit-game-balloon-or-bubble-pop-3069.wav", 0.5);
		sound_enemy_shoot = sound_player_shoot;
		sound_strong_enemy_shoot = load_sound_effect("mixkit-sci-fi-drill-alert-760.wav", 1.0);
		sound_bullet_collide = load_sound_effect("mixkit-quick-switch-click-2582.wav", 0.6);
		sound_player_explode = load_sound_effect("mixkit-water-sci-fi-bleep-902.wav", 0.7);
		sound_basic_enemy_explode = sound_player_explode;
		sound_strong_enemy_explode = sound_player_explode;
		
		// Lower volume because otherwise it's way too loud.
		Mix_VolumeMusic(MIX_MAX_VOLUME * 0.1); // Music at 10%
		Mix_Volume(-1, MIX_MAX_VOLUME * 0.15); // Sound effects at 15%
		
		// Allocate game memory, we could have also just made an array like   Ship ships[100];   instead of using malloc.
		ships = malloc(sizeof(Ship)*max_ship_count);
		bullets = malloc(sizeof(Bullet)*max_bullet_count);
		
		// Start game.
		restart_game();
		play_music(music_vibes);
		
		// Main game loop. Personally I like to put all the program initialization code into the main function, and the main loop logic into other functions.
		while (1) {
			int result = handle_input_and_events();
			if (result) break; // If quit event happened (for example when the window is closed), break the loop.
			
			result = game_logic();
			if (result) break; // If the player pressed a quit button or whatever, we can quit by returning a number from the game_logic function. This project doesn't have anything like that though.
			
			draw_game();
			
			SDL_Delay(time_delta); // Make the program wait 16 milliseconds before continuing (this causes the game tick to run at roughly 60 fps).
			time_elapsed += time_delta;
		}
		
		return 0;
	}