Fixes #37 and #39 Adds tooltips to everything

- A tooltip on first play will explain how it works
- A tooltip on levelup will display skill info
- A setting is introduced to disable tooltips
This commit is contained in:
Linus Probert 2018-08-20 14:30:31 +02:00
parent 5f754d551a
commit 358c0c7ddc
20 changed files with 441 additions and 61 deletions

View File

@ -178,6 +178,7 @@ add_executable(breakhack
src/hiscore src/hiscore
src/object src/object
src/gui_util src/gui_util
src/tooltip
) )
# Sqlite has some warnings that I we don't need to see # Sqlite has some warnings that I we don't need to see

View File

@ -27,6 +27,7 @@
#include "map.h" #include "map.h"
#include "texturecache.h" #include "texturecache.h"
#include "gui_util.h" #include "gui_util.h"
#include "tooltip.h"
#define DEFAULT_LOG { NULL, LOG_LINES_COUNT, 0, 200 } #define DEFAULT_LOG { NULL, LOG_LINES_COUNT, 0, 200 }
#define DEFAULT_EVENT_MESSAGES { NULL, 5, 0, 200 } #define DEFAULT_EVENT_MESSAGES { NULL, 5, 0, 200 }
@ -41,7 +42,7 @@ static struct LogData_t {
unsigned int strlen; unsigned int strlen;
} log_data = DEFAULT_LOG; } log_data = DEFAULT_LOG;
static struct GuiEventMsgData_t { static struct GuiEventMsgs {
char **messages; char **messages;
unsigned int len; unsigned int len;
unsigned int count; unsigned int count;
@ -180,6 +181,7 @@ gui_create(Camera *cam)
gui->sprites = linkedlist_create(); gui->sprites = linkedlist_create();
gui->health = linkedlist_create(); gui->health = linkedlist_create();
gui->xp_bar = linkedlist_create(); gui->xp_bar = linkedlist_create();
gui->activeTooltip = NULL;
for (i = 0; i < LOG_LINES_COUNT; ++i) { for (i = 0; i < LOG_LINES_COUNT; ++i) {
t = texture_create(); t = texture_create();
@ -464,6 +466,14 @@ gui_event_message(const char *fmt, ...)
event_messages.count++; event_messages.count++;
} }
void
gui_render_tooltip(Gui *gui, Camera *cam)
{
if (gui->activeTooltip) {
sprite_render(gui->activeTooltip, cam);
}
}
void void
gui_render_log(Gui *gui, Camera *cam) gui_render_log(Gui *gui, Camera *cam)
{ {
@ -520,8 +530,9 @@ gui_render_event_message(Gui *gui, Camera *cam)
void void
gui_clear_message_log(void) gui_clear_message_log(void)
{ {
for (size_t i = 0; i < event_messages.count; ++i) for (size_t i = 0; i < event_messages.count; ++i) {
free(event_messages.messages[i]); free(event_messages.messages[i]);
}
event_messages.count = 0; event_messages.count = 0;
for (size_t i = 0; i < log_data.count; ++i) for (size_t i = 0; i < log_data.count; ++i)
@ -549,8 +560,9 @@ destroy_event_messages(void)
if (event_messages.messages == NULL) if (event_messages.messages == NULL)
return; return;
for (unsigned int i = 0; i < event_messages.count; ++i) for (unsigned int i = 0; i < event_messages.count; ++i) {
free(event_messages.messages[i]); free(event_messages.messages[i]);
}
free(event_messages.messages); free(event_messages.messages);
event_messages.messages = NULL; event_messages.messages = NULL;

View File

@ -42,13 +42,14 @@ typedef enum Label_e {
LABEL_COUNT LABEL_COUNT
} LabelIndex; } LabelIndex;
typedef struct { typedef struct Gui {
LinkedList *sprites; LinkedList *sprites;
LinkedList *health; LinkedList *health;
LinkedList *xp_bar; LinkedList *xp_bar;
Sprite *bottomFrame; Sprite *bottomFrame;
Sprite *rightFrame; Sprite *rightFrame;
Sprite *labels[LABEL_COUNT]; Sprite *labels[LABEL_COUNT];
Sprite *activeTooltip;
Texture *log_lines[LOG_LINES_COUNT]; Texture *log_lines[LOG_LINES_COUNT];
Texture *event_message; Texture *event_message;
Timer *event_message_timer; Timer *event_message_timer;
@ -69,6 +70,9 @@ gui_render_log(Gui*, Camera*);
void void
gui_render_event_message(Gui*, Camera*); gui_render_event_message(Gui*, Camera*);
void
gui_render_tooltip(Gui*, Camera*);
void void
gui_log(const char *fmt, ...); gui_log(const char *fmt, ...);

View File

@ -19,20 +19,11 @@
#include "texturecache.h" #include "texturecache.h"
#include "gui_util.h" #include "gui_util.h"
static SDL_Rect frame_top_left = { 16, 160, 16, 16 }; static Sprite *
static SDL_Rect frame_top_right = { 48, 160, 16, 16 }; render_frame_on_texture(Uint32 width,
static SDL_Rect frame_bottom_left = { 16, 192, 16, 16 }; Uint32 height,
static SDL_Rect frame_bottom_right = { 48, 192, 16, 16 }; Position offset,
static SDL_Rect frame_top = { 32, 160, 16, 16 }; Camera *cam)
static SDL_Rect frame_bottom = { 32, 192, 16, 16 };
static SDL_Rect frame_center = { 32, 176, 16, 16 };
static SDL_Rect frame_left = { 16, 176, 16, 16 };
static SDL_Rect frame_right = { 48, 176, 16, 16 };
Sprite *
gui_util_create_frame_sprite(Uint32 width,
Uint32 height,
Camera *cam)
{ {
Sprite *frame = sprite_create(); Sprite *frame = sprite_create();
Texture *texture = texture_create(); Texture *texture = texture_create();
@ -48,11 +39,21 @@ gui_util_create_frame_sprite(Uint32 width,
texture_create_blank(texture, texture_create_blank(texture,
SDL_TEXTUREACCESS_TARGET, SDL_TEXTUREACCESS_TARGET,
cam->renderer); cam->renderer);
Texture *source = texturecache_get("GUI/GUI0.png");
SDL_SetRenderTarget(cam->renderer, texture->texture); SDL_SetRenderTarget(cam->renderer, texture->texture);
SDL_RenderClear(cam->renderer); SDL_RenderClear(cam->renderer);
SDL_Rect frame_top_left = CLIP16(offset.x, offset.y);
SDL_Rect frame_top_right = CLIP16(offset.x + 32, offset.y);
SDL_Rect frame_bottom_left = CLIP16(offset.x, offset.y + 32);
SDL_Rect frame_bottom_right = CLIP16(offset.x + 32, offset.y + 32);
SDL_Rect frame_top = CLIP16(offset.x + 16, offset.y);
SDL_Rect frame_bottom = CLIP16(offset.x + 16, offset.y + 32);
SDL_Rect frame_center = CLIP16(offset.x + 16, offset.y + 16);
SDL_Rect frame_left = CLIP16(offset.x, offset.y + 16);
SDL_Rect frame_right = CLIP16(offset.x + 32, offset.y + 16);
Texture *source = texturecache_get("GUI/GUI0.png");
SDL_Rect box = { 0, 0, 16, 16 }; SDL_Rect box = { 0, 0, 16, 16 };
unsigned int i, j; unsigned int i, j;
for (i = 0; i < width; ++i) { for (i = 0; i < width; ++i) {
@ -108,6 +109,24 @@ gui_util_create_frame_sprite(Uint32 width,
} }
} }
} }
SDL_SetRenderTarget(cam->renderer, NULL); SDL_SetRenderTarget(cam->renderer, NULL);
return frame; return frame;
} }
Sprite *
gui_util_create_frame_sprite(Uint32 width,
Uint32 height,
Camera *cam)
{
return render_frame_on_texture(width, height, POS(16, 16*10), cam);
}
Sprite *
gui_util_create_tooltip_frame_sprite(Uint32 width,
Uint32 height,
Camera *cam)
{
return render_frame_on_texture(width, height, POS(16*13, 16*13), cam);
}

View File

@ -25,3 +25,8 @@ Sprite *
gui_util_create_frame_sprite(Uint32 width, gui_util_create_frame_sprite(Uint32 width,
Uint32 height, Uint32 height,
Camera*); Camera*);
Sprite *
gui_util_create_tooltip_frame_sprite(Uint32 width,
Uint32 height,
Camera*);

View File

@ -107,6 +107,21 @@ get_event_modkey(SDL_Event *event)
key = KEY_CTRL_S; break; key = KEY_CTRL_S; break;
case SDLK_m: case SDLK_m:
key = KEY_CTRL_M; break; key = KEY_CTRL_M; break;
case SDLK_d:
key = KEY_CTRL_D; break;
}
} else if (event->key.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT)) {
switch (event->key.keysym.sym) {
case SDLK_1:
key = KEY_SHIFT_NUM1; break;
case SDLK_2:
key = KEY_SHIFT_NUM2; break;
case SDLK_3:
key = KEY_SHIFT_NUM3; break;
case SDLK_4:
key = KEY_SHIFT_NUM4; break;
case SDLK_5:
key = KEY_SHIFT_NUM5; break;
default: default:
key = 0; break; key = 0; break;
} }

View File

@ -39,8 +39,14 @@
#define KEY_ESC 16384 #define KEY_ESC 16384
#define KEY_ENTER 32768 #define KEY_ENTER 32768
#define KEY_CTRL_M 1 #define KEY_CTRL_M 0x1
#define KEY_CTRL_S 2 #define KEY_CTRL_S 0x2
#define KEY_CTRL_D 0x4
#define KEY_SHIFT_NUM1 0x8
#define KEY_SHIFT_NUM2 0x10
#define KEY_SHIFT_NUM3 0x20
#define KEY_SHIFT_NUM4 0x40
#define KEY_SHIFT_NUM5 0x80
#define MBUTTON_LEFT 1 #define MBUTTON_LEFT 1
#define MBUTTON_MIDDLE 2 #define MBUTTON_MIDDLE 2

View File

@ -52,29 +52,80 @@
#include "screen.h" #include "screen.h"
#include "hiscore.h" #include "hiscore.h"
#include "io_util.h" #include "io_util.h"
#include "tooltip.h"
static char *skills_tooltip[] = {
"CONGRATULATIONS!",
"",
" You have aquired a new skill!",
"",
" Skills are listed in the bar below the game screen.",
"",
"",
" SKILL INFO: CTRL + <NUM>",
" Where <NUM> is the skill number (1-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",
"",
" ATTACK: Walk into a monster to attack it",
"",
" THROW DAGGER: Press 4 then chose a direction (navigation keys)",
"",
" DRINK HEALTH: Press 5 (if you need health and have potions)",
"",
" TOGGLE MUSIC: CTRL + M",
"",
" TOGGLE SOUND: CTRL + S",
"",
" 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 { typedef enum Turn_t {
PLAYER, PLAYER,
MONSTER MONSTER
} Turn; } Turn;
static SDL_Window *gWindow = NULL; static SDL_Window *gWindow = NULL;
static SDL_Renderer *gRenderer = NULL; static SDL_Renderer *gRenderer = NULL;
static Player *gPlayer = NULL; static Player *gPlayer = NULL;
static Map *gMap = NULL; static Map *gMap = NULL;
static RoomMatrix *gRoomMatrix = NULL; static RoomMatrix *gRoomMatrix = NULL;
static Gui *gGui = NULL; static Gui *gGui = NULL;
static SkillBar *gSkillBar = NULL; static SkillBar *gSkillBar = NULL;
static Pointer *gPointer = NULL; static Pointer *gPointer = NULL;
static Menu *mainMenu = NULL; static Menu *mainMenu = NULL;
static Menu *inGameMenu = NULL; static Menu *inGameMenu = NULL;
static Timer *menuTimer = NULL; static Timer *menuTimer = NULL;
static Camera *gCamera = NULL; static Camera *gCamera = NULL;
static Screen *creditsScreen = NULL; static Screen *creditsScreen = NULL;
static Screen *scoreScreen = NULL; static Screen *scoreScreen = NULL;
static unsigned int cLevel = 1; static Sprite *new_skill_tooltip = NULL;
static float deltaTime = 1.0; static Sprite *howto_tooltip = NULL;
static double renderScale = 1.0; static unsigned int cLevel = 1;
static float deltaTime = 1.0;
static double renderScale = 1.0;
static GameState gGameState; static GameState gGameState;
static SDL_Rect gameViewport; static SDL_Rect gameViewport;
static SDL_Rect skillBarViewport; static SDL_Rect skillBarViewport;
@ -218,12 +269,17 @@ startGame(void *unused)
gGameState = PLAYING; gGameState = PLAYING;
if (gPlayer) if (gPlayer)
player_destroy(gPlayer); player_destroy(gPlayer);
gPlayer = player_create(WARRIOR, gRenderer); gPlayer = player_create(WARRIOR, gCamera);
mixer_play_music(GAME_MUSIC0 + get_random(2)); mixer_play_music(GAME_MUSIC0 + get_random(2));
resetGame(); resetGame();
gui_clear_message_log(); gui_clear_message_log();
gui_log("The Dungeon Crawl begins!"); gui_log("The Dungeon Crawl begins!");
gui_event_message("Welcome to the dungeon!"); gui_event_message("Welcome to the dungeon!");
Settings *settings = settings_get();
if (!settings->howto_tooltip_shown)
gGui->activeTooltip = howto_tooltip;
settings->howto_tooltip_shown = true;
} }
static void static void
@ -249,6 +305,7 @@ static void
goToMainMenu(void *unused) goToMainMenu(void *unused)
{ {
UNUSED(unused); UNUSED(unused);
gui_clear_message_log();
gGameState = MENU; gGameState = MENU;
menu_destroy(inGameMenu); menu_destroy(inGameMenu);
inGameMenu = NULL; inGameMenu = NULL;
@ -291,16 +348,25 @@ createMenu(Menu **menu, struct MENU_ITEM menu_items[], unsigned int size)
} }
} }
static void
showHowToTooltip(void *unused)
{
UNUSED(unused);
toggleInGameMenu(NULL);
gGui->activeTooltip = howto_tooltip;
}
static void static void
initInGameMenu(void) initInGameMenu(void)
{ {
struct MENU_ITEM menu_items[] = { struct MENU_ITEM menu_items[] = {
{ "RESUME", toggleInGameMenu }, { "RESUME", toggleInGameMenu },
{ "HOW TO PLAY", showHowToTooltip },
{ "MAIN MENU", goToMainMenu }, { "MAIN MENU", goToMainMenu },
{ "QUIT", exitGame }, { "QUIT", exitGame },
}; };
createMenu(&inGameMenu, menu_items, 3); createMenu(&inGameMenu, menu_items, 4);
} }
static void static void
@ -412,6 +478,9 @@ init(void)
hiscore_init(); hiscore_init();
initMainMenu(); initMainMenu();
howto_tooltip = tooltip_create(how_to_play_tooltip, gCamera);
new_skill_tooltip = tooltip_create(skills_tooltip, gCamera);
gCamera->pos = (Position) { 0, 0 }; gCamera->pos = (Position) { 0, 0 };
gGameState = MENU; gGameState = MENU;
@ -426,7 +495,7 @@ handle_main_input(void)
|| gGameState == IN_GAME_MENU || gGameState == IN_GAME_MENU
|| gGameState == GAME_OVER) || gGameState == GAME_OVER)
{ {
if (input_key_is_pressed(&input, KEY_ESC)) if (!gGui->activeTooltip && input_key_is_pressed(&input, KEY_ESC))
toggleInGameMenu(NULL); toggleInGameMenu(NULL);
} }
@ -436,6 +505,8 @@ handle_main_input(void)
gGameState = MENU; gGameState = MENU;
else if (gGameState == MENU && input_key_is_pressed(&input, KEY_ESC)) else if (gGameState == MENU && input_key_is_pressed(&input, KEY_ESC))
gGameState = QUIT; gGameState = QUIT;
else if (gGui->activeTooltip && input_key_is_pressed(&input, KEY_ESC))
gGui->activeTooltip = NULL;
if (input_modkey_is_pressed(&input, KEY_CTRL_M)) { if (input_modkey_is_pressed(&input, KEY_CTRL_M)) {
if (mixer_toggle_music(&gGameState)) if (mixer_toggle_music(&gGameState))
@ -450,6 +521,15 @@ handle_main_input(void)
else else
gui_log("Sound disabled"); gui_log("Sound disabled");
} }
if (input_modkey_is_pressed(&input, KEY_CTRL_D)) {
Settings *s = settings_get();
s->tooltips_enabled = !s->tooltips_enabled;
if (s->tooltips_enabled)
gui_log("Tooltips enabled");
else
gui_log("Tooltips disabled");
}
} }
static bool static bool
@ -518,6 +598,7 @@ populateUpdateData(UpdateData *data, float deltatime)
data->map = gMap; data->map = gMap;
data->matrix = gRoomMatrix; data->matrix = gRoomMatrix;
data->input = &input; data->input = &input;
data->gui = gGui;
data->deltatime = deltatime; data->deltatime = deltatime;
} }
@ -531,9 +612,14 @@ run_game_update(void)
menu_update(inGameMenu, &input); menu_update(inGameMenu, &input);
populateUpdateData(&updateData, deltaTime); populateUpdateData(&updateData, deltaTime);
bool skillActivated = false;
if (playerLevel != gPlayer->stats.lvl) { if (playerLevel != gPlayer->stats.lvl) {
playerLevel = gPlayer->stats.lvl; playerLevel = gPlayer->stats.lvl;
skillbar_check_skill_activation(gSkillBar, gPlayer); skillActivated = skillbar_check_skill_activation(gSkillBar,
gPlayer);
}
if (skillActivated && settings_get()->tooltips_enabled && playerLevel < 5) {
gGui->activeTooltip = new_skill_tooltip;
} }
map_clear_expired_entities(gMap, gPlayer); map_clear_expired_entities(gMap, gPlayer);
@ -601,6 +687,7 @@ run_game_render(void)
SDL_RenderSetViewport(gRenderer, NULL); SDL_RenderSetViewport(gRenderer, NULL);
particle_engine_render_global(gCamera); particle_engine_render_global(gCamera);
gui_render_tooltip(gGui, gCamera);
if (gGameState == IN_GAME_MENU) { if (gGameState == IN_GAME_MENU) {
SDL_Rect dimmer = { 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT }; SDL_Rect dimmer = { 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT };
@ -630,7 +717,6 @@ run_game(void)
gui_event_message("NEW HIGHSCORE"); gui_event_message("NEW HIGHSCORE");
gui_log("NEW HIGHSCORE"); gui_log("NEW HIGHSCORE");
} }
gui_event_message("Press ESC to open menu");
mixer_play_effect(SPLAT); mixer_play_effect(SPLAT);
gGameState = GAME_OVER; gGameState = GAME_OVER;
createInGameGameOverMenu(); createInGameGameOverMenu();
@ -750,6 +836,8 @@ void close(void)
if (inGameMenu) if (inGameMenu)
menu_destroy(inGameMenu); menu_destroy(inGameMenu);
sprite_destroy(howto_tooltip);
sprite_destroy(new_skill_tooltip);
camera_destroy(gCamera); camera_destroy(gCamera);
roommatrix_destroy(gRoomMatrix); roommatrix_destroy(gRoomMatrix);
gui_destroy(gGui); gui_destroy(gGui);

View File

@ -428,7 +428,7 @@ build_sword_animation(Player *p, SDL_Renderer *renderer)
} }
Player* Player*
player_create(class_t class, SDL_Renderer *renderer) player_create(class_t class, Camera *cam)
{ {
Player *player = malloc(sizeof(Player)); Player *player = malloc(sizeof(Player));
player->sprite = sprite_create(); player->sprite = sprite_create();
@ -451,7 +451,7 @@ player_create(class_t class, SDL_Renderer *renderer)
player->animationTimer = timer_create(); player->animationTimer = timer_create();
player->swordAnimation = animation_create(5); player->swordAnimation = animation_create(5);
build_sword_animation(player, renderer); build_sword_animation(player, cam->renderer);
memset(&player->skills, memset(&player->skills,
0, PLAYER_SKILL_COUNT * sizeof(Skill*)); 0, PLAYER_SKILL_COUNT * sizeof(Skill*));
@ -480,16 +480,16 @@ player_create(class_t class, SDL_Renderer *renderer)
case WARRIOR: case WARRIOR:
m_strcpy(asset, 100, "Commissions/Warrior.png"); m_strcpy(asset, 100, "Commissions/Warrior.png");
player->stats = (Stats) WARRIOR_STATS; player->stats = (Stats) WARRIOR_STATS;
player->skills[0] = skill_create(FLURRY); player->skills[0] = skill_create(FLURRY, cam);
player->skills[1] = skill_create(BASH); player->skills[1] = skill_create(BASH, cam);
player->skills[2] = skill_create(CHARGE); player->skills[2] = skill_create(CHARGE, cam);
player->skills[3] = skill_create(DAGGER_THROW); player->skills[3] = skill_create(DAGGER_THROW, cam);
break; break;
} }
player->skills[4] = skill_create(SIP_HEALTH); player->skills[4] = skill_create(SIP_HEALTH, cam);
sprite_load_texture(player->sprite, asset, 0, renderer); sprite_load_texture(player->sprite, asset, 0, cam->renderer);
player->sprite->pos = (Position) { TILE_DIMENSION, TILE_DIMENSION }; player->sprite->pos = (Position) { TILE_DIMENSION, TILE_DIMENSION };
player->sprite->dim = GAME_DIMENSION; player->sprite->dim = GAME_DIMENSION;
player->sprite->clip = (SDL_Rect) { 0, 0, 16, 16 }; player->sprite->clip = (SDL_Rect) { 0, 0, 16, 16 };

View File

@ -79,7 +79,7 @@ typedef struct Player {
} Player; } Player;
Player* Player*
player_create(class_t, SDL_Renderer*); player_create(class_t, Camera*);
ExperienceData ExperienceData
player_get_xp_data(Player*); player_get_xp_data(Player*);

View File

@ -21,6 +21,8 @@
#include <stdbool.h> #include <stdbool.h>
#define POS(x, y) (Position) { x, y }
typedef struct { typedef struct {
int x; int x;
int y; int y;

View File

@ -27,8 +27,10 @@
static sqlite3 *db = NULL; static sqlite3 *db = NULL;
static Settings settings; static Settings settings;
static const char *KEY_MUSIC_ENABLED = "music_enabled"; static const char *KEY_MUSIC_ENABLED = "music_enabled";
static const char *KEY_SOUND_ENABLED = "sound_enabled"; static const char *KEY_SOUND_ENABLED = "sound_enabled";
static const char *KEY_TOOLTIPS_ENABLED = "tooltips_enabled";
static const char *KEY_HOW_TO_PLAY_SHOWN = "how_to_play_shown";
static static
DbQuery MIGRATE_COMMANDS[] = { DbQuery MIGRATE_COMMANDS[] = {
@ -49,6 +51,8 @@ set_default_settings(void)
{ {
settings.music_enabled = true; settings.music_enabled = true;
settings.sound_enabled = true; settings.sound_enabled = true;
settings.tooltips_enabled = true;
settings.howto_tooltip_shown = false;
} }
static void static void
@ -82,6 +86,14 @@ load_settings_cb(void *unused, int count, char **values, char **colNames)
settings.music_enabled = (bool)atoi(values[i + 1]); settings.music_enabled = (bool)atoi(values[i + 1]);
i += 2; i += 2;
} }
else if (!strcmp(KEY_HOW_TO_PLAY_SHOWN, values[i])) {
settings.howto_tooltip_shown = (bool)atoi(values[i + 1]);
i += 2;
}
else if (!strcmp(KEY_TOOLTIPS_ENABLED, values[i])) {
settings.tooltips_enabled = (bool)atoi(values[i + 1]);
i += 2;
}
} }
return 0; return 0;
} }
@ -127,6 +139,8 @@ settings_save(void)
{ {
save_setting_int(KEY_SOUND_ENABLED, settings.sound_enabled); save_setting_int(KEY_SOUND_ENABLED, settings.sound_enabled);
save_setting_int(KEY_MUSIC_ENABLED, settings.music_enabled); save_setting_int(KEY_MUSIC_ENABLED, settings.music_enabled);
save_setting_int(KEY_TOOLTIPS_ENABLED, settings.tooltips_enabled);
save_setting_int(KEY_HOW_TO_PLAY_SHOWN, settings.howto_tooltip_shown);
} }
Settings * Settings *

View File

@ -24,6 +24,8 @@
typedef struct Settings { typedef struct Settings {
bool music_enabled; bool music_enabled;
bool sound_enabled; bool sound_enabled;
bool tooltips_enabled;
bool howto_tooltip_shown;
} Settings; } Settings;
void void

View File

@ -35,6 +35,106 @@
#include "animation.h" #include "animation.h"
#include "artifact.h" #include "artifact.h"
#include "trap.h" #include "trap.h"
#include "tooltip.h"
static char *flurry_tooltip[] = {
"FLURRY",
"",
" Hits an adjecant enemy with a flurry of three strikes.",
" Each strike has the same odds of hitting as a regular attack",
"",
"COOLDOWN:",
" 5 turns",
"",
"USAGE:",
" activate the skill (press 1)",
" followed by a direction (left, right, up or down)",
"",
"",
"Press ESC to close",
NULL
};
static char *bash_tooltip[] = {
"BASH",
"",
" Bashes an adjecant enemy with your shield",
" On a successful hit the target will be stunned for 2 turns",
"",
"COOLDOWN:",
" 2 turns",
"",
"USAGE:",
" activate the skill (press 2)",
" followed by a direction (left, right, up or down)",
"",
"",
"Press ESC to close",
NULL
};
static char *charge_tooltip[] = {
"CHARGE",
"",
" You charge in a chosen direction into the first obstructing",
" object. Charging into an enemy can deliver massive damage.",
"",
" Damage is affected by charge distance.",
" Longer distance, more damage.",
"",
"COOLDOWN:",
" 5 turns",
"",
"USAGE:",
" activate the skill (press 3)",
" followed by a direction (left, right, up or down)",
"",
"",
"Press ESC to close",
NULL
};
static char *dagger_tooltip[] = {
"THROW DAGGER",
"",
" You throw a dagger in the chosen direction.",
"",
" Damage is affected by throwing distance.",
" Longer distance, more damage.",
"",
" Dagger supply is not infinite, your current dagger",
" inventory is displayed in the panel to the right.",
"",
"COOLDOWN:",
" 0 turns",
"",
"USAGE:",
" activate the skill (press 4)",
" followed by a direction (left, right, up or down)",
"",
"",
"Press ESC to close",
NULL
};
static char *health_tooltip[] = {
"DRINK HEALTH",
"",
" You take a sip from your health vial",
"",
" The current amount of sips in your vials is",
" dsplayed in the panel to the right.",
"",
"COOLDOWN:",
" 0 turns",
"",
"USAGE:",
" Sip health (press 5)",
"",
"",
"Press ESC to close",
NULL
};
static Skill * static Skill *
create_default(const char *s_label, Sprite *s) create_default(const char *s_label, Sprite *s)
@ -50,6 +150,7 @@ create_default(const char *s_label, Sprite *s)
skill->available = NULL; skill->available = NULL;
skill->use = NULL; skill->use = NULL;
skill->levelcap = 1; skill->levelcap = 1;
skill->tooltip = NULL;
return skill; return skill;
} }
@ -410,24 +511,29 @@ create_charge(void)
} }
Skill* Skill*
skill_create(enum SkillType t) skill_create(enum SkillType t, Camera *cam)
{ {
Skill *skill; Skill *skill;
switch (t) { switch (t) {
case FLURRY: case FLURRY:
skill = create_flurry(); skill = create_flurry();
skill->tooltip = tooltip_create(flurry_tooltip, cam);
break; break;
case SIP_HEALTH: case SIP_HEALTH:
skill = create_sip_health(); skill = create_sip_health();
skill->tooltip = tooltip_create(health_tooltip, cam);
break; break;
case CHARGE: case CHARGE:
skill = create_charge(); skill = create_charge();
skill->tooltip = tooltip_create(charge_tooltip, cam);
break; break;
case DAGGER_THROW: case DAGGER_THROW:
skill = create_throw_dagger(); skill = create_throw_dagger();
skill->tooltip = tooltip_create(dagger_tooltip, cam);
break; break;
case BASH: case BASH:
skill = create_bash(); skill = create_bash();
skill->tooltip = tooltip_create(bash_tooltip, cam);
break; break;
default: default:
fatal("Unknown SkillType %u", (unsigned int) t); fatal("Unknown SkillType %u", (unsigned int) t);
@ -444,5 +550,7 @@ void
skill_destroy(Skill *skill) skill_destroy(Skill *skill)
{ {
sprite_destroy(skill->icon); sprite_destroy(skill->icon);
if (skill->tooltip)
sprite_destroy(skill->tooltip);
free(skill); free(skill);
} }

View File

@ -52,10 +52,11 @@ typedef struct Skill_t {
bool active; bool active;
bool (*available)(Player*); bool (*available)(Player*);
bool (*use)(struct Skill_t*, SkillData*); bool (*use)(struct Skill_t*, SkillData*);
Sprite *tooltip;
} Skill; } Skill;
Skill* Skill*
skill_create(enum SkillType); skill_create(enum SkillType, Camera *cam);
void void
skill_destroy(Skill*); skill_destroy(Skill*);

View File

@ -26,6 +26,7 @@
#include "texturecache.h" #include "texturecache.h"
#include "particle_engine.h" #include "particle_engine.h"
#include "update_data.h" #include "update_data.h"
#include "gui.h"
static void static void
load_texture(SkillBar *bar, const char *path, SDL_Renderer *renderer) load_texture(SkillBar *bar, const char *path, SDL_Renderer *renderer)
@ -34,7 +35,7 @@ load_texture(SkillBar *bar, const char *path, SDL_Renderer *renderer)
t->dim.width = 16; t->dim.width = 16;
t->dim.height = 16; t->dim.height = 16;
for (unsigned int i = 0; i < 10; ++i) { for (unsigned int i = 0; i < 5; ++i) {
char buffer[4]; char buffer[4];
Sprite *s = sprite_create(); Sprite *s = sprite_create();
s->pos = (Position) { i * 32 + 20, 20 }; s->pos = (Position) { i * 32 + 20, 20 };
@ -73,7 +74,7 @@ skillbar_create(SDL_Renderer *renderer)
return bar; return bar;
} }
void bool
skillbar_check_skill_activation(SkillBar *bar, Player *player) skillbar_check_skill_activation(SkillBar *bar, Player *player)
{ {
for (int i = 0; i < PLAYER_SKILL_COUNT; ++i) { for (int i = 0; i < PLAYER_SKILL_COUNT; ++i) {
@ -85,6 +86,8 @@ skillbar_check_skill_activation(SkillBar *bar, Player *player)
timer_start(bar->skillSparkleTimer); timer_start(bar->skillSparkleTimer);
} }
return timer_started(bar->skillSparkleTimer);
} }
static void static void
@ -256,8 +259,17 @@ skillbar_update(SkillBar *bar, UpdateData *data)
{ {
Input *input = data->input; Input *input = data->input;
unsigned int key = 0; for (int i = 0; i < 5; ++i) {
for (int i = 0; i < 10; ++i) { if (!data->player->skills[i])
continue;
if (input_modkey_is_pressed(input, KEY_SHIFT_NUM1 << i)) {
data->gui->activeTooltip = data->player->skills[i]->tooltip;
return;
}
}
Uint32 key = 0;
for (int i = 0; i < 5; ++i) {
if (!input_key_is_pressed(input, KEY_NUM0 << i)) if (!input_key_is_pressed(input, KEY_NUM0 << i))
continue; continue;
key = i; key = i;

View File

@ -39,7 +39,7 @@ typedef struct SkillBar_t {
SkillBar * SkillBar *
skillbar_create(SDL_Renderer*); skillbar_create(SDL_Renderer*);
void bool
skillbar_check_skill_activation(SkillBar*, Player*); skillbar_check_skill_activation(SkillBar*, Player*);
void void

64
src/tooltip.c Normal file
View File

@ -0,0 +1,64 @@
/*
* BreakHack - A dungeone crawler RPG
* Copyright (C) 2018 Linus Probert <linus.probert@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "tooltip.h"
#include "gui_util.h"
#include "defines.h"
#include "gui.h"
Sprite *
tooltip_create(char **content, Camera *cam)
{
int rowCount = 0;
char **contentIndex = content;
while (*contentIndex) {
rowCount++;
contentIndex++;
}
Sprite *sprite = gui_util_create_tooltip_frame_sprite(BOTTOM_GUI_WIDTH/16 - 6,
(Uint32) ((rowCount * 10 + 48)/16),
cam);
sprite->pos.x = 48;
sprite->pos.y = 96;
Texture *texture = sprite->textures[0];
Texture *text = texture_create();
texture_load_font(text, "GUI/SDS_8x8.ttf", LOG_FONT_SIZE, 0);
SDL_SetRenderTarget(cam->renderer, texture->texture);
SDL_Rect renderBox = { 16, 16, 0, 0 };
while (*content) {
if (strlen(*content) > 0) {
texture_load_from_text(text,
*content,
C_WHITE,
C_WHITE,
cam->renderer);
renderBox.w = text->dim.width;
renderBox.h = text->dim.height;
texture_render(text, &renderBox, cam);
}
renderBox.y += 10;
content++;
}
SDL_SetRenderTarget(cam->renderer, NULL);
texture_destroy(text);
return sprite;
}

25
src/tooltip.h Normal file
View File

@ -0,0 +1,25 @@
/*
* BreakHack - A dungeone crawler RPG
* Copyright (C) 2018 Linus Probert <linus.probert@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "camera.h"
#include "sprite.h"
Sprite *
tooltip_create(char **content, Camera*);

View File

@ -22,11 +22,13 @@
#include "player.h" #include "player.h"
#include "map.h" #include "map.h"
#include "roommatrix.h" #include "roommatrix.h"
#include "gui.h"
typedef struct UpdateData { typedef struct UpdateData {
Player *player; Player *player;
Map *map; Map *map;
RoomMatrix *matrix; RoomMatrix *matrix;
Gui *gui;
Input *input; Input *input;
float deltatime; float deltatime;
} UpdateData; } UpdateData;