aboutsummaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
authorThomas Guillermo Albers Raviola <thomas@thomaslabs.org>2026-01-16 23:26:01 +0100
committerThomas Guillermo Albers Raviola <thomas@thomaslabs.org>2026-01-16 23:26:01 +0100
commitc15c603b35e86fd42e6db94a7382ba7a1ddadd6e (patch)
treeab56040ce4768564bef5fbe9e65fe4c025cea6ce /main.c
Initial commit
Diffstat (limited to 'main.c')
-rw-r--r--main.c265
1 files changed, 265 insertions, 0 deletions
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..6cfb1d7
--- /dev/null
+++ b/main.c
@@ -0,0 +1,265 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "game.h"
+
+struct MainGame *game;
+static const char *game_name = "Highnoon";
+
+void process_events(void)
+{
+ SDL_Event e;
+ int x, y;
+
+ while( SDL_PollEvent(&e) )
+ {
+ switch(e.type)
+ {
+ case SDL_QUIT:
+ game->state = QUIT;
+ break;
+
+ case SDL_MOUSEBUTTONDOWN:
+ SDL_GetMouseState(&x, &y);
+ process_widget_events(MOUSE_BUTTON, x, y);
+ break;
+
+ case SDL_MOUSEMOTION:
+ process_widget_events(MOUSE_MOTION, e.motion.x, e.motion.y);
+ break;
+ }
+ }
+
+ if(game->state == RUNNING && game->keys[SDL_SCANCODE_ESCAPE])
+ {
+ game->state = MENU;
+ game->current_layer = MENU_LAYER;
+ }
+}
+
+void unload_game(void)
+{
+ int i;
+ struct Resources *res = &game->resources;
+
+ for(i = 0; i < res->num_textures; i ++)
+ SDL_DestroyTexture(res->textures[i]);
+
+ for(i = 0; i < res->num_audios; i ++)
+ Mix_FreeChunk(res->audios[i]);
+
+ TTF_CloseFont(res->font);
+}
+
+static void play_button_callback(struct Widget *w)
+{
+ game->state = RUNNING;
+ game->current_layer = GAME_LAYER;
+}
+
+static void quit_button_callback(struct Widget *w)
+{
+ game->state = QUIT;
+}
+
+void load_menu(void)
+{
+ struct Color c = {255, 255, 255};
+ struct Color on_hover = {255, 255, 0};
+
+ game->menu.play_button = add_button(MENU_LAYER, "Play", POSITION_CENTERED,
+ 150, play_button_callback);
+ set_color(game->menu.play_button, c);
+ game->menu.play_button->on_hover_color = on_hover;
+
+ game->menu.quit_button = add_button(MENU_LAYER, "Quit", POSITION_CENTERED,
+ 190, quit_button_callback);
+ set_color(game->menu.quit_button, c);
+ game->menu.quit_button->on_hover_color = on_hover;
+
+ add_label(MENU_LAYER, game_name, (struct Color){255, 255, 255}, POSITION_CENTERED, 50);
+}
+
+void load_game(void)
+{
+ int i;
+ struct PlayerKeys keys[2] =
+ {
+ {
+ .jump = SDL_SCANCODE_W,
+ .left = SDL_SCANCODE_A,
+ .right = SDL_SCANCODE_D,
+ .fire = SDL_SCANCODE_F,
+ .reload = SDL_SCANCODE_R,
+ .weaponds = {SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_3}
+ },
+ {
+ .jump = SDL_SCANCODE_UP,
+ .left = SDL_SCANCODE_LEFT,
+ .right = SDL_SCANCODE_RIGHT,
+ .fire = SDL_SCANCODE_K,
+ .reload = SDL_SCANCODE_L,
+ .weaponds = {SDL_SCANCODE_B, SDL_SCANCODE_N, SDL_SCANCODE_M}
+ }
+ };
+
+ game->guns[0] = load_texture("resources/revolver.png");
+ game->guns[1] = load_texture("resources/rifle.png");
+ game->guns[2] = load_texture("resources/shotgun.png");
+
+ game->revolver_sound = load_sound("resources/revolver.ogg");
+ game->rifle_sound = load_sound("resources/rifle.ogg");
+
+ game->num_players = 2;
+ game->bullets_left = MAX_BULLETS;
+ game->keys = SDL_GetKeyboardState(NULL);
+
+ init_player(&game->players[0], &keys[0], 200.0f, 200.0f, "Player1");
+ init_player(&game->players[1], &keys[1], 500.0f, 200.0f, "Player2");
+
+ game->bullet_texture = load_texture("resources/bullet.png");
+ srand(time(NULL));
+
+ game->score = add_label(GAME_LAYER, "",
+ (struct Color){255, 255, 255}, POSITION_CENTERED, 0);
+ update_score();
+
+ for(i = 0; i < 3; i ++)
+ {
+ game->players[0].hearts[i] = add_image(GAME_LAYER, load_texture("resources/heart.png"),
+ 20 + i * 80, 100, 64, 64);
+ game->players[0].hearts[i]->use_src_rect = true;
+ game->players[0].hearts[i]->src_rect = (SDL_Rect){0, 0, 16, 16};
+ }
+
+ int w, h;
+ SDL_QueryTexture(game->guns[0], NULL, NULL, &w, &h);
+ game->players[0].gun = add_image(GAME_LAYER, game->guns[0], 0, 0, w * 2, h * 2);
+ game->players[1].gun = add_image(GAME_LAYER, game->guns[0], 400, 0, w * 2, h * 2);
+
+ for(i = 0; i < 3; i ++)
+ {
+ game->players[1].hearts[i] = add_image(GAME_LAYER, load_texture("resources/heart.png"),
+ (game->width - 250) + i * 80, 100, 64, 64);
+ game->players[1].hearts[i]->use_src_rect = true;
+ game->players[1].hearts[i]->src_rect = (SDL_Rect){0, 0, 16, 16};
+ }
+
+ load_config("config");
+
+ game->camera.rect.x = WINDOW_WIDTH / 2;
+ game->camera.rect.y = WINDOW_HEIGHT / 2;
+ game->camera.rect.w = WINDOW_WIDTH;
+ game->camera.rect.h = WINDOW_HEIGHT;
+}
+
+static const unsigned int ticks_per_frame = 1000 / 75;
+
+/*
+ To make things easier with collision we can have moveable and unmoveable
+ entities. If a entity is unmoveable then under collisions it should stay in
+ place and we only have to go back with the moveable
+*/
+
+int main(int argc, char **argv)
+{
+ int i;
+ unsigned int start_ticks, frame_ticks;
+
+ game = calloc( 1, sizeof(struct MainGame) );
+
+ SDL_Init(SDL_INIT_EVERYTHING);
+ Mix_Init(MIX_INIT_OGG);
+ if( TTF_Init() != 0)
+ die("Error while initializing SDL2_ttf\n", TTF_GetError());
+
+ game->window = SDL_CreateWindow(game_name, SDL_WINDOWPOS_CENTERED,
+ SDL_WINDOWPOS_CENTERED, WINDOW_WIDTH, WINDOW_HEIGHT, 0);
+ game->renderer = SDL_CreateRenderer(game->window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
+
+ if(game->window == NULL || game->renderer == NULL)
+ {
+ die("Error while creating the window and/or renderer:\n%s\n",
+ SDL_GetError());
+ }
+
+ SDL_SetRenderDrawColor(game->renderer, 92, 51, 23, 255);
+
+ if(Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, 2, 4096) == -1)
+ die("Audio could not be opened: %s", Mix_GetError());
+
+ game->width = WINDOW_WIDTH;
+ game->height = WINDOW_HEIGHT;
+ game->gravity = 1200.0f;
+ game->state = MENU;
+ game->current_layer = MENU_LAYER;
+
+ game->resources.font = TTF_OpenFont("resources/font.ttf", 40);
+
+ load_menu();
+ load_game();
+
+ struct Widget w = {};
+
+ /* game->players[0].guns[2].max_bullets = 100; */
+ /* game->players[0].guns[2].projectiles_per_shot = 10; */
+ /* game->players[0].guns[2].cooldown = .5f; */
+
+ while(game->state != QUIT)
+ {
+ //game->camera.rect.x = game->players[0].entity.x;
+ //game->camera.rect.y = game->players[0].entity.y;
+ game->num_entities = 0;
+ start_ticks = SDL_GetTicks();
+
+ process_events();
+
+ if(game->current_layer == GAME_LAYER)
+ {
+ update_player(&game->players[0]);
+ update_player(&game->players[1]);
+ update_bullets();
+
+ for(i = 0; i < game->num_tiles; i ++)
+ game->entities[game->num_entities ++] = &game->tiles[i];
+
+ check_collisions();
+ }
+
+ render_begin();
+
+ if(game->state == RUNNING)
+ render_entities();
+
+ char text[50];
+ sprintf(text, "%hhd -- %hhd",
+ game->players[0].guns[game->players[0].current_gun].bullets,
+ game->players[1].guns[game->players[1].current_gun].bullets);
+ set_text(&w, text);
+ if (w.texture) {
+ SDL_Rect rect = {0, 200, 100, 50};
+ SDL_RenderCopyEx(game->renderer, w.texture, NULL, &rect, 0,
+ NULL, SDL_FLIP_NONE);
+ }
+ render_flush();
+
+ frame_ticks = SDL_GetTicks() - start_ticks;
+ if( frame_ticks < ticks_per_frame )
+ SDL_Delay(ticks_per_frame - frame_ticks);
+
+ // Frame time in seconds
+ game->frame_time = (float)frame_ticks / 1000.0f;
+ }
+
+ SDL_DestroyRenderer(game->renderer);
+ SDL_DestroyWindow(game->window);
+
+ unload_game();
+ free(game);
+
+ SDL_Quit();
+ TTF_Quit();
+ Mix_Quit();
+ return 0;
+}