aboutsummaryrefslogtreecommitdiff
#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;
}