diff --git a/CMakeLists.txt b/CMakeLists.txt index 14b3828..55ad5a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -251,6 +251,7 @@ add_executable(breakhack src/object.c src/gui_util.c src/tooltip.c + src/tooltip_manager.c src/gamecontroller.c src/effect_util.c ${STEAM_SOURCES} diff --git a/lib/SDL b/lib/SDL index e292d1f..e4215a0 160000 --- a/lib/SDL +++ b/lib/SDL @@ -1 +1 @@ -Subproject commit e292d1f5ace469f718d7b6b4dec8c28e37dcaa0e +Subproject commit e4215a04d9052a13024d315caca8dfca109d8c45 diff --git a/lib/SDL_image b/lib/SDL_image index 9b18364..33d18dd 160000 --- a/lib/SDL_image +++ b/lib/SDL_image @@ -1 +1 @@ -Subproject commit 9b183647f2b662d2855dc75547b091065f14fc2d +Subproject commit 33d18dd927aed357f4989777e0de61cc8322dea7 diff --git a/lib/SDL_mixer b/lib/SDL_mixer index 5175907..6d5c7a6 160000 --- a/lib/SDL_mixer +++ b/lib/SDL_mixer @@ -1 +1 @@ -Subproject commit 5175907b515ea9e07d0b35849bfaf09870d07d33 +Subproject commit 6d5c7a65c43c1729db1659239e658c3c584e3786 diff --git a/lib/SDL_ttf b/lib/SDL_ttf index 2554dd7..a670386 160000 --- a/lib/SDL_ttf +++ b/lib/SDL_ttf @@ -1 +1 @@ -Subproject commit 2554dd7af438594dfc006ece291ad879ab36388b +Subproject commit a670386a9c3c7146b81011cab213350661b4542c diff --git a/src/defines.h b/src/defines.h index a0d4515..2468b02 100644 --- a/src/defines.h +++ b/src/defines.h @@ -20,6 +20,7 @@ #define DEFINES_H_ #include +#include "gamecontroller.h" #include "config.h" /* Room/Map dimensions */ @@ -100,9 +101,9 @@ typedef enum GameMode { ARCADE } GameMode; -#define CONTROLLER_BTN(xindex, mode) CLIP16(xindex, mode == 1 ? 0 : 16) -#define CONTROLLER_TRIGGER(xindex, mode) CLIP16(xindex + (mode == 1 ? 16 : 0), 32) -#define CONTROLLER_BUMPER(xindex, mode) CLIP16(xindex + (mode == 1 ? 16 : 0), 48) -#define CONTROLLER_OPT(xindex, mode) CLIP16(xindex + (mode == 2 ? 16 : 0), 64) +#define CONTROLLER_BTN(xindex, mode) CLIP16(xindex, mode == GAMEPAD_TYPE_XB ? 0 : 16) +#define CONTROLLER_TRIGGER(xindex, mode) CLIP16(xindex + (mode == GAMEPAD_TYPE_XB ? 16 : 0), 32) +#define CONTROLLER_BUMPER(xindex, mode) CLIP16(xindex + (mode == GAMEPAD_TYPE_XB ? 16 : 0), 48) +#define CONTROLLER_OPT(xindex, mode) CLIP16(xindex + (mode == GAMEPAD_TYPE_PS ? 16 : 0), 64) #endif // DEFINES_H_ diff --git a/src/gamecontroller.c b/src/gamecontroller.c index 3c8664e..f0f4c0b 100644 --- a/src/gamecontroller.c +++ b/src/gamecontroller.c @@ -21,11 +21,25 @@ static SDL_Gamepad *controller = NULL; static SDL_Haptic *haptic = NULL; -static Uint8 controllerMode = 0; +static Uint8 controllerMode = GAMEPAD_TYPE_NONE; void gamecontroller_set(SDL_Gamepad *ctrler) { + if (ctrler == NULL) { + info("Game controller disconnected"); + if (controller) { + SDL_CloseGamepad(controller); + controller = NULL; + } + if (haptic) { + SDL_CloseHaptic(haptic); + haptic = NULL; + } + controllerMode = GAMEPAD_TYPE_NONE; + return; + } + controller = ctrler; const char *ctrlName = SDL_GetGamepadName(controller); @@ -35,9 +49,9 @@ gamecontroller_set(SDL_Gamepad *ctrler) if (ctrlName[0] == 'P' && ctrlName[1] == 'S' && (ctrlName[2] == '4' || ctrlName[2] == '3')) - controllerMode = 2; + controllerMode = GAMEPAD_TYPE_PS; else - controllerMode = 1; + controllerMode = GAMEPAD_TYPE_XB; haptic = SDL_OpenHapticFromJoystick(SDL_GetGamepadJoystick(controller)); if (haptic) { @@ -55,6 +69,9 @@ gamecontroller_set(SDL_Gamepad *ctrler) void gamecontroller_rumble(float intensity, Uint32 duration) { + if (controllerMode == GAMEPAD_TYPE_NONE) + return; + if (!haptic) return; diff --git a/src/gamecontroller.h b/src/gamecontroller.h index 46742cf..cf40d03 100644 --- a/src/gamecontroller.h +++ b/src/gamecontroller.h @@ -20,6 +20,13 @@ #include +typedef enum { + GAMEPAD_TYPE_NONE, + GAMEPAD_TYPE_XB, + GAMEPAD_TYPE_PS, + GAMEPAD_TYPE_MAX +} GamepadType; + typedef struct GameController { SDL_Gamepad *controller; unsigned int mode; diff --git a/src/input.c b/src/input.c index 25becbf..662f01b 100644 --- a/src/input.c +++ b/src/input.c @@ -193,41 +193,49 @@ get_event_mousebutton(SDL_Event *event) } void -input_handle_event(Input *input, SDL_Event *event) +input_handle_event(Input *input, SDL_Event *event, InputDeviceType *device_type) { + InputDeviceType current_device_type = DeviceType_Unknown; + if (event->type == SDL_EVENT_KEY_DOWN) { Uint32 key; - if ((key = get_event_modkey(event))) + if ((key = get_event_modkey(event))) { input->modKeyState |= key; - else + } else { input->keyState |= get_event_key(event); - } - else if (event->type == SDL_EVENT_KEY_UP) { + } + current_device_type = DeviceType_Keyboard; + } else if (event->type == SDL_EVENT_KEY_UP) { Uint32 key; - if ((key = get_event_modkey(event))) + if ((key = get_event_modkey(event))) { input->modKeyState &= ~key; - else + } else { input->keyState &= ~get_event_key(event); - } - else if (event->type == SDL_EVENT_MOUSE_BUTTON_DOWN) + } + current_device_type = DeviceType_Keyboard; + } else if (event->type == SDL_EVENT_MOUSE_BUTTON_DOWN) { input->mouseButtonState |= get_event_mousebutton(event); - else if (event->type == SDL_EVENT_MOUSE_BUTTON_UP) + } else if (event->type == SDL_EVENT_MOUSE_BUTTON_UP) { input->mouseButtonState &= ~get_event_mousebutton(event); - else if (event->type == SDL_EVENT_MOUSE_MOTION) { + } else if (event->type == SDL_EVENT_MOUSE_MOTION) { input->mouseX = (Uint32) event->motion.x; input->mouseY = (Uint32) event->motion.y; - } - else if (event->type == SDL_EVENT_GAMEPAD_BUTTON_DOWN) { + } else if (event->type == SDL_EVENT_GAMEPAD_BUTTON_DOWN) { input->keyState |= get_event_button(event); - } - else if (event->type == SDL_EVENT_GAMEPAD_BUTTON_UP) { + current_device_type = DeviceType_Gamepad; + } else if (event->type == SDL_EVENT_GAMEPAD_BUTTON_UP) { input->keyState &= ~get_event_button(event); - } - else if (event->type == SDL_EVENT_GAMEPAD_AXIS_MOTION) { - if (event->gaxis.value > 31500 || event->gaxis.value < -31500) + current_device_type = DeviceType_Gamepad; + } else if (event->type == SDL_EVENT_GAMEPAD_AXIS_MOTION) { + if (event->gaxis.value > 31500 || event->gaxis.value < -31500) { input->keyState |= get_axis_motion(event); - else + } else { input->keyState &= ~get_axis_motion(event); + } + } + + if (device_type != NULL) { + *device_type = current_device_type; } } diff --git a/src/input.h b/src/input.h index 45ad31b..b0f6ebd 100644 --- a/src/input.h +++ b/src/input.h @@ -54,6 +54,12 @@ #define MBUTTON_MIDDLE 0x2 #define MBUTTON_RIGHT 0x4 +typedef enum InputDeviceType { + DeviceType_Unknown, + DeviceType_Keyboard, + DeviceType_Gamepad +} InputDeviceType; + typedef struct Input { Uint64 keyState; Uint64 lastKeyState; @@ -74,7 +80,7 @@ void input_reset(Input *); void -input_handle_event(Input *, SDL_Event*); +input_handle_event(Input *, SDL_Event*, InputDeviceType *device_type); bool input_key_is_pressed(Input *, Uint64 key); diff --git a/src/main.c b/src/main.c index a7fbaab..62218d1 100644 --- a/src/main.c +++ b/src/main.c @@ -38,10 +38,8 @@ #include "util.h" #include "item_builder.h" #include "pointer.h" -#include "gui_button.h" #include "particle_engine.h" #include "menu.h" -#include "keyboard.h" #include "mixer.h" #include "random.h" #include "skillbar.h" @@ -53,7 +51,7 @@ #include "screen.h" #include "hiscore.h" #include "io_util.h" -#include "tooltip.h" +#include "tooltip_manager.h" #include "gamecontroller.h" #include "time.h" #include "sprite_util.h" @@ -66,81 +64,6 @@ #include "steam/steamworks_api_wrapper.h" #endif // STEAM_BUILD -static char *artifacts_tooltip[] = { - "CONGRATULATIONS!", "", - "", - " You just picked up your first artifact!", "", - "", - " Your current artifacts and corresponding level are", "", - " listed next to your skills.", "", - "", - "", - " Artifacts have mystical effects that improve your offensive", "", - " or defensive advantage in the dungeon. However it is sometimes", "", - " hard to know what effect an artifact has.", "", - "", - "", - " Perhaps an experienced dungeoner will know more?", "", - "", - "", - "Press ", "ESC", " to close", "", - NULL -}; - -static char *skills_tooltip[] = { - "CONGRATULATIONS!", "", - "", - " You have aquired a new level and a new skill!", "", - "", - " Skills are listed in the bar below the game screen.", "", - "", - "", - " SKILL INFO: SHIFT + ", "", - " Where is the number corresponding to the skill", "", - " Eg. 1, 2, 3, 4, 5", "", - "", - " DISABLE TOOLTIPS: CTRL + D", "", - "", - "", - "Press ", "ESC", " to close", "", - NULL -}; - -static char *how_to_play_tooltip[] = { - "HOW TO PLAY", "", - "", - " NAVIGATION: Use ARROWS or WASD or HJKL to move", "", - " Controller: LEFT STICK or D-PAD", "", - "", - " ATTACK: Walk into a monster to attack it", "", - "", - " HOLD TURN: Press ", "SPACE", "", - "", - " THROW DAGGER: Press ", "4", " then chose a direction (nav keys)", "", - "", - " DRINK HEALTH: Press ", "5", " (if you need health and have potions)", "", - "", - " TOGGLE MUSIC: CTRL + M", "", - "", - " TOGGLE SOUND: CTRL + S", "", - "", - " TOGGLE FULLSCREEN: CTRL + F", "", - "", - " TOGGLE MENU: ", "ESC", "", - "", - " Your stats and inventory are listed in the right panel", "", - "", - "", - " GOOD LUCK!", "", - " May your death be quick and painless...", "", - "", - "", - "", - "Press ", "ESC", " to close", "", - NULL -}; - - typedef enum Turn_t { PLAYER, MONSTER @@ -162,9 +85,6 @@ static Camera *gCamera = NULL; static Screen *creditsScreen = NULL; static Screen *scoreScreen = NULL; static Screen *characterSelectScreen = NULL; -static Sprite *new_skill_tooltip = NULL; -static Sprite *howto_tooltip = NULL; -static Sprite *new_artifact_tooltip = NULL; static unsigned int cLevel = 1; static float deltaTime = 1.0; static Turn currentTurn = PLAYER; @@ -190,14 +110,13 @@ static Pointer *gPointer = NULL; static void resetGame(void); static void initMainMenu(void); static bool is_player_dead(void); +static void initGamepads(void); static SDL_Surface *window_icon = NULL; static bool initSDL(void) { - int imgFlags = IMG_INIT_PNG; - debug("Initializing SDL"); if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMEPAD | SDL_INIT_HAPTIC)) { @@ -207,13 +126,6 @@ bool initSDL(void) Dimension dim = getScreenDimensions(); - debug("Initializing SDL_image"); - if ( (IMG_Init(imgFlags) & imgFlags) == 0 ) { - error("Unable to initiate img loading: %s", - SDL_GetError()); - return false; - } - debug("Initializing SDL_ttf"); if (!TTF_Init()) { error("Unable to initiate ttf library: %s", @@ -222,21 +134,7 @@ bool initSDL(void) } debug("Initializing gamepads"); - int num_joysticks; - SDL_JoystickID *sticks = SDL_GetJoysticks(&num_joysticks); - debug("Found %d joysticks", num_joysticks); - for (int i = 0; i < num_joysticks; i++) { - int stick = sticks[i]; - if (!SDL_IsGamepad(stick)) { - continue; - } - - SDL_Gamepad *ctrler = SDL_OpenGamepad(stick); - if (ctrler) { - gamecontroller_set(ctrler); - } - } - SDL_free(sticks); + initGamepads(); debug("Initializing SDL_mixer"); mixer_init(); @@ -368,8 +266,9 @@ startGame(void) gui_event_message("Welcome to the dungeon!"); Settings *settings = settings_get(); - if (!settings->howto_tooltip_shown) - gGui->activeTooltip = howto_tooltip; + if (!settings->howto_tooltip_shown) { + gGui->activeTooltip = tooltip_manager_get_tooltip(TOOLTIP_TYPE_HOWTO); + } settings->howto_tooltip_shown = true; if (arcadeGame) @@ -581,7 +480,7 @@ showHowToTooltip(void *unused) { UNUSED(unused); toggleInGameMenu(NULL); - gGui->activeTooltip = howto_tooltip; + gGui->activeTooltip = tooltip_manager_get_tooltip(TOOLTIP_TYPE_HOWTO); } static void @@ -628,6 +527,26 @@ viewScoreScreen(void *unused) gGameState = SCORE_SCREEN; } +static void +initGamepads(void) +{ + int num_joysticks; + SDL_JoystickID *sticks = SDL_GetJoysticks(&num_joysticks); + debug("Found %d joysticks", num_joysticks); + for (int i = 0; i < num_joysticks; i++) { + int stick = sticks[i]; + if (!SDL_IsGamepad(stick)) { + continue; + } + + SDL_Gamepad *ctrler = SDL_OpenGamepad(stick); + if (ctrler) { + gamecontroller_set(ctrler); + } + } + SDL_free(sticks); +} + static void initMainMenu(void) { @@ -762,11 +681,7 @@ init(void) save_init(); hiscore_init(); initMainMenu(); - - tooltip_set_controller_mode(gamecontroller_mode()); - howto_tooltip = tooltip_create(how_to_play_tooltip, gCamera); - new_skill_tooltip = tooltip_create(skills_tooltip, gCamera); - new_artifact_tooltip = tooltip_create(artifacts_tooltip, gCamera); + tooltip_manager_init(gCamera); gCamera->pos = (Position) { 0, 0 }; @@ -863,9 +778,12 @@ handle_main_input(void) static bool handle_events(void) { + static InputDeviceType last_device_type = DeviceType_Unknown; static SDL_Event event; + + InputDeviceType device_type = DeviceType_Unknown; bool quit = false; - int handleCount = 0; + input_reset(&input); while (SDL_PollEvent(&event) != 0) { @@ -874,14 +792,25 @@ handle_events(void) continue; } - input_handle_event(&input, &event); + if (event.type == SDL_EVENT_GAMEPAD_ADDED) { + initGamepads(); + } else if (event.type == SDL_EVENT_GAMEPAD_REMOVED) { + debug("Gamepad removed"); + gamecontroller_set(NULL); + } - handleCount++; - if (handleCount >= 20) { - debug("Flushing event queue"); - SDL_PumpEvents(); - SDL_FlushEvents(SDL_EVENT_FIRST, SDL_EVENT_LAST); - break; + input_handle_event(&input, &event, &device_type); + + if (device_type != DeviceType_Unknown && device_type != last_device_type) { + debug("Device type changed: %d", last_device_type); + last_device_type = device_type; + if (device_type == DeviceType_Gamepad) { + skillbar_set_controller_mode(gamecontroller_mode()); + tooltip_manager_set_controller_mode(gamecontroller_mode()); + } else { + skillbar_set_controller_mode(GAMEPAD_TYPE_NONE); + tooltip_manager_set_controller_mode(GAMEPAD_TYPE_NONE); + } } } @@ -902,7 +831,7 @@ end_game_details(void) { gui_log("You earned %.2f gold", gPlayer->gold); gui_event_message("You earned %.2f gold", gPlayer->gold); - + if (hiscore_get_top_gold() < gPlayer->gold) { gui_event_message("NEW HIGHSCORE"); gui_log("NEW HIGHSCORE"); @@ -972,13 +901,14 @@ check_tooltip_activation(bool skillActivated) static bool artifactTooltipShown = false; Settings *settings = settings_get(); - if (skillActivated && settings->tooltips_enabled) { - gGui->activeTooltip = new_skill_tooltip; - } - if (!artifactTooltipShown && gPlayer->equipment.hasArtifacts) { - artifactTooltipShown = true; - if (settings->tooltips_enabled) - gGui->activeTooltip = new_artifact_tooltip; + if (settings->tooltips_enabled) { + if (skillActivated) { + gGui->activeTooltip = tooltip_manager_get_tooltip(TOOLTIP_TYPE_SKILL); + } + if (!artifactTooltipShown && gPlayer->equipment.hasArtifacts) { + artifactTooltipShown = true; + gGui->activeTooltip = tooltip_manager_get_tooltip(TOOLTIP_TYPE_ARTIFACT); + } } } @@ -1385,8 +1315,7 @@ void close(void) if (window_icon) SDL_DestroySurface(window_icon); - sprite_destroy(howto_tooltip); - sprite_destroy(new_skill_tooltip); + tooltip_manager_close(); camera_destroy(gCamera); roommatrix_destroy(gRoomMatrix); gui_destroy(gGui); @@ -1415,7 +1344,6 @@ void close(void) SDL_DestroyWindow(gWindow); gWindow = NULL; TTF_Quit(); - IMG_Quit(); SDL_Quit(); } diff --git a/src/skill.c b/src/skill.c index 8ceb4a1..dd19123 100644 --- a/src/skill.c +++ b/src/skill.c @@ -1076,6 +1076,6 @@ skill_destroy(Skill *skill) { sprite_destroy(skill->icon); if (skill->tooltip) - sprite_destroy(skill->tooltip); + tooltip_destroy(skill->tooltip); free(skill); } diff --git a/src/skill.h b/src/skill.h index 4363b94..0e5da83 100644 --- a/src/skill.h +++ b/src/skill.h @@ -23,6 +23,7 @@ #include "roommatrix.h" #include "sprite.h" #include "vector2d.h" +#include "tooltip.h" // Forward declaration typedef struct Player Player; @@ -58,7 +59,7 @@ typedef struct Skill_t { bool active; bool (*available)(Player*); bool (*use)(struct Skill_t*, SkillData*); - Sprite *tooltip; + Tooltip *tooltip; } Skill; Skill* diff --git a/src/skillbar.c b/src/skillbar.c index cd61b19..2ab4369 100644 --- a/src/skillbar.c +++ b/src/skillbar.c @@ -22,18 +22,18 @@ #include "texture.h" #include "util.h" #include "sprite.h" -#include "keyboard.h" #include "texturecache.h" #include "particle_engine.h" #include "update_data.h" #include "gui.h" -static Uint8 controller_mode = 0; +static GamepadType controller_type = GAMEPAD_TYPE_NONE; void skillbar_set_controller_mode(Uint8 ctrl_mode) { - controller_mode = ctrl_mode; + debug("Setting controller mode to %u", ctrl_mode); + controller_type = ctrl_mode; } static Sprite * @@ -56,26 +56,54 @@ load_texture(SkillBar *bar, const char *path, SDL_Renderer *renderer) t->dim.width = 16; t->dim.height = 16; - if (!controller_mode) { - for (unsigned int i = 0; i < 5; ++i) { - char buffer[4]; - Sprite *s = sprite_create(); - s->pos = (Position) { i * 32 + 20, 20 }; - s->dim = (Dimension) { 8, 8 }; - s->fixed = true; - sprite_load_text_texture(s, "GUI/SDS_8x8.ttf", 0, 8, 0); - m_sprintf(buffer, 4, "%u", i + 1); - texture_load_from_text(s->textures[0], buffer, C_YELLOW, C_BLACK, renderer); - linkedlist_append(&bar->sprites, s); - } - } else { - Uint8 i = 0; - linkedlist_append(&bar->sprites, create_controller_button_sprite(POS(i++ * 32 + 16, 16), CONTROLLER_BTN(0, controller_mode))); - linkedlist_append(&bar->sprites, create_controller_button_sprite(POS(i++ * 32 + 16, 16), CONTROLLER_BTN(16, controller_mode))); - linkedlist_append(&bar->sprites, create_controller_button_sprite(POS(i++ * 32 + 16, 16), CONTROLLER_BTN(32, controller_mode))); - linkedlist_append(&bar->sprites, create_controller_button_sprite(POS(i++ * 32 + 16, 16), CONTROLLER_BTN(48, controller_mode))); - linkedlist_append(&bar->sprites, create_controller_button_sprite(POS(i++ * 32 + 16, 20), CONTROLLER_BUMPER(32, controller_mode))); + /* Load keyboard hint sprites */ + for (unsigned int i = 0; i < 5; ++i) { + char buffer[4]; + Sprite *s = sprite_create(); + s->pos = (Position) { i * 32 + 20, 20 }; + s->dim = (Dimension) { 8, 8 }; + s->fixed = true; + sprite_load_text_texture(s, "GUI/SDS_8x8.ttf", 0, 8, 0); + m_sprintf(buffer, 4, "%u", i + 1); + texture_load_from_text(s->textures[0], buffer, C_YELLOW, C_BLACK, renderer); + linkedlist_append(&bar->sprites_keyboard, s); } + + /* Load ps controller sprites */ + Uint8 i = 0; + linkedlist_append(&bar->sprites_gamepad_ps, + create_controller_button_sprite(POS(i++ * 32 + 16, 16), + CONTROLLER_BTN(0, GAMEPAD_TYPE_PS))); + linkedlist_append(&bar->sprites_gamepad_ps, + create_controller_button_sprite(POS(i++ * 32 + 16, 16), + CONTROLLER_BTN(16, GAMEPAD_TYPE_PS))); + linkedlist_append(&bar->sprites_gamepad_ps, + create_controller_button_sprite(POS(i++ * 32 + 16, 16), + CONTROLLER_BTN(32, GAMEPAD_TYPE_PS))); + linkedlist_append(&bar->sprites_gamepad_ps, + create_controller_button_sprite(POS(i++ * 32 + 16, 16), + CONTROLLER_BTN(48, GAMEPAD_TYPE_PS))); + linkedlist_append(&bar->sprites_gamepad_ps, + create_controller_button_sprite(POS(i++ * 32 + 16, 20), + CONTROLLER_BUMPER(32, GAMEPAD_TYPE_PS))); + + /* Load xbox controller sprites */ + i = 0; + linkedlist_append(&bar->sprites_gamepad_xb, + create_controller_button_sprite(POS(i++ * 32 + 16, 16), + CONTROLLER_BTN(0, GAMEPAD_TYPE_XB))); + linkedlist_append(&bar->sprites_gamepad_xb, + create_controller_button_sprite(POS(i++ * 32 + 16, 16), + CONTROLLER_BTN(16, GAMEPAD_TYPE_XB))); + linkedlist_append(&bar->sprites_gamepad_xb, + create_controller_button_sprite(POS(i++ * 32 + 16, 16), + CONTROLLER_BTN(32, GAMEPAD_TYPE_XB))); + linkedlist_append(&bar->sprites_gamepad_xb, + create_controller_button_sprite(POS(i++ * 32 + 16, 16), + CONTROLLER_BTN(48, GAMEPAD_TYPE_XB))); + linkedlist_append(&bar->sprites_gamepad_xb, + create_controller_button_sprite(POS(i++ * 32 + 16, 20), + CONTROLLER_BUMPER(32, GAMEPAD_TYPE_XB))); } static void @@ -180,7 +208,9 @@ SkillBar * skillbar_create(Camera *cam) { SkillBar *bar = ec_malloc(sizeof(SkillBar)); - bar->sprites = linkedlist_create(); + bar->sprites_keyboard = linkedlist_create(); + bar->sprites_gamepad_ps = linkedlist_create(); + bar->sprites_gamepad_xb = linkedlist_create(); bar->activationTimer = _timer_create(); bar->skillSparkleTimer = _timer_create(); bar->lastActivation = 0; @@ -225,7 +255,20 @@ skillbar_check_skill_activation(SkillBar *bar, Player *player) static void render_sprites(SkillBar *bar, Camera *cam) { - LinkedList *sprites = bar->sprites; + LinkedList *sprites; + + switch (controller_type) { + case GAMEPAD_TYPE_PS: + sprites = bar->sprites_gamepad_ps; + break; + case GAMEPAD_TYPE_XB: + sprites = bar->sprites_gamepad_xb; + break; + case GAMEPAD_TYPE_NONE: + default: + sprites = bar->sprites_keyboard; + break; + } while (sprites) { sprite_render(sprites->data, cam); @@ -382,7 +425,7 @@ skillbar_update(SkillBar *bar, UpdateData *data) if (!data->player->skills[i]) continue; if (input_modkey_is_pressed(input, KEY_SHIFT_NUM1 << i)) { - data->gui->activeTooltip = data->player->skills[i]->tooltip; + data->gui->activeTooltip = data->player->skills[i]->tooltip->sprite[controller_type]; return; } } @@ -433,8 +476,12 @@ skillbar_reset(SkillBar *bar) void skillbar_destroy(SkillBar *bar) { - while (bar->sprites) - sprite_destroy(linkedlist_pop(&bar->sprites)); + while (bar->sprites_keyboard) + sprite_destroy(linkedlist_pop(&bar->sprites_keyboard)); + while (bar->sprites_gamepad_ps) + sprite_destroy(linkedlist_pop(&bar->sprites_gamepad_ps)); + while (bar->sprites_gamepad_xb) + sprite_destroy(linkedlist_pop(&bar->sprites_gamepad_xb)); for (Uint32 i = 0; i < PLAYER_SKILL_COUNT; ++i) if (bar->countdowns[i]) sprite_destroy(bar->countdowns[i]); diff --git a/src/skillbar.h b/src/skillbar.h index 27b9041..e62de56 100644 --- a/src/skillbar.h +++ b/src/skillbar.h @@ -35,7 +35,9 @@ typedef struct ArtifactDisplay { } ArtifactDisplay; typedef struct SkillBar { - LinkedList *sprites; + LinkedList *sprites_keyboard; + LinkedList *sprites_gamepad_ps; + LinkedList *sprites_gamepad_xb; ArtifactDisplay artifacts[LAST_ARTIFACT_EFFECT]; Uint32 artifactDisplayOffset; Sprite *countdowns[PLAYER_SKILL_COUNT]; diff --git a/src/tooltip.c b/src/tooltip.c index 87d31df..9057bc7 100644 --- a/src/tooltip.c +++ b/src/tooltip.c @@ -22,32 +22,31 @@ #include "defines.h" #include "gui.h" #include "texturecache.h" - -static Uint8 controller_mode = 0; +#include "util.h" static bool -render_button_texture_for(const char *text, Position pos, Camera *cam) +render_button_texture_for(const char *text, Position pos, Camera *cam, GamepadType controller_type) { - if (!controller_mode) { + if (controller_type == GAMEPAD_TYPE_NONE) { return false; } Texture *t = texturecache_add("Extras/Controller.png"); SDL_Rect clip; if (strcmp(text, "1") == 0) { - clip = CONTROLLER_BTN(0, controller_mode); + clip = CONTROLLER_BTN(0, controller_type); } else if (strcmp(text, "2") == 0) { - clip = CONTROLLER_BTN(16, controller_mode); + clip = CONTROLLER_BTN(16, controller_type); } else if (strcmp(text, "3") == 0) { - clip = CONTROLLER_BTN(32, controller_mode); + clip = CONTROLLER_BTN(32, controller_type); } else if (strcmp(text, "4") == 0) { - clip = CONTROLLER_BTN(48, controller_mode); + clip = CONTROLLER_BTN(48, controller_type); } else if (strcmp(text, "5") == 0) { - clip = CONTROLLER_BUMPER(32, controller_mode); + clip = CONTROLLER_BUMPER(32, controller_type); } else if (strcmp(text, "ESC") == 0) { - clip = CONTROLLER_OPT(32, controller_mode); + clip = CONTROLLER_OPT(32, controller_type); } else if (strcmp(text, "ENTER") == 0) { - clip = CONTROLLER_OPT(0, controller_mode); + clip = CONTROLLER_OPT(0, controller_type); } else if (strcmp(text, "SPACE") == 0) { clip = CLIP16(0, 80); } else { @@ -75,8 +74,8 @@ load_texture_for(Texture *text, renderBox->h = text->dim.height; } -Sprite * -tooltip_create(char **content, Camera *cam) +static Sprite * +tooltip_create_sprite(char **content, Camera *cam, GamepadType controller_type) { int rowCount = 0; char **contentIndex = content; @@ -98,13 +97,14 @@ tooltip_create(char **content, Camera *cam) while (*content) { if (strlen(*content) > 0) { - if (render_button_texture_for(*content, POS(renderBox.x, renderBox.y - 4), cam)) { + if (render_button_texture_for(*content, POS(renderBox.x, renderBox.y - 4), + cam, controller_type)) { renderBox.x += 16; } else { load_texture_for(text, *content, &renderBox, cam->renderer); texture_render(text, &renderBox, cam); renderBox.x += text->dim.width; - } + } } else { renderBox.x = 16; renderBox.y += 14; @@ -117,8 +117,19 @@ tooltip_create(char **content, Camera *cam) return sprite; } -void -tooltip_set_controller_mode(Uint8 ctrl_mode) +Tooltip *tooltip_create(char **content, Camera *cam) +{ + Tooltip *tt = ec_malloc(sizeof(Tooltip)); + for (size_t i = 0; i < GAMEPAD_TYPE_MAX; ++i) { + tt->sprite[i] = tooltip_create_sprite(content, cam, (GamepadType) i); + } + return tt; +} + +void tooltip_destroy(Tooltip *tooltip) { - controller_mode = ctrl_mode; + for (size_t i = 0; i < GAMEPAD_TYPE_MAX; ++i) { + sprite_destroy(tooltip->sprite[i]); + } + free(tooltip); } diff --git a/src/tooltip.h b/src/tooltip.h index 880a043..1984f85 100644 --- a/src/tooltip.h +++ b/src/tooltip.h @@ -20,9 +20,14 @@ #include "camera.h" #include "sprite.h" +#include "gamecontroller.h" -Sprite * +typedef struct tooltip { + Sprite *sprite[GAMEPAD_TYPE_MAX]; +} Tooltip; + +Tooltip * tooltip_create(char **content, Camera*); void -tooltip_set_controller_mode(Uint8 ctrl_mode); \ No newline at end of file +tooltip_destroy(Tooltip *tooltip); diff --git a/src/tooltip_manager.c b/src/tooltip_manager.c new file mode 100644 index 0000000..ce275b8 --- /dev/null +++ b/src/tooltip_manager.c @@ -0,0 +1,136 @@ +/* + * BreakHack - A dungeone crawler RPG + * Copyright (C) 2024 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 "tooltip_manager.h" +#include "tooltip.h" +#include "sprite.h" + +static char *artifacts_tooltip[] = { + "CONGRATULATIONS!", "", + "", + " You just picked up your first artifact!", "", + "", + " Your current artifacts and corresponding level are", "", + " listed next to your skills.", "", + "", + "", + " Artifacts have mystical effects that improve your offensive", "", + " or defensive advantage in the dungeon. However it is sometimes", "", + " hard to know what effect an artifact has.", "", + "", + "", + " Perhaps an experienced dungeoner will know more?", "", + "", + "", + "Press ", "ESC", " to close", "", + NULL +}; + +static char *skills_tooltip[] = { + "CONGRATULATIONS!", "", + "", + " You have aquired a new level and a new skill!", "", + "", + " Skills are listed in the bar below the game screen.", "", + "", + "", + " SKILL INFO: SHIFT + ", "", + " Where is the number corresponding to the skill", "", + " Eg. 1, 2, 3, 4, 5", "", + "", + " DISABLE TOOLTIPS: CTRL + D", "", + "", + "", + "Press ", "ESC", " to close", "", + NULL +}; + +static char *how_to_play_tooltip[] = { + "HOW TO PLAY", "", + "", + " NAVIGATION: Use ARROWS or WASD or HJKL to move", "", + " Controller: LEFT STICK or D-PAD", "", + "", + " ATTACK: Walk into a monster to attack it", "", + "", + " HOLD TURN: Press ", "SPACE", "", + "", + " THROW DAGGER: Press ", "4", " then chose a direction (nav keys)", "", + "", + " DRINK HEALTH: Press ", "5", " (if you need health and have potions)", "", + "", + " TOGGLE MUSIC: CTRL + M", "", + "", + " TOGGLE SOUND: CTRL + S", "", + "", + " TOGGLE FULLSCREEN: CTRL + F", "", + "", + " TOGGLE MENU: ", "ESC", "", + "", + " Your stats and inventory are listed in the right panel", "", + "", + "", + " GOOD LUCK!", "", + " May your death be quick and painless...", "", + "", + "", + "", + "Press ", "ESC", " to close", "", + NULL +}; + +static Tooltip *new_skill_tooltip = NULL; +static Tooltip *howto_tooltip = NULL; +static Tooltip *new_artifact_tooltip = NULL; + +static GamepadType controller_type = GAMEPAD_TYPE_NONE; + +void tooltip_manager_init(Camera *gCamera) +{ + howto_tooltip = tooltip_create(how_to_play_tooltip, gCamera); + new_skill_tooltip = tooltip_create(skills_tooltip, gCamera); + new_artifact_tooltip = tooltip_create(artifacts_tooltip, gCamera); +} + +void tooltip_manager_set_controller_mode(GamepadType mode) +{ + controller_type = mode; +} + +Sprite* tooltip_manager_get_tooltip(TooltipType type) +{ + switch (type) { + case TOOLTIP_TYPE_HOWTO: + return howto_tooltip->sprite[controller_type]; + break; + case TOOLTIP_TYPE_SKILL: + return new_skill_tooltip->sprite[controller_type]; + case TOOLTIP_TYPE_ARTIFACT: + return new_artifact_tooltip->sprite[controller_type]; + default: + break; + } + + return NULL; +} + +void tooltip_manager_close() +{ + tooltip_destroy(new_skill_tooltip); + tooltip_destroy(howto_tooltip); + tooltip_destroy(new_artifact_tooltip); +} diff --git a/src/tooltip_manager.h b/src/tooltip_manager.h new file mode 100644 index 0000000..180c735 --- /dev/null +++ b/src/tooltip_manager.h @@ -0,0 +1,36 @@ +/* + * BreakHack - A dungeone crawler RPG + * Copyright (C) 2024 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 "camera.h" +#include "gamecontroller.h" + +typedef struct Sprite Sprite; + +typedef enum TooltipType { + TOOLTIP_TYPE_HOWTO, + TOOLTIP_TYPE_SKILL, + TOOLTIP_TYPE_ARTIFACT, +} TooltipType; + +void tooltip_manager_init(Camera *gCamera); + +void tooltip_manager_set_controller_mode(GamepadType mode); + +Sprite* tooltip_manager_get_tooltip(TooltipType type); + +void tooltip_manager_close(void); diff --git a/test/test_input.c b/test/test_input.c index 7b711a9..7185b9a 100644 --- a/test/test_input.c +++ b/test/test_input.c @@ -37,11 +37,11 @@ test_event_parse(void **state) event.key = SDLK_W; event.mod = SDL_KMOD_NONE; - input_handle_event(&input, (SDL_Event*) &event); + input_handle_event(&input, (SDL_Event*) &event, NULL); event.scancode = SDL_SCANCODE_0; event.key = SDLK_0; event.mod = SDL_KMOD_NONE; - input_handle_event(&input, (SDL_Event*) &event); + input_handle_event(&input, (SDL_Event*) &event, NULL); assert_true(input_key_is_pressed(&input, KEY_UP)); assert_true(input_key_is_pressed(&input, KEY_NUM0)); @@ -50,7 +50,7 @@ test_event_parse(void **state) event.scancode = SDL_SCANCODE_0; event.key = SDLK_0; event.mod = SDL_KMOD_NONE; - input_handle_event(&input, (SDL_Event*) &event); + input_handle_event(&input, (SDL_Event*) &event, NULL); assert_true(input_key_is_pressed(&input, KEY_UP)); assert_true(!input_key_is_pressed(&input, KEY_NUM0)); @@ -97,19 +97,20 @@ static void test_mousebuttons(void **state) { (void) state; + Input input; input_init(&input); SDL_MouseButtonEvent event; event.type = SDL_EVENT_MOUSE_BUTTON_DOWN; event.button = SDL_BUTTON_LEFT; - input_handle_event(&input, (SDL_Event*) &event); + input_handle_event(&input, (SDL_Event*) &event, NULL); assert_true(input_mousebutton_is_pressed(&input, MBUTTON_LEFT)); input_reset(&input); event.button = SDL_BUTTON_RIGHT; - input_handle_event(&input, (SDL_Event*) &event); + input_handle_event(&input, (SDL_Event*) &event, NULL); assert_true(!input_mousebutton_is_pressed(&input, MBUTTON_LEFT)); assert_true(input_mousebutton_is_pressed(&input, MBUTTON_RIGHT));