2017-11-30 21:00:47 +01:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <SDL2/SDL.h>
|
|
|
|
#include <SDL2/SDL_image.h>
|
|
|
|
|
2017-12-19 09:06:21 +01:00
|
|
|
#include "linkedlist.h"
|
2017-11-30 21:00:47 +01:00
|
|
|
#include "player.h"
|
|
|
|
#include "screenresolution.h"
|
|
|
|
#include "dimension.h"
|
2017-12-01 16:03:19 +01:00
|
|
|
#include "camera.h"
|
|
|
|
#include "map.h"
|
2017-12-02 23:32:40 +01:00
|
|
|
#include "map_lua.h"
|
2017-12-05 08:30:08 +01:00
|
|
|
#include "timer.h"
|
2017-12-05 15:03:20 +01:00
|
|
|
#include "roommatrix.h"
|
2017-12-22 06:27:58 +01:00
|
|
|
#include "gamestate.h"
|
2017-12-22 15:15:40 +01:00
|
|
|
#include "gui.h"
|
2018-01-23 22:54:02 +01:00
|
|
|
#include "util.h"
|
2018-01-24 21:14:34 +01:00
|
|
|
#include "item_builder.h"
|
2018-01-31 09:15:33 +01:00
|
|
|
#include "pointer.h"
|
2018-02-02 16:16:55 +01:00
|
|
|
#include "gui_button.h"
|
2017-11-30 21:00:47 +01:00
|
|
|
|
|
|
|
static SDL_Window *gWindow = NULL;
|
|
|
|
static SDL_Renderer *gRenderer = NULL;
|
2017-12-12 11:20:08 +01:00
|
|
|
static Player *gPlayer = NULL;
|
2017-12-01 16:03:19 +01:00
|
|
|
static Map *gMap = NULL;
|
2017-12-05 15:03:20 +01:00
|
|
|
static RoomMatrix *gRoomMatrix = NULL;
|
2017-12-22 15:15:40 +01:00
|
|
|
static Gui *gGui = NULL;
|
2018-01-31 09:15:33 +01:00
|
|
|
static Pointer *gPointer = NULL;
|
2018-02-02 16:16:55 +01:00
|
|
|
static GuiButton *gButton = NULL;
|
2018-01-23 12:14:44 +01:00
|
|
|
static unsigned int cLevel = 1;
|
|
|
|
static double renderScale = 1.0;
|
2017-12-22 15:15:40 +01:00
|
|
|
static GameState gGameState;
|
2017-12-01 16:03:19 +01:00
|
|
|
static Camera gCamera;
|
2018-01-23 12:14:44 +01:00
|
|
|
static SDL_Rect gameViewport;
|
|
|
|
static SDL_Rect bottomGuiViewport;
|
|
|
|
static SDL_Rect rightGuiViewport;
|
2017-11-30 21:00:47 +01:00
|
|
|
|
|
|
|
static
|
2017-12-19 21:00:02 +01:00
|
|
|
bool initSDL(void)
|
2017-11-30 21:00:47 +01:00
|
|
|
{
|
|
|
|
int imgFlags = IMG_INIT_PNG;
|
2017-12-03 11:09:57 +01:00
|
|
|
Dimension dim = getScreenDimensions();
|
2017-11-30 21:00:47 +01:00
|
|
|
|
2017-12-22 06:27:58 +01:00
|
|
|
if (dim.height > 1080) {
|
2018-01-24 06:41:37 +01:00
|
|
|
info("Hi resolution screen detected (%u x %u)", dim.width, dim.height);
|
2018-01-24 08:52:50 +01:00
|
|
|
renderScale = ((double) dim.height)/1080;
|
2018-01-24 18:06:10 +01:00
|
|
|
if (renderScale > 2)
|
|
|
|
renderScale = 3;
|
|
|
|
else if (renderScale > 1)
|
|
|
|
renderScale = 2;
|
2018-01-24 06:41:37 +01:00
|
|
|
info("Scaling by %f", renderScale);
|
2017-11-30 21:00:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (SDL_Init(SDL_INIT_VIDEO) < 0)
|
|
|
|
{
|
2018-01-24 06:41:37 +01:00
|
|
|
error("Could not initiate SDL2: %s", SDL_GetError());
|
2017-11-30 21:00:47 +01:00
|
|
|
return false;
|
|
|
|
}
|
2017-12-22 06:27:58 +01:00
|
|
|
|
|
|
|
if ( (IMG_Init(imgFlags) & imgFlags) == 0 ) {
|
2018-01-24 06:41:37 +01:00
|
|
|
error("Unable to initiate img loading: %s",
|
2017-12-22 06:27:58 +01:00
|
|
|
IMG_GetError());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( TTF_Init() == -1 ) {
|
2018-01-24 06:41:37 +01:00
|
|
|
error("Unable to initiate ttf library: %s",
|
2017-12-22 06:27:58 +01:00
|
|
|
TTF_GetError());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-11-30 21:00:47 +01:00
|
|
|
gWindow = SDL_CreateWindow("Breakhack",
|
|
|
|
SDL_WINDOWPOS_UNDEFINED,
|
|
|
|
SDL_WINDOWPOS_UNDEFINED,
|
2018-01-23 12:14:44 +01:00
|
|
|
(int)(SCREEN_WIDTH * renderScale),
|
2018-01-24 06:41:37 +01:00
|
|
|
(int)(SCREEN_HEIGHT * renderScale),
|
2017-11-30 21:00:47 +01:00
|
|
|
SDL_WINDOW_SHOWN);
|
|
|
|
if (gWindow == NULL)
|
|
|
|
{
|
2018-01-24 06:41:37 +01:00
|
|
|
error("Unable to create window: %s", SDL_GetError());
|
2017-11-30 21:00:47 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED);
|
|
|
|
if (gRenderer == NULL)
|
|
|
|
{
|
2018-01-24 06:41:37 +01:00
|
|
|
error("Unable to create renderer: %s", SDL_GetError());
|
2017-11-30 21:00:47 +01:00
|
|
|
return false;
|
|
|
|
}
|
2017-12-10 19:51:24 +01:00
|
|
|
if (SDL_SetRenderDrawBlendMode(gRenderer, SDL_BLENDMODE_BLEND) < 0) {
|
2018-01-24 06:41:37 +01:00
|
|
|
error("Unable to set blend mode: %s", SDL_GetError());
|
2017-12-10 19:51:24 +01:00
|
|
|
return false;
|
|
|
|
}
|
2017-11-30 21:00:47 +01:00
|
|
|
if (SDL_RenderSetLogicalSize(gRenderer, SCREEN_WIDTH, SCREEN_HEIGHT) < 0)
|
|
|
|
{
|
2018-01-24 06:41:37 +01:00
|
|
|
error("Unable to initiate scaling: %s",
|
2017-12-15 15:03:29 +01:00
|
|
|
SDL_GetError());
|
2017-11-30 21:00:47 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-01-23 12:14:44 +01:00
|
|
|
static void
|
|
|
|
initViewports(void)
|
|
|
|
{
|
|
|
|
gameViewport = (SDL_Rect) { 0, 0,
|
|
|
|
GAME_VIEW_WIDTH, GAME_VIEW_HEIGHT };
|
|
|
|
|
|
|
|
bottomGuiViewport = (SDL_Rect) { 0, GAME_VIEW_HEIGHT,
|
|
|
|
BOTTOM_GUI_WIDTH, BOTTOM_GUI_WIDTH };
|
|
|
|
|
|
|
|
rightGuiViewport = (SDL_Rect) { GAME_VIEW_WIDTH, 0,
|
|
|
|
RIGHT_GUI_WIDTH, RIGHT_GUI_HEIGHT };
|
|
|
|
}
|
|
|
|
|
2017-11-30 21:00:47 +01:00
|
|
|
static
|
2017-12-19 21:00:02 +01:00
|
|
|
bool initGame(void)
|
2017-11-30 21:00:47 +01:00
|
|
|
{
|
2018-01-22 10:12:44 +01:00
|
|
|
gMap = map_lua_generator_run(cLevel, gRenderer);
|
2018-01-31 09:15:33 +01:00
|
|
|
|
|
|
|
return true;
|
2017-11-30 21:00:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static
|
2017-12-19 21:00:02 +01:00
|
|
|
bool init(void)
|
2017-11-30 21:00:47 +01:00
|
|
|
{
|
|
|
|
bool result = true;
|
|
|
|
result = result && initSDL();
|
|
|
|
result = result && initGame();
|
2017-12-01 16:03:19 +01:00
|
|
|
if (result) {
|
2018-01-31 13:52:11 +01:00
|
|
|
initViewports();
|
2017-12-01 16:03:19 +01:00
|
|
|
gCamera.pos = (Position) { 0, 0 };
|
|
|
|
gCamera.renderer = gRenderer;
|
2017-12-05 15:03:20 +01:00
|
|
|
gRoomMatrix = roommatrix_create();
|
2018-01-31 13:52:11 +01:00
|
|
|
gGui = gui_create(gRenderer);
|
2018-01-24 21:14:34 +01:00
|
|
|
item_builder_init(gRenderer);
|
2018-01-31 13:52:11 +01:00
|
|
|
gPointer = pointer_create(gRenderer);
|
2018-02-02 16:16:55 +01:00
|
|
|
gButton = gui_button_create((SDL_Rect) { 100, 100, 100, 100 });
|
2017-12-01 16:03:19 +01:00
|
|
|
}
|
2017-12-17 13:43:41 +01:00
|
|
|
|
2017-12-22 15:15:40 +01:00
|
|
|
gGameState = PLAYING;
|
2017-12-22 06:27:58 +01:00
|
|
|
|
2017-11-30 21:00:47 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
2017-12-19 21:00:02 +01:00
|
|
|
void loadMedia(void)
|
2017-11-30 21:00:47 +01:00
|
|
|
{
|
2018-01-25 16:42:57 +01:00
|
|
|
gPlayer = player_create(PALADIN, gRenderer);
|
2017-11-30 21:00:47 +01:00
|
|
|
}
|
|
|
|
|
2017-12-03 11:09:57 +01:00
|
|
|
static
|
2017-12-19 21:00:02 +01:00
|
|
|
bool handle_events(void)
|
2017-12-03 11:09:57 +01:00
|
|
|
{
|
|
|
|
static SDL_Event event;
|
|
|
|
bool quit = false;
|
|
|
|
|
|
|
|
while (SDL_PollEvent(&event) != 0) {
|
|
|
|
if (event.type == SDL_QUIT) {
|
|
|
|
quit = true;
|
2017-12-22 15:15:40 +01:00
|
|
|
} else if (gGameState == PLAYING) {
|
2017-12-15 08:08:45 +01:00
|
|
|
gPlayer->handle_event(gPlayer,
|
|
|
|
gRoomMatrix,
|
|
|
|
&event);
|
2017-12-12 11:20:08 +01:00
|
|
|
camera_follow_position(&gCamera, &gPlayer->sprite->pos);
|
|
|
|
map_set_current_room(gMap, &gPlayer->sprite->pos);
|
2017-12-03 11:09:57 +01:00
|
|
|
}
|
2018-01-31 09:15:33 +01:00
|
|
|
pointer_handle_event(gPointer, &event);
|
2017-12-03 11:09:57 +01:00
|
|
|
}
|
2018-02-02 16:16:55 +01:00
|
|
|
|
|
|
|
gui_button_check_pointer(gButton, gPointer);
|
|
|
|
|
2017-12-03 11:09:57 +01:00
|
|
|
return quit;
|
|
|
|
}
|
|
|
|
|
2018-01-30 15:16:14 +01:00
|
|
|
static bool
|
|
|
|
check_if_dead(void)
|
|
|
|
{
|
|
|
|
if (gPlayer->stats.hp <= 0) {
|
|
|
|
gui_log("The dungeon consumed you");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-12-22 06:27:58 +01:00
|
|
|
static void
|
|
|
|
check_next_level(void)
|
|
|
|
{
|
|
|
|
Room *room = gMap->rooms[gMap->currentRoom.x][gMap->currentRoom.y];
|
|
|
|
Position pos = position_to_matrix_coords(&gPlayer->sprite->pos);
|
|
|
|
|
|
|
|
MapTile *tile = room->tiles[pos.x][pos.y];
|
|
|
|
if (!tile) {
|
2018-01-24 06:41:37 +01:00
|
|
|
error("Looks like we are out of place");
|
2017-12-22 06:27:58 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (tile->levelExit) {
|
2018-01-24 06:41:37 +01:00
|
|
|
info("Building new map");
|
2017-12-22 06:27:58 +01:00
|
|
|
map_destroy(gMap);
|
2018-01-22 10:12:44 +01:00
|
|
|
gMap = map_lua_generator_run(++cLevel, gRenderer);
|
2017-12-22 06:27:58 +01:00
|
|
|
gPlayer->sprite->pos = (Position) {
|
|
|
|
TILE_DIMENSION, TILE_DIMENSION };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-22 15:15:40 +01:00
|
|
|
static void
|
|
|
|
run_game(void)
|
|
|
|
{
|
2018-01-31 09:15:33 +01:00
|
|
|
SDL_RenderSetViewport(gRenderer, NULL);
|
2017-12-22 15:15:40 +01:00
|
|
|
map_clear_dead_monsters(gMap);
|
2018-01-24 21:14:34 +01:00
|
|
|
map_clear_collected_items(gMap);
|
2017-12-22 15:15:40 +01:00
|
|
|
roommatrix_populate_from_map(gRoomMatrix, gMap);
|
|
|
|
roommatrix_add_lightsource(gRoomMatrix,
|
2018-01-31 13:52:11 +01:00
|
|
|
&gPlayer->sprite->pos);
|
2018-01-31 09:15:33 +01:00
|
|
|
|
2017-12-22 15:15:40 +01:00
|
|
|
roommatrix_build_lightmap(gRoomMatrix);
|
|
|
|
|
2018-02-01 09:04:19 +01:00
|
|
|
gui_update_player_stats(gGui, gPlayer, gMap, gRenderer);
|
2018-01-31 20:59:55 +01:00
|
|
|
|
|
|
|
if (gPlayer->steps >= gPlayer->stats.speed) {
|
2017-12-22 15:15:40 +01:00
|
|
|
player_reset_steps(gPlayer);
|
|
|
|
roommatrix_update_with_player(gRoomMatrix, gPlayer);
|
|
|
|
map_move_monsters(gMap, gRoomMatrix);
|
|
|
|
}
|
|
|
|
|
|
|
|
SDL_RenderClear(gRenderer);
|
|
|
|
|
2018-01-23 12:14:44 +01:00
|
|
|
SDL_RenderSetViewport(gRenderer, &gameViewport);
|
2017-12-22 15:15:40 +01:00
|
|
|
map_render(gMap, &gCamera);
|
|
|
|
player_render(gPlayer, &gCamera);
|
|
|
|
roommatrix_render_lightmap(gRoomMatrix, &gCamera);
|
2018-01-23 12:14:44 +01:00
|
|
|
|
|
|
|
SDL_RenderSetViewport(gRenderer, &rightGuiViewport);
|
|
|
|
gui_render_panel(gGui, RIGHT_GUI_WIDTH,
|
|
|
|
RIGHT_GUI_HEIGHT, &gCamera);
|
|
|
|
|
|
|
|
SDL_RenderSetViewport(gRenderer, &bottomGuiViewport);
|
|
|
|
gui_render_log(gGui, BOTTOM_GUI_WIDTH,
|
|
|
|
BOTTOM_GUI_HEIGHT, &gCamera);
|
2017-12-22 15:15:40 +01:00
|
|
|
|
2018-01-31 09:15:33 +01:00
|
|
|
SDL_RenderSetViewport(gRenderer, NULL);
|
|
|
|
pointer_render(gPointer, &gCamera);
|
|
|
|
|
2017-12-22 15:15:40 +01:00
|
|
|
SDL_RenderPresent(gRenderer);
|
|
|
|
|
2018-01-30 15:16:14 +01:00
|
|
|
if (check_if_dead())
|
|
|
|
gGameState = GAME_OVER;
|
|
|
|
|
2017-12-22 15:15:40 +01:00
|
|
|
check_next_level();
|
|
|
|
}
|
|
|
|
|
2017-11-30 21:00:47 +01:00
|
|
|
static
|
2017-12-19 21:00:02 +01:00
|
|
|
void run(void)
|
2017-11-30 21:00:47 +01:00
|
|
|
{
|
|
|
|
bool quit = false;
|
2017-12-05 08:30:08 +01:00
|
|
|
Timer* fpsTimer = timer_create();
|
2017-11-30 21:00:47 +01:00
|
|
|
|
2018-01-25 16:42:57 +01:00
|
|
|
gui_log("The Dungeon Crawl begins!");
|
|
|
|
|
2017-11-30 21:00:47 +01:00
|
|
|
while (!quit)
|
|
|
|
{
|
2017-12-05 08:30:08 +01:00
|
|
|
timer_start(fpsTimer);
|
2017-11-30 21:00:47 +01:00
|
|
|
|
2017-12-03 11:09:57 +01:00
|
|
|
quit = handle_events();
|
2017-11-30 21:00:47 +01:00
|
|
|
|
2017-12-22 15:15:40 +01:00
|
|
|
switch (gGameState) {
|
|
|
|
case PLAYING:
|
|
|
|
run_game();
|
|
|
|
break;
|
|
|
|
case MENU:
|
2018-01-30 15:16:14 +01:00
|
|
|
fatal("MENU not implemented");
|
2017-12-22 15:15:40 +01:00
|
|
|
break;
|
|
|
|
case IN_GAME_MENU:
|
2018-01-30 15:16:14 +01:00
|
|
|
fatal("IN_GAME_MENU not implemented");
|
2017-12-22 15:15:40 +01:00
|
|
|
break;
|
|
|
|
case GAME_OVER:
|
2018-01-30 15:16:14 +01:00
|
|
|
fatal("GAME_OVER not implemented");
|
2017-12-22 15:15:40 +01:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2017-12-22 06:27:58 +01:00
|
|
|
|
2017-12-05 08:30:08 +01:00
|
|
|
int ticks = timer_get_ticks(fpsTimer);
|
2017-11-30 21:00:47 +01:00
|
|
|
if (ticks < 1000/60)
|
|
|
|
SDL_Delay((1000/60) - ticks);
|
2017-12-05 08:30:08 +01:00
|
|
|
timer_stop(fpsTimer);
|
2017-11-30 21:00:47 +01:00
|
|
|
}
|
2017-12-05 08:30:08 +01:00
|
|
|
|
|
|
|
timer_destroy(fpsTimer);
|
2017-11-30 21:00:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static
|
2017-12-19 21:00:02 +01:00
|
|
|
void close(void)
|
2017-11-30 21:00:47 +01:00
|
|
|
{
|
2017-12-12 11:20:08 +01:00
|
|
|
player_destroy(gPlayer);
|
2017-12-01 16:03:19 +01:00
|
|
|
map_destroy(gMap);
|
2017-12-06 11:44:17 +01:00
|
|
|
roommatrix_destroy(gRoomMatrix);
|
2017-12-22 15:15:40 +01:00
|
|
|
gui_destroy(gGui);
|
2018-01-31 09:15:33 +01:00
|
|
|
pointer_destroy(gPointer);
|
2018-02-02 16:16:55 +01:00
|
|
|
gui_button_destroy(gButton);
|
2018-01-24 21:14:34 +01:00
|
|
|
item_builder_close();
|
2017-12-22 15:15:40 +01:00
|
|
|
SDL_DestroyRenderer(gRenderer);
|
2017-11-30 21:00:47 +01:00
|
|
|
SDL_DestroyWindow(gWindow);
|
|
|
|
gWindow = NULL;
|
2017-12-20 18:56:28 +01:00
|
|
|
TTF_Quit();
|
2017-11-30 21:00:47 +01:00
|
|
|
IMG_Quit();
|
|
|
|
SDL_Quit();
|
|
|
|
}
|
|
|
|
|
2017-12-21 11:46:52 +01:00
|
|
|
int main(int argc, char *argv[])
|
2017-11-30 21:00:47 +01:00
|
|
|
{
|
2017-12-21 11:46:52 +01:00
|
|
|
UNUSED(argc);
|
|
|
|
UNUSED(argv);
|
|
|
|
|
2017-11-30 21:00:47 +01:00
|
|
|
if (!init())
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
loadMedia();
|
|
|
|
run();
|
|
|
|
close();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|