diff --git a/src/artifact.c b/src/artifact.c index d4f6e2e..99022d9 100644 --- a/src/artifact.c +++ b/src/artifact.c @@ -26,65 +26,39 @@ static void artifact_set_effect(Artifact *a, MagicalEffect effect) { - Texture *t; - a->effect = effect; switch (effect) { case IMPROVED_HEARING: a->info.name = "Potion of ear juice"; a->info.desc = "Your hearing is slightly improved"; - t = texturecache_add("Items/Potion.png"); - sprite_set_texture(a->sprite, t, 0); - a->sprite->clip = CLIP16(7*16, 4*16); break; case TRAP_AVOIDANCE: a->info.name = "Boot with nails inside"; a->info.desc = "You are lighter on your feet"; - t = texturecache_add("Items/Boot.png"); - sprite_set_texture(a->sprite, t, 0); - a->sprite->clip = CLIP16(5*16, 0); break; case PIERCING_DAGGERS: a->info.name = "Whetstone"; a->info.desc = "Your daggers are sharper"; - t = texturecache_add("Items/Rock.png"); - sprite_set_texture(a->sprite, t, 0); - a->sprite->clip = CLIP16(0, 0); break; case CHARGE_THROUGH: a->info.name = "Greasy shield"; a->info.desc = "You glide through obstructions"; - t = texturecache_add("Items/Shield.png"); - sprite_set_texture(a->sprite, t, 0); - a->sprite->clip = CLIP16(16, 0); break; case PUSH_BACK: a->info.name = "Glove of strength"; a->info.desc = "Your arm is stronger"; - t = texturecache_add("Items/Glove.png"); - sprite_set_texture(a->sprite, t, 0); - a->sprite->clip = CLIP16(0, 0); break; case DAGGER_RECOVERY: a->info.name = "Forging hammer"; a->info.desc = "Your daggers are more durable"; - t = texturecache_add("Items/LongWep.png"); - sprite_set_texture(a->sprite, t, 0); - a->sprite->clip = CLIP16(0, 6*16); break; case INCREASED_STUN: a->info.name = "Solid shield"; a->info.desc = "Your shield is harder"; - t = texturecache_add("Items/Shield.png"); - sprite_set_texture(a->sprite, t, 0); - a->sprite->clip = CLIP16(4*16, 0); break; case FEAR_INDUCING: a->info.name = "Ugly shirt"; a->info.desc = "You look disgusting"; - t = texturecache_add("Items/Armor.png"); - sprite_set_texture(a->sprite, t, 0); - a->sprite->clip = CLIP16(6*16, 8*16); break; default: break; @@ -107,11 +81,63 @@ artifact_create_random(Player *p, Uint8 level) return a; } +Sprite * +artifact_sprite_for(MagicalEffect effect) +{ + Sprite *sprite = sprite_create(); + Texture *t; + switch (effect) { + case IMPROVED_HEARING: + t = texturecache_add("Items/Potion.png"); + sprite_set_texture(sprite, t, 0); + sprite->clip = CLIP16(7*16, 4*16); + break; + case TRAP_AVOIDANCE: + t = texturecache_add("Items/Boot.png"); + sprite_set_texture(sprite, t, 0); + sprite->clip = CLIP16(5*16, 0); + break; + case PIERCING_DAGGERS: + t = texturecache_add("Items/Rock.png"); + sprite_set_texture(sprite, t, 0); + sprite->clip = CLIP16(0, 0); + break; + case CHARGE_THROUGH: + t = texturecache_add("Items/Shield.png"); + sprite_set_texture(sprite, t, 0); + sprite->clip = CLIP16(16, 0); + break; + case PUSH_BACK: + t = texturecache_add("Items/Glove.png"); + sprite_set_texture(sprite, t, 0); + sprite->clip = CLIP16(0, 0); + break; + case DAGGER_RECOVERY: + t = texturecache_add("Items/LongWep.png"); + sprite_set_texture(sprite, t, 0); + sprite->clip = CLIP16(0, 6*16); + break; + case INCREASED_STUN: + t = texturecache_add("Items/Shield.png"); + sprite_set_texture(sprite, t, 0); + sprite->clip = CLIP16(4*16, 0); + break; + case FEAR_INDUCING: + t = texturecache_add("Items/Armor.png"); + sprite_set_texture(sprite, t, 0); + sprite->clip = CLIP16(6*16, 8*16); + break; + default: + break; + } + return sprite; +} + Artifact * artifact_create(MagicalEffect effect) { Artifact *a = ec_malloc(sizeof(Artifact)); - a->sprite = sprite_create(); + a->sprite = artifact_sprite_for(effect); a->sprite->dim = GAME_DIMENSION; a->collected = false; a->level = 1; diff --git a/src/artifact.h b/src/artifact.h index eeb2471..689b77c 100644 --- a/src/artifact.h +++ b/src/artifact.h @@ -45,6 +45,9 @@ typedef struct Artifact { int level; } Artifact; +Sprite * +artifact_sprite_for(MagicalEffect); + Artifact * artifact_create_random(Player*, Uint8 level); diff --git a/src/dimension.h b/src/dimension.h index ddbc1b0..7b1b8d1 100644 --- a/src/dimension.h +++ b/src/dimension.h @@ -19,6 +19,8 @@ #ifndef DIMENSION_H_ #define DIMENSION_H_ +#define DIM(x, y) (Dimension) { x, y } + typedef struct { unsigned int width; unsigned int height; diff --git a/src/main.c b/src/main.c index ca9389e..86c3e94 100644 --- a/src/main.c +++ b/src/main.c @@ -54,6 +54,27 @@ #include "io_util.h" #include "tooltip.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!", "", @@ -123,6 +144,7 @@ static Screen *creditsScreen = NULL; static Screen *scoreScreen = 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 double renderScale = 1.0; @@ -251,7 +273,7 @@ initGame(void) gCamera = camera_create(gRenderer); gRoomMatrix = roommatrix_create(); gGui = gui_create(gCamera); - gSkillBar = skillbar_create(gRenderer); + gSkillBar = skillbar_create(gCamera); item_builder_init(gRenderer); gPointer = pointer_create(gRenderer); particle_engine_init(); @@ -452,6 +474,8 @@ resetGame(void) if (gMap) map_destroy(gMap); + skillbar_reset(gSkillBar); + particle_engine_clear(); info("Building new map"); @@ -480,6 +504,7 @@ init(void) 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); gCamera->pos = (Position) { 0, 0 }; @@ -600,6 +625,7 @@ populateUpdateData(UpdateData *data, float deltatime) data->input = &input; data->gui = gGui; data->deltatime = deltatime; + data->cam = gCamera; } static void @@ -607,6 +633,7 @@ run_game_update(void) { static UpdateData updateData; static unsigned int playerLevel = 1; + static bool artifactTooltipShown = false; if (gGameState == IN_GAME_MENU) menu_update(inGameMenu, &input); @@ -621,6 +648,10 @@ run_game_update(void) if (skillActivated && settings_get()->tooltips_enabled && playerLevel < 5) { gGui->activeTooltip = new_skill_tooltip; } + if (!artifactTooltipShown && gPlayer->equipment.hasArtifacts) { + artifactTooltipShown = true; + gGui->activeTooltip = new_artifact_tooltip; + } map_clear_expired_entities(gMap, gPlayer); if (gGameState == PLAYING && currentTurn == PLAYER) diff --git a/src/player.c b/src/player.c index 3225da3..41f8558 100644 --- a/src/player.c +++ b/src/player.c @@ -450,6 +450,7 @@ player_create(class_t class, Camera *cam) player->projectiles = linkedlist_create(); player->animationTimer = timer_create(); player->swordAnimation = animation_create(5); + player->equipment.hasArtifacts = false; build_sword_animation(player, cam->renderer); @@ -624,6 +625,7 @@ player_reset(Player *player) { for (size_t i = 0; i < LAST_ARTIFACT_EFFECT; ++i) player->equipment.artifacts[i].level = 0; + player->equipment.hasArtifacts = false; while (player->projectiles) projectile_destroy(linkedlist_pop(&player->projectiles)); @@ -677,4 +679,5 @@ player_add_artifact(Player *p, Artifact *a) gui_log("You pick an ancient %s", ad->name); gui_log("%s (%u)", ad->desc, ad->level); + p->equipment.hasArtifacts = true; } diff --git a/src/player.h b/src/player.h index 2e921a2..07d970d 100644 --- a/src/player.h +++ b/src/player.h @@ -59,6 +59,7 @@ typedef struct ArtifactData { typedef struct PlayerEquipment { ArtifactData artifacts[LAST_ARTIFACT_EFFECT]; + bool hasArtifacts; } PlayerEquipment; typedef struct Player { diff --git a/src/skillbar.c b/src/skillbar.c index 709ec5b..cd01a9c 100644 --- a/src/skillbar.c +++ b/src/skillbar.c @@ -53,7 +53,7 @@ load_countdown_sprites(SkillBar *bar) { for (int i = 0; i < PLAYER_SKILL_COUNT; ++i) { Sprite *s = sprite_create(); - sprite_load_text_texture(s, "GUI/SDS_8x8.ttf", 0, 16, 0); + sprite_load_text_texture(s, "GUI/SDS_8x8.ttf", 0, 14, 1); s->fixed = true; s->pos = (Position) { 8 + (32 * i), 8 }; s->dim = (Dimension) { 16, 16 }; @@ -61,47 +61,36 @@ load_countdown_sprites(SkillBar *bar) } } -SkillBar * -skillbar_create(SDL_Renderer *renderer) -{ - SkillBar *bar = ec_malloc(sizeof(SkillBar)); - bar->sprites = linkedlist_create(); - bar->activationTimer = timer_create(); - bar->skillSparkleTimer = timer_create(); - bar->lastActivation = 0; - load_texture(bar, "GUI/GUI0.png", renderer); - load_countdown_sprites(bar); - return bar; -} - -bool -skillbar_check_skill_activation(SkillBar *bar, Player *player) -{ - for (int i = 0; i < PLAYER_SKILL_COUNT; ++i) { - if (!player->skills[i]) - continue; - - if (player->skills[i]->levelcap != player->stats.lvl) - continue; - - timer_start(bar->skillSparkleTimer); - } - - return timer_started(bar->skillSparkleTimer); -} - -static void -render_frame(Camera *cam) +static Sprite* +create_frame_sprite(Camera *cam) { static SDL_Rect c_top_left = { 1*16, 10*16, 16, 16 }; static SDL_Rect c_top_right = { 3*16, 10*16, 16, 16 }; + static SDL_Rect c_center_top = { 2*16, 10*16, 16, 16 }; + static SDL_Rect c_center_bottom = { 2*16, 12*16, 16, 16 }; static SDL_Rect c_bottom_left = { 1*16, 12*16, 16, 16 }; static SDL_Rect c_bottom_right = { 3*16, 12*16, 16, 16 }; + Sprite *frame = sprite_create(); + Texture *texture = texture_create(); + texture->dim = (Dimension) { GAME_VIEW_WIDTH, 32 }; + frame->textures[0] = texture; + frame->destroyTextures = true; + frame->pos = (Position) { 0, 0 }; + frame->dim = (Dimension) { GAME_VIEW_WIDTH, 32 }; + frame->fixed = true; + texture_create_blank(texture, + SDL_TEXTUREACCESS_TARGET, + cam->renderer); + + SDL_SetRenderTarget(cam->renderer, texture->texture); + SDL_RenderClear(cam->renderer); + Texture *t = texturecache_get("GUI/GUI0.png"); SDL_Rect box = { 0, 0, 16, 16 }; - for (unsigned int i = 0; i < MAP_ROOM_WIDTH; ++i) { + // Render skill squares + for (Uint32 i = 0; i < 5; ++i) { box.x = i*32; box.y = 0; texture_render_clip(t, &box, &c_top_left, cam); @@ -114,6 +103,93 @@ render_frame(Camera *cam) box.y = 16; texture_render_clip(t, &box, &c_bottom_right, cam); } + + // Render inventory box + box.x = 5 * 32; + box.y = 0; + texture_render_clip(t, &box, &c_top_left, cam); + box.y = 16; + texture_render_clip(t, &box, &c_bottom_left, cam); + box.x = 5 * 32 + 16; + box.y = 0; + texture_render_clip(t, &box, &c_center_top, cam); + box.y = 16; + texture_render_clip(t, &box, &c_center_bottom, cam); + + for (Uint32 i = 6; i < MAP_ROOM_WIDTH - 1; ++i) { + box.x = i*32; + box.y = 0; + texture_render_clip(t, &box, &c_center_top, cam); + box.y = 16; + texture_render_clip(t, &box, &c_center_bottom, cam); + + box.x = i * 32 + 16; + box.y = 0; + texture_render_clip(t, &box, &c_center_top, cam); + box.y = 16; + texture_render_clip(t, &box, &c_center_bottom, cam); + } + + box.x = (MAP_ROOM_WIDTH - 1) * 32; + box.y = 0; + texture_render_clip(t, &box, &c_center_top, cam); + box.y = 16; + texture_render_clip(t, &box, &c_center_bottom, cam); + box.x = (MAP_ROOM_WIDTH - 1) * 32 + 16; + box.y = 0; + texture_render_clip(t, &box, &c_top_right, cam); + box.y = 16; + texture_render_clip(t, &box, &c_bottom_right, cam); + + SDL_SetRenderTarget(cam->renderer, NULL); + + return frame; +} + +SkillBar * +skillbar_create(Camera *cam) +{ + SkillBar *bar = ec_malloc(sizeof(SkillBar)); + bar->sprites = linkedlist_create(); + bar->activationTimer = timer_create(); + bar->skillSparkleTimer = timer_create(); + bar->lastActivation = 0; + bar->frame = create_frame_sprite(cam); + bar->artifactDisplayOffset = 5 * 32 + 8; + load_texture(bar, "GUI/GUI0.png", cam->renderer); + load_countdown_sprites(bar); + + for (Uint32 i = 0; i < LAST_ARTIFACT_EFFECT; ++i) { + bar->artifacts[i].aSprite = artifact_sprite_for(i); + bar->artifacts[i].aSprite->fixed = true; + bar->artifacts[i].lvl = 0; + + Sprite *lvlSprite = sprite_create(); + lvlSprite->fixed = true; + lvlSprite->dim = DIM(9, 9); + sprite_load_text_texture(lvlSprite, "GUI/SDS_8x8.ttf", 0, 9, 0); + bar->artifacts[i].lvlSprite = lvlSprite; + } + return bar; +} + +bool +skillbar_check_skill_activation(SkillBar *bar, Player *player) +{ + if (player->stats.lvl == 1) + return false; + + for (int i = 0; i < PLAYER_SKILL_COUNT; ++i) { + if (!player->skills[i]) + continue; + + if (player->skills[i]->levelcap != player->stats.lvl) + continue; + + timer_start(bar->skillSparkleTimer); + } + + return timer_started(bar->skillSparkleTimer); } static void @@ -180,6 +256,18 @@ render_skills(Player *player, Camera *cam) } } +static void +render_artifacts(SkillBar *bar, Camera *cam) +{ + UNUSED(bar); + for (size_t i = 0; i < LAST_ARTIFACT_EFFECT; ++i) { + if (bar->artifacts[i].lvl == 0) + continue; + sprite_render(bar->artifacts[i].aSprite, cam); + sprite_render(bar->artifacts[i].lvlSprite, cam); + } +} + static void render_skill_unavailable(SkillBar *bar, Player *player, Camera *cam) { @@ -245,8 +333,9 @@ render_skill_sparkles(SkillBar *bar, Player *player) void skillbar_render(SkillBar *bar, Player *player, Camera *cam) { - render_frame(cam); + sprite_render(bar->frame, cam); render_skills(player, cam); + render_artifacts(bar, cam); render_sprites(bar, cam); render_skill_unavailable(bar, player, cam); render_activation_indicator(bar, cam); @@ -280,6 +369,34 @@ skillbar_update(SkillBar *bar, UpdateData *data) bar->lastActivation = key; timer_start(bar->activationTimer); } + + for (size_t i = 0; i < LAST_ARTIFACT_EFFECT; ++i) { + if (data->player->equipment.artifacts[i].level == bar->artifacts[i].lvl) + continue; + + bar->artifacts[i].lvl = data->player->equipment.artifacts[i].level; + + char lvl[4]; + m_sprintf(lvl, 4, "%u", bar->artifacts[i].lvl); + + texture_load_from_text(bar->artifacts[i].lvlSprite->textures[0], + lvl, C_BLUE, C_WHITE, data->cam->renderer); + + // Only update position if this is the first pickup + if (bar->artifacts[i].lvl == 1) { + bar->artifacts[i].lvlSprite->pos.x = bar->artifactDisplayOffset + 12; + bar->artifacts[i].lvlSprite->pos.y = 16; + bar->artifacts[i].aSprite->pos.x = bar->artifactDisplayOffset; + bar->artifacts[i].aSprite->pos.y = 8; + bar->artifactDisplayOffset += 32; + } + } +} + +void +skillbar_reset(SkillBar *bar) +{ + bar->artifactDisplayOffset = 5 * 32 + 8; } void @@ -287,9 +404,14 @@ skillbar_destroy(SkillBar *bar) { while (bar->sprites) sprite_destroy(linkedlist_pop(&bar->sprites)); - for (unsigned int i = 0; i < PLAYER_SKILL_COUNT; ++i) + for (Uint32 i = 0; i < PLAYER_SKILL_COUNT; ++i) if (bar->countdowns[i]) sprite_destroy(bar->countdowns[i]); + for (Uint32 i = 0; i < LAST_ARTIFACT_EFFECT; ++i) { + sprite_destroy(bar->artifacts[i].aSprite); + sprite_destroy(bar->artifacts[i].lvlSprite); + } + sprite_destroy(bar->frame); timer_destroy(bar->activationTimer); timer_destroy(bar->skillSparkleTimer); free(bar); diff --git a/src/skillbar.h b/src/skillbar.h index 9cb24ff..2928faf 100644 --- a/src/skillbar.h +++ b/src/skillbar.h @@ -28,16 +28,25 @@ struct UpdateData; -typedef struct SkillBar_t { +typedef struct ArtifactDisplay { + Sprite *aSprite; + Sprite *lvlSprite; + Uint32 lvl; +} ArtifactDisplay; + +typedef struct SkillBar { LinkedList *sprites; + ArtifactDisplay artifacts[LAST_ARTIFACT_EFFECT]; + Uint32 artifactDisplayOffset; Sprite *countdowns[PLAYER_SKILL_COUNT]; + Sprite *frame; Timer *activationTimer; Timer *skillSparkleTimer; - unsigned int lastActivation; + Uint32 lastActivation; } SkillBar; SkillBar * -skillbar_create(SDL_Renderer*); +skillbar_create(Camera*); bool skillbar_check_skill_activation(SkillBar*, Player*); @@ -48,6 +57,9 @@ skillbar_render(SkillBar*, Player*, Camera*); void skillbar_update(SkillBar*, struct UpdateData*); +void +skillbar_reset(SkillBar*); + void skillbar_destroy(SkillBar*); diff --git a/src/update_data.h b/src/update_data.h index ca15601..a0c00d9 100644 --- a/src/update_data.h +++ b/src/update_data.h @@ -23,12 +23,14 @@ #include "map.h" #include "roommatrix.h" #include "gui.h" +#include "camera.h" typedef struct UpdateData { Player *player; Map *map; RoomMatrix *matrix; Gui *gui; + Camera *cam; Input *input; float deltatime; } UpdateData;