diff --git a/CMakeLists.txt b/CMakeLists.txt index 49f099b..d1f33e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -153,6 +153,7 @@ add_executable(breakhack src/menu src/collisions src/keyboard + src/keyboardinput src/mixer src/io_util src/physfsrwops @@ -215,6 +216,10 @@ IF (CMOCKA_FOUND) add_executable(test_hashtable test/test_hashtable src/hashtable src/util) target_link_libraries(test_hashtable ${CMOCKA_LIBRARY} ${CMAKE_THREAD_LIBS_INIT}) add_test(test_hashtable test_hashtable) + + add_executable(test_keyboardinput test/test_keyboardinput src/keyboardinput src/keyboard) + target_link_libraries(test_keyboardinput ${CMOCKA_LIBRARY} ${CMAKE_THREAD_LIBS_INIT}) + add_test(test_keyboardinput test_keyboardinput) ENDIF (CMOCKA_FOUND ) # LINT: diff --git a/src/keyboard.c b/src/keyboard.c index 3c626d2..b670003 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -19,12 +19,9 @@ #include "keyboard.h" #include "util.h" -bool -keyboard_direction_press(Direction dir, SDL_Event *event) +static bool +extract_key(Direction dir, SDL_Event *event) { - if (event->type != SDL_KEYDOWN) - return false; - Uint32 key = event->key.keysym.sym; switch (dir) { case UP: @@ -48,6 +45,24 @@ keyboard_direction_press(Direction dir, SDL_Event *event) } } +bool +keyboard_direction_press(Direction dir, SDL_Event *event) +{ + if (event->type != SDL_KEYDOWN) + return false; + + return extract_key(dir, event); +} + +bool +keyboard_direction_release(Direction dir, SDL_Event *event) +{ + if (event->type != SDL_KEYUP) + return false; + + return extract_key(dir, event); +} + bool keyboard_press(Uint32 key, SDL_Event *event) { @@ -57,6 +72,15 @@ keyboard_press(Uint32 key, SDL_Event *event) return key == (Uint32) event->key.keysym.sym; } +bool +keyboard_release(Uint32 key, SDL_Event *event) +{ + if (event->type != SDL_KEYUP) + return false; + + return key == (Uint32) event->key.keysym.sym; +} + bool keyboard_mod_press(Uint32 key, Uint32 mod, SDL_Event *event) { diff --git a/src/keyboard.h b/src/keyboard.h index 9de73eb..fd61375 100644 --- a/src/keyboard.h +++ b/src/keyboard.h @@ -26,9 +26,15 @@ bool keyboard_direction_press(Direction, SDL_Event*); +bool +keyboard_direction_release(Direction, SDL_Event*); + bool keyboard_press(Uint32 key, SDL_Event*); +bool +keyboard_release(Uint32 key, SDL_Event*); + bool keyboard_mod_press(Uint32 key, Uint32 mod, SDL_Event*); diff --git a/src/keyboardinput.c b/src/keyboardinput.c new file mode 100644 index 0000000..9eeaeaa --- /dev/null +++ b/src/keyboardinput.c @@ -0,0 +1,83 @@ +/* + * 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 |= (1 << i); + } + + 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 &= ~(1 << i); + } +} + +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/keyboardinput.h b/src/keyboardinput.h new file mode 100644 index 0000000..0619d36 --- /dev/null +++ b/src/keyboardinput.h @@ -0,0 +1,68 @@ +/* + * 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 . + */ + +#ifndef KEYBOARDINPUT_H_ +#define KEYBOARDINPUT_H_ + +#include +#include + +#define KEY_LEFT 1 +#define KEY_RIGHT 2 +#define KEY_UP 4 +#define KEY_DOWN 8 +#define KEY_NUM0 16 +#define KEY_NUM1 32 +#define KEY_NUM2 64 +#define KEY_NUM3 128 +#define KEY_NUM4 256 +#define KEY_NUM5 512 +#define KEY_NUM6 1024 +#define KEY_NUM7 2048 +#define KEY_NUM8 4096 +#define KEY_NUM9 8192 + +typedef struct KeyboardState { + bool dir_left; + bool dir_right; + bool dir_up; + bool dir_down; +} KeyboardState; + +typedef struct KeyboardInput { + Uint64 currentState; + Uint64 lastState; +} KeyboardInput; + +void +keyboardinput_init(KeyboardInput *); + +void +keyboardinput_handle_event(KeyboardInput *, SDL_Event*); + +bool +key_is_pressed(KeyboardInput *, Uint64 key); + +bool +key_is_released(KeyboardInput *, Uint64 key); + +bool +key_is_down(KeyboardInput *, Uint64 key); + +#endif // KEYBOARDINPUT_H_ + diff --git a/src/main.c b/src/main.c index 5085992..ab00089 100644 --- a/src/main.c +++ b/src/main.c @@ -412,8 +412,6 @@ handle_events(void) gPlayer->handle_event(gPlayer, gRoomMatrix, &event); - camera_follow_position(gCamera, &gPlayer->sprite->pos); - map_set_current_room(gMap, &gPlayer->sprite->pos); roommatrix_handle_event(gRoomMatrix, &event); skillbar_handle_event(gSkillBar, &event); } else if (gGameState == MENU) { @@ -496,8 +494,10 @@ run_game(void) particle_engine_update(deltaTime); actiontextbuilder_update(&updateData); - map_update(&updateData); player_update(&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) { diff --git a/src/monster.c b/src/monster.c index 23b3967..28627de 100644 --- a/src/monster.c +++ b/src/monster.c @@ -401,6 +401,9 @@ monster_drop_loot(Monster *monster, Map *map, Player *player) void monster_render(Monster *m, Camera *cam) { + if (m->stats.hp <= 0) + return; + sprite_render(m->sprite, cam); if (m->stateIndicator.displayCount > 0) sprite_render(m->stateIndicator.sprite, cam); diff --git a/src/player.c b/src/player.c index 3ce629e..9ac075c 100644 --- a/src/player.c +++ b/src/player.c @@ -209,41 +209,21 @@ player_sip_health(Player *player) } static void -handle_movement_input(Player *player, RoomMatrix *matrix, SDL_Event *event) +handle_next_move(Player *player, RoomMatrix *matrix) { static unsigned int step = 1; - Vector2d direction = VECTOR2D_NODIR; + if (!vector2d_equals(player->nextDirection, VECTOR2D_NODIR)) + move(player, matrix, player->nextDirection); - if (keyboard_direction_press(LEFT, event)) - direction = VECTOR2D_LEFT; - if (keyboard_direction_press(RIGHT, event)) - direction = VECTOR2D_RIGHT; - if (keyboard_direction_press(UP, event)) - direction = VECTOR2D_UP; - if (keyboard_direction_press(DOWN, event)) - direction = VECTOR2D_DOWN; + map_room_modifier_player_effect(player, matrix, &player->nextDirection, move); - if (!vector2d_equals(direction, VECTOR2D_NODIR)) - move(player, matrix, direction); - - map_room_modifier_player_effect(player, matrix, &direction, move); - - -#ifdef DEBUG - if (keyboard_mod_press(SDLK_SPACE, KMOD_CTRL, event)) { - Position pos = player->sprite->pos; - pos.x += 8; - pos.y += 8; - particle_engine_bloodspray(pos, (Dimension) { 8, 8 }, 200); - player->stats.hp = 0; - } -#endif // DEBUG - - if (!vector2d_equals(VECTOR2D_NODIR, direction)) { + if (!vector2d_equals(VECTOR2D_NODIR, player->nextDirection)) { player->sprite->clip.x = 16*step; ++step; step = step % 4; } + + player->nextDirection = VECTOR2D_NODIR; } static void @@ -293,8 +273,8 @@ check_skill_activation(Player *player, RoomMatrix *matrix, SDL_Event *event) } } -static bool -check_skill_trigger(Player *player, RoomMatrix *matrix, SDL_Event *event) +static void +check_skill_trigger(Player *player, RoomMatrix *matrix) { int activeSkill = -1; for (int i = 0; i < PLAYER_SKILL_COUNT; ++i) { @@ -305,26 +285,34 @@ check_skill_trigger(Player *player, RoomMatrix *matrix, SDL_Event *event) } if (activeSkill < 0) - return false; + return; - Vector2d dir; - if (keyboard_direction_press(UP, event)) - dir = VECTOR2D_UP; - else if (keyboard_direction_press(DOWN, event)) - dir = VECTOR2D_DOWN; - else if (keyboard_direction_press(LEFT, event)) - dir = VECTOR2D_LEFT; - else if (keyboard_direction_press(RIGHT, event)) - dir = VECTOR2D_RIGHT; - else - return false; - SkillData skillData = { player, matrix, dir }; + if (vector2d_equals(player->nextDirection, VECTOR2D_NODIR)) + return; + + SkillData skillData = { player, matrix, player->nextDirection }; use_skill(player->skills[activeSkill], &skillData); - return true; + 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) { @@ -338,8 +326,7 @@ handle_player_input(Player *player, RoomMatrix *matrix, SDL_Event *event) return; check_skill_activation(player, matrix, event); - if (!check_skill_trigger(player, matrix, event)) - handle_movement_input(player, matrix, event); + read_player_next_direction(player, event); } Player* @@ -360,6 +347,7 @@ 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; @@ -476,6 +464,10 @@ player_reset_steps(Player *p) void player_update(UpdateData *data) { Player *player = data->player; + + check_skill_trigger(player, data->matrix); + handle_next_move(player, data->matrix); + if (player->state == FALLING && player->stats.hp > 0) { if (!timer_started(player->animationTimer)) { timer_start(player->animationTimer); diff --git a/src/player.h b/src/player.h index 68d22c7..f866b29 100644 --- a/src/player.h +++ b/src/player.h @@ -63,6 +63,7 @@ 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; diff --git a/src/pointer.c b/src/pointer.c index 97b9e72..a523afd 100644 --- a/src/pointer.c +++ b/src/pointer.c @@ -44,14 +44,7 @@ pointer_handle_event(Pointer *p, SDL_Event *event) // Compensate for a small offset in the sprite p->sprite->pos.x = event->motion.x - 6; p->sprite->pos.y = event->motion.y - 6; - //debug("Pointer pos: %dx%d", p->sprite->pos.x, p->sprite->pos.y); } -#ifdef DEBUG - if (event->type == SDL_MOUSEBUTTONDOWN) { - Dimension dim = { 10, 10 }; - particle_engine_sparkle(p->sprite->pos, dim); - } -#endif // DEBUG } void diff --git a/test/test_keyboardinput.c b/test/test_keyboardinput.c new file mode 100644 index 0000000..2d8134f --- /dev/null +++ b/test/test_keyboardinput.c @@ -0,0 +1,64 @@ +/* + * 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" + +static KeyboardInput input = { 0, 0 }; + +static void +test_keypress(void **state) +{ + (void) state; + input.lastState = 0; + input.currentState = KEY_UP; + assert_true(key_is_pressed(&input, KEY_UP)); +} + +static void +test_keyrelease(void **state) +{ + (void) state; + input.lastState = KEY_UP; + input.currentState = 0; + assert_true(key_is_released(&input, KEY_UP)); +} + +static void +test_keydown(void **state) +{ + (void) state; + input.currentState = KEY_UP; + assert_true(key_is_down(&input, KEY_UP)); +} + +int main(void) +{ + + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_keypress), + cmocka_unit_test(test_keyrelease), + cmocka_unit_test(test_keydown), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +}