diff --git a/CMakeLists.txt b/CMakeLists.txt index 59f5627..e9e5dbc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -157,7 +157,7 @@ add_executable(breakhack src/menu src/collisions src/keyboard - src/keyboardinput + src/input src/mixer src/io_util src/physfsrwops @@ -221,15 +221,15 @@ IF (CMOCKA_FOUND AND NOT OSX AND NOT CLANG) target_link_libraries(test_hashtable ${CMOCKA_LIBRARY}) add_test(test_hashtable test_hashtable) - add_executable(test_keyboardinput test/test_keyboardinput src/keyboardinput src/keyboard) - target_link_libraries(test_keyboardinput + add_executable(test_input test/test_input src/input src/keyboard) + target_link_libraries(test_input ${CMOCKA_LIBRARY} ${SDL2_LIBRARY} ${SDL2MAIN_LIBRARY} ) - set_target_properties(test_keyboardinput PROPERTIES - LINK_FLAGS "-Wl,--wrap,keyboard_direction_press -Wl,--wrap,keyboard_press") - add_test(test_keyboardinput test_keyboardinput) + #set_target_properties(test_input PROPERTIES + #LINK_FLAGS "-Wl,--wrap,keyboard_direction_press -Wl,--wrap,keyboard_press") + add_test(test_input test_input) ENDIF () # LINT: diff --git a/src/actiontext.h b/src/actiontext.h index a2ff479..5bf6b80 100644 --- a/src/actiontext.h +++ b/src/actiontext.h @@ -27,7 +27,7 @@ #include "timer.h" #include "vector2d.h" -struct UpdateData_t; +struct UpdateData; typedef struct { Position pos; @@ -40,7 +40,7 @@ typedef struct { ActionText* actiontext_create(Sprite*); -void actiontext_update(ActionText*, struct UpdateData_t*); +void actiontext_update(ActionText*, struct UpdateData*); void actiontext_render(ActionText*, Camera*); diff --git a/src/gui_button.c b/src/gui_button.c index 4652010..135b7fb 100644 --- a/src/gui_button.c +++ b/src/gui_button.c @@ -40,20 +40,14 @@ gui_button_check_pointer(GuiButton *button, Pointer *pointer) } void -gui_button_handle_event(GuiButton *button, SDL_Event *event) +gui_button_update(GuiButton *button, Input *input) { - if (event->type == SDL_MOUSEBUTTONDOWN) { + Position p = { input->mouseX, input->mouseY }; + button->hover = position_in_rect(&p, &button->area); - if (event->button.button != SDL_BUTTON_LEFT) - return; - - Position p = { event->button.x, event->button.y }; + if (input_mousebutton_is_pressed(input, MBUTTON_LEFT)) { if (position_in_rect(&p, &button->area) && button->event) button->event(button->usrdata); - - } else if (event->type == SDL_MOUSEMOTION) { - Position p = { event->motion.x, event->motion.y }; - button->hover = position_in_rect(&p, &button->area); } } diff --git a/src/gui_button.h b/src/gui_button.h index 7695705..aa9a0aa 100644 --- a/src/gui_button.h +++ b/src/gui_button.h @@ -24,8 +24,9 @@ #include "sprite.h" #include "linkedlist.h" #include "camera.h" +#include "input.h" -typedef struct GuiButton_t { +typedef struct GuiButton { SDL_Rect area; bool hover; void *usrdata; @@ -39,7 +40,7 @@ void gui_button_check_pointer(GuiButton*, Pointer*); void -gui_button_handle_event(GuiButton*, SDL_Event*); +gui_button_update(GuiButton*, Input*); void gui_button_destroy(GuiButton*); diff --git a/src/input.c b/src/input.c new file mode 100644 index 0000000..364e12a --- /dev/null +++ b/src/input.c @@ -0,0 +1,154 @@ +/* + * BreakHack - A dungeone crawler RPG + * Copyright (C) 2018 Linus Probert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "input.h" +#include "vector2d.h" + +void +input_init(Input *input) +{ + input->keyState = 0; + input->lastKeyState = 0; + input->mouseButtonState = 0; + input->lastMouseButtonState = 0; + input->mouseX = 0; + input->mouseY = 0; +} + +void input_reset(Input *input) +{ + input->lastKeyState = input->keyState; + input->lastMouseButtonState = input->mouseButtonState; + input->keyState = 0; + input->mouseButtonState = 0; +} + +static Uint64 +get_event_key(SDL_Event *event) +{ + switch (event->key.keysym.sym) { + case SDLK_UP: + case SDLK_k: + case SDLK_w: + return KEY_UP; + case SDLK_DOWN: + case SDLK_j: + return KEY_DOWN; + case SDLK_s: + return KEY_DOWN | KEY_S; + case SDLK_LEFT: + case SDLK_h: + case SDLK_a: + return KEY_LEFT; + case SDLK_RIGHT: + case SDLK_l: + case SDLK_d: + return KEY_RIGHT; + case SDLK_0: + return KEY_NUM0; + case SDLK_1: + return KEY_NUM1; + case SDLK_2: + return KEY_NUM2; + case SDLK_3: + return KEY_NUM3; + case SDLK_4: + return KEY_NUM4; + case SDLK_5: + return KEY_NUM5; + case SDLK_6: + return KEY_NUM6; + case SDLK_7: + return KEY_NUM7; + case SDLK_8: + return KEY_NUM8; + case SDLK_9: + return KEY_NUM9; + case SDLK_ESCAPE: + return KEY_ESC; + case SDLK_RETURN: + return KEY_ENTER; + case SDLK_LALT: + case SDLK_RALT: + return KEY_ALT; + case SDLK_LCTRL: + case SDLK_RCTRL: + return KEY_CTRL; + case SDLK_m: + return KEY_M; + default: + return 0; + } +} + +static Uint32 +get_event_mousebutton(SDL_Event *event) +{ + switch (event->button.button) { + case SDL_BUTTON_LEFT: + return MBUTTON_LEFT; + case SDL_BUTTON_MIDDLE: + return MBUTTON_MIDDLE; + case SDL_BUTTON_RIGHT: + return MBUTTON_RIGHT; + default: + return 0; + } +} + +void +input_handle_event(Input *input, SDL_Event *event) +{ + if (event->type == SDL_KEYDOWN) + input->keyState |= get_event_key(event); + else if (event->type == SDL_KEYUP) + input->keyState &= ~get_event_key(event); + else if (event->type == SDL_MOUSEBUTTONDOWN) + input->mouseButtonState |= get_event_mousebutton(event); + else if (event->type == SDL_MOUSEBUTTONUP) + input->mouseButtonState &= ~get_event_mousebutton(event); + else if (event->type == SDL_MOUSEMOTION) { + input->mouseX = event->motion.x; + input->mouseY = event->motion.y; + } +} + +bool +input_key_is_pressed(Input *input, Uint64 key) +{ + return (input->keyState & key) && !(input->lastKeyState & key); +} + +bool +input_key_is_released(Input *input, Uint64 key) +{ + return (input->lastKeyState & key) && !(input->keyState & key); +} + +bool +input_key_is_down(Input *input, Uint64 key) +{ + return input->keyState & key; +} + +bool +input_mousebutton_is_pressed(Input *input, Uint8 button) +{ + return (input->mouseButtonState & button) + && !(input->lastMouseButtonState & button); +} diff --git a/src/keyboardinput.h b/src/input.h similarity index 61% rename from src/keyboardinput.h rename to src/input.h index 0619d36..7b6e4d5 100644 --- a/src/keyboardinput.h +++ b/src/input.h @@ -16,8 +16,8 @@ * along with this program. If not, see . */ -#ifndef KEYBOARDINPUT_H_ -#define KEYBOARDINPUT_H_ +#ifndef INPUT_H_ +#define INPUT_H_ #include #include @@ -36,33 +36,46 @@ #define KEY_NUM7 2048 #define KEY_NUM8 4096 #define KEY_NUM9 8192 +#define KEY_ESC 16384 +#define KEY_ENTER 32768 +#define KEY_CTRL 65536 +#define KEY_ALT 131072 +#define KEY_M 262144 +#define KEY_S 524288 -typedef struct KeyboardState { - bool dir_left; - bool dir_right; - bool dir_up; - bool dir_down; -} KeyboardState; +#define MBUTTON_LEFT 1 +#define MBUTTON_MIDDLE 2 +#define MBUTTON_RIGHT 4 -typedef struct KeyboardInput { - Uint64 currentState; - Uint64 lastState; -} KeyboardInput; +typedef struct Input { + Uint64 keyState; + Uint64 lastKeyState; + Uint32 mouseButtonState; + Uint32 lastMouseButtonState; + Uint32 mouseX; + Uint32 mouseY; +} Input; void -keyboardinput_init(KeyboardInput *); +input_init(Input *); void -keyboardinput_handle_event(KeyboardInput *, SDL_Event*); +input_reset(Input *); + +void +input_handle_event(Input *, SDL_Event*); bool -key_is_pressed(KeyboardInput *, Uint64 key); +input_key_is_pressed(Input *, Uint64 key); bool -key_is_released(KeyboardInput *, Uint64 key); +input_key_is_released(Input *, Uint64 key); bool -key_is_down(KeyboardInput *, Uint64 key); +input_key_is_down(Input *, Uint64 key); -#endif // KEYBOARDINPUT_H_ +bool +input_mousebutton_is_pressed(Input *, Uint8 button); + +#endif // INPUT_H_ diff --git a/src/keyboardinput.c b/src/keyboardinput.c deleted file mode 100644 index c9e2b5b..0000000 --- a/src/keyboardinput.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * BreakHack - A dungeone crawler RPG - * Copyright (C) 2018 Linus Probert - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "keyboardinput.h" -#include "keyboard.h" -#include "vector2d.h" - -void -keyboardinput_init(KeyboardInput *input) -{ - input->currentState = 0; - input->lastState = 0; -} - -void -keyboardinput_handle_event(KeyboardInput *input, SDL_Event *event) -{ - if (keyboard_direction_press(UP, event)) { - input->currentState |= KEY_UP; - } else if (keyboard_direction_press(DOWN, event)) { - input->currentState |= KEY_DOWN; - } else if (keyboard_direction_press(LEFT, event)) { - input->currentState |= KEY_LEFT; - } else if (keyboard_direction_press(RIGHT, event)) { - input->currentState |= KEY_RIGHT; - } else if (keyboard_press(SDLK_0, event)) { - input->currentState |= KEY_NUM1; - } - for (int i = SDLK_0; i <= SDLK_9; ++i) { - if (keyboard_press(i, event)) - input->currentState |= (KEY_NUM0 << (i - SDLK_0)); - } - - if (keyboard_direction_release(UP, event)) { - input->currentState &= ~KEY_UP; - } else if (keyboard_direction_release(DOWN, event)) { - input->currentState &= ~KEY_DOWN; - } else if (keyboard_direction_release(LEFT, event)) { - input->currentState &= ~KEY_LEFT; - } else if (keyboard_direction_release(RIGHT, event)) { - input->currentState &= ~KEY_RIGHT; - } else if (keyboard_release(SDLK_0, event)) { - input->currentState &= ~KEY_NUM1; - } - for (int i = SDLK_0; i <= SDLK_9; ++i) { - if (keyboard_release(i, event)) - input->currentState &= ~(KEY_NUM0 << (i - SDLK_0)); - } -} - -bool -key_is_pressed(KeyboardInput *input, Uint64 key) -{ - return (input->currentState & key) && !(input->lastState & key); -} - -bool -key_is_released(KeyboardInput *input, Uint64 key) -{ - return (input->lastState & key) && !(input->currentState & key); -} - -bool -key_is_down(KeyboardInput *input, Uint64 key) -{ - return input->currentState & key; -} - diff --git a/src/main.c b/src/main.c index ab00089..ad2a26d 100644 --- a/src/main.c +++ b/src/main.c @@ -48,6 +48,7 @@ #include "update_data.h" #include "settings.h" #include "actiontextbuilder.h" +#include "input.h" typedef enum Turn_t { PLAYER, @@ -61,7 +62,6 @@ static Map *gMap = NULL; static RoomMatrix *gRoomMatrix = NULL; static Gui *gGui = NULL; static SkillBar *gSkillBar = NULL; -static Pointer *gPointer = NULL; static unsigned int cLevel = 1; static float deltaTime = 1.0; static double renderScale = 1.0; @@ -76,6 +76,7 @@ static SDL_Rect bottomGuiViewport; static SDL_Rect rightGuiViewport; static SDL_Rect menuViewport; static Turn currentTurn = PLAYER; +static Input input; static SDL_Color C_MENU_DEFAULT = { 255, 255, 0, 255 }; static SDL_Color C_MENU_OUTLINE_DEFAULT = { 0, 0, 0, 255 }; @@ -189,13 +190,13 @@ static bool initGame(void) { initViewports(); + input_init(&input); texturecache_init(gRenderer); gCamera = camera_create(gRenderer); gRoomMatrix = roommatrix_create(); gGui = gui_create(gCamera); gSkillBar = skillbar_create(gRenderer); item_builder_init(gRenderer); - gPointer = pointer_create(gRenderer); particle_engine_init(); menuTimer = timer_create(); actiontextbuilder_init(gRenderer); @@ -360,19 +361,20 @@ init(void) } static bool -handle_main_events(SDL_Event *event) +handle_main_input(void) { if (gGameState == PLAYING || gGameState == IN_GAME_MENU || gGameState == GAME_OVER) { - if (keyboard_press(SDLK_ESCAPE, event)) { + if (input_key_is_pressed(&input, KEY_ESC)) { toggleInGameMenu(NULL); return true; } } - if (keyboard_mod_press(SDLK_m, KMOD_CTRL, event)) { + if (input_key_is_down(&input, KEY_CTRL) + && input_key_is_pressed(&input, SDLK_m)) { if (mixer_toggle_music(&gGameState)) gui_log("Music enabled"); else @@ -380,7 +382,8 @@ handle_main_events(SDL_Event *event) return true; } - if (keyboard_mod_press(SDLK_s, KMOD_CTRL, event)) { + if (input_key_is_down(&input, KEY_CTRL) + && input_key_is_pressed(&input, SDLK_s)) { if (mixer_toggle_sound()) gui_log("Sound enabled"); else @@ -398,31 +401,17 @@ handle_events(void) bool quit = false; int handleCount = 0; + input_reset(&input); while (SDL_PollEvent(&event) != 0) { if (event.type == SDL_QUIT) { quit = true; continue; } - if (handle_main_events(&event)) - continue; - - if (gGameState == PLAYING) { - if (currentTurn == PLAYER && !player_turn_over(gPlayer)) - gPlayer->handle_event(gPlayer, - gRoomMatrix, - &event); - roommatrix_handle_event(gRoomMatrix, &event); - skillbar_handle_event(gSkillBar, &event); - } else if (gGameState == MENU) { - menu_handle_event(mainMenu, &event); - } else if (gGameState == IN_GAME_MENU) { - menu_handle_event(inGameMenu, &event); - } - pointer_handle_event(gPointer, &event); + input_handle_event(&input, &event); handleCount++; - if (handleCount >= 5) { + if (handleCount >= 20) { debug("Flushing event queue"); SDL_PumpEvents(); SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT); @@ -467,6 +456,7 @@ populateUpdateData(UpdateData *data, float deltatime) data->player = gPlayer; data->map = gMap; data->matrix = gRoomMatrix; + data->input = &input; data->deltatime = deltatime; } @@ -476,6 +466,11 @@ run_game(void) static UpdateData updateData; static unsigned int playerLevel = 1; + if (gGameState == IN_GAME_MENU) + menu_update(inGameMenu, &input); + if (gGameState != PLAYING && gGameState != IN_GAME_MENU) + return; + map_clear_dead_monsters(gMap, gPlayer); map_clear_collected_items(gMap); roommatrix_populate_from_map(gRoomMatrix, gMap); @@ -489,17 +484,20 @@ run_game(void) playerLevel = gPlayer->stats.lvl; skillbar_check_skill_activation(gSkillBar, gPlayer); } + + if (gGameState == PLAYING && currentTurn == PLAYER) + player_update(&updateData); + gui_update_player_stats(gGui, gPlayer, gMap, gRenderer); camera_update(gCamera, updateData.deltatime); particle_engine_update(deltaTime); - + roommatrix_update(&updateData); actiontextbuilder_update(&updateData); - player_update(&updateData); + skillbar_update(gSkillBar, &updateData); camera_follow_position(gCamera, &gPlayer->sprite->pos); map_set_current_room(gMap, &gPlayer->sprite->pos); map_update(&updateData); - roommatrix_update_with_player(gRoomMatrix, gPlayer); if (currentTurn == PLAYER) { if (player_turn_over(gPlayer)) { currentTurn = MONSTER; @@ -541,16 +539,13 @@ run_game(void) SDL_RenderSetViewport(gRenderer, NULL); particle_engine_render_global(gCamera); + if (gGameState == IN_GAME_MENU) { SDL_Rect dimmer = { 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT }; SDL_SetRenderDrawColor(gRenderer, 0, 0, 0, 150); SDL_RenderFillRect(gRenderer, &dimmer); menu_render(inGameMenu, gCamera); } - if (gGameState == GAME_OVER) { - // TODO(Linus): Render game over? - } - pointer_render(gPointer, gCamera); SDL_RenderPresent(gRenderer); @@ -579,6 +574,10 @@ run_menu(void) map_move_monsters(gMap, gRoomMatrix); } + menu_update(mainMenu, &input); + if (gGameState != MENU) + return; + SDL_SetRenderDrawColor(gRenderer, 0, 0, 0, 0); SDL_RenderClear(gRenderer); SDL_RenderSetViewport(gRenderer, &menuViewport); @@ -587,7 +586,6 @@ run_menu(void) SDL_RenderSetViewport(gRenderer, NULL); menu_render(mainMenu, gCamera); - pointer_render(gPointer, gCamera); SDL_RenderPresent(gRenderer); } @@ -606,6 +604,7 @@ void run(void) timer_start(fpsTimer); quit = handle_events(); + handle_main_input(); switch (gGameState) { case PLAYING: @@ -656,7 +655,6 @@ void close(void) roommatrix_destroy(gRoomMatrix); gui_destroy(gGui); skillbar_destroy(gSkillBar); - pointer_destroy(gPointer); actiontextbuilder_close(); item_builder_close(); particle_engine_close(); diff --git a/src/map.h b/src/map.h index ca141da..54de725 100644 --- a/src/map.h +++ b/src/map.h @@ -32,7 +32,7 @@ #include "player.h" #include "map_room_modifiers.h" -struct UpdateData_t; +struct UpdateData; typedef struct MapTile_t { int textureIndex0; @@ -89,7 +89,7 @@ void map_clear_collected_items(Map*); void -map_update(struct UpdateData_t*); +map_update(struct UpdateData*); void map_render(Map*, Camera*); diff --git a/src/menu.c b/src/menu.c index d8398e2..209d2d0 100644 --- a/src/menu.c +++ b/src/menu.c @@ -42,17 +42,17 @@ menu_create(void) } static void -handle_keyboard_event(Menu *m, SDL_Event *event) +handle_keyboard_input(Menu *m, Input *input) { int lastSelect = -1; - if (keyboard_direction_press(UP, event)) { + if (input_key_is_pressed(input, KEY_UP)) { lastSelect = m->selected; m->selected--; - } else if (keyboard_direction_press(DOWN, event)) { + } else if (input_key_is_pressed(input, KEY_DOWN)) { lastSelect = m->selected; m->selected++; - } else if (keyboard_press(SDLK_RETURN, event)) { + } else if (input_key_is_pressed(input, KEY_ENTER)) { MenuItem *item = linkedlist_get(&m->items, m->selected); if (item->button->event) item->button->event(item->button->usrdata); @@ -69,55 +69,10 @@ handle_keyboard_event(Menu *m, SDL_Event *event) ((MenuItem*) linkedlist_get(&m->items, m->selected))->button->hover = true; } -static void -handle_mouse_motion_event(Menu *m, SDL_Event *event) -{ - LinkedList *items; - int current_select; - bool activeItemFound = false; - - items = m->items; - current_select = 0; - while (items) { - MenuItem *item = items->data; - items = items->next; - - item->button->hover = false; - gui_button_handle_event(item->button, event); - if (item->button->hover) { - if (current_select != m->selected) { - mixer_play_effect(CLICK); - m->selected = current_select; - } - activeItemFound = true; - } - current_select++; - } - - if (!activeItemFound) - ((MenuItem*) linkedlist_get(&m->items, m->selected))->button->hover = true; -} - -static void -handle_mouse_button_event(Menu *m, SDL_Event *event) -{ - /* NOTE: In some cases the button/item is destroyed by the click action - * make sure you don't 'use' items after a click event has fired. It - * might break. */ - - MenuItem *item = linkedlist_get(&m->items, m->selected); - gui_button_handle_event(item->button, event); -} - void -menu_handle_event(Menu *m, SDL_Event *event) +menu_update(Menu *m, Input *input) { - if (event->type == SDL_KEYDOWN) - handle_keyboard_event(m, event); - else if (event->type == SDL_MOUSEMOTION) - handle_mouse_motion_event(m, event); - else if (event->type == SDL_MOUSEBUTTONDOWN) - handle_mouse_button_event(m, event); + handle_keyboard_input(m, input); } void diff --git a/src/menu.h b/src/menu.h index a4af9c8..f4a572e 100644 --- a/src/menu.h +++ b/src/menu.h @@ -34,7 +34,7 @@ Menu * menu_create(void); void -menu_handle_event(Menu*, SDL_Event*); +menu_update(Menu*, Input*); void menu_item_add(Menu*, Sprite*, Sprite*, void (*)(void*)); diff --git a/src/monster.h b/src/monster.h index 7df48ad..64eef50 100644 --- a/src/monster.h +++ b/src/monster.h @@ -26,7 +26,7 @@ #include "player.h" #include "linkedlist.h" -struct UpdateData_t; +struct UpdateData; typedef enum { PACIFIST, @@ -83,13 +83,13 @@ void monster_update_stats_for_level(Monster*, unsigned int level); void -monster_update(Monster*, struct UpdateData_t*); +monster_update(Monster*, struct UpdateData*); void monster_drop_loot(Monster*, Map*, Player*); void -monster_set_behaviour(Monster *, MonsterBehaviour m); +monster_set_behaviour(Monster *, MonsterBehaviour behaviour); void monster_destroy(Monster*); diff --git a/src/player.c b/src/player.c index 9ac075c..52f65a0 100644 --- a/src/player.c +++ b/src/player.c @@ -208,22 +208,39 @@ player_sip_health(Player *player) } } +static Vector2d +read_direction_from(Input *input) +{ + if (input_key_is_pressed(input, KEY_LEFT)) + return VECTOR2D_LEFT; + else if (input_key_is_pressed(input, KEY_RIGHT)) + return VECTOR2D_RIGHT; + else if (input_key_is_pressed(input, KEY_UP)) + return VECTOR2D_UP; + else if (input_key_is_pressed(input, KEY_DOWN)) + return VECTOR2D_DOWN; + else + return VECTOR2D_NODIR; +} + static void -handle_next_move(Player *player, RoomMatrix *matrix) +handle_next_move(UpdateData *data) { static unsigned int step = 1; - if (!vector2d_equals(player->nextDirection, VECTOR2D_NODIR)) - move(player, matrix, player->nextDirection); - map_room_modifier_player_effect(player, matrix, &player->nextDirection, move); + Player *player = data->player; + RoomMatrix *matrix = data->matrix; + Vector2d nextDir = read_direction_from(data->input); + if (!vector2d_equals(nextDir, VECTOR2D_NODIR)) + move(player, matrix, nextDir); - if (!vector2d_equals(VECTOR2D_NODIR, player->nextDirection)) { + map_room_modifier_player_effect(player, matrix, &nextDir, move); + + if (!vector2d_equals(VECTOR2D_NODIR, nextDir)) { player->sprite->clip.x = 16*step; ++step; step = step % 4; } - - player->nextDirection = VECTOR2D_NODIR; } static void @@ -237,19 +254,23 @@ use_skill(Skill *skill, SkillData *skillData) } static void -check_skill_activation(Player *player, RoomMatrix *matrix, SDL_Event *event) +check_skill_activation(UpdateData *data) { // TODO(Linus): This could be "smarter" + Player *player = data->player; + Input *input = data->input; + RoomMatrix *matrix = data->matrix; + unsigned int selected = 0; - if (keyboard_press(SDLK_1, event)) { + if (input_key_is_pressed(input, KEY_NUM1)) { selected = 1; - } else if (keyboard_press(SDLK_2, event)) { + } else if (input_key_is_pressed(input, KEY_NUM2)) { selected = 2; - } else if (keyboard_press(SDLK_3, event)) { + } else if (input_key_is_pressed(input, KEY_NUM3)) { selected = 3; - } else if (keyboard_press(SDLK_4, event)) { + } else if (input_key_is_pressed(input, KEY_NUM4)) { selected = 4; - } else if (keyboard_press(SDLK_5, event)) { + } else if (input_key_is_pressed(input, KEY_NUM5)) { selected = 5; } @@ -273,9 +294,13 @@ check_skill_activation(Player *player, RoomMatrix *matrix, SDL_Event *event) } } -static void -check_skill_trigger(Player *player, RoomMatrix *matrix) +static bool +check_skill_trigger(UpdateData *data) { + Player *player = data->player; + RoomMatrix *matrix = data->matrix; + Input *input = data->input; + int activeSkill = -1; for (int i = 0; i < PLAYER_SKILL_COUNT; ++i) { if (player->skills[i] && player->skills[i]->active) { @@ -285,48 +310,16 @@ check_skill_trigger(Player *player, RoomMatrix *matrix) } if (activeSkill < 0) - return; + return false; + Vector2d nextDir = read_direction_from(input); + if (vector2d_equals(nextDir, VECTOR2D_NODIR)) + return false; - if (vector2d_equals(player->nextDirection, VECTOR2D_NODIR)) - return; - - SkillData skillData = { player, matrix, player->nextDirection }; + SkillData skillData = { player, matrix, nextDir }; use_skill(player->skills[activeSkill], &skillData); - player->nextDirection = VECTOR2D_NODIR; -} - -static void -read_player_next_direction(Player *player, SDL_Event *event) -{ - player->nextDirection = VECTOR2D_NODIR; - - if (keyboard_direction_press(LEFT, event)) - player->nextDirection = VECTOR2D_LEFT; - if (keyboard_direction_press(RIGHT, event)) - player->nextDirection = VECTOR2D_RIGHT; - if (keyboard_direction_press(UP, event)) - player->nextDirection = VECTOR2D_UP; - if (keyboard_direction_press(DOWN, event)) - player->nextDirection = VECTOR2D_DOWN; -} - - -static void -handle_player_input(Player *player, RoomMatrix *matrix, SDL_Event *event) -{ - if (player->state != ALIVE) - return; - - if (event->type != SDL_KEYDOWN) - return; - - if (player->projectiles) - return; - - check_skill_activation(player, matrix, event); - read_player_next_direction(player, event); + return true; } Player* @@ -347,7 +340,6 @@ player_create(class_t class, SDL_Renderer *renderer) player->state = ALIVE; player->projectiles = linkedlist_create(); player->animationTimer = timer_create(); - player->nextDirection = VECTOR2D_NODIR; for (size_t i = 0; i < PLAYER_SKILL_COUNT; ++i) { player->skills[i] = NULL; @@ -386,7 +378,6 @@ player_create(class_t class, SDL_Renderer *renderer) player->sprite->pos = (Position) { TILE_DIMENSION, TILE_DIMENSION }; player->sprite->dim = GAME_DIMENSION; player->sprite->clip = (SDL_Rect) { 0, 0, 16, 16 }; - player->handle_event = &handle_player_input; return player; } @@ -465,8 +456,9 @@ void player_update(UpdateData *data) { Player *player = data->player; - check_skill_trigger(player, data->matrix); - handle_next_move(player, data->matrix); + check_skill_activation(data); + if (!check_skill_trigger(data)) + handle_next_move(data); if (player->state == FALLING && player->stats.hp > 0) { if (!timer_started(player->animationTimer)) { diff --git a/src/player.h b/src/player.h index f866b29..352fc3d 100644 --- a/src/player.h +++ b/src/player.h @@ -26,11 +26,12 @@ #include "camera.h" #include "skill.h" #include "linkedlist.h" +#include "input.h" #define PLAYER_SKILL_COUNT 5 // Foward declare -struct UpdateData_t; +struct UpdateData; typedef enum PlayerClass { ENGINEER, MAGE, PALADIN, ROGUE, WARRIOR } class_t; typedef enum PlayerState { ALIVE, DEAD, FALLING } state_t; @@ -63,8 +64,6 @@ typedef struct Player_t { state_t state; Skill *skills[PLAYER_SKILL_COUNT]; Timer *animationTimer; - Vector2d nextDirection; - void (*handle_event)(struct Player_t*, RoomMatrix*, SDL_Event*); } Player; Player* @@ -86,7 +85,7 @@ void player_reset_steps(Player*); void -player_update(struct UpdateData_t *); +player_update(struct UpdateData *); void player_render(Player*, Camera*); diff --git a/src/pointer.c b/src/pointer.c index a523afd..c2262d0 100644 --- a/src/pointer.c +++ b/src/pointer.c @@ -38,13 +38,11 @@ pointer_create(SDL_Renderer *renderer) } void -pointer_handle_event(Pointer *p, SDL_Event *event) +pointer_handle_input(Pointer *p, Input *input) { - if (event->type == SDL_MOUSEMOTION) { - // Compensate for a small offset in the sprite - p->sprite->pos.x = event->motion.x - 6; - p->sprite->pos.y = event->motion.y - 6; - } + // Compensate for a small offset in the sprite + p->sprite->pos.x = input->mouseX - 6; + p->sprite->pos.y = input->mouseY - 6; } void diff --git a/src/pointer.h b/src/pointer.h index 7848dcb..8d97184 100644 --- a/src/pointer.h +++ b/src/pointer.h @@ -22,6 +22,7 @@ #include #include "sprite.h" #include "camera.h" +#include "input.h" typedef struct Pointer_t { Sprite *sprite; @@ -31,7 +32,7 @@ Pointer * pointer_create(SDL_Renderer *renderer); void -pointer_handle_event(Pointer*, SDL_Event *event); +pointer_handle_input(Pointer*, Input *); void pointer_toggle_clickable_pointer(Pointer *, bool clickable); diff --git a/src/roommatrix.c b/src/roommatrix.c index 0ab2090..e706d63 100644 --- a/src/roommatrix.c +++ b/src/roommatrix.c @@ -23,6 +23,7 @@ #include "map.h" #include "player.h" #include "item.h" +#include "update_data.h" RoomMatrix* roommatrix_create(void) { @@ -37,18 +38,28 @@ RoomMatrix* roommatrix_create(void) return m; } -void -roommatrix_handle_event(RoomMatrix *matrix, SDL_Event *event) +static void +roommatrix_update_with_player(RoomMatrix *rm, Player *p) { - if (event->type != SDL_MOUSEMOTION) - return; + Position rp = position_to_matrix_coords(&p->sprite->pos); + rm->spaces[rp.x][rp.y].occupied = true; + rm->spaces[rp.x][rp.y].player = p; + rm->playerRoomPos = rp; +} - if (event->motion.x < GAME_VIEW_WIDTH - && event->motion.y < GAME_VIEW_HEIGHT) +void +roommatrix_update(UpdateData *data) +{ + RoomMatrix *matrix = data->matrix; + Input *input = data->input; + + if (input->mouseX < GAME_VIEW_WIDTH + && input->mouseY < GAME_VIEW_HEIGHT) { - matrix->mousePos.x = event->motion.x; - matrix->mousePos.y = event->motion.y; + matrix->mousePos.x = input->mouseX; + matrix->mousePos.y = input->mouseY; } + roommatrix_update_with_player(matrix, data->player); } void roommatrix_populate_from_map(RoomMatrix *rm, Map *m) @@ -136,15 +147,6 @@ max(int a, int b) } #endif // max -void -roommatrix_update_with_player(RoomMatrix *rm, Player *p) -{ - Position rp = position_to_matrix_coords(&p->sprite->pos); - rm->spaces[rp.x][rp.y].occupied = true; - rm->spaces[rp.x][rp.y].player = p; - rm->playerRoomPos = rp; -} - void roommatrix_add_lightsource(RoomMatrix *matrix, Position *pos) { diff --git a/src/roommatrix.h b/src/roommatrix.h index 68e53ee..1cdbe22 100644 --- a/src/roommatrix.h +++ b/src/roommatrix.h @@ -24,6 +24,7 @@ #include "position.h" #include "camera.h" #include "map_room_modifiers.h" +#include "input.h" typedef struct Sprite_t Sprite; typedef struct Map_t Map; @@ -32,6 +33,8 @@ typedef struct Player_t Player; typedef struct Item_t Item; typedef struct Node LinkedList; +struct UpdateData; + typedef struct { bool occupied; bool lethal; @@ -52,12 +55,10 @@ typedef struct RoomMatrix_t { RoomMatrix* roommatrix_create(void); -void roommatrix_handle_event(RoomMatrix*, SDL_Event*); +void roommatrix_update(struct UpdateData*); void roommatrix_populate_from_map(RoomMatrix*, Map*); -void roommatrix_update_with_player(RoomMatrix*, Player*); - void roommatrix_add_lightsource(RoomMatrix*, Position*); void roommatrix_build_lightmap(RoomMatrix*); diff --git a/src/skillbar.c b/src/skillbar.c index c32f692..86c1d86 100644 --- a/src/skillbar.c +++ b/src/skillbar.c @@ -25,6 +25,7 @@ #include "keyboard.h" #include "texturecache.h" #include "particle_engine.h" +#include "update_data.h" static void load_texture(SkillBar *bar, const char *path, SDL_Renderer *renderer) @@ -250,17 +251,15 @@ skillbar_render(SkillBar *bar, Player *player, Camera *cam) } void -skillbar_handle_event(SkillBar *bar, SDL_Event *event) +skillbar_update(SkillBar *bar, UpdateData *data) { - if (event->type != SDL_KEYDOWN) - return; + Input *input = data->input; unsigned int key = 0; - for (SDL_Keycode keysym = SDLK_0; keysym <= SDLK_9; ++keysym) { - if (!keyboard_press(keysym, event)) + for (int i = 0; i < 10; ++i) { + if (!input_key_is_pressed(input, KEY_NUM0 << i)) continue; - key = (int)(keysym - SDLK_0); - if (key == 0) key = 10; + key = i; break; } diff --git a/src/skillbar.h b/src/skillbar.h index 103a9ce..89aaef4 100644 --- a/src/skillbar.h +++ b/src/skillbar.h @@ -24,6 +24,9 @@ #include "camera.h" #include "timer.h" #include "player.h" +#include "input.h" + +struct UpdateData; typedef struct SkillBar_t { LinkedList *sprites; @@ -43,7 +46,7 @@ void skillbar_render(SkillBar*, Player*, Camera*); void -skillbar_handle_event(SkillBar*, SDL_Event*); +skillbar_update(SkillBar*, struct UpdateData*); void skillbar_destroy(SkillBar*); diff --git a/src/update_data.h b/src/update_data.h index a39d112..c3a5164 100644 --- a/src/update_data.h +++ b/src/update_data.h @@ -23,10 +23,11 @@ #include "map.h" #include "roommatrix.h" -typedef struct UpdateData_t { +typedef struct UpdateData { Player *player; Map *map; RoomMatrix *matrix; + Input *input; float deltatime; } UpdateData; diff --git a/test/test_input.c b/test/test_input.c new file mode 100644 index 0000000..3c79d99 --- /dev/null +++ b/test/test_input.c @@ -0,0 +1,126 @@ +/* + * BreakHack - A dungeone crawler RPG + * Copyright (C) 2018 Linus Probert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include "../src/input.h" + +static void +test_event_parse(void **state) +{ + (void) state; + Input input; + input_init(&input); + + SDL_KeyboardEvent event; + event.type = SDL_KEYDOWN; + event.keysym = (SDL_Keysym) { SDL_SCANCODE_W, SDLK_w, KMOD_NONE, 0 }; + + input_handle_event(&input, (SDL_Event*) &event); + event.keysym = (SDL_Keysym) { SDL_SCANCODE_0, SDLK_0, KMOD_NONE, 0 }; + input_handle_event(&input, (SDL_Event*) &event); + + assert_true(input_key_is_pressed(&input, KEY_UP)); + assert_true(input_key_is_pressed(&input, KEY_NUM0)); + + event.type = SDL_KEYUP; + event.keysym = (SDL_Keysym) { SDL_SCANCODE_0, SDLK_0, KMOD_NONE, 0 }; + input_handle_event(&input, (SDL_Event*) &event); + + assert_true(input_key_is_pressed(&input, KEY_UP)); + assert_true(!input_key_is_pressed(&input, KEY_NUM0)); + + input_reset(&input); + + assert_true(input_key_is_released(&input, KEY_UP)); + assert_true(!input_key_is_released(&input, KEY_NUM0)); +} + +static void +test_keypress(void **state) +{ + (void) state; + Input input; + input_init(&input); + input.lastKeyState = 0; + input.keyState = KEY_UP; + assert_true(input_key_is_pressed(&input, KEY_UP)); +} + +static void +test_keyrelease(void **state) +{ + (void) state; + Input input; + input_init(&input); + input.lastKeyState = KEY_UP; + input.keyState = 0; + assert_true(input_key_is_released(&input, KEY_UP)); +} + +static void +test_keydown(void **state) +{ + (void) state; + Input input; + input_init(&input); + input.keyState = KEY_UP; + assert_true(input_key_is_down(&input, KEY_UP)); +} + +static void +test_mousebuttons(void **state) +{ + (void) state; + Input input; + input_init(&input); + + SDL_MouseButtonEvent event; + event.type = SDL_MOUSEBUTTONDOWN; + event.button = SDL_BUTTON_LEFT; + input_handle_event(&input, (SDL_Event*) &event); + + assert_true(input_mousebutton_is_pressed(&input, MBUTTON_LEFT)); + + input_reset(&input); + event.button = SDL_BUTTON_RIGHT; + input_handle_event(&input, (SDL_Event*) &event); + + assert_true(!input_mousebutton_is_pressed(&input, MBUTTON_LEFT)); + assert_true(input_mousebutton_is_pressed(&input, MBUTTON_RIGHT)); +} + +int main(int argc, char *argv[]) +{ + (void) argc; + (void) argv; + + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_keypress), + cmocka_unit_test(test_keyrelease), + cmocka_unit_test(test_keydown), + cmocka_unit_test(test_event_parse), + cmocka_unit_test(test_mousebuttons), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/test/test_keyboardinput.c b/test/test_keyboardinput.c deleted file mode 100644 index 2341921..0000000 --- a/test/test_keyboardinput.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * BreakHack - A dungeone crawler RPG - * Copyright (C) 2018 Linus Probert - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include "../src/keyboardinput.h" -#include "../src/keyboard.h" - - -bool __wrap_keyboard_direction_press(Direction, SDL_Event*); -bool __wrap_keyboard_press(Uint64, SDL_Event*); - -bool -__wrap_keyboard_direction_press(Direction d, SDL_Event *event) -{ - (void) d; - (void) event; - return mock_type(bool); -} - -bool -__wrap_keyboard_press(Uint64 key, SDL_Event *event) -{ - (void) key; - (void) event; - return mock_type(bool); -} - -static void -test_event_parse(void **state) -{ - (void) state; - KeyboardInput input = { 0, 0 }; - - will_return(__wrap_keyboard_direction_press, true); // KEY_UP - will_return(__wrap_keyboard_press, true); // NUM0 - will_return(__wrap_keyboard_press, false); // NUM1 - will_return(__wrap_keyboard_press, false); // NUM2 - will_return(__wrap_keyboard_press, false); // NUM3 - will_return(__wrap_keyboard_press, false); // NUM4 - will_return(__wrap_keyboard_press, false); // NUM5 - will_return(__wrap_keyboard_press, false); // NUM6 - will_return(__wrap_keyboard_press, false); // NUM7 - will_return(__wrap_keyboard_press, false); // NUM8 - will_return(__wrap_keyboard_press, false); // NUM9 - - SDL_Event event; - keyboardinput_handle_event(&input, &event); - - assert_true(key_is_pressed(&input, KEY_UP)); - assert_true(key_is_pressed(&input, KEY_NUM0)); -} - -static void -test_keypress(void **state) -{ - (void) state; - KeyboardInput input = { 0, 0 }; - input.lastState = 0; - input.currentState = KEY_UP; - assert_true(key_is_pressed(&input, KEY_UP)); -} - -static void -test_keyrelease(void **state) -{ - (void) state; - KeyboardInput input = { 0, 0 }; - input.lastState = KEY_UP; - input.currentState = 0; - assert_true(key_is_released(&input, KEY_UP)); -} - -static void -test_keydown(void **state) -{ - (void) state; - KeyboardInput input = { 0, 0 }; - input.currentState = KEY_UP; - assert_true(key_is_down(&input, KEY_UP)); -} - -int main(int argc, char *argv[]) -{ - (void) argc; - (void) argv; - - const struct CMUnitTest tests[] = { - cmocka_unit_test(test_keypress), - cmocka_unit_test(test_keyrelease), - cmocka_unit_test(test_keydown), - cmocka_unit_test(test_event_parse), - }; - - return cmocka_run_group_tests(tests, NULL, NULL); -}